openssl 2.2.3 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +33 -45
  3. data/History.md +217 -1
  4. data/README.md +36 -19
  5. data/ext/openssl/extconf.rb +98 -68
  6. data/ext/openssl/openssl_missing.c +0 -66
  7. data/ext/openssl/openssl_missing.h +21 -45
  8. data/ext/openssl/ossl.c +128 -237
  9. data/ext/openssl/ossl.h +31 -12
  10. data/ext/openssl/ossl_asn1.c +26 -13
  11. data/ext/openssl/ossl_bn.c +213 -139
  12. data/ext/openssl/ossl_cipher.c +13 -14
  13. data/ext/openssl/ossl_config.c +412 -41
  14. data/ext/openssl/ossl_config.h +4 -7
  15. data/ext/openssl/ossl_digest.c +10 -10
  16. data/ext/openssl/ossl_engine.c +17 -16
  17. data/ext/openssl/ossl_hmac.c +57 -136
  18. data/ext/openssl/ossl_kdf.c +12 -4
  19. data/ext/openssl/ossl_ns_spki.c +1 -1
  20. data/ext/openssl/ossl_ocsp.c +11 -60
  21. data/ext/openssl/ossl_pkcs12.c +22 -4
  22. data/ext/openssl/ossl_pkcs7.c +45 -62
  23. data/ext/openssl/ossl_pkey.c +1320 -196
  24. data/ext/openssl/ossl_pkey.h +36 -73
  25. data/ext/openssl/ossl_pkey_dh.c +152 -347
  26. data/ext/openssl/ossl_pkey_dsa.c +157 -413
  27. data/ext/openssl/ossl_pkey_ec.c +211 -331
  28. data/ext/openssl/ossl_pkey_rsa.c +159 -491
  29. data/ext/openssl/ossl_provider.c +211 -0
  30. data/ext/openssl/ossl_provider.h +5 -0
  31. data/ext/openssl/ossl_ssl.c +530 -450
  32. data/ext/openssl/ossl_ssl_session.c +29 -30
  33. data/ext/openssl/ossl_ts.c +37 -22
  34. data/ext/openssl/ossl_x509.c +0 -6
  35. data/ext/openssl/ossl_x509attr.c +1 -1
  36. data/ext/openssl/ossl_x509cert.c +168 -12
  37. data/ext/openssl/ossl_x509crl.c +14 -11
  38. data/ext/openssl/ossl_x509ext.c +14 -9
  39. data/ext/openssl/ossl_x509name.c +10 -3
  40. data/ext/openssl/ossl_x509req.c +14 -11
  41. data/ext/openssl/ossl_x509revoked.c +4 -4
  42. data/ext/openssl/ossl_x509store.c +166 -75
  43. data/lib/openssl/buffering.rb +9 -3
  44. data/lib/openssl/digest.rb +1 -5
  45. data/lib/openssl/hmac.rb +65 -0
  46. data/lib/openssl/pkey.rb +429 -0
  47. data/lib/openssl/ssl.rb +22 -17
  48. data/lib/openssl/version.rb +1 -1
  49. data/lib/openssl/x509.rb +22 -0
  50. data/lib/openssl.rb +0 -1
  51. metadata +10 -79
  52. data/ext/openssl/ruby_missing.h +0 -24
  53. data/lib/openssl/config.rb +0 -501
@@ -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
  {
@@ -89,40 +35,33 @@ const rb_data_type_t ossl_evp_pkey_type = {
89
35
  {
90
36
  0, ossl_evp_pkey_free,
91
37
  },
92
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
38
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
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;
100
-
101
- if (!pkey || (type = EVP_PKEY_base_id(pkey)) == EVP_PKEY_NONE)
102
- ossl_raise(rb_eRuntimeError, "pkey is empty");
44
+ EVP_PKEY *pkey = (EVP_PKEY *)arg;
45
+ VALUE klass, obj;
103
46
 
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,137 @@ 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
+ static EVP_PKEY *
86
+ ossl_pkey_read(BIO *bio, const char *input_type, int selection, 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, input_type, NULL, NULL,
94
+ selection, NULL, NULL);
95
+ if (!dctx)
96
+ goto out;
97
+ if (OSSL_DECODER_CTX_set_pem_password_cb(dctx, ossl_pem_passwd_cb,
98
+ ppass) != 1)
99
+ goto out;
100
+ while (1) {
101
+ if (OSSL_DECODER_from_bio(dctx, bio) == 1)
102
+ goto out;
103
+ if (BIO_eof(bio))
104
+ break;
105
+ pos2 = BIO_tell(bio);
106
+ if (pos2 < 0 || pos2 <= pos)
107
+ break;
108
+ ossl_clear_error();
109
+ pos = pos2;
110
+ }
111
+ out:
112
+ OSSL_BIO_reset(bio);
113
+ OSSL_DECODER_CTX_free(dctx);
114
+ return pkey;
115
+ }
116
+
117
+ EVP_PKEY *
118
+ ossl_pkey_read_generic(BIO *bio, VALUE pass)
119
+ {
120
+ EVP_PKEY *pkey = NULL;
121
+ /* First check DER, then check PEM. */
122
+ const char *input_types[] = {"DER", "PEM"};
123
+ int input_type_num = (int)(sizeof(input_types) / sizeof(char *));
124
+ /*
125
+ * Non-zero selections to try to decode.
126
+ *
127
+ * See EVP_PKEY_fromdata(3) - Selections to see all the selections.
128
+ *
129
+ * This is a workaround for the decoder failing to decode or returning
130
+ * bogus keys with selection 0, if a key management provider is different
131
+ * from a decoder provider. The workaround is to avoid using selection 0.
132
+ *
133
+ * Affected OpenSSL versions: >= 3.1.0, <= 3.1.2, or >= 3.0.0, <= 3.0.10
134
+ * Fixed OpenSSL versions: 3.2, next release of the 3.1.z and 3.0.z
135
+ *
136
+ * See https://github.com/openssl/openssl/pull/21519 for details.
137
+ *
138
+ * First check for private key formats (EVP_PKEY_KEYPAIR). This is to keep
139
+ * compatibility with ruby/openssl < 3.0 which decoded the following as a
140
+ * private key.
141
+ *
142
+ * $ openssl ecparam -name prime256v1 -genkey -outform PEM
143
+ * -----BEGIN EC PARAMETERS-----
144
+ * BggqhkjOPQMBBw==
145
+ * -----END EC PARAMETERS-----
146
+ * -----BEGIN EC PRIVATE KEY-----
147
+ * MHcCAQEEIAG8ugBbA5MHkqnZ9ujQF93OyUfL9tk8sxqM5Wv5tKg5oAoGCCqGSM49
148
+ * AwEHoUQDQgAEVcjhJfkwqh5C7kGuhAf8XaAjVuG5ADwb5ayg/cJijCgs+GcXeedj
149
+ * 86avKpGH84DXUlB23C/kPt+6fXYlitUmXQ==
150
+ * -----END EC PRIVATE KEY-----
151
+ *
152
+ * While the first PEM block is a proper encoding of ECParameters, thus
153
+ * OSSL_DECODER_from_bio() would pick it up, ruby/openssl used to return
154
+ * the latter instead. Existing applications expect this behavior.
155
+ *
156
+ * Note that normally, the input is supposed to contain a single decodable
157
+ * PEM block only, so this special handling should not create a new problem.
158
+ *
159
+ * Note that we need to create the OSSL_DECODER_CTX variable each time when
160
+ * we use the different selection as a workaround.
161
+ * See https://github.com/openssl/openssl/issues/20657 for details.
162
+ */
163
+ int selections[] = {
164
+ EVP_PKEY_KEYPAIR,
165
+ EVP_PKEY_KEY_PARAMETERS,
166
+ EVP_PKEY_PUBLIC_KEY
167
+ };
168
+ int selection_num = (int)(sizeof(selections) / sizeof(int));
169
+ int i, j;
170
+
171
+ for (i = 0; i < input_type_num; i++) {
172
+ for (j = 0; j < selection_num; j++) {
173
+ pkey = ossl_pkey_read(bio, input_types[i], selections[j], pass);
174
+ if (pkey) {
175
+ goto out;
176
+ }
177
+ }
178
+ }
179
+ out:
180
+ return pkey;
181
+ }
182
+ #else
183
+ EVP_PKEY *
184
+ ossl_pkey_read_generic(BIO *bio, VALUE pass)
185
+ {
186
+ void *ppass = (void *)pass;
187
+ EVP_PKEY *pkey;
188
+
189
+ if ((pkey = d2i_PrivateKey_bio(bio, NULL)))
190
+ goto out;
191
+ OSSL_BIO_reset(bio);
192
+ if ((pkey = d2i_PKCS8PrivateKey_bio(bio, NULL, ossl_pem_passwd_cb, ppass)))
193
+ goto out;
194
+ OSSL_BIO_reset(bio);
195
+ if ((pkey = d2i_PUBKEY_bio(bio, NULL)))
196
+ goto out;
197
+ OSSL_BIO_reset(bio);
198
+ /* PEM_read_bio_PrivateKey() also parses PKCS #8 formats */
199
+ if ((pkey = PEM_read_bio_PrivateKey(bio, NULL, ossl_pem_passwd_cb, ppass)))
200
+ goto out;
201
+ OSSL_BIO_reset(bio);
202
+ if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)))
203
+ goto out;
204
+ OSSL_BIO_reset(bio);
205
+ if ((pkey = PEM_read_bio_Parameters(bio, NULL)))
206
+ goto out;
207
+
208
+ out:
209
+ return pkey;
210
+ }
211
+ #endif
212
+
143
213
  /*
144
214
  * call-seq:
145
215
  * OpenSSL::PKey.read(string [, pwd ]) -> PKey
@@ -149,7 +219,7 @@ ossl_pkey_new(EVP_PKEY *pkey)
149
219
  * instance of the appropriate PKey class.
150
220
  *
151
221
  * === Parameters
152
- * * _string+ is a DER- or PEM-encoded string containing an arbitrary private
222
+ * * _string_ is a DER- or PEM-encoded string containing an arbitrary private
153
223
  * or public key.
154
224
  * * _io_ is an instance of IO containing a DER- or PEM-encoded
155
225
  * arbitrary private or public key.
@@ -164,36 +234,283 @@ ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self)
164
234
  VALUE data, pass;
165
235
 
166
236
  rb_scan_args(argc, argv, "11", &data, &pass);
167
- pass = ossl_pem_passwd_value(pass);
168
-
169
237
  bio = ossl_obj2bio(&data);
170
- if ((pkey = d2i_PrivateKey_bio(bio, NULL)))
171
- goto ok;
172
- OSSL_BIO_reset(bio);
173
- if ((pkey = d2i_PKCS8PrivateKey_bio(bio, NULL, ossl_pem_passwd_cb, (void *)pass)))
174
- goto ok;
175
- OSSL_BIO_reset(bio);
176
- if ((pkey = d2i_PUBKEY_bio(bio, NULL)))
177
- goto ok;
178
- OSSL_BIO_reset(bio);
179
- /* PEM_read_bio_PrivateKey() also parses PKCS #8 formats */
180
- if ((pkey = PEM_read_bio_PrivateKey(bio, NULL, ossl_pem_passwd_cb, (void *)pass)))
181
- goto ok;
182
- OSSL_BIO_reset(bio);
183
- if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)))
184
- goto ok;
185
-
186
- BIO_free(bio);
187
- ossl_raise(ePKeyError, "Could not parse PKey");
188
-
189
- ok:
238
+ pkey = ossl_pkey_read_generic(bio, ossl_pem_passwd_value(pass));
190
239
  BIO_free(bio);
