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