Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 54 additions & 24 deletions ext/openssl/ossl_cipher.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
static VALUE cCipher;
static VALUE eCipherError;
static VALUE eAuthTagError;
static ID id_auth_tag_len, id_key_set;
static ID id_auth_tag_len, id_key_set, id_cipher_holder;

static VALUE ossl_cipher_alloc(VALUE klass);
static void ossl_cipher_free(void *ptr);
Expand All @@ -46,30 +46,58 @@ static const rb_data_type_t ossl_cipher_type = {
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};

#ifdef OSSL_USE_PROVIDER
static void
ossl_evp_cipher_free(void *ptr)
{
// This is safe to call against const EVP_CIPHER * returned by
// EVP_get_cipherbyname()
EVP_CIPHER_free(ptr);
}

static const rb_data_type_t ossl_evp_cipher_holder_type = {
"OpenSSL/EVP_CIPHER",
{
.dfree = ossl_evp_cipher_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
#endif

/*
* PUBLIC
*/
const EVP_CIPHER *
ossl_evp_get_cipherbyname(VALUE obj)
ossl_evp_cipher_fetch(VALUE obj, volatile VALUE *holder)
{
*holder = Qnil;
if (rb_obj_is_kind_of(obj, cCipher)) {
EVP_CIPHER_CTX *ctx;

GetCipher(obj, ctx);

return EVP_CIPHER_CTX_cipher(ctx);
EVP_CIPHER_CTX *ctx;
GetCipher(obj, ctx);
EVP_CIPHER *cipher = (EVP_CIPHER *)EVP_CIPHER_CTX_cipher(ctx);
#ifdef OSSL_USE_PROVIDER
*holder = TypedData_Wrap_Struct(0, &ossl_evp_cipher_holder_type, NULL);
if (!EVP_CIPHER_up_ref(cipher))
ossl_raise(eCipherError, "EVP_CIPHER_up_ref");
RTYPEDDATA_DATA(*holder) = cipher;
#endif
return cipher;
}
else {
const EVP_CIPHER *cipher;

StringValueCStr(obj);
cipher = EVP_get_cipherbyname(RSTRING_PTR(obj));
if (!cipher)
ossl_raise(rb_eArgError,
"unsupported cipher algorithm: %"PRIsVALUE, obj);

return cipher;
const char *name = StringValueCStr(obj);
EVP_CIPHER *cipher = (EVP_CIPHER *)EVP_get_cipherbyname(name);
#ifdef OSSL_USE_PROVIDER
if (!cipher) {
ossl_clear_error();
*holder = TypedData_Wrap_Struct(0, &ossl_evp_cipher_holder_type, NULL);
cipher = EVP_CIPHER_fetch(NULL, name, NULL);
RTYPEDDATA_DATA(*holder) = cipher;
}
#endif
if (!cipher)
ossl_raise(eCipherError, "unsupported cipher algorithm: %"PRIsVALUE,
obj);
return cipher;
}

VALUE
Expand All @@ -78,6 +106,9 @@ ossl_cipher_new(const EVP_CIPHER *cipher)
VALUE ret;
EVP_CIPHER_CTX *ctx;

// NOTE: This does not set id_cipher_holder because this function should
// only be called from ossl_engine.c, which will not use any
// reference-counted ciphers.
ret = ossl_cipher_alloc(cCipher);
AllocCipher(ret, ctx);
if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, -1) != 1)
Expand Down Expand Up @@ -114,19 +145,17 @@ ossl_cipher_initialize(VALUE self, VALUE str)
{
EVP_CIPHER_CTX *ctx;
const EVP_CIPHER *cipher;
char *name;
VALUE cipher_holder;

name = StringValueCStr(str);
GetCipherInit(self, ctx);
if (ctx) {
ossl_raise(rb_eRuntimeError, "Cipher already initialized!");
}
cipher = ossl_evp_cipher_fetch(str, &cipher_holder);
AllocCipher(self, ctx);
if (!(cipher = EVP_get_cipherbyname(name))) {
ossl_raise(rb_eRuntimeError, "unsupported cipher algorithm (%"PRIsVALUE")", str);
}
if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, -1) != 1)
ossl_raise(eCipherError, NULL);
ossl_raise(eCipherError, "EVP_CipherInit_ex");
rb_ivar_set(self, id_cipher_holder, cipher_holder);

