diff --git a/Gopkg.lock b/Gopkg.lock index 15720c6..418d3f4 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -26,7 +26,7 @@ version = "0.0.4" [[projects]] - digest = "1:26ab843f72f1e7b54b7ad984510a956926e623f880a26faca9375d2199d928d2" + digest = "1:cd679ecc274bc8e7f7ab4ec77e1d0fd48d9f9f470fbad178925471d386357165" name = "github.com/mastahyeti/cms" packages = [ ".", @@ -35,8 +35,8 @@ "timestamp", ] pruneopts = "" - revision = "a229af0c48a09fb2fd15983d09eb47052521ce03" - version = "0.0.2" + revision = "ec6fafdd655a614d13a9336ea483e37d51a11752" + version = "0.0.5" [[projects]] branch = "master" diff --git a/Gopkg.toml b/Gopkg.toml index e71e016..7cba9eb 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -31,7 +31,7 @@ [[constraint]] name = "github.com/mastahyeti/cms" - version = "0.0.2" + version = "0.0.5" [[constraint]] branch = "master" diff --git a/vendor/github.com/mastahyeti/cms/.travis.yml b/vendor/github.com/mastahyeti/cms/.travis.yml index c98a380..cf64a5d 100644 --- a/vendor/github.com/mastahyeti/cms/.travis.yml +++ b/vendor/github.com/mastahyeti/cms/.travis.yml @@ -1,6 +1,7 @@ language: go go: - "1.10.x" + - "1.11.x" - "1.x" install: go get -v -t ./... diff --git a/vendor/github.com/mastahyeti/cms/README.md b/vendor/github.com/mastahyeti/cms/README.md index 291e398..e32346b 100644 --- a/vendor/github.com/mastahyeti/cms/README.md +++ b/vendor/github.com/mastahyeti/cms/README.md @@ -11,7 +11,7 @@ msg := []byte("some data") cert, _ := x509.ParseCertificate(someCertificateData) key, _ := x509.ParseECPrivateKey(somePrivateKeyData) -der, _ := cms.Sign(msg, cert, key) +der, _ := cms.Sign(msg, []*x509.Certificate{cert}, key) //// /// At another time, in another place... diff --git a/vendor/github.com/mastahyeti/cms/main_test.go b/vendor/github.com/mastahyeti/cms/main_test.go index c1c4515..1899506 100644 --- a/vendor/github.com/mastahyeti/cms/main_test.go +++ b/vendor/github.com/mastahyeti/cms/main_test.go @@ -98,7 +98,7 @@ func (tt *testTSA) Do(req timestamp.Request) (timestamp.Response, error) { panic(err) } - eci, err := protocol.NewEncapsulatedContentInfo(oid.TSTInfo, eciDER) + eci, err := protocol.NewEncapsulatedContentInfo(oid.ContentTypeTSTInfo, eciDER) if err != nil { panic(err) } diff --git a/vendor/github.com/mastahyeti/cms/oid/oid.go b/vendor/github.com/mastahyeti/cms/oid/oid.go index a635720..b281392 100644 --- a/vendor/github.com/mastahyeti/cms/oid/oid.go +++ b/vendor/github.com/mastahyeti/cms/oid/oid.go @@ -8,43 +8,45 @@ import ( "encoding/asn1" ) -// Content type OIDs var ( - Data = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 1} - SignedData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 2} - TSTInfo = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 16, 1, 4} -) + ContentTypeData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 1} + ContentTypeSignedData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 2} + ContentTypeTSTInfo = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 16, 1, 4} -// Attribute OIDs -var ( AttributeContentType = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 3} AttributeMessageDigest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 4} AttributeSigningTime = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 5} AttributeTimeStampToken = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 16, 2, 14} -) -// Signature Algorithm OIDs -var ( - SignatureAlgorithmRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1} - SignatureAlgorithmECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1} -) + PublicKeyAlgorithmRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1} + PublicKeyAlgorithmECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1} -// Digest Algorithm OIDs -var ( DigestAlgorithmSHA1 = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 26} DigestAlgorithmMD5 = asn1.ObjectIdentifier{1, 2, 840, 113549, 2, 5} DigestAlgorithmSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 1} DigestAlgorithmSHA384 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 2} DigestAlgorithmSHA512 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 3} -) -// X509 extensions -var ( - SubjectKeyIdentifier = asn1.ObjectIdentifier{2, 5, 29, 14} + SignatureAlgorithmMD2WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 2} + SignatureAlgorithmMD5WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4} + SignatureAlgorithmSHA1WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5} + SignatureAlgorithmSHA256WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11} + SignatureAlgorithmSHA384WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12} + SignatureAlgorithmSHA512WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13} + SignatureAlgorithmRSAPSS = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 10} + SignatureAlgorithmDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3} + SignatureAlgorithmDSAWithSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 2} + SignatureAlgorithmECDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 1} + SignatureAlgorithmECDSAWithSHA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2} + SignatureAlgorithmECDSAWithSHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3} + SignatureAlgorithmECDSAWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4} + SignatureAlgorithmISOSHA1WithRSA = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 29} + + ExtensionSubjectKeyIdentifier = asn1.ObjectIdentifier{2, 5, 29, 14} ) -// DigestAlgorithmToHash maps digest OIDs to crypto.Hash values. -var DigestAlgorithmToHash = map[string]crypto.Hash{ +// DigestAlgorithmToCryptoHash maps digest OIDs to crypto.Hash values. +var DigestAlgorithmToCryptoHash = map[string]crypto.Hash{ DigestAlgorithmSHA1.String(): crypto.SHA1, DigestAlgorithmMD5.String(): crypto.MD5, DigestAlgorithmSHA256.String(): crypto.SHA256, @@ -52,8 +54,8 @@ var DigestAlgorithmToHash = map[string]crypto.Hash{ DigestAlgorithmSHA512.String(): crypto.SHA512, } -// HashToDigestAlgorithm maps crypto.Hash values to digest OIDs. -var HashToDigestAlgorithm = map[crypto.Hash]asn1.ObjectIdentifier{ +// CryptoHashToDigestAlgorithm maps crypto.Hash values to digest OIDs. +var CryptoHashToDigestAlgorithm = map[crypto.Hash]asn1.ObjectIdentifier{ crypto.SHA1: DigestAlgorithmSHA1, crypto.MD5: DigestAlgorithmMD5, crypto.SHA256: DigestAlgorithmSHA256, @@ -61,9 +63,9 @@ var HashToDigestAlgorithm = map[crypto.Hash]asn1.ObjectIdentifier{ crypto.SHA512: DigestAlgorithmSHA512, } -// SignatureAlgorithmToDigestAlgorithm maps x509.SignatureAlgorithm to +// X509SignatureAlgorithmToDigestAlgorithm maps x509.SignatureAlgorithm to // digestAlgorithm OIDs. -var SignatureAlgorithmToDigestAlgorithm = map[x509.SignatureAlgorithm]asn1.ObjectIdentifier{ +var X509SignatureAlgorithmToDigestAlgorithm = map[x509.SignatureAlgorithm]asn1.ObjectIdentifier{ x509.SHA1WithRSA: DigestAlgorithmSHA1, x509.MD5WithRSA: DigestAlgorithmMD5, x509.SHA256WithRSA: DigestAlgorithmSHA256, @@ -75,31 +77,31 @@ var SignatureAlgorithmToDigestAlgorithm = map[x509.SignatureAlgorithm]asn1.Objec x509.ECDSAWithSHA512: DigestAlgorithmSHA512, } -// SignatureAlgorithmToSignatureAlgorithm maps x509.SignatureAlgorithm to +// X509SignatureAlgorithmToPublicKeyAlgorithm maps x509.SignatureAlgorithm to // signatureAlgorithm OIDs. -var SignatureAlgorithmToSignatureAlgorithm = map[x509.SignatureAlgorithm]asn1.ObjectIdentifier{ - x509.SHA1WithRSA: SignatureAlgorithmRSA, - x509.MD5WithRSA: SignatureAlgorithmRSA, - x509.SHA256WithRSA: SignatureAlgorithmRSA, - x509.SHA384WithRSA: SignatureAlgorithmRSA, - x509.SHA512WithRSA: SignatureAlgorithmRSA, - x509.ECDSAWithSHA1: SignatureAlgorithmECDSA, - x509.ECDSAWithSHA256: SignatureAlgorithmECDSA, - x509.ECDSAWithSHA384: SignatureAlgorithmECDSA, - x509.ECDSAWithSHA512: SignatureAlgorithmECDSA, +var X509SignatureAlgorithmToPublicKeyAlgorithm = map[x509.SignatureAlgorithm]asn1.ObjectIdentifier{ + x509.SHA1WithRSA: PublicKeyAlgorithmRSA, + x509.MD5WithRSA: PublicKeyAlgorithmRSA, + x509.SHA256WithRSA: PublicKeyAlgorithmRSA, + x509.SHA384WithRSA: PublicKeyAlgorithmRSA, + x509.SHA512WithRSA: PublicKeyAlgorithmRSA, + x509.ECDSAWithSHA1: PublicKeyAlgorithmECDSA, + x509.ECDSAWithSHA256: PublicKeyAlgorithmECDSA, + x509.ECDSAWithSHA384: PublicKeyAlgorithmECDSA, + x509.ECDSAWithSHA512: PublicKeyAlgorithmECDSA, } -// SignatureAlgorithms maps digest and signature OIDs to -// x509.SignatureAlgorithm values. -var SignatureAlgorithms = map[string]map[string]x509.SignatureAlgorithm{ - SignatureAlgorithmRSA.String(): map[string]x509.SignatureAlgorithm{ +// PublicKeyAndDigestAlgorithmToX509SignatureAlgorithm maps digest and signature +// OIDs to x509.SignatureAlgorithm values. +var PublicKeyAndDigestAlgorithmToX509SignatureAlgorithm = map[string]map[string]x509.SignatureAlgorithm{ + PublicKeyAlgorithmRSA.String(): map[string]x509.SignatureAlgorithm{ DigestAlgorithmSHA1.String(): x509.SHA1WithRSA, DigestAlgorithmMD5.String(): x509.MD5WithRSA, DigestAlgorithmSHA256.String(): x509.SHA256WithRSA, DigestAlgorithmSHA384.String(): x509.SHA384WithRSA, DigestAlgorithmSHA512.String(): x509.SHA512WithRSA, }, - SignatureAlgorithmECDSA.String(): map[string]x509.SignatureAlgorithm{ + PublicKeyAlgorithmECDSA.String(): map[string]x509.SignatureAlgorithm{ DigestAlgorithmSHA1.String(): x509.ECDSAWithSHA1, DigestAlgorithmSHA256.String(): x509.ECDSAWithSHA256, DigestAlgorithmSHA384.String(): x509.ECDSAWithSHA384, @@ -107,9 +109,23 @@ var SignatureAlgorithms = map[string]map[string]x509.SignatureAlgorithm{ }, } -// PublicKeyAlgorithmToSignatureAlgorithm maps certificate public key +// SignatureAlgorithmToX509SignatureAlgorithm maps signature algorithm OIDs to +// x509.SignatureAlgorithm values. +var SignatureAlgorithmToX509SignatureAlgorithm = map[string]x509.SignatureAlgorithm{ + SignatureAlgorithmSHA1WithRSA.String(): x509.SHA1WithRSA, + SignatureAlgorithmMD5WithRSA.String(): x509.MD5WithRSA, + SignatureAlgorithmSHA256WithRSA.String(): x509.SHA256WithRSA, + SignatureAlgorithmSHA384WithRSA.String(): x509.SHA384WithRSA, + SignatureAlgorithmSHA512WithRSA.String(): x509.SHA512WithRSA, + SignatureAlgorithmECDSAWithSHA1.String(): x509.ECDSAWithSHA1, + SignatureAlgorithmECDSAWithSHA256.String(): x509.ECDSAWithSHA256, + SignatureAlgorithmECDSAWithSHA384.String(): x509.ECDSAWithSHA384, + SignatureAlgorithmECDSAWithSHA512.String(): x509.ECDSAWithSHA512, +} + +// X509PublicKeyAlgorithmToPKIXAlgorithmIdentifier maps certificate public key // algorithms to CMS signature algorithms. -var PublicKeyAlgorithmToSignatureAlgorithm = map[x509.PublicKeyAlgorithm]pkix.AlgorithmIdentifier{ - x509.RSA: pkix.AlgorithmIdentifier{Algorithm: SignatureAlgorithmRSA}, - x509.ECDSA: pkix.AlgorithmIdentifier{Algorithm: SignatureAlgorithmECDSA}, +var X509PublicKeyAlgorithmToPKIXAlgorithmIdentifier = map[x509.PublicKeyAlgorithm]pkix.AlgorithmIdentifier{ + x509.RSA: pkix.AlgorithmIdentifier{Algorithm: PublicKeyAlgorithmRSA}, + x509.ECDSA: pkix.AlgorithmIdentifier{Algorithm: PublicKeyAlgorithmECDSA}, } diff --git a/vendor/github.com/mastahyeti/cms/protocol/protocol.go b/vendor/github.com/mastahyeti/cms/protocol/protocol.go index 9bd0038..35fb22b 100644 --- a/vendor/github.com/mastahyeti/cms/protocol/protocol.go +++ b/vendor/github.com/mastahyeti/cms/protocol/protocol.go @@ -79,7 +79,7 @@ func ParseContentInfo(ber []byte) (ci ContentInfo, err error) { // SignedDataContent gets the content assuming contentType is signedData. func (ci ContentInfo) SignedDataContent() (*SignedData, error) { - if !ci.ContentType.Equal(oid.SignedData) { + if !ci.ContentType.Equal(oid.ContentTypeSignedData) { return nil, ErrWrongType } @@ -106,7 +106,7 @@ type EncapsulatedContentInfo struct { // NewDataEncapsulatedContentInfo creates a new EncapsulatedContentInfo of type // id-data. func NewDataEncapsulatedContentInfo(data []byte) (EncapsulatedContentInfo, error) { - return NewEncapsulatedContentInfo(oid.Data, data) + return NewEncapsulatedContentInfo(oid.ContentTypeData, data) } // NewEncapsulatedContentInfo creates a new EncapsulatedContentInfo. @@ -186,7 +186,7 @@ func (eci EncapsulatedContentInfo) EContentValue() ([]byte, error) { // IsTypeData checks if the EContentType is id-data. func (eci EncapsulatedContentInfo) IsTypeData() bool { - return eci.EContentType.Equal(oid.Data) + return eci.EContentType.Equal(oid.ContentTypeData) } // DataEContent gets the EContent assuming EContentType is data. @@ -312,6 +312,17 @@ func (attrs Attributes) GetValues(oid asn1.ObjectIdentifier) ([]AnySet, error) { return vals, nil } +// HasAttribute checks if an attribute is present. +func (attrs Attributes) HasAttribute(oid asn1.ObjectIdentifier) bool { + for _, attr := range attrs { + if attr.Type.Equal(oid) { + return true + } + } + + return false +} + // IssuerAndSerialNumber ::= SEQUENCE { // issuer Name, // serialNumber CertificateSerialNumber } @@ -403,7 +414,7 @@ func (si SignerInfo) FindCertificate(certs []*x509.Certificate) (*x509.Certifica for _, cert := range certs { for _, ext := range cert.Extensions { - if oid.SubjectKeyIdentifier.Equal(ext.Id) { + if oid.ExtensionSubjectKeyIdentifier.Equal(ext.Id) { if bytes.Equal(ski, ext.Value) { return cert, nil } @@ -445,7 +456,7 @@ func (si SignerInfo) subjectKeyIdentifierSID() ([]byte, error) { // 0 is returned for unrecognized algorithms. func (si SignerInfo) Hash() (crypto.Hash, error) { algo := si.DigestAlgorithm.Algorithm.String() - hash := oid.DigestAlgorithmToHash[algo] + hash := oid.DigestAlgorithmToCryptoHash[algo] if hash == 0 || !hash.Available() { return 0, ErrUnsupported } @@ -461,7 +472,11 @@ func (si SignerInfo) X509SignatureAlgorithm() x509.SignatureAlgorithm { digestOID = si.DigestAlgorithm.Algorithm.String() ) - return oid.SignatureAlgorithms[sigOID][digestOID] + if sa := oid.SignatureAlgorithmToX509SignatureAlgorithm[sigOID]; sa != x509.UnknownSignatureAlgorithm { + return sa + } + + return oid.PublicKeyAndDigestAlgorithmToX509SignatureAlgorithm[sigOID][digestOID] } // GetContentTypeAttribute gets the signed ContentType attribute from the @@ -501,6 +516,9 @@ func (si SignerInfo) GetMessageDigestAttribute() ([]byte, error) { func (si SignerInfo) GetSigningTimeAttribute() (time.Time, error) { var t time.Time + if !si.SignedAttrs.HasAttribute(oid.AttributeSigningTime) { + return t, nil + } rv, err := si.SignedAttrs.GetOnlyAttributeValueBytes(oid.AttributeSigningTime) if err != nil { return t, err @@ -617,7 +635,7 @@ func (sd *SignedData) AddSignerInfo(chain []*x509.Certificate, signer crypto.Sig } digestAlgorithm := digestAlgorithmForPublicKey(pub) - signatureAlgorithm, ok := oid.PublicKeyAlgorithmToSignatureAlgorithm[cert.PublicKeyAlgorithm] + signatureAlgorithm, ok := oid.X509PublicKeyAlgorithmToPKIXAlgorithmIdentifier[cert.PublicKeyAlgorithm] if !ok { return errors.New("unsupported certificate public key algorithm") } @@ -652,6 +670,10 @@ func (sd *SignedData) AddSignerInfo(chain []*x509.Certificate, signer crypto.Sig } // Build our SignedAttributes + stAttr, err := NewAttribute(oid.AttributeSigningTime, time.Now().UTC()) + if err != nil { + return err + } mdAttr, err := NewAttribute(oid.AttributeMessageDigest, md.Sum(nil)) if err != nil { return err @@ -660,7 +682,8 @@ func (sd *SignedData) AddSignerInfo(chain []*x509.Certificate, signer crypto.Sig if err != nil { return err } - si.SignedAttrs = append(si.SignedAttrs, mdAttr, ctAttr) + + si.SignedAttrs = append(si.SignedAttrs, stAttr, mdAttr, ctAttr) // Signature is over the marshaled signed attributes sm, err := si.SignedAttrs.MarshaledForSigning() @@ -770,7 +793,7 @@ func (sd *SignedData) ContentInfo() (ContentInfo, error) { } return ContentInfo{ - ContentType: oid.SignedData, + ContentType: oid.ContentTypeSignedData, Content: asn1.RawValue{ Class: asn1.ClassContextSpecific, Tag: 0, diff --git a/vendor/github.com/mastahyeti/cms/protocol/protocol_test.go b/vendor/github.com/mastahyeti/cms/protocol/protocol_test.go index a0ef581..37fe33a 100644 --- a/vendor/github.com/mastahyeti/cms/protocol/protocol_test.go +++ b/vendor/github.com/mastahyeti/cms/protocol/protocol_test.go @@ -23,7 +23,7 @@ func TestSignerInfo(t *testing.T) { msg := []byte("hello, world!") - eci, err := NewEncapsulatedContentInfo(oid.Data, msg) + eci, err := NewEncapsulatedContentInfo(oid.ContentTypeData, msg) if err != nil { t.Fatal(err) } @@ -98,7 +98,7 @@ func TestEncapsulatedContentInfo(t *testing.T) { t.Fatal(err) } - newECI, err := NewEncapsulatedContentInfo(oid.Data, oldData) + newECI, err := NewEncapsulatedContentInfo(oid.ContentTypeData, oldData) if err != nil { t.Fatal(err) } @@ -211,6 +211,48 @@ func TestContentTypeAttribute(t *testing.T) { } } +func TestSigningTimeAttribute(t *testing.T) { + ci, _ := ParseContentInfo(fixtureSignatureOpenSSLAttached) + sd, _ := ci.SignedDataContent() + si := sd.SignerInfos[0] + + oldAttrVal, err := si.GetSigningTimeAttribute() + if err != nil { + t.Fatal(err) + } + + var oldAttr Attribute + for _, attr := range si.SignedAttrs { + if attr.Type.Equal(oid.AttributeSigningTime) { + oldAttr = attr + break + } + } + + newAttr, err := NewAttribute(oid.AttributeSigningTime, oldAttrVal) + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(oldAttr.RawValue.Bytes, newAttr.RawValue.Bytes) { + t.Fatal("raw value mismatch") + } + + oldDER, err := asn1.Marshal(oldAttr) + if err != nil { + t.Fatal(err) + } + + newDER, err := asn1.Marshal(newAttr) + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(oldDER, newDER) { + t.Fatal("der mismatch") + } +} + func TestIssuerAndSerialNumber(t *testing.T) { ci, _ := ParseContentInfo(fixtureSignatureOpenSSLAttached) sd, _ := ci.SignedDataContent() @@ -279,8 +321,8 @@ func testParseContentInfo(t *testing.T, ber []byte) { t.Fatal("expected id-data econtent") } - if !sd.EncapContentInfo.EContentType.Equal(oid.Data) { - t.Fatalf("expected %s content, got %s", oid.Data.String(), sd.EncapContentInfo.EContentType.String()) + if !sd.EncapContentInfo.EContentType.Equal(oid.ContentTypeData) { + t.Fatalf("expected %s content, got %s", oid.ContentTypeData.String(), sd.EncapContentInfo.EContentType.String()) } data, err := sd.EncapContentInfo.DataEContent() diff --git a/vendor/github.com/mastahyeti/cms/sign_test.go b/vendor/github.com/mastahyeti/cms/sign_test.go index 485b0e0..8d1c948 100644 --- a/vendor/github.com/mastahyeti/cms/sign_test.go +++ b/vendor/github.com/mastahyeti/cms/sign_test.go @@ -3,6 +3,7 @@ package cms import ( "crypto/x509" "testing" + "time" ) var ( @@ -46,6 +47,12 @@ func TestSign(t *testing.T) { t.Fatal("missing cert in sd") } } + + // check that we're including signing time attribute + st, err := sd2.psd.SignerInfos[0].GetSigningTimeAttribute() + if st.After(time.Now().Add(time.Second)) || st.Before(time.Now().Add(-time.Second)) { + t.Fatal("expected SigningTime to be now. Difference was", st.Sub(time.Now())) + } } func TestSignDetached(t *testing.T) { @@ -84,6 +91,12 @@ func TestSignDetached(t *testing.T) { t.Fatal("missing cert in sd") } } + + // check that we're including signing time attribute + st, err := sd2.psd.SignerInfos[0].GetSigningTimeAttribute() + if st.After(time.Now().Add(time.Second)) || st.Before(time.Now().Add(-time.Second)) { + t.Fatal("expected SigningTime to be now. Difference was", st.Sub(time.Now())) + } } func TestSignRemoveHeaders(t *testing.T) { diff --git a/vendor/github.com/mastahyeti/cms/timestamp/timestamp.go b/vendor/github.com/mastahyeti/cms/timestamp/timestamp.go index a99644f..9f601e2 100644 --- a/vendor/github.com/mastahyeti/cms/timestamp/timestamp.go +++ b/vendor/github.com/mastahyeti/cms/timestamp/timestamp.go @@ -303,7 +303,7 @@ type Info struct { func ParseInfo(eci protocol.EncapsulatedContentInfo) (Info, error) { i := Info{} - if !eci.EContentType.Equal(oid.TSTInfo) { + if !eci.EContentType.Equal(oid.ContentTypeTSTInfo) { return i, protocol.ErrWrongType } @@ -361,7 +361,7 @@ type MessageImprint struct { // NewMessageImprint creates a new MessageImprint, digesting all bytes from the // provided reader using the specified hash. func NewMessageImprint(hash crypto.Hash, r io.Reader) (MessageImprint, error) { - digestAlgorithm := oid.HashToDigestAlgorithm[hash] + digestAlgorithm := oid.CryptoHashToDigestAlgorithm[hash] if len(digestAlgorithm) == 0 { return MessageImprint{}, protocol.ErrUnsupported } @@ -384,7 +384,7 @@ func NewMessageImprint(hash crypto.Hash, r io.Reader) (MessageImprint, error) { // 0 is returned for unrecognized algorithms. func (mi MessageImprint) Hash() (crypto.Hash, error) { algo := mi.HashAlgorithm.Algorithm.String() - hash := oid.DigestAlgorithmToHash[algo] + hash := oid.DigestAlgorithmToCryptoHash[algo] if hash == 0 || !hash.Available() { return 0, protocol.ErrUnsupported } diff --git a/vendor/github.com/mastahyeti/cms/verify.go b/vendor/github.com/mastahyeti/cms/verify.go index d9cef10..8d16f29 100644 --- a/vendor/github.com/mastahyeti/cms/verify.go +++ b/vendor/github.com/mastahyeti/cms/verify.go @@ -59,6 +59,11 @@ func (sd *SignedData) verify(econtent []byte, opts x509.VerifyOptions) ([][][]*x opts.Intermediates.AddCert(cert) } + // Use provided verification options for timestamp verification also, but + // explicitly ask for key-usage=timestamping. + tsOpts := opts + tsOpts.KeyUsages = []x509.ExtKeyUsage{x509.ExtKeyUsageTimeStamping} + chains := make([][][]*x509.Certificate, 0, len(sd.psd.SignerInfos)) for _, si := range sd.psd.SignerInfos { @@ -133,13 +138,14 @@ func (sd *SignedData) verify(econtent []byte, opts x509.VerifyOptions) ([][][]*x // timestamp. If there's no timestamp we use the current time when checking // the cert validity window. This isn't perfect because the signature may // have been created before the cert's not-before date, but this is the best - // we can do. + // we can do. We update a copy of opts because we are verifying multiple + // signatures in a loop and only want the timestamp to affect this one. optsCopy := opts if hasTS, err := hasTimestamp(si); err != nil { return nil, err } else if hasTS { - tsti, err := getTimestamp(si, opts) + tsti, err := getTimestamp(si, tsOpts) if err != nil { return nil, err } diff --git a/vendor/github.com/mastahyeti/cms/verify_test.go b/vendor/github.com/mastahyeti/cms/verify_test.go index db641bc..40a66bd 100644 --- a/vendor/github.com/mastahyeti/cms/verify_test.go +++ b/vendor/github.com/mastahyeti/cms/verify_test.go @@ -11,13 +11,33 @@ import ( "github.com/mastahyeti/cms/protocol" ) -func verifyOptionsForSignedData(sd *SignedData) (opts x509.VerifyOptions) { - certs, err := sd.psd.X509Certificates() +func ExampleSignedData() { + data := []byte("hello, world!") + + // Wrap the data in a CMS SignedData structure and sign it with our key. + signedDataDER, err := Sign(data, exampleChain, examplePrivateKey) + if err != nil { + panic(err) + } + + // Re-parse the encoded SignedData structure. + signedData, err := ParseSignedData(signedDataDER) if err != nil { panic(err) } + // Verify the SignedData's signature. + if _, err = signedData.Verify(x509.VerifyOptions{Roots: root.ChainPool()}); err != nil { + panic(err) + } +} + +func verifyOptionsForSignedData(sd *SignedData) (opts x509.VerifyOptions) { // add self-signed cert as trusted root + certs, err := sd.psd.X509Certificates() + if err != nil { + panic(err) + } if len(certs) == 1 { opts.Roots = x509.NewCertPool() opts.Roots.AddCert(certs[0]) @@ -28,9 +48,11 @@ func verifyOptionsForSignedData(sd *SignedData) (opts x509.VerifyOptions) { if err != nil { panic(err) } - opts.CurrentTime = signingTime + // Any key usage + opts.KeyUsages = []x509.ExtKeyUsage{x509.ExtKeyUsageAny} + return } @@ -114,9 +136,24 @@ func TestVerifyOutlookDetached(t *testing.T) { t.Fatal(err) } - opts := x509.VerifyOptions{KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny}} + if _, err := sd.VerifyDetached(fixtureMessageOutlookDetached, verifyOptionsForSignedData(sd)); err != nil { + t.Fatal(err) + } +} + +func TestVerifySmimesignAttachedWithTimestamp(t *testing.T) { + sd, err := ParseSignedData(fixtureSmimesignAttachedWithTimestamp) + if err != nil { + t.Fatal(err) + } + + opts := verifyOptionsForSignedData(sd) - if _, err := sd.VerifyDetached(fixtureMessageOutlookDetached, opts); err != nil { + // specify key usage for signing cert to verify that this isn't also used + // when checking timestamp. + opts.KeyUsages = []x509.ExtKeyUsage{x509.ExtKeyUsageEmailProtection} + + if _, err := sd.Verify(opts); err != nil { t.Fatal(err) } } @@ -488,6 +525,194 @@ var fixtureMessageOutlookDetached = mustBase64Decode("" + "NzAtLQ0K", ) +var fixtureSmimesignAttachedWithTimestamp = mustBase64Decode("" + + "MIIgZQYJKoZIhvcNAQcCoIIgVjCCIFICAQExDTALBglghkgBZQMEAgEwFQYJ" + + "KoZIhvcNAQcBoAgEBmhlbGxvCqCCD1UwggVEMIIELKADAgECAhAMLfp+jIxN" + + "FhbxAJyYi7cNMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYD" + + "VQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x" + + "JDAiBgNVBAMTG0RpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJRCBDQTAeFw0xNzEx" + + "MjIwMDAwMDBaFw0yMDExMjIxMjAwMDBaMGUxCzAJBgNVBAYTAlVTMRMwEQYD" + + "VQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRUwEwYD" + + "VQQKEwxHaXRIdWIsIEluYy4xEjAQBgNVBAMTCUJlbiBUb2V3czCCASIwDQYJ" + + "KoZIhvcNAQEBBQADggEPADCCAQoCggEBAO9ZN/PY8mMHV/fGVQvEJqlNqQKY" + + "keUjZljjsOodUq1g6CjelFgqVjfib+B6yDfUESpi4gD0PK9jODyQ7vC221sS" + + "scihYl5BMsBn93bQwy2zFIfyW0lOFuhtpPT6DZHCrqSI+NWbQ4+Wf+braXRv" + + "re7nYB7LkbC9Y9n2wq8n3hMxggAI1GcgWi6OqV8FrJKLBgmkYvlBkKOROHSq" + + "UsHKx/FPZ9U3B4KvVSIwPR5fcR1M+zvWQ6vpY3iGWbZlklqAjCFX+s6gdwwO" + + "Xh5PcW+kRpM2oNTRtohR6xh+pQ631KzS4d3RKKMiJaBVpasVUH206+mtaSxa" + + "2Mw9Sm0UBZTnTG0CAwEAAaOCAe4wggHqMB8GA1UdIwQYMBaAFOcCI4AAT9jX" + + "vJQL2T90OUkyPIp5MB0GA1UdDgQWBBSRnqSdQlLKpx5J3ytAbMevm7xdbjAM" + + "BgNVHRMBAf8EAjAAMCAGA1UdEQQZMBeBFW1hc3RhaHlldGlAZ2l0aHViLmNv" + + "bTAOBgNVHQ8BAf8EBAMCBsAwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUF" + + "BwMEMEMGA1UdIAQ8MDowOAYKYIZIAYb9bAQBAjAqMCgGCCsGAQUFBwIBFhxo" + + "dHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMIGIBgNVHR8EgYAwfjA9oDug" + + "OYY3aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3Vy" + + "ZWRJRENBLWcyLmNybDA9oDugOYY3aHR0cDovL2NybDQuZGlnaWNlcnQuY29t" + + "L0RpZ2lDZXJ0U0hBMkFzc3VyZWRJRENBLWcyLmNybDB5BggrBgEFBQcBAQRt" + + "MGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBDBggr" + + "BgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0" + + "U0hBMkFzc3VyZWRJRENBLmNydDANBgkqhkiG9w0BAQsFAAOCAQEAVouNNiSm" + + "K9tUIk6pN5MbwGVTqNcLYzPJAXk1ufZynmlP0mJsyLrdlwLRrhWQUkRiAAAp" + + "EWBycg8hAF4h29ZuaLzp4zPL4L/nSjN7wGRwCzQZhkrazfRf24wLpNDWQuYh" + + "rot/AsfN56/aUXUZDrLIkTQID+u9qlWVAH/+sb096oTjDULRDlahEzGnNYna" + + "gi9X+o1r3zn4drbksjYL1Jb4XBNx3pFXcb3/sFCDYLYgP0k1VdZ7SVWqam7x" + + "LD3XCR6hcCACVCIvH1fa/LjNgCCy2M1xa92DTh1SBBzeiMoAGSvcEvA0DPVu" + + "Eco2fr8+PANEg55NvpBoacqyIhnsvn9qJTCCBk4wggU2oAMCAQICEASueWBm" + + "ZpAaucV/pmxb3M0wDQYJKoZIhvcNAQELBQAwZTELMAkGA1UEBhMCVVMxFTAT" + + "BgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNv" + + "bTEkMCIGA1UEAxMbRGlnaUNlcnQgQXNzdXJlZCBJRCBSb290IENBMB4XDTEz" + + "MTEwNTEyMDAwMFoXDTI4MTEwNTEyMDAwMFowZTELMAkGA1UEBhMCVVMxFTAT" + + "BgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNv" + + "bTEkMCIGA1UEAxMbRGlnaUNlcnQgU0hBMiBBc3N1cmVkIElEIENBMIIBIjAN" + + "BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3PgRIz9qte/AJ3kbLQWHohBD" + + "Md8O1BUbT3ekIs4+jHDwvgeO3ScqvAEdtiwKyt1pWB9B7WoFH9pjeFkeIiwr" + + "+Lp+yTU7VvEffEJ+JbAjGcZFONc9RPkgfGCuHLBaGAS+jzv3qfCUmqYMY0m2" + + "QRdTQDK9T+ZQelAfJUXo8Ymvzf9e/1Dz8BcR/73FifW9YrnY+45FBIVtmc3F" + + "SE39JqsCNkXqNtdfauIagkEK3OnZ9ZEXjsYhrTg8E+Yef2ac1U3ZRtr2z1Kn" + + "fTskw7TBUTXGm+vU737kewPhRL16CzfgT8uCig1xGOSm4IksG/OyczzBsJKe" + + "GH29q33FfQihLMKfcwIDAQABo4IC+DCCAvQwEgYDVR0TAQH/BAgwBgEB/wIB" + + "ADAOBgNVHQ8BAf8EBAMCAYYwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzAB" + + "hhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wgYEGA1UdHwR6MHgwOqA4oDaG" + + "NGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJv" + + "b3RDQS5jcmwwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdp" + + "Q2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwHQYDVR0lBBYwFAYIKwYBBQUHAwIG" + + "CCsGAQUFBwMEMIIBswYDVR0gBIIBqjCCAaYwggGiBgpghkgBhv1sAAIEMIIB" + + "kjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzCC" + + "AWQGCCsGAQUFBwICMIIBVh6CAVIAQQBuAHkAIAB1AHMAZQAgAG8AZgAgAHQA" + + "aABpAHMAIABDAGUAcgB0AGkAZgBpAGMAYQB0AGUAIABjAG8AbgBzAHQAaQB0" + + "AHUAdABlAHMAIABhAGMAYwBlAHAAdABhAG4AYwBlACAAbwBmACAAdABoAGUA" + + "IABEAGkAZwBpAEMAZQByAHQAIABDAFAALwBDAFAAUwAgAGEAbgBkACAAdABo" + + "AGUAIABSAGUAbAB5AGkAbgBnACAAUABhAHIAdAB5ACAAQQBnAHIAZQBlAG0A" + + "ZQBuAHQAIAB3AGgAaQBjAGgAIABsAGkAbQBpAHQAIABsAGkAYQBiAGkAbABp" + + "AHQAeQAgAGEAbgBkACAAYQByAGUAIABpAG4AYwBvAHIAcABvAHIAYQB0AGUA" + + "ZAAgAGgAZQByAGUAaQBuACAAYgB5ACAAcgBlAGYAZQByAGUAbgBjAGUALjAd" + + "BgNVHQ4EFgQU5wIjgABP2Ne8lAvZP3Q5STI8inkwHwYDVR0jBBgwFoAUReui" + + "r/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAE7UiSe5/R2H" + + "d34PKAWQ8QovyTs+vZOckMav+pFRhzJUa+jKwXFRXJmOtfrgYhmZpgeafBMn" + + "2+UCooQS2RX2CkRXxDSPbXMfOtagAT3e44LkRWuy6yX9gF4dOZC+W0L2zpFg" + + "4/mgVgxIEM4zaHvNk6vwastPWA+5e10bBIGepyLiV0kn7pKTCL5pCFMCOi5d" + + "yBn0UIBOAtmwXZG0k4f5lpaBVUCOZu2C2LsoX+1MYe0GWCgZUxFEvEcgKbIE" + + "bNiJVJk7ddtneCweknjGVT1YEhEybr1DDE0023vGQtvsvqubYUwGkuOO3yEq" + + "UFcEwGCiNdUknmY3CUnP1fhls+DibsIwggO3MIICn6ADAgECAhAM5+DlF9hG" + + "/o/lYPwb8DA5MA0GCSqGSIb3DQEBBQUAMGUxCzAJBgNVBAYTAlVTMRUwEwYD" + + "VQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x" + + "JDAiBgNVBAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0wNjEx" + + "MTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGUxCzAJBgNVBAYTAlVTMRUwEwYD" + + "VQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x" + + "JDAiBgNVBAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTCCASIwDQYJ" + + "KoZIhvcNAQEBBQADggEPADCCAQoCggEBAK0OFc7kQ4BcsYfzt2D5cRKlrtwm" + + "lIiq9M71IDkoWGAM+IDaqRWVMmE8tbEohIqK3J8KDIMXeo+QrIrneVNcMYQq" + + "9g+YMjZ2zN7dPKii72r7IfJSYd+fINcf4rHZ/hhk0hJbX/lYGDW8R82hNvlr" + + "f9SwOD7BG8OMM9nYLxj+KA+zp4PWw25EwGE1lhb+WZyLdm3X8aJLDSv/C3La" + + "nmDQjpA1xnhVhyChz+VtCshJfDGYM2wi6YfQMlqiuhOCEe05F52ZOnKh5vqk" + + "2dUXMXWuhX0irj8BRob2KHnIsdrkVxfEfhwOsLSSplazvbKX7aqn8LfFqD+V" + + "FtD/oZbrCF8Yd08CAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB" + + "/wQFMAMBAf8wHQYDVR0OBBYEFEXroq/0ksuCMS1Ri6enIZ3zbcgPMB8GA1Ud" + + "IwQYMBaAFEXroq/0ksuCMS1Ri6enIZ3zbcgPMA0GCSqGSIb3DQEBBQUAA4IB" + + "AQCiDrzf4u3w43JzemSUv/dyZtgy5EJ1Yq6H6/LV2d5Ws5/MzhQouQ2XYFwS" + + "TFjk0z2DSUVYlzVpGqhH6lbGeasS2GeBhN9/CTyU5rgmLCC9PbMoifdf/yLi" + + "l4Qf6WXvh+DfwWdJs13rsgkq6ybteL59PyvztyY1bV+JAbZJW58BBZurPSXB" + + "zLZ/wvFvhsb6ZGjrgS2U60K3+owe3WLxvlBnt2y98/Efaww2BxZ/N3ypW216" + + "8RJGYIPXJwS+S86XvsNnKmgR34DnDDNmvxMNFG7zfx9jEB76jRslbWyPpbdh" + + "AbHSoyahEHGdreLD+cOZUbcrBwjOLuZQsqf6CkUvovDyMYIQzDCCEMgCAQEw" + + "eTBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD" + + "VQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBTSEEy" + + "IEFzc3VyZWQgSUQgQ0ECEAwt+n6MjE0WFvEAnJiLtw0wCwYJYIZIAWUDBAIB" + + "oEswLwYJKoZIhvcNAQkEMSIEIFiRtbUi1d8IbQ/wsRD72dIbtPxxY6800IKG" + + "ouhG9r4DMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwCwYJKoZIhvcNAQEB" + + "BIIBAMQdkVhH1gK8cI2x6BzGW0Vu6IhQcvNqgUacjuzebIBDozpkOKVGYv1/" + + "qpmuDLyXEyweI307U5tArvRiWAaZnvjOpmQbdNipbCkjzzUu4tfHtLwTVjLV" + + "c6qW9THJWszaqU9rvWAgritkX3mN5AOR5X2Up/hsjMC8SMdwZRHHniRaGB7M" + + "IUwVrnnHgxfWUn2FaO85XN6vqsBz0ykI3NIDQGFAIMISX1lKYSBKHOwODvX+" + + "Z6aWr2JFVbdcc/hcLi/rbC5x0dlWVdDhREW0HTkZxW0Y37HEyz56d1qpj5II" + + "3wJLeoKdGckI7NTwGhY4lcY0lTCd1stsaoGDe9miVAlQfFahgg7bMIIO1wYL" + + "KoZIhvcNAQkQAg4xgg7GMIIOwgYJKoZIhvcNAQcCoIIOszCCDq8CAQMxDzAN" + + "BglghkgBZQMEAgEFADCBiAYLKoZIhvcNAQkQAQSgeQR3MHUCAQEGCWCGSAGG" + + "/WwHATAvMAsGCWCGSAFlAwQCAQQg3oBfclnOJ5THSQ6G1dMX7mo8WnWhN27z" + + "2w8+uXPmAHsCEHG548OQys1qPcVJD4482vQYDzIwMTgwOTEzMTQ1OTAyWgIR" + + "AN8rYymxrG3grObgUvx8VVygggu7MIIGgjCCBWqgAwIBAgIQCcD8RsgEQhO1" + + "WYuvKE9OQTANBgkqhkiG9w0BAQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UE" + + "ChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEw" + + "LwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgVGltZXN0YW1waW5n" + + "IENBMB4XDTE3MDEwNDAwMDAwMFoXDTI4MDExODAwMDAwMFowTDELMAkGA1UE" + + "BhMCVVMxETAPBgNVBAoTCERpZ2lDZXJ0MSowKAYDVQQDEyFEaWdpQ2VydCBT" + + "SEEyIFRpbWVzdGFtcCBSZXNwb25kZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IB" + + "DwAwggEKAoIBAQCelZhqNDtzG6h+/Me+KWmJx2gmRl89jWJzh4GjoZzwt1sk" + + "N1qS1PRZ13aJ5NzVJ/DVZrwK7rQrMWesWMVKkVkrRR4JAdZks1nujWZN+yNe" + + "zBANC4pn71KuoAiQwlL39ai1bpsse53ntT77eM0yUBi/QLVMjLtX9KBPEUVs" + + "QkK55a/W3/SnfApolg/SXylXzvsdMv/0EaETIvsSy+/XU9Lrl8uirBsdnVgh" + + "UYLCwt7qKz8sIoTQQ+w7Oz9HxPZW3EU3mLRrdLVZr3hXacgPCQJ43dhTwZnb" + + "YMSd6q6v4H6GSlypWGGoXnSKAShock6nhp21AlKHcGZI047vgSTM3NhlAgMB" + + "AAGjggM4MIIDNDAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADAWBgNV" + + "HSUBAf8EDDAKBggrBgEFBQcDCDCCAb8GA1UdIASCAbYwggGyMIIBoQYJYIZI" + + "AYb9bAcBMIIBkjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQu" + + "Y29tL0NQUzCCAWQGCCsGAQUFBwICMIIBVh6CAVIAQQBuAHkAIAB1AHMAZQAg" + + "AG8AZgAgAHQAaABpAHMAIABDAGUAcgB0AGkAZgBpAGMAYQB0AGUAIABjAG8A" + + "bgBzAHQAaQB0AHUAdABlAHMAIABhAGMAYwBlAHAAdABhAG4AYwBlACAAbwBm" + + "ACAAdABoAGUAIABEAGkAZwBpAEMAZQByAHQAIABDAFAALwBDAFAAUwAgAGEA" + + "bgBkACAAdABoAGUAIABSAGUAbAB5AGkAbgBnACAAUABhAHIAdAB5ACAAQQBn" + + "AHIAZQBlAG0AZQBuAHQAIAB3AGgAaQBjAGgAIABsAGkAbQBpAHQAIABsAGkA" + + "YQBiAGkAbABpAHQAeQAgAGEAbgBkACAAYQByAGUAIABpAG4AYwBvAHIAcABv" + + "AHIAYQB0AGUAZAAgAGgAZQByAGUAaQBuACAAYgB5ACAAcgBlAGYAZQByAGUA" + + "bgBjAGUALjALBglghkgBhv1sAxUwHwYDVR0jBBgwFoAU9LbhIB3+Ka7S5GGl" + + "sqIlssgXNW4wHQYDVR0OBBYEFOGnMkruASEofVTV8geSbrQHDz2HMHEGA1Ud" + + "HwRqMGgwMqAwoC6GLGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9zaGEyLWFz" + + "c3VyZWQtdHMuY3JsMDKgMKAuhixodHRwOi8vY3JsNC5kaWdpY2VydC5jb20v" + + "c2hhMi1hc3N1cmVkLXRzLmNybDCBhQYIKwYBBQUHAQEEeTB3MCQGCCsGAQUF" + + "BzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wTwYIKwYBBQUHMAKGQ2h0" + + "dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJBc3N1cmVk" + + "SURUaW1lc3RhbXBpbmdDQS5jcnQwDQYJKoZIhvcNAQELBQADggEBAB7wQYIy" + + "ru3xtDUT3FDC1ZeuIiKdDg6vM9NM/Xy/bwERp5RlIlzGIqHIiVJrmoxzXNle" + + "PzLeFmBMizb9MZkKvcGEt40d74kmEwVW80fNR1uthLI4r2ojtUXjHogyRoDS" + + "t6aZIv3BeM/1i9gMjAUJ7kTmgNVtcMyfUx4n3SpI3tqTZa1uZaOZp8JADnPM" + + "WE+PRSjlvJyI5ijOYF0tJV2Lcy6lDVtR2ppO/1AFiSja8ni70lh4jUSnrDoA" + + "kXhpiWQE012W3yq/+aVMLJP/5ordgqzx0rOihprBVYlWakc/+tYzlUM1iQV4" + + "Wjpp2iK4BEPTb2g1NnoUPkXpmGSGDxMMJkowggUxMIIEGaADAgECAhAKoSXW" + + "1jIbfkHkBdo2l8IVMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUw" + + "EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j" + + "b20xJDAiBgNVBAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0x" + + "NjAxMDcxMjAwMDBaFw0zMTAxMDcxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUw" + + "EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j" + + "b20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJRCBUaW1lc3Rh" + + "bXBpbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC90DLu" + + "S82Pf92puoKZxTlUKFe2I0rEDgdFM1EQfdD5fU1ofue2oPSNs4jkl79jIZCY" + + "vxO8V9PD4X4I1moUADj3Lh477sym9jJZ/l9lP+Cb6+NGRwYaVX4LJ37AovWg" + + "4N4iPw7/fpX786O6Ij4YrBHk8JkDbTuFfAnT7l3ImgtU46gJcWvgzyIQD3XP" + + "cXJOCq3fQDpct1HhoXkUxk0kIzBdvOw8YGqsLwfM/fDqR9mIUF79Zm5WYScp" + + "iYRR5oLnRlD9lCosp+R1PrqYD4R/nzEU1q3V8mTLex4F0IQZchfxFwbvPc3W" + + "Te8GQv2iUypPhR3EHTyvz9qsEPXdrKzpVv+TAgMBAAGjggHOMIIByjAdBgNV" + + "HQ4EFgQU9LbhIB3+Ka7S5GGlsqIlssgXNW4wHwYDVR0jBBgwFoAUReuir/SS" + + "y4IxLVGLp6chnfNtyA8wEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8E" + + "BAMCAYYwEwYDVR0lBAwwCgYIKwYBBQUHAwgweQYIKwYBBQUHAQEEbTBrMCQG" + + "CCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQwYIKwYBBQUH" + + "MAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3Vy" + + "ZWRJRFJvb3RDQS5jcnQwgYEGA1UdHwR6MHgwOqA4oDaGNGh0dHA6Ly9jcmw0" + + "LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwOqA4" + + "oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJ" + + "RFJvb3RDQS5jcmwwUAYDVR0gBEkwRzA4BgpghkgBhv1sAAIEMCowKAYIKwYB" + + "BQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCwYJYIZIAYb9" + + "bAcBMA0GCSqGSIb3DQEBCwUAA4IBAQBxlRLpUYdWac3v3dp8qmN6s3jPBjdA" + + "hO9LhL/KzwMC/cWnww4gQiyvd/MrHwwhWiq3BTQdaq6Z+CeiZr8JqmDfdqQ6" + + "kw/4stHYfBli6F6CJR7Euhx7LCHi1lssFDVDBGiy23UC4HLHmNY8ZOUfSBAY" + + "X4k4YU1iRiSHY4yRUiyvKYnleB/WCxSlgNcSR3CzddWThZN+tpJn+1Nhiaj1" + + "a5bA9FhpDXzIAbG5KHW3mWOFIoxhynmUfln8jA/jb7UBJrZspe6HUSHkWGCb" + + "ugwtK22ixH67xCUrRwIIfEmuE7bhfEJCKMYYVs9BNLZmXbZ0e/VWMyIvIjay" + + "S6JKldj1po5SMYICTTCCAkkCAQEwgYYwcjELMAkGA1UEBhMCVVMxFTATBgNV" + + "BAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEx" + + "MC8GA1UEAxMoRGlnaUNlcnQgU0hBMiBBc3N1cmVkIElEIFRpbWVzdGFtcGlu" + + "ZyBDQQIQCcD8RsgEQhO1WYuvKE9OQTANBglghkgBZQMEAgEFAKCBmDAaBgkq" + + "hkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwHAYJKoZIhvcNAQkFMQ8XDTE4MDkx" + + "MzE0NTkwMlowLwYJKoZIhvcNAQkEMSIEIFyJ+5SjrJKFITSeJofXvLgWWxPb" + + "6ggwDfbdg+klERNxMCsGCyqGSIb3DQEJEAIMMRwwGjAYMBYEFEABkUdcmIkd" + + "66EEr0cJG1621MvLMA0GCSqGSIb3DQEBAQUABIIBAJwA/28RMum8YR9Cvx1O" + + "N5pk7SlyC1OAA4f+RECrRzrV4TBLkqOeFU+LgCZ4sl9KdyrG+qvEmuy13iAP" + + "IAiJC5VY8+WYnmaWLvuO5lt147X5psNAx7xS8ehBywOW3otMqMuy1DaqSCQe" + + "oLkUAO/kkVB+X5k2HEUudno3w7pHiNkYWxJ9idgvTPo1E9120fI/pptuvtiK" + + "yV7MXWgWWTdZFdyQ9Ig6Ntwt1YvWLNLIw52AmiZp7xPqxj08+8MIruHaUN0u" + + "9nEUK+2UxorVSK1IrZkUEObFHVp7lmeINW6tN37esXU8BQzVF+zHd9hbBPIT" + + "PWw6BOUQ5LQYHqlrGwfbnlk=", +) + func mustBase64Decode(b64 string) []byte { decoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(b64)) buf := new(bytes.Buffer)