package x509
import (
"crypto/ecdh"
"crypto/ecdsa"
"crypto/elliptic"
"encoding/asn1"
"errors"
"fmt"
"math/big"
)
const ecPrivKeyVersion = 1
type ecPrivateKey struct {
Version int
PrivateKey []byte
NamedCurveOID asn1 .ObjectIdentifier `asn1:"optional,explicit,tag:0"`
PublicKey asn1 .BitString `asn1:"optional,explicit,tag:1"`
}
func ParseECPrivateKey (der []byte ) (*ecdsa .PrivateKey , error ) {
return parseECPrivateKey (nil , der )
}
func MarshalECPrivateKey (key *ecdsa .PrivateKey ) ([]byte , error ) {
oid , ok := oidFromNamedCurve (key .Curve )
if !ok {
return nil , errors .New ("x509: unknown elliptic curve" )
}
return marshalECPrivateKeyWithOID (key , oid )
}
func marshalECPrivateKeyWithOID (key *ecdsa .PrivateKey , oid asn1 .ObjectIdentifier ) ([]byte , error ) {
if !key .Curve .IsOnCurve (key .X , key .Y ) {
return nil , errors .New ("invalid elliptic key public key" )
}
privateKey := make ([]byte , (key .Curve .Params ().N .BitLen ()+7 )/8 )
return asn1 .Marshal (ecPrivateKey {
Version : 1 ,
PrivateKey : key .D .FillBytes (privateKey ),
NamedCurveOID : oid ,
PublicKey : asn1 .BitString {Bytes : elliptic .Marshal (key .Curve , key .X , key .Y )},
})
}
func marshalECDHPrivateKey (key *ecdh .PrivateKey ) ([]byte , error ) {
return asn1 .Marshal (ecPrivateKey {
Version : 1 ,
PrivateKey : key .Bytes (),
PublicKey : asn1 .BitString {Bytes : key .PublicKey ().Bytes ()},
})
}
func parseECPrivateKey (namedCurveOID *asn1 .ObjectIdentifier , der []byte ) (key *ecdsa .PrivateKey , err error ) {
var privKey ecPrivateKey
if _ , err := asn1 .Unmarshal (der , &privKey ); err != nil {
if _ , err := asn1 .Unmarshal (der , &pkcs8 {}); err == nil {
return nil , errors .New ("x509: failed to parse private key (use ParsePKCS8PrivateKey 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 , errors .New ("x509: failed to parse EC private key: " + err .Error())
}
if privKey .Version != ecPrivKeyVersion {
return nil , fmt .Errorf ("x509: unknown EC private key version %d" , privKey .Version )
}
var curve elliptic .Curve
if namedCurveOID != nil {
curve = namedCurveFromOID (*namedCurveOID )
} else {
curve = namedCurveFromOID (privKey .NamedCurveOID )
}
if curve == nil {
return nil , errors .New ("x509: unknown elliptic curve" )
}
k := new (big .Int ).SetBytes (privKey .PrivateKey )
curveOrder := curve .Params ().N
if k .Cmp (curveOrder ) >= 0 {
return nil , errors .New ("x509: invalid elliptic curve private key value" )
}
priv := new (ecdsa .PrivateKey )
priv .Curve = curve
priv .D = k
privateKey := make ([]byte , (curveOrder .BitLen ()+7 )/8 )
for len (privKey .PrivateKey ) > len (privateKey ) {
if privKey .PrivateKey [0 ] != 0 {
return nil , errors .New ("x509: invalid private key length" )
}
privKey .PrivateKey = privKey .PrivateKey [1 :]
}
copy (privateKey [len (privateKey )-len (privKey .PrivateKey ):], privKey .PrivateKey )
priv .X , priv .Y = curve .ScalarBaseMult (privateKey )
return priv , nil
}
The pages are generated with Golds v0.6.7 . (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 @Go100and1 (reachable from the left QR code) to get the latest news of Golds .