class OpenSSL::PKey::PKey

An abstract class that bundles signature creation (PKey#sign) and validation (PKey#verify) that is common to all implementations except OpenSSL::PKey::DH

Public Class Methods

new → self click to toggle source

Because PKey is an abstract class, actually calling this method explicitly will raise a NotImplementedError.

static VALUE
ossl_pkey_initialize(VALUE self)
{
    if (rb_obj_is_instance_of(self, cPKey)) {
        ossl_raise(rb_eTypeError, "OpenSSL::PKey::PKey can't be instantiated directly");
    }
    return self;
}

Public Instance Methods

compare?(another_pkey) → true | false click to toggle source

Used primarily to check if an OpenSSL::X509::Certificate#public_key compares to its private key.

Example

x509 = OpenSSL::X509::Certificate.new(pem_encoded_certificate)
rsa_key = OpenSSL::PKey::RSA.new(pem_encoded_private_key)

rsa_key.compare?(x509.public_key) => true | false
static VALUE
ossl_pkey_compare(VALUE self, VALUE other)
{
    int ret;
    EVP_PKEY *selfPKey;
    EVP_PKEY *otherPKey;

    GetPKey(self, selfPKey);
    GetPKey(other, otherPKey);

    /* Explicitly check the key type given EVP_PKEY_ASN1_METHOD(3)
     * docs param_cmp could return any negative number.
     */
    if (EVP_PKEY_id(selfPKey) != EVP_PKEY_id(otherPKey))
        ossl_raise(rb_eTypeError, "cannot match different PKey types");

    ret = EVP_PKEY_eq(selfPKey, otherPKey);

    if (ret == 0)
        return Qfalse;
    else if (ret == 1)
        return Qtrue;
    else
        ossl_raise(ePKeyError, "EVP_PKEY_eq");
}
decrypt(data [, options]) → string click to toggle source

Performs a public key decryption operation using pkey.

See encrypt for a description of the parameters and an example.

Added in version 3.0. See also the man page EVP_PKEY_decrypt(3).

static VALUE
ossl_pkey_decrypt(int argc, VALUE *argv, VALUE self)
{
    EVP_PKEY *pkey;
    EVP_PKEY_CTX *ctx;
    VALUE data, options, str;
    size_t outlen;
    int state;

    GetPKey(self, pkey);
    rb_scan_args(argc, argv, "11", &data, &options);
    StringValue(data);

    ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
    if (!ctx)
        ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
    if (EVP_PKEY_decrypt_init(ctx) <= 0) {
        EVP_PKEY_CTX_free(ctx);
        ossl_raise(ePKeyError, "EVP_PKEY_decrypt_init");
    }
    if (!NIL_P(options)) {
        pkey_ctx_apply_options(ctx, options, &state);
        if (state) {
            EVP_PKEY_CTX_free(ctx);
            rb_jump_tag(state);
        }
    }
    if (EVP_PKEY_decrypt(ctx, NULL, &outlen,
                         (unsigned char *)RSTRING_PTR(data),
                         RSTRING_LEN(data)) <= 0) {
        EVP_PKEY_CTX_free(ctx);
        ossl_raise(ePKeyError, "EVP_PKEY_decrypt");
    }
    if (outlen > LONG_MAX) {
        EVP_PKEY_CTX_free(ctx);
        rb_raise(ePKeyError, "decrypted data would be too large");
    }
    str = ossl_str_new(NULL, (long)outlen, &state);
    if (state) {
        EVP_PKEY_CTX_free(ctx);
        rb_jump_tag(state);
    }
    if (EVP_PKEY_decrypt(ctx, (unsigned char *)RSTRING_PTR(str), &outlen,
                         (unsigned char *)RSTRING_PTR(data),
                         RSTRING_LEN(data)) <= 0) {
        EVP_PKEY_CTX_free(ctx);
        ossl_raise(ePKeyError, "EVP_PKEY_decrypt");
    }
    EVP_PKEY_CTX_free(ctx);
    rb_str_set_len(str, outlen);
    return str;
}
derive(peer_pkey) → string click to toggle source

Derives a shared secret from pkey and peer_pkey. pkey must contain the private components, peer_pkey must contain the public components.

static VALUE
ossl_pkey_derive(int argc, VALUE *argv, VALUE self)
{
    EVP_PKEY *pkey, *peer_pkey;
    EVP_PKEY_CTX *ctx;
    VALUE peer_pkey_obj, str;
    size_t keylen;
    int state;

    GetPKey(self, pkey);
    rb_scan_args(argc, argv, "1", &peer_pkey_obj);
    GetPKey(peer_pkey_obj, peer_pkey);

    ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
    if (!ctx)
        ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
    if (EVP_PKEY_derive_init(ctx) <= 0) {
        EVP_PKEY_CTX_free(ctx);
        ossl_raise(ePKeyError, "EVP_PKEY_derive_init");
    }
    if (EVP_PKEY_derive_set_peer(ctx, peer_pkey) <= 0) {
        EVP_PKEY_CTX_free(ctx);
        ossl_raise(ePKeyError, "EVP_PKEY_derive_set_peer");
    }
    if (EVP_PKEY_derive(ctx, NULL, &keylen) <= 0) {
        EVP_PKEY_CTX_free(ctx);
        ossl_raise(ePKeyError, "EVP_PKEY_derive");
    }
    if (keylen > LONG_MAX)
        rb_raise(ePKeyError, "derived key would be too large");
    str = ossl_str_new(NULL, (long)keylen, &state);
    if (state) {
        EVP_PKEY_CTX_free(ctx);
        rb_jump_tag(state);
    }
    if (EVP_PKEY_derive(ctx, (unsigned char *)RSTRING_PTR(str), &keylen) <= 0) {
        EVP_PKEY_CTX_free(ctx);
        ossl_raise(ePKeyError, "EVP_PKEY_derive");
    }
    EVP_PKEY_CTX_free(ctx);
    rb_str_set_len(str, keylen);
    return str;
}
encrypt(data [, options]) → string click to toggle source

Performs a public key encryption operation using pkey.

See decrypt for the reverse operation.

Added in version 3.0. See also the man page EVP_PKEY_encrypt(3).

data

A String to be encrypted.

options

A Hash that contains algorithm specific control operations to OpenSSL. See OpenSSL’s man page EVP_PKEY_CTX_ctrl_str(3) for details.

Example:

pkey = OpenSSL::PKey.generate_key("RSA", rsa_keygen_bits: 2048)
data = "secret data"
encrypted = pkey.encrypt(data, rsa_padding_mode: "oaep")
decrypted = pkey.decrypt(data, rsa_padding_mode: "oaep")
p decrypted #=> "secret data"
static VALUE
ossl_pkey_encrypt(int argc, VALUE *argv, VALUE self)
{
    EVP_PKEY *pkey;
    EVP_PKEY_CTX *ctx;
    VALUE data, options, str;
    size_t outlen;
    int state;

    GetPKey(self, pkey);
    rb_scan_args(argc, argv, "11", &data, &options);
    StringValue(data);

    ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
    if (!ctx)
        ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
    if (EVP_PKEY_encrypt_init(ctx) <= 0) {
        EVP_PKEY_CTX_free(ctx);
        ossl_raise(ePKeyError, "EVP_PKEY_encrypt_init");
    }
    if (!NIL_P(options)) {
        pkey_ctx_apply_options(ctx, options, &state);
        if (state) {
            EVP_PKEY_CTX_free(ctx);
            rb_jump_tag(state);
        }
    }
    if (EVP_PKEY_encrypt(ctx, NULL, &outlen,
                         (unsigned char *)RSTRING_PTR(data),
                         RSTRING_LEN(data)) <= 0) {
        EVP_PKEY_CTX_free(ctx);
        ossl_raise(ePKeyError, "EVP_PKEY_encrypt");
    }
    if (outlen > LONG_MAX) {
        EVP_PKEY_CTX_free(ctx);
        rb_raise(ePKeyError, "encrypted data would be too large");
    }
    str = ossl_str_new(NULL, (long)outlen, &state);
    if (state) {
        EVP_PKEY_CTX_free(ctx);
        rb_jump_tag(state);
    }
    if (EVP_PKEY_encrypt(ctx, (unsigned char *)RSTRING_PTR(str), &outlen,
                         (unsigned char *)RSTRING_PTR(data),
                         RSTRING_LEN(data)) <= 0) {
        EVP_PKEY_CTX_free(ctx);
        ossl_raise(ePKeyError, "EVP_PKEY_encrypt");
    }
    EVP_PKEY_CTX_free(ctx);
    rb_str_set_len(str, outlen);
    return str;
}
initialize_copy(p1) click to toggle source
static VALUE
ossl_pkey_initialize_copy(VALUE self, VALUE other)
{
    EVP_PKEY *pkey, *pkey_other;

    TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);
    TypedData_Get_Struct(other, EVP_PKEY, &ossl_evp_pkey_type, pkey_other);
    if (pkey)
        rb_raise(rb_eTypeError, "pkey already initialized");
    if (pkey_other) {
        pkey = EVP_PKEY_dup(pkey_other);
        if (!pkey)
            ossl_raise(ePKeyError, "EVP_PKEY_dup");
        RTYPEDDATA_DATA(self) = pkey;
    }
    return self;
}
inspect → string click to toggle source

