github.com/amanya/packer@v0.12.1-0.20161117214323-902ac5ab2eb6/builder/azure/pkcs12/pkcs12.go (about)

     1  // Package pkcs12 provides some implementations of PKCS#12.
     2  //
     3  // This implementation is distilled from https://tools.ietf.org/html/rfc7292 and referenced documents.
     4  // It is intended for decoding P12/PFX-stored certificate+key for use with the crypto/tls package.
     5  package pkcs12
     6  
     7  import (
     8  	"crypto/rand"
     9  	"crypto/x509/pkix"
    10  	"encoding/asn1"
    11  	"errors"
    12  	"io"
    13  )
    14  
    15  var (
    16  	oidLocalKeyID      = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 21}
    17  	oidDataContentType = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 1}
    18  
    19  	localKeyId = []byte{0x01, 0x00, 0x00, 0x00}
    20  )
    21  
    22  type pfxPdu struct {
    23  	Version  int
    24  	AuthSafe contentInfo
    25  	MacData  macData `asn1:"optional"`
    26  }
    27  
    28  type contentInfo struct {
    29  	ContentType asn1.ObjectIdentifier
    30  	Content     asn1.RawValue `asn1:"tag:0,explicit,optional"`
    31  }
    32  
    33  type encryptedData struct {
    34  	Version              int
    35  	EncryptedContentInfo encryptedContentInfo
    36  }
    37  
    38  type encryptedContentInfo struct {
    39  	ContentType                asn1.ObjectIdentifier
    40  	ContentEncryptionAlgorithm pkix.AlgorithmIdentifier
    41  	EncryptedContent           []byte `asn1:"tag:0,optional"`
    42  }
    43  
    44  func (i encryptedContentInfo) GetAlgorithm() pkix.AlgorithmIdentifier {
    45  	return i.ContentEncryptionAlgorithm
    46  }
    47  
    48  func (i encryptedContentInfo) GetData() []byte { return i.EncryptedContent }
    49  
    50  type safeBag struct {
    51  	Id         asn1.ObjectIdentifier
    52  	Value      asn1.RawValue     `asn1:"tag:0,explicit"`
    53  	Attributes []pkcs12Attribute `asn1:"set,optional"`
    54  }
    55  
    56  type pkcs12Attribute struct {
    57  	Id    asn1.ObjectIdentifier
    58  	Value asn1.RawValue `ans1:"set"`
    59  }
    60  
    61  type encryptedPrivateKeyInfo struct {
    62  	AlgorithmIdentifier pkix.AlgorithmIdentifier
    63  	EncryptedData       []byte
    64  }
    65  
    66  func (i encryptedPrivateKeyInfo) GetAlgorithm() pkix.AlgorithmIdentifier { return i.AlgorithmIdentifier }
    67  func (i encryptedPrivateKeyInfo) GetData() []byte                        { return i.EncryptedData }
    68  
    69  // unmarshal calls asn1.Unmarshal, but also returns an error if there is any
    70  // trailing data after unmarshaling.
    71  func unmarshal(in []byte, out interface{}) error {
    72  	trailing, err := asn1.Unmarshal(in, out)
    73  	if err != nil {
    74  		return err
    75  	}
    76  	if len(trailing) != 0 {
    77  		return errors.New("pkcs12: trailing data found")
    78  	}
    79  	return nil
    80  }
    81  
    82  func getLocalKeyId(id []byte) (attribute pkcs12Attribute, err error) {
    83  	octetString := asn1.RawValue{Tag: 4, Class: 0, IsCompound: false, Bytes: id}
    84  	bytes, err := asn1.Marshal(octetString)
    85  	if err != nil {
    86  		return
    87  	}
    88  
    89  	attribute = pkcs12Attribute{
    90  		Id:    oidLocalKeyID,
    91  		Value: asn1.RawValue{Tag: 17, Class: 0, IsCompound: true, Bytes: bytes},
    92  	}
    93  
    94  	return attribute, nil
    95  }
    96  
    97  func convertToRawVal(val interface{}) (raw asn1.RawValue, err error) {
    98  	bytes, err := asn1.Marshal(val)
    99  	if err != nil {
   100  		return
   101  	}
   102  
   103  	_, err = asn1.Unmarshal(bytes, &raw)
   104  	return raw, nil
   105  }
   106  
   107  func makeSafeBags(oid asn1.ObjectIdentifier, value []byte) ([]safeBag, error) {
   108  	attribute, err := getLocalKeyId(localKeyId)
   109  
   110  	if err != nil {
   111  		return nil, EncodeError("local key id: " + err.Error())
   112  	}
   113  
   114  	bag := make([]safeBag, 1)
   115  	bag[0] = safeBag{
   116  		Id:         oid,
   117  		Value:      asn1.RawValue{Tag: 0, Class: 2, IsCompound: true, Bytes: value},
   118  		Attributes: []pkcs12Attribute{attribute},
   119  	}
   120  
   121  	return bag, nil
   122  }
   123  
   124  func makeCertBagContentInfo(derBytes []byte) (*contentInfo, error) {
   125  	certBag1 := certBag{
   126  		Id:   oidCertTypeX509Certificate,
   127  		Data: derBytes,
   128  	}
   129  
   130  	bytes, err := asn1.Marshal(certBag1)
   131  	if err != nil {
   132  		return nil, EncodeError("encoding cert bag: " + err.Error())
   133  	}
   134  
   135  	certSafeBags, err := makeSafeBags(oidCertBagType, bytes)
   136  	if err != nil {
   137  		return nil, EncodeError("safe bags: " + err.Error())
   138  	}
   139  
   140  	return makeContentInfo(certSafeBags)
   141  }
   142  
   143  func makeShroudedKeyBagContentInfo(privateKey interface{}, password []byte) (*contentInfo, error) {
   144  	shroudedKeyBagBytes, err := encodePkcs8ShroudedKeyBag(privateKey, password)
   145  	if err != nil {
   146  		return nil, EncodeError("encode PKCS#8 shrouded key bag: " + err.Error())
   147  	}
   148  
   149  	safeBags, err := makeSafeBags(oidPkcs8ShroudedKeyBagType, shroudedKeyBagBytes)
   150  	if err != nil {
   151  		return nil, EncodeError("safe bags: " + err.Error())
   152  	}
   153  
   154  	return makeContentInfo(safeBags)
   155  }
   156  
   157  func makeContentInfo(val interface{}) (*contentInfo, error) {
   158  	fullBytes, err := asn1.Marshal(val)
   159  	if err != nil {
   160  		return nil, EncodeError("contentInfo raw value marshal: " + err.Error())
   161  	}
   162  
   163  	octetStringVal := asn1.RawValue{Tag: 4, Class: 0, IsCompound: false, Bytes: fullBytes}
   164  	octetStringFullBytes, err := asn1.Marshal(octetStringVal)
   165  	if err != nil {
   166  		return nil, EncodeError("raw contentInfo to octet string: " + err.Error())
   167  	}
   168  
   169  	contentInfo := contentInfo{ContentType: oidDataContentType}
   170  	contentInfo.Content = asn1.RawValue{Tag: 0, Class: 2, IsCompound: true, Bytes: octetStringFullBytes}
   171  
   172  	return &contentInfo, nil
   173  }
   174  
   175  func makeContentInfos(derBytes []byte, privateKey interface{}, password []byte) ([]contentInfo, error) {
   176  	shroudedKeyContentInfo, err := makeShroudedKeyBagContentInfo(privateKey, password)
   177  	if err != nil {
   178  		return nil, EncodeError("shrouded key content info: " + err.Error())
   179  	}
   180  
   181  	certBagContentInfo, err := makeCertBagContentInfo(derBytes)
   182  	if err != nil {
   183  		return nil, EncodeError("cert bag content info: " + err.Error())
   184  	}
   185  
   186  	contentInfos := make([]contentInfo, 2)
   187  	contentInfos[0] = *shroudedKeyContentInfo
   188  	contentInfos[1] = *certBagContentInfo
   189  
   190  	return contentInfos, nil
   191  }
   192  
   193  func makeSalt(saltByteCount int) ([]byte, error) {
   194  	salt := make([]byte, saltByteCount)
   195  	_, err := io.ReadFull(rand.Reader, salt)
   196  	return salt, err
   197  }
   198  
   199  // Encode converts a certificate and a private key to the PKCS#12 byte stream format.
   200  //
   201  // derBytes is a DER encoded certificate.
   202  // privateKey is an RSA
   203  func Encode(derBytes []byte, privateKey interface{}, password string) ([]byte, error) {
   204  	secret, err := bmpString(password)
   205  	if err != nil {
   206  		return nil, ErrIncorrectPassword
   207  	}
   208  
   209  	contentInfos, err := makeContentInfos(derBytes, privateKey, secret)
   210  	if err != nil {
   211  		return nil, err
   212  	}
   213  
   214  	// Marhsal []contentInfo so we can re-constitute the byte stream that will
   215  	// be suitable for computing the MAC
   216  	bytes, err := asn1.Marshal(contentInfos)
   217  	if err != nil {
   218  		return nil, err
   219  	}
   220  
   221  	// Unmarshal as an asn1.RawValue so, we can compute the MAC against the .Bytes
   222  	var contentInfosRaw asn1.RawValue
   223  	err = unmarshal(bytes, &contentInfosRaw)
   224  	if err != nil {
   225  		return nil, err
   226  	}
   227  
   228  	authSafeContentInfo, err := makeContentInfo(contentInfosRaw)
   229  	if err != nil {
   230  		return nil, EncodeError("authSafe content info: " + err.Error())
   231  	}
   232  
   233  	salt, err := makeSalt(pbeSaltSizeBytes)
   234  	if err != nil {
   235  		return nil, EncodeError("salt value: " + err.Error())
   236  	}
   237  
   238  	// Compute the MAC for marshaled bytes of contentInfos, which includes the
   239  	// cert bag, and the shrouded key bag.
   240  	digest := computeMac(contentInfosRaw.FullBytes, pbeIterationCount, salt, secret)
   241  
   242  	pfx := pfxPdu{
   243  		Version:  3,
   244  		AuthSafe: *authSafeContentInfo,
   245  		MacData: macData{
   246  			Iterations: pbeIterationCount,
   247  			MacSalt:    salt,
   248  			Mac: digestInfo{
   249  				Algorithm: pkix.AlgorithmIdentifier{
   250  					Algorithm: oidSha1Algorithm,
   251  				},
   252  				Digest: digest,
   253  			},
   254  		},
   255  	}
   256  
   257  	bytes, err = asn1.Marshal(pfx)
   258  	if err != nil {
   259  		return nil, EncodeError("marshal PFX PDU: " + err.Error())
   260  	}
   261  
   262  	return bytes, err
   263  }