Skip to content

Commit 3ef9907

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 1758690 commit 3ef9907

File tree

3 files changed

+142
-0
lines changed

3 files changed

+142
-0
lines changed

ext/openssl/extconf.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,11 @@ 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+
# added in OpenSSL 1.0.2, not in LibreSSL or AWS-LC yet
141+
have_func("SSL_CTX_set1_client_sigalgs_list(NULL, NULL)", ssl_h)
142+
138143
# added in 1.1.0, currently not in LibreSSL
139144
have_func("EVP_PBE_scrypt(\"\", 0, (unsigned char *)\"\", 0, 0, 0, 0, 0, NULL, 0)", evp_h)
140145

ext/openssl/ossl_ssl.c

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,6 +1079,59 @@ 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+
#endif
1108+
1109+
#ifdef HAVE_SSL_CTX_SET1_CLIENT_SIGALGS_LIST
1110+
/*
1111+
* call-seq:
1112+
* ctx.client_sigalgs = "sigalg1:sigalg2:..."
1113+
*
1114+
* Sets the list of "supported signature algorithms" for client authentication
1115+
* for this context.
1116+
*
1117+
* The list is used in the "signature_algorithms" extension in the
1118+
* CertificateRequest message.
1119+
*/
1120+
static VALUE
1121+
ossl_sslctx_set_client_sigalgs(VALUE self, VALUE v)
1122+
{
1123+
SSL_CTX *ctx;
1124+
1125+
rb_check_frozen(self);
1126+
GetSSLCTX(self, ctx);
1127+
1128+
if (!SSL_CTX_set1_client_sigalgs_list(ctx, StringValueCStr(v)))
1129+
ossl_raise(eSSLError, "SSL_CTX_set1_client_sigalgs_list");
1130+
1131+
return v;
1132+
}
1133+
#endif
1134+
10821135
#ifndef OPENSSL_NO_DH
10831136
/*
10841137
* call-seq:
@@ -2892,6 +2945,12 @@ Init_ossl_ssl(void)
28922945
rb_define_method(cSSLContext, "ciphers", ossl_sslctx_get_ciphers, 0);
28932946
rb_define_method(cSSLContext, "ciphers=", ossl_sslctx_set_ciphers, 1);
28942947
rb_define_method(cSSLContext, "ciphersuites=", ossl_sslctx_set_ciphersuites, 1);
2948+
#ifdef HAVE_SSL_CTX_SET1_SIGALGS_LIST // Not in LibreSSL yet
2949+
rb_define_method(cSSLContext, "sigalgs=", ossl_sslctx_set_sigalgs, 1);
2950+
#endif
2951+
#ifdef HAVE_SSL_CTX_SET1_CLIENT_SIGALGS_LIST // Not in LibreSSL or AWS-LC yet
2952+
rb_define_method(cSSLContext, "client_sigalgs=", ossl_sslctx_set_client_sigalgs, 1);
2953+
#endif
28952954
#ifndef OPENSSL_NO_DH
28962955
rb_define_method(cSSLContext, "tmp_dh=", ossl_sslctx_set_tmp_dh, 1);
28972956
#endif

test/openssl/test_ssl.rb

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1968,6 +1968,84 @@ 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_rsae_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_secp256r1_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+
omit "SSL_CTX_set1_client_sigalgs_list() not supported" if libressl? || aws_lc?
2016+
2017+
cli_exts = [
2018+
["keyUsage","keyEncipherment,digitalSignature",true],
2019+
["subjectAltName","DNS:localhost",false],
2020+
]
2021+
ecdsa_key = Fixtures.pkey("p256")
2022+
ecdsa_cert = issue_cert(@cli, ecdsa_key, 10, cli_exts, @ca_cert, @ca_key)
2023+
2024+
ctx_proc = -> ctx {
2025+
store = OpenSSL::X509::Store.new
2026+
store.add_cert(@ca_cert)
2027+
store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT
2028+
ctx.cert_store = store
2029+
ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
2030+
ctx.client_sigalgs = "ECDSA+SHA256"
2031+
}
2032+
start_server(ctx_proc: ctx_proc, ignore_listener_error: true) do |port|
2033+
ctx1 = OpenSSL::SSL::SSLContext.new
2034+
ctx1.add_certificate(@cli_cert, @cli_key) # RSA
2035+
assert_handshake_error {
2036+
server_connect(port, ctx1) { |ssl|
2037+
ssl.puts("abc"); ssl.gets
2038+
}
2039+
}
2040+
2041+
ctx2 = OpenSSL::SSL::SSLContext.new
2042+
ctx2.add_certificate(ecdsa_cert, ecdsa_key) # ECDSA
2043+
server_connect(port, ctx2) { |ssl|
2044+
ssl.puts("abc"); ssl.gets
2045+
}
2046+
end
2047+
end
2048+
19712049
def test_connect_works_when_setting_dh_callback_to_nil
19722050
omit "AWS-LC does not support DHE ciphersuites" if aws_lc?
19732051

0 commit comments

Comments
 (0)