240
+ if (!pkey)
241
+ ossl_raise(ePKeyError, "Could not parse PKey");
191
242
  return ossl_pkey_new(pkey);
192
243
  }
193
244
 
245
+ static VALUE
246
+ pkey_ctx_apply_options_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ctx_v))
247
+ {
248
+ VALUE key = rb_ary_entry(i, 0), value = rb_ary_entry(i, 1);
249
+ EVP_PKEY_CTX *ctx = (EVP_PKEY_CTX *)ctx_v;
250
+
251
+ if (SYMBOL_P(key))
252
+ key = rb_sym2str(key);
253
+ value = rb_String(value);
254
+
255
+ if (EVP_PKEY_CTX_ctrl_str(ctx, StringValueCStr(key), StringValueCStr(value)) <= 0)
256
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_ctrl_str(ctx, %+"PRIsVALUE", %+"PRIsVALUE")",
257
+ key, value);
258
+ return Qnil;
259
+ }
260
+
261
+ static VALUE
262
+ pkey_ctx_apply_options0(VALUE args_v)
263
+ {
264
+ VALUE *args = (VALUE *)args_v;
265
+ Check_Type(args[1], T_HASH);
266
+
267
+ rb_block_call(args[1], rb_intern("each"), 0, NULL,
268
+ pkey_ctx_apply_options_i, args[0]);
269
+ return Qnil;
270
+ }
271
+
272
+ static void
273
+ pkey_ctx_apply_options(EVP_PKEY_CTX *ctx, VALUE options, int *state)
274
+ {
275
+ VALUE args[2];
276
+ args[0] = (VALUE)ctx;
277
+ args[1] = options;
278
+
279
+ rb_protect(pkey_ctx_apply_options0, (VALUE)args, state);
280
+ }
281
+
282
+ struct pkey_blocking_generate_arg {
283
+ EVP_PKEY_CTX *ctx;
284
+ EVP_PKEY *pkey;
285
+ int state;
286
+ unsigned int yield: 1;
287
+ unsigned int genparam: 1;
288
+ unsigned int interrupted: 1;
289
+ };
290
+
291
+ static VALUE
292
+ pkey_gen_cb_yield(VALUE ctx_v)
293
+ {
294
+ EVP_PKEY_CTX *ctx = (void *)ctx_v;
295
+ int i, info_num;
296
+ VALUE *argv;
297
+
298
+ info_num = EVP_PKEY_CTX_get_keygen_info(ctx, -1);
299
+ argv = ALLOCA_N(VALUE, info_num);
300
+ for (i = 0; i < info_num; i++)
301
+ argv[i] = INT2NUM(EVP_PKEY_CTX_get_keygen_info(ctx, i));
302
+
303
+ return rb_yield_values2(info_num, argv);
304
+ }
305
+
306
+ static VALUE
307
+ call_check_ints0(VALUE arg)
308
+ {
309
+ rb_thread_check_ints();
310
+ return Qnil;
311
+ }
312
+
313
+ static void *
314
+ call_check_ints(void *arg)
315
+ {
316
+ int state;
317
+ rb_protect(call_check_ints0, Qnil, &state);
318
+ return (void *)(VALUE)state;
319
+ }
320
+
321
+ static int
322
+ pkey_gen_cb(EVP_PKEY_CTX *ctx)
323
+ {
324
+ struct pkey_blocking_generate_arg *arg = EVP_PKEY_CTX_get_app_data(ctx);
325
+ int state;
326
+
327
+ if (arg->yield) {
328
+ rb_protect(pkey_gen_cb_yield, (VALUE)ctx, &state);
329
+ if (state) {
330
+ arg->state = state;
331
+ return 0;
332
+ }
333
+ }
334
+ if (arg->interrupted) {
335
+ arg->interrupted = 0;
336
+ state = (int)(VALUE)rb_thread_call_with_gvl(call_check_ints, NULL);
337
+ if (state) {
338
+ arg->state = state;
339
+ return 0;
340
+ }
341
+ }
342
+ return 1;
343
+ }
344
+
345
+ static void
346
+ pkey_blocking_gen_stop(void *ptr)
347
+ {
348
+ struct pkey_blocking_generate_arg *arg = ptr;
349
+ arg->interrupted = 1;
350
+ }
351
+
352
+ static void *
353
+ pkey_blocking_gen(void *ptr)
354
+ {
355
+ struct pkey_blocking_generate_arg *arg = ptr;
356
+
357
+ if (arg->genparam && EVP_PKEY_paramgen(arg->ctx, &arg->pkey) <= 0)
358
+ return NULL;
359
+ if (!arg->genparam && EVP_PKEY_keygen(arg->ctx, &arg->pkey) <= 0)
360
+ return NULL;
361
+ return arg->pkey;
362
+ }
363
+
364
+ static VALUE
365
+ pkey_generate(int argc, VALUE *argv, VALUE self, int genparam)
366
+ {
367
+ EVP_PKEY_CTX *ctx;
368
+ VALUE alg, options;
369
+ struct pkey_blocking_generate_arg gen_arg = { 0 };
370
+ int state;
371
+
372
+ rb_scan_args(argc, argv, "11", &alg, &options);
373
+ if (rb_obj_is_kind_of(alg, cPKey)) {
374
+ EVP_PKEY *base_pkey;
375
+
376
+ GetPKey(alg, base_pkey);
377
+ ctx = EVP_PKEY_CTX_new(base_pkey, NULL/* engine */);
378
+ if (!ctx)
379
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
380
+ }
381
+ else {
382
+ #if OSSL_OPENSSL_PREREQ(3, 0, 0)
383
+ ctx = EVP_PKEY_CTX_new_from_name(NULL, StringValueCStr(alg), NULL);
384
+ if (!ctx)
385
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new_from_name");
386
+ #else
387
+ const EVP_PKEY_ASN1_METHOD *ameth;
388
+ ENGINE *tmpeng;
389
+ int pkey_id;
390
+
391
+ StringValue(alg);
392
+ ameth = EVP_PKEY_asn1_find_str(&tmpeng, RSTRING_PTR(alg),
393
+ RSTRING_LENINT(alg));
394
+ if (!ameth)
395
+ ossl_raise(ePKeyError, "algorithm %"PRIsVALUE" not found", alg);
396
+ EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth);
397
+ #if !defined(OPENSSL_NO_ENGINE)
398
+ if (tmpeng)
399
+ ENGINE_finish(tmpeng);
400
+ #endif
401
+
402
+ ctx = EVP_PKEY_CTX_new_id(pkey_id, NULL/* engine */);
403
+ if (!ctx)
404
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new_id");
405
+ #endif
406
+ }
407
+
408
+ if (genparam && EVP_PKEY_paramgen_init(ctx) <= 0) {
409
+ EVP_PKEY_CTX_free(ctx);
410
+ ossl_raise(ePKeyError, "EVP_PKEY_paramgen_init");
411
+ }
412
+ if (!genparam && EVP_PKEY_keygen_init(ctx) <= 0) {
413
+ EVP_PKEY_CTX_free(ctx);
414
+ ossl_raise(ePKeyError, "EVP_PKEY_keygen_init");
415
+ }
416
+
417
+ if (!NIL_P(options)) {
418
+ pkey_ctx_apply_options(ctx, options, &state);
419
+ if (state) {
420
+ EVP_PKEY_CTX_free(ctx);
421
+ rb_jump_tag(state);
422
+ }
423
+ }
424
+
425
+ gen_arg.genparam = genparam;
426
+ gen_arg.ctx = ctx;
427
+ gen_arg.yield = rb_block_given_p();
428
+ EVP_PKEY_CTX_set_app_data(ctx, &gen_arg);
429
+ EVP_PKEY_CTX_set_cb(ctx, pkey_gen_cb);
430
+ if (gen_arg.yield)
431
+ pkey_blocking_gen(&gen_arg);
432
+ else
433
+ rb_thread_call_without_gvl(pkey_blocking_gen, &gen_arg,
434
+ pkey_blocking_gen_stop, &gen_arg);
435
+ EVP_PKEY_CTX_free(ctx);
436
+ if (!gen_arg.pkey) {
437
+ if (gen_arg.state) {
438
+ ossl_clear_error();
439
+ rb_jump_tag(gen_arg.state);
440
+ }
441
+ else {
442
+ ossl_raise(ePKeyError, genparam ? "EVP_PKEY_paramgen" : "EVP_PKEY_keygen");
443
+ }
444
+ }
445
+
446
+ return ossl_pkey_new(gen_arg.pkey);
447
+ }
448
+
449
+ /*
450
+ * call-seq:
451
+ * OpenSSL::PKey.generate_parameters(algo_name [, options]) -> pkey
452
+ *
453
+ * Generates new parameters for the algorithm. _algo_name_ is a String that
454
+ * represents the algorithm. The optional argument _options_ is a Hash that
455
+ * specifies the options specific to the algorithm. The order of the options
456
+ * can be important.
457
+ *
458
+ * A block can be passed optionally. The meaning of the arguments passed to
459
+ * the block varies depending on the implementation of the algorithm. The block
460
+ * may be called once or multiple times, or may not even be called.
461
+ *
462
+ * For the supported options, see the documentation for the 'openssl genpkey'
463
+ * utility command.
464
+ *
465
+ * == Example
466
+ * pkey = OpenSSL::PKey.generate_parameters("DSA", "dsa_paramgen_bits" => 2048)
467
+ * p pkey.p.num_bits #=> 2048
468
+ */
469
+ static VALUE
470
+ ossl_pkey_s_generate_parameters(int argc, VALUE *argv, VALUE self)
471
+ {
472
+ return pkey_generate(argc, argv, self, 1);
473
+ }
474
+
475
+ /*
476
+ * call-seq:
477
+ * OpenSSL::PKey.generate_key(algo_name [, options]) -> pkey
478
+ * OpenSSL::PKey.generate_key(pkey [, options]) -> pkey
479
+ *
480
+ * Generates a new key (pair).
481
+ *
482
+ * If a String is given as the first argument, it generates a new random key
483
+ * for the algorithm specified by the name just as ::generate_parameters does.
484
+ * If an OpenSSL::PKey::PKey is given instead, it generates a new random key
485
+ * for the same algorithm as the key, using the parameters the key contains.
486
+ *
487
+ * See ::generate_parameters for the details of _options_ and the given block.
488
+ *
489
+ * == Example
490
+ * pkey_params = OpenSSL::PKey.generate_parameters("DSA", "dsa_paramgen_bits" => 2048)
491
+ * pkey_params.priv_key #=> nil
492
+ * pkey = OpenSSL::PKey.generate_key(pkey_params)
493
+ * pkey.priv_key #=> #<OpenSSL::BN 6277...
494
+ */
495
+ static VALUE
496
+ ossl_pkey_s_generate_key(int argc, VALUE *argv, VALUE self)
497
+ {
498
+ return pkey_generate(argc, argv, self, 0);
499
+ }
500
+
501
+ /*
502
+ * TODO: There is no convenient way to check the presence of public key
503
+ * components on OpenSSL 3.0. But since keys are immutable on 3.0, pkeys without
504
+ * these should only be created by OpenSSL::PKey.generate_parameters or by
505
+ * parsing DER-/PEM-encoded string. We would need another flag for that.
506
+ */
194
507
  void
