123456789_123456789_123456789_123456789_123456789_

Class: OpenSSL::PKey::PKey

Relationships & Source Files
Extension / Inclusion / Inheritance Descendants
Subclasses:
DH, DSA, EC, RSA
Inherits: Object
Defined in: ext/openssl/ossl_pkey.c

Overview

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

Class Method Summary

  • PKeyClass.new ⇒ self constructor

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

Instance Method Summary

Constructor Details

PKeyClass.newself

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

[ GitHub ]

  
# File 'ext/openssl/ossl_pkey.c', line 609

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;
}

Instance Method Details

#compare?(another_pkey) ⇒ Boolean

Used primarily to check if an 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
[ GitHub ]

  
# File 'ext/openssl/ossl_pkey.c', line 1139

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");
}

#decapsulate(ciphertext) ⇒ shared_secret

Performs a key decapsulation operation using the private components of pkey.

See also the man page EVP_PKEY_decapsulate(3).

[ GitHub ]

  
# File 'ext/openssl/ossl_pkey.c', line 1673

static VALUE
ossl_pkey_decapsulate(VALUE self, VALUE ciphertext)
{
    EVP_PKEY *pkey;
    EVP_PKEY_CTX *ctx;
    VALUE shared_secret;
    size_t shared_secretlen;
    int state;

    GetPKey(self, pkey);
    StringValue(ciphertext);

    ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
    if (!ctx)
        ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
    if (EVP_PKEY_decapsulate_init(ctx, NULL) <= 0) {
        EVP_PKEY_CTX_free(ctx);
        ossl_raise(ePKeyError, "EVP_PKEY_decapsulate_init");
    }
    if (EVP_PKEY_decapsulate(ctx, NULL, &shared_secretlen,
                             (unsigned char *)RSTRING_PTR(ciphertext),
                             RSTRING_LEN(ciphertext)) <= 0) {
        EVP_PKEY_CTX_free(ctx);
        ossl_raise(ePKeyError, "EVP_PKEY_decapsulate");
    }
    if (shared_secretlen > LONG_MAX) {
        EVP_PKEY_CTX_free(ctx);
        rb_raise(ePKeyError, "decapsulated data would be too large");
    }
    shared_secret = ossl_str_new(NULL, (long)shared_secretlen, &state);
    if (state) {
        EVP_PKEY_CTX_free(ctx);
        rb_jump_tag(state);
    }
    if (EVP_PKEY_decapsulate(ctx,
                             (unsigned char *)RSTRING_PTR(shared_secret),
                             &shared_secretlen,
                             (unsigned char *)RSTRING_PTR(ciphertext),
                             RSTRING_LEN(ciphertext)) <= 0) {
        EVP_PKEY_CTX_free(ctx);
        ossl_raise(ePKeyError, "EVP_PKEY_decapsulate");
    }
    EVP_PKEY_CTX_free(ctx);
    rb_str_set_len(shared_secret, shared_secretlen);
    return shared_secret;
}

#decrypt(data [, options]) ⇒ String

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).

[ GitHub ]

  
# File 'ext/openssl/ossl_pkey.c', line 1807

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

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

[ GitHub ]

  
# File 'ext/openssl/ossl_pkey.c', line 1559

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) {
        EVP_PKEY_CTX_free(ctx);
        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;
}

#encapsulateArray, shared_secret

Performs a key encapsulation operation using the public components of pkey.

See also the man page EVP_PKEY_encapsulate(3).

[ GitHub ]

  
# File 'ext/openssl/ossl_pkey.c', line 1615

