summaryrefslogtreecommitdiff
path: root/ext/openssl/ossl_pkey_rsa.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/openssl/ossl_pkey_rsa.c')
-rw-r--r--ext/openssl/ossl_pkey_rsa.c193
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);