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

View as plain text