From 3928b7d8137b16636552ccd669152033e793b325 Mon Sep 17 00:00:00 2001 From: Jeroen Bobbeldijk Date: Thu, 13 Jul 2017 21:55:35 +0200 Subject: [PATCH] Creation of chain, add chain to signing, fetch OCSP/CRL for chain --- sign.go | 30 +++++++++++++++++++++++++++++- sign/pdfsignature.go | 36 ++++++++++++++++++++++++------------ sign/revocation.go | 4 +++- sign/sign.go | 2 +- 4 files changed, 57 insertions(+), 15 deletions(-) diff --git a/sign.go b/sign.go index 9e393f2..47cf665 100644 --- a/sign.go +++ b/sign.go @@ -17,7 +17,7 @@ import ( ) func usage() { - log.Fatal("Usage: sign input.pdf output.pdf certificate.crt private_key.key OR verify input.pdf") + log.Fatal("Usage: sign input.pdf output.pdf certificate.crt private_key.key [chain.crt] OR verify input.pdf") } func main() { @@ -90,6 +90,33 @@ func main() { log.Fatal(err) } + certificate_chains := make([][]*x509.Certificate, 0) + + if flag.Arg(5) != "" { + certificate_pool := x509.NewCertPool() + if err != nil { + log.Fatal(err) + } + + chain_data, err := ioutil.ReadFile(flag.Arg(5)) + if err != nil { + log.Fatal(err) + } + + certificate_pool.AppendCertsFromPEM(chain_data) + certificate_chains, err = cert.Verify(x509.VerifyOptions{ + Intermediates: certificate_pool, + }) + if err != nil { + log.Fatal(err) + } + + chain_data_block, _ := pem.Decode(chain_data) + if chain_data_block == nil { + log.Fatal(errors.New("failed to parse PEM block containing the chain")) + } + } + err = sign.SignFile(input, output, sign.SignData{ Signature: sign.SignDataSignature{ Info: sign.SignDataSignatureInfo{ @@ -104,6 +131,7 @@ func main() { }, Signer: pkey, Certificate: cert, + CertificateChains: certificate_chains, TSA: sign.TSA{ URL: "http://aatl-timestamp.globalsign.com/tsa/aohfewat2389535fnasgnlg5m23", }, diff --git a/sign/pdfsignature.go b/sign/pdfsignature.go index 00b5b8a..7066d02 100644 --- a/sign/pdfsignature.go +++ b/sign/pdfsignature.go @@ -14,6 +14,7 @@ import ( "github.com/digitorus/pkcs7" "github.com/digitorus/timestamp" + "crypto/x509" ) type pkiStatusInfo struct { @@ -28,7 +29,7 @@ type TSAResponse struct { TimeStampToken asn1.RawValue } -var signatureMaxLength = uint32(11742) +var signatureMaxLength = uint32(1000000) var signatureByteRangePlaceholder = "/ByteRange[0 ********** ********** **********]" func (context *SignContext) createSignaturePlaceholder() (signature string, byte_range_start_byte int64, signature_contents_start_byte int64) { @@ -139,16 +140,21 @@ func (context *SignContext) createSignature() ([]byte, error) { } if context.SignData.RevocationFunction != nil { - err = context.SignData.RevocationFunction(context.SignData.Certificate, nil, &context.SignData.RevocationData) - if err != nil { - return nil, err - } - - if context.SignData.CertificateChain != nil && len(context.SignData.CertificateChain) > 0 { - for _, cert := range context.SignData.CertificateChain { - err = context.SignData.RevocationFunction(cert, nil, &context.SignData.RevocationData) - if err != nil { - return nil, err + if (len(context.SignData.CertificateChains) > 0) { + certificate_chain := context.SignData.CertificateChains[0] + if (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 + } + } } } } @@ -160,8 +166,14 @@ func (context *SignContext) createSignature() ([]byte, error) { signer_config.ExtraSignedAttributes = append(signer_config.ExtraSignedAttributes, revocation_attribute) } + // Add the first certificate chain without our own certificate. + var certificate_chain []*x509.Certificate + if (len(context.SignData.CertificateChains) > 0 && len(context.SignData.CertificateChains[0]) > 1) { + certificate_chain = context.SignData.CertificateChains[0][1:] + } + // Add the signer and sign the data. - if err := signed_data.AddSignerChain(context.SignData.Certificate, context.SignData.Signer, context.SignData.CertificateChain, signer_config); err != nil { + if err := signed_data.AddSignerChain(context.SignData.Certificate, context.SignData.Signer, certificate_chain, signer_config); err != nil { return nil, err } diff --git a/sign/revocation.go b/sign/revocation.go index c969cb5..7200337 100644 --- a/sign/revocation.go +++ b/sign/revocation.go @@ -21,6 +21,7 @@ func embedOCSPRevocationStatus(cert, issuer *x509.Certificate, i *revocation.Inf ocspUrl := fmt.Sprintf("%s/%s", strings.TrimRight(cert.OCSPServer[0], "/"), base64.StdEncoding.EncodeToString(req)) + resp, err := http.Get(ocspUrl) if err != nil { return err @@ -70,7 +71,8 @@ func DefaultEmbedRevocationStatusFunction(cert, issuer *x509.Certificate, i *rev // TODO: Implement revocation status caching (required for higher volume signing) // using an OCSP server - if len(cert.OCSPServer) > 0 { + // OCSP requires issuer certificate. + if issuer != nil && len(cert.OCSPServer) > 0 { err := embedOCSPRevocationStatus(cert, issuer, i) if err != nil { return err diff --git a/sign/sign.go b/sign/sign.go index 3fe16a0..f3954f3 100644 --- a/sign/sign.go +++ b/sign/sign.go @@ -30,7 +30,7 @@ type SignData struct { Signature SignDataSignature Signer crypto.Signer Certificate *x509.Certificate - CertificateChain []*x509.Certificate + CertificateChains [][]*x509.Certificate TSA TSA RevocationData revocation.InfoArchival RevocationFunction RevocationFunction