zig_example 0.2.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/ext/mkmf.rb +2734 -0
  3. data/ext/openssl/openssl_missing.c +40 -0
  4. data/ext/openssl/openssl_missing.h +238 -0
  5. data/ext/openssl/ossl.c +1295 -0
  6. data/ext/openssl/ossl.h +201 -0
  7. data/ext/openssl/ossl_asn1.c +1891 -0
  8. data/ext/openssl/ossl_asn1.h +62 -0
  9. data/ext/openssl/ossl_bio.c +42 -0
  10. data/ext/openssl/ossl_bio.h +16 -0
  11. data/ext/openssl/ossl_bn.c +1344 -0
  12. data/ext/openssl/ossl_bn.h +26 -0
  13. data/ext/openssl/ossl_cipher.c +1074 -0
  14. data/ext/openssl/ossl_cipher.h +20 -0
  15. data/ext/openssl/ossl_config.c +460 -0
  16. data/ext/openssl/ossl_config.h +16 -0
  17. data/ext/openssl/ossl_digest.c +425 -0
  18. data/ext/openssl/ossl_digest.h +20 -0
  19. data/ext/openssl/ossl_engine.c +568 -0
  20. data/ext/openssl/ossl_engine.h +19 -0
  21. data/ext/openssl/ossl_hmac.c +310 -0
  22. data/ext/openssl/ossl_hmac.h +18 -0
  23. data/ext/openssl/ossl_kdf.c +311 -0
  24. data/ext/openssl/ossl_kdf.h +6 -0
  25. data/ext/openssl/ossl_ns_spki.c +405 -0
  26. data/ext/openssl/ossl_ns_spki.h +19 -0
  27. data/ext/openssl/ossl_ocsp.c +1965 -0
  28. data/ext/openssl/ossl_ocsp.h +23 -0
  29. data/ext/openssl/ossl_pkcs12.c +275 -0
  30. data/ext/openssl/ossl_pkcs12.h +13 -0
  31. data/ext/openssl/ossl_pkcs7.c +1081 -0
  32. data/ext/openssl/ossl_pkcs7.h +36 -0
  33. data/ext/openssl/ossl_pkey.c +1624 -0
  34. data/ext/openssl/ossl_pkey.h +204 -0
  35. data/ext/openssl/ossl_pkey_dh.c +440 -0
  36. data/ext/openssl/ossl_pkey_dsa.c +359 -0
  37. data/ext/openssl/ossl_pkey_ec.c +1655 -0
  38. data/ext/openssl/ossl_pkey_rsa.c +579 -0
  39. data/ext/openssl/ossl_rand.c +200 -0
  40. data/ext/openssl/ossl_rand.h +18 -0
  41. data/ext/openssl/ossl_ssl.c +3142 -0
  42. data/ext/openssl/ossl_ssl.h +36 -0
  43. data/ext/openssl/ossl_ssl_session.c +331 -0
  44. data/ext/openssl/ossl_ts.c +1539 -0
  45. data/ext/openssl/ossl_ts.h +16 -0
  46. data/ext/openssl/ossl_x509.c +256 -0
  47. data/ext/openssl/ossl_x509.h +115 -0
  48. data/ext/openssl/ossl_x509attr.c +324 -0
  49. data/ext/openssl/ossl_x509cert.c +1002 -0
  50. data/ext/openssl/ossl_x509crl.c +545 -0
  51. data/ext/openssl/ossl_x509ext.c +490 -0
  52. data/ext/openssl/ossl_x509name.c +597 -0
  53. data/ext/openssl/ossl_x509req.c +444 -0
  54. data/ext/openssl/ossl_x509revoked.c +300 -0
  55. data/ext/openssl/ossl_x509store.c +986 -0
  56. data/ext/zigrb_100doors/build.zig +0 -12
  57. data/ext/zigrb_100doors/extconf.rb +2 -19
  58. data/ext/zigrb_ackermann/build.zig +0 -12
  59. data/ext/zigrb_ackermann/extconf.rb +2 -19
  60. data/ext/zigrb_lucas_lehmer/build.zig +53 -0
  61. data/ext/zigrb_lucas_lehmer/extconf.rb +3 -0
  62. data/ext/zigrb_lucas_lehmer/src/lucas_lehmer.c +60 -0
  63. data/ext/zigrb_lucas_lehmer/src/lucas_lehmer.h +1 -0
  64. data/ext/zigrb_lucas_lehmer/src/wrapper.zig +42 -0
  65. data/lib/zig_example/version.rb +1 -1
  66. data/lib/zig_example.rb +1 -0
  67. metadata +63 -3
