openssl 2.2.0 → 3.1.0

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