openssl 2.1.3 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +35 -45
  3. data/History.md +302 -1
  4. data/README.md +2 -2
  5. data/ext/openssl/extconf.rb +77 -62
  6. data/ext/openssl/openssl_missing.c +0 -66
  7. data/ext/openssl/openssl_missing.h +59 -43
  8. data/ext/openssl/ossl.c +110 -64
  9. data/ext/openssl/ossl.h +33 -10
  10. data/ext/openssl/ossl_asn1.c +51 -13
  11. data/ext/openssl/ossl_bn.c +275 -146
  12. data/ext/openssl/ossl_bn.h +2 -1
  13. data/ext/openssl/ossl_cipher.c +39 -31
  14. data/ext/openssl/ossl_config.c +412 -41
  15. data/ext/openssl/ossl_config.h +4 -7
  16. data/ext/openssl/ossl_digest.c +25 -60
  17. data/ext/openssl/ossl_engine.c +18 -27
  18. data/ext/openssl/ossl_hmac.c +60 -145
  19. data/ext/openssl/ossl_kdf.c +14 -22
  20. data/ext/openssl/ossl_ns_spki.c +1 -1
  21. data/ext/openssl/ossl_ocsp.c +11 -64
  22. data/ext/openssl/ossl_ocsp.h +3 -3
  23. data/ext/openssl/ossl_pkcs12.c +21 -3
  24. data/ext/openssl/ossl_pkcs7.c +45 -78
  25. data/ext/openssl/ossl_pkcs7.h +16 -0
  26. data/ext/openssl/ossl_pkey.c +1295 -178
  27. data/ext/openssl/ossl_pkey.h +36 -73
  28. data/ext/openssl/ossl_pkey_dh.c +130 -340
  29. data/ext/openssl/ossl_pkey_dsa.c +100 -405
  30. data/ext/openssl/ossl_pkey_ec.c +192 -335
  31. data/ext/openssl/ossl_pkey_rsa.c +110 -489
  32. data/ext/openssl/ossl_rand.c +2 -32
  33. data/ext/openssl/ossl_ssl.c +556 -442
  34. data/ext/openssl/ossl_ssl_session.c +28 -29
  35. data/ext/openssl/ossl_ts.c +1539 -0
  36. data/ext/openssl/ossl_ts.h +16 -0
  37. data/ext/openssl/ossl_x509.c +0 -6
  38. data/ext/openssl/ossl_x509cert.c +169 -13
  39. data/ext/openssl/ossl_x509crl.c +13 -10
  40. data/ext/openssl/ossl_x509ext.c +15 -2
  41. data/ext/openssl/ossl_x509name.c +15 -4
  42. data/ext/openssl/ossl_x509req.c +13 -10
  43. data/ext/openssl/ossl_x509revoked.c +3 -3
  44. data/ext/openssl/ossl_x509store.c +154 -70
  45. data/lib/openssl/bn.rb +1 -1
  46. data/lib/openssl/buffering.rb +37 -5
  47. data/lib/openssl/cipher.rb +1 -1
  48. data/lib/openssl/digest.rb +10 -12
  49. data/lib/openssl/hmac.rb +78 -0
  50. data/lib/openssl/marshal.rb +30 -0
  51. data/lib/openssl/pkcs5.rb +1 -1
  52. data/lib/openssl/pkey.rb +447 -1
  53. data/lib/openssl/ssl.rb +52 -9
  54. data/lib/openssl/version.rb +5 -0
  55. data/lib/openssl/x509.rb +177 -1
  56. data/lib/openssl.rb +24 -9
  57. metadata +10 -79
  58. data/ext/openssl/deprecation.rb +0 -27
  59. data/ext/openssl/ossl_version.h +0 -15
  60. data/ext/openssl/ruby_missing.h +0 -24
  61. data/lib/openssl/config.rb +0 -492
@@ -9,6 +9,10 @@
9
9
  */
10
10
  #include "ossl.h"
11
11
 
12
+ #ifdef OSSL_USE_ENGINE
13
+ # include <openssl/engine.h>
14
+ #endif
15
+
12
16
  /*
13
17
  * Classes
14
18
  */
@@ -17,64 +21,6 @@ VALUE cPKey;
17
21
  VALUE ePKeyError;
18
22
  static ID id_private_q;
19
23
 
20
- /*
21
- * callback for generating keys
22
- */
23
- static VALUE
24
- call_check_ints0(VALUE arg)
25
- {
26
- rb_thread_check_ints();
27
- return Qnil;
28
- }
29
-
30
- static void *
31
- call_check_ints(void *arg)
32
- {
33
- int state;
34
- rb_protect(call_check_ints0, Qnil, &state);
35
- return (void *)(VALUE)state;
36
- }
37
-
38
- int
39
- ossl_generate_cb_2(int p, int n, BN_GENCB *cb)
40
- {
41
- VALUE ary;
42
- struct ossl_generate_cb_arg *arg;
43
- int state;
44
-
45
- arg = (struct ossl_generate_cb_arg *)BN_GENCB_get_arg(cb);
46
- if (arg->yield) {
47
- ary = rb_ary_new2(2);
48
- rb_ary_store(ary, 0, INT2NUM(p));
49
- rb_ary_store(ary, 1, INT2NUM(n));
50
-
51
- /*
52
- * can be break by raising exception or 'break'
53
- */
54
- rb_protect(rb_yield, ary, &state);
55
- if (state) {
56
- arg->state = state;
57
- return 0;
58
- }
59
- }
60
- if (arg->interrupted) {
61
- arg->interrupted = 0;
62
- state = (int)(VALUE)rb_thread_call_with_gvl(call_check_ints, NULL);
63
- if (state) {
64
- arg->state = state;
65
- return 0;
66
- }
67
- }
68
- return 1;
69
- }
70
-
71
- void
72
- ossl_generate_cb_stop(void *ptr)
73
- {
74
- struct ossl_generate_cb_arg *arg = (struct ossl_generate_cb_arg *)ptr;
75
- arg->interrupted = 1;
76
- }
77
-
78
24
  static void
79
25
  ossl_evp_pkey_free(void *ptr)
