rubysl-openssl 1.0.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +5 -6
  3. data/ext/rubysl/openssl/.gitignore +3 -0
  4. data/ext/rubysl/openssl/deprecation.rb +21 -0
  5. data/ext/rubysl/openssl/extconf.rb +45 -32
  6. data/ext/rubysl/openssl/openssl_missing.c +20 -7
  7. data/ext/rubysl/openssl/openssl_missing.h +22 -15
  8. data/ext/rubysl/openssl/ossl.c +610 -61
  9. data/ext/rubysl/openssl/ossl.h +31 -17
  10. data/ext/rubysl/openssl/ossl_asn1.c +974 -183
  11. data/ext/rubysl/openssl/ossl_asn1.h +3 -3
  12. data/ext/rubysl/openssl/ossl_bio.c +4 -3
  13. data/ext/rubysl/openssl/ossl_bio.h +1 -1
  14. data/ext/rubysl/openssl/ossl_bn.c +32 -28
  15. data/ext/rubysl/openssl/ossl_bn.h +1 -1
  16. data/ext/rubysl/openssl/ossl_cipher.c +494 -93
  17. data/ext/rubysl/openssl/ossl_cipher.h +1 -1
  18. data/ext/rubysl/openssl/ossl_config.c +4 -5
  19. data/ext/rubysl/openssl/ossl_config.h +1 -1
  20. data/ext/rubysl/openssl/ossl_digest.c +206 -24
  21. data/ext/rubysl/openssl/ossl_digest.h +1 -1
  22. data/ext/rubysl/openssl/ossl_engine.c +48 -26
  23. data/ext/rubysl/openssl/ossl_engine.h +1 -1
  24. data/ext/rubysl/openssl/ossl_hmac.c +40 -38
  25. data/ext/rubysl/openssl/ossl_hmac.h +1 -1
  26. data/ext/rubysl/openssl/ossl_ns_spki.c +157 -25
  27. data/ext/rubysl/openssl/ossl_ns_spki.h +1 -1
  28. data/ext/rubysl/openssl/ossl_ocsp.c +57 -40
  29. data/ext/rubysl/openssl/ossl_ocsp.h +1 -1
  30. data/ext/rubysl/openssl/ossl_pkcs12.c +15 -13
  31. data/ext/rubysl/openssl/ossl_pkcs12.h +1 -1
  32. data/ext/rubysl/openssl/ossl_pkcs5.c +108 -18
  33. data/ext/rubysl/openssl/ossl_pkcs7.c +44 -37
  34. data/ext/rubysl/openssl/ossl_pkcs7.h +1 -1
  35. data/ext/rubysl/openssl/ossl_pkey.c +211 -15
  36. data/ext/rubysl/openssl/ossl_pkey.h +19 -9
  37. data/ext/rubysl/openssl/ossl_pkey_dh.c +180 -47
  38. data/ext/rubysl/openssl/ossl_pkey_dsa.c +184 -47
  39. data/ext/rubysl/openssl/ossl_pkey_ec.c +177 -93
  40. data/ext/rubysl/openssl/ossl_pkey_rsa.c +209 -102
  41. data/ext/rubysl/openssl/ossl_rand.c +15 -15
  42. data/ext/rubysl/openssl/ossl_rand.h +1 -1
  43. data/ext/rubysl/openssl/ossl_ssl.c +939 -192
  44. data/ext/rubysl/openssl/ossl_ssl.h +6 -6
  45. data/ext/rubysl/openssl/ossl_ssl_session.c +78 -62
  46. data/ext/rubysl/openssl/ossl_version.h +2 -2
  47. data/ext/rubysl/openssl/ossl_x509.c +1 -1
  48. data/ext/rubysl/openssl/ossl_x509.h +1 -1
  49. data/ext/rubysl/openssl/ossl_x509attr.c +20 -19
  50. data/ext/rubysl/openssl/ossl_x509cert.c +169 -67
  51. data/ext/rubysl/openssl/ossl_x509crl.c +41 -39
  52. data/ext/rubysl/openssl/ossl_x509ext.c +51 -38
  53. data/ext/rubysl/openssl/ossl_x509name.c +139 -29
  54. data/ext/rubysl/openssl/ossl_x509req.c +42 -40
  55. data/ext/rubysl/openssl/ossl_x509revoked.c +20 -20
  56. data/ext/rubysl/openssl/ossl_x509store.c +99 -47
  57. data/ext/rubysl/openssl/ruby_missing.h +3 -16
  58. data/lib/openssl/bn.rb +19 -19
  59. data/lib/openssl/buffering.rb +222 -14
  60. data/lib/openssl/cipher.rb +20 -20
  61. data/lib/openssl/config.rb +1 -4
  62. data/lib/openssl/digest.rb +47 -19
  63. data/lib/openssl/ssl.rb +197 -1
  64. data/lib/openssl/x509.rb +162 -1
  65. data/lib/rubysl/openssl.rb +4 -8
  66. data/lib/rubysl/openssl/version.rb +1 -1
  67. data/rubysl-openssl.gemspec +1 -2
  68. metadata +16 -34
  69. data/ext/rubysl/openssl/extconf.h +0 -50
  70. data/lib/openssl/net/ftptls.rb +0 -53
  71. data/lib/openssl/net/telnets.rb +0 -251
  72. data/lib/openssl/pkcs7.rb +0 -25
  73. data/lib/openssl/ssl-internal.rb +0 -187
  74. data/lib/openssl/x509-internal.rb +0 -153
@@ -1,5 +1,5 @@
1
1
  /*
2
- * $Id: ossl_pkey_dsa.c 28004 2010-05-24 23:58:49Z shyouhei $
2
+ * $Id$
3
3
  * 'OpenSSL for Ruby' project
4
4
  * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
5
5
  * All rights reserved.
@@ -13,8 +13,8 @@
13
13
  #include "ossl.h"
14
14
 
15
15
  #define GetPKeyDSA(obj, pkey) do { \
16
- GetPKey(obj, pkey); \
17
- if (EVP_PKEY_type(pkey->type) != EVP_PKEY_DSA) { /* PARANOIA? */ \
16
+ GetPKey((obj), (pkey)); \
17
+ if (EVP_PKEY_type((pkey)->type) != EVP_PKEY_DSA) { /* PARANOIA? */ \
18
18
  ossl_raise(rb_eRuntimeError, "THIS IS NOT A DSA!"); \
19
19
  } \
20
20
  } while (0)