return self;
}
Expand Down Expand Up @@ -268,7 +297,7 @@ ossl_cipher_pkcs5_keyivgen(int argc, VALUE *argv, VALUE self)
{
EVP_CIPHER_CTX *ctx;
const EVP_MD *digest;
VALUE vpass, vsalt, viter, vdigest;
VALUE vpass, vsalt, viter, vdigest, md_holder;
unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH], *salt = NULL;
int iter;

Expand All @@ -283,7 +312,7 @@ ossl_cipher_pkcs5_keyivgen(int argc, VALUE *argv, VALUE self)
iter = NIL_P(viter) ? 2048 : NUM2INT(viter);
if (iter <= 0)
rb_raise(rb_eArgError, "iterations must be a positive integer");
digest = NIL_P(vdigest) ? EVP_md5() : ossl_evp_get_digestbyname(vdigest);
digest = NIL_P(vdigest) ? EVP_md5() : ossl_evp_md_fetch(vdigest, &md_holder);
GetCipher(self, ctx);
EVP_BytesToKey(EVP_CIPHER_CTX_cipher(ctx), digest, salt,
(unsigned char *)RSTRING_PTR(vpass), RSTRING_LENINT(vpass), iter, key, iv);
Expand Down Expand Up @@ -1110,4 +1139,5 @@ Init_ossl_cipher(void)

id_auth_tag_len = rb_intern_const("auth_tag_len");
id_key_set = rb_intern_const("key_set");
id_cipher_holder = rb_intern_const("EVP_CIPHER_holder");
}
11 changes: 10 additions & 1 deletion ext/openssl/ossl_cipher.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,16 @@
#if !defined(_OSSL_CIPHER_H_)
#define _OSSL_CIPHER_H_

const EVP_CIPHER *ossl_evp_get_cipherbyname(VALUE);
/*
* Gets EVP_CIPHER from a String or an OpenSSL::Digest instance (discouraged,
* but still supported for compatibility). A holder object is created if the
* EVP_CIPHER is a "fetched" algorithm.
*/
const EVP_CIPHER *ossl_evp_cipher_fetch(VALUE obj, volatile VALUE *holder);
/*
* This is meant for OpenSSL::Engine#cipher. EVP_CIPHER must not be a fetched
* one.
*/
VALUE ossl_cipher_new(const EVP_CIPHER *);
void Init_ossl_cipher(void);

Expand Down
77 changes: 56 additions & 21 deletions ext/openssl/ossl_digest.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
*/
static VALUE cDigest;
static VALUE eDigestError;
static ID id_md_holder;

static VALUE ossl_digest_alloc(VALUE klass);

Expand All @@ -38,34 +39,62 @@ static const rb_data_type_t ossl_digest_type = {
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};

#ifdef OSSL_USE_PROVIDER
static void
ossl_evp_md_free(void *ptr)
{
// This is safe to call against const EVP_MD * returned by
// EVP_get_digestbyname()
EVP_MD_free(ptr);
}