80
26
  {
@@ -93,36 +39,29 @@ const rb_data_type_t ossl_evp_pkey_type = {
93
39
  };
94
40
 
95
41
  static VALUE
96
- pkey_new0(EVP_PKEY *pkey)
42
+ pkey_new0(VALUE arg)
97
43
  {
98
- VALUE obj;
99
- int type;
44
+ EVP_PKEY *pkey = (EVP_PKEY *)arg;
45
+ VALUE klass, obj;
100
46
 
101
- if (!pkey || (type = EVP_PKEY_base_id(pkey)) == EVP_PKEY_NONE)
102
- ossl_raise(rb_eRuntimeError, "pkey is empty");
103
-
104
- switch (type) {
47
+ switch (EVP_PKEY_base_id(pkey)) {
105
48
  #if !defined(OPENSSL_NO_RSA)
106
- case EVP_PKEY_RSA:
107
- return ossl_rsa_new(pkey);
49
+ case EVP_PKEY_RSA: klass = cRSA; break;
108
50
  #endif
109
51
  #if !defined(OPENSSL_NO_DSA)
110
- case EVP_PKEY_DSA:
111
- return ossl_dsa_new(pkey);
52
+ case EVP_PKEY_DSA: klass = cDSA; break;
112
53
  #endif
113
54
  #if !defined(OPENSSL_NO_DH)
114
- case EVP_PKEY_DH:
115
- return ossl_dh_new(pkey);
55
+ case EVP_PKEY_DH: klass = cDH; break;
116
56
  #endif
117
57
  #if !defined(OPENSSL_NO_EC)
118
- case EVP_PKEY_EC:
119
- return ossl_ec_new(pkey);
58
+ case EVP_PKEY_EC: klass = cEC; break;
120
59
  #endif
121
- default:
122
- obj = NewPKey(cPKey);
123
- SetPKey(obj, pkey);
124
- return obj;
60
+ default: klass = cPKey; break;
125
61
  }
62
+ obj = rb_obj_alloc(klass);
63
+ RTYPEDDATA_DATA(obj) = pkey;
64
+ return obj;
126
65
  }
127
66
 
128
67
  VALUE
@@ -131,7 +70,7 @@ ossl_pkey_new(EVP_PKEY *pkey)
131
70
  VALUE obj;
132
71
  int status;
133
72
 
134
- obj = rb_protect((VALUE (*)(VALUE))pkey_new0, (VALUE)pkey, &status);
73
+ obj = rb_protect(pkey_new0, (VALUE)pkey, &status);
135
74
  if (status) {
136
75
  EVP_PKEY_free(pkey);
137
76
  rb_jump_tag(status);
@@ -140,6 +79,114 @@ ossl_pkey_new(EVP_PKEY *pkey)
140
79
  return obj;
141
80
  }
142
81
 
82
+ #if OSSL_OPENSSL_PREREQ(3, 0, 0)
83
+ # include <openssl/decoder.h>
84
+
85
+ EVP_PKEY *
86
+ ossl_pkey_read_generic(BIO *bio, VALUE pass)
87
+ {
88
+ void *ppass = (void *)pass;
89
+ OSSL_DECODER_CTX *dctx;
90
+ EVP_PKEY *pkey = NULL;
91
+ int pos = 0, pos2;
92
+
93
+ dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, "DER", NULL, NULL, 0, NULL, NULL);
94
+ if (!dctx)
95
+ goto out;
96
+ if (OSSL_DECODER_CTX_set_pem_password_cb(dctx, ossl_pem_passwd_cb, ppass) != 1)
97
+ goto out;
98
+
99
+ /* First check DER */
100
+ if (OSSL_DECODER_from_bio(dctx, bio) == 1)
101
+ goto out;
102
+ OSSL_BIO_reset(bio);
103
+
104
+ /* Then check PEM; multiple OSSL_DECODER_from_bio() calls may be needed */
105
+ if (OSSL_DECODER_CTX_set_input_type(dctx, "PEM") != 1)
106
+ goto out;
107
+ /*
108
+ * First check for private key formats. This is to keep compatibility with
109
+ * ruby/openssl < 3.0 which decoded the following as a private key.
110
+ *
111
+ * $ openssl ecparam -name prime256v1 -genkey -outform PEM
112
+ * -----BEGIN EC PARAMETERS-----
113
+ * BggqhkjOPQMBBw==
114
+ * -----END EC PARAMETERS-----
115
+ * -----BEGIN EC PRIVATE KEY-----
116
+ * MHcCAQEEIAG8ugBbA5MHkqnZ9ujQF93OyUfL9tk8sxqM5Wv5tKg5oAoGCCqGSM49
117
+ * AwEHoUQDQgAEVcjhJfkwqh5C7kGuhAf8XaAjVuG5ADwb5ayg/cJijCgs+GcXeedj
118
+ * 86avKpGH84DXUlB23C/kPt+6fXYlitUmXQ==
119
+ * -----END EC PRIVATE KEY-----
120
+ *
121
+ * While the first PEM block is a proper encoding of ECParameters, thus
122
+ * OSSL_DECODER_from_bio() would pick it up, ruby/openssl used to return
123
+ * the latter instead. Existing applications expect this behavior.
124
+ *
125
+ * Note that normally, the input is supposed to contain a single decodable
126
+ * PEM block only, so this special handling should not create a new problem.
127
+ */
128
+ OSSL_DECODER_CTX_set_selection(dctx, EVP_PKEY_KEYPAIR);
129
+ while (1) {
130
+ if (OSSL_DECODER_from_bio(dctx, bio) == 1)
131
+ goto out;
132
+ if (BIO_eof(bio))
133
+ break;
134
+ pos2 = BIO_tell(bio);
135
+ if (pos2 < 0 || pos2 <= pos)
136
+ break;
137
+ ossl_clear_error();
138
+ pos = pos2;
139
+ }
140
+
141
+ OSSL_BIO_reset(bio);
142
+ OSSL_DECODER_CTX_set_selection(dctx, 0);
143
+ while (1) {
144
+ if (OSSL_DECODER_from_bio(dctx, bio) == 1)
145
+ goto out;
146
+ if (BIO_eof(bio))
147
+ break;
148
+ pos2 = BIO_tell(bio);
149
+ if (pos2 < 0 || pos2 <= pos)
150
+ break;
151
+ ossl_clear_error();
152
+ pos = pos2;
153
+ }
154
+
155
+ out:
156
+ OSSL_DECODER_CTX_free(dctx);
157
+ return pkey;
158
+ }
159
+ #else
160
+ EVP_PKEY *
161
+ ossl_pkey_read_generic(BIO *bio, VALUE pass)
162
+ {
163
+ void *ppass = (void *)pass;
164
+ EVP_PKEY *pkey;
165
+
166
+ if ((pkey = d2i_PrivateKey_bio(bio, NULL)))
167
+ goto out;
168
+ OSSL_BIO_reset(bio);
169
+ if ((pkey = d2i_PKCS8PrivateKey_bio(bio, NULL, ossl_pem_passwd_cb, ppass)))
170
+ goto out;
171
+ OSSL_BIO_reset(bio);
172
+ if ((pkey = d2i_PUBKEY_bio(bio, NULL)))
173
+ goto out;
174
+ OSSL_BIO_reset(bio);
175
+ /* PEM_read_bio_PrivateKey() also parses PKCS #8 formats */
176
+ if ((pkey = PEM_read_bio_PrivateKey(bio, NULL, ossl_pem_passwd_cb, ppass)))
177
+ goto out;
178
+ OSSL_BIO_reset(bio);
179
+ if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)))
180
+ goto out;
181
+ OSSL_BIO_reset(bio);
182
+ if ((pkey = PEM_read_bio_Parameters(bio, NULL)))
183
+ goto out;
184
+
185
+ out:
186
+ return pkey;
187
+ }
188
+ #endif
189
+
143
190
  /*
144
191
  * call-seq:
145
192
  * OpenSSL::PKey.read(string [, pwd ]) -> PKey
@@ -149,7 +196,7 @@ ossl_pkey_new(EVP_PKEY *pkey)
149
196
  * instance of the appropriate PKey class.
150
197
  *
151
198
  * === Parameters
152
- * * _string+ is a DER- or PEM-encoded string containing an arbitrary private
199
+ * * _string_ is a DER- or PEM-encoded string containing an arbitrary private
153
200
  * or public key.
154
201
  * * _io_ is an instance of IO containing a DER- or PEM-encoded
155
202
  * arbitrary private or public key.
@@ -164,30 +211,283 @@ ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self)
164
211
  VALUE data, pass;
165
212
 
166
213
  rb_scan_args(argc, argv, "11", &data, &pass);
167
- pass = ossl_pem_passwd_value(pass);
168
-
169
214
  bio = ossl_obj2bio(&data);
170
- if (!(pkey = d2i_PrivateKey_bio(bio, NULL))) {
171
- OSSL_BIO_reset(bio);
172
- if (!(pkey = PEM_read_bio_PrivateKey(bio, NULL, ossl_pem_passwd_cb, (void *)pass))) {
173
- OSSL_BIO_reset(bio);
174
- if (!(pkey = d2i_PUBKEY_bio(bio, NULL))) {
175
- OSSL_BIO_reset(bio);
176
- pkey = PEM_read_bio_PUBKEY(bio, NULL, ossl_pem_passwd_cb, (void *)pass);
177
- }
178
- }
179
- }
180
-
215
+ pkey = ossl_pkey_read_generic(bio, ossl_pem_passwd_value(pass));
181
216
  BIO_free(bio);
182
217
  if (!pkey)
183
218
  ossl_raise(ePKeyError, "Could not parse PKey");
184
-
185
219
  return ossl_pkey_new(pkey);
186
220
  }
187
221
 
222
+ static VALUE
223
+ pkey_ctx_apply_options_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ctx_v))
224
+ {
225
+ VALUE key = rb_ary_entry(i, 0), value = rb_ary_entry(i, 1);
226
+ EVP_PKEY_CTX *ctx = (EVP_PKEY_CTX *)ctx_v;
227
+
228
+ if (SYMBOL_P(key))
229
+ key = rb_sym2str(key);
230
+ value = rb_String(value);
231
+
232
+ if (EVP_PKEY_CTX_ctrl_str(ctx, StringValueCStr(key), StringValueCStr(value)) <= 0)
233
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_ctrl_str(ctx, %+"PRIsVALUE", %+"PRIsVALUE")",
234
+ key, value);
235
+ return Qnil;
236
+ }
237
+
238
+ static VALUE
239
+ pkey_ctx_apply_options0(VALUE args_v)
240
+ {
241
+ VALUE *args = (VALUE *)args_v;
242
+ Check_Type(args[1], T_HASH);
243
+
244
+ rb_block_call(args[1], rb_intern("each"), 0, NULL,
245
+ pkey_ctx_apply_options_i, args[0]);
246
+ return Qnil;
247
+ }
248
+
249
+ static void
250
+ pkey_ctx_apply_options(EVP_PKEY_CTX *ctx, VALUE options, int *state)
251
+ {
252
+ VALUE args[2];
253
+ args[0] = (VALUE)ctx;
254
+ args[1] = options;
255
+
256
+ rb_protect(pkey_ctx_apply_options0, (VALUE)args, state);
257
+ }
258
+
259
+ struct pkey_blocking_generate_arg {
260
+ EVP_PKEY_CTX *ctx;
261
+ EVP_PKEY *pkey;
262
+ int state;
263
+ int yield: 1;
264
+ int genparam: 1;
265
+ int interrupted: 1;
266
+ };
267
+
268
+ static VALUE
269
+ pkey_gen_cb_yield(VALUE ctx_v)
270
+ {
271
+ EVP_PKEY_CTX *ctx = (void *)ctx_v;
272
+ int i, info_num;
273
+ VALUE *argv;
274
+
275
+ info_num = EVP_PKEY_CTX_get_keygen_info(ctx, -1);
276
+ argv = ALLOCA_N(VALUE, info_num);
277
+ for (i = 0; i < info_num; i++)
278
+ argv[i] = INT2NUM(EVP_PKEY_CTX_get_keygen_info(ctx, i));
279
+
280
+ return rb_yield_values2(info_num, argv);
281
+ }
282
+
283
+ static VALUE
284
+ call_check_ints0(VALUE arg)
285
+ {
286
+ rb_thread_check_ints();
287
+ return Qnil;
288
+ }
289
+
290
+ static void *
291
+ call_check_ints(void *arg)
292
+ {
293
+ int state;
294
+ rb_protect(call_check_ints0, Qnil, &state);
295
+ return (void *)(VALUE)state;
296
+ }
297
+
298
+ static int
299
+ pkey_gen_cb(EVP_PKEY_CTX *ctx)
300
+ {
301
+ struct pkey_blocking_generate_arg *arg = EVP_PKEY_CTX_get_app_data(ctx);
302
+ int state;
303
+
304
+ if (arg->yield) {
305
+ rb_protect(pkey_gen_cb_yield, (VALUE)ctx, &state);
306
+ if (state) {
307
+ arg->state = state;
308
+ return 0;
309
+ }
310
+ }
311
+ if (arg->interrupted) {
312
+ arg->interrupted = 0;
313
+ state = (int)(VALUE)rb_thread_call_with_gvl(call_check_ints, NULL);
314
+ if (state) {
315
+ arg->state = state;
316
+ return 0;
317
+ }
318
+ }
319
+ return 1;
320
+ }
321
+
322
+ static void
323
+ pkey_blocking_gen_stop(void *ptr)
324
+ {
325
+ struct pkey_blocking_generate_arg *arg = ptr;
326
+ arg->interrupted = 1;
327
+ }
328
+
329
+ static void *
330
+ pkey_blocking_gen(void *ptr)
331
+ {
332
+ struct pkey_blocking_generate_arg *arg = ptr;
333
+
334
+ if (arg->genparam && EVP_PKEY_paramgen(arg->ctx, &arg->pkey) <= 0)
335
+ return NULL;
336
+ if (!arg->genparam && EVP_PKEY_keygen(arg->ctx, &arg->pkey) <= 0)
337
+ return NULL;
338
+ return arg->pkey;
339
+ }
340
+
341
+ static VALUE
342
+ pkey_generate(int argc, VALUE *argv, VALUE self, int genparam)
343
+ {
344
+ EVP_PKEY_CTX *ctx;
345
+ VALUE alg, options;
346
+ struct pkey_blocking_generate_arg gen_arg = { 0 };
347
+ int state;
348
+
349
+ rb_scan_args(argc, argv, "11", &alg, &options);
350
+ if (rb_obj_is_kind_of(alg, cPKey)) {
351
+ EVP_PKEY *base_pkey;
352
+
353
+ GetPKey(alg, base_pkey);
354
+ ctx = EVP_PKEY_CTX_new(base_pkey, NULL/* engine */);
355
+ if (!ctx)
356
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
357
+ }
358
+ else {
359
+ #if OSSL_OPENSSL_PREREQ(3, 0, 0)
360
+ ctx = EVP_PKEY_CTX_new_from_name(NULL, StringValueCStr(alg), NULL);
361
+ if (!ctx)
362
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new_from_name");
363
+ #else
364
+ const EVP_PKEY_ASN1_METHOD *ameth;
365
+ ENGINE *tmpeng;
366
+ int pkey_id;
367
+
368
+ StringValue(alg);
369
+ ameth = EVP_PKEY_asn1_find_str(&tmpeng, RSTRING_PTR(alg),
370
+ RSTRING_LENINT(alg));
371
+ if (!ameth)
372
+ ossl_raise(ePKeyError, "algorithm %"PRIsVALUE" not found", alg);
373
+ EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth);
374
+ #if !defined(OPENSSL_NO_ENGINE)
375
+ if (tmpeng)
376
+ ENGINE_finish(tmpeng);
377
+ #endif
378
+
379
+ ctx = EVP_PKEY_CTX_new_id(pkey_id, NULL/* engine */);
380
+ if (!ctx)
381
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new_id");
382
+ #endif
383
+ }
384
+
385
+ if (genparam && EVP_PKEY_paramgen_init(ctx) <= 0) {
386
+ EVP_PKEY_CTX_free(ctx);
387
+ ossl_raise(ePKeyError, "EVP_PKEY_paramgen_init");
388
+ }
389
+ if (!genparam && EVP_PKEY_keygen_init(ctx) <= 0) {
390
+ EVP_PKEY_CTX_free(ctx);
391
+ ossl_raise(ePKeyError, "EVP_PKEY_keygen_init");
392
+ }
393
+
394
+ if (!NIL_P(options)) {
395
+ pkey_ctx_apply_options(ctx, options, &state);
396
+ if (state) {
397
+ EVP_PKEY_CTX_free(ctx);
398
+ rb_jump_tag(state);
399
+ }
400
+ }
401
+
402
+ gen_arg.genparam = genparam;
403
+ gen_arg.ctx = ctx;
404
+ gen_arg.yield = rb_block_given_p();
405
+ EVP_PKEY_CTX_set_app_data(ctx, &gen_arg);
406
+ EVP_PKEY_CTX_set_cb(ctx, pkey_gen_cb);
407
+ if (gen_arg.yield)
408
+ pkey_blocking_gen(&gen_arg);
409
+ else
410
+ rb_thread_call_without_gvl(pkey_blocking_gen, &gen_arg,
411
+ pkey_blocking_gen_stop, &gen_arg);
412
+ EVP_PKEY_CTX_free(ctx);
413
+ if (!gen_arg.pkey) {
414
+ if (gen_arg.state) {
415
+ ossl_clear_error();
416
+ rb_jump_tag(gen_arg.state);
417
+ }
418
+ else {
419
+ ossl_raise(ePKeyError, genparam ? "EVP_PKEY_paramgen" : "EVP_PKEY_keygen");
420
+ }
421
+ }
422
+
423
+ return ossl_pkey_new(gen_arg.pkey);
424
+ }
425
+
426
+ /*
427
+ * call-seq:
428
+ * OpenSSL::PKey.generate_parameters(algo_name [, options]) -> pkey
429
+ *
430
+ * Generates new parameters for the algorithm. _algo_name_ is a String that
431
+ * represents the algorithm. The optional argument _options_ is a Hash that
432
+ * specifies the options specific to the algorithm. The order of the options
433
+ * can be important.
434
+ *
435
+ * A block can be passed optionally. The meaning of the arguments passed to
436
+ * the block varies depending on the implementation of the algorithm. The block
437
+ * may be called once or multiple times, or may not even be called.
438
+ *
439
+ * For the supported options, see the documentation for the 'openssl genpkey'
440
+ * utility command.
441
+ *
442
+ * == Example
443
+ * pkey = OpenSSL::PKey.generate_parameters("DSA", "dsa_paramgen_bits" => 2048)
444
+ * p pkey.p.num_bits #=> 2048
445
+ */
446
+ static VALUE
447
+ ossl_pkey_s_generate_parameters(int argc, VALUE *argv, VALUE self)
448
+ {
449
+ return pkey_generate(argc, argv, self, 1);
450
+ }
451
+
452
+ /*
453
+ * call-seq:
454
+ * OpenSSL::PKey.generate_key(algo_name [, options]) -> pkey
455
+ * OpenSSL::PKey.generate_key(pkey [, options]) -> pkey
456
+ *
457
+ * Generates a new key (pair).
458
+ *
459
+ * If a String is given as the first argument, it generates a new random key
460
+ * for the algorithm specified by the name just as ::generate_parameters does.
461
+ * If an OpenSSL::PKey::PKey is given instead, it generates a new random key
462
+ * for the same algorithm as the key, using the parameters the key contains.
463
+ *
464
+ * See ::generate_parameters for the details of _options_ and the given block.
465
+ *
466
+ * == Example
467
+ * pkey_params = OpenSSL::PKey.generate_parameters("DSA", "dsa_paramgen_bits" => 2048)
468
+ * pkey_params.priv_key #=> nil
469
+ * pkey = OpenSSL::PKey.generate_key(pkey_params)
470
+ * pkey.priv_key #=> #<OpenSSL::BN 6277...
471
+ */
472
+ static VALUE
473
+ ossl_pkey_s_generate_key(int argc, VALUE *argv, VALUE self)
474
+ {
475
+ return pkey_generate(argc, argv, self, 0);
476
+ }
477
+
478
+ /*
479
+ * TODO: There is no convenient way to check the presence of public key
480
+ * components on OpenSSL 3.0. But since keys are immutable on 3.0, pkeys without
481
+ * these should only be created by OpenSSL::PKey.generate_parameters or by
482
+ * parsing DER-/PEM-encoded string. We would need another flag for that.
483
+ */
188
484
  void
