Source file src/crypto/x509/pkcs8.go

     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 := new(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  

View as plain text