From f2584fd5fa7be580d24f3b41b5da3d88fecb121f Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Wed, 4 Jun 2025 23:39:37 +0200 Subject: [PATCH] ALT_NAMES_OID: Mark IP address as WOLFSSL_V_ASN1_OCTET_STRING --- CMakeLists.txt | 1 + src/x509.c | 9 +++ tests/api.c | 3 + tests/api/include.am | 3 + tests/api/test_x509.c | 149 ++++++++++++++++++++++++++++++++++++++++++ tests/api/test_x509.h | 30 +++++++++ 6 files changed, 195 insertions(+) create mode 100644 tests/api/test_x509.c create mode 100644 tests/api/test_x509.h diff --git a/CMakeLists.txt b/CMakeLists.txt index fcf2bd188..688d9dc4e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2634,6 +2634,7 @@ if(WOLFSSL_EXAMPLES) tests/api/test_evp.c tests/api/test_tls_ext.c tests/api/test_tls.c + tests/api/test_x509.c tests/srp.c tests/suites.c tests/w64wrapper.c diff --git a/src/x509.c b/src/x509.c index eda280e73..2dbc7587c 100644 --- a/src/x509.c +++ b/src/x509.c @@ -2349,6 +2349,15 @@ void* wolfSSL_X509_get_ext_d2i(const WOLFSSL_X509* x509, int nid, int* c, } break; + case ASN_IP_TYPE: + if (wolfSSL_ASN1_STRING_set(gn->d.iPAddress, + dns->name, dns->len) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("ASN1_STRING_set failed"); + goto err; + } + gn->d.iPAddress->type = WOLFSSL_V_ASN1_OCTET_STRING; + break; + default: if (wolfSSL_ASN1_STRING_set(gn->d.dNSName, dns->name, dns->len) != WOLFSSL_SUCCESS) { diff --git a/tests/api.c b/tests/api.c index 63e3f0216..711e12ff1 100644 --- a/tests/api.c +++ b/tests/api.c @@ -325,6 +325,7 @@ #include #include #include +#include #if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && !defined(NO_TLS) && \ !defined(NO_RSA) && !defined(SINGLE_THREADED) && \ @@ -67130,6 +67131,8 @@ TEST_CASE testCases[] = { TEST_MLDSA_DECLS, /* Signature API */ TEST_SIGNATURE_DECLS, + /* x509 */ + TEST_X509_DECLS, /* PEM and DER APIs. */ TEST_DECL(test_wc_PemToDer), diff --git a/tests/api/include.am b/tests/api/include.am index afdc892c7..14a7a5468 100644 --- a/tests/api/include.am +++ b/tests/api/include.am @@ -54,6 +54,8 @@ tests_unit_test_SOURCES += tests/api/test_ocsp.c tests_unit_test_SOURCES += tests/api/test_evp.c tests_unit_test_SOURCES += tests/api/test_tls_ext.c tests_unit_test_SOURCES += tests/api/test_tls.c +# Certs +tests_unit_test_SOURCES += tests/api/test_x509.c endif EXTRA_DIST += tests/api/api.h @@ -105,4 +107,5 @@ EXTRA_DIST += tests/api/create_ocsp_test_blobs.py EXTRA_DIST += tests/api/test_evp.h EXTRA_DIST += tests/api/test_tls_ext.h EXTRA_DIST += tests/api/test_tls.h +EXTRA_DIST += tests/api/test_x509.h diff --git a/tests/api/test_x509.c b/tests/api/test_x509.c new file mode 100644 index 000000000..58073c47e --- /dev/null +++ b/tests/api/test_x509.c @@ -0,0 +1,149 @@ +/* test_x509.c + * + * Copyright (C) 2006-2025 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +#include + +#ifdef NO_INLINE + #include +#else + #define WOLFSSL_MISC_INCLUDED + #include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#if defined(OPENSSL_ALL) +#define HAVE_TEST_X509_RFC2818_VERIFICATION_CALLBACK +/* callback taken and simplified from + * include/boost/asio/ssl/impl/rfc2818_verification.ipp + * version: boost-1.84.0 */ +static int rfc2818_verification_callback(int preverify, + WOLFSSL_X509_STORE_CTX* store) +{ + EXPECT_DECLS; + int depth; + X509* cert; + GENERAL_NAMES* gens; + byte address_bytes[] = { 127, 0, 0, 1 }; + X509_NAME* name; + int i; + ASN1_STRING* common_name = 0; + int matches = 0; + + /* Don't bother looking at certificates that have + * failed pre-verification. */ + if (!preverify) + return 0; + + /* We're only interested in checking the certificate at + * the end of the chain. */ + depth = X509_STORE_CTX_get_error_depth(store); + if (depth > 0) + return 1; + + /* Try converting the host name to an address. If it is an address then we + * need to look for an IP address in the certificate rather than a + * host name. */ + + cert = X509_STORE_CTX_get_current_cert(store); + + /* Go through the alternate names in the certificate looking for matching + * DNS or IP address entries. */ + gens = (GENERAL_NAMES*)X509_get_ext_d2i( + cert, NID_subject_alt_name, NULL, NULL); + for (i = 0; i < sk_GENERAL_NAME_num(gens); ++i) { + GENERAL_NAME* gen = sk_GENERAL_NAME_value(gens, i); + if (gen->type == GEN_DNS) { + ASN1_IA5STRING* domain = gen->d.dNSName; + if (domain->type == V_ASN1_IA5STRING && domain->data && + domain->length && + XSTRCMP(domain->data, "example.com") == 0) + matches++; + } + else if (gen->type == GEN_IPADD) + { + ASN1_OCTET_STRING* ip_address = gen->d.iPAddress; + if (ip_address->type == V_ASN1_OCTET_STRING && ip_address->data && + ip_address->length == sizeof(address_bytes) && + XMEMCMP(address_bytes, ip_address->data, 4) == 0) + matches++; + } + } + GENERAL_NAMES_free(gens); + + /* No match in the alternate names, so try the common names. We should only + * use the "most specific" common name, which is the last one in + * the list. */ + name = X509_get_subject_name(cert); + i = -1; + while ((i = X509_NAME_get_index_by_NID(name, NID_commonName, i)) >= 0) + { + X509_NAME_ENTRY* name_entry = X509_NAME_get_entry(name, i); + common_name = X509_NAME_ENTRY_get_data(name_entry); + } + if (common_name && common_name->data && common_name->length) + { + if (XSTRCMP(common_name->data, "www.wolfssl.com") == 0) + matches++; + } + + ExpectIntEQ(matches, 3); + return matches == 3; +} +#endif + +int test_x509_rfc2818_verification_callback(void) +{ + EXPECT_DECLS; +#ifdef HAVE_TEST_X509_RFC2818_VERIFICATION_CALLBACK + struct test_memio_ctx test_ctx; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLS_client_method, wolfTLS_server_method), 0); + + ExpectIntEQ(wolfSSL_use_certificate_file(ssl_c, cliCertFile, + WOLFSSL_FILETYPE_PEM), 1); + ExpectIntEQ(wolfSSL_use_PrivateKey_file(ssl_c, cliKeyFile, + WOLFSSL_FILETYPE_PEM), 1); + + ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx_s, cliCertFile, NULL), 1); + wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_PEER, + rfc2818_verification_callback); + + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + wolfSSL_free(ssl_s); + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_s); + wolfSSL_CTX_free(ctx_c); +#endif + return EXPECT_RESULT(); +} diff --git a/tests/api/test_x509.h b/tests/api/test_x509.h new file mode 100644 index 000000000..1728fd1db --- /dev/null +++ b/tests/api/test_x509.h @@ -0,0 +1,30 @@ +/* test_x509.h + * + * Copyright (C) 2006-2025 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +#ifndef WOLFCRYPT_TEST_X509_H +#define WOLFCRYPT_TEST_X509_H + +int test_x509_rfc2818_verification_callback(void); + +#define TEST_X509_DECLS \ + TEST_DECL_GROUP("x509", test_x509_rfc2818_verification_callback) + +#endif /* WOLFCRYPT_TEST_X509_H */