diff --git a/ext/openssl/ossl.c b/ext/openssl/ossl.c index 0cc88c7b9..2b48586b8 100644 --- a/ext/openssl/ossl.c +++ b/ext/openssl/ossl.c @@ -613,13 +613,13 @@ static void Init_ossl_locks(void) * * A key can also be loaded from a file. * - * key2 = OpenSSL::PKey::RSA.new File.read 'private_key.pem' + * key2 = OpenSSL::PKey.read File.read 'private_key.pem' * key2.public? # => true * key2.private? # => true * * or * - * key3 = OpenSSL::PKey::RSA.new File.read 'public_key.pem' + * key3 = OpenSSL::PKey.read File.read 'public_key.pem' * key3.public? # => true * key3.private? # => false * @@ -631,7 +631,7 @@ static void Init_ossl_locks(void) * * key4_pem = File.read 'private.secure.pem' * pass_phrase = 'my secure pass phrase goes here' - * key4 = OpenSSL::PKey::RSA.new key4_pem, pass_phrase + * key4 = OpenSSL::PKey.read key4_pem, pass_phrase * * == RSA Encryption * diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c index 479903191..df0a12636 100644 --- a/ext/openssl/ossl_pkey.c +++ b/ext/openssl/ossl_pkey.c @@ -73,7 +73,7 @@ const rb_data_type_t ossl_evp_pkey_type = { static VALUE pkey_new0(EVP_PKEY *pkey) { - VALUE obj; + VALUE klass, obj; int type; if (!pkey || (type = EVP_PKEY_base_id(pkey)) == EVP_PKEY_NONE) @@ -81,26 +81,32 @@ pkey_new0(EVP_PKEY *pkey) switch (type) { #if !defined(OPENSSL_NO_RSA) - case EVP_PKEY_RSA: - return ossl_rsa_new(pkey); + case EVP_PKEY_RSA: + klass = cRSA; + break; #endif #if !defined(OPENSSL_NO_DSA) - case EVP_PKEY_DSA: - return ossl_dsa_new(pkey); + case EVP_PKEY_DSA: + klass = cDSA; + break; #endif #if !defined(OPENSSL_NO_DH) - case EVP_PKEY_DH: - return ossl_dh_new(pkey); + case EVP_PKEY_DH: + klass = cDH; + break; #endif #if !defined(OPENSSL_NO_EC) - case EVP_PKEY_EC: - return ossl_ec_new(pkey); + case EVP_PKEY_EC: + klass = cEC; + break; #endif - default: - obj = NewPKey(cPKey); - SetPKey(obj, pkey); - return obj; + default: + klass = cPKey; } + + obj = NewPKey(klass); + SetPKey(obj, pkey); + return obj; } VALUE @@ -118,6 +124,39 @@ ossl_pkey_new(EVP_PKEY *pkey) return obj; } +EVP_PKEY * +ossl_do_read_pkey(VALUE data, VALUE pass) +{ + EVP_PKEY *pkey = NULL; + BIO *bio; + + pass = ossl_pem_passwd_value(pass); + + bio = ossl_obj2bio(data); + if ((pkey = d2i_PrivateKey_bio(bio, NULL))) + goto ok; + OSSL_BIO_reset(bio); + if ((pkey = d2i_PKCS8PrivateKey_bio(bio, NULL, ossl_pem_passwd_cb, (void *)pass))) + goto ok; + OSSL_BIO_reset(bio); + if ((pkey = d2i_PUBKEY_bio(bio, NULL))) + goto ok; + OSSL_BIO_reset(bio); + /* PEM_read_bio_PrivateKey() also parses PKCS #8 formats */ + if ((pkey = PEM_read_bio_PrivateKey(bio, NULL, ossl_pem_passwd_cb, (void *)pass))) + goto ok; + OSSL_BIO_reset(bio); + if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL))) + goto ok; + OSSL_BIO_reset(bio); + if ((pkey = PEM_read_bio_Parameters(bio, NULL))) + goto ok; + +ok: + BIO_free(bio); + return pkey; +} + /* * call-seq: * OpenSSL::PKey.read(string [, pwd ]) -> PKey @@ -138,29 +177,226 @@ static VALUE ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self) { EVP_PKEY *pkey; - BIO *bio; VALUE data, pass; rb_scan_args(argc, argv, "11", &data, &pass); - pass = ossl_pem_passwd_value(pass); + pkey = ossl_do_read_pkey(data, pass); + if (!pkey) + ossl_raise(ePKeyError, "Could not parse PKey"); - bio = ossl_obj2bio(data); - if (!(pkey = d2i_PrivateKey_bio(bio, NULL))) { - OSSL_BIO_reset(bio); - if (!(pkey = PEM_read_bio_PrivateKey(bio, NULL, ossl_pem_passwd_cb, (void *)pass))) { - OSSL_BIO_reset(bio); - if (!(pkey = d2i_PUBKEY_bio(bio, NULL))) { - OSSL_BIO_reset(bio); - pkey = PEM_read_bio_PUBKEY(bio, NULL, ossl_pem_passwd_cb, (void *)pass); - } + return ossl_pkey_new(pkey); +} + +static VALUE +pkey_gen_apply_options_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ctx_v)) +{ + VALUE key = rb_ary_entry(i, 0), value = rb_ary_entry(i, 1); + EVP_PKEY_CTX *ctx = (EVP_PKEY_CTX *)ctx_v; + + if (SYMBOL_P(key)) + key = rb_sym2str(key); + if (RB_INTEGER_TYPE_P(value)) + value = rb_String(value); + + if (EVP_PKEY_CTX_ctrl_str(ctx, StringValueCStr(key), StringValueCStr(value)) <= 0) + ossl_raise(ePKeyError, "EVP_PKEY_CTX_ctrl_str(ctx, %+"PRIsVALUE", %+"PRIsVALUE")", + key, value); + return Qnil; +} + +static VALUE +pkey_gen_apply_options0(VALUE args_v) +{ + VALUE *args = (VALUE *)args_v; + + rb_block_call(args[1], rb_intern("each"), 0, NULL, + pkey_gen_apply_options_i, args[0]); + return Qnil; +} + +struct pkey_blocking_generate_arg { + EVP_PKEY_CTX *ctx; + EVP_PKEY *pkey; + int state; + int yield: 1; + int genparam: 1; + int stop: 1; +}; + +static int +pkey_gen_cb(EVP_PKEY_CTX *ctx) +{ + struct pkey_blocking_generate_arg *arg = EVP_PKEY_CTX_get_app_data(ctx); + + if (arg->yield) { + VALUE ary; + int state, i, info_num = EVP_PKEY_CTX_get_keygen_info(ctx, -1); + + ary = rb_ary_new2(info_num); + for (i = 0; i < info_num; i++) + rb_ary_store(ary, i, INT2NUM(EVP_PKEY_CTX_get_keygen_info(ctx, i))); + + /* + * can be break by raising exception or 'break' + */ + rb_protect(rb_yield, ary, &state); + if (state) { + arg->stop = 1; + arg->state = state; } } + if (arg->stop) + return 0; + return 1; +} - BIO_free(bio); - if (!pkey) - ossl_raise(ePKeyError, "Could not parse PKey"); +static void +pkey_blocking_gen_stop(void *ptr) +{ + struct pkey_blocking_generate_arg *arg = ptr; + arg->stop = 1; +} - return ossl_pkey_new(pkey); +static void * +pkey_blocking_gen(void *ptr) +{ + struct pkey_blocking_generate_arg *arg = ptr; + + if (arg->genparam && EVP_PKEY_paramgen(arg->ctx, &arg->pkey) <= 0) + return NULL; + if (!arg->genparam && EVP_PKEY_keygen(arg->ctx, &arg->pkey) <= 0) + return NULL; + return arg->pkey; +} + +static VALUE +pkey_generate(int argc, VALUE *argv, VALUE self, int genparam) +{ + EVP_PKEY_CTX *ctx; + VALUE alg, options; + struct pkey_blocking_generate_arg gen_arg = { 0 }; + int state; + + rb_scan_args(argc, argv, "11", &alg, &options); + if (rb_obj_is_kind_of(alg, cPKey)) { + EVP_PKEY *base_pkey; + + GetPKey(alg, base_pkey); + ctx = EVP_PKEY_CTX_new(base_pkey, NULL/* engine */); + if (!ctx) + ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); + } + else { + const EVP_PKEY_ASN1_METHOD *ameth; + ENGINE *tmpeng; + int pkey_id; + + StringValue(alg); + ameth = EVP_PKEY_asn1_find_str(&tmpeng, RSTRING_PTR(alg), RSTRING_LENINT(alg)); + if (!ameth) + ossl_raise(ePKeyError, "algorithm %"PRIsVALUE" not found", alg); + EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth); +#if !defined(OPENSSL_NO_ENGINE) + if (tmpeng) + ENGINE_finish(tmpeng); +#endif + + ctx = EVP_PKEY_CTX_new_id(pkey_id, NULL/* engine */); + if (!ctx) + ossl_raise(ePKeyError, "EVP_PKEY_CTX_new_id"); + } + + if ((genparam ? EVP_PKEY_paramgen_init(ctx) : EVP_PKEY_keygen_init(ctx)) <= 0) { + EVP_PKEY_CTX_free(ctx); + ossl_raise(ePKeyError, genparam ? "EVP_PKEY_paramgen_init" : "EVP_PKEY_keygen_init"); + } + + if (!NIL_P(options)) { + VALUE args[2]; + + args[0] = (VALUE)ctx; + args[1] = options; + rb_protect(pkey_gen_apply_options0, (VALUE)args, &state); + if (state) { + EVP_PKEY_CTX_free(ctx); + rb_jump_tag(state); + } + } + + gen_arg.genparam = genparam; + gen_arg.ctx = ctx; + gen_arg.yield = rb_block_given_p(); + EVP_PKEY_CTX_set_app_data(ctx, &gen_arg); + EVP_PKEY_CTX_set_cb(ctx, pkey_gen_cb); + if (gen_arg.yield) + pkey_blocking_gen(&gen_arg); + else + rb_thread_call_without_gvl(pkey_blocking_gen, &gen_arg, + pkey_blocking_gen_stop, &gen_arg); + EVP_PKEY_CTX_free(ctx); + if (!gen_arg.pkey) { + if (gen_arg.state) { + ossl_clear_error(); + rb_jump_tag(gen_arg.state); + } + else { + ossl_raise(ePKeyError, genparam ? "EVP_PKEY_paramgen" : "EVP_PKEY_keygen"); + } + } + + return ossl_pkey_new(gen_arg.pkey); +} + +/* + * call-seq: + * OpenSSL::PKey.generate_parameters(algo_name [, options]) -> pkey + * + * Generates new parameters for the algorithm. _algo_name_ is a String that + * represents the algorithm. The optional argument _options_ is a Hash that + * specifies the options specific to the algorithm. The order of the options + * can be important. + * + * A block can be passed optionally. The meaning of the arguments passed to + * the block varies depending on the implementation of the algorithm. The block + * may be called once or multiple times, or may not even be called. + * + * For the supported options, see the documentation for the 'openssl genpkey' + * utility command. + * + * == Example + * pkey = OpenSSL::PKey.generate_parameters("DSA", "dsa_paramgen_bits" => 2048) + * p pkey.p.num_bits #=> 2048 + */ +static VALUE +ossl_pkey_s_generate_parameters(int argc, VALUE *argv, VALUE self) +{ + return pkey_generate(argc, argv, self, 1); +} + +/* + * call-seq: + * OpenSSL::PKey.generate_key(algo_name [, options]) -> pkey + * OpenSSL::PKey.generate_key(pkey [, options]) -> pkey + * + * Generates a new key (pair). + * + * If a String is given as the first argument, it generates a new random key + * for the algorithm specified by the name just as ::generate_parameters does. + * If an OpenSSL::PKey::PKey is given instead, it generates a new random key + * for the same algorithm as the key, using the parameters the key contains. + * + * See ::generate_parameters for the details of _options_ and the given block. + * + * == Example + * pkey_params = OpenSSL::PKey.generate_parameters("DSA", "dsa_paramgen_bits" => 2048) + * pkey_params.priv_key #=> nil + * pkey = OpenSSL::PKey.generate_key(pkey_params) + * pkey.priv_key #=> # 0) { + /* + * TODO: EncryptedPrivateKeyInfo actually has more options. + * Should they be exposed? + */ + enc = GetCipherPtr(cipher); + pass = ossl_pem_passwd_value(pass); + } + + bio = BIO_new(BIO_s_mem()); + if (!bio) + ossl_raise(ePKeyError, "BIO_new"); + if (to_der) { + if (!i2d_PKCS8PrivateKey_bio(bio, pkey, enc, NULL, 0, + ossl_pem_passwd_cb, (void *)pass)) { + BIO_free(bio); + ossl_raise(ePKeyError, "i2d_PKCS8PrivateKey_bio"); + } + } + else { + if (!PEM_write_bio_PKCS8PrivateKey(bio, pkey, enc, NULL, 0, + ossl_pem_passwd_cb, (void *)pass)) { + BIO_free(bio); + ossl_raise(ePKeyError, "PEM_write_bio_PKCS8PrivateKey"); + } + } + return ossl_membio2str(bio); +} + +/* + * call-seq: + * pkey.private_to_der -> string + * pkey.private_to_der(cipher, password) -> string + * + * Serializes the private key to DER-encoded PKCS #8 format. If called without + * arguments, unencrypted PKCS #8 PrivateKeyInfo format is used. If called with + * a cipher name and a password, PKCS #8 EncryptedPrivateKeyInfo format with + * PBES2 encryption scheme is used. + */ +static VALUE +ossl_pkey_private_to_der(int argc, VALUE *argv, VALUE self) +{ + return do_pkcs8_export(argc, argv, self, 1); +} + +/* + * call-seq: + * pkey.private_to_pem -> string + * pkey.private_to_pem(cipher, password) -> string + * + * Serializes the private key to PEM-encoded PKCS #8 format. See #private_to_der + * for more details. + */ +static VALUE +ossl_pkey_private_to_pem(int argc, VALUE *argv, VALUE self) +{ + return do_pkcs8_export(argc, argv, self, 0); +} + +VALUE +ossl_do_spki_export(VALUE self, int to_der) +{ + EVP_PKEY *pkey; + BIO *bio; + + GetPKey(self, pkey); + bio = BIO_new(BIO_s_mem()); + if (!bio) + ossl_raise(ePKeyError, "BIO_new"); + if (to_der) { + if (!i2d_PUBKEY_bio(bio, pkey)) { + BIO_free(bio); + ossl_raise(ePKeyError, "i2d_PUBKEY_bio"); + } + } + else { + if (!PEM_write_bio_PUBKEY(bio, pkey)) { + BIO_free(bio); + ossl_raise(ePKeyError, "PEM_write_bio_PUBKEY"); + } + } + return ossl_membio2str(bio); +} + +VALUE +ossl_do_traditional_export(int argc, VALUE *argv, VALUE self, int to_der) +{ + EVP_PKEY *pkey; + VALUE cipher, pass; + const EVP_CIPHER *enc = NULL; + BIO *bio; + + GetPKey(self, pkey); + rb_scan_args(argc, argv, "02", &cipher, &pass); + if (!NIL_P(cipher)) { + enc = GetCipherPtr(cipher); + pass = ossl_pem_passwd_value(pass); + } + + bio = BIO_new(BIO_s_mem()); + if (!bio) + ossl_raise(ePKeyError, "BIO_new"); + if (to_der) { + if (!i2d_PrivateKey_bio(bio, pkey)) { + BIO_free(bio); + ossl_raise(ePKeyError, "i2d_PrivateKey_bio"); + } + } + else { +#if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER) + if (!PEM_write_bio_PrivateKey_traditional(bio, pkey, enc, NULL, 0, + ossl_pem_passwd_cb, (void *)pass)) { +#else + char pem_str[80]; + const char *aname; + + EVP_PKEY_asn1_get0_info(NULL, NULL, NULL, NULL, &aname, pkey->ameth); + snprintf(pem_str, sizeof(pem_str), "%s PRIVATE KEY", aname); + if (!PEM_ASN1_write_bio((i2d_of_void *)i2d_PrivateKey, pem_str, bio, + pkey, enc, NULL, 0, ossl_pem_passwd_cb, (void *)pass)) { +#endif + BIO_free(bio); + ossl_raise(ePKeyError, "PEM_write_bio_PrivateKey_traditional"); + } + } + return ossl_membio2str(bio); +} + +/* + * call-seq: + * pkey.public_to_der -> string + * + * Serializes the public key to DER-encoded X.509 SubjectPublicKeyInfo format. + */ +static VALUE +ossl_pkey_public_to_der(VALUE self) +{ + return ossl_do_spki_export(self, 1); +} + +/* + * call-seq: + * pkey.public_to_pem -> string + * + * Serializes the public key to PEM-encoded X.509 SubjectPublicKeyInfo format. + */ +static VALUE +ossl_pkey_public_to_pem(VALUE self) +{ + return ossl_do_spki_export(self, 0); +} + /* * call-seq: * pkey.sign(digest, data) -> String @@ -382,6 +780,53 @@ ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data) } } +/* + * call-seq: + * pkey.derive(peer_pkey) -> string + * + * Derives a shared secret from _pkey_ and _peer_pkey_. _pkey_ must contain + * the private components, _peer_pkey_ must contain the public components. + */ +static VALUE +ossl_pkey_derive(int argc, VALUE *argv, VALUE self) +{ + EVP_PKEY *pkey, *peer_pkey; + EVP_PKEY_CTX *ctx; + VALUE peer_pkey_obj, str; + size_t keylen; + + GetPKey(self, pkey); + rb_scan_args(argc, argv, "1", &peer_pkey_obj); + SafeGetPKey(peer_pkey_obj, peer_pkey); + + ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL); + if (!ctx) + ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); + if (EVP_PKEY_derive_init(ctx) <= 0) { + EVP_PKEY_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_PKEY_derive_init"); + } + if (EVP_PKEY_derive_set_peer(ctx, peer_pkey) <= 0) { + EVP_PKEY_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_PKEY_derive_set_peer"); + } + + if (EVP_PKEY_derive(ctx, NULL, &keylen) <= 0) { + EVP_PKEY_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_PKEY_derive"); + } + /* FIXME: memleak of |ctx| */ + assert(keylen <= LONG_MAX); + str = rb_str_new(NULL, (long)keylen); + if (EVP_PKEY_derive(ctx, (unsigned char *)RSTRING_PTR(str), &keylen) <= 0) { + EVP_PKEY_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_PKEY_derive"); + } + rb_str_set_len(str, (long)keylen); + EVP_PKEY_CTX_free(ctx); + return str; +} + /* * INIT */ @@ -464,14 +909,21 @@ Init_ossl_pkey(void) cPKey = rb_define_class_under(mPKey, "PKey", rb_cObject); rb_define_module_function(mPKey, "read", ossl_pkey_new_from_data, -1); + rb_define_module_function(mPKey, "generate_parameters", ossl_pkey_s_generate_parameters, -1); + rb_define_module_function(mPKey, "generate_key", ossl_pkey_s_generate_key, -1); rb_define_alloc_func(cPKey, ossl_pkey_alloc); rb_define_method(cPKey, "initialize", ossl_pkey_initialize, 0); + rb_define_method(cPKey, "private_to_der", ossl_pkey_private_to_der, -1); + rb_define_method(cPKey, "private_to_pem", ossl_pkey_private_to_pem, -1); + rb_define_method(cPKey, "public_to_der", ossl_pkey_public_to_der, 0); + rb_define_method(cPKey, "public_to_pem", ossl_pkey_public_to_pem, 0); rb_define_method(cPKey, "sign", ossl_pkey_sign, 2); rb_define_method(cPKey, "verify", ossl_pkey_verify, 3); + rb_define_method(cPKey, "derive", ossl_pkey_derive, -1); - id_private_q = rb_intern("private?"); + id_private_q = rb_intern_const("private?"); /* * INIT rsa, dsa, dh, ec diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h index e3b723cd6..47d3d9cc5 100644 --- a/ext/openssl/ossl_pkey.h +++ b/ext/openssl/ossl_pkey.h @@ -47,6 +47,22 @@ struct ossl_generate_cb_arg { int ossl_generate_cb_2(int p, int n, BN_GENCB *cb); void ossl_generate_cb_stop(void *ptr); +/* + * Serializes _self_ into X.509 SubjectPublicKeyInfo format and returns the + * resulting String. Sub-classes use this when overriding #to_der. + */ +VALUE ossl_do_spki_export(VALUE self, int to_der); +/* + * Serializes _self_ into the traditional format and returns the resulting + * String. Sub-classes use this when overriding #to_der. + */ +VALUE ossl_do_traditional_export(int argc, VALUE *argv, VALUE self, int to_der); +/* + * Reads a pkey and returns an EVP_PKEY, or NULL if cannot be parsed. It may + * raise an exception. + */ +EVP_PKEY *ossl_do_read_pkey(VALUE data, VALUE pass); + VALUE ossl_pkey_new(EVP_PKEY *); EVP_PKEY *GetPKeyPtr(VALUE); EVP_PKEY *DupPKeyPtr(VALUE); @@ -59,7 +75,6 @@ void Init_ossl_pkey(void); extern VALUE cRSA; extern VALUE eRSAError; -VALUE ossl_rsa_new(EVP_PKEY *); void Init_ossl_rsa(void); /* @@ -68,7 +83,6 @@ void Init_ossl_rsa(void); extern VALUE cDSA; extern VALUE eDSAError; -VALUE ossl_dsa_new(EVP_PKEY *); void Init_ossl_dsa(void); /* @@ -77,7 +91,6 @@ void Init_ossl_dsa(void); extern VALUE cDH; extern VALUE eDHError; -VALUE ossl_dh_new(EVP_PKEY *); void Init_ossl_dh(void); /* diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c index 48e898b5f..826f4e490 100644 --- a/ext/openssl/ossl_pkey_dh.c +++ b/ext/openssl/ossl_pkey_dh.c @@ -29,52 +29,6 @@ VALUE cDH; VALUE eDHError; -/* - * Public - */ -static VALUE -dh_instance(VALUE klass, DH *dh) -{ - EVP_PKEY *pkey; - VALUE obj; - - if (!dh) { - return Qfalse; - } - obj = NewPKey(klass); - if (!(pkey = EVP_PKEY_new())) { - return Qfalse; - } - if (!EVP_PKEY_assign_DH(pkey, dh)) { - EVP_PKEY_free(pkey); - return Qfalse; - } - SetPKey(obj, pkey); - - return obj; -} - -VALUE -ossl_dh_new(EVP_PKEY *pkey) -{ - VALUE obj; - - if (!pkey) { - obj = dh_instance(cDH, DH_new()); - } else { - obj = NewPKey(cDH); - if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DH) { - ossl_raise(rb_eTypeError, "Not a DH key!"); - } - SetPKey(obj, pkey); - } - if (obj == Qfalse) { - ossl_raise(eDHError, NULL); - } - - return obj; -} - /* * Private */ @@ -105,7 +59,7 @@ dh_generate(int size, int gen) if (!dh || !cb) { DH_free(dh); BN_GENCB_free(cb); - return NULL; + ossl_raise(eDHError, "malloc failure"); } if (rb_block_given_p()) @@ -131,12 +85,12 @@ dh_generate(int size, int gen) ossl_clear_error(); rb_jump_tag(cb_arg.state); } - return NULL; + ossl_raise(eDHError, "DH_generate_parameters_ex"); } if (!DH_generate_key(dh)) { DH_free(dh); - return NULL; + ossl_raise(eDHError, "DH_generate_key"); } return dh; @@ -157,6 +111,7 @@ dh_generate(int size, int gen) static VALUE ossl_dh_s_generate(int argc, VALUE *argv, VALUE klass) { + EVP_PKEY *pkey; DH *dh ; int g = 2; VALUE size, gen, obj; @@ -164,13 +119,14 @@ ossl_dh_s_generate(int argc, VALUE *argv, VALUE klass) if (rb_scan_args(argc, argv, "11", &size, &gen) == 2) { g = NUM2INT(gen); } + obj = rb_obj_alloc(klass); + GetPKey(obj, pkey); + dh = dh_generate(NUM2INT(size), g); - obj = dh_instance(klass, dh); - if (obj == Qfalse) { + if (!EVP_PKEY_assign_DH(pkey, dh)) { DH_free(dh); - ossl_raise(eDHError, NULL); + ossl_raise(eDHError, "EVP_PKEY_assign_DH"); } - return obj; } @@ -455,17 +411,21 @@ ossl_dh_to_text(VALUE self) static VALUE ossl_dh_to_public_key(VALUE self) { + EVP_PKEY *pkey; DH *orig_dh, *dh; VALUE obj; + obj = rb_obj_alloc(rb_obj_class(self)); + GetPKey(obj, pkey); + GetDH(self, orig_dh); - dh = DHparams_dup(orig_dh); /* err check perfomed by dh_instance */ - obj = dh_instance(rb_obj_class(self), dh); - if (obj == Qfalse) { + dh = DHparams_dup(orig_dh); + if (!dh) + ossl_raise(eDHError, "DHparams_dup"); + if (!EVP_PKEY_assign_DH(pkey, dh)) { DH_free(dh); - ossl_raise(eDHError, NULL); + ossl_raise(eDHError, "EVP_PKEY_assign_DH"); } - return obj; } @@ -518,40 +478,6 @@ ossl_dh_generate_key(VALUE self) return self; } -/* - * call-seq: - * dh.compute_key(pub_bn) -> aString - * - * Returns a String containing a shared secret computed from the other party's public value. - * See DH_compute_key() for further information. - * - * === Parameters - * * _pub_bn_ is a OpenSSL::BN, *not* the DH instance returned by - * DH#public_key as that contains the DH parameters only. - */ -static VALUE -ossl_dh_compute_key(VALUE self, VALUE pub) -{ - DH *dh; - const BIGNUM *pub_key, *dh_p; - VALUE str; - int len; - - GetDH(self, dh); - DH_get0_pqg(dh, &dh_p, NULL, NULL); - if (!dh_p) - ossl_raise(eDHError, "incomplete DH"); - pub_key = GetBNPtr(pub); - len = DH_size(dh); - str = rb_str_new(0, len); - if ((len = DH_compute_key((unsigned char *)RSTRING_PTR(str), pub_key, dh)) < 0) { - ossl_raise(eDHError, NULL); - } - rb_str_set_len(str, len); - - return str; -} - /* * Document-method: OpenSSL::PKey::DH#set_pqg * call-seq: @@ -629,7 +555,6 @@ Init_ossl_dh(void) rb_define_method(cDH, "public_key", ossl_dh_to_public_key, 0); rb_define_method(cDH, "params_ok?", ossl_dh_check_params, 0); rb_define_method(cDH, "generate_key!", ossl_dh_generate_key, 0); - rb_define_method(cDH, "compute_key", ossl_dh_compute_key, 1); DEF_OSSL_PKEY_BN(cDH, dh, p); DEF_OSSL_PKEY_BN(cDH, dh, q); diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c index 53d5c8d96..0540859f8 100644 --- a/ext/openssl/ossl_pkey_dsa.c +++ b/ext/openssl/ossl_pkey_dsa.c @@ -43,52 +43,6 @@ DSA_PRIVATE(VALUE obj, DSA *dsa) VALUE cDSA; VALUE eDSAError; -/* - * Public - */ -static VALUE -dsa_instance(VALUE klass, DSA *dsa) -{ - EVP_PKEY *pkey; - VALUE obj; - - if (!dsa) { - return Qfalse; - } - obj = NewPKey(klass); - if (!(pkey = EVP_PKEY_new())) { - return Qfalse; - } - if (!EVP_PKEY_assign_DSA(pkey, dsa)) { - EVP_PKEY_free(pkey); - return Qfalse; - } - SetPKey(obj, pkey); - - return obj; -} - -VALUE -ossl_dsa_new(EVP_PKEY *pkey) -{ - VALUE obj; - - if (!pkey) { - obj = dsa_instance(cDSA, DSA_new()); - } else { - obj = NewPKey(cDSA); - if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DSA) { - ossl_raise(rb_eTypeError, "Not a DSA key!"); - } - SetPKey(obj, pkey); - } - if (obj == Qfalse) { - ossl_raise(eDSAError, NULL); - } - - return obj; -} - /* * Private */ @@ -123,7 +77,7 @@ dsa_generate(int size) if (!dsa || !cb) { DSA_free(dsa); BN_GENCB_free(cb); - return NULL; + ossl_raise(eDSAError, "malloc failure"); } if (rb_block_given_p()) @@ -153,12 +107,12 @@ dsa_generate(int size) ossl_clear_error(); rb_jump_tag(cb_arg.state); } - return NULL; + ossl_raise(eDSAError, "DSA_generate_parameters_ex"); } if (!DSA_generate_key(dsa)) { DSA_free(dsa); - return NULL; + ossl_raise(eDSAError, "DSA_generate_key"); } return dsa; @@ -178,14 +132,18 @@ dsa_generate(int size) static VALUE ossl_dsa_s_generate(VALUE klass, VALUE size) { - DSA *dsa = dsa_generate(NUM2INT(size)); /* err handled by dsa_instance */ - VALUE obj = dsa_instance(klass, dsa); + EVP_PKEY *pkey; + DSA *dsa; + VALUE obj; - if (obj == Qfalse) { + obj = rb_obj_alloc(klass); + GetPKey(obj, pkey); + + dsa = dsa_generate(NUM2INT(size)); + if (!EVP_PKEY_assign_DSA(pkey, dsa)) { DSA_free(dsa); - ossl_raise(eDSAError, NULL); + ossl_raise(eDSAError, "EVP_PKEY_assign_DSA"); } - return obj; } @@ -212,8 +170,8 @@ ossl_dsa_s_generate(VALUE klass, VALUE size) static VALUE ossl_dsa_initialize(int argc, VALUE *argv, VALUE self) { - EVP_PKEY *pkey; - DSA *dsa; + EVP_PKEY *pkey, *pkey_tmp; + DSA *dsa = NULL; BIO *in; VALUE arg, pass; @@ -227,30 +185,25 @@ ossl_dsa_initialize(int argc, VALUE *argv, VALUE self) } } else { - pass = ossl_pem_passwd_value(pass); arg = ossl_to_der_if_possible(arg); - in = ossl_obj2bio(arg); - dsa = PEM_read_bio_DSAPrivateKey(in, NULL, ossl_pem_passwd_cb, (void *)pass); - if (!dsa) { - OSSL_BIO_reset(in); - dsa = PEM_read_bio_DSA_PUBKEY(in, NULL, NULL, NULL); - } - if (!dsa) { - OSSL_BIO_reset(in); - dsa = d2i_DSAPrivateKey_bio(in, NULL); + pkey_tmp = ossl_do_read_pkey(arg, pass); + if (pkey_tmp) { + if (EVP_PKEY_base_id(pkey_tmp) == EVP_PKEY_DSA) { + dsa = EVP_PKEY_get0_DSA(pkey_tmp); + DSA_up_ref(dsa); + } + EVP_PKEY_free(pkey_tmp); } - if (!dsa) { - OSSL_BIO_reset(in); - dsa = d2i_DSA_PUBKEY_bio(in, NULL); - } - if (!dsa) { - OSSL_BIO_reset(in); + else { + ossl_clear_error(); + in = ossl_obj2bio(arg); #define PEM_read_bio_DSAPublicKey(bp,x,cb,u) (DSA *)PEM_ASN1_read_bio( \ (d2i_of_void *)d2i_DSAPublicKey, PEM_STRING_DSA_PUBLIC, (bp), (void **)(x), (cb), (u)) dsa = PEM_read_bio_DSAPublicKey(in, NULL, NULL, NULL); #undef PEM_read_bio_DSAPublicKey + BIO_free(in); } - BIO_free(in); + if (!dsa) { ossl_clear_error(); ossl_raise(eDSAError, "Neither PUB key nor PRIV key"); @@ -341,34 +294,12 @@ static VALUE ossl_dsa_export(int argc, VALUE *argv, VALUE self) { DSA *dsa; - BIO *out; - const EVP_CIPHER *ciph = NULL; - VALUE cipher, pass, str; GetDSA(self, dsa); - rb_scan_args(argc, argv, "02", &cipher, &pass); - if (!NIL_P(cipher)) { - ciph = GetCipherPtr(cipher); - pass = ossl_pem_passwd_value(pass); - } - if (!(out = BIO_new(BIO_s_mem()))) { - ossl_raise(eDSAError, NULL); - } - if (DSA_HAS_PRIVATE(dsa)) { - if (!PEM_write_bio_DSAPrivateKey(out, dsa, ciph, NULL, 0, - ossl_pem_passwd_cb, (void *)pass)){ - BIO_free(out); - ossl_raise(eDSAError, NULL); - } - } else { - if (!PEM_write_bio_DSA_PUBKEY(out, dsa)) { - BIO_free(out); - ossl_raise(eDSAError, NULL); - } - } - str = ossl_membio2str(out); - - return str; + if (DSA_HAS_PRIVATE(dsa)) + return ossl_do_traditional_export(argc, argv, self, 0); + else + return ossl_do_spki_export(self, 0); } /* @@ -382,25 +313,12 @@ static VALUE ossl_dsa_to_der(VALUE self) { DSA *dsa; - int (*i2d_func)(DSA *, unsigned char **); - unsigned char *p; - long len; - VALUE str; GetDSA(self, dsa); - if(DSA_HAS_PRIVATE(dsa)) - i2d_func = (int (*)(DSA *,unsigned char **))i2d_DSAPrivateKey; + if (DSA_HAS_PRIVATE(dsa)) + return ossl_do_traditional_export(0, NULL, self, 1); else - i2d_func = i2d_DSA_PUBKEY; - if((len = i2d_func(dsa, NULL)) <= 0) - ossl_raise(eDSAError, NULL); - str = rb_str_new(0, len); - p = (unsigned char *)RSTRING_PTR(str); - if(i2d_func(dsa, &p) < 0) - ossl_raise(eDSAError, NULL); - ossl_str_adjust(str, p); - - return str; + return ossl_do_spki_export(self, 1); } @@ -481,20 +399,23 @@ ossl_dsa_to_text(VALUE self) static VALUE ossl_dsa_to_public_key(VALUE self) { - EVP_PKEY *pkey; + EVP_PKEY *pkey, *pkey_new; DSA *dsa; VALUE obj; GetPKeyDSA(self, pkey); - /* err check performed by dsa_instance */ + obj = rb_obj_alloc(rb_obj_class(self)); + GetPKey(obj, pkey_new); + #define DSAPublicKey_dup(dsa) (DSA *)ASN1_dup( \ (i2d_of_void *)i2d_DSAPublicKey, (d2i_of_void *)d2i_DSAPublicKey, (char *)(dsa)) dsa = DSAPublicKey_dup(EVP_PKEY_get0_DSA(pkey)); #undef DSAPublicKey_dup - obj = dsa_instance(rb_obj_class(self), dsa); - if (obj == Qfalse) { + if (!dsa) + ossl_raise(eDSAError, "DSAPublicKey_dup"); + if (!EVP_PKEY_assign_DSA(pkey_new, dsa)) { DSA_free(dsa); - ossl_raise(eDSAError, NULL); + ossl_raise(eDSAError, "EVP_PKEY_assign_DSA"); } return obj; } diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c index f0e274610..f425606fb 100644 --- a/ext/openssl/ossl_pkey_ec.c +++ b/ext/openssl/ossl_pkey_ec.c @@ -75,47 +75,6 @@ static ID id_i_group; static VALUE ec_group_new(const EC_GROUP *group); static VALUE ec_point_new(const EC_POINT *point, const EC_GROUP *group); -static VALUE ec_instance(VALUE klass, EC_KEY *ec) -{ - EVP_PKEY *pkey; - VALUE obj; - - if (!ec) { - return Qfalse; - } - obj = NewPKey(klass); - if (!(pkey = EVP_PKEY_new())) { - return Qfalse; - } - if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) { - EVP_PKEY_free(pkey); - return Qfalse; - } - SetPKey(obj, pkey); - - return obj; -} - -VALUE ossl_ec_new(EVP_PKEY *pkey) -{ - VALUE obj; - - if (!pkey) { - obj = ec_instance(cEC, EC_KEY_new()); - } else { - obj = NewPKey(cEC); - if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC) { - ossl_raise(rb_eTypeError, "Not a EC key!"); - } - SetPKey(obj, pkey); - } - if (obj == Qfalse) { - ossl_raise(eECError, NULL); - } - - return obj; -} - /* * Creates a new EC_KEY on the EC group obj. arg can be an EC::Group or a String * representing an OID. @@ -162,17 +121,18 @@ ec_key_new_from_group(VALUE arg) static VALUE ossl_ec_key_s_generate(VALUE klass, VALUE arg) { + EVP_PKEY *pkey; EC_KEY *ec; VALUE obj; - ec = ec_key_new_from_group(arg); + obj = rb_obj_alloc(klass); + GetPKey(obj, pkey); - obj = ec_instance(klass, ec); - if (obj == Qfalse) { + ec = ec_key_new_from_group(arg); + if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) { EC_KEY_free(ec); - ossl_raise(eECError, NULL); + ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY"); } - if (!EC_KEY_generate_key(ec)) ossl_raise(eECError, "EC_KEY_generate_key"); @@ -192,7 +152,7 @@ ossl_ec_key_s_generate(VALUE klass, VALUE arg) */ static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self) { - EVP_PKEY *pkey; + EVP_PKEY *pkey, *pkey_tmp; EC_KEY *ec; VALUE arg, pass; @@ -214,27 +174,14 @@ static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self) } else if (rb_obj_is_kind_of(arg, cEC_GROUP)) { ec = ec_key_new_from_group(arg); } else { - BIO *in; - - pass = ossl_pem_passwd_value(pass); - in = ossl_obj2bio(arg); - - ec = PEM_read_bio_ECPrivateKey(in, NULL, ossl_pem_passwd_cb, (void *)pass); - if (!ec) { - OSSL_BIO_reset(in); - ec = PEM_read_bio_EC_PUBKEY(in, NULL, ossl_pem_passwd_cb, (void *)pass); - } - if (!ec) { - OSSL_BIO_reset(in); - ec = d2i_ECPrivateKey_bio(in, NULL); + pkey_tmp = ossl_do_read_pkey(arg, pass); + if (pkey_tmp && EVP_PKEY_base_id(pkey_tmp) == EVP_PKEY_EC) { + ec = EVP_PKEY_get0_EC_KEY(pkey_tmp); + EC_KEY_up_ref(ec); + EVP_PKEY_free(pkey_tmp); } - if (!ec) { - OSSL_BIO_reset(in); - ec = d2i_EC_PUBKEY_bio(in, NULL); - } - BIO_free(in); - - if (!ec) { + else { + EVP_PKEY_free(pkey_tmp); ossl_clear_error(); ec = ec_key_new_from_group(arg); } @@ -437,66 +384,6 @@ static VALUE ossl_ec_key_is_private(VALUE self) return EC_KEY_get0_private_key(ec) ? Qtrue : Qfalse; } -static VALUE ossl_ec_key_to_string(VALUE self, VALUE ciph, VALUE pass, int format) -{ - EC_KEY *ec; - BIO *out; - int i = -1; - int private = 0; - VALUE str; - const EVP_CIPHER *cipher = NULL; - - GetEC(self, ec); - - if (EC_KEY_get0_public_key(ec) == NULL) - ossl_raise(eECError, "can't export - no public key set"); - - if (EC_KEY_check_key(ec) != 1) - ossl_raise(eECError, "can't export - EC_KEY_check_key failed"); - - if (EC_KEY_get0_private_key(ec)) - private = 1; - - if (!NIL_P(ciph)) { - cipher = GetCipherPtr(ciph); - pass = ossl_pem_passwd_value(pass); - } - - if (!(out = BIO_new(BIO_s_mem()))) - ossl_raise(eECError, "BIO_new(BIO_s_mem())"); - - switch(format) { - case EXPORT_PEM: - if (private) { - i = PEM_write_bio_ECPrivateKey(out, ec, cipher, NULL, 0, ossl_pem_passwd_cb, (void *)pass); - } else { - i = PEM_write_bio_EC_PUBKEY(out, ec); - } - - break; - case EXPORT_DER: - if (private) { - i = i2d_ECPrivateKey_bio(out, ec); - } else { - i = i2d_EC_PUBKEY_bio(out, ec); - } - - break; - default: - BIO_free(out); - ossl_raise(rb_eRuntimeError, "unknown format (internal error)"); - } - - if (i != 1) { - BIO_free(out); - ossl_raise(eECError, "outlen=%d", i); - } - - str = ossl_membio2str(out); - - return str; -} - /* * call-seq: * key.export([cipher, pass_phrase]) => String @@ -509,9 +396,13 @@ static VALUE ossl_ec_key_to_string(VALUE self, VALUE ciph, VALUE pass, int forma */ static VALUE ossl_ec_key_export(int argc, VALUE *argv, VALUE self) { - VALUE cipher, passwd; - rb_scan_args(argc, argv, "02", &cipher, &passwd); - return ossl_ec_key_to_string(self, cipher, passwd, EXPORT_PEM); + EC_KEY *ec; + + GetEC(self, ec); + if (EC_KEY_get0_private_key(ec)) + return ossl_do_traditional_export(argc, argv, self, 0); + else + return ossl_do_spki_export(self, 0); } /* @@ -522,7 +413,13 @@ static VALUE ossl_ec_key_export(int argc, VALUE *argv, VALUE self) */ static VALUE ossl_ec_key_to_der(VALUE self) { - return ossl_ec_key_to_string(self, Qnil, Qnil, EXPORT_DER); + EC_KEY *ec; + + GetEC(self, ec); + if (EC_KEY_get0_private_key(ec)) + return ossl_do_traditional_export(0, NULL, self, 1); + else + return ossl_do_spki_export(self, 1); } /* @@ -594,37 +491,6 @@ static VALUE ossl_ec_key_check_key(VALUE self) return Qtrue; } -/* - * call-seq: - * key.dh_compute_key(pubkey) => String - * - * See the OpenSSL documentation for ECDH_compute_key() - */ -static VALUE ossl_ec_key_dh_compute_key(VALUE self, VALUE pubkey) -{ - EC_KEY *ec; - EC_POINT *point; - int buf_len; - VALUE str; - - GetEC(self, ec); - SafeGetECPoint(pubkey, point); - -/* BUG: need a way to figure out the maximum string size */ - buf_len = 1024; - str = rb_str_new(0, buf_len); -/* BUG: take KDF as a block */ - buf_len = ECDH_compute_key(RSTRING_PTR(str), buf_len, point, ec, NULL); - if (buf_len < 0) - ossl_raise(eECError, "ECDH_compute_key"); - - rb_str_resize(str, buf_len); - - return str; -} - -/* sign_setup */ - /* * call-seq: * key.dsa_sign_asn1(data) => String @@ -1750,7 +1616,6 @@ void Init_ossl_ec(void) rb_define_alias(cEC, "generate_key", "generate_key!"); rb_define_method(cEC, "check_key", ossl_ec_key_check_key, 0); - rb_define_method(cEC, "dh_compute_key", ossl_ec_key_dh_compute_key, 1); rb_define_method(cEC, "dsa_sign_asn1", ossl_ec_key_dsa_sign_asn1, 1); rb_define_method(cEC, "dsa_verify_asn1", ossl_ec_key_dsa_verify_asn1, 2); /* do_sign/do_verify */ diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c index 59c12f5c7..e5e9bcb76 100644 --- a/ext/openssl/ossl_pkey_rsa.c +++ b/ext/openssl/ossl_pkey_rsa.c @@ -44,53 +44,6 @@ RSA_PRIVATE(VALUE obj, RSA *rsa) VALUE cRSA; VALUE eRSAError; -/* - * Public - */ -static VALUE -rsa_instance(VALUE klass, RSA *rsa) -{ - EVP_PKEY *pkey; - VALUE obj; - - if (!rsa) { - return Qfalse; - } - obj = NewPKey(klass); - if (!(pkey = EVP_PKEY_new())) { - return Qfalse; - } - if (!EVP_PKEY_assign_RSA(pkey, rsa)) { - EVP_PKEY_free(pkey); - return Qfalse; - } - SetPKey(obj, pkey); - - return obj; -} - -VALUE -ossl_rsa_new(EVP_PKEY *pkey) -{ - VALUE obj; - - if (!pkey) { - obj = rsa_instance(cRSA, RSA_new()); - } - else { - obj = NewPKey(cRSA); - if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) { - ossl_raise(rb_eTypeError, "Not a RSA key!"); - } - SetPKey(obj, pkey); - } - if (obj == Qfalse) { - ossl_raise(eRSAError, NULL); - } - - return obj; -} - /* * Private */ @@ -124,7 +77,7 @@ rsa_generate(int size, unsigned long exp) RSA_free(rsa); BN_free(e); BN_GENCB_free(cb); - return NULL; + ossl_raise(eRSAError, "malloc failure"); } for (i = 0; i < (int)sizeof(exp) * 8; ++i) { if (exp & (1UL << i)) { @@ -132,7 +85,7 @@ rsa_generate(int size, unsigned long exp) BN_free(e); RSA_free(rsa); BN_GENCB_free(cb); - return NULL; + ossl_raise(eRSAError, "BN_set_bit"); } } } @@ -161,7 +114,7 @@ rsa_generate(int size, unsigned long exp) ossl_clear_error(); rb_jump_tag(cb_arg.state); } - return NULL; + ossl_raise(eRSAError, "RSA_generate_key_ex"); } return rsa; @@ -180,26 +133,26 @@ static VALUE ossl_rsa_s_generate(int argc, VALUE *argv, VALUE klass) { /* why does this method exist? why can't initialize take an optional exponent? */ + EVP_PKEY *pkey; RSA *rsa; VALUE size, exp; VALUE obj; rb_scan_args(argc, argv, "11", &size, &exp); + obj = rb_obj_alloc(klass); + GetPKey(obj, pkey); - rsa = rsa_generate(NUM2INT(size), NIL_P(exp) ? RSA_F4 : NUM2ULONG(exp)); /* err handled by rsa_instance */ - obj = rsa_instance(klass, rsa); - - if (obj == Qfalse) { + rsa = rsa_generate(NUM2INT(size), NIL_P(exp) ? RSA_F4 : NUM2ULONG(exp)); + if (!EVP_PKEY_assign_RSA(pkey, rsa)) { RSA_free(rsa); - ossl_raise(eRSAError, NULL); + ossl_raise(eRSAError, "EVP_PKEY_assign_RSA"); } - return obj; } /* * call-seq: - * RSA.new(key_size) => RSA instance + * RSA.new(size [, exponent]) => RSA instance * RSA.new(encoded_key) => RSA instance * RSA.new(encoded_key, pass_phrase) => RSA instance * @@ -220,46 +173,42 @@ ossl_rsa_s_generate(int argc, VALUE *argv, VALUE klass) static VALUE ossl_rsa_initialize(int argc, VALUE *argv, VALUE self) { - EVP_PKEY *pkey; - RSA *rsa; + EVP_PKEY *pkey, *pkey_tmp; + RSA *rsa = NULL; BIO *in; VALUE arg, pass; GetPKey(self, pkey); if(rb_scan_args(argc, argv, "02", &arg, &pass) == 0) { rsa = RSA_new(); + if (!rsa) + ossl_raise(eRSAError, "RSA_new"); } else if (RB_INTEGER_TYPE_P(arg)) { rsa = rsa_generate(NUM2INT(arg), NIL_P(pass) ? RSA_F4 : NUM2ULONG(pass)); - if (!rsa) ossl_raise(eRSAError, NULL); } else { - pass = ossl_pem_passwd_value(pass); arg = ossl_to_der_if_possible(arg); - in = ossl_obj2bio(arg); - rsa = PEM_read_bio_RSAPrivateKey(in, NULL, ossl_pem_passwd_cb, (void *)pass); - if (!rsa) { - OSSL_BIO_reset(in); - rsa = PEM_read_bio_RSA_PUBKEY(in, NULL, NULL, NULL); - } - if (!rsa) { - OSSL_BIO_reset(in); - rsa = d2i_RSAPrivateKey_bio(in, NULL); - } - if (!rsa) { - OSSL_BIO_reset(in); - rsa = d2i_RSA_PUBKEY_bio(in, NULL); + pkey_tmp = ossl_do_read_pkey(arg, pass); + if (pkey_tmp) { + if (EVP_PKEY_base_id(pkey_tmp) == EVP_PKEY_RSA) { + rsa = EVP_PKEY_get0_RSA(pkey_tmp); + RSA_up_ref(rsa); + } + EVP_PKEY_free(pkey_tmp); } - if (!rsa) { - OSSL_BIO_reset(in); + else { + ossl_clear_error(); + in = ossl_obj2bio(arg); rsa = PEM_read_bio_RSAPublicKey(in, NULL, NULL, NULL); + if (!rsa) { + OSSL_BIO_reset(in); + rsa = d2i_RSAPublicKey_bio(in, NULL); + } + BIO_free(in); } if (!rsa) { - OSSL_BIO_reset(in); - rsa = d2i_RSAPublicKey_bio(in, NULL); - } - BIO_free(in); - if (!rsa) { + ossl_clear_error(); ossl_raise(eRSAError, "Neither PUB key nor PRIV key"); } } @@ -341,36 +290,12 @@ static VALUE ossl_rsa_export(int argc, VALUE *argv, VALUE self) { RSA *rsa; - BIO *out; - const EVP_CIPHER *ciph = NULL; - VALUE cipher, pass, str; GetRSA(self, rsa); - - rb_scan_args(argc, argv, "02", &cipher, &pass); - - if (!NIL_P(cipher)) { - ciph = GetCipherPtr(cipher); - pass = ossl_pem_passwd_value(pass); - } - if (!(out = BIO_new(BIO_s_mem()))) { - ossl_raise(eRSAError, NULL); - } - if (RSA_HAS_PRIVATE(rsa)) { - if (!PEM_write_bio_RSAPrivateKey(out, rsa, ciph, NULL, 0, - ossl_pem_passwd_cb, (void *)pass)) { - BIO_free(out); - ossl_raise(eRSAError, NULL); - } - } else { - if (!PEM_write_bio_RSA_PUBKEY(out, rsa)) { - BIO_free(out); - ossl_raise(eRSAError, NULL); - } - } - str = ossl_membio2str(out); - - return str; + if (RSA_HAS_PRIVATE(rsa)) + return ossl_do_traditional_export(argc, argv, self, 0); + else + return ossl_do_spki_export(self, 0); } /* @@ -383,25 +308,12 @@ static VALUE ossl_rsa_to_der(VALUE self) { RSA *rsa; - int (*i2d_func)(const RSA *, unsigned char **); - unsigned char *p; - long len; - VALUE str; GetRSA(self, rsa); if (RSA_HAS_PRIVATE(rsa)) - i2d_func = i2d_RSAPrivateKey; + return ossl_do_traditional_export(0, NULL, self, 1); else - i2d_func = (int (*)(const RSA *, unsigned char **))i2d_RSA_PUBKEY; - if((len = i2d_func(rsa, NULL)) <= 0) - ossl_raise(eRSAError, NULL); - str = rb_str_new(0, len); - p = (unsigned char *)RSTRING_PTR(str); - if(i2d_func(rsa, &p) < 0) - ossl_raise(eRSAError, NULL); - ossl_str_adjust(str, p); - - return str; + return ossl_do_spki_export(self, 1); } /* @@ -611,17 +523,20 @@ ossl_rsa_to_text(VALUE self) static VALUE ossl_rsa_to_public_key(VALUE self) { - EVP_PKEY *pkey; + EVP_PKEY *pkey, *pkey_new; RSA *rsa; VALUE obj; GetPKeyRSA(self, pkey); - /* err check performed by rsa_instance */ + obj = rb_obj_alloc(rb_obj_class(self)); + GetPKey(obj, pkey_new); + rsa = RSAPublicKey_dup(EVP_PKEY_get0_RSA(pkey)); - obj = rsa_instance(rb_obj_class(self), rsa); - if (obj == Qfalse) { + if (!rsa) + ossl_raise(eRSAError, "RSAPublicKey_dup"); + if (!EVP_PKEY_assign_RSA(pkey_new, rsa)) { RSA_free(rsa); - ossl_raise(eRSAError, NULL); + ossl_raise(eRSAError, "EVP_PKEY_assign_RSA"); } return obj; } diff --git a/lib/openssl/pkey.rb b/lib/openssl/pkey.rb index dcedd849a..ab2042c17 100644 --- a/lib/openssl/pkey.rb +++ b/lib/openssl/pkey.rb @@ -1,3 +1,42 @@ # frozen_string_literal: false module OpenSSL + module PKey + class DH + # :call-seq: + # dh.compute_key(pub_bn) -> string + # + # Returns a String containing a shared secret computed from the other + # party's public value. + # + # This method is provided for backwards compatibility, and calls #derive + # internally. + # + # === Parameters + # * _pub_bn_ is a OpenSSL::BN, *not* the DH instance returned by + # DH#public_key as that contains the DH parameters only. + def compute_key(pub_bn) + peer = dup + peer.set_key(pub_bn, nil) + derive(peer) + end + end + + if defined?(EC) + class EC + # :call-seq: + # ec.dh_compute_key(pubkey) -> string + # + # Derives a shared secret by ECDH. _pubkey_ must be an instance of + # OpenSSL::PKey::EC::Point and must belong to the same group. + # + # This method is provided for backwards compatibility, and calls #derive + # internally. + def dh_compute_key(pubkey) + peer = OpenSSL::PKey::EC.new(group) + peer.public_key = pubkey + derive(peer) + end + end + end + end end diff --git a/sample/echo_svr.rb b/sample/echo_svr.rb index 719de6be8..0f55b1b17 100644 --- a/sample/echo_svr.rb +++ b/sample/echo_svr.rb @@ -13,7 +13,7 @@ if cert_file && key_file cert = OpenSSL::X509::Certificate.new(File::read(cert_file)) - key = OpenSSL::PKey::RSA.new(File::read(key_file)) + key = OpenSSL::PKey.read(File::read(key_file)) else key = OpenSSL::PKey::RSA.new(512){ print "." } puts diff --git a/sample/gen_csr.rb b/sample/gen_csr.rb index 4228707fd..32e973274 100644 --- a/sample/gen_csr.rb +++ b/sample/gen_csr.rb @@ -25,7 +25,7 @@ def usage keypair = nil if keypair_file - keypair = PKey::RSA.new(File.open(keypair_file).read) + keypair = PKey.read(File.read(keypair_file)) else keypair = PKey::RSA.new(1024) { putc "." } puts diff --git a/sample/smime_read.rb b/sample/smime_read.rb index 17394f9b8..a70105fd6 100644 --- a/sample/smime_read.rb +++ b/sample/smime_read.rb @@ -11,7 +11,7 @@ data = $stdin.read cert = X509::Certificate.new(File::read(cert_file)) -key = PKey::RSA.new(File::read(key_file)) +key = PKey::read(File::read(key_file)) p7enc = PKCS7::read_smime(data) data = p7enc.decrypt(key, cert) diff --git a/sample/smime_write.rb b/sample/smime_write.rb index 5a5236c75..20c933b28 100644 --- a/sample/smime_write.rb +++ b/sample/smime_write.rb @@ -9,7 +9,7 @@ rcpt_file = options["r"] cert = X509::Certificate.new(File::read(cert_file)) -key = PKey::RSA.new(File::read(key_file)) +key = PKey::read(File::read(key_file)) data = "Content-Type: text/plain\r\n" data << "\r\n" diff --git a/test/test_pair.rb b/test/test_pair.rb index a462891db..ad801195c 100644 --- a/test/test_pair.rb +++ b/test/test_pair.rb @@ -11,7 +11,7 @@ def server ctx = OpenSSL::SSL::SSLContext.new() ctx.ciphers = "ADH" ctx.security_level = 0 - ctx.tmp_dh_callback = proc { OpenSSL::TestUtils::Fixtures.pkey_dh("dh1024") } + ctx.tmp_dh_callback = proc { OpenSSL::TestUtils::Fixtures.pkey("dh1024") } tcps = create_tcp_server(host, port) ssls = OpenSSL::SSL::SSLServer.new(tcps, ctx) return ssls @@ -354,7 +354,7 @@ def test_connect_accept_nonblock_no_exception ctx2 = OpenSSL::SSL::SSLContext.new ctx2.ciphers = "ADH" ctx2.security_level = 0 - ctx2.tmp_dh_callback = proc { OpenSSL::TestUtils::Fixtures.pkey_dh("dh1024") } + ctx2.tmp_dh_callback = proc { OpenSSL::TestUtils::Fixtures.pkey("dh1024") } sock1, sock2 = tcp_pair @@ -404,7 +404,7 @@ def test_connect_accept_nonblock ctx = OpenSSL::SSL::SSLContext.new() ctx.ciphers = "ADH" ctx.security_level = 0 - ctx.tmp_dh_callback = proc { OpenSSL::TestUtils::Fixtures.pkey_dh("dh1024") } + ctx.tmp_dh_callback = proc { OpenSSL::TestUtils::Fixtures.pkey("dh1024") } sock1, sock2 = tcp_pair diff --git a/test/test_pkey.rb b/test/test_pkey.rb new file mode 100644 index 000000000..f25b12b2e --- /dev/null +++ b/test/test_pkey.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: false +require_relative 'utils' + +class OpenSSL::TestPKey < OpenSSL::PKeyTestCase + def test_s_generate_parameters + # 512 is non-default; 1024 is used if 'dsa_paramgen_bits' is not specified + # with OpenSSL 1.1.0. + pkey = OpenSSL::PKey.generate_parameters("DSA", "dsa_paramgen_bits" => 512) + assert_instance_of OpenSSL::PKey::DSA, pkey + assert_equal 512, pkey.p.num_bits + assert_equal 160, pkey.q.num_bits + assert_equal nil, pkey.priv_key + + assert_raise(OpenSSL::PKey::PKeyError) { + OpenSSL::PKey.generate_parameters("DSA", "invalid" => "option") + } + end + + def test_s_generate_key + assert_raise(OpenSSL::PKey::PKeyError) { + # DSA key pair cannot be generated without parameters + OpenSSL::PKey.generate_key("DSA") + } + pkey_params = OpenSSL::PKey.generate_parameters("DSA", "dsa_paramgen_bits" => 512) + pkey = OpenSSL::PKey.generate_key(pkey_params) + assert_instance_of OpenSSL::PKey::DSA, pkey + assert_not_equal nil, pkey.priv_key + end + + def test_x25519 + # RFC 7748 Section 6.1 + alice_pem = <<~EOF + -----BEGIN PRIVATE KEY----- + MC4CAQAwBQYDK2VuBCIEIHcHbQpzGKV9PBbBclGyZkXfTC+H68CZKrF3+6UduSwq + -----END PRIVATE KEY----- + EOF + bob_pem = <<~EOF + -----BEGIN PUBLIC KEY----- + MCowBQYDK2VuAyEA3p7bfXt9wbTTW2HC7OQ1Nz+DQ8hbeGdNrfx+FG+IK08= + -----END PUBLIC KEY----- + EOF + shared_secret = "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742" + begin + alice = OpenSSL::PKey.read(alice_pem) + bob = OpenSSL::PKey.read(bob_pem) + rescue OpenSSL::PKey::PKeyError + # OpenSSL < 1.1.0 + pend "X25519 is not implemented" + end + assert_instance_of OpenSSL::PKey::PKey, alice + assert_equal alice_pem, alice.private_to_pem + assert_equal bob_pem, bob.public_to_pem + assert_equal [shared_secret].pack("H*"), alice.derive(bob) + + # Generating an X25519 key + assert_raise(OpenSSL::PKey::PKeyError) { + OpenSSL::PKey.generate_parameters("X25519") + } + key = OpenSSL::PKey.generate_key("X25519") + assert_nothing_raised { key.derive(bob) } + assert_raise(OpenSSL::PKey::PKeyError) { key.sign("sha256", "data") } + end +end diff --git a/test/test_pkey_dh.rb b/test/test_pkey_dh.rb index e7e76f973..f78f1102f 100644 --- a/test/test_pkey_dh.rb +++ b/test/test_pkey_dh.rb @@ -16,14 +16,28 @@ def test_new_break end end + def test_derive_key + dh1 = Fixtures.pkey("dh1024").generate_key! + dh2 = Fixtures.pkey("dh1024").generate_key! + dh1_pub = OpenSSL::PKey.read(dh1.public_to_der) + dh2_pub = OpenSSL::PKey.read(dh2.public_to_der) + z = dh1.g.mod_exp(dh1.priv_key, dh1.p).mod_exp(dh2.priv_key, dh1.p).to_s(2) + assert_equal z, dh1.derive(dh2_pub) + assert_equal z, dh2.derive(dh1_pub) + + assert_equal z, dh1.compute_key(dh2.pub_key) + assert_equal z, dh2.compute_key(dh1.pub_key) + end + def test_DHparams - dh1024 = Fixtures.pkey_dh("dh1024") + dh1024 = Fixtures.pkey("dh1024") asn1 = OpenSSL::ASN1::Sequence([ OpenSSL::ASN1::Integer(dh1024.p), OpenSSL::ASN1::Integer(dh1024.g) ]) key = OpenSSL::PKey::DH.new(asn1.to_der) assert_same_dh dup_public(dh1024), key + # OpenSSL::PKey.read does not understand DER-encoded DHParameter pem = <<~EOF -----BEGIN DH PARAMETERS----- @@ -34,13 +48,15 @@ def test_DHparams EOF key = OpenSSL::PKey::DH.new(pem) assert_same_dh dup_public(dh1024), key + key = OpenSSL::PKey.read(pem) + assert_same_dh dup_public(dh1024), key assert_equal asn1.to_der, dh1024.to_der assert_equal pem, dh1024.export end def test_public_key - dh = Fixtures.pkey_dh("dh1024") + dh = Fixtures.pkey("dh1024") public_key = dh.public_key assert_no_key(public_key) #implies public_key.public? is false! assert_equal(dh.to_der, public_key.to_der) @@ -48,14 +64,14 @@ def test_public_key end def test_generate_key - dh = Fixtures.pkey_dh("dh1024").public_key # creates a copy + dh = Fixtures.pkey("dh1024").public_key # creates a copy assert_no_key(dh) dh.generate_key! assert_key(dh) end def test_key_exchange - dh = Fixtures.pkey_dh("dh1024") + dh = Fixtures.pkey("dh1024") dh2 = dh.public_key dh.generate_key! dh2.generate_key! diff --git a/test/test_pkey_ec.rb b/test/test_pkey_ec.rb index e1d1e9425..bc43c7e16 100644 --- a/test/test_pkey_ec.rb +++ b/test/test_pkey_ec.rb @@ -86,6 +86,22 @@ def test_sign_verify assert_equal false, p256.verify("SHA256", signature1, data) end + def test_derive_key + # NIST CAVP, KAS_ECC_CDH_PrimitiveTest.txt, P-256 COUNT = 0 + qCAVSx = "700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287" + qCAVSy = "db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac" + dIUT = "7d7dc5f71eb29ddaf80d6214632eeae03d9058af1fb6d22ed80badb62bc1a534" + zIUT = "46fc62106420ff012e54a434fbdd2d25ccc5852060561e68040dd7778997bd7b" + a = OpenSSL::PKey::EC.new("prime256v1") + a.private_key = OpenSSL::BN.new(dIUT, 16) + b = OpenSSL::PKey::EC.new("prime256v1") + uncompressed = OpenSSL::BN.new("04" + qCAVSx + qCAVSy, 16) + b.public_key = OpenSSL::PKey::EC::Point.new(b.group, uncompressed) + assert_equal [zIUT].pack("H*"), a.derive(b) + + assert_equal a.derive(b), a.dh_compute_key(b.public_key) + end + def test_dsa_sign_verify data1 = "foo" data2 = "bar" diff --git a/test/test_pkey_rsa.rb b/test/test_pkey_rsa.rb index a4ade1346..99147063d 100644 --- a/test/test_pkey_rsa.rb +++ b/test/test_pkey_rsa.rb @@ -243,6 +243,85 @@ def test_PUBKEY assert_equal pem, dup_public(rsa1024).export end + def test_private_encoding + rsa1024 = Fixtures.pkey("rsa1024") + asn1 = OpenSSL::ASN1::Sequence([ + OpenSSL::ASN1::Integer(0), + OpenSSL::ASN1::Sequence([ + OpenSSL::ASN1::ObjectId("rsaEncryption"), + OpenSSL::ASN1::Null(nil) + ]), + OpenSSL::ASN1::OctetString(rsa1024.to_der) + ]) + assert_equal asn1.to_der, rsa1024.private_to_der + assert_same_rsa rsa1024, OpenSSL::PKey.read(asn1.to_der) + + pem = <<~EOF + -----BEGIN PRIVATE KEY----- + MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAMvCxLDUQKc+1P4+ + Q6AeFwYDvWfALb+cvzlUEadGoPE6qNWHsLFoo8RFgeyTgE8KQTduu1OE9Zz2SMcR + BDu5/1jWtsLPSVrI2ofLLBARUsWanVyki39DeB4u/xkP2mKGjAokPIwOI3oCthSZ + lzO9bj3voxTf6XngTqUX8l8URTmHAgMBAAECgYEApKX8xBqvJ7XI7Kypfo/x8MVC + 3rxW+1eQ2aVKIo4a7PKGjQz5RVIVyzqTUvSZoMTbkAxlSIbO5YfJpTnl3tFcOB6y + QMxqQPW/pl6Ni3EmRJdsRM5MsPBRZOfrXxOCdvXu1TWOS1S1TrvEr/TyL9eh2WCd + CGzpWgdO4KHce7vs7pECQQDv6DGoG5lHnvbvj9qSJb9K5ebRJc8S+LI7Uy5JHC0j + zsHTYPSqBXwPVQdGbgCEycnwwKzXzT2QxAQmJBQKun2ZAkEA2W3aeAE7Xi6zo2eG + 4Cx4UNMHMIdfBRS7VgoekwybGmcapqV0aBew5kHeWAmxP1WUZ/dgZh2QtM1VuiBA + qUqkHwJBAOJLCRvi/JB8N7z82lTk2i3R8gjyOwNQJv6ilZRMyZ9vFZFHcUE27zCf + Kb+bX03h8WPwupjMdfgpjShU+7qq8nECQQDBrmyc16QVyo40sgTgblyiysitvviy + ovwZsZv4q5MCmvOPnPUrwGbRRb2VONUOMOKpFiBl9lIv7HU//nj7FMVLAkBjUXED + 83dA8JcKM+HlioXEAxCzZVVhN+D63QwRwkN08xAPklfqDkcqccWDaZm2hdCtaYlK + funwYkrzI1OikQSs + -----END PRIVATE KEY----- + EOF + assert_equal pem, rsa1024.private_to_pem + assert_same_rsa rsa1024, OpenSSL::PKey.read(pem) + end + + def test_private_encoding_encrypted + rsa1024 = Fixtures.pkey("rsa1024") + encoded = rsa1024.private_to_der("aes-128-cbc", "abcdef") + asn1 = OpenSSL::ASN1.decode(encoded) # PKCS #8 EncryptedPrivateKeyInfo + assert_kind_of OpenSSL::ASN1::Sequence, asn1 + assert_equal 2, asn1.value.size + assert_not_equal rsa1024.private_to_der, encoded + assert_same_rsa rsa1024, OpenSSL::PKey.read(encoded, "abcdef") + assert_same_rsa rsa1024, OpenSSL::PKey.read(encoded) { "abcdef" } + assert_raise(OpenSSL::PKey::PKeyError) { OpenSSL::PKey.read(encoded, "abcxyz") } + + encoded = rsa1024.private_to_pem("aes-128-cbc", "abcdef") + assert_match (/BEGIN ENCRYPTED PRIVATE KEY/), encoded.lines[0] + assert_same_rsa rsa1024, OpenSSL::PKey.read(encoded, "abcdef") + + # certtool --load-privkey=test/fixtures/pkey/rsa1024.pem --to-p8 --password=abcdef + pem = <<~EOF + -----BEGIN ENCRYPTED PRIVATE KEY----- + MIICojAcBgoqhkiG9w0BDAEDMA4ECLqajUdSNfzwAgIEkQSCAoCDWhxr1HUrKLXA + FsFGGQfPT0aKH4gZipaSXXQRl0KwifHwHoDtfo/mAkJVZMnUVOm1AQ4LTFS3EdTy + JUwICGEQHb7QAiokIRoi0K2yHhOxVO8qgbnWuisWpiT6Ru1jCqTs/wcqlqF7z2jM + oXDk/vuekKst1DDXDcHrzhDkwhCQWj6jt1r2Vwaryy0FyeqsWAgBDiK2LsnCgkGD + 21uhNZ/iWMG6tvY9hB8MDdiBJ41YdSG/AKLulAxQ1ibJz0Tasu66TmwFvWhBlME+ + QbqfgmkgWg5buu53SvDfCA47zXihclbtdfW+U3CJ9OJkx0535TVdZbuC1QgKXvG7 + 4iKGFRMWYJqZvZM3GL4xbC75AxjXZsdCfV81VjZxjeU6ung/NRzCuCUcmBOQzo1D + Vv6COwAa6ttQWM0Ti8oIQHdu5Qi+nuOEHDLxCxD962M37H99sEO5cESjmrGVxhEo + 373L4+11geGSCajdp0yiAGnXQfwaKta8cL693bRObN+b1Y+vqtDKH26N9a4R3qgg + 2XwgQ5GH5CODoXZpi0wxncXO+3YuuhGeArtzKSXLNxHzIMlY7wZX+0e9UU03zfV/ + aOe4/q5DpkNxgHePt0oEpamSKY5W3jzVi1dlFWsRjud1p/Grt2zjSWTYClBlJqG1 + A/3IeDZCu+acaePJjFyv5dFffIj2l4bAYB+LFrZlSu3F/EimO/dCDWJ9JGlMK0aF + l9brh7786Mo+YfyklaqMMEHBbbR2Es7PR6Gt7lrcIXmzy9XSsxT6IiD1rG9KKR3i + CQxTup6JAx9w1q+adL+Ypikoy3gGD/ccUY6TtPoCmkQwSCS+JqQnFlCiThDJbu+V + eqqUNkZq + -----END ENCRYPTED PRIVATE KEY----- + EOF + assert_same_rsa rsa1024, OpenSSL::PKey.read(pem, "abcdef") + end + + def test_public_encoding + rsa1024 = Fixtures.pkey("rsa1024") + assert_equal dup_public(rsa1024).to_der, rsa1024.public_to_der + assert_equal dup_public(rsa1024).to_pem, rsa1024.public_to_pem + end + def test_dup key = OpenSSL::PKey::RSA.generate(256, 17) key2 = key.dup diff --git a/test/test_ssl.rb b/test/test_ssl.rb index 8bf0c2147..a9bec5f0c 100644 --- a/test/test_ssl.rb +++ b/test/test_ssl.rb @@ -621,7 +621,7 @@ def socketpair def test_tlsext_hostname ctx3 = OpenSSL::SSL::SSLContext.new ctx3.ciphers = "ADH" - ctx3.tmp_dh_callback = proc { Fixtures.pkey_dh("dh1024") } + ctx3.tmp_dh_callback = proc { Fixtures.pkey("dh1024") } ctx3.security_level = 0 assert_not_predicate ctx3, :frozen? @@ -671,7 +671,7 @@ def test_servername_cb_raises_an_exception_on_unknown_objects ctx2 = OpenSSL::SSL::SSLContext.new ctx2.ciphers = "aNULL" - ctx2.tmp_dh_callback = proc { Fixtures.pkey_dh("dh1024") } + ctx2.tmp_dh_callback = proc { Fixtures.pkey("dh1024") } ctx2.security_level = 0 ctx2.servername_cb = lambda { |args| Object.new } @@ -1070,7 +1070,7 @@ def test_close_and_socket_close_while_connecting # test it doesn't cause a segmentation fault ctx = OpenSSL::SSL::SSLContext.new ctx.ciphers = "aNULL" - ctx.tmp_dh_callback = proc { Fixtures.pkey_dh("dh1024") } + ctx.tmp_dh_callback = proc { Fixtures.pkey("dh1024") } ctx.security_level = 0 sock1, sock2 = socketpair @@ -1125,14 +1125,14 @@ def test_dh_callback ctx.ciphers = "DH:!NULL" ctx.tmp_dh_callback = ->(*args) { called = true - Fixtures.pkey_dh("dh1024") + Fixtures.pkey("dh1024") } } start_server(ctx_proc: ctx_proc) do |server, port| server_connect(port) { |ssl| assert called, "dh callback should be called" if ssl.respond_to?(:tmp_key) - assert_equal Fixtures.pkey_dh("dh1024").to_der, ssl.tmp_key.to_der + assert_equal Fixtures.pkey("dh1024").to_der, ssl.tmp_key.to_der end } end diff --git a/test/utils.rb b/test/utils.rb index 54f75f25c..6ebc33fdd 100644 --- a/test/utils.rb +++ b/test/utils.rb @@ -43,11 +43,6 @@ def pkey(name) OpenSSL::PKey.read(read_file("pkey", name)) end - def pkey_dh(name) - # DH parameters can be read by OpenSSL::PKey.read atm - OpenSSL::PKey::DH.new(read_file("pkey", name)) - end - def read_file(category, name) @file_cache ||= {} @file_cache[[category, name]] ||= @@ -219,7 +214,7 @@ def start_server(verify_mode: OpenSSL::SSL::VERIFY_NONE, start_immediately: true ctx.cert_store = store ctx.cert = @svr_cert ctx.key = @svr_key - ctx.tmp_dh_callback = proc { Fixtures.pkey_dh("dh1024") } + ctx.tmp_dh_callback = proc { Fixtures.pkey("dh1024") } begin ctx.ecdh_curves = "P-256" rescue NotImplementedError