Returns a string describing the PKey object.

static VALUE
ossl_pkey_inspect(VALUE self)
{
    EVP_PKEY *pkey;
    int nid;

    GetPKey(self, pkey);
    nid = EVP_PKEY_id(pkey);
    return rb_sprintf("#<%"PRIsVALUE":%p oid=%s>",
                      rb_class_name(CLASS_OF(self)), (void *)self,
                      OBJ_nid2sn(nid));
}
oid → string click to toggle source

Returns the short name of the OID associated with pkey.

static VALUE
ossl_pkey_oid(VALUE self)
{
    EVP_PKEY *pkey;
    int nid;

    GetPKey(self, pkey);
    nid = EVP_PKEY_id(pkey);
    return rb_str_new_cstr(OBJ_nid2sn(nid));
}
private_to_der → string click to toggle source
private_to_der(cipher, password) → string

Serializes the private key to DER-encoded PKCS #8 format. If called without arguments, unencrypted PKCS #8 PrivateKeyInfo format is used. If called with a cipher name and a password, PKCS #8 EncryptedPrivateKeyInfo format with PBES2 encryption scheme is used.

static VALUE
ossl_pkey_private_to_der(int argc, VALUE *argv, VALUE self)
{
    return do_pkcs8_export(argc, argv, self, 1);
}
private_to_pem → string click to toggle source
private_to_pem(cipher, password) → string