189
485
  ossl_pkey_check_public_key(const EVP_PKEY *pkey)
190
486
  {
487
+ #if OSSL_OPENSSL_PREREQ(3, 0, 0)
488
+ if (EVP_PKEY_missing_parameters(pkey))
489
+ ossl_raise(ePKeyError, "parameters missing");
490
+ #else
191
491
  void *ptr;
192
492
  const BIGNUM *n, *e, *pubkey;
193
493
 
@@ -223,6 +523,7 @@ ossl_pkey_check_public_key(const EVP_PKEY *pkey)
223
523
  return;
224
524
  }
225
525
  ossl_raise(ePKeyError, "public key missing");
526
+ #endif
226
527
  }
227
528
 
228
529
  EVP_PKEY *
@@ -240,12 +541,19 @@ GetPrivPKeyPtr(VALUE obj)
240
541
  {
241
542
  EVP_PKEY *pkey;
242
543
 
243
- if (rb_funcallv(obj, id_private_q, 0, NULL) != Qtrue) {
244
- ossl_raise(rb_eArgError, "Private key is needed.");
245
- }
246
544
  GetPKey(obj, pkey);
545
+ if (OSSL_PKEY_IS_PRIVATE(obj))
546
+ return pkey;
547
+ /*
548
+ * The EVP API does not provide a way to check if the EVP_PKEY has private
549
+ * components. Assuming it does...
550
+ */
551
+ if (!rb_respond_to(obj, id_private_q))
552
+ return pkey;
553
+ if (RTEST(rb_funcallv(obj, id_private_q, 0, NULL)))
554
+ return pkey;
247
555
 
248
- return pkey;
556
+ rb_raise(rb_eArgError, "private key is needed");
249
557
  }
250
558
 
251
559
  EVP_PKEY *
@@ -265,16 +573,7 @@ DupPKeyPtr(VALUE obj)
265
573
  static VALUE
266
574
  ossl_pkey_alloc(VALUE klass)