@@ -36,7 +36,7 @@ dsa_instance(VALUE klass, DSA *dsa)
36
36
  {
37
37
  EVP_PKEY *pkey;
38
38
  VALUE obj;
39
-
39
+
40
40
  if (!dsa) {
41
41
  return Qfalse;
42
42
  }
@@ -75,9 +75,69 @@ ossl_dsa_new(EVP_PKEY *pkey)
75
75
  /*
76
76
  * Private
77
77
  */
78
+ #if defined(HAVE_DSA_GENERATE_PARAMETERS_EX) && HAVE_BN_GENCB
79
+ struct dsa_blocking_gen_arg {
80
+ DSA *dsa;
81
+ int size;
82
+ unsigned char* seed;
83
+ int seed_len;
84
+ int *counter;
85
+ unsigned long *h;
86
+ BN_GENCB *cb;
87
+ int result;
88
+ };
89
+
90
+ static void *
91
+ dsa_blocking_gen(void *arg)
92
+ {
93
+ struct dsa_blocking_gen_arg *gen = (struct dsa_blocking_gen_arg *)arg;
94
+ gen->result = DSA_generate_parameters_ex(gen->dsa, gen->size, gen->seed, gen->seed_len, gen->counter, gen->h, gen->cb);
95
+ return 0;
96
+ }
97
+ #endif
98
+
78
99
  static DSA *
79
100
  dsa_generate(int size)
80
101
  {
102
+ #if defined(HAVE_DSA_GENERATE_PARAMETERS_EX) && HAVE_BN_GENCB
103
+ BN_GENCB cb;
104
+ struct ossl_generate_cb_arg cb_arg;
105
+ struct dsa_blocking_gen_arg gen_arg;
106
+ DSA *dsa = DSA_new();
107
+ unsigned char seed[20];
108
+ int seed_len = 20, counter;
109
+ unsigned long h;
110
+
111
+ if (!dsa) return 0;
112
+ if (!RAND_bytes(seed, seed_len)) {
113
+ DSA_free(dsa);
114
+ return 0;
115
+ }
116
+
117
+ memset(&cb_arg, 0, sizeof(struct ossl_generate_cb_arg));
118
+ if (rb_block_given_p())
119
+ cb_arg.yield = 1;
120
+ BN_GENCB_set(&cb, ossl_generate_cb_2, &cb_arg);
121
+ gen_arg.dsa = dsa;
122
+ gen_arg.size = size;
123
+ gen_arg.seed = seed;
124
+ gen_arg.seed_len = seed_len;
125
+ gen_arg.counter = &counter;
126
+ gen_arg.h = &h;
127
+ gen_arg.cb = &cb;
128
+ if (cb_arg.yield == 1) {
129
+ /* we cannot release GVL when callback proc is supplied */
130
+ dsa_blocking_gen(&gen_arg);
131
+ } else {
132
+ /* there's a chance to unblock */
133
+ rb_thread_call_without_gvl(dsa_blocking_gen, &gen_arg, ossl_generate_cb_stop, &cb_arg);
134
+ }
135
+ if (!gen_arg.result) {
136
+ DSA_free(dsa);
137
+ if (cb_arg.state) rb_jump_tag(cb_arg.state);
138
+ return 0;
139
+ }
140
+ #else
81
141
  DSA *dsa;
82
142
  unsigned char seed[20];
83
143
  int seed_len = 20, counter;
@@ -87,9 +147,9 @@ dsa_generate(int size)
87
147
  return 0;
88
148
  }
89
149
  dsa = DSA_generate_parameters(size, seed, seed_len, &counter, &h,
90
- rb_block_given_p() ? ossl_generate_cb : NULL,
91
- NULL);
150
+ rb_block_given_p() ? ossl_generate_cb : NULL, NULL);
92
151
  if(!dsa) return 0;
152
+ #endif
93
153
 
