diff options
Diffstat (limited to 'vendor/github.com/cloudflare/cfssl/helpers/derhelpers/ed25519.go')
-rw-r--r-- | vendor/github.com/cloudflare/cfssl/helpers/derhelpers/ed25519.go | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/vendor/github.com/cloudflare/cfssl/helpers/derhelpers/ed25519.go b/vendor/github.com/cloudflare/cfssl/helpers/derhelpers/ed25519.go new file mode 100644 index 0000000000..9220f3e5fa --- /dev/null +++ b/vendor/github.com/cloudflare/cfssl/helpers/derhelpers/ed25519.go @@ -0,0 +1,133 @@ +package derhelpers + +import ( + "crypto" + "crypto/x509/pkix" + "encoding/asn1" + "errors" + + "golang.org/x/crypto/ed25519" +) + +var errEd25519WrongID = errors.New("incorrect object identifier") +var errEd25519WrongKeyType = errors.New("incorrect key type") + +// ed25519OID is the OID for the Ed25519 signature scheme: see +// https://datatracker.ietf.org/doc/draft-ietf-curdle-pkix-04. +var ed25519OID = asn1.ObjectIdentifier{1, 3, 101, 112} + +// subjectPublicKeyInfo reflects the ASN.1 object defined in the X.509 standard. +// +// This is defined in crypto/x509 as "publicKeyInfo". +type subjectPublicKeyInfo struct { + Algorithm pkix.AlgorithmIdentifier + PublicKey asn1.BitString +} + +// MarshalEd25519PublicKey creates a DER-encoded SubjectPublicKeyInfo for an +// ed25519 public key, as defined in +// https://tools.ietf.org/html/draft-ietf-curdle-pkix-04. This is analagous to +// MarshalPKIXPublicKey in crypto/x509, which doesn't currently support Ed25519. +func MarshalEd25519PublicKey(pk crypto.PublicKey) ([]byte, error) { + pub, ok := pk.(ed25519.PublicKey) + if !ok { + return nil, errEd25519WrongKeyType + } + + spki := subjectPublicKeyInfo{ + Algorithm: pkix.AlgorithmIdentifier{ + Algorithm: ed25519OID, + }, + PublicKey: asn1.BitString{ + BitLength: len(pub) * 8, + Bytes: pub, + }, + } + + return asn1.Marshal(spki) +} + +// ParseEd25519PublicKey returns the Ed25519 public key encoded by the input. +func ParseEd25519PublicKey(der []byte) (crypto.PublicKey, error) { + var spki subjectPublicKeyInfo + if rest, err := asn1.Unmarshal(der, &spki); err != nil { + return nil, err + } else if len(rest) > 0 { + return nil, errors.New("SubjectPublicKeyInfo too long") + } + + if !spki.Algorithm.Algorithm.Equal(ed25519OID) { + return nil, errEd25519WrongID + } + + if spki.PublicKey.BitLength != ed25519.PublicKeySize*8 { + return nil, errors.New("SubjectPublicKeyInfo PublicKey length mismatch") + } + + return ed25519.PublicKey(spki.PublicKey.Bytes), nil +} + +// oneAsymmetricKey reflects the ASN.1 structure for storing private keys in +// https://tools.ietf.org/html/draft-ietf-curdle-pkix-04, excluding the optional +// fields, which we don't use here. +// +// This is identical to pkcs8 in crypto/x509. +type oneAsymmetricKey struct { + Version int + Algorithm pkix.AlgorithmIdentifier + PrivateKey []byte +} + +// curvePrivateKey is the innter type of the PrivateKey field of +// oneAsymmetricKey. +type curvePrivateKey []byte + +// MarshalEd25519PrivateKey returns a DER encdoing of the input private key as +// specified in https://tools.ietf.org/html/draft-ietf-curdle-pkix-04. +func MarshalEd25519PrivateKey(sk crypto.PrivateKey) ([]byte, error) { + priv, ok := sk.(ed25519.PrivateKey) + if !ok { + return nil, errEd25519WrongKeyType + } + + // Marshal the innter CurvePrivateKey. + curvePrivateKey, err := asn1.Marshal(priv.Seed()) + if err != nil { + return nil, err + } + + // Marshal the OneAsymmetricKey. + asym := oneAsymmetricKey{ + Version: 0, + Algorithm: pkix.AlgorithmIdentifier{ + Algorithm: ed25519OID, + }, + PrivateKey: curvePrivateKey, + } + return asn1.Marshal(asym) +} + +// ParseEd25519PrivateKey returns the Ed25519 private key encoded by the input. +func ParseEd25519PrivateKey(der []byte) (crypto.PrivateKey, error) { + asym := new(oneAsymmetricKey) + if rest, err := asn1.Unmarshal(der, asym); err != nil { + return nil, err + } else if len(rest) > 0 { + return nil, errors.New("OneAsymmetricKey too long") + } + + // Check that the key type is correct. + if !asym.Algorithm.Algorithm.Equal(ed25519OID) { + return nil, errEd25519WrongID + } + + // Unmarshal the inner CurvePrivateKey. + seed := new(curvePrivateKey) + if rest, err := asn1.Unmarshal(asym.PrivateKey, seed); err != nil { + return nil, err + } else if len(rest) > 0 { + return nil, errors.New("CurvePrivateKey too long") + } + + return ed25519.NewKeyFromSeed(*seed), nil +} |