1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

[ruby/openssl] pkey: port PKey::PKey#sign and #verify to the EVP_Digest* interface

Use EVP_DigestSign*() and EVP_DigestVerify*() interface instead of the
old EVP_Sign*() and EVP_Verify*() functions. They were added in OpenSSL
1.0.0.

Also, allow the digest to be specified as nil, as certain EVP_PKEY types
don't expect a digest algorithm.

9ff6e5143b
This commit is contained in:
Kazuki Yamaguchi 2017-05-15 23:47:47 +09:00
parent 1e3590fe22
commit 5cae289682
Notes: git 2021-03-16 20:38:52 +09:00
2 changed files with 63 additions and 39 deletions

View file

@ -753,35 +753,47 @@ static VALUE
ossl_pkey_sign(VALUE self, VALUE digest, VALUE data)
{
EVP_PKEY *pkey;
const EVP_MD *md;
const EVP_MD *md = NULL;
EVP_MD_CTX *ctx;
unsigned int buf_len;
VALUE str;
int result;
size_t siglen;
int state;
VALUE sig;
pkey = GetPrivPKeyPtr(self);
md = ossl_evp_get_digestbyname(digest);
if (!NIL_P(digest))
md = ossl_evp_get_digestbyname(digest);
StringValue(data);
str = rb_str_new(0, EVP_PKEY_size(pkey));
ctx = EVP_MD_CTX_new();
if (!ctx)
ossl_raise(ePKeyError, "EVP_MD_CTX_new");
if (!EVP_SignInit_ex(ctx, md, NULL)) {
EVP_MD_CTX_free(ctx);
ossl_raise(ePKeyError, "EVP_SignInit_ex");
ossl_raise(ePKeyError, "EVP_MD_CTX_new");
if (EVP_DigestSignInit(ctx, NULL, md, /* engine */NULL, pkey) < 1) {
EVP_MD_CTX_free(ctx);
ossl_raise(ePKeyError, "EVP_DigestSignInit");
}
if (!EVP_SignUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data))) {
EVP_MD_CTX_free(ctx);
ossl_raise(ePKeyError, "EVP_SignUpdate");
if (EVP_DigestSignUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)) < 1) {
EVP_MD_CTX_free(ctx);
ossl_raise(ePKeyError, "EVP_DigestSignUpdate");
}
if (EVP_DigestSignFinal(ctx, NULL, &siglen) < 1) {
EVP_MD_CTX_free(ctx);
ossl_raise(ePKeyError, "EVP_DigestSignFinal");
}
if (siglen > LONG_MAX)
rb_raise(ePKeyError, "signature would be too large");
sig = ossl_str_new(NULL, (long)siglen, &state);
if (state) {
EVP_MD_CTX_free(ctx);
rb_jump_tag(state);
}
if (EVP_DigestSignFinal(ctx, (unsigned char *)RSTRING_PTR(sig),
&siglen) < 1) {
EVP_MD_CTX_free(ctx);
ossl_raise(ePKeyError, "EVP_DigestSignFinal");
}
result = EVP_SignFinal(ctx, (unsigned char *)RSTRING_PTR(str), &buf_len, pkey);
EVP_MD_CTX_free(ctx);
if (!result)
ossl_raise(ePKeyError, "EVP_SignFinal");
rb_str_set_len(str, buf_len);
return str;
rb_str_set_len(sig, siglen);
return sig;
}
/*
@ -809,38 +821,38 @@ static VALUE
ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data)
{
EVP_PKEY *pkey;
const EVP_MD *md;
const EVP_MD *md = NULL;
EVP_MD_CTX *ctx;
int siglen, result;
int ret;
GetPKey(self, pkey);
ossl_pkey_check_public_key(pkey);
md = ossl_evp_get_digestbyname(digest);
if (!NIL_P(digest))
md = ossl_evp_get_digestbyname(digest);
StringValue(sig);
siglen = RSTRING_LENINT(sig);
StringValue(data);
ctx = EVP_MD_CTX_new();
if (!ctx)
ossl_raise(ePKeyError, "EVP_MD_CTX_new");
if (!EVP_VerifyInit_ex(ctx, md, NULL)) {
EVP_MD_CTX_free(ctx);
ossl_raise(ePKeyError, "EVP_VerifyInit_ex");
ossl_raise(ePKeyError, "EVP_MD_CTX_new");
if (EVP_DigestVerifyInit(ctx, NULL, md, /* engine */NULL, pkey) < 1) {
EVP_MD_CTX_free(ctx);
ossl_raise(ePKeyError, "EVP_DigestVerifyInit");
}
if (!EVP_VerifyUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data))) {
EVP_MD_CTX_free(ctx);
ossl_raise(ePKeyError, "EVP_VerifyUpdate");
if (EVP_DigestVerifyUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)) < 1) {
EVP_MD_CTX_free(ctx);
ossl_raise(ePKeyError, "EVP_DigestVerifyUpdate");
}
result = EVP_VerifyFinal(ctx, (unsigned char *)RSTRING_PTR(sig), siglen, pkey);
ret = EVP_DigestVerifyFinal(ctx, (unsigned char *)RSTRING_PTR(sig),
RSTRING_LEN(sig));
EVP_MD_CTX_free(ctx);
switch (result) {
case 0:
ossl_clear_error();
return Qfalse;
case 1:
return Qtrue;
default:
ossl_raise(ePKeyError, "EVP_VerifyFinal");
if (ret < 0)
ossl_raise(ePKeyError, "EVP_DigestVerifyFinal");
if (ret)
return Qtrue;
else {
ossl_clear_error();
return Qfalse;
}
}

View file

@ -68,4 +68,16 @@ class OpenSSL::TestPKey < OpenSSL::PKeyTestCase
assert_equal 512, pkey.p.num_bits
assert_not_equal nil, pkey.priv_key
end
def test_hmac_sign_verify
pkey = OpenSSL::PKey.generate_key("HMAC", { "key" => "abcd" })
hmac = OpenSSL::HMAC.new("abcd", "SHA256").update("data").digest
assert_equal hmac, pkey.sign("SHA256", "data")
# EVP_PKEY_HMAC does not support verify
assert_raise(OpenSSL::PKey::PKeyError) {
pkey.verify("SHA256", "data", hmac)
}
end
end