195
508
  ossl_pkey_check_public_key(const EVP_PKEY *pkey)
196
509
  {
510
+ #if OSSL_OPENSSL_PREREQ(3, 0, 0)
511
+ if (EVP_PKEY_missing_parameters(pkey))
512
+ ossl_raise(ePKeyError, "parameters missing");
513
+ #else
197
514
  void *ptr;
198
515
  const BIGNUM *n, *e, *pubkey;
199
516
 
@@ -229,6 +546,7 @@ ossl_pkey_check_public_key(const EVP_PKEY *pkey)
229
546
  return;
230
547
  }
231
548
  ossl_raise(ePKeyError, "public key missing");
549
+ #endif
232
550
  }
233
551
 
234
552
  EVP_PKEY *
@@ -246,12 +564,19 @@ GetPrivPKeyPtr(VALUE obj)
246
564
  {
247
565
  EVP_PKEY *pkey;
248
566
 
249
- if (rb_funcallv(obj, id_private_q, 0, NULL) != Qtrue) {
250
- ossl_raise(rb_eArgError, "Private key is needed.");
251
- }
252
567
  GetPKey(obj, pkey);
568
+ if (OSSL_PKEY_IS_PRIVATE(obj))
569
+ return pkey;
570
+ /*
571
+ * The EVP API does not provide a way to check if the EVP_PKEY has private
572
+ * components. Assuming it does...
573
+ */
574
+ if (!rb_respond_to(obj, id_private_q))
575
+ return pkey;
576
+ if (RTEST(rb_funcallv(obj, id_private_q, 0, NULL)))
577
+ return pkey;
253
578
 
254
- return pkey;
579
+ rb_raise(rb_eArgError, "private key is needed");
255
580
  }
256
581
 
257
582
  EVP_PKEY *
@@ -271,16 +596,7 @@ DupPKeyPtr(VALUE obj)
271
596
  static VALUE
272
597
  ossl_pkey_alloc(VALUE klass)
273
598
  {
274
- EVP_PKEY *pkey;
275
- VALUE obj;
276
-
277
- obj = NewPKey(klass);
278
- if (!(pkey = EVP_PKEY_new())) {
279
- ossl_raise(ePKeyError, NULL);
280
- }
281
- SetPKey(obj, pkey);
282
-
283
- return obj;
599
+ return TypedData_Wrap_Struct(klass, &ossl_evp_pkey_type, NULL);
284
600
  }
285
601
 
