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