94
154
  if (!DSA_generate_key(dsa)) {
95
155
  DSA_free(dsa);
@@ -103,8 +163,11 @@ dsa_generate(int size)
103
163
  * call-seq:
104
164
  * DSA.generate(size) -> dsa
105
165
  *
106
- * === Parameters
107
- * * +size+ is an integer representing the desired key size.
166
+ * Creates a new DSA instance by generating a private/public key pair
167
+ * from scratch.
168
+ *
169
+ * === Parameters
170
+ * * +size+ is an integer representing the desired key size.
108
171
  *
109
172
  */
110
173
  static VALUE
@@ -125,16 +188,18 @@ ossl_dsa_s_generate(VALUE klass, VALUE size)
125
188
  * call-seq:
126
189
  * DSA.new([size | string [, pass]) -> dsa
127
190
  *
128
- * === Parameters
129
- * * +size+ is an integer representing the desired key size.
130
- * * +string+ contains a DER or PEM encoded key.
131
- * * +pass+ is a string that contains a optional password.
191
+ * Creates a new DSA instance by reading an existing key from +string+.
132
192
  *
133
- * === Examples
134
- * * DSA.new -> dsa
135
- * * DSA.new(1024) -> dsa
136
- * * DSA.new(File.read('dsa.pem')) -> dsa
137
- * * DSA.new(File.read('dsa.pem'), 'mypassword') -> dsa
193
+ * === Parameters
194
+ * * +size+ is an integer representing the desired key size.
195
+ * * +string+ contains a DER or PEM encoded key.
196
+ * * +pass+ is a string that contains an optional password.
197
+ *
198
+ * === Examples
199
+ * DSA.new -> dsa
200
+ * DSA.new(1024) -> dsa
201
+ * DSA.new(File.read('dsa.pem')) -> dsa
202
+ * DSA.new(File.read('dsa.pem'), 'mypassword') -> dsa
138
203
  *
139
204
  */
140
205
  static VALUE
@@ -145,7 +210,7 @@ ossl_dsa_initialize(int argc, VALUE *argv, VALUE self)
145
210
  BIO *in;
146
211
  char *passwd = NULL;
147
212
  VALUE arg, pass;
148
-
213
+
149
214
  GetPKey(self, pkey);
150
215
  if(rb_scan_args(argc, argv, "02", &arg, &pass) == 0) {
151
216
  dsa = DSA_new();
@@ -161,23 +226,26 @@ ossl_dsa_initialize(int argc, VALUE *argv, VALUE self)
161
226
  in = ossl_obj2bio(arg);
162
227
  dsa = PEM_read_bio_DSAPrivateKey(in, NULL, ossl_pem_passwd_cb, passwd);
163
228
  if (!dsa) {
164
- BIO_reset(in);
165
- dsa = PEM_read_bio_DSAPublicKey(in, NULL, NULL, NULL);
166
- }
167
- if (!dsa) {
168
- BIO_reset(in);
229
+ OSSL_BIO_reset(in);
169
230
  dsa = PEM_read_bio_DSA_PUBKEY(in, NULL, NULL, NULL);
170
231
  }
171
232
  if (!dsa) {
172
- BIO_reset(in);
233
+ OSSL_BIO_reset(in);
173
234
  dsa = d2i_DSAPrivateKey_bio(in, NULL);
174
235
  }
175
236
  if (!dsa) {
176
- BIO_reset(in);
237
+ OSSL_BIO_reset(in);
177
238
  dsa = d2i_DSA_PUBKEY_bio(in, NULL);
178
239
  }
240
+ if (!dsa) {
241
+ OSSL_BIO_reset(in);
242
+ dsa = PEM_read_bio_DSAPublicKey(in, NULL, NULL, NULL);
243
+ }
179
244
  BIO_free(in);
180
- if (!dsa) ossl_raise(eDSAError, "Neither PUB key nor PRIV key:");
245
+ if (!dsa) {
246
+ ERR_clear_error();
247
+ ossl_raise(eDSAError, "Neither PUB key nor PRIV key");
248
+ }
181
249
  }
182
250
  if (!EVP_PKEY_assign_DSA(pkey, dsa)) {
183
251
  DSA_free(dsa);
@@ -191,6 +259,8 @@ ossl_dsa_initialize(int argc, VALUE *argv, VALUE self)
191
259
  * call-seq:
192
260
  * dsa.public? -> true | false
193
261
  *
262
+ * Indicates whether this DSA instance has a public key associated with it or
263
+ * not. The public key may be retrieved with DSA#public_key.
194
264
  */
195
265
  static VALUE
196
266
  ossl_dsa_is_public(VALUE self)
@@ -206,14 +276,16 @@ ossl_dsa_is_public(VALUE self)
206
276
  * call-seq:
207
277
  * dsa.private? -> true | false
208
278
  *
279
+ * Indicates whether this DSA instance has a private key associated with it or
280
+ * not. The private key may be retrieved with DSA#private_key.
209
281
  */
210
282
  static VALUE
211
283
  ossl_dsa_is_private(VALUE self)
212
284
  {
213
285
  EVP_PKEY *pkey;
214
-
286
+
215
287
  GetPKeyDSA(self, pkey);
216
-
288
+
217
289
  return (DSA_PRIVATE(self, pkey->pkey.dsa)) ? Qtrue : Qfalse;
218
290
  }
219
291
 
@@ -221,13 +293,15 @@ ossl_dsa_is_private(VALUE self)
221
293
  * call-seq:
222
294
  * dsa.to_pem([cipher, password]) -> aString
223
295
  *
224
- * === Parameters
225
- * +cipher+ is an OpenSSL::Cipher.
226
- * +password+ is a string containing your password.
296
+ * Encodes this DSA to its PEM encoding.
227
297
  *
228
- * === Examples
229
- * * DSA.to_pem -> aString
230
- * * DSA.to_pem(cipher, 'mypassword') -> aString
298
+ * === Parameters
299
+ * * +cipher+ is an OpenSSL::Cipher.
300
+ * * +password+ is a string containing your password.
301
+ *
302
+ * === Examples
303
+ * DSA.to_pem -> aString
304
+ * DSA.to_pem(cipher, 'mypassword') -> aString
231
305
  *
232
306
  */
233
307
  static VALUE
@@ -244,7 +318,10 @@ ossl_dsa_export(int argc, VALUE *argv, VALUE self)
244
318
  if (!NIL_P(cipher)) {
245
319
  ciph = GetCipherPtr(cipher);
246
320
  if (!NIL_P(pass)) {
247
- passwd = StringValuePtr(pass);
321
+ StringValue(pass);
322
+ if (RSTRING_LENINT(pass) < OSSL_MIN_PWD_LEN)
323
+ ossl_raise(eOSSLError, "OpenSSL requires passwords to be at least four characters long");
324
+ passwd = RSTRING_PTR(pass);
248
325
  }
249
326
  }
250
327
  if (!(out = BIO_new(BIO_s_mem()))) {
@@ -257,7 +334,7 @@ ossl_dsa_export(int argc, VALUE *argv, VALUE self)
257
334
  ossl_raise(eDSAError, NULL);
258
335
  }
259
336
  } else {
260
- if (!PEM_write_bio_DSAPublicKey(out, pkey->pkey.dsa)) {
337
+ if (!PEM_write_bio_DSA_PUBKEY(out, pkey->pkey.dsa)) {
261
338
  BIO_free(out);
262
339
  ossl_raise(eDSAError, NULL);
263
340
  }
@@ -271,6 +348,8 @@ ossl_dsa_export(int argc, VALUE *argv, VALUE self)
271
348
  * call-seq:
272
349
  * dsa.to_der -> aString
273
350
  *
351
+ * Encodes this DSA to its DER encoding.
352
+ *
274
353
  */
275
354
  static VALUE
276
355
  ossl_dsa_to_der(VALUE self)
@@ -289,7 +368,7 @@ ossl_dsa_to_der(VALUE self)
289
368
  if((len = i2d_func(pkey->pkey.dsa, NULL)) <= 0)
290
369
  ossl_raise(eDSAError, NULL);
291
370
  str = rb_str_new(0, len);
292
- p = RSTRING_PTR(str);
371
+ p = (unsigned char *)RSTRING_PTR(str);
293
372
  if(i2d_func(pkey->pkey.dsa, &p) < 0)
294
373
  ossl_raise(eDSAError, NULL);
295
374
  ossl_str_adjust(str, p);
@@ -320,7 +399,7 @@ ossl_dsa_get_params(VALUE self)
320
399
  rb_hash_aset(hash, rb_str_new2("g"), ossl_bn_new(pkey->pkey.dsa->g));
321
400
  rb_hash_aset(hash, rb_str_new2("pub_key"), ossl_bn_new(pkey->pkey.dsa->pub_key));
322
401
  rb_hash_aset(hash, rb_str_new2("priv_key"), ossl_bn_new(pkey->pkey.dsa->priv_key));
323
-
402
+
324
403
  return hash;
325
404
  }
326
405
 
@@ -356,7 +435,18 @@ ossl_dsa_to_text(VALUE self)
356
435
  * call-seq:
357
436
  * dsa.public_key -> aDSA
358
437
  *
359
- * Makes new instance DSA PUBLIC_KEY from PRIVATE_KEY
438
+ * Returns a new DSA instance that carries just the public key information.
439
+ * If the current instance has also private key information, this will no
440
+ * longer be present in the new instance. This feature is helpful for
441
+ * publishing the public key information without leaking any of the private
442
+ * information.
443
+ *
444
+ * === Example
445
+ * dsa = OpenSSL::PKey::DSA.new(2048) # has public and private information
446
+ * pub_key = dsa.public_key # has only the public part available
447
+ * pub_key_der = pub_key.to_der # it's safe to publish this
448
+ *
449
+ *
360
450
  */
361
451
  static VALUE
362
452
  ossl_dsa_to_public_key(VALUE self)
@@ -364,7 +454,7 @@ ossl_dsa_to_public_key(VALUE self)
364
454
  EVP_PKEY *pkey;
365
455
  DSA *dsa;
366
456
  VALUE obj;
367
-
457
+
368
458
  GetPKeyDSA(self, pkey);
369
459
  /* err check performed by dsa_instance */
370
460
  dsa = DSAPublicKey_dup(pkey->pkey.dsa);
@@ -382,12 +472,26 @@ ossl_dsa_to_public_key(VALUE self)
382
472
  * call-seq:
383
473
  * dsa.syssign(string) -> aString
384
474
  *
475
+ * Computes and returns the DSA signature of +string+, where +string+ is
476
+ * expected to be an already-computed message digest of the original input
477
+ * data. The signature is issued using the private key of this DSA instance.
478
+ *
479
+ * === Parameters
480
+ * * +string+ is a message digest of the original input data to be signed
481
+ *
482
+ * === Example
483
+ * dsa = OpenSSL::PKey::DSA.new(2048)
484
+ * doc = "Sign me"
485
+ * digest = OpenSSL::Digest::SHA1.digest(doc)
486
+ * sig = dsa.syssign(digest)
487
+ *
488
+ *
385
489
  */
386
490
  static VALUE
387
491
  ossl_dsa_sign(VALUE self, VALUE data)
388
492
  {
389
493
  EVP_PKEY *pkey;
390
- int buf_len;
494
+ unsigned int buf_len;
391
495
  VALUE str;
392
496
 
393
497
  GetPKeyDSA(self, pkey);
@@ -396,7 +500,8 @@ ossl_dsa_sign(VALUE self, VALUE data)
396
500
  ossl_raise(eDSAError, "Private DSA key needed!");
397
501
  }
398
502
  str = rb_str_new(0, ossl_dsa_buf_size(pkey));
399
- if (!DSA_sign(0, RSTRING_PTR(data), RSTRING_LEN(data), RSTRING_PTR(str),
503
+ if (!DSA_sign(0, (unsigned char *)RSTRING_PTR(data), RSTRING_LENINT(data),
504
+ (unsigned char *)RSTRING_PTR(str),
400
505
  &buf_len, pkey->pkey.dsa)) { /* type is ignored (0) */
401
506
  ossl_raise(eDSAError, NULL);
402
507
  }
@@ -409,6 +514,20 @@ ossl_dsa_sign(VALUE self, VALUE data)
409
514
  * call-seq:
410
515
  * dsa.sysverify(digest, sig) -> true | false
411
516
  *
517
+ * Verifies whether the signature is valid given the message digest input. It
518
+ * does so by validating +sig+ using the public key of this DSA instance.
519
+ *
520
+ * === Parameters
521
+ * * +digest+ is a message digest of the original input data to be signed
522
+ * * +sig+ is a DSA signature value
523
+ *
524
+ * === Example
525
+ * dsa = OpenSSL::PKey::DSA.new(2048)
526
+ * doc = "Sign me"
527
+ * digest = OpenSSL::Digest::SHA1.digest(doc)
528
+ * sig = dsa.syssign(digest)
529
+ * puts dsa.sysverify(digest, sig) # => true
530
+ *
412
531
  */
413
532
  static VALUE
414
533
  ossl_dsa_verify(VALUE self, VALUE digest, VALUE sig)
@@ -420,8 +539,8 @@ ossl_dsa_verify(VALUE self, VALUE digest, VALUE sig)
420
539
  StringValue(digest);
421
540
  StringValue(sig);
422
541
  /* type is ignored (0) */
423
- ret = DSA_verify(0, RSTRING_PTR(digest), RSTRING_LEN(digest),
424
- RSTRING_PTR(sig), RSTRING_LEN(sig), pkey->pkey.dsa);
542
+ ret = DSA_verify(0, (unsigned char *)RSTRING_PTR(digest), RSTRING_LENINT(digest),
543
+ (unsigned char *)RSTRING_PTR(sig), RSTRING_LENINT(sig), pkey->pkey.dsa);
425
544
  if (ret < 0) {
426
545
  ossl_raise(eDSAError, NULL);
427
546
  }
@@ -444,15 +563,33 @@ OSSL_PKEY_BN(dsa, priv_key)
444
563
  void
445
564
  Init_ossl_dsa()
446
565
  {
447
- #if 0 /* let rdoc know about mOSSL and mPKey */
448
- mOSSL = rb_define_module("OpenSSL");
566
+ #if 0
567
+ mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL and mPKey */
449
568
  mPKey = rb_define_module_under(mOSSL, "PKey");
450
569
  #endif
451
570
 
571
+ /* Document-class: OpenSSL::PKey::DSAError
572
+ *
573
+ * Generic exception that is raised if an operation on a DSA PKey
574
+ * fails unexpectedly or in case an instantiation of an instance of DSA
575
+ * fails due to non-conformant input data.
576
+ */
452
577
  eDSAError = rb_define_class_under(mPKey, "DSAError", ePKeyError);
453
578
 
579
+ /* Document-class: OpenSSL::PKey::DSA
580
+ *
581
+ * DSA, the Digital Signature Algorithm, is specified in NIST's
582
+ * FIPS 186-3. It is an asymmetric public key algorithm that may be used
583
+ * similar to e.g. RSA.
584
+ * Please note that for OpenSSL versions prior to 1.0.0 the digest
585
+ * algorithms OpenSSL::Digest::DSS (equivalent to SHA) or
586
+ * OpenSSL::Digest::DSS1 (equivalent to SHA-1) must be used for issuing
587
+ * signatures with a DSA key using OpenSSL::PKey#sign.
588
+ * Starting with OpenSSL 1.0.0, digest algorithms are no longer restricted,
589
+ * any Digest may be used for signing.
590
+ */
454
591
  cDSA = rb_define_class_under(mPKey, "DSA", cPKey);
455
-
592
+
456
593
  rb_define_singleton_method(cDSA, "generate", ossl_dsa_s_generate, 1);
457
594
  rb_define_method(cDSA, "initialize", ossl_dsa_initialize, -1);
458
595
 
@@ -22,70 +22,70 @@ typedef struct {
22
22
 
23
23
 
24
24
  #define GetPKeyEC(obj, pkey) do { \
25
- GetPKey(obj, pkey); \
26
- if (EVP_PKEY_type(pkey->type) != EVP_PKEY_EC) { \
25
+ GetPKey((obj), (pkey)); \
26
+ if (EVP_PKEY_type((pkey)->type) != EVP_PKEY_EC) { \
27
27
  ossl_raise(rb_eRuntimeError, "THIS IS NOT A EC PKEY!"); \
28
28
  } \
29
29
  } while (0)
30
30
 
31
31
  #define SafeGet_ec_group(obj, group) do { \
32
- OSSL_Check_Kind(obj, cEC_GROUP); \
33
- Data_Get_Struct(obj, ossl_ec_group, group); \
32
+ OSSL_Check_Kind((obj), cEC_GROUP); \
33
+ Data_Get_Struct((obj), ossl_ec_group, (group)); \
34
34
  } while(0)
35
35
 
36
36
  #define Get_EC_KEY(obj, key) do { \
37
37
  EVP_PKEY *pkey; \
38
- GetPKeyEC(obj, pkey); \
39
- key = pkey->pkey.ec; \
38
+ GetPKeyEC((obj), pkey); \
39
+ (key) = pkey->pkey.ec; \
40
40
  } while(0)
41
41
 
42
42
  #define Require_EC_KEY(obj, key) do { \
43
- Get_EC_KEY(obj, key); \
44
- if (key == NULL) \
45
- rb_raise(eECError, "EC_KEY is not initialized"); \
43
+ Get_EC_KEY((obj), (key)); \
44
+ if ((key) == NULL) \
45
+ ossl_raise(eECError, "EC_KEY is not initialized"); \
46
46
  } while(0)
47
47
 
48
48
  #define SafeRequire_EC_KEY(obj, key) do { \
49
- OSSL_Check_Kind(obj, cEC); \
50
- Require_EC_KEY(obj, key); \
49
+ OSSL_Check_Kind((obj), cEC); \
50
+ Require_EC_KEY((obj), (key)); \
51
51
  } while (0)
52
52
 
53
53
  #define Get_EC_GROUP(obj, g) do { \
54
54
  ossl_ec_group *ec_group; \
55
- Data_Get_Struct(obj, ossl_ec_group, ec_group); \
55
+ Data_Get_Struct((obj), ossl_ec_group, ec_group); \
56
56
  if (ec_group == NULL) \
57
- rb_raise(eEC_GROUP, "missing ossl_ec_group structure"); \
58
- g = ec_group->group; \
57
+ ossl_raise(eEC_GROUP, "missing ossl_ec_group structure"); \
58
+ (g) = ec_group->group; \
59
59
  } while(0)
60
60
 
61
61
  #define Require_EC_GROUP(obj, group) do { \
62
- Get_EC_GROUP(obj, group); \
63
- if (group == NULL) \
64
- rb_raise(eEC_GROUP, "EC_GROUP is not initialized"); \
62
+ Get_EC_GROUP((obj), (group)); \
63
+ if ((group) == NULL) \
64
+ ossl_raise(eEC_GROUP, "EC_GROUP is not initialized"); \
65
65
  } while(0)
66
66
 
67
67
  #define SafeRequire_EC_GROUP(obj, group) do { \
68
- OSSL_Check_Kind(obj, cEC_GROUP); \
69
- Require_EC_GROUP(obj, group); \
68
+ OSSL_Check_Kind((obj), cEC_GROUP); \
69
+ Require_EC_GROUP((obj), (group)); \
70
70
  } while(0)