286
602
  /*
@@ -299,6 +615,92 @@ ossl_pkey_initialize(VALUE self)
299
615
  return self;
300
616
  }
301
617
 
618
+ #ifdef HAVE_EVP_PKEY_DUP
619
+ static VALUE
620
+ ossl_pkey_initialize_copy(VALUE self, VALUE other)
621
+ {
622
+ EVP_PKEY *pkey, *pkey_other;
623
+
624
+ TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);
625
+ TypedData_Get_Struct(other, EVP_PKEY, &ossl_evp_pkey_type, pkey_other);
626
+ if (pkey)
627
+ rb_raise(rb_eTypeError, "pkey already initialized");
628
+ if (pkey_other) {
629
+ pkey = EVP_PKEY_dup(pkey_other);
630
+ if (!pkey)
631
+ ossl_raise(ePKeyError, "EVP_PKEY_dup");
632
+ RTYPEDDATA_DATA(self) = pkey;
633
+ }
634
+ return self;
635
+ }
636
+ #endif
637
+
638
+ #ifdef HAVE_EVP_PKEY_NEW_RAW_PRIVATE_KEY
639
+ /*
640
+ * call-seq:
641
+ * OpenSSL::PKey.new_raw_private_key(algo, string) -> PKey
642
+ *
643
+ * See the OpenSSL documentation for EVP_PKEY_new_raw_private_key()
644
+ */
645
+
646
+ static VALUE
647
+ ossl_pkey_new_raw_private_key(VALUE self, VALUE type, VALUE key)
648
+ {
649
+ EVP_PKEY *pkey;
650
+ const EVP_PKEY_ASN1_METHOD *ameth;
651
+ int pkey_id;
652
+ size_t keylen;
653
+
654
+ StringValue(type);
655
+ StringValue(key);
656
+ ameth = EVP_PKEY_asn1_find_str(NULL, RSTRING_PTR(type), RSTRING_LENINT(type));
657
+ if (!ameth)
658
+ ossl_raise(ePKeyError, "algorithm %"PRIsVALUE" not found", type);
659
+ EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth);
660
+
661
+ keylen = RSTRING_LEN(key);
662
+
663
+ pkey = EVP_PKEY_new_raw_private_key(pkey_id, NULL, (unsigned char *)RSTRING_PTR(key), keylen);
664
+ if (!pkey)
665
+ ossl_raise(ePKeyError, "EVP_PKEY_new_raw_private_key");
666
+
667
+ return ossl_pkey_new(pkey);
668
+ }
669
+ #endif
670
+
671
+ #ifdef HAVE_EVP_PKEY_NEW_RAW_PRIVATE_KEY
672
+ /*
673
+ * call-seq:
674
+ * OpenSSL::PKey.new_raw_public_key(algo, string) -> PKey
675
+ *
676
+ * See the OpenSSL documentation for EVP_PKEY_new_raw_public_key()
677
+ */
678
+
679
+ static VALUE
680
+ ossl_pkey_new_raw_public_key(VALUE self, VALUE type, VALUE key)
681
+ {
682
+ EVP_PKEY *pkey;
683
+ const EVP_PKEY_ASN1_METHOD *ameth;
684
+ int pkey_id;
685
+ size_t keylen;
686
+
687
+ StringValue(type);
688
+ StringValue(key);
689
+ ameth = EVP_PKEY_asn1_find_str(NULL, RSTRING_PTR(type), RSTRING_LENINT(type));
690
+ if (!ameth)
691
+ ossl_raise(ePKeyError, "algorithm %"PRIsVALUE" not found", type);
692
+ EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth);
693
+
694
+ keylen = RSTRING_LEN(key);
695
+
696
+ pkey = EVP_PKEY_new_raw_public_key(pkey_id, NULL, (unsigned char *)RSTRING_PTR(key), keylen);
697
+ if (!pkey)
698
+ ossl_raise(ePKeyError, "EVP_PKEY_new_raw_public_key");
699
+
700
+ return ossl_pkey_new(pkey);
701
+ }
702
+ #endif
703
+
302
704
  /*
303
705
  * call-seq:
304
706
  * pkey.oid -> string
@@ -328,11 +730,94 @@ ossl_pkey_inspect(VALUE self)
328
730
  EVP_PKEY *pkey;
329
731
  int nid;
330
732
 
331
- GetPKey(self, pkey);
332
- nid = EVP_PKEY_id(pkey);
333
- return rb_sprintf("#<%"PRIsVALUE":%p oid=%s>",
334
- rb_class_name(CLASS_OF(self)), (void *)self,
335
- OBJ_nid2sn(nid));
733
+ GetPKey(self, pkey);
734
+ nid = EVP_PKEY_id(pkey);
735
+ return rb_sprintf("#<%"PRIsVALUE":%p oid=%s>",
736
+ rb_class_name(CLASS_OF(self)), (void *)self,
737
+ OBJ_nid2sn(nid));
738
+ }
739
+
740
+ /*
741
+ * call-seq:
742
+ * pkey.to_text -> string
743
+ *
744
+ * Dumps key parameters, public key, and private key components contained in
745
+ * the key into a human-readable text.
746
+ *
747
+ * This is intended for debugging purpose.
748
+ *
749
+ * See also the man page EVP_PKEY_print_private(3).
750
+ */
751
+ static VALUE
752
+ ossl_pkey_to_text(VALUE self)
753
+ {
754
+ EVP_PKEY *pkey;
755
+ BIO *bio;
756
+
757
+ GetPKey(self, pkey);
758
+ if (!(bio = BIO_new(BIO_s_mem())))
759
+ ossl_raise(ePKeyError, "BIO_new");
760
+
761
+ if (EVP_PKEY_print_private(bio, pkey, 0, NULL) == 1)
762
+ goto out;
763
+ OSSL_BIO_reset(bio);
764
+ if (EVP_PKEY_print_public(bio, pkey, 0, NULL) == 1)
765
+ goto out;
766
+ OSSL_BIO_reset(bio);
767
+ if (EVP_PKEY_print_params(bio, pkey, 0, NULL) == 1)
768
+ goto out;
769
+
770
+ BIO_free(bio);
771
+ ossl_raise(ePKeyError, "EVP_PKEY_print_params");
772
+
773
+ out:
774
+ return ossl_membio2str(bio);
775
+ }
776
+
777
+ VALUE
778
+ ossl_pkey_export_traditional(int argc, VALUE *argv, VALUE self, int to_der)
779
+ {
780
+ EVP_PKEY *pkey;
781
+ VALUE cipher, pass;
782
+ const EVP_CIPHER *enc = NULL;
783
+ BIO *bio;
784
+
785
+ GetPKey(self, pkey);
786
+ rb_scan_args(argc, argv, "02", &cipher, &pass);
787
+ if (!NIL_P(cipher)) {
788
+ enc = ossl_evp_get_cipherbyname(cipher);
789
+ pass = ossl_pem_passwd_value(pass);
790
+ }
791
+
792
+ bio = BIO_new(BIO_s_mem());
793
+ if (!bio)
794
+ ossl_raise(ePKeyError, "BIO_new");
795
+ if (to_der) {
796
+ if (!i2d_PrivateKey_bio(bio, pkey)) {
797
+ BIO_free(bio);
798
+ ossl_raise(ePKeyError, "i2d_PrivateKey_bio");
799
+ }
800
+ }
801
+ else {
802
+ #if OSSL_OPENSSL_PREREQ(1, 1, 0) || OSSL_LIBRESSL_PREREQ(3, 5, 0)
803
+ if (!PEM_write_bio_PrivateKey_traditional(bio, pkey, enc, NULL, 0,
804
+ ossl_pem_passwd_cb,
805
+ (void *)pass)) {
806
+ #else
807
+ char pem_str[80];
808
+ const char *aname;
809
+
810
+ EVP_PKEY_asn1_get0_info(NULL, NULL, NULL, NULL, &aname, pkey->ameth);
811
+ snprintf(pem_str, sizeof(pem_str), "%s PRIVATE KEY", aname);
812
+ if (!PEM_ASN1_write_bio((i2d_of_void *)i2d_PrivateKey, pem_str, bio,
813
+ pkey, enc, NULL, 0, ossl_pem_passwd_cb,
814
+ (void *)pass)) {
815
+ #endif
816
+ BIO_free(bio);
817
+ ossl_raise(ePKeyError, "PEM_write_bio_PrivateKey_traditional");
818
+ }
819
+ }
820
+ return ossl_membio2str(bio);
336
821
  }
337
822
 
338
823
  static VALUE
@@ -397,6 +882,18 @@ ossl_pkey_private_to_der(int argc, VALUE *argv, VALUE self)
397
882
  *
398
883
  * Serializes the private key to PEM-encoded PKCS #8 format. See #private_to_der
399
884
  * for more details.
885
+ *
886
+ * An unencrypted PEM-encoded key will look like:
887
+ *
888
+ * -----BEGIN PRIVATE KEY-----
889
+ * [...]
890
+ * -----END PRIVATE KEY-----
891
+ *
892
+ * An encrypted PEM-encoded key will look like:
893
+ *
894
+ * -----BEGIN ENCRYPTED PRIVATE KEY-----
895
+ * [...]
896
+ * -----END ENCRYPTED PRIVATE KEY-----
400
897
  */
401
898
  static VALUE
402
899
  ossl_pkey_private_to_pem(int argc, VALUE *argv, VALUE self)
@@ -404,8 +901,37 @@ ossl_pkey_private_to_pem(int argc, VALUE *argv, VALUE self)
404
901
  return do_pkcs8_export(argc, argv, self, 0);
405
902
  }
406
903
 
904
+ #ifdef HAVE_EVP_PKEY_NEW_RAW_PRIVATE_KEY
905
+ /*
906
+ * call-seq:
907
+ * pkey.raw_private_key => string
908
+ *
909
+ * See the OpenSSL documentation for EVP_PKEY_get_raw_private_key()
910
+ */
911
+
407
912
  static VALUE
