diff --git a/sign/pdfsignature.go b/sign/pdfsignature.go index b0a2a25..3ec80c0 100644 --- a/sign/pdfsignature.go +++ b/sign/pdfsignature.go @@ -118,10 +118,10 @@ func (context *SignContext) fetchRevocationData() error { // Calculate space needed for signature. for _, crl := range context.SignData.RevocationData.CRL { - context.SignatureMaxLength += uint32(len(crl.FullBytes) * 2) + context.SignatureMaxLength += uint32(hex.EncodedLen(len(crl.FullBytes))) } for _, ocsp := range context.SignData.RevocationData.OCSP { - context.SignatureMaxLength += uint32(len(ocsp.FullBytes) * 2) + context.SignatureMaxLength += uint32(hex.EncodedLen(len(ocsp.FullBytes))) } return nil diff --git a/sign/sign.go b/sign/sign.go index 96b118a..a6d5c5d 100644 --- a/sign/sign.go +++ b/sign/sign.go @@ -3,12 +3,14 @@ package sign import ( "crypto" "crypto/x509" + "encoding/hex" "io" "os" "time" "bitbucket.org/digitorus/pdf" "bitbucket.org/digitorus/pdfsign/revocation" + "github.com/digitorus/pkcs7" "github.com/mattetti/filebuffer" ) @@ -148,12 +150,58 @@ func (context *SignContext) SignPDF() error { } // Base size for signature. - context.SignatureMaxLength = 100000 + context.SignatureMaxLength = uint32(hex.EncodedLen(512)) + + switch string(context.SignData.Certificate.SignatureAlgorithm) { + case "SHA1-RSA": + case "ECDSA-SHA1": + case "DSA-SHA1": + context.SignatureMaxLength += uint32(hex.EncodedLen(128)) + break + case "SHA256-RSA": + case "ECDSA-SHA256": + case "DSA-SHA256": + context.SignatureMaxLength += uint32(hex.EncodedLen(256)) + break + case "SHA384-RSA": + case "ECDSA-SHA384": + context.SignatureMaxLength += uint32(hex.EncodedLen(384)) + break + case "SHA512-RSA": + case "ECDSA-SHA512": + context.SignatureMaxLength += uint32(hex.EncodedLen(512)) + break + } + + // Add size for my certificate. + degenerated, err := pkcs7.DegenerateCertificate(context.SignData.Certificate.Raw) + if err != nil { + return err + } + + context.SignatureMaxLength += uint32(hex.EncodedLen(len(degenerated))) + + // Add size for certificate chain. + var certificate_chain []*x509.Certificate + if len(context.SignData.CertificateChains) > 0 && len(context.SignData.CertificateChains[0]) > 1 { + certificate_chain = context.SignData.CertificateChains[0][1:] + } + + if len(certificate_chain) > 0 { + for _, cert := range certificate_chain { + degenerated, err := pkcs7.DegenerateCertificate(cert.Raw) + if err != nil { + return err + } + + context.SignatureMaxLength += uint32(hex.EncodedLen(len(degenerated))) + } + } // Add estimated size for TSA. // We can't kow actual size of TSA until after signing. if context.SignData.TSA.URL != "" { - context.SignatureMaxLength += 10000 + context.SignatureMaxLength += uint32(hex.EncodedLen(5000)) } // Fetch revocation data before adding signature placeholder. diff --git a/sign/sign_test.go b/sign/sign_test.go index bce1127..c4bc78b 100644 --- a/sign/sign_test.go +++ b/sign/sign_test.go @@ -265,27 +265,29 @@ func BenchmarkSignPDF(b *testing.B) { certificate_chains := make([][]*x509.Certificate, 0) + input_file, err := os.Open("../testfiles/testfile20.pdf") + if err != nil { + b.Errorf("%s: %s", "testfile20.pdf", err.Error()) + return + } + + finfo, err := input_file.Stat() + if err != nil { + input_file.Close() + b.Errorf("%s: %s", "testfile20.pdf", err.Error()) + return + } + size := finfo.Size() + + rdr, err := pdf.NewReader(input_file, size) + if err != nil { + input_file.Close() + b.Errorf("%s: %s", "testfile20.pdf", err.Error()) + return + } + for n := 0; n < b.N; n++ { - input_file, err := os.Open("../testfiles/testfile20.pdf") - if err != nil { - b.Errorf("%s: %s", "testfile20.pdf", err.Error()) - return - } - finfo, err := input_file.Stat() - if err != nil { - input_file.Close() - b.Errorf("%s: %s", "testfile20.pdf", err.Error()) - return - } - size := finfo.Size() - - rdr, err := pdf.NewReader(input_file, size) - if err != nil { - input_file.Close() - b.Errorf("%s: %s", "testfile20.pdf", err.Error()) - return - } err = Sign(input_file, ioutil.Discard, rdr, size, SignData{ Signature: SignDataSignature{ @@ -305,11 +307,11 @@ func BenchmarkSignPDF(b *testing.B) { RevocationData: revocation.InfoArchival{}, }) - input_file.Close() - if err != nil { b.Errorf("%s: %s", "testfile20.pdf", err.Error()) return } } + + input_file.Close() }