summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/cloudflare/cfssl/helpers/derhelpers/ed25519.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/cloudflare/cfssl/helpers/derhelpers/ed25519.go')
-rw-r--r--vendor/github.com/cloudflare/cfssl/helpers/derhelpers/ed25519.go133
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
+}