Serializes the private key to PEM-encoded PKCS #8 format. See private_to_der for more details.

static VALUE
ossl_pkey_private_to_pem(int argc, VALUE *argv, VALUE self)
{
    return do_pkcs8_export(argc, argv, self, 0);
}
public_to_der → string click to toggle source

Serializes the public key to DER-encoded X.509 SubjectPublicKeyInfo format.

static VALUE
ossl_pkey_public_to_der(VALUE self)
{
    return ossl_pkey_export_spki(self, 1);
}
public_to_pem → string click to toggle source

Serializes the public key to PEM-encoded X.509 SubjectPublicKeyInfo format.

static VALUE
ossl_pkey_public_to_pem(VALUE self)
{
    return ossl_pkey_export_spki(self, 0);
}
sign(digest, data [, options]) → string click to toggle source

Hashes and signs the data using a message digest algorithm digest and a private key pkey.

See verify for the verification operation.

See also the man page EVP_DigestSign(3).

digest

A String that represents the message digest algorithm name, or nil if the PKey type requires no digest algorithm. For backwards compatibility, this can be an instance of OpenSSL::Digest. Its state will not affect the signature.

data

A String. The data to be hashed and signed.

options

A Hash that contains algorithm specific control operations to OpenSSL. See OpenSSL’s man page EVP_PKEY_CTX_ctrl_str(3) for details. options parameter was added in version 3.0.

Example:

data = "Sign me!"
pkey = OpenSSL::PKey.generate_key("RSA", rsa_keygen_bits: 2048)
signopts = { rsa_padding_mode: "pss" }
signature = pkey.sign("SHA256", data, signopts)

