diff options
author | SHIBATA Hiroshi <hsbt@ruby-lang.org> | 2015-01-11 12:12:11 +0900 |
---|---|---|
committer | SHIBATA Hiroshi <hsbt@ruby-lang.org> | 2015-01-11 12:12:11 +0900 |
commit | 49d6abbf144dcbe873b7cc67d7f6a43c44d657e4 (patch) | |
tree | 68aee518ff4a7fff7ef125d2d3aca53007743f74 | |
parent | 98311e6be14b723aba8cd4bba353c61b2a68153f (diff) | |
parent | cd90a9603593e1e1e7181a8738e32c2f9f399b05 (diff) | |
download | ruby-openssl-49d6abbf144dcbe873b7cc67d7f6a43c44d657e4.tar.gz |
Merge pull request #2 from ruby/merge-trunk
Sync with ruby trunk
54 files changed, 727 insertions, 288 deletions
diff --git a/ext/openssl/ossl.h b/ext/openssl/ossl.h index c843c06f..a53f0f41 100644 --- a/ext/openssl/ossl.h +++ b/ext/openssl/ossl.h @@ -64,6 +64,9 @@ extern "C" { #include <openssl/rand.h> #include <openssl/conf.h> #include <openssl/conf_api.h> +#if !defined(_WIN32) +# include <openssl/crypto.h> +#endif #undef X509_NAME #undef PKCS7_SIGNER_INFO #if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_EVP_CIPHER_CTX_ENGINE) diff --git a/ext/openssl/ossl_bn.c b/ext/openssl/ossl_bn.c index 0af7d639..58796fe2 100644 --- a/ext/openssl/ossl_bn.c +++ b/ext/openssl/ossl_bn.c @@ -45,7 +45,7 @@ ossl_bn_size(const void *ptr) static const rb_data_type_t ossl_bn_type = { "OpenSSL/BN", {0, ossl_bn_free, ossl_bn_size,}, - NULL, NULL, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, }; diff --git a/ext/openssl/ossl_cipher.c b/ext/openssl/ossl_cipher.c index 0efadd19..08fdacfb 100644 --- a/ext/openssl/ossl_cipher.c +++ b/ext/openssl/ossl_cipher.c @@ -43,7 +43,7 @@ static size_t ossl_cipher_memsize(const void *ptr); static const rb_data_type_t ossl_cipher_type = { "OpenSSL/Cipher", {0, ossl_cipher_free, ossl_cipher_memsize,}, - NULL, NULL, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, }; @@ -346,6 +346,33 @@ ossl_cipher_pkcs5_keyivgen(int argc, VALUE *argv, VALUE self) return Qnil; } +static int +ossl_cipher_update_long(EVP_CIPHER_CTX *ctx, unsigned char *out, long *out_len_ptr, + const unsigned char *in, long in_len) +{ + int out_part_len; + long out_len = 0; +#define UPDATE_LENGTH_LIMIT INT_MAX + +#if SIZEOF_LONG > UPDATE_LENGTH_LIMIT + if (in_len > UPDATE_LENGTH_LIMIT) { + const int in_part_len = (UPDATE_LENGTH_LIMIT / 2 + 1) & ~1; + do { + if (!EVP_CipherUpdate(ctx, out ? (out + out_len) : 0, + &out_part_len, in, in_part_len)) + return 0; + out_len += out_part_len; + in += in_part_len; + } while ((in_len -= in_part_len) > UPDATE_LENGTH_LIMIT); + } +#endif + if (!EVP_CipherUpdate(ctx, out ? (out + out_len) : 0, + &out_part_len, in, (int)in_len)) + return 0; + if (out_len_ptr) *out_len_ptr = out_len += out_part_len; + return 1; +} + /* * call-seq: * cipher.update(data [, buffer]) -> string or buffer @@ -364,17 +391,21 @@ ossl_cipher_update(int argc, VALUE *argv, VALUE self) { EVP_CIPHER_CTX *ctx; unsigned char *in; - int in_len, out_len; + long in_len, out_len; VALUE data, str; rb_scan_args(argc, argv, "11", &data, &str); StringValue(data); in = (unsigned char *)RSTRING_PTR(data); - if ((in_len = RSTRING_LENINT(data)) == 0) + if ((in_len = RSTRING_LEN(data)) == 0) ossl_raise(rb_eArgError, "data must not be empty"); GetCipher(self, ctx); out_len = in_len+EVP_CIPHER_CTX_block_size(ctx); + if (out_len <= 0) { + ossl_raise(rb_eRangeError, + "data too big to make output buffer: %ld bytes", in_len); + } if (NIL_P(str)) { str = rb_str_new(0, out_len); @@ -383,7 +414,7 @@ ossl_cipher_update(int argc, VALUE *argv, VALUE self) rb_str_resize(str, out_len); } - if (!EVP_CipherUpdate(ctx, (unsigned char *)RSTRING_PTR(str), &out_len, in, in_len)) + if (!ossl_cipher_update_long(ctx, (unsigned char *)RSTRING_PTR(str), &out_len, in, in_len)) ossl_raise(eCipherError, NULL); assert(out_len < RSTRING_LEN(str)); rb_str_set_len(str, out_len); @@ -523,17 +554,16 @@ ossl_cipher_set_auth_data(VALUE self, VALUE data) { EVP_CIPHER_CTX *ctx; unsigned char *in; - int in_len; - int out_len; + long in_len, out_len; StringValue(data); in = (unsigned char *) RSTRING_PTR(data); - in_len = RSTRING_LENINT(data); + in_len = RSTRING_LEN(data); GetCipher(self, ctx); - if (!EVP_CipherUpdate(ctx, NULL, &out_len, in, in_len)) + if (!ossl_cipher_update_long(ctx, NULL, &out_len, in, in_len)) ossl_raise(eCipherError, "couldn't set additional authenticated data"); return data; diff --git a/ext/openssl/ossl_digest.c b/ext/openssl/ossl_digest.c index bf618c83..6ce5316f 100644 --- a/ext/openssl/ossl_digest.c +++ b/ext/openssl/ossl_digest.c @@ -11,7 +11,7 @@ #include "ossl.h" #define GetDigest(obj, ctx) do { \ - Data_Get_Struct((obj), EVP_MD_CTX, (ctx)); \ + TypedData_Get_Struct((obj), EVP_MD_CTX, &ossl_digest_type, (ctx)); \ if (!(ctx)) { \ ossl_raise(rb_eRuntimeError, "Digest CTX wasn't initialized!"); \ } \ @@ -29,6 +29,20 @@ VALUE eDigestError; static VALUE ossl_digest_alloc(VALUE klass); +static void +ossl_digest_free(void *ctx) +{ + EVP_MD_CTX_destroy(ctx); +} + +static const rb_data_type_t ossl_digest_type = { + "OpenSSL/Digest", + { + 0, ossl_digest_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, +}; + /* * Public */ @@ -87,7 +101,7 @@ ossl_digest_alloc(VALUE klass) ctx = EVP_MD_CTX_create(); if (ctx == NULL) ossl_raise(rb_eRuntimeError, "EVP_MD_CTX_create() failed"); - obj = Data_Wrap_Struct(klass, 0, EVP_MD_CTX_destroy, ctx); + obj = TypedData_Wrap_Struct(klass, &ossl_digest_type, ctx); return obj; } diff --git a/ext/openssl/ossl_engine.c b/ext/openssl/ossl_engine.c index 96bce5e2..04b5879b 100644 --- a/ext/openssl/ossl_engine.c +++ b/ext/openssl/ossl_engine.c @@ -16,10 +16,10 @@ if (!(engine)) { \ ossl_raise(rb_eRuntimeError, "ENGINE wasn't initialized."); \ } \ - (obj) = Data_Wrap_Struct((klass), 0, ENGINE_free, (engine)); \ + (obj) = TypedData_Wrap_Struct((klass), &ossl_engine_type, (engine)); \ } while(0) #define GetEngine(obj, engine) do { \ - Data_Get_Struct((obj), ENGINE, (engine)); \ + TypedData_Get_Struct((obj), ENGINE, &ossl_engine_type, (engine)); \ if (!(engine)) { \ ossl_raise(rb_eRuntimeError, "ENGINE wasn't initialized."); \ } \ @@ -57,6 +57,20 @@ do{\ }\ }while(0) +static void +ossl_engine_free(void *engine) +{ + ENGINE_free(engine); +} + +static const rb_data_type_t ossl_engine_type = { + "OpenSSL/Engine", + { + 0, ossl_engine_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, +}; + /* Document-method: OpenSSL::Engine.load * * call-seq: diff --git a/ext/openssl/ossl_hmac.c b/ext/openssl/ossl_hmac.c index 516e3ed8..74fc962b 100644 --- a/ext/openssl/ossl_hmac.c +++ b/ext/openssl/ossl_hmac.c @@ -13,9 +13,9 @@ #include "ossl.h" #define MakeHMAC(obj, klass, ctx) \ - (obj) = Data_Make_Struct((klass), HMAC_CTX, 0, ossl_hmac_free, (ctx)) + (obj) = TypedData_Make_Struct((klass), HMAC_CTX, &ossl_hmac_type, (ctx)) #define GetHMAC(obj, ctx) do { \ - Data_Get_Struct((obj), HMAC_CTX, (ctx)); \ + TypedData_Get_Struct((obj), HMAC_CTX, &ossl_hmac_type, (ctx)); \ if (!(ctx)) { \ ossl_raise(rb_eRuntimeError, "HMAC wasn't initialized"); \ } \ @@ -39,12 +39,20 @@ VALUE eHMACError; * Private */ static void -ossl_hmac_free(HMAC_CTX *ctx) +ossl_hmac_free(void *ctx) { HMAC_CTX_cleanup(ctx); ruby_xfree(ctx); } +static const rb_data_type_t ossl_hmac_type = { + "OpenSSL/HMAC", + { + 0, ossl_hmac_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, +}; + static VALUE ossl_hmac_alloc(VALUE klass) { diff --git a/ext/openssl/ossl_ns_spki.c b/ext/openssl/ossl_ns_spki.c index 965bbe87..d2a52e6f 100644 --- a/ext/openssl/ossl_ns_spki.c +++ b/ext/openssl/ossl_ns_spki.c @@ -14,10 +14,10 @@ if (!(spki)) { \ ossl_raise(rb_eRuntimeError, "SPKI wasn't initialized!"); \ } \ - (obj) = Data_Wrap_Struct((klass), 0, NETSCAPE_SPKI_free, (spki)); \ + (obj) = TypedData_Wrap_Struct((klass), &ossl_netscape_spki_type, (spki)); \ } while (0) #define GetSPKI(obj, spki) do { \ - Data_Get_Struct((obj), NETSCAPE_SPKI, (spki)); \ + TypedData_Get_Struct((obj), NETSCAPE_SPKI, &ossl_netscape_spki_type, (spki)); \ if (!(spki)) { \ ossl_raise(rb_eRuntimeError, "SPKI wasn't initialized!"); \ } \ @@ -37,6 +37,21 @@ VALUE eSPKIError; /* * Private functions */ + +static void +ossl_netscape_spki_free(void *spki) +{ + NETSCAPE_SPKI_free(spki); +} + +static const rb_data_type_t ossl_netscape_spki_type = { + "OpenSSL/NETSCAPE_SPKI", + { + 0, ossl_netscape_spki_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, +}; + static VALUE ossl_spki_alloc(VALUE klass) { diff --git a/ext/openssl/ossl_ocsp.c b/ext/openssl/ossl_ocsp.c index 9848ba27..dc31d79c 100644 --- a/ext/openssl/ossl_ocsp.c +++ b/ext/openssl/ossl_ocsp.c @@ -15,10 +15,10 @@ #define WrapOCSPReq(klass, obj, req) do { \ if(!(req)) ossl_raise(rb_eRuntimeError, "Request wasn't initialized!"); \ - (obj) = Data_Wrap_Struct((klass), 0, OCSP_REQUEST_free, (req)); \ + (obj) = TypedData_Wrap_Struct((klass), &ossl_ocsp_request_type, (req)); \ } while (0) #define GetOCSPReq(obj, req) do { \ - Data_Get_Struct((obj), OCSP_REQUEST, (req)); \ + TypedData_Get_Struct((obj), OCSP_REQUEST, &ossl_ocsp_request_type, (req)); \ if(!(req)) ossl_raise(rb_eRuntimeError, "Request wasn't initialized!"); \ } while (0) #define SafeGetOCSPReq(obj, req) do { \ @@ -28,10 +28,10 @@ #define WrapOCSPRes(klass, obj, res) do { \ if(!(res)) ossl_raise(rb_eRuntimeError, "Response wasn't initialized!"); \ - (obj) = Data_Wrap_Struct((klass), 0, OCSP_RESPONSE_free, (res)); \ + (obj) = TypedData_Wrap_Struct((klass), &ossl_ocsp_response_type, (res)); \ } while (0) #define GetOCSPRes(obj, res) do { \ - Data_Get_Struct((obj), OCSP_RESPONSE, (res)); \ + TypedData_Get_Struct((obj), OCSP_RESPONSE, &ossl_ocsp_response_type, (res)); \ if(!(res)) ossl_raise(rb_eRuntimeError, "Response wasn't initialized!"); \ } while (0) #define SafeGetOCSPRes(obj, res) do { \ @@ -41,10 +41,10 @@ #define WrapOCSPBasicRes(klass, obj, res) do { \ if(!(res)) ossl_raise(rb_eRuntimeError, "Response wasn't initialized!"); \ - (obj) = Data_Wrap_Struct((klass), 0, OCSP_BASICRESP_free, (res)); \ + (obj) = TypedData_Wrap_Struct((klass), &ossl_ocsp_basicresp_type, (res)); \ } while (0) #define GetOCSPBasicRes(obj, res) do { \ - Data_Get_Struct((obj), OCSP_BASICRESP, (res)); \ + TypedData_Get_Struct((obj), OCSP_BASICRESP, &ossl_ocsp_basicresp_type, (res)); \ if(!(res)) ossl_raise(rb_eRuntimeError, "Response wasn't initialized!"); \ } while (0) #define SafeGetOCSPBasicRes(obj, res) do { \ @@ -54,10 +54,10 @@ #define WrapOCSPCertId(klass, obj, cid) do { \ if(!(cid)) ossl_raise(rb_eRuntimeError, "Cert ID wasn't initialized!"); \ - (obj) = Data_Wrap_Struct((klass), 0, OCSP_CERTID_free, (cid)); \ + (obj) = TypedData_Wrap_Struct((klass), &ossl_ocsp_certid_type, (cid)); \ } while (0) #define GetOCSPCertId(obj, cid) do { \ - Data_Get_Struct((obj), OCSP_CERTID, (cid)); \ + TypedData_Get_Struct((obj), OCSP_CERTID, &ossl_ocsp_certid_type, (cid)); \ if(!(cid)) ossl_raise(rb_eRuntimeError, "Cert ID wasn't initialized!"); \ } while (0) #define SafeGetOCSPCertId(obj, cid) do { \ @@ -72,6 +72,62 @@ VALUE cOCSPRes; VALUE cOCSPBasicRes; VALUE cOCSPCertId; +static void +ossl_ocsp_request_free(void *ptr) +{ + OCSP_REQUEST_free(ptr); +} + +static const rb_data_type_t ossl_ocsp_request_type = { + "OpenSSL/OCSP/REQUEST", + { + 0, ossl_ocsp_request_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, +}; + +static void +ossl_ocsp_response_free(void *ptr) +{ + OCSP_RESPONSE_free(ptr); +} + +static const rb_data_type_t ossl_ocsp_response_type = { + "OpenSSL/OCSP/RESPONSE", + { + 0, ossl_ocsp_response_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, +}; + +static void +ossl_ocsp_basicresp_free(void *ptr) +{ + OCSP_BASICRESP_free(ptr); +} + +static const rb_data_type_t ossl_ocsp_basicresp_type = { + "OpenSSL/OCSP/BASICRESP", + { + 0, ossl_ocsp_basicresp_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, +}; + +static void +ossl_ocsp_certid_free(void *ptr) +{ + OCSP_CERTID_free(ptr); +} + +static const rb_data_type_t ossl_ocsp_certid_type = { + "OpenSSL/OCSP/CERTID", + { + 0, ossl_ocsp_certid_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, +}; + /* * Public */ diff --git a/ext/openssl/ossl_pkcs12.c b/ext/openssl/ossl_pkcs12.c index b3974cb7..53e0e619 100644 --- a/ext/openssl/ossl_pkcs12.c +++ b/ext/openssl/ossl_pkcs12.c @@ -7,11 +7,11 @@ #define WrapPKCS12(klass, obj, p12) do { \ if(!(p12)) ossl_raise(rb_eRuntimeError, "PKCS12 wasn't initialized."); \ - (obj) = Data_Wrap_Struct((klass), 0, PKCS12_free, (p12)); \ + (obj) = TypedData_Wrap_Struct((klass), &ossl_pkcs12_type, (p12)); \ } while (0) #define GetPKCS12(obj, p12) do { \ - Data_Get_Struct((obj), PKCS12, (p12)); \ + TypedData_Get_Struct((obj), PKCS12, &ossl_pkcs12_type, (p12)); \ if(!(p12)) ossl_raise(rb_eRuntimeError, "PKCS12 wasn't initialized."); \ } while (0) @@ -36,6 +36,20 @@ VALUE ePKCS12Error; /* * Private */ +static void +ossl_pkcs12_free(void *ptr) +{ + PKCS12_free(ptr); +} + +static const rb_data_type_t ossl_pkcs12_type = { + "OpenSSL/PKCS12", + { + 0, ossl_pkcs12_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, +}; + static VALUE ossl_pkcs12_s_allocate(VALUE klass) { diff --git a/ext/openssl/ossl_pkcs7.c b/ext/openssl/ossl_pkcs7.c index f476807f..f4a5088e 100644 --- a/ext/openssl/ossl_pkcs7.c +++ b/ext/openssl/ossl_pkcs7.c @@ -14,10 +14,10 @@ if (!(pkcs7)) { \ ossl_raise(rb_eRuntimeError, "PKCS7 wasn't initialized."); \ } \ - (obj) = Data_Wrap_Struct((klass), 0, PKCS7_free, (pkcs7)); \ + (obj) = TypedData_Wrap_Struct((klass), &ossl_pkcs7_type, (pkcs7)); \ } while (0) #define GetPKCS7(obj, pkcs7) do { \ - Data_Get_Struct((obj), PKCS7, (pkcs7)); \ + TypedData_Get_Struct((obj), PKCS7, &ossl_pkcs7_type, (pkcs7)); \ if (!(pkcs7)) { \ ossl_raise(rb_eRuntimeError, "PKCS7 wasn't initialized."); \ } \ @@ -31,10 +31,10 @@ if (!(p7si)) { \ ossl_raise(rb_eRuntimeError, "PKCS7si wasn't initialized."); \ } \ - (obj) = Data_Wrap_Struct((klass), 0, PKCS7_SIGNER_INFO_free, (p7si)); \ + (obj) = TypedData_Wrap_Struct((klass), &ossl_pkcs7_signer_info_type, (p7si)); \ } while (0) #define GetPKCS7si(obj, p7si) do { \ - Data_Get_Struct((obj), PKCS7_SIGNER_INFO, (p7si)); \ + TypedData_Get_Struct((obj), PKCS7_SIGNER_INFO, &ossl_pkcs7_signer_info_type, (p7si)); \ if (!(p7si)) { \ ossl_raise(rb_eRuntimeError, "PKCS7si wasn't initialized."); \ } \ @@ -48,10 +48,10 @@ if (!(p7ri)) { \ ossl_raise(rb_eRuntimeError, "PKCS7ri wasn't initialized."); \ } \ - (obj) = Data_Wrap_Struct((klass), 0, PKCS7_RECIP_INFO_free, (p7ri)); \ + (obj) = TypedData_Wrap_Struct((klass), &ossl_pkcs7_recip_info_type, (p7ri)); \ } while (0) #define GetPKCS7ri(obj, p7ri) do { \ - Data_Get_Struct((obj), PKCS7_RECIP_INFO, (p7ri)); \ + TypedData_Get_Struct((obj), PKCS7_RECIP_INFO, &ossl_pkcs7_recip_info_type, (p7ri)); \ if (!(p7ri)) { \ ossl_raise(rb_eRuntimeError, "PKCS7ri wasn't initialized."); \ } \ @@ -76,6 +76,48 @@ VALUE cPKCS7Signer; VALUE cPKCS7Recipient; VALUE ePKCS7Error; +static void +ossl_pkcs7_free(void *ptr) +{ + PKCS7_free(ptr); +} + +static const rb_data_type_t ossl_pkcs7_type = { + "OpenSSL/PKCS7", + { + 0, ossl_pkcs7_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, +}; + +static void +ossl_pkcs7_signer_info_free(void *ptr) +{ + PKCS7_SIGNER_INFO_free(ptr); +} + +static const rb_data_type_t ossl_pkcs7_signer_info_type = { + "OpenSSL/PKCS7/SIGNER_INFO", + { + 0, ossl_pkcs7_signer_info_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, +}; + +static void +ossl_pkcs7_recip_info_free(void *ptr) +{ + PKCS7_RECIP_INFO_free(ptr); +} + +static const rb_data_type_t ossl_pkcs7_recip_info_type = { + "OpenSSL/PKCS7/RECIP_INFO", + { + 0, ossl_pkcs7_recip_info_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, +}; + /* * Public * (MADE PRIVATE UNTIL SOMEBODY WILL NEED THEM) diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c index 43942274..aa9b046d 100644 --- a/ext/openssl/ossl_pkey.c +++ b/ext/openssl/ossl_pkey.c @@ -69,9 +69,23 @@ ossl_generate_cb_stop(void *ptr) } #endif +static void +ossl_evp_pkey_free(void *ptr) +{ + EVP_PKEY_free(ptr); +} + /* * Public */ +const rb_data_type_t ossl_evp_pkey_type = { + "OpenSSL/EVP_PKEY", + { + 0, ossl_evp_pkey_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, +}; + VALUE ossl_pkey_new(EVP_PKEY *pkey) { diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h index 686e956e..6c0b7fd6 100644 --- a/ext/openssl/ossl_pkey.h +++ b/ext/openssl/ossl_pkey.h @@ -15,6 +15,7 @@ extern VALUE mPKey; extern VALUE cPKey; extern VALUE ePKeyError; extern ID id_private_q; +extern const rb_data_type_t ossl_evp_pkey_type; #define OSSL_PKEY_SET_PRIVATE(obj) rb_iv_set((obj), "private", Qtrue) #define OSSL_PKEY_SET_PUBLIC(obj) rb_iv_set((obj), "private", Qfalse) @@ -24,11 +25,11 @@ extern ID id_private_q; if (!(pkey)) { \ rb_raise(rb_eRuntimeError, "PKEY wasn't initialized!"); \ } \ - (obj) = Data_Wrap_Struct((klass), 0, EVP_PKEY_free, (pkey)); \ + (obj) = TypedData_Wrap_Struct((klass), &ossl_evp_pkey_type, (pkey)); \ OSSL_PKEY_SET_PUBLIC(obj); \ } while (0) #define GetPKey(obj, pkey) do {\ - Data_Get_Struct((obj), EVP_PKEY, (pkey));\ + TypedData_Get_Struct((obj), EVP_PKEY, &ossl_evp_pkey_type, (pkey)); \ if (!(pkey)) { \ rb_raise(rb_eRuntimeError, "PKEY wasn't initialized!");\ } \ diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c index cec00597..d63f7573 100644 --- a/ext/openssl/ossl_pkey_ec.c +++ b/ext/openssl/ossl_pkey_ec.c @@ -20,6 +20,8 @@ typedef struct { #define EXPORT_PEM 0 #define EXPORT_DER 1 +static const rb_data_type_t ossl_ec_group_type; +static const rb_data_type_t ossl_ec_point_type; #define GetPKeyEC(obj, pkey) do { \ GetPKey((obj), (pkey)); \ @@ -30,7 +32,7 @@ typedef struct { #define SafeGet_ec_group(obj, group) do { \ OSSL_Check_Kind((obj), cEC_GROUP); \ - Data_Get_Struct((obj), ossl_ec_group, (group)); \ + TypedData_Get_Struct((obj), ossl_ec_group, &ossl_ec_group_type, (group)); \ } while(0) #define Get_EC_KEY(obj, key) do { \ @@ -52,7 +54,7 @@ typedef struct { #define Get_EC_GROUP(obj, g) do { \ ossl_ec_group *ec_group; \ - Data_Get_Struct((obj), ossl_ec_group, ec_group); \ + TypedData_Get_Struct((obj), ossl_ec_group, &ossl_ec_group_type, ec_group); \ if (ec_group == NULL) \ ossl_raise(eEC_GROUP, "missing ossl_ec_group structure"); \ (g) = ec_group->group; \ @@ -71,7 +73,7 @@ typedef struct { #define Get_EC_POINT(obj, p) do { \ ossl_ec_point *ec_point; \ - Data_Get_Struct((obj), ossl_ec_point, ec_point); \ + TypedData_Get_Struct((obj), ossl_ec_point, &ossl_ec_point_type, ec_point); \ if (ec_point == NULL) \ ossl_raise(eEC_POINT, "missing ossl_ec_point structure"); \ (p) = ec_point->point; \ @@ -369,7 +371,7 @@ static VALUE ossl_ec_point_dup(const EC_POINT *point, VALUE group_v) ossl_ec_point *new_point; obj = rb_obj_alloc(cEC_POINT); - Data_Get_Struct(obj, ossl_ec_point, new_point); + TypedData_Get_Struct(obj, ossl_ec_point, &ossl_ec_point_type, new_point); SafeRequire_EC_GROUP(group_v, group); @@ -707,19 +709,28 @@ static VALUE ossl_ec_key_dsa_verify_asn1(VALUE self, VALUE data, VALUE sig) UNREACHABLE; } -static void ossl_ec_group_free(ossl_ec_group *ec_group) +static void ossl_ec_group_free(void *ptr) { + ossl_ec_group *ec_group = ptr; if (!ec_group->dont_free && ec_group->group) EC_GROUP_clear_free(ec_group->group); ruby_xfree(ec_group); } +static const rb_data_type_t ossl_ec_group_type = { + "OpenSSL/ec_group", + { + 0, ossl_ec_group_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, +}; + static VALUE ossl_ec_group_alloc(VALUE klass) { ossl_ec_group *ec_group; VALUE obj; - obj = Data_Make_Struct(klass, ossl_ec_group, 0, ossl_ec_group_free, ec_group); + obj = TypedData_Make_Struct(klass, ossl_ec_group, &ossl_ec_group_type, ec_group); return obj; } @@ -746,7 +757,7 @@ static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self) ossl_ec_group *ec_group; EC_GROUP *group = NULL; - Data_Get_Struct(self, ossl_ec_group, ec_group); + TypedData_Get_Struct(self, ossl_ec_group, &ossl_ec_group_type, ec_group); if (ec_group->group != NULL) ossl_raise(rb_eRuntimeError, "EC_GROUP is already initialized"); @@ -1219,19 +1230,28 @@ static VALUE ossl_ec_group_to_text(VALUE self) } -static void ossl_ec_point_free(ossl_ec_point *ec_point) +static void ossl_ec_point_free(void *ptr) { + ossl_ec_point *ec_point = ptr; if (!ec_point->dont_free && ec_point->point) EC_POINT_clear_free(ec_point->point); ruby_xfree(ec_point); } +static const rb_data_type_t ossl_ec_point_type = { + "OpenSSL/ec_point", + { + 0, ossl_ec_point_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, +}; + static VALUE ossl_ec_point_alloc(VALUE klass) { ossl_ec_point *ec_point; VALUE obj; - obj = Data_Make_Struct(klass, ossl_ec_point, 0, ossl_ec_point_free, ec_point); + obj = TypedData_Make_Struct(klass, ossl_ec_point, &ossl_ec_point_type, ec_point); return obj; } @@ -1252,7 +1272,7 @@ static VALUE ossl_ec_point_initialize(int argc, VALUE *argv, VALUE self) VALUE group_v = Qnil; const EC_GROUP *group = NULL; - Data_Get_Struct(self, ossl_ec_point, ec_point); + TypedData_Get_Struct(self, ossl_ec_point, &ossl_ec_point_type, ec_point); if (ec_point->point) ossl_raise(eEC_POINT, "EC_POINT already initialized"); diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c index ccfd72dd..af93252e 100644 --- a/ext/openssl/ossl_ssl.c +++ b/ext/openssl/ossl_ssl.c @@ -24,6 +24,10 @@ # define TO_SOCKET(s) (s) #endif +#define GetSSLCTX(obj, ctx) do { \ + TypedData_Get_Struct((obj), SSL_CTX, &ossl_sslctx_type, (ctx)); \ +} while (0) + VALUE mSSL; VALUE eSSLError; VALUE cSSLContext; @@ -150,13 +154,22 @@ int ossl_ssl_ex_client_cert_cb_idx; int ossl_ssl_ex_tmp_dh_callback_idx; static void -ossl_sslctx_free(SSL_CTX *ctx) +ossl_sslctx_free(void *ptr) { + SSL_CTX *ctx = ptr; if(ctx && SSL_CTX_get_ex_data(ctx, ossl_ssl_ex_store_p)== (void*)1) ctx->cert_store = NULL; SSL_CTX_free(ctx); } +static const rb_data_type_t ossl_sslctx_type = { + "OpenSSL/SSL/CTX", + { + 0, ossl_sslctx_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, +}; + static VALUE ossl_sslctx_s_alloc(VALUE klass) { @@ -172,7 +185,7 @@ ossl_sslctx_s_alloc(VALUE klass) ossl_raise(eSSLError, "SSL_CTX_new"); } SSL_CTX_set_mode(ctx, mode); - return Data_Wrap_Struct(klass, 0, ossl_sslctx_free, ctx); + return TypedData_Wrap_Struct(klass, &ossl_sslctx_type, ctx); } /* @@ -203,7 +216,7 @@ ossl_sslctx_set_ssl_version(VALUE self, VALUE ssl_method) if (!method) { ossl_raise(rb_eArgError, "unknown SSL method `%s'.", s); } - Data_Get_Struct(self, SSL_CTX, ctx); + GetSSLCTX(self, ctx); if (SSL_CTX_set_ssl_version(ctx, method) != 1) { ossl_raise(eSSLError, "SSL_CTX_set_ssl_version"); } @@ -244,7 +257,7 @@ ossl_call_client_cert_cb(VALUE obj) VALUE cb, ary, cert, key; SSL *ssl; - Data_Get_Struct(obj, SSL, ssl); + GetSSL(obj, ssl); cb = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_client_cert_cb_idx); if (NIL_P(cb)) return Qfalse; ary = rb_funcall(cb, rb_intern("call"), 1, obj); @@ -280,7 +293,7 @@ ossl_call_tmp_dh_callback(VALUE *args) VALUE cb, dh; EVP_PKEY *pkey; - Data_Get_Struct(args[0], SSL, ssl); + GetSSL(args[0], ssl); cb = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_tmp_dh_callback_idx); if (NIL_P(cb)) return Qfalse; dh = rb_funcall(cb, rb_intern("call"), 3, args[0], args[1], args[2]); @@ -482,7 +495,7 @@ ossl_sslctx_add_extra_chain_cert_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, arg)) X509 *x509; SSL_CTX *ctx; - Data_Get_Struct(arg, SSL_CTX, ctx); + GetSSLCTX(arg, ctx); x509 = DupX509CertPtr(i); if(!SSL_CTX_add_extra_chain_cert(ctx, x509)){ ossl_raise(eSSLError, NULL); @@ -513,8 +526,8 @@ ossl_call_servername_cb(VALUE ary) SSL_CTX *ctx2; ossl_sslctx_setup(ret_obj); - Data_Get_Struct(ssl_obj, SSL, ssl); - Data_Get_Struct(ret_obj, SSL_CTX, ctx2); + GetSSL(ssl_obj, ssl); + GetSSLCTX(ret_obj, ctx2); SSL_set_SSL_CTX(ssl, ctx2); } else if (!NIL_P(ret_obj)) { ossl_raise(rb_eArgError, "servername_cb must return an OpenSSL::SSL::SSLContext object or nil"); @@ -665,7 +678,7 @@ ossl_sslctx_setup(VALUE self) VALUE val; if(OBJ_FROZEN(self)) return Qnil; - Data_Get_Struct(self, SSL_CTX, ctx); + GetSSLCTX(self, ctx); #if !defined(OPENSSL_NO_DH) if (RTEST(ossl_sslctx_get_tmp_dh_cb(self))){ @@ -841,7 +854,7 @@ ossl_sslctx_get_ciphers(VALUE self) VALUE ary; int i, num; - Data_Get_Struct(self, SSL_CTX, ctx); + GetSSLCTX(self, ctx); if(!ctx){ rb_warning("SSL_CTX is not initialized."); return Qnil; @@ -896,7 +909,7 @@ ossl_sslctx_set_ciphers(VALUE self, VALUE v) StringValue(str); } - Data_Get_Struct(self, SSL_CTX, ctx); + GetSSLCTX(self, ctx); if(!ctx){ ossl_raise(eSSLError, "SSL_CTX is not initialized."); return Qnil; @@ -920,7 +933,7 @@ ossl_sslctx_session_add(VALUE self, VALUE arg) SSL_CTX *ctx; SSL_SESSION *sess; - Data_Get_Struct(self, SSL_CTX, ctx); + GetSSLCTX(self, ctx); SafeGetSSLSession(arg, sess); return SSL_CTX_add_session(ctx, sess) == 1 ? Qtrue : Qfalse; @@ -938,7 +951,7 @@ ossl_sslctx_session_remove(VALUE self, VALUE arg) SSL_CTX *ctx; SSL_SESSION *sess; - Data_Get_Struct(self, SSL_CTX, ctx); + GetSSLCTX(self, ctx); SafeGetSSLSession(arg, sess); return SSL_CTX_remove_session(ctx, sess) == 1 ? Qtrue : Qfalse; @@ -955,7 +968,7 @@ ossl_sslctx_get_session_cache_mode(VALUE self) { SSL_CTX *ctx; - Data_Get_Struct(self, SSL_CTX, ctx); + GetSSLCTX(self, ctx); return LONG2NUM(SSL_CTX_get_session_cache_mode(ctx)); } @@ -973,7 +986,7 @@ ossl_sslctx_set_session_cache_mode(VALUE self, VALUE arg) { SSL_CTX *ctx; - Data_Get_Struct(self, SSL_CTX, ctx); + GetSSLCTX(self, ctx); SSL_CTX_set_session_cache_mode(ctx, NUM2LONG(arg)); @@ -992,7 +1005,7 @@ ossl_sslctx_get_session_cache_size(VALUE self) { SSL_CTX *ctx; - Data_Get_Struct(self, SSL_CTX, ctx); + GetSSLCTX(self, ctx); return LONG2NUM(SSL_CTX_sess_get_cache_size(ctx)); } @@ -1009,7 +1022,7 @@ ossl_sslctx_set_session_cache_size(VALUE self, VALUE arg) { SSL_CTX *ctx; - Data_Get_Struct(self, SSL_CTX, ctx); + GetSSLCTX(self, ctx); SSL_CTX_sess_set_cache_size(ctx, NUM2LONG(arg)); @@ -1044,7 +1057,7 @@ ossl_sslctx_get_session_cache_stats(VALUE self) SSL_CTX *ctx; VALUE hash; - Data_Get_Struct(self, SSL_CTX, ctx); + GetSSLCTX(self, ctx); hash = rb_hash_new(); rb_hash_aset(hash, ID2SYM(rb_intern("cache_num")), LONG2NUM(SSL_CTX_sess_number(ctx))); @@ -1079,7 +1092,7 @@ ossl_sslctx_flush_sessions(int argc, VALUE *argv, VALUE self) rb_scan_args(argc, argv, "01", &arg1); - Data_Get_Struct(self, SSL_CTX, ctx); + GetSSLCTX(self, ctx); if (NIL_P(arg1)) { tm = time(0); @@ -1120,15 +1133,23 @@ ossl_ssl_shutdown(SSL *ssl) } static void -ossl_ssl_free(SSL *ssl) +ossl_ssl_free(void *ssl) { SSL_free(ssl); } +const rb_data_type_t ossl_ssl_type = { + "OpenSSL/SSL", + { + 0, ossl_ssl_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, +}; + static VALUE ossl_ssl_s_alloc(VALUE klass) { - return Data_Wrap_Struct(klass, 0, ossl_ssl_free, NULL); + return TypedData_Wrap_Struct(klass, &ossl_ssl_type, NULL); } /* @@ -1177,14 +1198,14 @@ ossl_ssl_setup(VALUE self) SSL *ssl; rb_io_t *fptr; - Data_Get_Struct(self, SSL, ssl); + GetSSL(self, ssl); if(!ssl){ #ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME VALUE hostname = rb_iv_get(self, "@hostname"); #endif v_ctx = ossl_ssl_get_ctx(self); - Data_Get_Struct(v_ctx, SSL_CTX, ctx); + GetSSLCTX(v_ctx, ctx); ssl = SSL_new(ctx); if (!ssl) { @@ -1224,7 +1245,7 @@ ossl_ssl_setup(VALUE self) #define ossl_ssl_data_get_struct(v, ssl) \ do { \ - Data_Get_Struct((v), SSL, (ssl)); \ + GetSSL((v), (ssl)); \ if (!(ssl)) { \ rb_warning("SSL session is not started yet."); \ return Qnil; \ @@ -1394,7 +1415,7 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock) } if(ilen == 0) return str; - Data_Get_Struct(self, SSL, ssl); + GetSSL(self, ssl); GetOpenFile(ossl_ssl_get_io(self), fptr); if (ssl) { if(!nonblock && SSL_pending(ssl) <= 0) @@ -1486,7 +1507,7 @@ ossl_ssl_write_internal(VALUE self, VALUE str, int nonblock, int no_exception) rb_io_t *fptr; StringValue(str); - Data_Get_Struct(self, SSL, ssl); + GetSSL(self, ssl); GetOpenFile(ossl_ssl_get_io(self), fptr); if (ssl) { @@ -1571,7 +1592,7 @@ ossl_ssl_close(VALUE self) /* ossl_ssl_data_get_struct() is not usable here because it may return * from this function; */ - Data_Get_Struct(self, SSL, ssl); + GetSSL(self, ssl); io = ossl_ssl_get_io(self); if (!RTEST(rb_funcall(io, rb_intern("closed?"), 0))) { diff --git a/ext/openssl/ossl_ssl.h b/ext/openssl/ossl_ssl.h index 034762fc..0c20b107 100644 --- a/ext/openssl/ossl_ssl.h +++ b/ext/openssl/ossl_ssl.h @@ -11,8 +11,12 @@ #if !defined(_OSSL_SSL_H_) #define _OSSL_SSL_H_ +#define GetSSL(obj, ssl) do { \ + TypedData_Get_Struct((obj), SSL, &ossl_ssl_type, (ssl)); \ +} while (0) + #define GetSSLSession(obj, sess) do { \ - Data_Get_Struct((obj), SSL_SESSION, (sess)); \ + TypedData_Get_Struct((obj), SSL_SESSION, &ossl_ssl_session_type, (sess)); \ if (!(sess)) { \ ossl_raise(rb_eRuntimeError, "SSL Session wasn't initialized."); \ } \ @@ -23,6 +27,8 @@ GetSSLSession((obj), (sess)); \ } while (0) +extern const rb_data_type_t ossl_ssl_type; +extern const rb_data_type_t ossl_ssl_session_type; extern VALUE mSSL; extern VALUE eSSLError; extern VALUE cSSLSocket; diff --git a/ext/openssl/ossl_ssl_session.c b/ext/openssl/ossl_ssl_session.c index a7437caf..e1bbc6fb 100644 --- a/ext/openssl/ossl_ssl_session.c +++ b/ext/openssl/ossl_ssl_session.c @@ -4,25 +4,26 @@ #include "ossl.h" -#define GetSSLSession(obj, sess) do { \ - Data_Get_Struct((obj), SSL_SESSION, (sess)); \ - if (!(sess)) { \ - ossl_raise(rb_eRuntimeError, "SSL Session wasn't initialized."); \ - } \ -} while (0) - -#define SafeGetSSLSession(obj, sess) do { \ - OSSL_Check_Kind((obj), cSSLSession); \ - GetSSLSession((obj), (sess)); \ -} while (0) - - VALUE cSSLSession; static VALUE eSSLSession; +static void +ossl_ssl_session_free(void *ptr) +{ + SSL_SESSION_free(ptr); +} + +const rb_data_type_t ossl_ssl_session_type = { + "OpenSSL/SSL/Session", + { + 0, ossl_ssl_session_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, +}; + static VALUE ossl_ssl_session_alloc(VALUE klass) { - return Data_Wrap_Struct(klass, 0, SSL_SESSION_free, NULL); + return TypedData_Wrap_Struct(klass, &ossl_ssl_session_type, NULL); } /* @@ -43,7 +44,7 @@ static VALUE ossl_ssl_session_initialize(VALUE self, VALUE arg1) if (rb_obj_is_instance_of(arg1, cSSLSocket)) { SSL *ssl; - Data_Get_Struct(arg1, SSL, ssl); + GetSSL(arg1, ssl); if (!ssl || (ctx = SSL_get1_session(ssl)) == NULL) ossl_raise(eSSLSession, "no session available"); @@ -78,7 +79,11 @@ int SSL_SESSION_cmp(const SSL_SESSION *a,const SSL_SESSION *b) if (a->ssl_version != b->ssl_version || a->session_id_length != b->session_id_length) return 1; - return memcmp(a->session_id,b-> session_id, a->session_id_length); +#if defined(_WIN32) + return memcmp(a->session_id, b->session_id, a->session_id_length); +#else + return CRYPTO_memcmp(a->session_id, b->session_id, a->session_id_length); +#endif } #endif diff --git a/ext/openssl/ossl_x509attr.c b/ext/openssl/ossl_x509attr.c index fdf0481c..c9036cad 100644 --- a/ext/openssl/ossl_x509attr.c +++ b/ext/openssl/ossl_x509attr.c @@ -14,10 +14,10 @@ if (!(attr)) { \ ossl_raise(rb_eRuntimeError, "ATTR wasn't initialized!"); \ } \ - (obj) = Data_Wrap_Struct((klass), 0, X509_ATTRIBUTE_free, (attr)); \ + (obj) = TypedData_Wrap_Struct((klass), &ossl_x509attr_type, (attr)); \ } while (0) #define GetX509Attr(obj, attr) do { \ - Data_Get_Struct((obj), X509_ATTRIBUTE, (attr)); \ + TypedData_Get_Struct((obj), X509_ATTRIBUTE, &ossl_x509attr_type, (attr)); \ if (!(attr)) { \ ossl_raise(rb_eRuntimeError, "ATTR wasn't initialized!"); \ } \ @@ -33,6 +33,20 @@ VALUE cX509Attr; VALUE eX509AttrError; +static void +ossl_x509attr_free(void *ptr) +{ + X509_ATTRIBUTE_free(ptr); +} + +static const rb_data_type_t ossl_x509attr_type = { + "OpenSSL/X509/ATTRIBUTE", + { + 0, ossl_x509attr_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, +}; + /* * Public */ diff --git a/ext/openssl/ossl_x509cert.c b/ext/openssl/ossl_x509cert.c index 0c8f0751..b76ea793 100644 --- a/ext/openssl/ossl_x509cert.c +++ b/ext/openssl/ossl_x509cert.c @@ -14,10 +14,10 @@ if (!(x509)) { \ ossl_raise(rb_eRuntimeError, "CERT wasn't initialized!"); \ } \ - (obj) = Data_Wrap_Struct((klass), 0, X509_free, (x509)); \ + (obj) = TypedData_Wrap_Struct((klass), &ossl_x509_type, (x509)); \ } while (0) #define GetX509(obj, x509) do { \ - Data_Get_Struct((obj), X509, (x509)); \ + TypedData_Get_Struct((obj), X509, &ossl_x509_type, (x509)); \ if (!(x509)) { \ ossl_raise(rb_eRuntimeError, "CERT wasn't initialized!"); \ } \ @@ -33,6 +33,20 @@ VALUE cX509Cert; VALUE eX509CertError; +static void +ossl_x509_free(void *ptr) +{ + X509_free(ptr); +} + +static const rb_data_type_t ossl_x509_type = { + "OpenSSL/X509", + { + 0, ossl_x509_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, +}; + /* * Public */ diff --git a/ext/openssl/ossl_x509crl.c b/ext/openssl/ossl_x509crl.c index beacc260..461c226f 100644 --- a/ext/openssl/ossl_x509crl.c +++ b/ext/openssl/ossl_x509crl.c @@ -14,10 +14,10 @@ if (!(crl)) { \ ossl_raise(rb_eRuntimeError, "CRL wasn't initialized!"); \ } \ - (obj) = Data_Wrap_Struct((klass), 0, X509_CRL_free, (crl)); \ + (obj) = TypedData_Wrap_Struct((klass), &ossl_x509crl_type, (crl)); \ } while (0) #define GetX509CRL(obj, crl) do { \ - Data_Get_Struct((obj), X509_CRL, (crl)); \ + TypedData_Get_Struct((obj), X509_CRL, &ossl_x509crl_type, (crl)); \ if (!(crl)) { \ ossl_raise(rb_eRuntimeError, "CRL wasn't initialized!"); \ } \ @@ -33,6 +33,20 @@ VALUE cX509CRL; VALUE eX509CRLError; +static void +ossl_x509crl_free(void *ptr) +{ + X509_CRL_free(ptr); +} + +static const rb_data_type_t ossl_x509crl_type = { + "OpenSSL/X509/CRL", + { + 0, ossl_x509crl_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, +}; + /* * PUBLIC */ diff --git a/ext/openssl/ossl_x509ext.c b/ext/openssl/ossl_x509ext.c index 48625f85..faffe06a 100644 --- a/ext/openssl/ossl_x509ext.c +++ b/ext/openssl/ossl_x509ext.c @@ -14,10 +14,10 @@ if (!(ext)) { \ ossl_raise(rb_eRuntimeError, "EXT wasn't initialized!"); \ } \ - (obj) = Data_Wrap_Struct((klass), 0, X509_EXTENSION_free, (ext)); \ + (obj) = TypedData_Wrap_Struct((klass), &ossl_x509ext_type, (ext)); \ } while (0) #define GetX509Ext(obj, ext) do { \ - Data_Get_Struct((obj), X509_EXTENSION, (ext)); \ + TypedData_Get_Struct((obj), X509_EXTENSION, &ossl_x509ext_type, (ext)); \ if (!(ext)) { \ ossl_raise(rb_eRuntimeError, "EXT wasn't initialized!"); \ } \ @@ -30,10 +30,10 @@ if (!((ctx) = OPENSSL_malloc(sizeof(X509V3_CTX)))) \ ossl_raise(rb_eRuntimeError, "CTX wasn't allocated!"); \ X509V3_set_ctx((ctx), NULL, NULL, NULL, NULL, 0); \ - (obj) = Data_Wrap_Struct((klass), 0, ossl_x509extfactory_free, (ctx)); \ + (obj) = TypedData_Wrap_Struct((klass), &ossl_x509extfactory_type, (ctx)); \ } while (0) #define GetX509ExtFactory(obj, ctx) do { \ - Data_Get_Struct((obj), X509V3_CTX, (ctx)); \ + TypedData_Get_Struct((obj), X509V3_CTX, &ossl_x509extfactory_type, (ctx)); \ if (!(ctx)) { \ ossl_raise(rb_eRuntimeError, "CTX wasn't initialized!"); \ } \ @@ -46,6 +46,20 @@ VALUE cX509Ext; VALUE cX509ExtFactory; VALUE eX509ExtError; +static void +ossl_x509ext_free(void *ptr) +{ + X509_EXTENSION_free(ptr); +} + +static const rb_data_type_t ossl_x509ext_type = { + "OpenSSL/X509/EXTENSION", + { + 0, ossl_x509ext_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, +}; + /* * Public */ @@ -98,11 +112,19 @@ DupX509ExtPtr(VALUE obj) * Ext factory */ static void -ossl_x509extfactory_free(X509V3_CTX *ctx) +ossl_x509extfactory_free(void *ctx) { OPENSSL_free(ctx); } +static const rb_data_type_t ossl_x509extfactory_type = { + "OpenSSL/X509/EXTENSION/Factory", + { + 0, ossl_x509extfactory_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, +}; + static VALUE ossl_x509extfactory_alloc(VALUE klass) { diff --git a/ext/openssl/ossl_x509name.c b/ext/openssl/ossl_x509name.c index cf541e56..546cf3bf 100644 --- a/ext/openssl/ossl_x509name.c +++ b/ext/openssl/ossl_x509name.c @@ -14,10 +14,10 @@ if (!(name)) { \ ossl_raise(rb_eRuntimeError, "Name wasn't initialized."); \ } \ - (obj) = Data_Wrap_Struct((klass), 0, X509_NAME_free, (name)); \ + (obj) = TypedData_Wrap_Struct((klass), &ossl_x509name_type, (name)); \ } while (0) #define GetX509Name(obj, name) do { \ - Data_Get_Struct((obj), X509_NAME, (name)); \ + TypedData_Get_Struct((obj), X509_NAME, &ossl_x509name_type, (name)); \ if (!(name)) { \ ossl_raise(rb_eRuntimeError, "Name wasn't initialized."); \ } \ @@ -38,6 +38,20 @@ VALUE cX509Name; VALUE eX509NameError; +static void +ossl_x509name_free(void *ptr) +{ + X509_NAME_free(ptr); +} + +static const rb_data_type_t ossl_x509name_type = { + "OpenSSL/X509/NAME", + { + 0, ossl_x509name_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, +}; + /* * Public */ diff --git a/ext/openssl/ossl_x509req.c b/ext/openssl/ossl_x509req.c index a7f5dd20..529b6850 100644 --- a/ext/openssl/ossl_x509req.c +++ b/ext/openssl/ossl_x509req.c @@ -14,10 +14,10 @@ if (!(req)) { \ ossl_raise(rb_eRuntimeError, "Req wasn't initialized!"); \ } \ - (obj) = Data_Wrap_Struct((klass), 0, X509_REQ_free, (req)); \ + (obj) = TypedData_Wrap_Struct((klass), &ossl_x509req_type, (req)); \ } while (0) #define GetX509Req(obj, req) do { \ - Data_Get_Struct((obj), X509_REQ, (req)); \ + TypedData_Get_Struct((obj), X509_REQ, &ossl_x509req_type, (req)); \ if (!(req)) { \ ossl_raise(rb_eRuntimeError, "Req wasn't initialized!"); \ } \ @@ -33,6 +33,20 @@ VALUE cX509Req; VALUE eX509ReqError; +static void +ossl_x509req_free(void *ptr) +{ + X509_REQ_free(ptr); +} + +static const rb_data_type_t ossl_x509req_type = { + "OpenSSL/X509/REQ", + { + 0, ossl_x509req_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, +}; + /* * Public functions */ diff --git a/ext/openssl/ossl_x509revoked.c b/ext/openssl/ossl_x509revoked.c index c98a95ea..30c362c3 100644 --- a/ext/openssl/ossl_x509revoked.c +++ b/ext/openssl/ossl_x509revoked.c @@ -14,10 +14,10 @@ if (!(rev)) { \ ossl_raise(rb_eRuntimeError, "REV wasn't initialized!"); \ } \ - (obj) = Data_Wrap_Struct((klass), 0, X509_REVOKED_free, (rev)); \ + (obj) = TypedData_Wrap_Struct((klass), &ossl_x509rev_type, (rev)); \ } while (0) #define GetX509Rev(obj, rev) do { \ - Data_Get_Struct((obj), X509_REVOKED, (rev)); \ + TypedData_Get_Struct((obj), X509_REVOKED, &ossl_x509rev_type, (rev)); \ if (!(rev)) { \ ossl_raise(rb_eRuntimeError, "REV wasn't initialized!"); \ } \ @@ -33,6 +33,20 @@ VALUE cX509Rev; VALUE eX509RevError; +static void +ossl_x509rev_free(void *ptr) +{ + X509_REVOKED_free(ptr); +} + +static const rb_data_type_t ossl_x509rev_type = { + "OpenSSL/X509/REV", + { + 0, ossl_x509rev_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, +}; + /* * PUBLIC */ diff --git a/ext/openssl/ossl_x509store.c b/ext/openssl/ossl_x509store.c index dd924bf9..3093e28a 100644 --- a/ext/openssl/ossl_x509store.c +++ b/ext/openssl/ossl_x509store.c @@ -14,10 +14,10 @@ if (!(st)) { \ ossl_raise(rb_eRuntimeError, "STORE wasn't initialized!"); \ } \ - (obj) = Data_Wrap_Struct((klass), 0, X509_STORE_free, (st)); \ + (obj) = TypedData_Wrap_Struct((klass), &ossl_x509store_type, (st)); \ } while (0) #define GetX509Store(obj, st) do { \ - Data_Get_Struct((obj), X509_STORE, (st)); \ + TypedData_Get_Struct((obj), X509_STORE, &ossl_x509store_type, (st)); \ if (!(st)) { \ ossl_raise(rb_eRuntimeError, "STORE wasn't initialized!"); \ } \ @@ -31,10 +31,10 @@ if (!(ctx)) { \ ossl_raise(rb_eRuntimeError, "STORE_CTX wasn't initialized!"); \ } \ - (obj) = Data_Wrap_Struct((klass), 0, ossl_x509stctx_free, (ctx)); \ + (obj) = TypedData_Wrap_Struct((klass), &ossl_x509stctx_type, (ctx)); \ } while (0) #define GetX509StCtx(obj, ctx) do { \ - Data_Get_Struct((obj), X509_STORE_CTX, (ctx)); \ + TypedData_Get_Struct((obj), X509_STORE_CTX, &ossl_x509stctx_type, (ctx)); \ if (!(ctx)) { \ ossl_raise(rb_eRuntimeError, "STORE_CTX is out of scope!"); \ } \ @@ -51,6 +51,20 @@ VALUE cX509Store; VALUE cX509StoreContext; VALUE eX509StoreError; +static void +ossl_x509store_free(void *ptr) +{ + X509_STORE_free(ptr); +} + +static const rb_data_type_t ossl_x509store_type = { + "OpenSSL/X509/STORE", + { + 0, ossl_x509store_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, +}; + /* * Public functions */ @@ -342,7 +356,17 @@ ossl_x509store_verify(int argc, VALUE *argv, VALUE self) /* * Public Functions */ -static void ossl_x509stctx_free(X509_STORE_CTX*); +static void ossl_x509stctx_free(void*); + + +static const rb_data_type_t ossl_x509stctx_type = { + "OpenSSL/X509/STORE_CTX", + { + 0, ossl_x509stctx_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, +}; + VALUE ossl_x509stctx_new(X509_STORE_CTX *ctx) @@ -367,8 +391,9 @@ ossl_x509stctx_clear_ptr(VALUE obj) * Private functions */ static void -ossl_x509stctx_free(X509_STORE_CTX *ctx) +ossl_x509stctx_free(void *ptr) { + X509_STORE_CTX *ctx = ptr; if(ctx->untrusted) sk_X509_pop_free(ctx->untrusted, X509_free); if(ctx->cert) diff --git a/test/envutil.rb b/test/envutil.rb index f5fbb7c1..1193a1a5 100644 --- a/test/envutil.rb +++ b/test/envutil.rb @@ -1,7 +1,6 @@ # -*- coding: us-ascii -*- require "open3" require "timeout" -require "test/unit" require_relative "find_executable" module EnvUtil @@ -69,8 +68,14 @@ module EnvUtil stderr = th_stderr.value if capture_stderr && capture_stderr != :merge_to_stdout else signal = /mswin|mingw/ =~ RUBY_PLATFORM ? :KILL : :TERM + case pgroup = opt[:pgroup] + when 0, true + pgroup = -pid + when nil, false + pgroup = pid + end begin - Process.kill signal, pid + Process.kill signal, pgroup Timeout.timeout((reprieve unless signal == :KILL)) do Process.wait(pid) end @@ -357,7 +362,7 @@ module Test line -= 5 # lines until src src = <<eom # -*- coding: #{src.encoding}; -*- - require #{__dir__.dump}'/envutil';include Test::Unit::Assertions + require #{__dir__.dump}'/test/unit';include Test::Unit::Assertions END { puts [Marshal.dump($!)].pack('m'), "assertions=\#{self._assertions}" } @@ -467,6 +472,8 @@ eom next unless a > 0 and b > 0 assert_operator(a.fdiv(b), :<, limit, message(message) {"#{n}: #{b} => #{a}"}) end + rescue LoadError + skip end def assert_is_minus_zero(f) @@ -520,6 +527,38 @@ eom end end + # threads should respond to shift method. + # Array can be used. + def assert_join_threads(threads, message = nil) + errs = [] + values = [] + while th = threads.shift + begin + values << th.value + rescue Exception + errs << [th, $!] + end + end + if !errs.empty? + msg = "exceptions on #{errs.length} threads:\n" + + errs.map {|t, err| + "#{t.inspect}:\n" + + err.backtrace.map.with_index {|line, i| + if i == 0 + "#{line}: #{err.message} (#{err.class})" + else + "\tfrom #{line}" + end + }.join("\n") + }.join("\n---\n") + if message + msg = "#{message}\n#{msg}" + end + raise MiniTest::Assertion, msg + end + values + end + class << (AssertFile = Struct.new(:failure_message).new) include Assertions def assert_file_predicate(predicate, *args) diff --git a/test/test_asn1.rb b/test/test_asn1.rb index 3ea2638b..9fb5a551 100644 --- a/test/test_asn1.rb +++ b/test/test_asn1.rb @@ -605,5 +605,5 @@ rEzBQ0F9dUyqQ9gyRg8KHhDfv9HzT1d/rnUZMkoombwYBRIUChGCYV0GnJcan2Zm assert_equal(:UNIVERSAL, asn1.tag_class) end -end if defined?(OpenSSL) +end if defined?(OpenSSL::TestUtils) diff --git a/test/test_bn.rb b/test/test_bn.rb index 27bbcdfe..667cb296 100644 --- a/test/test_bn.rb +++ b/test/test_bn.rb @@ -1,6 +1,6 @@ require_relative 'utils' -if defined?(OpenSSL) +if defined?(OpenSSL::TestUtils) class OpenSSL::TestBN < Test::Unit::TestCase def test_new_str diff --git a/test/test_buffering.rb b/test/test_buffering.rb index c4894e12..c62dd4d1 100644 --- a/test/test_buffering.rb +++ b/test/test_buffering.rb @@ -84,4 +84,4 @@ class OpenSSL::TestBuffering < Test::Unit::TestCase assert_equal([97, 98, 99], res) end -end if defined?(OpenSSL) +end if defined?(OpenSSL::TestUtils) diff --git a/test/test_cipher.rb b/test/test_cipher.rb index 156fa2a9..30220d16 100644 --- a/test/test_cipher.rb +++ b/test/test_cipher.rb @@ -1,6 +1,6 @@ require_relative 'utils' -if defined?(OpenSSL) +if defined?(OpenSSL::TestUtils) class OpenSSL::TestCipher < Test::Unit::TestCase diff --git a/test/test_config.rb b/test/test_config.rb index 939cae0b..62f9fabc 100644 --- a/test/test_config.rb +++ b/test/test_config.rb @@ -23,7 +23,7 @@ __EOD__ def test_constants assert(defined?(OpenSSL::Config::DEFAULT_CONFIG_FILE)) config_file = OpenSSL::Config::DEFAULT_CONFIG_FILE - pend "DEFAULT_CONFIG_FILE may return a wrong path on your platforms. [Bug #6830]" unless File.readable?(config_file) + skip "DEFAULT_CONFIG_FILE may return a wrong path on your platforms. [Bug #6830]" unless File.readable?(config_file) assert_nothing_raised do OpenSSL::Config.load(config_file) end @@ -294,4 +294,4 @@ __EOC__ @it['newsection'] = {'a' => 'b'} assert_not_equal(@it.sections.sort, c.sections.sort) end -end if defined?(OpenSSL) +end if defined?(OpenSSL::TestUtils) diff --git a/test/test_digest.rb b/test/test_digest.rb index c2a3f705..a23b2ef0 100644 --- a/test/test_digest.rb +++ b/test/test_digest.rb @@ -1,6 +1,6 @@ require_relative 'utils' -if defined?(OpenSSL) +if defined?(OpenSSL::TestUtils) class OpenSSL::TestDigest < Test::Unit::TestCase def setup diff --git a/test/test_engine.rb b/test/test_engine.rb index 46a2948c..a7264d0e 100644 --- a/test/test_engine.rb +++ b/test/test_engine.rb @@ -71,5 +71,5 @@ class OpenSSL::TestEngine < Test::Unit::TestCase cipher.update(data) + cipher.final end -end if defined?(OpenSSL) +end if defined?(OpenSSL::TestUtils) diff --git a/test/test_fips.rb b/test/test_fips.rb index 882647f7..6e4ac6d3 100644 --- a/test/test_fips.rb +++ b/test/test_fips.rb @@ -1,6 +1,6 @@ require_relative 'utils' -if defined?(OpenSSL) +if defined?(OpenSSL::TestUtils) class OpenSSL::TestFIPS < Test::Unit::TestCase diff --git a/test/test_hmac.rb b/test/test_hmac.rb index f1e45365..f709ebd6 100644 --- a/test/test_hmac.rb +++ b/test/test_hmac.rb @@ -38,4 +38,4 @@ class OpenSSL::TestHMAC < Test::Unit::TestCase result = hmac.update(data).hexdigest assert_equal "a13984b929a07912e4e21c5720876a8e150d6f67f854437206e7f86547248396", result end -end if defined?(OpenSSL) +end if defined?(OpenSSL::TestUtils) diff --git a/test/test_ns_spki.rb b/test/test_ns_spki.rb index 7cddefad..ab07bfbe 100644 --- a/test/test_ns_spki.rb +++ b/test/test_ns_spki.rb @@ -1,6 +1,6 @@ require_relative 'utils' -if defined?(OpenSSL) +if defined?(OpenSSL::TestUtils) class OpenSSL::TestNSSPI < Test::Unit::TestCase def setup diff --git a/test/test_ocsp.rb b/test/test_ocsp.rb index b42b57d4..af727d8e 100644 --- a/test/test_ocsp.rb +++ b/test/test_ocsp.rb @@ -1,6 +1,6 @@ require_relative "utils" -if defined?(OpenSSL) +if defined?(OpenSSL::TestUtils) class OpenSSL::TestOCSP < Test::Unit::TestCase def setup diff --git a/test/test_pair.rb b/test/test_pair.rb index 9154408a..3aca5f48 100644 --- a/test/test_pair.rb +++ b/test/test_pair.rb @@ -1,9 +1,9 @@ require_relative 'utils' -if defined?(OpenSSL) +if defined?(OpenSSL::TestUtils) require 'socket' -require_relative 'ut_eof' +require_relative '../ruby/ut_eof' module OpenSSL::SSLPairM def server diff --git a/test/test_partial_record_read.rb b/test/test_partial_record_read.rb index f3d83c69..1899a300 100644 --- a/test/test_partial_record_read.rb +++ b/test/test_partial_record_read.rb @@ -1,12 +1,10 @@ require_relative "utils" -if defined?(OpenSSL) +if defined?(OpenSSL::TestUtils) class OpenSSL::TestPartialRecordRead < OpenSSL::SSLTestCase def test_partial_tls_record_read_nonblock - port = 12345 - - start_server(port, OpenSSL::SSL::VERIFY_NONE, true, :server_proc => + start_server(OpenSSL::SSL::VERIFY_NONE, true, :server_proc => Proc.new do |server_ctx, server_ssl| begin server_ssl.io.write("\x01") # the beginning of a TLS record diff --git a/test/test_pkcs12.rb b/test/test_pkcs12.rb index 25ff6063..4e379041 100644 --- a/test/test_pkcs12.rb +++ b/test/test_pkcs12.rb @@ -1,6 +1,6 @@ require_relative "utils" -if defined?(OpenSSL) +if defined?(OpenSSL::TestUtils) module OpenSSL class TestPKCS12 < Test::Unit::TestCase diff --git a/test/test_pkcs5.rb b/test/test_pkcs5.rb index 30fa3e5b..5e85dde9 100644 --- a/test/test_pkcs5.rb +++ b/test/test_pkcs5.rb @@ -94,4 +94,4 @@ class OpenSSL::TestPKCS5 < Test::Unit::TestCase assert_equal(value1, value2) end if OpenSSL::PKCS5.respond_to?(:pbkdf2_hmac) -end if defined?(OpenSSL) +end if defined?(OpenSSL::TestUtils) diff --git a/test/test_pkcs7.rb b/test/test_pkcs7.rb index a1ff0485..47bd4f31 100644 --- a/test/test_pkcs7.rb +++ b/test/test_pkcs7.rb @@ -1,6 +1,6 @@ require_relative 'utils' -if defined?(OpenSSL) +if defined?(OpenSSL::TestUtils) class OpenSSL::TestPKCS7 < Test::Unit::TestCase def setup diff --git a/test/test_pkey_dh.rb b/test/test_pkey_dh.rb index 160a131c..67dd3e7d 100644 --- a/test/test_pkey_dh.rb +++ b/test/test_pkey_dh.rb @@ -1,6 +1,6 @@ require_relative 'utils' -if defined?(OpenSSL) +if defined?(OpenSSL::TestUtils) class OpenSSL::TestPKeyDH < Test::Unit::TestCase diff --git a/test/test_pkey_dsa.rb b/test/test_pkey_dsa.rb index 555637e7..e4ea1b5b 100644 --- a/test/test_pkey_dsa.rb +++ b/test/test_pkey_dsa.rb @@ -1,7 +1,7 @@ require_relative 'utils' require 'base64' -if defined?(OpenSSL) +if defined?(OpenSSL::TestUtils) class OpenSSL::TestPKeyDSA < Test::Unit::TestCase def test_private diff --git a/test/test_pkey_ec.rb b/test/test_pkey_ec.rb index 5ceea4c8..1693ace0 100644 --- a/test/test_pkey_ec.rb +++ b/test/test_pkey_ec.rb @@ -1,6 +1,6 @@ require_relative 'utils' -if defined?(OpenSSL::PKey::EC) +if defined?(OpenSSL::TestUtils) && defined?(OpenSSL::PKey::EC) class OpenSSL::TestEC < Test::Unit::TestCase def setup diff --git a/test/test_pkey_rsa.rb b/test/test_pkey_rsa.rb index df0c6090..ea042c27 100644 --- a/test/test_pkey_rsa.rb +++ b/test/test_pkey_rsa.rb @@ -1,7 +1,7 @@ require_relative 'utils' require 'base64' -if defined?(OpenSSL) +if defined?(OpenSSL::TestUtils) class OpenSSL::TestPKeyRSA < Test::Unit::TestCase def test_padding diff --git a/test/test_ssl.rb b/test/test_ssl.rb index 778dd8bc..3eddb0a8 100644 --- a/test/test_ssl.rb +++ b/test/test_ssl.rb @@ -1,6 +1,6 @@ require_relative "utils" -if defined?(OpenSSL) +if defined?(OpenSSL::TestUtils) class OpenSSL::TestSSL < OpenSSL::SSLTestCase @@ -19,15 +19,22 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase ctx.options & OpenSSL::SSL::OP_NO_COMPRESSION) end if defined?(OpenSSL::SSL::OP_NO_COMPRESSION) + def test_ctx_setup_with_extra_chain_cert + ctx = OpenSSL::SSL::SSLContext.new + ctx.extra_chain_cert = [@ca_cert, @cli_cert] + assert_equal(ctx.setup, true) + assert_equal(ctx.setup, nil) + end + def test_not_started_session - pend "non socket argument of SSLSocket.new is not supported on this platform" if /mswin|mingw/ =~ RUBY_PLATFORM + skip "non socket argument of SSLSocket.new is not supported on this platform" if /mswin|mingw/ =~ RUBY_PLATFORM open(__FILE__) do |f| assert_nil OpenSSL::SSL::SSLSocket.new(f).cert end end def test_ssl_gets - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true) { |server, port| + start_server(OpenSSL::SSL::VERIFY_NONE, true) { |server, port| server_connect(port) { |ssl| ssl.write "abc\n" IO.select [ssl] @@ -41,7 +48,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end def test_ssl_read_nonblock - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true) { |server, port| + start_server(OpenSSL::SSL::VERIFY_NONE, true) { |server, port| server_connect(port) { |ssl| assert_raise(IO::WaitReadable) { ssl.read_nonblock(100) } ssl.write("abc\n") @@ -54,7 +61,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end def test_connect_and_close - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| + start_server(OpenSSL::SSL::VERIFY_NONE, true){|server, port| sock = TCPSocket.new("127.0.0.1", port) ssl = OpenSSL::SSL::SSLSocket.new(sock) assert(ssl.connect) @@ -72,7 +79,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end def test_read_and_write - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| + start_server(OpenSSL::SSL::VERIFY_NONE, true){|server, port| server_connect(port) { |ssl| # syswrite and sysread ITERATIONS.times{|i| @@ -119,9 +126,9 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase } end - def test_client_auth + def test_client_auth_failure vflag = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT - start_server(PORT, vflag, true){|server, port| + start_server(vflag, true, :ignore_listener_error => true){|server, port| assert_raise(OpenSSL::SSL::SSLError, Errno::ECONNRESET){ sock = TCPSocket.new("127.0.0.1", port) ssl = OpenSSL::SSL::SSLSocket.new(sock) @@ -132,7 +139,12 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase ssl.close end } + } + end + def test_client_auth_success + vflag = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT + start_server(vflag, true){|server, port| ctx = OpenSSL::SSL::SSLContext.new ctx.key = @cli_key ctx.cert = @cli_cert @@ -163,7 +175,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase 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| + start_server(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| @@ -176,7 +188,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase def test_read_nonblock_without_session OpenSSL::TestUtils.silent do - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, false){|server, port| + start_server(OpenSSL::SSL::VERIFY_NONE, false){|server, port| sock = TCPSocket.new("127.0.0.1", port) ssl = OpenSSL::SSL::SSLSocket.new(sock) ssl.sync_close = true @@ -194,7 +206,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase def test_starttls OpenSSL::TestUtils.silent do - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, false){|server, port| + start_server(OpenSSL::SSL::VERIFY_NONE, false){|server, port| sock = TCPSocket.new("127.0.0.1", port) ssl = OpenSSL::SSL::SSLSocket.new(sock) ssl.sync_close = true @@ -218,7 +230,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase def test_parallel GC.start - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| + start_server(OpenSSL::SSL::VERIFY_NONE, true){|server, port| ssls = [] 10.times{ sock = TCPSocket.new("127.0.0.1", port) @@ -239,7 +251,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end def test_verify_result - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| + start_server(OpenSSL::SSL::VERIFY_NONE, true, :ignore_listener_error => true){|server, port| sock = TCPSocket.new("127.0.0.1", port) ctx = OpenSSL::SSL::SSLContext.new ctx.set_params @@ -253,7 +265,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end } - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| + start_server(OpenSSL::SSL::VERIFY_NONE, true){|server, port| sock = TCPSocket.new("127.0.0.1", port) ctx = OpenSSL::SSL::SSLContext.new ctx.set_params( @@ -272,7 +284,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end } - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| + start_server(OpenSSL::SSL::VERIFY_NONE, true, :ignore_listener_error => true){|server, port| sock = TCPSocket.new("127.0.0.1", port) ctx = OpenSSL::SSL::SSLContext.new ctx.set_params( @@ -293,7 +305,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end def test_exception_in_verify_callback_is_ignored - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| + start_server(OpenSSL::SSL::VERIFY_NONE, true, :ignore_listener_error => true){|server, port| sock = TCPSocket.new("127.0.0.1", port) ctx = OpenSSL::SSL::SSLContext.new ctx.set_params( @@ -317,7 +329,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end def test_sslctx_set_params - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| + start_server(OpenSSL::SSL::VERIFY_NONE, true, :ignore_listener_error => true){|server, port| sock = TCPSocket.new("127.0.0.1", port) ctx = OpenSSL::SSL::SSLContext.new ctx.set_params @@ -342,7 +354,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase def test_post_connection_check sslerr = OpenSSL::SSL::SSLError - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| + start_server(OpenSSL::SSL::VERIFY_NONE, true){|server, port| server_connect(port) { |ssl| assert_raise(sslerr){ssl.post_connection_check("localhost.localdomain")} assert_raise(sslerr){ssl.post_connection_check("127.0.0.1")} @@ -365,7 +377,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase ] @svr_cert = issue_cert(@svr, @svr_key, 4, now, now+1800, exts, @ca_cert, @ca_key, OpenSSL::Digest::SHA1.new) - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| + start_server(OpenSSL::SSL::VERIFY_NONE, true){|server, port| server_connect(port) { |ssl| assert(ssl.post_connection_check("localhost.localdomain")) assert(ssl.post_connection_check("127.0.0.1")) @@ -387,7 +399,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase ] @svr_cert = issue_cert(@svr, @svr_key, 5, now, now+1800, exts, @ca_cert, @ca_key, OpenSSL::Digest::SHA1.new) - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| + start_server(OpenSSL::SSL::VERIFY_NONE, true){|server, port| server_connect(port) { |ssl| assert(ssl.post_connection_check("localhost.localdomain")) assert_raise(sslerr){ssl.post_connection_check("127.0.0.1")} @@ -453,7 +465,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase readwrite_loop(ctx, ssl) end - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true, :ctx_proc => ctx_proc, :server_proc => server_proc) do |server, port| + start_server(OpenSSL::SSL::VERIFY_NONE, true, :ctx_proc => ctx_proc, :server_proc => server_proc) do |server, port| 2.times do |i| ctx = OpenSSL::SSL::SSLContext.new if defined?(OpenSSL::SSL::OP_NO_TICKET) @@ -486,7 +498,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase assert_equal(num_written, raw_size) ssl.close } - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true, :server_proc => server_proc){|server, port| + start_server(OpenSSL::SSL::VERIFY_NONE, true, :server_proc => server_proc){|server, port| server_connect(port) { |ssl| str = auml * i num_written = ssl.write(str) @@ -502,7 +514,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase # But it also degrades gracefully, so keep it ctx.options = OpenSSL::SSL::OP_ALL } - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true, :ctx_proc => ctx_proc){|server, port| + start_server(OpenSSL::SSL::VERIFY_NONE, true, :ctx_proc => ctx_proc){|server, port| server_connect(port) { |ssl| ssl.puts('hello') assert_equal("hello\n", ssl.gets) @@ -688,7 +700,7 @@ end def test_invalid_shutdown_by_gc assert_nothing_raised { - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| + start_server(OpenSSL::SSL::VERIFY_NONE, true){|server, port| 10.times { sock = TCPSocket.new("127.0.0.1", port) ssl = OpenSSL::SSL::SSLSocket.new(sock) @@ -701,7 +713,7 @@ end end def test_close_after_socket_close - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| + start_server(OpenSSL::SSL::VERIFY_NONE, true){|server, port| sock = TCPSocket.new("127.0.0.1", port) ssl = OpenSSL::SSL::SSLSocket.new(sock) ssl.sync_close = true @@ -730,11 +742,11 @@ end ctx_proc.call(ctx) if ctx_proc } start_server( - PORT, OpenSSL::SSL::VERIFY_NONE, true, :ctx_proc => ctx_wrap, :server_proc => server_proc, + :ignore_listener_error => true, &blk ) end @@ -746,7 +758,11 @@ end ssl.connect yield ssl ensure - ssl.close + if ssl + ssl.close + elsif sock + sock.close + end end end diff --git a/test/test_ssl_session.rb b/test/test_ssl_session.rb index 3e89633f..16432bcb 100644 --- a/test/test_ssl_session.rb +++ b/test/test_ssl_session.rb @@ -1,6 +1,6 @@ require_relative "utils" -if defined?(OpenSSL) +if defined?(OpenSSL::TestUtils) class OpenSSL::TestSSLSession < OpenSSL::SSLTestCase def test_session_equals @@ -26,23 +26,26 @@ tddwpBAEDjcwMzA5NTYzMTU1MzAwpQMCARM= -----END SSL SESSION PARAMETERS----- SESSION - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true) { |_, port| + start_server(OpenSSL::SSL::VERIFY_NONE, true, :ignore_listener_error => true) { |_, port| ctx = OpenSSL::SSL::SSLContext.new ctx.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT ctx.session_id_context = self.object_id.to_s sock = TCPSocket.new '127.0.0.1', port - ssl = OpenSSL::SSL::SSLSocket.new sock, ctx - ssl.session = session + begin + ssl = OpenSSL::SSL::SSLSocket.new sock, ctx + ssl.session = session - assert_equal session, ssl.session - sock.close + assert_equal session, ssl.session + ensure + sock.close + end } end def test_session timeout(5) do - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true) do |server, port| + start_server(OpenSSL::SSL::VERIFY_NONE, true) do |server, port| sock = TCPSocket.new("127.0.0.1", port) ctx = OpenSSL::SSL::SSLContext.new("TLSv1") ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) @@ -153,7 +156,7 @@ __EOS__ def test_client_session last_session = nil - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true) do |server, port| + start_server(OpenSSL::SSL::VERIFY_NONE, true) do |server, port| 2.times do sock = TCPSocket.new("127.0.0.1", port) # Debian's openssl 0.9.8g-13 failed at assert(ssl.session_reused?), @@ -239,7 +242,7 @@ __EOS__ end first_session = nil - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true, :ctx_proc => ctx_proc, :server_proc => server_proc) do |server, port| + start_server(OpenSSL::SSL::VERIFY_NONE, true, :ctx_proc => ctx_proc, :server_proc => server_proc) do |server, port| 10.times do |i| sock = TCPSocket.new("127.0.0.1", port) ctx = OpenSSL::SSL::SSLContext.new @@ -275,7 +278,7 @@ __EOS__ def test_ctx_client_session_cb called = {} - ctx = OpenSSL::SSL::SSLContext.new("SSLv3") + ctx = OpenSSL::SSL::SSLContext.new ctx.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT ctx.session_new_cb = lambda { |ary| @@ -289,18 +292,22 @@ __EOS__ # any resulting value is OK (ignored) } - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true) do |server, port| + start_server(OpenSSL::SSL::VERIFY_NONE, true) do |server, port| sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - ssl.sync_close = true - ssl.connect - assert_equal(1, ctx.session_cache_stats[:cache_num]) - assert_equal(1, ctx.session_cache_stats[:connect_good]) - assert_equal([ssl, ssl.session], called[:new]) - assert(ctx.session_remove(ssl.session)) - assert(!ctx.session_remove(ssl.session)) - assert_equal([ctx, ssl.session], called[:remove]) - ssl.close + begin + ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) + ssl.sync_close = true + ssl.connect + assert_equal(1, ctx.session_cache_stats[:cache_num]) + assert_equal(1, ctx.session_cache_stats[:connect_good]) + assert_equal([ssl, ssl.session], called[:new]) + assert(ctx.session_remove(ssl.session)) + assert(!ctx.session_remove(ssl.session)) + assert_equal([ctx, ssl.session], called[:remove]) + ssl.close + ensure + sock.close if !sock.closed? + end end end @@ -343,21 +350,25 @@ __EOS__ c.session_cache_stats readwrite_loop(c, ssl) } - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true, :ctx_proc => ctx_proc, :server_proc => server_proc) do |server, port| + start_server(OpenSSL::SSL::VERIFY_NONE, true, :ctx_proc => ctx_proc, :server_proc => server_proc) do |server, port| last_client_session = nil 3.times do sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock, OpenSSL::SSL::SSLContext.new("SSLv3")) - ssl.sync_close = true - ssl.session = last_client_session if last_client_session - ssl.connect - last_client_session = ssl.session - ssl.close - timeout(5) do - Thread.pass until called.key?(:new) - assert(called.delete(:new)) - Thread.pass until called.key?(:remove) - assert(called.delete(:remove)) + begin + ssl = OpenSSL::SSL::SSLSocket.new(sock, OpenSSL::SSL::SSLContext.new("SSLv3")) + ssl.sync_close = true + ssl.session = last_client_session if last_client_session + ssl.connect + last_client_session = ssl.session + ssl.close + timeout(5) do + Thread.pass until called.key?(:new) + assert(called.delete(:new)) + Thread.pass until called.key?(:remove) + assert(called.delete(:remove)) + end + ensure + sock.close if !sock.closed? end end end diff --git a/test/test_x509cert.rb b/test/test_x509cert.rb index f13d6456..783677a4 100644 --- a/test/test_x509cert.rb +++ b/test/test_x509cert.rb @@ -1,6 +1,6 @@ require_relative "utils" -if defined?(OpenSSL) +if defined?(OpenSSL::TestUtils) class OpenSSL::TestX509Certificate < Test::Unit::TestCase def setup diff --git a/test/test_x509crl.rb b/test/test_x509crl.rb index d5024751..9dc1b1cd 100644 --- a/test/test_x509crl.rb +++ b/test/test_x509crl.rb @@ -1,6 +1,6 @@ require_relative "utils" -if defined?(OpenSSL) +if defined?(OpenSSL::TestUtils) class OpenSSL::TestX509CRL < Test::Unit::TestCase def setup diff --git a/test/test_x509ext.rb b/test/test_x509ext.rb index 89b45c72..29e9f1dc 100644 --- a/test/test_x509ext.rb +++ b/test/test_x509ext.rb @@ -1,6 +1,6 @@ require_relative 'utils' -if defined?(OpenSSL) +if defined?(OpenSSL::TestUtils) class OpenSSL::TestX509Extension < Test::Unit::TestCase def setup diff --git a/test/test_x509name.rb b/test/test_x509name.rb index de35fc30..a92af534 100644 --- a/test/test_x509name.rb +++ b/test/test_x509name.rb @@ -1,7 +1,7 @@ # coding: US-ASCII require_relative 'utils' -if defined?(OpenSSL) +if defined?(OpenSSL::TestUtils) class OpenSSL::TestX509Name < Test::Unit::TestCase OpenSSL::ASN1::ObjectId.register( diff --git a/test/test_x509req.rb b/test/test_x509req.rb index 458f3079..27040cb7 100644 --- a/test/test_x509req.rb +++ b/test/test_x509req.rb @@ -1,6 +1,6 @@ require_relative "utils" -if defined?(OpenSSL) +if defined?(OpenSSL::TestUtils) class OpenSSL::TestX509Request < Test::Unit::TestCase def setup @@ -138,7 +138,7 @@ class OpenSSL::TestX509Request < Test::Unit::TestCase req.version = 1 assert_equal(false, req.verify(@rsa1024)) rescue OpenSSL::X509::RequestError - pend + skip end def test_sign_and_verify_dsa_md5 diff --git a/test/test_x509store.rb b/test/test_x509store.rb index 1e46ba19..f3e144fc 100644 --- a/test/test_x509store.rb +++ b/test/test_x509store.rb @@ -1,7 +1,6 @@ -require_relative "envutil" require_relative "utils" -if defined?(OpenSSL) +if defined?(OpenSSL::TestUtils) class OpenSSL::TestX509Store < Test::Unit::TestCase def setup diff --git a/test/utils.rb b/test/utils.rb index 607daea8..8a289e5d 100644 --- a/test/utils.rb +++ b/test/utils.rb @@ -12,7 +12,7 @@ require "digest/md5" require 'tempfile' require "rbconfig" require "socket" -require_relative 'envutil' +require "envutil" module OpenSSL::TestUtils TEST_KEY_RSA1024 = OpenSSL::PKey::RSA.new <<-_end_of_pem_ @@ -190,8 +190,6 @@ AQjjxMXhwULlmuR/K+WwlaZPiLIBYalLAZQ7ZbOPeVkJ8ePao0eLAgEC class OpenSSL::SSLTestCase < Test::Unit::TestCase RUBY = EnvUtil.rubybin - SSL_SERVER = File.join(File.dirname(__FILE__), "ssl_server.rb") - PORT = 20443 ITERATIONS = ($0 == __FILE__) ? 100 : 10 def setup @@ -240,88 +238,85 @@ AQjjxMXhwULlmuR/K+WwlaZPiLIBYalLAZQ7ZbOPeVkJ8ePao0eLAgEC ssl.close rescue nil end - def server_loop(ctx, ssls, server_proc, threads) + def server_loop(ctx, ssls, stop_pipe_r, ignore_listener_error, server_proc, threads) loop do ssl = nil begin + readable, = IO.select([ssls, stop_pipe_r]) + if readable.include? stop_pipe_r + return + end ssl = ssls.accept rescue OpenSSL::SSL::SSLError - retry + if ignore_listener_error + retry + else + raise + end end th = Thread.start do - Thread.current.abort_on_exception = true server_proc.call(ctx, ssl) end threads << th end rescue Errno::EBADF, IOError, Errno::EINVAL, Errno::ECONNABORTED, Errno::ENOTSOCK, Errno::ECONNRESET - end - - def start_server(port0, verify_mode, start_immediately, args = {}, &block) - ctx_proc = args[:ctx_proc] - server_proc = args[:server_proc] - server_proc ||= method(:readwrite_loop) - threads = [] - - store = OpenSSL::X509::Store.new - store.add_cert(@ca_cert) - store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT - ctx = OpenSSL::SSL::SSLContext.new - ctx.cert_store = store - #ctx.extra_chain_cert = [ ca_cert ] - ctx.cert = @svr_cert - ctx.key = @svr_key - ctx.tmp_dh_callback = proc { OpenSSL::TestUtils::TEST_KEY_DH1024 } - ctx.verify_mode = verify_mode - ctx_proc.call(ctx) if ctx_proc - - Socket.do_not_reverse_lookup = true - tcps = nil - port = port0 - begin - tcps = TCPServer.new("127.0.0.1", port) - rescue Errno::EADDRINUSE - port += 1 - retry + if !ignore_listener_error + raise end + end - ssls = OpenSSL::SSL::SSLServer.new(tcps, ctx) - ssls.start_immediately = start_immediately - - begin - server = Thread.new do - Thread.current.abort_on_exception = true - server_loop(ctx, ssls, server_proc, threads) - end + def start_server(verify_mode, start_immediately, args = {}, &block) + IO.pipe {|stop_pipe_r, stop_pipe_w| + ctx_proc = args[:ctx_proc] + server_proc = args[:server_proc] + ignore_listener_error = args.fetch(:ignore_listener_error, false) + server_proc ||= method(:readwrite_loop) + + store = OpenSSL::X509::Store.new + store.add_cert(@ca_cert) + store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT + ctx = OpenSSL::SSL::SSLContext.new + ctx.cert_store = store + #ctx.extra_chain_cert = [ ca_cert ] + ctx.cert = @svr_cert + ctx.key = @svr_key + ctx.tmp_dh_callback = proc { OpenSSL::TestUtils::TEST_KEY_DH1024 } + ctx.verify_mode = verify_mode + ctx_proc.call(ctx) if ctx_proc + + Socket.do_not_reverse_lookup = true + tcps = nil + tcps = TCPServer.new("127.0.0.1", 0) + port = tcps.connect_address.ip_port + + ssls = OpenSSL::SSL::SSLServer.new(tcps, ctx) + ssls.start_immediately = start_immediately + + threads = [] + begin + server = Thread.new do + begin + server_loop(ctx, ssls, stop_pipe_r, ignore_listener_error, server_proc, threads) + ensure + tcps.close + end + end + threads.unshift server - $stderr.printf("%s started: pid=%d port=%d\n", SSL_SERVER, $$, port) if $DEBUG + $stderr.printf("SSL server started: pid=%d port=%d\n", $$, port) if $DEBUG - block.call(server, port.to_i) - ensure - begin - begin - tcps.shutdown - rescue Errno::ENOTCONN - # when `Errno::ENOTCONN: Socket is not connected' on some platforms, - # call #close instead of #shutdown. - tcps.close - tcps = nil - end if (tcps) - if (server) - server.join(5) - if server.alive? - server.join - flunk("TCPServer was closed and SSLServer is still alive") unless $! + client = Thread.new do + begin + block.call(server, port.to_i) + ensure + stop_pipe_w.close end end + threads.unshift client ensure - tcps.close if (tcps) + assert_join_threads(threads) end - end - ensure - threads.each {|th| - th.join } end @@ -333,18 +328,5 @@ AQjjxMXhwULlmuR/K+WwlaZPiLIBYalLAZQ7ZbOPeVkJ8ePao0eLAgEC end end -end if defined?(OpenSSL) - -module Test - module Unit - class TestCase - def message msg = nil, ending = ".", &default - proc { - msg = msg.call.chomp(".") if Proc === msg - custom_message = "#{msg}.\n" unless msg.nil? or msg.to_s.empty? - "#{custom_message}#{default.call}#{ending}" - } - end - end - end -end +end if defined?(OpenSSL::OPENSSL_LIBRARY_VERSION) and + /\AOpenSSL +0\./ !~ OpenSSL::OPENSSL_LIBRARY_VERSION |