From c8e53c9bcf2d6c3a28f188daae8130b7e73cc4bc Mon Sep 17 00:00:00 2001 From: Jeroen Bobbeldijk Date: Thu, 13 Jul 2017 20:30:18 +0200 Subject: [PATCH] Add revocation information --- certificate.pem | 19 +++++++++++++++++++ revocation/revocation.go | 8 ++++---- sign.go | 5 ++++- sign/pdfsignature.go | 25 +++++++++++++++++++++++-- sign/revocation.go | 23 ++++++++++++----------- sign/revocation_test.go | 2 +- sign/sign.go | 23 ++++++++++++++--------- 7 files changed, 77 insertions(+), 28 deletions(-) create mode 100644 certificate.pem diff --git a/certificate.pem b/certificate.pem new file mode 100644 index 0000000..ddeeb1f --- /dev/null +++ b/certificate.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDBDCCAm2gAwIBAgIJAP6vkkLP72OOMA0GCSqGSIb3DQEBCwUAMIGZMQswCQYD +VQQGEwJOTDEVMBMGA1UECAwMWnVpZC1Ib2xsYW5kMRIwEAYDVQQHDAlSb3R0ZXJk +YW0xEjAQBgNVBAoMCVVuaWNvZGVyczELMAkGA1UECwwCSVQxGjAYBgNVBAMMEUpl +cm9lbiBCb2JiZWxkaWprMSIwIAYJKoZIhvcNAQkBFhNqZXJvZW5AdW5pY29kZXJz +Lm5sMCAXDTE3MDcwNjE5MzYwOVoYDzMwMTYxMTA2MTkzNjA5WjCBmTELMAkGA1UE +BhMCTkwxFTATBgNVBAgMDFp1aWQtSG9sbGFuZDESMBAGA1UEBwwJUm90dGVyZGFt +MRIwEAYDVQQKDAlVbmljb2RlcnMxCzAJBgNVBAsMAklUMRowGAYDVQQDDBFKZXJv +ZW4gQm9iYmVsZGlqazEiMCAGCSqGSIb3DQEJARYTamVyb2VuQHVuaWNvZGVycy5u +bDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEArpfaVUltYdOSISuc8V5vAy6b +jpqYuxsS5I6jpL1nMKms9IB5+uk+Glo2O/tb+W/R8zxQ3xrQ6JWZ4ZSsBhKNVink +Su3+kdAQJfHn3NLJzx0QGceo0TF2RvVGo5c91zxuA8rchdNz1QxrD6QesGKyfsXn +F+oELezafT346PbeqikCAwEAAaNQME4wHQYDVR0OBBYEFKA68BB0iwhY2RIRFIYs +gmq0l6y7MB8GA1UdIwQYMBaAFKA68BB0iwhY2RIRFIYsgmq0l6y7MAwGA1UdEwQF +MAMBAf8wDQYJKoZIhvcNAQELBQADgYEAZ75HjcE/d/nclPTQbCN9qvUyuU76ml4O +jDN8T+loOsUKmI4VVsNLzF6DXq8sg4EP7s8kEEzM7qhoijw09OUhVniBYN3SzJYX +l8AiThPGqcIm1TrkqPULYQBu/FnMoL6SP7kAULcsUvEmn1rPcG9ESQ4sK/ceJhFZ +zk9o3rVC0PU= +-----END CERTIFICATE----- diff --git a/revocation/revocation.go b/revocation/revocation.go index fcab598..0c44148 100644 --- a/revocation/revocation.go +++ b/revocation/revocation.go @@ -1,8 +1,8 @@ package revocation import ( + "crypto/x509" "encoding/asn1" - "crypto/x509" ) // InfoArchival is the pkcs7 container containing the revocation information for @@ -21,13 +21,13 @@ type InfoArchival struct { // pass the bytes of a downloaded CRL to this function. func (r *InfoArchival) AddCRL(b []byte) error { r.CRL = append(r.CRL, asn1.RawValue{FullBytes: b}) - return nil + return nil } // AddOCSP is used to embed the raw bytes of an OCSP response. func (r *InfoArchival) AddOCSP(b []byte) error { r.OCSP = append(r.OCSP, asn1.RawValue{FullBytes: b}) - return nil + return nil } // IsRevoked checks if there is a status inclded for the certificate and returns @@ -37,7 +37,7 @@ func (r *InfoArchival) AddOCSP(b []byte) error { // TODO: Information about the revocation (time, reason, etc) must be extractable func (r *InfoArchival) IsRevoked(c *x509.Certificate) bool { // check the crl and ocsp to see if this certificate is revoked - return true + return true } // CRL contains the raw bytes of a pkix.CertificateList and can be parsed with diff --git a/sign.go b/sign.go index 057dc45..9e393f2 100644 --- a/sign.go +++ b/sign.go @@ -11,6 +11,7 @@ import ( "errors" "io/ioutil" + "bitbucket.org/digitorus/pdfsign/revocation" "bitbucket.org/digitorus/pdfsign/sign" "bitbucket.org/digitorus/pdfsign/verify" ) @@ -104,8 +105,10 @@ func main() { Signer: pkey, Certificate: cert, TSA: sign.TSA{ - URL: "http://aatl-timestamp.globalsign.com/tsa/aohfewat2389535fnasgnlg5m23", + URL: "http://aatl-timestamp.globalsign.com/tsa/aohfewat2389535fnasgnlg5m23", }, + RevocationData: revocation.InfoArchival{}, + RevocationFunction: sign.DefaultEmbedRevocationStatusFunction, }) if err != nil { log.Println(err) diff --git a/sign/pdfsignature.go b/sign/pdfsignature.go index d2a93cb..00b5b8a 100644 --- a/sign/pdfsignature.go +++ b/sign/pdfsignature.go @@ -135,12 +135,33 @@ func (context *SignContext) createSignature() ([]byte, error) { Type: asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 16, 2, 14}, Value: resp.TimeStampToken, } - signer_config.ExtraUnsignedAttributes = append(signer_config.ExtraSignedAttributes, timestamp_attribute) + signer_config.ExtraUnsignedAttributes = append(signer_config.ExtraUnsignedAttributes, timestamp_attribute) + } + + 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 + } + } + } + + 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) } // 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 { - return nil, err } diff --git a/sign/revocation.go b/sign/revocation.go index 5796e62..c969cb5 100644 --- a/sign/revocation.go +++ b/sign/revocation.go @@ -3,7 +3,6 @@ package sign import ( "crypto/x509" "encoding/base64" - "errors" "fmt" "io/ioutil" "net/http" @@ -38,8 +37,7 @@ func embedOCSPRevocationStatus(cert, issuer *x509.Certificate, i *revocation.Inf return err } - i.AddOCSP(body) - return nil + return i.AddOCSP(body) } // embedCRLRevocationStatus requires an issuer as it needs to implement the @@ -56,11 +54,10 @@ func embedCRLRevocationStatus(cert, issuer *x509.Certificate, i *revocation.Info } // TODO: verify crl and certificate before embedding - i.AddCRL(body) - return nil + return i.AddCRL(body) } -func embedRevocationStatus(cert, issuer *x509.Certificate, i *revocation.InfoArchival) error { +func DefaultEmbedRevocationStatusFunction(cert, issuer *x509.Certificate, i *revocation.InfoArchival) error { // For each certificate a revoction status needs to be included, this can be done // by embedding a CRL or OCSP response. In most cases an OCSP response is smaller // to embed in the document but and empty CRL (often seen of dediced high volume @@ -74,15 +71,19 @@ func embedRevocationStatus(cert, issuer *x509.Certificate, i *revocation.InfoArc // using an OCSP server if len(cert.OCSPServer) > 0 { - embedOCSPRevocationStatus(cert, issuer, i) - return nil + err := embedOCSPRevocationStatus(cert, issuer, i) + if err != nil { + return err + } } // using a crl if len(cert.CRLDistributionPoints) > 0 { - embedCRLRevocationStatus(cert, issuer, i) - return nil + err := embedCRLRevocationStatus(cert, issuer, i) + if err != nil { + return err + } } - return errors.New("certificate contains no information to check status") + return nil } diff --git a/sign/revocation_test.go b/sign/revocation_test.go index 34b79b0..7542aac 100644 --- a/sign/revocation_test.go +++ b/sign/revocation_test.go @@ -75,7 +75,7 @@ htN+laG7bS/8xGTPothL9Abgd/9L3X0KKGUDCdcpzRuy20CI7E4uygD8 func TestEmbedRevocationStatus(t *testing.T) { var ia revocation.InfoArchival - err := embedRevocationStatus(pemToCert(certPem), pemToCert(issuerPem), &ia) + err := DefaultEmbedRevocationStatusFunction(pemToCert(certPem), pemToCert(issuerPem), &ia) if err != nil { t.Errorf("%s", err.Error()) } diff --git a/sign/sign.go b/sign/sign.go index b92b7e1..3fe16a0 100644 --- a/sign/sign.go +++ b/sign/sign.go @@ -8,6 +8,7 @@ import ( "time" "bitbucket.org/digitorus/pdf" + "bitbucket.org/digitorus/pdfsign/revocation" ) type CatalogData struct { @@ -17,18 +18,22 @@ type CatalogData struct { } type TSA struct { - URL string - Username string - Password string + URL string + Username string + Password string } +type RevocationFunction func(cert, issuer *x509.Certificate, i *revocation.InfoArchival) error + type SignData struct { - ObjectId uint32 - Signature SignDataSignature - Signer crypto.Signer - Certificate *x509.Certificate - CertificateChain []*x509.Certificate - TSA TSA + ObjectId uint32 + Signature SignDataSignature + Signer crypto.Signer + Certificate *x509.Certificate + CertificateChain []*x509.Certificate + TSA TSA + RevocationData revocation.InfoArchival + RevocationFunction RevocationFunction } type VisualSignData struct {