From 58f523beba15eaa18e878df6f6cbb5e42e3b1e1e Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Fri, 27 Apr 2018 14:43:04 +1000 Subject: [PATCH 1/4] Allow Ed25519 private-only keys to work in TLS Change Ed25519 in TLS 1.2 to keep a copy of all the messages for certificate verification - interop with OpenSSL. --- certs/ed25519/client-ed25519-priv.der | Bin 0 -> 48 bytes certs/ed25519/client-ed25519-priv.pem | 3 + certs/ed25519/server-ed25519-priv.der | Bin 0 -> 48 bytes certs/ed25519/server-ed25519-priv.pem | 3 + examples/client/client.c | 4 + examples/server/server.c | 34 +++- src/internal.c | 278 ++++++++++++++++++-------- src/ssl.c | 14 +- src/tls13.c | 5 +- tests/test-ed25519.conf | 50 ++--- wolfcrypt/src/asn.c | 49 +++-- wolfcrypt/src/ed25519.c | 8 + wolfcrypt/test/test.c | 80 +++++++- wolfssl/internal.h | 6 + wolfssl/wolfcrypt/ed25519.h | 1 + 15 files changed, 392 insertions(+), 143 deletions(-) create mode 100644 certs/ed25519/client-ed25519-priv.der create mode 100644 certs/ed25519/client-ed25519-priv.pem create mode 100644 certs/ed25519/server-ed25519-priv.der create mode 100644 certs/ed25519/server-ed25519-priv.pem diff --git a/certs/ed25519/client-ed25519-priv.der b/certs/ed25519/client-ed25519-priv.der new file mode 100644 index 0000000000000000000000000000000000000000..e5a27a4117330b059cf37c364e9a802dcefbd0f4 GIT binary patch literal 48 zcmXreV`5}5U}a<0PAy Benchmark throughput using bytes and print stats\n"); +#ifdef HAVE_CRL + printf("-V Disable CRL\n"); +#endif #ifdef WOLFSSL_TRUST_PEER_CERT printf("-E Path to load trusted peer cert\n"); #endif @@ -462,7 +465,14 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) char input[80]; int ch; int version = SERVER_DEFAULT_VERSION; +#ifndef WOLFSSL_NO_CLIENT_AUTH int doCliCertCheck = 1; +#else + int doCliCertCheck = 0; +#endif +#ifdef HAVE_CRL + int disableCRL = 0; +#endif int useAnyAddr = 0; word16 port = wolfSSLPort; int usePsk = 0; @@ -601,7 +611,7 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) /* Not Used: h, m, z, F, M, T, V, W, X */ while ((ch = mygetopt(argc, argv, "?" "abc:defgijk:l:nop:q:rstuv:wxy" - "A:B:C:D:E:GH:IJKL:NO:PQR:S:TUYZ:" + "A:B:C:D:E:GH:IJKL:NO:PQR:S:TUVYZ:" "03:")) != -1) { switch (ch) { case '?' : @@ -616,6 +626,12 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) doCliCertCheck = 0; break; + case 'V' : + #ifdef HAVE_CRL + disableCRL = 1; + #endif + break; + case 'b' : useAnyAddr = 1; break; @@ -1286,6 +1302,7 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) wolfSSL_SetHsDoneCb(ssl, myHsDoneCb, NULL); #endif #ifdef HAVE_CRL + if (!disableCRL) { #ifdef HAVE_CRL_MONITOR crlFlags = CYASSL_CRL_MONITOR | CYASSL_CRL_START_MON; #endif @@ -1296,6 +1313,7 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) err_sys_ex(runWithErrors, "unable to load CRL"); if (CyaSSL_SetCRL_Cb(ssl, CRL_CallBack) != WOLFSSL_SUCCESS) err_sys_ex(runWithErrors, "unable to set CRL callback url"); + } #endif #ifdef HAVE_OCSP if (useOcsp) { @@ -1563,17 +1581,19 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) if (postHandAuth) { SSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER | - ((usePskPlus)? WOLFSSL_VERIFY_FAIL_EXCEPT_PSK : - WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT),0); + ((usePskPlus) ? WOLFSSL_VERIFY_FAIL_EXCEPT_PSK : + WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT), 0); if (SSL_CTX_load_verify_locations(ctx, verifyCert, 0) - != WOLFSSL_SUCCESS) { - err_sys_ex(runWithErrors, "can't load ca file, Please run from wolfSSL home dir"); + != WOLFSSL_SUCCESS) { + err_sys_ex(runWithErrors, "can't load ca file, Please run from " + "wolfSSL home dir"); } #ifdef WOLFSSL_TRUST_PEER_CERT if (trustCert) { if ((ret = wolfSSL_CTX_trust_peer_cert(ctx, trustCert, - WOLFSSL_FILETYPE_PEM)) != WOLFSSL_SUCCESS) { - err_sys_ex(runWithErrors, "can't load trusted peer cert file"); + WOLFSSL_FILETYPE_PEM)) != WOLFSSL_SUCCESS) { + err_sys_ex(runWithErrors, "can't load trusted peer cert " + "file"); } } #endif /* WOLFSSL_TRUST_PEER_CERT */ diff --git a/src/internal.c b/src/internal.c index 8df6575bb..66c5b45b1 100644 --- a/src/internal.c +++ b/src/internal.c @@ -103,7 +103,8 @@ WOLFSSL_CALLBACKS needs LARGE_STATIC_BUFFERS, please add LARGE_STATIC_BUFFERS #ifndef NO_WOLFSSL_SERVER static int DoClientKeyExchange(WOLFSSL* ssl, byte* input, word32*, word32); - #if !defined(NO_RSA) || defined(HAVE_ECC) + #if (!defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519)) && \ + !defined(WOLFSSL_NO_CLIENT_AUTH) static int DoCertificateVerify(WOLFSSL* ssl, byte*, word32*, word32); #endif #ifdef WOLFSSL_DTLS @@ -2692,7 +2693,7 @@ void InitSuites(Suites* suites, ProtocolVersion pv, int keySz, word16 haveRSA, * * input The encoded signature algorithm. * hashalgo The hash algorithm. - * hsType The signature type. + * hsType The signature type. */ static INLINE void DecodeSigAlg(const byte* input, byte* hashAlgo, byte* hsType) { @@ -2888,35 +2889,37 @@ static INLINE void EncodeSigAlg(byte hashAlgo, byte hsType, byte* output) (void)output; } +#if !defined(WOLFSSL_NO_CLIENT_AUTH) static void SetDigest(WOLFSSL* ssl, int hashAlgo) { switch (hashAlgo) { - #ifndef NO_SHA + #ifndef NO_SHA case sha_mac: ssl->buffers.digest.buffer = ssl->hsHashes->certHashes.sha; ssl->buffers.digest.length = WC_SHA_DIGEST_SIZE; break; - #endif /* !NO_SHA */ - #ifndef NO_SHA256 + #endif /* !NO_SHA */ + #ifndef NO_SHA256 case sha256_mac: ssl->buffers.digest.buffer = ssl->hsHashes->certHashes.sha256; ssl->buffers.digest.length = WC_SHA256_DIGEST_SIZE; break; - #endif /* !NO_SHA256 */ - #ifdef WOLFSSL_SHA384 + #endif /* !NO_SHA256 */ + #ifdef WOLFSSL_SHA384 case sha384_mac: ssl->buffers.digest.buffer = ssl->hsHashes->certHashes.sha384; ssl->buffers.digest.length = WC_SHA384_DIGEST_SIZE; break; - #endif /* WOLFSSL_SHA384 */ - #ifdef WOLFSSL_SHA512 + #endif /* WOLFSSL_SHA384 */ + #ifdef WOLFSSL_SHA512 case sha512_mac: ssl->buffers.digest.buffer = ssl->hsHashes->certHashes.sha512; ssl->buffers.digest.length = WC_SHA512_DIGEST_SIZE; break; - #endif /* WOLFSSL_SHA512 */ + #endif /* WOLFSSL_SHA512 */ } /* switch */ } +#endif /* !WOLFSSL_NO_CLIENT_AUTH */ #endif /* !NO_CERTS */ #ifndef NO_RSA @@ -3632,6 +3635,43 @@ int EccMakeKey(WOLFSSL* ssl, ecc_key* key, ecc_key* peer) #endif /* HAVE_ECC */ #ifdef HAVE_ED25519 +/* Check whether the key contains a public key. + * If not then pull it out of the leaf certificate. + * + * ssl SSL/TLS object. + * returns MEMORY_E when unable to allocate memory, a parsing error, otherwise + * 0 on success. + */ +int Ed25519CheckPubKey(WOLFSSL* ssl) +{ + ed25519_key* key = (ed25519_key*)ssl->hsKey; + int ret = 0; + + /* Public key required for signing. */ + if (!key->pubKeySet) { + DerBuffer* leaf = ssl->buffers.certificate; + DecodedCert* cert = (DecodedCert*)XMALLOC(sizeof(*cert), + ssl->heap, DYNAMIC_TYPE_DCERT); + if (cert == NULL) + ret = MEMORY_E; + + if (ret == 0) { + InitDecodedCert(cert, leaf->buffer, leaf->length, ssl->heap); + ret = DecodeToKey(cert, 0); + } + if (ret == 0) { + ret = wc_ed25519_import_public(cert->publicKey, cert->pubKeySize, + key); + } + if (cert != NULL) { + FreeDecodedCert(cert); + XFREE(cert, ssl->heap, DYNAMIC_TYPE_DCERT); + } + } + + return ret; +} + /* Sign the data using EdDSA and key using X25519. * * ssl SSL object. @@ -4287,6 +4327,10 @@ void FreeHandshakeHashes(WOLFSSL* ssl) #ifdef WOLFSSL_SHA512 wc_Sha512Free(&ssl->hsHashes->hashSha512); #endif + #if defined(HAVE_ED25519) && !defined(WOLFSSL_NO_CLIENT_AUTH) + if (ssl->hsHashes->messages != NULL) + XFREE(ssl->hsHashes->messages, ssl->heap, DYNAMIC_TYPE_HASHES); + #endif XFREE(ssl->hsHashes, ssl->heap, DYNAMIC_TYPE_HASHES); ssl->hsHashes = NULL; @@ -5994,7 +6038,36 @@ ProtocolVersion MakeDTLSv1_2(void) return (word32)XTIME(0); } #endif +#if defined(HAVE_ED25519) && !defined(WOLFSSL_NO_CLIENT_AUTH) +/* Store the message for use with CertificateVerify using Ed25519. + * + * ssl SSL/TLS object. + * data Message to store. + * sz Size of message to store. + * returns MEMORY_E if not able to reallocate, otherwise 0. + */ +static int Ed25519Update(WOLFSSL* ssl, const byte* data, int sz) +{ + int ret = 0; + byte* msgs; + if (!IsAtLeastTLSv1_3(ssl->version) || ssl->options.downgrade) { + msgs = (byte*)XREALLOC(ssl->hsHashes->messages, + ssl->hsHashes->length + sz, ssl->heap, + DYNAMIC_TYPE_HASHES); + if (msgs == NULL) + ret = MEMORY_E; + if (ret == 0) { + ssl->hsHashes->messages = msgs; + XMEMCPY(msgs + ssl->hsHashes->length, data, sz); + ssl->hsHashes->prevLen = ssl->hsHashes->length; + ssl->hsHashes->length += sz; + } + } + + return ret; +} +#endif /* HAVE_ED25519 && !WOLFSSL_NO_CLIENT_AUTH */ #ifndef NO_CERTS int HashOutputRaw(WOLFSSL* ssl, const byte* output, int sz) @@ -6012,30 +6085,35 @@ int HashOutputRaw(WOLFSSL* ssl, const byte* output, int sz) ssl->fuzzerCb(ssl, output, sz, FUZZ_HASH, ssl->fuzzerCtx); #endif #ifndef NO_OLD_TLS -#ifndef NO_SHA - wc_ShaUpdate(&ssl->hsHashes->hashSha, output, sz); -#endif -#ifndef NO_MD5 - wc_Md5Update(&ssl->hsHashes->hashMd5, output, sz); -#endif + #ifndef NO_SHA + wc_ShaUpdate(&ssl->hsHashes->hashSha, output, sz); + #endif + #ifndef NO_MD5 + wc_Md5Update(&ssl->hsHashes->hashMd5, output, sz); + #endif #endif /* NO_OLD_TLS */ if (IsAtLeastTLSv1_2(ssl)) { -#ifndef NO_SHA256 + #ifndef NO_SHA256 ret = wc_Sha256Update(&ssl->hsHashes->hashSha256, output, sz); if (ret != 0) return ret; -#endif -#ifdef WOLFSSL_SHA384 + #endif + #ifdef WOLFSSL_SHA384 ret = wc_Sha384Update(&ssl->hsHashes->hashSha384, output, sz); if (ret != 0) return ret; -#endif -#ifdef WOLFSSL_SHA512 + #endif + #ifdef WOLFSSL_SHA512 ret = wc_Sha512Update(&ssl->hsHashes->hashSha512, output, sz); if (ret != 0) return ret; -#endif + #endif + #if defined(HAVE_ED25519) && !defined(WOLFSSL_NO_CLIENT_AUTH) + ret = Ed25519Update(ssl, output, sz); + if (ret != 0) + return ret; + #endif } return ret; @@ -6063,30 +6141,35 @@ int HashOutput(WOLFSSL* ssl, const byte* output, int sz, int ivSz) } #endif #ifndef NO_OLD_TLS -#ifndef NO_SHA - wc_ShaUpdate(&ssl->hsHashes->hashSha, adj, sz); -#endif -#ifndef NO_MD5 - wc_Md5Update(&ssl->hsHashes->hashMd5, adj, sz); -#endif + #ifndef NO_SHA + wc_ShaUpdate(&ssl->hsHashes->hashSha, adj, sz); + #endif + #ifndef NO_MD5 + wc_Md5Update(&ssl->hsHashes->hashMd5, adj, sz); + #endif #endif if (IsAtLeastTLSv1_2(ssl)) { -#ifndef NO_SHA256 + #ifndef NO_SHA256 ret = wc_Sha256Update(&ssl->hsHashes->hashSha256, adj, sz); if (ret != 0) return ret; -#endif -#ifdef WOLFSSL_SHA384 + #endif + #ifdef WOLFSSL_SHA384 ret = wc_Sha384Update(&ssl->hsHashes->hashSha384, adj, sz); if (ret != 0) return ret; -#endif -#ifdef WOLFSSL_SHA512 + #endif + #ifdef WOLFSSL_SHA512 ret = wc_Sha512Update(&ssl->hsHashes->hashSha512, adj, sz); if (ret != 0) return ret; -#endif + #endif + #if defined(HAVE_ED25519) && !defined(WOLFSSL_NO_CLIENT_AUTH) + ret = Ed25519Update(ssl, adj, sz); + if (ret != 0) + return ret; + #endif } return ret; @@ -6116,30 +6199,35 @@ int HashInput(WOLFSSL* ssl, const byte* input, int sz) } #ifndef NO_OLD_TLS -#ifndef NO_SHA - wc_ShaUpdate(&ssl->hsHashes->hashSha, adj, sz); -#endif -#ifndef NO_MD5 - wc_Md5Update(&ssl->hsHashes->hashMd5, adj, sz); -#endif + #ifndef NO_SHA + wc_ShaUpdate(&ssl->hsHashes->hashSha, adj, sz); + #endif + #ifndef NO_MD5 + wc_Md5Update(&ssl->hsHashes->hashMd5, adj, sz); + #endif #endif if (IsAtLeastTLSv1_2(ssl)) { -#ifndef NO_SHA256 + #ifndef NO_SHA256 ret = wc_Sha256Update(&ssl->hsHashes->hashSha256, adj, sz); if (ret != 0) return ret; -#endif -#ifdef WOLFSSL_SHA384 + #endif + #ifdef WOLFSSL_SHA384 ret = wc_Sha384Update(&ssl->hsHashes->hashSha384, adj, sz); if (ret != 0) return ret; -#endif -#ifdef WOLFSSL_SHA512 + #endif + #ifdef WOLFSSL_SHA512 ret = wc_Sha512Update(&ssl->hsHashes->hashSha512, adj, sz); if (ret != 0) return ret; -#endif + #endif + #if defined(HAVE_ED25519) && !defined(WOLFSSL_NO_CLIENT_AUTH) + ret = Ed25519Update(ssl, adj, sz); + if (ret != 0) + return ret; + #endif } return ret; @@ -9185,7 +9273,7 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx, } break; } - #endif /* HAVE_ECC */ + #endif /* HAVE_ED25519 */ default: break; } @@ -9408,7 +9496,7 @@ static int DoCertificate(WOLFSSL* ssl, byte* input, word32* inOutIdx, int ret; WOLFSSL_START(WC_FUNC_CERTIFICATE_DO); - WOLFSSL_ENTER("DoCertificateVerify"); + WOLFSSL_ENTER("DoCertificate"); ret = ProcessPeerCerts(ssl, input, inOutIdx, size); @@ -9416,7 +9504,7 @@ static int DoCertificate(WOLFSSL* ssl, byte* input, word32* inOutIdx, ssl->options.serverState = SERVER_CERT_COMPLETE; #endif - WOLFSSL_LEAVE("DoCertificateVerify", ret); + WOLFSSL_LEAVE("DoCertificate", ret); WOLFSSL_END(WC_FUNC_CERTIFICATE_DO); return ret; @@ -10231,12 +10319,13 @@ static int DoHandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, ret = DoClientKeyExchange(ssl, input, inOutIdx, size); break; -#if !defined(NO_RSA) || defined(HAVE_ECC) +#if (!defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519)) && \ + !defined(WOLFSSL_NO_CLIENT_AUTH) case certificate_verify: WOLFSSL_MSG("processing certificate verify"); ret = DoCertificateVerify(ssl, input, inOutIdx, size); break; -#endif /* !NO_RSA || HAVE_ECC */ +#endif /* (!NO_RSA || HAVE_ECC || HAVE_ED25519) && !WOLFSSL_NO_CLIENT_AUTH */ #endif /* !NO_WOLFSSL_SERVER */ @@ -13582,6 +13671,7 @@ int SendFinished(WOLFSSL* ssl) #ifndef NO_CERTS +#if !defined(NO_WOLFSSL_SERVER) || !defined(WOLFSSL_NO_CLIENT_AUTH) /* handle generation of certificate (11) */ int SendCertificate(WOLFSSL* ssl) { @@ -13845,6 +13935,7 @@ int SendCertificate(WOLFSSL* ssl) return ret; } +#endif /* !NO_WOLFSSL_SERVER || !WOLFSSL_NO_CLIENT_AUTH */ /* handle generation of certificate_request (13) */ int SendCertificateRequest(WOLFSSL* ssl) @@ -17751,7 +17842,7 @@ static int DoServerKeyExchange(WOLFSSL* ssl, const byte* input, } break; } - #endif /* HAVE_ECC */ + #endif /* HAVE_ED25519 */ default: ret = ALGO_ID_E; @@ -17871,7 +17962,7 @@ static int DoServerKeyExchange(WOLFSSL* ssl, const byte* input, break; } - #endif /* HAVE_ECC */ + #endif /* HAVE_ED25519 */ default: ret = ALGO_ID_E; @@ -17985,7 +18076,7 @@ static int DoServerKeyExchange(WOLFSSL* ssl, const byte* input, case ed25519_sa_algo: /* Nothing to do in this algo */ break; - #endif /* HAVE_ECC */ + #endif /* HAVE_ED25519 */ default: ret = ALGO_ID_E; } /* switch (sigAlgo) */ @@ -19627,9 +19718,9 @@ int DecodePrivateKey(WOLFSSL *ssl, word16* length) } #endif #ifdef HAVE_ED25519 -#if !defined(NO_RSA) || defined(HAVE_ECC) - FreeKey(ssl, ssl->hsType, (void**)&ssl->hsKey); -#endif + #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); @@ -19637,13 +19728,13 @@ int DecodePrivateKey(WOLFSSL *ssl, word16* length) goto exit_dpk; } -#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 + #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 /* Set start of data to beginning of buffer. */ idx = 0; @@ -19665,7 +19756,7 @@ int DecodePrivateKey(WOLFSSL *ssl, word16* length) goto exit_dpk; } -#endif +#endif /* HAVE_ED25519 */ (void)idx; (void)keySz; @@ -19675,6 +19766,7 @@ exit_dpk: } +#ifndef WOLFSSL_NO_CLIENT_AUTH typedef struct ScvArgs { byte* output; /* not allocated */ #ifndef NO_RSA @@ -19883,6 +19975,13 @@ int SendCertificateVerify(WOLFSSL* ssl) c16toa(args->length, args->verify + args->extraSz); } #endif /* !NO_RSA */ + #ifdef HAVE_ED25519 + if (args->sigAlgo == ed25519_sa_algo) { + ret = Ed25519CheckPubKey(ssl); + if (ret != 0) + goto exit_scv; + } + #endif /* HAVE_ED25519 */ /* Advance state and proceed */ ssl->options.asyncState = TLS_ASYNC_DO; @@ -19913,7 +20012,7 @@ int SendCertificateVerify(WOLFSSL* ssl) ed25519_key* key = (ed25519_key*)ssl->hsKey; ret = Ed25519Sign(ssl, - ssl->buffers.digest.buffer, ssl->buffers.digest.length, + ssl->hsHashes->messages, ssl->hsHashes->length, ssl->buffers.sig.buffer, &ssl->buffers.sig.length, key, #ifdef HAVE_PK_CALLBACKS @@ -19924,7 +20023,7 @@ int SendCertificateVerify(WOLFSSL* ssl) #endif ); } - #endif /* HAVE_ECC */ + #endif /* HAVE_ED25519 */ #ifndef NO_RSA if (ssl->hsType == DYNAMIC_TYPE_RSA) { RsaKey* key = (RsaKey*)ssl->hsKey; @@ -20133,6 +20232,7 @@ exit_scv: return ret; } +#endif /* WOLFSSL_NO_CLIENT_AUTH */ #endif /* NO_CERTS */ @@ -21330,13 +21430,17 @@ 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; } + #ifdef HAVE_ED25519 + case ed25519_sa_algo: + ret = Ed25519CheckPubKey(ssl); + if (ret != 0) + goto exit_sske; + break; + #endif /* HAVE_ED25519 */ } /* switch(ssl->specs.sig_algo) */ break; } @@ -21796,18 +21900,9 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, } #endif case ecc_dsa_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; - } #ifdef HAVE_ED25519 case ed25519_sa_algo: + #endif { /* Now that we know the real sig size, write it. */ c16toa((word16)args->sigSz, @@ -21818,7 +21913,6 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, args->sendSz += args->sigSz - args->tmpSigSz; break; } - #endif default: ERROR_OUT(ALGO_ID_E, exit_sske); /* unsupported type */ } /* switch(ssl->specs.sig_algo) */ @@ -22977,7 +23071,8 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, } -#if !defined(NO_RSA) || defined(HAVE_ECC) +#if (!defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519)) && \ + !defined(WOLFSSL_NO_CLIENT_AUTH) typedef struct DcvArgs { byte* output; /* not allocated */ @@ -23179,6 +23274,23 @@ 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"); + + ret = Ed25519Verify(ssl, + input + args->idx, args->sz, + ssl->hsHashes->messages, ssl->hsHashes->prevLen, + ssl->peerEd25519Key, + #ifdef HAVE_PK_CALLBACKS + &ssl->buffers.peerEd25519Key, + ssl->Ed25519VerifyCtx + #else + NULL, NULL + #endif + ); + } + #endif /* HAVE_ED25519 */ /* Check for error */ if (ret != 0) { @@ -23311,7 +23423,7 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, return ret; } -#endif /* !NO_RSA || HAVE_ECC */ +#endif /* (!NO_RSA || HAVE_ECC || HAVE_ED25519) && !WOLFSSL_NO_CLIENT_AUTH */ /* handle generation of server_hello_done (14) */ int SendServerHelloDone(WOLFSSL* ssl) diff --git a/src/ssl.c b/src/ssl.c index 766919905..10adf8b3b 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -8659,11 +8659,11 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, FALL_THROUGH; case FIRST_REPLY_DONE : - #ifdef WOLFSSL_TLS13 - if (ssl->options.tls1_3) - return wolfSSL_connect_TLSv13(ssl); - #endif - #ifndef NO_CERTS + #if !defined(NO_CERTS) && !defined(WOLFSSL_NO_CLIENT_AUTH) + #ifdef WOLFSSL_TLS13 + if (ssl->options.tls1_3) + return wolfSSL_connect_TLSv13(ssl); + #endif if (ssl->options.sendVerify) { if ( (ssl->error = SendCertificate(ssl)) != 0) { WOLFSSL_ERROR(ssl->error); @@ -8695,7 +8695,7 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, FALL_THROUGH; case FIRST_REPLY_SECOND : - #ifndef NO_CERTS + #if !defined(NO_CERTS) && !defined(WOLFSSL_NO_CLIENT_AUTH) if (ssl->options.sendVerify) { if ( (ssl->error = SendCertificateVerify(ssl)) != 0) { WOLFSSL_ERROR(ssl->error); @@ -8703,7 +8703,7 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, } WOLFSSL_MSG("sent: certificate verify"); } - #endif + #endif /* !NO_CERTS && !WOLFSSL_NO_CLIENT_AUTH */ ssl->options.connectState = FIRST_REPLY_THIRD; WOLFSSL_MSG("connect state: FIRST_REPLY_THIRD"); FALL_THROUGH; diff --git a/src/tls13.c b/src/tls13.c index 35a371845..ce444ea47 100755 --- a/src/tls13.c +++ b/src/tls13.c @@ -5252,7 +5252,10 @@ static int SendTls13CertificateVerify(WOLFSSL* ssl) #endif /* HAVE_ECC */ #ifdef HAVE_ED25519 if (ssl->hsType == DYNAMIC_TYPE_ED25519) { - /* Nothing to do */ + ret = Ed25519CheckPubKey(ssl); + if (ret < 0) { + ERROR_OUT(ret, exit_scv); + } sig->length = ED25519_SIG_SIZE; } #endif /* HAVE_ECC */ diff --git a/tests/test-ed25519.conf b/tests/test-ed25519.conf index cc68ba2d7..e13c67b18 100644 --- a/tests/test-ed25519.conf +++ b/tests/test-ed25519.conf @@ -10,21 +10,22 @@ -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 +-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 +-V +# Remove -V when CRL for ED25519 certificates available. # 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 +-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 @@ -40,16 +41,19 @@ # 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 +-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 +-V +# Remove -V when CRL for ED25519 certificates available. # 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 +-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/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index fafaf3f21..a0a5fee08 100755 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -12226,29 +12226,38 @@ int wc_Ed25519PrivateKeyDecode(const byte* input, word32* inOutIdx, if (input == NULL || inOutIdx == NULL || key == NULL || inSz == 0) return BAD_FUNC_ARG; - if (GetSequence(input, inOutIdx, &length, inSz) < 0) - return ASN_PARSE_E; - endKeyIdx = *inOutIdx + length; + if (GetSequence(input, inOutIdx, &length, inSz) >= 0) { + endKeyIdx = *inOutIdx + length; - if (GetMyVersion(input, inOutIdx, &version, inSz) < 0) - return ASN_PARSE_E; - if (version != 0) { - WOLFSSL_MSG("Unrecognized version of ED25519 private key"); - return ASN_PARSE_E; + if (GetMyVersion(input, inOutIdx, &version, inSz) < 0) + return ASN_PARSE_E; + if (version != 0) { + WOLFSSL_MSG("Unrecognized version of ED25519 private key"); + return ASN_PARSE_E; + } + + if (GetAlgoId(input, inOutIdx, &oid, oidKeyType, inSz) < 0) + return ASN_PARSE_E; + if (oid != ED25519k) + return ASN_PARSE_E; + + if (GetOctetString(input, inOutIdx, &length, inSz) < 0) + return ASN_PARSE_E; + + if (GetOctetString(input, inOutIdx, &privSz, inSz) < 0) + return ASN_PARSE_E; + + priv = input + *inOutIdx; + *inOutIdx += privSz; } + else { + if (GetOctetString(input, inOutIdx, &privSz, inSz) < 0) + return ASN_PARSE_E; - if (GetAlgoId(input, inOutIdx, &oid, oidKeyType, inSz) < 0) - return ASN_PARSE_E; - if (oid != ED25519k) - return ASN_PARSE_E; - - if (GetOctetString(input, inOutIdx, &length, inSz) < 0) - return ASN_PARSE_E; - - if (GetOctetString(input, inOutIdx, &privSz, inSz) < 0) - return ASN_PARSE_E; - priv = input + *inOutIdx; - *inOutIdx += privSz; + priv = input + *inOutIdx; + *inOutIdx += privSz; + endKeyIdx = *inOutIdx; + } if (endKeyIdx == (int)*inOutIdx) { ret = wc_ed25519_import_private_only(priv, privSz, key); diff --git a/wolfcrypt/src/ed25519.c b/wolfcrypt/src/ed25519.c index 633eb5c07..12d784347 100644 --- a/wolfcrypt/src/ed25519.c +++ b/wolfcrypt/src/ed25519.c @@ -90,6 +90,8 @@ int wc_ed25519_make_key(WC_RNG* rng, int keySz, ed25519_key* key) /* put public key after private key, on the same buffer */ XMEMMOVE(key->k + ED25519_KEY_SIZE, key->p, ED25519_PUB_KEY_SIZE); + key->pubKeySet = 1; + return ret; } @@ -121,6 +123,8 @@ int wc_ed25519_sign_msg(const byte* in, word32 inlen, byte* out, /* sanity check on arguments */ if (in == NULL || out == NULL || outLen == NULL || key == NULL) return BAD_FUNC_ARG; + if (!key->pubKeySet) + return BAD_FUNC_ARG; /* check and set up out length */ if (*outLen < ED25519_SIG_SIZE) { @@ -370,6 +374,7 @@ int wc_ed25519_import_public(const byte* in, word32 inLen, ed25519_key* key) pubKey.Y = key->pointY; LTC_PKHA_Ed25519_PointDecompress(key->p, ED25519_PUB_KEY_SIZE, &pubKey); #endif + key->pubKeySet = 1; return 0; } @@ -389,6 +394,8 @@ int wc_ed25519_import_public(const byte* in, word32 inLen, ed25519_key* key) ret = ge_compress_key(key->p, in+1, in+1+ED25519_PUB_KEY_SIZE, ED25519_PUB_KEY_SIZE); #endif /* FREESCALE_LTC_ECC */ + if (ret == 0) + key->pubKeySet = 1; return ret; } @@ -403,6 +410,7 @@ int wc_ed25519_import_public(const byte* in, word32 inLen, ed25519_key* key) pubKey.Y = key->pointY; LTC_PKHA_Ed25519_PointDecompress(key->p, ED25519_PUB_KEY_SIZE, &pubKey); #endif + key->pubKeySet = 1; return 0; } diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 30deba40a..df451da0f 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -17115,6 +17115,38 @@ int ed25519_test(void) 0 /*sizeof(msg1)*/, sizeof(msg4) }; + static byte privateEd25519[] = { + 0x30,0x2e,0x02,0x01,0x00,0x30,0x05,0x06, + 0x03,0x2b,0x65,0x70,0x04,0x22,0x04,0x20, + 0x9d,0x61,0xb1,0x9d,0xef,0xfd,0x5a,0x60, + 0xba,0x84,0x4a,0xf4,0x92,0xec,0x2c,0xc4, + 0x44,0x49,0xc5,0x69,0x7b,0x32,0x69,0x19, + 0x70,0x3b,0xac,0x03,0x1c,0xae,0x7f,0x60 + }; + static byte publicEd25519[] = { + 0x30,0x2a,0x30,0x05,0x06,0x03,0x2b,0x65, + 0x70,0x03,0x21,0x00,0xd7,0x5a,0x98,0x01, + 0x82,0xb1,0x0a,0xb7,0xd5,0x4b,0xfe,0xd3, + 0xc9,0x64,0x07,0x3a,0x0e,0xe1,0x72,0xf3, + 0xda,0xa6,0x23,0x25,0xaf,0x02,0x1a,0x68, + 0xf7,0x07,0x51,0x1a + }; + static byte privPubEd25519[] = { + 0x30,0x52,0x02,0x01,0x00,0x30,0x05,0x06, + 0x03,0x2b,0x65,0x70,0x04,0x22,0x04,0x20, + 0x9d,0x61,0xb1,0x9d,0xef,0xfd,0x5a,0x60, + 0xba,0x84,0x4a,0xf4,0x92,0xec,0x2c,0xc4, + 0x44,0x49,0xc5,0x69,0x7b,0x32,0x69,0x19, + 0x70,0x3b,0xac,0x03,0x1c,0xae,0x7f,0x60, + 0xa1,0x22,0x04,0x20,0xd7,0x5a,0x98,0x01, + 0x82,0xb1,0x0a,0xb7,0xd5,0x4b,0xfe,0xd3, + 0xc9,0x64,0x07,0x3a,0x0e,0xe1,0x72,0xf3, + 0xda,0xa6,0x23,0x25,0xaf,0x02,0x1a,0x68, + 0xf7,0x07,0x51,0x1a + }; + word32 idx; + ed25519_key key3; + #endif /* HAVE_ED25519_SIGN && HAVE_ED25519_KEY_EXPORT && HAVE_ED25519_KEY_IMPORT */ /* create ed25519 keys */ @@ -17128,6 +17160,7 @@ int ed25519_test(void) wc_ed25519_init(&key); wc_ed25519_init(&key2); + wc_ed25519_init(&key3); wc_ed25519_make_key(&rng, ED25519_KEY_SIZE, &key); wc_ed25519_make_key(&rng, ED25519_KEY_SIZE, &key2); @@ -17145,8 +17178,7 @@ int ed25519_test(void) pKeySz[i], &key) != 0) return -8901 - i; - if (wc_ed25519_sign_msg(msgs[i], msgSz[i], out, &outlen, &key) - != 0) + if (wc_ed25519_sign_msg(msgs[i], msgSz[i], out, &outlen, &key) != 0) return -8911 - i; if (XMEMCMP(out, sigs[i], 64)) @@ -17196,6 +17228,50 @@ int ed25519_test(void) return -9011 - i; #endif /* HAVE_ED25519_VERIFY */ } + + /* Try ASN.1 encoded private-only key and public key. */ + idx = 0; + if (wc_Ed25519PrivateKeyDecode(privateEd25519, &idx, &key3, + sizeof(privateEd25519)) != 0) + return -7230 - i; + + if (wc_ed25519_sign_msg(msgs[0], msgSz[0], out, &outlen, &key3) + != BAD_FUNC_ARG) + return -7231 - i; + + idx = 0; + if (wc_Ed25519PublicKeyDecode(publicEd25519, &idx, &key3, + sizeof(publicEd25519)) != 0) + return -7232 - i; + + if (wc_ed25519_sign_msg(msgs[0], msgSz[0], out, &outlen, &key3) != 0) + return -7233 - i; + + if (XMEMCMP(out, sigs[0], 64)) + return -7234 - i; + +#if defined(HAVE_ED25519_VERIFY) + /* test verify on good msg */ + if (wc_ed25519_verify_msg(out, outlen, msgs[0], msgSz[0], &verify, &key3) + != 0 || verify != 1) + return -7233 - i; +#endif /* HAVE_ED25519_VERIFY */ + + wc_ed25519_free(&key3); + wc_ed25519_init(&key3); + + idx = 0; + if (wc_Ed25519PrivateKeyDecode(privPubEd25519, &idx, &key3, + sizeof(privPubEd25519)) != 0) + return -7230 - i; + + if (wc_ed25519_sign_msg(msgs[0], msgSz[0], out, &outlen, &key3) != 0) + return -7233 - i; + + if (XMEMCMP(out, sigs[0], 64)) + return -7234 - i; + + wc_ed25519_free(&key3); #endif /* HAVE_ED25519_SIGN && HAVE_ED25519_KEY_EXPORT && HAVE_ED25519_KEY_IMPORT */ /* clean up keys when done */ diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 09295cbc0..de1da1212 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -3349,6 +3349,11 @@ typedef struct HS_Hashes { #ifdef WOLFSSL_SHA512 wc_Sha512 hashSha512; /* sha512 hash of handshake msgs */ #endif +#if defined(HAVE_ED25519) && !defined(WOLFSSL_NO_CLIENT_AUTH) + byte* messages; /* handshake messages */ + int length; /* length of handhsake messages' data */ + int prevLen; /* length of messages but last */ +#endif } HS_Hashes; @@ -3875,6 +3880,7 @@ WOLFSSL_LOCAL int wolfSSL_GetMaxRecordSize(WOLFSSL* ssl, int maxFragment); word32* outlen, int side, void* ctx); #endif /* HAVE_ECC */ #ifdef HAVE_ED25519 + WOLFSSL_LOCAL int Ed25519CheckPubKey(WOLFSSL* ssl); WOLFSSL_LOCAL int Ed25519Sign(WOLFSSL* ssl, const byte* in, word32 inSz, byte* out, word32* outSz, ed25519_key* key, DerBuffer* keyBufInfo, void* ctx); diff --git a/wolfssl/wolfcrypt/ed25519.h b/wolfssl/wolfcrypt/ed25519.h index 82aa41062..e3950c3ea 100644 --- a/wolfssl/wolfcrypt/ed25519.h +++ b/wolfssl/wolfcrypt/ed25519.h @@ -77,6 +77,7 @@ struct ed25519_key { byte pointX[ED25519_KEY_SIZE]; /* recovered X coordinate */ byte pointY[ED25519_KEY_SIZE]; /* Y coordinate is the public key with The most significant bit of the final octet always zero. */ #endif + int pubKeySet:1; #ifdef WOLFSSL_ASYNC_CRYPT WC_ASYNC_DEV asyncDev; #endif From 9358edf5dd46bb05de85378367f77c73de8a0392 Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Wed, 9 May 2018 08:43:22 +1000 Subject: [PATCH 2/4] Fixes from code review Include new private key files in release. Set messages field to NULL after free. --- certs/include.am | 6 +++++- src/internal.c | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/certs/include.am b/certs/include.am index 55e8632f2..7a227aa95 100755 --- a/certs/include.am +++ b/certs/include.am @@ -72,6 +72,8 @@ EXTRA_DIST += \ certs/ed25519/client-ed25519-key.der \ certs/ed25519/client-ed25519-key.pem \ certs/ed25519/client-ed25519.pem \ + certs/ed25519/client-ed25519-priv.pem \ + certs/ed25519/client-ed25519-priv.pem \ certs/ed25519/root-ed25519.der \ certs/ed25519/root-ed25519-key.der \ certs/ed25519/root-ed25519-key.pem \ @@ -79,7 +81,9 @@ EXTRA_DIST += \ certs/ed25519/server-ed25519.der \ certs/ed25519/server-ed25519-key.der \ certs/ed25519/server-ed25519-key.pem \ - certs/ed25519/server-ed25519.pem + certs/ed25519/server-ed25519.pem \ + certs/ed25519/server-ed25519-priv.der \ + certs/ed25519/server-ed25519-priv.pem # ECC CA prime256v1 EXTRA_DIST += \ diff --git a/src/internal.c b/src/internal.c index 66c5b45b1..a45c7d54d 100644 --- a/src/internal.c +++ b/src/internal.c @@ -4328,8 +4328,10 @@ void FreeHandshakeHashes(WOLFSSL* ssl) wc_Sha512Free(&ssl->hsHashes->hashSha512); #endif #if defined(HAVE_ED25519) && !defined(WOLFSSL_NO_CLIENT_AUTH) - if (ssl->hsHashes->messages != NULL) + if (ssl->hsHashes->messages != NULL) { XFREE(ssl->hsHashes->messages, ssl->heap, DYNAMIC_TYPE_HASHES); + ssl->hsHashes->messages = NULL; + } #endif XFREE(ssl->hsHashes, ssl->heap, DYNAMIC_TYPE_HASHES); From 982119b4958606af7b1a3df535565148ab9e4a95 Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Tue, 15 May 2018 10:43:17 +1000 Subject: [PATCH 3/4] Only cache messages when required. --- src/internal.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/src/internal.c b/src/internal.c index a45c7d54d..1ec9f1b38 100644 --- a/src/internal.c +++ b/src/internal.c @@ -6053,18 +6053,26 @@ static int Ed25519Update(WOLFSSL* ssl, const byte* data, int sz) int ret = 0; byte* msgs; - if (!IsAtLeastTLSv1_3(ssl->version) || ssl->options.downgrade) { - msgs = (byte*)XREALLOC(ssl->hsHashes->messages, - ssl->hsHashes->length + sz, ssl->heap, - DYNAMIC_TYPE_HASHES); - if (msgs == NULL) - ret = MEMORY_E; - if (ret == 0) { - ssl->hsHashes->messages = msgs; - XMEMCPY(msgs + ssl->hsHashes->length, data, sz); - ssl->hsHashes->prevLen = ssl->hsHashes->length; - ssl->hsHashes->length += sz; - } + if (!IsAtLeastTLSv1_2(ssl)) + return 0; + if (IsAtLeastTLSv1_3(ssl->version) && !ssl->options.downgrade) + return 0; + if (ssl->options.side == WOLFSSL_CLIENT_END && + ssl->buffers.keyType != ed25519_sa_algo) + return 0; + if (ssl->options.side == WOLFSSL_SERVER_END && (ssl->options.resuming || + !ssl->options.verifyPeer)) + return 0; + + msgs = (byte*)XREALLOC(ssl->hsHashes->messages, ssl->hsHashes->length + sz, + ssl->heap, DYNAMIC_TYPE_HASHES); + if (msgs == NULL) + ret = MEMORY_E; + if (ret == 0) { + ssl->hsHashes->messages = msgs; + XMEMCPY(msgs + ssl->hsHashes->length, data, sz); + ssl->hsHashes->prevLen = ssl->hsHashes->length; + ssl->hsHashes->length += sz; } return ret; From 450741f8ef13bf9f70b1bf35c3d0de520f7d6f82 Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Fri, 18 May 2018 09:45:30 +1000 Subject: [PATCH 4/4] Change checks for message chaching to happen once Add compile option to remove Ed25119 client auth in TLS 1.2. Cipher suite choice does not affect client auth. --- src/internal.c | 88 +++++++++++++++++++++++++++------------------- wolfssl/internal.h | 4 +++ 2 files changed, 56 insertions(+), 36 deletions(-) diff --git a/src/internal.c b/src/internal.c index 1ec9f1b38..3171ba4b2 100644 --- a/src/internal.c +++ b/src/internal.c @@ -4178,6 +4178,12 @@ int SetSSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup) ssl->buffers.keyType = ctx->privateKeyType; ssl->buffers.keySz = ctx->privateKeySz; #endif +#if !defined(WOLFSSL_NO_CLIENT_AUTH) && defined(HAVE_ED25519) && \ + !defined(NO_ED25519_CLIENT_AUTH) + ssl->options.cacheMessages = ssl->options.side == WOLFSSL_SERVER_END || + ssl->buffers.keyType == ed25519_sa_algo; +#endif + #ifdef WOLFSSL_ASYNC_CRYPT ssl->devId = ctx->devId; @@ -6040,7 +6046,8 @@ ProtocolVersion MakeDTLSv1_2(void) return (word32)XTIME(0); } #endif -#if defined(HAVE_ED25519) && !defined(WOLFSSL_NO_CLIENT_AUTH) +#if !defined(WOLFSSL_NO_CLIENT_AUTH) && defined(HAVE_ED25519) && \ + !defined(NO_ED25519_CLIENT_AUTH) /* Store the message for use with CertificateVerify using Ed25519. * * ssl SSL/TLS object. @@ -6053,26 +6060,18 @@ static int Ed25519Update(WOLFSSL* ssl, const byte* data, int sz) int ret = 0; byte* msgs; - if (!IsAtLeastTLSv1_2(ssl)) - return 0; - if (IsAtLeastTLSv1_3(ssl->version) && !ssl->options.downgrade) - return 0; - if (ssl->options.side == WOLFSSL_CLIENT_END && - ssl->buffers.keyType != ed25519_sa_algo) - return 0; - if (ssl->options.side == WOLFSSL_SERVER_END && (ssl->options.resuming || - !ssl->options.verifyPeer)) - return 0; - - msgs = (byte*)XREALLOC(ssl->hsHashes->messages, ssl->hsHashes->length + sz, + if (ssl->options.cacheMessages) { + msgs = (byte*)XREALLOC(ssl->hsHashes->messages, + ssl->hsHashes->length + sz, ssl->heap, DYNAMIC_TYPE_HASHES); - if (msgs == NULL) - ret = MEMORY_E; - if (ret == 0) { - ssl->hsHashes->messages = msgs; - XMEMCPY(msgs + ssl->hsHashes->length, data, sz); - ssl->hsHashes->prevLen = ssl->hsHashes->length; - ssl->hsHashes->length += sz; + if (msgs == NULL) + ret = MEMORY_E; + if (ret == 0) { + ssl->hsHashes->messages = msgs; + XMEMCPY(msgs + ssl->hsHashes->length, data, sz); + ssl->hsHashes->prevLen = ssl->hsHashes->length; + ssl->hsHashes->length += sz; + } } return ret; @@ -6119,7 +6118,8 @@ int HashOutputRaw(WOLFSSL* ssl, const byte* output, int sz) if (ret != 0) return ret; #endif - #if defined(HAVE_ED25519) && !defined(WOLFSSL_NO_CLIENT_AUTH) + #if !defined(WOLFSSL_NO_CLIENT_AUTH) && defined(HAVE_ED25519) && \ + !defined(NO_ED25519_CLIENT_AUTH) ret = Ed25519Update(ssl, output, sz); if (ret != 0) return ret; @@ -6175,7 +6175,8 @@ int HashOutput(WOLFSSL* ssl, const byte* output, int sz, int ivSz) if (ret != 0) return ret; #endif - #if defined(HAVE_ED25519) && !defined(WOLFSSL_NO_CLIENT_AUTH) + #if !defined(WOLFSSL_NO_CLIENT_AUTH) && defined(HAVE_ED25519) && \ + !defined(NO_ED25519_CLIENT_AUTH) ret = Ed25519Update(ssl, adj, sz); if (ret != 0) return ret; @@ -6233,7 +6234,8 @@ int HashInput(WOLFSSL* ssl, const byte* input, int sz) if (ret != 0) return ret; #endif - #if defined(HAVE_ED25519) && !defined(WOLFSSL_NO_CLIENT_AUTH) + #if !defined(WOLFSSL_NO_CLIENT_AUTH) && defined(HAVE_ED25519) && \ + !defined(NO_ED25519_CLIENT_AUTH) ret = Ed25519Update(ssl, adj, sz); if (ret != 0) return ret; @@ -10261,6 +10263,13 @@ static int DoHandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, case server_hello: WOLFSSL_MSG("processing server hello"); ret = DoServerHello(ssl, input, inOutIdx, size); + #if !defined(WOLFSSL_NO_CLIENT_AUTH) && defined(HAVE_ED25519) && \ + !defined(NO_ED25519_CLIENT_AUTH) + if (ssl->options.resuming || !IsAtLeastTLSv1_2(ssl) || + IsAtLeastTLSv1_3(ssl->version)) { + ssl->options.cacheMessages = 0; + } + #endif break; #ifndef NO_CERTS @@ -10322,6 +10331,13 @@ static int DoHandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, case client_hello: WOLFSSL_MSG("processing client hello"); ret = DoClientHello(ssl, input, inOutIdx, size); + #if !defined(WOLFSSL_NO_CLIENT_AUTH) && defined(HAVE_ED25519) && \ + !defined(NO_ED25519_CLIENT_AUTH) + if (ssl->options.resuming || !ssl->options.verifyPeer || \ + !IsAtLeastTLSv1_2(ssl) || IsAtLeastTLSv1_3(ssl->version)) { + ssl->options.cacheMessages = 0; + } + #endif break; case client_key_exchange: @@ -17844,7 +17860,7 @@ static int DoServerKeyExchange(WOLFSSL* ssl, const byte* input, break; } #endif /* HAVE_ECC */ - #ifdef HAVE_ED25519 + #if defined(HAVE_ED25519) case ed25519_sa_algo: { if (!ssl->peerEd25519KeyPresent) { @@ -17954,7 +17970,7 @@ static int DoServerKeyExchange(WOLFSSL* ssl, const byte* input, break; } #endif /* HAVE_ECC */ - #ifdef HAVE_ED25519 + #if defined(HAVE_ED25519) case ed25519_sa_algo: { ret = Ed25519Verify(ssl, @@ -18082,7 +18098,7 @@ static int DoServerKeyExchange(WOLFSSL* ssl, const byte* input, /* Nothing to do in this algo */ break; #endif /* HAVE_ECC */ - #ifdef HAVE_ED25519 + #if defined(HAVE_ED25519) case ed25519_sa_algo: /* Nothing to do in this algo */ break; @@ -19985,13 +20001,13 @@ int SendCertificateVerify(WOLFSSL* ssl) c16toa(args->length, args->verify + args->extraSz); } #endif /* !NO_RSA */ - #ifdef HAVE_ED25519 + #if defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH) if (args->sigAlgo == ed25519_sa_algo) { ret = Ed25519CheckPubKey(ssl); if (ret != 0) goto exit_scv; } - #endif /* HAVE_ED25519 */ + #endif /* HAVE_ED25519 && !NO_ED25519_CLIENT_AUTH */ /* Advance state and proceed */ ssl->options.asyncState = TLS_ASYNC_DO; @@ -20017,7 +20033,7 @@ int SendCertificateVerify(WOLFSSL* ssl) ); } #endif /* HAVE_ECC */ - #ifdef HAVE_ED25519 + #if defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH) if (ssl->hsType == DYNAMIC_TYPE_ED25519) { ed25519_key* key = (ed25519_key*)ssl->hsKey; @@ -20033,7 +20049,7 @@ int SendCertificateVerify(WOLFSSL* ssl) #endif ); } - #endif /* HAVE_ED25519 */ + #endif /* HAVE_ED25519 && !NO_ED25519_CLIENT_AUTH */ #ifndef NO_RSA if (ssl->hsType == DYNAMIC_TYPE_RSA) { RsaKey* key = (RsaKey*)ssl->hsKey; @@ -23177,10 +23193,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 + #if defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH) else if (ssl->peerEd25519KeyPresent) args->sigAlgo = ed25519_sa_algo; - #endif + #endif /* HAVE_ED25519 && !NO_ED25519_CLIENT_AUTH */ if ((args->idx - args->begin) + OPAQUE16_LEN > size) { ERROR_OUT(BUFFER_ERROR, exit_dcv); @@ -23221,7 +23237,7 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, } } #endif /* HAVE_ECC */ - #ifdef HAVE_ED25519 + #if defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH) if (ssl->peerEd25519KeyPresent) { WOLFSSL_MSG("Doing ED25519 peer cert verify"); if (IsAtLeastTLSv1_2(ssl) && @@ -23230,7 +23246,7 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, "Oops, peer sent ED25519 key but not in verify"); } } - #endif /* HAVE_ED25519 */ + #endif /* HAVE_ED25519 && !NO_ED25519_CLIENT_AUTH */ /* Advance state and proceed */ ssl->options.asyncState = TLS_ASYNC_DO; @@ -23284,7 +23300,7 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, ); } #endif /* HAVE_ECC */ - #ifdef HAVE_ED25519 + #if defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH) if (ssl->peerEd25519KeyPresent) { WOLFSSL_MSG("Doing Ed25519 peer cert verify"); @@ -23300,7 +23316,7 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #endif ); } - #endif /* HAVE_ED25519 */ + #endif /* HAVE_ED25519 && !NO_ED25519_CLIENT_AUTH */ /* Check for error */ if (ret != 0) { diff --git a/wolfssl/internal.h b/wolfssl/internal.h index de1da1212..a5f3701d2 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -3055,6 +3055,10 @@ typedef struct Options { #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT) word16 sentChangeCipher:1; /* Change Cipher Spec sent */ #endif +#if !defined(WOLFSSL_NO_CLIENT_AUTH) && defined(HAVE_ED25519) && \ + !defined(NO_ED25519_CLIENT_AUTH) + word16 cacheMessages:1; /* Cache messages for sign/verify */ +#endif /* need full byte values for this section */ byte processReply; /* nonblocking resume */