267
575
  {
268
- EVP_PKEY *pkey;
269
- VALUE obj;
270
-
271
- obj = NewPKey(klass);
272
- if (!(pkey = EVP_PKEY_new())) {
273
- ossl_raise(ePKeyError, NULL);
274
- }
275
- SetPKey(obj, pkey);
276
-
277
- return obj;
576
+ return TypedData_Wrap_Struct(klass, &ossl_evp_pkey_type, NULL);
278
577
  }
279
578
 
280
579
  /*
@@ -293,118 +592,915 @@ ossl_pkey_initialize(VALUE self)
293
592
  return self;
294
593
  }
295
594
 
595
+ #ifdef HAVE_EVP_PKEY_DUP
596
+ static VALUE
597
+ ossl_pkey_initialize_copy(VALUE self, VALUE other)
598
+ {
599
+ EVP_PKEY *pkey, *pkey_other;
600
+
601
+ TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);
602
+ TypedData_Get_Struct(other, EVP_PKEY, &ossl_evp_pkey_type, pkey_other);
603
+ if (pkey)
604
+ rb_raise(rb_eTypeError, "pkey already initialized");
605
+ if (pkey_other) {
606
+ pkey = EVP_PKEY_dup(pkey_other);
607
+ if (!pkey)
608
+ ossl_raise(ePKeyError, "EVP_PKEY_dup");
609
+ RTYPEDDATA_DATA(self) = pkey;
610
+ }
611
+ return self;
612
+ }
613
+ #endif
614
+
615
+ /*
616
+ * call-seq:
617
+ * pkey.oid -> string
618
+ *
619
+ * Returns the short name of the OID associated with _pkey_.
620
+ */
621
+ static VALUE
622
+ ossl_pkey_oid(VALUE self)
623
+ {
624
+ EVP_PKEY *pkey;
625
+ int nid;
626
+
627
+ GetPKey(self, pkey);
628
+ nid = EVP_PKEY_id(pkey);
629
+ return rb_str_new_cstr(OBJ_nid2sn(nid));
630
+ }
631
+
632
+ /*
633
+ * call-seq:
634
+ * pkey.inspect -> string
635
+ *
636
+ * Returns a string describing the PKey object.
637
+ */
638
+ static VALUE
639
+ ossl_pkey_inspect(VALUE self)
640
+ {
641
+ EVP_PKEY *pkey;
642
+ int nid;
643
+
644
+ GetPKey(self, pkey);
645
+ nid = EVP_PKEY_id(pkey);
646
+ return rb_sprintf("#<%"PRIsVALUE":%p oid=%s>",
647
+ rb_class_name(CLASS_OF(self)), (void *)self,
648
+ OBJ_nid2sn(nid));
649
+ }
650
+
651
+ /*
652
+ * call-seq:
653
+ * pkey.to_text -> string
654
+ *
655
+ * Dumps key parameters, public key, and private key components contained in
656
+ * the key into a human-readable text.
657
+ *
658
+ * This is intended for debugging purpose.
659
+ *
660
+ * See also the man page EVP_PKEY_print_private(3).
661
+ */
662
+ static VALUE
663
+ ossl_pkey_to_text(VALUE self)
664
+ {
665
+ EVP_PKEY *pkey;
666
+ BIO *bio;
667
+
668
+ GetPKey(self, pkey);
669
+ if (!(bio = BIO_new(BIO_s_mem())))
670
+ ossl_raise(ePKeyError, "BIO_new");
671
+
672
+ if (EVP_PKEY_print_private(bio, pkey, 0, NULL) == 1)
673
+ goto out;
674
+ OSSL_BIO_reset(bio);
675
+ if (EVP_PKEY_print_public(bio, pkey, 0, NULL) == 1)
676
+ goto out;
677
+ OSSL_BIO_reset(bio);
678
+ if (EVP_PKEY_print_params(bio, pkey, 0, NULL) == 1)
679
+ goto out;
680
+
681
+ BIO_free(bio);
682
+ ossl_raise(ePKeyError, "EVP_PKEY_print_params");
683
+
684
+ out:
685
+ return ossl_membio2str(bio);
686
+ }
687
+
688
+ VALUE
689
+ ossl_pkey_export_traditional(int argc, VALUE *argv, VALUE self, int to_der)
690
+ {
691
+ EVP_PKEY *pkey;
692
+ VALUE cipher, pass;
693
+ const EVP_CIPHER *enc = NULL;
694
+ BIO *bio;
695
+
696
+ GetPKey(self, pkey);
697
+ rb_scan_args(argc, argv, "02", &cipher, &pass);
698
+ if (!NIL_P(cipher)) {
699
+ enc = ossl_evp_get_cipherbyname(cipher);
700
+ pass = ossl_pem_passwd_value(pass);
701
+ }
702
+
703
+ bio = BIO_new(BIO_s_mem());
704
+ if (!bio)
705
+ ossl_raise(ePKeyError, "BIO_new");
706
+ if (to_der) {
707
+ if (!i2d_PrivateKey_bio(bio, pkey)) {
708
+ BIO_free(bio);
709
+ ossl_raise(ePKeyError, "i2d_PrivateKey_bio");
710
+ }
711
+ }
712
+ else {
713
+ #if OSSL_OPENSSL_PREREQ(1, 1, 0) || OSSL_LIBRESSL_PREREQ(3, 5, 0)
714
+ if (!PEM_write_bio_PrivateKey_traditional(bio, pkey, enc, NULL, 0,
715
+ ossl_pem_passwd_cb,
716
+ (void *)pass)) {
717
+ #else
718
+ char pem_str[80];
719
+ const char *aname;
720
+
721
+ EVP_PKEY_asn1_get0_info(NULL, NULL, NULL, NULL, &aname, pkey->ameth);
722
+ snprintf(pem_str, sizeof(pem_str), "%s PRIVATE KEY", aname);
723
+ if (!PEM_ASN1_write_bio((i2d_of_void *)i2d_PrivateKey, pem_str, bio,
724
+ pkey, enc, NULL, 0, ossl_pem_passwd_cb,
725
+ (void *)pass)) {
726
+ #endif
727
+ BIO_free(bio);
728
+ ossl_raise(ePKeyError, "PEM_write_bio_PrivateKey_traditional");
729
+ }
730
+ }
731
+ return ossl_membio2str(bio);
732
+ }
733
+
734
+ static VALUE
735
+ do_pkcs8_export(int argc, VALUE *argv, VALUE self, int to_der)
736
+ {
737
+ EVP_PKEY *pkey;
738
+ VALUE cipher, pass;
739
+ const EVP_CIPHER *enc = NULL;
740
+ BIO *bio;
741
+
742
+ GetPKey(self, pkey);
743
+ rb_scan_args(argc, argv, "02", &cipher, &pass);
744
+ if (argc > 0) {
745
+ /*
746
+ * TODO: EncryptedPrivateKeyInfo actually has more options.
747
+ * Should they be exposed?
748
+ */
749
+ enc = ossl_evp_get_cipherbyname(cipher);
750
+ pass = ossl_pem_passwd_value(pass);
751
+ }
752
+
753
+ bio = BIO_new(BIO_s_mem());
754
+ if (!bio)
755
+ ossl_raise(ePKeyError, "BIO_new");
756
+ if (to_der) {
757
+ if (!i2d_PKCS8PrivateKey_bio(bio, pkey, enc, NULL, 0,
758
+ ossl_pem_passwd_cb, (void *)pass)) {
759
+ BIO_free(bio);
760
+ ossl_raise(ePKeyError, "i2d_PKCS8PrivateKey_bio");
761
+ }
762
+ }
763
+ else {
764
+ if (!PEM_write_bio_PKCS8PrivateKey(bio, pkey, enc, NULL, 0,
765
+ ossl_pem_passwd_cb, (void *)pass)) {
766
+ BIO_free(bio);
767
+ ossl_raise(ePKeyError, "PEM_write_bio_PKCS8PrivateKey");
768
+ }
769
+ }
770
+ return ossl_membio2str(bio);
771
+ }
772
+
773
+ /*
774
+ * call-seq:
775
+ * pkey.private_to_der -> string
776
+ * pkey.private_to_der(cipher, password) -> string
777
+ *
778
+ * Serializes the private key to DER-encoded PKCS #8 format. If called without
779
+ * arguments, unencrypted PKCS #8 PrivateKeyInfo format is used. If called with
780
+ * a cipher name and a password, PKCS #8 EncryptedPrivateKeyInfo format with
781
+ * PBES2 encryption scheme is used.
782
+ */
783
+ static VALUE
784
+ ossl_pkey_private_to_der(int argc, VALUE *argv, VALUE self)
785
+ {
786
+ return do_pkcs8_export(argc, argv, self, 1);
787
+ }
788
+
789
+ /*
790
+ * call-seq:
791
+ * pkey.private_to_pem -> string
792
+ * pkey.private_to_pem(cipher, password) -> string
793
+ *
794
+ * Serializes the private key to PEM-encoded PKCS #8 format. See #private_to_der
795
+ * for more details.
796
+ */
797
+ static VALUE
798
+ ossl_pkey_private_to_pem(int argc, VALUE *argv, VALUE self)
799
+ {
800
+ return do_pkcs8_export(argc, argv, self, 0);
801
+ }
802
+
803
+ VALUE
804
+ ossl_pkey_export_spki(VALUE self, int to_der)
805
+ {
806
+ EVP_PKEY *pkey;
807
+ BIO *bio;
808
+
809
+ GetPKey(self, pkey);
810
+ bio = BIO_new(BIO_s_mem());
811
+ if (!bio)
812
+ ossl_raise(ePKeyError, "BIO_new");
813
+ if (to_der) {
814
+ if (!i2d_PUBKEY_bio(bio, pkey)) {
815
+ BIO_free(bio);
816
+ ossl_raise(ePKeyError, "i2d_PUBKEY_bio");
817
+ }
818
+ }
819
+ else {
820
+ if (!PEM_write_bio_PUBKEY(bio, pkey)) {
821
+ BIO_free(bio);
822
+ ossl_raise(ePKeyError, "PEM_write_bio_PUBKEY");
823
+ }
824
+ }
825
+ return ossl_membio2str(bio);
826
+ }
827
+
828
+ /*
829
+ * call-seq:
830
+ * pkey.public_to_der -> string
831
+ *
832
+ * Serializes the public key to DER-encoded X.509 SubjectPublicKeyInfo format.
833
+ */
834
+ static VALUE
835
+ ossl_pkey_public_to_der(VALUE self)
836
+ {
837
+ return ossl_pkey_export_spki(self, 1);
838
+ }
839
+
840
+ /*
841
+ * call-seq:
842
+ * pkey.public_to_pem -> string
843
+ *
844
+ * Serializes the public key to PEM-encoded X.509 SubjectPublicKeyInfo format.
845
+ */
846
+ static VALUE
847
+ ossl_pkey_public_to_pem(VALUE self)
848
+ {
849
+ return ossl_pkey_export_spki(self, 0);
850
+ }
851
+
296
852
  /*
297
853
  * call-seq:
298
- * pkey.sign(digest, data) -> String
854
+ * pkey.compare?(another_pkey) -> true | false
299
855
  *
300
- * To sign the String _data_, _digest_, an instance of OpenSSL::Digest, must
301
- * be provided. The return value is again a String containing the signature.
302
- * A PKeyError is raised should errors occur.
303
- * Any previous state of the Digest instance is irrelevant to the signature
304
- * outcome, the digest instance is reset to its initial state during the
305
- * operation.
856
+ * Used primarily to check if an OpenSSL::X509::Certificate#public_key compares to its private key.
306
857
  *
307
858
  * == Example
308
- * data = 'Sign me!'
309
- * digest = OpenSSL::Digest::SHA256.new
310
- * pkey = OpenSSL::PKey::RSA.new(2048)
311
- * signature = pkey.sign(digest, data)
859
+ * x509 = OpenSSL::X509::Certificate.new(pem_encoded_certificate)
860
+ * rsa_key = OpenSSL::PKey::RSA.new(pem_encoded_private_key)
861
+ *
862
+ * rsa_key.compare?(x509.public_key) => true | false
312
863
  */
313
864
  static VALUE
314
- ossl_pkey_sign(VALUE self, VALUE digest, VALUE data)
865
+ ossl_pkey_compare(VALUE self, VALUE other)
866
+ {
867
+ int ret;
868
+ EVP_PKEY *selfPKey;
869
+ EVP_PKEY *otherPKey;
870
+
871
+ GetPKey(self, selfPKey);
872
+ GetPKey(other, otherPKey);
873
+
874
+ /* Explicitly check the key type given EVP_PKEY_ASN1_METHOD(3)
875
+ * docs param_cmp could return any negative number.
876
+ */
877
+ if (EVP_PKEY_id(selfPKey) != EVP_PKEY_id(otherPKey))
878
+ ossl_raise(rb_eTypeError, "cannot match different PKey types");
879
+
880
+ ret = EVP_PKEY_eq(selfPKey, otherPKey);
881
+
882
+ if (ret == 0)
883
+ return Qfalse;
884
+ else if (ret == 1)
885
+ return Qtrue;
886
+ else
887
+ ossl_raise(ePKeyError, "EVP_PKEY_eq");
888
+ }
889
+
890
+ /*
891
+ * call-seq:
892
+ * pkey.sign(digest, data [, options]) -> string
893
+ *
894
+ * Hashes and signs the +data+ using a message digest algorithm +digest+ and
895
+ * a private key +pkey+.
896
+ *
897
+ * See #verify for the verification operation.
898
+ *
899
+ * See also the man page EVP_DigestSign(3).
900
+ *
901
+ * +digest+::
902
+ * A String that represents the message digest algorithm name, or +nil+
903
+ * if the PKey type requires no digest algorithm.
904
+ * For backwards compatibility, this can be an instance of OpenSSL::Digest.
905
+ * Its state will not affect the signature.
906
+ * +data+::
907
+ * A String. The data to be hashed and signed.
908
+ * +options+::
909
+ * A Hash that contains algorithm specific control operations to \OpenSSL.
910
+ * See OpenSSL's man page EVP_PKEY_CTX_ctrl_str(3) for details.
911
+ * +options+ parameter was added in version 3.0.
912
+ *
913
+ * Example:
914
+ * data = "Sign me!"
915
+ * pkey = OpenSSL::PKey.generate_key("RSA", rsa_keygen_bits: 2048)
916
+ * signopts = { rsa_padding_mode: "pss" }
917
+ * signature = pkey.sign("SHA256", data, signopts)
918
+ *
919
+ * # Creates a copy of the RSA key pkey, but without the private components
920
+ * pub_key = pkey.public_key
921
+ * puts pub_key.verify("SHA256", signature, data, signopts) # => true
922
+ */
923
+ static VALUE
924
+ ossl_pkey_sign(int argc, VALUE *argv, VALUE self)
315
925
  {
316
926
  EVP_PKEY *pkey;
317
- const EVP_MD *md;
927
+ VALUE digest, data, options, sig;
928
+ const EVP_MD *md = NULL;
318
929
  EVP_MD_CTX *ctx;
319
- unsigned int buf_len;
320
- VALUE str;
321
- int result;
930
+ EVP_PKEY_CTX *pctx;
931
+ size_t siglen;
932
+ int state;
322
933
 
323
934
  pkey = GetPrivPKeyPtr(self);
324
- md = ossl_evp_get_digestbyname(digest);
935
+ rb_scan_args(argc, argv, "21", &digest, &data, &options);
936
+ if (!NIL_P(digest))
937
+ md = ossl_evp_get_digestbyname(digest);
325
938
  StringValue(data);
326
- str = rb_str_new(0, EVP_PKEY_size(pkey));
327
939
 
328
940
  ctx = EVP_MD_CTX_new();
329
941
  if (!ctx)
330
- ossl_raise(ePKeyError, "EVP_MD_CTX_new");
331
- if (!EVP_SignInit_ex(ctx, md, NULL)) {
332
- EVP_MD_CTX_free(ctx);
333
- ossl_raise(ePKeyError, "EVP_SignInit_ex");
942
+ ossl_raise(ePKeyError, "EVP_MD_CTX_new");
943
+ if (EVP_DigestSignInit(ctx, &pctx, md, /* engine */NULL, pkey) < 1) {
944
+ EVP_MD_CTX_free(ctx);
945
+ ossl_raise(ePKeyError, "EVP_DigestSignInit");
946
+ }
947
+ if (!NIL_P(options)) {
948
+ pkey_ctx_apply_options(pctx, options, &state);
949
+ if (state) {
950
+ EVP_MD_CTX_free(ctx);
951
+ rb_jump_tag(state);
952
+ }
953
+ }
954
+ #if OSSL_OPENSSL_PREREQ(1, 1, 1) || OSSL_LIBRESSL_PREREQ(3, 4, 0)
955
+ if (EVP_DigestSign(ctx, NULL, &siglen, (unsigned char *)RSTRING_PTR(data),
956
+ RSTRING_LEN(data)) < 1) {
957
+ EVP_MD_CTX_free(ctx);
958
+ ossl_raise(ePKeyError, "EVP_DigestSign");
959
+ }
960
+ if (siglen > LONG_MAX) {
961
+ EVP_MD_CTX_free(ctx);
962
+ rb_raise(ePKeyError, "signature would be too large");
334
963
  }
335
- if (!EVP_SignUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data))) {
336
- EVP_MD_CTX_free(ctx);
337
- ossl_raise(ePKeyError, "EVP_SignUpdate");
964
+ sig = ossl_str_new(NULL, (long)siglen, &state);
965
+ if (state) {
966
+ EVP_MD_CTX_free(ctx);
967
+ rb_jump_tag(state);
338
968
  }
339
- result = EVP_SignFinal(ctx, (unsigned char *)RSTRING_PTR(str), &buf_len, pkey);
969
+ if (EVP_DigestSign(ctx, (unsigned char *)RSTRING_PTR(sig), &siglen,
970
+ (unsigned char *)RSTRING_PTR(data),
971
+ RSTRING_LEN(data)) < 1) {
972
+ EVP_MD_CTX_free(ctx);
973
+ ossl_raise(ePKeyError, "EVP_DigestSign");
974
+ }
975
+ #else
976
+ if (EVP_DigestSignUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)) < 1) {
977
+ EVP_MD_CTX_free(ctx);
978
+ ossl_raise(ePKeyError, "EVP_DigestSignUpdate");
979
+ }
980
+ if (EVP_DigestSignFinal(ctx, NULL, &siglen) < 1) {
981
+ EVP_MD_CTX_free(ctx);
982
+ ossl_raise(ePKeyError, "EVP_DigestSignFinal");
983
+ }
984
+ if (siglen > LONG_MAX) {
985
+ EVP_MD_CTX_free(ctx);
986
+ rb_raise(ePKeyError, "signature would be too large");
987
+ }
988
+ sig = ossl_str_new(NULL, (long)siglen, &state);
989
+ if (state) {
990
+ EVP_MD_CTX_free(ctx);
991
+ rb_jump_tag(state);
992
+ }
993
+ if (EVP_DigestSignFinal(ctx, (unsigned char *)RSTRING_PTR(sig),
994
+ &siglen) < 1) {
995
+ EVP_MD_CTX_free(ctx);
996
+ ossl_raise(ePKeyError, "EVP_DigestSignFinal");
997
+ }
998
+ #endif
340
999
  EVP_MD_CTX_free(ctx);
