diff --git a/examples/client/client.c b/examples/client/client.c index e4d26216d..8d5039236 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -629,6 +629,9 @@ static void Usage(void) printf("-Y Key Share with ECC named groups only\n"); #endif #endif /* WOLFSSL_TLS13 */ +#ifdef HAVE_CURVE25519 + printf("-t Use X25519 for key exchange\n"); +#endif } THREAD_RETURN WOLFSSL_THREAD client_test(void* args) @@ -732,6 +735,9 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) int useOcsp = 0; char* ocspUrl = NULL; #endif +#ifdef HAVE_CURVE25519 + int useX25519 = 0; +#endif #ifdef HAVE_WNR const char* wnrConfigFile = wnrConfig; @@ -771,7 +777,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) #ifndef WOLFSSL_VXWORKS /* Not used: t, Q */ while ((ch = mygetopt(argc, argv, "?" - "ab:c:defgh:ijk:l:mnop:q:rsuv:wxyz" + "ab:c:defgh:ijk:l:mnop:q:rstuv:wxyz" "A:B:CDE:F:GHIJKL:M:NO:PRS:TUVW:XYZ:")) != -1) { switch (ch) { case '?' : @@ -1076,6 +1082,12 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) useVerifyCb = 1; break; + case 't' : + #ifdef HAVE_CURVE25519 + useX25519 = 1; + #endif + break; + default: Usage(); exit(MY_EX_USAGE); @@ -1446,6 +1458,18 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) err_sys("DisableExtendedMasterSecret failed"); } #endif +#ifdef HAVE_CURVE25519 + if (useX25519) { + if (wolfSSL_CTX_UseSupportedCurve(ctx, WOLFSSL_ECC_X25519) + != SSL_SUCCESS) { + err_sys("unable to support X25519"); + } + if (wolfSSL_CTX_UseSupportedCurve(ctx, WOLFSSL_ECC_SECP256R1) + != SSL_SUCCESS) { + err_sys("unable to support secp256r1"); + } + } +#endif if (benchmark) { ((func_args*)args)->return_code = @@ -1495,14 +1519,13 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) #ifdef WOLFSSL_TLS13 if (!helloRetry) { - if (onlyKeyShare == 0 || onlyKeyShare == 1) { - #ifdef HAVE_FFDHE_2048 - if (wolfSSL_UseKeyShare(ssl, WOLFSSL_FFDHE_2048) != SSL_SUCCESS) { - err_sys("unable to use DH 2048-bit parameters"); - } - #endif - } if (onlyKeyShare == 0 || onlyKeyShare == 2) { + if (useX25519) { + if (wolfSSL_UseKeyShare(ssl, WOLFSSL_ECC_X25519) + != SSL_SUCCESS) { + err_sys("unable to use curve secp256r1"); + } + } if (wolfSSL_UseKeyShare(ssl, WOLFSSL_ECC_SECP256R1) != SSL_SUCCESS) { err_sys("unable to use curve secp256r1"); @@ -1512,6 +1535,13 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) err_sys("unable to use curve secp384r1"); } } + if (onlyKeyShare == 0 || onlyKeyShare == 1) { + #ifdef HAVE_FFDHE_2048 + if (wolfSSL_UseKeyShare(ssl, WOLFSSL_FFDHE_2048) != SSL_SUCCESS) { + err_sys("unable to use DH 2048-bit parameters"); + } + #endif + } } else { wolfSSL_NoKeyShares(ssl); @@ -1921,11 +1951,11 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) #endif #ifdef WOLFSSL_TLS13 - #ifdef HAVE_FFDHE_2048 - if (wolfSSL_UseKeyShare(sslResume, WOLFSSL_FFDHE_2048) != SSL_SUCCESS) { - err_sys("unable to use DH 2048-bit parameters"); + if (useX25519) { + if (wolfSSL_UseKeyShare(ssl, WOLFSSL_ECC_X25519) != SSL_SUCCESS) { + err_sys("unable to use curve secp256r1"); + } } - #endif if (wolfSSL_UseKeyShare(sslResume, WOLFSSL_ECC_SECP256R1) != SSL_SUCCESS) { err_sys("unable to use curve secp256r1"); @@ -1934,6 +1964,11 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) WOLFSSL_ECC_SECP384R1) != SSL_SUCCESS) { err_sys("unable to use curve secp384r1"); } + #ifdef HAVE_FFDHE_2048 + if (wolfSSL_UseKeyShare(sslResume, WOLFSSL_FFDHE_2048) != SSL_SUCCESS) { + err_sys("unable to use DH 2048-bit parameters"); + } + #endif #endif #ifndef WOLFSSL_CALLBACKS diff --git a/src/internal.c b/src/internal.c index 6b5ae54ba..7464f873d 100755 --- a/src/internal.c +++ b/src/internal.c @@ -3183,8 +3183,115 @@ int EccMakeKey(WOLFSSL* ssl, ecc_key* key, ecc_key* peer) return ret; } -#endif /* HAVE_ECC */ +#ifdef HAVE_CURVE25519 +#ifdef HAVE_PK_CALLBACKS + /* Gets X25519 key for shared secret callback testing + * Client side: returns peer key + * Server side: returns private key + */ + static int X25519GetKey(WOLFSSL* ssl, curve25519_key** otherKey) + { + int ret = NO_PEER_KEY; + struct curve25519_key* tmpKey = NULL; + + if (ssl == NULL || otherKey == NULL) { + return BAD_FUNC_ARG; + } + + if (ssl->options.side == WOLFSSL_CLIENT_END) { + if (!ssl->peerX25519Key || !ssl->peerX25519KeyPresent || + !ssl->peerX25519Key->dp) { + return NO_PEER_KEY; + } + tmpKey = (struct curve25519_key*)ssl->peerX25519Key; + } + else if (ssl->options.side == WOLFSSL_SERVER_END) { + if (!ssl->eccTempKeyPresent) { + return NO_PRIVATE_KEY; + } + tmpKey = (struct curve25519_key*)ssl->eccTempKey; + } + + if (tmpKey) { + *otherKey = (curve25519_key *)tmpKey; + ret = 0; + } + + return ret; + } +#endif /* HAVE_PK_CALLBACKS */ + +static int X25519SharedSecret(WOLFSSL* ssl, curve25519_key* priv_key, + curve25519_key* pub_key, byte* pubKeyDer, word32* pubKeySz, + byte* out, word32* outlen, int side, void* ctx) +{ + int ret; + + (void)ssl; + (void)pubKeyDer; + (void)pubKeySz; + (void)side; + (void)ctx; + + WOLFSSL_ENTER("X25519SharedSecret"); + +#ifdef HAVE_PK_CALLBACKS + if (ssl->ctx->X25519SharedSecretCb) { + curve25519_key* otherKey = NULL; + + ret = X25519GetKey(ssl, &otherKey); + if (ret == 0) { + ret = ssl->ctx->X25519SharedSecretCb(ssl, otherKey, pubKeyDer, + pubKeySz, out, outlen, side, ctx); + } + } + else +#endif + { + ret = wc_curve25519_shared_secret_ex(priv_key, pub_key, out, outlen, + EC25519_LITTLE_ENDIAN); + } + + /* Handle async pending response */ +#if defined(WOLFSSL_ASYNC_CRYPT) + if (ret == WC_PENDING_E) { + ret = wolfSSL_AsyncPush(ssl, &priv_key->asyncDev, + WC_ASYNC_FLAG_CALL_AGAIN); + } +#endif /* WOLFSSL_ASYNC_CRYPT */ + + WOLFSSL_LEAVE("X25519SharedSecret", ret); + + return ret; +} + +static int X25519MakeKey(WOLFSSL* ssl, curve25519_key* key, + curve25519_key* peer) +{ + int ret = 0; + + (void)peer; + + WOLFSSL_ENTER("X25519MakeKey"); + + ret = wc_curve25519_make_key(ssl->rng, CURVE25519_KEYSIZE, key); + if (ret == 0) + ssl->ecdhCurveOID = ECC_X25519_OID; + + /* Handle async pending response */ +#if defined(WOLFSSL_ASYNC_CRYPT) + if (ret == WC_PENDING_E) { + ret = wolfSSL_AsyncPush(ssl, &key->asyncDev, WC_ASYNC_FLAG_NONE); + } +#endif /* WOLFSSL_ASYNC_CRYPT */ + + WOLFSSL_LEAVE("X25519MakeKey", ret); + + return ret; +} +#endif /* HAVE_CURVE25519 */ +#endif /* HAVE_ECC */ #endif /* !NO_CERTS */ #if !defined(NO_CERTS) || !defined(NO_PSK) @@ -3835,6 +3942,11 @@ void FreeKey(WOLFSSL* ssl, int type, void** pKey) wc_ecc_free((ecc_key*)*pKey); break; #endif /* HAVE_ECC */ + #ifdef HAVE_CURVE25519 + case DYNAMIC_TYPE_CURVE25519: + wc_curve25519_free((curve25519_key*)*pKey); + break; + #endif /* HAVE_CURVE25519 */ #ifndef NO_DH case DYNAMIC_TYPE_DH: wc_FreeDhKey((DhKey*)*pKey); @@ -3867,21 +3979,26 @@ int AllocKey(WOLFSSL* ssl, int type, void** pKey) /* Determine size */ switch (type) { - case DYNAMIC_TYPE_RSA: #ifndef NO_RSA + case DYNAMIC_TYPE_RSA: sz = sizeof(RsaKey); + break; #endif /* ! NO_RSA */ - break; - case DYNAMIC_TYPE_ECC: #ifdef HAVE_ECC + case DYNAMIC_TYPE_ECC: sz = sizeof(ecc_key); + break; #endif /* HAVE_ECC */ + #ifdef HAVE_CURVE25519 + case DYNAMIC_TYPE_CURVE25519: + sz = sizeof(curve25519_key); break; - case DYNAMIC_TYPE_DH: + #endif /* HAVE_CURVE25519 */ #ifndef NO_DH + case DYNAMIC_TYPE_DH: sz = sizeof(DhKey); - #endif /* !NO_DH */ break; + #endif /* !NO_DH */ default: return BAD_FUNC_ARG; } @@ -3908,6 +4025,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_CURVE25519 + case DYNAMIC_TYPE_CURVE25519: + wc_curve25519_init((curve25519_key*)*pKey); + ret = 0; + break; + #endif /* HAVE_CURVE25519 */ #ifndef NO_DH case DYNAMIC_TYPE_DH: ret = wc_InitDhKey_ex((DhKey*)*pKey, ssl->heap, ssl->devId); @@ -3925,6 +4048,44 @@ int AllocKey(WOLFSSL* ssl, int type, void** pKey) return ret; } +#if !defined(NO_RSA) || defined(HAVE_ECC) +static int ReuseKey(WOLFSSL* ssl, int type, void* pKey) +{ + int ret = 0; + + switch (type) { + #ifndef NO_RSA + case DYNAMIC_TYPE_RSA: + wc_FreeRsaKey((RsaKey*)pKey); + ret = wc_InitRsaKey_ex((RsaKey*)pKey, ssl->heap, ssl->devId); + break; + #endif /* ! NO_RSA */ + #ifdef HAVE_ECC + case DYNAMIC_TYPE_ECC: + wc_ecc_free((ecc_key*)pKey); + ret = wc_ecc_init_ex((ecc_key*)pKey, ssl->heap, ssl->devId); + break; + #endif /* HAVE_ECC */ + #ifdef HAVE_CURVE25519 + case DYNAMIC_TYPE_CURVE25519: + wc_curve25519_free((curve25519_key*)pKey); + wc_curve25519_init((curve25519_key*)pKey); + break; + #endif /* HAVE_CURVE25519 */ + #ifndef NO_DH + case DYNAMIC_TYPE_DH: + wc_FreeDhKey((DhKey*)pKey); + ret = wc_InitDhKey_ex((DhKey*)pKey, ssl->heap, ssl->devId); + break; + #endif /* !NO_DH */ + default: + return BAD_FUNC_ARG; + } + + return ret; +} +#endif + void FreeKeyExchange(WOLFSSL* ssl) { /* Cleanup signature buffer */ @@ -4033,8 +4194,21 @@ void SSL_ResourceFree(WOLFSSL* ssl) ssl->peerEccKeyPresent = 0; FreeKey(ssl, DYNAMIC_TYPE_ECC, (void**)&ssl->peerEccDsaKey); ssl->peerEccDsaKeyPresent = 0; - FreeKey(ssl, DYNAMIC_TYPE_ECC, (void**)&ssl->eccTempKey); - ssl->eccTempKeyPresent = 0; +#ifdef HAVE_CURVE25519 + if (!ssl->peerX25519KeyPresent) +#endif /* HAVE_CURVE25519 */ + { + FreeKey(ssl, DYNAMIC_TYPE_ECC, (void**)&ssl->eccTempKey); + ssl->eccTempKeyPresent = 0; + } +#ifdef HAVE_CURVE25519 + else { + FreeKey(ssl, DYNAMIC_TYPE_CURVE25519, (void**)&ssl->eccTempKey); + ssl->eccTempKeyPresent = 0; + } + FreeKey(ssl, DYNAMIC_TYPE_CURVE25519, (void**)&ssl->peerX25519Key); + ssl->peerX25519KeyPresent = 0; +#endif #endif /* HAVE_ECC */ #ifdef HAVE_PK_CALLBACKS #ifdef HAVE_ECC @@ -4174,8 +4348,21 @@ void FreeHandshakeResources(WOLFSSL* ssl) ssl->peerEccKeyPresent = 0; FreeKey(ssl, DYNAMIC_TYPE_ECC, (void**)&ssl->peerEccDsaKey); ssl->peerEccDsaKeyPresent = 0; - FreeKey(ssl, DYNAMIC_TYPE_ECC, (void**)&ssl->eccTempKey); - ssl->eccTempKeyPresent = 0; +#ifdef HAVE_CURVE25519 + if (ssl->ecdhCurveOID != ECC_X25519_OID) +#endif /* HAVE_CURVE25519 */ + { + FreeKey(ssl, DYNAMIC_TYPE_ECC, (void**)&ssl->eccTempKey); + ssl->eccTempKeyPresent = 0; + } +#ifdef HAVE_CURVE25519 + else { + FreeKey(ssl, DYNAMIC_TYPE_CURVE25519, (void**)&ssl->eccTempKey); + ssl->eccTempKeyPresent = 0; + } + FreeKey(ssl, DYNAMIC_TYPE_CURVE25519, (void**)&ssl->peerX25519Key); + ssl->peerX25519KeyPresent = 0; +#endif /* HAVE_CURVE25519 */ #endif /* HAVE_ECC */ #ifndef NO_DH if (ssl->buffers.serverDH_Priv.buffer) { @@ -7567,11 +7754,9 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx, word32 totalSz keyRet = AllocKey(ssl, DYNAMIC_TYPE_RSA, (void**)&ssl->peerRsaKey); } else if (ssl->peerRsaKeyPresent) { - /* don't leak on reuse */ - wc_FreeRsaKey(ssl->peerRsaKey); + keyRet = ReuseKey(ssl, DYNAMIC_TYPE_RSA, + ssl->peerRsaKey); ssl->peerRsaKeyPresent = 0; - keyRet = wc_InitRsaKey_ex(ssl->peerRsaKey, - ssl->heap, ssl->devId); } if (keyRet != 0 || wc_RsaPublicKeyDecode( @@ -7637,11 +7822,9 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx, word32 totalSz keyRet = AllocKey(ssl, DYNAMIC_TYPE_ECC, (void**)&ssl->peerEccDsaKey); } else if (ssl->peerEccDsaKeyPresent) { - /* don't leak on reuse */ - wc_ecc_free(ssl->peerEccDsaKey); + keyRet = ReuseKey(ssl, DYNAMIC_TYPE_ECC, + ssl->peerEccDsaKey); ssl->peerEccDsaKeyPresent = 0; - keyRet = wc_ecc_init_ex(ssl->peerEccDsaKey, - ssl->heap, ssl->devId); } curveId = wc_ecc_get_oid(args->dCert->keyOID, NULL, NULL); @@ -15657,6 +15840,9 @@ void PickHashSigAlgo(WOLFSSL* ssl, const byte* hashSigAlgo, word32 hashSigAlgoSz #endif /* HAVE_ECC_KOBLITZ */ #endif #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES) + #ifdef HAVE_CURVE25519 + case WOLFSSL_ECC_X25519: return ECC_X25519_OID; + #endif #ifndef NO_ECC_SECP case WOLFSSL_ECC_SECP256R1: return ECC_SECP256R1_OID; #endif /* !NO_ECC_SECP */ @@ -15920,23 +16106,43 @@ static int DoServerKeyExchange(WOLFSSL* ssl, const byte* input, ERROR_OUT(BUFFER_ERROR, exit_dske); } - if (ssl->peerEccKey == NULL) { - /* alloc/init on demand */ - ssl->peerEccKey = (ecc_key*)XMALLOC(sizeof(ecc_key), - ssl->heap, DYNAMIC_TYPE_ECC); - if (ssl->peerEccKey == NULL) { - WOLFSSL_MSG("PeerEccKey Memory error"); - ERROR_OUT(MEMORY_E, exit_dske); + #ifdef HAVE_CURVE25519 + if (ssl->ecdhCurveOID == ECC_X25519_OID) { + if (ssl->peerX25519Key == NULL) { + ret = AllocKey(ssl, DYNAMIC_TYPE_CURVE25519, + (void**)&ssl->peerX25519Key); + if (ret != 0) { + goto exit_dske; + } + } else if (ssl->peerEccKeyPresent) { + ret = ReuseKey(ssl, DYNAMIC_TYPE_CURVE25519, + ssl->peerX25519Key); + ssl->peerX25519KeyPresent = 0; + if (ret != 0) { + goto exit_dske; + } } - ret = wc_ecc_init_ex(ssl->peerEccKey, ssl->heap, - ssl->devId); + + if (wc_curve25519_import_public_ex(input + args->idx, + length, ssl->peerX25519Key, + EC25519_LITTLE_ENDIAN) != 0) { + ERROR_OUT(ECC_PEERKEY_ERROR, exit_dske); + } + + args->idx += length; + ssl->peerX25519KeyPresent = 1; + break; + } + #endif + if (ssl->peerEccKey == NULL) { + ret = AllocKey(ssl, DYNAMIC_TYPE_ECC, + (void**)&ssl->peerEccKey); if (ret != 0) { goto exit_dske; } - } else if (ssl->peerEccKeyPresent) { /* don't leak on reuse */ - wc_ecc_free(ssl->peerEccKey); + } else if (ssl->peerEccKeyPresent) { + ret = ReuseKey(ssl, DYNAMIC_TYPE_ECC, ssl->peerEccKey); ssl->peerEccKeyPresent = 0; - ret = wc_ecc_init_ex(ssl->peerEccKey, ssl->heap, ssl->devId); if (ret != 0) { goto exit_dske; } @@ -16111,24 +16317,44 @@ static int DoServerKeyExchange(WOLFSSL* ssl, const byte* input, ERROR_OUT(BUFFER_ERROR, exit_dske); } - if (ssl->peerEccKey == NULL) { - /* alloc/init on demand */ - ssl->peerEccKey = (ecc_key*)XMALLOC(sizeof(ecc_key), - ssl->heap, DYNAMIC_TYPE_ECC); - if (ssl->peerEccKey == NULL) { - WOLFSSL_MSG("PeerEccKey Memory error"); - ERROR_OUT(MEMORY_E, exit_dske); + #ifdef HAVE_CURVE25519 + if (ssl->ecdhCurveOID == ECC_X25519_OID) { + if (ssl->peerX25519Key == NULL) { + ret = AllocKey(ssl, DYNAMIC_TYPE_CURVE25519, + (void**)&ssl->peerX25519Key); + if (ret != 0) { + goto exit_dske; + } + } else if (ssl->peerEccKeyPresent) { + ret = ReuseKey(ssl, DYNAMIC_TYPE_CURVE25519, + ssl->peerX25519Key); + ssl->peerX25519KeyPresent = 0; + if (ret != 0) { + goto exit_dske; + } } - ret = wc_ecc_init_ex(ssl->peerEccKey, ssl->heap, - ssl->devId); + + if (wc_curve25519_import_public_ex(input + args->idx, + length, ssl->peerX25519Key, + EC25519_LITTLE_ENDIAN) != 0) { + ERROR_OUT(ECC_PEERKEY_ERROR, exit_dske); + } + + args->idx += length; + ssl->peerX25519KeyPresent = 1; + break; + } + #endif + + if (ssl->peerEccKey == NULL) { + AllocKey(ssl, DYNAMIC_TYPE_ECC, + (void**)&ssl->peerEccKey); if (ret != 0) { goto exit_dske; } - } else if (ssl->peerEccKeyPresent) { /* don't leak on reuse */ - wc_ecc_free(ssl->peerEccKey); + } else if (ssl->peerEccKeyPresent) { + ret = ReuseKey(ssl, DYNAMIC_TYPE_ECC, ssl->peerEccKey); ssl->peerEccKeyPresent = 0; - ret = wc_ecc_init_ex(ssl->peerEccKey, ssl->heap, - ssl->devId); if (ret != 0) { goto exit_dske; } @@ -17093,6 +17319,32 @@ int SendClientKeyExchange(WOLFSSL* ssl) ERROR_OUT(PSK_KEY_ERROR, exit_scke); } + #ifdef HAVE_CURVE25519 + if (ssl->peerX25519KeyPresent) { + /* Check client ECC public key */ + if (!ssl->peerX25519Key || !ssl->peerX25519Key->dp) { + ERROR_OUT(NO_PEER_KEY, exit_scke); + } + + #ifdef HAVE_PK_CALLBACKS + /* if callback then use it for shared secret */ + if (ssl->ctx->X25519SharedSecretCb != NULL) { + break; + } + #endif + + /* create private key */ + ssl->hsType = DYNAMIC_TYPE_CURVE25519; + ret = AllocKey(ssl, ssl->hsType, &ssl->hsKey); + if (ret != 0) { + goto exit_scke; + } + + ret = X25519MakeKey(ssl, (curve25519_key*)ssl->hsKey, + ssl->peerX25519Key); + break; + } + #endif /* Check client ECC public key */ if (!ssl->peerEccKey || !ssl->peerEccKeyPresent || !ssl->peerEccKey->dp) { @@ -17131,11 +17383,37 @@ int SendClientKeyExchange(WOLFSSL* ssl) #ifdef HAVE_PK_CALLBACKS /* if callback then use it for shared secret */ + #ifdef HAVE_CURVE25519 + if (ssl->ecdhCurveOID == ECC_X25519_OID) { + if (ssl->ctx->X25519SharedSecretCb != NULL) + break; + } + else + #endif if (ssl->ctx->EccSharedSecretCb != NULL) { break; } #endif + #ifdef HAVE_CURVE25519 + if (ssl->peerX25519KeyPresent) { + if (!ssl->peerX25519Key || !ssl->peerX25519Key->dp) { + ERROR_OUT(NO_PEER_KEY, exit_scke); + } + + /* create private key */ + ssl->hsType = DYNAMIC_TYPE_CURVE25519; + ret = AllocKey(ssl, ssl->hsType, &ssl->hsKey); + if (ret != 0) { + goto exit_scke; + } + + ret = X25519MakeKey(ssl, (curve25519_key*)ssl->hsKey, + ssl->peerX25519Key); + break; + } + else + #endif if (ssl->specs.static_ecdh) { /* TODO: EccDsa is really fixed Ecc change naming */ if (!ssl->peerEccDsaKey || @@ -17367,6 +17645,26 @@ int SendClientKeyExchange(WOLFSSL* ssl) of buffer for size of shared key. */ ssl->arrays->preMasterSz = ENCRYPT_LEN - OPAQUE16_LEN; + #ifdef HAVE_CURVE25519 + if (ssl->ecdhCurveOID == ECC_X25519_OID) { + #ifdef HAVE_PK_CALLBACKS + /* if callback then use it for shared secret */ + if (ssl->ctx->X25519SharedSecretCb != NULL) { + break; + } + #endif + + ret = wc_curve25519_export_public_ex( + (curve25519_key*)ssl->hsKey, + args->output + OPAQUE8_LEN, &args->length, + EC25519_LITTLE_ENDIAN); + if (ret != 0) { + ERROR_OUT(ECC_EXPORT_ERROR, exit_scke); + } + + break; + } + #endif #ifdef HAVE_PK_CALLBACKS /* if callback then use it for shared secret */ if (ssl->ctx->EccSharedSecretCb != NULL) { @@ -17403,6 +17701,26 @@ int SendClientKeyExchange(WOLFSSL* ssl) { ssl->arrays->preMasterSz = ENCRYPT_LEN; + #ifdef HAVE_CURVE25519 + if (ssl->hsType == DYNAMIC_TYPE_CURVE25519) { + #ifdef HAVE_PK_CALLBACKS + /* if callback then use it for shared secret */ + if (ssl->ctx->X25519SharedSecretCb != NULL) { + break; + } + #endif + + ret = wc_curve25519_export_public_ex( + (curve25519_key*)ssl->hsKey, + args->encSecret + OPAQUE8_LEN, &args->encSz, + EC25519_LITTLE_ENDIAN); + if (ret != 0) { + ERROR_OUT(ECC_EXPORT_ERROR, exit_scke); + } + + break; + } + #endif #ifdef HAVE_PK_CALLBACKS /* if callback then use it for shared secret */ if (ssl->ctx->EccSharedSecretCb != NULL) { @@ -17490,8 +17808,25 @@ int SendClientKeyExchange(WOLFSSL* ssl) #if defined(HAVE_ECC) && !defined(NO_PSK) case ecdhe_psk_kea: { - ecc_key* key = (ecc_key*)ssl->hsKey; - ret = EccSharedSecret(ssl, key, ssl->peerEccKey, + #ifdef HAVE_CURVE25519 + if (ssl->peerX25519KeyPresent) { + ret = X25519SharedSecret(ssl, + (curve25519_key*)ssl->hsKey, ssl->peerX25519Key, + args->output + OPAQUE8_LEN, &args->length, + ssl->arrays->preMasterSecret + OPAQUE16_LEN, + &ssl->arrays->preMasterSz, + WOLFSSL_CLIENT_END, + #ifdef HAVE_PK_CALLBACKS + ssl->EccSharedSecretCtx + #else + NULL + #endif + ); + break; + } + #endif + ret = EccSharedSecret(ssl, + (ecc_key*)ssl->hsKey, ssl->peerEccKey, args->output + OPAQUE8_LEN, &args->length, ssl->arrays->preMasterSecret + OPAQUE16_LEN, &ssl->arrays->preMasterSz, @@ -17532,12 +17867,30 @@ int SendClientKeyExchange(WOLFSSL* ssl) #ifdef HAVE_ECC case ecc_diffie_hellman_kea: { - ecc_key* key = (ecc_key*)ssl->hsKey; - ecc_key* peerKey = (ssl->specs.static_ecdh) ? - ssl->peerEccDsaKey : ssl->peerEccKey; + ecc_key* peerKey; + + #ifdef HAVE_CURVE25519 + if (ssl->peerX25519KeyPresent) { + ret = X25519SharedSecret(ssl, + (curve25519_key*)ssl->hsKey, ssl->peerX25519Key, + args->encSecret + OPAQUE8_LEN, &args->encSz, + ssl->arrays->preMasterSecret, + &ssl->arrays->preMasterSz, + WOLFSSL_CLIENT_END, + #ifdef HAVE_PK_CALLBACKS + ssl->EccSharedSecretCtx + #else + NULL + #endif + ); + break; + } + #endif + peerKey = (ssl->specs.static_ecdh) ? + ssl->peerEccDsaKey : ssl->peerEccKey; ret = EccSharedSecret(ssl, - key, peerKey, + (ecc_key*)ssl->hsKey, peerKey, args->encSecret + OPAQUE8_LEN, &args->encSz, ssl->arrays->preMasterSecret, &ssl->arrays->preMasterSz, @@ -18728,6 +19081,10 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #endif /* HAVE_ECC_BRAINPOOL */ #endif #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES) + #ifdef HAVE_CURVE25519 + case ECC_X25519_OID: + return WOLFSSL_ECC_X25519; + #endif #ifndef NO_ECC_SECP case ECC_SECP384R1_OID: return WOLFSSL_ECC_SECP384R1; @@ -18959,6 +19316,28 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #ifdef HAVE_ECC case ecc_diffie_hellman_kea: { + #ifdef HAVE_CURVE25519 + if (ssl->ecdhCurveOID == ECC_X25519_OID) { + /* need ephemeral key now, create it if missing */ + if (ssl->eccTempKey == NULL) { + /* alloc/init on demand */ + ret = AllocKey(ssl, DYNAMIC_TYPE_CURVE25519, + (void**)&ssl->eccTempKey); + if (ret != 0) { + goto exit_sske; + } + } + + if (ssl->eccTempKeyPresent == 0) { + ret = X25519MakeKey(ssl, + (curve25519_key*)ssl->eccTempKey, NULL); + if (ret == 0 || ret == WC_PENDING_E) { + ssl->eccTempKeyPresent = 1; + } + } + break; + } + #endif /* need ephemeral key now, create it if missing */ if (ssl->eccTempKey == NULL) { /* alloc/init on demand */ @@ -19156,9 +19535,22 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, if (args->exportBuf == NULL) { ERROR_OUT(MEMORY_E, exit_sske); } - if (wc_ecc_export_x963(ssl->eccTempKey, args->exportBuf, - &args->exportSz) != 0) { - ERROR_OUT(ECC_EXPORT_ERROR, exit_sske); + #ifdef HAVE_CURVE25519 + if (ssl->ecdhCurveOID == ECC_X25519_OID) { + if (wc_curve25519_export_public_ex( + (curve25519_key*)ssl->eccTempKey, + args->exportBuf, &args->exportSz, + EC25519_LITTLE_ENDIAN) != 0) { + ERROR_OUT(ECC_EXPORT_ERROR, exit_sske); + } + } + else + #endif + { + if (wc_ecc_export_x963(ssl->eccTempKey, + args->exportBuf, &args->exportSz) != 0) { + ERROR_OUT(ECC_EXPORT_ERROR, exit_sske); + } } args->length += args->exportSz; @@ -19199,7 +19591,15 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, /* ECC key exchange data */ args->output[args->idx++] = named_curve; args->output[args->idx++] = 0x00; /* leading zero */ - args->output[args->idx++] = SetCurveId(ssl->eccTempKey); + #ifdef HAVE_CURVE25519 + if (ssl->ecdhCurveOID == ECC_X25519_OID) + args->output[args->idx++] = WOLFSSL_ECC_X25519; + else + #endif + { + args->output[args->idx++] = + SetCurveId(ssl->eccTempKey); + } args->output[args->idx++] = (byte)args->exportSz; XMEMCPY(args->output + args->idx, args->exportBuf, args->exportSz); @@ -19222,10 +19622,23 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, if (args->exportBuf == NULL) { ERROR_OUT(MEMORY_E, exit_sske); } - if (wc_ecc_export_x963(ssl->eccTempKey, args->exportBuf, - &args->exportSz) != 0) { - ERROR_OUT(ECC_EXPORT_ERROR, exit_sske); + #ifdef HAVE_CURVE25519 + if (ssl->ecdhCurveOID == ECC_X25519_OID) { + if (wc_curve25519_export_public_ex( + (curve25519_key*)ssl->eccTempKey, + args->exportBuf, &args->exportSz, + EC25519_LITTLE_ENDIAN) != 0) { + ERROR_OUT(ECC_EXPORT_ERROR, exit_sske); + } } + else + #endif + { + if (wc_ecc_export_x963(ssl->eccTempKey, + args->exportBuf, &args->exportSz) != 0) { + ERROR_OUT(ECC_EXPORT_ERROR, exit_sske); + } + } args->length += args->exportSz; preSigSz = args->length; @@ -19337,7 +19750,15 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, /* key exchange data */ args->output[args->idx++] = named_curve; args->output[args->idx++] = 0x00; /* leading zero */ - args->output[args->idx++] = SetCurveId(ssl->eccTempKey); + #ifdef HAVE_CURVE25519 + if (ssl->ecdhCurveOID == ECC_X25519_OID) + args->output[args->idx++] = WOLFSSL_ECC_X25519; + else + #endif + { + args->output[args->idx++] = + SetCurveId(ssl->eccTempKey); + } args->output[args->idx++] = (byte)args->exportSz; XMEMCPY(args->output + args->idx, args->exportBuf, args->exportSz); args->idx += args->exportSz; @@ -22027,7 +22448,8 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, ecc_key* private_key = ssl->eccTempKey; /* handle static private key */ - if (ssl->specs.static_ecdh) { + if (ssl->specs.static_ecdh && + ssl->ecdhCurveOID != ECC_X25519_OID) { word32 i = 0; ssl->hsType = DYNAMIC_TYPE_ECC; @@ -22064,6 +22486,45 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, ssl->arrays->preMasterSz = ENCRYPT_LEN; + #ifdef HAVE_CURVE25519 + if (ssl->ecdhCurveOID == ECC_X25519_OID) { + #ifdef HAVE_PK_CALLBACKS + /* if callback then use it for shared secret */ + if (ssl->ctx->X25519SharedSecretCb != NULL) { + break; + } + #endif + if (ssl->peerX25519Key == NULL) { + /* alloc/init on demand */ + ret = AllocKey(ssl, DYNAMIC_TYPE_CURVE25519, + (void**)&ssl->peerX25519Key); + if (ret != 0) { + goto exit_dcke; + } + } else if (ssl->peerX25519KeyPresent) { + ret = ReuseKey(ssl, DYNAMIC_TYPE_CURVE25519, + ssl->peerX25519Key); + ssl->peerX25519KeyPresent = 0; + if (ret != 0) { + goto exit_dcke; + } + } + + if (wc_curve25519_import_public_ex( + input + args->idx, args->length, + ssl->peerX25519Key, + EC25519_LITTLE_ENDIAN)) { + ERROR_OUT(ECC_PEERKEY_ERROR, exit_dcke); + } + + ssl->peerX25519KeyPresent = 1; + + if (ret != 0) { + goto exit_dcke; + } + break; + } + #endif #ifdef HAVE_PK_CALLBACKS /* if callback then use it for shared secret */ if (ssl->ctx->EccSharedSecretCb != NULL) { @@ -22084,11 +22545,10 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, if (ret != 0) { goto exit_dcke; } - } else if (ssl->peerEccKeyPresent) { /* don't leak on reuse */ - wc_ecc_free(ssl->peerEccKey); + } else if (ssl->peerEccKeyPresent) { + ret = ReuseKey(ssl, DYNAMIC_TYPE_ECC, + ssl->peerEccKey); ssl->peerEccKeyPresent = 0; - ret = wc_ecc_init_ex(ssl->peerEccKey, ssl->heap, - ssl->devId); if (ret != 0) { goto exit_dcke; } @@ -22230,6 +22690,49 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, args->sigSz = ENCRYPT_LEN - OPAQUE16_LEN; + #ifdef HAVE_CURVE25519 + if (ssl->ecdhCurveOID == ECC_X25519_OID) { + #ifdef HAVE_PK_CALLBACKS + /* if callback then use it for shared secret */ + if (ssl->ctx->X25519SharedSecretCb != NULL) { + break; + } + #endif + + if (ssl->eccTempKeyPresent == 0) { + WOLFSSL_MSG( + "X25519 ephemeral key not made correctly"); + ERROR_OUT(ECC_MAKEKEY_ERROR, exit_dcke); + } + + if (ssl->peerX25519Key == NULL) { + /* alloc/init on demand */ + ret = AllocKey(ssl, DYNAMIC_TYPE_CURVE25519, + (void**)&ssl->peerX25519Key); + if (ret != 0) { + goto exit_dcke; + } + } else if (ssl->peerX25519KeyPresent) { + ret = ReuseKey(ssl, DYNAMIC_TYPE_CURVE25519, + ssl->peerX25519Key); + ssl->peerX25519KeyPresent = 0; + if (ret != 0) { + goto exit_dcke; + } + } + + if (wc_curve25519_import_public_ex( + input + args->idx, args->length, + ssl->peerX25519Key, + EC25519_LITTLE_ENDIAN)) { + ERROR_OUT(ECC_PEERKEY_ERROR, exit_dcke); + } + + ssl->peerX25519KeyPresent = 1; + + break; + } + #endif #ifdef HAVE_PK_CALLBACKS /* if callback then use it for shared secret */ if (ssl->ctx->EccSharedSecretCb != NULL) { @@ -22250,11 +22753,10 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, goto exit_dcke; } } - else if (ssl->peerEccKeyPresent) { /* don't leak on reuse */ - wc_ecc_free(ssl->peerEccKey); + else if (ssl->peerEccKeyPresent) { + ret = ReuseKey(ssl, DYNAMIC_TYPE_ECC, + ssl->peerEccKey); ssl->peerEccKeyPresent = 0; - ret = wc_ecc_init_ex(ssl->peerEccKey, ssl->heap, - ssl->devId); if (ret != 0) { goto exit_dcke; } @@ -22321,14 +22823,33 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #ifdef HAVE_ECC case ecc_diffie_hellman_kea: { - ecc_key* private_key = ssl->eccTempKey; + void* private_key = ssl->eccTempKey; + + #ifdef HAVE_CURVE25519 + if (ssl->ecdhCurveOID == ECC_X25519_OID) { + ret = X25519SharedSecret(ssl, + (curve25519_key*)private_key, + ssl->peerX25519Key, + input + args->idx, &args->length, + ssl->arrays->preMasterSecret, + &ssl->arrays->preMasterSz, + WOLFSSL_SERVER_END, + #ifdef HAVE_PK_CALLBACKS + ssl->EccSharedSecretCtx + #else + NULL + #endif + ); + break; + } + #endif if (ssl->specs.static_ecdh) { - private_key = (ecc_key*)ssl->hsKey; + private_key = ssl->hsKey; } /* Generate shared secret */ ret = EccSharedSecret(ssl, - private_key, ssl->peerEccKey, + (ecc_key*)private_key, ssl->peerEccKey, input + args->idx, &args->length, ssl->arrays->preMasterSecret, &ssl->arrays->preMasterSz, @@ -22371,6 +22892,24 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #if defined(HAVE_ECC) && !defined(NO_PSK) case ecdhe_psk_kea: { + #ifdef HAVE_CURVE25519 + if (ssl->ecdhCurveOID == ECC_X25519_OID) { + ret = X25519SharedSecret(ssl, + (curve25519_key*)ssl->eccTempKey, + ssl->peerX25519Key, + input + args->idx, &args->length, + ssl->arrays->preMasterSecret + OPAQUE16_LEN, + &args->sigSz, + WOLFSSL_SERVER_END, + #ifdef HAVE_PK_CALLBACKS + ssl->EccSharedSecretCtx + #else + NULL + #endif + ); + break; + } + #endif /* Generate shared secret */ ret = EccSharedSecret(ssl, ssl->eccTempKey, ssl->peerEccKey, diff --git a/src/ssl.c b/src/ssl.c index b8b80b6ce..1ad509f99 100755 --- a/src/ssl.c +++ b/src/ssl.c @@ -1598,6 +1598,7 @@ int wolfSSL_UseSupportedCurve(WOLFSSL* ssl, word16 name) case WOLFSSL_ECC_BRAINPOOLP256R1: case WOLFSSL_ECC_BRAINPOOLP384R1: case WOLFSSL_ECC_BRAINPOOLP512R1: + case WOLFSSL_ECC_X25519: break; #ifdef WOLFSSL_TLS13 @@ -1641,6 +1642,7 @@ int wolfSSL_CTX_UseSupportedCurve(WOLFSSL_CTX* ctx, word16 name) case WOLFSSL_ECC_BRAINPOOLP256R1: case WOLFSSL_ECC_BRAINPOOLP384R1: case WOLFSSL_ECC_BRAINPOOLP512R1: + case WOLFSSL_ECC_X25519: break; #ifdef WOLFSSL_TLS13 @@ -14229,11 +14231,13 @@ const char* wolfSSL_get_curve_name(WOLFSSL* ssl) { if (ssl == NULL) return NULL; - if (ssl->specs.kea != ecdhe_psk_kea && + if (!IsAtLeastTLSv1_3(ssl->version) && ssl->specs.kea != ecdhe_psk_kea && ssl->specs.kea != ecc_diffie_hellman_kea) return NULL; if (ssl->ecdhCurveOID == 0) return NULL; + if (ssl->ecdhCurveOID == ECC_X25519_OID) + return "X25519"; return wc_ecc_get_name(wc_ecc_get_oid(ssl->ecdhCurveOID, NULL, NULL)); } #endif @@ -21989,6 +21993,30 @@ void* wolfSSL_GetEccSharedSecretCtx(WOLFSSL* ssl) return NULL; } + +#ifdef HAVE_CURVE25519 +void wolfSSL_CTX_SetX25519SharedSecretCb(WOLFSSL_CTX* ctx, + CallbackX25519SharedSecret cb) +{ + if (ctx) + ctx->X25519SharedSecretCb = cb; +} + +void wolfSSL_SetX25519SharedSecretCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->X25519SharedSecretCtx = ctx; +} + + +void* wolfSSL_GetX25519SharedSecretCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->X25519SharedSecretCtx; + + return NULL; +} +#endif #endif /* HAVE_ECC */ #ifndef NO_RSA diff --git a/src/tls.c b/src/tls.c index df8f7c5b5..2f346ca88 100755 --- a/src/tls.c +++ b/src/tls.c @@ -3061,6 +3061,12 @@ int TLSX_ValidateEllipticCurves(WOLFSSL* ssl, byte first, byte second) { octets = 32; break; #endif /* !NO_ECC_SECP */ + #ifdef HAVE_CURVE25519 + case WOLFSSL_ECC_X25519: + oid = ECC_X25519_OID; + octets = 32; + break; + #endif /* HAVE_CURVE25519 */ #ifdef HAVE_ECC_KOBLITZ case WOLFSSL_ECC_SECP256K1: oid = ECC_SECP256K1_OID; @@ -3148,6 +3154,10 @@ int TLSX_ValidateEllipticCurves(WOLFSSL* ssl, byte first, byte second) { case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384: case TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256: case TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384: + if (oid == ECC_X25519_OID && defOid == oid) { + defOid = 0; + defSz = 80; + } sig |= ssl->pkCurveOID == oid; key |= ssl->pkCurveOID == oid; break; @@ -3177,13 +3187,22 @@ int TLSX_ValidateEllipticCurves(WOLFSSL* ssl, byte first, byte second) { case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384: case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256: case TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384: + if (oid == ECC_X25519_OID && defOid == oid) { + defOid = 0; + defSz = 80; + } sig = 1; key |= ssl->pkCurveOID == oid; break; #endif /* WOLFSSL_STATIC_DH */ #endif default: - sig = 1; + if (oid == ECC_X25519_OID && defOid == oid) { + defOid = 0; + defSz = 80; + } + if (oid != ECC_X25519_OID) + sig = 1; key = 1; break; } @@ -5064,6 +5083,7 @@ static int TLSX_KeyShare_ProcessDh(WOLFSSL* ssl, KeyShareEntry* keyShareEntry) if (params->p_len != keyShareEntry->keLen) return BUFFER_ERROR; + ssl->options.dhKeySz = params->p_len; /* TODO: [TLS13] move this check down into wolfcrypt. */ /* Check that public DH key is not 0 or 1. */ @@ -5202,6 +5222,7 @@ static int TLSX_KeyShare_ProcessEcc(WOLFSSL* ssl, KeyShareEntry* keyShareEntry) EC25519_LITTLE_ENDIAN); wc_curve25519_free(peerEccKey); XFREE(peerEccKey, ssl->heap, DYNAMIC_TYPE_TLSX); + ssl->ecdhCurveOID = ECC_X25519_OID; return ret; } #endif @@ -5225,6 +5246,7 @@ static int TLSX_KeyShare_ProcessEcc(WOLFSSL* ssl, KeyShareEntry* keyShareEntry) ssl->peerEccKey, curveId) != 0) { return ECC_PEERKEY_ERROR; } + ssl->ecdhCurveOID = ssl->peerEccKey->dp->oidSum; ssl->arrays->preMasterSz = ENCRYPT_LEN; do { @@ -5588,6 +5610,10 @@ static int TLSX_KeyShare_IsSupported(int namedGroup) break; #endif /* !NO_ECC_SECP */ #endif + #ifdef HAVE_CURVE25519 + case WOLFSSL_ECC_X25519: + break; + #endif #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES) #ifndef NO_ECC_SECP case WOLFSSL_ECC_SECP384R1: @@ -5600,10 +5626,6 @@ static int TLSX_KeyShare_IsSupported(int namedGroup) break; #endif /* !NO_ECC_SECP */ #endif - #ifdef HAVE_CURVE25519 - case WOLFSSL_ECC_X25519: - break; - #endif #ifdef HAVE_X448 case WOLFSSL_ECC_X448: break; @@ -7019,6 +7041,11 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) WOLFSSL_ECC_SECP256R1, ssl->heap); if (ret != SSL_SUCCESS) return ret; #endif + #ifdef HAVE_CURVE25519 + ret = TLSX_UseSupportedCurve(&ssl->extensions, + WOLFSSL_ECC_X25519, ssl->heap); + if (ret != SSL_SUCCESS) return ret; + #endif #ifdef HAVE_ECC_KOBLITZ ret = TLSX_UseSupportedCurve(&ssl->extensions, WOLFSSL_ECC_SECP256K1, ssl->heap); @@ -7056,15 +7083,6 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) if (ret != SSL_SUCCESS) return ret; #endif #endif - #ifdef WOLFSSL_TLS13 - #if defined(HAVE_CURVE25519) - #ifndef NO_ECC_SECP - ret = TLSX_UseSupportedCurve(&ssl->extensions, - WOLFSSL_ECC_X25519, ssl->heap); - if (ret != SSL_SUCCESS) return ret; - #endif - #endif - #endif } #endif /* HAVE_ECC && HAVE_SUPPORTED_CURVES */ } /* is not server */ @@ -7120,6 +7138,8 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) !defined(NO_ECC_SECP) ret = TLSX_KeyShare_Use(ssl, WOLFSSL_ECC_SECP256R1, 0, NULL, NULL); + #elif defined(HAVE_CURVE25519) + ret = TLSX_KeyShare_Use(ssl, WOLFSSL_ECC_X25519, 0, NULL, NULL); #elif (!defined(NO_ECC384) || defined(HAVE_ALL_CURVES)) && \ !defined(NO_ECC_SECP) ret = TLSX_KeyShare_Use(ssl, WOLFSSL_ECC_SECP384R1, 0, NULL, diff --git a/wolfssl/internal.h b/wolfssl/internal.h index ea56d93b6..568fb7e86 100755 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -72,6 +72,9 @@ #ifdef HAVE_ECC #include #endif +#ifdef HAVE_CURVE25519 + #include +#endif #ifndef NO_SHA256 #include #endif @@ -2256,6 +2259,10 @@ struct WOLFSSL_CTX { CallbackEccSign EccSignCb; /* User EccSign Callback handler */ CallbackEccVerify EccVerifyCb; /* User EccVerify Callback handler */ CallbackEccSharedSecret EccSharedSecretCb; /* User EccVerify Callback handler */ + #ifdef HAVE_CURVE25519 + /* User EccSharedSecret Callback handler */ + CallbackX25519SharedSecret X25519SharedSecretCb; + #endif #endif /* HAVE_ECC */ #ifndef NO_RSA CallbackRsaSign RsaSignCb; /* User RsaSign Callback handler */ @@ -3116,6 +3123,10 @@ struct WOLFSSL { byte peerEccKeyPresent; byte peerEccDsaKeyPresent; byte eccTempKeyPresent; +#ifdef HAVE_CURVE25519 + curve25519_key* peerX25519Key; + byte peerX25519KeyPresent; +#endif #endif #ifdef HAVE_LIBZ z_stream c_stream; /* compression stream */ @@ -3219,6 +3230,9 @@ struct WOLFSSL { void* EccSignCtx; /* Ecc Sign Callback Context */ void* EccVerifyCtx; /* Ecc Verify Callback Context */ void* EccSharedSecretCtx; /* Ecc Pms Callback Context */ + #ifdef HAVE_CURVE25519 + void* X25519SharedSecretCtx; /* X25519 Pms Callback Context */ + #endif #endif /* HAVE_ECC */ #ifndef NO_RSA void* RsaSignCtx; /* Rsa Sign Callback Context */ diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 42750e788..7eccb75fc 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -1505,6 +1505,18 @@ 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 curve25519_key; +typedef int (*CallbackX25519SharedSecret)(WOLFSSL* ssl, + struct curve25519_key* otherKey, + unsigned char* pubKeyDer, unsigned int* pubKeySz, + unsigned char* out, unsigned int* outlen, + int side, void* ctx); + /* side is WOLFSSL_CLIENT_END or WOLFSSL_SERVER_END */ +WOLFSSL_API void wolfSSL_CTX_SetX25519SharedSecretCb(WOLFSSL_CTX*, + CallbackX25519SharedSecret); +WOLFSSL_API void wolfSSL_SetX25519SharedSecretCtx(WOLFSSL* ssl, void *ctx); +WOLFSSL_API void* wolfSSL_GetX25519SharedSecretCtx(WOLFSSL* ssl); + typedef int (*CallbackRsaSign)(WOLFSSL* ssl, const unsigned char* in, unsigned int inSz, unsigned char* out, unsigned int* outSz, @@ -1841,9 +1853,8 @@ enum { WOLFSSL_ECC_BRAINPOOLP256R1 = 26, WOLFSSL_ECC_BRAINPOOLP384R1 = 27, WOLFSSL_ECC_BRAINPOOLP512R1 = 28, -#ifdef WOLFSSL_TLS13 - /* Not implemented. */ WOLFSSL_ECC_X25519 = 29, +#ifdef WOLFSSL_TLS13 /* Not implemented. */ WOLFSSL_ECC_X448 = 30, diff --git a/wolfssl/test.h b/wolfssl/test.h index 9cc8ff6b5..3f48b2ce1 100644 --- a/wolfssl/test.h +++ b/wolfssl/test.h @@ -24,6 +24,9 @@ #ifdef HAVE_ECC #include #endif /* HAVE_ECC */ + #ifdef HAVE_CURVE25519 + #include + #endif /* HAVE_ECC */ #endif /*HAVE_PK_CALLBACKS */ #ifdef USE_WINDOWS_API @@ -1825,6 +1828,67 @@ static INLINE int myEccSharedSecret(WOLFSSL* ssl, ecc_key* otherKey, return ret; } +#ifdef HAVE_CURVE25519 +static INLINE int myX25519SharedSecret(WOLFSSL* ssl, curve25519_key* otherKey, + unsigned char* pubKeyDer, unsigned int* pubKeySz, + unsigned char* out, unsigned int* outlen, + int side, void* ctx) +{ + int ret; + curve25519_key* privKey = NULL; + curve25519_key* pubKey = NULL; + curve25519_key tmpKey; + + (void)ssl; + (void)ctx; + + ret = wc_curve25519_init(&tmpKey); + if (ret != 0) { + return ret; + } + + /* for client: create and export public key */ + if (side == WOLFSSL_CLIENT_END) { + WC_RNG rng; + + privKey = &tmpKey; + pubKey = otherKey; + + ret = wc_InitRng(&rng); + if (ret == 0) { + ret = wc_curve25519_make_key(&rng, CURVE25519_KEYSIZE, privKey); + if (ret == 0) { + ret = wc_curve25519_export_public_ex(privKey, pubKeyDer, + pubKeySz, EC25519_LITTLE_ENDIAN); + } + wc_FreeRng(&rng); + } + } + + /* for server: import public key */ + else if (side == WOLFSSL_SERVER_END) { + privKey = otherKey; + pubKey = &tmpKey; + + ret = wc_curve25519_import_public_ex(pubKeyDer, *pubKeySz, pubKey, + EC25519_LITTLE_ENDIAN); + } + else { + ret = BAD_FUNC_ARG; + } + + /* generate shared secret and return it */ + if (ret == 0) { + ret = wc_curve25519_shared_secret_ex(privKey, pubKey, out, outlen, + EC25519_LITTLE_ENDIAN); + } + + wc_curve25519_free(&tmpKey); + + return ret; +} +#endif /* HAVE_CURVE25519 */ + #endif /* HAVE_ECC */ #ifndef NO_RSA @@ -1959,6 +2023,9 @@ 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 */ #ifndef NO_RSA wolfSSL_CTX_SetRsaSignCb(ctx, myRsaSign); diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index 86776b810..a6ef14fa2 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -285,6 +285,7 @@ enum Ecc_Sum { ECC_SECP256R1_OID = 526, ECC_SECP256K1_OID = 186, ECC_BRAINPOOLP256R1_OID = 104, + ECC_X25519_OID = 365, ECC_BRAINPOOLP320R1_OID = 106, ECC_SECP384R1_OID = 210, ECC_BRAINPOOLP384R1_OID = 108, diff --git a/wolfssl/wolfcrypt/curve25519.h b/wolfssl/wolfcrypt/curve25519.h index d3a39eafc..fb4a96c29 100644 --- a/wolfssl/wolfcrypt/curve25519.h +++ b/wolfssl/wolfcrypt/curve25519.h @@ -53,7 +53,7 @@ typedef struct { }ECPoint; /* A CURVE25519 Key */ -typedef struct { +typedef struct curve25519_key { int idx; /* Index into the ecc_sets[] for the parameters of this curve if -1, this key is using user supplied curve in dp */ diff --git a/wolfssl/wolfcrypt/types.h b/wolfssl/wolfcrypt/types.h index 4d17719f9..880679b03 100755 --- a/wolfssl/wolfcrypt/types.h +++ b/wolfssl/wolfcrypt/types.h @@ -407,6 +407,7 @@ DYNAMIC_TYPE_ASYNC = 66, DYNAMIC_TYPE_ASYNC_NUMA = 67, DYNAMIC_TYPE_ASYNC_NUMA64 = 68, + DYNAMIC_TYPE_CURVE25519 = 69, }; /* max error buffer string size */