408
- do_spki_export(VALUE self, int to_der)
913
+ ossl_pkey_raw_private_key(VALUE self)
914
+ {
915
+ EVP_PKEY *pkey;
916
+ VALUE str;
917
+ size_t len;
918
+
919
+ GetPKey(self, pkey);
920
+ if (EVP_PKEY_get_raw_private_key(pkey, NULL, &len) != 1)
921
+ ossl_raise(ePKeyError, "EVP_PKEY_get_raw_private_key");
922
+ str = rb_str_new(NULL, len);
923
+
924
+ if (EVP_PKEY_get_raw_private_key(pkey, (unsigned char *)RSTRING_PTR(str), &len) != 1)
925
+ ossl_raise(ePKeyError, "EVP_PKEY_get_raw_private_key");
926
+
927
+ rb_str_set_len(str, len);
928
+
929
+ return str;
930
+ }
931
+ #endif
932
+
933
+ VALUE
934
+ ossl_pkey_export_spki(VALUE self, int to_der)
409
935
  {
410
936
  EVP_PKEY *pkey;
411
937
  BIO *bio;
@@ -438,7 +964,7 @@ do_spki_export(VALUE self, int to_der)
438
964
  static VALUE
439
965
  ossl_pkey_public_to_der(VALUE self)
440
966
  {
441
- return do_spki_export(self, 1);
967
+ return ossl_pkey_export_spki(self, 1);
442
968
  }
443
969
 
444
970
  /*
@@ -446,123 +972,698 @@ ossl_pkey_public_to_der(VALUE self)
446
972
  * pkey.public_to_pem -> string
447
973
  *
448
974
  * Serializes the public key to PEM-encoded X.509 SubjectPublicKeyInfo format.
975
+ *
976
+ * A PEM-encoded key will look like:
977
+ *
978
+ * -----BEGIN PUBLIC KEY-----
979
+ * [...]
980
+ * -----END PUBLIC KEY-----
449
981
  */
450
982
  static VALUE
451
983
  ossl_pkey_public_to_pem(VALUE self)
452
984
  {
453
- return do_spki_export(self, 0);
985
+ return ossl_pkey_export_spki(self, 0);
986
+ }
987
+
988
+ #ifdef HAVE_EVP_PKEY_NEW_RAW_PRIVATE_KEY
989
+ /*
990
+ * call-seq:
991
+ * pkey.raw_public_key => string
992
+ *
993
+ * See the OpenSSL documentation for EVP_PKEY_get_raw_public_key()
994
+ */
995
+
996
+ static VALUE
997
+ ossl_pkey_raw_public_key(VALUE self)
998
+ {
999
+ EVP_PKEY *pkey;
1000
+ VALUE str;
1001
+ size_t len;
1002
+
1003
+ GetPKey(self, pkey);
1004
+ if (EVP_PKEY_get_raw_public_key(pkey, NULL, &len) != 1)
1005
+ ossl_raise(ePKeyError, "EVP_PKEY_get_raw_public_key");
1006
+ str = rb_str_new(NULL, len);
1007
+
1008
+ if (EVP_PKEY_get_raw_public_key(pkey, (unsigned char *)RSTRING_PTR(str), &len) != 1)
1009
+ ossl_raise(ePKeyError, "EVP_PKEY_get_raw_public_key");
1010
+
1011
+ rb_str_set_len(str, len);
1012
+
1013
+ return str;
454
1014
  }
1015
+ #endif
455
1016
 
456
1017
  /*
457
1018
  * call-seq:
458
- * pkey.sign(digest, data) -> String
1019
+ * pkey.compare?(another_pkey) -> true | false
459
1020
  *
460
- * To sign the String _data_, _digest_, an instance of OpenSSL::Digest, must
461
- * be provided. The return value is again a String containing the signature.
462
- * A PKeyError is raised should errors occur.
463
- * Any previous state of the Digest instance is irrelevant to the signature
464
- * outcome, the digest instance is reset to its initial state during the
465
- * operation.
1021
+ * Used primarily to check if an OpenSSL::X509::Certificate#public_key compares to its private key.
466
1022
  *
467
1023
  * == Example
468
- * data = 'Sign me!'
469
- * digest = OpenSSL::Digest.new('SHA256')
470
- * pkey = OpenSSL::PKey::RSA.new(2048)
471
- * signature = pkey.sign(digest, data)
1024
+ * x509 = OpenSSL::X509::Certificate.new(pem_encoded_certificate)
1025
+ * rsa_key = OpenSSL::PKey::RSA.new(pem_encoded_private_key)
1026
+ *
1027
+ * rsa_key.compare?(x509.public_key) => true | false
1028
+ */
1029
+ static VALUE
1030
+ ossl_pkey_compare(VALUE self, VALUE other)
1031
+ {
1032
+ int ret;
1033
+ EVP_PKEY *selfPKey;
1034
+ EVP_PKEY *otherPKey;
1035
+
1036
+ GetPKey(self, selfPKey);
1037
+ GetPKey(other, otherPKey);
1038
+
1039
+ /* Explicitly check the key type given EVP_PKEY_ASN1_METHOD(3)
1040
+ * docs param_cmp could return any negative number.
1041
+ */
1042
+ if (EVP_PKEY_id(selfPKey) != EVP_PKEY_id(otherPKey))
1043
+ ossl_raise(rb_eTypeError, "cannot match different PKey types");
1044
+
1045
+ ret = EVP_PKEY_eq(selfPKey, otherPKey);
1046
+
1047
+ if (ret == 0)
1048
+ return Qfalse;
1049
+ else if (ret == 1)
1050
+ return Qtrue;
1051
+ else
1052
+ ossl_raise(ePKeyError, "EVP_PKEY_eq");
1053
+ }
1054
+
1055
+ /*
1056
+ * call-seq:
1057
+ * pkey.sign(digest, data [, options]) -> string
1058
+ *
1059
+ * Hashes and signs the +data+ using a message digest algorithm +digest+ and
1060
+ * a private key +pkey+.
1061
+ *
1062
+ * See #verify for the verification operation.
1063
+ *
1064
+ * See also the man page EVP_DigestSign(3).
1065
+ *
1066
+ * +digest+::
1067
+ * A String that represents the message digest algorithm name, or +nil+
1068
+ * if the PKey type requires no digest algorithm.
1069
+ * For backwards compatibility, this can be an instance of OpenSSL::Digest.
1070
+ * Its state will not affect the signature.
1071
+ * +data+::
1072
+ * A String. The data to be hashed and signed.
1073
+ * +options+::
1074
+ * A Hash that contains algorithm specific control operations to \OpenSSL.
1075
+ * See OpenSSL's man page EVP_PKEY_CTX_ctrl_str(3) for details.
1076
+ * +options+ parameter was added in version 3.0.
1077
+ *
1078
+ * Example:
1079
+ * data = "Sign me!"
1080
+ * pkey = OpenSSL::PKey.generate_key("RSA", rsa_keygen_bits: 2048)
1081
+ * signopts = { rsa_padding_mode: "pss" }
1082
+ * signature = pkey.sign("SHA256", data, signopts)
1083
+ *
1084
+ * # Creates a copy of the RSA key pkey, but without the private components
1085
+ * pub_key = pkey.public_key
1086
+ * puts pub_key.verify("SHA256", signature, data, signopts) # => true
472
1087
  */
473
1088
  static VALUE
474
- ossl_pkey_sign(VALUE self, VALUE digest, VALUE data)
1089
+ ossl_pkey_sign(int argc, VALUE *argv, VALUE self)
475
1090
  {
476
1091
  EVP_PKEY *pkey;
477
- const EVP_MD *md;
1092
+ VALUE digest, data, options, sig;
1093
+ const EVP_MD *md = NULL;
478
1094
  EVP_MD_CTX *ctx;
479
- unsigned int buf_len;
480
- VALUE str;
481
- int result;
1095
+ EVP_PKEY_CTX *pctx;
1096
+ size_t siglen;
1097
+ int state;
482
1098
 
483
1099
  pkey = GetPrivPKeyPtr(self);
484
- md = ossl_evp_get_digestbyname(digest);
1100
+ rb_scan_args(argc, argv, "21", &digest, &data, &options);
1101
+ if (!NIL_P(digest))
1102
+ md = ossl_evp_get_digestbyname(digest);
485
1103
  StringValue(data);
486
- str = rb_str_new(0, EVP_PKEY_size(pkey));
487
1104
 
488
1105
  ctx = EVP_MD_CTX_new();
489
1106
  if (!ctx)
490
- ossl_raise(ePKeyError, "EVP_MD_CTX_new");
491
- if (!EVP_SignInit_ex(ctx, md, NULL)) {
492
- EVP_MD_CTX_free(ctx);
493
- ossl_raise(ePKeyError, "EVP_SignInit_ex");
1107
+ ossl_raise(ePKeyError, "EVP_MD_CTX_new");
1108
+ if (EVP_DigestSignInit(ctx, &pctx, md, /* engine */NULL, pkey) < 1) {
1109
+ EVP_MD_CTX_free(ctx);
1110
+ ossl_raise(ePKeyError, "EVP_DigestSignInit");
1111
+ }
1112
+ if (!NIL_P(options)) {
1113
+ pkey_ctx_apply_options(pctx, options, &state);
1114
+ if (state) {
1115
+ EVP_MD_CTX_free(ctx);
1116
+ rb_jump_tag(state);
1117
+ }
1118
+ }
1119
+ #if OSSL_OPENSSL_PREREQ(1, 1, 1) || OSSL_LIBRESSL_PREREQ(3, 4, 0)
1120
+ if (EVP_DigestSign(ctx, NULL, &siglen, (unsigned char *)RSTRING_PTR(data),
1121
+ RSTRING_LEN(data)) < 1) {
1122
+ EVP_MD_CTX_free(ctx);
1123
+ ossl_raise(ePKeyError, "EVP_DigestSign");
1124
+ }
1125
+ if (siglen > LONG_MAX) {
1126
+ EVP_MD_CTX_free(ctx);
1127
+ rb_raise(ePKeyError, "signature would be too large");
1128
+ }
1129
+ sig = ossl_str_new(NULL, (long)siglen, &state);
1130
+ if (state) {
1131
+ EVP_MD_CTX_free(ctx);
1132
+ rb_jump_tag(state);
1133
+ }
1134
+ if (EVP_DigestSign(ctx, (unsigned char *)RSTRING_PTR(sig), &siglen,
1135
+ (unsigned char *)RSTRING_PTR(data),
1136
+ RSTRING_LEN(data)) < 1) {
1137
+ EVP_MD_CTX_free(ctx);
1138
+ ossl_raise(ePKeyError, "EVP_DigestSign");
494
1139
  }
495
- if (!EVP_SignUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data))) {
496
- EVP_MD_CTX_free(ctx);
497
- ossl_raise(ePKeyError, "EVP_SignUpdate");
1140
+ #else
1141
+ if (EVP_DigestSignUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)) < 1) {
1142
+ EVP_MD_CTX_free(ctx);
1143
+ ossl_raise(ePKeyError, "EVP_DigestSignUpdate");
498
1144
  }
499
- result = EVP_SignFinal(ctx, (unsigned char *)RSTRING_PTR(str), &buf_len, pkey);
1145
+ if (EVP_DigestSignFinal(ctx, NULL, &siglen) < 1) {
1146
+ EVP_MD_CTX_free(ctx);
1147
+ ossl_raise(ePKeyError, "EVP_DigestSignFinal");
1148
+ }
1149
+ if (siglen > LONG_MAX) {
1150
+ EVP_MD_CTX_free(ctx);
1151
+ rb_raise(ePKeyError, "signature would be too large");
1152
+ }
1153
+ sig = ossl_str_new(NULL, (long)siglen, &state);
1154
+ if (state) {
1155
+ EVP_MD_CTX_free(ctx);
1156
+ rb_jump_tag(state);
1157
+ }
1158
+ if (EVP_DigestSignFinal(ctx, (unsigned char *)RSTRING_PTR(sig),
1159
+ &siglen) < 1) {
1160
+ EVP_MD_CTX_free(ctx);
1161
+ ossl_raise(ePKeyError, "EVP_DigestSignFinal");
1162
+ }
1163
+ #endif
500
1164
  EVP_MD_CTX_free(ctx);
501
- if (!result)
502
- ossl_raise(ePKeyError, "EVP_SignFinal");
503
- rb_str_set_len(str, buf_len);
504
-
505
- return str;
1165
+ rb_str_set_len(sig, siglen);
1166
+ return sig;
506
1167
  }
507
1168
 
