@@ -777,44 +777,69 @@ ossl_pkey_compare(VALUE self, VALUE other)
777777}
778778
779779/*
780- * call-seq:
781- * pkey.sign(digest, data) -> String
780+ * call-seq:
781+ * pkey.sign(digest, data [, options] ) -> string
782782 *
783- * To sign the String _data_, _digest_, an instance of OpenSSL::Digest, must
784- * be provided. The return value is again a String containing the signature.
785- * A PKeyError is raised should errors occur.
786- * Any previous state of the Digest instance is irrelevant to the signature
787- * outcome, the digest instance is reset to its initial state during the
788- * operation.
783+ * Hashes and signs the +data+ using a message digest algorithm +digest+ and
784+ * a private key +pkey+.
789785 *
790- * == Example
791- * data = 'Sign me!'
792- * digest = OpenSSL::Digest.new('SHA256')
793- * pkey = OpenSSL::PKey::RSA.new(2048)
794- * signature = pkey.sign(digest, data)
786+ * See #verify for the verification operation.
787+ *
788+ * See also the man page EVP_DigestSign(3).
789+ *
790+ * +digest+::
791+ * A String that represents the message digest algorithm name, or +nil+
792+ * if the PKey type requires no digest algorithm.
793+ * For backwards compatibility, this can be an instance of OpenSSL::Digest.
794+ * Its state will not affect the signature.
795+ * +data+::
796+ * A String. The data to be hashed and signed.
797+ * +options+::
798+ * A Hash that contains algorithm specific control operations to \OpenSSL.
799+ * See OpenSSL's man page EVP_PKEY_CTX_ctrl_str(3) for details.
800+ * +options+ parameter was added in version 2.3.
801+ *
802+ * Example:
803+ * data = "Sign me!"
804+ * pkey = OpenSSL::PKey.generate_key("RSA", rsa_keygen_bits: 2048)
805+ * signopts = { rsa_padding_mode: "pss" }
806+ * signature = pkey.sign("SHA256", data, signopts)
807+ *
808+ * # Creates a copy of the RSA key pkey, but without the private components
809+ * pub_key = pkey.public_key
810+ * puts pub_key.verify("SHA256", signature, data, signopts) # => true
795811 */
796812static VALUE
797- ossl_pkey_sign (VALUE self , VALUE digest , VALUE data )
813+ ossl_pkey_sign (int argc , VALUE * argv , VALUE self )
798814{
799815 EVP_PKEY * pkey ;
816+ VALUE digest , data , options , sig ;
800817 const EVP_MD * md = NULL ;
801818 EVP_MD_CTX * ctx ;
819+ EVP_PKEY_CTX * pctx ;
802820 size_t siglen ;
803821 int state ;
804- VALUE sig ;
805822
806823 pkey = GetPrivPKeyPtr (self );
824+ rb_scan_args (argc , argv , "21" , & digest , & data , & options );
807825 if (!NIL_P (digest ))
808826 md = ossl_evp_get_digestbyname (digest );
809827 StringValue (data );
810828
811829 ctx = EVP_MD_CTX_new ();
812830 if (!ctx )
813831 ossl_raise (ePKeyError , "EVP_MD_CTX_new" );
814- if (EVP_DigestSignInit (ctx , NULL , md , /* engine */ NULL , pkey ) < 1 ) {
832+ if (EVP_DigestSignInit (ctx , & pctx , md , /* engine */ NULL , pkey ) < 1 ) {
815833 EVP_MD_CTX_free (ctx );
816834 ossl_raise (ePKeyError , "EVP_DigestSignInit" );
817835 }
836+ if (!NIL_P (options )) {
837+ pkey_ctx_apply_options (pctx , options , & state );
838+ if (state ) {
839+ EVP_MD_CTX_free (ctx );
840+ rb_jump_tag (state );
841+ }
842+ }
818843#if OPENSSL_VERSION_NUMBER >= 0x10101000 && !defined(LIBRESSL_VERSION_NUMBER )
819844 if (EVP_DigestSign (ctx , NULL , & siglen , (unsigned char * )RSTRING_PTR (data ),
820845 RSTRING_LEN (data )) < 1 ) {
@@ -866,35 +891,40 @@ ossl_pkey_sign(VALUE self, VALUE digest, VALUE data)
866891}
867892
868893/*
869- * call-seq:
870- * pkey.verify(digest, signature, data) -> String
894+ * call-seq:
895+ * pkey.verify(digest, signature, data [, options] ) -> true or false
871896 *
872- * To verify the String _signature_, _digest_, an instance of
873- * OpenSSL::Digest, must be provided to re-compute the message digest of the
874- * original _data_, also a String. The return value is +true+ if the
875- * signature is valid, +false+ otherwise. A PKeyError is raised should errors
876- * occur.
877- * Any previous state of the Digest instance is irrelevant to the validation
878- * outcome, the digest instance is reset to its initial state during the
879- * operation.
897+ * Verifies the +signature+ for the +data+ using a message digest algorithm
898+ * +digest+ and a public key +pkey+.
880899 *
881- * == Example
882- * data = 'Sign me!'
883- * digest = OpenSSL::Digest.new('SHA256')
884- * pkey = OpenSSL::PKey::RSA.new(2048)
885- * signature = pkey.sign(digest, data)
886- * pub_key = pkey.public_key
887- * puts pub_key.verify(digest, signature, data) # => true
900+ * Returns +true+ if the signature is successfully verified, +false+ otherwise.
901+ * The caller must check the return value.
902+ *
903+ * See #sign for the signing operation and an example.
904+ *
905+ * See also the man page EVP_DigestVerify(3).
906+ *
907+ * +digest+::
908+ * See #sign.
909+ * +signature+::
910+ * A String containing the signature to be verified.
911+ * +data+::
912+ * See #sign.
913+ * +options+::
914+ * See #sign. +options+ parameter was added in version 2.3.
888915 */
889916static VALUE
890- ossl_pkey_verify (VALUE self , VALUE digest , VALUE sig , VALUE data )
917+ ossl_pkey_verify (int argc , VALUE * argv , VALUE self )
891918{
892919 EVP_PKEY * pkey ;
920+ VALUE digest , sig , data , options ;
893921 const EVP_MD * md = NULL ;
894922 EVP_MD_CTX * ctx ;
895- int ret ;
923+ EVP_PKEY_CTX * pctx ;
924+ int state , ret ;
896925
897926 GetPKey (self , pkey );
927+ rb_scan_args (argc , argv , "31" , & digest , & sig , & data , & options );
898928 ossl_pkey_check_public_key (pkey );
899929 if (!NIL_P (digest ))
900930 md = ossl_evp_get_digestbyname (digest );
@@ -904,10 +934,17 @@ ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data)
904934 ctx = EVP_MD_CTX_new ();
905935 if (!ctx )
906936 ossl_raise (ePKeyError , "EVP_MD_CTX_new" );
907- if (EVP_DigestVerifyInit (ctx , NULL , md , /* engine */ NULL , pkey ) < 1 ) {
937+ if (EVP_DigestVerifyInit (ctx , & pctx , md , /* engine */ NULL , pkey ) < 1 ) {
908938 EVP_MD_CTX_free (ctx );
909939 ossl_raise (ePKeyError , "EVP_DigestVerifyInit" );
910940 }
941+ if (!NIL_P (options )) {
942+ pkey_ctx_apply_options (pctx , options , & state );
943+ if (state ) {
944+ EVP_MD_CTX_free (ctx );
945+ rb_jump_tag (state );
946+ }
947+ }
911948#if OPENSSL_VERSION_NUMBER >= 0x10101000 && !defined(LIBRESSL_VERSION_NUMBER )
912949 ret = EVP_DigestVerify (ctx , (unsigned char * )RSTRING_PTR (sig ),
913950 RSTRING_LEN (sig ), (unsigned char * )RSTRING_PTR (data ),
@@ -1081,8 +1118,8 @@ Init_ossl_pkey(void)
10811118 rb_define_method (cPKey , "public_to_pem" , ossl_pkey_public_to_pem , 0 );
10821119 rb_define_method (cPKey , "compare?" , ossl_pkey_compare , 1 );
10831120
1084- rb_define_method (cPKey , "sign" , ossl_pkey_sign , 2 );
1085- rb_define_method (cPKey , "verify" , ossl_pkey_verify , 3 );
1121+ rb_define_method (cPKey , "sign" , ossl_pkey_sign , -1 );
1122+ rb_define_method (cPKey , "verify" , ossl_pkey_verify , -1 );
10861123 rb_define_method (cPKey , "derive" , ossl_pkey_derive , -1 );
10871124
10881125 id_private_q = rb_intern ("private?" );
0 commit comments