Skip to content

Commit c38246b

Browse files
rheniummj-vivavis
andcommitted
ssl: add SSLContext#sigalgs= and #client_sigalgs=
Add methods for setting supported signature algorithms, corresponding to SSL_CTX_set1_sigalgs_list() and SSL_CTX_set1_client_sigalgs_list(), respectively. Co-authored-by: Markus Jung <[email protected]>
1 parent 330e66d commit c38246b

File tree

3 files changed

+134
-0
lines changed

3 files changed

+134
-0
lines changed

ext/openssl/extconf.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,9 @@ def find_openssl_library
135135
# compile options
136136
have_func("RAND_egd()", "openssl/rand.h")
137137

138+
# added in OpenSSL 1.0.2, not in LibreSSL yet
139+
have_func("SSL_CTX_set1_sigalgs_list(NULL, NULL)", ssl_h)
140+
138141
# added in 1.1.0, currently not in LibreSSL
139142
have_func("EVP_PBE_scrypt(\"\", 0, (unsigned char *)\"\", 0, 0, 0, 0, 0, NULL, 0)", evp_h)
140143

ext/openssl/ossl_ssl.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,6 +1079,57 @@ ossl_sslctx_set_ciphersuites(VALUE self, VALUE v)
10791079
return v;
10801080
}
10811081