# Creates a copy of the RSA key pkey, but without the private components
pub_key = pkey.public_key
puts pub_key.verify("SHA256", signature, data, signopts) # => true
static VALUE
ossl_pkey_sign(int argc, VALUE *argv, VALUE self)
{
    EVP_PKEY *pkey;
    VALUE digest, data, options, sig;
    const EVP_MD *md = NULL;
    EVP_MD_CTX *ctx;
    EVP_PKEY_CTX *pctx;
    size_t siglen;
    int state;

    pkey = GetPrivPKeyPtr(self);
    rb_scan_args(argc, argv, "21", &digest, &data, &options);
    if (!NIL_P(digest))
        md = ossl_evp_get_digestbyname(digest);
    StringValue(data);

    ctx = EVP_MD_CTX_new();
    if (!ctx)
        ossl_raise(ePKeyError, "EVP_MD_CTX_new");
    if (EVP_DigestSignInit(ctx, &pctx, md, /* engine */NULL, pkey) < 1) {
        EVP_MD_CTX_free(ctx);
        ossl_raise(ePKeyError, "EVP_DigestSignInit");
    }
    if (!NIL_P(options)) {
        pkey_ctx_apply_options(pctx, options, &state);
        if (state) {
            EVP_MD_CTX_free(ctx);
            rb_jump_tag(state);
        }
    }
#if OPENSSL_VERSION_NUMBER >= 0x10101000 && !defined(LIBRESSL_VERSION_NUMBER)
    if (EVP_DigestSign(ctx, NULL, &siglen, (unsigned char *)RSTRING_PTR(data),
                       RSTRING_LEN(data)) < 1) {
        EVP_MD_CTX_free(ctx);
        ossl_raise(ePKeyError, "EVP_DigestSign");
    }
    if (siglen > LONG_MAX) {
        EVP_MD_CTX_free(ctx);
        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_DigestSign(ctx, (unsigned char *)RSTRING_PTR(sig), &siglen,
                       (unsigned char *)RSTRING_PTR(data),
                       RSTRING_LEN(data)) < 1) {
        EVP_MD_CTX_free(ctx);
        ossl_raise(ePKeyError, "EVP_DigestSign");
    }
#else
    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) {
        EVP_MD_CTX_free(ctx);
        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");
    }
#endif
    EVP_MD_CTX_free(ctx);
    rb_str_set_len(sig, siglen);
    return sig;
}
sign_raw(digest, data [, options]) → string click to toggle source

Signs data using a private key pkey. Unlike sign, data will not be hashed by digest automatically.

See verify_raw for the verification operation.

Added in version 3.0. See also the man page EVP_PKEY_sign(3).

digest

A String that represents the message digest algorithm name, or nil if the PKey type requires no digest algorithm. Although this method will not hash data with it, this parameter may still be required depending on the signature algorithm.

data

A String. The data to be signed.

options

A Hash that contains algorithm specific control operations to OpenSSL. See OpenSSL’s man page EVP_PKEY_CTX_ctrl_str(3) for details.

Example:

data = "Sign me!"
hash = OpenSSL::Digest.digest("SHA256", data)
pkey = OpenSSL::PKey.generate_key("RSA", rsa_keygen_bits: 2048)
signopts = { rsa_padding_mode: "pss" }
signature = pkey.sign_raw("SHA256", hash, signopts)

# Creates a copy of the RSA key pkey, but without the private components
pub_key = pkey.public_key
puts pub_key.verify_raw("SHA256", signature, hash, signopts) # => true
static VALUE
ossl_pkey_sign_raw(int argc, VALUE *argv, VALUE self)
{
    EVP_PKEY *pkey;
    VALUE digest, data, options, sig;
    const EVP_MD *md = NULL;
    EVP_PKEY_CTX *ctx;
    size_t outlen;
    int state;

    GetPKey(self, pkey);
    rb_scan_args(argc, argv, "21", &digest, &data, &options);
    if (!NIL_P(digest))
        md = ossl_evp_get_digestbyname(digest);
    StringValue(data);

    ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
    if (!ctx)
        ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
    if (EVP_PKEY_sign_init(ctx) <= 0) {
        EVP_PKEY_CTX_free(ctx);
        ossl_raise(ePKeyError, "EVP_PKEY_sign_init");
    }
    if (md && EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) {
        EVP_PKEY_CTX_free(ctx);
        ossl_raise(ePKeyError, "EVP_PKEY_CTX_set_signature_md");
    }
    if (!NIL_P(options)) {
        pkey_ctx_apply_options(ctx, options, &state);
        if (state) {
            EVP_PKEY_CTX_free(ctx);
            rb_jump_tag(state);
        }
    }
    if (EVP_PKEY_sign(ctx, NULL, &outlen, (unsigned char *)RSTRING_PTR(data),
                      RSTRING_LEN(data)) <= 0) {
        EVP_PKEY_CTX_free(ctx);
        ossl_raise(ePKeyError, "EVP_PKEY_sign");
    }
    if (outlen > LONG_MAX) {
        EVP_PKEY_CTX_free(ctx);
        rb_raise(ePKeyError, "signature would be too large");
    }
    sig = ossl_str_new(NULL, (long)outlen, &state);
    if (state) {
        EVP_PKEY_CTX_free(ctx);
        rb_jump_tag(state);
    }
    if (EVP_PKEY_sign(ctx, (unsigned char *)RSTRING_PTR(sig), &outlen,
                      (unsigned char *)RSTRING_PTR(data),
                      RSTRING_LEN(data)) <= 0) {
        EVP_PKEY_CTX_free(ctx);
        ossl_raise(ePKeyError, "EVP_PKEY_sign");
    }
    EVP_PKEY_CTX_free(ctx);
    rb_str_set_len(sig, outlen);
    return sig;
}
to_text → string click to toggle source

