From b7663a940efa1ae70d3710dbdc2063683a8d9cf3 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Fri, 28 Sep 2018 09:05:59 -0700 Subject: [PATCH] Trusted CA Key Indication Extension Added an API for enabling the Trusted CA Key Indication extension from RFC6066 section 6. If the server doesn't have a match for the client, the client will abandon the session. --- configure.ac | 13 +- examples/client/client.c | 24 ++- examples/server/server.c | 23 ++- src/internal.c | 6 + src/ssl.c | 24 +++ src/tls.c | 339 +++++++++++++++++++++++++++++++++++++++ tests/api.c | 51 ++++++ wolfssl/error-ssl.h | 2 + wolfssl/internal.h | 20 +++ wolfssl/ssl.h | 17 ++ 10 files changed, 515 insertions(+), 4 deletions(-) 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 446e29e1c..cd72d5253 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -1290,6 +1290,9 @@ static void Usage(void) #endif #ifdef WOLFSSL_MULTICAST printf("%s", msg[++msgid]); /* -3 */ +#endif +#ifdef HAVE_TRUSTED_CA + printf("-5 Use Trusted CA Key Indication\n"); #endif printf("%s", msg[++msgid]); /* -1 */ #if !defined(NO_DH) && !defined(HAVE_FIPS) && \ @@ -1387,6 +1390,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 +1498,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) { @@ -1912,6 +1918,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: @@ -2356,11 +2367,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 @@ -2601,6 +2613,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..30ccd1879 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -825,6 +825,9 @@ static void Usage(void) printf("%s", msg[++msgId]); /* -3 */ #endif printf("%s", msg[++msgId]); /* -1 */ +#ifdef HAVE_TRUSTED_CA + printf("-5 Use Trusted CA Key Indication\n"); +#endif /* HAVE_TRUSTED_CA */ } THREAD_RETURN WOLFSSL_THREAD server_test(void* args) @@ -914,6 +917,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 +1017,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 +1379,11 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) doBlockSeq = 1; dtlsCtx.blockSeq = atoi(myoptarg); #endif + + case '5' : + #ifdef HAVE_TRUSTED_CA + trustedCaKeyId = 1; + #endif /* HAVE_TRUSTED_CA */ break; default: @@ -1953,6 +1965,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 c83b31726..592c8f8ef 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -1960,6 +1960,30 @@ 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* cert, word32 certSz) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + + return TLSX_UseTrustedCA(&ssl->extensions, type, cert, certSz, ssl->heap); +} + + +WOLFSSL_API int wolfSSL_CTX_UseTrustedCA(WOLFSSL_CTX* ctx, byte type, + const byte* cert, word32 certSz) +{ + if (ctx == NULL) + return BAD_FUNC_ARG; + + return TLSX_UseTrustedCA(&ctx->extensions, type, cert, certSz, ctx->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..6e9049a4f 100644 --- a/src/tls.c +++ b/src/tls.c @@ -2305,6 +2305,313 @@ 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; + + 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; + + 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; + case WOLFSSL_TRUSTED_CA_KEY_SHA1: + case WOLFSSL_TRUSTED_CA_CERT_SHA1: + XMEMCPY(output + offset, tca->id, tca->idSz); + offset += tca->idSz; + break; + case WOLFSSL_TRUSTED_CA_X509_NAME: + c16toa(tca->idSz, output + offset); /* tca length */ + offset += OPAQUE16_LEN; + XMEMCPY(output + offset, tca->id, tca->idSz); + offset += tca->idSz; + break; + } + } + + 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; + 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; + 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; + } + + tca = TLSX_TCA_Find((TCA*)extension->data, type, id, idSz); + if (!tca) + continue; + + TLSX_SetResponse(ssl, TLSX_TRUSTED_CA_KEYS); + } +#else + (void)input; +#endif + + return 0; +} + +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 +8547,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 +8676,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 +8820,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 +10164,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 +10465,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 99b2382af..384931256 100644 --- a/tests/api.c +++ b/tests/api.c @@ -3025,6 +3025,56 @@ 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_CTX_UseTrustedCA(NULL, 0, NULL, 0)); + AssertIntNE(WOLFSSL_SUCCESS, wolfSSL_UseTrustedCA(NULL, 0, NULL, 0)); + AssertIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_UseTrustedCA(ctx, + WOLFSSL_TRUSTED_CA_CERT_SHA1+1, NULL, 0)); + AssertIntNE(WOLFSSL_SUCCESS, wolfSSL_UseTrustedCA(ssl, + WOLFSSL_TRUSTED_CA_CERT_SHA1+1, NULL, 0)); + AssertIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_UseTrustedCA(ctx, + WOLFSSL_TRUSTED_CA_CERT_SHA1, NULL, 0)); + AssertIntNE(WOLFSSL_SUCCESS, wolfSSL_UseTrustedCA(ssl, + WOLFSSL_TRUSTED_CA_CERT_SHA1, NULL, 0)); + AssertIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_UseTrustedCA(ctx, + WOLFSSL_TRUSTED_CA_CERT_SHA1, id, 5)); + AssertIntNE(WOLFSSL_SUCCESS, wolfSSL_UseTrustedCA(ssl, + WOLFSSL_TRUSTED_CA_CERT_SHA1, id, 5)); + AssertIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_UseTrustedCA(ctx, + WOLFSSL_TRUSTED_CA_X509_NAME, id, 0)); + AssertIntNE(WOLFSSL_SUCCESS, wolfSSL_UseTrustedCA(ssl, + WOLFSSL_TRUSTED_CA_X509_NAME, id, 0)); + + /* success cases */ + AssertIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_UseTrustedCA(ctx, + WOLFSSL_TRUSTED_CA_PRE_AGREED, NULL, 0)); + AssertIntEQ(WOLFSSL_SUCCESS, wolfSSL_UseTrustedCA(ssl, + WOLFSSL_TRUSTED_CA_PRE_AGREED, NULL, 0)); + AssertIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_UseTrustedCA(ctx, + WOLFSSL_TRUSTED_CA_KEY_SHA1, id, sizeof(id))); + AssertIntEQ(WOLFSSL_SUCCESS, wolfSSL_UseTrustedCA(ssl, + WOLFSSL_TRUSTED_CA_KEY_SHA1, id, sizeof(id))); + AssertIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_UseTrustedCA(ctx, + WOLFSSL_TRUSTED_CA_X509_NAME, id, 5)); + 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) @@ -23409,6 +23459,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/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..6280d9712 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,24 @@ 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 */ +#ifndef NO_WOLFSSL_CLIENT + byte options; /* Behavior options */ +#endif /* NO_WOLFSSL_CLIENT */ +} 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..948263956 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -2248,6 +2248,23 @@ 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* cert, unsigned int certSz); +WOLFSSL_API int wolfSSL_CTX_UseTrustedCA(WOLFSSL_CTX* ctx, unsigned char type, + const unsigned char* cert, unsigned int certSz); +#endif /* HAVE_TRUSTED_CA */ + /* Application-Layer Protocol Negotiation */ #ifdef HAVE_ALPN