@@ -64,9 +64,11 @@ static VALUE eSSLErrorWaitWritable;
6464#define ossl_sslctx_get_client_cert_cb (o ) rb_iv_get((o),"@client_cert_cb")
6565#define ossl_sslctx_get_tmp_ecdh_cb (o ) rb_iv_get((o),"@tmp_ecdh_callback")
6666#define ossl_sslctx_get_sess_id_ctx (o ) rb_iv_get((o),"@session_id_context")
67+ #define ossl_sslctx_get_verify_hostname (o ) rb_iv_get((o),"@verify_hostname")
6768
6869#define ossl_ssl_get_io (o ) rb_iv_get((o),"@io")
6970#define ossl_ssl_get_ctx (o ) rb_iv_get((o),"@context")
71+ #define ossl_ssl_get_hostname_v (o ) rb_iv_get((o),"@hostname")
7072#define ossl_ssl_get_x509 (o ) rb_iv_get((o),"@x509")
7173#define ossl_ssl_get_key (o ) rb_iv_get((o),"@key")
7274
@@ -319,14 +321,48 @@ ossl_tmp_ecdh_callback(SSL *ssl, int is_export, int keylength)
319321}
320322#endif
321323
324+ static VALUE
325+ call_verify_certificate_identity (VALUE ctx_v )
326+ {
327+ X509_STORE_CTX * ctx = (X509_STORE_CTX * )ctx_v ;
328+ SSL * ssl ;
329+ VALUE ssl_obj , hostname , cert_obj ;
330+
331+ ssl = X509_STORE_CTX_get_ex_data (ctx , SSL_get_ex_data_X509_STORE_CTX_idx ());
332+ ssl_obj = (VALUE )SSL_get_ex_data (ssl , ossl_ssl_ex_ptr_idx );
333+ hostname = ossl_ssl_get_hostname_v (ssl_obj );
334+
335+ if (!RTEST (hostname )) {
336+ rb_warning ("verify_hostname requires hostname to be set" );
337+ return Qtrue ;
338+ }
339+
340+ cert_obj = ossl_x509_new (X509_STORE_CTX_get_current_cert (ctx ));
341+ return rb_funcall (mSSL , rb_intern ("verify_certificate_identity" ), 2 ,
342+ cert_obj , hostname );
343+ }
344+
322345static int
323346ossl_ssl_verify_callback (int preverify_ok , X509_STORE_CTX * ctx )
324347{
325- VALUE cb ;
348+ VALUE cb , ssl_obj , verify_hostname , ret ;
326349 SSL * ssl ;
350+ int status ;
327351
328352 ssl = X509_STORE_CTX_get_ex_data (ctx , SSL_get_ex_data_X509_STORE_CTX_idx ());
329353 cb = (VALUE )SSL_get_ex_data (ssl , ossl_ssl_ex_vcb_idx );
354+ ssl_obj = (VALUE )SSL_get_ex_data (ssl , ossl_ssl_ex_ptr_idx );
355+ verify_hostname = ossl_sslctx_get_verify_hostname (ossl_ssl_get_ctx (ssl_obj ));
356+
357+ if (preverify_ok && RTEST (verify_hostname ) && !SSL_is_server (ssl ) &&
358+ !X509_STORE_CTX_get_error_depth (ctx )) {
359+ ret = rb_protect (call_verify_certificate_identity , (VALUE )ctx , & status );
360+ if (status ) {
361+ rb_ivar_set (ssl_obj , ID_callback_state , INT2NUM (status ));
362+ return 0 ;
363+ }
364+ preverify_ok = ret == Qtrue ;
365+ }
330366
331367 return ossl_verify_cb_call (cb , preverify_ok , ctx );
332368}
@@ -2278,10 +2314,19 @@ Init_ossl_ssl(void)
22782314 * +store_context+ is an OpenSSL::X509::StoreContext containing the
22792315 * context used for certificate verification.
22802316 *
2281- * If the callback returns false verification is stopped.
2317+ * If the callback returns false, the chain verification is immediately
2318+ * stopped and a bad_certificate alert is then sent.
22822319 */
22832320 rb_attr (cSSLContext , rb_intern ("verify_callback" ), 1 , 1 , Qfalse );
22842321
2322+ /*
2323+ * Whether to check the server certificate is valid for the hostname.
2324+ *
2325+ * In order to make this work, verify_mode must be set to VERIFY_PEER and
2326+ * the server hostname must be given by OpenSSL::SSL::SSLSocket#hostname=.
2327+ */
2328+ rb_attr (cSSLContext , rb_intern ("verify_hostname" ), 1 , 1 , Qfalse );
2329+
22852330 /*
22862331 * An OpenSSL::X509::Store used for certificate verification
22872332 */
0 commit comments