static VALUE
ossl_pkey_encapsulate(VALUE self)
{
    EVP_PKEY *pkey;
    EVP_PKEY_CTX *ctx;
    VALUE ciphertext, shared_secret;
    size_t ciphertextlen, shared_secretlen;
    int state;

    GetPKey(self, pkey);
    ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
    if (!ctx)
        ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
    if (EVP_PKEY_encapsulate_init(ctx, NULL) <= 0) {
        EVP_PKEY_CTX_free(ctx);
        ossl_raise(ePKeyError, "EVP_PKEY_encapsulate_init");
    }
    if (EVP_PKEY_encapsulate(ctx, NULL, &ciphertextlen, NULL, &shared_secretlen) <= 0) {
        EVP_PKEY_CTX_free(ctx);
        ossl_raise(ePKeyError, "EVP_PKEY_encapsulate");
    }
    if (ciphertextlen > LONG_MAX || shared_secretlen > LONG_MAX) {
        EVP_PKEY_CTX_free(ctx);
        rb_raise(ePKeyError, "encapsulated data would be too large");
    }
    ciphertext = ossl_str_new(NULL, (long)ciphertextlen, &state);
    if (state) {
        EVP_PKEY_CTX_free(ctx);
        rb_jump_tag(state);
    }
    shared_secret = ossl_str_new(NULL, (long)shared_secretlen, &state);
    if (state) {
        EVP_PKEY_CTX_free(ctx);
        rb_jump_tag(state);
    }
    if (EVP_PKEY_encapsulate(ctx,
                             (unsigned char *)RSTRING_PTR(ciphertext),
                             &ciphertextlen,
                             (unsigned char *)RSTRING_PTR(shared_secret),
                             &shared_secretlen) <= 0) {
        EVP_PKEY_CTX_free(ctx);
        ossl_raise(ePKeyError, "EVP_PKEY_encapsulate");
    }
    EVP_PKEY_CTX_free(ctx);
    rb_str_set_len(ciphertext, ciphertextlen);
    rb_str_set_len(shared_secret, shared_secretlen);
    return rb_assoc_new(ciphertext, shared_secret);
}

#encrypt(data [, options]) ⇒ String

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"
[ GitHub ]

  
# File 'ext/openssl/ossl_pkey.c', line 1744

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;
}

#get_param(key) ⇒ String, OpenSSL::BN

Gets a parameter from the key. This is a low-level interface to OpenSSL's EVP_PKEY_get_params() function, available in ::OpenSSL 3.0 or later.

Check the relevant EVP_PKEY-* man page, or the documentation for the ::OpenSSL provider in use, for the supported parameter keys and their return types.

See the man page EVP_PKEY_get_params(3) for details.

[ GitHub ]

  
# File 'ext/openssl/ossl_pkey.c', line 787

static VALUE
ossl_pkey_get_param(VALUE self, VALUE keyv)
{
    EVP_PKEY *pkey;
    const OSSL_PARAM *gettable_params, *p;
    OSSL_PARAM params[] = {
        { NULL, 0, NULL, 0, OSSL_PARAM_UNMODIFIED },
        OSSL_PARAM_END,
    };
    VALUE ret, tmp = 0;

    GetPKey(self, pkey);
    gettable_params = EVP_PKEY_gettable_params(pkey);
    if (!gettable_params)
        ossl_raise(ePKeyError, "EVP_PKEY_gettable_params");
    p = OSSL_PARAM_locate_const(gettable_params, StringValueCStr(keyv));
    if (!p)
        ossl_raise(ePKeyError, "unrecognized OSSL_PARAM key: %"PRIsVALUE, keyv);

    params[0].key = p->key;
    params[0].data_type = p->data_type;
    if (!EVP_PKEY_get_params(pkey, params))
        ossl_raise(ePKeyError, "EVP_PKEY_get_params");
    if (!OSSL_PARAM_modified(&params[0]))
        ossl_raise(ePKeyError, "OSSL_PARAM_modified");

    switch (p->data_type) {
      case OSSL_PARAM_INTEGER:
      case OSSL_PARAM_UNSIGNED_INTEGER:
        ret = ossl_bn_new(BN_value_one());
        params[0].data_size =
            params[0].return_size > 0 ? params[0].return_size : 1;
        params[0].data = ALLOCV(tmp, params[0].data_size);
        break;
      case OSSL_PARAM_UTF8_STRING:
      case OSSL_PARAM_OCTET_STRING:
        ret = rb_str_new(NULL, params[0].return_size);
        if (p->data_type == OSSL_PARAM_UTF8_STRING)
            rb_enc_associate_index(ret, rb_utf8_encindex());
        params[0].data_size = params[0].return_size;
        params[0].data = RSTRING_PTR(ret);
        break;
      default:
        /*
         * As of OpenSSL 4.0, the following data types are defined, but are
         * not actually used in EVP_PKEY_gettable_params(). So leave them
         * unimplemented for now:
         *   - OSSL_PARAM_REAL (double)
         *   - OSSL_PARAM_UTF8_PTR (C string)
         *   - OSSL_PARAM_OCTET_PTR (arbitrary pointer?)
         */
        ossl_raise(ePKeyError, "unsupported OSSL_PARAM data type %d for key %s",
                   p->data_type, p->key);
    }
    if (!EVP_PKEY_get_params(pkey, params))
        ossl_raise(ePKeyError, "EVP_PKEY_get_params");

    switch (p->data_type) {
      case OSSL_PARAM_INTEGER:
      case OSSL_PARAM_UNSIGNED_INTEGER: {
        BIGNUM *bn = GetBNPtr(ret);
        if (!OSSL_PARAM_get_BN(&params[0], &bn))
            ossl_raise(eOSSLError, "OSSL_PARAM_get_BN");
        break;
      }
      case OSSL_PARAM_UTF8_STRING:
      case OSSL_PARAM_OCTET_STRING:
        rb_str_set_len(ret, params[0].return_size);
        break;
    }
    ALLOCV_END(tmp);
    return ret;
}

