github.com/maenmax/kairep@v0.0.0-20210218001208-55bf3df36788/src/golang.org/x/crypto/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/rsa"
    15  	"crypto/x509"
    16  	"crypto/x509/pkix"
    17  	"encoding/asn1"
    18  	"encoding/hex"
    19  	"encoding/pem"
    20  	"errors"
    21  )
    22  
    23  var (
    24  	oidDataContentType          = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 7, 1})
    25  	oidEncryptedDataContentType = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 7, 6})
    26  
    27  	oidFriendlyName     = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 20})
    28  	oidLocalKeyID       = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 21})
    29  	oidMicrosoftCSPName = asn1.ObjectIdentifier([]int{1, 3, 6, 1, 4, 1, 311, 17, 1})
    30  )
    31  
    32  type pfxPdu struct {
    33  	Version  int
    34  	AuthSafe contentInfo
    35  	MacData  macData `asn1:"optional"`
    36  }
    37  
    38  type contentInfo struct {
    39  	ContentType asn1.ObjectIdentifier
    40  	Content     asn1.RawValue `asn1:"tag:0,explicit,optional"`
    41  }
    42  
    43  type encryptedData struct {
    44  	Version              int
    45  	EncryptedContentInfo encryptedContentInfo
    46  }
    47  
    48  type encryptedContentInfo struct {
    49  	ContentType                asn1.ObjectIdentifier
    50  	ContentEncryptionAlgorithm pkix.AlgorithmIdentifier
    51  	EncryptedContent           []byte `asn1:"tag:0,optional"`
    52  }
    53  
    54  func (i encryptedContentInfo) Algorithm() pkix.AlgorithmIdentifier {
    55  	return i.ContentEncryptionAlgorithm
    56  }
    57  
    58  func (i encryptedContentInfo) Data() []byte { return i.EncryptedContent }
    59  
    60  type safeBag struct {
    61  	Id         asn1.ObjectIdentifier
    62  	Value      asn1.RawValue     `asn1:"tag:0,explicit"`
    63  	Attributes []pkcs12Attribute `asn1:"set,optional"`
    64  }
    65  
    66  type pkcs12Attribute struct {
    67  	Id    asn1.ObjectIdentifier
    68  	Value asn1.RawValue `asn1:"set"`
    69  }
    70  
    71  type encryptedPrivateKeyInfo struct {
    72  	AlgorithmIdentifier pkix.AlgorithmIdentifier
    73  	EncryptedData       []byte
    74  }
    75  
    76  func (i encryptedPrivateKeyInfo) Algorithm() pkix.AlgorithmIdentifier {
    77  	return i.AlgorithmIdentifier
    78  }
    79  
    80  func (i encryptedPrivateKeyInfo) Data() []byte {
    81  	return i.EncryptedData
    82  }
    83  
    84  // PEM block types
    85  const (
    86  	certificateType = "CERTIFICATE"
    87  	privateKeyType  = "PRIVATE KEY"
    88  )
    89  
    90  // unmarshal calls asn1.Unmarshal, but also returns an error if there is any
    91  // trailing data after unmarshaling.
    92  func unmarshal(in []byte, out interface{}) error {
    93  	trailing, err := asn1.Unmarshal(in, out)
    94  	if err != nil {
    95  		return err
    96  	}
    97  	if len(trailing) != 0 {
    98  		return errors.New("pkcs12: trailing data found")
    99  	}
   100  	return nil
   101  }
   102  
   103  // ConvertToPEM converts all "safe bags" contained in pfxData to PEM blocks.
   104  func ToPEM(pfxData []byte, password string) ([]*pem.Block, error) {
   105  	encodedPassword, err := bmpString(password)
   106  	if err != nil {
   107  		return nil, ErrIncorrectPassword
   108  	}
   109  
   110  	bags, encodedPassword, err := getSafeContents(pfxData, encodedPassword)
   111  
   112  	blocks := make([]*pem.Block, 0, len(bags))
   113  	for _, bag := range bags {
   114  		block, err := convertBag(&bag, encodedPassword)
   115  		if err != nil {
   116  			return nil, err
   117  		}
   118  		blocks = append(blocks, block)
   119  	}
   120  
   121  	return blocks, nil
   122  }
   123  
   124  func convertBag(bag *safeBag, password []byte) (*pem.Block, error) {
   125  	block := &pem.Block{
   126  		Headers: make(map[string]string),
   127  	}
   128  
   129  	for _, attribute := range bag.Attributes {
   130  		k, v, err := convertAttribute(&attribute)
   131  		if err != nil {
   132  			return nil, err
   133  		}
   134  		block.Headers[k] = v
   135  	}
   136  
   137  	switch {
   138  	case bag.Id.Equal(oidCertBag):
   139  		block.Type = certificateType
   140  		certsData, err := decodeCertBag(bag.Value.Bytes)
   141  		if err != nil {
   142  			return nil, err
   143  		}
   144  		block.Bytes = certsData
   145  	case bag.Id.Equal(oidPKCS8ShroundedKeyBag):
   146  		block.Type = privateKeyType
   147  
   148  		key, err := decodePkcs8ShroudedKeyBag(bag.Value.Bytes, password)
   149  		if err != nil {
   150  			return nil, err
   151  		}
   152  
   153  		switch key := key.(type) {
   154  		case *rsa.PrivateKey:
   155  			block.Bytes = x509.MarshalPKCS1PrivateKey(key)
   156  		case *ecdsa.PrivateKey:
   157  			block.Bytes, err = x509.MarshalECPrivateKey(key)
   158  			if err != nil {
   159  				return nil, err
   160  			}
   161  		default:
   162  			return nil, errors.New("found unknown private key type in PKCS#8 wrapping")
   163  		}
   164  	default:
   165  		return nil, errors.New("don't know how to convert a safe bag of type " + bag.Id.String())
   166  	}
   167  	return block, nil
   168  }
   169  
   170  func convertAttribute(attribute *pkcs12Attribute) (key, value string, err error) {
   171  	isString := false
   172  
   173  	switch {
   174  	case attribute.Id.Equal(oidFriendlyName):
   175  		key = "friendlyName"
   176  		isString = true
   177  	case attribute.Id.Equal(oidLocalKeyID):
   178  		key = "localKeyId"
   179  	case attribute.Id.Equal(oidMicrosoftCSPName):
   180  		// This key is chosen to match OpenSSL.
   181  		key = "Microsoft CSP Name"
   182  		isString = true
   183  	default:
   184  		return "", "", errors.New("pkcs12: unknown attribute with OID " + attribute.Id.String())
   185  	}
   186  
   187  	if isString {
   188  		if err := unmarshal(attribute.Value.Bytes, &attribute.Value); err != nil {
   189  			return "", "", err
   190  		}
   191  		if value, err = decodeBMPString(attribute.Value.Bytes); err != nil {
   192  			return "", "", err
   193  		}
   194  	} else {
   195  		var id []byte
   196  		if err := unmarshal(attribute.Value.Bytes, &id); err != nil {
   197  			return "", "", err
   198  		}
   199  		value = hex.EncodeToString(id)
   200  	}
   201  
   202  	return key, value, nil
   203  }
   204  
   205  // Decode extracts a certificate and private key from pfxData. This function
   206  // assumes that there is only one certificate and only one private key in the
   207  // pfxData.
   208  func Decode(pfxData []byte, password string) (privateKey interface{}, certificate *x509.Certificate, err error) {
   209  	encodedPassword, err := bmpString(password)
   210  	if err != nil {
   211  		return nil, nil, err
   212  	}
   213  
   214  	bags, encodedPassword, err := getSafeContents(pfxData, encodedPassword)
   215  	if err != nil {
   216  		return nil, nil, err
   217  	}
   218  
   219  //	if len(bags) != 2 {
   220  //		err = errors.New("pkcs12: expected exactly two safe bags in the PFX PDU")
   221  //		return
   222  //	}
   223  
   224  	for _, bag := range bags {
   225  		switch {
   226  		case bag.Id.Equal(oidCertBag):
   227  			if certificate != nil {
   228  				err = errors.New("pkcs12: expected exactly one certificate bag")
   229  			}
   230  
   231  			certsData, err := decodeCertBag(bag.Value.Bytes)
   232  			if err != nil {
   233  				return nil, nil, err
   234  			}
   235  			certs, err := x509.ParseCertificates(certsData)
   236  			if err != nil {
   237  				return nil, nil, err
   238  			}
   239  			if len(certs) != 1 {
   240  				err = errors.New("pkcs12: expected exactly one certificate in the certBag")
   241  				return nil, nil, err
   242  			}
   243  			certificate = certs[0]
   244  
   245  		case bag.Id.Equal(oidPKCS8ShroundedKeyBag):
   246  			if privateKey != nil {
   247  				err = errors.New("pkcs12: expected exactly one key bag")
   248  			}
   249  
   250  			if privateKey, err = decodePkcs8ShroudedKeyBag(bag.Value.Bytes, encodedPassword); err != nil {
   251  				return nil, nil, err
   252  			}
   253  		}
   254  	}
   255  
   256  	if certificate == nil {
   257  		return nil, nil, errors.New("pkcs12: certificate missing")
   258  	}
   259  	if privateKey == nil {
   260  		return nil, nil, errors.New("pkcs12: private key missing")
   261  	}
   262  
   263  	return
   264  }
   265  
   266  func getSafeContents(p12Data, password []byte) (bags []safeBag, updatedPassword []byte, err error) {
   267  	pfx := new(pfxPdu)
   268  	if err := unmarshal(p12Data, pfx); err != nil {
   269  		return nil, nil, errors.New("pkcs12: error reading P12 data: " + err.Error())
   270  	}
   271  
   272  	if pfx.Version != 3 {
   273  		return nil, nil, NotImplementedError("can only decode v3 PFX PDU's")
   274  	}
   275  
   276  	if !pfx.AuthSafe.ContentType.Equal(oidDataContentType) {
   277  		return nil, nil, NotImplementedError("only password-protected PFX is implemented")
   278  	}
   279  
   280  	// unmarshal the explicit bytes in the content for type 'data'
   281  	if err := unmarshal(pfx.AuthSafe.Content.Bytes, &pfx.AuthSafe.Content); err != nil {
   282  		return nil, nil, err
   283  	}
   284  
   285  	if len(pfx.MacData.Mac.Algorithm.Algorithm) == 0 {
   286  		return nil, nil, errors.New("pkcs12: no MAC in data")
   287  	}
   288  
   289  	if err := verifyMac(&pfx.MacData, pfx.AuthSafe.Content.Bytes, password); err != nil {
   290  		if err == ErrIncorrectPassword && len(password) == 2 && password[0] == 0 && password[1] == 0 {
   291  			// some implementations use an empty byte array
   292  			// for the empty string password try one more
   293  			// time with empty-empty password
   294  			password = nil
   295  			err = verifyMac(&pfx.MacData, pfx.AuthSafe.Content.Bytes, password)
   296  		}
   297  		if err != nil {
   298  			return nil, nil, err
   299  		}
   300  	}
   301  
   302  	var authenticatedSafe []contentInfo
   303  	if err := unmarshal(pfx.AuthSafe.Content.Bytes, &authenticatedSafe); err != nil {
   304  		return nil, nil, err
   305  	}
   306  
   307  	if len(authenticatedSafe) != 2 {
   308  		return nil, nil, NotImplementedError("expected exactly two items in the authenticated safe")
   309  	}
   310  
   311  	for _, ci := range authenticatedSafe {
   312  		var data []byte
   313  
   314  		switch {
   315  		case ci.ContentType.Equal(oidDataContentType):
   316  			if err := unmarshal(ci.Content.Bytes, &data); err != nil {
   317  				return nil, nil, err
   318  			}
   319  		case ci.ContentType.Equal(oidEncryptedDataContentType):
   320  			var encryptedData encryptedData
   321  			if err := unmarshal(ci.Content.Bytes, &encryptedData); err != nil {
   322  				return nil, nil, err
   323  			}
   324  			if encryptedData.Version != 0 {
   325  				return nil, nil, NotImplementedError("only version 0 of EncryptedData is supported")
   326  			}
   327  			if data, err = pbDecrypt(encryptedData.EncryptedContentInfo, password); err != nil {
   328  				return nil, nil, err
   329  			}
   330  		default:
   331  			return nil, nil, NotImplementedError("only data and encryptedData content types are supported in authenticated safe")
   332  		}
   333  
   334  		var safeContents []safeBag
   335  		if err := unmarshal(data, &safeContents); err != nil {
   336  			return nil, nil, err
   337  		}
   338  		bags = append(bags, safeContents...)
   339  	}
   340  
   341  	return bags, password, nil
   342  }