341
- if (!result)
342
- ossl_raise(ePKeyError, "EVP_SignFinal");
343
- rb_str_set_len(str, buf_len);
344
-
345
- return str;
1000
+ rb_str_set_len(sig, siglen);
1001
+ return sig;
346
1002
  }
347
1003
 
348
1004
  /*
349
- * call-seq:
350
- * pkey.verify(digest, signature, data) -> String
1005
+ * call-seq:
1006
+ * pkey.verify(digest, signature, data [, options]) -> true or false
351
1007
  *
352
- * To verify the String _signature_, _digest_, an instance of
353
- * OpenSSL::Digest, must be provided to re-compute the message digest of the
354
- * original _data_, also a String. The return value is +true+ if the
355
- * signature is valid, +false+ otherwise. A PKeyError is raised should errors
356
- * occur.
357
- * Any previous state of the Digest instance is irrelevant to the validation
358
- * outcome, the digest instance is reset to its initial state during the
359
- * operation.
1008
+ * Verifies the +signature+ for the +data+ using a message digest algorithm
1009
+ * +digest+ and a public key +pkey+.
360
1010
  *
361
- * == Example
362
- * data = 'Sign me!'
363
- * digest = OpenSSL::Digest::SHA256.new
364
- * pkey = OpenSSL::PKey::RSA.new(2048)
365
- * signature = pkey.sign(digest, data)
366
- * pub_key = pkey.public_key
367
- * puts pub_key.verify(digest, signature, data) # => true
1011
+ * Returns +true+ if the signature is successfully verified, +false+ otherwise.
1012
+ * The caller must check the return value.
1013
+ *
1014
+ * See #sign for the signing operation and an example.
1015
+ *
1016
+ * See also the man page EVP_DigestVerify(3).
1017
+ *
1018
+ * +digest+::
1019
+ * See #sign.
1020
+ * +signature+::
1021
+ * A String containing the signature to be verified.
1022
+ * +data+::
1023
+ * See #sign.
1024
+ * +options+::
1025
+ * See #sign. +options+ parameter was added in version 3.0.
368
1026
  */