#initialize_copy(other)

This method is for internal use only.
[ GitHub ]

  
# File 'ext/openssl/ossl_pkey.c', line 620

static VALUE
ossl_pkey_initialize_copy(VALUE self, VALUE other)
{
    EVP_PKEY *pkey, *pkey_other;

    ossl_want_uninitialized(self, &ossl_evp_pkey_type);
    TypedData_Get_Struct(other, EVP_PKEY, &ossl_evp_pkey_type, pkey_other);
    if (pkey_other) {
        pkey = EVP_PKEY_dup(pkey_other);
        if (!pkey)
            ossl_raise(ePKeyError, "EVP_PKEY_dup");
        RTYPEDDATA_DATA(self) = pkey;
    }
    return self;
}

#inspectString

Returns a string describing the PKey object.

[ GitHub ]

  
# File 'ext/openssl/ossl_pkey.c', line 751

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

    GetPKey(self, pkey);
    VALUE str = rb_sprintf("#<%"PRIsVALUE":%p",
                           rb_obj_class(self), (void *)self);
    int nid = EVP_PKEY_id(pkey);
#ifdef OSSL_USE_PROVIDER
    if (nid != EVP_PKEY_KEYMGMT)
#endif
    rb_str_catf(str, " oid=%s", OBJ_nid2sn(nid));
#ifdef OSSL_USE_PROVIDER
    rb_str_catf(str, " type_name=%s", EVP_PKEY_get0_type_name(pkey));
    const OSSL_PROVIDER *prov = EVP_PKEY_get0_provider(pkey);
    if (prov)
        rb_str_catf(str, " provider=%s", OSSL_PROVIDER_get0_name(prov));
#endif
    rb_str_catf(str, ">");
    return str;
}

#oidString

Returns the short name of the OID associated with pkey.

[ GitHub ]

  
# File 'ext/openssl/ossl_pkey.c', line 730

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

    GetPKey(self, pkey);
    nid = EVP_PKEY_id(pkey);
#ifdef OSSL_USE_PROVIDER
    if (nid == EVP_PKEY_KEYMGMT)
        ossl_raise(ePKeyError, "EVP_PKEY_id");
#endif
    return rb_str_new_cstr(OBJ_nid2sn(nid));
}

#private_to_derString #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.

[ GitHub ]

  
# File 'ext/openssl/ossl_pkey.c', line 985

static VALUE
ossl_pkey_private_to_der(int argc, VALUE *argv, VALUE self)
{
    return do_pkcs8_export(argc, argv, self, 1);
}

#private_to_pemString #private_to_pem(cipher, password) ⇒ String

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

An unencrypted PEM-encoded key will look like:

-----BEGIN PRIVATE KEY-----
[...]
-----END PRIVATE KEY-----

An encrypted PEM-encoded key will look like:

-----BEGIN ENCRYPTED PRIVATE KEY-----
[...]
-----END ENCRYPTED PRIVATE KEY-----
[ GitHub ]

  
# File 'ext/openssl/ossl_pkey.c', line 1011

static VALUE
ossl_pkey_private_to_pem(int argc, VALUE *argv, VALUE self)
{
    return do_pkcs8_export(argc, argv, self, 0);
}

#public_to_derString

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

[ GitHub ]

  
# File 'ext/openssl/ossl_pkey.c', line 1076

static VALUE
ossl_pkey_public_to_der(VALUE self)
{
    return ossl_pkey_export_spki(self, 1);
}

#public_to_pemString

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

A PEM-encoded key will look like:

