openssl 2.2.1 → 3.0.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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +32 -44
  3. data/History.md +103 -1
  4. data/ext/openssl/extconf.rb +24 -26
  5. data/ext/openssl/openssl_missing.c +0 -66
  6. data/ext/openssl/openssl_missing.h +26 -45
  7. data/ext/openssl/ossl.c +59 -46
  8. data/ext/openssl/ossl.h +20 -6
  9. data/ext/openssl/ossl_asn1.c +16 -4
  10. data/ext/openssl/ossl_bn.c +188 -126
  11. data/ext/openssl/ossl_cipher.c +11 -11
  12. data/ext/openssl/ossl_config.c +412 -41
  13. data/ext/openssl/ossl_config.h +4 -7
  14. data/ext/openssl/ossl_digest.c +9 -9
  15. data/ext/openssl/ossl_engine.c +16 -15
  16. data/ext/openssl/ossl_hmac.c +48 -135
  17. data/ext/openssl/ossl_kdf.c +8 -0
  18. data/ext/openssl/ossl_ocsp.c +3 -51
  19. data/ext/openssl/ossl_pkcs12.c +21 -3
  20. data/ext/openssl/ossl_pkcs7.c +42 -59
  21. data/ext/openssl/ossl_pkey.c +1102 -191
  22. data/ext/openssl/ossl_pkey.h +35 -72
  23. data/ext/openssl/ossl_pkey_dh.c +124 -334
  24. data/ext/openssl/ossl_pkey_dsa.c +93 -398
  25. data/ext/openssl/ossl_pkey_ec.c +126 -318
  26. data/ext/openssl/ossl_pkey_rsa.c +100 -487
  27. data/ext/openssl/ossl_ssl.c +256 -355
  28. data/ext/openssl/ossl_ssl_session.c +24 -29
  29. data/ext/openssl/ossl_ts.c +35 -20
  30. data/ext/openssl/ossl_x509.c +0 -6
  31. data/ext/openssl/ossl_x509cert.c +164 -8
  32. data/ext/openssl/ossl_x509crl.c +10 -7
  33. data/ext/openssl/ossl_x509ext.c +1 -2
  34. data/ext/openssl/ossl_x509name.c +9 -2
  35. data/ext/openssl/ossl_x509req.c +10 -7
  36. data/ext/openssl/ossl_x509store.c +154 -70
  37. data/lib/openssl/buffering.rb +9 -0
  38. data/lib/openssl/hmac.rb +65 -0
  39. data/lib/openssl/pkey.rb +417 -0
  40. data/lib/openssl/ssl.rb +7 -7
  41. data/lib/openssl/version.rb +1 -1
  42. data/lib/openssl/x509.rb +22 -0
  43. data/lib/openssl.rb +0 -1
  44. metadata +4 -76
  45. data/ext/openssl/ruby_missing.h +0 -24
  46. 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
  {
@@ -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;
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,75 @@ 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
+
103
+ /* Then check PEM; multiple OSSL_DECODER_from_bio() calls may be needed */
104
+ OSSL_BIO_reset(bio);
105
+ if (OSSL_DECODER_CTX_set_input_type(dctx, "PEM") != 1)
106
+ goto out;
107
+ while (OSSL_DECODER_from_bio(dctx, bio) != 1) {
108
+ if (BIO_eof(bio))
109
+ goto out;
110
+ pos2 = BIO_tell(bio);
111
+ if (pos2 < 0 || pos2 <= pos)
112
+ goto out;
113
+ pos = pos2;
114
+ }
115
+
116
+ out:
117
+ OSSL_DECODER_CTX_free(dctx);
118
+ return pkey;
119
+ }
120
+ #else
121
+ EVP_PKEY *
122
+ ossl_pkey_read_generic(BIO *bio, VALUE pass)
123
+ {
124
+ void *ppass = (void *)pass;
125
+ EVP_PKEY *pkey;
126
+
127
+ if ((pkey = d2i_PrivateKey_bio(bio, NULL)))
128
+ goto out;
129
+ OSSL_BIO_reset(bio);
130
+ if ((pkey = d2i_PKCS8PrivateKey_bio(bio, NULL, ossl_pem_passwd_cb, ppass)))
131
+ goto out;
132
+ OSSL_BIO_reset(bio);
133
+ if ((pkey = d2i_PUBKEY_bio(bio, NULL)))
134
+ goto out;
135
+ OSSL_BIO_reset(bio);
136
+ /* PEM_read_bio_PrivateKey() also parses PKCS #8 formats */
137
+ if ((pkey = PEM_read_bio_PrivateKey(bio, NULL, ossl_pem_passwd_cb, ppass)))
138
+ goto out;
139
+ OSSL_BIO_reset(bio);
140
+ if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)))
141
+ goto out;
142
+ OSSL_BIO_reset(bio);
143
+ if ((pkey = PEM_read_bio_Parameters(bio, NULL)))
144
+ goto out;
145
+
146
+ out:
147
+ return pkey;
148
+ }
149
+ #endif
150
+
143
151
  /*
144
152
  * call-seq:
145
153
  * OpenSSL::PKey.read(string [, pwd ]) -> PKey
@@ -149,7 +157,7 @@ ossl_pkey_new(EVP_PKEY *pkey)
149
157
  * instance of the appropriate PKey class.
150
158
  *
151
159
  * === Parameters
152
- * * _string+ is a DER- or PEM-encoded string containing an arbitrary private
160
+ * * _string_ is a DER- or PEM-encoded string containing an arbitrary private
153
161
  * or public key.
154
162
  * * _io_ is an instance of IO containing a DER- or PEM-encoded
155
163
  * arbitrary private or public key.
@@ -164,36 +172,282 @@ ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self)
164
172
  VALUE data, pass;
165
173
 
166
174
  rb_scan_args(argc, argv, "11", &data, &pass);
167
- pass = ossl_pem_passwd_value(pass);
168
-
169
175
  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:
176
+ pkey = ossl_pkey_read_generic(bio, ossl_pem_passwd_value(pass));
190
177
  BIO_free(bio);
178
+ if (!pkey)
179
+ ossl_raise(ePKeyError, "Could not parse PKey");
191
180
  return ossl_pkey_new(pkey);
192
181
  }
193
182
 
183
+ static VALUE
184
+ pkey_ctx_apply_options_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ctx_v))
185
+ {
186
+ VALUE key = rb_ary_entry(i, 0), value = rb_ary_entry(i, 1);
187
+ EVP_PKEY_CTX *ctx = (EVP_PKEY_CTX *)ctx_v;
188
+
189
+ if (SYMBOL_P(key))
190
+ key = rb_sym2str(key);
191
+ value = rb_String(value);
192
+
193
+ if (EVP_PKEY_CTX_ctrl_str(ctx, StringValueCStr(key), StringValueCStr(value)) <= 0)
194
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_ctrl_str(ctx, %+"PRIsVALUE", %+"PRIsVALUE")",
195
+ key, value);
196
+ return Qnil;
197
+ }
198
+
199
+ static VALUE
200
+ pkey_ctx_apply_options0(VALUE args_v)
201
+ {
202
+ VALUE *args = (VALUE *)args_v;
203
+
204
+ rb_block_call(args[1], rb_intern("each"), 0, NULL,
205
+ pkey_ctx_apply_options_i, args[0]);
206
+ return Qnil;
207
+ }
208
+
209
+ static void
210
+ pkey_ctx_apply_options(EVP_PKEY_CTX *ctx, VALUE options, int *state)
211
+ {
212
+ VALUE args[2];
213
+ args[0] = (VALUE)ctx;
214
+ args[1] = options;
215
+
216
+ rb_protect(pkey_ctx_apply_options0, (VALUE)args, state);
217
+ }
218
+
219
+ struct pkey_blocking_generate_arg {
220
+ EVP_PKEY_CTX *ctx;
221
+ EVP_PKEY *pkey;
222
+ int state;
223
+ int yield: 1;
224
+ int genparam: 1;
225
+ int interrupted: 1;
226
+ };
227
+
228
+ static VALUE
229
+ pkey_gen_cb_yield(VALUE ctx_v)
230
+ {
231
+ EVP_PKEY_CTX *ctx = (void *)ctx_v;
232
+ int i, info_num;
233
+ VALUE *argv;
234
+
235
+ info_num = EVP_PKEY_CTX_get_keygen_info(ctx, -1);
236
+ argv = ALLOCA_N(VALUE, info_num);
237
+ for (i = 0; i < info_num; i++)
238
+ argv[i] = INT2NUM(EVP_PKEY_CTX_get_keygen_info(ctx, i));
239
+
240
+ return rb_yield_values2(info_num, argv);
241
+ }
242
+
243
+ static VALUE
244
+ call_check_ints0(VALUE arg)
245
+ {
246
+ rb_thread_check_ints();
247
+ return Qnil;
248
+ }
249
+
250
+ static void *
251
+ call_check_ints(void *arg)
252
+ {
253
+ int state;
254
+ rb_protect(call_check_ints0, Qnil, &state);
255
+ return (void *)(VALUE)state;
256
+ }
257
+
258
+ static int
259
+ pkey_gen_cb(EVP_PKEY_CTX *ctx)
260
+ {
261
+ struct pkey_blocking_generate_arg *arg = EVP_PKEY_CTX_get_app_data(ctx);
262
+ int state;
263
+
264
+ if (arg->yield) {
265
+ rb_protect(pkey_gen_cb_yield, (VALUE)ctx, &state);
266
+ if (state) {
267
+ arg->state = state;
268
+ return 0;
269
+ }
270
+ }
271
+ if (arg->interrupted) {
272
+ arg->interrupted = 0;
273
+ state = (int)(VALUE)rb_thread_call_with_gvl(call_check_ints, NULL);
274
+ if (state) {
275
+ arg->state = state;
276
+ return 0;
277
+ }
278
+ }
279
+ return 1;
280
+ }
281
+
282
+ static void
283
+ pkey_blocking_gen_stop(void *ptr)
284
+ {
285
+ struct pkey_blocking_generate_arg *arg = ptr;
286
+ arg->interrupted = 1;
287
+ }
288
+
289
+ static void *
290
+ pkey_blocking_gen(void *ptr)
291
+ {
292
+ struct pkey_blocking_generate_arg *arg = ptr;
293
+
294
+ if (arg->genparam && EVP_PKEY_paramgen(arg->ctx, &arg->pkey) <= 0)
295
+ return NULL;
296
+ if (!arg->genparam && EVP_PKEY_keygen(arg->ctx, &arg->pkey) <= 0)
297
+ return NULL;
298
+ return arg->pkey;
299
+ }
300
+
301
+ static VALUE
302
+ pkey_generate(int argc, VALUE *argv, VALUE self, int genparam)
303
+ {
304
+ EVP_PKEY_CTX *ctx;
305
+ VALUE alg, options;
306
+ struct pkey_blocking_generate_arg gen_arg = { 0 };
307
+ int state;
308
+
309
+ rb_scan_args(argc, argv, "11", &alg, &options);
310
+ if (rb_obj_is_kind_of(alg, cPKey)) {
311
+ EVP_PKEY *base_pkey;
312
+
313
+ GetPKey(alg, base_pkey);
314
+ ctx = EVP_PKEY_CTX_new(base_pkey, NULL/* engine */);
315
+ if (!ctx)
316
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
317
+ }
318
+ else {
319
+ #if OSSL_OPENSSL_PREREQ(3, 0, 0)
320
+ ctx = EVP_PKEY_CTX_new_from_name(NULL, StringValueCStr(alg), NULL);
321
+ if (!ctx)
322
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new_from_name");
323
+ #else
324
+ const EVP_PKEY_ASN1_METHOD *ameth;
325
+ ENGINE *tmpeng;
326
+ int pkey_id;
327
+
328
+ StringValue(alg);
329
+ ameth = EVP_PKEY_asn1_find_str(&tmpeng, RSTRING_PTR(alg),
330
+ RSTRING_LENINT(alg));
331
+ if (!ameth)
332
+ ossl_raise(ePKeyError, "algorithm %"PRIsVALUE" not found", alg);
333
+ EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth);
334
+ #if !defined(OPENSSL_NO_ENGINE)
335
+ if (tmpeng)
336
+ ENGINE_finish(tmpeng);
337
+ #endif
338
+
339
+ ctx = EVP_PKEY_CTX_new_id(pkey_id, NULL/* engine */);
340
+ if (!ctx)
341
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new_id");
342
+ #endif
343
+ }
344
+
345
+ if (genparam && EVP_PKEY_paramgen_init(ctx) <= 0) {
346
+ EVP_PKEY_CTX_free(ctx);
347
+ ossl_raise(ePKeyError, "EVP_PKEY_paramgen_init");
348
+ }
349
+ if (!genparam && EVP_PKEY_keygen_init(ctx) <= 0) {
350
+ EVP_PKEY_CTX_free(ctx);
351
+ ossl_raise(ePKeyError, "EVP_PKEY_keygen_init");
352
+ }
353
+
354
+ if (!NIL_P(options)) {
355
+ pkey_ctx_apply_options(ctx, options, &state);
356
+ if (state) {
357
+ EVP_PKEY_CTX_free(ctx);
358
+ rb_jump_tag(state);
359
+ }
360
+ }
361
+
362
+ gen_arg.genparam = genparam;
363
+ gen_arg.ctx = ctx;
364
+ gen_arg.yield = rb_block_given_p();
365
+ EVP_PKEY_CTX_set_app_data(ctx, &gen_arg);
366
+ EVP_PKEY_CTX_set_cb(ctx, pkey_gen_cb);
367
+ if (gen_arg.yield)
368
+ pkey_blocking_gen(&gen_arg);
369
+ else
370
+ rb_thread_call_without_gvl(pkey_blocking_gen, &gen_arg,
371
+ pkey_blocking_gen_stop, &gen_arg);
372
+ EVP_PKEY_CTX_free(ctx);
373
+ if (!gen_arg.pkey) {
374
+ if (gen_arg.state) {
375
+ ossl_clear_error();
376
+ rb_jump_tag(gen_arg.state);
377
+ }
378
+ else {
379
+ ossl_raise(ePKeyError, genparam ? "EVP_PKEY_paramgen" : "EVP_PKEY_keygen");
380
+ }
381
+ }
382
+
383
+ return ossl_pkey_new(gen_arg.pkey);
384
+ }
385
+
386
+ /*
387
+ * call-seq:
388
+ * OpenSSL::PKey.generate_parameters(algo_name [, options]) -> pkey
389
+ *
390
+ * Generates new parameters for the algorithm. _algo_name_ is a String that
391
+ * represents the algorithm. The optional argument _options_ is a Hash that
392
+ * specifies the options specific to the algorithm. The order of the options
393
+ * can be important.
394
+ *
395
+ * A block can be passed optionally. The meaning of the arguments passed to
396
+ * the block varies depending on the implementation of the algorithm. The block
397
+ * may be called once or multiple times, or may not even be called.
398
+ *
399
+ * For the supported options, see the documentation for the 'openssl genpkey'
400
+ * utility command.
401
+ *
402
+ * == Example
403
+ * pkey = OpenSSL::PKey.generate_parameters("DSA", "dsa_paramgen_bits" => 2048)
404
+ * p pkey.p.num_bits #=> 2048
405
+ */
406
+ static VALUE
407
+ ossl_pkey_s_generate_parameters(int argc, VALUE *argv, VALUE self)
408
+ {
409
+ return pkey_generate(argc, argv, self, 1);
410
+ }
411
+
412
+ /*
413
+ * call-seq:
414
+ * OpenSSL::PKey.generate_key(algo_name [, options]) -> pkey
415
+ * OpenSSL::PKey.generate_key(pkey [, options]) -> pkey
416
+ *
417
+ * Generates a new key (pair).
418
+ *
419
+ * If a String is given as the first argument, it generates a new random key
420
+ * for the algorithm specified by the name just as ::generate_parameters does.
421
+ * If an OpenSSL::PKey::PKey is given instead, it generates a new random key
422
+ * for the same algorithm as the key, using the parameters the key contains.
423
+ *
424
+ * See ::generate_parameters for the details of _options_ and the given block.
425
+ *
426
+ * == Example
427
+ * pkey_params = OpenSSL::PKey.generate_parameters("DSA", "dsa_paramgen_bits" => 2048)
428
+ * pkey_params.priv_key #=> nil
429
+ * pkey = OpenSSL::PKey.generate_key(pkey_params)
430
+ * pkey.priv_key #=> #<OpenSSL::BN 6277...
431
+ */
432
+ static VALUE
433
+ ossl_pkey_s_generate_key(int argc, VALUE *argv, VALUE self)
434
+ {
435
+ return pkey_generate(argc, argv, self, 0);
436
+ }
437
+
438
+ /*
439
+ * TODO: There is no convenient way to check the presence of public key
440
+ * components on OpenSSL 3.0. But since keys are immutable on 3.0, pkeys without
441
+ * these should only be created by OpenSSL::PKey.generate_parameters or by
442
+ * parsing DER-/PEM-encoded string. We would need another flag for that.
443
+ */
194
444
  void
