github.com/zmap/zcrypto@v0.0.0-20240512203510-0fef58d9a9db/x509/sec1.go (about) 1 // Copyright 2012 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/ecdsa" 9 "crypto/elliptic" 10 "errors" 11 "fmt" 12 "math/big" 13 14 "github.com/zmap/zcrypto/encoding/asn1" 15 ) 16 17 const ecPrivKeyVersion = 1 18 19 // ecPrivateKey reflects an ASN.1 Elliptic Curve Private Key Structure. 20 // References: 21 // 22 // RFC 5915 23 // SEC1 - http://www.secg.org/sec1-v2.pdf 24 // 25 // Per RFC 5915 the NamedCurveOID is marked as ASN.1 OPTIONAL, however in 26 // most cases it is not. 27 type ecPrivateKey struct { 28 Version int 29 PrivateKey []byte 30 NamedCurveOID asn1.ObjectIdentifier `asn1:"optional,explicit,tag:0"` 31 PublicKey asn1.BitString `asn1:"optional,explicit,tag:1"` 32 } 33 34 // ParseECPrivateKey parses an ASN.1 Elliptic Curve Private Key Structure. 35 func ParseECPrivateKey(der []byte) (*ecdsa.PrivateKey, error) { 36 return parseECPrivateKey(nil, der) 37 } 38 39 // MarshalECPrivateKey marshals an EC private key into ASN.1, DER format. 40 func MarshalECPrivateKey(key *ecdsa.PrivateKey) ([]byte, error) { 41 oid, ok := oidFromNamedCurve(key.Curve) 42 if !ok { 43 return nil, errors.New("x509: unknown elliptic curve") 44 } 45 46 privateKeyBytes := key.D.Bytes() 47 paddedPrivateKey := make([]byte, (key.Curve.Params().N.BitLen()+7)/8) 48 copy(paddedPrivateKey[len(paddedPrivateKey)-len(privateKeyBytes):], privateKeyBytes) 49 50 return asn1.Marshal(ecPrivateKey{ 51 Version: 1, 52 PrivateKey: paddedPrivateKey, 53 NamedCurveOID: oid, 54 PublicKey: asn1.BitString{Bytes: elliptic.Marshal(key.Curve, key.X, key.Y)}, 55 }) 56 } 57 58 // parseECPrivateKey parses an ASN.1 Elliptic Curve Private Key Structure. 59 // The OID for the named curve may be provided from another source (such as 60 // the PKCS8 container) - if it is provided then use this instead of the OID 61 // that may exist in the EC private key structure. 62 func parseECPrivateKey(namedCurveOID *asn1.ObjectIdentifier, der []byte) (key *ecdsa.PrivateKey, err error) { 63 var privKey ecPrivateKey 64 if _, err := asn1.Unmarshal(der, &privKey); err != nil { 65 return nil, errors.New("x509: failed to parse EC private key: " + err.Error()) 66 } 67 if privKey.Version != ecPrivKeyVersion { 68 return nil, fmt.Errorf("x509: unknown EC private key version %d", privKey.Version) 69 } 70 71 var curve elliptic.Curve 72 if namedCurveOID != nil { 73 curve = namedCurveFromOID(*namedCurveOID) 74 } else { 75 curve = namedCurveFromOID(privKey.NamedCurveOID) 76 } 77 if curve == nil { 78 return nil, errors.New("x509: unknown elliptic curve") 79 } 80 81 k := new(big.Int).SetBytes(privKey.PrivateKey) 82 curveOrder := curve.Params().N 83 if k.Cmp(curveOrder) >= 0 { 84 return nil, errors.New("x509: invalid elliptic curve private key value") 85 } 86 priv := new(ecdsa.PrivateKey) 87 priv.Curve = curve 88 priv.D = k 89 90 privateKey := make([]byte, (curveOrder.BitLen()+7)/8) 91 92 // Some private keys have leading zero padding. This is invalid 93 // according to [SEC1], but this code will ignore it. 94 for len(privKey.PrivateKey) > len(privateKey) { 95 if privKey.PrivateKey[0] != 0 { 96 return nil, errors.New("x509: invalid private key length") 97 } 98 privKey.PrivateKey = privKey.PrivateKey[1:] 99 } 100 101 // Some private keys remove all leading zeros, this is also invalid 102 // according to [SEC1] but since OpenSSL used to do this, we ignore 103 // this too. 104 copy(privateKey[len(privateKey)-len(privKey.PrivateKey):], privKey.PrivateKey) 105 priv.X, priv.Y = curve.ScalarBaseMult(privateKey) 106 107 return priv, nil 108 }