# 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`

- `OpenSSL::PKey::RSA`

- `OpenSSL::PKey::DSA`

- `OpenSSL::PKey::EC`

### 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 OSSL_OPENSSL_PREREQ(1, 1, 1) || OSSL_LIBRESSL_PREREQ(3, 4, 0)
        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 OSSL_OPENSSL_PREREQ(1, 1, 1) || OSSL_LIBRESSL_PREREQ(3, 4, 0)
        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;
    }