195
445
  ossl_pkey_check_public_key(const EVP_PKEY *pkey)
196
446
  {
447
+ #if OSSL_OPENSSL_PREREQ(3, 0, 0)
448
+ if (EVP_PKEY_missing_parameters(pkey))
449
+ ossl_raise(ePKeyError, "parameters missing");
450
+ #else
197
451
  void *ptr;
198
452
  const BIGNUM *n, *e, *pubkey;
199
453
 
@@ -229,6 +483,7 @@ ossl_pkey_check_public_key(const EVP_PKEY *pkey)
229
483
  return;
230
484
  }
231
485
  ossl_raise(ePKeyError, "public key missing");
486
+ #endif
232
487
  }
233
488
 
234
489
  EVP_PKEY *
@@ -246,12 +501,19 @@ GetPrivPKeyPtr(VALUE obj)
246
501
  {
247
502
  EVP_PKEY *pkey;
248
503
 
249
- if (rb_funcallv(obj, id_private_q, 0, NULL) != Qtrue) {
250
- ossl_raise(rb_eArgError, "Private key is needed.");
251
- }
252
504
  GetPKey(obj, pkey);
505
+ if (OSSL_PKEY_IS_PRIVATE(obj))
506
+ return pkey;
507
+ /*
508
+ * The EVP API does not provide a way to check if the EVP_PKEY has private
509
+ * components. Assuming it does...
510
+ */
511
+ if (!rb_respond_to(obj, id_private_q))
512
+ return pkey;
513
+ if (RTEST(rb_funcallv(obj, id_private_q, 0, NULL)))
514
+ return pkey;
253
515
 
254
- return pkey;
516
+ rb_raise(rb_eArgError, "private key is needed");
255
517
  }