@@ -0,0 +1,1624 @@
1
+ /*
2
+ * 'OpenSSL for Ruby' project
3
+ * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
4
+ * All rights reserved.
5
+ */
6
+ /*
7
+ * This program is licensed under the same licence as Ruby.
8
+ * (See the file 'LICENCE'.)
9
+ */
10
+ #include "ossl.h"
11
+
12
+ #ifdef OSSL_USE_ENGINE
13
+ # include <openssl/engine.h>
14
+ #endif
15
+
16
+ /*
17
+ * Classes
18
+ */
19
+ VALUE mPKey;
20
+ VALUE cPKey;
21
+ VALUE ePKeyError;
22
+ static ID id_private_q;
23
+
24
+ static void
25
+ ossl_evp_pkey_free(void *ptr)
26
+ {
27
+ EVP_PKEY_free(ptr);
28
+ }
29
+
30
+ /*
31
+ * Public
32
+ */
33
+ const rb_data_type_t ossl_evp_pkey_type = {
34
+ "OpenSSL/EVP_PKEY",
35
+ {
36
+ 0, ossl_evp_pkey_free,
37
+ },
38
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
39
+ };
40
+
41
+ static VALUE
42
+ pkey_new0(VALUE arg)
43
+ {
44
+ EVP_PKEY *pkey = (EVP_PKEY *)arg;
45
+ VALUE klass, obj;
46
+
47
+ switch (EVP_PKEY_base_id(pkey)) {
48
+ #if !defined(OPENSSL_NO_RSA)
49
+ case EVP_PKEY_RSA: klass = cRSA; break;
50
+ #endif
51
+ #if !defined(OPENSSL_NO_DSA)
52
+ case EVP_PKEY_DSA: klass = cDSA; break;
53
+ #endif
54
+ #if !defined(OPENSSL_NO_DH)
55
+ case EVP_PKEY_DH: klass = cDH; break;
56
+ #endif
57
+ #if !defined(OPENSSL_NO_EC)
58
+ case EVP_PKEY_EC: klass = cEC; break;
59
+ #endif
60
+ default: klass = cPKey; break;
61
+ }
62
+ obj = rb_obj_alloc(klass);
63
+ RTYPEDDATA_DATA(obj) = pkey;
64
+ return obj;
65
+ }
66
+
67
+ VALUE
68
+ ossl_pkey_new(EVP_PKEY *pkey)
69
+ {
70
+ VALUE obj;
71
+ int status;
72
+
73
+ obj = rb_protect(pkey_new0, (VALUE)pkey, &status);
74
+ if (status) {
75
+ EVP_PKEY_free(pkey);
76
+ rb_jump_tag(status);
77
+ }
78
+
79
+ return obj;
80
+ }
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
+
190
+ /*
191
+ * call-seq:
192
+ * OpenSSL::PKey.read(string [, pwd ]) -> PKey
193
+ * OpenSSL::PKey.read(io [, pwd ]) -> PKey
194
+ *
195
+ * Reads a DER or PEM encoded string from _string_ or _io_ and returns an
196
+ * instance of the appropriate PKey class.
197
+ *
198
+ * === Parameters
199
+ * * _string_ is a DER- or PEM-encoded string containing an arbitrary private
200
+ * or public key.
201
+ * * _io_ is an instance of IO containing a DER- or PEM-encoded
202
+ * arbitrary private or public key.
203
+ * * _pwd_ is an optional password in case _string_ or _io_ is an encrypted
204
+ * PEM resource.
205
+ */
206
+ static VALUE
207
+ ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self)
208
+ {
209
+ EVP_PKEY *pkey;
210
+ BIO *bio;
211
+ VALUE data, pass;
212
+
213
+ rb_scan_args(argc, argv, "11", &data, &pass);
214
+ bio = ossl_obj2bio(&data);
215
+ pkey = ossl_pkey_read_generic(bio, ossl_pem_passwd_value(pass));
216
+ BIO_free(bio);
217
+ if (!pkey)
218
+ ossl_raise(ePKeyError, "Could not parse PKey");
219
+ return ossl_pkey_new(pkey);
220
+ }
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
+ */
484
+ void
485
+ ossl_pkey_check_public_key(const EVP_PKEY *pkey)
486
+ {
487
+ #if OSSL_OPENSSL_PREREQ(3, 0, 0)
488
+ if (EVP_PKEY_missing_parameters(pkey))
489
+ ossl_raise(ePKeyError, "parameters missing");
490
+ #else
491
+ void *ptr;
492
+ const BIGNUM *n, *e, *pubkey;
493
+
494
+ if (EVP_PKEY_missing_parameters(pkey))
495
+ ossl_raise(ePKeyError, "parameters missing");
496
+
497
+ /* OpenSSL < 1.1.0 takes non-const pointer */
498
+ ptr = EVP_PKEY_get0((EVP_PKEY *)pkey);
499
+ switch (EVP_PKEY_base_id(pkey)) {
500
+ case EVP_PKEY_RSA:
501
+ RSA_get0_key(ptr, &n, &e, NULL);
502
+ if (n && e)
503
+ return;
504
+ break;
505
+ case EVP_PKEY_DSA:
506
+ DSA_get0_key(ptr, &pubkey, NULL);
507
+ if (pubkey)
508
+ return;
509
+ break;
510
+ case EVP_PKEY_DH:
511
+ DH_get0_key(ptr, &pubkey, NULL);
512
+ if (pubkey)
513
+ return;
514
+ break;
515
+ #if !defined(OPENSSL_NO_EC)
516
+ case EVP_PKEY_EC:
517
+ if (EC_KEY_get0_public_key(ptr))
518
+ return;
519
+ break;
520
+ #endif
521
+ default:
522
+ /* unsupported type; assuming ok */
523
+ return;
524
+ }
525
+ ossl_raise(ePKeyError, "public key missing");
526
+ #endif
527
+ }
528
+
529
+ EVP_PKEY *
530
+ GetPKeyPtr(VALUE obj)
531
+ {
532
+ EVP_PKEY *pkey;
533
+
534
+ GetPKey(obj, pkey);
535
+
536
+ return pkey;
537
+ }
538
+
539
+ EVP_PKEY *
540
+ GetPrivPKeyPtr(VALUE obj)
541
+ {
542
+ EVP_PKEY *pkey;
543
+
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;
555
+
556
+ rb_raise(rb_eArgError, "private key is needed");
557
+ }
558
+
559
+ EVP_PKEY *
560
+ DupPKeyPtr(VALUE obj)
561
+ {
562
+ EVP_PKEY *pkey;
563
+
564
+ GetPKey(obj, pkey);
565
+ EVP_PKEY_up_ref(pkey);
566
+
567
+ return pkey;
568
+ }
569
+
570
+ /*
571
+ * Private
572
+ */
573
+ static VALUE
574
+ ossl_pkey_alloc(VALUE klass)
575
+ {
576
+ return TypedData_Wrap_Struct(klass, &ossl_evp_pkey_type, NULL);
577
+ }
578
+
579
+ /*
580
+ * call-seq:
581
+ * PKeyClass.new -> self
582
+ *
583
+ * Because PKey is an abstract class, actually calling this method explicitly
584
+ * will raise a NotImplementedError.
585
+ */
586
+ static VALUE
587
+ ossl_pkey_initialize(VALUE self)
588
+ {
589
+ if (rb_obj_is_instance_of(self, cPKey)) {
590
+ ossl_raise(rb_eTypeError, "OpenSSL::PKey::PKey can't be instantiated directly");
591
+ }
592
+ return self;
593
+ }
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
+
615
+ /*
616
+ * call-seq:
617
+ * pkey.oid -> string
618
+ *
619
+ * Returns the short name of the OID associated with _pkey_.
620
+ */
621
+ static VALUE
622
+ ossl_pkey_oid(VALUE self)
623
+ {
624
+ EVP_PKEY *pkey;
625
+ int nid;
626
+
627
+ GetPKey(self, pkey);
628
+ nid = EVP_PKEY_id(pkey);
629
+ return rb_str_new_cstr(OBJ_nid2sn(nid));
630
+ }
631
+
632
+ /*
633
+ * call-seq:
634
+ * pkey.inspect -> string
635
+ *
636
+ * Returns a string describing the PKey object.
637
+ */
638
+ static VALUE
639
+ ossl_pkey_inspect(VALUE self)
640
+ {
641
+ EVP_PKEY *pkey;
642
+ int nid;
643
+
644
+ GetPKey(self, pkey);
645
+ nid = EVP_PKEY_id(pkey);
646
+ return rb_sprintf("#<%"PRIsVALUE":%p oid=%s>",
647
+ rb_class_name(CLASS_OF(self)), (void *)self,
648
+ OBJ_nid2sn(nid));
649
+ }
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
+
734
+ static VALUE
735
+ do_pkcs8_export(int argc, VALUE *argv, VALUE self, int to_der)
736
+ {
737
+ EVP_PKEY *pkey;
738
+ VALUE cipher, pass;
739
+ const EVP_CIPHER *enc = NULL;
740
+ BIO *bio;
741
+
742
+ GetPKey(self, pkey);
743
+ rb_scan_args(argc, argv, "02", &cipher, &pass);
744
+ if (argc > 0) {
745
+ /*
746
+ * TODO: EncryptedPrivateKeyInfo actually has more options.
747
+ * Should they be exposed?
748
+ */
749
+ enc = ossl_evp_get_cipherbyname(cipher);
750
+ pass = ossl_pem_passwd_value(pass);
751
+ }
752
+
753
+ bio = BIO_new(BIO_s_mem());
754
+ if (!bio)
755
+ ossl_raise(ePKeyError, "BIO_new");
756
+ if (to_der) {
757
+ if (!i2d_PKCS8PrivateKey_bio(bio, pkey, enc, NULL, 0,
758
+ ossl_pem_passwd_cb, (void *)pass)) {
759
+ BIO_free(bio);
760
+ ossl_raise(ePKeyError, "i2d_PKCS8PrivateKey_bio");
761
+ }
762
+ }
763
+ else {
764
+ if (!PEM_write_bio_PKCS8PrivateKey(bio, pkey, enc, NULL, 0,
765
+ ossl_pem_passwd_cb, (void *)pass)) {
766
+ BIO_free(bio);
767
+ ossl_raise(ePKeyError, "PEM_write_bio_PKCS8PrivateKey");
768
+ }
769
+ }
770
+ return ossl_membio2str(bio);
771
+ }
772
+
773
+ /*
774
+ * call-seq:
775
+ * pkey.private_to_der -> string
776
+ * pkey.private_to_der(cipher, password) -> string
777
+ *
778
+ * Serializes the private key to DER-encoded PKCS #8 format. If called without
779
+ * arguments, unencrypted PKCS #8 PrivateKeyInfo format is used. If called with
780
+ * a cipher name and a password, PKCS #8 EncryptedPrivateKeyInfo format with
781
+ * PBES2 encryption scheme is used.
782
+ */
783
+ static VALUE
784
+ ossl_pkey_private_to_der(int argc, VALUE *argv, VALUE self)
785
+ {
786
+ return do_pkcs8_export(argc, argv, self, 1);
787
+ }
788
+
789
+ /*
790
+ * call-seq:
791
+ * pkey.private_to_pem -> string
792
+ * pkey.private_to_pem(cipher, password) -> string
793
+ *
794
+ * Serializes the private key to PEM-encoded PKCS #8 format. See #private_to_der
795
+ * for more details.
796
+ */
797
+ static VALUE
798
+ ossl_pkey_private_to_pem(int argc, VALUE *argv, VALUE self)
799
+ {
800
+ return do_pkcs8_export(argc, argv, self, 0);
801
+ }
802
+
803
+ VALUE
804
+ ossl_pkey_export_spki(VALUE self, int to_der)
805
+ {
806
+ EVP_PKEY *pkey;
807
+ BIO *bio;
808
+
809
+ GetPKey(self, pkey);
810
+ bio = BIO_new(BIO_s_mem());
811
+ if (!bio)
812
+ ossl_raise(ePKeyError, "BIO_new");
813
+ if (to_der) {
814
+ if (!i2d_PUBKEY_bio(bio, pkey)) {
815
+ BIO_free(bio);
816
+ ossl_raise(ePKeyError, "i2d_PUBKEY_bio");
817
+ }
818
+ }
819
+ else {
820
+ if (!PEM_write_bio_PUBKEY(bio, pkey)) {
821
+ BIO_free(bio);
822
+ ossl_raise(ePKeyError, "PEM_write_bio_PUBKEY");
823
+ }
824
+ }
825
+ return ossl_membio2str(bio);
826
+ }
827
+
828
+ /*
829
+ * call-seq:
830
+ * pkey.public_to_der -> string
831
+ *
832
+ * Serializes the public key to DER-encoded X.509 SubjectPublicKeyInfo format.
833
+ */
834
+ static VALUE
835
+ ossl_pkey_public_to_der(VALUE self)
836
+ {
837
+ return ossl_pkey_export_spki(self, 1);
838
+ }
839
+
840
+ /*
841
+ * call-seq:
842
+ * pkey.public_to_pem -> string
843
+ *
844
+ * Serializes the public key to PEM-encoded X.509 SubjectPublicKeyInfo format.
845
+ */
846
+ static VALUE
847
+ ossl_pkey_public_to_pem(VALUE self)
848
+ {
849
+ return ossl_pkey_export_spki(self, 0);
850
+ }
851
+
852
+ /*
853
+ * call-seq:
854
+ * pkey.compare?(another_pkey) -> true | false
855
+ *
856
+ * Used primarily to check if an OpenSSL::X509::Certificate#public_key compares to its private key.
857
+ *
858
+ * == Example
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
922
+ */
923
+ static VALUE
924
+ ossl_pkey_sign(int argc, VALUE *argv, VALUE self)
925
+ {
926
+ EVP_PKEY *pkey;
927
+ VALUE digest, data, options, sig;
928
+ const EVP_MD *md = NULL;
929
+ EVP_MD_CTX *ctx;
930
+ EVP_PKEY_CTX *pctx;
931
+ size_t siglen;
932
+ int state;
933
+
934
+ pkey = GetPrivPKeyPtr(self);
935
+ rb_scan_args(argc, argv, "21", &digest, &data, &options);
936
+ if (!NIL_P(digest))
937
+ md = ossl_evp_get_digestbyname(digest);
938
+ StringValue(data);
939
+
940
+ ctx = EVP_MD_CTX_new();
941
+ if (!ctx)
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");
983
+ }
984
+ if (siglen > LONG_MAX) {
985
+ EVP_MD_CTX_free(ctx);
986
+ rb_raise(ePKeyError, "signature would be too large");
987
+ }
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
999
+ EVP_MD_CTX_free(ctx);
1000
+ rb_str_set_len(sig, siglen);
1001
+ return sig;
1002
+ }
1003
+
1004
+ /*
1005
+ * call-seq:
1006
+ * pkey.verify(digest, signature, data [, options]) -> true or false
1007
+ *
1008
+ * Verifies the +signature+ for the +data+ using a message digest algorithm
1009
+ * +digest+ and a public key +pkey+.
1010
+ *
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.
1026
+ */
1027
+ static VALUE
1028
+ ossl_pkey_verify(int argc, VALUE *argv, VALUE self)
1029
+ {
1030
+ EVP_PKEY *pkey;
1031
+ VALUE digest, sig, data, options;
1032
+ const EVP_MD *md = NULL;
1033
+ EVP_MD_CTX *ctx;
1034
+ EVP_PKEY_CTX *pctx;
1035
+ int state, ret;
1036
+
1037
+ GetPKey(self, pkey);
1038
+ rb_scan_args(argc, argv, "31", &digest, &sig, &data, &options);
1039
+ ossl_pkey_check_public_key(pkey);
1040
+ if (!NIL_P(digest))
1041
+ md = ossl_evp_get_digestbyname(digest);
1042
+ StringValue(sig);
1043
+ StringValue(data);
1044
+
1045
+ ctx = EVP_MD_CTX_new();
1046
+ if (!ctx)
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
+ }
1058
+ }
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");
1070
+ }
1071
+ ret = EVP_DigestVerifyFinal(ctx, (unsigned char *)RSTRING_PTR(sig),
1072
+ RSTRING_LEN(sig));
1073
+ EVP_MD_CTX_free(ctx);
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");
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;
1502
+ }
1503
+
1504
+ /*
1505
+ * INIT
1506
+ */
1507
+ void
1508
+ Init_ossl_pkey(void)
1509
+ {
1510
+ #undef rb_intern
1511
+ #if 0
1512
+ mOSSL = rb_define_module("OpenSSL");
1513
+ eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
1514
+ #endif
1515
+
1516
+ /* Document-module: OpenSSL::PKey
1517
+ *
1518
+ * == Asymmetric Public Key Algorithms
1519
+ *
1520
+ * Asymmetric public key algorithms solve the problem of establishing and
1521
+ * sharing secret keys to en-/decrypt messages. The key in such an
1522
+ * algorithm consists of two parts: a public key that may be distributed
1523
+ * to others and a private key that needs to remain secret.
1524
+ *
1525
+ * Messages encrypted with a public key can only be decrypted by
1526
+ * recipients that are in possession of the associated private key.
1527
+ * Since public key algorithms are considerably slower than symmetric
1528
+ * key algorithms (cf. OpenSSL::Cipher) they are often used to establish
1529
+ * a symmetric key shared between two parties that are in possession of
1530
+ * each other's public key.
1531
+ *
1532
+ * Asymmetric algorithms offer a lot of nice features that are used in a
1533
+ * lot of different areas. A very common application is the creation and
1534
+ * validation of digital signatures. To sign a document, the signatory
1535
+ * generally uses a message digest algorithm (cf. OpenSSL::Digest) to
1536
+ * compute a digest of the document that is then encrypted (i.e. signed)
1537
+ * using the private key. Anyone in possession of the public key may then
1538
+ * verify the signature by computing the message digest of the original
1539
+ * document on their own, decrypting the signature using the signatory's
1540
+ * public key and comparing the result to the message digest they
1541
+ * previously computed. The signature is valid if and only if the
1542
+ * decrypted signature is equal to this message digest.
1543
+ *
1544
+ * The PKey module offers support for three popular public/private key
1545
+ * algorithms:
1546
+ * * RSA (OpenSSL::PKey::RSA)
1547
+ * * DSA (OpenSSL::PKey::DSA)
1548
+ * * Elliptic Curve Cryptography (OpenSSL::PKey::EC)
1549
+ * Each of these implementations is in fact a sub-class of the abstract
1550
+ * PKey class which offers the interface for supporting digital signatures
1551
+ * in the form of PKey#sign and PKey#verify.
1552
+ *
1553
+ * == Diffie-Hellman Key Exchange
1554
+ *
1555
+ * Finally PKey also features OpenSSL::PKey::DH, an implementation of
1556
+ * the Diffie-Hellman key exchange protocol based on discrete logarithms
1557
+ * in finite fields, the same basis that DSA is built on.
1558
+ * The Diffie-Hellman protocol can be used to exchange (symmetric) keys
1559
+ * over insecure channels without needing any prior joint knowledge
1560
+ * between the participating parties. As the security of DH demands
1561
+ * relatively long "public keys" (i.e. the part that is overtly
1562
+ * transmitted between participants) DH tends to be quite slow. If
1563
+ * security or speed is your primary concern, OpenSSL::PKey::EC offers
1564
+ * another implementation of the Diffie-Hellman protocol.
1565
+ *
1566
+ */
1567
+ mPKey = rb_define_module_under(mOSSL, "PKey");
1568
+
1569
+ /* Document-class: OpenSSL::PKey::PKeyError
1570
+ *
1571
+ *Raised when errors occur during PKey#sign or PKey#verify.
1572
+ */
1573
+ ePKeyError = rb_define_class_under(mPKey, "PKeyError", eOSSLError);
1574
+
1575
+ /* Document-class: OpenSSL::PKey::PKey
1576
+ *
1577
+ * An abstract class that bundles signature creation (PKey#sign) and
1578
+ * validation (PKey#verify) that is common to all implementations except
1579
+ * OpenSSL::PKey::DH
1580
+ * * OpenSSL::PKey::RSA
1581
+ * * OpenSSL::PKey::DSA
1582
+ * * OpenSSL::PKey::EC
1583
+ */
1584
+ cPKey = rb_define_class_under(mPKey, "PKey", rb_cObject);
1585
+
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);
1589
+
1590
+ rb_define_alloc_func(cPKey, ossl_pkey_alloc);
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
1597
+ rb_define_method(cPKey, "oid", ossl_pkey_oid, 0);
1598
+ rb_define_method(cPKey, "inspect", ossl_pkey_inspect, 0);
1599
+ rb_define_method(cPKey, "to_text", ossl_pkey_to_text, 0);
1600
+ rb_define_method(cPKey, "private_to_der", ossl_pkey_private_to_der, -1);
1601
+ rb_define_method(cPKey, "private_to_pem", ossl_pkey_private_to_pem, -1);
1602
+ rb_define_method(cPKey, "public_to_der", ossl_pkey_public_to_der, 0);
1603
+ rb_define_method(cPKey, "public_to_pem", ossl_pkey_public_to_pem, 0);
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);
1614
+
1615
+ id_private_q = rb_intern("private?");
1616
+
1617
+ /*
1618
+ * INIT rsa, dsa, dh, ec
1619
+ */
1620
+ Init_ossl_rsa();
1621
+ Init_ossl_dsa();
1622
+ Init_ossl_dh();
1623
+ Init_ossl_ec();
1624
+ }