mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-10-31 05:40:42 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			189 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			189 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // 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/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
 | |
| 
 | |
| }
 |