Dumps key parameters, public key, and private key components contained in the key into a human-readable text.

This is intended for debugging purpose.

See also the man page EVP_PKEY_print_private(3).

static VALUE
ossl_pkey_to_text(VALUE self)
{
    EVP_PKEY *pkey;
    BIO *bio;

    GetPKey(self, pkey);
    if (!(bio = BIO_new(BIO_s_mem())))
        ossl_raise(ePKeyError, "BIO_new");

    if (EVP_PKEY_print_private(bio, pkey, 0, NULL) == 1)
        goto out;
    OSSL_BIO_reset(bio);
    if (EVP_PKEY_print_public(bio, pkey, 0, NULL) == 1)
        goto out;
    OSSL_BIO_reset(bio);
    if (EVP_PKEY_print_params(bio, pkey, 0, NULL) == 1)
        goto out;

    BIO_free(bio);
    ossl_raise(ePKeyError, "EVP_PKEY_print_params");

  out:
    return ossl_membio2str(bio);
}
verify(digest, signature, data [, options]) → true or false click to toggle source

Verifies the signature for the data using a message digest algorithm digest and a public key pkey.

Returns true if the signature is successfully verified, false otherwise. The caller must check the return value.

See sign for the signing operation and an example.

See also the man page EVP_DigestVerify(3).

digest

See sign.

signature

A String containing the signature to be verified.

data

See sign.

options

See sign. options parameter was added in version 3.0.

static VALUE
ossl_pkey_verify(int argc, VALUE *argv, VALUE self)
{
    EVP_PKEY *pkey;
    VALUE digest, sig, data, options;
    const EVP_MD *md = NULL;
    EVP_MD_CTX *ctx;
    EVP_PKEY_CTX *pctx;
    int state, ret;

    GetPKey(self, pkey);
    rb_scan_args(argc, argv, "31", &digest, &sig, &data, &options);
    ossl_pkey_check_public_key(pkey);
    if (!NIL_P(digest))
        md = ossl_evp_get_digestbyname(digest);
    StringValue(sig);
    StringValue(data);

    ctx = EVP_MD_CTX_new();
    if (!ctx)
        ossl_raise(ePKeyError, "EVP_MD_CTX_new");
    if (EVP_DigestVerifyInit(ctx, &pctx, md, /* engine */NULL, pkey) < 1) {
        EVP_MD_CTX_free(ctx);
        ossl_raise(ePKeyError, "EVP_DigestVerifyInit");
    }
    if (!NIL_P(options)) {
        pkey_ctx_apply_options(pctx, options, &state);
        if (state) {
            EVP_MD_CTX_free(ctx);
            rb_jump_tag(state);
        }
    }
#if OPENSSL_VERSION_NUMBER >= 0x10101000 && !defined(LIBRESSL_VERSION_NUMBER)
    ret = EVP_DigestVerify(ctx, (unsigned char *)RSTRING_PTR(sig),
                           RSTRING_LEN(sig), (unsigned char *)RSTRING_PTR(data),
                           RSTRING_LEN(data));
    EVP_MD_CTX_free(ctx);
    if (ret < 0)
        ossl_raise(ePKeyError, "EVP_DigestVerify");
#else
    if (EVP_DigestVerifyUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)) < 1) {
        EVP_MD_CTX_free(ctx);
        ossl_raise(ePKeyError, "EVP_DigestVerifyUpdate");
    }
    ret = EVP_DigestVerifyFinal(ctx, (unsigned char *)RSTRING_PTR(sig),
                                RSTRING_LEN(sig));
    EVP_MD_CTX_free(ctx);
    if (ret < 0)
        ossl_raise(ePKeyError, "EVP_DigestVerifyFinal");
#endif
    if (ret)
        return Qtrue;
    else {
        ossl_clear_error();
        return Qfalse;
    }
}
verify_raw(digest, signature, data [, options]) → true or false click to toggle source

Verifies the signature for the data using a public key pkey. Unlike verify, this method will not hash data with digest automatically.

