diff options
Diffstat (limited to 'src/crypto/x509/pkcs8.go')
-rw-r--r-- | src/crypto/x509/pkcs8.go | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/src/crypto/x509/pkcs8.go b/src/crypto/x509/pkcs8.go new file mode 100644 index 0000000..2d085e0 --- /dev/null +++ b/src/crypto/x509/pkcs8.go @@ -0,0 +1,175 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package x509 + +import ( + "crypto/ecdh" + "crypto/ecdsa" + "crypto/ed25519" + "crypto/rsa" + "crypto/x509/pkix" + "encoding/asn1" + "errors" + "fmt" +) + +// pkcs8 reflects an ASN.1, PKCS #8 PrivateKey. See +// ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-8/pkcs-8v1_2.asn +// and RFC 5208. +type pkcs8 struct { + Version int + Algo pkix.AlgorithmIdentifier + PrivateKey []byte + // optional attributes omitted. +} + +// ParsePKCS8PrivateKey parses an unencrypted private key in PKCS #8, ASN.1 DER form. +// +// It returns a *rsa.PrivateKey, a *ecdsa.PrivateKey, a ed25519.PrivateKey (not +// a pointer), or a *ecdh.PrivateKey (for X25519). More types might be supported +// in the future. +// +// This kind of key is commonly encoded in PEM blocks of type "PRIVATE KEY". +func ParsePKCS8PrivateKey(der []byte) (key any, err error) { + var privKey pkcs8 + if _, err := asn1.Unmarshal(der, &privKey); err != nil { + if _, err := asn1.Unmarshal(der, &ecPrivateKey{}); err == nil { + return nil, errors.New("x509: failed to parse private key (use ParseECPrivateKey instead for this key format)") + } + if _, err := asn1.Unmarshal(der, &pkcs1PrivateKey{}); err == nil { + return nil, errors.New("x509: failed to parse private key (use ParsePKCS1PrivateKey instead for this key format)") + } + return nil, err + } + switch { + case privKey.Algo.Algorithm.Equal(oidPublicKeyRSA): + key, err = ParsePKCS1PrivateKey(privKey.PrivateKey) + if err != nil { + return nil, errors.New("x509: failed to parse RSA private key embedded in PKCS#8: " + err.Error()) + } + return key, nil + + case privKey.Algo.Algorithm.Equal(oidPublicKeyECDSA): + bytes := privKey.Algo.Parameters.FullBytes + namedCurveOID := new(asn1.ObjectIdentifier) + if _, err := asn1.Unmarshal(bytes, namedCurveOID); err != nil { + namedCurveOID = nil + } + key, err = parseECPrivateKey(namedCurveOID, privKey.PrivateKey) + if err != nil { + return nil, errors.New("x509: failed to parse EC private key embedded in PKCS#8: " + err.Error()) + } + return key, nil + + case privKey.Algo.Algorithm.Equal(oidPublicKeyEd25519): + if l := len(privKey.Algo.Parameters.FullBytes); l != 0 { + return nil, errors.New("x509: invalid Ed25519 private key parameters") + } + var curvePrivateKey []byte + if _, err := asn1.Unmarshal(privKey.PrivateKey, &curvePrivateKey); err != nil { + return nil, fmt.Errorf("x509: invalid Ed25519 private key: %v", err) + } + if l := len(curvePrivateKey); l != ed25519.SeedSize { + return nil, fmt.Errorf("x509: invalid Ed25519 private key length: %d", l) + } + return ed25519.NewKeyFromSeed(curvePrivateKey), nil + + case privKey.Algo.Algorithm.Equal(oidPublicKeyX25519): + if l := len(privKey.Algo.Parameters.FullBytes); l != 0 { + return nil, errors.New("x509: invalid X25519 private key parameters") + } + var curvePrivateKey []byte + if _, err := asn1.Unmarshal(privKey.PrivateKey, &curvePrivateKey); err != nil { + return nil, fmt.Errorf("x509: invalid X25519 private key: %v", err) + } + return ecdh.X25519().NewPrivateKey(curvePrivateKey) + + default: + return nil, fmt.Errorf("x509: PKCS#8 wrapping contained private key with unknown algorithm: %v", privKey.Algo.Algorithm) + } +} + +// MarshalPKCS8PrivateKey converts a private key to PKCS #8, ASN.1 DER form. +// +// The following key types are currently supported: *rsa.PrivateKey, +// *ecdsa.PrivateKey, ed25519.PrivateKey (not a pointer), and *ecdh.PrivateKey. +// Unsupported key types result in an error. +// +// This kind of key is commonly encoded in PEM blocks of type "PRIVATE KEY". +func MarshalPKCS8PrivateKey(key any) ([]byte, error) { + var privKey pkcs8 + + switch k := key.(type) { + case *rsa.PrivateKey: + privKey.Algo = pkix.AlgorithmIdentifier{ + Algorithm: oidPublicKeyRSA, + Parameters: asn1.NullRawValue, + } + privKey.PrivateKey = MarshalPKCS1PrivateKey(k) + + case *ecdsa.PrivateKey: + oid, ok := oidFromNamedCurve(k.Curve) + if !ok { + return nil, errors.New("x509: unknown curve while marshaling to PKCS#8") + } + oidBytes, err := asn1.Marshal(oid) + if err != nil { + return nil, errors.New("x509: failed to marshal curve OID: " + err.Error()) + } + privKey.Algo = pkix.AlgorithmIdentifier{ + Algorithm: oidPublicKeyECDSA, + Parameters: asn1.RawValue{ + FullBytes: oidBytes, + }, + } + if privKey.PrivateKey, err = marshalECPrivateKeyWithOID(k, nil); err != nil { + return nil, errors.New("x509: failed to marshal EC private key while building PKCS#8: " + err.Error()) + } + + case ed25519.PrivateKey: + privKey.Algo = pkix.AlgorithmIdentifier{ + Algorithm: oidPublicKeyEd25519, + } + curvePrivateKey, err := asn1.Marshal(k.Seed()) + if err != nil { + return nil, fmt.Errorf("x509: failed to marshal private key: %v", err) + } + privKey.PrivateKey = curvePrivateKey + + case *ecdh.PrivateKey: + if k.Curve() == ecdh.X25519() { + privKey.Algo = pkix.AlgorithmIdentifier{ + Algorithm: oidPublicKeyX25519, + } + var err error + if privKey.PrivateKey, err = asn1.Marshal(k.Bytes()); err != nil { + return nil, fmt.Errorf("x509: failed to marshal private key: %v", err) + } + } else { + oid, ok := oidFromECDHCurve(k.Curve()) + if !ok { + return nil, errors.New("x509: unknown curve while marshaling to PKCS#8") + } + oidBytes, err := asn1.Marshal(oid) + if err != nil { + return nil, errors.New("x509: failed to marshal curve OID: " + err.Error()) + } + privKey.Algo = pkix.AlgorithmIdentifier{ + Algorithm: oidPublicKeyECDSA, + Parameters: asn1.RawValue{ + FullBytes: oidBytes, + }, + } + if privKey.PrivateKey, err = marshalECDHPrivateKey(k); err != nil { + return nil, errors.New("x509: failed to marshal EC private key while building PKCS#8: " + err.Error()) + } + } + + default: + return nil, fmt.Errorf("x509: unknown key type while marshaling PKCS#8: %T", key) + } + + return asn1.Marshal(privKey) +} |