369
1027
  static VALUE
370
- ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data)
1028
+ ossl_pkey_verify(int argc, VALUE *argv, VALUE self)
371
1029
  {
372
1030
  EVP_PKEY *pkey;
373
- const EVP_MD *md;
1031
+ VALUE digest, sig, data, options;
1032
+ const EVP_MD *md = NULL;
374
1033
  EVP_MD_CTX *ctx;
375
- int siglen, result;
1034
+ EVP_PKEY_CTX *pctx;
1035
+ int state, ret;
376
1036
 
377
1037
  GetPKey(self, pkey);
1038
+ rb_scan_args(argc, argv, "31", &digest, &sig, &data, &options);
378
1039
  ossl_pkey_check_public_key(pkey);
379
- md = ossl_evp_get_digestbyname(digest);
1040
+ if (!NIL_P(digest))
1041
+ md = ossl_evp_get_digestbyname(digest);
380
1042
  StringValue(sig);
381
- siglen = RSTRING_LENINT(sig);
382
1043
  StringValue(data);
383
1044
 
384
1045
  ctx = EVP_MD_CTX_new();
385
1046
  if (!ctx)
386
- ossl_raise(ePKeyError, "EVP_MD_CTX_new");
387
- if (!EVP_VerifyInit_ex(ctx, md, NULL)) {
388
- EVP_MD_CTX_free(ctx);
389
- ossl_raise(ePKeyError, "EVP_VerifyInit_ex");
1047
+ ossl_raise(ePKeyError, "EVP_MD_CTX_new");
1048
+ if (EVP_DigestVerifyInit(ctx, &pctx, md, /* engine */NULL, pkey) < 1) {
1049
+ EVP_MD_CTX_free(ctx);
1050
+ ossl_raise(ePKeyError, "EVP_DigestVerifyInit");
390
1051
  }
391
- if (!EVP_VerifyUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data))) {
392
- EVP_MD_CTX_free(ctx);
393
- ossl_raise(ePKeyError, "EVP_VerifyUpdate");
1052
+ if (!NIL_P(options)) {
1053
+ pkey_ctx_apply_options(pctx, options, &state);
1054
+ if (state) {
1055
+ EVP_MD_CTX_free(ctx);
1056
+ rb_jump_tag(state);
1057
+ }
394
1058
  }
395
- result = EVP_VerifyFinal(ctx, (unsigned char *)RSTRING_PTR(sig), siglen, pkey);
1059
+ #if OSSL_OPENSSL_PREREQ(1, 1, 1) || OSSL_LIBRESSL_PREREQ(3, 4, 0)
1060
+ ret = EVP_DigestVerify(ctx, (unsigned char *)RSTRING_PTR(sig),
1061
+ RSTRING_LEN(sig), (unsigned char *)RSTRING_PTR(data),
1062
+ RSTRING_LEN(data));
396
1063
  EVP_MD_CTX_free(ctx);
397
- switch (result) {
398
- case 0:
399
- ossl_clear_error();
400
- return Qfalse;
401
- case 1:
402
- return Qtrue;
403
- default:
404
- ossl_raise(ePKeyError, "EVP_VerifyFinal");
1064
+ if (ret < 0)
1065
+ ossl_raise(ePKeyError, "EVP_DigestVerify");
1066
+ #else
1067
+ if (EVP_DigestVerifyUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)) < 1) {
1068
+ EVP_MD_CTX_free(ctx);
1069
+ ossl_raise(ePKeyError, "EVP_DigestVerifyUpdate");
1070
+ }
1071
+ ret = EVP_DigestVerifyFinal(ctx, (unsigned char *)RSTRING_PTR(sig),
1072
+ RSTRING_LEN(sig));
1073
+ EVP_MD_CTX_free(ctx);
1074
+ if (ret < 0)
1075
+ ossl_raise(ePKeyError, "EVP_DigestVerifyFinal");
1076
+ #endif
1077
+ if (ret)
1078
+ return Qtrue;
1079
+ else {
1080
+ ossl_clear_error();
1081
+ return Qfalse;
405
1082
  }
406
1083
  }
407
1084
 
