openssl-custom 2.2.2

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 (75) hide show
  1. checksums.yaml +7 -0
  2. data/BSDL +22 -0
  3. data/CONTRIBUTING.md +132 -0
  4. data/History.md +485 -0
  5. data/LICENSE.txt +56 -0
  6. data/README.md +66 -0
  7. data/ext/openssl/extconf.rb +190 -0
  8. data/ext/openssl/openssl_missing.c +106 -0
  9. data/ext/openssl/openssl_missing.h +257 -0
  10. data/ext/openssl/ossl.c +1282 -0
  11. data/ext/openssl/ossl.h +181 -0
  12. data/ext/openssl/ossl_asn1.c +1878 -0
  13. data/ext/openssl/ossl_asn1.h +62 -0
  14. data/ext/openssl/ossl_bio.c +42 -0
  15. data/ext/openssl/ossl_bio.h +16 -0
  16. data/ext/openssl/ossl_bn.c +1270 -0
  17. data/ext/openssl/ossl_bn.h +26 -0
  18. data/ext/openssl/ossl_cipher.c +1075 -0
  19. data/ext/openssl/ossl_cipher.h +20 -0
  20. data/ext/openssl/ossl_config.c +89 -0
  21. data/ext/openssl/ossl_config.h +19 -0
  22. data/ext/openssl/ossl_digest.c +425 -0
  23. data/ext/openssl/ossl_digest.h +20 -0
  24. data/ext/openssl/ossl_engine.c +567 -0
  25. data/ext/openssl/ossl_engine.h +19 -0
  26. data/ext/openssl/ossl_hmac.c +389 -0
  27. data/ext/openssl/ossl_hmac.h +18 -0
  28. data/ext/openssl/ossl_kdf.c +303 -0
  29. data/ext/openssl/ossl_kdf.h +6 -0
  30. data/ext/openssl/ossl_ns_spki.c +405 -0
  31. data/ext/openssl/ossl_ns_spki.h +19 -0
  32. data/ext/openssl/ossl_ocsp.c +2013 -0
  33. data/ext/openssl/ossl_ocsp.h +23 -0
  34. data/ext/openssl/ossl_pkcs12.c +257 -0
  35. data/ext/openssl/ossl_pkcs12.h +13 -0
  36. data/ext/openssl/ossl_pkcs7.c +1098 -0
  37. data/ext/openssl/ossl_pkcs7.h +36 -0
  38. data/ext/openssl/ossl_pkey.c +673 -0
  39. data/ext/openssl/ossl_pkey.h +241 -0
  40. data/ext/openssl/ossl_pkey_dh.c +650 -0
  41. data/ext/openssl/ossl_pkey_dsa.c +664 -0
  42. data/ext/openssl/ossl_pkey_ec.c +1827 -0
  43. data/ext/openssl/ossl_pkey_rsa.c +966 -0
  44. data/ext/openssl/ossl_rand.c +200 -0
  45. data/ext/openssl/ossl_rand.h +18 -0
  46. data/ext/openssl/ossl_ssl.c +3080 -0
  47. data/ext/openssl/ossl_ssl.h +36 -0
  48. data/ext/openssl/ossl_ssl_session.c +332 -0
  49. data/ext/openssl/ossl_ts.c +1524 -0
  50. data/ext/openssl/ossl_ts.h +16 -0
  51. data/ext/openssl/ossl_x509.c +262 -0
  52. data/ext/openssl/ossl_x509.h +115 -0
  53. data/ext/openssl/ossl_x509attr.c +324 -0
  54. data/ext/openssl/ossl_x509cert.c +846 -0
  55. data/ext/openssl/ossl_x509crl.c +542 -0
  56. data/ext/openssl/ossl_x509ext.c +491 -0
  57. data/ext/openssl/ossl_x509name.c +590 -0
  58. data/ext/openssl/ossl_x509req.c +441 -0
  59. data/ext/openssl/ossl_x509revoked.c +300 -0
  60. data/ext/openssl/ossl_x509store.c +902 -0
  61. data/ext/openssl/ruby_missing.h +24 -0
  62. data/lib/openssl/bn.rb +40 -0
  63. data/lib/openssl/buffering.rb +478 -0
  64. data/lib/openssl/cipher.rb +67 -0
  65. data/lib/openssl/config.rb +501 -0
  66. data/lib/openssl/digest.rb +73 -0
  67. data/lib/openssl/hmac.rb +13 -0
  68. data/lib/openssl/marshal.rb +30 -0
  69. data/lib/openssl/pkcs5.rb +22 -0
  70. data/lib/openssl/pkey.rb +42 -0
  71. data/lib/openssl/ssl.rb +542 -0
  72. data/lib/openssl/version.rb +5 -0
  73. data/lib/openssl/x509.rb +369 -0
  74. data/lib/openssl.rb +38 -0
  75. metadata +196 -0
