From 4fe43c0794e6343bbee36b77f073bc689f16ea55 Mon Sep 17 00:00:00 2001 From: Paul van Brouwershaven Date: Thu, 30 Jun 2022 18:05:16 +0200 Subject: [PATCH] Use timestamp package for TSA --- go.mod | 2 +- go.sum | 4 +++ sign/pdfsignature.go | 76 +++++++++++++++++--------------------------- 3 files changed, 35 insertions(+), 47 deletions(-) diff --git a/go.mod b/go.mod index 16e42a8..ca84f3d 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.17 require ( github.com/digitorus/pdf v0.1.2 github.com/digitorus/pkcs7 v0.0.0-20200320092839-808436b6f6d1 - github.com/digitorus/timestamp v0.0.0-20210102082646-54ddd7720e27 + github.com/digitorus/timestamp v0.0.0-20220630150916-a1b00e34b289 github.com/mattetti/filebuffer v1.0.1 golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70 ) diff --git a/go.sum b/go.sum index b538bc2..164fc45 100644 --- a/go.sum +++ b/go.sum @@ -8,6 +8,10 @@ github.com/digitorus/pkcs7 v0.0.0-20200320092839-808436b6f6d1 h1:V1cgDSp4Kq4eMCf github.com/digitorus/pkcs7 v0.0.0-20200320092839-808436b6f6d1/go.mod h1:p2IZ9yq2kEKGFr3rfpYxaaOzB0VdLbF8VkZReEIpJmU= github.com/digitorus/timestamp v0.0.0-20210102082646-54ddd7720e27 h1:X8tvQGATvS7vQBAPPn0f7nQPcTamu4ecCbRafPrBgik= github.com/digitorus/timestamp v0.0.0-20210102082646-54ddd7720e27/go.mod h1:IKw2TcDeMaZrNjpdq7gPc7I+a21+Sn34bUqWrTc70Hs= +github.com/digitorus/timestamp v0.0.0-20220630080933-558840f252f5 h1:zYpNMBe+1x3h0FMTJThci7KimEldiiOrn0ENMP6+I/8= +github.com/digitorus/timestamp v0.0.0-20220630080933-558840f252f5/go.mod h1:IKw2TcDeMaZrNjpdq7gPc7I+a21+Sn34bUqWrTc70Hs= +github.com/digitorus/timestamp v0.0.0-20220630150916-a1b00e34b289 h1:WIoYZV4zZKwIymytM65i+WgqyTN/ElCf7KddV01C+0s= +github.com/digitorus/timestamp v0.0.0-20220630150916-a1b00e34b289/go.mod h1:IKw2TcDeMaZrNjpdq7gPc7I+a21+Sn34bUqWrTc70Hs= github.com/mattetti/filebuffer v1.0.1 h1:gG7pyfnSIZCxdoKq+cPa8T0hhYtD9NxCdI4D7PTjRLM= github.com/mattetti/filebuffer v1.0.1/go.mod h1:YdMURNDOttIiruleeVr6f56OrMc+MydEnTcXwtkxNVs= golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70 h1:syTAU9FwmvzEoIYMqcPHOcVm4H3U5u90WsvuYgwpETU= diff --git a/sign/pdfsignature.go b/sign/pdfsignature.go index 32f4f73..c509457 100644 --- a/sign/pdfsignature.go +++ b/sign/pdfsignature.go @@ -15,18 +15,6 @@ import ( "github.com/digitorus/timestamp" ) -type pkiStatusInfo struct { - Status int - StatusString string `asn1:"optional"` - FailInfo int `asn1:"optional"` -} - -// 2.4.2. Response Format -type TSAResponse struct { - Status pkiStatusInfo - TimeStampToken asn1.RawValue -} - var signatureByteRangePlaceholder = "/ByteRange[0 ********** ********** **********]" func (context *SignContext) createSignaturePlaceholder() (dssd string, byte_range_start_byte int64, signature_contents_start_byte int64) { @@ -134,7 +122,9 @@ func (context *SignContext) fetchRevocationData() error { } func (context *SignContext) createSignature() ([]byte, error) { - context.OutputBuffer.Seek(0, 0) + if _, err := context.OutputBuffer.Seek(0, 0); err != nil { + return nil, err + } // Sadly we can't efficiently sign a file, we need to read all the bytes we want to sign. file_content := context.OutputBuffer.Buff.Bytes() @@ -147,7 +137,7 @@ func (context *SignContext) createSignature() ([]byte, error) { // Initialize pkcs7 signer. signed_data, err := pkcs7.NewSignedData(sign_content) if err != nil { - return nil, err + return nil, fmt.Errorf("new signed data: %w", err) } signer_config := pkcs7.SignerInfoConfig{ @@ -167,7 +157,7 @@ func (context *SignContext) createSignature() ([]byte, error) { // Add the signer and sign the data. if err := signed_data.AddSignerChain(context.SignData.Certificate, context.SignData.Signer, certificate_chain, signer_config); err != nil { - return nil, err + return nil, fmt.Errorf("add signer chain: %w", err) } // PDF needs a detached signature, meaning the content isn't included. @@ -178,36 +168,26 @@ func (context *SignContext) createSignature() ([]byte, error) { timestamp_response, err := context.GetTSA(signature_data.SignerInfos[0].EncryptedDigest) if err != nil { - return nil, err + return nil, fmt.Errorf("get timestamp: %w", err) } - var rest []byte - var resp TSAResponse - if rest, err = asn1.Unmarshal(timestamp_response, &resp); err != nil { - return nil, err - } - if len(rest) > 0 { - return nil, errors.New("trailing data in Time-Stamp response") - } - - if resp.Status.Status > 0 { - return nil, errors.New(fmt.Sprintf("%s: %s", timestamp.FailureInfo(resp.Status.FailInfo).String(), resp.Status.StatusString)) - } - - _, err = pkcs7.Parse(resp.TimeStampToken.FullBytes) + ts, err := timestamp.ParseResponse(timestamp_response) if err != nil { - return nil, err + return nil, fmt.Errorf("parse timestamp: %w", err) } - if len(resp.TimeStampToken.Bytes) == 0 { - return nil, errors.New("no pkcs7 data in Time-Stamp response") + _, err = pkcs7.Parse(ts.RawToken) + if err != nil { + return nil, fmt.Errorf("parse timestamp token: %w", err) } timestamp_attribute := pkcs7.Attribute{ Type: asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 16, 2, 14}, - Value: resp.TimeStampToken, + Value: asn1.RawValue{FullBytes: ts.RawToken}, + } + if err := signature_data.SignerInfos[0].SetUnauthenticatedAttributes([]pkcs7.Attribute{timestamp_attribute}); err != nil { + return nil, err } - signature_data.SignerInfos[0].SetUnauthenticatedAttributes([]pkcs7.Attribute{timestamp_attribute}) } return signed_data.Finish() @@ -219,13 +199,13 @@ func (context *SignContext) GetTSA(sign_content []byte) (timestamp_response []by Certificates: true, }) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to create request: %w", err) } ts_request_reader := bytes.NewReader(ts_request) req, err := http.NewRequest("POST", context.SignData.TSA.URL, ts_request_reader) if err != nil { - return nil, fmt.Errorf("error requesting timestamp (%s): %w", context.SignData.TSA.URL, err) + return nil, fmt.Errorf("failed to prepare request (%s): %w", context.SignData.TSA.URL, err) } req.Header.Add("Content-Type", "application/timestamp-query") @@ -247,18 +227,16 @@ func (context *SignContext) GetTSA(sign_content []byte) (timestamp_response []by if err == nil { defer resp.Body.Close() body, _ := ioutil.ReadAll(resp.Body) - err = errors.New("non success response (" + strconv.Itoa(code) + "): " + string(body)) - } else { - err = errors.New("non success response (" + strconv.Itoa(code) + ")") + return nil, errors.New("non success response (" + strconv.Itoa(code) + "): " + string(body)) } - return nil, err + return nil, errors.New("non success response (" + strconv.Itoa(code) + ")") } defer resp.Body.Close() timestamp_response_body, err := ioutil.ReadAll(resp.Body) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to read response: %w", err) } return timestamp_response_body, nil @@ -267,7 +245,7 @@ func (context *SignContext) GetTSA(sign_content []byte) (timestamp_response []by func (context *SignContext) replaceSignature() error { signature, err := context.createSignature() if err != nil { - return err + return fmt.Errorf("failed to create signature: %w", err) } dst := make([]byte, hex.EncodedLen(len(signature))) @@ -280,17 +258,23 @@ func (context *SignContext) replaceSignature() error { return context.SignPDF() } - context.OutputBuffer.Seek(0, 0) + if _, err := context.OutputBuffer.Seek(0, 0); err != nil { + return err + } file_content := context.OutputBuffer.Buff.Bytes() - context.OutputBuffer.Write(file_content[:(context.ByteRangeValues[0] + context.ByteRangeValues[1] + 1)]) + if _, err := context.OutputBuffer.Write(file_content[:(context.ByteRangeValues[0] + context.ByteRangeValues[1] + 1)]); err != nil { + return err + } // Write new ByteRange. if _, err := context.OutputBuffer.Write([]byte(dst)); err != nil { return err } - context.OutputBuffer.Write(file_content[(context.ByteRangeValues[0]+context.ByteRangeValues[1]+1)+int64(len(dst)):]) + if _, err := context.OutputBuffer.Write(file_content[(context.ByteRangeValues[0]+context.ByteRangeValues[1]+1)+int64(len(dst)):]); err != nil { + return err + } return nil }