类 OpenSSL::PKey::PKey

一个抽象类,它将签名创建 (PKey#sign) 和验证 (PKey#verify) 捆绑在一起,这些操作对所有实现都是通用的,除了 OpenSSL::PKey::DH

公共类方法

new → self 点击切换源代码

因为 PKey 是一个抽象类,所以显式调用此方法将引发 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;
}

公共实例方法

compare?(another_pkey) → true | false 点击切换源代码

主要用于检查 OpenSSL::X509::Certificate#public_key 是否与其私钥匹配。

示例

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 点击切换源代码

使用 pkey 执行公钥解密操作。

有关参数和示例的说明,请参阅 encrypt

在版本 3.0 中添加。另请参阅手册页 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 点击切换源代码

pkeypeer_pkey 推导出共享密钥。pkey 必须包含私有组件,peer_pkey 必须包含公有组件。

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 点击切换源代码

使用 pkey 执行公钥加密操作。

有关逆向操作,请参阅 decrypt

在版本 3.0 中添加。另请参阅手册页 EVP_PKEY_encrypt(3)。

data

要加密的 String

options

包含针对 OpenSSL 的算法特定控制操作的 Hash。有关详细信息,请参阅 OpenSSL 的手册页 EVP_PKEY_CTX_ctrl_str(3)。

示例

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) 点击切换源代码
HAVE_EVP_PKEY_DUP
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 点击切换源代码

返回描述 PKey 对象的字符串。

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 点击切换源代码

返回与 pkey 关联的 OID 的简短名称。

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 点击切换源代码
private_to_der(cipher, password) → string

将私钥序列化为 DER 编码的 PKCS #8 格式。如果在没有参数的情况下调用,则使用未加密的 PKCS #8 PrivateKeyInfo 格式。如果使用密码调用,则使用带有 PBES2 加密方案的 PKCS #8 EncryptedPrivateKeyInfo 格式。

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 点击切换源代码
private_to_pem(cipher, password) → string

将私钥序列化为 PEM 编码的 PKCS #8 格式。有关更多详细信息,请参阅 private_to_der

未加密的 PEM 编码密钥将如下所示

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

加密的 PEM 编码密钥将如下所示

-----BEGIN ENCRYPTED PRIVATE KEY-----
[...]
-----END ENCRYPTED PRIVATE KEY-----
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 点击切换源代码

将公钥序列化为 DER 编码的 X.509 SubjectPublicKeyInfo 格式。

static VALUE
ossl_pkey_public_to_der(VALUE self)
{
    return ossl_pkey_export_spki(self, 1);
}
public_to_pem → string 点击切换源代码

将公钥序列化为 PEM 编码的 X.509 SubjectPublicKeyInfo 格式。

PEM 编码密钥将如下所示

-----BEGIN PUBLIC KEY-----
[...]
-----END PUBLIC KEY-----
static VALUE
ossl_pkey_public_to_pem(VALUE self)
{
    return ossl_pkey_export_spki(self, 0);
}
raw_private_key → string 点击切换源代码

有关 EVP_PKEY_get_raw_private_key() 的信息,请参阅 OpenSSL 文档。

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_key → string 点击切换源代码

有关 EVP_PKEY_get_raw_public_key() 的信息,请参阅 OpenSSL 文档。

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 点击切换源代码

使用消息摘要算法 digest 和私钥 pkeydata 进行哈希和签名。

有关验证操作,请参阅 verify

另请参阅手册页 EVP_DigestSign(3)。

digest

表示消息摘要算法名称的 String,如果 PKey 类型不需要消息摘要算法,则为 nil。为了向后兼容,这可以是 OpenSSL::Digest 的实例。它的状态不会影响签名。

data

一个 String。要进行哈希和签名的數據。

options

包含针对 OpenSSL 的算法特定控制操作的 Hash。有关详细信息,请参阅 OpenSSL 的手册页 EVP_PKEY_CTX_ctrl_str(3)。options 参数是在版本 3.0 中添加的。

示例

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 点击切换源代码

使用私钥 pkeydata 进行签名。与 sign 不同,data 不会被 digest 自动进行哈希。

有关验证操作,请参阅 verify_raw

在版本 3.0 中添加。另请参阅手册页 EVP_PKEY_sign(3)。

digest

表示消息摘要算法名称的 String,如果 PKey 类型不需要消息摘要算法,则为 nil。虽然此方法不会使用它对 data 进行哈希,但根据签名算法,此参数可能仍然是必需的。

data

一个 String。要签名的數據。

options

包含针对 OpenSSL 的算法特定控制操作的 Hash。有关详细信息,请参阅 OpenSSL 的手册页 EVP_PKEY_CTX_ctrl_str(3)。

示例

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 点击切换源代码

将密钥参数、公钥和私钥组件(包含在密钥中)转储到人类可读的文本中。

这是为了调试目的。

另请参阅手册页 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 点击切换源代码

使用消息摘要算法 digest 和公钥 pkey 验证 datasignature

如果签名成功验证,则返回 true,否则返回 false。调用者必须检查返回值。

有关签名操作和示例,请参阅 sign

另请参阅手册页 EVP_DigestVerify(3)。

digest

参阅 sign

signature

包含要验证的签名的 String

data

参阅 sign

options

参阅 signoptions 参数是在版本 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 点击切换源代码

使用公钥 pkey 验证 datasignature。与 verify 不同,此方法不会使用 digest 自动对 data 进行哈希。

如果签名成功验证,则返回 true,否则返回 false。调用者必须检查返回值。

有关签名操作和示例代码,请参阅 sign_raw

在版本 3.0 中添加。另请参阅手册页 EVP_PKEY_verify(3)。

signature

包含要验证的签名的 String

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 点击切换源代码

使用公钥 pkeysignature 中恢复已签名的數據。并非所有签名算法都支持此操作。

在版本 3.0 中添加。另请参阅手册页 EVP_PKEY_verify_recover(3)。

signature

包含要验证的签名的 String

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