256
518
 
257
519
  EVP_PKEY *
@@ -271,16 +533,7 @@ DupPKeyPtr(VALUE obj)
271
533
  static VALUE
272
534
  ossl_pkey_alloc(VALUE klass)
273
535
  {
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;
536
+ return TypedData_Wrap_Struct(klass, &ossl_evp_pkey_type, NULL);
284
537
  }
285
538
 
286
539
  /*
@@ -299,6 +552,26 @@ ossl_pkey_initialize(VALUE self)
299
552
  return self;
300
553
  }
301
554
 
555
+ #ifdef HAVE_EVP_PKEY_DUP
556
+ static VALUE
557
+ ossl_pkey_initialize_copy(VALUE self, VALUE other)
558
+ {
559
+ EVP_PKEY *pkey, *pkey_other;
560
+
561
+ TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);
562
+ TypedData_Get_Struct(other, EVP_PKEY, &ossl_evp_pkey_type, pkey_other);
563
+ if (pkey)
564
+ rb_raise(rb_eTypeError, "pkey already initialized");
565
+ if (pkey_other) {
566
+ pkey = EVP_PKEY_dup(pkey_other);
567
+ if (!pkey)
568
+ ossl_raise(ePKeyError, "EVP_PKEY_dup");
569
+ RTYPEDDATA_DATA(self) = pkey;
570
+ }
571
+ return self;
572
+ }
573
+ #endif
574
+
302
575
  /*
303
576
  * call-seq:
304
577
  * pkey.oid -> string
@@ -335,6 +608,89 @@ ossl_pkey_inspect(VALUE self)
335
608
  OBJ_nid2sn(nid));
336
609
  }
337
610
 
611
+ /*
612
+ * call-seq:
613
+ * pkey.to_text -> string
614
+ *
615
+ * Dumps key parameters, public key, and private key components contained in
616
+ * the key into a human-readable text.
617
+ *
618
+ * This is intended for debugging purpose.
619
+ *
620
+ * See also the man page EVP_PKEY_print_private(3).
621
+ */
622
+ static VALUE
623
+ ossl_pkey_to_text(VALUE self)
624
+ {
625
+ EVP_PKEY *pkey;
626
+ BIO *bio;
627
+
628
+ GetPKey(self, pkey);
629
+ if (!(bio = BIO_new(BIO_s_mem())))
630
+ ossl_raise(ePKeyError, "BIO_new");
631
+
632
+ if (EVP_PKEY_print_private(bio, pkey, 0, NULL) == 1)
633
+ goto out;
634
+ OSSL_BIO_reset(bio);
635
+ if (EVP_PKEY_print_public(bio, pkey, 0, NULL) == 1)
636
+ goto out;
637
+ OSSL_BIO_reset(bio);
638
+ if (EVP_PKEY_print_params(bio, pkey, 0, NULL) == 1)
639
+ goto out;
640
+
641
+ BIO_free(bio);
642
+ ossl_raise(ePKeyError, "EVP_PKEY_print_params");
643
+
644
+ out:
645
+ return ossl_membio2str(bio);
646
+ }
647
+
648
+ VALUE
649
+ ossl_pkey_export_traditional(int argc, VALUE *argv, VALUE self, int to_der)
650
+ {
651
+ EVP_PKEY *pkey;
652
+ VALUE cipher, pass;
653
+ const EVP_CIPHER *enc = NULL;
654
+ BIO *bio;
655
+
656
+ GetPKey(self, pkey);
657
+ rb_scan_args(argc, argv, "02", &cipher, &pass);
658
+ if (!NIL_P(cipher)) {
659
+ enc = ossl_evp_get_cipherbyname(cipher);
660
+ pass = ossl_pem_passwd_value(pass);
661
+ }
662
+
663
+ bio = BIO_new(BIO_s_mem());
664
+ if (!bio)
665
+ ossl_raise(ePKeyError, "BIO_new");
666
+ if (to_der) {
667
+ if (!i2d_PrivateKey_bio(bio, pkey)) {
668
+ BIO_free(bio);
669
+ ossl_raise(ePKeyError, "i2d_PrivateKey_bio");
670
+ }
671
+ }
672
+ else {
673
+ #if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER)
674
+ if (!PEM_write_bio_PrivateKey_traditional(bio, pkey, enc, NULL, 0,
675
+ ossl_pem_passwd_cb,
676
+ (void *)pass)) {
677
+ #else
678
+ char pem_str[80];
679
+ const char *aname;
680
+
681
+ EVP_PKEY_asn1_get0_info(NULL, NULL, NULL, NULL, &aname, pkey->ameth);
682
+ snprintf(pem_str, sizeof(pem_str), "%s PRIVATE KEY", aname);
683
+ if (!PEM_ASN1_write_bio((i2d_of_void *)i2d_PrivateKey, pem_str, bio,
684
+ pkey, enc, NULL, 0, ossl_pem_passwd_cb,
685
+ (void *)pass)) {
686
+ #endif
687
+ BIO_free(bio);
688
+ ossl_raise(ePKeyError, "PEM_write_bio_PrivateKey_traditional");
689
+ }
690
+ }
691
+ return ossl_membio2str(bio);
692
+ }
693
+
338
694
  static VALUE
339
695
  do_pkcs8_export(int argc, VALUE *argv, VALUE self, int to_der)
340
696
  {
@@ -404,8 +760,8 @@ ossl_pkey_private_to_pem(int argc, VALUE *argv, VALUE self)
404
760
  return do_pkcs8_export(argc, argv, self, 0);
405
761
  }
406
762
 
407
- static VALUE
408
- do_spki_export(VALUE self, int to_der)
763
+ VALUE
764
+ ossl_pkey_export_spki(VALUE self, int to_der)
409
765
  {
410
766
  EVP_PKEY *pkey;
411
767
  BIO *bio;
@@ -438,7 +794,7 @@ do_spki_export(VALUE self, int to_der)
438
794
  static VALUE
439
795
  ossl_pkey_public_to_der(VALUE self)
440
796
  {
441
- return do_spki_export(self, 1);
797
+ return ossl_pkey_export_spki(self, 1);
442
798
  }
443
799
 
444
800
  /*
@@ -450,121 +806,661 @@ ossl_pkey_public_to_der(VALUE self)
450
806
  static VALUE
451
807
  ossl_pkey_public_to_pem(VALUE self)
452
808
  {
453
- return do_spki_export(self, 0);
809
+ return ossl_pkey_export_spki(self, 0);
454
810
  }
455
811
 
456
812
  /*
457
813
  * call-seq:
458
- * pkey.sign(digest, data) -> String
814
+ * pkey.compare?(another_pkey) -> true | false
459
815
  *
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.
816
+ * Used primarily to check if an OpenSSL::X509::Certificate#public_key compares to its private key.
466
817
  *
467
818
  * == Example
468
- * data = 'Sign me!'
469
- * digest = OpenSSL::Digest.new('SHA256')
470
- * pkey = OpenSSL::PKey::RSA.new(2048)
471
- * signature = pkey.sign(digest, data)
819
+ * x509 = OpenSSL::X509::Certificate.new(pem_encoded_certificate)
820
+ * rsa_key = OpenSSL::PKey::RSA.new(pem_encoded_private_key)
821
+ *
822
+ * rsa_key.compare?(x509.public_key) => true | false
823
+ */
824
+ static VALUE
825
+ ossl_pkey_compare(VALUE self, VALUE other)
826
+ {
827
+ int ret;
828
+ EVP_PKEY *selfPKey;
829
+ EVP_PKEY *otherPKey;
830
+
831
+ GetPKey(self, selfPKey);
832
+ GetPKey(other, otherPKey);
833
+
834
+ /* Explicitly check the key type given EVP_PKEY_ASN1_METHOD(3)
835
+ * docs param_cmp could return any negative number.
836
+ */
837
+ if (EVP_PKEY_id(selfPKey) != EVP_PKEY_id(otherPKey))
838
+ ossl_raise(rb_eTypeError, "cannot match different PKey types");
839
+
840
+ ret = EVP_PKEY_eq(selfPKey, otherPKey);
841
+
842
+ if (ret == 0)
843
+ return Qfalse;
844
+ else if (ret == 1)
845
+ return Qtrue;
846
+ else
847
+ ossl_raise(ePKeyError, "EVP_PKEY_eq");
848
+ }
849
+
850
+ /*
851
+ * call-seq:
852
+ * pkey.sign(digest, data [, options]) -> string
853
+ *
854
+ * Hashes and signs the +data+ using a message digest algorithm +digest+ and
855
+ * a private key +pkey+.
856
+ *
857
+ * See #verify for the verification operation.
858
+ *
859
+ * See also the man page EVP_DigestSign(3).
860
+ *
861
+ * +digest+::
862
+ * A String that represents the message digest algorithm name, or +nil+
863
+ * if the PKey type requires no digest algorithm.
864
+ * For backwards compatibility, this can be an instance of OpenSSL::Digest.
865
+ * Its state will not affect the signature.
866
+ * +data+::
867
+ * A String. The data to be hashed and signed.
868
+ * +options+::
869
+ * A Hash that contains algorithm specific control operations to \OpenSSL.
870
+ * See OpenSSL's man page EVP_PKEY_CTX_ctrl_str(3) for details.
871
+ * +options+ parameter was added in version 3.0.
872
+ *
873
+ * Example:
874
+ * data = "Sign me!"
875
+ * pkey = OpenSSL::PKey.generate_key("RSA", rsa_keygen_bits: 2048)
876
+ * signopts = { rsa_padding_mode: "pss" }
877
+ * signature = pkey.sign("SHA256", data, signopts)
878
+ *
879
+ * # Creates a copy of the RSA key pkey, but without the private components
880
+ * pub_key = pkey.public_key
881
+ * puts pub_key.verify("SHA256", signature, data, signopts) # => true
472
882
  */
473
883
  static VALUE
474
- ossl_pkey_sign(VALUE self, VALUE digest, VALUE data)
884
+ ossl_pkey_sign(int argc, VALUE *argv, VALUE self)
475
885
  {
476
886
  EVP_PKEY *pkey;
477
- const EVP_MD *md;
887
+ VALUE digest, data, options, sig;
888
+ const EVP_MD *md = NULL;
478
889
  EVP_MD_CTX *ctx;
479
- unsigned int buf_len;
480
- VALUE str;
481
- int result;
890
+ EVP_PKEY_CTX *pctx;
891
+ size_t siglen;
892
+ int state;
482
893
 
483
894
  pkey = GetPrivPKeyPtr(self);
484
- md = ossl_evp_get_digestbyname(digest);
895
+ rb_scan_args(argc, argv, "21", &digest, &data, &options);
896
+ if (!NIL_P(digest))
897
+ md = ossl_evp_get_digestbyname(digest);
485
898
  StringValue(data);
486
- str = rb_str_new(0, EVP_PKEY_size(pkey));
487
899
 
488
900
  ctx = EVP_MD_CTX_new();
489
901
  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");
902
+ ossl_raise(ePKeyError, "EVP_MD_CTX_new");
903
+ if (EVP_DigestSignInit(ctx, &pctx, md, /* engine */NULL, pkey) < 1) {
904
+ EVP_MD_CTX_free(ctx);
905
+ ossl_raise(ePKeyError, "EVP_DigestSignInit");
906
+ }
907
+ if (!NIL_P(options)) {
908
+ pkey_ctx_apply_options(pctx, options, &state);
909
+ if (state) {
910
+ EVP_MD_CTX_free(ctx);
911
+ rb_jump_tag(state);
912
+ }
913
+ }
914
+ #if OPENSSL_VERSION_NUMBER >= 0x10101000 && !defined(LIBRESSL_VERSION_NUMBER)
915
+ if (EVP_DigestSign(ctx, NULL, &siglen, (unsigned char *)RSTRING_PTR(data),
916
+ RSTRING_LEN(data)) < 1) {
917
+ EVP_MD_CTX_free(ctx);
918
+ ossl_raise(ePKeyError, "EVP_DigestSign");
494
919
  }
495
- if (!EVP_SignUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data))) {
496
- EVP_MD_CTX_free(ctx);
497
- ossl_raise(ePKeyError, "EVP_SignUpdate");
920
+ if (siglen > LONG_MAX) {
921
+ EVP_MD_CTX_free(ctx);
922
+ rb_raise(ePKeyError, "signature would be too large");
498
923
  }
499
- result = EVP_SignFinal(ctx, (unsigned char *)RSTRING_PTR(str), &buf_len, pkey);
924
+ sig = ossl_str_new(NULL, (long)siglen, &state);
925
+ if (state) {
926
+ EVP_MD_CTX_free(ctx);
927
+ rb_jump_tag(state);
928
+ }
929
+ if (EVP_DigestSign(ctx, (unsigned char *)RSTRING_PTR(sig), &siglen,
930
+ (unsigned char *)RSTRING_PTR(data),
931
+ RSTRING_LEN(data)) < 1) {
932
+ EVP_MD_CTX_free(ctx);
933
+ ossl_raise(ePKeyError, "EVP_DigestSign");
934
+ }
935
+ #else
936
+ if (EVP_DigestSignUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)) < 1) {
937
+ EVP_MD_CTX_free(ctx);
938
+ ossl_raise(ePKeyError, "EVP_DigestSignUpdate");
939
+ }
940
+ if (EVP_DigestSignFinal(ctx, NULL, &siglen) < 1) {
941
+ EVP_MD_CTX_free(ctx);
942
+ ossl_raise(ePKeyError, "EVP_DigestSignFinal");
943
+ }
944
+ if (siglen > LONG_MAX) {
945
+ EVP_MD_CTX_free(ctx);
946
+ rb_raise(ePKeyError, "signature would be too large");
947
+ }
948
+ sig = ossl_str_new(NULL, (long)siglen, &state);
949
+ if (state) {
950
+ EVP_MD_CTX_free(ctx);
951
+ rb_jump_tag(state);
952
+ }
953
+ if (EVP_DigestSignFinal(ctx, (unsigned char *)RSTRING_PTR(sig),
954
+ &siglen) < 1) {
955
+ EVP_MD_CTX_free(ctx);
956
+ ossl_raise(ePKeyError, "EVP_DigestSignFinal");
957
+ }
958
+ #endif
500
959
  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;
