openssl 2.2.0 → 3.1.0

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