Raw Public Keys: Configure cert types accepted from the server To indicate support for Raw Public Keys (RFC 7250), the client may list cert type(s) accepted from the server (the options are RawPublicKey or X.509) in the ClientHello, and the server may list a client cert type accepted from the client in the ServerHello. This CL adds API functions to configure the cert types that the caller wishes to accept from the peer (whether the caller is client or server), and implements the client's sending of the accepted types in server_certificate_type in the ClientHello. (The client_certificate_type extension in the ServerHello, which is also derived from the accepted types on the server side, is implemented later.) Bug: 467663225 Change-Id: I6042fa9a03eb395d85f9c92fd766e2836a6a6964 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/89827 Commit-Queue: Lily Chen <chlily@google.com> Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/crypto/err/ssl.errordata b/crypto/err/ssl.errordata index e0159fe..fe6b26b 100644 --- a/crypto/err/ssl.errordata +++ b/crypto/err/ssl.errordata
@@ -85,6 +85,7 @@ SSL,315,INVALID_ALPN_PROTOCOL_LIST SSL,322,INVALID_ALPS_CODEPOINT SSL,329,INVALID_CERTIFICATE_PROPERTY_LIST +SSL,333,INVALID_CERT_TYPES_LIST SSL,314,INVALID_CLIENT_HELLO_INNER SSL,158,INVALID_COMMAND SSL,256,INVALID_COMPRESSION_LIST
diff --git a/gen/crypto/err_data.cc b/gen/crypto/err_data.cc index 846ca1f..1c70e15 100644 --- a/gen/crypto/err_data.cc +++ b/gen/crypto/err_data.cc
@@ -205,51 +205,51 @@ 0x283500f7, 0x28358cc1, 0x2836099a, - 0x2c323492, + 0x2c3234aa, 0x2c32943b, - 0x2c3334a0, - 0x2c33b4b2, - 0x2c3434c6, - 0x2c34b4d8, - 0x2c3534f3, - 0x2c35b505, - 0x2c363535, + 0x2c3334b8, + 0x2c33b4ca, + 0x2c3434de, + 0x2c34b4f0, + 0x2c35350b, + 0x2c35b51d, + 0x2c36354d, 0x2c36833a, - 0x2c373542, - 0x2c37b56e, - 0x2c3835ac, - 0x2c38b5c3, - 0x2c3935e1, - 0x2c39b5f1, - 0x2c3a3603, - 0x2c3ab617, - 0x2c3b3628, - 0x2c3bb647, + 0x2c37355a, + 0x2c37b586, + 0x2c3835c4, + 0x2c38b5db, + 0x2c3935f9, + 0x2c39b609, + 0x2c3a361b, + 0x2c3ab62f, + 0x2c3b3640, + 0x2c3bb65f, 0x2c3c144d, 0x2c3c9463, - 0x2c3d368c, + 0x2c3d36a4, 0x2c3d947c, - 0x2c3e36b6, - 0x2c3eb6c4, - 0x2c3f36dc, - 0x2c3fb6f4, - 0x2c40371e, + 0x2c3e36ce, + 0x2c3eb6dc, + 0x2c3f36f4, + 0x2c3fb70c, + 0x2c403736, 0x2c409330, - 0x2c41372f, - 0x2c41b742, + 0x2c413747, + 0x2c41b75a, 0x2c4212f6, - 0x2c42b753, + 0x2c42b76b, 0x2c43076d, - 0x2c43b639, - 0x2c443581, - 0x2c44b701, - 0x2c453518, - 0x2c45b554, - 0x2c4635d1, - 0x2c46b65b, - 0x2c473670, - 0x2c47b6a9, - 0x2c483593, + 0x2c43b651, + 0x2c443599, + 0x2c44b719, + 0x2c453530, + 0x2c45b56c, + 0x2c4635e9, + 0x2c46b673, + 0x2c473688, + 0x2c47b6c1, + 0x2c4835ab, 0x30320000, 0x30328015, 0x3033001f, @@ -447,213 +447,214 @@ 0x404da145, 0x404e2159, 0x404ea166, - 0x404f2239, - 0x404fa2af, - 0x40502354, - 0x4050a368, - 0x405123b5, - 0x405223c5, - 0x4052a3e9, - 0x40532401, - 0x4053a414, - 0x40542429, - 0x4054a44c, - 0x40552477, - 0x4055a4b4, - 0x405624d9, - 0x4056a4f2, - 0x4057250a, - 0x4057a51d, - 0x40582532, - 0x4058a559, - 0x40592588, - 0x4059a5c8, - 0x405aa5dc, - 0x405b25f4, - 0x405ba605, - 0x405c2618, - 0x405ca66d, - 0x405d267a, - 0x405da69f, - 0x405e26dd, + 0x404f2251, + 0x404fa2c7, + 0x4050236c, + 0x4050a380, + 0x405123cd, + 0x405223dd, + 0x4052a401, + 0x40532419, + 0x4053a42c, + 0x40542441, + 0x4054a464, + 0x4055248f, + 0x4055a4cc, + 0x405624f1, + 0x4056a50a, + 0x40572522, + 0x4057a535, + 0x4058254a, + 0x4058a571, + 0x405925a0, + 0x4059a5e0, + 0x405aa5f4, + 0x405b260c, + 0x405ba61d, + 0x405c2630, + 0x405ca685, + 0x405d2692, + 0x405da6b7, + 0x405e26f5, 0x405e8afe, - 0x405f272c, - 0x405fa739, - 0x40602747, - 0x4060a769, - 0x406127dd, - 0x4061a815, - 0x4062282c, - 0x4062a83d, - 0x4063288a, - 0x4063a89f, - 0x406428b6, - 0x4064a8e2, - 0x406528fd, - 0x4065a914, - 0x4066292c, - 0x4066a956, - 0x40672981, - 0x4067a9c6, - 0x40682a0e, - 0x4068aa2f, - 0x40692a61, - 0x4069aa8f, - 0x406a2ab0, - 0x406aaad0, - 0x406b2c58, - 0x406bac7b, - 0x406c2c91, - 0x406caf9b, - 0x406d2fca, - 0x406daff2, - 0x406e3020, - 0x406eb06d, - 0x406f30c6, - 0x406fb0fe, - 0x40703111, - 0x4070b12e, + 0x405f2744, + 0x405fa751, + 0x4060275f, + 0x4060a781, + 0x406127f5, + 0x4061a82d, + 0x40622844, + 0x4062a855, + 0x406328a2, + 0x4063a8b7, + 0x406428ce, + 0x4064a8fa, + 0x40652915, + 0x4065a92c, + 0x40662944, + 0x4066a96e, + 0x40672999, + 0x4067a9de, + 0x40682a26, + 0x4068aa47, + 0x40692a79, + 0x4069aaa7, + 0x406a2ac8, + 0x406aaae8, + 0x406b2c70, + 0x406bac93, + 0x406c2ca9, + 0x406cafb3, + 0x406d2fe2, + 0x406db00a, + 0x406e3038, + 0x406eb085, + 0x406f30de, + 0x406fb116, + 0x40703129, + 0x4070b146, 0x4071084d, - 0x4071b140, - 0x40723153, - 0x4072b189, - 0x407331a1, + 0x4071b158, + 0x4072316b, + 0x4072b1a1, + 0x407331b9, 0x40739665, - 0x407431b5, - 0x4074b1cf, - 0x407531e0, - 0x4075b1f4, - 0x40763202, + 0x407431cd, + 0x4074b1e7, + 0x407531f8, + 0x4075b20c, + 0x4076321a, 0x407693f3, - 0x40773227, - 0x4077b283, - 0x4078329e, - 0x4078b2d7, - 0x407932ee, - 0x4079b304, - 0x407a3330, - 0x407ab343, - 0x407b3358, - 0x407bb36a, - 0x407c339b, - 0x407cb3a4, - 0x407d2a4a, - 0x407da2d7, - 0x407e32b3, - 0x407ea569, + 0x4077323f, + 0x4077b29b, + 0x407832b6, + 0x4078b2ef, + 0x40793306, + 0x4079b31c, + 0x407a3348, + 0x407ab35b, + 0x407b3370, + 0x407bb382, + 0x407c33b3, + 0x407cb3bc, + 0x407d2a62, + 0x407da2ef, + 0x407e32cb, + 0x407ea581, 0x407f1eca, 0x407fa0ad, - 0x40802249, + 0x40802261, 0x40809ef2, - 0x408123d7, + 0x408123ef, 0x4081a1b4, - 0x4082300b, + 0x40823023, 0x40829c45, - 0x40832544, - 0x4083a8c7, + 0x4083255c, + 0x4083a8df, 0x40841f16, - 0x4084a5a1, - 0x40852629, - 0x4085a7a4, - 0x408626bf, - 0x4086a30c, - 0x40873051, - 0x4087a7f2, + 0x4084a5b9, + 0x40852641, + 0x4085a7bc, + 0x408626d7, + 0x4086a324, + 0x40873069, + 0x4087a80a, 0x40881c83, - 0x4088a9d9, + 0x4088a9f1, 0x40891cd2, 0x40899c5f, - 0x408a2cc9, + 0x408a2ce1, 0x408a9a7d, - 0x408b337f, - 0x408bb0db, - 0x408c264f, + 0x408b3397, + 0x408bb0f3, + 0x408c2667, 0x408d1ffe, 0x408d9f48, 0x408e212e, - 0x408ea494, - 0x408f29ed, - 0x408fa7c0, - 0x409029a2, - 0x4090a691, - 0x40912cb1, + 0x408ea4ac, + 0x408f2a05, + 0x408fa7d8, + 0x409029ba, + 0x4090a6a9, + 0x40912cc9, 0x40919ab5, 0x40921d1f, - 0x4092b08c, - 0x4093316c, - 0x4093a31d, + 0x4092b0a4, + 0x40933184, + 0x4093a335, 0x40941f2a, - 0x4094ace2, - 0x4095284e, - 0x4095b310, - 0x40963038, - 0x4096a262, - 0x4097239d, + 0x4094acfa, + 0x40952866, + 0x4095b328, + 0x40963050, + 0x4096a27a, + 0x409723b5, 0x4097a17d, 0x40981d7f, - 0x4098a862, - 0x409930a8, - 0x4099a4c1, - 0x409a245a, + 0x4098a87a, + 0x409930c0, + 0x4099a4d9, + 0x409a2472, 0x409a9a99, 0x409b1f84, 0x409b9faf, - 0x409c3265, + 0x409c327d, 0x409c9fd7, - 0x409d221e, + 0x409d2236, 0x409da1ca, 0x409e1e10, - 0x409ea297, - 0x409f227f, + 0x409ea2af, + 0x409f2297, 0x409f9f77, - 0x40a022bf, + 0x40a022d7, 0x40a0a197, 0x40a121e5, - 0x40a1a5b5, - 0x40a22339, - 0x40a2a71d, - 0x40a32791, - 0x40a3b249, - 0x40a42383, + 0x40a1a5cd, + 0x40a22351, + 0x40a2a735, + 0x40a327a9, + 0x40a3b261, + 0x40a4239b, 0x40a4a1fc, 0x40a51f06, - 0x40a5a2f1, - 0x40a62639, - 0x41f42b83, - 0x41f92c15, - 0x41fe2b08, - 0x41feadbe, - 0x41ff2eec, - 0x42032b9c, - 0x42082bbe, - 0x4208abfa, - 0x42092aec, - 0x4209ac34, - 0x420a2b43, - 0x420aab23, - 0x420b2b63, - 0x420babdc, - 0x420c2f08, - 0x420cacf2, - 0x420d2da5, - 0x420daddc, - 0x42122e0f, - 0x42172ecf, - 0x4217ae51, - 0x421c2e73, - 0x421f2e2e, - 0x42212f80, - 0x42262eb2, - 0x422b2f5e, - 0x422bad80, - 0x422c2f40, - 0x422cad33, - 0x422d2d0c, - 0x422daf1f, - 0x422e2d5f, - 0x42302e8e, - 0x4230adf6, - 0x423126fe, + 0x40a5a309, + 0x40a62651, + 0x40a6a21e, + 0x41f42b9b, + 0x41f92c2d, + 0x41fe2b20, + 0x41feadd6, + 0x41ff2f04, + 0x42032bb4, + 0x42082bd6, + 0x4208ac12, + 0x42092b04, + 0x4209ac4c, + 0x420a2b5b, + 0x420aab3b, + 0x420b2b7b, + 0x420babf4, + 0x420c2f20, + 0x420cad0a, + 0x420d2dbd, + 0x420dadf4, + 0x42122e27, + 0x42172ee7, + 0x4217ae69, + 0x421c2e8b, + 0x421f2e46, + 0x42212f98, + 0x42262eca, + 0x422b2f76, + 0x422bad98, + 0x422c2f58, + 0x422cad4b, + 0x422d2d24, + 0x422daf37, + 0x422e2d77, + 0x42302ea6, + 0x4230ae0e, + 0x42312716, 0x44320778, 0x44328787, 0x44330793, @@ -709,71 +710,71 @@ 0x4c419545, 0x4c4216ae, 0x4c42948d, - 0x50323765, - 0x5032b774, - 0x5033377f, - 0x5033b78f, - 0x503437a8, - 0x5034b7c2, - 0x503537d0, - 0x5035b7e6, - 0x503637f8, - 0x5036b80e, - 0x50373827, - 0x5037b83a, - 0x50383852, - 0x5038b863, - 0x50393878, - 0x5039b88c, - 0x503a38ac, - 0x503ab8c2, - 0x503b38da, - 0x503bb8ec, - 0x503c3908, - 0x503cb91f, - 0x503d3938, - 0x503db94e, - 0x503e395b, - 0x503eb971, - 0x503f3983, + 0x5032377d, + 0x5032b78c, + 0x50333797, + 0x5033b7a7, + 0x503437c0, + 0x5034b7da, + 0x503537e8, + 0x5035b7fe, + 0x50363810, + 0x5036b826, + 0x5037383f, + 0x5037b852, + 0x5038386a, + 0x5038b87b, + 0x50393890, + 0x5039b8a4, + 0x503a38c4, + 0x503ab8da, + 0x503b38f2, + 0x503bb904, + 0x503c3920, + 0x503cb937, + 0x503d3950, + 0x503db966, + 0x503e3973, + 0x503eb989, + 0x503f399b, 0x503f83b3, - 0x50403996, - 0x5040b9a6, - 0x504139c0, - 0x5041b9cf, - 0x504239e9, - 0x5042ba06, - 0x50433a16, - 0x5043ba26, - 0x50443a43, + 0x504039ae, + 0x5040b9be, + 0x504139d8, + 0x5041b9e7, + 0x50423a01, + 0x5042ba1e, + 0x50433a2e, + 0x5043ba3e, + 0x50443a5b, 0x50448469, - 0x50453a57, - 0x5045ba75, - 0x50463a88, - 0x5046ba9e, - 0x50473ab0, - 0x5047bac5, - 0x50483aeb, - 0x5048baf9, - 0x50493b0c, - 0x5049bb21, - 0x504a3b37, - 0x504abb47, - 0x504b3b67, - 0x504bbb7a, - 0x504c3b9d, - 0x504cbbcb, - 0x504d3bf8, - 0x504dbc15, - 0x504e3c30, - 0x504ebc4c, - 0x504f3c5e, - 0x504fbc75, - 0x50503c84, + 0x50453a6f, + 0x5045ba8d, + 0x50463aa0, + 0x5046bab6, + 0x50473ac8, + 0x5047badd, + 0x50483b03, + 0x5048bb11, + 0x50493b24, + 0x5049bb39, + 0x504a3b4f, + 0x504abb5f, + 0x504b3b7f, + 0x504bbb92, + 0x504c3bb5, + 0x504cbbe3, + 0x504d3c10, + 0x504dbc2d, + 0x504e3c48, + 0x504ebc64, + 0x504f3c76, + 0x504fbc8d, + 0x50503c9c, 0x50508729, - 0x50513c97, - 0x5051ba35, - 0x50523bdd, + 0x50513caf, + 0x5051ba4d, + 0x50523bf5, 0x58321011, 0x68320fd3, 0x68328d2b, @@ -818,19 +819,19 @@ 0x7c32130c, 0x80321558, 0x80328090, - 0x80333461, + 0x80333479, 0x803380b9, - 0x80343470, - 0x8034b3d8, - 0x803533f6, - 0x8035b484, - 0x80363438, - 0x8036b3e7, - 0x8037342a, - 0x8037b3c5, - 0x8038344b, - 0x8038b407, - 0x8039341c, + 0x80343488, + 0x8034b3f0, + 0x8035340e, + 0x8035b49c, + 0x80363450, + 0x8036b3ff, + 0x80373442, + 0x8037b3dd, + 0x80383463, + 0x8038b41f, + 0x80393434, 0x84320bb0, 0x84328bc9, }; @@ -1265,6 +1266,7 @@ "INVALID_ALPN_PROTOCOL_LIST\0" "INVALID_ALPS_CODEPOINT\0" "INVALID_CERTIFICATE_PROPERTY_LIST\0" + "INVALID_CERT_TYPES_LIST\0" "INVALID_CLIENT_HELLO_INNER\0" "INVALID_COMMAND\0" "INVALID_COMPRESSION_LIST\0"
diff --git a/include/openssl/prefix_symbols.h b/include/openssl/prefix_symbols.h index 2fdf44e..d211431 100644 --- a/include/openssl/prefix_symbols.h +++ b/include/openssl/prefix_symbols.h
@@ -1948,6 +1948,7 @@ #pragma redefine_extname SSL_CTX_set0_chain BORINGSSL_ADD_USER_LABEL_AND_PREFIX(SSL_CTX_set0_chain) #pragma redefine_extname SSL_CTX_set0_client_CAs BORINGSSL_ADD_USER_LABEL_AND_PREFIX(SSL_CTX_set0_client_CAs) #pragma redefine_extname SSL_CTX_set0_verify_cert_store BORINGSSL_ADD_USER_LABEL_AND_PREFIX(SSL_CTX_set0_verify_cert_store) +#pragma redefine_extname SSL_CTX_set1_accepted_peer_cert_types BORINGSSL_ADD_USER_LABEL_AND_PREFIX(SSL_CTX_set1_accepted_peer_cert_types) #pragma redefine_extname SSL_CTX_set1_chain BORINGSSL_ADD_USER_LABEL_AND_PREFIX(SSL_CTX_set1_chain) #pragma redefine_extname SSL_CTX_set1_curves BORINGSSL_ADD_USER_LABEL_AND_PREFIX(SSL_CTX_set1_curves) #pragma redefine_extname SSL_CTX_set1_curves_list BORINGSSL_ADD_USER_LABEL_AND_PREFIX(SSL_CTX_set1_curves_list) @@ -2283,6 +2284,7 @@ #pragma redefine_extname SSL_set0_rbio BORINGSSL_ADD_USER_LABEL_AND_PREFIX(SSL_set0_rbio) #pragma redefine_extname SSL_set0_verify_cert_store BORINGSSL_ADD_USER_LABEL_AND_PREFIX(SSL_set0_verify_cert_store) #pragma redefine_extname SSL_set0_wbio BORINGSSL_ADD_USER_LABEL_AND_PREFIX(SSL_set0_wbio) +#pragma redefine_extname SSL_set1_accepted_peer_cert_types BORINGSSL_ADD_USER_LABEL_AND_PREFIX(SSL_set1_accepted_peer_cert_types) #pragma redefine_extname SSL_set1_chain BORINGSSL_ADD_USER_LABEL_AND_PREFIX(SSL_set1_chain) #pragma redefine_extname SSL_set1_client_key_shares BORINGSSL_ADD_USER_LABEL_AND_PREFIX(SSL_set1_client_key_shares) #pragma redefine_extname SSL_set1_curves BORINGSSL_ADD_USER_LABEL_AND_PREFIX(SSL_set1_curves) @@ -5025,6 +5027,7 @@ #define SSL_CTX_set0_chain BORINGSSL_ADD_PREFIX(SSL_CTX_set0_chain) #define SSL_CTX_set0_client_CAs BORINGSSL_ADD_PREFIX(SSL_CTX_set0_client_CAs) #define SSL_CTX_set0_verify_cert_store BORINGSSL_ADD_PREFIX(SSL_CTX_set0_verify_cert_store) +#define SSL_CTX_set1_accepted_peer_cert_types BORINGSSL_ADD_PREFIX(SSL_CTX_set1_accepted_peer_cert_types) #define SSL_CTX_set1_chain BORINGSSL_ADD_PREFIX(SSL_CTX_set1_chain) #define SSL_CTX_set1_curves BORINGSSL_ADD_PREFIX(SSL_CTX_set1_curves) #define SSL_CTX_set1_curves_list BORINGSSL_ADD_PREFIX(SSL_CTX_set1_curves_list) @@ -5360,6 +5363,7 @@ #define SSL_set0_rbio BORINGSSL_ADD_PREFIX(SSL_set0_rbio) #define SSL_set0_verify_cert_store BORINGSSL_ADD_PREFIX(SSL_set0_verify_cert_store) #define SSL_set0_wbio BORINGSSL_ADD_PREFIX(SSL_set0_wbio) +#define SSL_set1_accepted_peer_cert_types BORINGSSL_ADD_PREFIX(SSL_set1_accepted_peer_cert_types) #define SSL_set1_chain BORINGSSL_ADD_PREFIX(SSL_set1_chain) #define SSL_set1_client_key_shares BORINGSSL_ADD_PREFIX(SSL_set1_client_key_shares) #define SSL_set1_curves BORINGSSL_ADD_PREFIX(SSL_set1_curves)
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index 27f71de..795f859 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h
@@ -3877,6 +3877,41 @@ SSL_CREDENTIAL *cred, CRYPTO_BUFFER *dc); +// Raw Public Keys (RFC 7250). +// +// Raw public keys can be used (e.g., instead of X.509 certificates) to +// authenticate a TLS connection, assuming an out-of-band mechanism has been +// used to bind the public keys to their presenting entities. +// +// When raw public keys are in use, the client_certificate_type and +// server_certificate_type extensions are sent in the handshake to indicate to +// the peer which type(s) of certificate(s) can be exchanged. + +// TODO(crbug.com/467663225): Implementation is not yet complete. The values +// configured via functions in this section may not currently be used. + +// TLSEXT_cert_type_* are certificate types with values taken from the "TLS +// Certificate Types" subregistry of the TLS Extensions registry. +#define TLSEXT_cert_type_x509 0x00 +#define TLSEXT_cert_type_rpk 0x02 + +// SSL_CTX_set1_accepted_peer_cert_types sets the types of certificates that the +// caller wishes to accept from the peer, for |ctx|. |values| is a nonempty list +// of |num_values| certificate types (|TLSEXT_cert_type_*| values) in preference +// order. If a valid list is not configured explicitly, only X.509 certificates +// are accepted by default. This function returns one on success or zero on +// failure. +OPENSSL_EXPORT int SSL_CTX_set1_accepted_peer_cert_types(SSL_CTX *ctx, + const uint8_t *values, + size_t num_values); + +// SSL_set1_accepted_peer_cert_types behaves like +// |SSL_CTX_set1_accepted_peer_cert_types|, but configures the values on |ssl|. +OPENSSL_EXPORT int SSL_set1_accepted_peer_cert_types(SSL *ssl, + const uint8_t *values, + size_t num_values); + + // Password Authenticated Key Exchange (PAKE). // // Password Authenticated Key Exchange protocols allow client and server to @@ -6822,6 +6857,7 @@ #define SSL_R_DUPLICATE_GROUP 330 #define SSL_R_INVALID_PSK_FOR_CONNECTION 331 #define SSL_R_NO_SUPPORTED_PSK_MODE 332 +#define SSL_R_INVALID_CERT_TYPES_LIST 333 #define SSL_R_SSLV3_ALERT_CLOSE_NOTIFY 1000 #define SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE 1010 #define SSL_R_SSLV3_ALERT_BAD_RECORD_MAC 1020
diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h index 696ccfd..94fc824 100644 --- a/include/openssl/tls1.h +++ b/include/openssl/tls1.h
@@ -64,6 +64,9 @@ // ExtensionType value from RFC 7301 #define TLSEXT_TYPE_application_layer_protocol_negotiation 16 +// ExtensionType values from RFC 7250 +#define TLSEXT_TYPE_server_cert_type 20 + // ExtensionType value from RFC 7685 #define TLSEXT_TYPE_padding 21
diff --git a/ssl/extensions.cc b/ssl/extensions.cc index 84c80ab..7578b66 100644 --- a/ssl/extensions.cc +++ b/ssl/extensions.cc
@@ -3694,6 +3694,52 @@ return true; } +// Server certificate type +// +// https://www.rfc-editor.org/rfc/rfc7250.html#section-3 + +static bool ext_server_cert_type_add_clienthello(const SSL_HANDSHAKE *hs, + CBB *out, + CBB *out_compressible, + ssl_client_hello_type_t type) { + assert(!hs->config->accepted_peer_cert_types.empty()); + // Omit extension if the only type would be the default, X.509. + if (hs->config->accepted_peer_cert_types.size() == 1 && + hs->config->accepted_peer_cert_types[0] == kDefaultCertType) { + return true; + } + CBB contents, server_cert_types; + if (!CBB_add_u16(out, TLSEXT_TYPE_server_cert_type) || + !CBB_add_u16_length_prefixed(out, &contents) || + !CBB_add_u8_length_prefixed(&contents, &server_cert_types) || + !CBB_add_bytes(&server_cert_types, + hs->config->accepted_peer_cert_types.data(), + hs->config->accepted_peer_cert_types.size()) || + !CBB_flush(out)) { + return false; + } + return true; +} + +static bool ext_server_cert_type_parse_serverhello(SSL_HANDSHAKE *hs, + uint8_t *out_alert, + CBS *contents) { + // TODO(crbug.com/467663225): Implement this. + return true; +} + +static bool ext_server_cert_type_parse_clienthello(SSL_HANDSHAKE *hs, + uint8_t *out_alert, + CBS *contents) { + // TODO(crbug.com/467663225): Implement this. + return true; +} + +static bool ext_server_cert_type_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) { + // TODO(crbug.com/467663225): Implement this. + return true; +} + // kExtensions contains all the supported extensions. static const struct tls_extension kExtensions[] = { { @@ -3898,6 +3944,13 @@ ext_trust_anchors_parse_clienthello, ext_trust_anchors_add_serverhello, }, + { + TLSEXT_TYPE_server_cert_type, + ext_server_cert_type_add_clienthello, + ext_server_cert_type_parse_serverhello, + ext_server_cert_type_parse_clienthello, + ext_server_cert_type_add_serverhello, + }, }; #define kNumExtensions (sizeof(kExtensions) / sizeof(struct tls_extension))
diff --git a/ssl/internal.h b/ssl/internal.h index 0c81546..e30164c 100644 --- a/ssl/internal.h +++ b/ssl/internal.h
@@ -1571,6 +1571,16 @@ uint16_t *out_sigalg); +// Server certificate type. + +inline constexpr uint8_t kCertTypes[] = { + TLSEXT_cert_type_x509, + TLSEXT_cert_type_rpk, +}; +inline constexpr size_t kNumCertTypes = std::size(kCertTypes); +inline constexpr uint8_t kDefaultCertType = TLSEXT_cert_type_x509; + + // Handshake functions. enum ssl_hs_wait_t { @@ -3373,6 +3383,12 @@ // verify_mode is a bitmask of |SSL_VERIFY_*| values. uint8_t verify_mode = SSL_VERIFY_NONE; + // accepted_peer_cert_types contains a list of |TLSEXT_cert_type_*| values in + // preference order indicating the types of certificates to accept from the + // peer. This list should always be non-empty. If the caller did not configure + // a valid list, only X.509 certificates are accepted by default. + InplaceVector<uint8_t, kNumCertTypes> accepted_peer_cert_types; + // ech_grease_enabled controls whether ECH GREASE may be sent in the // ClientHello. bool ech_grease_enabled : 1; @@ -4016,6 +4032,9 @@ // accepted from the peer in decreasing order of preference. bssl::Array<uint16_t> verify_sigalgs; + // accepted_peer_cert_types inherited by SSL struct. + bssl::InplaceVector<uint8_t, bssl::kNumCertTypes> accepted_peer_cert_types; + // retain_only_sha256_of_client_certs is true if we should compute the SHA256 // hash of the peer's certificate and then discard it to save memory and // session space. Only effective on the server side.
diff --git a/ssl/ssl_lib.cc b/ssl/ssl_lib.cc index 3a4b690..6444344 100644 --- a/ssl/ssl_lib.cc +++ b/ssl/ssl_lib.cc
@@ -446,6 +446,7 @@ if (!ret->supported_group_list_flags.Init(ret->supported_group_list.size())) { return nullptr; } + ret->accepted_peer_cert_types.PushBack(kDefaultCertType); return ret.release(); } @@ -525,7 +526,9 @@ ctx->supported_group_list_flags) || !ssl->config->alpn_client_proto_list.CopyFrom( ctx->alpn_client_proto_list) || - !ssl->config->verify_sigalgs.CopyFrom(ctx->verify_sigalgs)) { + !ssl->config->verify_sigalgs.CopyFrom(ctx->verify_sigalgs) || + !ssl->config->accepted_peer_cert_types.TryCopyFrom( + ctx->accepted_peer_cert_types)) { return nullptr; } @@ -3574,3 +3577,48 @@ } int SSL_CTX_get_security_level(const SSL_CTX *ctx) { return 0; } + +static bool is_valid_cert_types_list(Span<const uint8_t> list) { + if (list.empty() || list.size() > kNumCertTypes) { + return false; + } + for (size_t i = 0u; i < list.size(); ++i) { + // Check that each value is a recognized cert type. + if (std::find(std::begin(kCertTypes), std::end(kCertTypes), list[i]) == + std::end(kCertTypes)) { + return false; + } + // Reject duplicates. + for (size_t j = 0u; j < i; ++j) { + if (list[i] == list[j]) { + return false; + } + } + } + return true; +} + +static bool set1_cert_types(InplaceVector<uint8_t, kNumCertTypes> *out, + Span<const uint8_t> values) { + if (!is_valid_cert_types_list(values)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_CERT_TYPES_LIST); + return false; + } + out->CopyFrom(values); + return true; +} + +int SSL_CTX_set1_accepted_peer_cert_types(SSL_CTX *ctx, const uint8_t *values, + size_t num_values) { + return set1_cert_types(&ctx->accepted_peer_cert_types, + Span(values, num_values)); +} + +int SSL_set1_accepted_peer_cert_types(SSL *ssl, const uint8_t *values, + size_t num_values) { + if (!ssl->config) { + return 0; + } + return set1_cert_types(&ssl->config->accepted_peer_cert_types, + Span(values, num_values)); +}
diff --git a/ssl/ssl_test.cc b/ssl/ssl_test.cc index 8c24934..e47a92e 100644 --- a/ssl/ssl_test.cc +++ b/ssl/ssl_test.cc
@@ -9362,6 +9362,41 @@ check_alpn_proto({}); } +TEST(SSLTest, AcceptedPeerCertTypesConfig) { + bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method())); + ASSERT_TRUE(ctx); + + // Valid configurations. + for (const auto &list : std::vector<std::vector<uint8_t>>({ + // Listing only the default type is considered valid here; we just + // won't send a ClientHello extension for this list. + {TLSEXT_cert_type_x509}, + {TLSEXT_cert_type_rpk}, + {TLSEXT_cert_type_x509, TLSEXT_cert_type_rpk}, + {TLSEXT_cert_type_rpk, TLSEXT_cert_type_x509}, + })) { + EXPECT_EQ(1, SSL_CTX_set1_accepted_peer_cert_types(ctx.get(), list.data(), + list.size())); + } + + // Invalid configurations. + for (const auto &list : std::vector<std::vector<uint8_t>>({ + // Empty list is invalid. + {}, + // Bogus value. + {0xff}, + // Contains duplicate. + {TLSEXT_cert_type_x509, TLSEXT_cert_type_x509}, + // Too long. + {TLSEXT_cert_type_x509, TLSEXT_cert_type_rpk, 0x03}, + })) { + EXPECT_EQ(0, SSL_CTX_set1_accepted_peer_cert_types(ctx.get(), list.data(), + list.size())); + EXPECT_TRUE(ErrorEquals(ERR_get_error(), ERR_LIB_SSL, + SSL_R_INVALID_CERT_TYPES_LIST)); + } +} + // This is a basic unit-test class to verify completing handshake successfully, // sending the correct codepoint extension and having correct application // setting on different combination of ALPS codepoint settings. More integration
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go index b23fd15..bd75440 100644 --- a/ssl/test/runner/common.go +++ b/ssl/test/runner/common.go
@@ -205,6 +205,7 @@ extensionUseSRTP uint16 = 14 extensionALPN uint16 = 16 extensionSignedCertificateTimestamp uint16 = 18 + extensionServerCertificateType uint16 = 20 extensionPadding uint16 = 21 extensionExtendedMasterSecret uint16 = 23 extensionCompressedCertAlgs uint16 = 27 @@ -270,6 +271,14 @@ pointFormatCompressedPrime uint8 = 1 ) +// TLS certificate types (RFC 7250). +type CertificateType uint8 + +const ( + certTypeX509 CertificateType = 0 + certTypeRawPublicKey CertificateType = 2 +) + // TLS CertificateStatusType (RFC 3546) const ( statusTypeOCSP uint8 = 1 @@ -2236,6 +2245,11 @@ // NewSessionTicket messages to have or not have the resumption_across_names // flag set. ExpectResumptionAcrossNames *bool + + // ExpectServerCertificateTypes, if not nil, causes the server to + // expect the server_certificate_type extension sent by the peer to contain + // exactly the given values. + ExpectServerCertificateTypes []CertificateType } func (c *Config) serverInit() {
diff --git a/ssl/test/runner/handshake_messages.go b/ssl/test/runner/handshake_messages.go index 12cb52b..d0d8536 100644 --- a/ssl/test/runner/handshake_messages.go +++ b/ssl/test/runner/handshake_messages.go
@@ -254,6 +254,7 @@ pakeShares []pakeShare certificateAuthorities [][]byte trustAnchors [][]byte + serverCertificateTypes []CertificateType outerExtensions []uint16 reorderOuterExtensionsWithoutCompressing bool prefixExtensions []uint16 @@ -634,6 +635,18 @@ body: body.BytesOrPanic(), }) } + if m.serverCertificateTypes != nil { + body := cryptobyte.NewBuilder(nil) + body.AddUint8LengthPrefixed(func(certTypesList *cryptobyte.Builder) { + for _, certType := range m.serverCertificateTypes { + certTypesList.AddUint8(uint8(certType)) + } + }) + extensions = append(extensions, extension{ + id: extensionServerCertificateType, + body: body.BytesOrPanic(), + }) + } // The PSK extension must be last. See https://tools.ietf.org/html/rfc8446#section-4.2.11 if len(m.pskIdentities) > 0 { pskExtension := cryptobyte.NewBuilder(nil) @@ -858,6 +871,7 @@ m.pakeClientID = nil m.pakeServerID = nil m.pakeShares = nil + m.serverCertificateTypes = nil if len(reader) == 0 { // ClientHello is optionally followed by extension data @@ -1186,6 +1200,23 @@ if !parseTrustAnchors(&body, &m.trustAnchors) || len(body) != 0 { return false } + case extensionServerCertificateType: + var certTypes cryptobyte.String + if !body.ReadUint8LengthPrefixed(&certTypes) || len(body) != 0 { + return false + } + for len(certTypes) > 0 { + var certType uint8 + if !certTypes.ReadUint8(&certType) { + return false + } + m.serverCertificateTypes = append(m.serverCertificateTypes, CertificateType(certType)) + } + // A client must omit the extension if empty or if the only type is the default, X.509. + if len(m.serverCertificateTypes) == 0 || + (len(m.serverCertificateTypes) == 1 && m.serverCertificateTypes[0] == certTypeX509) { + return false + } } if isGREASEValue(extension) {
diff --git a/ssl/test/runner/handshake_server.go b/ssl/test/runner/handshake_server.go index 1acab4a..c760ea8 100644 --- a/ssl/test/runner/handshake_server.go +++ b/ssl/test/runner/handshake_server.go
@@ -441,6 +441,12 @@ } } + if expected := c.config.Bugs.ExpectServerCertificateTypes; expected != nil { + if !slices.Equal(expected, hs.clientHello.serverCertificateTypes) { + return fmt.Errorf("tls: client offered server certificate types %v, but expected %v", hs.clientHello.serverCertificateTypes, expected) + } + } + applyBugsToClientHello(hs.clientHello, config) return nil
diff --git a/ssl/test/runner/raw_public_key_tests.go b/ssl/test/runner/raw_public_key_tests.go new file mode 100644 index 0000000..1046d76 --- /dev/null +++ b/ssl/test/runner/raw_public_key_tests.go
@@ -0,0 +1,77 @@ +// Copyright 2026 The BoringSSL Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package runner + +import ( + "fmt" +) + +var ( + certTypesListRPKOnly = []CertificateType{certTypeRawPublicKey} + certTypesListRPKX509 = []CertificateType{certTypeRawPublicKey, certTypeX509} + certTypesListX509RPK = []CertificateType{certTypeX509, certTypeRawPublicKey} + certTypesListX509Only = []CertificateType{certTypeX509} +) + +func addServerCertTypeTests() { + // Tests sending list of accepted server cert types in the ClientHello. + // TODO(crbug.com/467663225): Test server response and rest of the handshake. + for _, ver := range allVersions(tls) { + for _, test := range []struct { + name string + serverCertTypesAccepted []CertificateType + expectedClientHelloExtension []CertificateType + }{ + { + name: "RPKOnly", + serverCertTypesAccepted: certTypesListRPKOnly, + expectedClientHelloExtension: certTypesListRPKOnly, + }, + { + name: "RPKX509", + serverCertTypesAccepted: certTypesListRPKX509, + expectedClientHelloExtension: certTypesListRPKX509, + }, + { + name: "X509RPK", + serverCertTypesAccepted: certTypesListX509RPK, + expectedClientHelloExtension: certTypesListX509RPK, + }, + { + // Configuring the default cert type only omits the extension. + name: "DefaultOnly-Omitted", + serverCertTypesAccepted: certTypesListX509Only, + expectedClientHelloExtension: []CertificateType{}, + }, + } { + testCases = append(testCases, testCase{ + testType: clientTest, + name: fmt.Sprintf("ServerCertificateType-Client-Requests%s-%s", test.name, ver.name), + config: Config{ + MinVersion: ver.version, + MaxVersion: ver.version, + Bugs: ProtocolBugs{ + ExpectServerCertificateTypes: test.expectedClientHelloExtension, + }, + }, + flags: flagCertTypes("-accepted-peer-cert-types", test.serverCertTypesAccepted), + }) + } + } +} + +func addRawPublicKeyTests() { + addServerCertTypeTests() +}
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go index 33ab9e9..6554262 100644 --- a/ssl/test/runner/runner.go +++ b/ssl/test/runner/runner.go
@@ -297,6 +297,14 @@ return ret } +func flagCertTypes(flagName string, vals []CertificateType) []string { + ret := make([]string, 0, 2*len(vals)) + for _, val := range vals { + ret = append(ret, flagName, strconv.Itoa(int(val))) + } + return ret +} + func base64FlagValue(in []byte) string { return base64.StdEncoding.EncodeToString(in) } @@ -2273,6 +2281,7 @@ addPAKETests() addTrustAnchorTests() addPSKTests() + addRawPublicKeyTests() toAppend, err := convertToSplitHandshakeTests(testCases) if err != nil {
diff --git a/ssl/test/test_config.cc b/ssl/test/test_config.cc index b99985b..a0c7516 100644 --- a/ssl/test/test_config.cc +++ b/ssl/test/test_config.cc
@@ -627,6 +627,8 @@ SetValueFlag("-expect-not-resumable-across-names", &TestConfig::expect_resumable_across_names, false), BoolFlag("-no-server-name-ack", &TestConfig::no_server_name_ack), + IntVectorFlag("-accepted-peer-cert-types", + &TestConfig::accepted_peer_cert_types), }; std::sort(ret.begin(), ret.end(), FlagNameComparator{}); return ret; @@ -2572,6 +2574,12 @@ if (jdk11_workaround) { SSL_set_jdk11_workaround(ssl.get(), 1); } + if (!accepted_peer_cert_types.empty() && + !SSL_set1_accepted_peer_cert_types(ssl.get(), + accepted_peer_cert_types.data(), + accepted_peer_cert_types.size())) { + return nullptr; + } if (session != nullptr) { if (!is_server) {
diff --git a/ssl/test/test_config.h b/ssl/test/test_config.h index 164232f..abab643 100644 --- a/ssl/test/test_config.h +++ b/ssl/test/test_config.h
@@ -250,6 +250,7 @@ bool resumption_across_names_enabled = false; std::optional<bool> expect_resumable_across_names; bool no_server_name_ack = false; + std::vector<uint8_t> accepted_peer_cert_types; std::vector<const char *> handshaker_args;