71
71
 
72
72
  #define Get_EC_POINT(obj, p) do { \
73
73
  ossl_ec_point *ec_point; \
74
- Data_Get_Struct(obj, ossl_ec_point, ec_point); \
74
+ Data_Get_Struct((obj), ossl_ec_point, ec_point); \
75
75
  if (ec_point == NULL) \
76
- rb_raise(eEC_POINT, "missing ossl_ec_point structure"); \
77
- p = ec_point->point; \
76
+ ossl_raise(eEC_POINT, "missing ossl_ec_point structure"); \
77
+ (p) = ec_point->point; \
78
78
  } while(0)
79
79
 
80
80
  #define Require_EC_POINT(obj, point) do { \
81
- Get_EC_POINT(obj, point); \
82
- if (point == NULL) \
83
- rb_raise(eEC_POINT, "EC_POINT is not initialized"); \
81
+ Get_EC_POINT((obj), (point)); \
82
+ if ((point) == NULL) \
83
+ ossl_raise(eEC_POINT, "EC_POINT is not initialized"); \
84
84
  } while(0)
85
85
 
86
86
  #define SafeRequire_EC_POINT(obj, point) do { \
87
- OSSL_Check_Kind(obj, cEC_POINT); \
88
- Require_EC_POINT(obj, point); \
87
+ OSSL_Check_Kind((obj), cEC_POINT); \
88
+ Require_EC_POINT((obj), (point)); \
89
89
  } while(0)