960
+ rb_str_set_len(sig, siglen);
961
+ return sig;
506
962
  }
507
963
 
508
964
  /*
509
- * call-seq:
510
- * pkey.verify(digest, signature, data) -> String
965
+ * call-seq:
966
+ * pkey.verify(digest, signature, data [, options]) -> true or false
511
967
  *
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.
968
+ * Verifies the +signature+ for the +data+ using a message digest algorithm
969
+ * +digest+ and a public key +pkey+.
520
970
  *
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
971
+ * Returns +true+ if the signature is successfully verified, +false+ otherwise.
972
+ * The caller must check the return value.
973
+ *
974
+ * See #sign for the signing operation and an example.
975
+ *
976
+ * See also the man page EVP_DigestVerify(3).
977
+ *
978
+ * +digest+::
979
+ * See #sign.
980
+ * +signature+::
981
+ * A String containing the signature to be verified.
982
+ * +data+::
983
+ * See #sign.
984
+ * +options+::
985
+ * See #sign. +options+ parameter was added in version 3.0.
528
986
  */
529
987
  static VALUE
530
- ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data)
988
+ ossl_pkey_verify(int argc, VALUE *argv, VALUE self)
531
989
  {
532
990
  EVP_PKEY *pkey;
533
- const EVP_MD *md;
991
+ VALUE digest, sig, data, options;
992
+ const EVP_MD *md = NULL;
534
993
  EVP_MD_CTX *ctx;
535
- int siglen, result;
994
+ EVP_PKEY_CTX *pctx;
995
+ int state, ret;
536
996
 
537
997
  GetPKey(self, pkey);
998
+ rb_scan_args(argc, argv, "31", &digest, &sig, &data, &options);
538
999
  ossl_pkey_check_public_key(pkey);
539
- md = ossl_evp_get_digestbyname(digest);
1000
+ if (!NIL_P(digest))
1001
+ md = ossl_evp_get_digestbyname(digest);
540
1002
  StringValue(sig);
541
- siglen = RSTRING_LENINT(sig);
542
1003
  StringValue(data);
543
1004
 
544
1005
  ctx = EVP_MD_CTX_new();
545
1006
  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");
1007
+ ossl_raise(ePKeyError, "EVP_MD_CTX_new");
1008
+ if (EVP_DigestVerifyInit(ctx, &pctx, md, /* engine */NULL, pkey) < 1) {
1009
+ EVP_MD_CTX_free(ctx);
1010
+ ossl_raise(ePKeyError, "EVP_DigestVerifyInit");
550
1011
  }
551
- if (!EVP_VerifyUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data))) {
552
- EVP_MD_CTX_free(ctx);
553
- ossl_raise(ePKeyError, "EVP_VerifyUpdate");
1012
+ if (!NIL_P(options)) {
1013
+ pkey_ctx_apply_options(pctx, options, &state);
1014
+ if (state) {
1015
+ EVP_MD_CTX_free(ctx);
1016
+ rb_jump_tag(state);
1017
+ }
554
1018
  }
555
- result = EVP_VerifyFinal(ctx, (unsigned char *)RSTRING_PTR(sig), siglen, pkey);
1019
+ #if OPENSSL_VERSION_NUMBER >= 0x10101000 && !defined(LIBRESSL_VERSION_NUMBER)
1020
+ ret = EVP_DigestVerify(ctx, (unsigned char *)RSTRING_PTR(sig),
1021
+ RSTRING_LEN(sig), (unsigned char *)RSTRING_PTR(data),
1022
+ RSTRING_LEN(data));
556
1023
  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");
1024
+ if (ret < 0)
1025
+ ossl_raise(ePKeyError, "EVP_DigestVerify");
1026
+ #else
1027
+ if (EVP_DigestVerifyUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)) < 1) {
1028
+ EVP_MD_CTX_free(ctx);
1029
+ ossl_raise(ePKeyError, "EVP_DigestVerifyUpdate");
1030
+ }
1031
+ ret = EVP_DigestVerifyFinal(ctx, (unsigned char *)RSTRING_PTR(sig),
1032
+ RSTRING_LEN(sig));
1033
+ EVP_MD_CTX_free(ctx);
1034
+ if (ret < 0)
1035
+ ossl_raise(ePKeyError, "EVP_DigestVerifyFinal");
1036
+ #endif
1037
+ if (ret)
1038
+ return Qtrue;
1039
+ else {
1040
+ ossl_clear_error();
1041
+ return Qfalse;
1042
+ }
1043
+ }
1044
+
1045
+ /*
1046
+ * call-seq:
1047
+ * pkey.sign_raw(digest, data [, options]) -> string
1048
+ *
1049
+ * Signs +data+ using a private key +pkey+. Unlike #sign, +data+ will not be
1050
+ * hashed by +digest+ automatically.
1051
+ *
1052
+ * See #verify_raw for the verification operation.
1053
+ *
1054
+ * Added in version 3.0. See also the man page EVP_PKEY_sign(3).
1055
+ *
1056
+ * +digest+::
1057
+ * A String that represents the message digest algorithm name, or +nil+
1058
+ * if the PKey type requires no digest algorithm.
1059
+ * Although this method will not hash +data+ with it, this parameter may still
1060
+ * be required depending on the signature algorithm.
1061
+ * +data+::
1062
+ * A String. The data to be signed.
1063
+ * +options+::
1064
+ * A Hash that contains algorithm specific control operations to \OpenSSL.
1065
+ * See OpenSSL's man page EVP_PKEY_CTX_ctrl_str(3) for details.
1066
+ *
1067
+ * Example:
1068
+ * data = "Sign me!"
1069
+ * hash = OpenSSL::Digest.digest("SHA256", data)
1070
+ * pkey = OpenSSL::PKey.generate_key("RSA", rsa_keygen_bits: 2048)
1071
+ * signopts = { rsa_padding_mode: "pss" }
1072
+ * signature = pkey.sign_raw("SHA256", hash, signopts)
1073
+ *
1074
+ * # Creates a copy of the RSA key pkey, but without the private components
1075
+ * pub_key = pkey.public_key
1076
+ * puts pub_key.verify_raw("SHA256", signature, hash, signopts) # => true
1077
+ */
1078
+ static VALUE
1079
+ ossl_pkey_sign_raw(int argc, VALUE *argv, VALUE self)
1080
+ {
1081
+ EVP_PKEY *pkey;
1082
+ VALUE digest, data, options, sig;
1083
+ const EVP_MD *md = NULL;
1084
+ EVP_PKEY_CTX *ctx;
1085
+ size_t outlen;
1086
+ int state;
1087
+
1088
+ GetPKey(self, pkey);
1089
+ rb_scan_args(argc, argv, "21", &digest, &data, &options);
1090
+ if (!NIL_P(digest))
1091
+ md = ossl_evp_get_digestbyname(digest);
1092
+ StringValue(data);
1093
+
1094
+ ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
1095
+ if (!ctx)
1096
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
1097
+ if (EVP_PKEY_sign_init(ctx) <= 0) {
1098
+ EVP_PKEY_CTX_free(ctx);
1099
+ ossl_raise(ePKeyError, "EVP_PKEY_sign_init");
1100
+ }
1101
+ if (md && EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) {
1102
+ EVP_PKEY_CTX_free(ctx);
1103
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_set_signature_md");
1104
+ }
1105
+ if (!NIL_P(options)) {
1106
+ pkey_ctx_apply_options(ctx, options, &state);
1107
+ if (state) {
1108
+ EVP_PKEY_CTX_free(ctx);
1109
+ rb_jump_tag(state);
1110
+ }
1111
+ }
1112
+ if (EVP_PKEY_sign(ctx, NULL, &outlen, (unsigned char *)RSTRING_PTR(data),
1113
+ RSTRING_LEN(data)) <= 0) {
1114
+ EVP_PKEY_CTX_free(ctx);
1115
+ ossl_raise(ePKeyError, "EVP_PKEY_sign");
1116
+ }
1117
+ if (outlen > LONG_MAX) {
1118
+ EVP_PKEY_CTX_free(ctx);
1119
+ rb_raise(ePKeyError, "signature would be too large");
1120
+ }
1121
+ sig = ossl_str_new(NULL, (long)outlen, &state);
1122
+ if (state) {
1123
+ EVP_PKEY_CTX_free(ctx);
1124
+ rb_jump_tag(state);
1125
+ }
1126
+ if (EVP_PKEY_sign(ctx, (unsigned char *)RSTRING_PTR(sig), &outlen,
1127
+ (unsigned char *)RSTRING_PTR(data),
1128
+ RSTRING_LEN(data)) <= 0) {
1129
+ EVP_PKEY_CTX_free(ctx);
1130
+ ossl_raise(ePKeyError, "EVP_PKEY_sign");
1131
+ }
1132
+ EVP_PKEY_CTX_free(ctx);
1133
+ rb_str_set_len(sig, outlen);
1134
+ return sig;
1135
+ }
1136
+
1137
+ /*
1138
+ * call-seq:
1139
+ * pkey.verify_raw(digest, signature, data [, options]) -> true or false
1140
+ *
1141
+ * Verifies the +signature+ for the +data+ using a public key +pkey+. Unlike
1142
+ * #verify, this method will not hash +data+ with +digest+ automatically.
1143
+ *
1144
+ * Returns +true+ if the signature is successfully verified, +false+ otherwise.
1145
+ * The caller must check the return value.
1146
+ *
1147
+ * See #sign_raw for the signing operation and an example code.
1148
+ *
1149
+ * Added in version 3.0. See also the man page EVP_PKEY_verify(3).
1150
+ *
1151
+ * +signature+::
1152
+ * A String containing the signature to be verified.
1153
+ */
1154
+ static VALUE
1155
+ ossl_pkey_verify_raw(int argc, VALUE *argv, VALUE self)
1156
+ {
1157
+ EVP_PKEY *pkey;
1158
+ VALUE digest, sig, data, options;
1159
+ const EVP_MD *md = NULL;
1160
+ EVP_PKEY_CTX *ctx;
1161
+ int state, ret;
1162
+
1163
+ GetPKey(self, pkey);
1164
+ rb_scan_args(argc, argv, "31", &digest, &sig, &data, &options);
1165
+ ossl_pkey_check_public_key(pkey);
1166
+ if (!NIL_P(digest))
1167
+ md = ossl_evp_get_digestbyname(digest);
1168
+ StringValue(sig);
1169
+ StringValue(data);
1170
+
1171
+ ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
1172
+ if (!ctx)
1173
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
1174
+ if (EVP_PKEY_verify_init(ctx) <= 0) {
1175
+ EVP_PKEY_CTX_free(ctx);
1176
+ ossl_raise(ePKeyError, "EVP_PKEY_verify_init");
1177
+ }
1178
+ if (md && EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) {
1179
+ EVP_PKEY_CTX_free(ctx);
1180
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_set_signature_md");
1181
+ }
1182
+ if (!NIL_P(options)) {
1183
+ pkey_ctx_apply_options(ctx, options, &state);
1184
+ if (state) {
1185
+ EVP_PKEY_CTX_free(ctx);
1186
+ rb_jump_tag(state);
1187
+ }
1188
+ }
1189
+ ret = EVP_PKEY_verify(ctx, (unsigned char *)RSTRING_PTR(sig),
1190
+ RSTRING_LEN(sig),
1191
+ (unsigned char *)RSTRING_PTR(data),
1192
+ RSTRING_LEN(data));
1193
+ EVP_PKEY_CTX_free(ctx);
1194
+ if (ret < 0)
1195
+ ossl_raise(ePKeyError, "EVP_PKEY_verify");
1196
+
1197
+ if (ret)
1198
+ return Qtrue;
1199
+ else {
1200
+ ossl_clear_error();
1201
+ return Qfalse;
565
1202
  }
566
1203
  }