508
1169
  /*
509
- * call-seq:
510
- * pkey.verify(digest, signature, data) -> String
1170
+ * call-seq:
1171
+ * pkey.verify(digest, signature, data [, options]) -> true or false
511
1172
  *
512
- * To verify the String _signature_, _digest_, an instance of
513
- * OpenSSL::Digest, must be provided to re-compute the message digest of the
514
- * original _data_, also a String. The return value is +true+ if the
515
- * signature is valid, +false+ otherwise. A PKeyError is raised should errors
516
- * occur.
517
- * Any previous state of the Digest instance is irrelevant to the validation
518
- * outcome, the digest instance is reset to its initial state during the
519
- * operation.
1173
+ * Verifies the +signature+ for the +data+ using a message digest algorithm
1174
+ * +digest+ and a public key +pkey+.
520
1175
  *
521
- * == Example
522
- * data = 'Sign me!'
523
- * digest = OpenSSL::Digest.new('SHA256')
524
- * pkey = OpenSSL::PKey::RSA.new(2048)
525
- * signature = pkey.sign(digest, data)
526
- * pub_key = pkey.public_key
527
- * puts pub_key.verify(digest, signature, data) # => true
1176
+ * Returns +true+ if the signature is successfully verified, +false+ otherwise.
1177
+ * The caller must check the return value.
1178
+ *
1179
+ * See #sign for the signing operation and an example.
1180
+ *
1181
+ * See also the man page EVP_DigestVerify(3).
1182
+ *
1183
+ * +digest+::
1184
+ * See #sign.
1185
+ * +signature+::
1186
+ * A String containing the signature to be verified.
1187
+ * +data+::
1188
+ * See #sign.
1189
+ * +options+::
1190
+ * See #sign. +options+ parameter was added in version 3.0.
528
1191
  */
529
1192
  static VALUE
530
- ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data)
1193
+ ossl_pkey_verify(int argc, VALUE *argv, VALUE self)
531
1194
  {
532
1195
  EVP_PKEY *pkey;
533
- const EVP_MD *md;
1196
+ VALUE digest, sig, data, options;
1197
+ const EVP_MD *md = NULL;
534
1198
  EVP_MD_CTX *ctx;
535
- int siglen, result;
1199
+ EVP_PKEY_CTX *pctx;
1200
+ int state, ret;
536
1201
 
537
1202
  GetPKey(self, pkey);
1203
+ rb_scan_args(argc, argv, "31", &digest, &sig, &data, &options);
538
1204
  ossl_pkey_check_public_key(pkey);
539
- md = ossl_evp_get_digestbyname(digest);
1205
+ if (!NIL_P(digest))
1206
+ md = ossl_evp_get_digestbyname(digest);
540
1207
  StringValue(sig);
541
- siglen = RSTRING_LENINT(sig);
542
1208
  StringValue(data);
543
1209
 
544
1210
  ctx = EVP_MD_CTX_new();
545
1211
  if (!ctx)
546
- ossl_raise(ePKeyError, "EVP_MD_CTX_new");
547
- if (!EVP_VerifyInit_ex(ctx, md, NULL)) {
548
- EVP_MD_CTX_free(ctx);
549
- ossl_raise(ePKeyError, "EVP_VerifyInit_ex");
1212
+ ossl_raise(ePKeyError, "EVP_MD_CTX_new");
1213
+ if (EVP_DigestVerifyInit(ctx, &pctx, md, /* engine */NULL, pkey) < 1) {
1214
+ EVP_MD_CTX_free(ctx);
1215
+ ossl_raise(ePKeyError, "EVP_DigestVerifyInit");
550
1216
  }
551
- if (!EVP_VerifyUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data))) {
552
- EVP_MD_CTX_free(ctx);
553
- ossl_raise(ePKeyError, "EVP_VerifyUpdate");
1217
+ if (!NIL_P(options)) {
1218
+ pkey_ctx_apply_options(pctx, options, &state);
1219
+ if (state) {
1220
+ EVP_MD_CTX_free(ctx);
1221
+ rb_jump_tag(state);
1222
+ }
1223
+ }
1224
+ #if OSSL_OPENSSL_PREREQ(1, 1, 1) || OSSL_LIBRESSL_PREREQ(3, 4, 0)
1225
+ ret = EVP_DigestVerify(ctx, (unsigned char *)RSTRING_PTR(sig),
1226
+ RSTRING_LEN(sig), (unsigned char *)RSTRING_PTR(data),
1227
+ RSTRING_LEN(data));
1228
+ EVP_MD_CTX_free(ctx);
1229
+ if (ret < 0)
1230
+ ossl_raise(ePKeyError, "EVP_DigestVerify");
1231
+ #else
1232
+ if (EVP_DigestVerifyUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)) < 1) {
1233
+ EVP_MD_CTX_free(ctx);
1234
+ ossl_raise(ePKeyError, "EVP_DigestVerifyUpdate");
554
1235
  }
555
- result = EVP_VerifyFinal(ctx, (unsigned char *)RSTRING_PTR(sig), siglen, pkey);
1236
+ ret = EVP_DigestVerifyFinal(ctx, (unsigned char *)RSTRING_PTR(sig),
1237
+ RSTRING_LEN(sig));
556
1238
  EVP_MD_CTX_free(ctx);