1085
+ /*
1086
+ * call-seq:
1087
+ * pkey.sign_raw(digest, data [, options]) -> string
1088
+ *
1089
+ * Signs +data+ using a private key +pkey+. Unlike #sign, +data+ will not be
1090
+ * hashed by +digest+ automatically.
1091
+ *
1092
+ * See #verify_raw for the verification operation.
1093
+ *
1094
+ * Added in version 3.0. See also the man page EVP_PKEY_sign(3).
1095
+ *
1096
+ * +digest+::
1097
+ * A String that represents the message digest algorithm name, or +nil+
1098
+ * if the PKey type requires no digest algorithm.
1099
+ * Although this method will not hash +data+ with it, this parameter may still
1100
+ * be required depending on the signature algorithm.
1101
+ * +data+::
1102
+ * A String. The data to be signed.
1103
+ * +options+::
1104
+ * A Hash that contains algorithm specific control operations to \OpenSSL.
1105
+ * See OpenSSL's man page EVP_PKEY_CTX_ctrl_str(3) for details.
1106
+ *
1107
+ * Example:
1108
+ * data = "Sign me!"
1109
+ * hash = OpenSSL::Digest.digest("SHA256", data)
1110
+ * pkey = OpenSSL::PKey.generate_key("RSA", rsa_keygen_bits: 2048)
1111
+ * signopts = { rsa_padding_mode: "pss" }
1112
+ * signature = pkey.sign_raw("SHA256", hash, signopts)
1113
+ *
1114
+ * # Creates a copy of the RSA key pkey, but without the private components
1115
+ * pub_key = pkey.public_key
1116
+ * puts pub_key.verify_raw("SHA256", signature, hash, signopts) # => true
1117
+ */
1118
+ static VALUE
1119
+ ossl_pkey_sign_raw(int argc, VALUE *argv, VALUE self)
1120
+ {
1121
+ EVP_PKEY *pkey;
1122
+ VALUE digest, data, options, sig;
1123
+ const EVP_MD *md = NULL;
1124
+ EVP_PKEY_CTX *ctx;
1125
+ size_t outlen;
1126
+ int state;
1127
+
1128
+ GetPKey(self, pkey);
1129
+ rb_scan_args(argc, argv, "21", &digest, &data, &options);
1130
+ if (!NIL_P(digest))
1131
+ md = ossl_evp_get_digestbyname(digest);
1132
+ StringValue(data);
1133
+
1134
+ ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
1135
+ if (!ctx)
1136
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
1137
+ if (EVP_PKEY_sign_init(ctx) <= 0) {
1138
+ EVP_PKEY_CTX_free(ctx);
1139
+ ossl_raise(ePKeyError, "EVP_PKEY_sign_init");
1140
+ }
1141
+ if (md && EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) {
1142
+ EVP_PKEY_CTX_free(ctx);
1143
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_set_signature_md");
1144
+ }
1145
+ if (!NIL_P(options)) {
1146
+ pkey_ctx_apply_options(ctx, options, &state);
1147
+ if (state) {
1148
+ EVP_PKEY_CTX_free(ctx);
1149
+ rb_jump_tag(state);
1150
+ }
1151
+ }
1152
+ if (EVP_PKEY_sign(ctx, NULL, &outlen, (unsigned char *)RSTRING_PTR(data),
1153
+ RSTRING_LEN(data)) <= 0) {
1154
+ EVP_PKEY_CTX_free(ctx);
1155
+ ossl_raise(ePKeyError, "EVP_PKEY_sign");
1156
+ }
1157
+ if (outlen > LONG_MAX) {
1158
+ EVP_PKEY_CTX_free(ctx);
1159
+ rb_raise(ePKeyError, "signature would be too large");
1160
+ }
1161
+ sig = ossl_str_new(NULL, (long)outlen, &state);
1162
+ if (state) {
1163
+ EVP_PKEY_CTX_free(ctx);
1164
+ rb_jump_tag(state);
1165
+ }
1166
+ if (EVP_PKEY_sign(ctx, (unsigned char *)RSTRING_PTR(sig), &outlen,
1167
+ (unsigned char *)RSTRING_PTR(data),
1168
+ RSTRING_LEN(data)) <= 0) {
1169
+ EVP_PKEY_CTX_free(ctx);
1170
+ ossl_raise(ePKeyError, "EVP_PKEY_sign");
1171
+ }
1172
+ EVP_PKEY_CTX_free(ctx);
1173
+ rb_str_set_len(sig, outlen);
1174
+ return sig;
1175
+ }
1176
+
1177
+ /*
1178
+ * call-seq:
1179
+ * pkey.verify_raw(digest, signature, data [, options]) -> true or false
1180
+ *
1181
+ * Verifies the +signature+ for the +data+ using a public key +pkey+. Unlike
1182
+ * #verify, this method will not hash +data+ with +digest+ automatically.
1183
+ *
1184
+ * Returns +true+ if the signature is successfully verified, +false+ otherwise.
1185
+ * The caller must check the return value.
1186
+ *
1187
+ * See #sign_raw for the signing operation and an example code.
1188
+ *
1189
+ * Added in version 3.0. See also the man page EVP_PKEY_verify(3).
1190
+ *
1191
+ * +signature+::
1192
+ * A String containing the signature to be verified.
1193
+ */
1194
+ static VALUE
1195
+ ossl_pkey_verify_raw(int argc, VALUE *argv, VALUE self)
1196
+ {
1197
+ EVP_PKEY *pkey;
1198
+ VALUE digest, sig, data, options;
1199
+ const EVP_MD *md = NULL;
1200
+ EVP_PKEY_CTX *ctx;
1201
+ int state, ret;
1202
+
1203
+ GetPKey(self, pkey);
1204
+ rb_scan_args(argc, argv, "31", &digest, &sig, &data, &options);
1205
+ ossl_pkey_check_public_key(pkey);
1206
+ if (!NIL_P(digest))
1207
+ md = ossl_evp_get_digestbyname(digest);
1208
+ StringValue(sig);
1209
+ StringValue(data);
1210
+
1211
+ ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
1212
+ if (!ctx)
1213
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
1214
+ if (EVP_PKEY_verify_init(ctx) <= 0) {
1215
+ EVP_PKEY_CTX_free(ctx);
1216
+ ossl_raise(ePKeyError, "EVP_PKEY_verify_init");
1217
+ }
1218
+ if (md && EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) {
1219
+ EVP_PKEY_CTX_free(ctx);
1220
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_set_signature_md");
1221
+ }
1222
+ if (!NIL_P(options)) {
1223
+ pkey_ctx_apply_options(ctx, options, &state);
1224
+ if (state) {
1225
+ EVP_PKEY_CTX_free(ctx);
1226
+ rb_jump_tag(state);
1227
+ }
1228
+ }
1229
+ ret = EVP_PKEY_verify(ctx, (unsigned char *)RSTRING_PTR(sig),
1230
+ RSTRING_LEN(sig),
1231
+ (unsigned char *)RSTRING_PTR(data),
1232
+ RSTRING_LEN(data));
1233
+ EVP_PKEY_CTX_free(ctx);
1234
+ if (ret < 0)
1235
+ ossl_raise(ePKeyError, "EVP_PKEY_verify");
1236
+
1237
+ if (ret)
1238
+ return Qtrue;
1239
+ else {
1240
+ ossl_clear_error();
1241
+ return Qfalse;
1242
+ }
1243
+ }
1244
+
1245
+ /*
1246
+ * call-seq:
1247
+ * pkey.verify_recover(digest, signature [, options]) -> string
1248
+ *
1249
+ * Recovers the signed data from +signature+ using a public key +pkey+. Not all
1250
+ * signature algorithms support this operation.
1251
+ *
1252
+ * Added in version 3.0. See also the man page EVP_PKEY_verify_recover(3).
1253
+ *
1254
+ * +signature+::
1255
+ * A String containing the signature to be verified.
1256
+ */
1257
+ static VALUE
1258
+ ossl_pkey_verify_recover(int argc, VALUE *argv, VALUE self)
1259
+ {
1260
+ EVP_PKEY *pkey;
1261
+ VALUE digest, sig, options, out;
1262
+ const EVP_MD *md = NULL;
1263
+ EVP_PKEY_CTX *ctx;
1264
+ int state;
1265
+ size_t outlen;
1266
+
1267
+ GetPKey(self, pkey);
1268
+ rb_scan_args(argc, argv, "21", &digest, &sig, &options);
1269
+ ossl_pkey_check_public_key(pkey);
1270
+ if (!NIL_P(digest))
1271
+ md = ossl_evp_get_digestbyname(digest);
1272
+ StringValue(sig);
1273
+
1274
+ ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
1275
+ if (!ctx)
1276
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
1277
+ if (EVP_PKEY_verify_recover_init(ctx) <= 0) {
1278
+ EVP_PKEY_CTX_free(ctx);
1279
+ ossl_raise(ePKeyError, "EVP_PKEY_verify_recover_init");
1280
+ }
1281
+ if (md && EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) {
1282
+ EVP_PKEY_CTX_free(ctx);
1283
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_set_signature_md");
1284
+ }
1285
+ if (!NIL_P(options)) {
1286
+ pkey_ctx_apply_options(ctx, options, &state);
1287
+ if (state) {
1288
+ EVP_PKEY_CTX_free(ctx);
1289
+ rb_jump_tag(state);
1290
+ }
1291
+ }
1292
+ if (EVP_PKEY_verify_recover(ctx, NULL, &outlen,
1293
+ (unsigned char *)RSTRING_PTR(sig),
1294
+ RSTRING_LEN(sig)) <= 0) {
1295
+ EVP_PKEY_CTX_free(ctx);
1296
+ ossl_raise(ePKeyError, "EVP_PKEY_verify_recover");
1297
+ }
1298
+ out = ossl_str_new(NULL, (long)outlen, &state);
1299
+ if (state) {
1300
+ EVP_PKEY_CTX_free(ctx);
1301
+ rb_jump_tag(state);
1302
+ }
1303
+ if (EVP_PKEY_verify_recover(ctx, (unsigned char *)RSTRING_PTR(out), &outlen,
1304
+ (unsigned char *)RSTRING_PTR(sig),
1305
+ RSTRING_LEN(sig)) <= 0) {
1306
+ EVP_PKEY_CTX_free(ctx);
1307
+ ossl_raise(ePKeyError, "EVP_PKEY_verify_recover");
1308
+ }
1309
+ EVP_PKEY_CTX_free(ctx);
1310
+ rb_str_set_len(out, outlen);
1311
+ return out;
1312
+ }
1313
+
1314
+ /*
1315
+ * call-seq:
1316
+ * pkey.derive(peer_pkey) -> string
1317
+ *
1318
+ * Derives a shared secret from _pkey_ and _peer_pkey_. _pkey_ must contain
1319
+ * the private components, _peer_pkey_ must contain the public components.
1320
+ */
1321
+ static VALUE
1322
+ ossl_pkey_derive(int argc, VALUE *argv, VALUE self)
1323
+ {
1324
+ EVP_PKEY *pkey, *peer_pkey;
1325
+ EVP_PKEY_CTX *ctx;
1326
+ VALUE peer_pkey_obj, str;
1327
+ size_t keylen;
1328
+ int state;
1329
+
1330
+ GetPKey(self, pkey);
1331
+ rb_scan_args(argc, argv, "1", &peer_pkey_obj);
1332
+ GetPKey(peer_pkey_obj, peer_pkey);
1333
+
1334
+ ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
1335
+ if (!ctx)
1336
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
1337
+ if (EVP_PKEY_derive_init(ctx) <= 0) {
1338
+ EVP_PKEY_CTX_free(ctx);
1339
+ ossl_raise(ePKeyError, "EVP_PKEY_derive_init");
1340
+ }
1341
+ if (EVP_PKEY_derive_set_peer(ctx, peer_pkey) <= 0) {
1342
+ EVP_PKEY_CTX_free(ctx);
1343
+ ossl_raise(ePKeyError, "EVP_PKEY_derive_set_peer");
1344
+ }
1345
+ if (EVP_PKEY_derive(ctx, NULL, &keylen) <= 0) {
1346
+ EVP_PKEY_CTX_free(ctx);
1347
+ ossl_raise(ePKeyError, "EVP_PKEY_derive");
1348
+ }
1349
+ if (keylen > LONG_MAX)
1350
+ rb_raise(ePKeyError, "derived key would be too large");
1351
+ str = ossl_str_new(NULL, (long)keylen, &state);
1352
+ if (state) {
1353
+ EVP_PKEY_CTX_free(ctx);
1354
+ rb_jump_tag(state);
1355
+ }
1356
+ if (EVP_PKEY_derive(ctx, (unsigned char *)RSTRING_PTR(str), &keylen) <= 0) {
1357
+ EVP_PKEY_CTX_free(ctx);
1358
+ ossl_raise(ePKeyError, "EVP_PKEY_derive");
1359
+ }
1360
+ EVP_PKEY_CTX_free(ctx);
1361
+ rb_str_set_len(str, keylen);
1362
+ return str;
1363
+ }
1364
+
1365
+ /*
1366
+ * call-seq:
1367
+ * pkey.encrypt(data [, options]) -> string
1368
+ *
1369
+ * Performs a public key encryption operation using +pkey+.
1370
+ *
1371
+ * See #decrypt for the reverse operation.
1372
+ *
1373
+ * Added in version 3.0. See also the man page EVP_PKEY_encrypt(3).
1374
+ *
1375
+ * +data+::
1376
+ * A String to be encrypted.
1377
+ * +options+::
1378
+ * A Hash that contains algorithm specific control operations to \OpenSSL.
1379
+ * See OpenSSL's man page EVP_PKEY_CTX_ctrl_str(3) for details.
1380
+ *
1381
+ * Example:
1382
+ * pkey = OpenSSL::PKey.generate_key("RSA", rsa_keygen_bits: 2048)
1383
+ * data = "secret data"
1384
+ * encrypted = pkey.encrypt(data, rsa_padding_mode: "oaep")
1385
+ * decrypted = pkey.decrypt(data, rsa_padding_mode: "oaep")
1386
+ * p decrypted #=> "secret data"
1387
+ */
1388
+ static VALUE
1389
+ ossl_pkey_encrypt(int argc, VALUE *argv, VALUE self)
1390
+ {
1391
+ EVP_PKEY *pkey;
1392
+ EVP_PKEY_CTX *ctx;
1393
+ VALUE data, options, str;
1394
+ size_t outlen;
1395
+ int state;
1396
+
1397
+ GetPKey(self, pkey);
1398
+ rb_scan_args(argc, argv, "11", &data, &options);
1399
+ StringValue(data);
1400
+
1401
+ ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
1402
+ if (!ctx)
1403
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
1404
+ if (EVP_PKEY_encrypt_init(ctx) <= 0) {
1405
+ EVP_PKEY_CTX_free(ctx);
1406
+ ossl_raise(ePKeyError, "EVP_PKEY_encrypt_init");
1407
+ }
1408
+ if (!NIL_P(options)) {
1409
+ pkey_ctx_apply_options(ctx, options, &state);
1410
+ if (state) {
1411
+ EVP_PKEY_CTX_free(ctx);
1412
+ rb_jump_tag(state);
1413
+ }
1414
+ }
1415
+ if (EVP_PKEY_encrypt(ctx, NULL, &outlen,
1416
+ (unsigned char *)RSTRING_PTR(data),
1417
+ RSTRING_LEN(data)) <= 0) {
1418
+ EVP_PKEY_CTX_free(ctx);
1419
+ ossl_raise(ePKeyError, "EVP_PKEY_encrypt");
1420
+ }
1421
+ if (outlen > LONG_MAX) {
1422
+ EVP_PKEY_CTX_free(ctx);
1423
+ rb_raise(ePKeyError, "encrypted data would be too large");
1424
+ }
1425
+ str = ossl_str_new(NULL, (long)outlen, &state);
1426
+ if (state) {
1427
+ EVP_PKEY_CTX_free(ctx);
1428
+ rb_jump_tag(state);
1429
+ }
1430
+ if (EVP_PKEY_encrypt(ctx, (unsigned char *)RSTRING_PTR(str), &outlen,
1431
+ (unsigned char *)RSTRING_PTR(data),
1432
+ RSTRING_LEN(data)) <= 0) {
1433
+ EVP_PKEY_CTX_free(ctx);
1434
+ ossl_raise(ePKeyError, "EVP_PKEY_encrypt");
1435
+ }
1436
+ EVP_PKEY_CTX_free(ctx);
1437
+ rb_str_set_len(str, outlen);
1438
+ return str;
1439
+ }
1440
+
1441
+ /*
1442
+ * call-seq:
1443
+ * pkey.decrypt(data [, options]) -> string
1444
+ *
1445
+ * Performs a public key decryption operation using +pkey+.
1446
+ *
1447
+ * See #encrypt for a description of the parameters and an example.
1448
+ *
1449
+ * Added in version 3.0. See also the man page EVP_PKEY_decrypt(3).
1450
+ */
1451
+ static VALUE
1452
+ ossl_pkey_decrypt(int argc, VALUE *argv, VALUE self)
1453
+ {
1454
+ EVP_PKEY *pkey;
1455
+ EVP_PKEY_CTX *ctx;
1456
+ VALUE data, options, str;
1457
+ size_t outlen;
1458
+ int state;
1459
+
1460
+ GetPKey(self, pkey);
1461
+ rb_scan_args(argc, argv, "11", &data, &options);
1462
+ StringValue(data);
1463
+
1464
+ ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
1465
+ if (!ctx)
1466
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
1467
+ if (EVP_PKEY_decrypt_init(ctx) <= 0) {
1468
+ EVP_PKEY_CTX_free(ctx);
1469
+ ossl_raise(ePKeyError, "EVP_PKEY_decrypt_init");
1470
+ }
1471
+ if (!NIL_P(options)) {
1472
+ pkey_ctx_apply_options(ctx, options, &state);
1473
+ if (state) {
1474
+ EVP_PKEY_CTX_free(ctx);
1475
+ rb_jump_tag(state);
1476
+ }
1477
+ }
1478
+ if (EVP_PKEY_decrypt(ctx, NULL, &outlen,
1479
+ (unsigned char *)RSTRING_PTR(data),
1480
+ RSTRING_LEN(data)) <= 0) {
1481
+ EVP_PKEY_CTX_free(ctx);
1482
+ ossl_raise(ePKeyError, "EVP_PKEY_decrypt");
1483
+ }
1484
+ if (outlen > LONG_MAX) {
1485
+ EVP_PKEY_CTX_free(ctx);
1486
+ rb_raise(ePKeyError, "decrypted data would be too large");
1487
+ }
1488
+ str = ossl_str_new(NULL, (long)outlen, &state);
1489
+ if (state) {
1490
+ EVP_PKEY_CTX_free(ctx);
1491
+ rb_jump_tag(state);
1492
+ }
1493
+ if (EVP_PKEY_decrypt(ctx, (unsigned char *)RSTRING_PTR(str), &outlen,
1494
+ (unsigned char *)RSTRING_PTR(data),
1495
+ RSTRING_LEN(data)) <= 0) {
1496
+ EVP_PKEY_CTX_free(ctx);
1497
+ ossl_raise(ePKeyError, "EVP_PKEY_decrypt");
1498
+ }
1499
+ EVP_PKEY_CTX_free(ctx);
1500
+ rb_str_set_len(str, outlen);
1501
+ return str;
1502
+ }
1503
+
408
1504
  /*
409
1505
  * INIT
410
1506
  */
