From 599ec7720fefdb60344bb4a9dab481ed302aa473 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Mon, 6 May 2019 14:06:47 -0400 Subject: [PATCH] crypto/x509: add support for Ed25519 certificates and keys Based on RFC 8410. Updates #25355 Change-Id: If7abb7eeb0ede10a9bb3d2004f2116e587c6207a Reviewed-on: https://go-review.googlesource.com/c/go/+/175478 Run-TryBot: Filippo Valsorda TryBot-Result: Gobot Gobot Reviewed-by: Adam Langley --- src/crypto/x509/pkcs8.go | 36 ++++++++-- src/crypto/x509/pkcs8_test.go | 9 +++ src/crypto/x509/x509.go | 130 ++++++++++++++++++++++++---------- src/crypto/x509/x509_test.go | 124 +++++++++++++++++++++++++++++--- src/go/build/deps_test.go | 2 +- 5 files changed, 246 insertions(+), 55 deletions(-) diff --git a/src/crypto/x509/pkcs8.go b/src/crypto/x509/pkcs8.go index fa8d408228..fa1847e5e7 100644 --- a/src/crypto/x509/pkcs8.go +++ b/src/crypto/x509/pkcs8.go @@ -6,6 +6,7 @@ package x509 import ( "crypto/ecdsa" + "crypto/ed25519" "crypto/rsa" "crypto/x509/pkix" "encoding/asn1" @@ -23,8 +24,9 @@ type pkcs8 struct { // optional attributes omitted. } -// ParsePKCS8PrivateKey parses an unencrypted, PKCS#8 private key. -// See RFC 5208. +// ParsePKCS8PrivateKey parses an unencrypted, PKCS#8 private key. It returns a +// *rsa.PrivateKey, a *ecdsa.PrivateKey, or a ed25519.PrivateKey. More types +// might be supported in future versions. See RFC 5208 and RFC 8410. func ParsePKCS8PrivateKey(der []byte) (key interface{}, err error) { var privKey pkcs8 if _, err := asn1.Unmarshal(der, &privKey); err != nil { @@ -56,16 +58,28 @@ func ParsePKCS8PrivateKey(der []byte) (key interface{}, 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 + default: return nil, fmt.Errorf("x509: PKCS#8 wrapping contained private key with unknown algorithm: %v", privKey.Algo.Algorithm) } } // MarshalPKCS8PrivateKey converts a private key to PKCS#8 encoded form. -// The following key types are supported: *rsa.PrivateKey, *ecdsa.PrivateKey. -// Unsupported key types result in an error. -// -// See RFC 5208. +// The following key types are currently supported: *rsa.PrivateKey, +// *ecdsa.PrivateKey and ed25519.PrivateKey. Unsupported key types result in an +// error. See RFC 5208 and RFC 8410. func MarshalPKCS8PrivateKey(key interface{}) ([]byte, error) { var privKey pkcs8 @@ -99,6 +113,16 @@ func MarshalPKCS8PrivateKey(key interface{}) ([]byte, error) { 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 + default: return nil, fmt.Errorf("x509: unknown key type while marshaling PKCS#8: %T", key) } diff --git a/src/crypto/x509/pkcs8_test.go b/src/crypto/x509/pkcs8_test.go index 9e890c386e..cb7ee4c162 100644 --- a/src/crypto/x509/pkcs8_test.go +++ b/src/crypto/x509/pkcs8_test.go @@ -7,6 +7,7 @@ package x509 import ( "bytes" "crypto/ecdsa" + "crypto/ed25519" "crypto/elliptic" "crypto/rsa" "encoding/hex" @@ -40,6 +41,9 @@ var pkcs8P384PrivateKeyHex = `3081b6020100301006072a8648ce3d020106052b8104002204 // expected and the Go test will fail to recreate it exactly. var pkcs8P521PrivateKeyHex = `3081ee020100301006072a8648ce3d020106052b810400230481d63081d3020101044200cfe0b87113a205cf291bb9a8cd1a74ac6c7b2ebb8199aaa9a5010d8b8012276fa3c22ac913369fa61beec2a3b8b4516bc049bde4fb3b745ac11b56ab23ac52e361a1818903818600040138f75acdd03fbafa4f047a8e4b272ba9d555c667962b76f6f232911a5786a0964e5edea6bd21a6f8725720958de049c6e3e6661c1c91b227cebee916c0319ed6ca003db0a3206d372229baf9dd25d868bf81140a518114803ce40c1855074d68c4e9dab9e65efba7064c703b400f1767f217dac82715ac1f6d88c74baf47a7971de4ea` +// From RFC 8410, Section 7. +var pkcs8Ed25519PrivateKeyHex = `302e020100300506032b657004220420d4ee72dbf913584ad5b6d8f1f769f8ad3afe7c28cbf1d4fbe097a88f44755842` + func TestPKCS8(t *testing.T) { tests := []struct { name string @@ -76,6 +80,11 @@ func TestPKCS8(t *testing.T) { keyType: reflect.TypeOf(&ecdsa.PrivateKey{}), curve: elliptic.P521(), }, + { + name: "Ed25519 private key", + keyHex: pkcs8Ed25519PrivateKeyHex, + keyType: reflect.TypeOf(ed25519.PrivateKey{}), + }, } for _, test := range tests { diff --git a/src/crypto/x509/x509.go b/src/crypto/x509/x509.go index 4aca7ca40b..16c0526196 100644 --- a/src/crypto/x509/x509.go +++ b/src/crypto/x509/x509.go @@ -14,6 +14,7 @@ import ( "crypto" "crypto/dsa" "crypto/ecdsa" + "crypto/ed25519" "crypto/elliptic" "crypto/rsa" _ "crypto/sha1" @@ -50,7 +51,7 @@ type pkixPublicKey struct { // types result in an error. // // On success, pub will be of type *rsa.PublicKey, *dsa.PublicKey, -// or *ecdsa.PublicKey. +// *ecdsa.PublicKey, or ed25519.PublicKey. func ParsePKIXPublicKey(derBytes []byte) (pub interface{}, err error) { var pki publicKeyInfo if rest, err := asn1.Unmarshal(derBytes, &pki); err != nil { @@ -95,6 +96,9 @@ func marshalPublicKey(pub interface{}) (publicKeyBytes []byte, publicKeyAlgorith return } publicKeyAlgorithm.Parameters.FullBytes = paramBytes + case ed25519.PublicKey: + publicKeyBytes = pub + publicKeyAlgorithm.Algorithm = oidPublicKeyEd25519 default: return nil, pkix.AlgorithmIdentifier{}, errors.New("x509: only RSA and ECDSA public keys supported") } @@ -191,6 +195,7 @@ const ( SHA256WithRSAPSS SHA384WithRSAPSS SHA512WithRSAPSS + PureEd25519 ) func (algo SignatureAlgorithm) isRSAPSS() bool { @@ -218,12 +223,14 @@ const ( RSA DSA ECDSA + Ed25519 ) var publicKeyAlgoName = [...]string{ - RSA: "RSA", - DSA: "DSA", - ECDSA: "ECDSA", + RSA: "RSA", + DSA: "DSA", + ECDSA: "ECDSA", + Ed25519: "Ed25519", } func (algo PublicKeyAlgorithm) String() string { @@ -282,6 +289,11 @@ func (algo PublicKeyAlgorithm) String() string { // // ecdsa-with-SHA512 OBJECT IDENTIFIER ::= { iso(1) member-body(2) // us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 4 } +// +// +// RFC 8410 3 Curve25519 and Curve448 Algorithm Identifiers +// +// id-Ed25519 OBJECT IDENTIFIER ::= { 1 3 101 112 } var ( oidSignatureMD2WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 2} @@ -297,6 +309,7 @@ var ( oidSignatureECDSAWithSHA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2} oidSignatureECDSAWithSHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3} oidSignatureECDSAWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4} + oidSignatureEd25519 = asn1.ObjectIdentifier{1, 3, 101, 112} oidSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 1} oidSHA384 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 2} @@ -333,6 +346,7 @@ var signatureAlgorithmDetails = []struct { {ECDSAWithSHA256, "ECDSA-SHA256", oidSignatureECDSAWithSHA256, ECDSA, crypto.SHA256}, {ECDSAWithSHA384, "ECDSA-SHA384", oidSignatureECDSAWithSHA384, ECDSA, crypto.SHA384}, {ECDSAWithSHA512, "ECDSA-SHA512", oidSignatureECDSAWithSHA512, ECDSA, crypto.SHA512}, + {PureEd25519, "Ed25519", oidSignatureEd25519, Ed25519, crypto.Hash(0) /* no pre-hashing */}, } // pssParameters reflects the parameters in an AlgorithmIdentifier that @@ -393,6 +407,14 @@ func rsaPSSParameters(hashFunc crypto.Hash) asn1.RawValue { } func getSignatureAlgorithmFromAI(ai pkix.AlgorithmIdentifier) SignatureAlgorithm { + if ai.Algorithm.Equal(oidSignatureEd25519) { + // RFC 8410, Section 3 + // > For all of the OIDs, the parameters MUST be absent. + if len(ai.Parameters.FullBytes) != 0 { + return UnknownSignatureAlgorithm + } + } + if !ai.Algorithm.Equal(oidSignatureRSAPSS) { for _, details := range signatureAlgorithmDetails { if ai.Algorithm.Equal(details.oid) { @@ -455,9 +477,10 @@ func getSignatureAlgorithmFromAI(ai pkix.AlgorithmIdentifier) SignatureAlgorithm // id-ecPublicKey OBJECT IDENTIFIER ::= { // iso(1) member-body(2) us(840) ansi-X9-62(10045) keyType(2) 1 } var ( - oidPublicKeyRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1} - oidPublicKeyDSA = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 1} - oidPublicKeyECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1} + oidPublicKeyRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1} + oidPublicKeyDSA = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 1} + oidPublicKeyECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1} + oidPublicKeyEd25519 = oidSignatureEd25519 ) func getPublicKeyAlgorithmFromOID(oid asn1.ObjectIdentifier) PublicKeyAlgorithm { @@ -468,6 +491,8 @@ func getPublicKeyAlgorithmFromOID(oid asn1.ObjectIdentifier) PublicKeyAlgorithm return DSA case oid.Equal(oidPublicKeyECDSA): return ECDSA + case oid.Equal(oidPublicKeyEd25519): + return Ed25519 } return UnknownPublicKeyAlgorithm } @@ -874,28 +899,29 @@ func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey switch hashType { case crypto.Hash(0): - return ErrUnsupportedAlgorithm + if pubKeyAlgo != Ed25519 { + return ErrUnsupportedAlgorithm + } case crypto.MD5: return InsecureAlgorithmError(algo) + default: + if !hashType.Available() { + return ErrUnsupportedAlgorithm + } + h := hashType.New() + h.Write(signed) + signed = h.Sum(nil) } - if !hashType.Available() { - return ErrUnsupportedAlgorithm - } - h := hashType.New() - - h.Write(signed) - digest := h.Sum(nil) - switch pub := publicKey.(type) { case *rsa.PublicKey: if pubKeyAlgo != RSA { return signaturePublicKeyAlgoMismatchError(pubKeyAlgo, pub) } if algo.isRSAPSS() { - return rsa.VerifyPSS(pub, hashType, digest, signature, &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash}) + return rsa.VerifyPSS(pub, hashType, signed, signature, &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash}) } else { - return rsa.VerifyPKCS1v15(pub, hashType, digest, signature) + return rsa.VerifyPKCS1v15(pub, hashType, signed, signature) } case *dsa.PublicKey: if pubKeyAlgo != DSA { @@ -910,7 +936,7 @@ func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey if dsaSig.R.Sign() <= 0 || dsaSig.S.Sign() <= 0 { return errors.New("x509: DSA signature contained zero or negative values") } - if !dsa.Verify(pub, digest, dsaSig.R, dsaSig.S) { + if !dsa.Verify(pub, signed, dsaSig.R, dsaSig.S) { return errors.New("x509: DSA verification failure") } return @@ -927,10 +953,18 @@ func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 { return errors.New("x509: ECDSA signature contained zero or negative values") } - if !ecdsa.Verify(pub, digest, ecdsaSig.R, ecdsaSig.S) { + if !ecdsa.Verify(pub, signed, ecdsaSig.R, ecdsaSig.S) { return errors.New("x509: ECDSA verification failure") } return + case ed25519.PublicKey: + if pubKeyAlgo != Ed25519 { + return signaturePublicKeyAlgoMismatchError(pubKeyAlgo, pub) + } + if !ed25519.Verify(pub, signed, signature) { + return errors.New("x509: Ed25519 verification failure") + } + return } return ErrUnsupportedAlgorithm } @@ -1068,6 +1102,18 @@ func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{ Y: y, } return pub, nil + case Ed25519: + // RFC 8410, Section 3 + // > For all of the OIDs, the parameters MUST be absent. + if len(keyData.Algorithm.Parameters.FullBytes) != 0 { + return nil, errors.New("x509: Ed25519 key encoded with illegal parameters") + } + if len(asn1Data) != ed25519.PublicKeySize { + return nil, errors.New("x509: wrong Ed25519 public key size") + } + pub := make([]byte, ed25519.PublicKeySize) + copy(pub, asn1Data) + return ed25519.PublicKey(pub), nil default: return nil, nil } @@ -1989,8 +2035,12 @@ func signingParamsForPublicKey(pub interface{}, requestedSigAlgo SignatureAlgori err = errors.New("x509: unknown elliptic curve") } + case ed25519.PublicKey: + pubType = Ed25519 + sigAlgo.Algorithm = oidSignatureEd25519 + default: - err = errors.New("x509: only RSA and ECDSA keys supported") + err = errors.New("x509: only RSA, ECDSA and Ed25519 keys supported") } if err != nil { @@ -2009,7 +2059,7 @@ func signingParamsForPublicKey(pub interface{}, requestedSigAlgo SignatureAlgori return } sigAlgo.Algorithm, hashFunc = details.oid, details.hash - if hashFunc == 0 { + if hashFunc == 0 && pubType != Ed25519 { err = errors.New("x509: cannot sign with hash function requested") return } @@ -2073,8 +2123,9 @@ var emptyASN1Subject = []byte{0x30, 0} // // The returned slice is the certificate in DER encoding. // -// All keys types that are implemented via crypto.Signer are supported (This -// includes *rsa.PublicKey and *ecdsa.PublicKey.) +// The currently supported key types are *rsa.PublicKey, *ecdsa.PublicKey and +// ed25519.PublicKey. pub must be a supported key type, and priv must be a +// crypto.Signer with a supported public key. // // The AuthorityKeyId will be taken from the SubjectKeyId of parent, if any, // unless the resulting certificate is self-signed. Otherwise the value from @@ -2135,15 +2186,16 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv if err != nil { return } - c.Raw = tbsCertContents - h := hashFunc.New() - h.Write(tbsCertContents) - digest := h.Sum(nil) + signed := tbsCertContents + if hashFunc != 0 { + h := hashFunc.New() + h.Write(signed) + signed = h.Sum(nil) + } - var signerOpts crypto.SignerOpts - signerOpts = hashFunc + var signerOpts crypto.SignerOpts = hashFunc if template.SignatureAlgorithm != 0 && template.SignatureAlgorithm.isRSAPSS() { signerOpts = &rsa.PSSOptions{ SaltLength: rsa.PSSSaltLengthEqualsHash, @@ -2152,7 +2204,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv } var signature []byte - signature, err = key.Sign(rand, digest, signerOpts) + signature, err = key.Sign(rand, signed, signerOpts) if err != nil { return } @@ -2403,8 +2455,9 @@ func parseCSRExtensions(rawAttributes []asn1.RawValue) ([]pkix.Extension, error) // // priv is the private key to sign the CSR with, and the corresponding public // key will be included in the CSR. It must implement crypto.Signer and its -// Public() method must return a *rsa.PublicKey or a *ecdsa.PublicKey. (A -// *rsa.PrivateKey or *ecdsa.PrivateKey satisfies this.) +// Public() method must return a *rsa.PublicKey or a *ecdsa.PublicKey or a +// ed25519.PublicKey. (A *rsa.PrivateKey, *ecdsa.PrivateKey or +// ed25519.PrivateKey satisfies this.) // // The returned slice is the certificate request in DER encoding. func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv interface{}) (csr []byte, err error) { @@ -2553,12 +2606,15 @@ func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv } tbsCSR.Raw = tbsCSRContents - h := hashFunc.New() - h.Write(tbsCSRContents) - digest := h.Sum(nil) + signed := tbsCSRContents + if hashFunc != 0 { + h := hashFunc.New() + h.Write(signed) + signed = h.Sum(nil) + } var signature []byte - signature, err = key.Sign(rand, digest, hashFunc) + signature, err = key.Sign(rand, signed, hashFunc) if err != nil { return } diff --git a/src/crypto/x509/x509_test.go b/src/crypto/x509/x509_test.go index f5851f1f11..7dadb77dfd 100644 --- a/src/crypto/x509/x509_test.go +++ b/src/crypto/x509/x509_test.go @@ -8,6 +8,7 @@ import ( "bytes" "crypto/dsa" "crypto/ecdsa" + "crypto/ed25519" "crypto/elliptic" "crypto/rand" "crypto/rsa" @@ -65,27 +66,39 @@ func TestPKCS1MismatchPublicKeyFormat(t *testing.T) { } } -func TestParsePKIXPublicKey(t *testing.T) { - block, _ := pem.Decode([]byte(pemPublicKey)) +func testParsePKIXPublicKey(t *testing.T, pemBytes string) (pub interface{}) { + block, _ := pem.Decode([]byte(pemBytes)) pub, err := ParsePKIXPublicKey(block.Bytes) if err != nil { - t.Errorf("Failed to parse RSA public key: %s", err) - return - } - rsaPub, ok := pub.(*rsa.PublicKey) - if !ok { - t.Errorf("Value returned from ParsePKIXPublicKey was not an RSA public key") - return + t.Fatalf("Failed to parse public key: %s", err) } - pubBytes2, err := MarshalPKIXPublicKey(rsaPub) + pubBytes2, err := MarshalPKIXPublicKey(pub) if err != nil { - t.Errorf("Failed to marshal RSA public key for the second time: %s", err) + t.Errorf("Failed to marshal public key for the second time: %s", err) return } if !bytes.Equal(pubBytes2, block.Bytes) { t.Errorf("Reserialization of public key didn't match. got %x, want %x", pubBytes2, block.Bytes) } + return +} + +func TestParsePKIXPublicKey(t *testing.T) { + t.Run("RSA", func(t *testing.T) { + pub := testParsePKIXPublicKey(t, pemPublicKey) + _, ok := pub.(*rsa.PublicKey) + if !ok { + t.Errorf("Value returned from ParsePKIXPublicKey was not an RSA public key") + } + }) + t.Run("Ed25519", func(t *testing.T) { + pub := testParsePKIXPublicKey(t, pemEd25519Key) + _, ok := pub.(ed25519.PublicKey) + if !ok { + t.Errorf("Value returned from ParsePKIXPublicKey was not an Ed25519 public key") + } + }) } var pemPublicKey = `-----BEGIN PUBLIC KEY----- @@ -117,6 +130,13 @@ wg/HcAJWY60xZTJDFN+Qfx8ZQvBEin6c2/h+zZi5IVY= -----END RSA PRIVATE KEY----- ` +// pemEd25519Key is the example from RFC 8410, Secrion 4. +var pemEd25519Key = ` +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEAGb9ECWmEzf6FQbrBZ9w7lshQhqowtrbLDFw4rXAxZuE= +-----END PUBLIC KEY----- +` + func TestPKIXMismatchPublicKeyFormat(t *testing.T) { const pkcs1PublicKey = "308201080282010100817cfed98bcaa2e2a57087451c7674e0c675686dc33ff1268b0c2a6ee0202dec710858ee1c31bdf5e7783582e8ca800be45f3275c6576adc35d98e26e95bb88ca5beb186f853b8745d88bc9102c5f38753bcda519fb05948d5c77ac429255ff8aaf27d9f45d1586e95e2e9ba8a7cb771b8a09dd8c8fed3f933fd9b439bc9f30c475953418ef25f71a2b6496f53d94d39ce850aa0cc75d445b5f5b4f4ee4db78ab197a9a8d8a852f44529a007ac0ac23d895928d60ba538b16b0b087a7f903ed29770e215019b77eaecc360f35f7ab11b6d735978795b2c4a74e5bdea4dc6594cd67ed752a108e666729a753ab36d6c4f606f8760f507e1765be8cd744007e629020103" @@ -518,6 +538,11 @@ func TestCreateSelfSignedCertificate(t *testing.T) { t.Fatalf("Failed to generate ECDSA key: %s", err) } + ed25519Pub, ed25519Priv, err := ed25519.GenerateKey(random) + if err != nil { + t.Fatalf("Failed to generate Ed25519 key: %s", err) + } + tests := []struct { name string pub, priv interface{} @@ -531,6 +556,7 @@ func TestCreateSelfSignedCertificate(t *testing.T) { {"RSAPSS/RSAPSS", &testPrivateKey.PublicKey, testPrivateKey, true, SHA256WithRSAPSS}, {"ECDSA/RSAPSS", &ecdsaPriv.PublicKey, testPrivateKey, false, SHA256WithRSAPSS}, {"RSAPSS/ECDSA", &testPrivateKey.PublicKey, ecdsaPriv, false, ECDSAWithSHA384}, + {"Ed25519", ed25519Pub, ed25519Priv, true, PureEd25519}, } testExtKeyUsage := []ExtKeyUsage{ExtKeyUsageClientAuth, ExtKeyUsageServerAuth} @@ -1017,6 +1043,76 @@ func TestRSAPSSSelfSigned(t *testing.T) { } } +const ed25519Certificate = ` +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 0c:83:d8:21:2b:82:cb:23:98:23:63:e2:f7:97:8a:43:5b:f3:bd:92 + Signature Algorithm: ED25519 + Issuer: CN = Ed25519 test certificate + Validity + Not Before: May 6 17:27:16 2019 GMT + Not After : Jun 5 17:27:16 2019 GMT + Subject: CN = Ed25519 test certificate + Subject Public Key Info: + Public Key Algorithm: ED25519 + ED25519 Public-Key: + pub: + 36:29:c5:6c:0d:4f:14:6c:81:d0:ff:75:d3:6a:70: + 5f:69:cd:0f:4d:66:d5:da:98:7e:82:49:89:a3:8a: + 3c:fa + X509v3 extensions: + X509v3 Subject Key Identifier: + 09:3B:3A:9D:4A:29:D8:95:FF:68:BE:7B:43:54:72:E0:AD:A2:E3:AE + X509v3 Authority Key Identifier: + keyid:09:3B:3A:9D:4A:29:D8:95:FF:68:BE:7B:43:54:72:E0:AD:A2:E3:AE + + X509v3 Basic Constraints: critical + CA:TRUE + Signature Algorithm: ED25519 + 53:a5:58:1c:2c:3b:2a:9e:ac:9d:4e:a5:1d:5f:5d:6d:a6:b5: + 08:de:12:82:f3:97:20:ae:fa:d8:98:f4:1a:83:32:6b:91:f5: + 24:1d:c4:20:7f:2c:e2:4d:da:13:3b:6d:54:1a:d2:a8:28:dc: + 60:b9:d4:f4:78:4b:3c:1c:91:00 +-----BEGIN CERTIFICATE----- +MIIBWzCCAQ2gAwIBAgIUDIPYISuCyyOYI2Pi95eKQ1vzvZIwBQYDK2VwMCMxITAf +BgNVBAMMGEVkMjU1MTkgdGVzdCBjZXJ0aWZpY2F0ZTAeFw0xOTA1MDYxNzI3MTZa +Fw0xOTA2MDUxNzI3MTZaMCMxITAfBgNVBAMMGEVkMjU1MTkgdGVzdCBjZXJ0aWZp +Y2F0ZTAqMAUGAytlcAMhADYpxWwNTxRsgdD/ddNqcF9pzQ9NZtXamH6CSYmjijz6 +o1MwUTAdBgNVHQ4EFgQUCTs6nUop2JX/aL57Q1Ry4K2i464wHwYDVR0jBBgwFoAU +CTs6nUop2JX/aL57Q1Ry4K2i464wDwYDVR0TAQH/BAUwAwEB/zAFBgMrZXADQQBT +pVgcLDsqnqydTqUdX11tprUI3hKC85cgrvrYmPQagzJrkfUkHcQgfyziTdoTO21U +GtKoKNxgudT0eEs8HJEA +-----END CERTIFICATE-----` + +func TestEd25519SelfSigned(t *testing.T) { + der, _ := pem.Decode([]byte(ed25519Certificate)) + if der == nil { + t.Fatalf("Failed to find PEM block") + } + + cert, err := ParseCertificate(der.Bytes) + if err != nil { + t.Fatalf("Failed to parse: %s", err) + } + + if cert.PublicKeyAlgorithm != Ed25519 { + t.Fatalf("Parsed key algorithm was not Ed25519") + } + parsedKey, ok := cert.PublicKey.(ed25519.PublicKey) + if !ok { + t.Fatalf("Parsed key was not an Ed25519 key: %s", err) + } + if len(parsedKey) != ed25519.PublicKeySize { + t.Fatalf("Invalid Ed25519 key") + } + + if err = cert.CheckSignatureFrom(cert); err != nil { + t.Fatalf("Signature check failed: %s", err) + } +} + const pemCertificate = `-----BEGIN CERTIFICATE----- MIIDATCCAemgAwIBAgIRAKQkkrFx1T/dgB/Go/xBM5swDQYJKoZIhvcNAQELBQAw EjEQMA4GA1UEChMHQWNtZSBDbzAeFw0xNjA4MTcyMDM2MDdaFw0xNzA4MTcyMDM2 @@ -1176,6 +1272,11 @@ func TestCreateCertificateRequest(t *testing.T) { t.Fatalf("Failed to generate ECDSA key: %s", err) } + _, ed25519Priv, err := ed25519.GenerateKey(random) + if err != nil { + t.Fatalf("Failed to generate Ed25519 key: %s", err) + } + tests := []struct { name string priv interface{} @@ -1185,6 +1286,7 @@ func TestCreateCertificateRequest(t *testing.T) { {"ECDSA-256", ecdsa256Priv, ECDSAWithSHA1}, {"ECDSA-384", ecdsa384Priv, ECDSAWithSHA1}, {"ECDSA-521", ecdsa521Priv, ECDSAWithSHA1}, + {"Ed25519", ed25519Priv, PureEd25519}, } for _, test := range tests { diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index 6d46ee82f0..c1010c1534 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -403,7 +403,7 @@ var pkgDeps = map[string][]string{ "container/list", "crypto/x509", "encoding/pem", "net", "syscall", }, "crypto/x509": { - "L4", "CRYPTO-MATH", "OS", "CGO", + "L4", "CRYPTO-MATH", "OS", "CGO", "crypto/ed25519", "crypto/x509/pkix", "encoding/pem", "encoding/hex", "net", "os/user", "syscall", "net/url", "golang.org/x/crypto/cryptobyte", "golang.org/x/crypto/cryptobyte/asn1", }, -- 2.50.0