static const rb_data_type_t ossl_evp_md_holder_type = {
"OpenSSL/EVP_MD",
{
.dfree = ossl_evp_md_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
#endif

/*
* Public
*/
const EVP_MD *
ossl_evp_get_digestbyname(VALUE obj)
ossl_evp_md_fetch(VALUE obj, volatile VALUE *holder)
{
const EVP_MD *md;
ASN1_OBJECT *oid = NULL;

if (RB_TYPE_P(obj, T_STRING)) {
const char *name = StringValueCStr(obj);

md = EVP_get_digestbyname(name);
if (!md) {
oid = OBJ_txt2obj(name, 0);
md = EVP_get_digestbyobj(oid);
ASN1_OBJECT_free(oid);
}
if(!md)
ossl_raise(rb_eRuntimeError, "Unsupported digest algorithm (%"PRIsVALUE").", obj);
} else {
*holder = Qnil;
if (rb_obj_is_kind_of(obj, cDigest)) {
EVP_MD_CTX *ctx;

GetDigest(obj, ctx);

md = EVP_MD_CTX_get0_md(ctx);
EVP_MD *md = (EVP_MD *)EVP_MD_CTX_get0_md(ctx);
#ifdef OSSL_USE_PROVIDER
*holder = TypedData_Wrap_Struct(0, &ossl_evp_md_holder_type, NULL);
if (!EVP_MD_up_ref(md))
ossl_raise(eDigestError, "EVP_MD_up_ref");
RTYPEDDATA_DATA(*holder) = md;
#endif
return md;
}

const char *name = StringValueCStr(obj);
EVP_MD *md = (EVP_MD *)EVP_get_digestbyname(name);
if (!md) {
ASN1_OBJECT *oid = OBJ_txt2obj(name, 0);
md = (EVP_MD *)EVP_get_digestbyobj(oid);
ASN1_OBJECT_free(oid);
}
#ifdef OSSL_USE_PROVIDER
if (!md) {
ossl_clear_error();
*holder = TypedData_Wrap_Struct(0, &ossl_evp_md_holder_type, NULL);
md = EVP_MD_fetch(NULL, name, NULL);
RTYPEDDATA_DATA(*holder) = md;
}
#endif
if (!md)
ossl_raise(eDigestError, "unsupported digest algorithm: %"PRIsVALUE,
obj);
return md;
}

Expand All @@ -75,6 +104,9 @@ ossl_digest_new(const EVP_MD *md)
VALUE ret;
EVP_MD_CTX *ctx;

// NOTE: This does not set id_md_holder because this function should
// only be called from ossl_engine.c, which will not use any
// reference-counted digests.
ret = ossl_digest_alloc(cDigest);
ctx = EVP_MD_CTX_new();
if (!ctx)
Expand Down Expand Up @@ -121,10 +153,10 @@ ossl_digest_initialize(int argc, VALUE *argv, VALUE self)
{
EVP_MD_CTX *ctx;
const EVP_MD *md;
VALUE type, data;
VALUE type, data, md_holder;

rb_scan_args(argc, argv, "11", &type, &data);
md = ossl_evp_get_digestbyname(type);
md = ossl_evp_md_fetch(type, &md_holder);
if (!NIL_P(data)) StringValue(data);

TypedData_Get_Struct(self, EVP_MD_CTX, &ossl_digest_type, ctx);
Expand All @@ -136,6 +168,7 @@ ossl_digest_initialize(int argc, VALUE *argv, VALUE self)

if (!EVP_DigestInit_ex(ctx, md, NULL))
ossl_raise(eDigestError, "Digest initialization failed");
rb_ivar_set(self, id_md_holder, md_holder);

if (!NIL_P(data)) return ossl_digest_update(self, data);
return self;
Expand Down Expand Up @@ -442,4 +475,6 @@ Init_ossl_digest(void)
rb_define_method(cDigest, "block_length", ossl_digest_block_length, 0);

rb_define_method(cDigest, "name", ossl_digest_name, 0);

id_md_holder = rb_intern_const("EVP_MD_holder");
}
10 changes: 9 additions & 1 deletion ext/openssl/ossl_digest.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,15 @@
#if !defined(_OSSL_DIGEST_H_)
#define _OSSL_DIGEST_H_

const EVP_MD *ossl_evp_get_digestbyname(VALUE);
/*
* Gets EVP_MD from a String or an OpenSSL::Digest instance (discouraged, but
* still supported for compatibility). A holder object is created if the EVP_MD
* is a "fetched" algorithm.
*/
const EVP_MD *ossl_evp_md_fetch(VALUE obj, volatile VALUE *holder);
/*
* This is meant for OpenSSL::Engine#digest. EVP_MD must not be a fetched one.
*/
VALUE ossl_digest_new(const EVP_MD *);
void Init_ossl_digest(void);

Expand Down
10 changes: 8 additions & 2 deletions ext/openssl/ossl_hmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
*/
static VALUE cHMAC;
static VALUE eHMACError;
static ID id_md_holder;

/*
* Public
Expand Down Expand Up @@ -94,16 +95,19 @@ ossl_hmac_initialize(VALUE self, VALUE key, VALUE digest)
{
EVP_MD_CTX *ctx;
EVP_PKEY *pkey;
const EVP_MD *md;
VALUE md_holder;

GetHMAC(self, ctx);
StringValue(key);
md = ossl_evp_md_fetch(digest, &md_holder);
rb_ivar_set(self, id_md_holder, md_holder);
pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, NULL,
(unsigned char *)RSTRING_PTR(key),
RSTRING_LENINT(key));
if (!pkey)
ossl_raise(eHMACError, "EVP_PKEY_new_raw_private_key");
if (EVP_DigestSignInit(ctx, NULL, ossl_evp_get_digestbyname(digest),
NULL, pkey) != 1) {
if (EVP_DigestSignInit(ctx, NULL, md, NULL, pkey) != 1) {
EVP_PKEY_free(pkey);
ossl_raise(eHMACError, "EVP_DigestSignInit");
}
Expand Down Expand Up @@ -300,4 +304,6 @@ Init_ossl_hmac(void)
rb_define_method(cHMAC, "hexdigest", ossl_hmac_hexdigest, 0);
rb_define_alias(cHMAC, "inspect", "hexdigest");
rb_define_alias(cHMAC, "to_s", "hexdigest");

id_md_holder = rb_intern_const("EVP_MD_holder");
}
8 changes: 4 additions & 4 deletions ext/openssl/ossl_kdf.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ static VALUE mKDF, eKDF;
static VALUE
kdf_pbkdf2_hmac(int argc, VALUE *argv, VALUE self)
{
VALUE pass, salt, opts, kwargs[4], str;
VALUE pass, salt, opts, kwargs[4], str, md_holder;
static ID kwargs_ids[4];
int iters, len;
const EVP_MD *md;
Expand All @@ -53,7 +53,7 @@ kdf_pbkdf2_hmac(int argc, VALUE *argv, VALUE self)
salt = StringValue(kwargs[0]);
iters = NUM2INT(kwargs[1]);
len = NUM2INT(kwargs[2]);
md = ossl_evp_get_digestbyname(kwargs[3]);
md = ossl_evp_md_fetch(kwargs[3], &md_holder);

str = rb_str_new(0, len);
if (!PKCS5_PBKDF2_HMAC(RSTRING_PTR(pass), RSTRING_LENINT(pass),
Expand Down Expand Up @@ -172,7 +172,7 @@ kdf_scrypt(int argc, VALUE *argv, VALUE self)
static VALUE
kdf_hkdf(int argc, VALUE *argv, VALUE self)
{
VALUE ikm, salt, info, opts, kwargs[4], str;
VALUE ikm, salt, info, opts, kwargs[4], str, md_holder;
static ID kwargs_ids[4];
int saltlen, ikmlen, infolen;
size_t len;
Expand All @@ -197,7 +197,7 @@ kdf_hkdf(int argc, VALUE *argv, VALUE self)
len = (size_t)NUM2LONG(kwargs[2]);
if (len > LONG_MAX)
rb_raise(rb_eArgError, "length must be non-negative");
md = ossl_evp_get_digestbyname(kwargs[3]);
md = ossl_evp_md_fetch(kwargs[3], &md_holder);

str = rb_str_new(NULL, (long)len);
pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
Expand Down
8 changes: 4 additions & 4 deletions ext/openssl/ossl_ns_spki.c
Original file line number Diff line number Diff line change
Expand Up @@ -283,13 +283,13 @@ ossl_spki_sign(VALUE self, VALUE key, VALUE digest)
NETSCAPE_SPKI *spki;
EVP_PKEY *pkey;
const EVP_MD *md;
VALUE md_holder;

pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
md = ossl_evp_get_digestbyname(digest);
md = ossl_evp_md_fetch(digest, &md_holder);
GetSPKI(self, spki);
if (!NETSCAPE_SPKI_sign(spki, pkey, md)) {
ossl_raise(eSPKIError, NULL);
}
if (!NETSCAPE_SPKI_sign(spki, pkey, md))
ossl_raise(eSPKIError, "NETSCAPE_SPKI_sign");

return self;
}
Expand Down
Loading
Loading