Returns true if the signature is successfully verified, false otherwise. The caller must check the return value.

See sign_raw for the signing operation and an example code.

Added in version 3.0. See also the man page EVP_PKEY_verify(3).

signature

A String containing the signature to be verified.

static VALUE
ossl_pkey_verify_raw(int argc, VALUE *argv, VALUE self)
{
    EVP_PKEY *pkey;
    VALUE digest, sig, data, options;
    const EVP_MD *md = NULL;
    EVP_PKEY_CTX *ctx;
    int state, ret;

    GetPKey(self, pkey);
    rb_scan_args(argc, argv, "31", &digest, &sig, &data, &options);
    ossl_pkey_check_public_key(pkey);
    if (!NIL_P(digest))
        md = ossl_evp_get_digestbyname(digest);
    StringValue(sig);
    StringValue(data);

    ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
    if (!ctx)
        ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
    if (EVP_PKEY_verify_init(ctx) <= 0) {
        EVP_PKEY_CTX_free(ctx);
        ossl_raise(ePKeyError, "EVP_PKEY_verify_init");
    }
    if (md && EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) {
        EVP_PKEY_CTX_free(ctx);
        ossl_raise(ePKeyError, "EVP_PKEY_CTX_set_signature_md");
    }
    if (!NIL_P(options)) {
        pkey_ctx_apply_options(ctx, options, &state);
        if (state) {
            EVP_PKEY_CTX_free(ctx);
            rb_jump_tag(state);
        }
    }
    ret = EVP_PKEY_verify(ctx, (unsigned char *)RSTRING_PTR(sig),
                          RSTRING_LEN(sig),
                          (unsigned char *)RSTRING_PTR(data),
                          RSTRING_LEN(data));
    EVP_PKEY_CTX_free(ctx);
    if (ret < 0)
        ossl_raise(ePKeyError, "EVP_PKEY_verify");

    if (ret)
        return Qtrue;
    else {
        ossl_clear_error();
        return Qfalse;
    }
}
verify_recover(digest, signature [, options]) → string click to toggle source

Recovers the signed data from signature using a public key pkey. Not all signature algorithms support this operation.

Added in version 3.0. See also the man page EVP_PKEY_verify_recover(3).

signature

A String containing the signature to be verified.

static VALUE
ossl_pkey_verify_recover(int argc, VALUE *argv, VALUE self)
{
    EVP_PKEY *pkey;
    VALUE digest, sig, options, out;
    const EVP_MD *md = NULL;
    EVP_PKEY_CTX *ctx;
    int state;
    size_t outlen;

    GetPKey(self, pkey);
    rb_scan_args(argc, argv, "21", &digest, &sig, &options);
    ossl_pkey_check_public_key(pkey);
    if (!NIL_P(digest))
        md = ossl_evp_get_digestbyname(digest);
    StringValue(sig);

    ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
    if (!ctx)
        ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
    if (EVP_PKEY_verify_recover_init(ctx) <= 0) {
        EVP_PKEY_CTX_free(ctx);
        ossl_raise(ePKeyError, "EVP_PKEY_verify_recover_init");
    }
    if (md && EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) {
        EVP_PKEY_CTX_free(ctx);
        ossl_raise(ePKeyError, "EVP_PKEY_CTX_set_signature_md");
    }
    if (!NIL_P(options)) {
        pkey_ctx_apply_options(ctx, options, &state);
        if (state) {
            EVP_PKEY_CTX_free(ctx);
            rb_jump_tag(state);
        }
    }
    if (EVP_PKEY_verify_recover(ctx, NULL, &outlen,
                                (unsigned char *)RSTRING_PTR(sig),
                                RSTRING_LEN(sig)) <= 0) {
        EVP_PKEY_CTX_free(ctx);
        ossl_raise(ePKeyError, "EVP_PKEY_verify_recover");
    }
    out = ossl_str_new(NULL, (long)outlen, &state);
    if (state) {
        EVP_PKEY_CTX_free(ctx);
        rb_jump_tag(state);
    }
    if (EVP_PKEY_verify_recover(ctx, (unsigned char *)RSTRING_PTR(out), &outlen,
                                (unsigned char *)RSTRING_PTR(sig),
                                RSTRING_LEN(sig)) <= 0) {
        EVP_PKEY_CTX_free(ctx);
        ossl_raise(ePKeyError, "EVP_PKEY_verify_recover");
    }
    EVP_PKEY_CTX_free(ctx);
    rb_str_set_len(out, outlen);
    return out;
}