90
90
 
91
91
  VALUE cEC;
@@ -110,7 +110,7 @@ static VALUE ec_instance(VALUE klass, EC_KEY *ec)
110
110
  {
111
111
  EVP_PKEY *pkey;
112
112
  VALUE obj;
113
-
113
+
114
114
  if (!ec) {
115
115
  return Qfalse;
116
116
  }
@@ -152,6 +152,7 @@ VALUE ossl_ec_new(EVP_PKEY *pkey)
152
152
  * OpenSSL::PKey::EC.new(ec_group)
153
153
  * OpenSSL::PKey::EC.new("secp112r1")
154
154
  * OpenSSL::PKey::EC.new(pem_string)
155
+ * OpenSSL::PKey::EC.new(pem_string [, pwd])
155
156
  * OpenSSL::PKey::EC.new(der_string)
156
157
  *
157
158
  * See the OpenSSL documentation for:
@@ -163,10 +164,11 @@ static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self)
163
164
  EC_KEY *ec = NULL;
164
165
  VALUE arg, pass;
165
166
  VALUE group = Qnil;
166
-
167
+ char *passwd = NULL;
168
+
167
169
  GetPKey(self, pkey);
168
170
  if (pkey->pkey.ec)
169
- rb_raise(eECError, "EC_KEY already initialized");
171
+ ossl_raise(eECError, "EC_KEY already initialized");
170
172
 
171
173
  rb_scan_args(argc, argv, "02", &arg, &pass);
172
174
 
