openssl 2.2.1 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
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