diff --git a/configure.ac b/configure.ac index 02f6bfa74..8040eeb19 100644 --- a/configure.ac +++ b/configure.ac @@ -3317,6 +3317,16 @@ then then ENABLED_PSK="yes" fi + if test "x$ENABLED_CERTEXT" = "xno" + then + ENABLED_CERTEXT="yes" + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_CERT_EXT" + fi + if test "x$ENABLED_CERTGEN" = "xno" + then + ENABLED_CERTGEN="yes" + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_CERT_GEN" + fi fi # lighty Support diff --git a/examples/client/client.c b/examples/client/client.c index 7dccfacd7..9f908f99a 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -2815,6 +2815,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) showPeerEx(ssl, lng_index); #ifdef OPENSSL_EXTRA + printf("Session timeout set to %ld seconds\n", wolfSSL_get_timeout(ssl)); { byte* rnd; byte* pt; diff --git a/src/internal.c b/src/internal.c index 5dd7e79d5..5a92c78e8 100644 --- a/src/internal.c +++ b/src/internal.c @@ -16033,6 +16033,27 @@ void SetErrorString(int error, char* str) static const CipherSuiteInfo cipher_names[] = { + +#ifdef BUILD_TLS_AES_128_GCM_SHA256 + SUITE_INFO("TLS13-AES128-GCM-SHA256","TLS_AES_128_GCM_SHA256",TLS13_BYTE,TLS_AES_128_GCM_SHA256), +#endif + +#ifdef BUILD_TLS_AES_256_GCM_SHA384 + SUITE_INFO("TLS13-AES256-GCM-SHA384","TLS_AES_256_GCM_SHA384",TLS13_BYTE,TLS_AES_256_GCM_SHA384), +#endif + +#ifdef BUILD_TLS_CHACHA20_POLY1305_SHA256 + SUITE_INFO("TLS13-CHACHA20-POLY1305-SHA256","TLS_CHACHA20_POLY1305_SHA256",TLS13_BYTE,TLS_CHACHA20_POLY1305_SHA256), +#endif + +#ifdef BUILD_TLS_AES_128_CCM_SHA256 + SUITE_INFO("TLS13-AES128-CCM-SHA256","TLS_AES_128_CCM_SHA256",TLS13_BYTE,TLS_AES_128_CCM_SHA256), +#endif + +#ifdef BUILD_TLS_AES_128_CCM_8_SHA256 + SUITE_INFO("TLS13-AES128-CCM-8-SHA256","TLS_AES_128_CCM_8_SHA256",TLS13_BYTE,TLS_AES_128_CCM_8_SHA256), +#endif + #ifndef WOLFSSL_NO_TLS12 #ifdef BUILD_SSL_RSA_WITH_RC4_128_SHA @@ -16484,26 +16505,6 @@ static const CipherSuiteInfo cipher_names[] = #endif #endif /* WOLFSSL_NO_TLS12 */ - -#ifdef BUILD_TLS_AES_128_GCM_SHA256 - SUITE_INFO("TLS13-AES128-GCM-SHA256","TLS_AES_128_GCM_SHA256",TLS13_BYTE,TLS_AES_128_GCM_SHA256), -#endif - -#ifdef BUILD_TLS_AES_256_GCM_SHA384 - SUITE_INFO("TLS13-AES256-GCM-SHA384","TLS_AES_256_GCM_SHA384",TLS13_BYTE,TLS_AES_256_GCM_SHA384), -#endif - -#ifdef BUILD_TLS_CHACHA20_POLY1305_SHA256 - SUITE_INFO("TLS13-CHACHA20-POLY1305-SHA256","TLS_CHACHA20_POLY1305_SHA256",TLS13_BYTE,TLS_CHACHA20_POLY1305_SHA256), -#endif - -#ifdef BUILD_TLS_AES_128_CCM_SHA256 - SUITE_INFO("TLS13-AES128-CCM-SHA256","TLS_AES_128_CCM_SHA256",TLS13_BYTE,TLS_AES_128_CCM_SHA256), -#endif - -#ifdef BUILD_TLS_AES_128_CCM_8_SHA256 - SUITE_INFO("TLS13-AES128-CCM-8-SHA256","TLS_AES_128_CCM_8_SHA256",TLS13_BYTE,TLS_AES_128_CCM_8_SHA256), -#endif }; @@ -16636,7 +16637,11 @@ int SetCipherList(WOLFSSL_CTX* ctx, Suites* suites, const char* list) name[(length == sizeof(name)) ? length - 1 : length] = 0; for (i = 0; i < suiteSz; i++) { - if (XSTRNCMP(name, cipher_names[i].name, sizeof(name)) == 0) { + if (XSTRNCMP(name, cipher_names[i].name, sizeof(name)) == 0 + #ifndef NO_ERROR_STRINGS + || XSTRNCMP(name, cipher_names[i].name_iana, sizeof(name)) == 0 + #endif + ) { #ifdef WOLFSSL_DTLS /* don't allow stream ciphers with DTLS */ if (ctx->method->version.major == DTLS_MAJOR) { @@ -16656,29 +16661,12 @@ int SetCipherList(WOLFSSL_CTX* ctx, Suites* suites, const char* list) return 0; /* suites buffer not large enough, error out */ } - suites->suites[idx++] = - #ifdef WOLFSSL_TLS13 - (XSTRSTR(name, "TLS13")) ? TLS13_BYTE : - #endif - #ifdef HAVE_CHACHA - (XSTRSTR(name, "CHACHA")) ? CHACHA_BYTE : - #endif - #ifdef HAVE_QSH - (XSTRSTR(name, "QSH")) ? QSH_BYTE : - #endif - #if defined(HAVE_ECC) || defined(HAVE_CURVE25519) - (XSTRSTR(name, "EC")) ? ECC_BYTE : - #endif - #ifdef HAVE_AESCCM - (XSTRSTR(name, "CCM")) ? ECC_BYTE : - #endif - CIPHER_BYTE; /* normal */ - + suites->suites[idx++] = cipher_names[i].cipherSuite0; suites->suites[idx++] = cipher_names[i].cipherSuite; /* The suites are either ECDSA, RSA, PSK, or Anon. The RSA * suites don't necessarily have RSA in the name. */ #ifdef WOLFSSL_TLS13 - if (XSTRSTR(name, "TLS13")) { + if (cipher_names[i].cipherSuite0 == TLS13_BYTE) { #ifndef NO_RSA haveRSAsig = 1; #endif @@ -17869,6 +17857,30 @@ exit_dpk: return ret; } +#ifdef WOLFSSL_TLS13 + /* returns 1 if able to do TLS 1.3 otherwise 0 */ + static int TLSv1_3_Capable(WOLFSSL* ssl) + { + #ifndef WOLFSSL_TLS13 + return 0; + #else + int ret = 0; + + if (IsAtLeastTLSv1_3(ssl->ctx->method->version)) { + ret = 1; + } + + #ifdef OPENSSL_EXTRA + if ((wolfSSL_get_options(ssl) & SSL_OP_NO_TLSv1_3)) { + /* option set at run time to disable TLS 1.3 */ + ret = 0; + } + #endif + return ret; + #endif + } +#endif /* WOLFSSL_TLS13 */ + int CompleteServerHello(WOLFSSL* ssl) { int ret; @@ -17878,7 +17890,7 @@ exit_dpk: TLS13_DOWNGRADE_SZ - 1; byte vers = ssl->arrays->serverRandom[RAN_LEN - 1]; #ifdef WOLFSSL_TLS13 - if (IsAtLeastTLSv1_3(ssl->ctx->method->version)) { + if (TLSv1_3_Capable(ssl)) { /* TLS v1.3 capable client not allowed to downgrade when * connecting to TLS v1.3 capable server unless cipher suite * demands it. diff --git a/src/ssl.c b/src/ssl.c index f7fd20680..3979bcaaf 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -720,6 +720,41 @@ int wolfSSL_get_ciphers(char* buf, int len) return WOLFSSL_SUCCESS; } + +#ifndef NO_ERROR_STRINGS +/* places a list of all supported cipher suites in TLS_* format into "buf" + * return WOLFSSL_SUCCESS on success */ +int wolfSSL_get_ciphers_iana(char* buf, int len) +{ + const CipherSuiteInfo* ciphers = GetCipherNames(); + int ciphersSz = GetCipherNamesSize(); + int i; + int cipherNameSz; + + if (buf == NULL || len <= 0) + return BAD_FUNC_ARG; + + /* Add each member to the buffer delimited by a : */ + for (i = 0; i < ciphersSz; i++) { + cipherNameSz = (int)XSTRLEN(ciphers[i].name_iana); + if (cipherNameSz + 1 < len) { + XSTRNCPY(buf, ciphers[i].name_iana, len); + buf += cipherNameSz; + + if (i < ciphersSz - 1) + *buf++ = ':'; + *buf = 0; + + len -= cipherNameSz + 1; + } + else + return BUFFER_E; + } + return WOLFSSL_SUCCESS; +} +#endif /* NO_ERROR_STRINGS */ + + const char* wolfSSL_get_shared_ciphers(WOLFSSL* ssl, char* buf, int len) { const char* cipher; @@ -15318,7 +15353,8 @@ WOLFSSL_X509* wolfSSL_X509_d2i(WOLFSSL_X509** x509, const byte* in, int len) unsigned char* buf, int* bufSz) { WOLFSSL_ENTER("wolfSSL_X509_get_signature"); - if (x509 == NULL || bufSz == NULL || *bufSz < (int)x509->sig.length) + if (x509 == NULL || bufSz == NULL || (*bufSz < (int)x509->sig.length && + buf != NULL)) return WOLFSSL_FATAL_ERROR; if (buf != NULL) @@ -15329,6 +15365,91 @@ WOLFSSL_X509* wolfSSL_X509_d2i(WOLFSSL_X509** x509, const byte* in, int len) } + /* Getter function that copies over the DER public key buffer to "buf" and + * sets the size in bufSz. If "buf" is NULL then just bufSz is set to needed + * buffer size. "bufSz" passed in should initially be set by the user to be + * the size of "buf". This gets checked to make sure the buffer is large + * enough to hold the public key. + * + * Note: this is the X.509 form of key with "header" info. + * return WOLFSSL_SUCCESS on success + */ + int wolfSSL_X509_get_pubkey_buffer(WOLFSSL_X509* x509, + unsigned char* buf, int* bufSz) + { + #ifdef WOLFSSL_SMALL_STACK + DecodedCert* cert; + #else + DecodedCert cert[1]; + #endif + word32 idx; + const byte* der; + int length = 0; + int ret, derSz = 0; + int badDate = 0; + const byte* pubKeyX509 = NULL; + int pubKeyX509Sz = 0; + + WOLFSSL_ENTER("wolfSSL_X509_get_pubkey_buffer"); + if (x509 == NULL || bufSz == NULL) { + WOLFSSL_LEAVE("wolfSSL_X509_get_pubkey_buffer", BAD_FUNC_ARG); + return WOLFSSL_FATAL_ERROR; + } + + + #ifdef WOLFSSL_SMALL_STACK + cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), + x509->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (cert == NULL) { + WOLFSSL_LEAVE("wolfSSL_X509_get_pubkey_buffer", MEMORY_E); + return WOLFSSL_FATAL_ERROR; + } + #endif + + der = wolfSSL_X509_get_der(x509, &derSz); + InitDecodedCert(cert, der, derSz, NULL); + ret = wc_GetPubX509(cert, 0, &badDate); + if (ret >= 0) { + idx = cert->srcIdx; + pubKeyX509 = cert->source + cert->srcIdx; + ret = GetSequence(cert->source, &cert->srcIdx, &length, + cert->maxIdx); + pubKeyX509Sz = length + (cert->srcIdx - idx); + } + + FreeDecodedCert(cert); + #ifdef WOLFSSL_SMALL_STACK + XFREE(cert, x509->heap, DYNAMIC_TYPE_TMP_BUFFER); + #endif + + if (ret < 0) { + WOLFSSL_LEAVE("wolfSSL_X509_get_pubkey_buffer", ret); + return WOLFSSL_FATAL_ERROR; + } + + if (buf != NULL) { + if (pubKeyX509Sz > *bufSz) { + WOLFSSL_LEAVE("wolfSSL_X509_get_pubkey_buffer", BUFFER_E); + return WOLFSSL_FATAL_ERROR; + } + XMEMCPY(buf, pubKeyX509, pubKeyX509Sz); + } + *bufSz = pubKeyX509Sz; + + return WOLFSSL_SUCCESS; + } + + + /* Getter function for the public key OID value + * return public key OID stored in WOLFSSL_X509 structure */ + int wolfSSL_X509_get_pubkey_type(WOLFSSL_X509* x509) + { + if (x509 == NULL) + return WOLFSSL_FAILURE; + return x509->pubKeyOID; + } + + /* write X509 serial number in unsigned binary to buffer buffer needs to be at least EXTERNAL_SERIAL_SIZE (32) for all cases return WOLFSSL_SUCCESS on success */ @@ -15359,6 +15480,40 @@ WOLFSSL_X509* wolfSSL_X509_d2i(WOLFSSL_X509** x509, const byte* in, int len) } + /* get the buffer to be signed (tbs) from the WOLFSSL_X509 certificate + * + * outSz : gets set to the size of the buffer + * returns a pointer to the internal buffer at the location of TBS on + * on success and NULL on failure. + */ + const unsigned char* wolfSSL_X509_get_tbs(WOLFSSL_X509* x509, int* outSz) + { + int sz = 0, len; + unsigned int idx = 0, tmpIdx; + const unsigned char* der = NULL; + const unsigned char* tbs = NULL; + + if (x509 == NULL || outSz == NULL) { + return NULL; + } + + der = wolfSSL_X509_get_der(x509, &sz); + if (der == NULL) { + return NULL; + } + + if (GetSequence(der, &idx, &len, sz) < 0) { + return NULL; + } + tbs = der + idx; + tmpIdx = idx; + if (GetSequence(der, &idx, &len, sz) < 0) { + return NULL; + } + *outSz = len + (idx - tmpIdx); + return tbs; + } + int wolfSSL_X509_version(WOLFSSL_X509* x509) { WOLFSSL_ENTER("wolfSSL_X509_version"); @@ -16643,6 +16798,7 @@ WOLFSSL_EVP_PKEY* wolfSSL_X509_get_pubkey(WOLFSSL_X509* x509) case AUTH_KEY_OID: isSet = x509->authKeyIdSet; break; case SUBJ_KEY_OID: isSet = x509->subjKeyIdSet; break; case KEY_USAGE_OID: isSet = x509->keyUsageSet; break; + case CRL_DIST_OID: isSet = x509->CRLdistSet; break; #ifdef WOLFSSL_SEP case CERT_POLICY_OID: isSet = x509->certPolicySet; break; #endif /* WOLFSSL_SEP */ @@ -16668,6 +16824,7 @@ WOLFSSL_EVP_PKEY* wolfSSL_X509_get_pubkey(WOLFSSL_X509* x509) case AUTH_KEY_OID: crit = x509->authKeyIdCrit; break; case SUBJ_KEY_OID: crit = x509->subjKeyIdCrit; break; case KEY_USAGE_OID: crit = x509->keyUsageCrit; break; + case CRL_DIST_OID: crit= x509->CRLdistCrit; break; #ifdef WOLFSSL_SEP case CERT_POLICY_OID: crit = x509->certPolicyCrit; break; #endif /* WOLFSSL_SEP */ @@ -19113,6 +19270,53 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx) } return WOLFSSL_FATAL_ERROR; } + + +/* Use the public key to verify the signature. Note: this only verifies + * the certificate signature. + * returns WOLFSSL_SUCCESS on successful signature verification */ +int wolfSSL_X509_verify(WOLFSSL_X509* x509, WOLFSSL_EVP_PKEY* pkey) +{ + int ret; + const byte* der; + int derSz = 0; + int type; + + if (x509 == NULL || pkey == NULL) { + return WOLFSSL_FATAL_ERROR; + } + + der = wolfSSL_X509_get_der(x509, &derSz); + if (der == NULL) { + WOLFSSL_MSG("Error getting WOLFSSL_X509 DER"); + return WOLFSSL_FATAL_ERROR; + } + + switch (pkey->type) { + case EVP_PKEY_RSA: + type = RSAk; + break; + + case EVP_PKEY_EC: + type = ECDSAk; + break; + + case EVP_PKEY_DSA: + type = DSAk; + break; + + default: + WOLFSSL_MSG("Unknown pkey key type"); + return WOLFSSL_FATAL_ERROR; + } + + ret = CheckCertSignaturePubKey(der, derSz, x509->heap, + (unsigned char*)pkey->pkey.ptr, pkey->pkey_sz, type); + if (ret == 0) { + return WOLFSSL_SUCCESS; + } + return WOLFSSL_FAILURE; +} #endif /* NO_CERTS */ #if !defined(NO_FILESYSTEM) @@ -31278,8 +31482,8 @@ void* wolfSSL_GetDhAgreeCtx(WOLFSSL* ssl) { KEY_USAGE_OID, KEY_USAGE_OID, oidCertExtType, "X509 key usage" }, { INHIBIT_ANY_OID, INHIBIT_ANY_OID, oidCertExtType, "X509 inhibit any" }, - { NID_ext_key_usage, KEY_USAGE_OID, oidCertExtType, - "X509 ext key usage" }, + { NID_key_usage, KEY_USAGE_OID, oidCertExtType, + "X509 key usage" }, { NID_name_constraints, NAME_CONS_OID, oidCertExtType, "X509 name constraints" }, { NID_certificate_policies, CERT_POLICY_OID, oidCertExtType, @@ -32016,7 +32220,7 @@ void* wolfSSL_GetDhAgreeCtx(WOLFSSL* ssl) case INHIBIT_ANY_OID: return INHIBIT_ANY_OID; case KEY_USAGE_OID: - return NID_ext_key_usage; + return NID_key_usage; case NAME_CONS_OID: return NID_name_constraints; case CERT_POLICY_OID: @@ -32173,15 +32377,47 @@ void* wolfSSL_GetDhAgreeCtx(WOLFSSL* ssl) } #endif -#ifndef NO_WOLFSSL_STUB +#ifdef WOLFSSL_CERT_EXT + /* Gets the NID value that is related to the OID string passed in. Example + * string would be "2.5.29.14" for subject key ID. + * + * @TODO does not handle short names yet + * + * returns NID value on success and NID_undef on error + */ int wolfSSL_OBJ_txt2nid(const char* s) { - (void)s; - WOLFSSL_STUB("OBJ_txt2nid"); + int ret; + unsigned int outSz = MAX_OID_SZ; + unsigned char out[MAX_OID_SZ]; - return 0; + WOLFSSL_ENTER("OBJ_txt2nid"); + + if (s == NULL) { + return NID_undef; + } + + ret = EncodePolicyOID(out, &outSz, s, NULL); + if (ret == 0) { + unsigned int i, sum = 0; + + /* sum OID */ + for (i = 0; i < outSz; i++) { + sum += out[i]; + } + + /* get the group that the OID's sum is in + * @TODO possible conflict with multiples */ + for (i = 0; i < WOLFSSL_OBJECT_INFO_SZ; i++) { + if (wolfssl_object_info[i].id == (int)sum) { + return wolfssl_object_info[i].nid; + } + } + } + return NID_undef; } -#endif +#endif /* WOLFSSL_CERT_EXT */ + /* compatibility function. It's intended use is to remove OID's from an * internal table that have been added with OBJ_create. wolfSSL manages it's @@ -33878,8 +34114,8 @@ WOLFSSL_CTX* wolfSSL_get_SSL_CTX(WOLFSSL* ssl) } #if defined(OPENSSL_ALL) || \ - (defined(OPENSSL_EXTRA) && (defined(HAVE_STUNNEL) || \ - defined(WOLFSSL_NGINX)) || defined(WOLFSSL_HAPROXY)) + defined(OPENSSL_EXTRA) || defined(HAVE_STUNNEL) || \ + defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) const byte* wolfSSL_SESSION_get_id(WOLFSSL_SESSION* sess, unsigned int* idLen) { @@ -34450,6 +34686,17 @@ long wolfSSL_SSL_CTX_get_timeout(const WOLFSSL_CTX *ctx) return ctx->timeout; } + +/* returns the time in seconds of the current timeout */ +long wolfSSL_get_timeout(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_get_timeout"); + + if (ssl == NULL) + return 0; + return ssl->timeout; +} + #ifdef HAVE_ECC int wolfSSL_SSL_CTX_set_tmp_ecdh(WOLFSSL_CTX *ctx, WOLFSSL_EC_KEY *ecdh) { diff --git a/src/tls.c b/src/tls.c index 6a8ed3fcb..1fc090b8d 100644 --- a/src/tls.c +++ b/src/tls.c @@ -10755,6 +10755,31 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte msgType, } #endif /* !WOLFSSL_NO_TLS12 */ + #ifdef WOLFSSL_TLS13 + /* Gets a WOLFSL_METHOD type that is not set as client or server + * + * Returns a pointer to a WOLFSSL_METHOD struct + */ + WOLFSSL_METHOD* wolfTLSv1_3_method(void) + { + return wolfTLSv1_3_method_ex(NULL); + } + WOLFSSL_METHOD* wolfTLSv1_3_method_ex(void* heap) + { + WOLFSSL_METHOD* m; + WOLFSSL_ENTER("TLSv1_3_method"); + #ifndef NO_WOLFSSL_CLIENT + m = wolfTLSv1_3_client_method_ex(heap); + #else + m = wolfTLSv1_3_server_method_ex(heap); + #endif + if (m != NULL) { + m->side = WOLFSSL_NEITHER_END; + } + return m; + } + #endif /* WOLFSSL_TLS13 */ + #ifdef WOLFSSL_DTLS WOLFSSL_METHOD* wolfDTLS_method(void) { diff --git a/src/wolfio.c b/src/wolfio.c index d2d3f00f4..3462e2b3e 100644 --- a/src/wolfio.c +++ b/src/wolfio.c @@ -1486,6 +1486,30 @@ WOLFSSL_API void wolfSSL_CTX_SetIOSend(WOLFSSL_CTX *ctx, CallbackIOSend CBIOSend } +/* sets the IO callback to use for receives at WOLFSSL level */ +WOLFSSL_API void wolfSSL_SSLSetIORecv(WOLFSSL *ssl, CallbackIORecv CBIORecv) +{ + if (ssl != NULL) { + ssl->CBIORecv = CBIORecv; + #ifdef OPENSSL_EXTRA + ssl->cbioFlag |= WOLFSSL_CBIO_RECV; + #endif + } +} + + +/* sets the IO callback to use for sends at WOLFSSL level */ +WOLFSSL_API void wolfSSL_SSLSetIOSend(WOLFSSL *ssl, CallbackIOSend CBIOSend) +{ + if (ssl != NULL) { + ssl->CBIOSend = CBIOSend; + #ifdef OPENSSL_EXTRA + ssl->cbioFlag |= WOLFSSL_CBIO_SEND; + #endif + } +} + + WOLFSSL_API void wolfSSL_SetIOReadCtx(WOLFSSL* ssl, void *rctx) { ssl->IOCB_ReadCtx = rctx; diff --git a/tests/api.c b/tests/api.c index 87efb38b1..aeb060aa1 100644 --- a/tests/api.c +++ b/tests/api.c @@ -578,6 +578,9 @@ static void test_wolfSSL_Method_Allocators(void) #ifndef WOLFSSL_NO_TLS12 TEST_VALID_METHOD_ALLOCATOR(wolfTLSv1_2_method); #endif /* !WOLFSSL_NO_TLS12 */ + #ifdef WOLFSSL_TLS13 + TEST_VALID_METHOD_ALLOCATOR(wolfTLSv1_3_method); + #endif /* WOLFSSL_TLS13 */ #ifdef WOLFSSL_DTLS TEST_VALID_METHOD_ALLOCATOR(wolfDTLS_method); #ifndef NO_OLD_TLS @@ -4353,6 +4356,87 @@ static void test_wolfSSL_URI(void) #endif } + +static void test_wolfSSL_TBS(void) +{ +#if !defined(NO_CERTS) && !defined(NO_RSA) && !defined(NO_FILESYSTEM) \ + && defined(OPENSSL_EXTRA) + WOLFSSL_X509* x509; + const unsigned char* tbs; + int tbsSz; + + printf(testingFmt, "wolfSSL TBS"); + + AssertNotNull(x509 = + wolfSSL_X509_load_certificate_file(caCertFile, WOLFSSL_FILETYPE_PEM)); + + AssertNull(tbs = wolfSSL_X509_get_tbs(NULL, &tbsSz)); + AssertNull(tbs = wolfSSL_X509_get_tbs(x509, NULL)); + AssertNotNull(tbs = wolfSSL_X509_get_tbs(x509, &tbsSz)); + AssertIntEQ(tbsSz, 918); + + wolfSSL_FreeX509(x509); + + printf(resultFmt, passed); +#endif +} + +static void test_wolfSSL_X509_verify(void) +{ +#if !defined(NO_CERTS) && !defined(NO_RSA) && !defined(NO_FILESYSTEM) \ + && defined(OPENSSL_EXTRA) + WOLFSSL_X509* ca; + WOLFSSL_X509* server; + WOLFSSL_EVP_PKEY* pkey; + unsigned char buf[2048]; + unsigned char* pt; + int bufSz; + + printf(testingFmt, "wolfSSL X509 verify"); + + AssertNotNull(ca = + wolfSSL_X509_load_certificate_file(caCertFile, WOLFSSL_FILETYPE_PEM)); + + AssertIntNE(wolfSSL_X509_get_pubkey_buffer(NULL, buf, &bufSz), + WOLFSSL_SUCCESS); + AssertIntEQ(wolfSSL_X509_get_pubkey_buffer(ca, NULL, &bufSz), + WOLFSSL_SUCCESS); + AssertIntEQ(bufSz, 294); + + bufSz = 2048; + AssertIntEQ(wolfSSL_X509_get_pubkey_buffer(ca, buf, &bufSz), + WOLFSSL_SUCCESS); + AssertIntEQ(wolfSSL_X509_get_pubkey_type(NULL), WOLFSSL_FAILURE); + AssertIntEQ(wolfSSL_X509_get_pubkey_type(ca), RSAk); + + + AssertNotNull(server = + wolfSSL_X509_load_certificate_file(svrCertFile, WOLFSSL_FILETYPE_PEM)); + + /* success case */ + pt = buf; + AssertNotNull(pkey = wolfSSL_d2i_PUBKEY(NULL, &pt, bufSz)); + AssertIntEQ(wolfSSL_X509_verify(server, pkey), WOLFSSL_SUCCESS); + wolfSSL_EVP_PKEY_free(pkey); + + /* fail case */ + bufSz = 2048; + AssertIntEQ(wolfSSL_X509_get_pubkey_buffer(server, buf, &bufSz), + WOLFSSL_SUCCESS); + pt = buf; + AssertNotNull(pkey = wolfSSL_d2i_PUBKEY(NULL, &pt, bufSz)); + AssertIntEQ(wolfSSL_X509_verify(server, pkey), WOLFSSL_FAILURE); + + AssertIntEQ(wolfSSL_X509_verify(NULL, pkey), WOLFSSL_FATAL_ERROR); + AssertIntEQ(wolfSSL_X509_verify(server, NULL), WOLFSSL_FATAL_ERROR); + wolfSSL_EVP_PKEY_free(pkey); + + wolfSSL_FreeX509(ca); + wolfSSL_FreeX509(server); + + printf(resultFmt, passed); +#endif +} /* Testing function wolfSSL_CTX_SetMinVersion; sets the minimum downgrade * version allowed. * POST: 1 on success. @@ -20676,6 +20760,9 @@ static void test_wolfSSL_OBJ(void) AssertNotNull(obj = OBJ_nid2obj(NID_sha256)); AssertIntEQ(OBJ_obj2nid(obj), NID_sha256); AssertIntEQ(OBJ_obj2txt(buf, (int)sizeof(buf), obj, 1), 22); +#ifdef WOLFSSL_CERT_EXT + AssertIntEQ(OBJ_txt2nid(buf), NID_sha256); +#endif AssertIntGT(OBJ_obj2txt(buf, (int)sizeof(buf), obj, 0), 0); ASN1_OBJECT_free(obj); @@ -24365,6 +24452,8 @@ void ApiTest(void) test_wolfSSL_PKCS8(); test_wolfSSL_PKCS5(); test_wolfSSL_URI(); + test_wolfSSL_TBS(); + test_wolfSSL_X509_verify(); test_wc_PemToDer(); test_wc_AllocDer(); diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 497074374..c008da043 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -5640,12 +5640,20 @@ int wc_GetCertDates(Cert* cert, struct tm* before, struct tm* after) #endif /* WOLFSSL_CERT_GEN && WOLFSSL_ALT_NAMES */ #endif /* !NO_ASN_TIME */ - -int DecodeToKey(DecodedCert* cert, int verify) +/* parses certificate up to point of X.509 public key + * + * if cert date is invalid then badDate gets set to error value, otherwise is 0 + * + * returns a negative value on fail case + */ +int wc_GetPubX509(DecodedCert* cert, int verify, int* badDate) { - int badDate = 0; int ret; + if (cert == NULL || badDate == NULL) + return BAD_FUNC_ARG; + + *badDate = 0; if ( (ret = GetCertHeader(cert)) < 0) return ret; @@ -5661,12 +5669,23 @@ int DecodeToKey(DecodedCert* cert, int verify) return ret; if ( (ret = GetValidity(cert, verify)) < 0) - badDate = ret; + *badDate = ret; if ( (ret = GetName(cert, SUBJECT)) < 0) return ret; WOLFSSL_MSG("Got Subject Name"); + return ret; +} + + +int DecodeToKey(DecodedCert* cert, int verify) +{ + int badDate = 0; + int ret; + + if ( (ret = wc_GetPubX509(cert, verify, &badDate)) < 0) + return ret; /* Determine if self signed */ cert->selfSigned = XMEMCMP(cert->issuerHash, @@ -7749,7 +7768,7 @@ static Signer* GetCABySubjectAndPubKey(DecodedCert* cert, void* cm) } #endif -#ifdef WOLFSSL_SMALL_CERT_VERIFY +#if defined(WOLFSSL_SMALL_CERT_VERIFY) || defined(OPENSSL_EXTRA) /* Only quick step through the certificate to find fields that are then used * in certificate signature verification. * Must use the signature OID from the signed part of the certificate. @@ -7759,7 +7778,8 @@ static Signer* GetCABySubjectAndPubKey(DecodedCert* cert, void* cm) * Doesn't support: * OCSP Only: alt lookup using subject and pub key w/o sig check */ -int CheckCertSignature(const byte* cert, word32 certSz, void* heap, void* cm) +static int CheckCertSignature_ex(const byte* cert, word32 certSz, void* heap, + void* cm, const byte* pubKey, word32 pubKeySz, int pubKeyOID) { #ifndef WOLFSSL_SMALL_STACK SignatureCtx sigCtx[1]; @@ -7770,12 +7790,12 @@ int CheckCertSignature(const byte* cert, word32 certSz, void* heap, void* cm) Signer* ca = NULL; word32 idx = 0; int len; - word32 tbsCertIdx; - word32 sigIndex; + word32 tbsCertIdx = 0; + word32 sigIndex = 0; word32 signatureOID; word32 oid; - word32 issuerIdx; - word32 issuerSz; + word32 issuerIdx = 0; + word32 issuerSz = 0; #ifndef NO_SKID int extLen; word32 extIdx; @@ -7963,7 +7983,7 @@ int CheckCertSignature(const byte* cert, word32 certSz, void* heap, void* cm) } } - if (ret == 0) { + if (ret == 0 && pubKey == NULL) { if (extAuthKeyIdSet) ca = GetCA(cm, hash); if (ca == NULL) { @@ -7973,13 +7993,13 @@ int CheckCertSignature(const byte* cert, word32 certSz, void* heap, void* cm) } } #else - if (ret == 0) { + if (ret == 0 && pubKey == NULL) { ret = CalcHashId(cert + issuerIdx, issuerSz, hash); if (ret == 0) ca = GetCA(cm, hash); } #endif /* !NO_SKID */ - if (ca == NULL) + if (ca == NULL && pubKey == NULL) ret = ASN_NO_SIGNER_E; if (ret == 0) { @@ -7999,9 +8019,18 @@ int CheckCertSignature(const byte* cert, word32 certSz, void* heap, void* cm) } if (ret == 0) { - ret = ConfirmSignature(sigCtx, cert + tbsCertIdx, sigIndex - tbsCertIdx, + if (pubKey != NULL) { + ret = ConfirmSignature(sigCtx, cert + tbsCertIdx, + sigIndex - tbsCertIdx, + pubKey, pubKeySz, pubKeyOID, + cert + idx, len, signatureOID); + } + else { + ret = ConfirmSignature(sigCtx, cert + tbsCertIdx, + sigIndex - tbsCertIdx, ca->publicKey, ca->pubKeySize, ca->keyOID, cert + idx, len, signatureOID); + } if (ret != 0) { WOLFSSL_MSG("Confirm signature failed"); } @@ -8014,7 +8043,26 @@ int CheckCertSignature(const byte* cert, word32 certSz, void* heap, void* cm) #endif return ret; } + +#ifdef OPENSSL_EXTRA +/* Call CheckCertSignature_ex using a public key buffer for verification + */ +int CheckCertSignaturePubKey(const byte* cert, word32 certSz, void* heap, + const byte* pubKey, word32 pubKeySz, int pubKeyOID) +{ + return CheckCertSignature_ex(cert, certSz, heap, NULL, + pubKey, pubKeySz, pubKeyOID); +} +#endif /* OPENSSL_EXTRA */ +#ifdef WOLFSSL_SMALL_CERT_VERIFY +/* Call CheckCertSignature_ex using a certificate manager (cm) + */ +int CheckCertSignature(const byte* cert, word32 certSz, void* heap, void* cm) +{ + return CheckCertSignature_ex(cert, certSz, heap, cm, NULL, 0, 0); +} #endif /* WOLFSSL_SMALL_CERT_VERIFY */ +#endif /* WOLFSSL_SMALL_CERT_VERIFY || OPENSSL_EXTRA */ int ParseCertRelative(DecodedCert* cert, int type, int verify, void* cm) { @@ -10818,7 +10866,7 @@ static int SetExtKeyUsage(Cert* cert, byte* output, word32 outSz, byte input) } /* Encode OID string representation to ITU-T X.690 format */ -static int EncodePolicyOID(byte *out, word32 *outSz, const char *in, void* heap) +int EncodePolicyOID(byte *out, word32 *outSz, const char *in, void* heap) { word32 val, idx = 0, nb_val; char *token, *str, *ptr; diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 45e6a19e7..d768b041b 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -468,6 +468,7 @@ WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_2_method(void); WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_2_server_method(void); WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_2_client_method(void); #ifdef WOLFSSL_TLS13 + WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_3_method(void); WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_3_server_method(void); WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_3_client_method(void); #endif @@ -579,6 +580,7 @@ WOLFSSL_API int wolfSSL_set_read_fd (WOLFSSL*, int); WOLFSSL_API char* wolfSSL_get_cipher_list(int priority); WOLFSSL_API char* wolfSSL_get_cipher_list_ex(WOLFSSL* ssl, int priority); WOLFSSL_API int wolfSSL_get_ciphers(char*, int); +WOLFSSL_API int wolfSSL_get_ciphers_iana(char*, int); WOLFSSL_API const char* wolfSSL_get_cipher_name(WOLFSSL* ssl); WOLFSSL_API const char* wolfSSL_get_cipher_name_from_suite(const unsigned char, const unsigned char); @@ -930,6 +932,7 @@ WOLFSSL_API unsigned char* wolfSSL_X509_get_authorityKeyID( WOLFSSL_API unsigned char* wolfSSL_X509_get_subjectKeyID( WOLFSSL_X509*, unsigned char*, int*); +WOLFSSL_API int wolfSSL_X509_verify(WOLFSSL_X509* x509, WOLFSSL_EVP_PKEY* pkey); WOLFSSL_API int wolfSSL_X509_set_subject_name(WOLFSSL_X509*, WOLFSSL_X509_NAME*); WOLFSSL_API int wolfSSL_X509_set_pubkey(WOLFSSL_X509*, WOLFSSL_EVP_PKEY*); @@ -952,6 +955,9 @@ WOLFSSL_API int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX*); WOLFSSL_API const char* wolfSSL_X509_verify_cert_error_string(long); WOLFSSL_API int wolfSSL_X509_get_signature_type(WOLFSSL_X509*); WOLFSSL_API int wolfSSL_X509_get_signature(WOLFSSL_X509*, unsigned char*, int*); +WOLFSSL_API int wolfSSL_X509_get_pubkey_buffer(WOLFSSL_X509*, unsigned char*, + int*); +WOLFSSL_API int wolfSSL_X509_get_pubkey_type(WOLFSSL_X509* x509); WOLFSSL_API int wolfSSL_X509_LOOKUP_add_dir(WOLFSSL_X509_LOOKUP*,const char*,long); WOLFSSL_API int wolfSSL_X509_LOOKUP_load_file(WOLFSSL_X509_LOOKUP*, const char*, @@ -1586,6 +1592,7 @@ WOLFSSL_API const unsigned char* wolfSSL_get_sessionID(const WOLFSSL_SESSION* s) WOLFSSL_API int wolfSSL_X509_get_serial_number(WOLFSSL_X509*,unsigned char*,int*); WOLFSSL_API char* wolfSSL_X509_get_subjectCN(WOLFSSL_X509*); WOLFSSL_API const unsigned char* wolfSSL_X509_get_der(WOLFSSL_X509*, int*); +WOLFSSL_API const unsigned char* wolfSSL_X509_get_tbs(WOLFSSL_X509*, int*); WOLFSSL_API const unsigned char* wolfSSL_X509_notBefore(WOLFSSL_X509*); WOLFSSL_API const unsigned char* wolfSSL_X509_notAfter(WOLFSSL_X509*); WOLFSSL_API int wolfSSL_X509_version(WOLFSSL_X509*); @@ -2966,6 +2973,7 @@ WOLFSSL_API int wolfSSL_X509_NAME_digest(const WOLFSSL_X509_NAME *data, const WOLFSSL_EVP_MD *type, unsigned char *md, unsigned int *len); WOLFSSL_API long wolfSSL_SSL_CTX_get_timeout(const WOLFSSL_CTX *ctx); +WOLFSSL_API long wolfSSL_get_timeout(WOLFSSL* ssl); WOLFSSL_API int wolfSSL_SSL_CTX_set_tmp_ecdh(WOLFSSL_CTX *ctx, WOLFSSL_EC_KEY *ecdh); WOLFSSL_API int wolfSSL_SSL_CTX_remove_session(WOLFSSL_CTX *, diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index 33ebd9a4a..38d48717b 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -939,9 +939,14 @@ WOLFSSL_ASN_API int ParseCert(DecodedCert*, int type, int verify, void* cm); WOLFSSL_LOCAL int DecodePolicyOID(char *o, word32 oSz, const byte *in, word32 inSz); +WOLFSSL_LOCAL int EncodePolicyOID(byte *out, word32 *outSz, + const char *in, void* heap); WOLFSSL_API int CheckCertSignature(const byte*,word32,void*,void* cm); +WOLFSSL_LOCAL int CheckCertSignaturePubKey(const byte* cert, word32 certSz, + void* heap, const byte* pubKey, word32 pubKeySz, int pubKeyOID); WOLFSSL_LOCAL int ParseCertRelative(DecodedCert*,int type,int verify,void* cm); WOLFSSL_LOCAL int DecodeToKey(DecodedCert*, int verify); +WOLFSSL_LOCAL int wc_GetPubX509(DecodedCert* cert, int verify, int* badDate); WOLFSSL_LOCAL const byte* OidFromId(word32 id, word32 type, word32* oidSz); WOLFSSL_LOCAL Signer* MakeSigner(void*); diff --git a/wolfssl/wolfio.h b/wolfssl/wolfio.h index 77ec47243..27290d0dc 100644 --- a/wolfssl/wolfio.h +++ b/wolfssl/wolfio.h @@ -418,6 +418,8 @@ typedef int (*CallbackIORecv)(WOLFSSL *ssl, char *buf, int sz, void *ctx); typedef int (*CallbackIOSend)(WOLFSSL *ssl, char *buf, int sz, void *ctx); WOLFSSL_API void wolfSSL_CTX_SetIORecv(WOLFSSL_CTX*, CallbackIORecv); WOLFSSL_API void wolfSSL_CTX_SetIOSend(WOLFSSL_CTX*, CallbackIOSend); +WOLFSSL_API void wolfSSL_SSLSetIORecv(WOLFSSL*, CallbackIORecv); +WOLFSSL_API void wolfSSL_SSLSetIOSend(WOLFSSL*, CallbackIOSend); /* deprecated old name */ #define wolfSSL_SetIORecv wolfSSL_CTX_SetIORecv #define wolfSSL_SetIOSend wolfSSL_CTX_SetIOSend