diff --git a/configure.ac b/configure.ac index f9a7cca60..f36fafb17 100644 --- a/configure.ac +++ b/configure.ac @@ -168,6 +168,7 @@ then enable_maxfragment=yes enable_alpn=yes enable_truncatedhmac=yes + enable_trusted_ca=yes enable_supportedcurves=yes enable_session_ticket=yes enable_tlsx=yes @@ -2863,6 +2864,14 @@ then AM_CFLAGS="$AM_CFLAGS -DHAVE_TLS_EXTENSIONS -DHAVE_MAX_FRAGMENT" fi +# Trusted CA Indication Extension +AC_ARG_ENABLE([trustedca], + [AS_HELP_STRING([--enable-trustedca],[Enable Trusted CA Indication (default: disabled)])], + [ ENABLED_TRUSTED_CA=$enableval ],[ ENABLED_TRUSTED_CA=no ]) + +AS_IF([test "x$ENABLED_TRUSTED_CA" = "xyes"], + [AM_CFLAGS="$AM_CFLAGS -DHAVE_TLS_EXTENSIONS -DHAVE_TRUSTED_CA"]) + # Truncated HMAC AC_ARG_ENABLE([truncatedhmac], [AS_HELP_STRING([--enable-truncatedhmac],[Enable Truncated HMAC (default: disabled)])], @@ -2992,7 +3001,8 @@ then ENABLED_MAX_FRAGMENT=yes ENABLED_TRUNCATED_HMAC=yes ENABLED_ALPN=yes - AM_CFLAGS="$AM_CFLAGS -DHAVE_TLS_EXTENSIONS -DHAVE_SNI -DHAVE_MAX_FRAGMENT -DHAVE_TRUNCATED_HMAC -DHAVE_ALPN" + ENABLED_TRUSTED_CA=yes + AM_CFLAGS="$AM_CFLAGS -DHAVE_TLS_EXTENSIONS -DHAVE_SNI -DHAVE_MAX_FRAGMENT -DHAVE_TRUNCATED_HMAC -DHAVE_ALPN -DHAVE_TRUSTED_CA" # Check the ECC supported curves prereq AS_IF([test "x$ENABLED_ECC" = "xyes" || test "x$ENABLED_CURVE25519" = "xyes"], [ENABLED_SUPPORTED_CURVES=yes @@ -4930,6 +4940,7 @@ echo " * Whitewood netRandom: $ENABLED_WNR" echo " * Server Name Indication: $ENABLED_SNI" echo " * ALPN: $ENABLED_ALPN" echo " * Maximum Fragment Length: $ENABLED_MAX_FRAGMENT" +echo " * Trusted CA Indication: $ENABLED_TRUSTED_CA" echo " * Truncated HMAC: $ENABLED_TRUNCATED_HMAC" echo " * Supported Elliptic Curves: $ENABLED_SUPPORTED_CURVES" echo " * FFDHE only in client: $ENABLED_FFDHE_ONLY" diff --git a/examples/client/client.c b/examples/client/client.c index 94734d828..afd55800a 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -988,7 +988,12 @@ static const char* client_usage_msg[][59] = { !defined(HAVE_SELFTEST) && !defined(WOLFSSL_OLD_PRIME_CHECK) "-2 Disable DH Prime check\n", /* 59 */ #endif +#ifdef HAVE_SECURE_RENEGOTIATION "-4 Use resumption for renegotiation\n", /* 60 */ +#endif +#ifdef HAVE_TRUSTED_CA + "-5 Use Trusted CA Key Indication\n", /* 61 */ +#endif NULL, }, #ifndef NO_MULTIBYTE_PRINT @@ -1146,6 +1151,9 @@ static const char* client_usage_msg[][59] = { #endif #ifdef HAVE_SECURE_RENEGOTIATION "-4 再交渉に再開を使用\n", /* 60 */ +#endif +#ifdef HAVE_TRUSTED_CA + "-5 信頼できる認証局の鍵表示を使用する\n", /* 61 */ #endif NULL, }, @@ -1299,6 +1307,9 @@ static void Usage(void) #ifdef HAVE_SECURE_RENEGOTIATION printf("%s", msg[++msgid]); /* -4 */ #endif +#ifdef HAVE_TRUSTED_CA + printf("%s", msg[++msgid]); /* -5 */ +#endif } THREAD_RETURN WOLFSSL_THREAD client_test(void* args) @@ -1387,6 +1398,9 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) #ifdef HAVE_SNI char* sniHostName = NULL; #endif +#ifdef HAVE_TRUSTED_CA + int trustedCaKeyId = 0; +#endif #ifdef HAVE_MAX_FRAGMENT byte maxFragment = 0; #endif @@ -1492,7 +1506,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) while ((ch = mygetopt(argc, argv, "?:" "ab:c:defgh:ijk:l:mnop:q:rstuv:wxyz" "A:B:CDE:F:GH:IJKL:M:NO:PQRS:TUVW:XYZ:" - "01:23:4")) != -1) { + "01:23:5")) != -1) { switch (ch) { case '?' : if(myoptarg!=NULL) { @@ -1916,6 +1930,11 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) forceScr = 1; resumeScr = 1; #endif + + case '5' : + #ifdef HAVE_TRUSTED_CA + trustedCaKeyId = 1; + #endif /* HAVE_TRUSTED_CA */ break; default: @@ -2360,11 +2379,12 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) #endif /* WOLFSSL_ASYNC_CRYPT */ #ifdef HAVE_SNI - if (sniHostName) + if (sniHostName) { if (wolfSSL_CTX_UseSNI(ctx, 0, sniHostName, (word16) XSTRLEN(sniHostName)) != WOLFSSL_SUCCESS) { wolfSSL_CTX_free(ctx); ctx = NULL; err_sys("UseSNI failed"); + } } #endif #ifdef HAVE_MAX_FRAGMENT @@ -2605,6 +2625,14 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) wolfSSL_set_SessionTicket_cb(ssl, sessionTicketCB, (void*)"initial session"); #endif +#ifdef HAVE_TRUSTED_CA + if (trustedCaKeyId) { + if (wolfSSL_UseTrustedCA(ssl, WOLFSSL_TRUSTED_CA_PRE_AGREED, + NULL, 0) != WOLFSSL_SUCCESS) { + err_sys("UseTrustedCA failed"); + } + } +#endif #ifdef HAVE_ALPN if (alpnList != NULL) { printf("ALPN accepted protocols list : %s\n", alpnList); diff --git a/examples/server/server.c b/examples/server/server.c index dc1b30ae6..4eda55701 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -594,6 +594,9 @@ static const char* server_usage_msg[][49] = { #endif "-1 Display a result by specified language." "\n 0: English, 1: Japanese\n", /* 48 */ +#ifdef HAVE_TRUSTED_CA + "-5 Use Trusted CA Key Indication\n", /* 51 */ +#endif NULL, }, #ifndef NO_MULTIBYTE_PRINT @@ -709,10 +712,12 @@ static const char* server_usage_msg[][49] = { #endif "-1 指定された言語で結果を表示します。" "\n 0: 英語、 1: 日本語\n", /* 48 */ +#ifdef HAVE_TRUSTED_CA + "-5 信頼できる認証局の鍵表示を使用する\n", /* 51 */ +#endif NULL, }, #endif - }; static void Usage(void) @@ -825,6 +830,9 @@ static void Usage(void) printf("%s", msg[++msgId]); /* -3 */ #endif printf("%s", msg[++msgId]); /* -1 */ +#ifdef HAVE_TRUSTED_CA + printf("%s", msg[++msgId]); /* -5 */ +#endif /* HAVE_TRUSTED_CA */ } THREAD_RETURN WOLFSSL_THREAD server_test(void* args) @@ -914,6 +922,10 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) char* sniHostName = NULL; #endif +#ifdef HAVE_TRUSTED_CA + int trustedCaKeyId = 0; +#endif /* HAVE_TRUSTED_CA */ + #ifdef HAVE_OCSP int useOcsp = 0; char* ocspUrl = NULL; @@ -1010,7 +1022,7 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) while ((ch = mygetopt(argc, argv, "?:" "abc:defgijk:l:mnop:q:rstuv:wxy" "A:B:C:D:E:GH:IJKL:MNO:PQR:S:TUVYZ:" - "01:23:4:")) != -1) { + "01:23:4:5")) != -1) { switch (ch) { case '?' : if(myoptarg!=NULL) { @@ -1372,6 +1384,12 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) doBlockSeq = 1; dtlsCtx.blockSeq = atoi(myoptarg); #endif + break; + + case '5' : + #ifdef HAVE_TRUSTED_CA + trustedCaKeyId = 1; + #endif /* HAVE_TRUSTED_CA */ break; default: @@ -1953,6 +1971,15 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) err_sys_ex(runWithErrors, "error in setting fd"); } +#ifdef HAVE_TRUSTED_CA + if (trustedCaKeyId) { + if (wolfSSL_UseTrustedCA(ssl, WOLFSSL_TRUSTED_CA_PRE_AGREED, + NULL, 0) != WOLFSSL_SUCCESS) { + err_sys_ex(runWithErrors, "UseTrustedCA failed"); + } + } +#endif /* HAVE_TRUSTED_CA */ + #ifdef HAVE_ALPN if (alpnList != NULL) { printf("ALPN accepted protocols list : %s\n", alpnList); diff --git a/src/internal.c b/src/internal.c index 133ce6f2a..39c0ea003 100644 --- a/src/internal.c +++ b/src/internal.c @@ -15947,6 +15947,12 @@ const char* wolfSSL_ERR_reason_error_string(unsigned long e) case DH_PARAMS_NOT_FFDHE_E: return "Server DH parameters were not from the FFDHE set as required"; + case TCA_INVALID_ID_TYPE: + return "TLS Extension Trusted CA ID type invalid"; + + case TCA_ABSENT_ERROR: + return "TLS Extension Trusted CA ID response absent"; + default : return "unknown error number"; } diff --git a/src/ssl.c b/src/ssl.c index 59d1f4ed5..ea1c34f6e 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -1960,6 +1960,39 @@ int wolfSSL_SNI_GetFromBuffer(const byte* clientHello, word32 helloSz, #endif /* HAVE_SNI */ +#ifdef HAVE_TRUSTED_CA + +WOLFSSL_API int wolfSSL_UseTrustedCA(WOLFSSL* ssl, byte type, + const byte* certId, word32 certIdSz) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + + if (type == WOLFSSL_TRUSTED_CA_PRE_AGREED) { + if (certId != NULL || certIdSz != 0) + return BAD_FUNC_ARG; + } + else if (type == WOLFSSL_TRUSTED_CA_X509_NAME) { + if (certId == NULL || certIdSz == 0) + return BAD_FUNC_ARG; + } + #ifndef NO_SHA + else if (type == WOLFSSL_TRUSTED_CA_KEY_SHA1 || + type == WOLFSSL_TRUSTED_CA_CERT_SHA1) { + if (certId == NULL || certIdSz != SHA_DIGEST_SIZE) + return BAD_FUNC_ARG; + } + #endif + else + return BAD_FUNC_ARG; + + return TLSX_UseTrustedCA(&ssl->extensions, + type, certId, certIdSz, ssl->heap); +} + +#endif /* HAVE_TRUSTED_CA */ + + #ifdef HAVE_MAX_FRAGMENT #ifndef NO_WOLFSSL_CLIENT diff --git a/src/tls.c b/src/tls.c index 6532cf10e..8c048cf90 100644 --- a/src/tls.c +++ b/src/tls.c @@ -2305,6 +2305,340 @@ int TLSX_SNI_GetFromBuffer(const byte* clientHello, word32 helloSz, #endif /* HAVE_SNI */ +/******************************************************************************/ +/* Trusted CA Key Indication */ +/******************************************************************************/ + +#ifdef HAVE_TRUSTED_CA + +/** Creates a new TCA object. */ +static TCA* TLSX_TCA_New(byte type, const byte* id, word16 idSz, void* heap) +{ + TCA* tca = (TCA*)XMALLOC(sizeof(TCA), heap, DYNAMIC_TYPE_TLSX); + + if (tca) { + XMEMSET(tca, 0, sizeof(TCA)); + tca->type = type; + + switch (type) { + case WOLFSSL_TRUSTED_CA_PRE_AGREED: + break; + + #ifndef NO_SHA + case WOLFSSL_TRUSTED_CA_KEY_SHA1: + case WOLFSSL_TRUSTED_CA_CERT_SHA1: + if (idSz == SHA_DIGEST_SIZE && + (tca->id = + (byte*)XMALLOC(idSz, heap, DYNAMIC_TYPE_TLSX))) { + XMEMCPY(tca->id, id, idSz); + tca->idSz = idSz; + } + else { + XFREE(tca, heap, DYNAMIC_TYPE_TLSX); + tca = NULL; + } + break; + #endif + + case WOLFSSL_TRUSTED_CA_X509_NAME: + if (idSz > 0 && + (tca->id = + (byte*)XMALLOC(idSz, heap, DYNAMIC_TYPE_TLSX))) { + XMEMCPY(tca->id, id, idSz); + tca->idSz = idSz; + } + else { + XFREE(tca, heap, DYNAMIC_TYPE_TLSX); + tca = NULL; + } + break; + + default: /* invalid type */ + XFREE(tca, heap, DYNAMIC_TYPE_TLSX); + tca = NULL; + } + } + + return tca; +} + +/** Releases a TCA object. */ +static void TLSX_TCA_Free(TCA* tca, void* heap) +{ + (void)heap; + + if (tca) { + if (tca->id) + XFREE(tca->id, heap, DYNAMIC_TYPE_TLSX); + XFREE(tca, heap, DYNAMIC_TYPE_TLSX); + } +} + +/** Releases all TCA objects in the provided list. */ +static void TLSX_TCA_FreeAll(TCA* list, void* heap) +{ + TCA* tca; + + while ((tca = list)) { + list = tca->next; + TLSX_TCA_Free(tca, heap); + } +} + +/** Tells the buffered size of the TCA objects in a list. */ +static word16 TLSX_TCA_GetSize(TCA* list) +{ + TCA* tca; + word16 length = OPAQUE16_LEN; /* list length */ + + while ((tca = list)) { + list = tca->next; + + length += ENUM_LEN; /* tca type */ + + switch (tca->type) { + case WOLFSSL_TRUSTED_CA_PRE_AGREED: + break; + case WOLFSSL_TRUSTED_CA_KEY_SHA1: + case WOLFSSL_TRUSTED_CA_CERT_SHA1: + length += tca->idSz; + break; + case WOLFSSL_TRUSTED_CA_X509_NAME: + length += OPAQUE16_LEN + tca->idSz; + break; + } + } + + return length; +} + +/** Writes the TCA objects of a list in a buffer. */ +static word16 TLSX_TCA_Write(TCA* list, byte* output) +{ + TCA* tca; + word16 offset = OPAQUE16_LEN; /* list length offset */ + + while ((tca = list)) { + list = tca->next; + + output[offset++] = tca->type; /* tca type */ + + switch (tca->type) { + case WOLFSSL_TRUSTED_CA_PRE_AGREED: + break; + #ifndef NO_SHA + case WOLFSSL_TRUSTED_CA_KEY_SHA1: + case WOLFSSL_TRUSTED_CA_CERT_SHA1: + if (tca->id != NULL) { + XMEMCPY(output + offset, tca->id, tca->idSz); + offset += tca->idSz; + } + else { + /* ID missing. Set to an empty string. */ + c16toa(0, output + offset); + offset += OPAQUE16_LEN; + } + break; + #endif + case WOLFSSL_TRUSTED_CA_X509_NAME: + if (tca->id != NULL) { + c16toa(tca->idSz, output + offset); /* tca length */ + offset += OPAQUE16_LEN; + XMEMCPY(output + offset, tca->id, tca->idSz); + offset += tca->idSz; + } + else { + /* ID missing. Set to an empty string. */ + c16toa(0, output + offset); + offset += OPAQUE16_LEN; + } + break; + default: + /* ID unknown. Set to an empty string. */ + c16toa(0, output + offset); + offset += OPAQUE16_LEN; + } + } + + c16toa(offset - OPAQUE16_LEN, output); /* writing list length */ + + return offset; +} + +static TCA* TLSX_TCA_Find(TCA *list, byte type, const byte* id, word16 idSz) +{ + TCA* tca = list; + + while (tca && tca->type != type && type != WOLFSSL_TRUSTED_CA_PRE_AGREED && + idSz != tca->idSz && !XMEMCMP(id, tca->id, idSz)) + tca = tca->next; + + return tca; +} + +/** Parses a buffer of TCA extensions. */ +static int TLSX_TCA_Parse(WOLFSSL* ssl, const byte* input, word16 length, + byte isRequest) +{ +#ifndef NO_WOLFSSL_SERVER + word16 size = 0; + word16 offset = 0; +#endif + + TLSX *extension = TLSX_Find(ssl->extensions, TLSX_TRUSTED_CA_KEYS); + + if (!extension) + extension = TLSX_Find(ssl->ctx->extensions, TLSX_TRUSTED_CA_KEYS); + + if (!isRequest) { + #ifndef NO_WOLFSSL_CLIENT + if (!extension || !extension->data) + return TLSX_HandleUnsupportedExtension(ssl); + + if (length > 0) + return BUFFER_ERROR; /* TCA response MUST be empty. */ + + /* Set the flag that we're good for keys */ + TLSX_SetResponse(ssl, TLSX_TRUSTED_CA_KEYS); + + return 0; + #endif + } + +#ifndef NO_WOLFSSL_SERVER + if (!extension || !extension->data) { + /* Skipping, TCA not enabled at server side. */ + return 0; + } + + if (OPAQUE16_LEN > length) + return BUFFER_ERROR; + + ato16(input, &size); + offset += OPAQUE16_LEN; + + /* validating tca list length */ + if (length != OPAQUE16_LEN + size) + return BUFFER_ERROR; + + for (size = 0; offset < length; offset += size) { + TCA *tca = NULL; + byte type; + const byte* id = NULL; + word16 idSz = 0; + + if (offset + ENUM_LEN > length) + return BUFFER_ERROR; + + type = input[offset++]; + + switch (type) { + case WOLFSSL_TRUSTED_CA_PRE_AGREED: + break; + #ifndef NO_SHA + case WOLFSSL_TRUSTED_CA_KEY_SHA1: + case WOLFSSL_TRUSTED_CA_CERT_SHA1: + if (offset + SHA_DIGEST_SIZE > length) + return BUFFER_ERROR; + idSz = SHA_DIGEST_SIZE; + id = input + offset; + offset += idSz; + break; + #endif + case WOLFSSL_TRUSTED_CA_X509_NAME: + if (offset + OPAQUE16_LEN > length) + return BUFFER_ERROR; + ato16(input + offset, &idSz); + offset += OPAQUE16_LEN; + if (offset + idSz > length) + return BUFFER_ERROR; + id = input + offset; + offset += idSz; + break; + default: + return TCA_INVALID_ID_TYPE; + } + + /* Find the type/ID in the TCA list. */ + tca = TLSX_TCA_Find((TCA*)extension->data, type, id, idSz); + if (tca != NULL) { + /* Found it. Set the response flag and break out of the loop. */ + TLSX_SetResponse(ssl, TLSX_TRUSTED_CA_KEYS); + break; + } + } +#else + (void)input; +#endif + + return 0; +} + +/* Checks to see if the server sent a response for the TCA. */ +static int TLSX_TCA_VerifyParse(WOLFSSL* ssl, byte isRequest) +{ + (void)ssl; + + if (!isRequest) { + #ifndef NO_WOLFSSL_CLIENT + TLSX* extension = TLSX_Find(ssl->extensions, TLSX_TRUSTED_CA_KEYS); + + if (extension && !extension->resp) { + SendAlert(ssl, alert_fatal, handshake_failure); + return TCA_ABSENT_ERROR; + } + #endif /* NO_WOLFSSL_CLIENT */ + } + + return 0; +} + +int TLSX_UseTrustedCA(TLSX** extensions, byte type, + const byte* id, word16 idSz, void* heap) +{ + TLSX* extension; + TCA* tca = NULL; + + if (extensions == NULL) + return BAD_FUNC_ARG; + + if ((tca = TLSX_TCA_New(type, id, idSz, heap)) == NULL) + return MEMORY_E; + + extension = TLSX_Find(*extensions, TLSX_TRUSTED_CA_KEYS); + if (!extension) { + int ret = TLSX_Push(extensions, TLSX_TRUSTED_CA_KEYS, (void*)tca, heap); + + if (ret != 0) { + TLSX_TCA_Free(tca, heap); + return ret; + } + } + else { + /* push new TCA object to extension data. */ + tca->next = (TCA*)extension->data; + extension->data = (void*)tca; + } + + return WOLFSSL_SUCCESS; +} + +#define TCA_FREE_ALL TLSX_TCA_FreeAll +#define TCA_GET_SIZE TLSX_TCA_GetSize +#define TCA_WRITE TLSX_TCA_Write +#define TCA_PARSE TLSX_TCA_Parse +#define TCA_VERIFY_PARSE TLSX_TCA_VerifyParse + +#else /* HAVE_TRUSTED_CA */ + +#define TCA_FREE_ALL(list, heap) +#define TCA_GET_SIZE(list) 0 +#define TCA_WRITE(a, b) 0 +#define TCA_PARSE(a, b, c, d) 0 +#define TCA_VERIFY_PARSE(a, b) 0 + +#endif /* HAVE_TRUSTED_CA */ + /******************************************************************************/ /* Max Fragment Length Negotiation */ /******************************************************************************/ @@ -8240,6 +8574,10 @@ void TLSX_FreeAll(TLSX* list, void* heap) SNI_FREE_ALL((SNI*)extension->data, heap); break; + case TLSX_TRUSTED_CA_KEYS: + TCA_FREE_ALL((TCA*)extension->data, heap); + break; + case TLSX_MAX_FRAGMENT_LENGTH: MFL_FREE_ALL(extension->data, heap); break; @@ -8365,6 +8703,12 @@ static int TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType, word16* pLeng length += SNI_GET_SIZE((SNI*)extension->data); break; + case TLSX_TRUSTED_CA_KEYS: + /* TCA only sends the list on the request. */ + if (isRequest) + length += TCA_GET_SIZE((TCA*)extension->data); + break; + case TLSX_MAX_FRAGMENT_LENGTH: length += MFL_GET_SIZE(extension->data); break; @@ -8503,6 +8847,13 @@ static int TLSX_Write(TLSX* list, byte* output, byte* semaphore, } break; + case TLSX_TRUSTED_CA_KEYS: + WOLFSSL_MSG("Trusted CA Indication extension to write"); + if (isRequest) { + offset += TCA_WRITE((TCA*)extension->data, output + offset); + } + break; + case TLSX_MAX_FRAGMENT_LENGTH: WOLFSSL_MSG("Max Fragment Length extension to write"); offset += MFL_WRITE((byte*)extension->data, output + offset); @@ -9840,6 +10191,19 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte msgType, ret = SNI_PARSE(ssl, input + offset, size, isRequest); break; + case TLSX_TRUSTED_CA_KEYS: + WOLFSSL_MSG("Trusted CA extension received"); + +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version) && + msgType != client_hello && + msgType != encrypted_extensions) { + return EXT_NOT_ALLOWED; + } +#endif + ret = TCA_PARSE(ssl, input + offset, size, isRequest); + break; + case TLSX_MAX_FRAGMENT_LENGTH: WOLFSSL_MSG("Max Fragment Length extension received"); @@ -10128,6 +10492,8 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte msgType, if (ret == 0) ret = SNI_VERIFY_PARSE(ssl, isRequest); + if (ret == 0) + ret = TCA_VERIFY_PARSE(ssl, isRequest); return ret; } diff --git a/tests/api.c b/tests/api.c index 184f39c57..dbee20fab 100644 --- a/tests/api.c +++ b/tests/api.c @@ -3025,6 +3025,47 @@ static void test_wolfSSL_UseSNI(void) #endif } +static void test_wolfSSL_UseTrustedCA(void) +{ +#ifdef HAVE_TRUSTED_CA + WOLFSSL_CTX *ctx; + WOLFSSL *ssl; + byte id[20]; + + AssertNotNull((ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()))); + AssertNotNull((ssl = wolfSSL_new(ctx))); + XMEMSET(id, 0, sizeof(id)); + + /* error cases */ + AssertIntNE(WOLFSSL_SUCCESS, wolfSSL_UseTrustedCA(NULL, 0, NULL, 0)); + AssertIntNE(WOLFSSL_SUCCESS, wolfSSL_UseTrustedCA(ssl, + WOLFSSL_TRUSTED_CA_CERT_SHA1+1, NULL, 0)); + AssertIntNE(WOLFSSL_SUCCESS, wolfSSL_UseTrustedCA(ssl, + WOLFSSL_TRUSTED_CA_CERT_SHA1, NULL, 0)); + AssertIntNE(WOLFSSL_SUCCESS, wolfSSL_UseTrustedCA(ssl, + WOLFSSL_TRUSTED_CA_CERT_SHA1, id, 5)); +#ifdef NO_SHA + AssertIntNE(WOLFSSL_SUCCESS, wolfSSL_UseTrustedCA(ssl, + WOLFSSL_TRUSTED_CA_KEY_SHA1, id, sizeof(id))); +#endif + AssertIntNE(WOLFSSL_SUCCESS, wolfSSL_UseTrustedCA(ssl, + WOLFSSL_TRUSTED_CA_X509_NAME, id, 0)); + + /* success cases */ + AssertIntEQ(WOLFSSL_SUCCESS, wolfSSL_UseTrustedCA(ssl, + WOLFSSL_TRUSTED_CA_PRE_AGREED, NULL, 0)); +#ifndef NO_SHA + AssertIntEQ(WOLFSSL_SUCCESS, wolfSSL_UseTrustedCA(ssl, + WOLFSSL_TRUSTED_CA_KEY_SHA1, id, sizeof(id))); +#endif + AssertIntEQ(WOLFSSL_SUCCESS, wolfSSL_UseTrustedCA(ssl, + WOLFSSL_TRUSTED_CA_X509_NAME, id, 5)); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif /* HAVE_TRUSTED_CA */ +} + static void test_wolfSSL_UseMaxFragment(void) { #if defined(HAVE_MAX_FRAGMENT) && !defined(NO_WOLFSSL_CLIENT) @@ -23430,6 +23471,7 @@ void ApiTest(void) /* TLS extensions tests */ test_wolfSSL_UseSNI(); + test_wolfSSL_UseTrustedCA(); test_wolfSSL_UseMaxFragment(); test_wolfSSL_UseTruncatedHMAC(); test_wolfSSL_UseSupportedCurve(); diff --git a/tests/test.conf b/tests/test.conf index eaece3e6e..64e8b48ee 100644 --- a/tests/test.conf +++ b/tests/test.conf @@ -2438,3 +2438,11 @@ -v 3 -l ECDHE-RSA-AES128-GCM-SHA256 -i -4 + +# server TLSv1.2 with Trusted CA Indication (pre-shared) +-v 3 +-5 + +# client TLSv1.2 with Trusted CA Indication (pre-shared) +-v 3 +-5 diff --git a/wolfssl/error-ssl.h b/wolfssl/error-ssl.h index c16002762..fcbcbc71f 100644 --- a/wolfssl/error-ssl.h +++ b/wolfssl/error-ssl.h @@ -161,6 +161,8 @@ enum wolfSSL_ErrorCodes { PRF_MISSING = -430, /* PRF not compiled in */ DTLS_RETX_OVER_TX = -431, /* Retransmit DTLS flight over */ DH_PARAMS_NOT_FFDHE_E = -432, /* DH params from server not FFDHE */ + TCA_INVALID_ID_TYPE = -433, /* TLSX TCA ID type invalid */ + TCA_ABSENT_ERROR = -434, /* TLSX TCA ID no response */ /* add strings to wolfSSL_ERR_reason_error_string in internal.c !!!!! */ /* begin negotiation parameter errors */ diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 4be19bae5..b81054044 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -2055,6 +2055,7 @@ typedef struct Keys { typedef enum { TLSX_SERVER_NAME = 0x0000, /* a.k.a. SNI */ TLSX_MAX_FRAGMENT_LENGTH = 0x0001, + TLSX_TRUSTED_CA_KEYS = 0x0003, TLSX_TRUNCATED_HMAC = 0x0004, TLSX_STATUS_REQUEST = 0x0005, /* a.k.a. OCSP stapling */ TLSX_SUPPORTED_GROUPS = 0x000a, /* a.k.a. Supported Curves */ @@ -2125,6 +2126,7 @@ WOLFSSL_LOCAL int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, #elif defined(HAVE_SNI) \ || defined(HAVE_MAX_FRAGMENT) \ + || defined(HAVE_TRUSTED_CA) \ || defined(HAVE_TRUNCATED_HMAC) \ || defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) \ @@ -2167,6 +2169,21 @@ WOLFSSL_LOCAL int TLSX_SNI_GetFromBuffer(const byte* buffer, word32 bufferSz, #endif /* HAVE_SNI */ +/* Trusted CA Key Indication - RFC 6066 (section 6) */ +#ifdef HAVE_TRUSTED_CA + +typedef struct TCA { + byte type; /* TCA Type */ + byte* id; /* TCA identifier */ + word16 idSz; /* TCA identifier size */ + struct TCA* next; /* List Behavior */ +} TCA; + +WOLFSSL_LOCAL int TLSX_UseTrustedCA(TLSX** extensions, byte type, + const byte* id, word16 idSz, void* heap); + +#endif /* HAVE_TRUSTED_CA */ + /* Application-Layer Protocol Negotiation - RFC 7301 */ #ifdef HAVE_ALPN typedef struct ALPN { diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 42004e0da..ec1a0bee0 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -2248,6 +2248,21 @@ WOLFSSL_API unsigned short wolfSSL_SNI_GetRequest(WOLFSSL *ssl, #endif /* HAVE_SNI */ +/* Trusted CA Key Indication - RFC 6066 (Section 6) */ +#ifdef HAVE_TRUSTED_CA + +/* TCA Identifier Type */ +enum { + WOLFSSL_TRUSTED_CA_PRE_AGREED = 0, + WOLFSSL_TRUSTED_CA_KEY_SHA1 = 1, + WOLFSSL_TRUSTED_CA_X509_NAME = 2, + WOLFSSL_TRUSTED_CA_CERT_SHA1 = 3 +}; + +WOLFSSL_API int wolfSSL_UseTrustedCA(WOLFSSL* ssl, unsigned char type, + const unsigned char* certId, unsigned int certIdSz); +#endif /* HAVE_TRUSTED_CA */ + /* Application-Layer Protocol Negotiation */ #ifdef HAVE_ALPN