567
1204
 
1205
+ /*
1206
+ * call-seq:
1207
+ * pkey.verify_recover(digest, signature [, options]) -> string
1208
+ *
1209
+ * Recovers the signed data from +signature+ using a public key +pkey+. Not all
1210
+ * signature algorithms support this operation.
1211
+ *
1212
+ * Added in version 3.0. See also the man page EVP_PKEY_verify_recover(3).
1213
+ *
1214
+ * +signature+::
1215
+ * A String containing the signature to be verified.
1216
+ */
1217
+ static VALUE
1218
+ ossl_pkey_verify_recover(int argc, VALUE *argv, VALUE self)
1219
+ {
1220
+ EVP_PKEY *pkey;
1221
+ VALUE digest, sig, options, out;
1222
+ const EVP_MD *md = NULL;
1223
+ EVP_PKEY_CTX *ctx;
1224
+ int state;
1225
+ size_t outlen;
1226
+
1227
+ GetPKey(self, pkey);
1228
+ rb_scan_args(argc, argv, "21", &digest, &sig, &options);
1229
+ ossl_pkey_check_public_key(pkey);
1230
+ if (!NIL_P(digest))
1231
+ md = ossl_evp_get_digestbyname(digest);
1232
+ StringValue(sig);
1233
+
1234
+ ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
1235
+ if (!ctx)
1236
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
1237
+ if (EVP_PKEY_verify_recover_init(ctx) <= 0) {
1238
+ EVP_PKEY_CTX_free(ctx);
1239
+ ossl_raise(ePKeyError, "EVP_PKEY_verify_recover_init");
1240
+ }
1241
+ if (md && EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) {
1242
+ EVP_PKEY_CTX_free(ctx);
1243
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_set_signature_md");
1244
+ }
1245
+ if (!NIL_P(options)) {
1246
+ pkey_ctx_apply_options(ctx, options, &state);
1247
+ if (state) {
1248
+ EVP_PKEY_CTX_free(ctx);
1249
+ rb_jump_tag(state);
1250
+ }
1251
+ }
1252
+ if (EVP_PKEY_verify_recover(ctx, NULL, &outlen,
1253
+ (unsigned char *)RSTRING_PTR(sig),
1254
+ RSTRING_LEN(sig)) <= 0) {
1255
+ EVP_PKEY_CTX_free(ctx);
1256
+ ossl_raise(ePKeyError, "EVP_PKEY_verify_recover");
1257
+ }
1258
+ out = ossl_str_new(NULL, (long)outlen, &state);
1259
+ if (state) {
1260
+ EVP_PKEY_CTX_free(ctx);
1261
+ rb_jump_tag(state);
1262
+ }
1263
+ if (EVP_PKEY_verify_recover(ctx, (unsigned char *)RSTRING_PTR(out), &outlen,
1264
+ (unsigned char *)RSTRING_PTR(sig),
1265
+ RSTRING_LEN(sig)) <= 0) {
1266
+ EVP_PKEY_CTX_free(ctx);
1267
+ ossl_raise(ePKeyError, "EVP_PKEY_verify_recover");
1268
+ }
1269
+ EVP_PKEY_CTX_free(ctx);
1270
+ rb_str_set_len(out, outlen);
1271
+ return out;
1272
+ }
1273
+
1274
+ /*
1275
+ * call-seq:
1276
+ * pkey.derive(peer_pkey) -> string
1277
+ *
1278
+ * Derives a shared secret from _pkey_ and _peer_pkey_. _pkey_ must contain
1279
+ * the private components, _peer_pkey_ must contain the public components.
1280
+ */
1281
+ static VALUE
1282
+ ossl_pkey_derive(int argc, VALUE *argv, VALUE self)
1283
+ {
1284
+ EVP_PKEY *pkey, *peer_pkey;
1285
+ EVP_PKEY_CTX *ctx;
1286
+ VALUE peer_pkey_obj, str;
1287
+ size_t keylen;
1288
+ int state;
1289
+
1290
+ GetPKey(self, pkey);
1291
+ rb_scan_args(argc, argv, "1", &peer_pkey_obj);
1292
+ GetPKey(peer_pkey_obj, peer_pkey);
1293
+
1294
+ ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
1295
+ if (!ctx)
1296
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
1297
+ if (EVP_PKEY_derive_init(ctx) <= 0) {
1298
+ EVP_PKEY_CTX_free(ctx);
1299
+ ossl_raise(ePKeyError, "EVP_PKEY_derive_init");
1300
+ }
1301
+ if (EVP_PKEY_derive_set_peer(ctx, peer_pkey) <= 0) {
1302
+ EVP_PKEY_CTX_free(ctx);
1303
+ ossl_raise(ePKeyError, "EVP_PKEY_derive_set_peer");
1304
+ }
1305
+ if (EVP_PKEY_derive(ctx, NULL, &keylen) <= 0) {
1306
+ EVP_PKEY_CTX_free(ctx);
1307
+ ossl_raise(ePKeyError, "EVP_PKEY_derive");
1308
+ }
1309
+ if (keylen > LONG_MAX)
1310
+ rb_raise(ePKeyError, "derived key would be too large");
1311
+ str = ossl_str_new(NULL, (long)keylen, &state);
1312
+ if (state) {
1313
+ EVP_PKEY_CTX_free(ctx);
1314
+ rb_jump_tag(state);
1315
+ }
1316
+ if (EVP_PKEY_derive(ctx, (unsigned char *)RSTRING_PTR(str), &keylen) <= 0) {
1317
+ EVP_PKEY_CTX_free(ctx);
1318
+ ossl_raise(ePKeyError, "EVP_PKEY_derive");
1319
+ }
1320
+ EVP_PKEY_CTX_free(ctx);
1321
+ rb_str_set_len(str, keylen);
1322
+ return str;
1323
+ }
1324
+
1325
+ /*
1326
+ * call-seq:
1327
+ * pkey.encrypt(data [, options]) -> string
1328
+ *
1329
+ * Performs a public key encryption operation using +pkey+.
1330
+ *
1331
+ * See #decrypt for the reverse operation.
1332
+ *
1333
+ * Added in version 3.0. See also the man page EVP_PKEY_encrypt(3).
1334
+ *
1335
+ * +data+::
1336
+ * A String to be encrypted.
1337
+ * +options+::
1338
+ * A Hash that contains algorithm specific control operations to \OpenSSL.
1339
+ * See OpenSSL's man page EVP_PKEY_CTX_ctrl_str(3) for details.
1340
+ *
1341
+ * Example:
1342
+ * pkey = OpenSSL::PKey.generate_key("RSA", rsa_keygen_bits: 2048)
1343
+ * data = "secret data"
1344
+ * encrypted = pkey.encrypt(data, rsa_padding_mode: "oaep")
1345
+ * decrypted = pkey.decrypt(data, rsa_padding_mode: "oaep")
1346
+ * p decrypted #=> "secret data"
1347
+ */
1348
+ static VALUE
1349
+ ossl_pkey_encrypt(int argc, VALUE *argv, VALUE self)
1350
+ {
1351
+ EVP_PKEY *pkey;
1352
+ EVP_PKEY_CTX *ctx;
1353
+ VALUE data, options, str;
1354
+ size_t outlen;
1355
+ int state;
1356
+
1357
+ GetPKey(self, pkey);
1358
+ rb_scan_args(argc, argv, "11", &data, &options);
1359
+ StringValue(data);
1360
+
1361
+ ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
1362
+ if (!ctx)
1363
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
1364
+ if (EVP_PKEY_encrypt_init(ctx) <= 0) {
1365
+ EVP_PKEY_CTX_free(ctx);
1366
+ ossl_raise(ePKeyError, "EVP_PKEY_encrypt_init");
1367
+ }
1368
+ if (!NIL_P(options)) {
1369
+ pkey_ctx_apply_options(ctx, options, &state);
1370
+ if (state) {
1371
+ EVP_PKEY_CTX_free(ctx);
1372
+ rb_jump_tag(state);
1373
+ }
1374
+ }
1375
+ if (EVP_PKEY_encrypt(ctx, NULL, &outlen,
1376
+ (unsigned char *)RSTRING_PTR(data),
1377
+ RSTRING_LEN(data)) <= 0) {
1378
+ EVP_PKEY_CTX_free(ctx);
1379
+ ossl_raise(ePKeyError, "EVP_PKEY_encrypt");
1380
+ }
1381
+ if (outlen > LONG_MAX) {
1382
+ EVP_PKEY_CTX_free(ctx);
1383
+ rb_raise(ePKeyError, "encrypted data would be too large");
1384
+ }
1385
+ str = ossl_str_new(NULL, (long)outlen, &state);
1386
+ if (state) {
1387
+ EVP_PKEY_CTX_free(ctx);
1388
+ rb_jump_tag(state);
1389
+ }
1390
+ if (EVP_PKEY_encrypt(ctx, (unsigned char *)RSTRING_PTR(str), &outlen,
1391
+ (unsigned char *)RSTRING_PTR(data),
1392
+ RSTRING_LEN(data)) <= 0) {
1393
+ EVP_PKEY_CTX_free(ctx);
1394
+ ossl_raise(ePKeyError, "EVP_PKEY_encrypt");
1395
+ }
1396
+ EVP_PKEY_CTX_free(ctx);
1397
+ rb_str_set_len(str, outlen);
1398
+ return str;
1399
+ }
1400
+
1401
+ /*
1402
+ * call-seq:
1403
+ * pkey.decrypt(data [, options]) -> string
1404
+ *
1405
+ * Performs a public key decryption operation using +pkey+.
1406
+ *
1407
+ * See #encrypt for a description of the parameters and an example.
1408
+ *
1409
+ * Added in version 3.0. See also the man page EVP_PKEY_decrypt(3).
1410
+ */
1411
+ static VALUE
1412
+ ossl_pkey_decrypt(int argc, VALUE *argv, VALUE self)
1413
+ {
1414
+ EVP_PKEY *pkey;
1415
+ EVP_PKEY_CTX *ctx;
1416
+ VALUE data, options, str;
1417
+ size_t outlen;
1418
+ int state;
1419
+
1420
+ GetPKey(self, pkey);
1421
+ rb_scan_args(argc, argv, "11", &data, &options);
1422
+ StringValue(data);
1423
+
1424
+ ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
1425
+ if (!ctx)
1426
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
1427
+ if (EVP_PKEY_decrypt_init(ctx) <= 0) {
1428
+ EVP_PKEY_CTX_free(ctx);
1429
+ ossl_raise(ePKeyError, "EVP_PKEY_decrypt_init");
1430
+ }
1431
+ if (!NIL_P(options)) {
1432
+ pkey_ctx_apply_options(ctx, options, &state);
1433
+ if (state) {
1434
+ EVP_PKEY_CTX_free(ctx);
1435
+ rb_jump_tag(state);
1436
+ }
1437
+ }
1438
+ if (EVP_PKEY_decrypt(ctx, NULL, &outlen,
1439
+ (unsigned char *)RSTRING_PTR(data),
1440
+ RSTRING_LEN(data)) <= 0) {
1441
+ EVP_PKEY_CTX_free(ctx);
1442
+ ossl_raise(ePKeyError, "EVP_PKEY_decrypt");
1443
+ }
1444
+ if (outlen > LONG_MAX) {
1445
+ EVP_PKEY_CTX_free(ctx);
1446
+ rb_raise(ePKeyError, "decrypted data would be too large");
1447
+ }
1448
+ str = ossl_str_new(NULL, (long)outlen, &state);
1449
+ if (state) {
1450
+ EVP_PKEY_CTX_free(ctx);
1451
+ rb_jump_tag(state);
1452
+ }
1453
+ if (EVP_PKEY_decrypt(ctx, (unsigned char *)RSTRING_PTR(str), &outlen,
1454
+ (unsigned char *)RSTRING_PTR(data),
1455
+ RSTRING_LEN(data)) <= 0) {
1456
+ EVP_PKEY_CTX_free(ctx);
1457
+ ossl_raise(ePKeyError, "EVP_PKEY_decrypt");
1458
+ }
1459
+ EVP_PKEY_CTX_free(ctx);
1460
+ rb_str_set_len(str, outlen);
1461
+ return str;
1462
+ }
1463
+
568
1464
  /*
569
1465
  * INIT
570
1466
  */
