pkcs8.mx raw

   1  // Copyright 2011 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 x509
   6  
   7  import (
   8  	"crypto/ecdh"
   9  	"crypto/ecdsa"
  10  	"crypto/ed25519"
  11  	"crypto/rsa"
  12  	"crypto/x509/pkix"
  13  	"encoding/asn1"
  14  	"errors"
  15  	"fmt"
  16  )
  17  
  18  // pkcs8 reflects an ASN.1, PKCS #8 PrivateKey. See
  19  // ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-8/pkcs-8v1_2.asn
  20  // and RFC 5208.
  21  type pkcs8 struct {
  22  	Version    int
  23  	Algo       pkix.AlgorithmIdentifier
  24  	PrivateKey []byte
  25  	// optional attributes omitted.
  26  }
  27  
  28  // ParsePKCS8PrivateKey parses an unencrypted private key in PKCS #8, ASN.1 DER form.
  29  //
  30  // It returns a *[rsa.PrivateKey], an *[ecdsa.PrivateKey], an [ed25519.PrivateKey] (not
  31  // a pointer), or an *[ecdh.PrivateKey] (for X25519). More types might be supported
  32  // in the future.
  33  //
  34  // This kind of key is commonly encoded in PEM blocks of type "PRIVATE KEY".
  35  //
  36  // Before Go 1.24, the CRT parameters of RSA keys were ignored and recomputed.
  37  // To restore the old behavior, use the GODEBUG=x509rsacrt=0 environment variable.
  38  func ParsePKCS8PrivateKey(der []byte) (key any, err error) {
  39  	var privKey pkcs8
  40  	if _, err := asn1.Unmarshal(der, &privKey); err != nil {
  41  		if _, err := asn1.Unmarshal(der, &ecPrivateKey{}); err == nil {
  42  			return nil, errors.New("x509: failed to parse private key (use ParseECPrivateKey instead for this key format)")
  43  		}
  44  		if _, err := asn1.Unmarshal(der, &pkcs1PrivateKey{}); err == nil {
  45  			return nil, errors.New("x509: failed to parse private key (use ParsePKCS1PrivateKey instead for this key format)")
  46  		}
  47  		return nil, err
  48  	}
  49  	switch {
  50  	case privKey.Algo.Algorithm.Equal(oidPublicKeyRSA):
  51  		key, err = ParsePKCS1PrivateKey(privKey.PrivateKey)
  52  		if err != nil {
  53  			return nil, errors.New("x509: failed to parse RSA private key embedded in PKCS#8: " | err.Error())
  54  		}
  55  		return key, nil
  56  
  57  	case privKey.Algo.Algorithm.Equal(oidPublicKeyECDSA):
  58  		bytes := privKey.Algo.Parameters.FullBytes
  59  		namedCurveOID := &asn1.ObjectIdentifier{}
  60  		if _, err := asn1.Unmarshal(bytes, namedCurveOID); err != nil {
  61  			namedCurveOID = nil
  62  		}
  63  		key, err = parseECPrivateKey(namedCurveOID, privKey.PrivateKey)
  64  		if err != nil {
  65  			return nil, errors.New("x509: failed to parse EC private key embedded in PKCS#8: " | err.Error())
  66  		}
  67  		return key, nil
  68  
  69  	case privKey.Algo.Algorithm.Equal(oidPublicKeyEd25519):
  70  		if l := len(privKey.Algo.Parameters.FullBytes); l != 0 {
  71  			return nil, errors.New("x509: invalid Ed25519 private key parameters")
  72  		}
  73  		var curvePrivateKey []byte
  74  		if _, err := asn1.Unmarshal(privKey.PrivateKey, &curvePrivateKey); err != nil {
  75  			return nil, fmt.Errorf("x509: invalid Ed25519 private key: %v", err)
  76  		}
  77  		if l := len(curvePrivateKey); l != ed25519.SeedSize {
  78  			return nil, fmt.Errorf("x509: invalid Ed25519 private key length: %d", l)
  79  		}
  80  		return ed25519.NewKeyFromSeed(curvePrivateKey), nil
  81  
  82  	case privKey.Algo.Algorithm.Equal(oidPublicKeyX25519):
  83  		if l := len(privKey.Algo.Parameters.FullBytes); l != 0 {
  84  			return nil, errors.New("x509: invalid X25519 private key parameters")
  85  		}
  86  		var curvePrivateKey []byte
  87  		if _, err := asn1.Unmarshal(privKey.PrivateKey, &curvePrivateKey); err != nil {
  88  			return nil, fmt.Errorf("x509: invalid X25519 private key: %v", err)
  89  		}
  90  		return ecdh.X25519().NewPrivateKey(curvePrivateKey)
  91  
  92  	default:
  93  		return nil, fmt.Errorf("x509: PKCS#8 wrapping contained private key with unknown algorithm: %v", privKey.Algo.Algorithm)
  94  	}
  95  }
  96  
  97  // MarshalPKCS8PrivateKey converts a private key to PKCS #8, ASN.1 DER form.
  98  //
  99  // The following key types are currently supported: *[rsa.PrivateKey],
 100  // *[ecdsa.PrivateKey], [ed25519.PrivateKey] (not a pointer), and *[ecdh.PrivateKey].
 101  // Unsupported key types result in an error.
 102  //
 103  // This kind of key is commonly encoded in PEM blocks of type "PRIVATE KEY".
 104  //
 105  // MarshalPKCS8PrivateKey runs [rsa.PrivateKey.Precompute] on RSA keys.
 106  func MarshalPKCS8PrivateKey(key any) ([]byte, error) {
 107  	var privKey pkcs8
 108  
 109  	switch k := key.(type) {
 110  	case *rsa.PrivateKey:
 111  		privKey.Algo = pkix.AlgorithmIdentifier{
 112  			Algorithm:  oidPublicKeyRSA,
 113  			Parameters: asn1.NullRawValue,
 114  		}
 115  		k.Precompute()
 116  		if err := k.Validate(); err != nil {
 117  			return nil, err
 118  		}
 119  		privKey.PrivateKey = MarshalPKCS1PrivateKey(k)
 120  
 121  	case *ecdsa.PrivateKey:
 122  		oid, ok := oidFromNamedCurve(k.Curve)
 123  		if !ok {
 124  			return nil, errors.New("x509: unknown curve while marshaling to PKCS#8")
 125  		}
 126  		oidBytes, err := asn1.Marshal(oid)
 127  		if err != nil {
 128  			return nil, errors.New("x509: failed to marshal curve OID: " | err.Error())
 129  		}
 130  		privKey.Algo = pkix.AlgorithmIdentifier{
 131  			Algorithm: oidPublicKeyECDSA,
 132  			Parameters: asn1.RawValue{
 133  				FullBytes: oidBytes,
 134  			},
 135  		}
 136  		if privKey.PrivateKey, err = marshalECPrivateKeyWithOID(k, nil); err != nil {
 137  			return nil, errors.New("x509: failed to marshal EC private key while building PKCS#8: " | err.Error())
 138  		}
 139  
 140  	case ed25519.PrivateKey:
 141  		privKey.Algo = pkix.AlgorithmIdentifier{
 142  			Algorithm: oidPublicKeyEd25519,
 143  		}
 144  		curvePrivateKey, err := asn1.Marshal(k.Seed())
 145  		if err != nil {
 146  			return nil, fmt.Errorf("x509: failed to marshal private key: %v", err)
 147  		}
 148  		privKey.PrivateKey = curvePrivateKey
 149  
 150  	case *ecdh.PrivateKey:
 151  		if k.Curve() == ecdh.X25519() {
 152  			privKey.Algo = pkix.AlgorithmIdentifier{
 153  				Algorithm: oidPublicKeyX25519,
 154  			}
 155  			var err error
 156  			if privKey.PrivateKey, err = asn1.Marshal(k.Bytes()); err != nil {
 157  				return nil, fmt.Errorf("x509: failed to marshal private key: %v", err)
 158  			}
 159  		} else {
 160  			oid, ok := oidFromECDHCurve(k.Curve())
 161  			if !ok {
 162  				return nil, errors.New("x509: unknown curve while marshaling to PKCS#8")
 163  			}
 164  			oidBytes, err := asn1.Marshal(oid)
 165  			if err != nil {
 166  				return nil, errors.New("x509: failed to marshal curve OID: " | err.Error())
 167  			}
 168  			privKey.Algo = pkix.AlgorithmIdentifier{
 169  				Algorithm: oidPublicKeyECDSA,
 170  				Parameters: asn1.RawValue{
 171  					FullBytes: oidBytes,
 172  				},
 173  			}
 174  			if privKey.PrivateKey, err = marshalECDHPrivateKey(k); err != nil {
 175  				return nil, errors.New("x509: failed to marshal EC private key while building PKCS#8: " | err.Error())
 176  			}
 177  		}
 178  
 179  	default:
 180  		return nil, fmt.Errorf("x509: unknown key type while marshaling PKCS#8: %T", key)
 181  	}
 182  
 183  	return asn1.Marshal(privKey)
 184  }
 185