@@ -184,26 +186,30 @@ static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self)
184
186
  } else {
185
187
  BIO *in = ossl_obj2bio(arg);
186
188
 
187
- ec = PEM_read_bio_ECPrivateKey(in, NULL, NULL, NULL);
189
+ if (!NIL_P(pass)) {
190
+ passwd = StringValuePtr(pass);
191
+ }
192
+ ec = PEM_read_bio_ECPrivateKey(in, NULL, ossl_pem_passwd_cb, passwd);
188
193
  if (!ec) {
189
- BIO_reset(in);
190
- ec = PEM_read_bio_EC_PUBKEY(in, NULL, NULL, NULL);
194
+ OSSL_BIO_reset(in);
195
+ ec = PEM_read_bio_EC_PUBKEY(in, NULL, ossl_pem_passwd_cb, passwd);
191
196
  }
192
197
  if (!ec) {
193
- BIO_reset(in);
198
+ OSSL_BIO_reset(in);
194
199
  ec = d2i_ECPrivateKey_bio(in, NULL);
195
200
  }
196
201
  if (!ec) {
197
- BIO_reset(in);
202
+ OSSL_BIO_reset(in);
198
203
  ec = d2i_EC_PUBKEY_bio(in, NULL);
199
204
  }
200
205
 
201
206
  BIO_free(in);
202
207
 
203
208
  if (ec == NULL) {
204
- const char *name = STR2CSTR(arg);
209
+ const char *name = StringValueCStr(arg);
205
210
  int nid = OBJ_sn2nid(name);
206
211
 
212
+ (void)ERR_get_error();
207
213
  if (nid == NID_undef)
208
214
  ossl_raise(eECError, "unknown curve name (%s)\n", name);
209
215
 
@@ -274,7 +280,7 @@ static VALUE ossl_ec_key_get_group(VALUE self)
274
280
  * the group.
275
281
  *
276
282
  * Setting the group will immediately destroy any previously assigned group object.
277
- * The group is internally copied by OpenSSL. Modifying the original group after
283
+ * The group is internally copied by OpenSSL. Modifying the original group after
278
284
  * assignment will not effect the internal key structure.
279
285
  * (your changes may be lost). BE CAREFUL.
280
286
  *
@@ -457,22 +463,19 @@ static VALUE ossl_ec_key_is_private_key(VALUE self)
457
463
  return (EC_KEY_get0_private_key(ec) ? Qtrue : Qfalse);
458
464
  }
459
465
 
460
- static VALUE ossl_ec_key_to_string(VALUE self, int format)
466
+ static VALUE ossl_ec_key_to_string(VALUE self, VALUE ciph, VALUE pass, int format)
461
467
  {
462
468
  EC_KEY *ec;
463
469
  BIO *out;
464
470
  int i = -1;
465
471
  int private = 0;
466
- #if 0 /* unused now */
467
- EVP_CIPHER *cipher = NULL;
468
472
  char *password = NULL;
469
- #endif
470
473
  VALUE str;
471
474
 
472
475
  Require_EC_KEY(self, ec);
473
476
 
474
477
  if (EC_KEY_get0_public_key(ec) == NULL)
475
- rb_raise(eECError, "can't export - no public key set");
478
+ ossl_raise(eECError, "can't export - no public key set");
476
479
 
477
480
  if (EC_KEY_check_key(ec) != 1)
478
481
  ossl_raise(eECError, "can't export - EC_KEY_check_key failed");
@@ -486,44 +489,36 @@ static VALUE ossl_ec_key_to_string(VALUE self, int format)
486
489
  switch(format) {
487
490
  case EXPORT_PEM:
488
491
  if (private) {
489
- #if 0 /* unused now */
490
- if (cipher || password)
491
- /* BUG: finish cipher/password key export */
492
- rb_notimplement();
492
+ const EVP_CIPHER *cipher;
493
+ if (!NIL_P(ciph)) {
494
+ cipher = GetCipherPtr(ciph);
495
+ if (!NIL_P(pass)) {
496
+ StringValue(pass);
497
+ if (RSTRING_LENINT(pass) < OSSL_MIN_PWD_LEN)
498
+ ossl_raise(eOSSLError, "OpenSSL requires passwords to be at least four characters long");
499
+ password = RSTRING_PTR(pass);
500
+ }
501
+ }
502
+ else {
503
+ cipher = NULL;
504
+ }
493
505
  i = PEM_write_bio_ECPrivateKey(out, ec, cipher, NULL, 0, NULL, password);
494
- #endif
495
- i = PEM_write_bio_ECPrivateKey(out, ec, NULL, NULL, 0, NULL, NULL);
496
506
  } else {
497
- #if 0 /* unused now */
498
- if (cipher || password)
499
- rb_raise(rb_eArgError, "encryption is not supported when exporting this key type");
500
- #endif
501
-
502
507
  i = PEM_write_bio_EC_PUBKEY(out, ec);
503
508
  }
504
509
 
505
510
  break;
506
511
  case EXPORT_DER:
507
512
  if (private) {
508
- #if 0 /* unused now */
509
- if (cipher || password)
510
- rb_raise(rb_eArgError, "encryption is not supported when exporting this key type");
511
- #endif
512
-
513
513
  i = i2d_ECPrivateKey_bio(out, ec);
514
514
  } else {
515
- #if 0 /* unused now */
516
- if (cipher || password)
517
- rb_raise(rb_eArgError, "encryption is not supported when exporting this key type");
518
- #endif
519
-
520
515
  i = i2d_EC_PUBKEY_bio(out, ec);
521
516
  }
522
517
 
523
518
  break;
524
519
  default:
525
520
  BIO_free(out);
526
- rb_raise(rb_eRuntimeError, "unknown format (internal error)");
521
+ ossl_raise(rb_eRuntimeError, "unknown format (internal error)");
527
522
  }
528
523
 
529
524
  if (i != 1) {
@@ -538,13 +533,21 @@ static VALUE ossl_ec_key_to_string(VALUE self, int format)
538
533
 
539
534
  /*
540
535
  * call-seq:
541
- * key.to_pem => String
536
+ * key.export => String
537
+ * key.export(cipher, pass_phrase) => String
538
+ *
539
+ * Outputs the EC key in PEM encoding. If +cipher+ and +pass_phrase+ are
540
+ * given they will be used to encrypt the key. +cipher+ must be an
541
+ * OpenSSL::Cipher::Cipher instance. Note that encryption will only be
542
+ * effective for a private key, public keys will always be encoded in plain
543
+ * text.
542
544
  *
543
- * See the OpenSSL documentation for PEM_write_bio_ECPrivateKey()
544
545
  */
545
- static VALUE ossl_ec_key_to_pem(VALUE self)
546
+ static VALUE ossl_ec_key_export(int argc, VALUE *argv, VALUE self)
546
547
  {
547
- return ossl_ec_key_to_string(self, EXPORT_PEM);
548
+ VALUE cipher, passwd;
549
+ rb_scan_args(argc, argv, "02", &cipher, &passwd);
550
+ return ossl_ec_key_to_string(self, cipher, passwd, EXPORT_PEM);
548
551
  }
549
552
 
550
553
  /*
@@ -555,7 +558,7 @@ static VALUE ossl_ec_key_to_pem(VALUE self)
555
558
  */
556
559
  static VALUE ossl_ec_key_to_der(VALUE self)
557
560
  {
558
- return ossl_ec_key_to_string(self, EXPORT_DER);
561
+ return ossl_ec_key_to_string(self, Qnil, Qnil, EXPORT_DER);
559
562
  }
560
563
 
561
564
  /*
@@ -671,7 +674,7 @@ static VALUE ossl_ec_key_dsa_sign_asn1(VALUE self, VALUE data)
671
674
  ossl_raise(eECError, "Private EC key needed!");
672
675
 
673
676
  str = rb_str_new(0, ECDSA_size(ec) + 16);
674
- if (ECDSA_sign(0, (unsigned char *) RSTRING_PTR(data), RSTRING_LEN(data), (unsigned char *) RSTRING_PTR(str), &buf_len, ec) != 1)
677
+ if (ECDSA_sign(0, (unsigned char *) RSTRING_PTR(data), RSTRING_LENINT(data), (unsigned char *) RSTRING_PTR(str), &buf_len, ec) != 1)
675
678
  ossl_raise(eECError, "ECDSA_sign");
676
679
 
677
680
  rb_str_resize(str, buf_len);
@@ -693,13 +696,15 @@ static VALUE ossl_ec_key_dsa_verify_asn1(VALUE self, VALUE data, VALUE sig)
693
696
  StringValue(data);
694
697
  StringValue(sig);
695
698
 
696
- switch (ECDSA_verify(0, (unsigned char *) RSTRING_PTR(data), RSTRING_LEN(data), (unsigned char *) RSTRING_PTR(sig), RSTRING_LEN(sig), ec)) {
699
+ switch (ECDSA_verify(0, (unsigned char *) RSTRING_PTR(data), RSTRING_LENINT(data), (unsigned char *) RSTRING_PTR(sig), (int)RSTRING_LEN(sig), ec)) {
697
700
  case 1: return Qtrue;
698
701
  case 0: return Qfalse;
699
702
  default: break;
700
703
  }
701
704
 
702
705
  ossl_raise(eECError, "ECDSA_verify");
706
+
707
+ UNREACHABLE;
703
708
  }
704
709
 
705
710
  static void ossl_ec_group_free(ossl_ec_group *ec_group)
@@ -743,7 +748,7 @@ static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self)
743
748
 
744
749
  Data_Get_Struct(self, ossl_ec_group, ec_group);
745
750
  if (ec_group->group != NULL)
746
- rb_raise(rb_eRuntimeError, "EC_GROUP is already initialized");
751
+ ossl_raise(rb_eRuntimeError, "EC_GROUP is already initialized");
747
752
 
748
753
  switch (rb_scan_args(argc, argv, "13", &arg1, &arg2, &arg3, &arg4)) {
749
754
  case 1:
@@ -765,7 +770,7 @@ static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self)
765
770
  if ((group = EC_GROUP_new(method)) == NULL)
766
771
  ossl_raise(eEC_GROUP, "EC_GROUP_new");
767
772
  } else {
768
- rb_raise(rb_eArgError, "unknown symbol, must be :GFp_simple, :GFp_mont, :GFp_nist or :GF2m_simple");
773
+ ossl_raise(rb_eArgError, "unknown symbol, must be :GFp_simple, :GFp_mont, :GFp_nist or :GF2m_simple");
769
774
  }
770
775
  } else if (rb_obj_is_kind_of(arg1, cEC_GROUP)) {
771
776
  const EC_GROUP *arg1_group;
@@ -778,16 +783,17 @@ static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self)
778
783
 
779
784
  group = PEM_read_bio_ECPKParameters(in, NULL, NULL, NULL);
780
785
  if (!group) {
781
- BIO_reset(in);
786
+ OSSL_BIO_reset(in);
782
787
  group = d2i_ECPKParameters_bio(in, NULL);
783
788
  }
784
789
 
785
790
  BIO_free(in);
786
791
 
787
792
  if (!group) {
788
- const char *name = STR2CSTR(arg1);
793
+ const char *name = StringValueCStr(arg1);
789
794
  int nid = OBJ_sn2nid(name);
790
795
 
796
+ (void)ERR_get_error();
791
797
  if (nid == NID_undef)
792
798
  ossl_raise(eEC_GROUP, "unknown curve name (%s)", name);
793
799
 
@@ -814,18 +820,18 @@ static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self)
814
820
  } else if (id == s_GF2m) {
815
821
  new_curve = EC_GROUP_new_curve_GF2m;
816
822
  } else {
817
- rb_raise(rb_eArgError, "unknown symbol, must be :GFp or :GF2m");
823
+ ossl_raise(rb_eArgError, "unknown symbol, must be :GFp or :GF2m");
818
824
  }
819
825
 
820
826
  if ((group = new_curve(p, a, b, ossl_bn_ctx)) == NULL)
821
827
  ossl_raise(eEC_GROUP, "EC_GROUP_new_by_GF*");
822
828
  } else {
823
- rb_raise(rb_eArgError, "unknown argument, must be :GFp or :GF2m");
829
+ ossl_raise(rb_eArgError, "unknown argument, must be :GFp or :GF2m");
824
830
  }
825
831
 
826
832
  break;
827
833
  default:
828
- rb_raise(rb_eArgError, "wrong number of arguments");
834
+ ossl_raise(rb_eArgError, "wrong number of arguments");
829
835
  }
830
836
 
831
837
  if (group == NULL)
@@ -965,7 +971,7 @@ static VALUE ossl_s_builtin_curves(VALUE self)
965
971
  {
966
972
  EC_builtin_curve *curves = NULL;
967
973
  int n;
968
- int crv_len = EC_get_builtin_curves(NULL, 0);
974
+ int crv_len = rb_long2int(EC_get_builtin_curves(NULL, 0));
969
975
  VALUE ary, ret;
970
976
 
971
977
  curves = ALLOCA_N(EC_builtin_curve, crv_len);
@@ -1023,7 +1029,7 @@ static VALUE ossl_ec_group_set_asn1_flag(VALUE self, VALUE flag_v)
1023
1029
  }
1024
1030
 
1025
1031
  /* call-seq:
1026
- * group.point_conversion_form => :uncompressed | :compressed | :hybrid
1032
+ * group.point_conversion_form => :uncompressed | :compressed | :hybrid
1027
1033
  *
1028
1034
  * See the OpenSSL documentation for EC_GROUP_get_point_conversion_form()
1029
1035
  */
@@ -1041,9 +1047,9 @@ static VALUE ossl_ec_group_get_point_conversion_form(VALUE self)
1041
1047
  case POINT_CONVERSION_UNCOMPRESSED: ret = ID_uncompressed; break;
1042
1048
  case POINT_CONVERSION_COMPRESSED: ret = ID_compressed; break;
1043
1049
  case POINT_CONVERSION_HYBRID: ret = ID_hybrid; break;
1044
- default: rb_raise(eEC_GROUP, "unsupported point conversion form: %d, this module should be updated", form);
1050
+ default: ossl_raise(eEC_GROUP, "unsupported point conversion form: %d, this module should be updated", form);
1045
1051
  }
1046
-
1052
+
1047
1053
  return ID2SYM(ret);
1048
1054
  }
1049
1055
 
@@ -1067,7 +1073,7 @@ static VALUE ossl_ec_group_set_point_conversion_form(VALUE self, VALUE form_v)
1067
1073
  } else if (form_id == ID_hybrid) {
1068
1074
  form = POINT_CONVERSION_HYBRID;
1069
1075
  } else {
1070
- rb_raise(rb_eArgError, "form must be :compressed, :uncompressed, or :hybrid");
1076
+ ossl_raise(rb_eArgError, "form must be :compressed, :uncompressed, or :hybrid");
1071
1077
  }
