From 613d30bcae2734ea802701f34bcee36a45198a16 Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Tue, 30 May 2017 16:04:24 +1000 Subject: [PATCH] ED25519 TLS support --- certs/ed25519/ca-ed25519-key.der | Bin 0 -> 84 bytes certs/ed25519/ca-ed25519-key.pem | 4 + certs/ed25519/ca-ed25519.der | Bin 0 -> 605 bytes certs/ed25519/ca-ed25519.pem | 15 + certs/ed25519/client-ed25519-key.der | Bin 0 -> 84 bytes certs/ed25519/client-ed25519-key.pem | 4 + certs/ed25519/client-ed25519.der | Bin 0 -> 597 bytes certs/ed25519/client-ed25519.pem | 15 + certs/ed25519/root-ed25519-key.der | Bin 0 -> 84 bytes certs/ed25519/root-ed25519-key.pem | 4 + certs/ed25519/root-ed25519.der | Bin 0 -> 607 bytes certs/ed25519/root-ed25519.pem | 15 + certs/ed25519/server-ed25519-key.der | Bin 0 -> 84 bytes certs/ed25519/server-ed25519-key.pem | 4 + certs/ed25519/server-ed25519.der | Bin 0 -> 591 bytes certs/ed25519/server-ed25519.pem | 30 ++ src/internal.c | 546 +++++++++++++++++++++++---- src/ssl.c | 179 ++++++++- src/tls.c | 112 +++--- src/tls13.c | 91 ++++- tests/suites.c | 10 + tests/test-ed25519.conf | 56 +++ tests/test-tls13.conf | 12 + tests/test.conf | 12 + wolfcrypt/src/asn.c | 15 +- wolfssl/internal.h | 40 +- wolfssl/ssl.h | 21 ++ wolfssl/test.h | 59 ++- wolfssl/wolfcrypt/asn.h | 1 + 29 files changed, 1091 insertions(+), 154 deletions(-) create mode 100644 certs/ed25519/ca-ed25519-key.der create mode 100644 certs/ed25519/ca-ed25519-key.pem create mode 100644 certs/ed25519/ca-ed25519.der create mode 100644 certs/ed25519/ca-ed25519.pem create mode 100644 certs/ed25519/client-ed25519-key.der create mode 100644 certs/ed25519/client-ed25519-key.pem create mode 100644 certs/ed25519/client-ed25519.der create mode 100644 certs/ed25519/client-ed25519.pem create mode 100644 certs/ed25519/root-ed25519-key.der create mode 100644 certs/ed25519/root-ed25519-key.pem create mode 100644 certs/ed25519/root-ed25519.der create mode 100644 certs/ed25519/root-ed25519.pem create mode 100644 certs/ed25519/server-ed25519-key.der create mode 100644 certs/ed25519/server-ed25519-key.pem create mode 100644 certs/ed25519/server-ed25519.der create mode 100644 certs/ed25519/server-ed25519.pem create mode 100644 tests/test-ed25519.conf diff --git a/certs/ed25519/ca-ed25519-key.der b/certs/ed25519/ca-ed25519-key.der new file mode 100644 index 0000000000000000000000000000000000000000..01156fec2949fb7c50ca359e52a69a5386fd10bf GIT binary patch literal 84 zcmXpAVq#=4U}a<0PAy qU8uyO;K=@_lqaJ|$cCkfJx?s(!7+D9KgXv>bC)|GQqh=Ew*~;`5+F7J literal 0 HcmV?d00001 diff --git a/certs/ed25519/ca-ed25519-key.pem b/certs/ed25519/ca-ed25519-key.pem new file mode 100644 index 000000000..a78c396f7 --- /dev/null +++ b/certs/ed25519/ca-ed25519-key.pem @@ -0,0 +1,4 @@ +-----BEGIN RSA PRIVATE KEY----- +MFICAQAwBQYDK2VwBCIEIE3EyZVR/gbofvUgIsCeuA3yZ9E7DbTQxW7HMDYQhbxl +oSIEIEEH7HUMaHISPASCB24Wb0BBbaSPCPLinadDwiQomH6s +-----END RSA PRIVATE KEY----- diff --git a/certs/ed25519/ca-ed25519.der b/certs/ed25519/ca-ed25519.der new file mode 100644 index 0000000000000000000000000000000000000000..fd6f31d1d8517b5f991fd05ce1de26065becfb5a GIT binary patch literal 605 zcmXqLVv00qV&Y!F%*4pV#KHLOq1~R!g{=mxY|PrJ1qO}t4Y>_C*_cCF*o2uvgAD}? z_&^*E9(LdSypqJcM3@LW54%%-RcdZxo*}ORH%JW&4@*#fehEwg7Y}=Reok6&un$ax zn}^-i#mLmu(9%%CKn$dXnTNl;yj%~YuDCcyFF8NgP~Je6jZ>@5qwPB{BPXMnKxSTA zz5|j110@N5BLhQo15+alBV!{oBg-hTfTe+{ktI~Xpm8qgzJPk0g@?)65$0lA`9TXB z+{}s$j_hwrc`}NGY*?Du^ThHU9CMfSb9{OCDd1;h{LjM5%*1$%0p=J-1|?}W@dJV-@+lV=f2(F=km3&L zd%ZDvlIyNJj}B&tDD&j$Otsl4BdI_C*_cCF*o2uvgAD}? z_&^*E9(LdSypqJcM3@LW54%%-RcdZxo*};hFGvjw4_k6hW@=suObHhcdwG6NT5zxr zOoW?<-POg&)YQ<@P{KeAq=}h_zr4I$52UWRI7crzKi5#+K$eYDtIebBJ1-+AqnJQu zURu5bk^%!I34S93LvsUDBMT#ABQqn*D6oK~fvJ%tRA5N>Lkk+{%!&+Vwt@4u9G;l4 z!HRQ7d(=`^{^;PRDdKhoJ9*QDmOT9!xH#A#&_I@rIaHR9MT|vc+4O?RF`1LKry0q$ zSDWpcJWDhDqk%j~TA4+{K&%0~0)CJJen!UsEUe5-YzG)%);lsxSzLDe;p}hwtWCcC zd}P(7z|eSbnw_rYEm`&7S8EjmC4X5OnjN)VCpd%q=4AV6_wxiNNOMd-QZwlwZ}qv` H>J0nmFdR`2M;#+keMb0T<;rR&FPUy-|z%OB2gLrXp&%V|&S(;bqjo9?Tu4*&p@dmqLC literal 0 HcmV?d00001 diff --git a/certs/ed25519/root-ed25519-key.pem b/certs/ed25519/root-ed25519-key.pem new file mode 100644 index 000000000..be922d961 --- /dev/null +++ b/certs/ed25519/root-ed25519-key.pem @@ -0,0 +1,4 @@ +-----BEGIN RSA PRIVATE KEY----- +MFICAQAwBQYDK2VwBCIEIFwOftlJ9QL4yEBIBh9UmTRwCu+A6puPK9OFmVk0A19P +oSIEIKZgKbt92EfL1B7QbQ9XANgqH1BqQrxd5bgZZbLfJK9Q +-----END RSA PRIVATE KEY----- diff --git a/certs/ed25519/root-ed25519.der b/certs/ed25519/root-ed25519.der new file mode 100644 index 0000000000000000000000000000000000000000..f4da216c4f44dcba10db9f1767a80bb3ffce814a GIT binary patch literal 607 zcmXqLVv06sV&YxE%*4pV#KCyf@ZAev3poQ;HfHVA0)xi+hTI06Y|No7Y{E>T!G;0` zd>{@754&%EUP)qJB20vxhutZ^Dm6DT&yd%E8>EJXhb1UKzXYa$i-)~DKPN3X*as%U z&BN~MVq|J+XlW>6AO_OH%)?(^UakjHS6rN<*rz)rQ#ajLSs$=C(IDP{hmAQ@R+xp=fSHl;zkw`>$HyYZBGPt1 z{pGx0tq1=;&i@kT!G;0` zd>{@754&%EUP)qJB20vxhutZ^Dm6DT52k^IhsoIyCe6jeUY?(m798vY6XE7zcXcr` zH8r#}lrRtj8OqGVUtV6W2U1sDoTHbVpKB;@Aj`(7)#lOmotKf5QA{8+FD>5zNr8cq z1iz7ip}B#nk%f`5k(rTY6j;F0z|_bRDqzq!ALb(~MguMRWW-rn1Ujs4)7`<~GZ1c1pM5 p2FdL5nce^YFqyG(XPUPsmEH=_(Txq7V$U#F!ZqJqsPD@Y1_0$yoErcD literal 0 HcmV?d00001 diff --git a/certs/ed25519/server-ed25519.pem b/certs/ed25519/server-ed25519.pem new file mode 100644 index 000000000..cafd77a99 --- /dev/null +++ b/certs/ed25519/server-ed25519.pem @@ -0,0 +1,30 @@ +-----BEGIN CERTIFICATE----- +MIICSzCCAf2gAwIBAgIIAdCSEGpaRlcwBQYDK2VwMIGdMQswCQYDVQQGEwJVUzEQ +MA4GA1UECAwHTW9udGFuYTEQMA4GA1UEBwwHQm96ZW1hbjELMAkGA1UEBAwCQ0Ex +EDAOBgNVBAoMB3dvbGZTU0wxEDAOBgNVBAsMB0VEMjU1MTkxGDAWBgNVBAMMD3d3 +dy53b2xmc3NsLmNvbTEfMB0GCSqGSIb3DQEJARYQaW5mb0B3b2xmc3NsLmNvbTAi +GA8yMDE3MDUyODIzMjYyOVoYDzIwMTkwNTI5MjMyNjI5WjCBnzELMAkGA1UEBhMC +VVMxEDAOBgNVBAgMB01vbnRhbmExEDAOBgNVBAcMB0JvemVtYW4xDTALBgNVBAQM +BExlYWYxEDAOBgNVBAoMB3dvbGZTU0wxEDAOBgNVBAsMB0VEMjU1MTkxGDAWBgNV +BAMMD3d3dy53b2xmc3NsLmNvbTEfMB0GCSqGSIb3DQEJARYQaW5mb0B3b2xmc3Ns +LmNvbTAqMAUGAytlcAMhABowiBhHL5faBPSk471sDBa5SMHRQteOkoSgdCpDng4p +o1MwUTAdBgNVHQ4EFgQU9rKEGpW0cDJT/tnrmymAS9a18cAwHwYDVR0jBBgwFoAU +ktUL2vEEi7mhiwMCn1gANTYHeskwDwYDVR0PAQH/BAUDAgbAADAFBgMrZXADQQAS +VncMlkKY2skVbE5IlQUd0Hgy+IZGmkabZIsxsBlrd5mL//wCNgULaTeHYnXaUCwt +XVKUPwCdGEVvNxKO9OQA +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICWTCCAgugAwIBAgIIAfbhPrx5oYUwBQYDK2VwMIGfMQswCQYDVQQGEwJVUzEQ +MA4GA1UECAwHTW9udGFuYTEQMA4GA1UEBwwHQm96ZW1hbjENMAsGA1UEBAwEUm9v +dDEQMA4GA1UECgwHd29sZlNTTDEQMA4GA1UECwwHRUQyNTUxOTEYMBYGA1UEAwwP +d3d3LndvbGZzc2wuY29tMR8wHQYJKoZIhvcNAQkBFhBpbmZvQHdvbGZzc2wuY29t +MCIYDzIwMTcwNTI4MjMyNjI5WhgPMjAxOTA1MjkyMzI2MjlaMIGdMQswCQYDVQQG +EwJVUzEQMA4GA1UECAwHTW9udGFuYTEQMA4GA1UEBwwHQm96ZW1hbjELMAkGA1UE +BAwCQ0ExEDAOBgNVBAoMB3dvbGZTU0wxEDAOBgNVBAsMB0VEMjU1MTkxGDAWBgNV +BAMMD3d3dy53b2xmc3NsLmNvbTEfMB0GCSqGSIb3DQEJARYQaW5mb0B3b2xmc3Ns +LmNvbTAqMAUGAytlcAMhAEEH7HUMaHISPASCB24Wb0BBbaSPCPLinadDwiQomH6s +o2EwXzAMBgNVHRMEBTADAQH/MB0GA1UdDgQWBBSS1Qva8QSLuaGLAwKfWAA1Ngd6 +yTAfBgNVHSMEGDAWgBSGwCfpnvqFwf3jb/xUWXI3xzOSuzAPBgNVHQ8BAf8EBQMC +AcYAMAUGAytlcANBACIbBhfAEXQfZNGj9nsGABoLUI7rsWOSRbrc4sFoFCMMbiyV +PLEcGSeYUD5VUczESVivuUZP7ZxXOAQp1KkS/gg= +-----END CERTIFICATE----- diff --git a/src/internal.c b/src/internal.c index 8a3e89b70..50888927b 100755 --- a/src/internal.c +++ b/src/internal.c @@ -1723,6 +1723,10 @@ static void InitSuitesHashSigAlgo(Suites* suites, int haveECDSAsig, suites->hashSigAlgo[idx++] = sha_mac; suites->hashSigAlgo[idx++] = ecc_dsa_sa_algo; #endif + #ifdef HAVE_ED25519 + suites->hashSigAlgo[idx++] = ED25519_SA_MAJOR; + suites->hashSigAlgo[idx++] = ED25519_SA_MINOR; + #endif } if (haveRSAsig) { @@ -2652,17 +2656,24 @@ void InitSuites(Suites* suites, ProtocolVersion pv, word16 haveRSA, static INLINE void DecodeSigAlg(const byte* input, byte* hashAlgo, byte* hsType) { switch (input[0]) { + case NEW_SA_MAJOR: #ifdef WC_RSA_PSS - case rsa_pss_sa_algo: - /* PSS signatures: 0x080[4-6] */ - if (input[1] <= sha512_mac) { - *hsType = input[0]; - *hashAlgo = input[1]; - } - break; + /* PSS signatures: 0x080[4-6] */ + if (input[1] <= sha512_mac) { + *hsType = input[0]; + *hashAlgo = input[1]; + } #endif - /* ED25519: 0x0807 */ - /* ED448: 0x0808 */ + #ifdef HAVE_ED25519 + /* ED25519: 0x0807 */ + if (input[1] == ED25519_SA_MINOR) { + *hsType = ed25519_sa_algo; + /* Hash performed as part of sign/verify operation. */ + *hashAlgo = sha512_mac; + } + #endif + /* ED448: 0x0808 */ + break; default: *hashAlgo = input[0]; *hsType = input[1]; @@ -2828,6 +2839,12 @@ static INLINE void EncodeSigAlg(byte hashAlgo, byte hsType, byte* output) output[0] = hashAlgo; output[1] = ecc_dsa_sa_algo; break; + #ifdef HAVE_ED25519 + case ed25519_sa_algo: + output[0] = ED25519_SA_MAJOR; + output[1] = ED25519_SA_MINOR; + break; + #endif #endif #ifndef NO_RSA case rsa_sa_algo: @@ -2842,7 +2859,6 @@ static INLINE void EncodeSigAlg(byte hashAlgo, byte hsType, byte* output) break; #endif #endif - /* ED25519: 0x0807 */ /* ED448: 0x0808 */ } } @@ -3420,6 +3436,108 @@ int EccMakeKey(WOLFSSL* ssl, ecc_key* key, ecc_key* peer) return ret; } +#ifdef HAVE_ED25519 +/* Sign the data using EdDSA and key using X25519. + * + * ssl SSL object. + * in Data or message to sign. + * inSz Length of the data. + * out Buffer to hold signature. + * outSz On entry, size of the buffer. On exit, the size of the signature. + * key The private X25519 key data. + * keySz The length of the private key data in bytes. + * ctx The callback context. + * returns 0 on succes, otherwise the valus is an error. + */ +int Ed25519Sign(WOLFSSL* ssl, const byte* in, word32 inSz, byte* out, + word32* outSz, ed25519_key* key, byte* keyBuf, word32 keySz, + void* ctx) +{ + int ret; + + (void)ssl; + (void)keyBuf; + (void)keySz; + (void)ctx; + + WOLFSSL_ENTER("Ed25519Sign"); + +#if defined(HAVE_PK_CALLBACKS) + if (ssl->ctx->Ed25519SignCb) { + ret = ssl->ctx->Ed25519SignCb(ssl, in, inSz, out, outSz, keyBuf, + keySz, ctx); + } + else +#endif /* HAVE_PK_CALLBACKS */ + { + ret = wc_ed25519_sign_msg(in, inSz, out, outSz, key); + } + + /* Handle async pending response */ +#if defined(WOLFSSL_ASYNC_CRYPT) + if (ret == WC_PENDING_E) { + ret = wolfSSL_AsyncPush(ssl, &key->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN); + } +#endif /* WOLFSSL_ASYNC_CRYPT */ + + WOLFSSL_LEAVE("Ed25519Sign", ret); + + return ret; +} + +/* Verify the data using EdDSA and key using X25519. + * + * ssl SSL object. + * in Signature data. + * inSz Length of the signature data in bytes. + * msg Message to verify. + * outSz Length of message in bytes. + * key The public X25519 key data. + * keySz The length of the private key data in bytes. + * ctx The callback context. + * returns 0 on succes, otherwise the valus is an error. + */ +int Ed25519Verify(WOLFSSL* ssl, const byte* in, word32 inSz, const byte* msg, + word32 msgSz, ed25519_key* key, byte* keyBuf, word32 keySz, + void* ctx) +{ + int ret; + + (void)ssl; + (void)keyBuf; + (void)keySz; + (void)ctx; + + WOLFSSL_ENTER("Ed25519Verify"); + +#ifdef HAVE_PK_CALLBACKS + if (ssl->ctx->Ed25519VerifyCb) { + ret = ssl->ctx->Ed25519VerifyCb(ssl, in, inSz, msg, msgSz, keyBuf, + keySz, &ssl->eccVerifyRes, ctx); + } + else +#endif /* HAVE_PK_CALLBACKS */ + { + ret = wc_ed25519_verify_msg(in, inSz, msg, msgSz, + &ssl->eccVerifyRes, key); + } + + /* Handle async pending response */ +#if defined(WOLFSSL_ASYNC_CRYPT) + if (ret == WC_PENDING_E) { + ret = wolfSSL_AsyncPush(ssl, &key->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN); + } + else +#endif /* WOLFSSL_ASYNC_CRYPT */ + { + ret = (ret != 0 || ssl->eccVerifyRes == 0) ? VERIFY_SIGN_ERROR : 0; + } + + WOLFSSL_LEAVE("Ed25519Verify", ret); + + return ret; +} +#endif /* HAVE_ED25519 */ #ifdef HAVE_CURVE25519 #ifdef HAVE_PK_CALLBACKS @@ -4179,6 +4297,11 @@ void FreeKey(WOLFSSL* ssl, int type, void** pKey) wc_ecc_free((ecc_key*)*pKey); break; #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + case DYNAMIC_TYPE_ED25519: + wc_ed25519_free((ed25519_key*)*pKey); + break; + #endif /* HAVE_CURVE25519 */ #ifdef HAVE_CURVE25519 case DYNAMIC_TYPE_CURVE25519: wc_curve25519_free((curve25519_key*)*pKey); @@ -4216,26 +4339,31 @@ int AllocKey(WOLFSSL* ssl, int type, void** pKey) /* Determine size */ switch (type) { - #ifndef NO_RSA + #ifndef NO_RSA case DYNAMIC_TYPE_RSA: sz = sizeof(RsaKey); break; - #endif /* ! NO_RSA */ - #ifdef HAVE_ECC + #endif /* ! NO_RSA */ + #ifdef HAVE_ECC case DYNAMIC_TYPE_ECC: sz = sizeof(ecc_key); break; - #endif /* HAVE_ECC */ - #ifdef HAVE_CURVE25519 + #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + case DYNAMIC_TYPE_ED25519: + sz = sizeof(ed25519_key); + break; + #endif /* HAVE_ED25519 */ + #ifdef HAVE_CURVE25519 case DYNAMIC_TYPE_CURVE25519: sz = sizeof(curve25519_key); break; - #endif /* HAVE_CURVE25519 */ - #ifndef NO_DH + #endif /* HAVE_CURVE25519 */ + #ifndef NO_DH case DYNAMIC_TYPE_DH: sz = sizeof(DhKey); break; - #endif /* !NO_DH */ + #endif /* !NO_DH */ default: return BAD_FUNC_ARG; } @@ -4262,6 +4390,12 @@ int AllocKey(WOLFSSL* ssl, int type, void** pKey) ret = wc_ecc_init_ex((ecc_key*)*pKey, ssl->heap, ssl->devId); break; #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + case DYNAMIC_TYPE_ED25519: + wc_ed25519_init((ed25519_key*)*pKey); + ret = 0; + break; + #endif /* HAVE_CURVE25519 */ #ifdef HAVE_CURVE25519 case DYNAMIC_TYPE_CURVE25519: wc_curve25519_init((curve25519_key*)*pKey); @@ -4303,6 +4437,12 @@ static int ReuseKey(WOLFSSL* ssl, int type, void* pKey) ret = wc_ecc_init_ex((ecc_key*)pKey, ssl->heap, ssl->devId); break; #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + case DYNAMIC_TYPE_ED25519: + wc_ed25519_free((ed25519_key*)pKey); + wc_ed25519_init((ed25519_key*)pKey); + break; + #endif /* HAVE_CURVE25519 */ #ifdef HAVE_CURVE25519 case DYNAMIC_TYPE_CURVE25519: wc_curve25519_free((curve25519_key*)pKey); @@ -4447,6 +4587,10 @@ void SSL_ResourceFree(WOLFSSL* ssl) ssl->peerX25519KeyPresent = 0; #endif #endif /* HAVE_ECC */ +#ifdef HAVE_ED25519 + FreeKey(ssl, DYNAMIC_TYPE_ED25519, (void**)&ssl->peerEd25519Key); + ssl->peerEd25519KeyPresent = 0; +#endif #ifdef HAVE_PK_CALLBACKS #ifdef HAVE_ECC XFREE(ssl->buffers.peerEccDsaKey.buffer, ssl->heap, DYNAMIC_TYPE_ECC); @@ -7640,6 +7784,17 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx, word32 totalSz } break; #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + case ED25519k: + if (ssl->options.minEccKeySz < 0 || + ED25519_KEY_SIZE < + (word16)ssl->options.minEccKeySz) { + WOLFSSL_MSG( + "ECC key size in cert chain error"); + ret = ECC_KEY_SIZE_E; + } + break; + #endif /* HAVE_ED25519 */ default: WOLFSSL_MSG("Key size not checked"); /* key not being checked for size if not in @@ -8098,7 +8253,6 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx, word32 totalSz else { ssl->peerEccDsaKeyPresent = 1; #ifdef HAVE_PK_CALLBACKS - #ifdef HAVE_ECC ssl->buffers.peerEccDsaKey.buffer = (byte*)XMALLOC(args->dCert->pubKeySize, ssl->heap, DYNAMIC_TYPE_ECC); @@ -8112,7 +8266,6 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx, word32 totalSz ssl->buffers.peerEccDsaKey.length = args->dCert->pubKeySize; } - #endif /* HAVE_ECC */ #endif /*HAVE_PK_CALLBACKS */ } @@ -8126,6 +8279,56 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx, word32 totalSz } break; } + #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + case ED25519k: + { + int keyRet = 0; + if (ssl->peerEd25519Key == NULL) { + /* alloc/init on demand */ + keyRet = AllocKey(ssl, DYNAMIC_TYPE_ECC, + (void**)&ssl->peerEd25519Key); + } else if (ssl->peerEd25519KeyPresent) { + keyRet = ReuseKey(ssl, DYNAMIC_TYPE_ECC, + ssl->peerEd25519Key); + ssl->peerEd25519KeyPresent = 0; + } + + if (keyRet != 0 || + wc_ed25519_import_public(args->dCert->publicKey, + args->dCert->pubKeySize, + ssl->peerEd25519Key) + != 0) { + ret = PEER_KEY_ERROR; + } + else { + ssl->peerEd25519KeyPresent = 1; + #ifdef HAVE_PK_CALLBACKS + ssl->buffers.peerEd25519Key.buffer = + (byte*)XMALLOC(args->dCert->pubKeySize, + ssl->heap, DYNAMIC_TYPE_ECC); + if (ssl->buffers.peerEd25519Key.buffer == NULL) { + ERROR_OUT(MEMORY_ERROR, exit_ppc); + } + else { + XMEMCPY(ssl->buffers.peerEd25519Key.buffer, + args->dCert->publicKey, + args->dCert->pubKeySize); + ssl->buffers.peerEd25519Key.length = + args->dCert->pubKeySize; + } + #endif /*HAVE_PK_CALLBACKS */ + } + + /* check size of peer ECC key */ + if (ret == 0 && ssl->peerEd25519KeyPresent && + !ssl->options.verifyNone && + ED25519_KEY_SIZE < ssl->options.minEccKeySz) { + ret = ECC_KEY_SIZE_E; + WOLFSSL_MSG("Peer ECC key is too small"); + } + break; + } #endif /* HAVE_ECC */ default: break; @@ -15177,6 +15380,17 @@ void PickHashSigAlgo(WOLFSSL* ssl, const byte* hashSigAlgo, byte hashAlgo = 0, sigAlgo = 0; DecodeSigAlg(&hashSigAlgo[i], &hashAlgo, &sigAlgo); + #ifdef HAVE_ECC + if (ssl->pkCurveOID == ECC_ED25519_OID && sigAlgo != ed25519_sa_algo) + continue; + + if (sigAlgo == ed25519_sa_algo && + ssl->specs.sig_algo == ecc_dsa_sa_algo) { + ssl->suites->sigAlgo = sigAlgo; + ssl->suites->hashAlgo = sha512_mac; + break; + } + #endif if (sigAlgo == ssl->specs.sig_algo || (sigAlgo == rsa_pss_sa_algo && ssl->specs.sig_algo == rsa_sa_algo)) { if (hashAlgo == sha_mac) { @@ -16756,15 +16970,6 @@ static int DoServerKeyExchange(WOLFSSL* ssl, const byte* input, } ssl->buffers.sig.length = SEED_LEN + verifySz; - /* buffer for hash */ - ssl->buffers.digest.length = wc_HashGetDigestSize(hashType); - ssl->buffers.digest.buffer = (byte*)XMALLOC( - ssl->buffers.digest.length, ssl->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (ssl->buffers.digest.buffer == NULL) { - ERROR_OUT(MEMORY_E, exit_dske); - } - /* build message to hash */ XMEMCPY(ssl->buffers.sig.buffer, ssl->arrays->clientRandom, RAN_LEN); @@ -16773,12 +16978,25 @@ static int DoServerKeyExchange(WOLFSSL* ssl, const byte* input, XMEMCPY(&ssl->buffers.sig.buffer[RAN_LEN * 2], input + args->begin, verifySz); /* message */ - /* Perform hash */ - ret = wc_Hash(hashType, - ssl->buffers.sig.buffer, ssl->buffers.sig.length, - ssl->buffers.digest.buffer, ssl->buffers.digest.length); - if (ret != 0) { - goto exit_dske; + if (args->sigAlgo != ed25519_sa_algo) { + /* buffer for hash */ + ssl->buffers.digest.length = + wc_HashGetDigestSize(hashType); + ssl->buffers.digest.buffer = (byte*)XMALLOC( + ssl->buffers.digest.length, ssl->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (ssl->buffers.digest.buffer == NULL) { + ERROR_OUT(MEMORY_E, exit_dske); + } + + /* Perform hash */ + ret = wc_Hash(hashType, ssl->buffers.sig.buffer, + ssl->buffers.sig.length, + ssl->buffers.digest.buffer, + ssl->buffers.digest.length); + if (ret != 0) { + goto exit_dske; + } } switch (args->sigAlgo) @@ -16805,6 +17023,15 @@ static int DoServerKeyExchange(WOLFSSL* ssl, const byte* input, break; } #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + case ed25519_sa_algo: + { + if (!ssl->peerEd25519KeyPresent) { + ERROR_OUT(NO_PEER_KEY, exit_dske); + } + break; + } + #endif /* HAVE_ECC */ default: ret = ALGO_ID_E; @@ -16908,6 +17135,26 @@ static int DoServerKeyExchange(WOLFSSL* ssl, const byte* input, break; } #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + case ed25519_sa_algo: + { + ret = Ed25519Verify(ssl, + args->verifySig, args->verifySigSz, + ssl->buffers.sig.buffer, + ssl->buffers.sig.length, + ssl->peerEd25519Key, + #ifdef HAVE_PK_CALLBACKS + ssl->buffers.peerEccDsaKey.buffer, + ssl->buffers.peerEccDsaKey.length, + ssl->Ed25519VerifyCtx + #else + NULL, 0, NULL + #endif + ); + + break; + } + #endif /* HAVE_ECC */ default: ret = ALGO_ID_E; @@ -17016,6 +17263,11 @@ static int DoServerKeyExchange(WOLFSSL* ssl, const byte* input, case ecc_dsa_sa_algo: /* Nothing to do in this algo */ break; + #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + case ed25519_sa_algo: + /* Nothing to do in this algo */ + break; #endif /* HAVE_ECC */ default: ret = ALGO_ID_E; @@ -18582,22 +18834,61 @@ int DecodePrivateKey(WOLFSSL *ssl, word16* length) ret = wc_EccPrivateKeyDecode(ssl->buffers.key->buffer, &idx, (ecc_key*)ssl->hsKey, ssl->buffers.key->length); + if (ret == 0) { + WOLFSSL_MSG("Using ECC private key"); + + /* Check it meets the minimum ECC key size requirements. */ + keySz = wc_ecc_size((ecc_key*)ssl->hsKey); + if (keySz < ssl->options.minEccKeySz) { + WOLFSSL_MSG("ECC key size too small"); + ERROR_OUT(ECC_KEY_SIZE_E, exit_dpk); + } + + /* Return the maximum signature length. */ + *length = wc_ecc_sig_size((ecc_key*)ssl->hsKey); + + goto exit_dpk; + } +#endif +#ifdef HAVE_ED25519 +#if !defined(NO_RSA) || defined(HAVE_ECC) + FreeKey(ssl, ssl->hsType, (void**)&ssl->hsKey); +#endif + + ssl->hsType = DYNAMIC_TYPE_ED25519; + ret = AllocKey(ssl, ssl->hsType, &ssl->hsKey); if (ret != 0) { - WOLFSSL_MSG("Bad client cert type"); goto exit_dpk; } - WOLFSSL_MSG("Using ECC private key"); +#ifdef HAVE_ECC + WOLFSSL_MSG("Trying ED25519 private key, ECC didn't work"); +#elif !defined(NO_RSA) + WOLFSSL_MSG("Trying ED25519 private key, RSA didn't work"); +#else + WOLFSSL_MSG("Trying ED25519 private key"); +#endif - /* Check it meets the minimum ECC key size requirements. */ - keySz = wc_ecc_size((ecc_key*)ssl->hsKey); - if (keySz < ssl->options.minEccKeySz) { - WOLFSSL_MSG("ECC key size too small"); - ERROR_OUT(ECC_KEY_SIZE_E, exit_dpk); + /* Set start of data to beginning of buffer. */ + idx = 0; + /* Decode the key assuming it is an ED25519 private key. */ + ret = wc_Ed25519PrivateKeyDecode(ssl->buffers.key->buffer, &idx, + (ed25519_key*)ssl->hsKey, + ssl->buffers.key->length); + if (ret == 0) { + WOLFSSL_MSG("Using ED25519 private key"); + + /* Check it meets the minimum ECC key size requirements. */ + if (ED25519_KEY_SIZE < ssl->options.minEccKeySz) { + WOLFSSL_MSG("ED25519 key size too small"); + ERROR_OUT(ECC_KEY_SIZE_E, exit_dpk); + } + + /* Return the maximum signature length. */ + *length = ED25519_SIG_SIZE; + + goto exit_dpk; } - - /* Return the maximum signature length. */ - *length = wc_ecc_sig_size((ecc_key*)ssl->hsKey); #endif exit_dpk: @@ -18755,6 +19046,8 @@ int SendCertificateVerify(WOLFSSL* ssl) } else if (ssl->hsType == DYNAMIC_TYPE_ECC) args->sigAlgo = ecc_dsa_sa_algo; + else if (ssl->hsType == DYNAMIC_TYPE_ED25519) + args->sigAlgo = ed25519_sa_algo; if (IsAtLeastTLSv1_2(ssl)) { EncodeSigAlg(ssl->suites->hashAlgo, args->sigAlgo, @@ -18821,6 +19114,24 @@ int SendCertificateVerify(WOLFSSL* ssl) ); } #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + if (ssl->hsType == DYNAMIC_TYPE_ED25519) { + ed25519_key* key = (ed25519_key*)ssl->hsKey; + + ret = Ed25519Sign(ssl, + ssl->buffers.digest.buffer, ssl->buffers.digest.length, + ssl->buffers.sig.buffer, &ssl->buffers.sig.length, + key, + #if defined(HAVE_PK_CALLBACKS) + ssl->buffers.key->buffer, + ssl->buffers.key->length, + ssl->Ed25519SignCtx + #else + NULL, 0, NULL + #endif + ); + } + #endif /* HAVE_ECC */ #ifndef NO_RSA if (ssl->hsType == DYNAMIC_TYPE_RSA) { RsaKey* key = (RsaKey*)ssl->hsKey; @@ -18867,6 +19178,16 @@ int SendCertificateVerify(WOLFSSL* ssl) ssl->buffers.sig.buffer, ssl->buffers.sig.length); } #endif /* HAVE_ECC */ + #ifdef HAVE_ECC + if (ssl->hsType == DYNAMIC_TYPE_ED25519) { + args->length = ssl->buffers.sig.length; + /* prepend hdr */ + c16toa((word16)ssl->buffers.sig.length, args->verify + + args->extraSz); + XMEMCPY(args->verify + args->extraSz + VERIFY_HEADER, + ssl->buffers.sig.buffer, ssl->buffers.sig.length); + } + #endif /* HAVE_ECC */ #ifndef NO_RSA if (ssl->hsType == DYNAMIC_TYPE_RSA) { RsaKey* key = (RsaKey*)ssl->hsKey; @@ -19991,6 +20312,38 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, } break; } + #ifdef HAVE_ED25519 + case ed25519_sa_algo: + { + word32 i = 0; + + ssl->hsType = DYNAMIC_TYPE_ED25519; + ret = AllocKey(ssl, ssl->hsType, &ssl->hsKey); + if (ret != 0) { + goto exit_sske; + } + + ret = wc_Ed25519PrivateKeyDecode( + ssl->buffers.key->buffer, + &i, + (ed25519_key*)ssl->hsKey, + ssl->buffers.key->length); + if (ret != 0) { + goto exit_sske; + } + /* worst case estimate */ + args->tmpSigSz = ED25519_SIG_SIZE; + + /* check the minimum ECC key size */ + if (ED25519_KEY_SIZE < + ssl->options.minEccKeySz) { + WOLFSSL_MSG("Ed25519 key size too small"); + ret = ECC_KEY_SIZE_E; + goto exit_sske; + } + break; + } + #endif default: ERROR_OUT(ALGO_ID_E, exit_sske); /* unsupported type */ } /* switch(ssl->specs.sig_algo) */ @@ -20091,20 +20444,24 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, XMEMCPY(args->sigDataBuf+RAN_LEN+RAN_LEN, args->output + preSigIdx, preSigSz); - ssl->buffers.sig.length = wc_HashGetDigestSize(hashType); - ssl->buffers.sig.buffer = (byte*)XMALLOC( + if (ssl->suites->sigAlgo != ed25519_sa_algo) { + ssl->buffers.sig.length = + wc_HashGetDigestSize(hashType); + ssl->buffers.sig.buffer = (byte*)XMALLOC( ssl->buffers.sig.length, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); - if (ssl->buffers.sig.buffer == NULL) { - ERROR_OUT(MEMORY_E, exit_sske); - } + if (ssl->buffers.sig.buffer == NULL) { + ERROR_OUT(MEMORY_E, exit_sske); + } - /* Perform hash */ - ret = wc_Hash(hashType, - args->sigDataBuf, args->sigDataSz, - ssl->buffers.sig.buffer, ssl->buffers.sig.length); - if (ret != 0) { - goto exit_sske; + /* Perform hash */ + ret = wc_Hash(hashType, args->sigDataBuf, + args->sigDataSz, + ssl->buffers.sig.buffer, + ssl->buffers.sig.length); + if (ret != 0) { + goto exit_sske; + } } args->sigSz = args->tmpSigSz; @@ -20151,6 +20508,9 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, break; #endif #endif /* !NO_RSA */ + #ifdef HAVE_ED25519 + case ed25519_sa_algo: + #endif case ecc_dsa_sa_algo: { break; @@ -20321,20 +20681,24 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, XMEMCPY(args->sigDataBuf+RAN_LEN+RAN_LEN, args->output + preSigIdx, preSigSz); - ssl->buffers.sig.length = wc_HashGetDigestSize(hashType); - ssl->buffers.sig.buffer = (byte*)XMALLOC( + if (ssl->suites->sigAlgo != ed25519_sa_algo) { + ssl->buffers.sig.length = + wc_HashGetDigestSize(hashType); + ssl->buffers.sig.buffer = (byte*)XMALLOC( ssl->buffers.sig.length, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); - if (ssl->buffers.sig.buffer == NULL) { - ERROR_OUT(MEMORY_E, exit_sske); - } + if (ssl->buffers.sig.buffer == NULL) { + ERROR_OUT(MEMORY_E, exit_sske); + } - /* Perform hash */ - ret = wc_Hash(hashType, - args->sigDataBuf, args->sigDataSz, - ssl->buffers.sig.buffer, ssl->buffers.sig.length); - if (ret != 0) { - goto exit_sske; + /* Perform hash */ + ret = wc_Hash(hashType, args->sigDataBuf, + args->sigDataSz, + ssl->buffers.sig.buffer, + ssl->buffers.sig.length); + if (ret != 0) { + goto exit_sske; + } } args->sigSz = args->tmpSigSz; @@ -20458,6 +20822,27 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, ); break; } + #ifdef HAVE_ED25519 + case ed25519_sa_algo: + { + ed25519_key* key = (ed25519_key*)ssl->hsKey; + + ret = Ed25519Sign(ssl, + args->sigDataBuf, args->sigDataSz, + args->output + LENGTH_SZ + args->idx, + &args->sigSz, + key, + #if defined(HAVE_PK_CALLBACKS) + ssl->buffers.key->buffer, + ssl->buffers.key->length, + ssl->Ed25519SignCtx + #else + NULL, 0, NULL + #endif + ); + break; + } + #endif } /* switch(ssl->specs.sig_algo) */ break; } @@ -20589,6 +20974,19 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, args->sendSz += args->sigSz - args->tmpSigSz; break; } + #ifdef HAVE_ED25519 + case ed25519_sa_algo: + { + /* Now that we know the real sig size, write it. */ + c16toa((word16)args->sigSz, + args->output + args->idx); + + /* And adjust length and sendSz from estimates */ + args->length += args->sigSz - args->tmpSigSz; + args->sendSz += args->sigSz - args->tmpSigSz; + break; + } + #endif default: ERROR_OUT(ALGO_ID_E, exit_sske); /* unsupported type */ } /* switch(ssl->specs.sig_algo) */ @@ -21714,6 +22112,10 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, else if (ssl->peerEccDsaKeyPresent) args->sigAlgo = ecc_dsa_sa_algo; #endif + #ifdef HAVE_ED25519 + else if (ssl->peerEd25519KeyPresent) + args->sigAlgo = ed25519_sa_algo; + #endif if ((args->idx - args->begin) + OPAQUE16_LEN > size) { ERROR_OUT(BUFFER_ERROR, exit_dcv); @@ -21754,6 +22156,16 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, } } #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + if (ssl->peerEd25519KeyPresent) { + WOLFSSL_MSG("Doing ED25519 peer cert verify"); + if (IsAtLeastTLSv1_2(ssl) && + args->sigAlgo != ed25519_sa_algo) { + WOLFSSL_MSG( + "Oops, peer sent ED25519 key but not in verify"); + } + } + #endif /* HAVE_ED25519 */ /* Advance state and proceed */ ssl->options.asyncState = TLS_ASYNC_DO; diff --git a/src/ssl.c b/src/ssl.c index eceafd442..59a18ec42 100755 --- a/src/ssl.c +++ b/src/ssl.c @@ -3635,6 +3635,15 @@ int AddCA(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer, int type, int verify) } break; #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + case ED25519k: + if (cm->minEccKeySz < 0 || + ED25519_KEY_SIZE < (word16)cm->minEccKeySz) { + ret = ECC_KEY_SIZE_E; + WOLFSSL_MSG("\tCA ECC key size error"); + } + break; + #endif /* HAVE_ED25519 */ default: WOLFSSL_MSG("\tNo key size check done on CA"); @@ -4375,6 +4384,7 @@ int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, DerBuffer* der = NULL; /* holds DER or RAW (for NTRU) */ int ret = 0; int eccKey = 0; + int ed25519Key = 0; int rsaKey = 0; int resetSuites = 0; void* heap = ctx ? ctx->heap : ((ssl) ? ssl->heap : NULL); @@ -4574,7 +4584,7 @@ int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, if (type == PRIVATEKEY_TYPE && format != SSL_FILETYPE_RAW) { #ifndef NO_RSA - if (!eccKey) { + if (!eccKey && !ed25519Key) { /* make sure RSA key can be used */ word32 idx = 0; #ifdef WOLFSSL_SMALL_STACK @@ -4638,40 +4648,83 @@ int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, } #endif #ifdef HAVE_ECC - if (!rsaKey) { + if (!rsaKey && !ed25519Key) { /* make sure ECC key can be used */ word32 idx = 0; ecc_key key; - ret = wc_ecc_init_ex(&key, heap, devId); + if (wc_ecc_init_ex(&key, heap, devId) == 0) { + if (wc_EccPrivateKeyDecode(der->buffer, &idx, &key, + der->length) == 0) { + + /* check for minimum ECC key size and then free */ + if (ssl) { + if (wc_ecc_size(&key) < ssl->options.minEccKeySz) { + wc_ecc_free(&key); + WOLFSSL_MSG("ECC private key too small"); + return ECC_KEY_SIZE_E; + } + } + else if (ctx) { + if (wc_ecc_size(&key) < ctx->minEccKeySz) { + wc_ecc_free(&key); + WOLFSSL_MSG("ECC private key too small"); + return ECC_KEY_SIZE_E; + } + } + + eccKey = 1; + if (ssl) { + ssl->options.haveStaticECC = 1; + } + else if (ctx) { + ctx->haveStaticECC = 1; + } + + if (ssl && ssl->options.side == WOLFSSL_SERVER_END) { + resetSuites = 1; + } + } + + wc_ecc_free(&key); + } + } + #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + if (!rsaKey && !eccKey) { + /* make sure Ed25519 key can be used */ + word32 idx = 0; + ed25519_key key; + + ret = wc_ed25519_init(&key); if (ret != 0) { return ret; } - if (wc_EccPrivateKeyDecode(der->buffer, &idx, &key, - der->length) != 0) { - wc_ecc_free(&key); + if (wc_Ed25519PrivateKeyDecode(der->buffer, &idx, &key, + der->length) != 0) { + wc_ed25519_free(&key); return SSL_BAD_FILE; } /* check for minimum ECC key size and then free */ if (ssl) { - if (wc_ecc_size(&key) < ssl->options.minEccKeySz) { - wc_ecc_free(&key); - WOLFSSL_MSG("ECC private key too small"); + if (ED25519_KEY_SIZE < ssl->options.minEccKeySz) { + wc_ed25519_free(&key); + WOLFSSL_MSG("ED25519 private key too small"); return ECC_KEY_SIZE_E; } } else if (ctx) { - if (wc_ecc_size(&key) < ctx->minEccKeySz) { - wc_ecc_free(&key); - WOLFSSL_MSG("ECC private key too small"); + if (ED25519_KEY_SIZE < ctx->minEccKeySz) { + wc_ed25519_free(&key); + WOLFSSL_MSG("ED25519 private key too small"); return ECC_KEY_SIZE_E; } } - wc_ecc_free(&key); - eccKey = 1; + wc_ed25519_free(&key); + ed25519Key = 1; if (ssl) { ssl->options.haveStaticECC = 1; } @@ -4683,7 +4736,12 @@ int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, resetSuites = 1; } } - #endif /* HAVE_ECC */ + #endif + + if (!rsaKey && !eccKey && !ed25519Key) + return SSL_BAD_FILE; + + (void)ed25519Key; } else if (type == CERT_TYPE) { #ifdef WOLFSSL_SMALL_STACK @@ -4730,6 +4788,13 @@ int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, else if (ctx) ctx->haveECDSAsig = 1; break; + case CTC_ED25519: + WOLFSSL_MSG("ED25519 cert signature"); + if (ssl) + ssl->options.haveECDSAsig = 1; + else if (ctx) + ctx->haveECDSAsig = 1; + break; default: WOLFSSL_MSG("Not ECDSA cert signature"); break; @@ -4742,6 +4807,11 @@ int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, if (cert->keyOID == ECDSAk) { ssl->options.haveECC = 1; } + #ifdef HAVE_ED25519 + else if (cert->keyOID == ED25519k) { + ssl->options.haveECC = 1; + } + #endif #else ssl->options.haveECC = ssl->options.haveECDSAsig; #endif @@ -4752,6 +4822,11 @@ int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, if (cert->keyOID == ECDSAk) { ctx->haveECC = 1; } + #ifdef HAVE_ED25519 + else if (cert->keyOID == ED25519k) { + ctx->haveECC = 1; + } + #endif #else ctx->haveECC = ctx->haveECDSAsig; #endif @@ -4777,7 +4852,7 @@ int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, } } break; - #endif /* !NO_RSA */ + #endif /* !NO_RSA */ #ifdef HAVE_ECC case ECDSAk: if (ssl && !ssl->options.verifyNone) { @@ -4795,7 +4870,25 @@ int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, } } break; - #endif /* HAVE_ECC */ + #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + case ED25519k: + if (ssl && !ssl->options.verifyNone) { + if (ssl->options.minEccKeySz < 0 || + ED25519_KEY_SIZE < (word16)ssl->options.minEccKeySz) { + ret = ECC_KEY_SIZE_E; + WOLFSSL_MSG("Certificate Ed key size error"); + } + } + else if (ctx && !ctx->verifyNone) { + if (ctx->minEccKeySz < 0 || + ED25519_KEY_SIZE < (word16)ctx->minEccKeySz) { + ret = ECC_KEY_SIZE_E; + WOLFSSL_MSG("Certificate ECC key size error"); + } + } + break; + #endif /* HAVE_ED25519 */ default: WOLFSSL_MSG("No key size check done on certificate"); @@ -22022,6 +22115,54 @@ void* wolfSSL_GetEccSharedSecretCtx(WOLFSSL* ssl) return NULL; } +#endif /* HAVE_ECC */ + +#ifdef HAVE_ED25519 +void wolfSSL_CTX_SetEd25519SignCb(WOLFSSL_CTX* ctx, CallbackEd25519Sign cb) +{ + if (ctx) + ctx->Ed25519SignCb = cb; +} + + +void wolfSSL_SetEd25519SignCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->Ed25519SignCtx = ctx; +} + + +void* wolfSSL_GetEd25519SignCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->Ed25519SignCtx; + + return NULL; +} + + +void wolfSSL_CTX_SetEd25519VerifyCb(WOLFSSL_CTX* ctx, CallbackEd25519Verify cb) +{ + if (ctx) + ctx->Ed25519VerifyCb = cb; +} + + +void wolfSSL_SetEd25519VerifyCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->Ed25519VerifyCtx = ctx; +} + + +void* wolfSSL_GetEd25519VerifyCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->Ed25519VerifyCtx; + + return NULL; +} +#endif #ifdef HAVE_CURVE25519 void wolfSSL_CTX_SetX25519SharedSecretCb(WOLFSSL_CTX* ctx, @@ -22046,7 +22187,6 @@ void* wolfSSL_GetX25519SharedSecretCtx(WOLFSSL* ssl) return NULL; } #endif -#endif /* HAVE_ECC */ #ifndef NO_RSA @@ -22365,6 +22505,9 @@ void* wolfSSL_GetRsaDecCtx(WOLFSSL* ssl) case RSAk: ctx->haveRSA = 1; break; + #ifdef HAVE_ED25519 + case ED25519k: + #endif case ECDSAk: ctx->haveECC = 1; ctx->pkCurveOID = x->pkCurveOID; diff --git a/src/tls.c b/src/tls.c index 5e5c47148..4a713d0c9 100755 --- a/src/tls.c +++ b/src/tls.c @@ -2985,6 +2985,7 @@ int TLSX_ValidateEllipticCurves(WOLFSSL* ssl, byte first, byte second) { : NULL; EllipticCurve* curve = NULL; word32 oid = 0; + word32 pkOid = 0; word32 defOid = 0; word32 defSz = 80; /* Maximum known curve size is 66. */ word32 nextOid = 0; @@ -3009,19 +3010,19 @@ int TLSX_ValidateEllipticCurves(WOLFSSL* ssl, byte first, byte second) { #if defined(HAVE_ECC160) || defined(HAVE_ALL_CURVES) #ifndef NO_ECC_SECP case WOLFSSL_ECC_SECP160R1: - oid = ECC_SECP160R1_OID; + pkOid = oid = ECC_SECP160R1_OID; octets = 20; break; #endif /* !NO_ECC_SECP */ #ifdef HAVE_ECC_SECPR2 case WOLFSSL_ECC_SECP160R2: - oid = ECC_SECP160R2_OID; + pkOid = oid = ECC_SECP160R2_OID; octets = 20; break; #endif /* HAVE_ECC_SECPR2 */ #ifdef HAVE_ECC_KOBLITZ case WOLFSSL_ECC_SECP160K1: - oid = ECC_SECP160K1_OID; + pkOid = oid = ECC_SECP160K1_OID; octets = 20; break; #endif /* HAVE_ECC_KOBLITZ */ @@ -3029,13 +3030,13 @@ int TLSX_ValidateEllipticCurves(WOLFSSL* ssl, byte first, byte second) { #if defined(HAVE_ECC192) || defined(HAVE_ALL_CURVES) #ifndef NO_ECC_SECP case WOLFSSL_ECC_SECP192R1: - oid = ECC_SECP192R1_OID; + pkOid = oid = ECC_SECP192R1_OID; octets = 24; break; #endif /* !NO_ECC_SECP */ #ifdef HAVE_ECC_KOBLITZ case WOLFSSL_ECC_SECP192K1: - oid = ECC_SECP192K1_OID; + pkOid = oid = ECC_SECP192K1_OID; octets = 24; break; #endif /* HAVE_ECC_KOBLITZ */ @@ -3043,13 +3044,13 @@ int TLSX_ValidateEllipticCurves(WOLFSSL* ssl, byte first, byte second) { #if defined(HAVE_ECC224) || defined(HAVE_ALL_CURVES) #ifndef NO_ECC_SECP case WOLFSSL_ECC_SECP224R1: - oid = ECC_SECP224R1_OID; + pkOid = oid = ECC_SECP224R1_OID; octets = 28; break; #endif /* !NO_ECC_SECP */ #ifdef HAVE_ECC_KOBLITZ case WOLFSSL_ECC_SECP224K1: - oid = ECC_SECP224K1_OID; + pkOid = oid = ECC_SECP224K1_OID; octets = 28; break; #endif /* HAVE_ECC_KOBLITZ */ @@ -3057,25 +3058,30 @@ int TLSX_ValidateEllipticCurves(WOLFSSL* ssl, byte first, byte second) { #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES) #ifndef NO_ECC_SECP case WOLFSSL_ECC_SECP256R1: - oid = ECC_SECP256R1_OID; + pkOid = oid = ECC_SECP256R1_OID; octets = 32; break; #endif /* !NO_ECC_SECP */ #ifdef HAVE_CURVE25519 case WOLFSSL_ECC_X25519: oid = ECC_X25519_OID; + #ifdef HAVE_ED25519 + pkOid = ECC_ED25519_OID; + #else + pkOid = ECC_X25519_OID; + #endif octets = 32; break; #endif /* HAVE_CURVE25519 */ #ifdef HAVE_ECC_KOBLITZ case WOLFSSL_ECC_SECP256K1: - oid = ECC_SECP256K1_OID; + pkOid = oid = ECC_SECP256K1_OID; octets = 32; break; #endif /* HAVE_ECC_KOBLITZ */ #ifdef HAVE_ECC_BRAINPOOL case WOLFSSL_ECC_BRAINPOOLP256R1: - oid = ECC_BRAINPOOLP256R1_OID; + pkOid = oid = ECC_BRAINPOOLP256R1_OID; octets = 32; break; #endif /* HAVE_ECC_BRAINPOOL */ @@ -3083,13 +3089,13 @@ int TLSX_ValidateEllipticCurves(WOLFSSL* ssl, byte first, byte second) { #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES) #ifndef NO_ECC_SECP case WOLFSSL_ECC_SECP384R1: - oid = ECC_SECP384R1_OID; + pkOid = oid = ECC_SECP384R1_OID; octets = 48; break; #endif /* !NO_ECC_SECP */ #ifdef HAVE_ECC_BRAINPOOL case WOLFSSL_ECC_BRAINPOOLP384R1: - oid = ECC_BRAINPOOLP384R1_OID; + pkOid = oid = ECC_BRAINPOOLP384R1_OID; octets = 48; break; #endif /* HAVE_ECC_BRAINPOOL */ @@ -3097,7 +3103,7 @@ int TLSX_ValidateEllipticCurves(WOLFSSL* ssl, byte first, byte second) { #if defined(HAVE_ECC512) || defined(HAVE_ALL_CURVES) #ifdef HAVE_ECC_BRAINPOOL case WOLFSSL_ECC_BRAINPOOLP512R1: - oid = ECC_BRAINPOOLP512R1_OID; + pkOid = oid = ECC_BRAINPOOLP512R1_OID; octets = 64; break; #endif /* HAVE_ECC_BRAINPOOL */ @@ -3105,7 +3111,7 @@ int TLSX_ValidateEllipticCurves(WOLFSSL* ssl, byte first, byte second) { #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES) #ifndef NO_ECC_SECP case WOLFSSL_ECC_SECP521R1: - oid = ECC_SECP521R1_OID; + pkOid = oid = ECC_SECP521R1_OID; octets = 66; break; #endif /* !NO_ECC_SECP */ @@ -3139,7 +3145,7 @@ int TLSX_ValidateEllipticCurves(WOLFSSL* ssl, byte first, byte second) { case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: case TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8: - sig |= ssl->pkCurveOID == oid; + sig |= ssl->pkCurveOID == pkOid; key |= ssl->ecdhCurveOID == oid; ephmSuite = 1; break; @@ -3158,7 +3164,7 @@ int TLSX_ValidateEllipticCurves(WOLFSSL* ssl, byte first, byte second) { defOid = 0; defSz = 80; } - sig |= ssl->pkCurveOID == oid; + sig |= ssl->pkCurveOID == pkOid; key |= ssl->pkCurveOID == oid; break; #endif /* WOLFSSL_STATIC_DH */ @@ -3192,7 +3198,7 @@ int TLSX_ValidateEllipticCurves(WOLFSSL* ssl, byte first, byte second) { defSz = 80; } sig = 1; - key |= ssl->pkCurveOID == oid; + key |= ssl->pkCurveOID == pkOid; break; #endif /* WOLFSSL_STATIC_DH */ #endif @@ -3214,7 +3220,7 @@ int TLSX_ValidateEllipticCurves(WOLFSSL* ssl, byte first, byte second) { /* ECDHE_ECDSA */ case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 : case TLS_ECDHE_ECDSA_WITH_CHACHA20_OLD_POLY1305_SHA256 : - sig |= ssl->pkCurveOID == oid; + sig |= ssl->pkCurveOID == pkOid; key |= ssl->ecdhCurveOID == oid; ephmSuite = 1; break; @@ -6969,9 +6975,9 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) WOLFSSL_ECC_SECP256R1, ssl->heap); if (ret != SSL_SUCCESS) return ret; #endif - #ifdef HAVE_CURVE25519 + #if defined(HAVE_CURVE25519) ret = TLSX_UseSupportedCurve(&ssl->extensions, - WOLFSSL_ECC_X25519, ssl->heap); + WOLFSSL_ECC_X25519, ssl->heap); if (ret != SSL_SUCCESS) return ret; #endif #ifdef HAVE_ECC_KOBLITZ @@ -7028,38 +7034,40 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) ssl->heap)) != 0) return ret; - /* Add FFDHE supported groups. */ - #ifdef HAVE_FFDHE_2048 - ret = TLSX_UseSupportedCurve(&ssl->extensions, - WOLFSSL_FFDHE_2048, ssl->heap); - if (ret != SSL_SUCCESS) - return ret; - #endif - #ifdef HAVE_FFDHE_3072 - ret = TLSX_UseSupportedCurve(&ssl->extensions, - WOLFSSL_FFDHE_3072, ssl->heap); - if (ret != SSL_SUCCESS) - return ret; - #endif - #ifdef HAVE_FFDHE_4096 - ret = TLSX_UseSupportedCurve(&ssl->extensions, - WOLFSSL_FFDHE_4096, ssl->heap); - if (ret != SSL_SUCCESS) - return ret; - #endif - #ifdef HAVE_FFDHE_6144 - ret = TLSX_UseSupportedCurve(&ssl->extensions, - WOLFSSL_FFDHE_6144, ssl->heap); - if (ret != SSL_SUCCESS) - return ret; - #endif - #ifdef HAVE_FFDHE_8192 - ret = TLSX_UseSupportedCurve(&ssl->extensions, - WOLFSSL_FFDHE_8192, ssl->heap); - if (ret != SSL_SUCCESS) - return ret; - #endif - ret = 0; + if (!ssl->options.userCurves && !ssl->ctx->userCurves) { + /* Add FFDHE supported groups. */ + #ifdef HAVE_FFDHE_2048 + ret = TLSX_UseSupportedCurve(&ssl->extensions, + WOLFSSL_FFDHE_2048, ssl->heap); + if (ret != SSL_SUCCESS) + return ret; + #endif + #ifdef HAVE_FFDHE_3072 + ret = TLSX_UseSupportedCurve(&ssl->extensions, + WOLFSSL_FFDHE_3072, ssl->heap); + if (ret != SSL_SUCCESS) + return ret; + #endif + #ifdef HAVE_FFDHE_4096 + ret = TLSX_UseSupportedCurve(&ssl->extensions, + WOLFSSL_FFDHE_4096, ssl->heap); + if (ret != SSL_SUCCESS) + return ret; + #endif + #ifdef HAVE_FFDHE_6144 + ret = TLSX_UseSupportedCurve(&ssl->extensions, + WOLFSSL_FFDHE_6144, ssl->heap); + if (ret != SSL_SUCCESS) + return ret; + #endif + #ifdef HAVE_FFDHE_8192 + ret = TLSX_UseSupportedCurve(&ssl->extensions, + WOLFSSL_FFDHE_8192, ssl->heap); + if (ret != SSL_SUCCESS) + return ret; + #endif + ret = 0; + } if (TLSX_Find(ssl->extensions, TLSX_KEY_SHARE) == NULL) { #if (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && \ diff --git a/src/tls13.c b/src/tls13.c index 852b30f80..3679c06d0 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -3087,6 +3087,13 @@ static INLINE void EncodeSigAlg(byte hashAlgo, byte hsType, byte* output) output[0] = hashAlgo; output[1] = ecc_dsa_sa_algo; break; + #ifdef HAVE_ED25519 + /* ED25519: 0x0807 */ + case ed25519_sa_algo: + output[0] = ED25519_SA_MAJOR; + output[1] = ED25519_SA_MINOR; + break; + #endif #endif #ifndef NO_RSA case rsa_sa_algo: @@ -3101,7 +3108,6 @@ static INLINE void EncodeSigAlg(byte hashAlgo, byte hsType, byte* output) break; #endif #endif - /* ED25519: 0x0807 */ /* ED448: 0x0808 */ } } @@ -3115,17 +3121,24 @@ static INLINE void EncodeSigAlg(byte hashAlgo, byte hsType, byte* output) static INLINE void DecodeSigAlg(byte* input, byte* hashAlgo, byte* hsType) { switch (input[0]) { + case NEW_SA_MAJOR: #ifdef WC_RSA_PSS - case 0x08: - /* PSS signatures: 0x080[4-6] */ - if (input[1] <= 0x06) { - *hsType = input[0]; - *hashAlgo = input[1]; - } - break; + /* PSS signatures: 0x080[4-6] */ + if (input[1] <= sha512_mac) { + *hsType = input[0]; + *hashAlgo = input[1]; + } #endif - /* ED25519: 0x0807 */ - /* ED448: 0x0808 */ + #ifdef HAVE_ED25519 + /* ED25519: 0x0807 */ + if (input[1] == ED25519_SA_MINOR) { + *hsType = ed25519_sa_algo; + /* Hash performed as part of sign/verify operation. */ + *hashAlgo = sha512_mac; + } + #endif + /* ED448: 0x0808 */ + break; default: *hashAlgo = input[0]; *hsType = input[1]; @@ -3825,6 +3838,8 @@ int SendTls13CertificateVerify(WOLFSSL* ssl) } else if (ssl->hsType == DYNAMIC_TYPE_ECC) args->sigAlgo = ecc_dsa_sa_algo; + else if (ssl->hsType == DYNAMIC_TYPE_ED25519) + args->sigAlgo = ed25519_sa_algo; EncodeSigAlg(ssl->suites->hashAlgo, args->sigAlgo, args->verify); /* Create the data to be signed. */ @@ -3869,6 +3884,12 @@ int SendTls13CertificateVerify(WOLFSSL* ssl) ret = 0; } #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + if (ssl->hsType == DYNAMIC_TYPE_ED25519) { + /* Nothing to do */ + sig->length = ED25519_SIG_SIZE; + } + #endif /* HAVE_ECC */ /* Advance state and proceed */ ssl->options.asyncState = TLS_ASYNC_DO; @@ -3892,6 +3913,21 @@ int SendTls13CertificateVerify(WOLFSSL* ssl) args->length = sig->length; } #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + if (ssl->hsType == DYNAMIC_TYPE_ED25519) { + ret = Ed25519Sign(ssl, args->sigData, args->sigDataSz, + args->verify + HASH_SIG_SIZE + VERIFY_HEADER, + &sig->length, (ed25519_key*)ssl->hsKey, + #if defined(HAVE_PK_CALLBACKS) + ssl->buffers.key->buffer, ssl->buffers.key->length, + ssl->Ed25519SignCtx + #else + NULL, 0, NULL + #endif + ); + args->length = sig->length; + } + #endif #ifndef NO_RSA if (ssl->hsType == DYNAMIC_TYPE_RSA) { /* restore verify pointer */ @@ -4154,6 +4190,10 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, } /* Check for public key of required type. */ + if (args->sigAlgo == ed25519_sa_algo && + !ssl->peerEd25519KeyPresent) { + WOLFSSL_MSG("Oops, peer sent ED25519 key but not in verify"); + } if (args->sigAlgo == ecc_dsa_sa_algo && !ssl->peerEccDsaKeyPresent) { WOLFSSL_MSG("Oops, peer sent ECC key but not in verify"); @@ -4191,6 +4231,20 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, ret = 0; } #endif + #ifdef HAVE_ED25519 + if (ssl->peerEd25519KeyPresent) { + WOLFSSL_MSG("Doing ED25519 peer cert verify"); + + args->sigData = (byte*)XMALLOC(MAX_SIG_DATA_SZ, ssl->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (args->sigData == NULL) { + ERROR_OUT(MEMORY_E, exit_dcv); + } + + CreateSigData(ssl, args->sigData, &args->sigDataSz, 1); + ret = 0; + } + #endif /* Advance state and proceed */ ssl->options.asyncState = TLS_ASYNC_DO; @@ -4237,6 +4291,23 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, ); } #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + if (ssl->peerEd25519KeyPresent) { + WOLFSSL_MSG("Doing ED25519 peer cert verify"); + + ret = Ed25519Verify(ssl, input + args->idx, args->sz, + args->sigData, args->sigDataSz, + ssl->peerEd25519Key, + #ifdef HAVE_PK_CALLBACKS + ssl->buffers.peerEd25519Key.buffer, + ssl->buffers.peerEd25519Key.length, + ssl->Ed25519VerifyCtx + #else + NULL, 0, NULL + #endif + ); + } + #endif /* Check for error */ if (ret != 0) { diff --git a/tests/suites.c b/tests/suites.c index 289c5ef46..cb37e203f 100644 --- a/tests/suites.c +++ b/tests/suites.c @@ -574,6 +574,16 @@ int SuiteTest(void) exit(EXIT_FAILURE); } #endif +#if defined(HAVE_CURVE25519) && defined(HAVE_ED25519) + /* add ED25519 certificate cipher suite tests */ + strcpy(argv0[1], "tests/test-ed25519.conf"); + printf("starting ED25519 extra cipher suite tests\n"); + test_harness(&args); + if (args.return_code != 0) { + printf("error from script %d\n", args.return_code); + exit(EXIT_FAILURE); + } +#endif #ifdef WOLFSSL_DTLS /* add dtls extra suites */ strcpy(argv0[1], "tests/test-dtls.conf"); diff --git a/tests/test-ed25519.conf b/tests/test-ed25519.conf new file mode 100644 index 000000000..cdd3ade35 --- /dev/null +++ b/tests/test-ed25519.conf @@ -0,0 +1,56 @@ +# server TLSv1.2 ECDHE-ECDSA-AES128-GCM-SHA256 +-v 3 +-l ECDHE-ECDSA-AES128-GCM-SHA256 +-c ./certs/ed25519/server-ed25519.pem +-k ./certs/ed25519/server-ed25519-key.pem + +# client TLSv1.2 ECDHE-ECDSA-AES128-GCM-SHA256 +-v 3 +-l ECDHE-ECDSA-AES128-GCM-SHA256 +-A ./certs/ed25519/root-ed25519.pem +-C + +# Enable when CRL for ED25519 certificates available. +# server TLSv1.2 ECDHE-ECDSA-AES128-GCM-SHA256 +#-v 3 +#-l ECDHE-ECDSA-AES128-GCM-SHA256 +#-c ./certs/ed25519/server-ed25519.pem +#-k ./certs/ed25519/server-ed25519-key.pem +#-A ./certs/ed25519/client-ed25519.pem + +# client TLSv1.2 ECDHE-ECDSA-AES128-GCM-SHA256 +#-v 3 +#-l ECDHE-ECDSA-AES128-GCM-SHA256 +#-c ./certs/ed25519/client-ed25519.pem +#-k ./certs/ed25519/client-ed25519-key.pem +#-A ./certs/ed25519/root-ed25519.pem +#-C + +# server TLSv1.3 TLS13-AES128-GCM-SHA256 +-v 4 +-l TLS13-AES128-GCM-SHA256 +-c ./certs/ed25519/server-ed25519.pem +-k ./certs/ed25519/server-ed25519-key.pem + +# client TLSv1.3 TLS13-AES128-GCM-SHA256 +-v 4 +-l TLS13-AES128-GCM-SHA256 +-A ./certs/ed25519/root-ed25519.pem +-C + +# Enable when CRL for ED25519 certificates available. +# server TLSv1.3 TLS13-AES128-GCM-SHA256 +#-v 4 +#-l TLS13-AES128-GCM-SHA256 +#-c ./certs/ed25519/server-ed25519.pem +#-k ./certs/ed25519/server-ed25519-key.pem +#-A ./certs/ed25519/client-ed25519.pem + +# client TLSv1.3 TLS13-AES128-GCM-SHA256 +#-v 4 +#-l TLS13-AES128-GCM-SHA256 +#-c ./certs/ed25519/client-ed25519.pem +#-k ./certs/ed25519/client-ed25519-key.pem +#-A ./certs/ed25519/root-ed25519.pem +#-C + diff --git a/tests/test-tls13.conf b/tests/test-tls13.conf index cf1e9f7f9..b0c2aa92f 100644 --- a/tests/test-tls13.conf +++ b/tests/test-tls13.conf @@ -93,3 +93,15 @@ -l TLS13-AES128-CCM-8-SHA256 -A ./certs/server-ecc.pem +# server TLSv1.3 TLS13-AES128-GCM-SHA256 +-v 4 +-l TLS13-AES128-GCM-SHA256 +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1.3 TLS13-AES128-GCM-SHA256 +-v 4 +-l TLS13-AES128-GCM-SHA256 +-A ./certs/server-ecc.pem +-t + diff --git a/tests/test.conf b/tests/test.conf index 933d001fd..e8223797e 100644 --- a/tests/test.conf +++ b/tests/test.conf @@ -2178,3 +2178,15 @@ -l ECDHE-RSA-AES128-SHA256 -j +# server TLSv1.2 ECDHE-EDCSA-CHACHA20-POLY1305 +-v 3 +-l ECDHE-ECDSA-CHACHA20-POLY1305 +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1.2 ECDHE-ECDSA-CHACHA20-POLY1305 +-v 3 +-l ECDHE-ECDSA-CHACHA20-POLY1305 +-A ./certs/server-ecc.pem +-t + diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index e3e647e07..51df86d6b 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -2502,7 +2502,7 @@ int wc_GetKeyOID(byte* key, word32 keySz, const byte** curveOID, word32* oidSz, } #endif /* HAVE_ECC */ #ifdef HAVE_ED25519 - if (*algoID != RSAk && *algoId != ECDSAk) { + if (*algoID != RSAk && *algoID != ECDSAk) { if (wc_ed25519_init(&ed25519) == 0) { if (wc_Ed25519PrivateKeyDecode(key, &tmpIdx, &ed25519, keySz) == 0) { @@ -3448,6 +3448,8 @@ static int GetKey(DecodedCert* cert) { int ret; + cert->pkCurveOID = ED25519k; + ret = CheckBitString(cert->source, &cert->srcIdx, &length, cert->maxIdx, 1, NULL); if (ret != 0) @@ -4637,7 +4639,7 @@ static int HashForSignature(const byte* buf, word32 bufSz, word32 sigOID, WOLFSSL_MSG("Hash for Signature has unsupported type"); } - return 0; + return ret; } /* Return codes: 0=Success, Negative (see error-crypt.h), ASN_SIG_CONFIRM_E */ @@ -10228,6 +10230,15 @@ int wc_Ed25519PrivateKeyDecode(const byte* input, word32* inOutIdx, if (input == NULL || inOutIdx == NULL || key == NULL || inSz == 0) return BAD_FUNC_ARG; + if (GetOctetString(input, inOutIdx, &privSz, inSz) >= 0) { + priv = input + *inOutIdx; + *inOutIdx += privSz; + + if (*inOutIdx != inSz) + return ASN_PARSE_E; + return wc_ed25519_import_private_only(priv, privSz, key); + } + if (GetSequence(input, inOutIdx, &length, inSz) < 0) return ASN_PARSE_E; endKeyIdx = *inOutIdx + length; diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 9487a7947..4293dd873 100755 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -72,6 +72,9 @@ #ifdef HAVE_ECC #include #endif +#ifdef HAVE_ED25519 + #include +#endif #ifdef HAVE_CURVE25519 #include #endif @@ -909,7 +912,7 @@ enum Misc { ECC_BYTE = 0xC0, /* ECC first cipher suite byte */ QSH_BYTE = 0xD0, /* Quantum-safe Handshake cipher suite */ CHACHA_BYTE = 0xCC, /* ChaCha first cipher suite */ - TLS13_BYTE = 0x13, /* TLS v.13 first byte of cipher suite */ + TLS13_BYTE = 0x13, /* TLS v1.3 first byte of cipher suite */ SEND_CERT = 1, SEND_BLANK_CERT = 2, @@ -1093,6 +1096,12 @@ enum Misc { ECDHE_SIZE = 32, /* ECHDE server size defaults to 256 bit */ MAX_EXPORT_ECC_SZ = 256, /* Export ANS X9.62 max future size */ + NEW_SA_MAJOR = 8, /* Most signicant byte used with new sig algos */ + ED25519_SA_MAJOR = 8, /* Most significant byte for ED25519 */ + ED25519_SA_MINOR = 7, /* Least significant byte for ED25519 */ + ED448_SA_MAJOR = 8, /* Most significant byte for ED448 */ + ED448_SA_MINOR = 8, /* Least significant byte for ED448 */ + #ifdef HAVE_QSH /* qsh handshake sends 600+ size keys over hello extensions */ MAX_HELLO_SZ = 2048, /* max client or server hello */ @@ -2263,6 +2272,12 @@ struct WOLFSSL_CTX { CallbackEccSign EccSignCb; /* User EccSign Callback handler */ CallbackEccVerify EccVerifyCb; /* User EccVerify Callback handler */ CallbackEccSharedSecret EccSharedSecretCb; /* User EccVerify Callback handler */ + #ifdef HAVE_ED25519 + /* User Ed25519Sign Callback handler */ + CallbackEd25519Sign Ed25519SignCb; + /* User Ed25519Verify Callback handler */ + CallbackEd25519Verify Ed25519VerifyCb; + #endif #ifdef HAVE_CURVE25519 /* User EccSharedSecret Callback handler */ CallbackX25519SharedSecret X25519SharedSecretCb; @@ -2374,7 +2389,8 @@ enum SignatureAlgorithm { rsa_sa_algo = 1, dsa_sa_algo = 2, ecc_dsa_sa_algo = 3, - rsa_pss_sa_algo = 8 + rsa_pss_sa_algo = 8, + ed25519_sa_algo = 9 }; @@ -2637,6 +2653,9 @@ typedef struct Buffers { #ifdef HAVE_ECC buffer peerEccDsaKey; /* we own for Ecc Verify Callbacks */ #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + buffer peerEd25519Key; /* for Ed25519 Verify Callbacks */ + #endif /* HAVE_ED25519 */ #ifndef NO_RSA buffer peerRsaKey; /* we own for Rsa Verify Callbacks */ #endif /* NO_RSA */ @@ -3134,6 +3153,10 @@ struct WOLFSSL { byte peerEccKeyPresent; byte peerEccDsaKeyPresent; byte eccTempKeyPresent; +#ifdef HAVE_ED25519 + ed25519_key* peerEd25519Key; + byte peerEd25519KeyPresent; +#endif #ifdef HAVE_CURVE25519 curve25519_key* peerX25519Key; byte peerX25519KeyPresent; @@ -3241,6 +3264,10 @@ struct WOLFSSL { void* EccSignCtx; /* Ecc Sign Callback Context */ void* EccVerifyCtx; /* Ecc Verify Callback Context */ void* EccSharedSecretCtx; /* Ecc Pms Callback Context */ + #ifdef HAVE_ED25519 + void* Ed25519SignCtx; /* ED25519 Sign Callback Context */ + void* Ed25519VerifyCtx; /* ED25519 Verify Callback Context */ + #endif #ifdef HAVE_CURVE25519 void* X25519SharedSecretCtx; /* X25519 Pms Callback Context */ #endif @@ -3472,6 +3499,15 @@ WOLFSSL_LOCAL int VerifyClientSuite(WOLFSSL* ssl); ecc_key* pub_key, byte* pubKeyDer, word32* pubKeySz, byte* out, word32* outlen, int side, void* ctx); #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + WOLFSSL_LOCAL int Ed25519Sign(WOLFSSL* ssl, const byte* in, word32 inSz, + byte* out, word32* outSz, ed25519_key* key, byte* keyBuf, + word32 keySz, void* ctx); + WOLFSSL_LOCAL int Ed25519Verify(WOLFSSL* ssl, const byte* in, + word32 inSz, const byte* msg, word32 msgSz, ed25519_key* key, + byte* keyBuf, word32 keySz, void* ctx); + #endif /* HAVE_ED25519 */ + #ifdef WOLFSSL_TRUST_PEER_CERT diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 9ae8cd9f5..7e573a398 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -1506,6 +1506,27 @@ WOLFSSL_API void wolfSSL_CTX_SetEccSharedSecretCb(WOLFSSL_CTX*, CallbackEccShar WOLFSSL_API void wolfSSL_SetEccSharedSecretCtx(WOLFSSL* ssl, void *ctx); WOLFSSL_API void* wolfSSL_GetEccSharedSecretCtx(WOLFSSL* ssl); +struct ed25519_key; +typedef int (*CallbackEd25519Sign)(WOLFSSL* ssl, + const unsigned char* in, unsigned int inSz, + unsigned char* out, unsigned int* outSz, + const unsigned char* keyDer, unsigned int keySz, + void* ctx); +WOLFSSL_API void wolfSSL_CTX_SetEd25519SignCb(WOLFSSL_CTX*, + CallbackEd25519Sign); +WOLFSSL_API void wolfSSL_SetEd25519SignCtx(WOLFSSL* ssl, void *ctx); +WOLFSSL_API void* wolfSSL_GetEd25519SignCtx(WOLFSSL* ssl); + +typedef int (*CallbackEd25519Verify)(WOLFSSL* ssl, + const unsigned char* sig, unsigned int sigSz, + const unsigned char* msg, unsigned int msgSz, + const unsigned char* keyDer, unsigned int keySz, + int* result, void* ctx); +WOLFSSL_API void wolfSSL_CTX_SetEd25519VerifyCb(WOLFSSL_CTX*, + CallbackEd25519Verify); +WOLFSSL_API void wolfSSL_SetEd25519VerifyCtx(WOLFSSL* ssl, void *ctx); +WOLFSSL_API void* wolfSSL_GetEd25519VerifyCtx(WOLFSSL* ssl); + struct curve25519_key; typedef int (*CallbackX25519SharedSecret)(WOLFSSL* ssl, struct curve25519_key* otherKey, diff --git a/wolfssl/test.h b/wolfssl/test.h index aab51b4e6..7535465af 100644 --- a/wolfssl/test.h +++ b/wolfssl/test.h @@ -24,6 +24,9 @@ #ifdef HAVE_ECC #include #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + #include + #endif /* HAVE_ED25519 */ #ifdef HAVE_CURVE25519 #include #endif /* HAVE_ECC */ @@ -1828,6 +1831,52 @@ static INLINE int myEccSharedSecret(WOLFSSL* ssl, ecc_key* otherKey, return ret; } +#ifdef HAVE_ED25519 +static INLINE int myEd25519Sign(WOLFSSL* ssl, const byte* in, word32 inSz, + byte* out, word32* outSz, const byte* key, word32 keySz, void* ctx) +{ + int ret; + word32 idx = 0; + ed25519_key myKey; + + (void)ssl; + (void)ctx; + + ret = wc_ed25519_init(&myKey); + if (ret == 0) { + ret = wc_Ed25519PrivateKeyDecode(key, &idx, &myKey, keySz); + if (ret == 0) + ret = wc_ed25519_sign_msg(in, inSz, out, outSz, &myKey); + wc_ed25519_free(&myKey); + } + + return ret; +} + + +static INLINE int myEd25519Verify(WOLFSSL* ssl, const byte* sig, word32 sigSz, + const byte* msg, word32 msgSz, const byte* key, word32 keySz, + int* result, void* ctx) +{ + int ret; + ed25519_key myKey; + + (void)ssl; + (void)ctx; + + ret = wc_ed25519_init(&myKey); + if (ret == 0) { + ret = wc_ed25519_import_public(key, keySz, &myKey); + if (ret == 0) { + ret = wc_ed25519_verify_msg(sig, sigSz, msg, msgSz, result, &myKey); + } + wc_ed25519_free(&myKey); + } + + return ret; +} +#endif /* HAVE_ED25519 */ + #ifdef HAVE_CURVE25519 static INLINE int myX25519SharedSecret(WOLFSSL* ssl, curve25519_key* otherKey, unsigned char* pubKeyDer, unsigned int* pubKeySz, @@ -2121,10 +2170,14 @@ static INLINE void SetupPkCallbacks(WOLFSSL_CTX* ctx, WOLFSSL* ssl) wolfSSL_CTX_SetEccSignCb(ctx, myEccSign); wolfSSL_CTX_SetEccVerifyCb(ctx, myEccVerify); wolfSSL_CTX_SetEccSharedSecretCb(ctx, myEccSharedSecret); - #ifdef HAVE_CURVE25519 - wolfSSL_CTX_SetX25519SharedSecretCb(ctx, myX25519SharedSecret); - #endif #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + wolfSSL_CTX_SetEd25519SignCb(ctx, myEd25519Sign); + wolfSSL_CTX_SetEd25519VerifyCb(ctx, myEd25519Verify); + #endif + #ifdef HAVE_CURVE25519 + wolfSSL_CTX_SetX25519SharedSecretCb(ctx, myX25519SharedSecret); + #endif #ifndef NO_RSA wolfSSL_CTX_SetRsaSignCb(ctx, myRsaSign); wolfSSL_CTX_SetRsaVerifyCb(ctx, myRsaVerify); diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index 42be1f71c..f2c5c9aa5 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -287,6 +287,7 @@ enum Ecc_Sum { ECC_SECP256K1_OID = 186, ECC_BRAINPOOLP256R1_OID = 104, ECC_X25519_OID = 365, + ECC_ED25519_OID = 256, ECC_BRAINPOOLP320R1_OID = 106, ECC_SECP384R1_OID = 210, ECC_BRAINPOOLP384R1_OID = 108,