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
5package x509
6
7import (
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.
21type 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".
35func ParsePKCS8PrivateKey(der []byte) (key any, err error) {
36	var privKey pkcs8
37	if _, err := asn1.Unmarshal(der, &privKey); err != nil {
38		if _, err := asn1.Unmarshal(der, &ecPrivateKey{}); err == nil {
39			return nil, errors.New("x509: failed to parse private key (use ParseECPrivateKey instead for this key format)")
40		}
41		if _, err := asn1.Unmarshal(der, &pkcs1PrivateKey{}); err == nil {
42			return nil, errors.New("x509: failed to parse private key (use ParsePKCS1PrivateKey instead for this key format)")
43		}
44		return nil, err
45	}
46	switch {
47	case privKey.Algo.Algorithm.Equal(oidPublicKeyRSA):
48		key, err = ParsePKCS1PrivateKey(privKey.PrivateKey)
49		if err != nil {
50			return nil, errors.New("x509: failed to parse RSA private key embedded in PKCS#8: " + err.Error())
51		}
52		return key, nil
53
54	case privKey.Algo.Algorithm.Equal(oidPublicKeyECDSA):
55		bytes := privKey.Algo.Parameters.FullBytes
56		namedCurveOID := new(asn1.ObjectIdentifier)
57		if _, err := asn1.Unmarshal(bytes, namedCurveOID); err != nil {
58			namedCurveOID = nil
59		}
60		key, err = parseECPrivateKey(namedCurveOID, privKey.PrivateKey)
61		if err != nil {
62			return nil, errors.New("x509: failed to parse EC private key embedded in PKCS#8: " + err.Error())
63		}
64		return key, nil
65
66	case privKey.Algo.Algorithm.Equal(oidPublicKeyEd25519):
67		if l := len(privKey.Algo.Parameters.FullBytes); l != 0 {
68			return nil, errors.New("x509: invalid Ed25519 private key parameters")
69		}
70		var curvePrivateKey []byte
71		if _, err := asn1.Unmarshal(privKey.PrivateKey, &curvePrivateKey); err != nil {
72			return nil, fmt.Errorf("x509: invalid Ed25519 private key: %v", err)
73		}
74		if l := len(curvePrivateKey); l != ed25519.SeedSize {
75			return nil, fmt.Errorf("x509: invalid Ed25519 private key length: %d", l)
76		}
77		return ed25519.NewKeyFromSeed(curvePrivateKey), nil
78
79	case privKey.Algo.Algorithm.Equal(oidPublicKeyX25519):
80		if l := len(privKey.Algo.Parameters.FullBytes); l != 0 {
81			return nil, errors.New("x509: invalid X25519 private key parameters")
82		}
83		var curvePrivateKey []byte
84		if _, err := asn1.Unmarshal(privKey.PrivateKey, &curvePrivateKey); err != nil {
85			return nil, fmt.Errorf("x509: invalid X25519 private key: %v", err)
86		}
87		return ecdh.X25519().NewPrivateKey(curvePrivateKey)
88
89	default:
90		return nil, fmt.Errorf("x509: PKCS#8 wrapping contained private key with unknown algorithm: %v", privKey.Algo.Algorithm)
91	}
92}
93
94// MarshalPKCS8PrivateKey converts a private key to PKCS #8, ASN.1 DER form.
95//
96// The following key types are currently supported: *[rsa.PrivateKey],
97// *[ecdsa.PrivateKey], [ed25519.PrivateKey] (not a pointer), and *[ecdh.PrivateKey].
98// Unsupported key types result in an error.
99//
100// This kind of key is commonly encoded in PEM blocks of type "PRIVATE KEY".
101func MarshalPKCS8PrivateKey(key any) ([]byte, error) {
102	var privKey pkcs8
103
104	switch k := key.(type) {
105	case *rsa.PrivateKey:
106		privKey.Algo = pkix.AlgorithmIdentifier{
107			Algorithm:  oidPublicKeyRSA,
108			Parameters: asn1.NullRawValue,
109		}
110		privKey.PrivateKey = MarshalPKCS1PrivateKey(k)
111
112	case *ecdsa.PrivateKey:
113		oid, ok := oidFromNamedCurve(k.Curve)
114		if !ok {
115			return nil, errors.New("x509: unknown curve while marshaling to PKCS#8")
116		}
117		oidBytes, err := asn1.Marshal(oid)
118		if err != nil {
119			return nil, errors.New("x509: failed to marshal curve OID: " + err.Error())
120		}
121		privKey.Algo = pkix.AlgorithmIdentifier{
122			Algorithm: oidPublicKeyECDSA,
123			Parameters: asn1.RawValue{
124				FullBytes: oidBytes,
125			},
126		}
127		if privKey.PrivateKey, err = marshalECPrivateKeyWithOID(k, nil); err != nil {
128			return nil, errors.New("x509: failed to marshal EC private key while building PKCS#8: " + err.Error())
129		}
130
131	case ed25519.PrivateKey:
132		privKey.Algo = pkix.AlgorithmIdentifier{
133			Algorithm: oidPublicKeyEd25519,
134		}
135		curvePrivateKey, err := asn1.Marshal(k.Seed())
136		if err != nil {
137			return nil, fmt.Errorf("x509: failed to marshal private key: %v", err)
138		}
139		privKey.PrivateKey = curvePrivateKey
140
141	case *ecdh.PrivateKey:
142		if k.Curve() == ecdh.X25519() {
143			privKey.Algo = pkix.AlgorithmIdentifier{
144				Algorithm: oidPublicKeyX25519,
145			}
146			var err error
147			if privKey.PrivateKey, err = asn1.Marshal(k.Bytes()); err != nil {
148				return nil, fmt.Errorf("x509: failed to marshal private key: %v", err)
149			}
150		} else {
151			oid, ok := oidFromECDHCurve(k.Curve())
152			if !ok {
153				return nil, errors.New("x509: unknown curve while marshaling to PKCS#8")
154			}
155			oidBytes, err := asn1.Marshal(oid)
156			if err != nil {
157				return nil, errors.New("x509: failed to marshal curve OID: " + err.Error())
158			}
159			privKey.Algo = pkix.AlgorithmIdentifier{
160				Algorithm: oidPublicKeyECDSA,
161				Parameters: asn1.RawValue{
162					FullBytes: oidBytes,
163				},
164			}
165			if privKey.PrivateKey, err = marshalECDHPrivateKey(k); err != nil {
166				return nil, errors.New("x509: failed to marshal EC private key while building PKCS#8: " + err.Error())
167			}
168		}
169
170	default:
171		return nil, fmt.Errorf("x509: unknown key type while marshaling PKCS#8: %T", key)
172	}
173
174	return asn1.Marshal(privKey)
175}
176