diff options
Diffstat (limited to 'ext/openssl/ossl_pkey_rsa.c')
-rw-r--r-- | ext/openssl/ossl_pkey_rsa.c | 193 |
1 files changed, 135 insertions, 58 deletions
diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c index 8ebd3ec559..389f76f309 100644 --- a/ext/openssl/ossl_pkey_rsa.c +++ b/ext/openssl/ossl_pkey_rsa.c @@ -24,7 +24,7 @@ } while (0) static inline int -RSA_HAS_PRIVATE(RSA *rsa) +RSA_HAS_PRIVATE(OSSL_3_const RSA *rsa) { const BIGNUM *e, *d; @@ -33,7 +33,7 @@ RSA_HAS_PRIVATE(RSA *rsa) } static inline int -RSA_PRIVATE(VALUE obj, RSA *rsa) +RSA_PRIVATE(VALUE obj, OSSL_3_const RSA *rsa) { return RSA_HAS_PRIVATE(rsa) || OSSL_PKEY_IS_PRIVATE(obj); } @@ -50,8 +50,8 @@ VALUE eRSAError; /* * call-seq: * RSA.new -> rsa - * RSA.new(encoded_key [, passphrase]) -> rsa - * RSA.new(encoded_key) { passphrase } -> rsa + * RSA.new(encoded_key [, password ]) -> rsa + * RSA.new(encoded_key) { password } -> rsa * RSA.new(size [, exponent]) -> rsa * * Generates or loads an \RSA keypair. @@ -61,9 +61,9 @@ VALUE eRSAError; * #set_crt_params. * * If called with a String, tries to parse as DER or PEM encoding of an \RSA key. - * Note that, if _passphrase_ is not specified but the key is encrypted with a - * passphrase, \OpenSSL will prompt for it. - * See also OpenSSL::PKey.read which can parse keys of any kinds. + * Note that if _password_ is not specified, but the key is encrypted with a + * password, \OpenSSL will prompt for it. + * See also OpenSSL::PKey.read which can parse keys of any kind. * * If called with a number, generates a new key pair. This form works as an * alias of RSA.generate. @@ -71,78 +71,98 @@ VALUE eRSAError; * Examples: * OpenSSL::PKey::RSA.new 2048 * OpenSSL::PKey::RSA.new File.read 'rsa.pem' - * OpenSSL::PKey::RSA.new File.read('rsa.pem'), 'my pass phrase' + * OpenSSL::PKey::RSA.new File.read('rsa.pem'), 'my password' */ static VALUE ossl_rsa_initialize(int argc, VALUE *argv, VALUE self) { - EVP_PKEY *pkey, *tmp; - RSA *rsa = NULL; - BIO *in; + EVP_PKEY *pkey; + RSA *rsa; + BIO *in = NULL; VALUE arg, pass; + int type; + + TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey); + if (pkey) + rb_raise(rb_eTypeError, "pkey already initialized"); - GetPKey(self, pkey); /* The RSA.new(size, generator) form is handled by lib/openssl/pkey.rb */ rb_scan_args(argc, argv, "02", &arg, &pass); if (argc == 0) { rsa = RSA_new(); if (!rsa) ossl_raise(eRSAError, "RSA_new"); + goto legacy; } - else { - pass = ossl_pem_passwd_value(pass); - arg = ossl_to_der_if_possible(arg); - in = ossl_obj2bio(&arg); - - tmp = ossl_pkey_read_generic(in, pass); - if (tmp) { - if (EVP_PKEY_base_id(tmp) != EVP_PKEY_RSA) - rb_raise(eRSAError, "incorrect pkey type: %s", - OBJ_nid2sn(EVP_PKEY_base_id(tmp))); - rsa = EVP_PKEY_get1_RSA(tmp); - EVP_PKEY_free(tmp); - } - if (!rsa) { - OSSL_BIO_reset(in); - 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_clear_error(); - ossl_raise(eRSAError, "Neither PUB key nor PRIV key"); - } - } - if (!EVP_PKEY_assign_RSA(pkey, rsa)) { - RSA_free(rsa); - ossl_raise(eRSAError, "EVP_PKEY_assign_RSA"); + + pass = ossl_pem_passwd_value(pass); + arg = ossl_to_der_if_possible(arg); + in = ossl_obj2bio(&arg); + + /* First try RSAPublicKey format */ + rsa = d2i_RSAPublicKey_bio(in, NULL); + if (rsa) + goto legacy; + OSSL_BIO_reset(in); + rsa = PEM_read_bio_RSAPublicKey(in, NULL, NULL, NULL); + if (rsa) + goto legacy; + OSSL_BIO_reset(in); + + /* Use the generic routine */ + pkey = ossl_pkey_read_generic(in, pass); + BIO_free(in); + if (!pkey) + ossl_raise(eRSAError, "Neither PUB key nor PRIV key"); + + type = EVP_PKEY_base_id(pkey); + if (type != EVP_PKEY_RSA) { + EVP_PKEY_free(pkey); + rb_raise(eRSAError, "incorrect pkey type: %s", OBJ_nid2sn(type)); } + RTYPEDDATA_DATA(self) = pkey; + return self; + legacy: + BIO_free(in); + pkey = EVP_PKEY_new(); + if (!pkey || EVP_PKEY_assign_RSA(pkey, rsa) != 1) { + EVP_PKEY_free(pkey); + RSA_free(rsa); + ossl_raise(eRSAError, "EVP_PKEY_assign_RSA"); + } + RTYPEDDATA_DATA(self) = pkey; return self; } +#ifndef HAVE_EVP_PKEY_DUP 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"); + TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey); + if (pkey) + rb_raise(rb_eTypeError, "pkey already initialized"); GetRSA(other, rsa); - rsa_new = ASN1_dup((i2d_of_void *)i2d_RSAPrivateKey, (d2i_of_void *)d2i_RSAPrivateKey, (char *)rsa); + rsa_new = (RSA *)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); + pkey = EVP_PKEY_new(); + if (!pkey || EVP_PKEY_assign_RSA(pkey, rsa_new) != 1) { + RSA_free(rsa_new); + ossl_raise(eRSAError, "EVP_PKEY_assign_RSA"); + } + RTYPEDDATA_DATA(self) = pkey; return self; } +#endif /* * call-seq: @@ -154,7 +174,7 @@ ossl_rsa_initialize_copy(VALUE self, VALUE other) static VALUE ossl_rsa_is_public(VALUE self) { - RSA *rsa; + OSSL_3_const RSA *rsa; GetRSA(self, rsa); /* @@ -173,7 +193,7 @@ ossl_rsa_is_public(VALUE self) static VALUE ossl_rsa_is_private(VALUE self) { - RSA *rsa; + OSSL_3_const RSA *rsa; GetRSA(self, rsa); @@ -183,7 +203,7 @@ ossl_rsa_is_private(VALUE self) static int can_export_rsaprivatekey(VALUE self) { - RSA *rsa; + OSSL_3_const RSA *rsa; const BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp; GetRSA(self, rsa); @@ -197,13 +217,61 @@ can_export_rsaprivatekey(VALUE self) /* * call-seq: - * rsa.export([cipher, pass_phrase]) => PEM-format String - * rsa.to_pem([cipher, pass_phrase]) => PEM-format String - * rsa.to_s([cipher, pass_phrase]) => PEM-format String + * rsa.export([cipher, password]) => PEM-format String + * rsa.to_pem([cipher, password]) => PEM-format String + * rsa.to_s([cipher, password]) => PEM-format String + * + * Serializes a private or public key to a PEM-encoding. + * + * [When the key contains public components only] + * + * Serializes it into an X.509 SubjectPublicKeyInfo. + * The parameters _cipher_ and _password_ are ignored. + * + * A PEM-encoded key will look like: * - * Outputs this keypair in PEM encoding. If _cipher_ and _pass_phrase_ are - * given they will be used to encrypt the key. _cipher_ must be an - * OpenSSL::Cipher instance. + * -----BEGIN PUBLIC KEY----- + * [...] + * -----END PUBLIC KEY----- + * + * Consider using #public_to_pem instead. This serializes the key into an + * X.509 SubjectPublicKeyInfo regardless of whether the key is a public key + * or a private key. + * + * [When the key contains private components, and no parameters are given] + * + * Serializes it into a PKCS #1 RSAPrivateKey. + * + * A PEM-encoded key will look like: + * + * -----BEGIN RSA PRIVATE KEY----- + * [...] + * -----END RSA PRIVATE KEY----- + * + * [When the key contains private components, and _cipher_ and _password_ are given] + * + * Serializes it into a PKCS #1 RSAPrivateKey + * and encrypts it in OpenSSL's traditional PEM encryption format. + * _cipher_ must be a cipher name understood by OpenSSL::Cipher.new or an + * instance of OpenSSL::Cipher. + * + * An encrypted PEM-encoded key will look like: + * + * -----BEGIN RSA PRIVATE KEY----- + * Proc-Type: 4,ENCRYPTED + * DEK-Info: AES-128-CBC,733F5302505B34701FC41F5C0746E4C0 + * + * [...] + * -----END RSA PRIVATE KEY----- + * + * Note that this format uses MD5 to derive the encryption key, and hence + * will not be available on FIPS-compliant systems. + * + * <b>This method is kept for compatibility.</b> + * This should only be used when the PKCS #1 RSAPrivateKey format is required. + * + * Consider using #public_to_pem (X.509 SubjectPublicKeyInfo) or #private_to_pem + * (PKCS #8 PrivateKeyInfo or EncryptedPrivateKeyInfo) instead. */ static VALUE ossl_rsa_export(int argc, VALUE *argv, VALUE self) @@ -218,7 +286,14 @@ ossl_rsa_export(int argc, VALUE *argv, VALUE self) * call-seq: * rsa.to_der => DER-format String * - * Outputs this keypair in DER encoding. + * Serializes a private or public key to a DER-encoding. + * + * See #to_pem for details. + * + * <b>This method is kept for compatibility.</b> + * This should only be used when the PKCS #1 RSAPrivateKey format is required. + * + * Consider using #public_to_der or #private_to_der instead. */ static VALUE ossl_rsa_to_der(VALUE self) @@ -433,7 +508,7 @@ ossl_rsa_verify_pss(int argc, VALUE *argv, VALUE self) static VALUE ossl_rsa_get_params(VALUE self) { - RSA *rsa; + OSSL_3_const RSA *rsa; VALUE hash; const BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp; @@ -517,7 +592,9 @@ Init_ossl_rsa(void) cRSA = rb_define_class_under(mPKey, "RSA", cPKey); rb_define_method(cRSA, "initialize", ossl_rsa_initialize, -1); +#ifndef HAVE_EVP_PKEY_DUP rb_define_method(cRSA, "initialize_copy", ossl_rsa_initialize_copy, 1); +#endif rb_define_method(cRSA, "public?", ossl_rsa_is_public, 0); rb_define_method(cRSA, "private?", ossl_rsa_is_private, 0); |