// Package pkcs7 implements parsing and generation of some PKCS#7 structures. package pkcs7 import ( "bytes" "crypto" "crypto/dsa" "crypto/ecdsa" "crypto/rsa" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" "errors" "fmt" "sort" _ "crypto/sha1" // for crypto.SHA1 ) // PKCS7 Represents a PKCS7 structure type PKCS7 struct { Content []byte Certificates []*x509.Certificate CRLs []pkix.CertificateList Signers []signerInfo raw interface{} } type contentInfo struct { ContentType asn1.ObjectIdentifier Content asn1.RawValue `asn1:"explicit,optional,tag:0"` } // ErrUnsupportedContentType is returned when a PKCS7 content is not supported. // Currently only Data (1.2.840.113549.1.7.1), Signed Data (1.2.840.113549.1.7.2), // and Enveloped Data are supported (1.2.840.113549.1.7.3) var ErrUnsupportedContentType = errors.New("pkcs7: cannot parse data: unimplemented content type") type unsignedData []byte var ( // Signed Data OIDs OIDData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 1} OIDSignedData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 2} OIDEnvelopedData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 3} OIDEncryptedData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 6} OIDAttributeContentType = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 3} OIDAttributeMessageDigest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 4} OIDAttributeSigningTime = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 5} // Digest Algorithms OIDDigestAlgorithmSHA1 = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 26} OIDDigestAlgorithmSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 1} OIDDigestAlgorithmSHA384 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 2} OIDDigestAlgorithmSHA512 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 3} OIDDigestAlgorithmDSA = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 1} OIDDigestAlgorithmDSASHA1 = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3} OIDDigestAlgorithmECDSASHA1 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 1} OIDDigestAlgorithmECDSASHA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2} OIDDigestAlgorithmECDSASHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3} OIDDigestAlgorithmECDSASHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4} // Signature Algorithms OIDEncryptionAlgorithmRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1} OIDEncryptionAlgorithmRSASHA1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5} OIDEncryptionAlgorithmRSASHA256 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11} OIDEncryptionAlgorithmRSASHA384 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12} OIDEncryptionAlgorithmRSASHA512 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13} OIDEncryptionAlgorithmECDSAP256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7} OIDEncryptionAlgorithmECDSAP384 = asn1.ObjectIdentifier{1, 3, 132, 0, 34} OIDEncryptionAlgorithmECDSAP521 = asn1.ObjectIdentifier{1, 3, 132, 0, 35} // Encryption Algorithms OIDEncryptionAlgorithmDESCBC = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 7} OIDEncryptionAlgorithmDESEDE3CBC = asn1.ObjectIdentifier{1, 2, 840, 113549, 3, 7} OIDEncryptionAlgorithmAES256CBC = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 42} OIDEncryptionAlgorithmAES128GCM = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 6} OIDEncryptionAlgorithmAES128CBC = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 2} OIDEncryptionAlgorithmAES256GCM = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 46} ) func getHashForOID(oid asn1.ObjectIdentifier) (crypto.Hash, error) { switch { case oid.Equal(OIDDigestAlgorithmSHA1), oid.Equal(OIDDigestAlgorithmECDSASHA1), oid.Equal(OIDDigestAlgorithmDSA), oid.Equal(OIDDigestAlgorithmDSASHA1), oid.Equal(OIDEncryptionAlgorithmRSA): return crypto.SHA1, nil case oid.Equal(OIDDigestAlgorithmSHA256), oid.Equal(OIDDigestAlgorithmECDSASHA256): return crypto.SHA256, nil case oid.Equal(OIDDigestAlgorithmSHA384), oid.Equal(OIDDigestAlgorithmECDSASHA384): return crypto.SHA384, nil case oid.Equal(OIDDigestAlgorithmSHA512), oid.Equal(OIDDigestAlgorithmECDSASHA512): return crypto.SHA512, nil } return crypto.Hash(0), ErrUnsupportedAlgorithm } // getDigestOIDForSignatureAlgorithm takes an x509.SignatureAlgorithm // and returns the corresponding OID digest algorithm func getDigestOIDForSignatureAlgorithm(digestAlg x509.SignatureAlgorithm) (asn1.ObjectIdentifier, error) { switch digestAlg { case x509.SHA1WithRSA, x509.ECDSAWithSHA1: return OIDDigestAlgorithmSHA1, nil case x509.SHA256WithRSA, x509.ECDSAWithSHA256: return OIDDigestAlgorithmSHA256, nil case x509.SHA384WithRSA, x509.ECDSAWithSHA384: return OIDDigestAlgorithmSHA384, nil case x509.SHA512WithRSA, x509.ECDSAWithSHA512: return OIDDigestAlgorithmSHA512, nil } return nil, fmt.Errorf("pkcs7: cannot convert hash to oid, unknown hash algorithm") } // getOIDForEncryptionAlgorithm takes the private key type of the signer and // the OID of a digest algorithm to return the appropriate signerInfo.DigestEncryptionAlgorithm func getOIDForEncryptionAlgorithm(pkey crypto.PrivateKey, OIDDigestAlg asn1.ObjectIdentifier) (asn1.ObjectIdentifier, error) { switch pkey.(type) { case *rsa.PrivateKey: switch { default: return OIDEncryptionAlgorithmRSA, nil case OIDDigestAlg.Equal(OIDEncryptionAlgorithmRSA): return OIDEncryptionAlgorithmRSA, nil case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA1): return OIDEncryptionAlgorithmRSASHA1, nil case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA256): return OIDEncryptionAlgorithmRSASHA256, nil case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA384): return OIDEncryptionAlgorithmRSASHA384, nil case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA512): return OIDEncryptionAlgorithmRSASHA512, nil } case *ecdsa.PrivateKey: switch { case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA1): return OIDDigestAlgorithmECDSASHA1, nil case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA256): return OIDDigestAlgorithmECDSASHA256, nil case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA384): return OIDDigestAlgorithmECDSASHA384, nil case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA512): return OIDDigestAlgorithmECDSASHA512, nil } case *dsa.PrivateKey: return OIDDigestAlgorithmDSA, nil } return nil, fmt.Errorf("pkcs7: cannot convert encryption algorithm to oid, unknown private key type %T", pkey) } // Parse decodes a DER encoded PKCS7 package func Parse(data []byte) (p7 *PKCS7, err error) { if len(data) == 0 { return nil, errors.New("pkcs7: input data is empty") } var info contentInfo der, err := ber2der(data) if err != nil { return nil, err } rest, err := asn1.Unmarshal(der, &info) if len(rest) > 0 { err = asn1.SyntaxError{Msg: "trailing data"} return } if err != nil { return } // fmt.Printf("--> Content Type: %s", info.ContentType) switch { case info.ContentType.Equal(OIDSignedData): return parseSignedData(info.Content.Bytes) case info.ContentType.Equal(OIDEnvelopedData): return parseEnvelopedData(info.Content.Bytes) case info.ContentType.Equal(OIDEncryptedData): return parseEncryptedData(info.Content.Bytes) } return nil, ErrUnsupportedContentType } func parseEnvelopedData(data []byte) (*PKCS7, error) { var ed envelopedData if _, err := asn1.Unmarshal(data, &ed); err != nil { return nil, err } return &PKCS7{ raw: ed, }, nil } func parseEncryptedData(data []byte) (*PKCS7, error) { var ed encryptedData if _, err := asn1.Unmarshal(data, &ed); err != nil { return nil, err } return &PKCS7{ raw: ed, }, nil } func (raw rawCertificates) Parse() ([]*x509.Certificate, error) { if len(raw.Raw) == 0 { return nil, nil } var val asn1.RawValue if _, err := asn1.Unmarshal(raw.Raw, &val); err != nil { return nil, err } return x509.ParseCertificates(val.Bytes) } func isCertMatchForIssuerAndSerial(cert *x509.Certificate, ias issuerAndSerial) bool { return cert.SerialNumber.Cmp(ias.SerialNumber) == 0 && bytes.Equal(cert.RawIssuer, ias.IssuerName.FullBytes) } // Attribute represents a key value pair attribute. Value must be marshalable byte // `encoding/asn1` type Attribute struct { Type asn1.ObjectIdentifier Value interface{} } type attributes struct { types []asn1.ObjectIdentifier values []interface{} } // Add adds the attribute, maintaining insertion order func (attrs *attributes) Add(attrType asn1.ObjectIdentifier, value interface{}) { attrs.types = append(attrs.types, attrType) attrs.values = append(attrs.values, value) } type sortableAttribute struct { SortKey []byte Attribute attribute } type attributeSet []sortableAttribute func (sa attributeSet) Len() int { return len(sa) } func (sa attributeSet) Less(i, j int) bool { return bytes.Compare(sa[i].SortKey, sa[j].SortKey) < 0 } func (sa attributeSet) Swap(i, j int) { sa[i], sa[j] = sa[j], sa[i] } func (sa attributeSet) Attributes() []attribute { attrs := make([]attribute, len(sa)) for i, attr := range sa { attrs[i] = attr.Attribute } return attrs } func (attrs *attributes) ForMarshalling() ([]attribute, error) { sortables := make(attributeSet, len(attrs.types)) for i := range sortables { attrType := attrs.types[i] attrValue := attrs.values[i] asn1Value, err := asn1.Marshal(attrValue) if err != nil { return nil, err } attr := attribute{ Type: attrType, Value: asn1.RawValue{Tag: 17, IsCompound: true, Bytes: asn1Value}, // 17 == SET tag } encoded, err := asn1.Marshal(attr) if err != nil { return nil, err } sortables[i] = sortableAttribute{ SortKey: encoded, Attribute: attr, } } sort.Sort(sortables) return sortables.Attributes(), nil }