1072
1078
 
1073
1079
  EC_GROUP_set_point_conversion_form(group, form);
@@ -1092,7 +1098,7 @@ static VALUE ossl_ec_group_get_seed(VALUE self)
1092
1098
  if (seed_len == 0)
1093
1099
  return Qnil;
1094
1100
 
1095
- return rb_str_new(EC_GROUP_get0_seed(group), seed_len);
1101
+ return rb_str_new((const char *)EC_GROUP_get0_seed(group), seed_len);
1096
1102
  }
1097
1103
 
1098
1104
  /* call-seq:
@@ -1107,7 +1113,7 @@ static VALUE ossl_ec_group_set_seed(VALUE self, VALUE seed)
1107
1113
  Require_EC_GROUP(self, group);
1108
1114
  StringValue(seed);
1109
1115
 
1110
- if (EC_GROUP_set_seed(group, RSTRING_PTR(seed), RSTRING_LEN(seed)) != RSTRING_LEN(seed))
1116
+ if (EC_GROUP_set_seed(group, (unsigned char *)RSTRING_PTR(seed), RSTRING_LEN(seed)) != (size_t)RSTRING_LEN(seed))
1111
1117
  ossl_raise(eEC_GROUP, "EC_GROUP_set_seed");
1112
1118
 
1113
1119
  return seed;
@@ -1150,7 +1156,7 @@ static VALUE ossl_ec_group_to_string(VALUE self, int format)
1150
1156
  break;
1151
1157
  default:
1152
1158
  BIO_free(out);
1153
- rb_raise(rb_eRuntimeError, "unknown format (internal error)");
1159
+ ossl_raise(rb_eRuntimeError, "unknown format (internal error)");
1154
1160
  }
1155
1161
 
1156
1162
  if (i != 1) {
@@ -1243,7 +1249,7 @@ static VALUE ossl_ec_point_initialize(int argc, VALUE *argv, VALUE self)
1243
1249
 
1244
1250
  Data_Get_Struct(self, ossl_ec_point, ec_point);
1245
1251
  if (ec_point->point)
1246
- rb_raise(eEC_POINT, "EC_POINT already initialized");
1252
+ ossl_raise(eEC_POINT, "EC_POINT already initialized");
1247
1253
 
1248
1254
  switch (rb_scan_args(argc, argv, "11", &arg1, &arg2)) {
1249
1255
  case 1:
@@ -1261,16 +1267,16 @@ static VALUE ossl_ec_point_initialize(int argc, VALUE *argv, VALUE self)
1261
1267
 
1262
1268
  point = EC_POINT_new(group);
1263
1269
  } else {
1264
- rb_raise(eEC_POINT, "wrong argument type: must be OpenSSL::PKey::EC::Point or OpenSSL::Pkey::EC::Group");
1270
+ ossl_raise(eEC_POINT, "wrong argument type: must be OpenSSL::PKey::EC::Point or OpenSSL::Pkey::EC::Group");
1265
1271
  }
1266
1272
 
1267
1273
  break;
1268
1274
  case 2:
1269
1275
  if (!rb_obj_is_kind_of(arg1, cEC_GROUP))
1270
- rb_raise(rb_eArgError, "1st argument must be OpenSSL::PKey::EC::Group");
1276
+ ossl_raise(rb_eArgError, "1st argument must be OpenSSL::PKey::EC::Group");
1271
1277
  group_v = arg1;
1272
1278
  SafeRequire_EC_GROUP(group_v, group);
1273
-
1279
+
1274
1280
  if (rb_obj_is_kind_of(arg2, cBN)) {
1275
1281
  const BIGNUM *bn = GetBNPtr(arg2);
1276
1282
 
@@ -1288,14 +1294,14 @@ static VALUE ossl_ec_point_initialize(int argc, VALUE *argv, VALUE self)
1288
1294
  }
1289
1295
  break;
1290
1296
  default:
1291
- rb_raise(rb_eArgError, "wrong number of arguments");
1297
+ ossl_raise(rb_eArgError, "wrong number of arguments");
1292
1298
  }
1293
1299
 
1294
1300
  if (point == NULL)
1295
1301
  ossl_raise(eEC_POINT, NULL);
1296
1302
 
1297
1303
  if (NIL_P(group_v))
1298
- rb_raise(rb_eRuntimeError, "missing group (internal error)");
1304
+ ossl_raise(rb_eRuntimeError, "missing group (internal error)");
1299
1305
 
1300
1306
  ec_point->point = point;
1301
1307
 
@@ -1348,6 +1354,8 @@ static VALUE ossl_ec_point_is_at_infinity(VALUE self)
1348
1354
  case 0: return Qfalse;
1349
1355
  default: ossl_raise(cEC_POINT, "EC_POINT_is_at_infinity");
1350
1356
  }
1357
+
1358
+ UNREACHABLE;
1351
1359
  }
1352
1360
 
1353
1361
  /*
@@ -1369,6 +1377,8 @@ static VALUE ossl_ec_point_is_on_curve(VALUE self)
1369
1377
  case 0: return Qfalse;
1370
1378
  default: ossl_raise(cEC_POINT, "EC_POINT_is_on_curve");
1371
1379
  }
1380
+
1381
+ UNREACHABLE;
1372
1382
  }
1373
1383
 
1374
1384
  /*
@@ -1460,6 +1470,78 @@ static VALUE ossl_ec_point_to_bn(VALUE self)
1460
1470
  return bn_obj;
1461
1471
  }
1462
1472
 
1473
+ /*
1474
+ * call-seq:
1475
+ * point.mul(bn) => point
1476
+ * point.mul(bn, bn) => point
1477
+ * point.mul([bn], [point]) => point
1478
+ * point.mul([bn], [point], bn) => point
1479
+ */
1480
+ static VALUE ossl_ec_point_mul(int argc, VALUE *argv, VALUE self)
1481
+ {
1482
+ EC_POINT *point1, *point2;
1483
+ const EC_GROUP *group;
1484
+ VALUE group_v = rb_iv_get(self, "@group");
1485
+ VALUE bn_v1, bn_v2, r, points_v;
1486
+ BIGNUM *bn1 = NULL, *bn2 = NULL;
1487
+
1488
+ Require_EC_POINT(self, point1);
1489
+ SafeRequire_EC_GROUP(group_v, group);
1490
+
1491
+ r = rb_obj_alloc(cEC_POINT);
1492
+ ossl_ec_point_initialize(1, &group_v, r);
1493
+ Require_EC_POINT(r, point2);
1494
+
1495
+ argc = rb_scan_args(argc, argv, "12", &bn_v1, &points_v, &bn_v2);
1496
+
1497
+ if (rb_obj_is_kind_of(bn_v1, cBN)) {
1498
+ bn1 = GetBNPtr(bn_v1);
1499
+ if (argc >= 2) {
1500
+ bn2 = GetBNPtr(points_v);
1501
+ }
1502
+ if (EC_POINT_mul(group, point2, bn2, point1, bn1, ossl_bn_ctx) != 1)
1503
+ ossl_raise(eEC_POINT, "Multiplication failed");
1504
+ } else {
1505
+ size_t i, points_len, bignums_len;
1506
+ const EC_POINT **points;
1507
+ const BIGNUM **bignums;
1508
+
1509
+ Check_Type(bn_v1, T_ARRAY);
1510
+ bignums_len = RARRAY_LEN(bn_v1);
1511
+ bignums = (const BIGNUM **)OPENSSL_malloc(bignums_len * (int)sizeof(BIGNUM *));
1512
+
1513
+ for (i = 0; i < bignums_len; ++i) {
1514
+ bignums[i] = GetBNPtr(rb_ary_entry(bn_v1, i));
1515
+ }
1516
+
1517
+ if (!rb_obj_is_kind_of(points_v, rb_cArray)) {
1518
+ OPENSSL_free((void *)bignums);
1519
+ rb_raise(rb_eTypeError, "Argument2 must be an array");
1520
+ }
1521
+
1522
+ rb_ary_unshift(points_v, self);
1523
+ points_len = RARRAY_LEN(points_v);
1524
+ points = (const EC_POINT **)OPENSSL_malloc(points_len * (int)sizeof(EC_POINT *));
1525
+
1526
+ for (i = 0; i < points_len; ++i) {
1527
+ Get_EC_POINT(rb_ary_entry(points_v, i), points[i]);
1528
+ }
1529
+
1530
+ if (argc >= 3) {
1531
+ bn2 = GetBNPtr(bn_v2);
1532
+ }
1533
+ if (EC_POINTs_mul(group, point2, bn2, points_len, points, bignums, ossl_bn_ctx) != 1) {
1534
+ OPENSSL_free((void *)bignums);
1535
+ OPENSSL_free((void *)points);
1536
+ ossl_raise(eEC_POINT, "Multiplication failed");
1537
+ }
1538
+ OPENSSL_free((void *)bignums);
1539
+ OPENSSL_free((void *)points);
1540
+ }
1541
+
1542
+ return r;
1543
+ }
1544
+
1463
1545
  static void no_copy(VALUE klass)