@@ -648,18 +1544,33 @@ Init_ossl_pkey(void)
648
1544
  cPKey = rb_define_class_under(mPKey, "PKey", rb_cObject);
649
1545
 
650
1546
  rb_define_module_function(mPKey, "read", ossl_pkey_new_from_data, -1);
1547
+ rb_define_module_function(mPKey, "generate_parameters", ossl_pkey_s_generate_parameters, -1);
1548
+ rb_define_module_function(mPKey, "generate_key", ossl_pkey_s_generate_key, -1);
651
1549
 
652
1550
  rb_define_alloc_func(cPKey, ossl_pkey_alloc);
653
1551
  rb_define_method(cPKey, "initialize", ossl_pkey_initialize, 0);
1552
+ #ifdef HAVE_EVP_PKEY_DUP
1553
+ rb_define_method(cPKey, "initialize_copy", ossl_pkey_initialize_copy, 1);
1554
+ #else
1555
+ rb_undef_method(cPKey, "initialize_copy");
1556
+ #endif
654
1557
  rb_define_method(cPKey, "oid", ossl_pkey_oid, 0);
655
1558
  rb_define_method(cPKey, "inspect", ossl_pkey_inspect, 0);
1559
+ rb_define_method(cPKey, "to_text", ossl_pkey_to_text, 0);
656
1560
  rb_define_method(cPKey, "private_to_der", ossl_pkey_private_to_der, -1);
657
1561
  rb_define_method(cPKey, "private_to_pem", ossl_pkey_private_to_pem, -1);
658
1562
  rb_define_method(cPKey, "public_to_der", ossl_pkey_public_to_der, 0);
659
1563
  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);
1564
+ rb_define_method(cPKey, "compare?", ossl_pkey_compare, 1);
1565
+
1566
+ rb_define_method(cPKey, "sign", ossl_pkey_sign, -1);
1567
+ rb_define_method(cPKey, "verify", ossl_pkey_verify, -1);
1568
+ rb_define_method(cPKey, "sign_raw", ossl_pkey_sign_raw, -1);
1569
+ rb_define_method(cPKey, "verify_raw", ossl_pkey_verify_raw, -1);
1570
+ rb_define_method(cPKey, "verify_recover", ossl_pkey_verify_recover, -1);
1571
+ rb_define_method(cPKey, "derive", ossl_pkey_derive, -1);
1572
+ rb_define_method(cPKey, "encrypt", ossl_pkey_encrypt, -1);
1573
+ rb_define_method(cPKey, "decrypt", ossl_pkey_decrypt, -1);
663
1574
 
664
1575
  id_private_q = rb_intern("private?");
665
1576