1082+
#ifdef HAVE_SSL_CTX_SET1_SIGALGS_LIST
1083+
/*
1084+
* call-seq:
1085+
* ctx.sigalgs = "sigalg1:sigalg2:..."
1086+
*
1087+
* Sets the list of "supported signature algorithms" for this context.
1088+
*
1089+
* For a TLS client, the list is used in the "signature_algorithms" extension
1090+
* in the ClientHello messsage.
1091+
* For a server, the list is used by OpenSSL to determine the set of shared
1092+
* signature algorithms. OpenSSL will pick the most appropriate one from it.
1093+
*/
1094+
static VALUE
1095+
ossl_sslctx_set_sigalgs(VALUE self, VALUE v)
1096+
{
1097+
SSL_CTX *ctx;
1098+
1099+
rb_check_frozen(self);
1100+
GetSSLCTX(self, ctx);
1101+
1102+
if (!SSL_CTX_set1_sigalgs_list(ctx, StringValueCStr(v)))
1103+
ossl_raise(eSSLError, "SSL_CTX_set1_sigalgs_list");
1104+
1105+
return v;
1106+
}
1107+
1108+
/*
1109+
* call-seq:
1110+
* ctx.client_sigalgs = "sigalg1:sigalg2:..."
1111+
*
1112+
* Sets the list of "supported signature algorithms" for client authentication
1113+
* for this context.
1114+
*
1115+
* The list is used in the "signature_algorithms" extension in the
1116+
* CertificateRequest message.
1117+
*/
1118+
static VALUE
1119+
ossl_sslctx_set_client_sigalgs(VALUE self, VALUE v)
1120+
{
1121+
SSL_CTX *ctx;
1122+
1123+
rb_check_frozen(self);
1124+
GetSSLCTX(self, ctx);
1125+
1126+
if (!SSL_CTX_set1_client_sigalgs_list(ctx, StringValueCStr(v)))
1127+
ossl_raise(eSSLError, "SSL_CTX_set1_client_sigalgs_list");
1128+
1129+
return v;
1130+
}
1131+
#endif
1132+
10821133
#ifndef OPENSSL_NO_DH
10831134
/*
10841135
* call-seq:
@@ -2892,6 +2943,10 @@ Init_ossl_ssl(void)
28922943
rb_define_method(cSSLContext, "ciphers", ossl_sslctx_get_ciphers, 0);
28932944
rb_define_method(cSSLContext, "ciphers=", ossl_sslctx_set_ciphers, 1);
28942945
rb_define_method(cSSLContext, "ciphersuites=", ossl_sslctx_set_ciphersuites, 1);
2946+
#ifdef HAVE_SSL_CTX_SET1_SIGALGS_LIST
2947+
rb_define_method(cSSLContext, "sigalgs=", ossl_sslctx_set_sigalgs, 1);
2948+
rb_define_method(cSSLContext, "client_sigalgs=", ossl_sslctx_set_client_sigalgs, 1);
2949+
#endif
28952950
#ifndef OPENSSL_NO_DH
28962951
rb_define_method(cSSLContext, "tmp_dh=", ossl_sslctx_set_tmp_dh, 1);
28972952
#endif

test/openssl/test_ssl.rb

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1968,6 +1968,82 @@ def test_ciphers_method_bogus_csuite
19681968
) { ssl_ctx.ciphers = 'BOGUS' }
19691969
end
19701970

1971+
def test_sigalgs
1972+
omit "SSL_CTX_set1_sigalgs_list() not supported" if libressl?
1973+
1974+
svr_exts = [
1975+
["keyUsage","keyEncipherment,digitalSignature",true],
1976+
["subjectAltName","DNS:localhost",false],
1977+
]
1978+
ecdsa_key = Fixtures.pkey("p256")
1979+
ecdsa_cert = issue_cert(@svr, ecdsa_key, 10, svr_exts, @ca_cert, @ca_key)
1980+
1981+
ctx_proc = -> ctx {
1982+
# Unset values set by start_server
1983+
ctx.cert = ctx.key = ctx.extra_chain_cert = nil
1984+
ctx.add_certificate(@svr_cert, @svr_key, [@ca_cert]) # RSA
1985+
ctx.add_certificate(ecdsa_cert, ecdsa_key, [@ca_cert]) # ECDSA
1986+
}
1987+
start_server(ctx_proc: ctx_proc) do |port|
1988+
ctx1 = OpenSSL::SSL::SSLContext.new
1989+
ctx1.sigalgs = "RSA-PSS+SHA256:ECDSA+SHA256"
1990+
server_connect(port, ctx1) { |ssl|
1991+
assert_kind_of(OpenSSL::PKey::RSA, ssl.peer_cert.public_key)
1992+
ssl.puts("abc"); ssl.gets
1993+
}
1994+
1995+
ctx2 = OpenSSL::SSL::SSLContext.new
1996+
ctx2.sigalgs = "ED25519:ECDSA+SHA256"
1997+
server_connect(port, ctx2) { |ssl|
1998+
assert_kind_of(OpenSSL::PKey::EC, ssl.peer_cert.public_key)
1999+
ssl.puts("abc"); ssl.gets
2000+
}
2001+
end
2002+
2003+
# Frozen
2004+
ssl_ctx = OpenSSL::SSL::SSLContext.new
2005+
ssl_ctx.freeze
2006+
assert_raise(FrozenError) { ssl_ctx.sigalgs = "ECDSA+SHA256:RSA+SHA256" }
2007+
2008+
# Bogus
2009+
ssl_ctx = OpenSSL::SSL::SSLContext.new
2010+
assert_raise(TypeError) { ssl_ctx.sigalgs = nil }
2011+
assert_raise(OpenSSL::SSL::SSLError) { ssl_ctx.sigalgs = "BOGUS" }
2012+
end
2013+
2014+
def test_client_sigalgs
2015+
cli_exts = [
2016+
["keyUsage","keyEncipherment,digitalSignature",true],
2017+
["subjectAltName","DNS:localhost",false],
2018+
]
2019+
ecdsa_key = Fixtures.pkey("p256")
2020+
ecdsa_cert = issue_cert(@cli, ecdsa_key, 10, cli_exts, @ca_cert, @ca_key)
2021+
2022+
ctx_proc = -> ctx {
2023+
store = OpenSSL::X509::Store.new
2024+
store.add_cert(@ca_cert)
2025+
store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT
2026+
ctx.cert_store = store
2027+
ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
2028+
ctx.client_sigalgs = "ECDSA+SHA256"
2029+
}
2030+
start_server(ctx_proc: ctx_proc, ignore_listener_error: true) do |port|
2031+
ctx1 = OpenSSL::SSL::SSLContext.new
2032+
ctx1.add_certificate(@cli_cert, @cli_key) # RSA
2033+
assert_handshake_error {
2034+
server_connect(port, ctx1) { |ssl|
2035+
ssl.puts("abc"); ssl.gets
2036+
}
2037+
}
2038+
2039+
ctx2 = OpenSSL::SSL::SSLContext.new
2040+
ctx2.add_certificate(ecdsa_cert, ecdsa_key) # ECDSA
2041+
server_connect(port, ctx2) { |ssl|
2042+
ssl.puts("abc"); ssl.gets
2043+
}
2044+
end
2045+
end
2046+
19712047
def test_connect_works_when_setting_dh_callback_to_nil
19722048
omit "AWS-LC does not support DHE ciphersuites" if aws_lc?
19732049

0 commit comments

Comments
 (0)