123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 |
- // Package pkcs7 implements the subset of the CMS PKCS #7 datatype that is typically
- // used to package certificates and CRLs. Using openssl, every certificate converted
- // to PKCS #7 format from another encoding such as PEM conforms to this implementation.
- // reference: https://www.openssl.org/docs/man1.1.0/apps/crl2pkcs7.html
- //
- // PKCS #7 Data type, reference: https://tools.ietf.org/html/rfc2315
- //
- // The full pkcs#7 cryptographic message syntax allows for cryptographic enhancements,
- // for example data can be encrypted and signed and then packaged through pkcs#7 to be
- // sent over a network and then verified and decrypted. It is asn1, and the type of
- // PKCS #7 ContentInfo, which comprises the PKCS #7 structure, is:
- //
- // ContentInfo ::= SEQUENCE {
- // contentType ContentType,
- // content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL
- // }
- //
- // There are 6 possible ContentTypes, data, signedData, envelopedData,
- // signedAndEnvelopedData, digestedData, and encryptedData. Here signedData, Data, and encrypted
- // Data are implemented, as the degenerate case of signedData without a signature is the typical
- // format for transferring certificates and CRLS, and Data and encryptedData are used in PKCS #12
- // formats.
- // The ContentType signedData has the form:
- //
- // signedData ::= SEQUENCE {
- // version Version,
- // digestAlgorithms DigestAlgorithmIdentifiers,
- // contentInfo ContentInfo,
- // certificates [0] IMPLICIT ExtendedCertificatesAndCertificates OPTIONAL
- // crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
- // signerInfos SignerInfos
- // }
- //
- // As of yet signerInfos and digestAlgorithms are not parsed, as they are not relevant to
- // this system's use of PKCS #7 data. Version is an integer type, note that PKCS #7 is
- // recursive, this second layer of ContentInfo is similar ignored for our degenerate
- // usage. The ExtendedCertificatesAndCertificates type consists of a sequence of choices
- // between PKCS #6 extended certificates and x509 certificates. Any sequence consisting
- // of any number of extended certificates is not yet supported in this implementation.
- //
- // The ContentType Data is simply a raw octet string and is parsed directly into a Go []byte slice.
- //
- // The ContentType encryptedData is the most complicated and its form can be gathered by
- // the go type below. It essentially contains a raw octet string of encrypted data and an
- // algorithm identifier for use in decrypting this data.
- package pkcs7
- import (
- "crypto/x509"
- "crypto/x509/pkix"
- "encoding/asn1"
- "errors"
- cferr "github.com/cloudflare/cfssl/errors"
- )
- // Types used for asn1 Unmarshaling.
- type signedData struct {
- Version int
- DigestAlgorithms asn1.RawValue
- ContentInfo asn1.RawValue
- Certificates asn1.RawValue `asn1:"optional" asn1:"tag:0"`
- Crls asn1.RawValue `asn1:"optional"`
- SignerInfos asn1.RawValue
- }
- type initPKCS7 struct {
- Raw asn1.RawContent
- ContentType asn1.ObjectIdentifier
- Content asn1.RawValue `asn1:"tag:0,explicit,optional"`
- }
- // Object identifier strings of the three implemented PKCS7 types.
- const (
- ObjIDData = "1.2.840.113549.1.7.1"
- ObjIDSignedData = "1.2.840.113549.1.7.2"
- ObjIDEncryptedData = "1.2.840.113549.1.7.6"
- )
- // PKCS7 represents the ASN1 PKCS #7 Content type. It contains one of three
- // possible types of Content objects, as denoted by the object identifier in
- // the ContentInfo field, the other two being nil. SignedData
- // is the degenerate SignedData Content info without signature used
- // to hold certificates and crls. Data is raw bytes, and EncryptedData
- // is as defined in PKCS #7 standard.
- type PKCS7 struct {
- Raw asn1.RawContent
- ContentInfo string
- Content Content
- }
- // Content implements three of the six possible PKCS7 data types. Only one is non-nil.
- type Content struct {
- Data []byte
- SignedData SignedData
- EncryptedData EncryptedData
- }
- // SignedData defines the typical carrier of certificates and crls.
- type SignedData struct {
- Raw asn1.RawContent
- Version int
- Certificates []*x509.Certificate
- Crl *pkix.CertificateList
- }
- // Data contains raw bytes. Used as a subtype in PKCS12.
- type Data struct {
- Bytes []byte
- }
- // EncryptedData contains encrypted data. Used as a subtype in PKCS12.
- type EncryptedData struct {
- Raw asn1.RawContent
- Version int
- EncryptedContentInfo EncryptedContentInfo
- }
- // EncryptedContentInfo is a subtype of PKCS7EncryptedData.
- type EncryptedContentInfo struct {
- Raw asn1.RawContent
- ContentType asn1.ObjectIdentifier
- ContentEncryptionAlgorithm pkix.AlgorithmIdentifier
- EncryptedContent []byte `asn1:"tag:0,optional"`
- }
- // ParsePKCS7 attempts to parse the DER encoded bytes of a
- // PKCS7 structure.
- func ParsePKCS7(raw []byte) (msg *PKCS7, err error) {
- var pkcs7 initPKCS7
- _, err = asn1.Unmarshal(raw, &pkcs7)
- if err != nil {
- return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err)
- }
- msg = new(PKCS7)
- msg.Raw = pkcs7.Raw
- msg.ContentInfo = pkcs7.ContentType.String()
- switch {
- case msg.ContentInfo == ObjIDData:
- msg.ContentInfo = "Data"
- _, err = asn1.Unmarshal(pkcs7.Content.Bytes, &msg.Content.Data)
- if err != nil {
- return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err)
- }
- case msg.ContentInfo == ObjIDSignedData:
- msg.ContentInfo = "SignedData"
- var signedData signedData
- _, err = asn1.Unmarshal(pkcs7.Content.Bytes, &signedData)
- if err != nil {
- return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err)
- }
- if len(signedData.Certificates.Bytes) != 0 {
- msg.Content.SignedData.Certificates, err = x509.ParseCertificates(signedData.Certificates.Bytes)
- if err != nil {
- return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err)
- }
- }
- if len(signedData.Crls.Bytes) != 0 {
- msg.Content.SignedData.Crl, err = x509.ParseDERCRL(signedData.Crls.Bytes)
- if err != nil {
- return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err)
- }
- }
- msg.Content.SignedData.Version = signedData.Version
- msg.Content.SignedData.Raw = pkcs7.Content.Bytes
- case msg.ContentInfo == ObjIDEncryptedData:
- msg.ContentInfo = "EncryptedData"
- var encryptedData EncryptedData
- _, err = asn1.Unmarshal(pkcs7.Content.Bytes, &encryptedData)
- if err != nil {
- return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err)
- }
- if encryptedData.Version != 0 {
- return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, errors.New("Only support for PKCS #7 encryptedData version 0"))
- }
- msg.Content.EncryptedData = encryptedData
- default:
- return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, errors.New("Attempt to parse PKCS# 7 Content not of type data, signed data or encrypted data"))
- }
- return msg, nil
- }
|