@@ -488,12 +1584,33 @@ Init_ossl_pkey(void)
488
1584
  cPKey = rb_define_class_under(mPKey, "PKey", rb_cObject);
489
1585
 
490
1586
  rb_define_module_function(mPKey, "read", ossl_pkey_new_from_data, -1);
1587
+ rb_define_module_function(mPKey, "generate_parameters", ossl_pkey_s_generate_parameters, -1);
1588
+ rb_define_module_function(mPKey, "generate_key", ossl_pkey_s_generate_key, -1);
491
1589
 
492
1590
  rb_define_alloc_func(cPKey, ossl_pkey_alloc);
493
1591
  rb_define_method(cPKey, "initialize", ossl_pkey_initialize, 0);
1592
+ #ifdef HAVE_EVP_PKEY_DUP
1593
+ rb_define_method(cPKey, "initialize_copy", ossl_pkey_initialize_copy, 1);
1594
+ #else
1595
+ rb_undef_method(cPKey, "initialize_copy");
1596
+ #endif
1597
+ rb_define_method(cPKey, "oid", ossl_pkey_oid, 0);
1598
+ rb_define_method(cPKey, "inspect", ossl_pkey_inspect, 0);
1599
+ rb_define_method(cPKey, "to_text", ossl_pkey_to_text, 0);
1600
+ rb_define_method(cPKey, "private_to_der", ossl_pkey_private_to_der, -1);
1601
+ rb_define_method(cPKey, "private_to_pem", ossl_pkey_private_to_pem, -1);
1602
+ rb_define_method(cPKey, "public_to_der", ossl_pkey_public_to_der, 0);
1603
+ rb_define_method(cPKey, "public_to_pem", ossl_pkey_public_to_pem, 0);
1604
+ rb_define_method(cPKey, "compare?", ossl_pkey_compare, 1);
494
1605
 
495
- rb_define_method(cPKey, "sign", ossl_pkey_sign, 2);
496
- rb_define_method(cPKey, "verify", ossl_pkey_verify, 3);
1606
+ rb_define_method(cPKey, "sign", ossl_pkey_sign, -1);
1607
+ rb_define_method(cPKey, "verify", ossl_pkey_verify, -1);
1608
+ rb_define_method(cPKey, "sign_raw", ossl_pkey_sign_raw, -1);
1609
+ rb_define_method(cPKey, "verify_raw", ossl_pkey_verify_raw, -1);
1610
+ rb_define_method(cPKey, "verify_recover", ossl_pkey_verify_recover, -1);
1611
+ rb_define_method(cPKey, "derive", ossl_pkey_derive, -1);
1612
+ rb_define_method(cPKey, "encrypt", ossl_pkey_encrypt, -1);
1613
+ rb_define_method(cPKey, "decrypt", ossl_pkey_decrypt, -1);
497
1614
 
498
1615
  id_private_q = rb_intern("private?");
499
1616