* ext/openssl/ossl.c/.h: Added ossl_x509_name_sk2ary.

* ext/openssl/ossl.c: Replaced ossl_x509_ary2k by generic macro to
  simplify future conversions.
* ext/openssl/ossl_ssl.c: Implement SSLSocket#client_ca.
* test/openssl/test_ssl.rb: Add test for SSLSocket#client_ca.
  Thanks to Ippei Obayashi for providing the patch!
  [ Ruby 1.9 - Feature #4481 ] [ruby-core:35461]


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@32337 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
emboss 2011-06-30 14:48:52 +00:00
parent c4becf8aaf
commit 1dcd4b325e
5 changed files with 108 additions and 41 deletions

View File

@ -1,3 +1,13 @@
Thu Jun 30 23:43:30 2011 Martin Bosslet <Martin.Bosslet@googlemail.com>
* ext/openssl/ossl.c/.h: Added ossl_x509_name_sk2ary.
* ext/openssl/ossl.c: Replaced ossl_x509_ary2k by generic macro to
simplify future conversions.
* ext/openssl/ossl_ssl.c: Implement SSLSocket#client_ca.
* test/openssl/test_ssl.rb: Add test for SSLSocket#client_ca.
Thanks to Ippei Obayashi for providing the patch!
[ Ruby 1.9 - Feature #4481 ] [ruby-core:35461]
Thu Jun 30 22:38:58 2011 Koichi Sasada <ko1@atdot.net> Thu Jun 30 22:38:58 2011 Koichi Sasada <ko1@atdot.net>
* benchmark/bm_vm2_defined_method.rb: added to measure performance of * benchmark/bm_vm2_defined_method.rb: added to measure performance of

View File

@ -47,48 +47,53 @@ string2hex(const unsigned char *buf, int buf_len, char **hexbuf, int *hexbuf_len
/* /*
* Data Conversion * Data Conversion
*/ */
STACK_OF(X509) * #define OSSL_IMPL_ARY2SK(name, type, expected_class, dup) \
ossl_x509_ary2sk0(VALUE ary) STACK_OF(type) * \
{ ossl_##name##_ary2sk0(VALUE ary) \
STACK_OF(X509) *sk; { \
VALUE val; STACK_OF(type) *sk; \
X509 *x509; VALUE val; \
int i; type *x; \
int i; \
Check_Type(ary, T_ARRAY); \
sk = sk_X509_new_null(); Check_Type(ary, T_ARRAY); \
if (!sk) ossl_raise(eOSSLError, NULL); sk = sk_##type##_new_null(); \
if (!sk) ossl_raise(eOSSLError, NULL); \
for (i = 0; i < RARRAY_LEN(ary); i++) { \
val = rb_ary_entry(ary, i); for (i = 0; i < RARRAY_LEN(ary); i++) { \
if (!rb_obj_is_kind_of(val, cX509Cert)) { val = rb_ary_entry(ary, i); \
sk_X509_pop_free(sk, X509_free); if (!rb_obj_is_kind_of(val, expected_class)) { \
ossl_raise(eOSSLError, "object not X509 cert in array"); sk_##type##_pop_free(sk, type##_free); \
} ossl_raise(eOSSLError, "object in array not" \
x509 = DupX509CertPtr(val); /* NEED TO DUP */ " of class ##type##"); \
sk_X509_push(sk, x509); } \
} x = dup(val); /* NEED TO DUP */ \
return sk; sk_##type##_push(sk, x); \
} } \
return sk; \
STACK_OF(X509) * } \
ossl_protect_x509_ary2sk(VALUE ary, int *status) \
{ STACK_OF(type) * \
return (STACK_OF(X509)*)rb_protect((VALUE(*)_((VALUE)))ossl_x509_ary2sk0, ossl_protect_##name##_ary2sk(VALUE ary, int *status) \
ary, status); { \
} return (STACK_OF(type)*)rb_protect( \
(VALUE(*)_((VALUE)))ossl_##name##_ary2sk0, \
STACK_OF(X509) * ary, \
ossl_x509_ary2sk(VALUE ary) status); \
{ } \
STACK_OF(X509) *sk; \
int status = 0; STACK_OF(type) * \
ossl_##name##_ary2sk(VALUE ary) \
sk = ossl_protect_x509_ary2sk(ary, &status); { \
if(status) rb_jump_tag(status); STACK_OF(type) *sk; \
int status = 0; \
return sk; \
sk = ossl_protect_##name##_ary2sk(ary, &status); \
if (status) rb_jump_tag(status); \
\
return sk; \
} }
OSSL_IMPL_ARY2SK(x509, X509, cX509Cert, DupX509CertPtr)
#define OSSL_IMPL_SK2ARY(name, type) \ #define OSSL_IMPL_SK2ARY(name, type) \
VALUE \ VALUE \
@ -117,6 +122,7 @@ ossl_##name##_sk2ary(STACK_OF(type) *sk) \
} }
OSSL_IMPL_SK2ARY(x509, X509) OSSL_IMPL_SK2ARY(x509, X509)
OSSL_IMPL_SK2ARY(x509crl, X509_CRL) OSSL_IMPL_SK2ARY(x509crl, X509_CRL)
OSSL_IMPL_SK2ARY(x509name, X509_NAME)
static VALUE static VALUE
ossl_str_new(int size) ossl_str_new(int size)

View File

@ -126,6 +126,7 @@ STACK_OF(X509) *ossl_x509_ary2sk(VALUE);
STACK_OF(X509) *ossl_protect_x509_ary2sk(VALUE,int*); STACK_OF(X509) *ossl_protect_x509_ary2sk(VALUE,int*);
VALUE ossl_x509_sk2ary(STACK_OF(X509) *certs); VALUE ossl_x509_sk2ary(STACK_OF(X509) *certs);
VALUE ossl_x509crl_sk2ary(STACK_OF(X509_CRL) *crl); VALUE ossl_x509crl_sk2ary(STACK_OF(X509_CRL) *crl);
VALUE ossl_x509name_sk2ary(STACK_OF(X509_NAME) *names);
VALUE ossl_buf2str(char *buf, int len); VALUE ossl_buf2str(char *buf, int len);
#define ossl_str_adjust(str, p) \ #define ossl_str_adjust(str, p) \
do{\ do{\

View File

@ -1643,6 +1643,33 @@ ossl_ssl_get_verify_result(VALUE self)
return INT2FIX(SSL_get_verify_result(ssl)); return INT2FIX(SSL_get_verify_result(ssl));
} }
/*
* call-seq:
* ssl.client_ca => [x509name, ...]
*
* Returns the list of client CAs. Please note that in contrast to
* SSLContext#client_ca= no array of X509::Certificate is returned but
* X509::Name instances of the CA's subject distinguished name.
*
* In server mode, returns the list set by SSLContext#client_ca=.
* In client mode, returns the list of client CAs sent from the server.
*/
static VALUE
ossl_ssl_get_client_ca_list(VALUE self)
{
SSL *ssl;
STACK_OF(X509_NAME) *ca;
Data_Get_Struct(self, SSL, ssl);
if (!ssl) {
rb_warning("SSL session is not started yet.");
return Qnil;
}
ca = SSL_get_client_CA_list(ssl);
return ossl_x509name_sk2ary(ca);
}
void void
Init_ossl_ssl() Init_ossl_ssl()
{ {
@ -1930,6 +1957,7 @@ Init_ossl_ssl()
rb_define_method(cSSLSocket, "session_reused?", ossl_ssl_session_reused, 0); rb_define_method(cSSLSocket, "session_reused?", ossl_ssl_session_reused, 0);
rb_define_method(cSSLSocket, "session=", ossl_ssl_set_session, 1); rb_define_method(cSSLSocket, "session=", ossl_ssl_set_session, 1);
rb_define_method(cSSLSocket, "verify_result", ossl_ssl_get_verify_result, 0); rb_define_method(cSSLSocket, "verify_result", ossl_ssl_get_verify_result, 0);
rb_define_method(cSSLSocket, "client_ca", ossl_ssl_get_client_ca_list, 0);
#define ossl_ssl_def_const(x) rb_define_const(mSSL, #x, INT2NUM(SSL_##x)) #define ossl_ssl_def_const(x) rb_define_const(mSSL, #x, INT2NUM(SSL_##x))

View File

@ -135,6 +135,28 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
} }
end end
def test_client_ca
ctx_proc = Proc.new do |ctx|
ctx.client_ca = [@ca_cert]
end
vflag = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
start_server(PORT, vflag, true, :ctx_proc => ctx_proc){|server, port|
ctx = OpenSSL::SSL::SSLContext.new
client_ca_from_server = nil
ctx.client_cert_cb = Proc.new do |sslconn|
client_ca_from_server = sslconn.client_ca
[@cli_cert, @cli_key]
end
sock = TCPSocket.new("127.0.0.1", port)
ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)
ssl.sync_close = true
ssl.connect
assert_equal([@ca], client_ca_from_server)
ssl.close
}
end
def test_starttls def test_starttls
start_server(PORT, OpenSSL::SSL::VERIFY_NONE, false){|server, port| start_server(PORT, OpenSSL::SSL::VERIFY_NONE, false){|server, port|
sock = TCPSocket.new("127.0.0.1", port) sock = TCPSocket.new("127.0.0.1", port)