diff --git a/certs/include.am b/certs/include.am index 69db67898..637b6b2d7 100644 --- a/certs/include.am +++ b/certs/include.am @@ -140,4 +140,5 @@ include certs/falcon/include.am include certs/rsapss/include.am include certs/dilithium/include.am include certs/sphincs/include.am +include certs/rpk/include.am diff --git a/certs/renewcerts.sh b/certs/renewcerts.sh index ece320c79..a09616393 100755 --- a/certs/renewcerts.sh +++ b/certs/renewcerts.sh @@ -687,6 +687,28 @@ run_renewcerts(){ echo "End of section" echo "---------------------------------------------------------------------" + ############################################################ + ########## update Raw Public Key certificates ############## + ############################################################ + echo "Updating certificates" + echo "Updating client-cert-rpk.der" + cp client-keyPub.der ./rpk/client-cert-rpk.der + check_result $? "Step 1" + + echo "Updating client-ecc-cert-rpk.der" + cp ecc-client-keyPub.der ./rpk/ecc-client-cert-rpk.der + check_result $? "Step 2" + + echo "Updating server-cert-rpk.der" + openssl rsa -inform pem -in server-key.pem -outform der -out ./rpk/server-cert-rpk.der -pubout + check_result $? "Step 3" + + echo "Updating server-ecc-cert-rpk.der" + openssl ec -inform pem -in ecc-key.pem -outform der -out ./rpk/server-ecc-cert-rpk.der -pubout + check_result $? "Step 4" + + echo "End of section" + echo "---------------------------------------------------------------------" ############################################################ ###### update the ecc-rsa-server.p12 file ################## ############################################################ diff --git a/certs/rpk/client-cert-rpk.der b/certs/rpk/client-cert-rpk.der new file mode 100644 index 000000000..b27f0e9bb Binary files /dev/null and b/certs/rpk/client-cert-rpk.der differ diff --git a/certs/rpk/client-ecc-cert-rpk.der b/certs/rpk/client-ecc-cert-rpk.der new file mode 100644 index 000000000..5dace05a9 Binary files /dev/null and b/certs/rpk/client-ecc-cert-rpk.der differ diff --git a/certs/rpk/include.am b/certs/rpk/include.am new file mode 100644 index 000000000..6274be450 --- /dev/null +++ b/certs/rpk/include.am @@ -0,0 +1,9 @@ +# vim:ft=automake +# All paths should be given relative to the root +# + +EXTRA_DIST += \ + certs/rpk/client-cert-rpk.der \ + certs/rpk/client-ecc-cert-rpk.der \ + certs/rpk/server-cert-rpk.der \ + certs/rpk/server-ecc-cert-rpk.der diff --git a/certs/rpk/server-cert-rpk.der b/certs/rpk/server-cert-rpk.der new file mode 100644 index 000000000..b6d8fbe66 Binary files /dev/null and b/certs/rpk/server-cert-rpk.der differ diff --git a/certs/rpk/server-ecc-cert-rpk.der b/certs/rpk/server-ecc-cert-rpk.der new file mode 100644 index 000000000..91aa79bee Binary files /dev/null and b/certs/rpk/server-ecc-cert-rpk.der differ diff --git a/doc/dox_comments/header_files-ja/ssl.h b/doc/dox_comments/header_files-ja/ssl.h index 2a1aeac15..4653fb12b 100644 --- a/doc/dox_comments/header_files-ja/ssl.h +++ b/doc/dox_comments/header_files-ja/ssl.h @@ -9515,6 +9515,195 @@ WOLFSSL_METHOD *wolfTLSv1_3_method_ex(void* heap); */ WOLFSSL_METHOD *wolfTLSv1_3_method(void); +/*! + \ingroup Setup + \brief この関数はクライアント側で呼び出される場合には、サーバー側にCertificateメッセージで送信できる証明書タイプを設定します。 + サーバー側で呼び出される場合には、受入れ可能なクライアント証明書タイプを設定します。 + Raw Public Key 証明書を送受信したい場合にはこの関数を使って証明書タイプを設定しなければなりません。 + 設定する証明書タイプは優先度順に格納したバイト配列として渡します。 + 設定するバッファアドレスにNULLを渡すか、あるいはバッファサイズに0を渡すと規定値にもどすことができます。 + 規定値はX509証明書(WOLFSSL_CERT_TYPE_X509)のみを扱う設定となっています。 + + \return WOLFSSL_SUCCESS 成功 + \return BAD_FUNC_ARG ctxとしてNULLを渡した、あるいは不正な証明書タイプを指定した、 + あるいはMAX_CLIENT_CERT_TYPE_CNT以上のバッファサイズを指定した、あるいは指定の証明書タイプに重複がある + \param ctx wolfssl_ctxコンテキストポインタ + \param ctype 証明書タイプを格納したバッファへのポインタ + \param len 証明書タイプを格納したバッファのサイズ(バイト数) + _Example_ + \code + int ret; + WOLFSSL_CTX* ctx; + char ctype[] = {WOLFSSL_CERT_TYPE_RPK, WOLFSSL_CERT_TYPE_X509}; + int len = sizeof(ctype)/sizeof(byte); + ... + + ret = wolfSSL_CTX_set_client_cert_type(ctx, ctype, len); + \endcode + \sa wolfSSL_set_client_cert_type + \sa wolfSSL_CTX_set_server_cert_type + \sa wolfSSL_set_server_cert_type + \sa wolfSSL_get_negotiated_client_cert_type + \sa wolfSSL_get_negotiated_server_cert_type + */ +int wolfSSL_CTX_set_client_cert_type(WOLFSSL_CTX* ctx, const char* buf, int len); + +/*! + \ingroup Setup + \brief この関数はサーバー側で呼び出される場合には、クライアント側にCertificateメッセージで送信できる証明書タイプを設定します。 + クライアント側で呼び出される場合には、受入れ可能なサーバー証明書タイプを設定します。 + Raw Public Key 証明書を送受信したい場合にはこの関数を使って証明書タイプを設定しなければなりません。 + 設定する証明書タイプは優先度順に格納したバイト配列として渡します。 + 設定するバッファアドレスにNULLを渡すか、あるいはバッファサイズに0を渡すと規定値にもどすことができます。 + 規定値はX509証明書(WOLFSSL_CERT_TYPE_X509)のみを扱う設定となっています。 + + \return WOLFSSL_SUCCESS 成功 + \return BAD_FUNC_ARG ctxとしてNULLを渡した、あるいは不正な証明書タイプを指定した、 + あるいはMAX_SERVER_CERT_TYPE_CNT以上のバッファサイズを指定した、あるいは指定の証明書タイプに重複がある + + \param ctx wolfssl_ctxコンテキストポインタ + \param ctype 証明書タイプを格納したバッファへのポインタ + \param len 証明書タイプを格納したバッファのサイズ(バイト数) + _Example_ + \code + int ret; + WOLFSSL_CTX* ctx; + char ctype[] = {WOLFSSL_CERT_TYPE_RPK, WOLFSSL_CERT_TYPE_X509}; + int len = sizeof(ctype)/sizeof(byte); + ... + + ret = wolfSSL_CTX_set_server_cert_type(ctx, ctype, len); + \endcode + \sa wolfSSL_set_client_cert_type + \sa wolfSSL_CTX_set_client_cert_type + \sa wolfSSL_set_server_cert_type + \sa wolfSSL_get_negotiated_client_cert_type + \sa wolfSSL_get_negotiated_server_cert_type + */ +int wolfSSL_CTX_set_server_cert_type(WOLFSSL_CTX* ctx, const char* buf, int len); + +/*! + \ingroup Setup + \brief この関数はクライアント側で呼び出される場合には、サーバー側にCertificateメッセージで送信できる証明書タイプを設定します。 + サーバー側で呼び出される場合には、受入れ可能なクライアント証明書タイプを設定します。 + Raw Public Key 証明書を送受信したい場合にはこの関数を使って証明書タイプを設定しなければなりません。 + 設定する証明書タイプは優先度順に格納したバイト配列として渡します。 + 設定するバッファアドレスにNULLを渡すか、あるいはバッファサイズに0を渡すと規定値にもどすことができます。 + 規定値はX509証明書(WOLFSSL_CERT_TYPE_X509)のみを扱う設定となっています。 + + \return WOLFSSL_SUCCESS 成功 + \return BAD_FUNC_ARG sslとしてNULLを渡した、あるいは不正な証明書タイプを指定した、 + あるいはMAX_CLIENT_CERT_TYPE_CNT以上のバッファサイズを指定した、あるいは指定の証明書タイプに重複がある + + \param ssl WOLFSSL構造体へのポインタ + \param ctype 証明書タイプを格納したバッファへのポインタ + \param len 証明書タイプを格納したバッファのサイズ(バイト数) + _Example_ + \code + int ret; + WOLFSSL* ssl; + char ctype[] = {WOLFSSL_CERT_TYPE_RPK, WOLFSSL_CERT_TYPE_X509}; + int len = sizeof(ctype)/sizeof(byte); + ... + + ret = wolfSSL_set_client_cert_type(ssl, ctype, len); + \endcode + \sa wolfSSL_CTX_set_client_cert_type + \sa wolfSSL_CTX_set_server_cert_type + \sa wolfSSL_set_server_cert_type + \sa wolfSSL_get_negotiated_client_cert_type + \sa wolfSSL_get_negotiated_server_cert_type + */ +int wolfSSL_set_client_cert_type(WOLFSSL* ssl, const char* buf, int len); + +/*! + \ingroup Setup + \brief この関数はサーバー側で呼び出される場合には、クライアント側にCertificateメッセージで送信できる証明書タイプを設定します。 + クライアント側で呼び出される場合には、受入れ可能なサーバー証明書タイプを設定します。 + Raw Public Key 証明書を送受信したい場合にはこの関数を使って証明書タイプを設定しなければなりません。 + 設定する証明書タイプは優先度順に格納したバイト配列として渡します。 + 設定するバッファアドレスにNULLを渡すか、あるいはバッファサイズに0を渡すと規定値にもどすことができます。 + 規定値はX509証明書(WOLFSSL_CERT_TYPE_X509)のみを扱う設定となっています。 + + \return WOLFSSL_SUCCESS 成功 + \return BAD_FUNC_ARG ctxとしてNULLを渡した、あるいは不正な証明書タイプを指定した、 + あるいはMAX_SERVER_CERT_TYPE_CNT以上のバッファサイズを指定した、あるいは指定の証明書タイプに重複がある + + \param ssl WOLFSSL構造体へのポインタ + \param ctype 証明書タイプを格納したバッファへのポインタ + \param len 証明書タイプを格納したバッファのサイズ(バイト数) + _Example_ + \code + int ret; + WOLFSSL* ssl; + char ctype[] = {WOLFSSL_CERT_TYPE_RPK, WOLFSSL_CERT_TYPE_X509}; + int len = sizeof(ctype)/sizeof(byte); + ... + + ret = wolfSSL_set_server_cert_type(ssl, ctype, len); + \endcode + \sa wolfSSL_set_client_cert_type + \sa wolfSSL_CTX_set_server_cert_type + \sa wolfSSL_set_server_cert_type + \sa wolfSSL_get_negotiated_client_cert_type + \sa wolfSSL_get_negotiated_server_cert_type + */ +int wolfSSL_set_server_cert_type(WOLFSSL* ssl, const char* buf, int len); + +/*! + \ingroup SSL + \brief この関数はハンドシェーク終了後に呼び出し、相手とのネゴシエーションの結果得られたクライアント証明書のタイプを返します。 + ネゴシエーションが発生しない場合には戻り値としてWOLFSSL_SUCCESSが返されますが、 + 証明書タイプとしてはWOLFSSL_CERT_TYPE_UNKNOWNが返されます。 + + \return WOLFSSL_SUCCESS 成功時にかえります。tpに返された証明書タイプはWOLFSSL_CERT_TYPE_X509, + WOLFSSL_CERT_TYPE_RPK あるいはWOLFSSL_CERT_TYPE_UNKNOWNのいずれかとなります。 + \return BAD_FUNC_ARG sslとしてNULLを渡した、あるいはtpとしてNULLを渡した + \param ssl WOLFSSL構造体へのポインタ + \param tp 証明書タイプが返されるバッファへのポインタ + _Example_ + \code + int ret; + WOLFSSL* ssl; + int tp; + ... + + ret = wolfSSL_get_negotiated_client_cert_type(ssl, &tp); + \endcode + \sa wolfSSL_set_client_cert_type + \sa wolfSSL_CTX_set_client_cert_type + \sa wolfSSL_set_server_cert_type + \sa wolfSSL_CTX_set_server_cert_type + \sa wolfSSL_get_negotiated_server_cert_type + */ +int wolfSSL_get_negotiated_client_cert_type(WOLFSSL* ssl, int* tp); + +/*! + \ingroup SSL + \brief この関数はハンドシェーク終了後に呼び出し、相手とのネゴシエーションの結果得られたサーバー証明書のタイプを返します。 + ネゴシエーションが発生しない場合には戻り値としてWOLFSSL_SUCCESSが返されますが、証明書タイプとしてはWOLFSSL_CERT_TYPE_UNKNOWNが返されます。 + \return WOLFSSL_SUCCESS 成功時にかえります。tpに返された証明書タイプはWOLFSSL_CERT_TYPE_X509, + WOLFSSL_CERT_TYPE_RPK あるいはWOLFSSL_CERT_TYPE_UNKNOWNのいずれかとなります。 + \return BAD_FUNC_ARG sslとしてNULLを渡した、あるいはtpとしてNULLを渡した + \param ssl WOLFSSL構造体へのポインタ + \param tp 証明書タイプが返されるバッファへのポインタ + _Example_ + \code + int ret; + WOLFSSL* ssl; + int tp; + ... + + ret = wolfSSL_get_negotiated_server_cert_type(ssl, &tp); + \endcode + \sa wolfSSL_set_client_cert_type + \sa wolfSSL_CTX_set_client_cert_type + \sa wolfSSL_set_server_cert_type + \sa wolfSSL_CTX_set_server_cert_type + \sa wolfSSL_get_negotiated_client_cert_type + */ +int wolfSSL_get_negotiated_server_cert_type(WOLFSSL* ssl, int* tp); + /*! \ingroup SSL \brief この関数はテストのための固定/静的なエフェラルキーを設定します。 diff --git a/doc/dox_comments/header_files/ssl.h b/doc/dox_comments/header_files/ssl.h index b9cdd8dcf..d0595e1f2 100644 --- a/doc/dox_comments/header_files/ssl.h +++ b/doc/dox_comments/header_files/ssl.h @@ -14490,6 +14490,211 @@ unsigned int wolfSSL_SESSION_get_max_early_data(const WOLFSSL_SESSION *s); */ int wolfSSL_CRYPTO_get_ex_new_index(int, void*, void*, void*, void*); +/*! + \ingroup Setup + \brief In case this function is called in a client side, set certificate types + that can be sent to its peer. In case called in a server side, + set certificate types that can be acceptable from its peer. Put cert types in the + buffer with prioritised order. To reset the settings to default, pass NULL + for the buffer or pass zero for len. By default, certificate type is only X509. + In case both side intend to send or accept "Raw public key" cert, + WOLFSSL_CERT_TYPE_RPK should be included in the buffer to set. + + \return WOLFSSL_SUCCESS if cert types set successfully + \return BAD_FUNC_ARG if NULL was passed for ctx, illegal value was specified as + cert type, buf size exceed MAX_CLIENT_CERT_TYPE_CNT was specified or + a duplicate value is found in buf. + + \param ctx WOLFSSL_CTX object pointer + \param buf A buffer where certificate types are stored + \param len buf size in bytes (same as number of certificate types included) + _Example_ + \code + int ret; + WOLFSSL_CTX* ctx; + char buf[] = {WOLFSSL_CERT_TYPE_RPK, WOLFSSL_CERT_TYPE_X509}; + int len = sizeof(buf)/sizeof(char); + ... + + ret = wolfSSL_CTX_set_client_cert_type(ctx, buf, len); + \endcode + \sa wolfSSL_set_client_cert_type + \sa wolfSSL_CTX_set_server_cert_type + \sa wolfSSL_set_server_cert_type + \sa wolfSSL_get_negotiated_client_cert_type + \sa wolfSSL_get_negotiated_server_cert_type + */ +int wolfSSL_CTX_set_client_cert_type(WOLFSSL_CTX* ctx, const char* buf, int len); + +/*! + \ingroup Setup + \brief In case this function is called in a server side, set certificate types + that can be sent to its peer. In case called in a client side, + set certificate types that can be acceptable from its peer. Put cert types in the + buffer with prioritised order. To reset the settings to default, pass NULL + for the buffer or pass zero for len. By default, certificate type is only X509. + In case both side intend to send or accept "Raw public key" cert, + WOLFSSL_CERT_TYPE_RPK should be included in the buffer to set. + + \return WOLFSSL_SUCCESS if cert types set successfully + \return BAD_FUNC_ARG if NULL was passed for ctx, illegal value was specified as + cert type, buf size exceed MAX_SERVER_CERT_TYPE_CNT was specified or + a duplicate value is found in buf. + + \param ctx WOLFSSL_CTX object pointer + \param buf A buffer where certificate types are stored + \param len buf size in bytes (same as number of certificate types included) + _Example_ + \code + int ret; + WOLFSSL_CTX* ctx; + char buf[] = {WOLFSSL_CERT_TYPE_RPK, WOLFSSL_CERT_TYPE_X509}; + int len = sizeof(buf)/sizeof(char); + ... + + ret = wolfSSL_CTX_set_server_cert_type(ctx, buf, len); + \endcode + \sa wolfSSL_set_client_cert_type + \sa wolfSSL_CTX_set_client_cert_type + \sa wolfSSL_set_server_cert_type + \sa wolfSSL_get_negotiated_client_cert_type + \sa wolfSSL_get_negotiated_server_cert_type + */ +int wolfSSL_CTX_set_server_cert_type(WOLFSSL_CTX* ctx, const char* buf, int len); + +/*! + \ingroup Setup + \brief In case this function is called in a client side, set certificate types + that can be sent to its peer. In case called in a server side, + set certificate types that can be acceptable from its peer. Put cert types in the + buffer with prioritised order. To reset the settings to default, pass NULL + for the buffer or pass zero for len. By default, certificate type is only X509. + In case both side intend to send or accept "Raw public key" cert, + WOLFSSL_CERT_TYPE_RPK should be included in the buffer to set. + + \return WOLFSSL_SUCCESS if cert types set successfully + \return BAD_FUNC_ARG if NULL was passed for ctx, illegal value was specified as + cert type, buf size exceed MAX_CLIENT_CERT_TYPE_CNT was specified or + a duplicate value is found in buf. + + \param ssl WOLFSSL object pointer + \param buf A buffer where certificate types are stored + \param len buf size in bytes (same as number of certificate types included) + _Example_ + \code + int ret; + WOLFSSL* ssl; + char buf[] = {WOLFSSL_CERT_TYPE_RPK, WOLFSSL_CERT_TYPE_X509}; + int len = sizeof(buf)/sizeof(char); + ... + + ret = wolfSSL_set_client_cert_type(ssl, buf, len); + \endcode + \sa wolfSSL_CTX_set_client_cert_type + \sa wolfSSL_CTX_set_server_cert_type + \sa wolfSSL_set_server_cert_type + \sa wolfSSL_get_negotiated_client_cert_type + \sa wolfSSL_get_negotiated_server_cert_type + */ +int wolfSSL_set_client_cert_type(WOLFSSL* ssl, const char* buf, int len); + +/*! + \ingroup Setup + \brief In case this function is called in a server side, set certificate types + that can be sent to its peer. In case called in a client side, + set certificate types that can be acceptable from its peer. Put cert types in the + buffer with prioritised order. To reset the settings to default, pass NULL + for the buffer or pass zero for len. By default, certificate type is only X509. + In case both side intend to send or accept "Raw public key" cert, + WOLFSSL_CERT_TYPE_RPK should be included in the buffer to set. + + \return WOLFSSL_SUCCESS if cert types set successfully + \return BAD_FUNC_ARG if NULL was passed for ctx, illegal value was specified as + cert type, buf size exceed MAX_SERVER_CERT_TYPE_CNT was specified or + a duplicate value is found in buf. + + \param ctx WOLFSSL_CTX object pointer + \param buf A buffer where certificate types are stored + \param len buf size in bytes (same as number of certificate types included) + _Example_ + \code + int ret; + WOLFSSL* ssl; + char buf[] = {WOLFSSL_CERT_TYPE_RPK, WOLFSSL_CERT_TYPE_X509}; + int len = sizeof(buf)/sizeof(char); + ... + + ret = wolfSSL_set_server_cert_type(ssl, buf, len); + \endcode + \sa wolfSSL_set_client_cert_type + \sa wolfSSL_CTX_set_server_cert_type + \sa wolfSSL_set_server_cert_type + \sa wolfSSL_get_negotiated_client_cert_type + \sa wolfSSL_get_negotiated_server_cert_type + */ +int wolfSSL_set_server_cert_type(WOLFSSL* ssl, const char* buf, int len); + +/*! + \ingroup SSL + \brief This function returns the result of the client certificate type + negotiation done in ClientHello and ServerHello. WOLFSSL_SUCCESS is returned as + a return value if no negotiation occurs and WOLFSSL_CERT_TYPE_UNKNOWN is + returned as the certificate type. + + \return WOLFSSL_SUCCESS if a negotiated certificate type could be got + \return BAD_FUNC_ARG if NULL was passed for ctx or tp + \param ssl WOLFSSL object pointer + \param tp A buffer where a certificate type is to be returned. One of three + certificate types will be returned: WOLFSSL_CERT_TYPE_RPK, + WOLFSSL_CERT_TYPE_X509 or WOLFSSL_CERT_TYPE_UNKNOWN. + + _Example_ + \code + int ret; + WOLFSSL* ssl; + int tp; + ... + + ret = wolfSSL_get_negotiated_client_cert_type(ssl, &tp); + \endcode + \sa wolfSSL_set_client_cert_type + \sa wolfSSL_CTX_set_client_cert_type + \sa wolfSSL_set_server_cert_type + \sa wolfSSL_CTX_set_server_cert_type + \sa wolfSSL_get_negotiated_server_cert_type + */ +int wolfSSL_get_negotiated_client_cert_type(WOLFSSL* ssl, int* tp); + +/*! + \ingroup SSL + \brief This function returns the result of the server certificate type + negotiation done in ClientHello and ServerHello. WOLFSSL_SUCCESS is returned as + a return value if no negotiation occurs and WOLFSSL_CERT_TYPE_UNKNOWN is + returned as the certificate type. + + \return WOLFSSL_SUCCESS if a negotiated certificate type could be got + \return BAD_FUNC_ARG if NULL was passed for ctx or tp + \param ssl WOLFSSL object pointer + \param tp A buffer where a certificate type is to be returned. One of three + certificate types will be returned: WOLFSSL_CERT_TYPE_RPK, + WOLFSSL_CERT_TYPE_X509 or WOLFSSL_CERT_TYPE_UNKNOWN. + _Example_ + \code + int ret; + WOLFSSL* ssl; + int tp; + ... + + ret = wolfSSL_get_negotiated_server_cert_type(ssl, &tp); + \endcode + \sa wolfSSL_set_client_cert_type + \sa wolfSSL_CTX_set_client_cert_type + \sa wolfSSL_set_server_cert_type + \sa wolfSSL_CTX_set_server_cert_type + \sa wolfSSL_get_negotiated_client_cert_type + */ +int wolfSSL_get_negotiated_server_cert_type(WOLFSSL* ssl, int* tp); + /*! \brief Enable use of ConnectionID extensions for the SSL object. See RFC 9146 diff --git a/src/internal.c b/src/internal.c index 71f6a1ebc..e1daa20b4 100644 --- a/src/internal.c +++ b/src/internal.c @@ -2279,6 +2279,11 @@ int InitSSL_Ctx(WOLFSSL_CTX* ctx, WOLFSSL_METHOD* method, void* heap) #endif /* MICRIUM */ #endif /* WOLFSSL_USER_IO */ +#if defined(HAVE_RPK) + wolfSSL_CTX_set_client_cert_type(ctx, NULL, 0); /* set to default */ + wolfSSL_CTX_set_server_cert_type(ctx, NULL, 0); /* set to default */ +#endif /* HAVE_RPK */ + #ifdef HAVE_PQC #ifdef HAVE_FALCON if (method->side == WOLFSSL_CLIENT_END) @@ -6671,6 +6676,11 @@ int SetSSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup) ssl->buffers.serverDH_G = ctx->serverDH_G; #endif +#if defined(HAVE_RPK) + ssl->options.rpkConfig = ctx->rpkConfig; + ssl->options.rpkState = ctx->rpkState; +#endif /* HAVE_RPK */ + #ifndef NO_CERTS /* ctx still owns certificate, certChain, key, dh, and cm */ ssl->buffers.certificate = ctx->certificate; @@ -12751,6 +12761,11 @@ void DoCertFatalAlert(WOLFSSL* ssl, int ret) alertWhy = certificate_revoked; } #endif +#if defined(HAVE_RPK) + else if (ret == UNSUPPORTED_CERTIFICATE) { + alertWhy = unsupported_certificate; + } +#endif /* HAVE_RPK */ else if (ret == NO_PEER_CERT) { #ifdef WOLFSSL_TLS13 if (ssl->options.tls1_3) { @@ -13341,6 +13356,9 @@ static int ProcessPeerCertParse(WOLFSSL* ssl, ProcPeerCertArgs* args, buffer* cert; byte* subjectHash = NULL; int alreadySigner = 0; +#if defined(HAVE_RPK) + int cType; +#endif #ifdef WOLFSSL_SMALL_CERT_VERIFY int sigRet = 0; #endif @@ -13442,6 +13460,37 @@ PRAGMA_GCC_DIAG_POP /* Parse Certificate */ ret = ParseCertRelative(args->dCert, certType, verify, SSL_CM(ssl)); + +#if defined(HAVE_RPK) + /* if cert type has negotiated with peer, confirm the cert received has + * the same type. + */ + if (ret == 0 ) { + if (ssl->options.side == WOLFSSL_CLIENT_END) { + if (ssl->options.rpkState.received_ServerCertTypeCnt == 1) { + cType = ssl->options.rpkState.received_ServerCertTypes[0]; + if ((cType == WOLFSSL_CERT_TYPE_RPK && !args->dCert->isRPK) || + (cType == WOLFSSL_CERT_TYPE_X509 && args->dCert->isRPK)) { + /* cert type mismatch */ + WOLFSSL_MSG("unsuported certificate type received"); + ret = UNSUPPORTED_CERTIFICATE; + } + } + } + else if (ssl->options.side == WOLFSSL_SERVER_END) { + if (ssl->options.rpkState.received_ClientCertTypeCnt == 1) { + cType = ssl->options.rpkState.sending_ClientCertTypes[0]; + if ((cType == WOLFSSL_CERT_TYPE_RPK && !args->dCert->isRPK) || + (cType == WOLFSSL_CERT_TYPE_X509 && args->dCert->isRPK)) { + /* cert type mismatch */ + WOLFSSL_MSG("unsuported certificate type received"); + ret = UNSUPPORTED_CERTIFICATE; + } + } + } + } +#endif /* HAVE_RPK */ + /* perform below checks for date failure cases */ if (ret == 0 || ret == ASN_BEFORE_DATE_E || ret == ASN_AFTER_DATE_E) { /* get subject and determine if already loaded */ @@ -14262,6 +14311,20 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx, * OpenSSL doesn't appear to be performing this check. * For TLS 1.3 see RFC8446 Section 4.4.2.3 */ if (ssl->options.side == WOLFSSL_SERVER_END) { + #if defined(HAVE_RPK) + if (args->dCert->isRPK) { + /* to verify Raw Public Key cert, DANE(RFC6698) + * should be introduced. Without DANE, no + * authentication is performed. + */ + #if defined(HAVE_DANE) + if (ssl->useDANE) { + /* DANE authentication should be added */ + } + #endif /* HAVE_DANE */ + } + else /* skip followingx509 version check */ + #endif /* HAVE_RPK */ if (args->dCert->version != WOLFSSL_X509_V3) { WOLFSSL_MSG("Peers certificate was not version 3!"); args->lastErr = ASN_VERSION_E; @@ -24387,6 +24450,9 @@ const char* wolfSSL_ERR_reason_error_string(unsigned long e) case SOCKET_FILTERED_E: return "Session stopped by network filter"; + case UNSUPPORTED_CERTIFICATE: + return "Unsupported certificate type"; + #ifdef HAVE_HTTP_CLIENT case HTTP_TIMEOUT: return "HTTP timeout for OCSP or CRL req"; diff --git a/src/ssl.c b/src/ssl.c index e5820b422..a7eb025ef 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -7402,6 +7402,20 @@ int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, #endif return WOLFSSL_BAD_FILE; } +#if defined(HAVE_RPK) + if (ssl) { + ssl->options.rpkState.isRPKLoaded = 0; + if (cert->isRPK) { + ssl->options.rpkState.isRPKLoaded = 1; + } + } + else if (ctx) { + ctx->rpkState.isRPKLoaded = 0; + if (cert->isRPK) { + ctx->rpkState.isRPKLoaded = 1; + } + } +#endif /* HAVE_RPK */ if (ssl) { if (ssl->options.side == WOLFSSL_SERVER_END) @@ -10183,6 +10197,232 @@ int wolfSSL_use_certificate(WOLFSSL* ssl, WOLFSSL_X509* x509) #endif /* OPENSSL_EXTRA */ +#if defined(HAVE_RPK) +/* Confirm that all the byte data in the buffer is unique. + * return 1 if all the byte data in the buffer is unique, otherwise 0. + */ +static int isArrayUnique(const char* buf, size_t len) +{ + size_t i, j; + /* check the array is unique */ + for (i = 0; i < len -1; ++i) { + for (j = i+ 1; j < len; ++j) { + if (buf[i] == buf[j]) { + return 0; + } + } + } + return 1; +} + +/* Set user preference for the client_cert_type exetnsion. + * Takes byte array containing cert types the caller can provide to its peer. + * Cert types are in preferred order in the array. + */ +WOLFSSL_API int wolfSSL_CTX_set_client_cert_type(WOLFSSL_CTX* ctx, + const char* buf, int bufLen) +{ + int i; + + if (ctx == NULL || bufLen > MAX_CLIENT_CERT_TYPE_CNT) { + return BAD_FUNC_ARG; + } + + /* if buf is set to NULL or bufLen is set to zero, it defaults the setting*/ + if (buf == NULL || bufLen == 0) { + ctx->rpkConfig.preferred_ClientCertTypeCnt = 1; + ctx->rpkConfig.preferred_ClientCertTypes[0]= WOLFSSL_CERT_TYPE_X509; + ctx->rpkConfig.preferred_ClientCertTypes[1]= WOLFSSL_CERT_TYPE_X509; + return WOLFSSL_SUCCESS; + } + + if (!isArrayUnique(buf, bufLen)) + return BAD_FUNC_ARG; + + for (i = 0; i < bufLen; i++){ + if (buf[i] != WOLFSSL_CERT_TYPE_RPK && buf[i] != WOLFSSL_CERT_TYPE_X509) + return BAD_FUNC_ARG; + + ctx->rpkConfig.preferred_ClientCertTypes[i] = buf[i]; + } + ctx->rpkConfig.preferred_ClientCertTypeCnt = bufLen; + + return WOLFSSL_SUCCESS; +} + +/* Set user preference for the server_cert_type exetnsion. + * Takes byte array containing cert types the caller can provide to its peer. + * Cert types are in preferred order in the array. + */ +WOLFSSL_API int wolfSSL_CTX_set_server_cert_type(WOLFSSL_CTX* ctx, + const char* buf, int bufLen) +{ + int i; + + if (ctx == NULL || bufLen > MAX_SERVER_CERT_TYPE_CNT) { + return BAD_FUNC_ARG; + } + + /* if buf is set to NULL or bufLen is set to zero, it defaults the setting*/ + if (buf == NULL || bufLen == 0) { + ctx->rpkConfig.preferred_ServerCertTypeCnt = 1; + ctx->rpkConfig.preferred_ServerCertTypes[0]= WOLFSSL_CERT_TYPE_X509; + ctx->rpkConfig.preferred_ServerCertTypes[1]= WOLFSSL_CERT_TYPE_X509; + return WOLFSSL_SUCCESS; + } + + if (!isArrayUnique(buf, bufLen)) + return BAD_FUNC_ARG; + + for (i = 0; i < bufLen; i++){ + if (buf[i] != WOLFSSL_CERT_TYPE_RPK && buf[i] != WOLFSSL_CERT_TYPE_X509) + return BAD_FUNC_ARG; + + ctx->rpkConfig.preferred_ServerCertTypes[i] = buf[i]; + } + ctx->rpkConfig.preferred_ServerCertTypeCnt = bufLen; + + return WOLFSSL_SUCCESS; +} + +/* Set user preference for the client_cert_type exetnsion. + * Takes byte array containing cert types the caller can provide to its peer. + * Cert types are in preferred order in the array. + */ +WOLFSSL_API int wolfSSL_set_client_cert_type(WOLFSSL* ssl, + const char* buf, int bufLen) +{ + int i; + + if (ssl == NULL || bufLen > MAX_CLIENT_CERT_TYPE_CNT) { + return BAD_FUNC_ARG; + } + + /* if buf is set to NULL or bufLen is set to zero, it defaults the setting*/ + if (buf == NULL || bufLen == 0) { + ssl->options.rpkConfig.preferred_ClientCertTypeCnt = 1; + ssl->options.rpkConfig.preferred_ClientCertTypes[0] + = WOLFSSL_CERT_TYPE_X509; + ssl->options.rpkConfig.preferred_ClientCertTypes[1] + = WOLFSSL_CERT_TYPE_X509; + return WOLFSSL_SUCCESS; + } + + if (!isArrayUnique(buf, bufLen)) + return BAD_FUNC_ARG; + + for (i = 0; i < bufLen; i++){ + if (buf[i] != WOLFSSL_CERT_TYPE_RPK && buf[i] != WOLFSSL_CERT_TYPE_X509) + return BAD_FUNC_ARG; + + ssl->options.rpkConfig.preferred_ClientCertTypes[i] = buf[i]; + } + ssl->options.rpkConfig.preferred_ClientCertTypeCnt = bufLen; + + return WOLFSSL_SUCCESS; +} + +/* Set user preference for the server_cert_type exetnsion. + * Takes byte array containing cert types the caller can provide to its peer. + * Cert types are in preferred order in the array. + */ +WOLFSSL_API int wolfSSL_set_server_cert_type(WOLFSSL* ssl, + const char* buf, int bufLen) +{ + int i; + + if (ssl == NULL || bufLen > MAX_SERVER_CERT_TYPE_CNT) { + return BAD_FUNC_ARG; + } + + /* if buf is set to NULL or bufLen is set to zero, it defaults the setting*/ + if (buf == NULL || bufLen == 0) { + ssl->options.rpkConfig.preferred_ServerCertTypeCnt = 1; + ssl->options.rpkConfig.preferred_ServerCertTypes[0] + = WOLFSSL_CERT_TYPE_X509; + ssl->options.rpkConfig.preferred_ServerCertTypes[1] + = WOLFSSL_CERT_TYPE_X509; + return WOLFSSL_SUCCESS; + } + + if (!isArrayUnique(buf, bufLen)) + return BAD_FUNC_ARG; + + for (i = 0; i < bufLen; i++){ + if (buf[i] != WOLFSSL_CERT_TYPE_RPK && buf[i] != WOLFSSL_CERT_TYPE_X509) + return BAD_FUNC_ARG; + + ssl->options.rpkConfig.preferred_ServerCertTypes[i] = buf[i]; + } + ssl->options.rpkConfig.preferred_ServerCertTypeCnt = bufLen; + + return WOLFSSL_SUCCESS; +} + +/* get negotiated certificate type value and return it to the second parameter. + * cert type value: + * -1: WOLFSSL_CERT_TYPE_UNKNOWN + * 0: WOLFSSL_CERT_TYPE_X509 + * 2: WOLFSSL_CERT_TYPE_RPK + * return WOLFSSL_SUCCESS on success, otherwise negative value. + * in case no negotiation performed, it returns WOLFSSL_SUCCESS and -1 is for + * cert type. + */ +WOLFSSL_API int wolfSSL_get_negotiated_client_cert_type(WOLFSSL* ssl, int* tp) +{ + int ret = WOLFSSL_SUCCESS; + + if (ssl == NULL || tp == NULL) + return BAD_FUNC_ARG; + + if (ssl->options.side == WOLFSSL_CLIENT_END) { + if (ssl->options.rpkState.received_ClientCertTypeCnt == 1) + *tp = ssl->options.rpkState.received_ClientCertTypes[0]; + else + *tp = WOLFSSL_CERT_TYPE_UNKNOWN; + } + else { + if (ssl->options.rpkState.sending_ClientCertTypeCnt == 1) + *tp = ssl->options.rpkState.sending_ClientCertTypes[0]; + else + *tp = WOLFSSL_CERT_TYPE_UNKNOWN; + } + return ret; +} + +/* get negotiated certificate type value and return it to the second parameter. + * cert type value: + * -1: WOLFSSL_CERT_TYPE_UNKNOWN + * 0: WOLFSSL_CERT_TYPE_X509 + * 2: WOLFSSL_CERT_TYPE_RPK + * return WOLFSSL_SUCCESS on success, otherwise negative value. + * in case no negotiation performed, it returns WOLFSSL_SUCCESS and -1 is for + * cert type. + */ +WOLFSSL_API int wolfSSL_get_negotiated_server_cert_type(WOLFSSL* ssl, int* tp) +{ + int ret = WOLFSSL_SUCCESS; + + if (ssl == NULL || tp == NULL) + return BAD_FUNC_ARG; + + if (ssl->options.side == WOLFSSL_CLIENT_END) { + if (ssl->options.rpkState.received_ServerCertTypeCnt == 1) + *tp = ssl->options.rpkState.received_ServerCertTypes[0]; + else + *tp = WOLFSSL_CERT_TYPE_UNKNOWN; + } + else { + if (ssl->options.rpkState.sending_ServerCertTypeCnt == 1) + *tp = ssl->options.rpkState.sending_ServerCertTypes[0]; + else + *tp = WOLFSSL_CERT_TYPE_UNKNOWN; + } + return ret; +} + +#endif /* HAVE_RPK */ + int wolfSSL_use_certificate_ASN1(WOLFSSL* ssl, const unsigned char* der, int derSz) { diff --git a/src/tls.c b/src/tls.c index 3a9ef7a57..26e25bf94 100644 --- a/src/tls.c +++ b/src/tls.c @@ -10729,6 +10729,497 @@ static int TLSX_QuicTP_Parse(WOLFSSL *ssl, const byte *input, size_t len, int ex #define CID_FREE(a, b) 0 #endif /* defined(WOLFSSL_DTLS_CID) */ +#if defined(HAVE_RPK) +/******************************************************************************/ +/* Client_Certificate_Type extension */ +/******************************************************************************/ +/* return 1 if specified type is included in the given list, otherwise 0 */ +static int IsCertTypeListed(byte type, byte cnt, const byte* list) +{ + int ret = 0; + int i; + + if (cnt == 0 || list == NULL) + return ret; + + if (cnt > 0 && cnt <= MAX_CLIENT_CERT_TYPE_CNT) { + for (i = 0; i < cnt; i++) { + if (list[i] == type) + return 1; + } + } + return 0; +} + +/* Search both arrays from above to find a common value between the two given + * arrays(a and b). return 1 if it finds a common value, otherwise return 0. + */ +static int GetCommonItem(const byte* a, byte aLen, const byte* b, byte bLen, + byte* type) +{ + int i, j; + + if (a == NULL || b == NULL) + return 0; + + for (i = 0; i < aLen; i++) { + for (j = 0; j < bLen; j++) { + if (a[i] == b[j]) { + *type = a[i]; + return 1; + } + } + } + return 0; +} + +/* Creates a "client certificate type" extension if necessary. + * Returns 0 if no error occured, negative value otherwise. + * A return of 0, it does not indicae that the extension was created. + */ +static int TLSX_ClientCertificateType_Use(WOLFSSL* ssl, byte isServer) +{ + int ret = 0; + + if (ssl == NULL) + return BAD_FUNC_ARG; + + if (isServer) { + /* [in server side] + */ + + if (IsCertTypeListed(WOLFSSL_CERT_TYPE_RPK, + ssl->options.rpkConfig.preferred_ClientCertTypeCnt, + ssl->options.rpkConfig.preferred_ClientCertTypes)) { + + WOLFSSL_MSG("Adding Client Certificate Type extension"); + ret = TLSX_Push(&ssl->extensions, TLSX_CLIENT_CERTIFICATE_TYPE, ssl, + ssl->heap); + if (ret == 0) { + TLSX_SetResponse(ssl, TLSX_CLIENT_CERTIFICATE_TYPE); + } + } + } + else { + /* [in client side] + * This extension MUST be omitted from the ClientHello unless the RPK + * certificate is preferred by the user and actually loaded. + */ + + if (IsCertTypeListed(WOLFSSL_CERT_TYPE_RPK, + ssl->options.rpkConfig.preferred_ClientCertTypeCnt, + ssl->options.rpkConfig.preferred_ClientCertTypes)) { + + if (ssl->options.rpkState.isRPKLoaded) { + + ssl->options.rpkState.sending_ClientCertTypeCnt = 1; + ssl->options.rpkState.sending_ClientCertTypes[0] = + WOLFSSL_CERT_TYPE_RPK; + + /* Push new client_certificate_type extension. */ + WOLFSSL_MSG("Adding Client Certificate Type extension"); + ret = TLSX_Push(&ssl->extensions, TLSX_CLIENT_CERTIFICATE_TYPE, + ssl, ssl->heap); + } + else { + WOLFSSL_MSG("Willing to use RPK cert but not loaded it"); + } + } + else { + WOLFSSL_MSG("No will to use RPK cert"); + } + } + return ret; +} + +/* Parse a "client certificate type" extension received from peer. + * returns 0 on success and other values indicate failure. + */ +static int TLSX_ClientCertificateType_Parse(WOLFSSL* ssl, const byte* input, + word16 length, byte msgType) +{ + byte typeCnt; + int idx = 0; + int ret = 0; + int i; + int populate = 0; + byte cmnType; + + + if (msgType == client_hello) { + /* [parse ClientHello in server end] + * case 1) if peer verify is disabled, this extension must be omitted + * from ServerHello. + * case 2) if user have not set his preference, find X509 in parsed + * result, then populate "Client Certificate Type" extension. + * case 3) if user have not set his preference and X509 isn't included + * in parsed result, send "unsupported certificate" alert. + * case 4) if user have set his preference, find a common cert type + * in users preference and received cert types. + * case 5) if user have set his preference, but no common cert type + * found. + */ + + /* case 1 */ + if (ssl->options.verifyNone) { + return ret; + } + + /* parse extension */ + if (length < OPAQUE8_LEN) + return BUFFER_E; + + typeCnt = input[idx]; + + if (typeCnt > MAX_CLIENT_CERT_TYPE_CNT) + return BUFFER_E; + + if ((typeCnt + 1) * OPAQUE8_LEN != length){ + return BUFFER_E; + } + + ssl->options.rpkState.received_ClientCertTypeCnt = input[idx]; + idx += OPAQUE8_LEN; + + for (i = 0; i < typeCnt; i++) { + ssl->options.rpkState.received_ClientCertTypes[i] = input[idx]; + idx += OPAQUE8_LEN; + } + + if (ssl->options.rpkConfig.preferred_ClientCertTypeCnt == 0) { + /* case 2 */ + if (IsCertTypeListed(WOLFSSL_CERT_TYPE_X509, + ssl->options.rpkState.received_ClientCertTypeCnt, + ssl->options.rpkState.received_ClientCertTypes)) { + + ssl->options.rpkState.sending_ClientCertTypeCnt = 1; + ssl->options.rpkState.sending_ClientCertTypes[0] = + WOLFSSL_CERT_TYPE_X509; + populate = 1; + } + /* case 3 */ + else { + WOLFSSL_MSG("No common cert type found in client_certificate_type ext"); + SendAlert(ssl, alert_fatal, unsupported_certificate); + return UNSUPPORTED_CERTIFICATE; + } + } + else if (ssl->options.rpkConfig.preferred_ClientCertTypeCnt > 0) { + /* case 4 */ + if (GetCommonItem( + ssl->options.rpkConfig.preferred_ClientCertTypes, + ssl->options.rpkConfig.preferred_ClientCertTypeCnt, + ssl->options.rpkState.received_ClientCertTypes, + ssl->options.rpkState.received_ClientCertTypeCnt, + &cmnType)) { + ssl->options.rpkState.sending_ClientCertTypeCnt = 1; + ssl->options.rpkState.sending_ClientCertTypes[0] = cmnType; + populate = 1; + } + /* case 5 */ + else { + WOLFSSL_MSG("No common cert type found in client_certificate_type ext"); + SendAlert(ssl, alert_fatal, unsupported_certificate); + return UNSUPPORTED_CERTIFICATE; + } + } + + /* populate client_certificate_type extension */ + if (populate) { + WOLFSSL_MSG("Adding Client Certificate Type extension"); + ret = TLSX_Push(&ssl->extensions, TLSX_CLIENT_CERTIFICATE_TYPE, ssl, + ssl->heap); + if (ret == 0) { + TLSX_SetResponse(ssl, TLSX_CLIENT_CERTIFICATE_TYPE); + } + } + } + else if (msgType == server_hello || msgType == encrypted_extensions) { + /* parse it in client side */ + if (length == 1) { + ssl->options.rpkState.received_ClientCertTypeCnt = 1; + ssl->options.rpkState.received_ClientCertTypes[0] = *input; + } + else { + return BUFFER_E; + } + } + + return ret; +} + +/* Write out the "client certificate type" extension data into the given buffer. + * return the size wrote in the buffer on success, negative value on error. + */ +static word16 TLSX_ClientCertificateType_Write(void* data, byte* output, + byte msgType) +{ + WOLFSSL* ssl = (WOLFSSL*)data; + word16 idx = 0; + byte cnt = 0; + int i; + + /* skip to write extension if count is zero */ + cnt = ssl->options.rpkState.sending_ClientCertTypeCnt; + + if (cnt == 0) + return 0; + + if (msgType == client_hello) { + /* client side */ + + *(output + idx) = cnt; + idx += OPAQUE8_LEN; + + for (i = 0; i < cnt; i++) { + *(output + idx) = ssl->options.rpkState.sending_ClientCertTypes[i]; + idx += OPAQUE8_LEN; + } + return idx; + } + else if (msgType == server_hello || msgType == encrypted_extensions) { + /* sever side */ + if (cnt == 1) { + *(output + idx) = ssl->options.rpkState.sending_ClientCertTypes[0]; + idx += OPAQUE8_LEN; + } + } + return idx; +} + +/* Calculate then return the size of the "client certificate type" extension + * data. + * return the extension data size on success, negative value on error. +*/ +static int TLSX_ClientCertificateType_GetSize(WOLFSSL* ssl, byte msgType) +{ + int ret = 0; + byte cnt; + + if (ssl == NULL) + return BAD_FUNC_ARG; + + if (msgType == client_hello) { + /* client side */ + cnt = ssl->options.rpkState.sending_ClientCertTypeCnt; + ret = (int)(OPAQUE8_LEN + cnt * OPAQUE8_LEN); + } + else if (msgType == server_hello || msgType == encrypted_extensions) { + /* sever side */ + cnt = ssl->options.rpkState.sending_ClientCertTypeCnt;/* must be one */ + ret = OPAQUE8_LEN; + } + else { + return SANITY_MSG_E; + } + return ret; +} + + #define CCT_GET_SIZE TLSX_ClientCertificateType_GetSize + #define CCT_WRITE TLSX_ClientCertificateType_Write + #define CCT_PARSE TLSX_ClientCertificateType_Parse +#else + #define CCT_GET_SIZE(a) 0 + #define CCT_WRITE(a, b) 0 + #define CCT_PARSE(a, b, c, d) 0 +#endif /* HAVE_RPK */ + +#if defined(HAVE_RPK) +/******************************************************************************/ +/* Server_Certificate_Type extension */ +/******************************************************************************/ +/* Creates a "server certificate type" extension if necessary. + * Returns 0 if no error occured, negative value otherwise. + * A return of 0, it does not indicae that the extension was created. + */ +static int TLSX_ServerCertificateType_Use(WOLFSSL* ssl, byte isServer) +{ + int ret = 0; + byte ctype; + + if (ssl == NULL) + return BAD_FUNC_ARG; + + if (isServer) { + /* [in server side] */ + /* find common cert type to both end */ + if (GetCommonItem( + ssl->options.rpkConfig.preferred_ServerCertTypes, + ssl->options.rpkConfig.preferred_ServerCertTypeCnt, + ssl->options.rpkState.received_ServerCertTypes, + ssl->options.rpkState.received_ServerCertTypeCnt, + &ctype)) { + ssl->options.rpkState.sending_ServerCertTypeCnt = 1; + ssl->options.rpkState.sending_ServerCertTypes[0] = ctype; + + /* Push new server_certificate_type extension. */ + WOLFSSL_MSG("Adding Server Certificate Type extension"); + ret = TLSX_Push(&ssl->extensions, TLSX_SERVER_CERTIFICATE_TYPE, ssl, + ssl->heap); + if (ret == 0) { + TLSX_SetResponse(ssl, TLSX_SERVER_CERTIFICATE_TYPE); + } + } + else { + /* no common cert type found */ + WOLFSSL_MSG("No common cert type found in server_certificate_type ext"); + SendAlert(ssl, alert_fatal, unsupported_certificate); + ret = UNSUPPORTED_CERTIFICATE; + } + } + else { + /* [in client side] */ + if (IsCertTypeListed(WOLFSSL_CERT_TYPE_RPK, + ssl->options.rpkConfig.preferred_ServerCertTypeCnt, + ssl->options.rpkConfig.preferred_ServerCertTypes)) { + + ssl->options.rpkState.sending_ServerCertTypeCnt = + ssl->options.rpkConfig.preferred_ServerCertTypeCnt; + XMEMCPY(ssl->options.rpkState.sending_ServerCertTypes, + ssl->options.rpkConfig.preferred_ServerCertTypes, + ssl->options.rpkConfig.preferred_ServerCertTypeCnt); + + /* Push new server_certificate_type extension. */ + WOLFSSL_MSG("Adding Server Certificate Type extension"); + ret = TLSX_Push(&ssl->extensions, TLSX_SERVER_CERTIFICATE_TYPE, ssl, + ssl->heap); + } + else { + WOLFSSL_MSG("No will to accept RPK cert"); + } + } + + return ret; +} + +/* Parse a "server certificate type" extension received from peer. + * returns 0 on success and other values indicate failure. + */ +static int TLSX_ServerCertificateType_Parse(WOLFSSL* ssl, const byte* input, + word16 length, byte msgType) +{ + byte typeCnt; + int idx = 0; + int ret = 0; + int i; + + if (msgType == client_hello) { + /* in server side */ + + if (length < OPAQUE8_LEN) + return BUFFER_E; + + typeCnt = input[idx]; + + if (typeCnt > MAX_SERVER_CERT_TYPE_CNT) + return BUFFER_E; + + if ((typeCnt + 1) * OPAQUE8_LEN != length){ + return BUFFER_E; + } + ssl->options.rpkState.received_ServerCertTypeCnt = input[idx]; + idx += OPAQUE8_LEN; + + for (i = 0; i < typeCnt; i++) { + ssl->options.rpkState.received_ServerCertTypes[i] = input[idx]; + idx += OPAQUE8_LEN; + } + + ret = TLSX_ServerCertificateType_Use(ssl, 1); + if (ret == 0) { + TLSX_SetResponse(ssl, TLSX_SERVER_CERTIFICATE_TYPE); + } + } + else if (msgType == server_hello || msgType == encrypted_extensions) { + /* in client side */ + if (length != 1) /* length slould be 1 */ + return BUFFER_E; + + ssl->options.rpkState.received_ServerCertTypeCnt = 1; + ssl->options.rpkState.received_ServerCertTypes[0] = *input; + } + + return 0; +} + +/* Write out the "server certificate type" extension data into the given buffer. + * return the size wrote in the buffer on success, negative value on error. + */ +static word16 TLSX_ServerCertificateType_Write(void* data, byte* output, + byte msgType) +{ + WOLFSSL* ssl = (WOLFSSL*)data; + word16 idx = 0; + int cnt = 0; + int i; + + /* skip to write extension if count is zero */ + cnt = ssl->options.rpkState.sending_ServerCertTypeCnt; + + if (cnt == 0) + return 0; + + if (msgType == client_hello) { + /* in client side */ + + *(output + idx) = cnt; + idx += OPAQUE8_LEN; + + for (i = 0; i < cnt; i++) { + *(output + idx) = ssl->options.rpkState.sending_ServerCertTypes[i]; + idx += OPAQUE8_LEN; + } + } + else if (msgType == server_hello || msgType == encrypted_extensions) { + /* in server side */ + /* ensure cnt is one */ + if (cnt != 1) + return 0; + + *(output + idx) = ssl->options.rpkState.sending_ServerCertTypes[0]; + idx += OPAQUE8_LEN; + } + return idx; +} + +/* Calculate then return the size of the "server certificate type" extension + * data. + * return the extension data size on success, negative value on error. +*/ +static int TLSX_ServerCertificateType_GetSize(WOLFSSL* ssl, byte msgType) +{ + int ret = 0; + int cnt; + + if (ssl == NULL) + return BAD_FUNC_ARG; + + if (msgType == client_hello) { + /* in clent side */ + cnt = ssl->options.rpkState.sending_ServerCertTypeCnt; + if (cnt > 0) { + ret = (int)(OPAQUE8_LEN + cnt * OPAQUE8_LEN); + } + } + else if (msgType == server_hello || msgType == encrypted_extensions) { + /* in server side */ + ret = (int)OPAQUE8_LEN; + } + else { + return SANITY_MSG_E; + } + return ret; +} + + #define SCT_GET_SIZE TLSX_ServerCertificateType_GetSize + #define SCT_WRITE TLSX_ServerCertificateType_Write + #define SCT_PARSE TLSX_ServerCertificateType_Parse +#else + #define SCT_GET_SIZE(a) 0 + #define SCT_WRITE(a, b) 0 + #define SCT_PARSE(a, b, c, d) 0 +#endif /* HAVE_RPK */ + /******************************************************************************/ /* TLS Extensions Framework */ /******************************************************************************/ @@ -11468,6 +11959,13 @@ void TLSX_FreeAll(TLSX* list, void* heap) switch (extension->type) { +#if defined(HAVE_RPK) + case TLSX_CLIENT_CERTIFICATE_TYPE: + case TLSX_SERVER_CERTIFICATE_TYPE: + /* nothing to do */ + break; +#endif + #ifdef HAVE_SNI case TLSX_SERVER_NAME: SNI_FREE_ALL((SNI*)extension->data, heap); @@ -11751,6 +12249,16 @@ static int TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType, break; #endif +#ifdef HAVE_RPK + case TLSX_CLIENT_CERTIFICATE_TYPE: + length += CCT_GET_SIZE((WOLFSSL*)extension->data, msgType); + break; + + case TLSX_SERVER_CERTIFICATE_TYPE: + length += SCT_GET_SIZE((WOLFSSL*)extension->data, msgType); + break; +#endif /* HAVE_RPK */ + #ifdef WOLFSSL_QUIC case TLSX_KEY_QUIC_TP_PARAMS: FALL_THROUGH; /* followed by */ @@ -11962,6 +12470,19 @@ static int TLSX_Write(TLSX* list, byte* output, byte* semaphore, offset += SRTP_WRITE((TlsxSrtp*)extension->data, output+offset); break; #endif + +#ifdef HAVE_RPK + case TLSX_CLIENT_CERTIFICATE_TYPE: + WOLFSSL_MSG("Client Certificate Type extension to write"); + offset += CCT_WRITE(extension->data, output + offset, msgType); + break; + + case TLSX_SERVER_CERTIFICATE_TYPE: + WOLFSSL_MSG("Server Certificate Type extension to write"); + offset += SCT_WRITE(extension->data, output + offset, msgType); + break; +#endif /* HAVE_RPK */ + #ifdef WOLFSSL_QUIC case TLSX_KEY_QUIC_TP_PARAMS: FALL_THROUGH; @@ -12258,6 +12779,16 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) /* server will add extension depending on what is parsed from client */ if (!isServer) { +#if defined(HAVE_RPK) + ret = TLSX_ClientCertificateType_Use(ssl, isServer); + if (ret != 0) + return ret; + + ret = TLSX_ServerCertificateType_Use(ssl, isServer); + if (ret != 0) + return ret; +#endif /* HAVE_RPK */ + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) if (!ssl->options.disallowEncThenMac) { ret = TLSX_EncryptThenMac_Use(ssl); @@ -14080,6 +14611,17 @@ int TLSX_Parse(WOLFSSL* ssl, const byte* input, word16 length, byte msgType, break; #endif /* defined(WOLFSSL_DTLS_CID) */ +#if defined(HAVE_RPK) + case TLSX_CLIENT_CERTIFICATE_TYPE: + WOLFSSL_MSG("Client Certificate Type extension received"); + ret = CCT_PARSE(ssl, input + offset, size, msgType); + break; + + case TLSX_SERVER_CERTIFICATE_TYPE: + WOLFSSL_MSG("Server Certificate Type extension received"); + ret = SCT_PARSE(ssl, input + offset, size, msgType); + break; +#endif /* HAVE_RPK */ #if defined(WOLFSSL_TLS13) && defined(HAVE_ECH) case TLSX_ECH: ret = ECH_PARSE(ssl, input + offset, size, msgType); diff --git a/tests/api.c b/tests/api.c index 8e2345580..62a8231e8 100644 --- a/tests/api.c +++ b/tests/api.c @@ -62545,6 +62545,1019 @@ static int test_override_alt_cert_chain(void) } #endif +#if defined(HAVE_RPK) + +#define svrRpkCertFile "./certs/rpk/server-cert-rpk.der" +#define clntRpkCertFile "./certs/rpk/client-cert-rpk.der" + +#if defined(WOLFSSL_ALWAYS_VERIFY_CB) +static int MyRpkVerifyCb(int mode, WOLFSSL_X509_STORE_CTX* strctx) +{ + int ret = WOLFSSL_SUCCESS; + (void)mode; + (void)strctx; + WOLFSSL_ENTER("MyRpkVerifyCb"); + return ret; +} +#endif /* WOLFSSL_ALWAYS_VERIFY_CB */ + +static WC_INLINE int test_rpk_memio_setup( + struct test_memio_ctx *ctx, + WOLFSSL_CTX **ctx_c, + WOLFSSL_CTX **ctx_s, + WOLFSSL **ssl_c, + WOLFSSL **ssl_s, + method_provider method_c, + method_provider method_s, + const char* certfile_c, int fmt_cc, /* client cert file path and format */ + const char* certfile_s, int fmt_cs, /* server cert file path and format */ + const char* pkey_c, int fmt_kc, /* client private key and format */ + const char* pkey_s, int fmt_ks /* server private key and format */ + ) +{ + int ret; + if (ctx_c != NULL && *ctx_c == NULL) { + *ctx_c = wolfSSL_CTX_new(method_c()); + if (*ctx_c == NULL) { + return -1; + } + wolfSSL_CTX_set_verify(*ctx_c, WOLFSSL_VERIFY_PEER, NULL); + + ret = wolfSSL_CTX_load_verify_locations(*ctx_c, caCertFile, 0); + if (ret != WOLFSSL_SUCCESS) { + return -1; + } + wolfSSL_SetIORecv(*ctx_c, test_memio_read_cb); + wolfSSL_SetIOSend(*ctx_c, test_memio_write_cb); + + ret = wolfSSL_CTX_use_certificate_file(*ctx_c, certfile_c, fmt_cc); + if (ret != WOLFSSL_SUCCESS) { + return -1; + } + ret = wolfSSL_CTX_use_PrivateKey_file(*ctx_c, pkey_c, fmt_kc); + if (ret != WOLFSSL_SUCCESS) { + return -1; + } + } + + if (ctx_s != NULL && *ctx_s == NULL) { + *ctx_s = wolfSSL_CTX_new(method_s()); + if (*ctx_s == NULL) { + return -1; + } + wolfSSL_CTX_set_verify(*ctx_s, WOLFSSL_VERIFY_PEER, NULL); + + ret = wolfSSL_CTX_load_verify_locations(*ctx_s, cliCertFile, 0); + if (ret != WOLFSSL_SUCCESS) { + return -1; + } + + ret = wolfSSL_CTX_use_PrivateKey_file(*ctx_s, pkey_s, fmt_ks); + if (ret != WOLFSSL_SUCCESS) { + return -1; + } + ret = wolfSSL_CTX_use_certificate_file(*ctx_s, certfile_s, fmt_cs); + if (ret != WOLFSSL_SUCCESS) { + return -1; + } + wolfSSL_SetIORecv(*ctx_s, test_memio_read_cb); + wolfSSL_SetIOSend(*ctx_s, test_memio_write_cb); + if (ctx->s_ciphers != NULL) { + ret = wolfSSL_CTX_set_cipher_list(*ctx_s, ctx->s_ciphers); + if (ret != WOLFSSL_SUCCESS) { + return -1; + } + } + } + + if (ctx_c != NULL && ssl_c != NULL) { + *ssl_c = wolfSSL_new(*ctx_c); + if (*ssl_c == NULL) { + return -1; + } + wolfSSL_SetIOWriteCtx(*ssl_c, ctx); + wolfSSL_SetIOReadCtx(*ssl_c, ctx); + } + if (ctx_s != NULL && ssl_s != NULL) { + *ssl_s = wolfSSL_new(*ctx_s); + if (*ssl_s == NULL) { + return -1; + } + wolfSSL_SetIOWriteCtx(*ssl_s, ctx); + wolfSSL_SetIOReadCtx(*ssl_s, ctx); +#if !defined(NO_DH) + SetDH(*ssl_s); +#endif + } + + return 0; +} +#endif /* HAVE_RPK */ + +static int test_rpk_set_xxx_cert_type(void) +{ + EXPECT_DECLS; +#if defined(HAVE_RPK) + + char ctype[MAX_CLIENT_CERT_TYPE_CNT + 1]; /* prepare bigger buffer */ + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + int tp; + + ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()); + ExpectNotNull(ctx); + + ssl = wolfSSL_new(ctx); + ExpectNotNull(ssl); + + /*--------------------------------------------*/ + /* tests for wolfSSL_CTX_set_client_cert_type */ + /*--------------------------------------------*/ + + /* illegal parameter test caces */ + ExpectIntEQ(wolfSSL_CTX_set_client_cert_type(NULL, ctype, + MAX_CLIENT_CERT_TYPE_CNT), + BAD_FUNC_ARG); + + ExpectIntEQ(wolfSSL_CTX_set_client_cert_type(ctx, ctype, + sizeof(ctype)), + BAD_FUNC_ARG); + + ctype[0] = WOLFSSL_CERT_TYPE_RPK; /* set an identical cert type */ + ctype[1] = WOLFSSL_CERT_TYPE_RPK; + + ExpectIntEQ(wolfSSL_CTX_set_client_cert_type(ctx, ctype, + MAX_CLIENT_CERT_TYPE_CNT), + BAD_FUNC_ARG); + + ctype[0] = WOLFSSL_CERT_TYPE_X509; + ctype[1] = 10; /* set unknown cert type */ + + ExpectIntEQ(wolfSSL_CTX_set_client_cert_type(ctx, ctype, + MAX_CLIENT_CERT_TYPE_CNT), + BAD_FUNC_ARG); + /* pass larger type count */ + ctype[0] = WOLFSSL_CERT_TYPE_RPK; + ctype[1] = WOLFSSL_CERT_TYPE_X509; + ctype[2] = 1; /* pass unacceptable type count */ + + ExpectIntEQ(wolfSSL_CTX_set_client_cert_type(ctx, ctype, + MAX_CLIENT_CERT_TYPE_CNT + 1), + BAD_FUNC_ARG); + + /* should accept NULL for type buffer */ + ExpectIntEQ(wolfSSL_CTX_set_client_cert_type(ctx, NULL, + MAX_CLIENT_CERT_TYPE_CNT), + WOLFSSL_SUCCESS); + + /* should accept zero for type count */ + ExpectIntEQ(wolfSSL_CTX_set_client_cert_type(ctx, ctype, + 0), + WOLFSSL_SUCCESS); + + ExpectIntEQ(wolfSSL_CTX_set_client_cert_type(ctx, ctype, + MAX_CLIENT_CERT_TYPE_CNT), + WOLFSSL_SUCCESS); + + /*--------------------------------------------*/ + /* tests for wolfSSL_CTX_set_server_cert_type */ + /*--------------------------------------------*/ + + ExpectIntEQ(wolfSSL_CTX_set_server_cert_type(NULL, ctype, + MAX_SERVER_CERT_TYPE_CNT), + BAD_FUNC_ARG); + + ExpectIntEQ(wolfSSL_CTX_set_server_cert_type(ctx, ctype, + sizeof(ctype)), + BAD_FUNC_ARG); + + ctype[0] = WOLFSSL_CERT_TYPE_RPK; /* set an identical cert type */ + ctype[1] = WOLFSSL_CERT_TYPE_RPK; + + ExpectIntEQ(wolfSSL_CTX_set_server_cert_type(ctx, ctype, + MAX_SERVER_CERT_TYPE_CNT), + BAD_FUNC_ARG); + + ctype[0] = WOLFSSL_CERT_TYPE_X509; + ctype[1] = 10; /* set unknown cert type */ + + ExpectIntEQ(wolfSSL_CTX_set_server_cert_type(ctx, ctype, + MAX_SERVER_CERT_TYPE_CNT), + BAD_FUNC_ARG); + /* pass larger type count */ + ctype[0] = WOLFSSL_CERT_TYPE_RPK; + ctype[1] = WOLFSSL_CERT_TYPE_X509; + ctype[2] = 1; /* pass unacceptable type count */ + + ExpectIntEQ(wolfSSL_CTX_set_server_cert_type(ctx, ctype, + MAX_SERVER_CERT_TYPE_CNT + 1), + BAD_FUNC_ARG); + + /* should accept NULL for type buffer */ + ExpectIntEQ(wolfSSL_CTX_set_server_cert_type(ctx, NULL, + MAX_SERVER_CERT_TYPE_CNT), + WOLFSSL_SUCCESS); + + /* should accept zero for type count */ + ExpectIntEQ(wolfSSL_CTX_set_server_cert_type(ctx, ctype, + 0), + WOLFSSL_SUCCESS); + + ExpectIntEQ(wolfSSL_CTX_set_server_cert_type(ctx, ctype, + MAX_CLIENT_CERT_TYPE_CNT), + WOLFSSL_SUCCESS); + + /*--------------------------------------------*/ + /* tests for wolfSSL_set_client_cert_type */ + /*--------------------------------------------*/ + + ExpectIntEQ(wolfSSL_set_client_cert_type(NULL, ctype, + MAX_CLIENT_CERT_TYPE_CNT), + BAD_FUNC_ARG); + + ExpectIntEQ(wolfSSL_set_client_cert_type(ssl, ctype, + sizeof(ctype)), + BAD_FUNC_ARG); + + ctype[0] = WOLFSSL_CERT_TYPE_RPK; /* set an identical cert type */ + ctype[1] = WOLFSSL_CERT_TYPE_RPK; + + ExpectIntEQ(wolfSSL_set_client_cert_type(ssl, ctype, + MAX_CLIENT_CERT_TYPE_CNT), + BAD_FUNC_ARG); + + ctype[0] = WOLFSSL_CERT_TYPE_X509; + ctype[1] = 10; /* set unknown cert type */ + + ExpectIntEQ(wolfSSL_set_client_cert_type(ssl, ctype, + MAX_CLIENT_CERT_TYPE_CNT), + BAD_FUNC_ARG); + /* pass larger type count */ + ctype[0] = WOLFSSL_CERT_TYPE_RPK; + ctype[1] = WOLFSSL_CERT_TYPE_X509; + ctype[2] = 1; /* pass unacceptable type count */ + + ExpectIntEQ(wolfSSL_set_client_cert_type(ssl, ctype, + MAX_CLIENT_CERT_TYPE_CNT + 1), + BAD_FUNC_ARG); + + /* should accept NULL for type buffer */ + ExpectIntEQ(wolfSSL_set_client_cert_type(ssl, NULL, + MAX_CLIENT_CERT_TYPE_CNT), + WOLFSSL_SUCCESS); + + /* should accept zero for type count */ + ExpectIntEQ(wolfSSL_set_client_cert_type(ssl, ctype, + 0), + WOLFSSL_SUCCESS); + + ExpectIntEQ(wolfSSL_set_client_cert_type(ssl, ctype, + MAX_CLIENT_CERT_TYPE_CNT), + WOLFSSL_SUCCESS); + + /*--------------------------------------------*/ + /* tests for wolfSSL_CTX_set_server_cert_type */ + /*--------------------------------------------*/ + + ExpectIntEQ(wolfSSL_set_server_cert_type(NULL, ctype, + MAX_SERVER_CERT_TYPE_CNT), + BAD_FUNC_ARG); + + ExpectIntEQ(wolfSSL_set_server_cert_type(ssl, ctype, + sizeof(ctype)), + BAD_FUNC_ARG); + + ctype[0] = WOLFSSL_CERT_TYPE_RPK; /* set an identical cert type */ + ctype[1] = WOLFSSL_CERT_TYPE_RPK; + + ExpectIntEQ(wolfSSL_set_server_cert_type(ssl, ctype, + MAX_SERVER_CERT_TYPE_CNT), + BAD_FUNC_ARG); + + ctype[0] = WOLFSSL_CERT_TYPE_X509; + ctype[1] = 10; /* set unknown cert type */ + + ExpectIntEQ(wolfSSL_set_server_cert_type(ssl, ctype, + MAX_SERVER_CERT_TYPE_CNT), + BAD_FUNC_ARG); + /* pass larger type count */ + ctype[0] = WOLFSSL_CERT_TYPE_RPK; + ctype[1] = WOLFSSL_CERT_TYPE_X509; + ctype[2] = 1; /* pass unacceptable type count */ + + ExpectIntEQ(wolfSSL_set_server_cert_type(ssl, ctype, + MAX_SERVER_CERT_TYPE_CNT + 1), + BAD_FUNC_ARG); + + /* should accept NULL for type buffer */ + ExpectIntEQ(wolfSSL_set_server_cert_type(ssl, NULL, + MAX_SERVER_CERT_TYPE_CNT), + WOLFSSL_SUCCESS); + + /* should accept zero for type count */ + ExpectIntEQ(wolfSSL_set_server_cert_type(ssl, ctype, + 0), + WOLFSSL_SUCCESS); + + ExpectIntEQ(wolfSSL_set_server_cert_type(ssl, ctype, + MAX_SERVER_CERT_TYPE_CNT), + WOLFSSL_SUCCESS); + + /*------------------------------------------------*/ + /* tests for wolfSSL_get_negotiated_xxx_cert_type */ + /*------------------------------------------------*/ + + ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(NULL, &tp), + BAD_FUNC_ARG); + + ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl, NULL), + BAD_FUNC_ARG); + + ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(NULL, &tp), + BAD_FUNC_ARG); + + ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl, NULL), + BAD_FUNC_ARG); + + + /* clean up */ + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); + +#endif + return EXPECT_RESULT(); +} + +static int test_tls13_rpk_handshake(void) +{ + EXPECT_DECLS; +#if defined(HAVE_RPK) + int ret = 0; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + int err; + char certType_c[MAX_CLIENT_CERT_TYPE_CNT]; + char certType_s[MAX_CLIENT_CERT_TYPE_CNT]; + int typeCnt_c; + int typeCnt_s; + int tp; + + (void)err; + (void)typeCnt_c; + (void)typeCnt_s; + (void)certType_c; + (void)certType_s; + + /* TLS1.2 + * Both client and server load x509 cert and start handshaking. + * Check no negotiation occurred. + */ + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + ExpectIntEQ( + test_rpk_memio_setup( + &test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_2_client_method, wolfTLSv1_2_server_method, + cliCertFile, WOLFSSL_FILETYPE_PEM, + svrCertFile, WOLFSSL_FILETYPE_PEM, + cliKeyFile, WOLFSSL_FILETYPE_PEM, + svrKeyFile, WOLFSSL_FILETYPE_PEM) + , 0); + + + /* set client certificate type in client end */ + certType_c[0] = WOLFSSL_CERT_TYPE_RPK; + certType_c[1] = WOLFSSL_CERT_TYPE_X509; + typeCnt_c = 2; + + certType_s[0] = WOLFSSL_CERT_TYPE_RPK; + certType_s[1] = WOLFSSL_CERT_TYPE_X509; + typeCnt_s = 2; + + /* both clien and server do not call client/server_cert_type APIs, + * expecting default settings works and no negotiation performed. + */ + + if (test_memio_do_handshake(ssl_c, ssl_s, 10, NULL) != 0) + return TEST_FAIL; + + /* confirm no negotiation occurred */ + ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl_c, &tp), + WOLFSSL_SUCCESS); + ExpectIntEQ((int)tp, WOLFSSL_CERT_TYPE_UNKNOWN); + ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl_c, &tp), + WOLFSSL_SUCCESS); + ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_UNKNOWN); + ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl_s, &tp), + WOLFSSL_SUCCESS); + ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_UNKNOWN); + + ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl_s, &tp), + WOLFSSL_SUCCESS); + ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_UNKNOWN); + + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_s); + ssl_c = ssl_s = NULL; + ctx_c = ctx_s = NULL; + + /* Both client and server load x509 cert and start handshaking. + * Check no negotiation occurred. + */ + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + ExpectIntEQ( + test_rpk_memio_setup( + &test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_3_client_method, wolfTLSv1_3_server_method, + cliCertFile, WOLFSSL_FILETYPE_PEM, + svrCertFile, WOLFSSL_FILETYPE_PEM, + cliKeyFile, WOLFSSL_FILETYPE_PEM, + svrKeyFile, WOLFSSL_FILETYPE_PEM ) + , 0); + + /* set client certificate type in client end */ + certType_c[0] = WOLFSSL_CERT_TYPE_RPK; + certType_c[1] = WOLFSSL_CERT_TYPE_X509; + typeCnt_c = 2; + + certType_s[0] = WOLFSSL_CERT_TYPE_RPK; + certType_s[1] = WOLFSSL_CERT_TYPE_X509; + typeCnt_s = 2; + + /* both clien and server do not call client/server_cert_type APIs, + * expecting default settings works and no negotiation performed. + */ + + if (test_memio_do_handshake(ssl_c, ssl_s, 10, NULL) != 0) + return TEST_FAIL; + + /* confirm no negotiation occurred */ + ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl_c, &tp), + WOLFSSL_SUCCESS); + ExpectIntEQ((int)tp, WOLFSSL_CERT_TYPE_UNKNOWN); + + ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl_c, &tp), + WOLFSSL_SUCCESS); + ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_UNKNOWN); + + ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl_s, &tp), + WOLFSSL_SUCCESS); + ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_UNKNOWN); + + ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl_s, &tp), + WOLFSSL_SUCCESS); + ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_UNKNOWN); + + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_s); + ssl_c = ssl_s = NULL; + ctx_c = ctx_s = NULL; + + + /* Both client and server load RPK cert and start handshaking. + * Confirm negotiated cert types match as expected. + */ + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + ExpectIntEQ( + test_rpk_memio_setup( + &test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_3_client_method, wolfTLSv1_3_server_method, + clntRpkCertFile, WOLFSSL_FILETYPE_ASN1, + svrRpkCertFile, WOLFSSL_FILETYPE_ASN1, + cliKeyFile, WOLFSSL_FILETYPE_PEM, + svrKeyFile, WOLFSSL_FILETYPE_PEM ) + , 0); + + /* set client certificate type in client end */ + certType_c[0] = WOLFSSL_CERT_TYPE_RPK; + certType_c[1] = WOLFSSL_CERT_TYPE_X509; + typeCnt_c = 2; + + certType_s[0] = WOLFSSL_CERT_TYPE_RPK; + certType_s[1] = WOLFSSL_CERT_TYPE_X509; + typeCnt_s = 2; + + ExpectIntEQ(wolfSSL_set_client_cert_type(ssl_c, certType_c, typeCnt_c), + WOLFSSL_SUCCESS); + + /* set server certificate type in client end */ + ExpectIntEQ(wolfSSL_set_server_cert_type(ssl_c, certType_s, typeCnt_s), + WOLFSSL_SUCCESS); + + /* set client certificate type in server end */ + ExpectIntEQ(wolfSSL_set_client_cert_type(ssl_s, certType_c, typeCnt_c), + WOLFSSL_SUCCESS); + + /* set server certificate type in server end */ + ExpectIntEQ(wolfSSL_set_server_cert_type(ssl_s, certType_s, typeCnt_s), + WOLFSSL_SUCCESS); + + if (test_memio_do_handshake(ssl_c, ssl_s, 10, NULL) != 0) + return TEST_FAIL; + + ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl_c, &tp), + WOLFSSL_SUCCESS); + ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_RPK); + + ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl_c, &tp), + WOLFSSL_SUCCESS); + ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_RPK); + + ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl_s, &tp), + WOLFSSL_SUCCESS); + ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_RPK); + + ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl_s, &tp), + WOLFSSL_SUCCESS); + ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_RPK); + + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_s); + ssl_c = ssl_s = NULL; + ctx_c = ctx_s = NULL; + + + /* TLS1.2 + * Both client and server load RPK cert and start handshaking. + * Confirm negotiated cert types match as expected. + */ + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + ExpectIntEQ( + test_rpk_memio_setup( + &test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_2_client_method, wolfTLSv1_2_server_method, + clntRpkCertFile, WOLFSSL_FILETYPE_ASN1, + svrRpkCertFile, WOLFSSL_FILETYPE_ASN1, + cliKeyFile, WOLFSSL_FILETYPE_PEM, + svrKeyFile, WOLFSSL_FILETYPE_PEM ) + , 0); + + /* set client certificate type in client end */ + certType_c[0] = WOLFSSL_CERT_TYPE_RPK; + certType_c[1] = WOLFSSL_CERT_TYPE_X509; + typeCnt_c = 2; + + certType_s[0] = WOLFSSL_CERT_TYPE_RPK; + certType_s[1] = WOLFSSL_CERT_TYPE_X509; + typeCnt_s = 2; + + ExpectIntEQ(wolfSSL_set_client_cert_type(ssl_c, certType_c, typeCnt_c), + WOLFSSL_SUCCESS); + + /* set server certificate type in client end */ + ExpectIntEQ(wolfSSL_set_server_cert_type(ssl_c, certType_s, typeCnt_s), + WOLFSSL_SUCCESS); + + /* set client certificate type in server end */ + ExpectIntEQ(wolfSSL_set_client_cert_type(ssl_s, certType_c, typeCnt_c), + WOLFSSL_SUCCESS); + + /* set server certificate type in server end */ + ExpectIntEQ(wolfSSL_set_server_cert_type(ssl_s, certType_s, typeCnt_s), + WOLFSSL_SUCCESS); + + if (test_memio_do_handshake(ssl_c, ssl_s, 10, NULL) != 0) + return TEST_FAIL; + + ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl_c, &tp), + WOLFSSL_SUCCESS); + ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_RPK); + + ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl_c, &tp), + WOLFSSL_SUCCESS); + ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_RPK); + + ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl_s, &tp), + WOLFSSL_SUCCESS); + ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_RPK); + + ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl_s, &tp), + WOLFSSL_SUCCESS); + ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_RPK); + + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_s); + ssl_c = ssl_s = NULL; + ctx_c = ctx_s = NULL; + + + /* Both client and server load x509 cert. + * Have client call set_client_cert_type with both RPK and x509. + * This doesn't makes client add client cert type extension to ClientHello, + * since it does not load RPK cert actually. + */ + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + ExpectIntEQ( + test_rpk_memio_setup( + &test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_3_client_method, wolfTLSv1_3_server_method, + cliCertFile, WOLFSSL_FILETYPE_PEM, + svrCertFile, WOLFSSL_FILETYPE_PEM, + cliKeyFile, WOLFSSL_FILETYPE_PEM, + svrKeyFile, WOLFSSL_FILETYPE_PEM ) + , 0); + + /* set client certificate type in client end */ + certType_c[0] = WOLFSSL_CERT_TYPE_RPK; + certType_c[1] = WOLFSSL_CERT_TYPE_X509; + typeCnt_c = 2; + + /* client indicates both RPK and x509 certs are available but loaded RPK + * cert only. It does not have client add client-cert-type extension in CH. + */ + certType_c[0] = WOLFSSL_CERT_TYPE_RPK; + certType_c[1] = WOLFSSL_CERT_TYPE_X509; + typeCnt_c = 2; + + ExpectIntEQ(wolfSSL_set_client_cert_type(ssl_c, certType_c, typeCnt_c), + WOLFSSL_SUCCESS); + + /* client indicates both RPK and x509 certs are acceptable */ + certType_s[0] = WOLFSSL_CERT_TYPE_RPK; + certType_s[1] = WOLFSSL_CERT_TYPE_X509; + typeCnt_s = 2; + + ExpectIntEQ(wolfSSL_set_server_cert_type(ssl_c, certType_s, typeCnt_s), + WOLFSSL_SUCCESS); + + /* server indicates both RPK and x509 certs are acceptable */ + certType_c[0] = WOLFSSL_CERT_TYPE_RPK; + certType_c[1] = WOLFSSL_CERT_TYPE_X509; + typeCnt_c = 2; + + ExpectIntEQ(wolfSSL_set_client_cert_type(ssl_s, certType_c, typeCnt_c), + WOLFSSL_SUCCESS); + + /* server should indicate only RPK cert is available */ + certType_s[0] = WOLFSSL_CERT_TYPE_X509; + certType_s[1] = -1; + typeCnt_s = 1; + + ExpectIntEQ(wolfSSL_set_server_cert_type(ssl_s, certType_s, typeCnt_s), + WOLFSSL_SUCCESS); + + if (test_memio_do_handshake(ssl_c, ssl_s, 10, NULL) != 0) + return TEST_FAIL; + + /* Negotiation for client-cert-type should NOT happen. Therefore -1 should + * be returned as cert type. + */ + ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl_c, &tp), + WOLFSSL_SUCCESS); + ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_UNKNOWN); + + ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl_c, &tp), + WOLFSSL_SUCCESS); + ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_X509); + + ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl_s, &tp), + WOLFSSL_SUCCESS); + ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_UNKNOWN); + + ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl_s, &tp), + WOLFSSL_SUCCESS); + ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_X509); + + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_s); + ssl_c = ssl_s = NULL; + ctx_c = ctx_s = NULL; + + + /* Have client load RPK cert and have server load x509 cert. + * Check the negotiation result from both ends. + */ + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + ExpectIntEQ( + test_rpk_memio_setup( + &test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_3_client_method, wolfTLSv1_3_server_method, + clntRpkCertFile, WOLFSSL_FILETYPE_ASN1, + svrCertFile, WOLFSSL_FILETYPE_PEM, + cliKeyFile, WOLFSSL_FILETYPE_PEM, + svrKeyFile, WOLFSSL_FILETYPE_PEM ) + , 0); + + /* have client tell to use RPK cert */ + certType_c[0] = WOLFSSL_CERT_TYPE_RPK; + certType_c[1] = -1; + typeCnt_c = 1; + + ExpectIntEQ(wolfSSL_set_client_cert_type(ssl_c, certType_c, typeCnt_c), + WOLFSSL_SUCCESS); + + /* have client tell to accept both RPK and x509 cert */ + certType_s[0] = WOLFSSL_CERT_TYPE_X509; + certType_s[1] = WOLFSSL_CERT_TYPE_RPK; + typeCnt_s = 2; + + ExpectIntEQ(wolfSSL_set_server_cert_type(ssl_c, certType_s, typeCnt_s), + WOLFSSL_SUCCESS); + + /* have server accept to both RPK and x509 cert */ + certType_c[0] = WOLFSSL_CERT_TYPE_X509; + certType_c[1] = WOLFSSL_CERT_TYPE_RPK; + typeCnt_c = 2; + + ExpectIntEQ(wolfSSL_set_client_cert_type(ssl_s, certType_c, typeCnt_c), + WOLFSSL_SUCCESS); + + /* does not call wolfSSL_set_server_cert_type intentionally in sesrver + * end, expecting the default setting works. + */ + + + if (test_memio_do_handshake(ssl_c, ssl_s, 10, NULL) != 0) + return TEST_FAIL; + + ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl_c, &tp), + WOLFSSL_SUCCESS); + ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_RPK); + + ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl_c, &tp), + WOLFSSL_SUCCESS); + ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_X509); + + ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl_s, &tp), + WOLFSSL_SUCCESS); + ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_RPK); + + ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl_s, &tp), + WOLFSSL_SUCCESS); + ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_X509); + + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_s); + ssl_c = ssl_s = NULL; + ctx_c = ctx_s = NULL; + + + /* Have both client and server load RPK cert, however, have server + * indicate its cert type x509. + * Client is expected to detect the cert type mismatch then to send alert + * with "unsupported_certificate". + */ + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + ExpectIntEQ( + test_rpk_memio_setup( + &test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_3_client_method, wolfTLSv1_3_server_method, + clntRpkCertFile, WOLFSSL_FILETYPE_ASN1, + svrRpkCertFile, WOLFSSL_FILETYPE_ASN1, /* server sends RPK cert */ + cliKeyFile, WOLFSSL_FILETYPE_PEM, + svrKeyFile, WOLFSSL_FILETYPE_PEM ) + , 0); + + /* have client tell to use RPK cert */ + certType_c[0] = WOLFSSL_CERT_TYPE_RPK; + certType_c[1] = -1; + typeCnt_c = 1; + + ExpectIntEQ(wolfSSL_set_client_cert_type(ssl_c, certType_c, typeCnt_c), + WOLFSSL_SUCCESS); + + /* have client tell to accept both RPK and x509 cert */ + certType_s[0] = WOLFSSL_CERT_TYPE_X509; + certType_s[1] = WOLFSSL_CERT_TYPE_RPK; + typeCnt_s = 2; + + ExpectIntEQ(wolfSSL_set_server_cert_type(ssl_c, certType_s, typeCnt_s), + WOLFSSL_SUCCESS); + + /* have server accept to both RPK and x509 cert */ + certType_c[0] = WOLFSSL_CERT_TYPE_X509; + certType_c[1] = WOLFSSL_CERT_TYPE_RPK; + typeCnt_c = 2; + + ExpectIntEQ(wolfSSL_set_client_cert_type(ssl_s, certType_c, typeCnt_c), + WOLFSSL_SUCCESS); + + /* have server tell to use x509 cert intensionally. This will bring + * certificate type mismatch in client side. + */ + certType_s[0] = WOLFSSL_CERT_TYPE_X509; + certType_s[1] = -1; + typeCnt_s = 1; + + ExpectIntEQ(wolfSSL_set_server_cert_type(ssl_s, certType_s, typeCnt_s), + WOLFSSL_SUCCESS); + + /* expect client detect cert type mismatch then send Alert */ + ret = test_memio_do_handshake(ssl_c, ssl_s, 10, NULL); + if (ret != -1) + return TEST_FAIL; + + ExpectIntEQ(wolfSSL_get_error(ssl_c, ret), UNSUPPORTED_CERTIFICATE); + + ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl_c, &tp), + WOLFSSL_SUCCESS); + ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_RPK); + + ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl_c, &tp), + WOLFSSL_SUCCESS); + ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_X509); + + ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl_s, &tp), + WOLFSSL_SUCCESS); + ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_RPK); + + ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl_s, &tp), + WOLFSSL_SUCCESS); + ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_X509); + + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_s); + ssl_c = ssl_s = NULL; + ctx_c = ctx_s = NULL; + + + /* Have client load x509 cert and server load RPK cert, + * however, have client indicate its cert type RPK. + * Server is expected to detect the cert type mismatch then to send alert + * with "unsupported_certificate". + */ + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + ExpectIntEQ( + test_rpk_memio_setup( + &test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_3_client_method, wolfTLSv1_3_server_method, + cliCertFile, WOLFSSL_FILETYPE_PEM, + svrRpkCertFile, WOLFSSL_FILETYPE_ASN1, + cliKeyFile, WOLFSSL_FILETYPE_PEM, + svrKeyFile, WOLFSSL_FILETYPE_PEM ) + , 0); + + /* have client tell to use RPK cert intentionally */ + certType_c[0] = WOLFSSL_CERT_TYPE_RPK; + certType_c[1] = -1; + typeCnt_c = 1; + + ExpectIntEQ(wolfSSL_set_client_cert_type(ssl_c, certType_c, typeCnt_c), + WOLFSSL_SUCCESS); + + /* have client tell to accept both RPK and x509 cert */ + certType_s[0] = WOLFSSL_CERT_TYPE_X509; + certType_s[1] = WOLFSSL_CERT_TYPE_RPK; + typeCnt_s = 2; + + ExpectIntEQ(wolfSSL_set_server_cert_type(ssl_c, certType_s, typeCnt_s), + WOLFSSL_SUCCESS); + + /* have server accept to both RPK and x509 cert */ + certType_c[0] = WOLFSSL_CERT_TYPE_X509; + certType_c[1] = WOLFSSL_CERT_TYPE_RPK; + typeCnt_c = 2; + + ExpectIntEQ(wolfSSL_set_client_cert_type(ssl_s, certType_c, typeCnt_c), + WOLFSSL_SUCCESS); + + /* have server tell to use x509 cert intensionally. This will bring + * certificate type mismatch in client side. + */ + certType_s[0] = WOLFSSL_CERT_TYPE_X509; + certType_s[1] = -1; + typeCnt_s = 1; + + ExpectIntEQ(wolfSSL_set_server_cert_type(ssl_s, certType_s, typeCnt_s), + WOLFSSL_SUCCESS); + + ret = test_memio_do_handshake(ssl_c, ssl_s, 10, NULL); + + /* expect server detect cert type mismatch then send Alert */ + ExpectIntNE(ret, 0); + err = wolfSSL_get_error(ssl_c, ret); + ExpectIntEQ(err, UNSUPPORTED_CERTIFICATE); + + /* client did not load RPK cert actually, so negotiation did not happen */ + ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl_c, &tp), + WOLFSSL_SUCCESS); + ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_UNKNOWN); + + ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl_c, &tp), + WOLFSSL_SUCCESS); + ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_X509); + + /* client did not load RPK cert actually, so negotiation did not happen */ + ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl_s, &tp), + WOLFSSL_SUCCESS); + ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_UNKNOWN); + + ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl_s, &tp), + WOLFSSL_SUCCESS); + ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_X509); + + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_s); + ssl_c = ssl_s = NULL; + ctx_c = ctx_s = NULL; + + +#if defined(WOLFSSL_ALWAYS_VERIFY_CB) + /* Both client and server load RPK cert and set certificate vefiry + * callbacks then start handshaking. + * Confirm both side can refer the peer's cert. + */ + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + ExpectIntEQ( + test_rpk_memio_setup( + &test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_3_client_method, wolfTLSv1_3_server_method, + clntRpkCertFile, WOLFSSL_FILETYPE_ASN1, + svrRpkCertFile, WOLFSSL_FILETYPE_ASN1, + cliKeyFile, WOLFSSL_FILETYPE_PEM, + svrKeyFile, WOLFSSL_FILETYPE_PEM ) + , 0); + + /* set client certificate type in client end */ + certType_c[0] = WOLFSSL_CERT_TYPE_RPK; + certType_c[1] = WOLFSSL_CERT_TYPE_X509; + typeCnt_c = 2; + + certType_s[0] = WOLFSSL_CERT_TYPE_RPK; + certType_s[1] = WOLFSSL_CERT_TYPE_X509; + typeCnt_s = 2; + + ExpectIntEQ(wolfSSL_set_client_cert_type(ssl_c, certType_c, typeCnt_c), + WOLFSSL_SUCCESS); + + /* set server certificate type in client end */ + ExpectIntEQ(wolfSSL_set_server_cert_type(ssl_c, certType_s, typeCnt_s), + WOLFSSL_SUCCESS); + + /* set client certificate type in server end */ + ExpectIntEQ(wolfSSL_set_client_cert_type(ssl_s, certType_c, typeCnt_c), + WOLFSSL_SUCCESS); + + /* set server certificate type in server end */ + ExpectIntEQ(wolfSSL_set_server_cert_type(ssl_s, certType_s, typeCnt_s), + WOLFSSL_SUCCESS); + + /* set certificate verify callcack to both client and server */ + int isServer = 0; + wolfSSL_SetCertCbCtx(ssl_c, &isServer); + wolfSSL_set_verify(ssl_c, SSL_VERIFY_PEER, MyRpkVerifyCb); + + isServer = 1; + wolfSSL_SetCertCbCtx(ssl_c, &isServer); + wolfSSL_set_verify(ssl_s, SSL_VERIFY_PEER, MyRpkVerifyCb); + + ret = test_memio_do_handshake(ssl_c, ssl_s, 10, NULL); + if (ret != 0) + return TEST_FAIL; + + ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl_c, &tp), + WOLFSSL_SUCCESS); + ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_RPK); + + ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl_c, &tp), + WOLFSSL_SUCCESS); + ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_RPK); + + ExpectIntEQ(wolfSSL_get_negotiated_client_cert_type(ssl_s, &tp), + WOLFSSL_SUCCESS); + ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_RPK); + + ExpectIntEQ(wolfSSL_get_negotiated_server_cert_type(ssl_s, &tp), + WOLFSSL_SUCCESS); + ExpectIntEQ(tp, WOLFSSL_CERT_TYPE_RPK); + + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_s); + ssl_c = ssl_s = NULL; + ctx_c = ctx_s = NULL; +#endif /* WOLFSSL_ALWAYS_VERIFY_CB */ + +#endif /* HAVE_RPK */ + return EXPECT_RESULT(); +} + #if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) @@ -64378,6 +65391,8 @@ TEST_CASE testCases[] = { /* Can't memory test as client/server Asserts. */ TEST_DECL(test_harden_no_secure_renegotiation), TEST_DECL(test_override_alt_cert_chain), + TEST_DECL(test_rpk_set_xxx_cert_type), + TEST_DECL(test_tls13_rpk_handshake), TEST_DECL(test_dtls13_bad_epoch_ch), TEST_DECL(test_short_session_id), TEST_DECL(test_wolfSSL_dtls13_null_cipher), diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 3772382d7..d659d6b22 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -15054,6 +15054,54 @@ static int DecodeCertInternal(DecodedCert* cert, int verify, int* criticalExt, int stopAfterPubKey); #endif +/* Assumes the target is a Raw-Public-Key certificate and parsed up to the + * public key. Returns CRYPTOCB_UNAVAILABLE if it determines that the cert is + * different from the Paw-Public-Key cert. In that case, cert->srcIdx is not + * consumed so as successing parse function can take over. + * In case that the target is Raw-Public-Key cert and contains a public key, + * returns 0 and consumes cert->srcIdx so as a public key retrieval function + * can follow. + */ +#if defined(HAVE_RPK) +int TryDecodeRPKToKey(DecodedCert* cert) +{ + int ret = 0, len; + word32 tmpIdx; + word32 oid; + + WOLFSSL_ENTER("TryDecodeRPKToKey"); + + if (cert == NULL) + return BAD_FUNC_ARG; + + tmpIdx = cert->srcIdx; + + /* both X509 cert and RPK cert should start with a Sequence tag */ + if (ret == 0) { + if (GetSequence(cert->source, &tmpIdx, &len, cert->maxIdx) < 0) + ret = ASN_PARSE_E; + } + /* TBSCertificate of X509 or AlgorithmIdentifier of RPK cert */ + if (ret == 0) { + if (GetSequence(cert->source, &tmpIdx, &len, cert->maxIdx) < 0) + ret = ASN_PARSE_E; + } + /* OBJ ID should be next in RPK cert */ + if (ret == 0) { + if (GetObjectId(cert->source, &tmpIdx, &oid, oidKeyType, cert->maxIdx) + < 0) + ret = CRYPTOCB_UNAVAILABLE; + } + /* consume cert->srcIdx */ + if (ret == 0) { + WOLFSSL_MSG("Looks like RPK certificate"); + cert->srcIdx = tmpIdx; + } + WOLFSSL_LEAVE("TryDecodeRPKToKey", ret); + return ret; +} +#endif /* HAVE_RPK */ + /* Parse the certificate up to the X.509 public key. * * If cert data is invalid then badDate get set to error value. @@ -15146,6 +15194,20 @@ int DecodeToKey(DecodedCert* cert, int verify) int badDate = 0; int ret; +#if defined(HAVE_RPK) + + /* Raw Public Key certificate has only a SubjectPublicKeyInfo structure + * as its contents. So try to call GetCertKey to get public key from it. + * If it fails, the cert should be a X509 cert and proceed to process as + * x509 cert. */ + ret = GetCertKey(cert, cert->source, &cert->srcIdx, cert->maxIdx); + if (ret == 0) { + WOLFSSL_MSG("Raw Public Key certificate found and parsed"); + cert->isRPK = 1; + return ret; + } +#endif /* HAVE_RPK */ + if ( (ret = wc_GetPubX509(cert, verify, &badDate)) < 0) return ret; @@ -20748,6 +20810,41 @@ end: } #ifdef WOLFSSL_ASN_TEMPLATE + +#if defined(HAVE_RPK) +/* ASN template for a Raw Public Key certificate defined RFC7250. */ +static const ASNItem RPKCertASN[] = { +/* SubjectPublicKeyInfo ::= SEQUENCE */ { 0, ASN_SEQUENCE, 1, 1, 0 }, + /* algorithm AlgorithmIdentifier */ + /* AlgorithmIdentifier ::= SEQUENCE */ { 1, ASN_SEQUENCE, 1, 1, 0 }, + /* Algorithm OBJECT IDENTIFIER */ + /* TBS_SPUBKEYINFO_ALGO_OID */ { 2, ASN_OBJECT_ID, 0, 0, 0 }, + /* parameters ANY defined by algorithm OPTIONAL */ + /* TBS_SPUBKEYINFO_ALGO_NULL */ { 2, ASN_TAG_NULL, 0, 0, 2 }, + /* TBS_SPUBKEYINFO_ALGO_CURVEID */ { 2, ASN_OBJECT_ID, 0, 0, 2 }, +#ifdef WC_RSA_PSS + /* TBS_SPUBKEYINFO_ALGO_P_SEQ */ { 2, ASN_SEQUENCE, 1, 0, 2 }, +#endif + /* subjectPublicKey BIT STRING */ + /* TBS_SPUBKEYINFO_PUBKEY */ { 1, ASN_BIT_STRING, 0, 0, 0 }, +}; +/* Number of items in ASN template for a RawPublicKey certificate. */ +#define RPKCertASN_Length (sizeof(RPKCertASN) / sizeof(ASNItem)) + +enum { + RPKCERTASN_IDX_SPUBKEYINFO_SEQ = 0, + RPKCERTASN_IDX_SPUBKEYINFO_ALGO_SEQ, + RPKCERTASN_IDX_SPUBKEYINFO_ALGO_OID, + RPKCERTASN_IDX_SPUBKEYINFO_ALGO_NULL, + RPKCERTASN_IDX_SPUBKEYINFO_ALGO_CURVEID, +#ifdef WC_RSA_PSS + RPKCERTASN_IDX_SPUBKEYINFO_ALGO_P_SEQ, +#endif + RPKCERTASN_IDX_SPUBKEYINFO_PUBKEY, +}; + +#endif /* HAVE_RPK */ + /* ASN template for an X509 certificate. * X.509: RFC 5280, 4.1 - Basic Certificate Fields. */ @@ -20952,6 +21049,40 @@ static int DecodeCertInternal(DecodedCert* cert, int verify, int* criticalExt, word32 pubKeyEnd = 0; int done = 0; +#if defined(HAVE_RPK) + /* try to parse the cert as Raw Public Key cert */ + DECL_ASNGETDATA(RPKdataASN, RPKCertASN_Length); + CALLOC_ASNGETDATA(RPKdataASN, RPKCertASN_Length, ret, cert->heap); + GetASN_OID(&RPKdataASN[RPKCERTASN_IDX_SPUBKEYINFO_ALGO_OID], + oidKeyType); + GetASN_OID(&RPKdataASN[RPKCERTASN_IDX_SPUBKEYINFO_ALGO_CURVEID], + oidCurveType); + ret = GetASN_Items(RPKCertASN, RPKdataASN, RPKCertASN_Length, 1, + cert->source, &cert->srcIdx, cert->maxIdx); + if (ret == 0) { + cert->keyOID = + RPKdataASN[RPKCERTASN_IDX_SPUBKEYINFO_ALGO_OID].data.oid.sum; + + /* Parse the public key. */ + pubKeyOffset = RPKdataASN[RPKCERTASN_IDX_SPUBKEYINFO_SEQ].offset; + pubKeyEnd = cert->maxIdx; + ret = GetCertKey(cert, cert->source, &pubKeyOffset, pubKeyEnd); + if (ret == 0) { + WOLFSSL_MSG("Raw Public Key certificate found and parsed"); + cert->isRPK = 1; + } + } + /* Dispose of memory before allocating for extension decoding. */ + FREE_ASNGETDATA(RPKdataASN, cert->heap); + + if (ret == 0) { + return ret; + } + else { + ret = 0; /* proceed to the original x509 parsing */ + } +#endif /* HAVE_RPK */ + CALLOC_ASNGETDATA(dataASN, x509CertASN_Length, ret, cert->heap); if (ret == 0) { @@ -22533,7 +22664,11 @@ int ParseCertRelative(DecodedCert* cert, int type, int verify, void* cm) } WOLFSSL_MSG("Parsed Past Key"); - +#if defined(HAVE_RPK) + if (cert->isRPK) { + return ret; + } +#endif /* HAVE_RPK */ #ifdef WOLFSSL_CERT_REQ /* Read attributes */ @@ -22778,6 +22913,11 @@ int ParseCertRelative(DecodedCert* cert, int type, int verify, void* cm) WOLFSSL_ERROR_VERBOSE(ret); return ret; } +#if defined(HAVE_RPK) + if (cert->isRPK) { + return ret; + } +#endif /* HAVE_RPK */ } #endif diff --git a/wolfssl/error-ssl.h b/wolfssl/error-ssl.h index 9a6a9cf28..e579bfb66 100644 --- a/wolfssl/error-ssl.h +++ b/wolfssl/error-ssl.h @@ -191,7 +191,8 @@ enum wolfSSL_ErrorCodes { COMPRESSION_ERROR = -502, /* compression mismatch */ KEY_SHARE_ERROR = -503, /* key share mismatch */ POST_HAND_AUTH_ERROR = -504, /* client won't do post-hand auth */ - HRR_COOKIE_ERROR = -505 /* HRR msg cookie mismatch */ + HRR_COOKIE_ERROR = -505, /* HRR msg cookie mismatch */ + UNSUPPORTED_CERTIFICATE = -506 /* unsupported certificate type */ /* end negotiation parameter errors only 10 for now */ /* add strings to wolfSSL_ERR_reason_error_string in internal.c !!!!! */ diff --git a/wolfssl/internal.h b/wolfssl/internal.h index d8752091a..140c7b77e 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -2796,6 +2796,10 @@ typedef enum { #endif TLSX_APPLICATION_LAYER_PROTOCOL = 0x0010, /* a.k.a. ALPN */ TLSX_STATUS_REQUEST_V2 = 0x0011, /* a.k.a. OCSP stapling v2 */ +#ifdef HAVE_RPK + TLSX_CLIENT_CERTIFICATE_TYPE = 0x0013, /* RFC8446 */ + TLSX_SERVER_CERTIFICATE_TYPE = 0x0014, /* RFC8446 */ +#endif #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) TLSX_ENCRYPT_THEN_MAC = 0x0016, /* RFC 7366 */ #endif @@ -2841,6 +2845,36 @@ typedef enum { #endif } TLSX_Type; +/* TLS Certificate type defined RFC7250 + * https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#tls-extensiontype-values-3 + */ +#if defined(HAVE_RPK) +typedef struct RpkConfig { + /* user's preference */ + byte preferred_ClientCertTypeCnt; + byte preferred_ClientCertTypes[MAX_CLIENT_CERT_TYPE_CNT]; + byte preferred_ServerCertTypeCnt; + byte preferred_ServerCertTypes[MAX_CLIENT_CERT_TYPE_CNT]; + /* reflect to client_certificate_type extension in xxxHello */ +} RpkConfig; + +typedef struct RpkState { + byte sending_ClientCertTypeCnt; + byte sending_ClientCertTypes[MAX_CLIENT_CERT_TYPE_CNT]; + /* reflect to server_certificate_type extension in xxxHello */ + byte sending_ServerCertTypeCnt; + byte sending_ServerCertTypes[MAX_SERVER_CERT_TYPE_CNT]; + /* client_certificate_type extension in received yyyHello */ + byte received_ClientCertTypeCnt; + byte received_ClientCertTypes[MAX_CLIENT_CERT_TYPE_CNT]; + /* server_certificate_type extension in received yyyHello */ + byte received_ServerCertTypeCnt; + byte received_ServerCertTypes[MAX_SERVER_CERT_TYPE_CNT]; + /* set if Raw-public-key cert is loaded as own certificate */ + int isRPKLoaded; +} RpkState; +#endif /* HAVE_RPK */ + #if defined(WOLFSSL_TLS13) && defined(HAVE_ECH) typedef enum { @@ -3591,7 +3625,10 @@ struct WOLFSSL_CTX { #endif word16 minProto:1; /* sets min to min available */ word16 maxProto:1; /* sets max to max available */ - +#if defined(HAVE_RPK) + RpkConfig rpkConfig; + RpkState rpkState; +#endif /* HAVE_RPK */ #ifdef WOLFSSL_SRTP word16 dtlsSrtpProfiles; /* DTLS-with-SRTP mode * (list of selected profiles - up to 16) */ @@ -4695,6 +4732,13 @@ struct Options { #ifdef WOLFSSL_SEND_HRR_COOKIE word16 cookieGood:1; #endif +#if defined(HAVE_DANE) + word16 useDANE:1; +#endif /* HAVE_DANE */ +#if defined(HAVE_RPK) + RpkConfig rpkConfig; + RpkState rpkState; +#endif /* HAVE_RPK */ /* need full byte values for this section */ byte processReply; /* nonblocking resume */ diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index b7c6f960a..3b7be3e8e 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -5131,6 +5131,29 @@ WOLFSSL_API int wolfSSL_get_ephemeral_key(WOLFSSL* ssl, int keyAlgo, const unsigned char** key, unsigned int* keySz); #endif +#ifdef HAVE_RPK +/* cert type for client_certificate_type/server_certificate_type extensions */ +enum { + WOLFSSL_CERT_TYPE_UNKNOWN = -1, + WOLFSSL_CERT_TYPE_X509 = 0, + WOLFSSL_CERT_TYPE_RPK = 2, +}; +#define MAX_CLIENT_CERT_TYPE_CNT 2 +#define MAX_SERVER_CERT_TYPE_CNT 2 + +WOLFSSL_API int wolfSSL_CTX_set_client_cert_type(WOLFSSL_CTX* ctx, + const char* buf, int len); +WOLFSSL_API int wolfSSL_CTX_set_server_cert_type(WOLFSSL_CTX* ctx, + const char* buf, int len); +WOLFSSL_API int wolfSSL_set_client_cert_type(WOLFSSL* ssl, + const char* buf, int len); +WOLFSSL_API int wolfSSL_set_server_cert_type(WOLFSSL* ssl, + const char* buf, int len); +WOLFSSL_API int wolfSSL_get_negotiated_client_cert_type(WOLFSSL* ssl, int* tp); +WOLFSSL_API int wolfSSL_get_negotiated_server_cert_type(WOLFSSL* ssl, int* tp); +#endif /* HAVE_RPK */ + + #if defined(OPENSSL_EXTRA) #ifndef WOLFCRYPT_ONLY WOLFSSL_API int wolfSSL_EVP_PKEY_param_check(WOLFSSL_EVP_PKEY_CTX* ctx); diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index 9b0a1a5ef..48ea8a3a5 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -1931,6 +1931,9 @@ struct DecodedCert { #ifdef WOLFSSL_CERT_REQ byte isCSR : 1; /* Do we intend on parsing a CSR? */ #endif +#ifdef HAVE_RPK + byte isRPK : 1; /* indicate the cert is Raw-Public-Key cert in RFC7250 */ +#endif #if defined(WOLFSSL_CUSTOM_OID) && defined(WOLFSSL_ASN_TEMPLATE) \ && defined(HAVE_OID_DECODING) wc_UnknownExtCallback unknownExtCallback; @@ -2112,6 +2115,7 @@ WOLFSSL_LOCAL int DecodeToKey(DecodedCert* cert, int verify); #ifdef WOLFSSL_ASN_TEMPLATE WOLFSSL_LOCAL int DecodeCert(DecodedCert* cert, int verify, int* criticalExt); #endif +WOLFSSL_LOCAL int TryDecodeRPKToKey(DecodedCert* cert); WOLFSSL_LOCAL int wc_GetPubX509(DecodedCert* cert, int verify, int* badDate); WOLFSSL_LOCAL const byte* OidFromId(word32 id, word32 type, word32* oidSz);