@@ -0,0 +1,36 @@
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
+ #if !defined(_OSSL_PKCS7_H_)
11
+ #define _OSSL_PKCS7_H_
12
+
13
+ #define NewPKCS7(klass) \
14
+ TypedData_Wrap_Struct((klass), &ossl_pkcs7_type, 0)
15
+ #define SetPKCS7(obj, pkcs7) do { \
16
+ if (!(pkcs7)) { \
17
+ ossl_raise(rb_eRuntimeError, "PKCS7 wasn't initialized."); \
18
+ } \
19
+ RTYPEDDATA_DATA(obj) = (pkcs7); \
20
+ } while (0)
21
+ #define GetPKCS7(obj, pkcs7) do { \
22
+ TypedData_Get_Struct((obj), PKCS7, &ossl_pkcs7_type, (pkcs7)); \
23
+ if (!(pkcs7)) { \
24
+ ossl_raise(rb_eRuntimeError, "PKCS7 wasn't initialized."); \
25
+ } \
26
+ } while (0)
27
+
28
+ extern const rb_data_type_t ossl_pkcs7_type;
29
+ extern VALUE cPKCS7;
30
+ extern VALUE cPKCS7Signer;
31
+ extern VALUE cPKCS7Recipient;
32
+ extern VALUE ePKCS7Error;
33
+
34
+ void Init_ossl_pkcs7(void);
35
+
36
+ #endif /* _OSSL_PKCS7_H_ */
@@ -0,0 +1,673 @@
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
+ /*
13
+ * Classes
14
+ */
15
+ VALUE mPKey;
16
+ VALUE cPKey;
17
+ VALUE ePKeyError;
18
+ static ID id_private_q;
19
+
20
+ /*
21
+ * callback for generating keys
22
+ */
23
+ static VALUE
24
+ call_check_ints0(VALUE arg)
25
+ {
26
+ rb_thread_check_ints();
27
+ return Qnil;
28
+ }
29
+
30
+ static void *
31
+ call_check_ints(void *arg)
32
+ {
33
+ int state;
34
+ rb_protect(call_check_ints0, Qnil, &state);
35
+ return (void *)(VALUE)state;
36
+ }
37
+
38
+ int
39
+ ossl_generate_cb_2(int p, int n, BN_GENCB *cb)
40
+ {
41
+ VALUE ary;
42
+ struct ossl_generate_cb_arg *arg;
43
+ int state;
44
+
45
+ arg = (struct ossl_generate_cb_arg *)BN_GENCB_get_arg(cb);
46
+ if (arg->yield) {
47
+ ary = rb_ary_new2(2);
48
+ rb_ary_store(ary, 0, INT2NUM(p));
49
+ rb_ary_store(ary, 1, INT2NUM(n));
50
+
51
+ /*
52
+ * can be break by raising exception or 'break'
53
+ */
54
+ rb_protect(rb_yield, ary, &state);
55
+ if (state) {
56
+ arg->state = state;
57
+ return 0;
58
+ }
59
+ }
60
+ if (arg->interrupted) {
61
+ arg->interrupted = 0;
62
+ state = (int)(VALUE)rb_thread_call_with_gvl(call_check_ints, NULL);
63
+ if (state) {
64
+ arg->state = state;
65
+ return 0;
66
+ }
67
+ }
68
+ return 1;
69
+ }
70
+
71
+ void
72
+ ossl_generate_cb_stop(void *ptr)
73
+ {
74
+ struct ossl_generate_cb_arg *arg = (struct ossl_generate_cb_arg *)ptr;
75
+ arg->interrupted = 1;
76
+ }
77
+
78
+ static void
79
+ ossl_evp_pkey_free(void *ptr)
80
+ {
81
+ EVP_PKEY_free(ptr);
82
+ }
83
+
84
+ /*
85
+ * Public
86
+ */
87
+ const rb_data_type_t ossl_evp_pkey_type = {
88
+ "OpenSSL/EVP_PKEY",
89
+ {
90
+ 0, ossl_evp_pkey_free,
91
+ },
92
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
93
+ };
94
+
95
+ static VALUE
96
+ pkey_new0(EVP_PKEY *pkey)
97
+ {
98
+ VALUE obj;
99
+ int type;
100
+
101
+ if (!pkey || (type = EVP_PKEY_base_id(pkey)) == EVP_PKEY_NONE)
102
+ ossl_raise(rb_eRuntimeError, "pkey is empty");
103
+
104
+ switch (type) {
105
+ #if !defined(OPENSSL_NO_RSA)
106
+ case EVP_PKEY_RSA:
107
+ return ossl_rsa_new(pkey);
108
+ #endif
109
+ #if !defined(OPENSSL_NO_DSA)
110
+ case EVP_PKEY_DSA:
111
+ return ossl_dsa_new(pkey);
112
+ #endif
113
+ #if !defined(OPENSSL_NO_DH)
114
+ case EVP_PKEY_DH:
115
+ return ossl_dh_new(pkey);
116
+ #endif
117
+ #if !defined(OPENSSL_NO_EC)
118
+ case EVP_PKEY_EC:
119
+ return ossl_ec_new(pkey);
120
+ #endif
121
+ default:
122
+ obj = NewPKey(cPKey);
123
+ SetPKey(obj, pkey);
124
+ return obj;
125
+ }
126
+ }
127
+
128
+ VALUE
129
+ ossl_pkey_new(EVP_PKEY *pkey)
130
+ {
131
+ VALUE obj;
132
+ int status;
133
+
134
+ obj = rb_protect((VALUE (*)(VALUE))pkey_new0, (VALUE)pkey, &status);
135
+ if (status) {
136
+ EVP_PKEY_free(pkey);
137
+ rb_jump_tag(status);
138
+ }
139
+
140
+ return obj;
141
+ }
142
+
143
+ /*
144
+ * call-seq:
145
+ * OpenSSL::PKey.read(string [, pwd ]) -> PKey
146
+ * OpenSSL::PKey.read(io [, pwd ]) -> PKey
147
+ *
148
+ * Reads a DER or PEM encoded string from _string_ or _io_ and returns an
149
+ * instance of the appropriate PKey class.
150
+ *
151
+ * === Parameters
152
+ * * _string+ is a DER- or PEM-encoded string containing an arbitrary private
153
+ * or public key.
154
+ * * _io_ is an instance of IO containing a DER- or PEM-encoded
155
+ * arbitrary private or public key.
156
+ * * _pwd_ is an optional password in case _string_ or _io_ is an encrypted
157
+ * PEM resource.
158
+ */
159
+ static VALUE
160
+ ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self)
161
+ {
162
+ EVP_PKEY *pkey;
163
+ BIO *bio;
164
+ VALUE data, pass;
165
+
166
+ rb_scan_args(argc, argv, "11", &data, &pass);
167
+ pass = ossl_pem_passwd_value(pass);
168
+
169
+ bio = ossl_obj2bio(&data);
170
+ if ((pkey = d2i_PrivateKey_bio(bio, NULL)))
171
+ goto ok;
172
+ OSSL_BIO_reset(bio);
173
+ if ((pkey = d2i_PKCS8PrivateKey_bio(bio, NULL, ossl_pem_passwd_cb, (void *)pass)))
174
+ goto ok;
175
+ OSSL_BIO_reset(bio);
176
+ if ((pkey = d2i_PUBKEY_bio(bio, NULL)))
177
+ goto ok;
178
+ OSSL_BIO_reset(bio);
179
+ /* PEM_read_bio_PrivateKey() also parses PKCS #8 formats */
180
+ if ((pkey = PEM_read_bio_PrivateKey(bio, NULL, ossl_pem_passwd_cb, (void *)pass)))
181
+ goto ok;
182
+ OSSL_BIO_reset(bio);
183
+ if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)))
184
+ goto ok;
185
+
186
+ BIO_free(bio);
187
+ ossl_raise(ePKeyError, "Could not parse PKey");
188
+
189
+ ok:
190
+ BIO_free(bio);
191
+ return ossl_pkey_new(pkey);
192
+ }
193
+
194
+ void
195
+ ossl_pkey_check_public_key(const EVP_PKEY *pkey)
196
+ {
197
+ void *ptr;
198
+ const BIGNUM *n, *e, *pubkey;
199
+
200
+ if (EVP_PKEY_missing_parameters(pkey))
201
+ ossl_raise(ePKeyError, "parameters missing");
202
+
203
+ /* OpenSSL < 1.1.0 takes non-const pointer */
204
+ ptr = EVP_PKEY_get0((EVP_PKEY *)pkey);
205
+ switch (EVP_PKEY_base_id(pkey)) {
206
+ case EVP_PKEY_RSA:
207
+ RSA_get0_key(ptr, &n, &e, NULL);
208
+ if (n && e)
209
+ return;
210
+ break;
211
+ case EVP_PKEY_DSA:
212
+ DSA_get0_key(ptr, &pubkey, NULL);
213
+ if (pubkey)
214
+ return;
215
+ break;
216
+ case EVP_PKEY_DH:
217
+ DH_get0_key(ptr, &pubkey, NULL);
218
+ if (pubkey)
219
+ return;
220
+ break;
221
+ #if !defined(OPENSSL_NO_EC)
222
+ case EVP_PKEY_EC:
223
+ if (EC_KEY_get0_public_key(ptr))
224
+ return;
225
+ break;
226
+ #endif
227
+ default:
228
+ /* unsupported type; assuming ok */
229
+ return;
230
+ }
231
+ ossl_raise(ePKeyError, "public key missing");
232
+ }
233
+
234
+ EVP_PKEY *
235
+ GetPKeyPtr(VALUE obj)
236
+ {
237
+ EVP_PKEY *pkey;
238
+
239
+ GetPKey(obj, pkey);
240
+
241
+ return pkey;
242
+ }
243
+
244
+ EVP_PKEY *
245
+ GetPrivPKeyPtr(VALUE obj)
246
+ {
247
+ EVP_PKEY *pkey;
248
+
249
+ if (rb_funcallv(obj, id_private_q, 0, NULL) != Qtrue) {
250
+ ossl_raise(rb_eArgError, "Private key is needed.");
251
+ }
252
+ GetPKey(obj, pkey);
253
+
254
+ return pkey;
255
+ }
256
+
257
+ EVP_PKEY *
258
+ DupPKeyPtr(VALUE obj)
259
+ {
260
+ EVP_PKEY *pkey;
261
+
262
+ GetPKey(obj, pkey);
263
+ EVP_PKEY_up_ref(pkey);
264
+
265
+ return pkey;
266
+ }
267
+
268
+ /*
269
+ * Private
270
+ */
271
+ static VALUE
272
+ ossl_pkey_alloc(VALUE klass)
273
+ {
274
+ EVP_PKEY *pkey;
275
+ VALUE obj;
276
+
277
+ obj = NewPKey(klass);
278
+ if (!(pkey = EVP_PKEY_new())) {
279
+ ossl_raise(ePKeyError, NULL);
280
+ }
281
+ SetPKey(obj, pkey);
282
+
283
+ return obj;
284
+ }
285
+
286
+ /*
287
+ * call-seq:
288
+ * PKeyClass.new -> self
289
+ *
290
+ * Because PKey is an abstract class, actually calling this method explicitly
291
+ * will raise a NotImplementedError.
292
+ */
293
+ static VALUE
294
+ ossl_pkey_initialize(VALUE self)
295
+ {
296
+ if (rb_obj_is_instance_of(self, cPKey)) {
297
+ ossl_raise(rb_eTypeError, "OpenSSL::PKey::PKey can't be instantiated directly");
298
+ }
299
+ return self;
300
+ }
301
+
302
+ /*
303
+ * call-seq:
304
+ * pkey.oid -> string
305
+ *
306
+ * Returns the short name of the OID associated with _pkey_.
307
+ */
308
+ static VALUE
309
+ ossl_pkey_oid(VALUE self)
310
+ {
311
+ EVP_PKEY *pkey;
312
+ int nid;
313
+
314
+ GetPKey(self, pkey);
315
+ nid = EVP_PKEY_id(pkey);
316
+ return rb_str_new_cstr(OBJ_nid2sn(nid));
317
+ }
318
+
319
+ /*
320
+ * call-seq:
321
+ * pkey.inspect -> string
322
+ *
323
+ * Returns a string describing the PKey object.
324
+ */
325
+ static VALUE
326
+ ossl_pkey_inspect(VALUE self)
327
+ {
328
+ EVP_PKEY *pkey;
329
+ int nid;
330
+
331
+ GetPKey(self, pkey);
332
+ nid = EVP_PKEY_id(pkey);
333
+ return rb_sprintf("#<%"PRIsVALUE":%p oid=%s>",
334
+ rb_class_name(CLASS_OF(self)), (void *)self,
335
+ OBJ_nid2sn(nid));
336
+ }
337
+
338
+ static VALUE
339
+ do_pkcs8_export(int argc, VALUE *argv, VALUE self, int to_der)
340
+ {
341
+ EVP_PKEY *pkey;
342
+ VALUE cipher, pass;
343
+ const EVP_CIPHER *enc = NULL;
344
+ BIO *bio;
345
+
346
+ GetPKey(self, pkey);
347
+ rb_scan_args(argc, argv, "02", &cipher, &pass);
348
+ if (argc > 0) {
349
+ /*
350
+ * TODO: EncryptedPrivateKeyInfo actually has more options.
351
+ * Should they be exposed?
352
+ */
353
+ enc = ossl_evp_get_cipherbyname(cipher);
354
+ pass = ossl_pem_passwd_value(pass);
355
+ }
356
+
357
+ bio = BIO_new(BIO_s_mem());
358
+ if (!bio)
359
+ ossl_raise(ePKeyError, "BIO_new");
360
+ if (to_der) {
361
+ if (!i2d_PKCS8PrivateKey_bio(bio, pkey, enc, NULL, 0,
362
+ ossl_pem_passwd_cb, (void *)pass)) {
363
+ BIO_free(bio);
364
+ ossl_raise(ePKeyError, "i2d_PKCS8PrivateKey_bio");
365
+ }
366
+ }
367
+ else {
368
+ if (!PEM_write_bio_PKCS8PrivateKey(bio, pkey, enc, NULL, 0,
369
+ ossl_pem_passwd_cb, (void *)pass)) {
370
+ BIO_free(bio);
371
+ ossl_raise(ePKeyError, "PEM_write_bio_PKCS8PrivateKey");
372
+ }
373
+ }
374
+ return ossl_membio2str(bio);
375
+ }
376
+
377
+ /*
378
+ * call-seq:
379
+ * pkey.private_to_der -> string
380
+ * pkey.private_to_der(cipher, password) -> string
381
+ *
382
+ * Serializes the private key to DER-encoded PKCS #8 format. If called without
383
+ * arguments, unencrypted PKCS #8 PrivateKeyInfo format is used. If called with
384
+ * a cipher name and a password, PKCS #8 EncryptedPrivateKeyInfo format with
385
+ * PBES2 encryption scheme is used.
386
+ */
387
+ static VALUE
388
+ ossl_pkey_private_to_der(int argc, VALUE *argv, VALUE self)
389
+ {
390
+ return do_pkcs8_export(argc, argv, self, 1);
391
+ }
392
+
393
+ /*
394
+ * call-seq:
395
+ * pkey.private_to_pem -> string
396
+ * pkey.private_to_pem(cipher, password) -> string
397
+ *
398
+ * Serializes the private key to PEM-encoded PKCS #8 format. See #private_to_der
399
+ * for more details.
400
+ */
401
+ static VALUE
402
+ ossl_pkey_private_to_pem(int argc, VALUE *argv, VALUE self)
403
+ {
404
+ return do_pkcs8_export(argc, argv, self, 0);
405
+ }
406
+
407
+ static VALUE
408
+ do_spki_export(VALUE self, int to_der)
409
+ {
410
+ EVP_PKEY *pkey;
411
+ BIO *bio;
412
+
413
+ GetPKey(self, pkey);
414
+ bio = BIO_new(BIO_s_mem());
415
+ if (!bio)
416
+ ossl_raise(ePKeyError, "BIO_new");
417
+ if (to_der) {
418
+ if (!i2d_PUBKEY_bio(bio, pkey)) {
419
+ BIO_free(bio);
420
+ ossl_raise(ePKeyError, "i2d_PUBKEY_bio");
421
+ }
422
+ }
423
+ else {
424
+ if (!PEM_write_bio_PUBKEY(bio, pkey)) {
425
+ BIO_free(bio);
426
+ ossl_raise(ePKeyError, "PEM_write_bio_PUBKEY");
427
+ }
428
+ }
429
+ return ossl_membio2str(bio);
430
+ }
431
+
432
+ /*
433
+ * call-seq:
434
+ * pkey.public_to_der -> string
435
+ *
436
+ * Serializes the public key to DER-encoded X.509 SubjectPublicKeyInfo format.
437
+ */
438
+ static VALUE
439
+ ossl_pkey_public_to_der(VALUE self)
440
+ {
441
+ return do_spki_export(self, 1);
442
+ }
443
+
444
+ /*
445
+ * call-seq:
446
+ * pkey.public_to_pem -> string
447
+ *
448
+ * Serializes the public key to PEM-encoded X.509 SubjectPublicKeyInfo format.
449
+ */
450
+ static VALUE
451
+ ossl_pkey_public_to_pem(VALUE self)
452
+ {
453
+ return do_spki_export(self, 0);
454
+ }
455
+
456
+ /*
457
+ * call-seq:
458
+ * pkey.sign(digest, data) -> String
459
+ *
460
+ * To sign the String _data_, _digest_, an instance of OpenSSL::Digest, must
461
+ * be provided. The return value is again a String containing the signature.
462
+ * A PKeyError is raised should errors occur.
463
+ * Any previous state of the Digest instance is irrelevant to the signature
464
+ * outcome, the digest instance is reset to its initial state during the
465
+ * operation.
466
+ *
467
+ * == Example
468
+ * data = 'Sign me!'
469
+ * digest = OpenSSL::Digest.new('SHA256')
470
+ * pkey = OpenSSL::PKey::RSA.new(2048)
471
+ * signature = pkey.sign(digest, data)
472
+ */
473
+ static VALUE
474
+ ossl_pkey_sign(VALUE self, VALUE digest, VALUE data)
475
+ {
476
+ EVP_PKEY *pkey;
477
+ const EVP_MD *md;
478
+ EVP_MD_CTX *ctx;
479
+ unsigned int buf_len;
480
+ VALUE str;
481
+ int result;
482
+
483
+ pkey = GetPrivPKeyPtr(self);
484
+ md = ossl_evp_get_digestbyname(digest);
485
+ StringValue(data);
486
+ str = rb_str_new(0, EVP_PKEY_size(pkey));
487
+
488
+ ctx = EVP_MD_CTX_new();
489
+ if (!ctx)
490
+ ossl_raise(ePKeyError, "EVP_MD_CTX_new");
491
+ if (!EVP_SignInit_ex(ctx, md, NULL)) {
492
+ EVP_MD_CTX_free(ctx);
493
+ ossl_raise(ePKeyError, "EVP_SignInit_ex");
494
+ }
495
+ if (!EVP_SignUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data))) {
496
+ EVP_MD_CTX_free(ctx);
497
+ ossl_raise(ePKeyError, "EVP_SignUpdate");
498
+ }
499
+ result = EVP_SignFinal(ctx, (unsigned char *)RSTRING_PTR(str), &buf_len, pkey);
500
+ EVP_MD_CTX_free(ctx);
501
+ if (!result)
502
+ ossl_raise(ePKeyError, "EVP_SignFinal");
503
+ rb_str_set_len(str, buf_len);
504
+
505
+ return str;
506
+ }
507
+
508
+ /*
509
+ * call-seq:
510
+ * pkey.verify(digest, signature, data) -> String
511
+ *
512
+ * To verify the String _signature_, _digest_, an instance of
513
+ * OpenSSL::Digest, must be provided to re-compute the message digest of the
514
+ * original _data_, also a String. The return value is +true+ if the
515
+ * signature is valid, +false+ otherwise. A PKeyError is raised should errors
516
+ * occur.
517
+ * Any previous state of the Digest instance is irrelevant to the validation
518
+ * outcome, the digest instance is reset to its initial state during the
519
+ * operation.
520
+ *
521
+ * == Example
522
+ * data = 'Sign me!'
523
+ * digest = OpenSSL::Digest.new('SHA256')
524
+ * pkey = OpenSSL::PKey::RSA.new(2048)
525
+ * signature = pkey.sign(digest, data)
526
+ * pub_key = pkey.public_key
527
+ * puts pub_key.verify(digest, signature, data) # => true
528
+ */
529
+ static VALUE
530
+ ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data)
531
+ {
532
+ EVP_PKEY *pkey;
533
+ const EVP_MD *md;
534
+ EVP_MD_CTX *ctx;
535
+ int siglen, result;
536
+
537
+ GetPKey(self, pkey);
538
+ ossl_pkey_check_public_key(pkey);
539
+ md = ossl_evp_get_digestbyname(digest);
540
+ StringValue(sig);
541
+ siglen = RSTRING_LENINT(sig);
542
+ StringValue(data);
543
+
544
+ ctx = EVP_MD_CTX_new();
545
+ if (!ctx)
546
+ ossl_raise(ePKeyError, "EVP_MD_CTX_new");
547
+ if (!EVP_VerifyInit_ex(ctx, md, NULL)) {
548
+ EVP_MD_CTX_free(ctx);
549
+ ossl_raise(ePKeyError, "EVP_VerifyInit_ex");
550
+ }
551
+ if (!EVP_VerifyUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data))) {
552
+ EVP_MD_CTX_free(ctx);
553
+ ossl_raise(ePKeyError, "EVP_VerifyUpdate");
554
+ }
555
+ result = EVP_VerifyFinal(ctx, (unsigned char *)RSTRING_PTR(sig), siglen, pkey);
556
+ EVP_MD_CTX_free(ctx);
557
+ switch (result) {
558
+ case 0:
559
+ ossl_clear_error();
560
+ return Qfalse;
561
+ case 1:
562
+ return Qtrue;
563
+ default:
564
+ ossl_raise(ePKeyError, "EVP_VerifyFinal");
565
+ }
566
+ }
567
+
568
+ /*
569
+ * INIT
570
+ */
571
+ void
572
+ Init_ossl_pkey(void)
573
+ {
574
+ #undef rb_intern
575
+ #if 0
576
+ mOSSL = rb_define_module("OpenSSL");
577
+ eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
578
+ #endif
579
+
580
+ /* Document-module: OpenSSL::PKey
581
+ *
582
+ * == Asymmetric Public Key Algorithms
583
+ *
584
+ * Asymmetric public key algorithms solve the problem of establishing and
585
+ * sharing secret keys to en-/decrypt messages. The key in such an
586
+ * algorithm consists of two parts: a public key that may be distributed
587
+ * to others and a private key that needs to remain secret.
588
+ *
589
+ * Messages encrypted with a public key can only be decrypted by
590
+ * recipients that are in possession of the associated private key.
591
+ * Since public key algorithms are considerably slower than symmetric
592
+ * key algorithms (cf. OpenSSL::Cipher) they are often used to establish
593
+ * a symmetric key shared between two parties that are in possession of
594
+ * each other's public key.
595
+ *
596
+ * Asymmetric algorithms offer a lot of nice features that are used in a
597
+ * lot of different areas. A very common application is the creation and
598
+ * validation of digital signatures. To sign a document, the signatory
599
+ * generally uses a message digest algorithm (cf. OpenSSL::Digest) to
600
+ * compute a digest of the document that is then encrypted (i.e. signed)
601
+ * using the private key. Anyone in possession of the public key may then
602
+ * verify the signature by computing the message digest of the original
603
+ * document on their own, decrypting the signature using the signatory's
604
+ * public key and comparing the result to the message digest they
605
+ * previously computed. The signature is valid if and only if the
606
+ * decrypted signature is equal to this message digest.
607
+ *
608
+ * The PKey module offers support for three popular public/private key
609
+ * algorithms:
610
+ * * RSA (OpenSSL::PKey::RSA)
611
+ * * DSA (OpenSSL::PKey::DSA)
612
+ * * Elliptic Curve Cryptography (OpenSSL::PKey::EC)
613
+ * Each of these implementations is in fact a sub-class of the abstract
614
+ * PKey class which offers the interface for supporting digital signatures
615
+ * in the form of PKey#sign and PKey#verify.
616
+ *
617
+ * == Diffie-Hellman Key Exchange
618
+ *
619
+ * Finally PKey also features OpenSSL::PKey::DH, an implementation of
620
+ * the Diffie-Hellman key exchange protocol based on discrete logarithms
621
+ * in finite fields, the same basis that DSA is built on.
622
+ * The Diffie-Hellman protocol can be used to exchange (symmetric) keys
623
+ * over insecure channels without needing any prior joint knowledge
624
+ * between the participating parties. As the security of DH demands
625
+ * relatively long "public keys" (i.e. the part that is overtly
626
+ * transmitted between participants) DH tends to be quite slow. If
627
+ * security or speed is your primary concern, OpenSSL::PKey::EC offers
628
+ * another implementation of the Diffie-Hellman protocol.
629
+ *
630
+ */
631
+ mPKey = rb_define_module_under(mOSSL, "PKey");
632
+
633
+ /* Document-class: OpenSSL::PKey::PKeyError
634
+ *
635
+ *Raised when errors occur during PKey#sign or PKey#verify.
636
+ */
637
+ ePKeyError = rb_define_class_under(mPKey, "PKeyError", eOSSLError);
638
+
639
+ /* Document-class: OpenSSL::PKey::PKey
640
+ *
641
+ * An abstract class that bundles signature creation (PKey#sign) and
642
+ * validation (PKey#verify) that is common to all implementations except
643
+ * OpenSSL::PKey::DH
644
+ * * OpenSSL::PKey::RSA
645
+ * * OpenSSL::PKey::DSA
646
+ * * OpenSSL::PKey::EC
647
+ */
648
+ cPKey = rb_define_class_under(mPKey, "PKey", rb_cObject);
649
+
650
+ rb_define_module_function(mPKey, "read", ossl_pkey_new_from_data, -1);
651
+
652
+ rb_define_alloc_func(cPKey, ossl_pkey_alloc);
653
+ rb_define_method(cPKey, "initialize", ossl_pkey_initialize, 0);
654
+ rb_define_method(cPKey, "oid", ossl_pkey_oid, 0);
655
+ rb_define_method(cPKey, "inspect", ossl_pkey_inspect, 0);
656
+ rb_define_method(cPKey, "private_to_der", ossl_pkey_private_to_der, -1);
657
+ rb_define_method(cPKey, "private_to_pem", ossl_pkey_private_to_pem, -1);
658
+ rb_define_method(cPKey, "public_to_der", ossl_pkey_public_to_der, 0);
659
+ rb_define_method(cPKey, "public_to_pem", ossl_pkey_public_to_pem, 0);
660
+
661
+ rb_define_method(cPKey, "sign", ossl_pkey_sign, 2);
662
+ rb_define_method(cPKey, "verify", ossl_pkey_verify, 3);
663
+
664
+ id_private_q = rb_intern("private?");
665
+
666
+ /*
667
+ * INIT rsa, dsa, dh, ec
668
+ */
669
+ Init_ossl_rsa();
670
+ Init_ossl_dsa();
671
+ Init_ossl_dh();
672
+ Init_ossl_ec();
673
+ }