1464
1546
  {
1465
1547
  rb_undef_method(klass, "copy");
@@ -1526,7 +1608,8 @@ void Init_ossl_ec()
1526
1608
  rb_define_method(cEC, "dsa_verify_asn1", ossl_ec_key_dsa_verify_asn1, 2);
1527
1609
  /* do_sign/do_verify */
1528
1610
 
1529
- rb_define_method(cEC, "to_pem", ossl_ec_key_to_pem, 0);
1611
+ rb_define_method(cEC, "export", ossl_ec_key_export, -1);
1612
+ rb_define_alias(cEC, "to_pem", "export");
1530
1613
  rb_define_method(cEC, "to_der", ossl_ec_key_to_der, 0);
1531
1614
  rb_define_method(cEC, "to_text", ossl_ec_key_to_text, 0);
1532
1615
 
@@ -1580,6 +1663,7 @@ void Init_ossl_ec()
1580
1663
  /* all the other methods */
1581
1664
 
1582
1665
  rb_define_method(cEC_POINT, "to_bn", ossl_ec_point_to_bn, 0);
1666
+ rb_define_method(cEC_POINT, "mul", ossl_ec_point_mul, -1);
1583
1667
 
1584
1668
  no_copy(cEC);
1585
1669
  no_copy(cEC_GROUP);