Skip to content

Commit d49df86

Browse files
authored
Merge pull request #9935 from padelsbach/padelsbach/san-ip-addr-test
Add IP SAN matching
2 parents 82b6b9c + 041bb18 commit d49df86

7 files changed

Lines changed: 206 additions & 1 deletion

File tree

doc/dox_comments/header_files-ja/ssl.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5435,6 +5435,22 @@ int wolfSSL_want_read(WOLFSSL* ssl);
54355435
*/
54365436
int wolfSSL_check_domain_name(WOLFSSL* ssl, const char* dn);
54375437

5438+
/*!
5439+
\ingroup Setup
5440+
5441+
\brief wolfSSL_connect() または wolfSSL_accept() の前にこの関数を呼ぶと、
5442+
ピア証明書の SAN iPAddress エントリに対する IP アドレス検証を追加します。
5443+
5444+
\return SSL_SUCCESS 成功。
5445+
\return SSL_FAILURE パラメータ不正またはメモリ確保失敗。
5446+
5447+
\param ssl wolfSSL_new() で作成された WOLFSSL 構造体へのポインタ。
5448+
\param ipaddr 検証する NULL 終端 ASCII IP アドレス文字列。
5449+
5450+
\sa wolfSSL_check_domain_name
5451+
*/
5452+
int wolfSSL_check_ip_address(WOLFSSL* ssl, const char* ipaddr);
5453+
54385454
/*!
54395455
\ingroup TLS
54405456

doc/dox_comments/header_files/ssl.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6432,6 +6432,37 @@ int wolfSSL_want_write(WOLFSSL* ssl);
64326432
*/
64336433
int wolfSSL_check_domain_name(WOLFSSL* ssl, const char* dn);
64346434

6435+
/*!
6436+
\ingroup Setup
6437+
6438+
\brief Calling this function before wolfSSL_connect() or wolfSSL_accept()
6439+
adds an IP-address identity check against the peer certificate SAN
6440+
iPAddress entries.
6441+
6442+
\return SSL_SUCCESS upon success.
6443+
\return SSL_FAILURE if parameters are invalid or memory allocation fails.
6444+
6445+
\param ssl a pointer to a WOLFSSL structure, created using wolfSSL_new().
6446+
\param ipaddr NULL-terminated ASCII IP address string to verify against the
6447+
peer certificate.
6448+
6449+
_Example_
6450+
\code
6451+
int ret = 0;
6452+
WOLFSSL* ssl;
6453+
const char* ip = "127.0.0.1";
6454+
...
6455+
6456+
ret = wolfSSL_check_ip_address(ssl, ip);
6457+
if (ret != SSL_SUCCESS) {
6458+
// failed to enable IP check
6459+
}
6460+
\endcode
6461+
6462+
\sa wolfSSL_check_domain_name
6463+
*/
6464+
int wolfSSL_check_ip_address(WOLFSSL* ssl, const char* ipaddr);
6465+
64356466
/*!
64366467
\ingroup TLS
64376468

src/internal.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8720,6 +8720,7 @@ void wolfSSL_ResourceFree(WOLFSSL* ssl)
87208720
FreeHandshakeHashes(ssl);
87218721
#endif
87228722
XFREE(ssl->buffers.domainName.buffer, ssl->heap, DYNAMIC_TYPE_DOMAIN);
8723+
XFREE(ssl->buffers.ipasc.buffer, ssl->heap, DYNAMIC_TYPE_DOMAIN);
87238724

87248725
/* clear keys struct after session */
87258726
ForceZero(&ssl->keys, sizeof(Keys));
@@ -16889,7 +16890,7 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
1688916890
(char*)ssl->buffers.domainName.buffer,
1689016891
(ssl->buffers.domainName.buffer == NULL ? 0 :
1689116892
(word32)XSTRLEN(ssl->buffers.domainName.buffer)),
16892-
NULL, 0) != 1) {
16893+
NULL, 0, 0) != 1) {
1689316894
WOLFSSL_MSG("DomainName match failed");
1689416895
/* try to get peer key still */
1689516896
ret = DOMAIN_NAME_MISMATCH;
@@ -16899,6 +16900,17 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
1689916900
#endif /* WOLFSSL_ALL_NO_CN_IN_SAN */
1690016901
}
1690116902

16903+
#ifndef OPENSSL_EXTRA
16904+
if (!ssl->options.verifyNone && ssl->buffers.ipasc.buffer) {
16905+
if (CheckIPAddr(args->dCert,
16906+
(const char*)ssl->buffers.ipasc.buffer) != 0) {
16907+
WOLFSSL_MSG("IPAddr match on alt names failed");
16908+
ret = IPADDR_MISMATCH;
16909+
WOLFSSL_ERROR_VERBOSE(ret);
16910+
}
16911+
}
16912+
#endif
16913+
1690216914
/* decode peer key */
1690316915
switch (args->dCert->keyOID) {
1690416916
#ifndef NO_RSA

src/ssl.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7563,6 +7563,48 @@ int wolfSSL_check_domain_name(WOLFSSL* ssl, const char* dn)
75637563
}
75647564
}
75657565

7566+
/* call before SSL_connect, if verifying will add IP SAN check to
7567+
date check and signature check */
7568+
WOLFSSL_ABI
7569+
int wolfSSL_check_ip_address(WOLFSSL* ssl, const char* ipaddr)
7570+
{
7571+
WOLFSSL_ENTER("wolfSSL_check_ip_address");
7572+
7573+
if (ssl == NULL || ipaddr == NULL) {
7574+
WOLFSSL_MSG("Bad function argument: NULL");
7575+
return WOLFSSL_FAILURE;
7576+
}
7577+
7578+
if (ssl->buffers.ipasc.buffer != NULL) {
7579+
XFREE(ssl->buffers.ipasc.buffer, ssl->heap, DYNAMIC_TYPE_DOMAIN);
7580+
ssl->buffers.ipasc.buffer = NULL;
7581+
ssl->buffers.ipasc.length = 0;
7582+
}
7583+
7584+
ssl->buffers.ipasc.length = (word32)XSTRLEN(ipaddr);
7585+
ssl->buffers.ipasc.buffer = (byte*)XMALLOC(ssl->buffers.ipasc.length + 1,
7586+
ssl->heap, DYNAMIC_TYPE_DOMAIN);
7587+
if (ssl->buffers.ipasc.buffer == NULL) {
7588+
ssl->error = MEMORY_ERROR;
7589+
return WOLFSSL_FAILURE;
7590+
}
7591+
7592+
XMEMCPY(ssl->buffers.ipasc.buffer, ipaddr, ssl->buffers.ipasc.length);
7593+
ssl->buffers.ipasc.buffer[ssl->buffers.ipasc.length] = '\0';
7594+
7595+
#ifdef OPENSSL_EXTRA
7596+
if (ssl->param == NULL) {
7597+
return WOLFSSL_FAILURE;
7598+
}
7599+
if (wolfSSL_X509_VERIFY_PARAM_set1_ip_asc(ssl->param, ipaddr) !=
7600+
WOLFSSL_SUCCESS) {
7601+
return WOLFSSL_FAILURE;
7602+
}
7603+
#endif
7604+
7605+
return WOLFSSL_SUCCESS;
7606+
}
7607+
75667608
#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA)
75677609
const char *wolfSSL_get0_peername(WOLFSSL *ssl) {
75687610
if (ssl == NULL) {

tests/api.c

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16004,6 +16004,8 @@ static int test_wolfSSL_check_domain_basic_client_ssl(WOLFSSL* ssl)
1600416004

1600516005
return EXPECT_RESULT();
1600616006
}
16007+
/* Verify wolfSSL_check_domain_name() controls DNS-name matching during
16008+
* handshake with expected fail/pass outcomes. */
1600716009
static int test_wolfSSL_check_domain_basic(void)
1600816010
{
1600916011
EXPECT_DECLS;
@@ -16036,6 +16038,102 @@ static int test_wolfSSL_check_domain_basic(void)
1603616038
}
1603716039
#endif /* HAVE_SSL_MEMIO_TESTS_DEPENDENCIES */
1603816040

16041+
#if defined(OPENSSL_EXTRA) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && \
16042+
(defined(WOLFSSL_IP_ALT_NAME) || defined(OPENSSL_ALL)) && \
16043+
!defined(OPENSSL_COMPATIBLE_DEFAULTS) && !defined(NO_SHA256)
16044+
static const char* ipaddr = NULL;
16045+
static int test_wolfSSL_check_ip_param_client_ssl(WOLFSSL* ssl)
16046+
{
16047+
EXPECT_DECLS;
16048+
X509_VERIFY_PARAM* param = NULL;
16049+
16050+
ExpectNotNull(param = SSL_get0_param(ssl));
16051+
ExpectIntEQ(X509_VERIFY_PARAM_set1_ip_asc(param, ipaddr), WOLFSSL_SUCCESS);
16052+
16053+
return EXPECT_RESULT();
16054+
}
16055+
16056+
/* Verify the OpenSSL-compat verify-param path:
16057+
* SSL_get0_param() + X509_VERIFY_PARAM_set1_ip_asc() controls IP SAN matching
16058+
* during handshake. */
16059+
static int test_wolfSSL_check_ip_param_basic(void)
16060+
{
16061+
EXPECT_DECLS;
16062+
test_ssl_cbf func_cb_client;
16063+
test_ssl_cbf func_cb_server;
16064+
16065+
XMEMSET(&func_cb_client, 0, sizeof(func_cb_client));
16066+
XMEMSET(&func_cb_server, 0, sizeof(func_cb_server));
16067+
16068+
func_cb_client.ssl_ready = &test_wolfSSL_check_ip_param_client_ssl;
16069+
16070+
ipaddr = "127.0.0.2";
16071+
/* Expect to fail: cert SAN IP is 127.0.0.1 */
16072+
ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&func_cb_client,
16073+
&func_cb_server, NULL), -1001);
16074+
16075+
ipaddr = "127.0.0.1";
16076+
/* Expect to succeed */
16077+
ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&func_cb_client,
16078+
&func_cb_server, NULL), TEST_SUCCESS);
16079+
16080+
return EXPECT_RESULT();
16081+
}
16082+
#else
16083+
static int test_wolfSSL_check_ip_param_basic(void)
16084+
{
16085+
EXPECT_DECLS;
16086+
return EXPECT_RESULT();
16087+
}
16088+
#endif
16089+
16090+
#if defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && \
16091+
!defined(OPENSSL_COMPATIBLE_DEFAULTS) && !defined(NO_SHA256) && \
16092+
defined(WOLFSSL_IP_ALT_NAME)
16093+
static const char* ipaddr_api = NULL;
16094+
static int test_wolfSSL_check_ip_address_basic_client_ssl(WOLFSSL* ssl)
16095+
{
16096+
EXPECT_DECLS;
16097+
16098+
ExpectIntEQ(wolfSSL_check_ip_address(ssl, ipaddr_api), WOLFSSL_SUCCESS);
16099+
16100+
return EXPECT_RESULT();
16101+
}
16102+
16103+
/* Verify wolfSSL convenience API path:
16104+
* wolfSSL_check_ip_address() enables IP SAN matching during handshake,
16105+
* including the non-OPENSSL_EXTRA storage/verification flow. */
16106+
static int test_wolfSSL_check_ip_address_basic(void)
16107+
{
16108+
EXPECT_DECLS;
16109+
test_ssl_cbf func_cb_client;
16110+
test_ssl_cbf func_cb_server;
16111+
16112+
XMEMSET(&func_cb_client, 0, sizeof(func_cb_client));
16113+
XMEMSET(&func_cb_server, 0, sizeof(func_cb_server));
16114+
16115+
func_cb_client.ssl_ready = &test_wolfSSL_check_ip_address_basic_client_ssl;
16116+
16117+
ipaddr_api = "127.0.0.2";
16118+
/* Expect to fail: cert SAN IP is 127.0.0.1 */
16119+
ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&func_cb_client,
16120+
&func_cb_server, NULL), -1001);
16121+
16122+
ipaddr_api = "127.0.0.1";
16123+
/* Expect to succeed */
16124+
ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&func_cb_client,
16125+
&func_cb_server, NULL), TEST_SUCCESS);
16126+
16127+
return EXPECT_RESULT();
16128+
}
16129+
#else
16130+
static int test_wolfSSL_check_ip_address_basic(void)
16131+
{
16132+
EXPECT_DECLS;
16133+
return EXPECT_RESULT();
16134+
}
16135+
#endif
16136+
1603916137
static int test_wolfSSL_BUF(void)
1604016138
{
1604116139
EXPECT_DECLS;
@@ -34201,6 +34299,8 @@ TEST_CASE testCases[] = {
3420134299

3420234300
TEST_DECL(test_wolfSSL_check_domain),
3420334301
TEST_DECL(test_wolfSSL_check_domain_basic),
34302+
TEST_DECL(test_wolfSSL_check_ip_param_basic),
34303+
TEST_DECL(test_wolfSSL_check_ip_address_basic),
3420434304
TEST_DECL(test_wolfSSL_cert_cb),
3420534305
TEST_DECL(test_wolfSSL_cert_cb_dyn_ciphers),
3420634306
TEST_DECL(test_wolfSSL_ciphersuite_auth),

wolfssl/internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4891,6 +4891,7 @@ typedef struct Buffers {
48914891
ThreadCrypt encrypt[WOLFSSL_THREADED_CRYPT_CNT];
48924892
#endif
48934893
buffer domainName; /* for client check */
4894+
buffer ipasc; /* for client IP SAN check */
48944895
buffer clearOutputBuffer;
48954896
buffer sig; /* signature data */
48964897
buffer digest; /* digest data */

wolfssl/ssl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3356,6 +3356,9 @@ WOLFSSL_API int wolfSSL_get_chain_cert_pem(WOLFSSL_X509_CHAIN* chain, int idx,
33563356
/* call before SSL_connect, if verifying will add name check to
33573357
date check and signature check */
33583358
WOLFSSL_ABI WOLFSSL_API int wolfSSL_check_domain_name(WOLFSSL* ssl, const char* dn);
3359+
/* call before SSL_connect, if verifying will add IP address check to
3360+
date check and signature check */
3361+
WOLFSSL_ABI WOLFSSL_API int wolfSSL_check_ip_address(WOLFSSL* ssl, const char* ipaddr);
33593362

33603363

33613364
/* need to call once to load library (session cache) */

0 commit comments

Comments
 (0)