diff options
Diffstat (limited to 'ext/openssl/ossl_pkey_dsa.c')
-rw-r--r-- | ext/openssl/ossl_pkey_dsa.c | 176 |
1 files changed, 123 insertions, 53 deletions
diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c index 7af00eebec..058ce73888 100644 --- a/ext/openssl/ossl_pkey_dsa.c +++ b/ext/openssl/ossl_pkey_dsa.c @@ -24,7 +24,7 @@ } while (0) static inline int -DSA_HAS_PRIVATE(DSA *dsa) +DSA_HAS_PRIVATE(OSSL_3_const DSA *dsa) { const BIGNUM *bn; DSA_get0_key(dsa, NULL, &bn); @@ -32,7 +32,7 @@ DSA_HAS_PRIVATE(DSA *dsa) } static inline int -DSA_PRIVATE(VALUE obj, DSA *dsa) +DSA_PRIVATE(VALUE obj, OSSL_3_const DSA *dsa) { return DSA_HAS_PRIVATE(dsa) || OSSL_PKEY_IS_PRIVATE(obj); } @@ -83,72 +83,91 @@ VALUE eDSAError; static VALUE ossl_dsa_initialize(int argc, VALUE *argv, VALUE self) { - EVP_PKEY *pkey, *tmp; - DSA *dsa = NULL; - BIO *in; + EVP_PKEY *pkey; + DSA *dsa; + 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 DSA.new(size, generator) form is handled by lib/openssl/pkey.rb */ rb_scan_args(argc, argv, "02", &arg, &pass); if (argc == 0) { dsa = DSA_new(); if (!dsa) ossl_raise(eDSAError, "DSA_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_DSA) - rb_raise(eDSAError, "incorrect pkey type: %s", - OBJ_nid2sn(EVP_PKEY_base_id(tmp))); - dsa = EVP_PKEY_get1_DSA(tmp); - EVP_PKEY_free(tmp); - } - if (!dsa) { - OSSL_BIO_reset(in); -#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); - if (!dsa) { - ossl_clear_error(); - ossl_raise(eDSAError, "Neither PUB key nor PRIV key"); - } - } - if (!EVP_PKEY_assign_DSA(pkey, dsa)) { - DSA_free(dsa); - ossl_raise(eDSAError, NULL); + + pass = ossl_pem_passwd_value(pass); + arg = ossl_to_der_if_possible(arg); + in = ossl_obj2bio(&arg); + + /* DER-encoded DSAPublicKey format isn't supported by the generic routine */ + dsa = (DSA *)PEM_ASN1_read_bio((d2i_of_void *)d2i_DSAPublicKey, + PEM_STRING_DSA_PUBLIC, + in, NULL, NULL, NULL); + if (dsa) + goto legacy; + OSSL_BIO_reset(in); + + pkey = ossl_pkey_read_generic(in, pass); + BIO_free(in); + if (!pkey) + ossl_raise(eDSAError, "Neither PUB key nor PRIV key"); + + type = EVP_PKEY_base_id(pkey); + if (type != EVP_PKEY_DSA) { + EVP_PKEY_free(pkey); + rb_raise(eDSAError, "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_DSA(pkey, dsa) != 1) { + EVP_PKEY_free(pkey); + DSA_free(dsa); + ossl_raise(eDSAError, "EVP_PKEY_assign_DSA"); + } + RTYPEDDATA_DATA(self) = pkey; return self; } +#ifndef HAVE_EVP_PKEY_DUP 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"); + TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey); + if (pkey) + rb_raise(rb_eTypeError, "pkey already initialized"); GetDSA(other, dsa); - dsa_new = ASN1_dup((i2d_of_void *)i2d_DSAPrivateKey, (d2i_of_void *)d2i_DSAPrivateKey, (char *)dsa); + dsa_new = (DSA *)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); + pkey = EVP_PKEY_new(); + if (!pkey || EVP_PKEY_assign_DSA(pkey, dsa_new) != 1) { + EVP_PKEY_free(pkey); + DSA_free(dsa_new); + ossl_raise(eDSAError, "EVP_PKEY_assign_DSA"); + } + RTYPEDDATA_DATA(self) = pkey; return self; } +#endif /* * call-seq: @@ -160,7 +179,7 @@ ossl_dsa_initialize_copy(VALUE self, VALUE other) static VALUE ossl_dsa_is_public(VALUE self) { - DSA *dsa; + const DSA *dsa; const BIGNUM *bn; GetDSA(self, dsa); @@ -179,7 +198,7 @@ ossl_dsa_is_public(VALUE self) static VALUE ossl_dsa_is_private(VALUE self) { - DSA *dsa; + OSSL_3_const DSA *dsa; GetDSA(self, dsa); @@ -192,21 +211,63 @@ ossl_dsa_is_private(VALUE self) * dsa.to_pem([cipher, password]) -> aString * dsa.to_s([cipher, password]) -> aString * - * Encodes this DSA to its PEM encoding. + * 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: + * + * -----BEGIN PUBLIC KEY----- + * [...] + * -----END PUBLIC KEY----- + * + * Consider using #public_to_pem instead. This serializes the key into an + * X.509 SubjectPublicKeyInfo regardless of whether it is a public key + * or a private key. * - * === Parameters - * * _cipher_ is an OpenSSL::Cipher. - * * _password_ is a string containing your password. + * [When the key contains private components, and no parameters are given] * - * === Examples - * DSA.to_pem -> aString - * DSA.to_pem(cipher, 'mypassword') -> aString + * Serializes it into a traditional \OpenSSL DSAPrivateKey. * + * A PEM-encoded key will look like: + * + * -----BEGIN DSA PRIVATE KEY----- + * [...] + * -----END DSA PRIVATE KEY----- + * + * [When the key contains private components, and _cipher_ and _password_ are given] + * + * Serializes it into a traditional \OpenSSL DSAPrivateKey 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 DSA PRIVATE KEY----- + * Proc-Type: 4,ENCRYPTED + * DEK-Info: AES-128-CBC,733F5302505B34701FC41F5C0746E4C0 + * + * [...] + * -----END DSA 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 traditional, non-standard \OpenSSL format + * is required. + * + * Consider using #public_to_pem (X.509 SubjectPublicKeyInfo) or #private_to_pem + * (PKCS #8 PrivateKeyInfo or EncryptedPrivateKeyInfo) instead. */ static VALUE ossl_dsa_export(int argc, VALUE *argv, VALUE self) { - DSA *dsa; + OSSL_3_const DSA *dsa; GetDSA(self, dsa); if (DSA_HAS_PRIVATE(dsa)) @@ -219,13 +280,20 @@ ossl_dsa_export(int argc, VALUE *argv, VALUE self) * call-seq: * dsa.to_der -> aString * - * Encodes this DSA to its 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 traditional, non-standard \OpenSSL format + * is required. * + * Consider using #public_to_der or #private_to_der instead. */ static VALUE ossl_dsa_to_der(VALUE self) { - DSA *dsa; + OSSL_3_const DSA *dsa; GetDSA(self, dsa); if (DSA_HAS_PRIVATE(dsa)) @@ -246,7 +314,7 @@ ossl_dsa_to_der(VALUE self) static VALUE ossl_dsa_get_params(VALUE self) { - DSA *dsa; + OSSL_3_const DSA *dsa; VALUE hash; const BIGNUM *p, *q, *g, *pub_key, *priv_key; @@ -310,7 +378,9 @@ Init_ossl_dsa(void) cDSA = rb_define_class_under(mPKey, "DSA", cPKey); rb_define_method(cDSA, "initialize", ossl_dsa_initialize, -1); +#ifndef HAVE_EVP_PKEY_DUP rb_define_method(cDSA, "initialize_copy", ossl_dsa_initialize_copy, 1); +#endif rb_define_method(cDSA, "public?", ossl_dsa_is_public, 0); rb_define_method(cDSA, "private?", ossl_dsa_is_private, 0); |