package x509
import (
"crypto/ecdh"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/rsa"
"crypto/x509/pkix"
"encoding/asn1"
"errors"
"fmt"
)
type pkcs8 struct {
Version int
Algo pkix .AlgorithmIdentifier
PrivateKey []byte
}
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 )
}
}
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 ,
}
k .Precompute ()
if err := k .Validate (); err != nil {
return nil , err
}
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 )
}
The pages are generated with Golds v0.7.3-preview . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .