From c5a211ca286f0d22921d989d49eeac7c46cccad0 Mon Sep 17 00:00:00 2001 From: Eric Blankenhorn Date: Fri, 12 Jun 2026 07:36:31 -0500 Subject: [PATCH] Fixes from review --- doc/dox_comments/header_files/ssl.h | 72 +++++++++++++++++++++++++++++ tests/api/test_tls13.c | 8 ++++ wolfssl/ssl.h | 5 +- 3 files changed, 83 insertions(+), 2 deletions(-) diff --git a/doc/dox_comments/header_files/ssl.h b/doc/dox_comments/header_files/ssl.h index c26fe92a92..e35c69708f 100644 --- a/doc/dox_comments/header_files/ssl.h +++ b/doc/dox_comments/header_files/ssl.h @@ -16095,6 +16095,78 @@ int wolfSSL_get_negotiated_client_cert_type(WOLFSSL* ssl, int* tp); */ int wolfSSL_get_negotiated_server_cert_type(WOLFSSL* ssl, int* tp); +/*! + \ingroup Setup + \brief Pin a DER-encoded SubjectPublicKeyInfo that the peer is expected to + present as a Raw Public Key (RFC 7250), establishing out-of-band trust on the + WOLFSSL_CTX object. An unauthenticated RPK peer is otherwise rejected: when the + peer is being authenticated (any verify mode other than WOLFSSL_VERIFY_NONE) + the handshake fails closed unless the presented key matches a pin (or a verify + callback accepts it). May be called more than once to pin several keys, up to + WOLFSSL_MAX_RPK_PINS. The key is stored as its SHA-256 digest, so this API + requires SHA-256. Pins are append-only for the lifetime of the CTX. + + \return WOLFSSL_SUCCESS on success + \return BAD_FUNC_ARG if ctx or spki is NULL, or spkiSz is 0 + \return BUFFER_E if the pin table is already full (WOLFSSL_MAX_RPK_PINS) + \return other negative error code on a hashing failure + + \param ctx WOLFSSL_CTX object pointer + \param spki DER-encoded SubjectPublicKeyInfo the peer is expected to present + \param spkiSz length of spki in bytes + _Example_ + \code + int ret; + WOLFSSL_CTX* ctx; + const unsigned char* spki; /* DER SubjectPublicKeyInfo */ + unsigned int spkiSz; + ... + + ret = wolfSSL_CTX_set_expected_rpk(ctx, spki, spkiSz); + \endcode + \sa wolfSSL_set_expected_rpk + \sa wolfSSL_set_client_cert_type + \sa wolfSSL_set_server_cert_type + */ +int wolfSSL_CTX_set_expected_rpk(WOLFSSL_CTX* ctx, const unsigned char* spki, + unsigned int spkiSz); + +/*! + \ingroup Setup + \brief Pin a DER-encoded SubjectPublicKeyInfo that the peer is expected to + present as a Raw Public Key (RFC 7250), establishing out-of-band trust on the + WOLFSSL object. An unauthenticated RPK peer is otherwise rejected: when the + peer is being authenticated (any verify mode other than WOLFSSL_VERIFY_NONE) + the handshake fails closed unless the presented key matches a pin (or a verify + callback accepts it). May be called more than once to pin several keys, up to + WOLFSSL_MAX_RPK_PINS. The key is stored as its SHA-256 digest, so this API + requires SHA-256. Pins are append-only for the lifetime of the object. + + \return WOLFSSL_SUCCESS on success + \return BAD_FUNC_ARG if ssl or spki is NULL, or spkiSz is 0 + \return BUFFER_E if the pin table is already full (WOLFSSL_MAX_RPK_PINS) + \return other negative error code on a hashing failure + + \param ssl WOLFSSL object pointer + \param spki DER-encoded SubjectPublicKeyInfo the peer is expected to present + \param spkiSz length of spki in bytes + _Example_ + \code + int ret; + WOLFSSL* ssl; + const unsigned char* spki; /* DER SubjectPublicKeyInfo */ + unsigned int spkiSz; + ... + + ret = wolfSSL_set_expected_rpk(ssl, spki, spkiSz); + \endcode + \sa wolfSSL_CTX_set_expected_rpk + \sa wolfSSL_set_client_cert_type + \sa wolfSSL_set_server_cert_type + */ +int wolfSSL_set_expected_rpk(WOLFSSL* ssl, const unsigned char* spki, + unsigned int spkiSz); + /*! \brief Enable use of ConnectionID extensions for the SSL object. See RFC 9146 diff --git a/tests/api/test_tls13.c b/tests/api/test_tls13.c index 44626e0a91..901f7d9495 100644 --- a/tests/api/test_tls13.c +++ b/tests/api/test_tls13.c @@ -3883,6 +3883,14 @@ int test_tls13_rpk_trust(void) ExpectIntEQ(load_file(svrRpkCertFile, &svrSpki, &svrSpkiSz), 0); ExpectIntEQ(load_file(clntRpkCertFile, &cliSpki, &cliSpkiSz), 0); + /* If either pin failed to load, stop before feeding NULL/zero-length + * buffers into the pinning calls below (which would only produce + * misleading downstream failures). */ + if (EXPECT_FAIL()) { + XFREE(svrSpki, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(cliSpki, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return EXPECT_RESULT(); + } /* --- WOLFSSL_VERIFY_NONE: completes, but reported as untrusted --- */ ctx_c = ctx_s = NULL; diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index ef5bc9cd71..1e31d9e7a8 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -2782,8 +2782,9 @@ enum { WOLFSSL_X509_V_ERR_IP_ADDRESS_MISMATCH = 64, WOLFSSL_X509_V_ERR_INVALID_CA = 79, WC_OSSL_V509_V_ERR_MAX = 80, - /* Codes at or above WC_OSSL_V509_V_ERR_MAX are intentionally outside the - * contiguous range swept by the error-string test in tests/api.c. */ + /* wolfSSL-specific verify-result codes are assigned at or above + * WC_OSSL_V509_V_ERR_MAX, intentionally outside the contiguous + * OpenSSL-compatible range below it. */ WOLFSSL_X509_V_ERR_RPK_UNTRUSTED = 95, #ifdef HAVE_OCSP