aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ext/openssl/openssl_missing.h4
-rw-r--r--ext/openssl/ossl.c23
-rw-r--r--ext/openssl/ossl.h5
-rw-r--r--ext/openssl/ossl_bn.c10
-rw-r--r--ext/openssl/ossl_cipher.c14
-rw-r--r--ext/openssl/ossl_engine.c54
-rw-r--r--ext/openssl/ossl_ssl.c46
-rw-r--r--ext/openssl/ossl_x509cert.c25
-rw-r--r--ext/openssl/ossl_x509crl.c4
-rw-r--r--ext/openssl/ossl_x509revoked.c21
-rw-r--r--lib/openssl/ssl.rb3
-rw-r--r--lib/openssl/x509.rb33
-rw-r--r--test/test_ssl.rb71
-rw-r--r--test/test_x509attr.rb17
-rw-r--r--test/test_x509cert.rb14
-rw-r--r--test/test_x509crl.rb50
-rw-r--r--test/test_x509ext.rb11
-rw-r--r--test/test_x509req.rb10
18 files changed, 352 insertions, 63 deletions
diff --git a/ext/openssl/openssl_missing.h b/ext/openssl/openssl_missing.h
index cc31f6ac..debd25ad 100644
--- a/ext/openssl/openssl_missing.h
+++ b/ext/openssl/openssl_missing.h
@@ -209,6 +209,10 @@ IMPL_PKEY_GETTER(EC_KEY, ec)
# define X509_get0_notAfter(x) X509_get_notAfter(x)
# define X509_CRL_get0_lastUpdate(x) X509_CRL_get_lastUpdate(x)
# define X509_CRL_get0_nextUpdate(x) X509_CRL_get_nextUpdate(x)
+# define X509_set1_notBefore(x, t) X509_set_notBefore(x, t)
+# define X509_set1_notAfter(x, t) X509_set_notAfter(x, t)
+# define X509_CRL_set1_lastUpdate(x, t) X509_CRL_set_lastUpdate(x, t)
+# define X509_CRL_set1_nextUpdate(x, t) X509_CRL_set_nextUpdate(x, t)
#endif
#if !defined(HAVE_SSL_SESSION_GET_PROTOCOL_VERSION)
diff --git a/ext/openssl/ossl.c b/ext/openssl/ossl.c
index 93ecc7d4..245385e7 100644
--- a/ext/openssl/ossl.c
+++ b/ext/openssl/ossl.c
@@ -1109,25 +1109,14 @@ Init_openssl(void)
/*
* Init all digests, ciphers
*/
- /* CRYPTO_malloc_init(); */
- /* ENGINE_load_builtin_engines(); */
+#if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000
+ if (!OPENSSL_init_ssl(0, NULL))
+ rb_raise(rb_eRuntimeError, "OPENSSL_init_ssl");
+#else
OpenSSL_add_ssl_algorithms();
OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();
SSL_load_error_strings();
-
- /*
- * FIXME:
- * On unload do:
- */
-#if 0
- CONF_modules_unload(1);
- destroy_ui_method();
- EVP_cleanup();
- ENGINE_cleanup();
- CRYPTO_cleanup_all_ex_data();
- ERR_remove_state(0);
- ERR_free_strings();
#endif
/*
@@ -1149,7 +1138,11 @@ Init_openssl(void)
/*
* Version of OpenSSL the ruby OpenSSL extension is running with
*/
+#if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000
+ rb_define_const(mOSSL, "OPENSSL_LIBRARY_VERSION", rb_str_new2(OpenSSL_version(OPENSSL_VERSION)));
+#else
rb_define_const(mOSSL, "OPENSSL_LIBRARY_VERSION", rb_str_new2(SSLeay_version(SSLEAY_VERSION)));
+#endif
/*
* Version number of OpenSSL the ruby OpenSSL extension was built with
diff --git a/ext/openssl/ossl.h b/ext/openssl/ossl.h
index f08889b2..5a15839c 100644
--- a/ext/openssl/ossl.h
+++ b/ext/openssl/ossl.h
@@ -35,6 +35,11 @@
#if !defined(OPENSSL_NO_OCSP)
# include <openssl/ocsp.h>
#endif
+#include <openssl/bn.h>
+#include <openssl/rsa.h>
+#include <openssl/dsa.h>
+#include <openssl/evp.h>
+#include <openssl/dh.h>
/*
* Common Module
diff --git a/ext/openssl/ossl_bn.c b/ext/openssl/ossl_bn.c
index d337d509..4666ce6c 100644
--- a/ext/openssl/ossl_bn.c
+++ b/ext/openssl/ossl_bn.c
@@ -979,20 +979,20 @@ static VALUE
ossl_bn_hash(VALUE self)
{
BIGNUM *bn;
- VALUE hash;
+ VALUE tmp, hash;
unsigned char *buf;
int len;
GetBN(self, bn);
len = BN_num_bytes(bn);
- buf = xmalloc(len);
+ buf = ALLOCV(tmp, len);
if (BN_bn2bin(bn, buf) != len) {
- xfree(buf);
- ossl_raise(eBNError, NULL);
+ ALLOCV_END(tmp);
+ ossl_raise(eBNError, "BN_bn2bin");
}
hash = ST2FIX(rb_memhash(buf, len));
- xfree(buf);
+ ALLOCV_END(tmp);
return hash;
}
diff --git a/ext/openssl/ossl_cipher.c b/ext/openssl/ossl_cipher.c
index bfa76c1a..e6179733 100644
--- a/ext/openssl/ossl_cipher.c
+++ b/ext/openssl/ossl_cipher.c
@@ -508,7 +508,7 @@ ossl_cipher_set_iv(VALUE self, VALUE iv)
StringValue(iv);
GetCipher(self, ctx);
- if (EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_FLAG_AEAD_CIPHER)
+ if (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER)
iv_len = (int)(VALUE)EVP_CIPHER_CTX_get_app_data(ctx);
if (!iv_len)
iv_len = EVP_CIPHER_CTX_iv_length(ctx);
@@ -535,7 +535,7 @@ ossl_cipher_is_authenticated(VALUE self)
GetCipher(self, ctx);
- return (EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_FLAG_AEAD_CIPHER) ? Qtrue : Qfalse;
+ return (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER) ? Qtrue : Qfalse;
}
/*
@@ -606,7 +606,7 @@ ossl_cipher_get_auth_tag(int argc, VALUE *argv, VALUE self)
GetCipher(self, ctx);
- if (!(EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_FLAG_AEAD_CIPHER))
+ if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))
ossl_raise(eCipherError, "authentication tag not supported by this cipher");
ret = rb_str_new(NULL, tag_len);
@@ -641,7 +641,7 @@ ossl_cipher_set_auth_tag(VALUE self, VALUE vtag)
tag_len = RSTRING_LENINT(vtag);
GetCipher(self, ctx);
- if (!(EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_FLAG_AEAD_CIPHER))
+ if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))
ossl_raise(eCipherError, "authentication tag not supported by this cipher");
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, tag))
@@ -668,7 +668,7 @@ ossl_cipher_set_auth_tag_len(VALUE self, VALUE vlen)
EVP_CIPHER_CTX *ctx;
GetCipher(self, ctx);
- if (!(EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_FLAG_AEAD_CIPHER))
+ if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))
ossl_raise(eCipherError, "AEAD not supported by this cipher");
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, NULL))
@@ -695,7 +695,7 @@ ossl_cipher_set_iv_length(VALUE self, VALUE iv_length)
EVP_CIPHER_CTX *ctx;
GetCipher(self, ctx);
- if (!(EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_FLAG_AEAD_CIPHER))
+ if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))
ossl_raise(eCipherError, "cipher does not support AEAD");
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, len, NULL))
@@ -786,7 +786,7 @@ ossl_cipher_iv_length(VALUE self)
int len = 0;
GetCipher(self, ctx);
- if (EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_FLAG_AEAD_CIPHER)
+ if (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER)
len = (int)(VALUE)EVP_CIPHER_CTX_get_app_data(ctx);
if (!len)
len = EVP_CIPHER_CTX_iv_length(ctx);
diff --git a/ext/openssl/ossl_engine.c b/ext/openssl/ossl_engine.c
index d69b5dca..5ca0d4ca 100644
--- a/ext/openssl/ossl_engine.c
+++ b/ext/openssl/ossl_engine.c
@@ -46,13 +46,25 @@ VALUE eEngineError;
/*
* Private
*/
-#define OSSL_ENGINE_LOAD_IF_MATCH(x) \
+#if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000
+#define OSSL_ENGINE_LOAD_IF_MATCH(engine_name, x) \
do{\
- if(!strcmp(#x, RSTRING_PTR(name))){\
- ENGINE_load_##x();\
+ if(!strcmp(#engine_name, RSTRING_PTR(name))){\
+ if (OPENSSL_init_crypto(OPENSSL_INIT_ENGINE_##x, NULL))\
+ return Qtrue;\
+ else\
+ ossl_raise(eEngineError, "OPENSSL_init_crypto"); \
+ }\
+}while(0)
+#else
+#define OSSL_ENGINE_LOAD_IF_MATCH(engine_name, x) \
+do{\
+ if(!strcmp(#engine_name, RSTRING_PTR(name))){\
+ ENGINE_load_##engine_name();\
return Qtrue;\
}\
}while(0)
+#endif
static void
ossl_engine_free(void *engine)
@@ -94,55 +106,55 @@ ossl_engine_s_load(int argc, VALUE *argv, VALUE klass)
StringValueCStr(name);
#ifndef OPENSSL_NO_STATIC_ENGINE
#if HAVE_ENGINE_LOAD_DYNAMIC
- OSSL_ENGINE_LOAD_IF_MATCH(dynamic);
+ OSSL_ENGINE_LOAD_IF_MATCH(dynamic, DYNAMIC);
#endif
#if HAVE_ENGINE_LOAD_4758CCA
- OSSL_ENGINE_LOAD_IF_MATCH(4758cca);
+ OSSL_ENGINE_LOAD_IF_MATCH(4758cca, 4758CCA);
#endif
#if HAVE_ENGINE_LOAD_AEP
- OSSL_ENGINE_LOAD_IF_MATCH(aep);
+ OSSL_ENGINE_LOAD_IF_MATCH(aep, AEP);
#endif
#if HAVE_ENGINE_LOAD_ATALLA
- OSSL_ENGINE_LOAD_IF_MATCH(atalla);
+ OSSL_ENGINE_LOAD_IF_MATCH(atalla, ATALLA);
#endif
#if HAVE_ENGINE_LOAD_CHIL
- OSSL_ENGINE_LOAD_IF_MATCH(chil);
+ OSSL_ENGINE_LOAD_IF_MATCH(chil, CHIL);
#endif
#if HAVE_ENGINE_LOAD_CSWIFT
- OSSL_ENGINE_LOAD_IF_MATCH(cswift);
+ OSSL_ENGINE_LOAD_IF_MATCH(cswift, CSWIFT);
#endif
#if HAVE_ENGINE_LOAD_NURON
- OSSL_ENGINE_LOAD_IF_MATCH(nuron);
+ OSSL_ENGINE_LOAD_IF_MATCH(nuron, NURON);
#endif
#if HAVE_ENGINE_LOAD_SUREWARE
- OSSL_ENGINE_LOAD_IF_MATCH(sureware);
+ OSSL_ENGINE_LOAD_IF_MATCH(sureware, SUREWARE);
#endif
#if HAVE_ENGINE_LOAD_UBSEC
- OSSL_ENGINE_LOAD_IF_MATCH(ubsec);
+ OSSL_ENGINE_LOAD_IF_MATCH(ubsec, UBSEC);
#endif
#if HAVE_ENGINE_LOAD_PADLOCK
- OSSL_ENGINE_LOAD_IF_MATCH(padlock);
+ OSSL_ENGINE_LOAD_IF_MATCH(padlock, PADLOCK);
#endif
#if HAVE_ENGINE_LOAD_CAPI
- OSSL_ENGINE_LOAD_IF_MATCH(capi);
+ OSSL_ENGINE_LOAD_IF_MATCH(capi, CAPI);
#endif
#if HAVE_ENGINE_LOAD_GMP
- OSSL_ENGINE_LOAD_IF_MATCH(gmp);
+ OSSL_ENGINE_LOAD_IF_MATCH(gmp, GMP);
#endif
#if HAVE_ENGINE_LOAD_GOST
- OSSL_ENGINE_LOAD_IF_MATCH(gost);
+ OSSL_ENGINE_LOAD_IF_MATCH(gost, GOST);
#endif
#if HAVE_ENGINE_LOAD_CRYPTODEV
- OSSL_ENGINE_LOAD_IF_MATCH(cryptodev);
+ OSSL_ENGINE_LOAD_IF_MATCH(cryptodev, CRYPTODEV);
#endif
#if HAVE_ENGINE_LOAD_AESNI
- OSSL_ENGINE_LOAD_IF_MATCH(aesni);
+ OSSL_ENGINE_LOAD_IF_MATCH(aesni, AESNI);
#endif
#endif
#ifdef HAVE_ENGINE_LOAD_OPENBSD_DEV_CRYPTO
- OSSL_ENGINE_LOAD_IF_MATCH(openbsd_dev_crypto);
+ OSSL_ENGINE_LOAD_IF_MATCH(openbsd_dev_crypto, OPENBSD_DEV_CRYPTO);
#endif
- OSSL_ENGINE_LOAD_IF_MATCH(openssl);
+ OSSL_ENGINE_LOAD_IF_MATCH(openssl, OPENSSL);
rb_warning("no such builtin loader for `%"PRIsVALUE"'", name);
return Qnil;
#endif /* HAVE_ENGINE_LOAD_BUILTIN_ENGINES */
@@ -160,7 +172,9 @@ ossl_engine_s_load(int argc, VALUE *argv, VALUE klass)
static VALUE
ossl_engine_s_cleanup(VALUE self)
{
+#if defined(LIBRESSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10100000
ENGINE_cleanup();
+#endif
return Qnil;
}
diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c
index 93fc497e..d32a299c 100644
--- a/ext/openssl/ossl_ssl.c
+++ b/ext/openssl/ossl_ssl.c
@@ -32,7 +32,7 @@ VALUE cSSLSocket;
static VALUE eSSLErrorWaitReadable;
static VALUE eSSLErrorWaitWritable;
-static ID ID_callback_state, id_tmp_dh_callback, id_tmp_ecdh_callback,
+static ID id_call, ID_callback_state, id_tmp_dh_callback, id_tmp_ecdh_callback,
id_npn_protocols_encoded;
static VALUE sym_exception, sym_wait_readable, sym_wait_writable;
@@ -205,7 +205,7 @@ ossl_call_client_cert_cb(VALUE obj)
if (NIL_P(cb))
return Qnil;
- ary = rb_funcall(cb, rb_intern("call"), 1, obj);
+ ary = rb_funcallv(cb, id_call, 1, &obj);
Check_Type(ary, T_ARRAY);
GetX509CertPtr(cert = rb_ary_entry(ary, 0));
GetPrivPKeyPtr(key = rb_ary_entry(ary, 1));
@@ -248,8 +248,8 @@ ossl_call_tmp_dh_callback(struct tmp_dh_callback_args *args)
cb = rb_funcall(args->ssl_obj, args->id, 0);
if (NIL_P(cb))
return NULL;
- dh = rb_funcall(cb, rb_intern("call"), 3,
- args->ssl_obj, INT2NUM(args->is_export), INT2NUM(args->keylength));
+ dh = rb_funcall(cb, id_call, 3, args->ssl_obj, INT2NUM(args->is_export),
+ INT2NUM(args->keylength));
pkey = GetPKeyPtr(dh);
if (EVP_PKEY_base_id(pkey) != args->type)
return NULL;
@@ -374,12 +374,12 @@ ossl_call_session_get_cb(VALUE ary)
cb = rb_funcall(ssl_obj, rb_intern("session_get_cb"), 0);
if (NIL_P(cb)) return Qnil;
- return rb_funcall(cb, rb_intern("call"), 1, ary);
+ return rb_funcallv(cb, id_call, 1, &ary);
}
/* this method is currently only called for servers (in OpenSSL <= 0.9.8e) */
static SSL_SESSION *
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER)
ossl_sslctx_session_get_cb(SSL *ssl, const unsigned char *buf, int len, int *copy)
#else
ossl_sslctx_session_get_cb(SSL *ssl, unsigned char *buf, int len, int *copy)
@@ -420,7 +420,7 @@ ossl_call_session_new_cb(VALUE ary)
cb = rb_funcall(ssl_obj, rb_intern("session_new_cb"), 0);
if (NIL_P(cb)) return Qnil;
- return rb_funcall(cb, rb_intern("call"), 1, ary);
+ return rb_funcallv(cb, id_call, 1, &ary);
}
/* return 1 normal. return 0 removes the session */
@@ -467,7 +467,7 @@ ossl_call_session_remove_cb(VALUE ary)
cb = rb_attr_get(sslctx_obj, id_i_session_remove_cb);
if (NIL_P(cb)) return Qnil;
- return rb_funcall(cb, rb_intern("call"), 1, ary);
+ return rb_funcallv(cb, id_call, 1, &ary);
}
static void
@@ -533,7 +533,7 @@ ossl_call_servername_cb(VALUE ary)
cb = rb_attr_get(sslctx_obj, id_i_servername_cb);
if (NIL_P(cb)) return Qnil;
- ret_obj = rb_funcall(cb, rb_intern("call"), 1, ary);
+ ret_obj = rb_funcallv(cb, id_call, 1, &ary);
if (rb_obj_is_kind_of(ret_obj, cSSLContext)) {
SSL *ssl;
SSL_CTX *ctx2;
@@ -585,7 +585,7 @@ ssl_renegotiation_cb(const SSL *ssl)
cb = rb_attr_get(sslctx_obj, id_i_renegotiation_cb);
if (NIL_P(cb)) return;
- (void) rb_funcall(cb, rb_intern("call"), 1, ssl_obj);
+ rb_funcallv(cb, id_call, 1, &ssl_obj);
}
#if !defined(OPENSSL_NO_NEXTPROTONEG) || \
@@ -635,7 +635,7 @@ npn_select_cb_common_i(VALUE tmp)
in += l;
}
- selected = rb_funcall(args->cb, rb_intern("call"), 1, protocols);
+ selected = rb_funcallv(args->cb, id_call, 1, &protocols);
StringValue(selected);
len = RSTRING_LEN(selected);
if (len < 1 || len >= 256) {
@@ -1193,6 +1193,26 @@ ossl_sslctx_set_security_level(VALUE self, VALUE value)
return value;
}
+#ifdef SSL_MODE_SEND_FALLBACK_SCSV
+/*
+ * call-seq:
+ * ctx.enable_fallback_scsv() => nil
+ *
+ * Activate TLS_FALLBACK_SCSV for this context.
+ * See RFC 7507.
+ */
+static VALUE
+ossl_sslctx_enable_fallback_scsv(VALUE self)
+{
+ SSL_CTX *ctx;
+
+ GetSSLCTX(self, ctx);
+ SSL_CTX_set_mode(ctx, SSL_MODE_SEND_FALLBACK_SCSV);
+
+ return Qnil;
+}
+#endif
+
/*
* call-seq:
* ctx.session_add(session) -> true | false
@@ -2261,6 +2281,7 @@ Init_ossl_ssl(void)
rb_mWaitWritable = rb_define_module_under(rb_cIO, "WaitWritable");
#endif
+ id_call = rb_intern("call");
ID_callback_state = rb_intern("callback_state");
ossl_ssl_ex_vcb_idx = SSL_get_ex_new_index(0, (void *)"ossl_ssl_ex_vcb_idx", 0, 0, 0);
@@ -2557,6 +2578,9 @@ Init_ossl_ssl(void)
rb_define_method(cSSLContext, "ecdh_curves=", ossl_sslctx_set_ecdh_curves, 1);
rb_define_method(cSSLContext, "security_level", ossl_sslctx_get_security_level, 0);
rb_define_method(cSSLContext, "security_level=", ossl_sslctx_set_security_level, 1);
+#ifdef SSL_MODE_SEND_FALLBACK_SCSV
+ rb_define_method(cSSLContext, "enable_fallback_scsv", ossl_sslctx_enable_fallback_scsv, 0);
+#endif
rb_define_method(cSSLContext, "setup", ossl_sslctx_setup, 0);
rb_define_alias(cSSLContext, "freeze", "setup");
diff --git a/ext/openssl/ossl_x509cert.c b/ext/openssl/ossl_x509cert.c
index 003a9c19..8d16b9b7 100644
--- a/ext/openssl/ossl_x509cert.c
+++ b/ext/openssl/ossl_x509cert.c
@@ -440,7 +440,7 @@ ossl_x509_set_not_before(VALUE self, VALUE time)
GetX509(self, x509);
asn1time = ossl_x509_time_adjust(NULL, time);
- if (!X509_set_notBefore(x509, asn1time)) {
+ if (!X509_set1_notBefore(x509, asn1time)) {
ASN1_TIME_free(asn1time);
ossl_raise(eX509CertError, "X509_set_notBefore");
}
@@ -479,7 +479,7 @@ ossl_x509_set_not_after(VALUE self, VALUE time)
GetX509(self, x509);
asn1time = ossl_x509_time_adjust(NULL, time);
- if (!X509_set_notAfter(x509, asn1time)) {
+ if (!X509_set1_notAfter(x509, asn1time)) {
ASN1_TIME_free(asn1time);
ossl_raise(eX509CertError, "X509_set_notAfter");
}
@@ -684,6 +684,26 @@ ossl_x509_inspect(VALUE self)
}
/*
+ * call-seq:
+ * cert1 == cert2 -> true | false
+ *
+ * Compares the two certificates. Note that this takes into account all fields,
+ * not just the issuer name and the serial number.
+ */
+static VALUE
+ossl_x509_eq(VALUE self, VALUE other)
+{
+ X509 *a, *b;
+
+ GetX509(self, a);
+ if (!rb_obj_is_kind_of(other, cX509Cert))
+ return Qfalse;
+ GetX509(other, b);
+
+ return !X509_cmp(a, b) ? Qtrue : Qfalse;
+}
+
+/*
* INIT
*/
void
@@ -821,4 +841,5 @@ Init_ossl_x509cert(void)
rb_define_method(cX509Cert, "extensions=", ossl_x509_set_extensions, 1);
rb_define_method(cX509Cert, "add_extension", ossl_x509_add_extension, 1);
rb_define_method(cX509Cert, "inspect", ossl_x509_inspect, 0);
+ rb_define_method(cX509Cert, "==", ossl_x509_eq, 1);
}
diff --git a/ext/openssl/ossl_x509crl.c b/ext/openssl/ossl_x509crl.c
index 5ecd7ea0..45cf7fb4 100644
--- a/ext/openssl/ossl_x509crl.c
+++ b/ext/openssl/ossl_x509crl.c
@@ -226,7 +226,7 @@ ossl_x509crl_set_last_update(VALUE self, VALUE time)
GetX509CRL(self, crl);
asn1time = ossl_x509_time_adjust(NULL, time);
- if (!X509_CRL_set_lastUpdate(crl, asn1time)) {
+ if (!X509_CRL_set1_lastUpdate(crl, asn1time)) {
ASN1_TIME_free(asn1time);
ossl_raise(eX509CRLError, "X509_CRL_set_lastUpdate");
}
@@ -257,7 +257,7 @@ ossl_x509crl_set_next_update(VALUE self, VALUE time)
GetX509CRL(self, crl);
asn1time = ossl_x509_time_adjust(NULL, time);
- if (!X509_CRL_set_nextUpdate(crl, asn1time)) {
+ if (!X509_CRL_set1_nextUpdate(crl, asn1time)) {
ASN1_TIME_free(asn1time);
ossl_raise(eX509CRLError, "X509_CRL_set_nextUpdate");
}
diff --git a/ext/openssl/ossl_x509revoked.c b/ext/openssl/ossl_x509revoked.c
index 85489efd..5fe68534 100644
--- a/ext/openssl/ossl_x509revoked.c
+++ b/ext/openssl/ossl_x509revoked.c
@@ -249,6 +249,26 @@ ossl_x509revoked_add_extension(VALUE self, VALUE ext)
return ext;
}
+static VALUE
+ossl_x509revoked_to_der(VALUE self)
+{
+ X509_REVOKED *rev;
+ VALUE str;
+ int len;
+ unsigned char *p;
+
+ GetX509Rev(self, rev);
+ len = i2d_X509_REVOKED(rev, NULL);
+ if (len <= 0)
+ ossl_raise(eX509RevError, "i2d_X509_REVOKED");
+ str = rb_str_new(NULL, len);
+ p = (unsigned char *)RSTRING_PTR(str);
+ if (i2d_X509_REVOKED(rev, &p) <= 0)
+ ossl_raise(eX509RevError, "i2d_X509_REVOKED");
+ ossl_str_adjust(str, p);
+ return str;
+}
+
/*
* INIT
*/
@@ -276,4 +296,5 @@ Init_ossl_x509revoked(void)
rb_define_method(cX509Rev, "extensions", ossl_x509revoked_get_extensions, 0);
rb_define_method(cX509Rev, "extensions=", ossl_x509revoked_set_extensions, 1);
rb_define_method(cX509Rev, "add_extension", ossl_x509revoked_add_extension, 1);
+ rb_define_method(cX509Rev, "to_der", ossl_x509revoked_to_der, 0);
}
diff --git a/lib/openssl/ssl.rb b/lib/openssl/ssl.rb
index a628648e..6a6f2b94 100644
--- a/lib/openssl/ssl.rb
+++ b/lib/openssl/ssl.rb
@@ -136,6 +136,7 @@ YoaOffgTf5qxiwkjnlVZQc3whgnEt9FpVMvQ9eknyeGB5KHfayAc3+hUAvI3/Cr3
# used.
def set_params(params={})
params = DEFAULT_PARAMS.merge(params)
+ self.options = params.delete(:options) # set before min_version/max_version
params.each{|name, value| self.__send__("#{name}=", value) }
if self.verify_mode != OpenSSL::SSL::VERIFY_NONE
unless self.ca_file or self.ca_path or self.cert_store
@@ -201,7 +202,7 @@ YoaOffgTf5qxiwkjnlVZQc3whgnEt9FpVMvQ9eknyeGB5KHfayAc3+hUAvI3/Cr3
if /(?<type>_client|_server)\z/ =~ meth
meth = $`
if $VERBOSE
- warn "#{caller(1)[0]}: method type #{type.inspect} is ignored"
+ warn "#{caller(1, 1)[0]}: method type #{type.inspect} is ignored"
end
end
version = METHODS_MAP[meth.intern] or
diff --git a/lib/openssl/x509.rb b/lib/openssl/x509.rb
index 6d31b98c..98358f90 100644
--- a/lib/openssl/x509.rb
+++ b/lib/openssl/x509.rb
@@ -41,6 +41,11 @@ module OpenSSL
end
class Extension
+ def ==(other)
+ return false unless Extension === other
+ to_der == other.to_der
+ end
+
def to_s # "oid = critical, value"
str = self.oid
str << " = "
@@ -160,6 +165,13 @@ module OpenSSL
end
end
+ class Attribute
+ def ==(other)
+ return false unless Attribute === other
+ to_der == other.to_der
+ end
+ end
+
class StoreContext
def cleanup
warn "(#{caller.first}) OpenSSL::X509::StoreContext#cleanup is deprecated with no replacement" if $VERBOSE
@@ -178,5 +190,26 @@ module OpenSSL
}
end
end
+
+ class CRL
+ def ==(other)
+ return false unless CRL === other
+ to_der == other.to_der
+ end
+ end
+
+ class Revoked
+ def ==(other)
+ return false unless Revoked === other
+ to_der == other.to_der
+ end
+ end
+
+ class Request
+ def ==(other)
+ return false unless Request === other
+ to_der == other.to_der
+ end
+ end
end
end
diff --git a/test/test_ssl.rb b/test/test_ssl.rb
index ab6382d7..07b87259 100644
--- a/test/test_ssl.rb
+++ b/test/test_ssl.rb
@@ -811,6 +811,24 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
supported
end
+ def test_set_params_min_version
+ supported = check_supported_protocol_versions
+ store = OpenSSL::X509::Store.new
+ store.add_cert(@ca_cert)
+
+ if supported.include?(OpenSSL::SSL::SSL3_VERSION)
+ # SSLContext#set_params properly disables SSL 3.0 by default
+ ctx_proc = proc { |ctx|
+ ctx.min_version = ctx.max_version = OpenSSL::SSL::SSL3_VERSION
+ }
+ start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port|
+ ctx = OpenSSL::SSL::SSLContext.new
+ ctx.set_params(cert_store: store, verify_hostname: false)
+ assert_handshake_error { server_connect(port, ctx) { } }
+ }
+ end
+ end
+
def test_minmax_version
supported = check_supported_protocol_versions
@@ -1204,6 +1222,59 @@ end
end
end
+ def test_fallback_scsv
+ pend "Fallback SCSV is not supported" unless OpenSSL::SSL::SSLContext.method_defined?( :enable_fallback_scsv)
+
+ start_server do |port|
+ ctx = OpenSSL::SSL::SSLContext.new
+ ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION
+ # Here is OK
+ # TLS1.2 supported and this is what we ask the first time
+ server_connect(port, ctx)
+ end
+
+ ctx_proc = proc { |ctx|
+ ctx.max_version = OpenSSL::SSL::TLS1_1_VERSION
+ }
+ start_server(ctx_proc: ctx_proc) do |port|
+ ctx = OpenSSL::SSL::SSLContext.new
+ ctx.enable_fallback_scsv
+ ctx.max_version = OpenSSL::SSL::TLS1_1_VERSION
+ # Here is OK too
+ # TLS1.2 not supported, fallback to TLS1.1 and signaling the fallback
+ # Server doesn't support better, so connection OK
+ server_connect(port, ctx)
+ end
+
+ # Here is not OK
+ # TLS1.2 is supported, fallback to TLS1.1 (downgrade attack) and signaling the fallback
+ # Server support better, so refuse the connection
+ sock1, sock2 = socketpair
+ begin
+ ctx1 = OpenSSL::SSL::SSLContext.new
+ s1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx1)
+
+ ctx2 = OpenSSL::SSL::SSLContext.new
+ ctx2.enable_fallback_scsv
+ ctx2.max_version = OpenSSL::SSL::TLS1_1_VERSION
+ s2 = OpenSSL::SSL::SSLSocket.new(sock2, ctx2)
+ t = Thread.new {
+ assert_raise_with_message(OpenSSL::SSL::SSLError, /inappropriate fallback/) {
+ s2.connect
+ }
+ }
+
+ assert_raise_with_message(OpenSSL::SSL::SSLError, /inappropriate fallback/) {
+ s1.accept
+ }
+
+ assert t.join
+ ensure
+ sock1.close
+ sock2.close
+ end
+ end
+
def test_dh_callback
pend "TLS 1.2 is not supported" unless tls12_supported?
diff --git a/test/test_x509attr.rb b/test/test_x509attr.rb
index 108162f4..c6c48e86 100644
--- a/test/test_x509attr.rb
+++ b/test/test_x509attr.rb
@@ -62,6 +62,23 @@ class OpenSSL::TestX509Attribute < OpenSSL::TestCase
attr = OpenSSL::X509::Attribute.new("challengePassword", val)
assert_equal(attr.to_der, attr.dup.to_der)
end
+
+ def test_eq
+ val1 = OpenSSL::ASN1::Set([
+ OpenSSL::ASN1::UTF8String("abc123")
+ ])
+ attr1 = OpenSSL::X509::Attribute.new("challengePassword", val1)
+ attr2 = OpenSSL::X509::Attribute.new("challengePassword", val1)
+ ef = OpenSSL::X509::ExtensionFactory.new
+ val2 = OpenSSL::ASN1::Set.new([OpenSSL::ASN1::Sequence.new([
+ ef.create_extension("keyUsage", "keyCertSign", true)
+ ])])
+ attr3 = OpenSSL::X509::Attribute.new("extReq", val2)
+
+ assert_equal false, attr1 == 12345
+ assert_equal true, attr1 == attr2
+ assert_equal false, attr1 == attr3
+ end
end
end
diff --git a/test/test_x509cert.rb b/test/test_x509cert.rb
index 289994d1..bde3fbc9 100644
--- a/test/test_x509cert.rb
+++ b/test/test_x509cert.rb
@@ -169,6 +169,20 @@ class OpenSSL::TestX509Certificate < OpenSSL::TestCase
}
end
+ def test_eq
+ cacert = issue_cert(@ca, @rsa1024, 1, [], nil, nil)
+ cert1 = issue_cert(@ee1, @rsa2048, 2, [], cacert, @rsa1024)
+ cert2 = issue_cert(@ee1, @rsa2048, 2, [], cacert, @rsa1024)
+ cert3 = issue_cert(@ee1, @rsa2048, 3, [], cacert, @rsa1024)
+ cert4 = issue_cert(@ee1, @rsa2048, 2, [], cacert, @rsa1024, digest: "sha512")
+
+ assert_equal false, cert1 == 12345
+ assert_equal true, cert1 == cert2
+ assert_equal false, cert1 == cert3
+ assert_equal false, cert1 == cert4
+ assert_equal false, cert3 == cert4
+ end
+
private
def certificate_error_returns_false
diff --git a/test/test_x509crl.rb b/test/test_x509crl.rb
index 1914a651..a11073fb 100644
--- a/test/test_x509crl.rb
+++ b/test/test_x509crl.rb
@@ -197,6 +197,56 @@ class OpenSSL::TestX509CRL < OpenSSL::TestCase
assert_equal(false, crl.verify(@dsa512))
end
+ def test_revoked_to_der
+ # revokedCertificates SEQUENCE OF SEQUENCE {
+ # userCertificate CertificateSerialNumber,
+ # revocationDate Time,
+ # crlEntryExtensions Extensions OPTIONAL
+ # -- if present, version MUST be v2
+ # } OPTIONAL,
+
+ now = Time.utc(2000, 1, 1)
+ rev1 = OpenSSL::X509::Revoked.new
+ rev1.serial = 123
+ rev1.time = now
+ ext = OpenSSL::X509::Extension.new("CRLReason", OpenSSL::ASN1::Enumerated(1))
+ rev1.extensions = [ext]
+ asn1 = OpenSSL::ASN1::Sequence([
+ OpenSSL::ASN1::Integer(123),
+ OpenSSL::ASN1::UTCTime(now),
+ OpenSSL::ASN1::Sequence([ext.to_der])
+ ])
+
+ assert_equal asn1.to_der, rev1.to_der
+ end
+
+ def test_eq
+ cacert = issue_cert(@ca, @rsa1024, 1, [], nil, nil)
+ crl1 = issue_crl([], 1, Time.now, Time.now + 3600, [], cacert, @rsa1024, "sha256")
+ rev1 = OpenSSL::X509::Revoked.new.tap { |rev|
+ rev.serial = 1
+ rev.time = Time.now
+ }
+ crl1.add_revoked(rev1)
+ crl2 = OpenSSL::X509::CRL.new(crl1.to_der)
+
+ # CRL
+ assert_equal false, crl1 == 12345
+ assert_equal true, crl1 == crl2
+ rev2 = OpenSSL::X509::Revoked.new.tap { |rev|
+ rev.serial = 2
+ rev.time = Time.now
+ }
+ crl2.add_revoked(rev2)
+ assert_equal false, crl1 == crl2
+
+ # Revoked
+ assert_equal false, rev1 == 12345
+ assert_equal true, rev1 == crl2.revoked[0]
+ assert_equal false, rev1 == crl2.revoked[1]
+ assert_equal true, rev2 == crl2.revoked[1]
+ end
+
private
def crl_error_returns_false
diff --git a/test/test_x509ext.rb b/test/test_x509ext.rb
index f384a25e..91ce202f 100644
--- a/test/test_x509ext.rb
+++ b/test/test_x509ext.rb
@@ -75,6 +75,17 @@ class OpenSSL::TestX509Extension < OpenSSL::TestCase
assert_equal(@basic_constraints.to_der, ext.to_der)
assert_equal(ext.to_der, ext.dup.to_der)
end
+
+ def test_eq
+ ext1 = OpenSSL::X509::Extension.new(@basic_constraints.to_der)
+ ef = OpenSSL::X509::ExtensionFactory.new
+ ext2 = ef.create_extension("basicConstraints", "critical, CA:TRUE, pathlen:2")
+ ext3 = ef.create_extension("basicConstraints", "critical, CA:TRUE")
+
+ assert_equal false, ext1 == 12345
+ assert_equal true, ext1 == ext2
+ assert_equal false, ext1 == ext3
+ end
end
end
diff --git a/test/test_x509req.rb b/test/test_x509req.rb
index a21d45da..2c447ccd 100644
--- a/test/test_x509req.rb
+++ b/test/test_x509req.rb
@@ -141,6 +141,16 @@ class OpenSSL::TestX509Request < OpenSSL::TestCase
assert_equal(req.to_der, req.dup.to_der)
end
+ def test_eq
+ req1 = issue_csr(0, @dn, @rsa1024, "sha1")
+ req2 = issue_csr(0, @dn, @rsa1024, "sha1")
+ req3 = issue_csr(0, @dn, @rsa1024, "sha256")
+
+ assert_equal false, req1 == 12345
+ assert_equal true, req1 == req2
+ assert_equal false, req1 == req3
+ end
+
private
def request_error_returns_false