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