github.phpd.cn/hashicorp/packer@v1.3.2/builder/azure/pkcs12/pkcs12.go (about)

     1  // Copyright 2015 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package pkcs12 implements some of PKCS#12.
     6  //
     7  // This implementation is distilled from https://tools.ietf.org/html/rfc7292
     8  // and referenced documents. It is intended for decoding P12/PFX-stored
     9  // certificates and keys for use with the crypto/tls package.
    10  package pkcs12
    11  
    12  import (
    13  	"crypto/ecdsa"
    14  	"crypto/rand"
    15  	"crypto/rsa"
    16  	"crypto/x509"
    17  	"crypto/x509/pkix"
    18  	"encoding/asn1"
    19  	"encoding/hex"
    20  	"encoding/pem"
    21  	"errors"
    22  	"io"
    23  )
    24  
    25  var (
    26  	oidDataContentType          = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 7, 1})
    27  	oidEncryptedDataContentType = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 7, 6})
    28  
    29  	oidFriendlyName     = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 20})
    30  	oidLocalKeyID       = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 21})
    31  	oidMicrosoftCSPName = asn1.ObjectIdentifier([]int{1, 3, 6, 1, 4, 1, 311, 17, 1})
    32  
    33  	localKeyId = []byte{0x01, 0x00, 0x00, 0x00}
    34  )
    35  
    36  type pfxPdu struct {
    37  	Version  int
    38  	AuthSafe contentInfo
    39  	MacData  macData `asn1:"optional"`
    40  }
    41  
    42  type contentInfo struct {
    43  	ContentType asn1.ObjectIdentifier
    44  	Content     asn1.RawValue `asn1:"tag:0,explicit,optional"`
    45  }
    46  
    47  type encryptedData struct {
    48  	Version              int
    49  	EncryptedContentInfo encryptedContentInfo
    50  }
    51  
    52  type encryptedContentInfo struct {
    53  	ContentType                asn1.ObjectIdentifier
    54  	ContentEncryptionAlgorithm pkix.AlgorithmIdentifier
    55  	EncryptedContent           []byte `asn1:"tag:0,optional"`
    56  }
    57  
    58  func (i encryptedContentInfo) Algorithm() pkix.AlgorithmIdentifier {
    59  	return i.ContentEncryptionAlgorithm
    60  }
    61  
    62  func (i encryptedContentInfo) Data() []byte { return i.EncryptedContent }
    63  
    64  type safeBag struct {
    65  	Id         asn1.ObjectIdentifier
    66  	Value      asn1.RawValue     `asn1:"tag:0,explicit"`
    67  	Attributes []pkcs12Attribute `asn1:"set,optional"`
    68  }
    69  
    70  type pkcs12Attribute struct {
    71  	Id    asn1.ObjectIdentifier
    72  	Value asn1.RawValue `asn1:"set"`
    73  }
    74  
    75  type encryptedPrivateKeyInfo struct {
    76  	AlgorithmIdentifier pkix.AlgorithmIdentifier
    77  	EncryptedData       []byte
    78  }
    79  
    80  func (i encryptedPrivateKeyInfo) Algorithm() pkix.AlgorithmIdentifier {
    81  	return i.AlgorithmIdentifier
    82  }
    83  
    84  func (i encryptedPrivateKeyInfo) Data() []byte {
    85  	return i.EncryptedData
    86  }
    87  
    88  // PEM block types
    89  const (
    90  	certificateType = "CERTIFICATE"
    91  	privateKeyType  = "PRIVATE KEY"
    92  )
    93  
    94  // unmarshal calls asn1.Unmarshal, but also returns an error if there is any
    95  // trailing data after unmarshalling.
    96  func unmarshal(in []byte, out interface{}) error {
    97  	trailing, err := asn1.Unmarshal(in, out)
    98  	if err != nil {
    99  		return err
   100  	}
   101  	if len(trailing) != 0 {
   102  		return errors.New("pkcs12: trailing data found")
   103  	}
   104  	return nil
   105  }
   106  
   107  // ConvertToPEM converts all "safe bags" contained in pfxData to PEM blocks.
   108  func ToPEM(pfxData []byte, password string) ([]*pem.Block, error) {
   109  	encodedPassword, err := bmpString(password)
   110  	if err != nil {
   111  		return nil, ErrIncorrectPassword
   112  	}
   113  
   114  	bags, encodedPassword, err := getSafeContents(pfxData, encodedPassword)
   115  
   116  	blocks := make([]*pem.Block, 0, len(bags))
   117  	for _, bag := range bags {
   118  		block, err := convertBag(&bag, encodedPassword)
   119  		if err != nil {
   120  			return nil, err
   121  		}
   122  		blocks = append(blocks, block)
   123  	}
   124  
   125  	return blocks, nil
   126  }
   127  
   128  func convertBag(bag *safeBag, password []byte) (*pem.Block, error) {
   129  	block := &pem.Block{
   130  		Headers: make(map[string]string),
   131  	}
   132  
   133  	for _, attribute := range bag.Attributes {
   134  		k, v, err := convertAttribute(&attribute)
   135  		if err != nil {
   136  			return nil, err
   137  		}
   138  		block.Headers[k] = v
   139  	}
   140  
   141  	switch {
   142  	case bag.Id.Equal(oidCertBag):
   143  		block.Type = certificateType
   144  		certsData, err := decodeCertBag(bag.Value.Bytes)
   145  		if err != nil {
   146  			return nil, err
   147  		}
   148  		block.Bytes = certsData
   149  	case bag.Id.Equal(oidPKCS8ShroudedKeyBag):
   150  		block.Type = privateKeyType
   151  
   152  		key, err := decodePkcs8ShroudedKeyBag(bag.Value.Bytes, password)
   153  		if err != nil {
   154  			return nil, err
   155  		}
   156  
   157  		switch key := key.(type) {
   158  		case *rsa.PrivateKey:
   159  			block.Bytes = x509.MarshalPKCS1PrivateKey(key)
   160  		case *ecdsa.PrivateKey:
   161  			block.Bytes, err = x509.MarshalECPrivateKey(key)
   162  			if err != nil {
   163  				return nil, err
   164  			}
   165  		default:
   166  			return nil, errors.New("found unknown private key type in PKCS#8 wrapping")
   167  		}
   168  	default:
   169  		return nil, errors.New("don't know how to convert a safe bag of type " + bag.Id.String())
   170  	}
   171  	return block, nil
   172  }
   173  
   174  func convertAttribute(attribute *pkcs12Attribute) (key, value string, err error) {
   175  	isString := false
   176  
   177  	switch {
   178  	case attribute.Id.Equal(oidFriendlyName):
   179  		key = "friendlyName"
   180  		isString = true
   181  	case attribute.Id.Equal(oidLocalKeyID):
   182  		key = "localKeyId"
   183  	case attribute.Id.Equal(oidMicrosoftCSPName):
   184  		// This key is chosen to match OpenSSL.
   185  		key = "Microsoft CSP Name"
   186  		isString = true
   187  	default:
   188  		return "", "", errors.New("pkcs12: unknown attribute with OID " + attribute.Id.String())
   189  	}
   190  
   191  	if isString {
   192  		if err := unmarshal(attribute.Value.Bytes, &attribute.Value); err != nil {
   193  			return "", "", err
   194  		}
   195  		if value, err = decodeBMPString(attribute.Value.Bytes); err != nil {
   196  			return "", "", err
   197  		}
   198  	} else {
   199  		var id []byte
   200  		if err := unmarshal(attribute.Value.Bytes, &id); err != nil {
   201  			return "", "", err
   202  		}
   203  		value = hex.EncodeToString(id)
   204  	}
   205  
   206  	return key, value, nil
   207  }
   208  
   209  // Decode extracts a certificate and private key from pfxData. This function
   210  // assumes that there is only one certificate and only one private key in the
   211  // pfxData.
   212  func Decode(pfxData []byte, password string) (privateKey interface{}, certificate *x509.Certificate, err error) {
   213  	encodedPassword, err := bmpString(password)
   214  	if err != nil {
   215  		return nil, nil, err
   216  	}
   217  
   218  	bags, encodedPassword, err := getSafeContents(pfxData, encodedPassword)
   219  	if err != nil {
   220  		return nil, nil, err
   221  	}
   222  
   223  	if len(bags) != 2 {
   224  		err = errors.New("pkcs12: expected exactly two safe bags in the PFX PDU")
   225  		return
   226  	}
   227  
   228  	for _, bag := range bags {
   229  		switch {
   230  		case bag.Id.Equal(oidCertBag):
   231  			if certificate != nil {
   232  				err = errors.New("pkcs12: expected exactly one certificate bag")
   233  			}
   234  
   235  			certsData, err := decodeCertBag(bag.Value.Bytes)
   236  			if err != nil {
   237  				return nil, nil, err
   238  			}
   239  			certs, err := x509.ParseCertificates(certsData)
   240  			if err != nil {
   241  				return nil, nil, err
   242  			}
   243  			if len(certs) != 1 {
   244  				err = errors.New("pkcs12: expected exactly one certificate in the certBag")
   245  				return nil, nil, err
   246  			}
   247  			certificate = certs[0]
   248  
   249  		case bag.Id.Equal(oidPKCS8ShroudedKeyBag):
   250  			if privateKey != nil {
   251  				err = errors.New("pkcs12: expected exactly one key bag")
   252  			}
   253  			if privateKey, err = decodePkcs8ShroudedKeyBag(bag.Value.Bytes, encodedPassword); err != nil {
   254  				return nil, nil, err
   255  			}
   256  		}
   257  	}
   258  
   259  	if certificate == nil {
   260  		return nil, nil, errors.New("pkcs12: certificate missing")
   261  	}
   262  	if privateKey == nil {
   263  		return nil, nil, errors.New("pkcs12: private key missing")
   264  	}
   265  
   266  	return
   267  }
   268  
   269  func getLocalKeyId(id []byte) (attribute pkcs12Attribute, err error) {
   270  	octetString := asn1.RawValue{Tag: 4, Class: 0, IsCompound: false, Bytes: id}
   271  	bytes, err := asn1.Marshal(octetString)
   272  	if err != nil {
   273  		return
   274  	}
   275  
   276  	attribute = pkcs12Attribute{
   277  		Id:    oidLocalKeyID,
   278  		Value: asn1.RawValue{Tag: 17, Class: 0, IsCompound: true, Bytes: bytes},
   279  	}
   280  
   281  	return attribute, nil
   282  }
   283  
   284  func convertToRawVal(val interface{}) (raw asn1.RawValue, err error) {
   285  	bytes, err := asn1.Marshal(val)
   286  	if err != nil {
   287  		return
   288  	}
   289  
   290  	_, err = asn1.Unmarshal(bytes, &raw)
   291  	return raw, nil
   292  }
   293  
   294  func makeSafeBags(oid asn1.ObjectIdentifier, value []byte) ([]safeBag, error) {
   295  	attribute, err := getLocalKeyId(localKeyId)
   296  
   297  	if err != nil {
   298  		return nil, EncodeError("local key id: " + err.Error())
   299  	}
   300  
   301  	bag := make([]safeBag, 1)
   302  	bag[0] = safeBag{
   303  		Id:         oid,
   304  		Value:      asn1.RawValue{Tag: 0, Class: 2, IsCompound: true, Bytes: value},
   305  		Attributes: []pkcs12Attribute{attribute},
   306  	}
   307  
   308  	return bag, nil
   309  }
   310  
   311  func makeCertBagContentInfo(derBytes []byte) (*contentInfo, error) {
   312  	certBag1 := certBag{
   313  		Id:   oidCertTypeX509Certificate,
   314  		Data: derBytes,
   315  	}
   316  
   317  	bytes, err := asn1.Marshal(certBag1)
   318  	if err != nil {
   319  		return nil, EncodeError("encoding cert bag: " + err.Error())
   320  	}
   321  
   322  	certSafeBags, err := makeSafeBags(oidCertBag, bytes)
   323  	if err != nil {
   324  		return nil, EncodeError("safe bags: " + err.Error())
   325  	}
   326  
   327  	return makeContentInfo(certSafeBags)
   328  }
   329  
   330  func makeShroudedKeyBagContentInfo(privateKey interface{}, password []byte) (*contentInfo, error) {
   331  	shroudedKeyBagBytes, err := encodePkcs8ShroudedKeyBag(privateKey, password)
   332  	if err != nil {
   333  		return nil, EncodeError("encode PKCS#8 shrouded key bag: " + err.Error())
   334  	}
   335  
   336  	safeBags, err := makeSafeBags(oidPKCS8ShroudedKeyBag, shroudedKeyBagBytes)
   337  	if err != nil {
   338  		return nil, EncodeError("safe bags: " + err.Error())
   339  	}
   340  
   341  	return makeContentInfo(safeBags)
   342  }
   343  
   344  func makeContentInfo(val interface{}) (*contentInfo, error) {
   345  	fullBytes, err := asn1.Marshal(val)
   346  	if err != nil {
   347  		return nil, EncodeError("contentInfo raw value marshal: " + err.Error())
   348  	}
   349  
   350  	octetStringVal := asn1.RawValue{Tag: 4, Class: 0, IsCompound: false, Bytes: fullBytes}
   351  	octetStringFullBytes, err := asn1.Marshal(octetStringVal)
   352  	if err != nil {
   353  		return nil, EncodeError("raw contentInfo to octet string: " + err.Error())
   354  	}
   355  
   356  	contentInfo := contentInfo{ContentType: oidDataContentType}
   357  	contentInfo.Content = asn1.RawValue{Tag: 0, Class: 2, IsCompound: true, Bytes: octetStringFullBytes}
   358  
   359  	return &contentInfo, nil
   360  }
   361  
   362  func makeContentInfos(derBytes []byte, privateKey interface{}, password []byte) ([]contentInfo, error) {
   363  	shroudedKeyContentInfo, err := makeShroudedKeyBagContentInfo(privateKey, password)
   364  	if err != nil {
   365  		return nil, EncodeError("shrouded key content info: " + err.Error())
   366  	}
   367  
   368  	certBagContentInfo, err := makeCertBagContentInfo(derBytes)
   369  	if err != nil {
   370  		return nil, EncodeError("cert bag content info: " + err.Error())
   371  	}
   372  
   373  	contentInfos := make([]contentInfo, 2)
   374  	contentInfos[0] = *shroudedKeyContentInfo
   375  	contentInfos[1] = *certBagContentInfo
   376  
   377  	return contentInfos, nil
   378  }
   379  
   380  func makeSalt(saltByteCount int) ([]byte, error) {
   381  	salt := make([]byte, saltByteCount)
   382  	_, err := io.ReadFull(rand.Reader, salt)
   383  	return salt, err
   384  }
   385  
   386  // Encode converts a certificate and a private key to the PKCS#12 byte stream format.
   387  //
   388  // derBytes is a DER encoded certificate.
   389  // privateKey is an RSA
   390  func Encode(derBytes []byte, privateKey interface{}, password string) (pfxBytes []byte, err error) {
   391  	secret, err := bmpString(password)
   392  	if err != nil {
   393  		return nil, ErrIncorrectPassword
   394  	}
   395  
   396  	contentInfos, err := makeContentInfos(derBytes, privateKey, secret)
   397  	if err != nil {
   398  		return nil, err
   399  	}
   400  
   401  	// Marshal []contentInfo so we can re-constitute the byte stream that will
   402  	// be suitable for computing the MAC
   403  	bytes, err := asn1.Marshal(contentInfos)
   404  	if err != nil {
   405  		return nil, err
   406  	}
   407  
   408  	// Unmarshal as an asn1.RawValue so, we can compute the MAC against the .Bytes
   409  	var contentInfosRaw asn1.RawValue
   410  	err = unmarshal(bytes, &contentInfosRaw)
   411  	if err != nil {
   412  		return nil, err
   413  	}
   414  
   415  	authSafeContentInfo, err := makeContentInfo(contentInfosRaw)
   416  	if err != nil {
   417  		return nil, EncodeError("authSafe content info: " + err.Error())
   418  	}
   419  
   420  	salt, err := makeSalt(pbeSaltSizeBytes)
   421  	if err != nil {
   422  		return nil, EncodeError("salt value: " + err.Error())
   423  	}
   424  
   425  	// Compute the MAC for marshaled bytes of contentInfos, which includes the
   426  	// cert bag, and the shrouded key bag.
   427  	digest := computeMac(contentInfosRaw.FullBytes, pbeIterationCount, salt, secret)
   428  
   429  	pfx := pfxPdu{
   430  		Version:  3,
   431  		AuthSafe: *authSafeContentInfo,
   432  		MacData: macData{
   433  			Iterations: pbeIterationCount,
   434  			MacSalt:    salt,
   435  			Mac: digestInfo{
   436  				Algorithm: pkix.AlgorithmIdentifier{
   437  					Algorithm: oidSHA1,
   438  				},
   439  				Digest: digest,
   440  			},
   441  		},
   442  	}
   443  
   444  	bytes, err = asn1.Marshal(pfx)
   445  	if err != nil {
   446  		return nil, EncodeError("marshal PFX PDU: " + err.Error())
   447  	}
   448  
   449  	return bytes, err
   450  }
   451  
   452  func getSafeContents(p12Data, password []byte) (bags []safeBag, updatedPassword []byte, err error) {
   453  	pfx := new(pfxPdu)
   454  
   455  	if err := unmarshal(p12Data, pfx); err != nil {
   456  		return nil, nil, errors.New("pkcs12: error reading P12 data: " + err.Error())
   457  	}
   458  
   459  	if pfx.Version != 3 {
   460  		return nil, nil, NotImplementedError("can only decode v3 PFX PDU's")
   461  	}
   462  
   463  	if !pfx.AuthSafe.ContentType.Equal(oidDataContentType) {
   464  		return nil, nil, NotImplementedError("only password-protected PFX is implemented")
   465  	}
   466  
   467  	// unmarshal the explicit bytes in the content for type 'data'
   468  	if err := unmarshal(pfx.AuthSafe.Content.Bytes, &pfx.AuthSafe.Content); err != nil {
   469  		return nil, nil, err
   470  	}
   471  
   472  	if len(pfx.MacData.Mac.Algorithm.Algorithm) == 0 {
   473  		return nil, nil, errors.New("pkcs12: no MAC in data")
   474  	}
   475  
   476  	if err := verifyMac(&pfx.MacData, pfx.AuthSafe.Content.Bytes, password); err != nil {
   477  		if err == ErrIncorrectPassword && len(password) == 2 && password[0] == 0 && password[1] == 0 {
   478  			// some implementations use an empty byte array
   479  			// for the empty string password try one more
   480  			// time with empty-empty password
   481  			password = nil
   482  			err = verifyMac(&pfx.MacData, pfx.AuthSafe.Content.Bytes, password)
   483  		}
   484  		if err != nil {
   485  			return nil, nil, err
   486  		}
   487  	}
   488  
   489  	var authenticatedSafe []contentInfo
   490  	if err := unmarshal(pfx.AuthSafe.Content.Bytes, &authenticatedSafe); err != nil {
   491  		return nil, nil, err
   492  	}
   493  
   494  	if len(authenticatedSafe) != 2 {
   495  		return nil, nil, NotImplementedError("expected exactly two items in the authenticated safe")
   496  	}
   497  
   498  	for _, ci := range authenticatedSafe {
   499  		var data []byte
   500  
   501  		switch {
   502  		case ci.ContentType.Equal(oidDataContentType):
   503  			if err := unmarshal(ci.Content.Bytes, &data); err != nil {
   504  				return nil, nil, err
   505  			}
   506  		case ci.ContentType.Equal(oidEncryptedDataContentType):
   507  			var encryptedData encryptedData
   508  			if err := unmarshal(ci.Content.Bytes, &encryptedData); err != nil {
   509  				return nil, nil, err
   510  			}
   511  			if encryptedData.Version != 0 {
   512  				return nil, nil, NotImplementedError("only version 0 of EncryptedData is supported")
   513  			}
   514  			if data, err = pbDecrypt(encryptedData.EncryptedContentInfo, password); err != nil {
   515  				return nil, nil, err
   516  			}
   517  		default:
   518  			return nil, nil, NotImplementedError("only data and encryptedData content types are supported in authenticated safe")
   519  		}
   520  
   521  		var safeContents []safeBag
   522  		if err := unmarshal(data, &safeContents); err != nil {
   523  			return nil, nil, err
   524  		}
   525  
   526  		bags = append(bags, safeContents...)
   527  	}
   528  
   529  	return bags, password, nil
   530  }