diff options
Diffstat (limited to 'OpenSSL/PKey/PKey.html')
-rw-r--r-- | OpenSSL/PKey/PKey.html | 825 |
1 files changed, 772 insertions, 53 deletions
diff --git a/OpenSSL/PKey/PKey.html b/OpenSSL/PKey/PKey.html index 5f981ef2..7b3cf677 100644 --- a/OpenSSL/PKey/PKey.html +++ b/OpenSSL/PKey/PKey.html @@ -73,6 +73,11 @@ <ul class="link-list" role="directory"> <li ><a href="#method-c-new">::new</a> + <li ><a href="#method-i-compare-3F">#compare?</a> + <li ><a href="#method-i-decrypt">#decrypt</a> + <li ><a href="#method-i-derive">#derive</a> + <li ><a href="#method-i-encrypt">#encrypt</a> + <li ><a href="#method-i-initialize_copy">#initialize_copy</a> <li ><a href="#method-i-inspect">#inspect</a> <li ><a href="#method-i-oid">#oid</a> <li ><a href="#method-i-private_to_der">#private_to_der</a> @@ -80,7 +85,11 @@ <li ><a href="#method-i-public_to_der">#public_to_der</a> <li ><a href="#method-i-public_to_pem">#public_to_pem</a> <li ><a href="#method-i-sign">#sign</a> + <li ><a href="#method-i-sign_raw">#sign_raw</a> + <li ><a href="#method-i-to_text">#to_text</a> <li ><a href="#method-i-verify">#verify</a> + <li ><a href="#method-i-verify_raw">#verify_raw</a> + <li ><a href="#method-i-verify_recover">#verify_recover</a> </ul> </div> @@ -149,6 +158,316 @@ ossl_pkey_initialize(VALUE self) <h3>Public Instance Methods</h3> </header> + <div id="method-i-compare-3F" class="method-detail "> + <div class="method-heading"> + <span class="method-callseq"> + compare?(another_pkey) → true | false + </span> + <span class="method-click-advice">click to toggle source</span> + </div> + + <div class="method-description"> + <p>Used primarily to check if an <a href="../X509/Certificate.html#method-i-public_key"><code>OpenSSL::X509::Certificate#public_key</code></a> compares to its private key.</p> + +<h2 id="method-i-compare-3F-label-Example">Example<span><a href="#method-i-compare-3F-label-Example">¶</a> <a href="#top">↑</a></span></h2> + +<pre class="ruby"><span class="ruby-identifier">x509</span> = <span class="ruby-constant">OpenSSL</span><span class="ruby-operator">::</span><span class="ruby-constant">X509</span><span class="ruby-operator">::</span><span class="ruby-constant">Certificate</span>.<span class="ruby-identifier">new</span>(<span class="ruby-identifier">pem_encoded_certificate</span>) +<span class="ruby-identifier">rsa_key</span> = <span class="ruby-constant">OpenSSL</span><span class="ruby-operator">::</span><span class="ruby-constant">PKey</span><span class="ruby-operator">::</span><span class="ruby-constant">RSA</span>.<span class="ruby-identifier">new</span>(<span class="ruby-identifier">pem_encoded_private_key</span>) + +<span class="ruby-identifier">rsa_key</span>.<span class="ruby-identifier">compare?</span>(<span class="ruby-identifier">x509</span>.<span class="ruby-identifier">public_key</span>) <span class="ruby-operator">=></span> <span class="ruby-keyword">true</span> <span class="ruby-operator">|</span> <span class="ruby-keyword">false</span> +</pre> + + <div class="method-source-code" id="compare-3F-source"> + <pre>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"); +}</pre> + </div> + </div> + + + </div> + + <div id="method-i-decrypt" class="method-detail "> + <div class="method-heading"> + <span class="method-callseq"> + decrypt(data [, options]) → string + </span> + <span class="method-click-advice">click to toggle source</span> + </div> + + <div class="method-description"> + <p>Performs a public key decryption operation using <code>pkey</code>.</p> + +<p>See <a href="PKey.html#method-i-encrypt"><code>encrypt</code></a> for a description of the parameters and an example.</p> + +<p>Added in version 3.0. See also the man page EVP_PKEY_decrypt(3).</p> + + <div class="method-source-code" id="decrypt-source"> + <pre>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; +}</pre> + </div> + </div> + + + </div> + + <div id="method-i-derive" class="method-detail "> + <div class="method-heading"> + <span class="method-callseq"> + derive(peer_pkey) → string + </span> + <span class="method-click-advice">click to toggle source</span> + </div> + + <div class="method-description"> + <p>Derives a shared secret from <em>pkey</em> and <em>peer_pkey</em>. <em>pkey</em> must contain the private components, <em>peer_pkey</em> must contain the public components.</p> + + <div class="method-source-code" id="derive-source"> + <pre>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; +}</pre> + </div> + </div> + + + </div> + + <div id="method-i-encrypt" class="method-detail "> + <div class="method-heading"> + <span class="method-callseq"> + encrypt(data [, options]) → string + </span> + <span class="method-click-advice">click to toggle source</span> + </div> + + <div class="method-description"> + <p>Performs a public key encryption operation using <code>pkey</code>.</p> + +<p>See <a href="PKey.html#method-i-decrypt"><code>decrypt</code></a> for the reverse operation.</p> + +<p>Added in version 3.0. See also the man page EVP_PKEY_encrypt(3).</p> +<dl class="rdoc-list note-list"><dt><code>data</code> +<dd> +<p>A String to be encrypted.</p> +</dd><dt><code>options</code> +<dd> +<p>A Hash that contains algorithm specific control operations to OpenSSL. See OpenSSL’s man page EVP_PKEY_CTX_ctrl_str(3) for details.</p> +</dd></dl> + +<p>Example:</p> + +<pre class="ruby"><span class="ruby-identifier">pkey</span> = <span class="ruby-constant">OpenSSL</span><span class="ruby-operator">::</span><span class="ruby-constant">PKey</span>.<span class="ruby-identifier">generate_key</span>(<span class="ruby-string">"RSA"</span>, <span class="ruby-value">rsa_keygen_bits:</span> <span class="ruby-value">2048</span>) +<span class="ruby-identifier">data</span> = <span class="ruby-string">"secret data"</span> +<span class="ruby-identifier">encrypted</span> = <span class="ruby-identifier">pkey</span>.<span class="ruby-identifier">encrypt</span>(<span class="ruby-identifier">data</span>, <span class="ruby-value">rsa_padding_mode:</span> <span class="ruby-string">"oaep"</span>) +<span class="ruby-identifier">decrypted</span> = <span class="ruby-identifier">pkey</span>.<span class="ruby-identifier">decrypt</span>(<span class="ruby-identifier">data</span>, <span class="ruby-value">rsa_padding_mode:</span> <span class="ruby-string">"oaep"</span>) +<span class="ruby-identifier">p</span> <span class="ruby-identifier">decrypted</span> <span class="ruby-comment">#=> "secret data"</span> +</pre> + + <div class="method-source-code" id="encrypt-source"> + <pre>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; +}</pre> + </div> + </div> + + + </div> + + <div id="method-i-initialize_copy" class="method-detail "> + <div class="method-heading"> + <span class="method-name">initialize_copy</span><span + class="method-args">(p1)</span> + <span class="method-click-advice">click to toggle source</span> + </div> + + <div class="method-description"> + + + <div class="method-source-code" id="initialize_copy-source"> + <pre>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; +}</pre> + </div> + </div> + + + </div> + <div id="method-i-inspect" class="method-detail "> <div class="method-heading"> <span class="method-callseq"> @@ -278,7 +597,7 @@ ossl_pkey_private_to_pem(int argc, VALUE *argv, VALUE self) <pre>static VALUE ossl_pkey_public_to_der(VALUE self) { - return do_spki_export(self, 1); + return ossl_pkey_export_spki(self, 1); }</pre> </div> </div> @@ -301,7 +620,7 @@ ossl_pkey_public_to_der(VALUE self) <pre>static VALUE ossl_pkey_public_to_pem(VALUE self) { - return do_spki_export(self, 0); + return ossl_pkey_export_spki(self, 0); }</pre> </div> </div> @@ -312,56 +631,223 @@ ossl_pkey_public_to_pem(VALUE self) <div id="method-i-sign" class="method-detail "> <div class="method-heading"> <span class="method-callseq"> - sign(digest, data) → String + sign(digest, data [, options]) → string </span> <span class="method-click-advice">click to toggle source</span> </div> <div class="method-description"> - <p>To sign the String <em>data</em>, <em>digest</em>, an instance of <a href="../Digest.html"><code>OpenSSL::Digest</code></a>, must be provided. The return value is again a String containing the signature. A <a href="PKeyError.html"><code>PKeyError</code></a> is raised should errors occur. Any previous state of the <a href="../Digest.html"><code>Digest</code></a> instance is irrelevant to the signature outcome, the digest instance is reset to its initial state during the operation.</p> - -<h2 id="method-i-sign-label-Example">Example<span><a href="#method-i-sign-label-Example">¶</a> <a href="#top">↑</a></span></h2> - -<pre class="ruby"><span class="ruby-identifier">data</span> = <span class="ruby-string">'Sign me!'</span> -<span class="ruby-identifier">digest</span> = <span class="ruby-constant">OpenSSL</span><span class="ruby-operator">::</span><span class="ruby-constant">Digest</span>.<span class="ruby-identifier">new</span>(<span class="ruby-string">'SHA256'</span>) -<span class="ruby-identifier">pkey</span> = <span class="ruby-constant">OpenSSL</span><span class="ruby-operator">::</span><span class="ruby-constant">PKey</span><span class="ruby-operator">::</span><span class="ruby-constant">RSA</span>.<span class="ruby-identifier">new</span>(<span class="ruby-value">2048</span>) -<span class="ruby-identifier">signature</span> = <span class="ruby-identifier">pkey</span>.<span class="ruby-identifier">sign</span>(<span class="ruby-identifier">digest</span>, <span class="ruby-identifier">data</span>) + <p>Hashes and signs the <code>data</code> using a message digest algorithm <code>digest</code> and a private key <code>pkey</code>.</p> + +<p>See <a href="PKey.html#method-i-verify"><code>verify</code></a> for the verification operation.</p> + +<p>See also the man page EVP_DigestSign(3).</p> +<dl class="rdoc-list note-list"><dt><code>digest</code> +<dd> +<p>A String that represents the message digest algorithm name, or <code>nil</code> if the <a href="PKey.html"><code>PKey</code></a> type requires no digest algorithm. For backwards compatibility, this can be an instance of <a href="../Digest.html"><code>OpenSSL::Digest</code></a>. Its state will not affect the signature.</p> +</dd><dt><code>data</code> +<dd> +<p>A String. The data to be hashed and signed.</p> +</dd><dt><code>options</code> +<dd> +<p>A Hash that contains algorithm specific control operations to OpenSSL. See OpenSSL’s man page EVP_PKEY_CTX_ctrl_str(3) for details. <code>options</code> parameter was added in version 3.0.</p> +</dd></dl> + +<p>Example:</p> + +<pre class="ruby"><span class="ruby-identifier">data</span> = <span class="ruby-string">"Sign me!"</span> +<span class="ruby-identifier">pkey</span> = <span class="ruby-constant">OpenSSL</span><span class="ruby-operator">::</span><span class="ruby-constant">PKey</span>.<span class="ruby-identifier">generate_key</span>(<span class="ruby-string">"RSA"</span>, <span class="ruby-value">rsa_keygen_bits:</span> <span class="ruby-value">2048</span>) +<span class="ruby-identifier">signopts</span> = { <span class="ruby-value">rsa_padding_mode:</span> <span class="ruby-string">"pss"</span> } +<span class="ruby-identifier">signature</span> = <span class="ruby-identifier">pkey</span>.<span class="ruby-identifier">sign</span>(<span class="ruby-string">"SHA256"</span>, <span class="ruby-identifier">data</span>, <span class="ruby-identifier">signopts</span>) + +<span class="ruby-comment"># Creates a copy of the RSA key pkey, but without the private components</span> +<span class="ruby-identifier">pub_key</span> = <span class="ruby-identifier">pkey</span>.<span class="ruby-identifier">public_key</span> +<span class="ruby-identifier">puts</span> <span class="ruby-identifier">pub_key</span>.<span class="ruby-identifier">verify</span>(<span class="ruby-string">"SHA256"</span>, <span class="ruby-identifier">signature</span>, <span class="ruby-identifier">data</span>, <span class="ruby-identifier">signopts</span>) <span class="ruby-comment"># => true</span> </pre> <div class="method-source-code" id="sign-source"> <pre>static VALUE -ossl_pkey_sign(VALUE self, VALUE digest, VALUE data) +ossl_pkey_sign(int argc, VALUE *argv, VALUE self) { EVP_PKEY *pkey; - const EVP_MD *md; + VALUE digest, data, options, sig; + const EVP_MD *md = NULL; EVP_MD_CTX *ctx; - unsigned int buf_len; - VALUE str; - int result; + EVP_PKEY_CTX *pctx; + size_t siglen; + int state; pkey = GetPrivPKeyPtr(self); - md = ossl_evp_get_digestbyname(digest); + rb_scan_args(argc, argv, "21", &digest, &data, &options); + if (!NIL_P(digest)) + md = ossl_evp_get_digestbyname(digest); StringValue(data); - str = rb_str_new(0, EVP_PKEY_size(pkey)); ctx = EVP_MD_CTX_new(); if (!ctx) ossl_raise(ePKeyError, "EVP_MD_CTX_new"); - if (!EVP_SignInit_ex(ctx, md, NULL)) { + 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_SignInit_ex"); + ossl_raise(ePKeyError, "EVP_DigestSignUpdate"); } - if (!EVP_SignUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data))) { + if (EVP_DigestSignFinal(ctx, NULL, &siglen) < 1) { EVP_MD_CTX_free(ctx); - ossl_raise(ePKeyError, "EVP_SignUpdate"); + ossl_raise(ePKeyError, "EVP_DigestSignFinal"); } - result = EVP_SignFinal(ctx, (unsigned char *)RSTRING_PTR(str), &buf_len, pkey); + 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); - if (!result) - ossl_raise(ePKeyError, "EVP_SignFinal"); - rb_str_set_len(str, buf_len); + rb_str_set_len(sig, siglen); + return sig; +}</pre> + </div> + </div> - return str; + + </div> + + <div id="method-i-sign_raw" class="method-detail "> + <div class="method-heading"> + <span class="method-callseq"> + sign_raw(digest, data [, options]) → string + </span> + <span class="method-click-advice">click to toggle source</span> + </div> + + <div class="method-description"> + <p>Signs <code>data</code> using a private key <code>pkey</code>. Unlike <a href="PKey.html#method-i-sign"><code>sign</code></a>, <code>data</code> will not be hashed by <code>digest</code> automatically.</p> + +<p>See <a href="PKey.html#method-i-verify_raw"><code>verify_raw</code></a> for the verification operation.</p> + +<p>Added in version 3.0. See also the man page EVP_PKEY_sign(3).</p> +<dl class="rdoc-list note-list"><dt><code>digest</code> +<dd> +<p>A String that represents the message digest algorithm name, or <code>nil</code> if the <a href="PKey.html"><code>PKey</code></a> type requires no digest algorithm. Although this method will not hash <code>data</code> with it, this parameter may still be required depending on the signature algorithm.</p> +</dd><dt><code>data</code> +<dd> +<p>A String. The data to be signed.</p> +</dd><dt><code>options</code> +<dd> +<p>A Hash that contains algorithm specific control operations to OpenSSL. See OpenSSL’s man page EVP_PKEY_CTX_ctrl_str(3) for details.</p> +</dd></dl> + +<p>Example:</p> + +<pre class="ruby"><span class="ruby-identifier">data</span> = <span class="ruby-string">"Sign me!"</span> +<span class="ruby-identifier">hash</span> = <span class="ruby-constant">OpenSSL</span><span class="ruby-operator">::</span><span class="ruby-constant">Digest</span>.<span class="ruby-identifier">digest</span>(<span class="ruby-string">"SHA256"</span>, <span class="ruby-identifier">data</span>) +<span class="ruby-identifier">pkey</span> = <span class="ruby-constant">OpenSSL</span><span class="ruby-operator">::</span><span class="ruby-constant">PKey</span>.<span class="ruby-identifier">generate_key</span>(<span class="ruby-string">"RSA"</span>, <span class="ruby-value">rsa_keygen_bits:</span> <span class="ruby-value">2048</span>) +<span class="ruby-identifier">signopts</span> = { <span class="ruby-value">rsa_padding_mode:</span> <span class="ruby-string">"pss"</span> } +<span class="ruby-identifier">signature</span> = <span class="ruby-identifier">pkey</span>.<span class="ruby-identifier">sign_raw</span>(<span class="ruby-string">"SHA256"</span>, <span class="ruby-identifier">hash</span>, <span class="ruby-identifier">signopts</span>) + +<span class="ruby-comment"># Creates a copy of the RSA key pkey, but without the private components</span> +<span class="ruby-identifier">pub_key</span> = <span class="ruby-identifier">pkey</span>.<span class="ruby-identifier">public_key</span> +<span class="ruby-identifier">puts</span> <span class="ruby-identifier">pub_key</span>.<span class="ruby-identifier">verify_raw</span>(<span class="ruby-string">"SHA256"</span>, <span class="ruby-identifier">signature</span>, <span class="ruby-identifier">hash</span>, <span class="ruby-identifier">signopts</span>) <span class="ruby-comment"># => true</span> +</pre> + + <div class="method-source-code" id="sign_raw-source"> + <pre>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; }</pre> </div> </div> @@ -369,65 +855,298 @@ ossl_pkey_sign(VALUE self, VALUE digest, VALUE data) </div> - <div id="method-i-verify" class="method-detail "> + <div id="method-i-to_text" class="method-detail "> <div class="method-heading"> <span class="method-callseq"> - verify(digest, signature, data) → String + to_text → string </span> <span class="method-click-advice">click to toggle source</span> </div> <div class="method-description"> - <p>To verify the String <em>signature</em>, <em>digest</em>, an instance of <a href="../Digest.html"><code>OpenSSL::Digest</code></a>, must be provided to re-compute the message digest of the original <em>data</em>, also a String. The return value is <code>true</code> if the signature is valid, <code>false</code> otherwise. A <a href="PKeyError.html"><code>PKeyError</code></a> is raised should errors occur. Any previous state of the <a href="../Digest.html"><code>Digest</code></a> instance is irrelevant to the validation outcome, the digest instance is reset to its initial state during the operation.</p> + <p>Dumps key parameters, public key, and private key components contained in the key into a human-readable text.</p> -<h2 id="method-i-verify-label-Example">Example<span><a href="#method-i-verify-label-Example">¶</a> <a href="#top">↑</a></span></h2> +<p>This is intended for debugging purpose.</p> -<pre class="ruby"><span class="ruby-identifier">data</span> = <span class="ruby-string">'Sign me!'</span> -<span class="ruby-identifier">digest</span> = <span class="ruby-constant">OpenSSL</span><span class="ruby-operator">::</span><span class="ruby-constant">Digest</span>.<span class="ruby-identifier">new</span>(<span class="ruby-string">'SHA256'</span>) -<span class="ruby-identifier">pkey</span> = <span class="ruby-constant">OpenSSL</span><span class="ruby-operator">::</span><span class="ruby-constant">PKey</span><span class="ruby-operator">::</span><span class="ruby-constant">RSA</span>.<span class="ruby-identifier">new</span>(<span class="ruby-value">2048</span>) -<span class="ruby-identifier">signature</span> = <span class="ruby-identifier">pkey</span>.<span class="ruby-identifier">sign</span>(<span class="ruby-identifier">digest</span>, <span class="ruby-identifier">data</span>) -<span class="ruby-identifier">pub_key</span> = <span class="ruby-identifier">pkey</span>.<span class="ruby-identifier">public_key</span> -<span class="ruby-identifier">puts</span> <span class="ruby-identifier">pub_key</span>.<span class="ruby-identifier">verify</span>(<span class="ruby-identifier">digest</span>, <span class="ruby-identifier">signature</span>, <span class="ruby-identifier">data</span>) <span class="ruby-comment"># => true</span> -</pre> +<p>See also the man page EVP_PKEY_print_private(3).</p> + + <div class="method-source-code" id="to_text-source"> + <pre>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); +}</pre> + </div> + </div> + + + </div> + + <div id="method-i-verify" class="method-detail "> + <div class="method-heading"> + <span class="method-callseq"> + verify(digest, signature, data [, options]) → true or false + </span> + <span class="method-click-advice">click to toggle source</span> + </div> + + <div class="method-description"> + <p>Verifies the <code>signature</code> for the <code>data</code> using a message digest algorithm <code>digest</code> and a public key <code>pkey</code>.</p> + +<p>Returns <code>true</code> if the signature is successfully verified, <code>false</code> otherwise. The caller must check the return value.</p> + +<p>See <a href="PKey.html#method-i-sign"><code>sign</code></a> for the signing operation and an example.</p> + +<p>See also the man page EVP_DigestVerify(3).</p> +<dl class="rdoc-list note-list"><dt><code>digest</code> +<dd> +<p>See <a href="PKey.html#method-i-sign"><code>sign</code></a>.</p> +</dd><dt><code>signature</code> +<dd> +<p>A String containing the signature to be verified.</p> +</dd><dt><code>data</code> +<dd> +<p>See <a href="PKey.html#method-i-sign"><code>sign</code></a>.</p> +</dd><dt><code>options</code> +<dd> +<p>See <a href="PKey.html#method-i-sign"><code>sign</code></a>. <code>options</code> parameter was added in version 3.0.</p> +</dd></dl> <div class="method-source-code" id="verify-source"> <pre>static VALUE -ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data) +ossl_pkey_verify(int argc, VALUE *argv, VALUE self) { EVP_PKEY *pkey; - const EVP_MD *md; + VALUE digest, sig, data, options; + const EVP_MD *md = NULL; EVP_MD_CTX *ctx; - int siglen, result; + 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); - md = ossl_evp_get_digestbyname(digest); + if (!NIL_P(digest)) + md = ossl_evp_get_digestbyname(digest); StringValue(sig); - siglen = RSTRING_LENINT(sig); StringValue(data); ctx = EVP_MD_CTX_new(); if (!ctx) ossl_raise(ePKeyError, "EVP_MD_CTX_new"); - if (!EVP_VerifyInit_ex(ctx, md, NULL)) { + if (EVP_DigestVerifyInit(ctx, &pctx, md, /* engine */NULL, pkey) < 1) { EVP_MD_CTX_free(ctx); - ossl_raise(ePKeyError, "EVP_VerifyInit_ex"); + 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 (!EVP_VerifyUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data))) { +#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_VerifyUpdate"); + ossl_raise(ePKeyError, "EVP_DigestVerifyUpdate"); } - result = EVP_VerifyFinal(ctx, (unsigned char *)RSTRING_PTR(sig), siglen, pkey); + ret = EVP_DigestVerifyFinal(ctx, (unsigned char *)RSTRING_PTR(sig), + RSTRING_LEN(sig)); EVP_MD_CTX_free(ctx); - switch (result) { - case 0: + if (ret < 0) + ossl_raise(ePKeyError, "EVP_DigestVerifyFinal"); +#endif + if (ret) + return Qtrue; + else { ossl_clear_error(); return Qfalse; - case 1: + } +}</pre> + </div> + </div> + + + </div> + + <div id="method-i-verify_raw" class="method-detail "> + <div class="method-heading"> + <span class="method-callseq"> + verify_raw(digest, signature, data [, options]) → true or false + </span> + <span class="method-click-advice">click to toggle source</span> + </div> + + <div class="method-description"> + <p>Verifies the <code>signature</code> for the <code>data</code> using a public key <code>pkey</code>. Unlike <a href="PKey.html#method-i-verify"><code>verify</code></a>, this method will not hash <code>data</code> with <code>digest</code> automatically.</p> + +<p>Returns <code>true</code> if the signature is successfully verified, <code>false</code> otherwise. The caller must check the return value.</p> + +<p>See <a href="PKey.html#method-i-sign_raw"><code>sign_raw</code></a> for the signing operation and an example code.</p> + +<p>Added in version 3.0. See also the man page EVP_PKEY_verify(3).</p> +<dl class="rdoc-list note-list"><dt><code>signature</code> +<dd> +<p>A String containing the signature to be verified.</p> +</dd></dl> + + <div class="method-source-code" id="verify_raw-source"> + <pre>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; - default: - ossl_raise(ePKeyError, "EVP_VerifyFinal"); + else { + ossl_clear_error(); + return Qfalse; + } +}</pre> + </div> + </div> + + + </div> + + <div id="method-i-verify_recover" class="method-detail "> + <div class="method-heading"> + <span class="method-callseq"> + verify_recover(digest, signature [, options]) → string + </span> + <span class="method-click-advice">click to toggle source</span> + </div> + + <div class="method-description"> + <p>Recovers the signed data from <code>signature</code> using a public key <code>pkey</code>. Not all signature algorithms support this operation.</p> + +<p>Added in version 3.0. See also the man page EVP_PKEY_verify_recover(3).</p> +<dl class="rdoc-list note-list"><dt><code>signature</code> +<dd> +<p>A String containing the signature to be verified.</p> +</dd></dl> + + <div class="method-source-code" id="verify_recover-source"> + <pre>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; }</pre> </div> </div> |