aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKazuki Yamaguchi <k@rhe.jp>2016-06-19 23:25:32 +0900
committerKazuki Yamaguchi <k@rhe.jp>2016-06-19 23:32:17 +0900
commite1c7ee1bb3e13fa4fe0f200cf9a8cd3531c45d39 (patch)
tree0e0f781de70fa607c5275401ba7a881d4039bdbe
parent3b8046d83ce3271d20c182054e44caf9270d4429 (diff)
parent9ead0ecaa2f500cf19e7cfb484d21c401c4c4ca4 (diff)
downloadruby-openssl-e1c7ee1bb3e13fa4fe0f200cf9a8cd3531c45d39.tar.gz
Merge changes from Ruby trunk r55335..r55457
Also adjust tests. * ruby-trunk r55335..r55457: (15 commits) (r55457) openssl: add OpenSSL::OCSP::SingleResponse (r55456) openssl: allow passing absolute times in OCSP::BasicRespons.. (r55455) openssl: implement initialize_copy for OpenSSL::OCSP::* (r55454) openssl: implement initialize_copy method for PKey classes (r55450) openssl: add 'const's required in OpenSSL master (r55444) openssl: avoid test crash on Ubuntu 16.04 (r55423) openssl: refactor OpenSSL::OCSP::*#verify (r55422) openssl: allow specifying hash algorithm in OCSP::*#sign (r55411) openssl: add some accessor methods for OCSP::CertificateId (r55409) openssl: add missing #to_der to OCSP::{CertificateId,BasicR.. (r55408) openssl: fix acesssor functions for RSA and DH in openssl_m.. (r55388) openssl: support non AES-GCM AEAD ciphers in OpenSSL::Cipher (r55387) openssl: avoid test failure in test_engine.rb (r55344) openssl: use ASN1_ENUMERATED_to_BN() if needed (r55342) openssl: fix build with OPENSSL_NO_EC Sync-with-trunk: r55457
-rw-r--r--ext/openssl/openssl_missing.h13
-rw-r--r--ext/openssl/ossl_asn1.c8
-rw-r--r--ext/openssl/ossl_cipher.c72
-rw-r--r--ext/openssl/ossl_ocsp.c929
-rw-r--r--ext/openssl/ossl_pkey.h2
-rw-r--r--ext/openssl/ossl_pkey_dh.c42
-rw-r--r--ext/openssl/ossl_pkey_dsa.c29
-rw-r--r--ext/openssl/ossl_pkey_ec.c83
-rw-r--r--ext/openssl/ossl_pkey_rsa.c33
-rw-r--r--ext/openssl/ossl_ssl.c6
-rw-r--r--ext/openssl/ruby_missing.h5
-rw-r--r--test/envutil.rb7
-rw-r--r--test/test_asn1.rb6
-rw-r--r--test/test_engine.rb8
-rw-r--r--test/test_ocsp.rb213
-rw-r--r--test/test_pair.rb7
-rw-r--r--test/test_pkey_dh.rb10
-rw-r--r--test/test_pkey_dsa.rb8
-rw-r--r--test/test_pkey_ec.rb29
-rw-r--r--test/test_pkey_rsa.rb8
-rw-r--r--test/utils.rb5
21 files changed, 1290 insertions, 233 deletions
diff --git a/ext/openssl/openssl_missing.h b/ext/openssl/openssl_missing.h
index 67df70a5..769c7c2d 100644
--- a/ext/openssl/openssl_missing.h
+++ b/ext/openssl/openssl_missing.h
@@ -179,7 +179,7 @@ void X509_REQ_get0_signature(ASN1_BIT_STRING **psig, X509_ALGOR **palg, X509_REQ
static inline _type *EVP_PKEY_get0_##_type(EVP_PKEY *pkey) { \
return pkey->pkey._name; }
#define IMPL_KEY_ACCESSOR2(_type, _group, a1, a2, _fail_cond) \
-static inline void _type##_get0_##_group(_type *obj, BIGNUM **a1, BIGNUM **a2) { \
+static inline void _type##_get0_##_group(_type *obj, const BIGNUM **a1, const BIGNUM **a2) { \
if (a1) *a1 = obj->a1; \
if (a2) *a2 = obj->a2; } \
static inline int _type##_set0_##_group(_type *obj, BIGNUM *a1, BIGNUM *a2) { \
@@ -188,7 +188,7 @@ static inline int _type##_set0_##_group(_type *obj, BIGNUM *a1, BIGNUM *a2) { \
BN_clear_free(obj->a2); obj->a2 = a2; \
return 1; }
#define IMPL_KEY_ACCESSOR3(_type, _group, a1, a2, a3, _fail_cond) \
-static inline void _type##_get0_##_group(_type *obj, BIGNUM **a1, BIGNUM **a2, BIGNUM **a3) { \
+static inline void _type##_get0_##_group(_type *obj, const BIGNUM **a1, const BIGNUM **a2, const BIGNUM **a3) { \
if (a1) *a1 = obj->a1; \
if (a2) *a2 = obj->a2; \
if (a3) *a3 = obj->a3; } \
@@ -201,7 +201,7 @@ static inline int _type##_set0_##_group(_type *obj, BIGNUM *a1, BIGNUM *a2, BIGN
#if !defined(OPENSSL_NO_RSA)
IMPL_PKEY_GETTER(RSA, rsa)
-IMPL_KEY_ACCESSOR3(RSA, key, n, e, d, (n == obj->n || e == obj->e || (obj->d && e == obj->d)))
+IMPL_KEY_ACCESSOR3(RSA, key, n, e, d, (n == obj->n || e == obj->e || (obj->d && d == obj->d)))
IMPL_KEY_ACCESSOR2(RSA, factors, p, q, (p == obj->p || q == obj->q))
IMPL_KEY_ACCESSOR3(RSA, crt_params, dmp1, dmq1, iqmp, (dmp1 == obj->dmp1 || dmq1 == obj->dmq1 || iqmp == obj->iqmp))
#endif
@@ -215,7 +215,7 @@ IMPL_KEY_ACCESSOR3(DSA, pqg, p, q, g, (p == obj->p || q == obj->q || g == obj->g
#if !defined(OPENSSL_NO_DH)
IMPL_PKEY_GETTER(DH, dh)
IMPL_KEY_ACCESSOR2(DH, key, pub_key, priv_key, (pub_key == obj->pub_key || (obj->priv_key && priv_key == obj->priv_key)))
-IMPL_KEY_ACCESSOR3(DH, pqg, p, q, g, (p == obj->p || q == obj->q || g == obj->g))
+IMPL_KEY_ACCESSOR3(DH, pqg, p, q, g, (p == obj->p || obj->q && q == obj->q || g == obj->g))
static inline ENGINE *DH_get0_engine(DH *dh) { return dh->engine; }
#endif
@@ -228,4 +228,9 @@ IMPL_PKEY_GETTER(EC_KEY, ec)
#undef IMPL_KEY_ACCESSOR3
#endif /* HAVE_OPAQUE_OPENSSL */
+#if defined(HAVE_AUTHENTICATED_ENCRYPTION) && !defined(EVP_CTRL_AEAD_GET_TAG)
+# define EVP_CTRL_AEAD_GET_TAG EVP_CTRL_GCM_GET_TAG
+# define EVP_CTRL_AEAD_SET_TAG EVP_CTRL_GCM_SET_TAG
+#endif
+
#endif /* _OSSL_OPENSSL_MISSING_H_ */
diff --git a/ext/openssl/ossl_asn1.c b/ext/openssl/ossl_asn1.c
index 03822b5c..cbedd59e 100644
--- a/ext/openssl/ossl_asn1.c
+++ b/ext/openssl/ossl_asn1.c
@@ -125,9 +125,13 @@ asn1integer_to_num(ASN1_INTEGER *ai)
if (!ai) {
ossl_raise(rb_eTypeError, "ASN1_INTEGER is NULL!");
}
- if (!(bn = ASN1_INTEGER_to_BN(ai, NULL))) {
+ if (ai->type == V_ASN1_ENUMERATED)
+ bn = ASN1_ENUMERATED_to_BN(ai, NULL);
+ else
+ bn = ASN1_INTEGER_to_BN(ai, NULL);
+
+ if (!bn)
ossl_raise(eOSSLError, NULL);
- }
#if DO_IT_VIA_RUBY
if (!(txt = BN_bn2dec(bn))) {
BN_free(bn);
diff --git a/ext/openssl/ossl_cipher.c b/ext/openssl/ossl_cipher.c
index e1408b91..be7a0321 100644
--- a/ext/openssl/ossl_cipher.c
+++ b/ext/openssl/ossl_cipher.c
@@ -553,29 +553,9 @@ ossl_cipher_set_auth_data(VALUE self, VALUE data)
return data;
}
-#define ossl_is_gcm(nid) (nid) == NID_aes_128_gcm || \
- (nid) == NID_aes_192_gcm || \
- (nid) == NID_aes_256_gcm
-
-static VALUE
-ossl_get_gcm_auth_tag(EVP_CIPHER_CTX *ctx, int len)
-{
- unsigned char *tag;
- VALUE ret;
-
- tag = ALLOC_N(unsigned char, len);
-
- if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, len, tag))
- ossl_raise(eCipherError, "retrieving the authentication tag failed");
-
- ret = rb_str_new((const char *) tag, len);
- xfree(tag);
- return ret;
-}
-
/*
* call-seq:
- * cipher.auth_tag([ tag_len ] -> string
+ * cipher.auth_tag(tag_len = 16) -> String
*
* Gets the authentication tag generated by Authenticated Encryption Cipher
* modes (GCM for example). This tag may be stored along with the ciphertext,
@@ -590,32 +570,23 @@ ossl_get_gcm_auth_tag(EVP_CIPHER_CTX *ctx, int len)
static VALUE
ossl_cipher_get_auth_tag(int argc, VALUE *argv, VALUE self)
{
- VALUE vtag_len;
+ VALUE vtag_len, ret;
EVP_CIPHER_CTX *ctx;
- int nid, tag_len;
+ int tag_len = 16;
- if (rb_scan_args(argc, argv, "01", &vtag_len) == 0) {
- tag_len = 16;
- } else {
+ if (rb_scan_args(argc, argv, "01", &vtag_len) == 1)
tag_len = NUM2INT(vtag_len);
- }
GetCipher(self, ctx);
- nid = EVP_CIPHER_CTX_nid(ctx);
- if (ossl_is_gcm(nid)) {
- return ossl_get_gcm_auth_tag(ctx, tag_len);
- } else {
+ if (!(EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_FLAG_AEAD_CIPHER))
ossl_raise(eCipherError, "authentication tag not supported by this cipher");
- return Qnil; /* dummy */
- }
-}
-static inline void
-ossl_set_gcm_auth_tag(EVP_CIPHER_CTX *ctx, unsigned char *tag, int tag_len)
-{
- if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, tag_len, tag))
- ossl_raise(eCipherError, "unable to set GCM tag");
+ ret = rb_str_new(NULL, tag_len);
+ if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, tag_len, RSTRING_PTR(ret)))
+ ossl_raise(eCipherError, "retrieving the authentication tag failed");
+
+ return ret;
}
/*
@@ -634,7 +605,6 @@ static VALUE
ossl_cipher_set_auth_tag(VALUE self, VALUE vtag)
{
EVP_CIPHER_CTX *ctx;
- int nid;
unsigned char *tag;
int tag_len;
@@ -643,13 +613,11 @@ ossl_cipher_set_auth_tag(VALUE self, VALUE vtag)
tag_len = RSTRING_LENINT(vtag);
GetCipher(self, ctx);
- nid = EVP_CIPHER_CTX_nid(ctx);
-
- if (ossl_is_gcm(nid)) {
- ossl_set_gcm_auth_tag(ctx, tag, tag_len);
- } else {
+ if (!(EVP_CIPHER_CTX_flags(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))
+ ossl_raise(eCipherError, "unable to set AEAD tag");
return vtag;
}
@@ -665,16 +633,10 @@ static VALUE
ossl_cipher_is_authenticated(VALUE self)
{
EVP_CIPHER_CTX *ctx;
- int nid;
GetCipher(self, ctx);
- nid = EVP_CIPHER_CTX_nid(ctx);
- if (ossl_is_gcm(nid)) {
- return Qtrue;
- } else {
- return Qfalse;
- }
+ return (EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_FLAG_AEAD_CIPHER) ? Qtrue : Qfalse;
}
#else
#define ossl_cipher_set_auth_data rb_f_notimplement
@@ -948,7 +910,7 @@ Init_ossl_cipher(void)
* the OpenSSL library still requires a value to be set - "" may be used in
* case none is available. An example using the GCM (Galois Counter Mode):
*
- * cipher = OpenSSL::Cipher::AES.new(128, :GCM)
+ * cipher = OpenSSL::Cipher.new("aes-128-gcm")
* cipher.encrypt
* key = cipher.random_key
* iv = cipher.random_iv
@@ -957,7 +919,7 @@ Init_ossl_cipher(void)
* encrypted = cipher.update(data) + cipher.final
* tag = cipher.auth_tag
*
- * decipher = OpenSSL::Cipher::AES.new(128, :GCM)
+ * decipher = OpenSSL::Cipher.new("aes-128-gcm")
* decipher.decrypt
* decipher.key = key
* decipher.iv = iv
diff --git a/ext/openssl/ossl_ocsp.c b/ext/openssl/ossl_ocsp.c
index ae15d93b..bb5eb5a8 100644
--- a/ext/openssl/ossl_ocsp.c
+++ b/ext/openssl/ossl_ocsp.c
@@ -57,6 +57,21 @@
GetOCSPBasicRes((obj), (res)); \
} while (0)
+#define NewOCSPSingleRes(klass) \
+ TypedData_Wrap_Struct((klass), &ossl_ocsp_singleresp_type, 0)
+#define SetOCSPSingleRes(obj, res) do { \
+ if(!(res)) ossl_raise(rb_eRuntimeError, "SingleResponse wasn't initialized!"); \
+ RTYPEDDATA_DATA(obj) = (res); \
+} while (0)
+#define GetOCSPSingleRes(obj, res) do { \
+ TypedData_Get_Struct((obj), OCSP_SINGLERESP, &ossl_ocsp_singleresp_type, (res)); \
+ if(!(res)) ossl_raise(rb_eRuntimeError, "SingleResponse wasn't initialized!"); \
+} while (0)
+#define SafeGetOCSPSingleRes(obj, res) do { \
+ OSSL_Check_Kind((obj), cOCSPSingleRes); \
+ GetOCSPSingleRes((obj), (res)); \
+} while (0)
+
#define NewOCSPCertId(klass) \
TypedData_Wrap_Struct((klass), &ossl_ocsp_certid_type, 0)
#define SetOCSPCertId(obj, cid) do { \
@@ -77,6 +92,7 @@ VALUE eOCSPError;
VALUE cOCSPReq;
VALUE cOCSPRes;
VALUE cOCSPBasicRes;
+VALUE cOCSPSingleRes;
VALUE cOCSPCertId;
static void
@@ -122,6 +138,20 @@ static const rb_data_type_t ossl_ocsp_basicresp_type = {
};
static void
+ossl_ocsp_singleresp_free(void *ptr)
+{
+ OCSP_SINGLERESP_free(ptr);
+}
+
+static const rb_data_type_t ossl_ocsp_singleresp_type = {
+ "OpenSSL/OCSP/SINGLERESP",
+ {
+ 0, ossl_ocsp_singleresp_free,
+ },
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
+};
+
+static void
ossl_ocsp_certid_free(void *ptr)
{
OCSP_CERTID_free(ptr);
@@ -163,6 +193,25 @@ ossl_ocspreq_alloc(VALUE klass)
return obj;
}
+static VALUE
+ossl_ocspreq_initialize_copy(VALUE self, VALUE other)
+{
+ OCSP_REQUEST *req, *req_old, *req_new;
+
+ rb_check_frozen(self);
+ GetOCSPReq(self, req_old);
+ SafeGetOCSPReq(other, req);
+
+ req_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_REQUEST), req);
+ if (!req_new)
+ ossl_raise(eOCSPError, "ASN1_item_dup");
+
+ SetOCSPReq(self, req_new);
+ OCSP_REQUEST_free(req_old);
+
+ return self;
+}
+
/*
* call-seq:
* OpenSSL::OCSP::Request.new -> request
@@ -180,15 +229,13 @@ ossl_ocspreq_initialize(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "01", &arg);
if(!NIL_P(arg)){
- OCSP_REQUEST *req = DATA_PTR(self), *x;
+ OCSP_REQUEST *req;
+ GetOCSPReq(self, req);
arg = ossl_to_der_if_possible(arg);
StringValue(arg);
- p = (unsigned char*)RSTRING_PTR(arg);
- x = d2i_OCSP_REQUEST(&req, &p, RSTRING_LEN(arg));
- DATA_PTR(self) = req;
- if(!x){
+ p = (unsigned char *)RSTRING_PTR(arg);
+ if (!d2i_OCSP_REQUEST(&req, &p, RSTRING_LEN(arg)))
ossl_raise(eOCSPError, "cannot load DER encoded request");
- }
}
return self;
@@ -314,49 +361,59 @@ ossl_ocspreq_get_certid(VALUE self)
/*
* call-seq:
- * request.sign(signer_cert, signer_key) -> self
- * request.sign(signer_cert, signer_key, certificates) -> self
- * request.sign(signer_cert, signer_key, certificates, flags) -> self
+ * request.sign(cert, key, certs = nil, flags = 0, digest = nil) -> self
+ *
+ * Signs this OCSP request using +cert+, +key+ and optional +digest+. If
+ * +digest+ is not specified, SHA-1 is used. +certs+ is an optional Array of
+ * additional certificates that will be included in the request. If +certs+ is
+ * not specified, flag OpenSSL::OCSP::NOCERTS is set. Pass an empty array to
+ * include only the signer certificate.
*
- * Signs this OCSP request using +signer_cert+ and +signer_key+.
- * +certificates+ is an optional Array of certificates that may be included in
- * the request.
+ * +flags+ can include:
+ * OpenSSL::OCSP::NOCERTS:: don't include certificates
*/
static VALUE
ossl_ocspreq_sign(int argc, VALUE *argv, VALUE self)
{
- VALUE signer_cert, signer_key, certs, flags;
+ VALUE signer_cert, signer_key, certs, flags, digest;
OCSP_REQUEST *req;
X509 *signer;
EVP_PKEY *key;
- STACK_OF(X509) *x509s;
- unsigned long flg;
+ STACK_OF(X509) *x509s = NULL;
+ unsigned long flg = 0;
+ const EVP_MD *md;
int ret;
- rb_scan_args(argc, argv, "22", &signer_cert, &signer_key, &certs, &flags);
+ rb_scan_args(argc, argv, "23", &signer_cert, &signer_key, &certs, &flags, &digest);
+ GetOCSPReq(self, req);
signer = GetX509CertPtr(signer_cert);
key = GetPrivPKeyPtr(signer_key);
- flg = NIL_P(flags) ? 0 : NUM2INT(flags);
- if(NIL_P(certs)){
- x509s = sk_X509_new_null();
+ if (!NIL_P(flags))
+ flg = NUM2INT(flags);
+ if (NIL_P(digest))
+ md = EVP_sha1();
+ else
+ md = GetDigestPtr(digest);
+ if (NIL_P(certs))
flags |= OCSP_NOCERTS;
- }
- else x509s = ossl_x509_ary2sk(certs);
- GetOCSPReq(self, req);
- ret = OCSP_request_sign(req, signer, key, EVP_sha1(), x509s, flg);
+ else
+ x509s = ossl_x509_ary2sk(certs);
+
+ ret = OCSP_request_sign(req, signer, key, md, x509s, flg);
sk_X509_pop_free(x509s, X509_free);
- if(!ret) ossl_raise(eOCSPError, NULL);
+ if (!ret) ossl_raise(eOCSPError, NULL);
return self;
}
/*
* call-seq:
- * request.verify(certificates, store) -> true or false
- * request.verify(certificates, store, flags) -> true or false
+ * request.verify(certificates, store, flags = 0) -> true or false
*
- * Verifies this request using the given +certificates+ and X509 +store+.
+ * Verifies this request using the given +certificates+ and +store+.
+ * +certificates+ is an array of OpenSSL::X509::Certificate, +store+ is an
+ * OpenSSL::X509::Store.
*/
static VALUE
@@ -369,15 +426,16 @@ ossl_ocspreq_verify(int argc, VALUE *argv, VALUE self)
int flg, result;
rb_scan_args(argc, argv, "21", &certs, &store, &flags);
+ GetOCSPReq(self, req);
x509st = GetX509StorePtr(store);
flg = NIL_P(flags) ? 0 : NUM2INT(flags);
x509s = ossl_x509_ary2sk(certs);
- GetOCSPReq(self, req);
result = OCSP_request_verify(req, x509s, x509st, flg);
sk_X509_pop_free(x509s, X509_free);
- if(!result) rb_warn("%s", ERR_error_string(ERR_peek_error(), NULL));
+ if (!result)
+ ossl_clear_error();
- return result ? Qtrue : Qfalse;
+ return result > 0 ? Qtrue : Qfalse;
}
/*
@@ -446,6 +504,25 @@ ossl_ocspres_alloc(VALUE klass)
return obj;
}
+static VALUE
+ossl_ocspres_initialize_copy(VALUE self, VALUE other)
+{
+ OCSP_RESPONSE *res, *res_old, *res_new;
+
+ rb_check_frozen(self);
+ GetOCSPRes(self, res_old);
+ SafeGetOCSPRes(other, res);
+
+ res_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_RESPONSE), res);
+ if (!res_new)
+ ossl_raise(eOCSPError, "ASN1_item_dup");
+
+ SetOCSPRes(self, res_new);
+ OCSP_RESPONSE_free(res_old);
+
+ return self;
+}
+
/*
* call-seq:
* OpenSSL::OCSP::Response.new -> response
@@ -463,15 +540,13 @@ ossl_ocspres_initialize(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "01", &arg);
if(!NIL_P(arg)){
- OCSP_RESPONSE *res = DATA_PTR(self), *x;
+ OCSP_RESPONSE *res;
+ GetOCSPRes(self, res);
arg = ossl_to_der_if_possible(arg);
StringValue(arg);
p = (unsigned char *)RSTRING_PTR(arg);
- x = d2i_OCSP_RESPONSE(&res, &p, RSTRING_LEN(arg));
- DATA_PTR(self) = res;
- if(!x){
+ if (!d2i_OCSP_RESPONSE(&res, &p, RSTRING_LEN(arg)))
ossl_raise(eOCSPError, "cannot load DER encoded response");
- }
}
return self;
@@ -582,16 +657,50 @@ ossl_ocspbres_alloc(VALUE klass)
return obj;
}
+static VALUE
+ossl_ocspbres_initialize_copy(VALUE self, VALUE other)
+{
+ OCSP_BASICRESP *bs, *bs_old, *bs_new;
+
+ rb_check_frozen(self);
+ GetOCSPBasicRes(self, bs_old);
+ SafeGetOCSPBasicRes(other, bs);
+
+ bs_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_BASICRESP), bs);
+ if (!bs_new)
+ ossl_raise(eOCSPError, "ASN1_item_dup");
+
+ SetOCSPBasicRes(self, bs_new);
+ OCSP_BASICRESP_free(bs_old);
+
+ return self;
+}
+
/*
* call-seq:
- * OpenSSL::OCSP::BasicResponse.new(*) -> basic_response
+ * OpenSSL::OCSP::BasicResponse.new(der_string = nil) -> basic_response
*
- * Creates a new BasicResponse and ignores all arguments.
+ * Creates a new BasicResponse. If +der_string+ is given, decodes +der_string+
+ * as DER.
*/
static VALUE
ossl_ocspbres_initialize(int argc, VALUE *argv, VALUE self)
{
+ VALUE arg;
+ const unsigned char *p;
+
+ rb_scan_args(argc, argv, "01", &arg);
+ if (!NIL_P(arg)) {
+ OCSP_BASICRESP *res;
+ GetOCSPBasicRes(self, res);
+ arg = ossl_to_der_if_possible(arg);
+ StringValue(arg);
+ p = (unsigned char *)RSTRING_PTR(arg);
+ if (!d2i_OCSP_BASICRESP(&res, &p, RSTRING_LEN(arg)))
+ ossl_raise(eOCSPError, "d2i_OCSP_BASICRESP");
+ }
+
return self;
}
@@ -647,22 +756,49 @@ ossl_ocspbres_add_nonce(int argc, VALUE *argv, VALUE self)
return self;
}
+static VALUE
+add_status_convert_time(VALUE obj)
+{
+ ASN1_TIME *time;
+
+ if (RB_INTEGER_TYPE_P(obj))
+ time = X509_gmtime_adj(NULL, NUM2INT(obj));
+ else
+ time = ossl_x509_time_adjust(NULL, obj);
+
+ if (!time)
+ ossl_raise(eOCSPError, NULL);
+
+ return (VALUE)time;
+}
+
/*
* call-seq:
* basic_response.add_status(certificate_id, status, reason, revocation_time, this_update, next_update, extensions) -> basic_response
*
- * Adds a validation +status+ (0 for good, 1 for revoked, 2 for unknown) to this
- * response for +certificate_id+. +reason+ describes the reason for the
- * revocation, if any.
+ * Adds a certificate status for +certificate_id+. +status+ is the status, and
+ * must be one of these:
+ *
+ * - OpenSSL::OCSP::V_CERTSTATUS_GOOD
+ * - OpenSSL::OCSP::V_CERTSTATUS_REVOKED
+ * - OpenSSL::OCSP::V_CERTSTATUS_UNKNOWN
*
- * The +revocation_time+, +this_update+ and +next_update+ are times for the
- * certificate's revocation time, the time of this status and the next update
- * time for a new status, respectively.
+ * +reason+ and +revocation_time+ can be given only when +status+ is
+ * OpenSSL::OCSP::V_CERTSTATUS_REVOKED. +reason+ describes the reason for the
+ * revocation, and must be one of OpenSSL::OCSP::REVOKED_STATUS_* constants.
+ * +revocation_time+ is the time when the certificate is revoked.
*
- * +extensions+ may be an Array of OpenSSL::X509::Extension that will
- * be added to this response or nil.
+ * +this_update+ and +next_update+ indicate the time at which ths status is
+ * verified to be correct and the time at or before which newer information
+ * will be available, respectively. +next_update+ is optional.
+ *
+ * +extensions+ is an Array of OpenSSL::X509::Extension to be included in the
+ * SingleResponse. This is also optional.
+ *
+ * Note that the times, +revocation_time+, +this_update+ and +next_update+
+ * can be specified in either of Integer or Time object. If they are Integer, it
+ * is treated as the relative seconds from the current time.
*/
-
static VALUE
ossl_ocspbres_add_status(VALUE self, VALUE cid, VALUE status,
VALUE reason, VALUE revtime,
@@ -671,36 +807,37 @@ ossl_ocspbres_add_status(VALUE self, VALUE cid, VALUE status,
OCSP_BASICRESP *bs;
OCSP_SINGLERESP *single;
OCSP_CERTID *id;
- ASN1_TIME *ths, *nxt, *rev;
- int st, rsn, error, rstatus = 0;
+ ASN1_TIME *ths = NULL, *nxt = NULL, *rev = NULL;
+ int st, rsn = 0, error = 0, rstatus = 0;
long i;
VALUE tmp;
+ GetOCSPBasicRes(self, bs);
+ SafeGetOCSPCertId(cid, id);
st = NUM2INT(status);
- rsn = NIL_P(status) ? 0 : NUM2INT(reason);
- if(!NIL_P(ext)){
- /* All ary's members should be X509Extension */
- Check_Type(ext, T_ARRAY);
+ if (!NIL_P(ext)) { /* All ext's members must be X509::Extension */
+ ext = rb_check_array_type(ext);
for (i = 0; i < RARRAY_LEN(ext); i++)
OSSL_Check_Kind(RARRAY_AREF(ext, i), cX509Ext);
}
- error = 0;
- ths = nxt = rev = NULL;
- if(!NIL_P(revtime)){
- tmp = rb_protect(rb_Integer, revtime, &rstatus);
- if(rstatus) goto err;
- rev = X509_gmtime_adj(NULL, NUM2INT(tmp));
+ if (st == V_OCSP_CERTSTATUS_REVOKED) {
+ rsn = NUM2INT(reason);
+ tmp = rb_protect(add_status_convert_time, revtime, &rstatus);
+ if (rstatus) goto err;
+ rev = (ASN1_TIME *)tmp;
+ }
+
+ tmp = rb_protect(add_status_convert_time, thisupd, &rstatus);
+ if (rstatus) goto err;
+ ths = (ASN1_TIME *)tmp;
+
+ if (!NIL_P(nextupd)) {
+ tmp = rb_protect(add_status_convert_time, nextupd, &rstatus);
+ if (rstatus) goto err;
+ nxt = (ASN1_TIME *)tmp;
}
- tmp = rb_protect(rb_Integer, thisupd, &rstatus);
- if(rstatus) goto err;
- ths = X509_gmtime_adj(NULL, NUM2INT(tmp));
- tmp = rb_protect(rb_Integer, nextupd, &rstatus);
- if(rstatus) goto err;
- nxt = X509_gmtime_adj(NULL, NUM2INT(tmp));
- GetOCSPBasicRes(self, bs);
- SafeGetOCSPCertId(cid, id);
if(!(single = OCSP_basic_add1_status(bs, id, st, rsn, rev, ths, nxt))){
error = 1;
goto err;
@@ -708,8 +845,7 @@ ossl_ocspbres_add_status(VALUE self, VALUE cid, VALUE status,
if(!NIL_P(ext)){
X509_EXTENSION *x509ext;
- while ((x509ext = OCSP_SINGLERESP_delete_ext(single, 0)))
- X509_EXTENSION_free(x509ext);
+
for(i = 0; i < RARRAY_LEN(ext); i++){
x509ext = DupX509ExtPtr(RARRAY_AREF(ext, i));
if(!OCSP_SINGLERESP_add_ext(single, x509ext, -1)){
@@ -736,11 +872,13 @@ ossl_ocspbres_add_status(VALUE self, VALUE cid, VALUE status,
* basic_response.status -> statuses
*
* Returns an Array of statuses for this response. Each status contains a
- * CertificateId, the status (0 for good, 1 for revoked, 2 for unknown), the reason for
- * the status, the revocation time, the time of this update, the time for the
- * next update and a list of OpenSSL::X509::Extensions.
+ * CertificateId, the status (0 for good, 1 for revoked, 2 for unknown), the
+ * reason for the status, the revocation time, the time of this update, the time
+ * for the next update and a list of OpenSSL::X509::Extensions.
+ *
+ * This should be superseded by BasicResponse#responses and #find_response that
+ * return SingleResponse.
*/
-
static VALUE
ossl_ocspbres_get_status(VALUE self)
{
@@ -786,76 +924,462 @@ ossl_ocspbres_get_status(VALUE self)
return ret;
}
+static VALUE ossl_ocspsres_new(OCSP_SINGLERESP *);
+
+/*
+ * call-seq:
+ * basic_response.responses -> Array of SingleResponse
+ *
+ * Returns an Array of SingleResponse for this BasicResponse.
+ */
+
+static VALUE
+ossl_ocspbres_get_responses(VALUE self)
+{
+ OCSP_BASICRESP *bs;
+ VALUE ret;
+ int count, i;
+
+ GetOCSPBasicRes(self, bs);
+ count = OCSP_resp_count(bs);
+ ret = rb_ary_new2(count);
+
+ for (i = 0; i < count; i++) {
+ OCSP_SINGLERESP *sres, *sres_new;
+
+ sres = OCSP_resp_get0(bs, i);
+ sres_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_SINGLERESP), sres);
+ if (!sres_new)
+ ossl_raise(eOCSPError, "ASN1_item_dup");
+
+ rb_ary_push(ret, ossl_ocspsres_new(sres_new));
+ }
+
+ return ret;
+}
+
+
/*
* call-seq:
- * basic_response.sign(signer_cert, signer_key) -> self
- * basic_response.sign(signer_cert, signer_key, certificates) -> self
- * basic_response.sign(signer_cert, signer_key, certificates, flags) -> self
+ * basic_response.find_response(certificate_id) -> SingleResponse | nil
*
- * Signs this response using the +signer_cert+ and +signer_key+. Additional
- * +certificates+ may be added to the signature along with a set of +flags+.
+ * Returns a SingleResponse whose CertId matches with +certificate_id+, or nil
+ * if this BasicResponse does not contain it.
+ */
+static VALUE
+ossl_ocspbres_find_response(VALUE self, VALUE target)
+{
+ OCSP_BASICRESP *bs;
+ OCSP_SINGLERESP *sres, *sres_new;
+ OCSP_CERTID *id;
+ int n;
+
+ SafeGetOCSPCertId(target, id);
+ GetOCSPBasicRes(self, bs);
+
+ if ((n = OCSP_resp_find(bs, id, -1)) == -1)
+ return Qnil;
+
+ sres = OCSP_resp_get0(bs, n);
+ sres_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_SINGLERESP), sres);
+ if (!sres_new)
+ ossl_raise(eOCSPError, "ASN1_item_dup");
+
+ return ossl_ocspsres_new(sres_new);
+}
+
+/*
+ * call-seq:
+ * basic_response.sign(cert, key, certs = nil, flags = 0, digest = nil) -> self
+ *
+ * Signs this OCSP response using the +cert+, +key+ and optional +digest+. This
+ * behaves in the similar way as OpenSSL::OCSP::Request#sign.
+ *
+ * +flags+ can include:
+ * OpenSSL::OCSP::NOCERTS:: don't include certificates
+ * OpenSSL::OCSP::NOTIME:: don't set producedAt
+ * OpenSSL::OCSP::RESPID_KEY:: use signer's public key hash as responderID
*/
static VALUE
ossl_ocspbres_sign(int argc, VALUE *argv, VALUE self)
{
- VALUE signer_cert, signer_key, certs, flags;
+ VALUE signer_cert, signer_key, certs, flags, digest;
OCSP_BASICRESP *bs;
X509 *signer;
EVP_PKEY *key;
- STACK_OF(X509) *x509s;
- unsigned long flg;
+ STACK_OF(X509) *x509s = NULL;
+ unsigned long flg = 0;
+ const EVP_MD *md;
int ret;
- rb_scan_args(argc, argv, "22", &signer_cert, &signer_key, &certs, &flags);
+ rb_scan_args(argc, argv, "23", &signer_cert, &signer_key, &certs, &flags, &digest);
+ GetOCSPBasicRes(self, bs);
signer = GetX509CertPtr(signer_cert);
key = GetPrivPKeyPtr(signer_key);
- flg = NIL_P(flags) ? 0 : NUM2INT(flags);
- if(NIL_P(certs)){
- x509s = sk_X509_new_null();
+ if (!NIL_P(flags))
+ flg = NUM2INT(flags);
+ if (NIL_P(digest))
+ md = EVP_sha1();
+ else
+ md = GetDigestPtr(digest);
+ if (NIL_P(certs))
flg |= OCSP_NOCERTS;
- }
- else{
+ else
x509s = ossl_x509_ary2sk(certs);
- }
- GetOCSPBasicRes(self, bs);
- ret = OCSP_basic_sign(bs, signer, key, EVP_sha1(), x509s, flg);
+
+ ret = OCSP_basic_sign(bs, signer, key, md, x509s, flg);
sk_X509_pop_free(x509s, X509_free);
- if(!ret) ossl_raise(eOCSPError, NULL);
+ if (!ret) ossl_raise(eOCSPError, NULL);
return self;
}
/*
* call-seq:
- * basic_response.verify(certificates, store) -> true or false
- * basic_response.verify(certificates, store, flags) -> true or false
+ * basic_response.verify(certificates, store, flags = 0) -> true or false
*
- * Verifies the signature of the response using the given +certificates+,
- * +store+ and +flags+.
+ * Verifies the signature of the response using the given +certificates+ and
+ * +store+. This works in the similar way as OpenSSL::OCSP::Request#verify.
*/
static VALUE
ossl_ocspbres_verify(int argc, VALUE *argv, VALUE self)
{
- VALUE certs, store, flags, result;
+ VALUE certs, store, flags;
OCSP_BASICRESP *bs;
STACK_OF(X509) *x509s;
X509_STORE *x509st;
- int flg;
+ int flg, result;
rb_scan_args(argc, argv, "21", &certs, &store, &flags);
+ GetOCSPBasicRes(self, bs);
x509st = GetX509StorePtr(store);
flg = NIL_P(flags) ? 0 : NUM2INT(flags);
x509s = ossl_x509_ary2sk(certs);
- GetOCSPBasicRes(self, bs);
- result = OCSP_basic_verify(bs, x509s, x509st, flg) > 0 ? Qtrue : Qfalse;
+ result = OCSP_basic_verify(bs, x509s, x509st, flg);
sk_X509_pop_free(x509s, X509_free);
- if(!result) rb_warn("%s", ERR_error_string(ERR_peek_error(), NULL));
+ if (!result)
+ ossl_clear_error();
- return result;
+ return result > 0 ? Qtrue : Qfalse;
}
/*
+ * call-seq:
+ * basic_response.to_der -> String
+ *
+ * Encodes this basic response into a DER-encoded string.
+ */
+static VALUE
+ossl_ocspbres_to_der(VALUE self)
+{
+ OCSP_BASICRESP *res;
+ VALUE str;
+ long len;
+ unsigned char *p;
+
+ GetOCSPBasicRes(self, res);
+ if ((len = i2d_OCSP_BASICRESP(res, NULL)) <= 0)
+ ossl_raise(eOCSPError, NULL);
+ str = rb_str_new(0, len);
+ p = (unsigned char *)RSTRING_PTR(str);
+ if (i2d_OCSP_BASICRESP(res, &p) <= 0)
+ ossl_raise(eOCSPError, NULL);
+ ossl_str_adjust(str, p);
+
+ return str;
+}
+
+/*
+ * OCSP::SingleResponse
+ */
+static VALUE
+ossl_ocspsres_new(OCSP_SINGLERESP *sres)
+{
+ VALUE obj;
+
+ obj = NewOCSPSingleRes(cOCSPSingleRes);
+ SetOCSPSingleRes(obj, sres);
+
+ return obj;
+}
+
+static VALUE
+ossl_ocspsres_alloc(VALUE klass)
+{
+ OCSP_SINGLERESP *sres;
+ VALUE obj;
+
+ obj = NewOCSPSingleRes(klass);
+ if (!(sres = OCSP_SINGLERESP_new()))
+ ossl_raise(eOCSPError, NULL);
+ SetOCSPSingleRes(obj, sres);
+
+ return obj;
+}
+
+/*
+ * call-seq:
+ * OpenSSL::OCSP::SingleResponse.new(der_string) -> SingleResponse
+ *
+ * Creates a new SingleResponse from +der_string+.
+ */
+static VALUE
+ossl_ocspsres_initialize(VALUE self, VALUE arg)
+{
+ OCSP_SINGLERESP *res;
+ const unsigned char *p;
+
+ arg = ossl_to_der_if_possible(arg);
+ StringValue(arg);
+ GetOCSPSingleRes(self, res);
+
+ p = (unsigned char*)RSTRING_PTR(arg);
+ if (!d2i_OCSP_SINGLERESP(&res, &p, RSTRING_LEN(arg)))
+ ossl_raise(eOCSPError, "d2i_OCSP_SINGLERESP");
+
+ return self;
+}
+
+static VALUE
+ossl_ocspsres_initialize_copy(VALUE self, VALUE other)
+{
+ OCSP_SINGLERESP *sres, *sres_old, *sres_new;
+
+ rb_check_frozen(self);
+ GetOCSPSingleRes(self, sres_old);
+ SafeGetOCSPSingleRes(other, sres);
+
+ sres_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_SINGLERESP), sres);
+ if (!sres_new)
+ ossl_raise(eOCSPError, "ASN1_item_dup");
+
+ SetOCSPSingleRes(self, sres_new);
+ OCSP_SINGLERESP_free(sres_old);
+
+ return self;
+}
+
+/*
+ * call-seq:
+ * single_response.check_validity(nsec = 0, maxsec = -1) -> true | false
+ *
+ * Checks the validity of thisUpdate and nextUpdate fields of this
+ * SingleResponse. This checks the current time is within the range thisUpdate
+ * to nextUpdate.
+ *
+ * It is possible that the OCSP request takes a few seconds or the time is not
+ * accurate. To avoid rejecting a valid response, this method allows the times
+ * to be within +nsec+ of the current time.
+ *
+ * Some responders don't set the nextUpdate field. This may cause a very old
+ * response to be considered valid. The +maxsec+ parameter can be used to limit
+ * the age of responses.
+ */
+static VALUE
+ossl_ocspsres_check_validity(int argc, VALUE *argv, VALUE self)
+{
+ OCSP_SINGLERESP *sres;
+ ASN1_GENERALIZEDTIME *this_update, *next_update;
+ VALUE nsec_v, maxsec_v;
+ int nsec, maxsec, status, ret;
+
+ rb_scan_args(argc, argv, "02", &nsec_v, &maxsec_v);
+ nsec = NIL_P(nsec_v) ? 0 : NUM2INT(nsec_v);
+ maxsec = NIL_P(maxsec_v) ? -1 : NUM2INT(maxsec_v);
+
+ GetOCSPSingleRes(self, sres);
+ status = OCSP_single_get0_status(sres, NULL, NULL, &this_update, &next_update);
+ if (status < 0)
+ ossl_raise(eOCSPError, "OCSP_single_get0_status");
+
+ ret = OCSP_check_validity(this_update, next_update, nsec, maxsec);
+
+ if (ret)
+ return Qtrue;
+ else {
+ ossl_clear_error();
+ return Qfalse;
+ }
+}
+
+/*
+ * call-seq:
+ * single_response.certid -> CertificateId
+ *
+ * Returns the CertificateId for which this SingleResponse is.
+ */
+static VALUE
+ossl_ocspsres_get_certid(VALUE self)
+{
+ OCSP_SINGLERESP *sres;
+ OCSP_CERTID *id;
+
+ GetOCSPSingleRes(self, sres);
+ id = OCSP_CERTID_dup(OCSP_SINGLERESP_get0_id(sres));
+
+ return ossl_ocspcertid_new(id);
+}
+
+/*
+ * call-seq:
+ * single_response.cert_status -> Integer
+ *
+ * Returns the status of the certificate identified by the certid.
+ * The return value may be one of these constant:
+ *
+ * - V_CERTSTATUS_GOOD
+ * - V_CERTSTATUS_REVOKED
+ * - V_CERTSTATUS_UNKNOWN
+ *
+ * When the status is V_CERTSTATUS_REVOKED, the time at which the certificate
+ * was revoked can be retrieved by #revocation_time.
+ */
+static VALUE
+ossl_ocspsres_get_cert_status(VALUE self)
+{
+ OCSP_SINGLERESP *sres;
+ int status;
+
+ GetOCSPSingleRes(self, sres);
+ status = OCSP_single_get0_status(sres, NULL, NULL, NULL, NULL);
+ if (status < 0)
+ ossl_raise(eOCSPError, "OCSP_single_get0_status");
+
+ return INT2NUM(status);
+}
+
+/*
+ * call-seq:
+ * single_response.this_update -> Time
+ */
+static VALUE
+ossl_ocspsres_get_this_update(VALUE self)
+{
+ OCSP_SINGLERESP *sres;
+ int status;
+ ASN1_GENERALIZEDTIME *time;
+
+ GetOCSPSingleRes(self, sres);
+ status = OCSP_single_get0_status(sres, NULL, NULL, &time, NULL);
+ if (status < 0)
+ ossl_raise(eOCSPError, "OCSP_single_get0_status");
+
+ return asn1time_to_time(time); /* will handle NULL */
+}
+
+/*
+ * call-seq:
+ * single_response.next_update -> Time | nil
+ */
+static VALUE
+ossl_ocspsres_get_next_update(VALUE self)
+{
+ OCSP_SINGLERESP *sres;
+ int status;
+ ASN1_GENERALIZEDTIME *time;
+
+ GetOCSPSingleRes(self, sres);
+ status = OCSP_single_get0_status(sres, NULL, NULL, NULL, &time);
+ if (status < 0)
+ ossl_raise(eOCSPError, "OCSP_single_get0_status");
+
+ return asn1time_to_time(time);
+}
+
+/*
+ * call-seq:
+ * single_response.revocation_time -> Time | nil
+ */
+static VALUE
+ossl_ocspsres_get_revocation_time(VALUE self)
+{
+ OCSP_SINGLERESP *sres;
+ int status;
+ ASN1_GENERALIZEDTIME *time;
+
+ GetOCSPSingleRes(self, sres);
+ status = OCSP_single_get0_status(sres, NULL, &time, NULL, NULL);
+ if (status < 0)
+ ossl_raise(eOCSPError, "OCSP_single_get0_status");
+ if (status != V_OCSP_CERTSTATUS_REVOKED)
+ ossl_raise(eOCSPError, "certificate is not revoked");
+
+ return asn1time_to_time(time);
+}
+
+/*
+ * call-seq:
+ * single_response.revocation_reason -> Integer | nil
+ */
+static VALUE
+ossl_ocspsres_get_revocation_reason(VALUE self)
+{
+ OCSP_SINGLERESP *sres;
+ int status, reason;
+
+ GetOCSPSingleRes(self, sres);
+ status = OCSP_single_get0_status(sres, &reason, NULL, NULL, NULL);
+ if (status < 0)
+ ossl_raise(eOCSPError, "OCSP_single_get0_status");
+ if (status != V_OCSP_CERTSTATUS_REVOKED)
+ ossl_raise(eOCSPError, "certificate is not revoked");
+
+ return INT2NUM(reason);
+}
+
+/*
+ * call-seq:
+ * single_response.extensions -> Array of X509::Extension
+ */
+static VALUE
+ossl_ocspsres_get_extensions(VALUE self)
+{
+ OCSP_SINGLERESP *sres;
+ X509_EXTENSION *ext;
+ int count, i;
+ VALUE ary;
+
+ GetOCSPSingleRes(self, sres);
+
+ count = OCSP_SINGLERESP_get_ext_count(sres);
+ ary = rb_ary_new2(count);
+ for (i = 0; i < count; i++) {
+ ext = OCSP_SINGLERESP_get_ext(sres, i);
+ rb_ary_push(ary, ossl_x509ext_new(ext)); /* will dup */
+ }
+
+ return ary;
+}
+
+/*
+ * call-seq:
+ * single_response.to_der -> String
+ *
+ * Encodes this SingleResponse into a DER-encoded string.
+ */
+static VALUE
+ossl_ocspsres_to_der(VALUE self)
+{
+ OCSP_SINGLERESP *sres;
+ VALUE str;
+ long len;
+ unsigned char *p;
+
+ GetOCSPSingleRes(self, sres);
+ if ((len = i2d_OCSP_SINGLERESP(sres, NULL)) <= 0)
+ ossl_raise(eOCSPError, NULL);
+ str = rb_str_new(0, len);
+ p = (unsigned char *)RSTRING_PTR(str);
+ if (i2d_OCSP_SINGLERESP(sres, &p) <= 0)
+ ossl_raise(eOCSPError, NULL);
+ ossl_str_adjust(str, p);
+
+ return str;
+}
+
+
+/*
* OCSP::CertificateId
*/
static VALUE
@@ -872,13 +1396,36 @@ ossl_ocspcid_alloc(VALUE klass)
return obj;
}
+static VALUE
+ossl_ocspcid_initialize_copy(VALUE self, VALUE other)
+{
+ OCSP_CERTID *cid, *cid_old, *cid_new;
+
+ rb_check_frozen(self);
+ GetOCSPCertId(self, cid_old);
+ SafeGetOCSPCertId(other, cid);
+
+ cid_new = OCSP_CERTID_dup(cid);
+ if (!cid_new)
+ ossl_raise(eOCSPError, "OCSP_CERTID_dup");
+
+ SetOCSPCertId(self, cid_new);
+ OCSP_CERTID_free(cid_old);
+
+ return self;
+}
+
/*
* call-seq:
* OpenSSL::OCSP::CertificateId.new(subject, issuer, digest = nil) -> certificate_id
+ * OpenSSL::OCSP::CertificateId.new(der_string) -> certificate_id
*
* Creates a new OpenSSL::OCSP::CertificateId for the given +subject+ and
* +issuer+ X509 certificates. The +digest+ is used to compute the
* certificate ID and must be an OpenSSL::Digest instance.
+ *
+ * If only one argument is given, decodes it as DER representation of a
+ * certificate ID.
*/
static VALUE
@@ -889,7 +1436,17 @@ ossl_ocspcid_initialize(int argc, VALUE *argv, VALUE self)
VALUE subject, issuer, digest;
const EVP_MD *md;
- if (rb_scan_args(argc, argv, "21", &subject, &issuer, &digest) == 0) {
+ GetOCSPCertId(self, id);
+ if (rb_scan_args(argc, argv, "12", &subject, &issuer, &digest) == 1) {
+ VALUE arg;
+ const unsigned char *p;
+
+ arg = ossl_to_der_if_possible(subject);
+ StringValue(arg);
+ p = (unsigned char *)RSTRING_PTR(arg);
+ if (!d2i_OCSP_CERTID(&id, &p, RSTRING_LEN(arg)))
+ ossl_raise(eOCSPError, "d2i_OCSP_CERTID");
+
return self;
}
@@ -904,9 +1461,8 @@ ossl_ocspcid_initialize(int argc, VALUE *argv, VALUE self)
}
if(!newid)
ossl_raise(eOCSPError, NULL);
- GetOCSPCertId(self, id);
OCSP_CERTID_free(id);
- RDATA(self)->data = newid;
+ SetOCSPCertId(self, newid);
return self;
}
@@ -954,11 +1510,11 @@ ossl_ocspcid_cmp_issuer(VALUE self, VALUE other)
/*
* call-seq:
- * certificate_id.get_serial -> Integer
+ * certificate_id.serial -> Integer
*
- * Returns the serial number of the issuing certificate.
+ * Returns the serial number of the certificate for which status is being
+ * requested.
*/
-
static VALUE
ossl_ocspcid_get_serial(VALUE self)
{
@@ -971,6 +1527,105 @@ ossl_ocspcid_get_serial(VALUE self)
return asn1integer_to_num(serial);
}
+/*
+ * call-seq:
+ * certificate_id.issuer_name_hash -> String
+ *
+ * Returns the issuerNameHash of this certificate ID, the hash of the
+ * issuer's distinguished name calculated with the hashAlgorithm.
+ */
+static VALUE
+ossl_ocspcid_get_issuer_name_hash(VALUE self)
+{
+ OCSP_CERTID *id;
+ ASN1_OCTET_STRING *name_hash;
+ char *hexbuf;
+
+ GetOCSPCertId(self, id);
+ OCSP_id_get0_info(&name_hash, NULL, NULL, NULL, id);
+
+ if (string2hex(name_hash->data, name_hash->length, &hexbuf, NULL) < 0)
+ ossl_raise(eOCSPError, "string2hex");
+
+ return ossl_buf2str(hexbuf, name_hash->length * 2);
+}
+
+/*
+ * call-seq:
+ * certificate_id.issuer_key_hash -> String
+ *
+ * Returns the issuerKeyHash of this certificate ID, the hash of the issuer's
+ * public key.
+ */
+static VALUE
+ossl_ocspcid_get_issuer_key_hash(VALUE self)
+{
+ OCSP_CERTID *id;
+ ASN1_OCTET_STRING *key_hash;
+ char *hexbuf;
+
+ GetOCSPCertId(self, id);
+ OCSP_id_get0_info(NULL, NULL, &key_hash, NULL, id);
+
+ if (string2hex(key_hash->data, key_hash->length, &hexbuf, NULL) < 0)
+ ossl_raise(eOCSPError, "string2hex");
+
+ return ossl_buf2str(hexbuf, key_hash->length * 2);
+}
+
+/*
+ * call-seq:
+ * certificate_id.hash_algorithm -> String
+ *
+ * Returns the ln (long name) of the hash algorithm used to generate
+ * the issuerNameHash and the issuerKeyHash values.
+ */
+static VALUE
+ossl_ocspcid_get_hash_algorithm(VALUE self)
+{
+ OCSP_CERTID *id;
+ ASN1_OBJECT *oid;
+ BIO *out;
+
+ GetOCSPCertId(self, id);
+ OCSP_id_get0_info(NULL, &oid, NULL, NULL, id);
+
+ if (!(out = BIO_new(BIO_s_mem())))
+ ossl_raise(eOCSPError, "BIO_new");
+
+ if (!i2a_ASN1_OBJECT(out, oid)) {
+ BIO_free(out);
+ ossl_raise(eOCSPError, "i2a_ASN1_OBJECT");
+ }
+ return ossl_membio2str(out);
+}
+
+/*
+ * call-seq:
+ * certificate_id.to_der -> String
+ *
+ * Encodes this certificate identifier into a DER-encoded string.
+ */
+static VALUE
+ossl_ocspcid_to_der(VALUE self)
+{
+ OCSP_CERTID *id;
+ VALUE str;
+ long len;
+ unsigned char *p;
+
+ GetOCSPCertId(self, id);
+ if ((len = i2d_OCSP_CERTID(id, NULL)) <= 0)
+ ossl_raise(eOCSPError, NULL);
+ str = rb_str_new(0, len);
+ p = (unsigned char *)RSTRING_PTR(str);
+ if (i2d_OCSP_CERTID(id, &p) <= 0)
+ ossl_raise(eOCSPError, NULL);
+ ossl_str_adjust(str, p);
+
+ return str;
+}
+
void
Init_ossl_ocsp(void)
{
@@ -1043,7 +1698,7 @@ Init_ossl_ocsp(void)
* store = OpenSSL::X509::Store.new
* store.set_default_paths
*
- * unless response.verify [], store then
+ * unless response_basic.verify [], store then
* raise 'response is not signed by a trusted certificate'
* end
*
@@ -1059,27 +1714,28 @@ Init_ossl_ocsp(void)
*
* p request.check_nonce basic_response #=> value from -1 to 3
*
- * Then extract the status information from the basic response. (You can
- * check multiple certificates in a request, but for this example we only
- * submitted one.)
- *
- * response_certificate_id, status, reason, revocation_time,
- * this_update, next_update, extensions = basic_response.status
+ * Then extract the status information for the certificate from the basic
+ * response.
*
- * Then check the various fields.
+ * single_response = basic_response.find_response(certificate_id)
*
- * unless response_certificate_id == certificate_id then
- * raise 'certificate id mismatch'
+ * unless single_response
+ * raise 'basic_response does not have the status for the certificiate'
* end
*
- * now = Time.now
+ * Then check the validity. A status issued in the future must be rejected.
*
- * if this_update > now then
- * raise 'update date is in the future'
+ * unless single_response.check_validity
+ * raise 'this_update is in the future or next_update time has passed'
* end
*
- * if now > next_update then
- * raise 'next update time has passed'
+ * case single_response.cert_status
+ * when OpenSSL::OCSP::V_CERTSTATUS_GOOD
+ * puts 'certificate is still valid'
+ * when OpenSSL::OCSP::V_CERTSTATUS_REVOKED
+ * puts "certificate has been revoked at #{single_response.revocation_time}"
+ * when OpenSSL::OCSP::V_CERTSTATUS_UNKNOWN
+ * puts 'responder doesn't know about the certificate'
* end
*/
@@ -1100,6 +1756,7 @@ Init_ossl_ocsp(void)
cOCSPReq = rb_define_class_under(mOCSP, "Request", rb_cObject);
rb_define_alloc_func(cOCSPReq, ossl_ocspreq_alloc);
+ rb_define_copy_func(cOCSPReq, ossl_ocspreq_initialize_copy);
rb_define_method(cOCSPReq, "initialize", ossl_ocspreq_initialize, -1);
rb_define_method(cOCSPReq, "add_nonce", ossl_ocspreq_add_nonce, -1);
rb_define_method(cOCSPReq, "check_nonce", ossl_ocspreq_check_nonce, 1);
@@ -1117,6 +1774,7 @@ Init_ossl_ocsp(void)
cOCSPRes = rb_define_class_under(mOCSP, "Response", rb_cObject);
rb_define_singleton_method(cOCSPRes, "create", ossl_ocspres_s_create, 2);
rb_define_alloc_func(cOCSPRes, ossl_ocspres_alloc);
+ rb_define_copy_func(cOCSPRes, ossl_ocspres_initialize_copy);
rb_define_method(cOCSPRes, "initialize", ossl_ocspres_initialize, -1);
rb_define_method(cOCSPRes, "status", ossl_ocspres_status, 0);
rb_define_method(cOCSPRes, "status_string", ossl_ocspres_status_string, 0);
@@ -1131,13 +1789,36 @@ Init_ossl_ocsp(void)
cOCSPBasicRes = rb_define_class_under(mOCSP, "BasicResponse", rb_cObject);
rb_define_alloc_func(cOCSPBasicRes, ossl_ocspbres_alloc);
+ rb_define_copy_func(cOCSPBasicRes, ossl_ocspbres_initialize_copy);
rb_define_method(cOCSPBasicRes, "initialize", ossl_ocspbres_initialize, -1);
rb_define_method(cOCSPBasicRes, "copy_nonce", ossl_ocspbres_copy_nonce, 1);
rb_define_method(cOCSPBasicRes, "add_nonce", ossl_ocspbres_add_nonce, -1);
rb_define_method(cOCSPBasicRes, "add_status", ossl_ocspbres_add_status, 7);
rb_define_method(cOCSPBasicRes, "status", ossl_ocspbres_get_status, 0);
+ rb_define_method(cOCSPBasicRes, "responses", ossl_ocspbres_get_responses, 0);
+ rb_define_method(cOCSPBasicRes, "find_response", ossl_ocspbres_find_response, 1);
rb_define_method(cOCSPBasicRes, "sign", ossl_ocspbres_sign, -1);
rb_define_method(cOCSPBasicRes, "verify", ossl_ocspbres_verify, -1);
+ rb_define_method(cOCSPBasicRes, "to_der", ossl_ocspbres_to_der, 0);
+
+ /*
+ * An OpenSSL::OCSP::SingleResponse represents an OCSP SingleResponse
+ * structure, which contains the basic information of the status of the
+ * certificate.
+ */
+ cOCSPSingleRes = rb_define_class_under(mOCSP, "SingleResponse", rb_cObject);
+ rb_define_alloc_func(cOCSPSingleRes, ossl_ocspsres_alloc);
+ rb_define_copy_func(cOCSPSingleRes, ossl_ocspsres_initialize_copy);
+ rb_define_method(cOCSPSingleRes, "initialize", ossl_ocspsres_initialize, 1);
+ rb_define_method(cOCSPSingleRes, "check_validity", ossl_ocspsres_check_validity, -1);
+ rb_define_method(cOCSPSingleRes, "certid", ossl_ocspsres_get_certid, 0);
+ rb_define_method(cOCSPSingleRes, "cert_status", ossl_ocspsres_get_cert_status, 0);
+ rb_define_method(cOCSPSingleRes, "this_update", ossl_ocspsres_get_this_update, 0);
+ rb_define_method(cOCSPSingleRes, "next_update", ossl_ocspsres_get_next_update, 0);
+ rb_define_method(cOCSPSingleRes, "revocation_time", ossl_ocspsres_get_revocation_time, 0);
+ rb_define_method(cOCSPSingleRes, "revocation_reason", ossl_ocspsres_get_revocation_reason, 0);
+ rb_define_method(cOCSPSingleRes, "extensions", ossl_ocspsres_get_extensions, 0);
+ rb_define_method(cOCSPSingleRes, "to_der", ossl_ocspsres_to_der, 0);
/*
* An OpenSSL::OCSP::CertificateId identifies a certificate to the CA so
@@ -1146,10 +1827,15 @@ Init_ossl_ocsp(void)
cOCSPCertId = rb_define_class_under(mOCSP, "CertificateId", rb_cObject);
rb_define_alloc_func(cOCSPCertId, ossl_ocspcid_alloc);
+ rb_define_copy_func(cOCSPCertId, ossl_ocspcid_initialize_copy);
rb_define_method(cOCSPCertId, "initialize", ossl_ocspcid_initialize, -1);
rb_define_method(cOCSPCertId, "cmp", ossl_ocspcid_cmp, 1);
rb_define_method(cOCSPCertId, "cmp_issuer", ossl_ocspcid_cmp_issuer, 1);
rb_define_method(cOCSPCertId, "serial", ossl_ocspcid_get_serial, 0);
+ rb_define_method(cOCSPCertId, "issuer_name_hash", ossl_ocspcid_get_issuer_name_hash, 0);
+ rb_define_method(cOCSPCertId, "issuer_key_hash", ossl_ocspcid_get_issuer_key_hash, 0);
+ rb_define_method(cOCSPCertId, "hash_algorithm", ossl_ocspcid_get_hash_algorithm, 0);
+ rb_define_method(cOCSPCertId, "to_der", ossl_ocspcid_to_der, 0);
/* Internal error in issuer */
rb_define_const(mOCSP, "RESPONSE_STATUS_INTERNALERROR", INT2NUM(OCSP_RESPONSE_STATUS_INTERNALERROR));
@@ -1251,7 +1937,6 @@ Init_ossl_ocsp(void)
/* The responder ID is based on the public key. */
rb_define_const(mOCSP, "V_RESPID_KEY", INT2NUM(V_OCSP_RESPID_KEY));
}
-
#else
void
Init_ossl_ocsp(void)
diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h
index 6f9555e5..1f68352c 100644
--- a/ext/openssl/ossl_pkey.h
+++ b/ext/openssl/ossl_pkey.h
@@ -103,7 +103,7 @@ void Init_ossl_ec(void);
static VALUE ossl_##_keytype##_get_##_name(VALUE self) \
{ \
_type *obj; \
- BIGNUM *bn; \
+ const BIGNUM *bn; \
\
Get##_type(self, obj); \
_get; \
diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c
index 74402fb9..139af152 100644
--- a/ext/openssl/ossl_pkey_dh.c
+++ b/ext/openssl/ossl_pkey_dh.c
@@ -238,6 +238,39 @@ ossl_dh_initialize(int argc, VALUE *argv, VALUE self)
return self;
}
+static VALUE
+ossl_dh_initialize_copy(VALUE self, VALUE other)
+{
+ EVP_PKEY *pkey;
+ DH *dh, *dh_other;
+ const BIGNUM *pub, *priv;
+
+ GetPKey(self, pkey);
+ if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE)
+ ossl_raise(eDHError, "DH already initialized");
+ GetDH(other, dh_other);
+
+ dh = DHparams_dup(dh_other);
+ if (!dh)
+ ossl_raise(eDHError, "DHparams_dup");
+ EVP_PKEY_assign_DH(pkey, dh);
+
+ DH_get0_key(dh_other, &pub, &priv);
+ if (pub) {
+ BIGNUM *pub2 = BN_dup(pub);
+ BIGNUM *priv2 = BN_dup(priv);
+
+ if (!pub2 || priv && !priv2) {
+ BN_clear_free(pub2);
+ BN_clear_free(priv2);
+ ossl_raise(eDHError, "BN_dup");
+ }
+ DH_set0_key(dh, pub2, priv2);
+ }
+
+ return self;
+}
+
/*
* call-seq:
* dh.public? -> true | false
@@ -249,7 +282,7 @@ static VALUE
ossl_dh_is_public(VALUE self)
{
DH *dh;
- BIGNUM *bn;
+ const BIGNUM *bn;
GetDH(self, dh);
DH_get0_key(dh, &bn, NULL);
@@ -268,7 +301,7 @@ static VALUE
ossl_dh_is_private(VALUE self)
{
DH *dh;
- BIGNUM *bn;
+ const BIGNUM *bn;
GetDH(self, dh);
DH_get0_key(dh, NULL, &bn);
@@ -352,7 +385,7 @@ ossl_dh_get_params(VALUE self)
{
DH *dh;
VALUE hash;
- BIGNUM *p, *q, *g, *pub_key, *priv_key;
+ const BIGNUM *p, *q, *g, *pub_key, *priv_key;
GetDH(self, dh);
DH_get0_pqg(dh, &p, &q, &g);
@@ -498,7 +531,7 @@ static VALUE
ossl_dh_compute_key(VALUE self, VALUE pub)
{
DH *dh;
- BIGNUM *pub_key, *dh_p;
+ const BIGNUM *pub_key, *dh_p;
VALUE str;
int len;
@@ -568,6 +601,7 @@ Init_ossl_dh(void)
cDH = rb_define_class_under(mPKey, "DH", cPKey);
rb_define_singleton_method(cDH, "generate", ossl_dh_s_generate, -1);
rb_define_method(cDH, "initialize", ossl_dh_initialize, -1);
+ rb_define_copy_func(cDH, ossl_dh_initialize_copy);
rb_define_method(cDH, "public?", ossl_dh_is_public, 0);
rb_define_method(cDH, "private?", ossl_dh_is_private, 0);
rb_define_method(cDH, "to_text", ossl_dh_to_text, 0);
diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c
index 28246790..1ddc0d48 100644
--- a/ext/openssl/ossl_pkey_dsa.c
+++ b/ext/openssl/ossl_pkey_dsa.c
@@ -26,7 +26,7 @@
static inline int
DSA_HAS_PRIVATE(DSA *dsa)
{
- BIGNUM *bn;
+ const BIGNUM *bn;
DSA_get0_key(dsa, NULL, &bn);
return !!bn;
}
@@ -269,6 +269,26 @@ ossl_dsa_initialize(int argc, VALUE *argv, VALUE self)
return self;
}
+static VALUE
+ossl_dsa_initialize_copy(VALUE self, VALUE other)
+{
+ EVP_PKEY *pkey;
+ DSA *dsa, *dsa_new;
+
+ GetPKey(self, pkey);
+ if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE)
+ ossl_raise(eDSAError, "DSA already initialized");
+ GetDSA(other, dsa);
+
+ dsa_new = ASN1_dup((i2d_of_void *)i2d_DSAPrivateKey, (d2i_of_void *)d2i_DSAPrivateKey, (char *)dsa);
+ if (!dsa_new)
+ ossl_raise(eDSAError, "ASN1_dup");
+
+ EVP_PKEY_assign_DSA(pkey, dsa_new);
+
+ return self;
+}
+
/*
* call-seq:
* dsa.public? -> true | false
@@ -280,7 +300,7 @@ static VALUE
ossl_dsa_is_public(VALUE self)
{
DSA *dsa;
- BIGNUM *bn;
+ const BIGNUM *bn;
GetDSA(self, dsa);
DSA_get0_key(dsa, &bn, NULL);
@@ -402,7 +422,7 @@ ossl_dsa_get_params(VALUE self)
{
DSA *dsa;
VALUE hash;
- BIGNUM *p, *q, *g, *pub_key, *priv_key;
+ const BIGNUM *p, *q, *g, *pub_key, *priv_key;
GetDSA(self, dsa);
DSA_get0_pqg(dsa, &p, &q, &g);
@@ -509,7 +529,7 @@ static VALUE
ossl_dsa_sign(VALUE self, VALUE data)
{
DSA *dsa;
- BIGNUM *dsa_q;
+ const BIGNUM *dsa_q;
unsigned int buf_len;
VALUE str;
@@ -610,6 +630,7 @@ Init_ossl_dsa(void)
rb_define_singleton_method(cDSA, "generate", ossl_dsa_s_generate, 1);
rb_define_method(cDSA, "initialize", ossl_dsa_initialize, -1);
+ rb_define_copy_func(cDSA, ossl_dsa_initialize_copy);
rb_define_method(cDSA, "public?", ossl_dsa_is_public, 0);
rb_define_method(cDSA, "private?", ossl_dsa_is_private, 0);
diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c
index 30ded33c..43eebd26 100644
--- a/ext/openssl/ossl_pkey_ec.c
+++ b/ext/openssl/ossl_pkey_ec.c
@@ -285,6 +285,29 @@ static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self)
return self;
}
+static VALUE
+ossl_ec_key_initialize_copy(VALUE self, VALUE other)
+{
+ EVP_PKEY *pkey;
+ EC_KEY *ec, *ec_new;
+
+ GetPKey(self, pkey);
+ if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE)
+ ossl_raise(eECError, "EC already initialized");
+ SafeRequire_EC_KEY(other, ec);
+
+ ec_new = EC_KEY_dup(ec);
+ if (!ec_new)
+ ossl_raise(eECError, "EC_KEY_dup");
+ if (!EVP_PKEY_assign_EC_KEY(pkey, ec_new)) {
+ EC_KEY_free(ec_new);
+ ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY");
+ }
+ rb_iv_set(self, "@group", Qnil); /* EC_KEY_dup() also copies the EC_GROUP */
+
+ return self;
+}
+
/*
* call-seq:
* key.group => group
@@ -903,6 +926,26 @@ static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self)
return self;
}
+static VALUE
+ossl_ec_group_initialize_copy(VALUE self, VALUE other)
+{
+ ossl_ec_group *ec_group;
+ EC_GROUP *orig;
+
+ TypedData_Get_Struct(self, ossl_ec_group, &ossl_ec_group_type, ec_group);
+ if (ec_group->group)
+ ossl_raise(eEC_GROUP, "EC::Group already initialized");
+ SafeRequire_EC_GROUP(other, orig);
+
+ ec_group->group = EC_GROUP_dup(orig);
+ if (!ec_group->group)
+ ossl_raise(eEC_GROUP, "EC_GROUP_dup");
+
+ rb_iv_set(self, "@key", Qnil);
+
+ return self;
+}
+
/* call-seq:
* group1.eql?(group2) => true | false
* group1 == group2 => true | false
@@ -1381,6 +1424,31 @@ static VALUE ossl_ec_point_initialize(int argc, VALUE *argv, VALUE self)
return self;
}
+static VALUE
+ossl_ec_point_initialize_copy(VALUE self, VALUE other)
+{
+ ossl_ec_point *ec_point;
+ EC_POINT *orig;
+ EC_GROUP *group;
+ VALUE group_v;
+
+ 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");
+ SafeRequire_EC_POINT(other, orig);
+
+ group_v = rb_obj_dup(rb_iv_get(other, "@group"));
+ SafeRequire_EC_GROUP(group_v, group);
+
+ ec_point->point = EC_POINT_dup(orig, group);
+ if (!ec_point->point)
+ ossl_raise(eEC_POINT, "EC_POINT_dup");
+ rb_iv_set(self, "@key", Qnil);
+ rb_iv_set(self, "@group", group_v);
+
+ return self;
+}
+
/*
* call-seq:
* point1.eql?(point2) => true | false
@@ -1624,14 +1692,6 @@ static VALUE ossl_ec_point_mul(int argc, VALUE *argv, VALUE self)
return result;
}
-static void no_copy(VALUE klass)
-{
- rb_undef_method(klass, "copy");
- rb_undef_method(klass, "clone");
- rb_undef_method(klass, "dup");
- rb_undef_method(klass, "initialize_copy");
-}
-
void Init_ossl_ec(void)
{
#ifdef DONT_NEED_RDOC_WORKAROUND
@@ -1664,6 +1724,7 @@ void Init_ossl_ec(void)
rb_define_singleton_method(cEC, "generate", ossl_ec_key_s_generate, 1);
rb_define_method(cEC, "initialize", ossl_ec_key_initialize, -1);
+ rb_define_copy_func(cEC, ossl_ec_key_initialize_copy);
/* copy/dup/cmp */
rb_define_method(cEC, "group", ossl_ec_key_get_group, 0);
@@ -1700,6 +1761,7 @@ void Init_ossl_ec(void)
rb_define_alloc_func(cEC_GROUP, ossl_ec_group_alloc);
rb_define_method(cEC_GROUP, "initialize", ossl_ec_group_initialize, -1);
+ rb_define_copy_func(cEC_GROUP, ossl_ec_group_initialize_copy);
rb_define_method(cEC_GROUP, "eql?", ossl_ec_group_eql, 1);
rb_define_alias(cEC_GROUP, "==", "eql?");
/* copy/dup/cmp */
@@ -1735,6 +1797,7 @@ void Init_ossl_ec(void)
rb_define_alloc_func(cEC_POINT, ossl_ec_point_alloc);
rb_define_method(cEC_POINT, "initialize", ossl_ec_point_initialize, -1);
+ rb_define_copy_func(cEC_POINT, ossl_ec_point_initialize_copy);
rb_attr(cEC_POINT, rb_intern("group"), 1, 0, 0);
rb_define_method(cEC_POINT, "eql?", ossl_ec_point_eql, 1);
rb_define_alias(cEC_POINT, "==", "eql?");
@@ -1748,10 +1811,6 @@ void Init_ossl_ec(void)
rb_define_method(cEC_POINT, "to_bn", ossl_ec_point_to_bn, 0);
rb_define_method(cEC_POINT, "mul", ossl_ec_point_mul, -1);
-
- no_copy(cEC);
- no_copy(cEC_GROUP);
- no_copy(cEC_POINT);
}
#else /* defined NO_EC */
diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c
index 1ee45d0f..2326a70f 100644
--- a/ext/openssl/ossl_pkey_rsa.c
+++ b/ext/openssl/ossl_pkey_rsa.c
@@ -26,7 +26,7 @@
static inline int
RSA_HAS_PRIVATE(RSA *rsa)
{
- BIGNUM *p, *q;
+ const BIGNUM *p, *q;
RSA_get0_factors(rsa, &p, &q);
return p && q; /* d? why? */
@@ -271,6 +271,26 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self)
return self;
}
+static VALUE
+ossl_rsa_initialize_copy(VALUE self, VALUE other)
+{
+ EVP_PKEY *pkey;
+ RSA *rsa, *rsa_new;
+
+ GetPKey(self, pkey);
+ if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE)
+ ossl_raise(eRSAError, "RSA already initialized");
+ GetRSA(other, rsa);
+
+ rsa_new = ASN1_dup((i2d_of_void *)i2d_RSAPrivateKey, (d2i_of_void *)d2i_RSAPrivateKey, (char *)rsa);
+ if (!rsa_new)
+ ossl_raise(eRSAError, "ASN1_dup");
+
+ EVP_PKEY_assign_RSA(pkey, rsa_new);
+
+ return self;
+}
+
/*
* call-seq:
* rsa.public? => true
@@ -398,7 +418,7 @@ static VALUE
ossl_rsa_public_encrypt(int argc, VALUE *argv, VALUE self)
{
RSA *rsa;
- BIGNUM *rsa_n;
+ const BIGNUM *rsa_n;
int buf_len, pad;
VALUE str, buffer, padding;
@@ -430,7 +450,7 @@ static VALUE
ossl_rsa_public_decrypt(int argc, VALUE *argv, VALUE self)
{
RSA *rsa;
- BIGNUM *rsa_n;
+ const BIGNUM *rsa_n;
int buf_len, pad;
VALUE str, buffer, padding;
@@ -462,7 +482,7 @@ static VALUE
ossl_rsa_private_encrypt(int argc, VALUE *argv, VALUE self)
{
RSA *rsa;
- BIGNUM *rsa_n;
+ const BIGNUM *rsa_n;
int buf_len, pad;
VALUE str, buffer, padding;
@@ -496,7 +516,7 @@ static VALUE
ossl_rsa_private_decrypt(int argc, VALUE *argv, VALUE self)
{
RSA *rsa;
- BIGNUM *rsa_n;
+ const BIGNUM *rsa_n;
int buf_len, pad;
VALUE str, buffer, padding;
@@ -534,7 +554,7 @@ ossl_rsa_get_params(VALUE self)
{
RSA *rsa;
VALUE hash;
- BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp;
+ const BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp;
GetRSA(self, rsa);
RSA_get0_key(rsa, &n, &e, &d);
@@ -675,6 +695,7 @@ Init_ossl_rsa(void)
rb_define_singleton_method(cRSA, "generate", ossl_rsa_s_generate, -1);
rb_define_method(cRSA, "initialize", ossl_rsa_initialize, -1);
+ rb_define_copy_func(cRSA, ossl_rsa_initialize_copy);
rb_define_method(cRSA, "public?", ossl_rsa_is_public, 0);
rb_define_method(cRSA, "private?", ossl_rsa_is_private, 0);
diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c
index 1ee06583..58769461 100644
--- a/ext/openssl/ossl_ssl.c
+++ b/ext/openssl/ossl_ssl.c
@@ -163,7 +163,7 @@ ossl_sslctx_s_alloc(VALUE klass)
RTYPEDDATA_DATA(obj) = ctx;
SSL_CTX_set_ex_data(ctx, ossl_ssl_ex_ptr_idx, (void*)obj);
-#if defined(HAVE_SSL_CTX_SET_ECDH_AUTO)
+#if !defined(OPENSSL_NO_EC) && defined(HAVE_SSL_CTX_SET_ECDH_AUTO)
/* We use SSL_CTX_set1_curves_list() to specify the curve used in ECDH. It
* allows to specify multiple curve names and OpenSSL will select
* automatically from them. In OpenSSL 1.0.2, the automatic selection has to
@@ -285,7 +285,7 @@ ossl_tmp_dh_callback(SSL *ssl, int is_export, int keylength)
}
#endif /* OPENSSL_NO_DH */
-#if !defined(OPENSSL_NO_EC)
+#if !defined(OPENSSL_NO_EC) && defined(HAVE_SSL_CTX_SET_TMP_ECDH_CALLBACK)
static VALUE
ossl_call_tmp_ecdh_callback(VALUE args)
{
@@ -2300,7 +2300,7 @@ Init_ossl_ssl(void)
*/
rb_attr(cSSLContext, rb_intern("client_cert_cb"), 1, 1, Qfalse);
-#if defined(HAVE_SSL_CTX_SET_TMP_ECDH_CALLBACK)
+#if !defined(OPENSSL_NO_EC) && defined(HAVE_SSL_CTX_SET_TMP_ECDH_CALLBACK)
/*
* A callback invoked when ECDH parameters are required.
*
diff --git a/ext/openssl/ruby_missing.h b/ext/openssl/ruby_missing.h
index d7384ec3..f076b175 100644
--- a/ext/openssl/ruby_missing.h
+++ b/ext/openssl/ruby_missing.h
@@ -24,4 +24,9 @@
#define rb_io_t OpenFile
#endif
+#ifndef RB_INTEGER_TYPE_P
+/* for Ruby 2.3 compatibility */
+#define RB_INTEGER_TYPE_P(obj) (RB_FIXNUM_P(obj) || RB_TYPE_P(obj, T_BIGNUM))
+#endif
+
#endif /* _OSSL_RUBY_MISSING_H_ */
diff --git a/test/envutil.rb b/test/envutil.rb
index ac2a3c0c..a4964c2c 100644
--- a/test/envutil.rb
+++ b/test/envutil.rb
@@ -365,7 +365,7 @@ module Test
file ||= loc.path
line ||= loc.lineno
end
- line -= 5 # lines until src
+ line -= 6 # lines until src
src = <<eom
# -*- coding: #{src.encoding}; -*-
require 'test/unit';include Test::Unit::Assertions
@@ -373,6 +373,7 @@ module Test
puts [Marshal.dump($!)].pack('m')#, "assertions=\#{self._assertions}"
exit
}
+ def pend(msg = nil) $stdout.syswrite [Marshal.dump(msg.to_s)].pack("m"); exit! 0 end
#{src}
class Test::Unit::Runner
@@stop_auto_run = true
@@ -389,7 +390,9 @@ eom
rescue => marshal_error
ignore_stderr = nil
end
- if res
+ if res.is_a?(String)
+ pend res
+ elsif res
if bt = res.backtrace
bt.each do |l|
l.sub!(/\A-:(\d+)/){"#{file}:#{line + $1.to_i}"}
diff --git a/test/test_asn1.rb b/test/test_asn1.rb
index 96c0859c..f226da5c 100644
--- a/test/test_asn1.rb
+++ b/test/test_asn1.rb
@@ -280,6 +280,12 @@ rEzBQ0F9dUyqQ9gyRg8KHhDfv9HzT1d/rnUZMkoombwYBRIUChGCYV0GnJcan2Zm
assert_equal 2 ** 31, OpenSSL::ASN1.decode(encoded).value.to_i
end
+ def test_decode_enumerated
+ encoded = OpenSSL::ASN1.Enumerated(0).to_der
+ assert_equal "\x0a\x01\x00".b, encoded
+ assert_equal encoded, OpenSSL::ASN1.decode(encoded).to_der
+ end
+
def test_create_inf_length_primitive
expected = %w{ 24 80 04 01 61 00 00 }
raw = [expected.join('')].pack('H*')
diff --git a/test/test_engine.rb b/test/test_engine.rb
index 77f6e1a9..1aa105f1 100644
--- a/test/test_engine.rb
+++ b/test/test_engine.rb
@@ -13,17 +13,21 @@ class OpenSSL::TestEngine < OpenSSL::TestCase
def test_openssl_engine_builtin
with_openssl <<-'end;'
+ orig = OpenSSL::Engine.engines
+ pend "'openssl' is already loaded" if orig.any? { |e| e.id == "openssl" }
engine = OpenSSL::Engine.load("openssl")
assert_equal(true, engine)
- assert_equal(1, OpenSSL::Engine.engines.size)
+ assert_equal(1, OpenSSL::Engine.engines.size - orig.size)
end;
end
def test_openssl_engine_by_id_string
with_openssl <<-'end;'
+ orig = OpenSSL::Engine.engines
+ pend "'openssl' is already loaded" if orig.any? { |e| e.id == "openssl" }
engine = get_engine
assert_not_nil(engine)
- assert_equal(1, OpenSSL::Engine.engines.size)
+ assert_equal(1, OpenSSL::Engine.engines.size - orig.size)
end;
end
diff --git a/test/test_ocsp.rb b/test/test_ocsp.rb
index d04b4216..f1e34982 100644
--- a/test/test_ocsp.rb
+++ b/test/test_ocsp.rb
@@ -8,6 +8,10 @@ class OpenSSL::TestOCSP < OpenSSL::TestCase
ca_subj = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCA")
ca_key = OpenSSL::TestUtils::TEST_KEY_RSA1024
ca_serial = 0xabcabcabcabc
+ ca_exts = [
+ ["basicConstraints", "CA:TRUE", true],
+ ["keyUsage", "cRLSign,keyCertSign", true],
+ ]
subj = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCert")
@key = OpenSSL::TestUtils::TEST_KEY_RSA1024
@@ -17,31 +21,218 @@ class OpenSSL::TestOCSP < OpenSSL::TestCase
dgst = OpenSSL::Digest::SHA1.new
@ca_cert = OpenSSL::TestUtils.issue_cert(
- ca_subj, ca_key, ca_serial, now, now+3600, [], nil, nil, dgst)
+ ca_subj, ca_key, ca_serial, now, now+3600, ca_exts, nil, nil, dgst)
@cert = OpenSSL::TestUtils.issue_cert(
- subj, @key, serial, now, now+3600, [], @ca_cert, nil, dgst)
+ subj, @key, serial, now, now+3600, [], @ca_cert, ca_key, dgst)
+
+ @key2 = OpenSSL::TestUtils::TEST_KEY_RSA2048
+ cert2_exts = [
+ ["extendedKeyUsage", "OCSPSigning", true],
+ ]
+ @cert2 = OpenSSL::TestUtils.issue_cert(
+ OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCert2"),
+ @key2, serial+1, now, now+3600, cert2_exts, @ca_cert, ca_key, "SHA256")
end
def test_new_certificate_id
cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert)
assert_kind_of OpenSSL::OCSP::CertificateId, cid
assert_equal @cert.serial, cid.serial
- end
-
- def test_new_certificate_id_with_digest
cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA256.new)
assert_kind_of OpenSSL::OCSP::CertificateId, cid
assert_equal @cert.serial, cid.serial
- end if defined?(OpenSSL::Digest::SHA256)
+ end
+
+ def test_certificate_id_issuer_name_hash
+ cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert)
+ assert_equal OpenSSL::Digest::SHA1.hexdigest(@cert.issuer.to_der), cid.issuer_name_hash
+ assert_equal "d91f736ac4dc3242f0fb9b77a3149bd83c5c43d0", cid.issuer_name_hash
+ end
+
+ def test_certificate_id_issuer_key_hash
+ cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert)
+ assert_equal OpenSSL::Digest::SHA1.hexdigest(OpenSSL::ASN1.decode(@ca_cert.to_der).value[0].value[6].value[1].value), cid.issuer_key_hash
+ assert_equal "d1fef9fbf8ae1bc160cbfa03e2596dd873089213", cid.issuer_key_hash
+ end
+
+ def test_certificate_id_hash_algorithm
+ cid_sha1 = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new)
+ cid_sha256 = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA256.new)
+ assert_equal "sha1", cid_sha1.hash_algorithm
+ assert_equal "sha256", cid_sha256.hash_algorithm
+ end
+
+ def test_certificate_id_der
+ cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert) # hash algorithm defaults to SHA-1
+ der = cid.to_der
+ asn1 = OpenSSL::ASN1.decode(der)
+ assert_equal OpenSSL::ASN1.ObjectId("SHA1").to_der, asn1.value[0].value[0].to_der
+ assert_equal OpenSSL::Digest::SHA1.digest(@cert.issuer.to_der), asn1.value[1].value
+ assert_equal OpenSSL::Digest::SHA1.digest(OpenSSL::ASN1.decode(@ca_cert.to_der).value[0].value[6].value[1].value), asn1.value[2].value
+ assert_equal @cert.serial, asn1.value[3].value
+ assert_equal der, OpenSSL::OCSP::CertificateId.new(der).to_der
+ end
- def test_new_ocsp_request
+ def test_certificate_id_dup
+ cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert)
+ assert_equal cid.to_der, cid.dup.to_der
+ end
+
+ def test_request_der
request = OpenSSL::OCSP::Request.new
cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new)
request.add_certid(cid)
- request.sign(@cert, @key, [@cert])
- assert_kind_of OpenSSL::OCSP::Request, request
- # in current implementation not same instance of certificate id, but should contain same data
- assert_equal cid.serial, request.certid.first.serial
+ request.sign(@cert, @key, [@ca_cert], 0)
+ asn1 = OpenSSL::ASN1.decode(request.to_der)
+ assert_equal cid.to_der, asn1.value[0].value.find { |a| a.tag_class == :UNIVERSAL }.value[0].value[0].to_der
+ assert_equal OpenSSL::ASN1.ObjectId("sha1WithRSAEncryption").to_der, asn1.value[1].value[0].value[0].value[0].to_der
+ assert_equal @cert.to_der, asn1.value[1].value[0].value[2].value[0].value[0].to_der
+ assert_equal @ca_cert.to_der, asn1.value[1].value[0].value[2].value[0].value[1].to_der
+ assert_equal asn1.to_der, OpenSSL::OCSP::Request.new(asn1.to_der).to_der
+ end
+
+ def test_request_sign_verify
+ request = OpenSSL::OCSP::Request.new
+ cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new)
+ request.add_certid(cid)
+ request.sign(@cert, @key, nil, 0, "SHA1")
+ assert_equal cid.to_der, request.certid.first.to_der
+ store1 = OpenSSL::X509::Store.new; store1.add_cert(@ca_cert)
+ assert_equal true, request.verify([@cert], store1)
+ assert_equal true, request.verify([], store1)
+ store2 = OpenSSL::X509::Store.new; store1.add_cert(@cert2)
+ assert_equal false, request.verify([], store2)
+ assert_equal true, request.verify([], store2, OpenSSL::OCSP::NOVERIFY)
+ end
+
+ def test_request_nonce
+ req0 = OpenSSL::OCSP::Request.new
+ req1 = OpenSSL::OCSP::Request.new
+ req1.add_nonce("NONCE")
+ req2 = OpenSSL::OCSP::Request.new
+ req2.add_nonce("NONCF")
+ bres = OpenSSL::OCSP::BasicResponse.new
+ assert_equal 2, req0.check_nonce(bres)
+ bres.copy_nonce(req1)
+ assert_equal 1, req1.check_nonce(bres)
+ bres.add_nonce("NONCE")
+ assert_equal 1, req1.check_nonce(bres)
+ assert_equal 0, req2.check_nonce(bres)
+ assert_equal 3, req0.check_nonce(bres)
+ end
+
+ def test_request_dup
+ request = OpenSSL::OCSP::Request.new
+ cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new)
+ request.add_certid(cid)
+ request.sign(@cert, @key, nil, 0, "SHA1")
+ assert_equal request.to_der, request.dup.to_der
+ end
+
+ def test_basic_response_der
+ bres = OpenSSL::OCSP::BasicResponse.new
+ cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new)
+ bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, 0, nil, -300, 500, [])
+ bres.add_nonce("NONCE")
+ bres.sign(@cert2, @key2, [@ca_cert], 0)
+ der = bres.to_der
+ asn1 = OpenSSL::ASN1.decode(der)
+ assert_equal cid.to_der, asn1.value[0].value.find { |a| a.class == OpenSSL::ASN1::Sequence }.value[0].value[0].to_der
+ assert_equal OpenSSL::ASN1.Sequence([@cert2, @ca_cert]).to_der, asn1.value[3].value[0].to_der
+ assert_equal der, OpenSSL::OCSP::BasicResponse.new(der).to_der
+ end
+
+ def test_basic_response_sign_verify
+ cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA256.new)
+ bres = OpenSSL::OCSP::BasicResponse.new
+ bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_REVOKED, OpenSSL::OCSP::REVOKED_STATUS_UNSPECIFIED, -400, -300, 500, [])
+ bres.sign(@cert2, @key2, [], 0, "SHA256") # how can I check the algorithm?
+ store1 = OpenSSL::X509::Store.new; store1.add_cert(@ca_cert)
+ assert_equal true, bres.verify([], store1)
+ store2 = OpenSSL::X509::Store.new; store2.add_cert(@cert)
+ assert_equal false, bres.verify([], store2)
+ assert_equal true, bres.verify([], store2, OpenSSL::OCSP::NOVERIFY)
+ end
+
+ def test_basic_response_dup
+ bres = OpenSSL::OCSP::BasicResponse.new
+ cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new)
+ bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, 0, nil, -300, 500, [])
+ bres.sign(@cert2, @key2, [@ca_cert], 0)
+ assert_equal bres.to_der, bres.dup.to_der
+ end
+
+ def test_basic_response_response_operations
+ bres = OpenSSL::OCSP::BasicResponse.new
+ now = Time.at(Time.now.to_i)
+ cid1 = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new)
+ cid2 = OpenSSL::OCSP::CertificateId.new(@cert2, @ca_cert, OpenSSL::Digest::SHA1.new)
+ cid3 = OpenSSL::OCSP::CertificateId.new(@ca_cert, @ca_cert, OpenSSL::Digest::SHA1.new)
+ bres.add_status(cid1, OpenSSL::OCSP::V_CERTSTATUS_REVOKED, OpenSSL::OCSP::REVOKED_STATUS_UNSPECIFIED, now - 400, -300, nil, nil)
+ bres.add_status(cid2, OpenSSL::OCSP::V_CERTSTATUS_GOOD, nil, nil, -300, 500, [])
+
+ assert_equal 2, bres.responses.size
+ single = bres.responses.first
+ assert_equal cid1.to_der, single.certid.to_der
+ assert_equal OpenSSL::OCSP::V_CERTSTATUS_REVOKED, single.cert_status
+ assert_equal OpenSSL::OCSP::REVOKED_STATUS_UNSPECIFIED, single.revocation_reason
+ assert_equal now - 400, single.revocation_time
+ assert_equal now - 300, single.this_update
+ assert_equal nil, single.next_update
+ assert_equal [], single.extensions
+
+ assert_equal cid2.to_der, bres.find_response(cid2).certid.to_der
+ assert_equal nil, bres.find_response(cid3)
+ end
+
+ def test_single_response_der
+ bres = OpenSSL::OCSP::BasicResponse.new
+ cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert)
+ bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, nil, nil, -300, 500, nil)
+ single = bres.responses[0]
+ der = single.to_der
+ asn1 = OpenSSL::ASN1.decode(der)
+ assert_equal :CONTEXT_SPECIFIC, asn1.value[1].tag_class
+ assert_equal 0, asn1.value[1].tag # good
+ assert_equal der, OpenSSL::OCSP::SingleResponse.new(der).to_der
+ end
+
+ def test_single_response_check_validity
+ bres = OpenSSL::OCSP::BasicResponse.new
+ cid1 = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new)
+ cid2 = OpenSSL::OCSP::CertificateId.new(@cert2, @ca_cert, OpenSSL::Digest::SHA1.new)
+ bres.add_status(cid1, OpenSSL::OCSP::V_CERTSTATUS_REVOKED, OpenSSL::OCSP::REVOKED_STATUS_UNSPECIFIED, -400, -300, -50, [])
+ bres.add_status(cid2, OpenSSL::OCSP::V_CERTSTATUS_REVOKED, OpenSSL::OCSP::REVOKED_STATUS_UNSPECIFIED, -400, -300, nil, [])
+
+ single1 = bres.responses[0]
+ assert_equal false, single1.check_validity
+ assert_equal false, single1.check_validity(30)
+ assert_equal true, single1.check_validity(60)
+ single2 = bres.responses[1]
+ assert_equal true, single2.check_validity
+ assert_equal true, single2.check_validity(0, 500)
+ assert_equal false, single2.check_validity(0, 200)
+ end
+
+ def test_response_der
+ bres = OpenSSL::OCSP::BasicResponse.new
+ cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new)
+ bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, 0, nil, -300, 500, [])
+ bres.sign(@cert2, @key2, [@ca_cert], 0)
+ res = OpenSSL::OCSP::Response.create(OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL, bres)
+ der = res.to_der
+ asn1 = OpenSSL::ASN1.decode(der)
+ assert_equal OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL, asn1.value[0].value
+ assert_equal OpenSSL::ASN1.ObjectId("basicOCSPResponse").to_der, asn1.value[1].value[0].value[0].to_der
+ assert_equal bres.to_der, asn1.value[1].value[0].value[1].value
+ assert_equal der, OpenSSL::OCSP::Response.new(der).to_der
+ end
+
+ def test_response_dup
+ bres = OpenSSL::OCSP::BasicResponse.new
+ bres.sign(@cert2, @key2, [@ca_cert], 0)
+ res = OpenSSL::OCSP::Response.create(OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL, bres)
+ assert_equal res.to_der, res.dup.to_der
end
end
diff --git a/test/test_pair.rb b/test/test_pair.rb
index 88e52a71..575cb6c1 100644
--- a/test/test_pair.rb
+++ b/test/test_pair.rb
@@ -433,7 +433,12 @@ module OpenSSL::TestPairM
sock1, sock2 = tcp_pair
ctx1 = OpenSSL::SSL::SSLContext.new
- ctx1.ciphers = "ECDH"
+ begin
+ ctx1.ciphers = "ECDH"
+ rescue OpenSSL::SSL::SSLError
+ pend "ECDH is not enabled in this OpenSSL" if $!.message =~ /no cipher match/
+ raise
+ end
ctx1.ecdh_curves = "P-384:P-521"
ctx1.security_level = 0
s1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx1)
diff --git a/test/test_pkey_dh.rb b/test/test_pkey_dh.rb
index afd7a318..4d84f7ad 100644
--- a/test/test_pkey_dh.rb
+++ b/test/test_pkey_dh.rb
@@ -83,6 +83,16 @@ YoaOffgTf5qxiwkjnlVZQc3whgnEt9FpVMvQ9eknyeGB5KHfayAc3+hUAvI3/Cr3
assert_equal(dh.compute_key(dh2.pub_key), dh2.compute_key(dh.pub_key))
end
+ def test_dup
+ dh = OpenSSL::PKey::DH.new(NEW_KEYLEN)
+ dh2 = dh.dup
+ assert_equal dh.to_der, dh2.to_der # params
+ assert_equal_params dh, dh2 # keys
+ dh2.set_pqg(dh2.p + 1, nil, dh2.g)
+ assert_not_equal dh2.p, dh.p
+ assert_equal dh2.g, dh.g
+ end
+
private
def assert_equal_params(dh1, dh2)
diff --git a/test/test_pkey_dsa.rb b/test/test_pkey_dsa.rb
index 211c0342..9c29c034 100644
--- a/test/test_pkey_dsa.rb
+++ b/test/test_pkey_dsa.rb
@@ -230,6 +230,14 @@ YNMbNw==
assert(key3.private?)
end
+ def test_dup
+ key = OpenSSL::PKey::DSA.new(256)
+ key2 = key.dup
+ assert_equal key.params, key2.params
+ key2.set_pqg(key2.p + 1, key2.q, key2.g)
+ assert_not_equal key.params, key2.params
+ end
+
private
def check_sign_verify(digest)
diff --git a/test/test_pkey_ec.rb b/test/test_pkey_ec.rb
index e05b70ac..4498b2b8 100644
--- a/test/test_pkey_ec.rb
+++ b/test/test_pkey_ec.rb
@@ -14,17 +14,40 @@ class OpenSSL::TestEC < OpenSSL::TestCase
OpenSSL::PKey::EC.builtin_curves.each do |curve, comment|
group = OpenSSL::PKey::EC::Group.new(curve)
- key = OpenSSL::PKey::EC.new(group)
- key.generate_key!
-
# Oakley curves and X25519 are not suitable for signing
next if ["Oakley", "X25519"].any? { |n| curve.start_with?(n) }
+ key = OpenSSL::PKey::EC.new(group)
+ key.generate_key!
+
@groups << group
@keys << key
end
end
+ def test_dup
+ key = OpenSSL::PKey::EC.new("prime256v1")
+ key.generate_key!
+ key2 = key.dup
+ assert_equal key.to_der, key2.to_der
+ key_tmp = OpenSSL::PKey::EC.new("prime256v1").generate_key!
+ key2.private_key = key_tmp.private_key
+ key2.public_key = key_tmp.public_key
+ assert_not_equal key.to_der, key2.to_der
+
+ group = key.group
+ group2 = group.dup
+ assert_equal group.to_der, group2.to_der
+ group2.asn1_flag ^= OpenSSL::PKey::EC::NAMED_CURVE
+ assert_not_equal group.to_der, group2.to_der
+
+ point = key.public_key
+ point2 = point.dup
+ assert_equal point.to_bn, point2.to_bn
+ point2.invert!
+ assert_not_equal point.to_bn, point2.to_bn
+ end
+
def compare_keys(k1, k2)
assert_equal(k1.to_pem, k2.to_pem)
end
diff --git a/test/test_pkey_rsa.rb b/test/test_pkey_rsa.rb
index c3532f63..49e8ceac 100644
--- a/test/test_pkey_rsa.rb
+++ b/test/test_pkey_rsa.rb
@@ -294,6 +294,14 @@ AwEAAQ==
assert(key3.private?)
end
+ def test_dup
+ key = OpenSSL::PKey::RSA.generate(256, 17)
+ key2 = key.dup
+ assert_equal key.params, key2.params
+ key2.set_key(key2.n, 3, key2.d)
+ assert_not_equal key.params, key2.params
+ end
+
private
def check_PUBKEY(asn1, key)
diff --git a/test/utils.rb b/test/utils.rb
index 88a02391..5cd772e7 100644
--- a/test/utils.rb
+++ b/test/utils.rb
@@ -299,7 +299,10 @@ AQjjxMXhwULlmuR/K+WwlaZPiLIBYalLAZQ7ZbOPeVkJ8ePao0eLAgEC
ctx.cert = @svr_cert
ctx.key = @svr_key
ctx.tmp_dh_callback = proc { OpenSSL::TestUtils::TEST_KEY_DH1024 }
- ctx.ecdh_curves = "P-256"
+ begin
+ ctx.ecdh_curves = "P-256"
+ rescue NotImplementedError
+ end
ctx.verify_mode = verify_mode
ctx_proc.call(ctx) if ctx_proc