557
- switch (result) {
558
- case 0:
559
- ossl_clear_error();
560
- return Qfalse;
561
- case 1:
562
- return Qtrue;
563
- default:
564
- ossl_raise(ePKeyError, "EVP_VerifyFinal");
1239
+ if (ret < 0)
1240
+ ossl_raise(ePKeyError, "EVP_DigestVerifyFinal");
1241
+ #endif
1242
+ if (ret)
1243
+ return Qtrue;
1244
+ else {
1245
+ ossl_clear_error();
1246
+ return Qfalse;
1247
+ }
1248
+ }
1249
+
1250
+ /*
1251
+ * call-seq:
1252
+ * pkey.sign_raw(digest, data [, options]) -> string
1253
+ *
1254
+ * Signs +data+ using a private key +pkey+. Unlike #sign, +data+ will not be
1255
+ * hashed by +digest+ automatically.
1256
+ *
1257
+ * See #verify_raw for the verification operation.
1258
+ *
1259
+ * Added in version 3.0. See also the man page EVP_PKEY_sign(3).
1260
+ *
1261
+ * +digest+::
1262
+ * A String that represents the message digest algorithm name, or +nil+
1263
+ * if the PKey type requires no digest algorithm.
1264
+ * Although this method will not hash +data+ with it, this parameter may still
1265
+ * be required depending on the signature algorithm.
1266
+ * +data+::
1267
+ * A String. The data to be signed.
1268
+ * +options+::
1269
+ * A Hash that contains algorithm specific control operations to \OpenSSL.
1270
+ * See OpenSSL's man page EVP_PKEY_CTX_ctrl_str(3) for details.
1271
+ *
1272
+ * Example:
1273
+ * data = "Sign me!"
1274
+ * hash = OpenSSL::Digest.digest("SHA256", data)
1275
+ * pkey = OpenSSL::PKey.generate_key("RSA", rsa_keygen_bits: 2048)
1276
+ * signopts = { rsa_padding_mode: "pss" }
1277
+ * signature = pkey.sign_raw("SHA256", hash, signopts)
1278
+ *
1279
+ * # Creates a copy of the RSA key pkey, but without the private components
1280
+ * pub_key = pkey.public_key
1281
+ * puts pub_key.verify_raw("SHA256", signature, hash, signopts) # => true
1282
+ */
1283
+ static VALUE
1284
+ ossl_pkey_sign_raw(int argc, VALUE *argv, VALUE self)
1285
+ {
1286
+ EVP_PKEY *pkey;
1287
+ VALUE digest, data, options, sig;
1288
+ const EVP_MD *md = NULL;
1289
+ EVP_PKEY_CTX *ctx;
1290
+ size_t outlen;
1291
+ int state;
1292
+
1293
+ GetPKey(self, pkey);
1294
+ rb_scan_args(argc, argv, "21", &digest, &data, &options);
1295
+ if (!NIL_P(digest))
1296
+ md = ossl_evp_get_digestbyname(digest);
1297
+ StringValue(data);
1298
+
1299
+ ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
1300
+ if (!ctx)
1301
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
1302
+ if (EVP_PKEY_sign_init(ctx) <= 0) {
1303
+ EVP_PKEY_CTX_free(ctx);
1304
+ ossl_raise(ePKeyError, "EVP_PKEY_sign_init");
565
1305
  }
1306
+ if (md && EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) {
1307
+ EVP_PKEY_CTX_free(ctx);
1308
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_set_signature_md");
1309
+ }
1310
+ if (!NIL_P(options)) {
1311
+ pkey_ctx_apply_options(ctx, options, &state);
1312
+ if (state) {
1313
+ EVP_PKEY_CTX_free(ctx);
1314
+ rb_jump_tag(state);
1315
+ }
1316
+ }
1317
+ if (EVP_PKEY_sign(ctx, NULL, &outlen, (unsigned char *)RSTRING_PTR(data),
1318
+ RSTRING_LEN(data)) <= 0) {
1319
+ EVP_PKEY_CTX_free(ctx);
1320
+ ossl_raise(ePKeyError, "EVP_PKEY_sign");
1321
+ }
1322
+ if (outlen > LONG_MAX) {
1323
+ EVP_PKEY_CTX_free(ctx);
1324
+ rb_raise(ePKeyError, "signature would be too large");
1325
+ }
1326
+ sig = ossl_str_new(NULL, (long)outlen, &state);
1327
+ if (state) {
1328
+ EVP_PKEY_CTX_free(ctx);
1329
+ rb_jump_tag(state);
1330
+ }
1331
+ if (EVP_PKEY_sign(ctx, (unsigned char *)RSTRING_PTR(sig), &outlen,
1332
+ (unsigned char *)RSTRING_PTR(data),
1333
+ RSTRING_LEN(data)) <= 0) {
1334
+ EVP_PKEY_CTX_free(ctx);
1335
+ ossl_raise(ePKeyError, "EVP_PKEY_sign");
1336
+ }
1337
+ EVP_PKEY_CTX_free(ctx);
1338
+ rb_str_set_len(sig, outlen);
1339
+ return sig;
1340
+ }
1341
+
1342
+ /*
1343
+ * call-seq:
1344
+ * pkey.verify_raw(digest, signature, data [, options]) -> true or false
1345
+ *
1346
+ * Verifies the +signature+ for the +data+ using a public key +pkey+. Unlike
1347
+ * #verify, this method will not hash +data+ with +digest+ automatically.
1348
+ *
1349
+ * Returns +true+ if the signature is successfully verified, +false+ otherwise.
1350
+ * The caller must check the return value.
1351
+ *
1352
+ * See #sign_raw for the signing operation and an example code.
1353
+ *
1354
+ * Added in version 3.0. See also the man page EVP_PKEY_verify(3).
1355
+ *
1356
+ * +signature+::
1357
+ * A String containing the signature to be verified.
1358
+ */
1359
+ static VALUE
1360
+ ossl_pkey_verify_raw(int argc, VALUE *argv, VALUE self)
1361
+ {
1362
+ EVP_PKEY *pkey;
1363
+ VALUE digest, sig, data, options;
1364
+ const EVP_MD *md = NULL;
1365
+ EVP_PKEY_CTX *ctx;
1366
+ int state, ret;
1367
+
1368
+ GetPKey(self, pkey);
1369
+ rb_scan_args(argc, argv, "31", &digest, &sig, &data, &options);
1370
+ ossl_pkey_check_public_key(pkey);
1371
+ if (!NIL_P(digest))
1372
+ md = ossl_evp_get_digestbyname(digest);
1373
+ StringValue(sig);
1374
+ StringValue(data);
1375
+
1376
+ ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
1377
+ if (!ctx)
1378
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
1379
+ if (EVP_PKEY_verify_init(ctx) <= 0) {
1380
+ EVP_PKEY_CTX_free(ctx);
1381
+ ossl_raise(ePKeyError, "EVP_PKEY_verify_init");
1382
+ }
1383
+ if (md && EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) {
1384
+ EVP_PKEY_CTX_free(ctx);
1385
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_set_signature_md");
1386
+ }
1387
+ if (!NIL_P(options)) {
1388
+ pkey_ctx_apply_options(ctx, options, &state);
1389
+ if (state) {
1390
+ EVP_PKEY_CTX_free(ctx);
1391
+ rb_jump_tag(state);
1392
+ }
1393
+ }
1394
+ ret = EVP_PKEY_verify(ctx, (unsigned char *)RSTRING_PTR(sig),
1395
+ RSTRING_LEN(sig),
1396
+ (unsigned char *)RSTRING_PTR(data),
1397
+ RSTRING_LEN(data));
1398
+ EVP_PKEY_CTX_free(ctx);
1399
+ if (ret < 0)
1400
+ ossl_raise(ePKeyError, "EVP_PKEY_verify");
1401
+
1402
+ if (ret)
1403
+ return Qtrue;
1404
+ else {
1405
+ ossl_clear_error();
1406
+ return Qfalse;
1407
+ }
1408
+ }
1409
+
1410
+ /*
1411
+ * call-seq:
1412
+ * pkey.verify_recover(digest, signature [, options]) -> string
1413
+ *
1414
+ * Recovers the signed data from +signature+ using a public key +pkey+. Not all
1415
+ * signature algorithms support this operation.
1416
+ *
1417
+ * Added in version 3.0. See also the man page EVP_PKEY_verify_recover(3).
1418
+ *
1419
+ * +signature+::
1420
+ * A String containing the signature to be verified.
1421
+ */
1422
+ static VALUE
1423
+ ossl_pkey_verify_recover(int argc, VALUE *argv, VALUE self)
1424
+ {
1425
+ EVP_PKEY *pkey;
1426
+ VALUE digest, sig, options, out;
1427
+ const EVP_MD *md = NULL;
1428
+ EVP_PKEY_CTX *ctx;
1429
+ int state;
1430
+ size_t outlen;
1431
+
1432
+ GetPKey(self, pkey);
1433
+ rb_scan_args(argc, argv, "21", &digest, &sig, &options);
1434
+ ossl_pkey_check_public_key(pkey);
1435
+ if (!NIL_P(digest))
1436
+ md = ossl_evp_get_digestbyname(digest);
1437
+ StringValue(sig);
1438
+
1439
+ ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
1440
+ if (!ctx)
1441
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
1442
+ if (EVP_PKEY_verify_recover_init(ctx) <= 0) {
1443
+ EVP_PKEY_CTX_free(ctx);
1444
+ ossl_raise(ePKeyError, "EVP_PKEY_verify_recover_init");
1445
+ }
1446
+ if (md && EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) {
1447
+ EVP_PKEY_CTX_free(ctx);
1448
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_set_signature_md");
1449
+ }
1450
+ if (!NIL_P(options)) {
1451
+ pkey_ctx_apply_options(ctx, options, &state);
1452
+ if (state) {
1453
+ EVP_PKEY_CTX_free(ctx);
1454
+ rb_jump_tag(state);
1455
+ }
1456
+ }
1457
+ if (EVP_PKEY_verify_recover(ctx, NULL, &outlen,
1458
+ (unsigned char *)RSTRING_PTR(sig),
1459
+ RSTRING_LEN(sig)) <= 0) {
1460
+ EVP_PKEY_CTX_free(ctx);
1461
+ ossl_raise(ePKeyError, "EVP_PKEY_verify_recover");
1462
+ }
1463
+ out = ossl_str_new(NULL, (long)outlen, &state);
1464
+ if (state) {
1465
+ EVP_PKEY_CTX_free(ctx);
1466
+ rb_jump_tag(state);
1467
+ }
1468
+ if (EVP_PKEY_verify_recover(ctx, (unsigned char *)RSTRING_PTR(out), &outlen,
1469
+ (unsigned char *)RSTRING_PTR(sig),
1470
+ RSTRING_LEN(sig)) <= 0) {
1471
+ EVP_PKEY_CTX_free(ctx);
1472
+ ossl_raise(ePKeyError, "EVP_PKEY_verify_recover");
1473
+ }
1474
+ EVP_PKEY_CTX_free(ctx);
1475
+ rb_str_set_len(out, outlen);
1476
+ return out;
1477
+ }
1478
+
1479
+ /*
1480
+ * call-seq:
1481
+ * pkey.derive(peer_pkey) -> string
1482
+ *
1483
+ * Derives a shared secret from _pkey_ and _peer_pkey_. _pkey_ must contain
1484
+ * the private components, _peer_pkey_ must contain the public components.
1485
+ */
1486
+ static VALUE
1487
+ ossl_pkey_derive(int argc, VALUE *argv, VALUE self)
1488
+ {
1489
+ EVP_PKEY *pkey, *peer_pkey;
1490
+ EVP_PKEY_CTX *ctx;
1491
+ VALUE peer_pkey_obj, str;
1492
+ size_t keylen;
1493
+ int state;
1494
+
1495
+ GetPKey(self, pkey);
1496
+ rb_scan_args(argc, argv, "1", &peer_pkey_obj);
1497
+ GetPKey(peer_pkey_obj, peer_pkey);
1498
+
1499
+ ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
1500
+ if (!ctx)
1501
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
1502
+ if (EVP_PKEY_derive_init(ctx) <= 0) {
1503
+ EVP_PKEY_CTX_free(ctx);
1504
+ ossl_raise(ePKeyError, "EVP_PKEY_derive_init");
1505
+ }
1506
+ if (EVP_PKEY_derive_set_peer(ctx, peer_pkey) <= 0) {
1507
+ EVP_PKEY_CTX_free(ctx);
1508
+ ossl_raise(ePKeyError, "EVP_PKEY_derive_set_peer");
1509
+ }
1510
+ if (EVP_PKEY_derive(ctx, NULL, &keylen) <= 0) {
1511
+ EVP_PKEY_CTX_free(ctx);
1512
+ ossl_raise(ePKeyError, "EVP_PKEY_derive");
1513
+ }
1514
+ if (keylen > LONG_MAX)
1515
+ rb_raise(ePKeyError, "derived key would be too large");
1516
+ str = ossl_str_new(NULL, (long)keylen, &state);
1517
+ if (state) {
1518
+ EVP_PKEY_CTX_free(ctx);
1519
+ rb_jump_tag(state);
1520
+ }
1521
+ if (EVP_PKEY_derive(ctx, (unsigned char *)RSTRING_PTR(str), &keylen) <= 0) {
1522
+ EVP_PKEY_CTX_free(ctx);
1523
+ ossl_raise(ePKeyError, "EVP_PKEY_derive");
1524
+ }
1525
+ EVP_PKEY_CTX_free(ctx);
1526
+ rb_str_set_len(str, keylen);
1527
+ return str;
1528
+ }
1529
+
1530
+ /*
1531
+ * call-seq:
1532
+ * pkey.encrypt(data [, options]) -> string
1533
+ *
1534
+ * Performs a public key encryption operation using +pkey+.
1535
+ *
1536
+ * See #decrypt for the reverse operation.
1537
+ *
1538
+ * Added in version 3.0. See also the man page EVP_PKEY_encrypt(3).
1539
+ *
1540
+ * +data+::
1541
+ * A String to be encrypted.
1542
+ * +options+::
1543
+ * A Hash that contains algorithm specific control operations to \OpenSSL.
1544
+ * See OpenSSL's man page EVP_PKEY_CTX_ctrl_str(3) for details.
1545
+ *
1546
+ * Example:
1547
+ * pkey = OpenSSL::PKey.generate_key("RSA", rsa_keygen_bits: 2048)
1548
+ * data = "secret data"
1549
+ * encrypted = pkey.encrypt(data, rsa_padding_mode: "oaep")
1550
+ * decrypted = pkey.decrypt(data, rsa_padding_mode: "oaep")
1551
+ * p decrypted #=> "secret data"
1552
+ */
1553
+ static VALUE
1554
+ ossl_pkey_encrypt(int argc, VALUE *argv, VALUE self)
1555
+ {
1556
+ EVP_PKEY *pkey;
1557
+ EVP_PKEY_CTX *ctx;
1558
+ VALUE data, options, str;
1559
+ size_t outlen;
1560
+ int state;
1561
+
1562
+ GetPKey(self, pkey);
1563
+ rb_scan_args(argc, argv, "11", &data, &options);
1564
+ StringValue(data);
1565
+
1566
+ ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
1567
+ if (!ctx)
1568
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
1569
+ if (EVP_PKEY_encrypt_init(ctx) <= 0) {
1570
+ EVP_PKEY_CTX_free(ctx);
1571
+ ossl_raise(ePKeyError, "EVP_PKEY_encrypt_init");
1572
+ }
1573
+ if (!NIL_P(options)) {
1574
+ pkey_ctx_apply_options(ctx, options, &state);
1575
+ if (state) {
1576
+ EVP_PKEY_CTX_free(ctx);
1577
+ rb_jump_tag(state);
1578
+ }
1579
+ }
1580
+ if (EVP_PKEY_encrypt(ctx, NULL, &outlen,
1581
+ (unsigned char *)RSTRING_PTR(data),
1582
+ RSTRING_LEN(data)) <= 0) {
1583
+ EVP_PKEY_CTX_free(ctx);
1584
+ ossl_raise(ePKeyError, "EVP_PKEY_encrypt");
1585
+ }
1586
+ if (outlen > LONG_MAX) {
1587
+ EVP_PKEY_CTX_free(ctx);
1588
+ rb_raise(ePKeyError, "encrypted data would be too large");
1589
+ }
1590
+ str = ossl_str_new(NULL, (long)outlen, &state);
1591
+ if (state) {
1592
+ EVP_PKEY_CTX_free(ctx);
1593
+ rb_jump_tag(state);
1594
+ }
1595
+ if (EVP_PKEY_encrypt(ctx, (unsigned char *)RSTRING_PTR(str), &outlen,
1596
+ (unsigned char *)RSTRING_PTR(data),
1597
+ RSTRING_LEN(data)) <= 0) {
1598
+ EVP_PKEY_CTX_free(ctx);
1599
+ ossl_raise(ePKeyError, "EVP_PKEY_encrypt");
1600
+ }
1601
+ EVP_PKEY_CTX_free(ctx);
1602
+ rb_str_set_len(str, outlen);
1603
+ return str;
1604
+ }
1605
+
1606
+ /*
1607
+ * call-seq:
1608
+ * pkey.decrypt(data [, options]) -> string
1609
+ *
1610
+ * Performs a public key decryption operation using +pkey+.
1611
+ *
1612
+ * See #encrypt for a description of the parameters and an example.
1613
+ *
1614
+ * Added in version 3.0. See also the man page EVP_PKEY_decrypt(3).
1615
+ */
1616
+ static VALUE
1617
+ ossl_pkey_decrypt(int argc, VALUE *argv, VALUE self)
1618
+ {
1619
+ EVP_PKEY *pkey;
1620
+ EVP_PKEY_CTX *ctx;
1621
+ VALUE data, options, str;
1622
+ size_t outlen;
1623
+ int state;
1624
+
1625
+ GetPKey(self, pkey);
1626
+ rb_scan_args(argc, argv, "11", &data, &options);
1627
+ StringValue(data);
1628
+
1629
+ ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
1630
+ if (!ctx)
1631
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
1632
+ if (EVP_PKEY_decrypt_init(ctx) <= 0) {
1633
+ EVP_PKEY_CTX_free(ctx);
1634
+ ossl_raise(ePKeyError, "EVP_PKEY_decrypt_init");
1635
+ }
1636
+ if (!NIL_P(options)) {
1637
+ pkey_ctx_apply_options(ctx, options, &state);
1638
+ if (state) {
1639
+ EVP_PKEY_CTX_free(ctx);
1640
+ rb_jump_tag(state);
1641
+ }
1642
+ }
1643
+ if (EVP_PKEY_decrypt(ctx, NULL, &outlen,
1644
+ (unsigned char *)RSTRING_PTR(data),
1645
+ RSTRING_LEN(data)) <= 0) {
1646
+ EVP_PKEY_CTX_free(ctx);
1647
+ ossl_raise(ePKeyError, "EVP_PKEY_decrypt");
1648
+ }
1649
+ if (outlen > LONG_MAX) {
1650
+ EVP_PKEY_CTX_free(ctx);
1651
+ rb_raise(ePKeyError, "decrypted data would be too large");
1652
+ }
1653
+ str = ossl_str_new(NULL, (long)outlen, &state);
1654
+ if (state) {
1655
+ EVP_PKEY_CTX_free(ctx);
1656
+ rb_jump_tag(state);
1657
+ }
1658
+ if (EVP_PKEY_decrypt(ctx, (unsigned char *)RSTRING_PTR(str), &outlen,
1659
+ (unsigned char *)RSTRING_PTR(data),
1660
+ RSTRING_LEN(data)) <= 0) {
1661
+ EVP_PKEY_CTX_free(ctx);
1662
+ ossl_raise(ePKeyError, "EVP_PKEY_decrypt");
1663
+ }
1664
+ EVP_PKEY_CTX_free(ctx);
1665
+ rb_str_set_len(str, outlen);
1666
+ return str;
566
1667
  }
