From 1c9a9d60b15e833f69cd8775c8161f226a8e68cd Mon Sep 17 00:00:00 2001 From: Jeroen Bobbeldijk Date: Sun, 23 Jul 2017 13:10:35 +0200 Subject: [PATCH] Move fetching of revocation data, guess size of signature --- sign/pdfbyterange.go | 2 +- sign/pdfsignature.go | 93 ++++++++++++++++++++------------------------ sign/sign.go | 14 +++++++ 3 files changed, 57 insertions(+), 52 deletions(-) diff --git a/sign/pdfbyterange.go b/sign/pdfbyterange.go index 5bc3550..9a5e9f0 100644 --- a/sign/pdfbyterange.go +++ b/sign/pdfbyterange.go @@ -22,7 +22,7 @@ func (context *SignContext) updateByteRange() error { context.ByteRangeValues[1] = context.SignatureContentsStartByte - 1 // Signature ByteRange part 2 start byte directly starts after the actual signature. - context.ByteRangeValues[2] = context.ByteRangeValues[1] + 1 + int64(signatureMaxLength) + 1 + context.ByteRangeValues[2] = context.ByteRangeValues[1] + 1 + int64(context.SignatureMaxLength) + 1 // Signature ByteRange part 2 length is everything else of the file. context.ByteRangeValues[3] = output_file_size - context.ByteRangeValues[2] diff --git a/sign/pdfsignature.go b/sign/pdfsignature.go index 5d94b7b..2e28f22 100644 --- a/sign/pdfsignature.go +++ b/sign/pdfsignature.go @@ -29,7 +29,6 @@ type TSAResponse struct { TimeStampToken asn1.RawValue } -var signatureMaxLength = uint32(1000000) var signatureByteRangePlaceholder = "/ByteRange[0 ********** ********** **********]" func (context *SignContext) createSignaturePlaceholder() (signature string, byte_range_start_byte int64, signature_contents_start_byte int64) { @@ -46,7 +45,7 @@ func (context *SignContext) createSignaturePlaceholder() (signature string, byte signature_contents_start_byte = int64(len(signature)) + 11 // Create a placeholder for the actual signature content, we wil replace it later. - signature += " /Contents<" + strings.Repeat("0", int(signatureMaxLength)) + ">" + signature += " /Contents<" + strings.Repeat("0", int(context.SignatureMaxLength)) + ">" if !context.SignData.Signature.Approval { signature += " /Reference [" // array of signature reference dictionaries @@ -88,6 +87,39 @@ func (context *SignContext) createSignaturePlaceholder() (signature string, byte return signature, byte_range_start_byte, signature_contents_start_byte } +func (context *SignContext) fetchRevocationData() error { + if context.SignData.RevocationFunction != nil { + if context.SignData.CertificateChains != nil && (len(context.SignData.CertificateChains) > 0) { + certificate_chain := context.SignData.CertificateChains[0] + if certificate_chain != nil && (len(certificate_chain) > 0) { + for i, certificate := range certificate_chain { + if i < len(certificate_chain)-1 { + err := context.SignData.RevocationFunction(certificate, certificate_chain[i+1], &context.SignData.RevocationData) + if err != nil { + return err + } + } else { + err := context.SignData.RevocationFunction(certificate, nil, &context.SignData.RevocationData) + if err != nil { + return err + } + } + } + } + } + } + + // Calculate space needed for signature. + for _, crl := range context.SignData.RevocationData.CRL { + context.SignatureMaxLength += uint32(len(crl.FullBytes) * 2) + } + for _, ocsp := range context.SignData.RevocationData.OCSP { + context.SignatureMaxLength += uint32(len(ocsp.FullBytes) * 2) + } + + return nil +} + func (context *SignContext) createSignature() ([]byte, error) { // Sadly we can't efficiently sign a file, we need to read all the bytes we want to sign. @@ -107,54 +139,13 @@ func (context *SignContext) createSignature() ([]byte, error) { return nil, err } - signer_config := pkcs7.SignerInfoConfig{} - - TSATokenChain := make([][]*x509.Certificate, 0) - - if context.SignData.RevocationFunction != nil { - if context.SignData.CertificateChains != nil && (len(context.SignData.CertificateChains) > 0) { - certificate_chain := context.SignData.CertificateChains[0] - if certificate_chain != nil && (len(certificate_chain) > 0) { - for i, certificate := range certificate_chain { - if i < len(certificate_chain)-1 { - err = context.SignData.RevocationFunction(certificate, certificate_chain[i+1], &context.SignData.RevocationData) - if err != nil { - return nil, err - } - } else { - err = context.SignData.RevocationFunction(certificate, nil, &context.SignData.RevocationData) - if err != nil { - return nil, err - } - } - } - } - } - - if TSATokenChain != nil && (len(TSATokenChain) > 0) { - certificate_chain := TSATokenChain[0] - if certificate_chain != nil && (len(certificate_chain) > 0) { - for i, certificate := range certificate_chain { - if i < len(certificate_chain)-1 { - err = context.SignData.RevocationFunction(certificate, certificate_chain[i+1], &context.SignData.RevocationData) - if err != nil { - return nil, err - } - } else { - err = context.SignData.RevocationFunction(certificate, nil, &context.SignData.RevocationData) - if err != nil { - return nil, err - } - } - } - } - } - - revocation_attribute := pkcs7.Attribute{ - Type: asn1.ObjectIdentifier{1, 2, 840, 113583, 1, 1, 8}, - Value: context.SignData.RevocationData, - } - signer_config.ExtraSignedAttributes = append(signer_config.ExtraSignedAttributes, revocation_attribute) + signer_config := pkcs7.SignerInfoConfig{ + ExtraSignedAttributes: []pkcs7.Attribute{ + { + Type: asn1.ObjectIdentifier{1, 2, 840, 113583, 1, 1, 8}, + Value: context.SignData.RevocationData, + }, + }, } // Add the first certificate chain without our own certificate. @@ -271,7 +262,7 @@ func (context *SignContext) replaceSignature() error { dst := make([]byte, hex.EncodedLen(len(signature))) hex.Encode(dst, signature) - if uint32(len(dst)) > signatureMaxLength { + if uint32(len(dst)) > context.SignatureMaxLength { return errors.New("Signature is too big to fit in reserved space.") } diff --git a/sign/sign.go b/sign/sign.go index f3954f3..0deb1de 100644 --- a/sign/sign.go +++ b/sign/sign.go @@ -73,6 +73,7 @@ type SignContext struct { ByteRangeStartByte int64 SignatureContentsStartByte int64 ByteRangeValues []int64 + SignatureMaxLength uint32 } func SignFile(input string, output string, sign_data SignData) error { @@ -143,6 +144,19 @@ func (context *SignContext) SignPDF() error { return err } + // Base size for signature. + context.SignatureMaxLength = 100000 + + // Add estimated size for TSA. + // We can't kow actual size of TSA until after signing. + if context.SignData.TSA.URL != "" { + context.SignatureMaxLength += 10000 + } + + // Fetch revocation data before adding signature placeholder. + // Revocation data can be quite large and we need to create enough space in the placeholder. + context.fetchRevocationData() + visual_signature, err := context.createVisualSignature() if err != nil { return err