github.com/devops-filetransfer/sshego@v7.0.4+incompatible/_vendor/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  	if err != nil {
   113  		return nil, err
   114  	}
   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(oidPKCS8ShroundedKeyBag):
   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(oidPKCS8ShroundedKeyBag):
   250  			if privateKey != nil {
   251  				err = errors.New("pkcs12: expected exactly one key bag")
   252  			}
   253  
   254  			if privateKey, err = decodePkcs8ShroudedKeyBag(bag.Value.Bytes, encodedPassword); err != nil {
   255  				return nil, nil, err
   256  			}
   257  		}
   258  	}
   259  
   260  	if certificate == nil {
   261  		return nil, nil, errors.New("pkcs12: certificate missing")
   262  	}
   263  	if privateKey == nil {
   264  		return nil, nil, errors.New("pkcs12: private key missing")
   265  	}
   266  
   267  	return
   268  }
   269  
   270  func getSafeContents(p12Data, password []byte) (bags []safeBag, updatedPassword []byte, err error) {
   271  	pfx := new(pfxPdu)
   272  	if err := unmarshal(p12Data, pfx); err != nil {
   273  		return nil, nil, errors.New("pkcs12: error reading P12 data: " + err.Error())
   274  	}
   275  
   276  	if pfx.Version != 3 {
   277  		return nil, nil, NotImplementedError("can only decode v3 PFX PDU's")
   278  	}
   279  
   280  	if !pfx.AuthSafe.ContentType.Equal(oidDataContentType) {
   281  		return nil, nil, NotImplementedError("only password-protected PFX is implemented")
   282  	}
   283  
   284  	// unmarshal the explicit bytes in the content for type 'data'
   285  	if err := unmarshal(pfx.AuthSafe.Content.Bytes, &pfx.AuthSafe.Content); err != nil {
   286  		return nil, nil, err
   287  	}
   288  
   289  	if len(pfx.MacData.Mac.Algorithm.Algorithm) == 0 {
   290  		return nil, nil, errors.New("pkcs12: no MAC in data")
   291  	}
   292  
   293  	if err := verifyMac(&pfx.MacData, pfx.AuthSafe.Content.Bytes, password); err != nil {
   294  		if err == ErrIncorrectPassword && len(password) == 2 && password[0] == 0 && password[1] == 0 {
   295  			// some implementations use an empty byte array
   296  			// for the empty string password try one more
   297  			// time with empty-empty password
   298  			password = nil
   299  			err = verifyMac(&pfx.MacData, pfx.AuthSafe.Content.Bytes, password)
   300  		}
   301  		if err != nil {
   302  			return nil, nil, err
   303  		}
   304  	}
   305  
   306  	var authenticatedSafe []contentInfo
   307  	if err := unmarshal(pfx.AuthSafe.Content.Bytes, &authenticatedSafe); err != nil {
   308  		return nil, nil, err
   309  	}
   310  
   311  	if len(authenticatedSafe) != 2 {
   312  		return nil, nil, NotImplementedError("expected exactly two items in the authenticated safe")
   313  	}
   314  
   315  	for _, ci := range authenticatedSafe {
   316  		var data []byte
   317  
   318  		switch {
   319  		case ci.ContentType.Equal(oidDataContentType):
   320  			if err := unmarshal(ci.Content.Bytes, &data); err != nil {
   321  				return nil, nil, err
   322  			}
   323  		case ci.ContentType.Equal(oidEncryptedDataContentType):
   324  			var encryptedData encryptedData
   325  			if err := unmarshal(ci.Content.Bytes, &encryptedData); err != nil {
   326  				return nil, nil, err
   327  			}
   328  			if encryptedData.Version != 0 {
   329  				return nil, nil, NotImplementedError("only version 0 of EncryptedData is supported")
   330  			}
   331  			if data, err = pbDecrypt(encryptedData.EncryptedContentInfo, password); err != nil {
   332  				return nil, nil, err
   333  			}
   334  		default:
   335  			return nil, nil, NotImplementedError("only data and encryptedData content types are supported in authenticated safe")
   336  		}
   337  
   338  		var safeContents []safeBag
   339  		if err := unmarshal(data, &safeContents); err != nil {
   340  			return nil, nil, err
   341  		}
   342  		bags = append(bags, safeContents...)
   343  	}
   344  
   345  	return bags, password, nil
   346  }