567
1668
 
568
1669
  /*
@@ -648,18 +1749,41 @@ Init_ossl_pkey(void)
648
1749
  cPKey = rb_define_class_under(mPKey, "PKey", rb_cObject);
649
1750
 
650
1751
  rb_define_module_function(mPKey, "read", ossl_pkey_new_from_data, -1);
1752
+ rb_define_module_function(mPKey, "generate_parameters", ossl_pkey_s_generate_parameters, -1);
1753
+ rb_define_module_function(mPKey, "generate_key", ossl_pkey_s_generate_key, -1);
1754
+ #ifdef HAVE_EVP_PKEY_NEW_RAW_PRIVATE_KEY
1755
+ rb_define_module_function(mPKey, "new_raw_private_key", ossl_pkey_new_raw_private_key, 2);
1756
+ rb_define_module_function(mPKey, "new_raw_public_key", ossl_pkey_new_raw_public_key, 2);
1757
+ #endif
651
1758
 
652
1759
  rb_define_alloc_func(cPKey, ossl_pkey_alloc);
653
1760
  rb_define_method(cPKey, "initialize", ossl_pkey_initialize, 0);
1761
+ #ifdef HAVE_EVP_PKEY_DUP
1762
+ rb_define_method(cPKey, "initialize_copy", ossl_pkey_initialize_copy, 1);
1763
+ #else
1764
+ rb_undef_method(cPKey, "initialize_copy");
1765
+ #endif
654
1766
  rb_define_method(cPKey, "oid", ossl_pkey_oid, 0);
655
1767
  rb_define_method(cPKey, "inspect", ossl_pkey_inspect, 0);
1768
+ rb_define_method(cPKey, "to_text", ossl_pkey_to_text, 0);
656
1769
  rb_define_method(cPKey, "private_to_der", ossl_pkey_private_to_der, -1);
657
1770
  rb_define_method(cPKey, "private_to_pem", ossl_pkey_private_to_pem, -1);
658
1771
  rb_define_method(cPKey, "public_to_der", ossl_pkey_public_to_der, 0);
659
1772
  rb_define_method(cPKey, "public_to_pem", ossl_pkey_public_to_pem, 0);
660
-
661
- rb_define_method(cPKey, "sign", ossl_pkey_sign, 2);
662
- rb_define_method(cPKey, "verify", ossl_pkey_verify, 3);
1773
+ #ifdef HAVE_EVP_PKEY_NEW_RAW_PRIVATE_KEY
1774
+ rb_define_method(cPKey, "raw_private_key", ossl_pkey_raw_private_key, 0);
1775
+ rb_define_method(cPKey, "raw_public_key", ossl_pkey_raw_public_key, 0);
1776
+ #endif
1777
+ rb_define_method(cPKey, "compare?", ossl_pkey_compare, 1);
1778
+
1779
+ rb_define_method(cPKey, "sign", ossl_pkey_sign, -1);
1780
+ rb_define_method(cPKey, "verify", ossl_pkey_verify, -1);
1781
+ rb_define_method(cPKey, "sign_raw", ossl_pkey_sign_raw, -1);
1782
+ rb_define_method(cPKey, "verify_raw", ossl_pkey_verify_raw, -1);
1783
+ rb_define_method(cPKey, "verify_recover", ossl_pkey_verify_recover, -1);
1784
+ rb_define_method(cPKey, "derive", ossl_pkey_derive, -1);
1785
+ rb_define_method(cPKey, "encrypt", ossl_pkey_encrypt, -1);
1786
+ rb_define_method(cPKey, "decrypt", ossl_pkey_decrypt, -1);
663
1787
 
664
1788
  id_private_q = rb_intern("private?");
665
1789