@@ -973,6 +973,235 @@ ossl_pkey_verify(int argc, VALUE *argv, VALUE self)
973
973
}
974
974
}
975
975
976
+ /*
977
+ * call-seq:
978
+ * pkey.sign_raw(digest, data [, options]) -> string
979
+ *
980
+ * Signs +data+ using a private key +pkey+. Unlike #sign, +data+ will not be
981
+ * hashed by +digest+ automatically.
982
+ *
983
+ * See #verify_raw for the verification operation.
984
+ *
985
+ * Added in version 3.0. See also the man page EVP_PKEY_sign(3).
986
+ *
987
+ * +digest+::
988
+ * A String that represents the message digest algorithm name, or +nil+
989
+ * if the PKey type requires no digest algorithm.
990
+ * Although this method will not hash +data+ with it, this parameter may still
991
+ * be required depending on the signature algorithm.
992
+ * +data+::
993
+ * A String. The data to be signed.
994
+ * +options+::
995
+ * A Hash that contains algorithm specific control operations to \OpenSSL.
996
+ * See OpenSSL's man page EVP_PKEY_CTX_ctrl_str(3) for details.
997
+ *
998
+ * Example:
999
+ * data = "Sign me!"
1000
+ * hash = OpenSSL::Digest.digest("SHA256", data)
1001
+ * pkey = OpenSSL::PKey.generate_key("RSA", rsa_keygen_bits: 2048)
1002
+ * signopts = { rsa_padding_mode: "pss" }
1003
+ * signature = pkey.sign_raw("SHA256", hash, signopts)
1004
+ *
1005
+ * # Creates a copy of the RSA key pkey, but without the private components
1006
+ * pub_key = pkey.public_key
1007
+ * puts pub_key.verify_raw("SHA256", signature, hash, signopts) # => true
1008
+ */
1009
+ static VALUE
1010
+ ossl_pkey_sign_raw (int argc , VALUE * argv , VALUE self )
1011
+ {
1012
+ EVP_PKEY * pkey ;
1013
+ VALUE digest , data , options , sig ;
1014
+ const EVP_MD * md = NULL ;
1015
+ EVP_PKEY_CTX * ctx ;
1016
+ size_t outlen ;
1017
+ int state ;
1018
+
1019
+ GetPKey (self , pkey );
1020
+ rb_scan_args (argc , argv , "21" , & digest , & data , & options );
1021
+ if (!NIL_P (digest ))
1022
+ md = ossl_evp_get_digestbyname (digest );
1023
+ StringValue (data );
1024
+
1025
+ ctx = EVP_PKEY_CTX_new (pkey , /* engine */ NULL );
1026
+ if (!ctx )
1027
+ ossl_raise (ePKeyError , "EVP_PKEY_CTX_new" );
1028
+ if (EVP_PKEY_sign_init (ctx ) <= 0 ) {
1029
+ EVP_PKEY_CTX_free (ctx );
1030
+ ossl_raise (ePKeyError , "EVP_PKEY_sign_init" );
1031
+ }
1032
+ if (md && EVP_PKEY_CTX_set_signature_md (ctx , md ) <= 0 ) {
1033
+ EVP_PKEY_CTX_free (ctx );
1034
+ ossl_raise (ePKeyError , "EVP_PKEY_CTX_set_signature_md" );
1035
+ }
1036
+ if (!NIL_P (options )) {
1037
+ pkey_ctx_apply_options (ctx , options , & state );
1038
+ if (state ) {
1039
+ EVP_PKEY_CTX_free (ctx );
1040
+ rb_jump_tag (state );
1041
+ }
1042
+ }
1043
+ if (EVP_PKEY_sign (ctx , NULL , & outlen , (unsigned char * )RSTRING_PTR (data ),
1044
+ RSTRING_LEN (data )) <= 0 ) {
1045
+ EVP_PKEY_CTX_free (ctx );
1046
+ ossl_raise (ePKeyError , "EVP_PKEY_sign" );
1047
+ }
1048
+ if (outlen > LONG_MAX ) {
1049
+ EVP_PKEY_CTX_free (ctx );
1050
+ rb_raise (ePKeyError , "signature would be too large" );
1051
+ }
1052
+ sig = ossl_str_new (NULL , (long )outlen , & state );
1053
+ if (state ) {
1054
+ EVP_PKEY_CTX_free (ctx );
1055
+ rb_jump_tag (state );
1056
+ }
1057
+ if (EVP_PKEY_sign (ctx , (unsigned char * )RSTRING_PTR (sig ), & outlen ,
1058
+ (unsigned char * )RSTRING_PTR (data ),
1059
+ RSTRING_LEN (data )) <= 0 ) {
1060
+ EVP_PKEY_CTX_free (ctx );
1061
+ ossl_raise (ePKeyError , "EVP_PKEY_sign" );
1062
+ }
1063
+ EVP_PKEY_CTX_free (ctx );
1064
+ rb_str_set_len (sig , outlen );
1065
+ return sig ;
1066
+ }
1067
+
1068
+ /*
1069
+ * call-seq:
1070
+ * pkey.verify_raw(digest, signature, data [, options]) -> true or false
1071
+ *
1072
+ * Verifies the +signature+ for the +data+ using a public key +pkey+. Unlike
1073
+ * #verify, this method will not hash +data+ with +digest+ automatically.
1074
+ *
1075
+ * Returns +true+ if the signature is successfully verified, +false+ otherwise.
1076
+ * The caller must check the return value.
1077
+ *
1078
+ * See #sign_raw for the signing operation and an example.
1079
+ *
1080
+ * Added in version 3.0. See also the man page EVP_PKEY_verify(3).
1081
+ *
1082
+ * +signature+::
1083
+ * A String containing the signature to be verified.
1084
+ */
1085
+ static VALUE
1086
+ ossl_pkey_verify_raw (int argc , VALUE * argv , VALUE self )
1087
+ {
1088
+ EVP_PKEY * pkey ;
1089
+ VALUE digest , sig , data , options ;
1090
+ const EVP_MD * md = NULL ;
1091
+ EVP_PKEY_CTX * ctx ;
1092
+ int state , ret ;
1093
+
1094
+ GetPKey (self , pkey );
1095
+ rb_scan_args (argc , argv , "31" , & digest , & sig , & data , & options );
1096
+ ossl_pkey_check_public_key (pkey );
1097
+ if (!NIL_P (digest ))
1098
+ md = ossl_evp_get_digestbyname (digest );
1099
+ StringValue (sig );
1100
+ StringValue (data );
1101
+
1102
+ ctx = EVP_PKEY_CTX_new (pkey , /* engine */ NULL );
1103
+ if (!ctx )
1104
+ ossl_raise (ePKeyError , "EVP_PKEY_CTX_new" );
1105
+ if (EVP_PKEY_verify_init (ctx ) <= 0 ) {
1106
+ EVP_PKEY_CTX_free (ctx );
1107
+ ossl_raise (ePKeyError , "EVP_PKEY_verify_init" );
1108
+ }
1109
+ if (md && EVP_PKEY_CTX_set_signature_md (ctx , md ) <= 0 ) {
1110
+ EVP_PKEY_CTX_free (ctx );
1111
+ ossl_raise (ePKeyError , "EVP_PKEY_CTX_set_signature_md" );
1112
+ }
1113
+ if (!NIL_P (options )) {
1114
+ pkey_ctx_apply_options (ctx , options , & state );
1115
+ if (state ) {
1116
+ EVP_PKEY_CTX_free (ctx );
1117
+ rb_jump_tag (state );
1118
+ }
1119
+ }
1120
+ ret = EVP_PKEY_verify (ctx , (unsigned char * )RSTRING_PTR (sig ),
1121
+ RSTRING_LEN (sig ),
1122
+ (unsigned char * )RSTRING_PTR (data ),
1123
+ RSTRING_LEN (data ));
1124
+ EVP_PKEY_CTX_free (ctx );
1125
+ if (ret < 0 )
1126
+ ossl_raise (ePKeyError , "EVP_PKEY_verify" );
1127
+
1128
+ if (ret )
1129
+ return Qtrue ;
1130
+ else {
1131
+ ossl_clear_error ();
1132
+ return Qfalse ;
1133
+ }
1134
+ }
1135
+
1136
+ /*
1137
+ * call-seq:
1138
+ * pkey.verify_recover(digest, signature [, options]) -> string
1139
+ *
1140
+ * Recovers the signed data from +signature+ using a public key +pkey+. Not all
1141
+ * signature algorithm supports this operation.
1142
+ *
1143
+ * Added in version 3.0. See also the man page EVP_PKEY_verify_recover(3).
1144
+ *
1145
+ * +signature+::
1146
+ * A String containing the signature to be verified.
1147
+ */
1148
+ static VALUE
1149
+ ossl_pkey_verify_recover (int argc , VALUE * argv , VALUE self )
1150
+ {
1151
+ EVP_PKEY * pkey ;
1152
+ VALUE digest , sig , options , out ;
1153
+ const EVP_MD * md = NULL ;
1154
+ EVP_PKEY_CTX * ctx ;
1155
+ int state ;
1156
+ size_t outlen ;
1157
+
1158
+ GetPKey (self , pkey );
1159
+ rb_scan_args (argc , argv , "21" , & digest , & sig , & options );
1160
+ ossl_pkey_check_public_key (pkey );
1161
+ if (!NIL_P (digest ))
1162
+ md = ossl_evp_get_digestbyname (digest );
1163
+ StringValue (sig );
1164
+
1165
+ ctx = EVP_PKEY_CTX_new (pkey , /* engine */ NULL );
1166
+ if (!ctx )
1167
+ ossl_raise (ePKeyError , "EVP_PKEY_CTX_new" );
1168
+ if (EVP_PKEY_verify_recover_init (ctx ) <= 0 ) {
1169
+ EVP_PKEY_CTX_free (ctx );
1170
+ ossl_raise (ePKeyError , "EVP_PKEY_verify_recover_init" );
1171
+ }
1172
+ if (md && EVP_PKEY_CTX_set_signature_md (ctx , md ) <= 0 ) {
1173
+ EVP_PKEY_CTX_free (ctx );
1174
+ ossl_raise (ePKeyError , "EVP_PKEY_CTX_set_signature_md" );
1175
+ }
1176
+ if (!NIL_P (options )) {
1177
+ pkey_ctx_apply_options (ctx , options , & state );
1178
+ if (state ) {
1179
+ EVP_PKEY_CTX_free (ctx );
1180
+ rb_jump_tag (state );
1181
+ }
1182
+ }
1183
+ if (EVP_PKEY_verify_recover (ctx , NULL , & outlen ,
1184
+ (unsigned char * )RSTRING_PTR (sig ),
1185
+ RSTRING_LEN (sig )) <= 0 ) {
1186
+ EVP_PKEY_CTX_free (ctx );
1187
+ ossl_raise (ePKeyError , "EVP_PKEY_verify_recover" );
1188
+ }
1189
+ out = ossl_str_new (NULL , (long )outlen , & state );
1190
+ if (state ) {
1191
+ EVP_PKEY_CTX_free (ctx );
1192
+ rb_jump_tag (state );
1193
+ }
1194
+ if (EVP_PKEY_verify_recover (ctx , (unsigned char * )RSTRING_PTR (out ), & outlen ,
1195
+ (unsigned char * )RSTRING_PTR (sig ),
1196
+ RSTRING_LEN (sig )) <= 0 ) {
1197
+ EVP_PKEY_CTX_free (ctx );
1198
+ ossl_raise (ePKeyError , "EVP_PKEY_verify_recover" );
1199
+ }
1200
+ EVP_PKEY_CTX_free (ctx );
1201
+ rb_str_set_len (out , outlen );
1202
+ return out ;
1203
+ }
1204
+
976
1205
/*
977
1206
* call-seq:
978
1207
* pkey.derive(peer_pkey) -> string
@@ -1262,6 +1491,9 @@ Init_ossl_pkey(void)
1262
1491
1263
1492
rb_define_method (cPKey , "sign" , ossl_pkey_sign , -1 );
1264
1493
rb_define_method (cPKey , "verify" , ossl_pkey_verify , -1 );
1494
+ rb_define_method (cPKey , "sign_raw" , ossl_pkey_sign_raw , -1 );
1495
+ rb_define_method (cPKey , "verify_raw" , ossl_pkey_verify_raw , -1 );
1496
+ rb_define_method (cPKey , "verify_recover" , ossl_pkey_verify_recover , -1 );
1265
1497
rb_define_method (cPKey , "derive" , ossl_pkey_derive , -1 );
1266
1498
rb_define_method (cPKey , "encrypt" , ossl_pkey_encrypt , -1 );
1267
1499
rb_define_method (cPKey , "decrypt" , ossl_pkey_decrypt , -1 );
0 commit comments