-----BEGIN PUBLIC KEY-----
[...]
-----END PUBLIC KEY-----
[ GitHub ]

  
# File 'ext/openssl/ossl_pkey.c', line 1094

static VALUE
ossl_pkey_public_to_pem(VALUE self)
{
    return ossl_pkey_export_spki(self, 0);
}

#raw_private_keyString

See the ::OpenSSL documentation for EVP_PKEY_get_raw_private_key()

[ GitHub ]

  
# File 'ext/openssl/ossl_pkey.c', line 1024

static VALUE
ossl_pkey_raw_private_key(VALUE self)
{
    EVP_PKEY *pkey;
    VALUE str;
    size_t len;

    GetPKey(self, pkey);
    if (EVP_PKEY_get_raw_private_key(pkey, NULL, &len) != 1)
        ossl_raise(ePKeyError, "EVP_PKEY_get_raw_private_key");
    str = rb_str_new(NULL, len);

    if (EVP_PKEY_get_raw_private_key(pkey, (unsigned char *)RSTRING_PTR(str), &len) != 1)
        ossl_raise(ePKeyError, "EVP_PKEY_get_raw_private_key");

    rb_str_set_len(str, len);

    return str;
}

#raw_public_keyString

See the ::OpenSSL documentation for EVP_PKEY_get_raw_public_key()

[ GitHub ]

  
# File 'ext/openssl/ossl_pkey.c', line 1107

static VALUE
ossl_pkey_raw_public_key(VALUE self)
{
    EVP_PKEY *pkey;
    VALUE str;
    size_t len;

    GetPKey(self, pkey);
    if (EVP_PKEY_get_raw_public_key(pkey, NULL, &len) != 1)
        ossl_raise(ePKeyError, "EVP_PKEY_get_raw_public_key");
    str = rb_str_new(NULL, len);

    if (EVP_PKEY_get_raw_public_key(pkey, (unsigned char *)RSTRING_PTR(str), &len) != 1)
        ossl_raise(ePKeyError, "EVP_PKEY_get_raw_public_key");

    rb_str_set_len(str, len);

    return str;
}

#sign(digest, data [, options]) ⇒ String

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
[ GitHub ]

  
# File 'ext/openssl/ossl_pkey.c', line 1198

static VALUE
ossl_pkey_sign(int argc, VALUE *argv, VALUE self)
{
    EVP_PKEY *pkey;
    VALUE digest, data, options, sig, md_holder;
    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_md_fetch(digest, &md_holder);
    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 (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");
    }
    EVP_MD_CTX_free(ctx);
    rb_str_set_len(sig, siglen);
    return sig;
}

#sign_raw(digest, data [, options]) ⇒ String

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
[ GitHub ]

  
# File 'ext/openssl/ossl_pkey.c', line 1356

static VALUE
ossl_pkey_sign_raw(int argc, VALUE *argv, VALUE self)
{
    EVP_PKEY *pkey;
    VALUE digest, data, options, sig, md_holder;
    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_md_fetch(digest, &md_holder);
    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_textString

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).

[ GitHub ]

  
# File 'ext/openssl/ossl_pkey.c', line 875

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]) ⇒ Boolean

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.

[ GitHub ]

  
# File 'ext/openssl/ossl_pkey.c', line 1277

static VALUE
ossl_pkey_verify(int argc, VALUE *argv, VALUE self)
{
    EVP_PKEY *pkey;
    VALUE digest, sig, data, options, md_holder;
    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_md_fetch(digest, &md_holder);
    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);
        }
    }
    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");
    if (ret)
        return Qtrue;
    else {
        ossl_clear_error();
        return Qfalse;
    }
}

#verify_raw(digest, signature, data [, options]) ⇒ Boolean

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.

[ GitHub ]

  
# File 'ext/openssl/ossl_pkey.c', line 1432

static VALUE
ossl_pkey_verify_raw(int argc, VALUE *argv, VALUE self)
{
    EVP_PKEY *pkey;
    VALUE digest, sig, data, options, md_holder;
    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_md_fetch(digest, &md_holder);
    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

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.

[ GitHub ]

  
# File 'ext/openssl/ossl_pkey.c', line 1495

static VALUE
ossl_pkey_verify_recover(int argc, VALUE *argv, VALUE self)
{
    EVP_PKEY *pkey;
    VALUE digest, sig, options, out, md_holder;
    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_md_fetch(digest, &md_holder);
    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;
}