Ruby  2.0.0p353(2013-11-22revision43784)
ossl_pkey_ec.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006-2007 Technorama Ltd. <oss-ruby@technorama.net>
3  */
4 
5 #include "ossl.h"
6 
7 #if !defined(OPENSSL_NO_EC) && (OPENSSL_VERSION_NUMBER >= 0x0090802fL)
8 
9 typedef struct {
10  EC_GROUP *group;
11  int dont_free;
12 } ossl_ec_group;
13 
14 typedef struct {
15  EC_POINT *point;
16  int dont_free;
17 } ossl_ec_point;
18 
19 
20 #define EXPORT_PEM 0
21 #define EXPORT_DER 1
22 
23 
24 #define GetPKeyEC(obj, pkey) do { \
25  GetPKey((obj), (pkey)); \
26  if (EVP_PKEY_type((pkey)->type) != EVP_PKEY_EC) { \
27  ossl_raise(rb_eRuntimeError, "THIS IS NOT A EC PKEY!"); \
28  } \
29 } while (0)
30 
31 #define SafeGet_ec_group(obj, group) do { \
32  OSSL_Check_Kind((obj), cEC_GROUP); \
33  Data_Get_Struct((obj), ossl_ec_group, (group)); \
34 } while(0)
35 
36 #define Get_EC_KEY(obj, key) do { \
37  EVP_PKEY *pkey; \
38  GetPKeyEC((obj), pkey); \
39  (key) = pkey->pkey.ec; \
40 } while(0)
41 
42 #define Require_EC_KEY(obj, key) do { \
43  Get_EC_KEY((obj), (key)); \
44  if ((key) == NULL) \
45  ossl_raise(eECError, "EC_KEY is not initialized"); \
46 } while(0)
47 
48 #define SafeRequire_EC_KEY(obj, key) do { \
49  OSSL_Check_Kind((obj), cEC); \
50  Require_EC_KEY((obj), (key)); \
51 } while (0)
52 
53 #define Get_EC_GROUP(obj, g) do { \
54  ossl_ec_group *ec_group; \
55  Data_Get_Struct((obj), ossl_ec_group, ec_group); \
56  if (ec_group == NULL) \
57  ossl_raise(eEC_GROUP, "missing ossl_ec_group structure"); \
58  (g) = ec_group->group; \
59 } while(0)
60 
61 #define Require_EC_GROUP(obj, group) do { \
62  Get_EC_GROUP((obj), (group)); \
63  if ((group) == NULL) \
64  ossl_raise(eEC_GROUP, "EC_GROUP is not initialized"); \
65 } while(0)
66 
67 #define SafeRequire_EC_GROUP(obj, group) do { \
68  OSSL_Check_Kind((obj), cEC_GROUP); \
69  Require_EC_GROUP((obj), (group)); \
70 } while(0)
71 
72 #define Get_EC_POINT(obj, p) do { \
73  ossl_ec_point *ec_point; \
74  Data_Get_Struct((obj), ossl_ec_point, ec_point); \
75  if (ec_point == NULL) \
76  ossl_raise(eEC_POINT, "missing ossl_ec_point structure"); \
77  (p) = ec_point->point; \
78 } while(0)
79 
80 #define Require_EC_POINT(obj, point) do { \
81  Get_EC_POINT((obj), (point)); \
82  if ((point) == NULL) \
83  ossl_raise(eEC_POINT, "EC_POINT is not initialized"); \
84 } while(0)
85 
86 #define SafeRequire_EC_POINT(obj, point) do { \
87  OSSL_Check_Kind((obj), cEC_POINT); \
88  Require_EC_POINT((obj), (point)); \
89 } while(0)
90 
91 VALUE cEC;
97 
98 static ID s_GFp;
99 static ID s_GFp_simple;
100 static ID s_GFp_mont;
101 static ID s_GFp_nist;
102 static ID s_GF2m;
103 static ID s_GF2m_simple;
104 
105 static ID ID_uncompressed;
106 static ID ID_compressed;
107 static ID ID_hybrid;
108 
109 static VALUE ec_instance(VALUE klass, EC_KEY *ec)
110 {
111  EVP_PKEY *pkey;
112  VALUE obj;
113 
114  if (!ec) {
115  return Qfalse;
116  }
117  if (!(pkey = EVP_PKEY_new())) {
118  return Qfalse;
119  }
120  if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) {
121  EVP_PKEY_free(pkey);
122  return Qfalse;
123  }
124  WrapPKey(klass, obj, pkey);
125 
126  return obj;
127 }
128 
129 VALUE ossl_ec_new(EVP_PKEY *pkey)
130 {
131  VALUE obj;
132 
133  if (!pkey) {
134  obj = ec_instance(cEC, EC_KEY_new());
135  } else {
136  if (EVP_PKEY_type(pkey->type) != EVP_PKEY_EC) {
137  ossl_raise(rb_eTypeError, "Not a EC key!");
138  }
139  WrapPKey(cEC, obj, pkey);
140  }
141  if (obj == Qfalse) {
143  }
144 
145  return obj;
146 }
147 
148 
149 /* call-seq:
150  * OpenSSL::PKey::EC.new()
151  * OpenSSL::PKey::EC.new(ec_key)
152  * OpenSSL::PKey::EC.new(ec_group)
153  * OpenSSL::PKey::EC.new("secp112r1")
154  * OpenSSL::PKey::EC.new(pem_string)
155  * OpenSSL::PKey::EC.new(pem_string [, pwd])
156  * OpenSSL::PKey::EC.new(der_string)
157  *
158  * See the OpenSSL documentation for:
159  * EC_KEY_*
160  */
161 static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self)
162 {
163  EVP_PKEY *pkey;
164  EC_KEY *ec = NULL;
165  VALUE arg, pass;
166  VALUE group = Qnil;
167  char *passwd = NULL;
168 
169  GetPKey(self, pkey);
170  if (pkey->pkey.ec)
171  ossl_raise(eECError, "EC_KEY already initialized");
172 
173  rb_scan_args(argc, argv, "02", &arg, &pass);
174 
175  if (NIL_P(arg)) {
176  ec = EC_KEY_new();
177  } else {
178  if (rb_obj_is_kind_of(arg, cEC)) {
179  EC_KEY *other_ec = NULL;
180 
181  SafeRequire_EC_KEY(arg, other_ec);
182  ec = EC_KEY_dup(other_ec);
183  } else if (rb_obj_is_kind_of(arg, cEC_GROUP)) {
184  ec = EC_KEY_new();
185  group = arg;
186  } else {
187  BIO *in = ossl_obj2bio(arg);
188 
189  if (!NIL_P(pass)) {
190  passwd = StringValuePtr(pass);
191  }
192  ec = PEM_read_bio_ECPrivateKey(in, NULL, ossl_pem_passwd_cb, passwd);
193  if (!ec) {
194  OSSL_BIO_reset(in);
195  ec = PEM_read_bio_EC_PUBKEY(in, NULL, ossl_pem_passwd_cb, passwd);
196  }
197  if (!ec) {
198  OSSL_BIO_reset(in);
199  ec = d2i_ECPrivateKey_bio(in, NULL);
200  }
201  if (!ec) {
202  OSSL_BIO_reset(in);
203  ec = d2i_EC_PUBKEY_bio(in, NULL);
204  }
205 
206  BIO_free(in);
207 
208  if (ec == NULL) {
209  const char *name = StringValueCStr(arg);
210  int nid = OBJ_sn2nid(name);
211 
212  (void)ERR_get_error();
213  if (nid == NID_undef)
214  ossl_raise(eECError, "unknown curve name (%s)\n", name);
215 
216  if ((ec = EC_KEY_new_by_curve_name(nid)) == NULL)
217  ossl_raise(eECError, "unable to create curve (%s)\n", name);
218 
219  EC_KEY_set_asn1_flag(ec, OPENSSL_EC_NAMED_CURVE);
220  EC_KEY_set_conv_form(ec, POINT_CONVERSION_UNCOMPRESSED);
221  }
222  }
223  }
224 
225  if (ec == NULL)
227 
228  if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) {
229  EC_KEY_free(ec);
230  ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY");
231  }
232 
233  rb_iv_set(self, "@group", Qnil);
234 
235  if (!NIL_P(group))
236  rb_funcall(self, rb_intern("group="), 1, arg);
237 
238  return self;
239 }
240 
241 /*
242  * call-seq:
243  * key.group => group
244  *
245  * Returns a constant <code>OpenSSL::EC::Group</code> that is tied to the key.
246  * Modifying the returned group can make the key invalid.
247  */
248 static VALUE ossl_ec_key_get_group(VALUE self)
249 {
250  VALUE group_v;
251  EC_KEY *ec;
252  ossl_ec_group *ec_group;
253  EC_GROUP *group;
254 
255  Require_EC_KEY(self, ec);
256 
257  group_v = rb_iv_get(self, "@group");
258  if (!NIL_P(group_v))
259  return group_v;
260 
261  if ((group = (EC_GROUP *)EC_KEY_get0_group(ec)) != NULL) {
262  group_v = rb_obj_alloc(cEC_GROUP);
263  SafeGet_ec_group(group_v, ec_group);
264  ec_group->group = group;
265  ec_group->dont_free = 1;
266  rb_iv_set(group_v, "@key", self);
267  rb_iv_set(self, "@group", group_v);
268  return group_v;
269  }
270 
271  return Qnil;
272 }
273 
274 /*
275  * call-seq:
276  * key.group = group => group
277  *
278  * Returns the same object passed, not the group object associated with the key.
279  * If you wish to access the group object tied to the key call key.group after setting
280  * the group.
281  *
282  * Setting the group will immediately destroy any previously assigned group object.
283  * The group is internally copied by OpenSSL. Modifying the original group after
284  * assignment will not effect the internal key structure.
285  * (your changes may be lost). BE CAREFUL.
286  *
287  * EC_KEY_set_group calls EC_GROUP_free(key->group) then EC_GROUP_dup(), not EC_GROUP_copy.
288  * This documentation is accurate for OpenSSL 0.9.8b.
289  */
290 static VALUE ossl_ec_key_set_group(VALUE self, VALUE group_v)
291 {
292  VALUE old_group_v;
293  EC_KEY *ec;
294  EC_GROUP *group;
295 
296  Require_EC_KEY(self, ec);
297  SafeRequire_EC_GROUP(group_v, group);
298 
299  old_group_v = rb_iv_get(self, "@group");
300  if (!NIL_P(old_group_v)) {
301  ossl_ec_group *old_ec_group;
302  SafeGet_ec_group(old_group_v, old_ec_group);
303 
304  old_ec_group->group = NULL;
305  old_ec_group->dont_free = 0;
306  rb_iv_set(old_group_v, "@key", Qnil);
307  }
308 
309  rb_iv_set(self, "@group", Qnil);
310 
311  if (EC_KEY_set_group(ec, group) != 1)
312  ossl_raise(eECError, "EC_KEY_set_group");
313 
314  return group_v;
315 }
316 
317 /*
318  * call-seq:
319  * key.private_key => OpenSSL::BN
320  *
321  * See the OpenSSL documentation for EC_KEY_get0_private_key()
322  */
323 static VALUE ossl_ec_key_get_private_key(VALUE self)
324 {
325  EC_KEY *ec;
326  const BIGNUM *bn;
327 
328  Require_EC_KEY(self, ec);
329 
330  if ((bn = EC_KEY_get0_private_key(ec)) == NULL)
331  return Qnil;
332 
333  return ossl_bn_new(bn);
334 }
335 
336 /*
337  * call-seq:
338  * key.private_key = openssl_bn
339  *
340  * See the OpenSSL documentation for EC_KEY_set_private_key()
341  */
342 static VALUE ossl_ec_key_set_private_key(VALUE self, VALUE private_key)
343 {
344  EC_KEY *ec;
345  BIGNUM *bn = NULL;
346 
347  Require_EC_KEY(self, ec);
348  if (!NIL_P(private_key))
349  bn = GetBNPtr(private_key);
350 
351  switch (EC_KEY_set_private_key(ec, bn)) {
352  case 1:
353  break;
354  case 0:
355  if (bn == NULL)
356  break;
357  default:
358  ossl_raise(eECError, "EC_KEY_set_private_key");
359  }
360 
361  return private_key;
362 }
363 
364 
365 static VALUE ossl_ec_point_dup(const EC_POINT *point, VALUE group_v)
366 {
367  VALUE obj;
368  const EC_GROUP *group;
369  ossl_ec_point *new_point;
370 
371  obj = rb_obj_alloc(cEC_POINT);
372  Data_Get_Struct(obj, ossl_ec_point, new_point);
373 
374  SafeRequire_EC_GROUP(group_v, group);
375 
376  new_point->point = EC_POINT_dup(point, group);
377  if (new_point->point == NULL)
378  ossl_raise(eEC_POINT, "EC_POINT_dup");
379  rb_iv_set(obj, "@group", group_v);
380 
381  return obj;
382 }
383 
384 /*
385  * call-seq:
386  * key.public_key => OpenSSL::PKey::EC::Point
387  *
388  * See the OpenSSL documentation for EC_KEY_get0_public_key()
389  */
390 static VALUE ossl_ec_key_get_public_key(VALUE self)
391 {
392  EC_KEY *ec;
393  const EC_POINT *point;
394  VALUE group;
395 
396  Require_EC_KEY(self, ec);
397 
398  if ((point = EC_KEY_get0_public_key(ec)) == NULL)
399  return Qnil;
400 
401  group = rb_funcall(self, rb_intern("group"), 0);
402  if (NIL_P(group))
403  ossl_raise(eECError, "EC_KEY_get0_get0_group (has public_key but no group???");
404 
405  return ossl_ec_point_dup(point, group);
406 }
407 
408 /*
409  * call-seq:
410  * key.public_key = ec_point
411  *
412  * See the OpenSSL documentation for EC_KEY_set_public_key()
413  */
414 static VALUE ossl_ec_key_set_public_key(VALUE self, VALUE public_key)
415 {
416  EC_KEY *ec;
417  EC_POINT *point = NULL;
418 
419  Require_EC_KEY(self, ec);
420  if (!NIL_P(public_key))
421  SafeRequire_EC_POINT(public_key, point);
422 
423  switch (EC_KEY_set_public_key(ec, point)) {
424  case 1:
425  break;
426  case 0:
427  if (point == NULL)
428  break;
429  default:
430  ossl_raise(eECError, "EC_KEY_set_public_key");
431  }
432 
433  return public_key;
434 }
435 
436 /*
437  * call-seq:
438  * key.public_key? => true or false
439  *
440  * Both public_key? and private_key? may return false at the same time unlike other PKey classes.
441  */
442 static VALUE ossl_ec_key_is_public_key(VALUE self)
443 {
444  EC_KEY *ec;
445 
446  Require_EC_KEY(self, ec);
447 
448  return (EC_KEY_get0_public_key(ec) ? Qtrue : Qfalse);
449 }
450 
451 /*
452  * call-seq:
453  * key.private_key? => true or false
454  *
455  * Both public_key? and private_key? may return false at the same time unlike other PKey classes.
456  */
457 static VALUE ossl_ec_key_is_private_key(VALUE self)
458 {
459  EC_KEY *ec;
460 
461  Require_EC_KEY(self, ec);
462 
463  return (EC_KEY_get0_private_key(ec) ? Qtrue : Qfalse);
464 }
465 
466 static VALUE ossl_ec_key_to_string(VALUE self, VALUE ciph, VALUE pass, int format)
467 {
468  EC_KEY *ec;
469  BIO *out;
470  int i = -1;
471  int private = 0;
472  char *password = NULL;
473  VALUE str;
474 
475  Require_EC_KEY(self, ec);
476 
477  if (EC_KEY_get0_public_key(ec) == NULL)
478  ossl_raise(eECError, "can't export - no public key set");
479 
480  if (EC_KEY_check_key(ec) != 1)
481  ossl_raise(eECError, "can't export - EC_KEY_check_key failed");
482 
483  if (EC_KEY_get0_private_key(ec))
484  private = 1;
485 
486  if (!(out = BIO_new(BIO_s_mem())))
487  ossl_raise(eECError, "BIO_new(BIO_s_mem())");
488 
489  switch(format) {
490  case EXPORT_PEM:
491  if (private) {
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  }
505  i = PEM_write_bio_ECPrivateKey(out, ec, cipher, NULL, 0, NULL, password);
506  } else {
507  i = PEM_write_bio_EC_PUBKEY(out, ec);
508  }
509 
510  break;
511  case EXPORT_DER:
512  if (private) {
513  i = i2d_ECPrivateKey_bio(out, ec);
514  } else {
515  i = i2d_EC_PUBKEY_bio(out, ec);
516  }
517 
518  break;
519  default:
520  BIO_free(out);
521  ossl_raise(rb_eRuntimeError, "unknown format (internal error)");
522  }
523 
524  if (i != 1) {
525  BIO_free(out);
526  ossl_raise(eECError, "outlen=%d", i);
527  }
528 
529  str = ossl_membio2str(out);
530 
531  return str;
532 }
533 
534 /*
535  * call-seq:
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.
544  *
545  */
546 static VALUE ossl_ec_key_export(int argc, VALUE *argv, VALUE self)
547 {
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);
551 }
552 
553 /*
554  * call-seq:
555  * key.to_der => String
556  *
557  * See the OpenSSL documentation for i2d_ECPrivateKey_bio()
558  */
559 static VALUE ossl_ec_key_to_der(VALUE self)
560 {
561  return ossl_ec_key_to_string(self, Qnil, Qnil, EXPORT_DER);
562 }
563 
564 /*
565  * call-seq:
566  * key.to_text => String
567  *
568  * See the OpenSSL documentation for EC_KEY_print()
569  */
570 static VALUE ossl_ec_key_to_text(VALUE self)
571 {
572  EC_KEY *ec;
573  BIO *out;
574  VALUE str;
575 
576  Require_EC_KEY(self, ec);
577  if (!(out = BIO_new(BIO_s_mem()))) {
578  ossl_raise(eECError, "BIO_new(BIO_s_mem())");
579  }
580  if (!EC_KEY_print(out, ec, 0)) {
581  BIO_free(out);
582  ossl_raise(eECError, "EC_KEY_print");
583  }
584  str = ossl_membio2str(out);
585 
586  return str;
587 }
588 
589 /*
590  * call-seq:
591  * key.generate_key => self
592  *
593  * See the OpenSSL documentation for EC_KEY_generate_key()
594  */
595 static VALUE ossl_ec_key_generate_key(VALUE self)
596 {
597  EC_KEY *ec;
598 
599  Require_EC_KEY(self, ec);
600 
601  if (EC_KEY_generate_key(ec) != 1)
602  ossl_raise(eECError, "EC_KEY_generate_key");
603 
604  return self;
605 }
606 
607 /*
608  * call-seq:
609  * key.check_key => true
610  *
611  * Raises an exception if the key is invalid.
612  *
613  * See the OpenSSL documentation for EC_KEY_check_key()
614  */
615 static VALUE ossl_ec_key_check_key(VALUE self)
616 {
617  EC_KEY *ec;
618 
619  Require_EC_KEY(self, ec);
620 
621  if (EC_KEY_check_key(ec) != 1)
622  ossl_raise(eECError, "EC_KEY_check_key");
623 
624  return Qtrue;
625 }
626 
627 /*
628  * call-seq:
629  * key.dh_compute_key(pubkey) => String
630  *
631  * See the OpenSSL documentation for ECDH_compute_key()
632  */
633 static VALUE ossl_ec_key_dh_compute_key(VALUE self, VALUE pubkey)
634 {
635  EC_KEY *ec;
636  EC_POINT *point;
637  int buf_len;
638  VALUE str;
639 
640  Require_EC_KEY(self, ec);
641  SafeRequire_EC_POINT(pubkey, point);
642 
643 /* BUG: need a way to figure out the maximum string size */
644  buf_len = 1024;
645  str = rb_str_new(0, buf_len);
646 /* BUG: take KDF as a block */
647  buf_len = ECDH_compute_key(RSTRING_PTR(str), buf_len, point, ec, NULL);
648  if (buf_len < 0)
649  ossl_raise(eECError, "ECDH_compute_key");
650 
651  rb_str_resize(str, buf_len);
652 
653  return str;
654 }
655 
656 /* sign_setup */
657 
658 /*
659  * call-seq:
660  * key.dsa_sign_asn1(data) => String
661  *
662  * See the OpenSSL documentation for ECDSA_sign()
663  */
664 static VALUE ossl_ec_key_dsa_sign_asn1(VALUE self, VALUE data)
665 {
666  EC_KEY *ec;
667  unsigned int buf_len;
668  VALUE str;
669 
670  Require_EC_KEY(self, ec);
671  StringValue(data);
672 
673  if (EC_KEY_get0_private_key(ec) == NULL)
674  ossl_raise(eECError, "Private EC key needed!");
675 
676  str = rb_str_new(0, ECDSA_size(ec) + 16);
677  if (ECDSA_sign(0, (unsigned char *) RSTRING_PTR(data), RSTRING_LENINT(data), (unsigned char *) RSTRING_PTR(str), &buf_len, ec) != 1)
678  ossl_raise(eECError, "ECDSA_sign");
679 
680  rb_str_resize(str, buf_len);
681 
682  return str;
683 }
684 
685 /*
686  * call-seq:
687  * key.dsa_verify_asn1(data, sig) => true or false
688  *
689  * See the OpenSSL documentation for ECDSA_verify()
690  */
691 static VALUE ossl_ec_key_dsa_verify_asn1(VALUE self, VALUE data, VALUE sig)
692 {
693  EC_KEY *ec;
694 
695  Require_EC_KEY(self, ec);
696  StringValue(data);
697  StringValue(sig);
698 
699  switch (ECDSA_verify(0, (unsigned char *) RSTRING_PTR(data), RSTRING_LENINT(data), (unsigned char *) RSTRING_PTR(sig), (int)RSTRING_LEN(sig), ec)) {
700  case 1: return Qtrue;
701  case 0: return Qfalse;
702  default: break;
703  }
704 
705  ossl_raise(eECError, "ECDSA_verify");
706 
707  UNREACHABLE;
708 }
709 
710 static void ossl_ec_group_free(ossl_ec_group *ec_group)
711 {
712  if (!ec_group->dont_free && ec_group->group)
713  EC_GROUP_clear_free(ec_group->group);
714  ruby_xfree(ec_group);
715 }
716 
717 static VALUE ossl_ec_group_alloc(VALUE klass)
718 {
719  ossl_ec_group *ec_group;
720  VALUE obj;
721 
722  obj = Data_Make_Struct(klass, ossl_ec_group, 0, ossl_ec_group_free, ec_group);
723 
724  return obj;
725 }
726 
727 /* call-seq:
728  * OpenSSL::PKey::EC::Group.new("secp112r1")
729  * OpenSSL::PKey::EC::Group.new(ec_group)
730  * OpenSSL::PKey::EC::Group.new(pem_string)
731  * OpenSSL::PKey::EC::Group.new(der_string)
732  * OpenSSL::PKey::EC::Group.new(pem_file)
733  * OpenSSL::PKey::EC::Group.new(der_file)
734  * OpenSSL::PKey::EC::Group.new(:GFp_simple)
735  * OpenSSL::PKey::EC::Group.new(:GFp_mult)
736  * OpenSSL::PKey::EC::Group.new(:GFp_nist)
737  * OpenSSL::PKey::EC::Group.new(:GF2m_simple)
738  * OpenSSL::PKey::EC::Group.new(:GFp, bignum_p, bignum_a, bignum_b)
739  * OpenSSL::PKey::EC::Group.new(:GF2m, bignum_p, bignum_a, bignum_b)
740  *
741  * See the OpenSSL documentation for EC_GROUP_*
742  */
743 static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self)
744 {
745  VALUE arg1, arg2, arg3, arg4;
746  ossl_ec_group *ec_group;
747  EC_GROUP *group = NULL;
748 
749  Data_Get_Struct(self, ossl_ec_group, ec_group);
750  if (ec_group->group != NULL)
751  ossl_raise(rb_eRuntimeError, "EC_GROUP is already initialized");
752 
753  switch (rb_scan_args(argc, argv, "13", &arg1, &arg2, &arg3, &arg4)) {
754  case 1:
755  if (SYMBOL_P(arg1)) {
756  const EC_METHOD *method = NULL;
757  ID id = SYM2ID(arg1);
758 
759  if (id == s_GFp_simple) {
760  method = EC_GFp_simple_method();
761  } else if (id == s_GFp_mont) {
762  method = EC_GFp_mont_method();
763  } else if (id == s_GFp_nist) {
764  method = EC_GFp_nist_method();
765 #if !defined(OPENSSL_NO_EC2M)
766  } else if (id == s_GF2m_simple) {
767  method = EC_GF2m_simple_method();
768 #endif
769  }
770 
771  if (method) {
772  if ((group = EC_GROUP_new(method)) == NULL)
773  ossl_raise(eEC_GROUP, "EC_GROUP_new");
774  } else {
775  ossl_raise(rb_eArgError, "unknown symbol, must be :GFp_simple, :GFp_mont, :GFp_nist or :GF2m_simple");
776  }
777  } else if (rb_obj_is_kind_of(arg1, cEC_GROUP)) {
778  const EC_GROUP *arg1_group;
779 
780  SafeRequire_EC_GROUP(arg1, arg1_group);
781  if ((group = EC_GROUP_dup(arg1_group)) == NULL)
782  ossl_raise(eEC_GROUP, "EC_GROUP_dup");
783  } else {
784  BIO *in = ossl_obj2bio(arg1);
785 
786  group = PEM_read_bio_ECPKParameters(in, NULL, NULL, NULL);
787  if (!group) {
788  OSSL_BIO_reset(in);
789  group = d2i_ECPKParameters_bio(in, NULL);
790  }
791 
792  BIO_free(in);
793 
794  if (!group) {
795  const char *name = StringValueCStr(arg1);
796  int nid = OBJ_sn2nid(name);
797 
798  (void)ERR_get_error();
799  if (nid == NID_undef)
800  ossl_raise(eEC_GROUP, "unknown curve name (%s)", name);
801 
802  group = EC_GROUP_new_by_curve_name(nid);
803  if (group == NULL)
804  ossl_raise(eEC_GROUP, "unable to create curve (%s)", name);
805 
806  EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE);
807  EC_GROUP_set_point_conversion_form(group, POINT_CONVERSION_UNCOMPRESSED);
808  }
809  }
810 
811  break;
812  case 4:
813  if (SYMBOL_P(arg1)) {
814  ID id = SYM2ID(arg1);
815  EC_GROUP *(*new_curve)(const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *) = NULL;
816  const BIGNUM *p = GetBNPtr(arg2);
817  const BIGNUM *a = GetBNPtr(arg3);
818  const BIGNUM *b = GetBNPtr(arg4);
819 
820  if (id == s_GFp) {
821  new_curve = EC_GROUP_new_curve_GFp;
822 #if !defined(OPENSSL_NO_EC2M)
823  } else if (id == s_GF2m) {
824  new_curve = EC_GROUP_new_curve_GF2m;
825 #endif
826  } else {
827  ossl_raise(rb_eArgError, "unknown symbol, must be :GFp or :GF2m");
828  }
829 
830  if ((group = new_curve(p, a, b, ossl_bn_ctx)) == NULL)
831  ossl_raise(eEC_GROUP, "EC_GROUP_new_by_GF*");
832  } else {
833  ossl_raise(rb_eArgError, "unknown argument, must be :GFp or :GF2m");
834  }
835 
836  break;
837  default:
838  ossl_raise(rb_eArgError, "wrong number of arguments");
839  }
840 
841  if (group == NULL)
842  ossl_raise(eEC_GROUP, "");
843 
844  ec_group->group = group;
845 
846  return self;
847 }
848 
849 /* call-seq:
850  * group1 == group2 => true | false
851  *
852  */
853 static VALUE ossl_ec_group_eql(VALUE a, VALUE b)
854 {
855  EC_GROUP *group1 = NULL, *group2 = NULL;
856 
857  Require_EC_GROUP(a, group1);
858  SafeRequire_EC_GROUP(b, group2);
859 
860  if (EC_GROUP_cmp(group1, group2, ossl_bn_ctx) == 1)
861  return Qfalse;
862 
863  return Qtrue;
864 }
865 
866 /* call-seq:
867  * group.generator => ec_point
868  *
869  * See the OpenSSL documentation for EC_GROUP_get0_generator()
870  */
871 static VALUE ossl_ec_group_get_generator(VALUE self)
872 {
873  VALUE point_obj;
874  EC_GROUP *group = NULL;
875 
876  Require_EC_GROUP(self, group);
877 
878  point_obj = ossl_ec_point_dup(EC_GROUP_get0_generator(group), self);
879 
880  return point_obj;
881 }
882 
883 /* call-seq:
884  * group.set_generator(generator, order, cofactor) => self
885  *
886  * See the OpenSSL documentation for EC_GROUP_set_generator()
887  */
888 static VALUE ossl_ec_group_set_generator(VALUE self, VALUE generator, VALUE order, VALUE cofactor)
889 {
890  EC_GROUP *group = NULL;
891  const EC_POINT *point;
892  const BIGNUM *o, *co;
893 
894  Require_EC_GROUP(self, group);
895  SafeRequire_EC_POINT(generator, point);
896  o = GetBNPtr(order);
897  co = GetBNPtr(cofactor);
898 
899  if (EC_GROUP_set_generator(group, point, o, co) != 1)
900  ossl_raise(eEC_GROUP, "EC_GROUP_set_generator");
901 
902  return self;
903 }
904 
905 /* call-seq:
906  * group.get_order => order_bn
907  *
908  * See the OpenSSL documentation for EC_GROUP_get_order()
909  */
910 static VALUE ossl_ec_group_get_order(VALUE self)
911 {
912  VALUE bn_obj;
913  BIGNUM *bn;
914  EC_GROUP *group = NULL;
915 
916  Require_EC_GROUP(self, group);
917 
918  bn_obj = ossl_bn_new(NULL);
919  bn = GetBNPtr(bn_obj);
920 
921  if (EC_GROUP_get_order(group, bn, ossl_bn_ctx) != 1)
922  ossl_raise(eEC_GROUP, "EC_GROUP_get_order");
923 
924  return bn_obj;
925 }
926 
927 /* call-seq:
928  * group.get_cofactor => cofactor_bn
929  *
930  * See the OpenSSL documentation for EC_GROUP_get_cofactor()
931  */
932 static VALUE ossl_ec_group_get_cofactor(VALUE self)
933 {
934  VALUE bn_obj;
935  BIGNUM *bn;
936  EC_GROUP *group = NULL;
937 
938  Require_EC_GROUP(self, group);
939 
940  bn_obj = ossl_bn_new(NULL);
941  bn = GetBNPtr(bn_obj);
942 
943  if (EC_GROUP_get_cofactor(group, bn, ossl_bn_ctx) != 1)
944  ossl_raise(eEC_GROUP, "EC_GROUP_get_cofactor");
945 
946  return bn_obj;
947 }
948 
949 /* call-seq:
950  * group.curve_name => String
951  *
952  * See the OpenSSL documentation for EC_GROUP_get_curve_name()
953  */
954 static VALUE ossl_ec_group_get_curve_name(VALUE self)
955 {
956  EC_GROUP *group = NULL;
957  int nid;
958 
959  Get_EC_GROUP(self, group);
960  if (group == NULL)
961  return Qnil;
962 
963  nid = EC_GROUP_get_curve_name(group);
964 
965 /* BUG: an nid or asn1 object should be returned, maybe. */
966  return rb_str_new2(OBJ_nid2sn(nid));
967 }
968 
969 /* call-seq:
970  * EC.builtin_curves => [[name, comment], ...]
971  *
972  * See the OpenSSL documentation for EC_builtin_curves()
973  */
974 static VALUE ossl_s_builtin_curves(VALUE self)
975 {
976  EC_builtin_curve *curves = NULL;
977  int n;
978  int crv_len = rb_long2int(EC_get_builtin_curves(NULL, 0));
979  VALUE ary, ret;
980 
981  curves = ALLOCA_N(EC_builtin_curve, crv_len);
982  if (curves == NULL)
983  return Qnil;
984  if (!EC_get_builtin_curves(curves, crv_len))
985  ossl_raise(rb_eRuntimeError, "EC_get_builtin_curves");
986 
987  ret = rb_ary_new2(crv_len);
988 
989  for (n = 0; n < crv_len; n++) {
990  const char *sname = OBJ_nid2sn(curves[n].nid);
991  const char *comment = curves[n].comment;
992 
993  ary = rb_ary_new2(2);
994  rb_ary_push(ary, rb_str_new2(sname));
995  rb_ary_push(ary, comment ? rb_str_new2(comment) : Qnil);
996  rb_ary_push(ret, ary);
997  }
998 
999  return ret;
1000 }
1001 
1002 /* call-seq:
1003  * group.asn1_flag => Fixnum
1004  *
1005  * See the OpenSSL documentation for EC_GROUP_get_asn1_flag()
1006  */
1007 static VALUE ossl_ec_group_get_asn1_flag(VALUE self)
1008 {
1009  EC_GROUP *group = NULL;
1010  int flag;
1011 
1012  Require_EC_GROUP(self, group);
1013 
1014  flag = EC_GROUP_get_asn1_flag(group);
1015 
1016  return INT2FIX(flag);
1017 }
1018 
1019 /* call-seq:
1020  * group.asn1_flag = Fixnum => Fixnum
1021  *
1022  * See the OpenSSL documentation for EC_GROUP_set_asn1_flag()
1023  */
1024 static VALUE ossl_ec_group_set_asn1_flag(VALUE self, VALUE flag_v)
1025 {
1026  EC_GROUP *group = NULL;
1027 
1028  Require_EC_GROUP(self, group);
1029 
1030  EC_GROUP_set_asn1_flag(group, NUM2INT(flag_v));
1031 
1032  return flag_v;
1033 }
1034 
1035 /* call-seq:
1036  * group.point_conversion_form => :uncompressed | :compressed | :hybrid
1037  *
1038  * See the OpenSSL documentation for EC_GROUP_get_point_conversion_form()
1039  */
1040 static VALUE ossl_ec_group_get_point_conversion_form(VALUE self)
1041 {
1042  EC_GROUP *group = NULL;
1043  point_conversion_form_t form;
1044  VALUE ret;
1045 
1046  Require_EC_GROUP(self, group);
1047 
1048  form = EC_GROUP_get_point_conversion_form(group);
1049 
1050  switch (form) {
1051  case POINT_CONVERSION_UNCOMPRESSED: ret = ID_uncompressed; break;
1052  case POINT_CONVERSION_COMPRESSED: ret = ID_compressed; break;
1053  case POINT_CONVERSION_HYBRID: ret = ID_hybrid; break;
1054  default: ossl_raise(eEC_GROUP, "unsupported point conversion form: %d, this module should be updated", form);
1055  }
1056 
1057  return ID2SYM(ret);
1058 }
1059 
1060 /* call-seq:
1061  * group.point_conversion_form = form => form
1062  *
1063  * See the OpenSSL documentation for EC_GROUP_set_point_conversion_form()
1064  */
1065 static VALUE ossl_ec_group_set_point_conversion_form(VALUE self, VALUE form_v)
1066 {
1067  EC_GROUP *group = NULL;
1068  point_conversion_form_t form;
1069  ID form_id = SYM2ID(form_v);
1070 
1071  Require_EC_GROUP(self, group);
1072 
1073  if (form_id == ID_uncompressed) {
1074  form = POINT_CONVERSION_UNCOMPRESSED;
1075  } else if (form_id == ID_compressed) {
1076  form = POINT_CONVERSION_COMPRESSED;
1077  } else if (form_id == ID_hybrid) {
1078  form = POINT_CONVERSION_HYBRID;
1079  } else {
1080  ossl_raise(rb_eArgError, "form must be :compressed, :uncompressed, or :hybrid");
1081  }
1082 
1083  EC_GROUP_set_point_conversion_form(group, form);
1084 
1085  return form_v;
1086 }
1087 
1088 /* call-seq:
1089  * group.seed => String or nil
1090  *
1091  * See the OpenSSL documentation for EC_GROUP_get0_seed()
1092  */
1093 static VALUE ossl_ec_group_get_seed(VALUE self)
1094 {
1095  EC_GROUP *group = NULL;
1096  size_t seed_len;
1097 
1098  Require_EC_GROUP(self, group);
1099 
1100  seed_len = EC_GROUP_get_seed_len(group);
1101 
1102  if (seed_len == 0)
1103  return Qnil;
1104 
1105  return rb_str_new((const char *)EC_GROUP_get0_seed(group), seed_len);
1106 }
1107 
1108 /* call-seq:
1109  * group.seed = seed => seed
1110  *
1111  * See the OpenSSL documentation for EC_GROUP_set_seed()
1112  */
1113 static VALUE ossl_ec_group_set_seed(VALUE self, VALUE seed)
1114 {
1115  EC_GROUP *group = NULL;
1116 
1117  Require_EC_GROUP(self, group);
1118  StringValue(seed);
1119 
1120  if (EC_GROUP_set_seed(group, (unsigned char *)RSTRING_PTR(seed), RSTRING_LEN(seed)) != (size_t)RSTRING_LEN(seed))
1121  ossl_raise(eEC_GROUP, "EC_GROUP_set_seed");
1122 
1123  return seed;
1124 }
1125 
1126 /* get/set curve GFp, GF2m */
1127 
1128 /* call-seq:
1129  * group.degree => Fixnum
1130  *
1131  * See the OpenSSL documentation for EC_GROUP_get_degree()
1132  */
1133 static VALUE ossl_ec_group_get_degree(VALUE self)
1134 {
1135  EC_GROUP *group = NULL;
1136 
1137  Require_EC_GROUP(self, group);
1138 
1139  return INT2NUM(EC_GROUP_get_degree(group));
1140 }
1141 
1142 static VALUE ossl_ec_group_to_string(VALUE self, int format)
1143 {
1144  EC_GROUP *group;
1145  BIO *out;
1146  int i = -1;
1147  VALUE str;
1148 
1149  Get_EC_GROUP(self, group);
1150 
1151  if (!(out = BIO_new(BIO_s_mem())))
1152  ossl_raise(eEC_GROUP, "BIO_new(BIO_s_mem())");
1153 
1154  switch(format) {
1155  case EXPORT_PEM:
1156  i = PEM_write_bio_ECPKParameters(out, group);
1157  break;
1158  case EXPORT_DER:
1159  i = i2d_ECPKParameters_bio(out, group);
1160  break;
1161  default:
1162  BIO_free(out);
1163  ossl_raise(rb_eRuntimeError, "unknown format (internal error)");
1164  }
1165 
1166  if (i != 1) {
1167  BIO_free(out);
1169  }
1170 
1171  str = ossl_membio2str(out);
1172 
1173  return str;
1174 }
1175 
1176 /* call-seq:
1177  * group.to_pem => String
1178  *
1179  * See the OpenSSL documentation for PEM_write_bio_ECPKParameters()
1180  */
1181 static VALUE ossl_ec_group_to_pem(VALUE self)
1182 {
1183  return ossl_ec_group_to_string(self, EXPORT_PEM);
1184 }
1185 
1186 /* call-seq:
1187  * group.to_der => String
1188  *
1189  * See the OpenSSL documentation for i2d_ECPKParameters_bio()
1190  */
1191 static VALUE ossl_ec_group_to_der(VALUE self)
1192 {
1193  return ossl_ec_group_to_string(self, EXPORT_DER);
1194 }
1195 
1196 /* call-seq:
1197  * group.to_text => String
1198  *
1199  * See the OpenSSL documentation for ECPKParameters_print()
1200  */
1201 static VALUE ossl_ec_group_to_text(VALUE self)
1202 {
1203  EC_GROUP *group;
1204  BIO *out;
1205  VALUE str;
1206 
1207  Require_EC_GROUP(self, group);
1208  if (!(out = BIO_new(BIO_s_mem()))) {
1209  ossl_raise(eEC_GROUP, "BIO_new(BIO_s_mem())");
1210  }
1211  if (!ECPKParameters_print(out, group, 0)) {
1212  BIO_free(out);
1214  }
1215  str = ossl_membio2str(out);
1216 
1217  return str;
1218 }
1219 
1220 
1221 static void ossl_ec_point_free(ossl_ec_point *ec_point)
1222 {
1223  if (!ec_point->dont_free && ec_point->point)
1224  EC_POINT_clear_free(ec_point->point);
1225  ruby_xfree(ec_point);
1226 }
1227 
1228 static VALUE ossl_ec_point_alloc(VALUE klass)
1229 {
1230  ossl_ec_point *ec_point;
1231  VALUE obj;
1232 
1233  obj = Data_Make_Struct(klass, ossl_ec_point, 0, ossl_ec_point_free, ec_point);
1234 
1235  return obj;
1236 }
1237 
1238 /*
1239  * call-seq:
1240  * OpenSSL::PKey::EC::Point.new(point)
1241  * OpenSSL::PKey::EC::Point.new(group)
1242  * OpenSSL::PKey::EC::Point.new(group, bn)
1243  *
1244  * See the OpenSSL documentation for EC_POINT_*
1245  */
1246 static VALUE ossl_ec_point_initialize(int argc, VALUE *argv, VALUE self)
1247 {
1248  ossl_ec_point *ec_point;
1249  EC_POINT *point = NULL;
1250  VALUE arg1, arg2;
1251  VALUE group_v = Qnil;
1252  const EC_GROUP *group = NULL;
1253 
1254  Data_Get_Struct(self, ossl_ec_point, ec_point);
1255  if (ec_point->point)
1256  ossl_raise(eEC_POINT, "EC_POINT already initialized");
1257 
1258  switch (rb_scan_args(argc, argv, "11", &arg1, &arg2)) {
1259  case 1:
1260  if (rb_obj_is_kind_of(arg1, cEC_POINT)) {
1261  const EC_POINT *arg_point;
1262 
1263  group_v = rb_iv_get(arg1, "@group");
1264  SafeRequire_EC_GROUP(group_v, group);
1265  SafeRequire_EC_POINT(arg1, arg_point);
1266 
1267  point = EC_POINT_dup(arg_point, group);
1268  } else if (rb_obj_is_kind_of(arg1, cEC_GROUP)) {
1269  group_v = arg1;
1270  SafeRequire_EC_GROUP(group_v, group);
1271 
1272  point = EC_POINT_new(group);
1273  } else {
1274  ossl_raise(eEC_POINT, "wrong argument type: must be OpenSSL::PKey::EC::Point or OpenSSL::Pkey::EC::Group");
1275  }
1276 
1277  break;
1278  case 2:
1279  if (!rb_obj_is_kind_of(arg1, cEC_GROUP))
1280  ossl_raise(rb_eArgError, "1st argument must be OpenSSL::PKey::EC::Group");
1281  group_v = arg1;
1282  SafeRequire_EC_GROUP(group_v, group);
1283 
1284  if (rb_obj_is_kind_of(arg2, cBN)) {
1285  const BIGNUM *bn = GetBNPtr(arg2);
1286 
1287  point = EC_POINT_bn2point(group, bn, NULL, ossl_bn_ctx);
1288  } else {
1289  BIO *in = ossl_obj2bio(arg1);
1290 
1291 /* BUG: finish me */
1292 
1293  BIO_free(in);
1294 
1295  if (point == NULL) {
1296  ossl_raise(eEC_POINT, "unknown type for 2nd arg");
1297  }
1298  }
1299  break;
1300  default:
1301  ossl_raise(rb_eArgError, "wrong number of arguments");
1302  }
1303 
1304  if (point == NULL)
1306 
1307  if (NIL_P(group_v))
1308  ossl_raise(rb_eRuntimeError, "missing group (internal error)");
1309 
1310  ec_point->point = point;
1311 
1312  rb_iv_set(self, "@group", group_v);
1313 
1314  return self;
1315 }
1316 
1317 /*
1318  * call-seq:
1319  * point1 == point2 => true | false
1320  *
1321  */
1322 static VALUE ossl_ec_point_eql(VALUE a, VALUE b)
1323 {
1324  EC_POINT *point1, *point2;
1325  VALUE group_v1 = rb_iv_get(a, "@group");
1326  VALUE group_v2 = rb_iv_get(b, "@group");
1327  const EC_GROUP *group;
1328 
1329  if (ossl_ec_group_eql(group_v1, group_v2) == Qfalse)
1330  return Qfalse;
1331 
1332  Require_EC_POINT(a, point1);
1333  SafeRequire_EC_POINT(b, point2);
1334  SafeRequire_EC_GROUP(group_v1, group);
1335 
1336  if (EC_POINT_cmp(group, point1, point2, ossl_bn_ctx) == 1)
1337  return Qfalse;
1338 
1339  return Qtrue;
1340 }
1341 
1342 /*
1343  * call-seq:
1344  * point.infinity? => true | false
1345  *
1346  */
1347 static VALUE ossl_ec_point_is_at_infinity(VALUE self)
1348 {
1349  EC_POINT *point;
1350  VALUE group_v = rb_iv_get(self, "@group");
1351  const EC_GROUP *group;
1352 
1353  Require_EC_POINT(self, point);
1354  SafeRequire_EC_GROUP(group_v, group);
1355 
1356  switch (EC_POINT_is_at_infinity(group, point)) {
1357  case 1: return Qtrue;
1358  case 0: return Qfalse;
1359  default: ossl_raise(cEC_POINT, "EC_POINT_is_at_infinity");
1360  }
1361 
1362  UNREACHABLE;
1363 }
1364 
1365 /*
1366  * call-seq:
1367  * point.on_curve? => true | false
1368  *
1369  */
1370 static VALUE ossl_ec_point_is_on_curve(VALUE self)
1371 {
1372  EC_POINT *point;
1373  VALUE group_v = rb_iv_get(self, "@group");
1374  const EC_GROUP *group;
1375 
1376  Require_EC_POINT(self, point);
1377  SafeRequire_EC_GROUP(group_v, group);
1378 
1379  switch (EC_POINT_is_on_curve(group, point, ossl_bn_ctx)) {
1380  case 1: return Qtrue;
1381  case 0: return Qfalse;
1382  default: ossl_raise(cEC_POINT, "EC_POINT_is_on_curve");
1383  }
1384 
1385  UNREACHABLE;
1386 }
1387 
1388 /*
1389  * call-seq:
1390  * point.make_affine! => self
1391  *
1392  */
1393 static VALUE ossl_ec_point_make_affine(VALUE self)
1394 {
1395  EC_POINT *point;
1396  VALUE group_v = rb_iv_get(self, "@group");
1397  const EC_GROUP *group;
1398 
1399  Require_EC_POINT(self, point);
1400  SafeRequire_EC_GROUP(group_v, group);
1401 
1402  if (EC_POINT_make_affine(group, point, ossl_bn_ctx) != 1)
1403  ossl_raise(cEC_POINT, "EC_POINT_make_affine");
1404 
1405  return self;
1406 }
1407 
1408 /*
1409  * call-seq:
1410  * point.invert! => self
1411  *
1412  */
1413 static VALUE ossl_ec_point_invert(VALUE self)
1414 {
1415  EC_POINT *point;
1416  VALUE group_v = rb_iv_get(self, "@group");
1417  const EC_GROUP *group;
1418 
1419  Require_EC_POINT(self, point);
1420  SafeRequire_EC_GROUP(group_v, group);
1421 
1422  if (EC_POINT_invert(group, point, ossl_bn_ctx) != 1)
1423  ossl_raise(cEC_POINT, "EC_POINT_invert");
1424 
1425  return self;
1426 }
1427 
1428 /*
1429  * call-seq:
1430  * point.set_to_infinity! => self
1431  *
1432  */
1433 static VALUE ossl_ec_point_set_to_infinity(VALUE self)
1434 {
1435  EC_POINT *point;
1436  VALUE group_v = rb_iv_get(self, "@group");
1437  const EC_GROUP *group;
1438 
1439  Require_EC_POINT(self, point);
1440  SafeRequire_EC_GROUP(group_v, group);
1441 
1442  if (EC_POINT_set_to_infinity(group, point) != 1)
1443  ossl_raise(cEC_POINT, "EC_POINT_set_to_infinity");
1444 
1445  return self;
1446 }
1447 
1448 /*
1449  * call-seq:
1450  * point.to_bn => OpenSSL::BN
1451  *
1452  * See the OpenSSL documentation for EC_POINT_point2bn()
1453  */
1454 static VALUE ossl_ec_point_to_bn(VALUE self)
1455 {
1456  EC_POINT *point;
1457  VALUE bn_obj;
1458  VALUE group_v = rb_iv_get(self, "@group");
1459  const EC_GROUP *group;
1460  point_conversion_form_t form;
1461  BIGNUM *bn;
1462 
1463  Require_EC_POINT(self, point);
1464  SafeRequire_EC_GROUP(group_v, group);
1465 
1466  form = EC_GROUP_get_point_conversion_form(group);
1467 
1468  bn_obj = rb_obj_alloc(cBN);
1469  bn = GetBNPtr(bn_obj);
1470 
1471  if (EC_POINT_point2bn(group, point, form, bn, ossl_bn_ctx) == NULL)
1472  ossl_raise(eEC_POINT, "EC_POINT_point2bn");
1473 
1474  return bn_obj;
1475 }
1476 
1477 /*
1478  * call-seq:
1479  * point.mul(bn) => point
1480  * point.mul(bn, bn) => point
1481  * point.mul([bn], [point]) => point
1482  * point.mul([bn], [point], bn) => point
1483  */
1484 static VALUE ossl_ec_point_mul(int argc, VALUE *argv, VALUE self)
1485 {
1486  EC_POINT *point1, *point2;
1487  const EC_GROUP *group;
1488  VALUE group_v = rb_iv_get(self, "@group");
1489  VALUE bn_v1, bn_v2, r, points_v;
1490  BIGNUM *bn1 = NULL, *bn2 = NULL;
1491 
1492  Require_EC_POINT(self, point1);
1493  SafeRequire_EC_GROUP(group_v, group);
1494 
1495  r = rb_obj_alloc(cEC_POINT);
1496  ossl_ec_point_initialize(1, &group_v, r);
1497  Require_EC_POINT(r, point2);
1498 
1499  argc = rb_scan_args(argc, argv, "12", &bn_v1, &points_v, &bn_v2);
1500 
1501  if (rb_obj_is_kind_of(bn_v1, cBN)) {
1502  bn1 = GetBNPtr(bn_v1);
1503  if (argc >= 2) {
1504  bn2 = GetBNPtr(points_v);
1505  }
1506  if (EC_POINT_mul(group, point2, bn2, point1, bn1, ossl_bn_ctx) != 1)
1507  ossl_raise(eEC_POINT, "Multiplication failed");
1508  } else {
1509  size_t i, points_len, bignums_len;
1510  const EC_POINT **points;
1511  const BIGNUM **bignums;
1512 
1513  Check_Type(bn_v1, T_ARRAY);
1514  bignums_len = RARRAY_LEN(bn_v1);
1515  bignums = (const BIGNUM **)OPENSSL_malloc(bignums_len * (int)sizeof(BIGNUM *));
1516 
1517  for (i = 0; i < bignums_len; ++i) {
1518  bignums[i] = GetBNPtr(rb_ary_entry(bn_v1, i));
1519  }
1520 
1521  if (!rb_obj_is_kind_of(points_v, rb_cArray)) {
1522  OPENSSL_free((void *)bignums);
1523  rb_raise(rb_eTypeError, "Argument2 must be an array");
1524  }
1525 
1526  rb_ary_unshift(points_v, self);
1527  points_len = RARRAY_LEN(points_v);
1528  points = (const EC_POINT **)OPENSSL_malloc(points_len * (int)sizeof(EC_POINT *));
1529 
1530  for (i = 0; i < points_len; ++i) {
1531  Get_EC_POINT(rb_ary_entry(points_v, i), points[i]);
1532  }
1533 
1534  if (argc >= 3) {
1535  bn2 = GetBNPtr(bn_v2);
1536  }
1537  if (EC_POINTs_mul(group, point2, bn2, points_len, points, bignums, ossl_bn_ctx) != 1) {
1538  OPENSSL_free((void *)bignums);
1539  OPENSSL_free((void *)points);
1540  ossl_raise(eEC_POINT, "Multiplication failed");
1541  }
1542  OPENSSL_free((void *)bignums);
1543  OPENSSL_free((void *)points);
1544  }
1545 
1546  return r;
1547 }
1548 
1549 static void no_copy(VALUE klass)
1550 {
1551  rb_undef_method(klass, "copy");
1552  rb_undef_method(klass, "clone");
1553  rb_undef_method(klass, "dup");
1554  rb_undef_method(klass, "initialize_copy");
1555 }
1556 
1557 void Init_ossl_ec()
1558 {
1559 #ifdef DONT_NEED_RDOC_WORKAROUND
1560  mOSSL = rb_define_module("OpenSSL");
1561  mPKey = rb_define_module_under(mOSSL, "PKey");
1562 #endif
1563 
1565 
1571 
1572  s_GFp = rb_intern("GFp");
1573  s_GF2m = rb_intern("GF2m");
1574  s_GFp_simple = rb_intern("GFp_simple");
1575  s_GFp_mont = rb_intern("GFp_mont");
1576  s_GFp_nist = rb_intern("GFp_nist");
1577  s_GF2m_simple = rb_intern("GF2m_simple");
1578 
1579  ID_uncompressed = rb_intern("uncompressed");
1580  ID_compressed = rb_intern("compressed");
1581  ID_hybrid = rb_intern("hybrid");
1582 
1583 #ifdef OPENSSL_EC_NAMED_CURVE
1584  rb_define_const(cEC, "NAMED_CURVE", ULONG2NUM(OPENSSL_EC_NAMED_CURVE));
1585 #endif
1586 
1587  rb_define_singleton_method(cEC, "builtin_curves", ossl_s_builtin_curves, 0);
1588 
1589  rb_define_method(cEC, "initialize", ossl_ec_key_initialize, -1);
1590 /* copy/dup/cmp */
1591 
1592  rb_define_method(cEC, "group", ossl_ec_key_get_group, 0);
1593  rb_define_method(cEC, "group=", ossl_ec_key_set_group, 1);
1594  rb_define_method(cEC, "private_key", ossl_ec_key_get_private_key, 0);
1595  rb_define_method(cEC, "private_key=", ossl_ec_key_set_private_key, 1);
1596  rb_define_method(cEC, "public_key", ossl_ec_key_get_public_key, 0);
1597  rb_define_method(cEC, "public_key=", ossl_ec_key_set_public_key, 1);
1598  rb_define_method(cEC, "private_key?", ossl_ec_key_is_private_key, 0);
1599  rb_define_method(cEC, "public_key?", ossl_ec_key_is_public_key, 0);
1600 /* rb_define_method(cEC, "", ossl_ec_key_get_, 0);
1601  rb_define_method(cEC, "=", ossl_ec_key_set_ 1);
1602  set/get enc_flags
1603  set/get _conv_from
1604  set/get asn1_flag (can use ruby to call self.group.asn1_flag)
1605  set/get precompute_mult
1606 */
1607  rb_define_method(cEC, "generate_key", ossl_ec_key_generate_key, 0);
1608  rb_define_method(cEC, "check_key", ossl_ec_key_check_key, 0);
1609 
1610  rb_define_method(cEC, "dh_compute_key", ossl_ec_key_dh_compute_key, 1);
1611  rb_define_method(cEC, "dsa_sign_asn1", ossl_ec_key_dsa_sign_asn1, 1);
1612  rb_define_method(cEC, "dsa_verify_asn1", ossl_ec_key_dsa_verify_asn1, 2);
1613 /* do_sign/do_verify */
1614 
1615  rb_define_method(cEC, "export", ossl_ec_key_export, -1);
1616  rb_define_alias(cEC, "to_pem", "export");
1617  rb_define_method(cEC, "to_der", ossl_ec_key_to_der, 0);
1618  rb_define_method(cEC, "to_text", ossl_ec_key_to_text, 0);
1619 
1620 
1621  rb_define_alloc_func(cEC_GROUP, ossl_ec_group_alloc);
1622  rb_define_method(cEC_GROUP, "initialize", ossl_ec_group_initialize, -1);
1623  rb_define_method(cEC_GROUP, "eql?", ossl_ec_group_eql, 1);
1624  rb_define_alias(cEC_GROUP, "==", "eql?");
1625 /* copy/dup/cmp */
1626 
1627  rb_define_method(cEC_GROUP, "generator", ossl_ec_group_get_generator, 0);
1628  rb_define_method(cEC_GROUP, "set_generator", ossl_ec_group_set_generator, 3);
1629  rb_define_method(cEC_GROUP, "order", ossl_ec_group_get_order, 0);
1630  rb_define_method(cEC_GROUP, "cofactor", ossl_ec_group_get_cofactor, 0);
1631 
1632  rb_define_method(cEC_GROUP, "curve_name", ossl_ec_group_get_curve_name, 0);
1633 /* rb_define_method(cEC_GROUP, "curve_name=", ossl_ec_group_set_curve_name, 1); */
1634 
1635  rb_define_method(cEC_GROUP, "asn1_flag", ossl_ec_group_get_asn1_flag, 0);
1636  rb_define_method(cEC_GROUP, "asn1_flag=", ossl_ec_group_set_asn1_flag, 1);
1637 
1638  rb_define_method(cEC_GROUP, "point_conversion_form", ossl_ec_group_get_point_conversion_form, 0);
1639  rb_define_method(cEC_GROUP, "point_conversion_form=", ossl_ec_group_set_point_conversion_form, 1);
1640 
1641  rb_define_method(cEC_GROUP, "seed", ossl_ec_group_get_seed, 0);
1642  rb_define_method(cEC_GROUP, "seed=", ossl_ec_group_set_seed, 1);
1643 
1644 /* get/set GFp, GF2m */
1645 
1646  rb_define_method(cEC_GROUP, "degree", ossl_ec_group_get_degree, 0);
1647 
1648 /* check* */
1649 
1650 
1651  rb_define_method(cEC_GROUP, "to_pem", ossl_ec_group_to_pem, 0);
1652  rb_define_method(cEC_GROUP, "to_der", ossl_ec_group_to_der, 0);
1653  rb_define_method(cEC_GROUP, "to_text", ossl_ec_group_to_text, 0);
1654 
1655 
1656  rb_define_alloc_func(cEC_POINT, ossl_ec_point_alloc);
1657  rb_define_method(cEC_POINT, "initialize", ossl_ec_point_initialize, -1);
1658  rb_attr(cEC_POINT, rb_intern("group"), 1, 0, 0);
1659  rb_define_method(cEC_POINT, "eql?", ossl_ec_point_eql, 1);
1660  rb_define_alias(cEC_POINT, "==", "eql?");
1661 
1662  rb_define_method(cEC_POINT, "infinity?", ossl_ec_point_is_at_infinity, 0);
1663  rb_define_method(cEC_POINT, "on_curve?", ossl_ec_point_is_on_curve, 0);
1664  rb_define_method(cEC_POINT, "make_affine!", ossl_ec_point_make_affine, 0);
1665  rb_define_method(cEC_POINT, "invert!", ossl_ec_point_invert, 0);
1666  rb_define_method(cEC_POINT, "set_to_infinity!", ossl_ec_point_set_to_infinity, 0);
1667 /* all the other methods */
1668 
1669  rb_define_method(cEC_POINT, "to_bn", ossl_ec_point_to_bn, 0);
1670  rb_define_method(cEC_POINT, "mul", ossl_ec_point_mul, -1);
1671 
1672  no_copy(cEC);
1673  no_copy(cEC_GROUP);
1674  no_copy(cEC_POINT);
1675 }
1676 
1677 #else /* defined NO_EC */
1679 {
1680 }
1681 #endif /* NO_EC */
VALUE rb_ary_unshift(VALUE ary, VALUE item)
Definition: array.c:1084
VALUE mOSSL
Definition: ossl.c:259
VALUE rb_ary_entry(VALUE ary, long offset)
Definition: array.c:1101
#define RARRAY_LEN(a)
Definition: ruby.h:899
#define INT2NUM(x)
Definition: ruby.h:1178
int i
Definition: win32ole.c:784
#define NUM2INT(x)
Definition: ruby.h:622
VALUE eEC_GROUP
#define Data_Get_Struct(obj, type, sval)
Definition: ruby.h:1025
void rb_define_singleton_method(VALUE obj, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a singleton method for obj.
Definition: class.c:1497
VALUE mPKey
Definition: ossl_pkey.c:16
VALUE ePKeyError
Definition: ossl_pkey.c:18
#define Qtrue
Definition: ruby.h:434
VALUE rb_eTypeError
Definition: error.c:511
#define UNREACHABLE
Definition: ruby.h:40
#define ULONG2NUM(x)
Definition: ruby.h:1209
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:822
#define rb_long2int(n)
Definition: ruby.h:325
#define SYM2ID(x)
Definition: ruby.h:364
VALUE rb_funcall(VALUE, ID, int,...)
Calls a method.
Definition: vm_eval.c:774
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:545
#define Check_Type(v, t)
Definition: ruby.h:539
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1780
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
VALUE rb_obj_is_kind_of(VALUE, VALUE)
Definition: object.c:582
VALUE eEC_POINT
#define GetPKey(obj, pkey)
Definition: ossl_pkey.h:30
#define T_ARRAY
Definition: ruby.h:492
VALUE ossl_membio2str(BIO *bio)
Definition: ossl_bio.c:77
void rb_undef_method(VALUE klass, const char *name)
Definition: class.c:1362
#define OSSL_MIN_PWD_LEN
Definition: ossl.h:81
Win32OLEIDispatch * p
Definition: win32ole.c:786
RUBY_EXTERN VALUE rb_cObject
Definition: ruby.h:1426
VALUE rb_eRuntimeError
Definition: error.c:510
void rb_attr(VALUE, ID, int, int, int)
Definition: vm_method.c:796
#define OSSL_BIO_reset(bio)
Definition: ossl.h:155
VALUE rb_iv_get(VALUE, const char *)
Definition: variable.c:2583
#define NIL_P(v)
Definition: ruby.h:446
void rb_define_const(VALUE, const char *, VALUE)
Definition: variable.c:2202
VALUE eOSSLError
Definition: ossl.c:264
int argc
Definition: ruby.c:130
#define Qfalse
Definition: ruby.h:433
#define ALLOCA_N(type, n)
Definition: ruby.h:1227
VALUE rb_obj_alloc(VALUE)
Definition: object.c:1721
const EVP_CIPHER * GetCipherPtr(VALUE obj)
Definition: ossl_cipher.c:45
VALUE rb_str_resize(VALUE, long)
Definition: string.c:1853
void Init_ossl_ec()
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition: class.c:1539
#define RSTRING_LEN(str)
Definition: ruby.h:862
#define WrapPKey(klass, obj, pkey)
Definition: ossl_pkey.h:23
BIO * ossl_obj2bio(VALUE obj)
Definition: ossl_bio.c:17
VALUE rb_iv_set(VALUE, const char *, VALUE)
Definition: variable.c:2591
void ruby_xfree(void *x)
Definition: gc.c:3651
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1570
VALUE cEC_GROUP
unsigned long ID
Definition: ruby.h:105
#define Qnil
Definition: ruby.h:435
unsigned long VALUE
Definition: ruby.h:104
VALUE cBN
Definition: ossl_bn.c:36
#define Data_Make_Struct(klass, type, mark, free, sval)
Definition: ruby.h:1010
VALUE rb_define_module_under(VALUE outer, const char *name)
Definition: class.c:637
#define StringValueCStr(v)
Definition: ruby.h:548
VALUE cEC_POINT
#define RSTRING_PTR(str)
Definition: ruby.h:866
#define INT2FIX(i)
Definition: ruby.h:241
VALUE eECError
BN_CTX * ossl_bn_ctx
Definition: ossl_bn.c:89
void ossl_raise(VALUE exc, const char *fmt,...)
Definition: ossl.c:328
VALUE rb_cArray
Definition: array.c:29
VALUE rb_ary_new2(long capa)
Definition: array.c:417
const char * name
Definition: nkf.c:208
#define ID2SYM(x)
Definition: ruby.h:363
VALUE ossl_bn_new(const BIGNUM *bn)
Definition: ossl_bn.c:43
#define StringValuePtr(v)
Definition: ruby.h:547
int ossl_pem_passwd_cb(char *buf, int max_len, int flag, void *pwd)
Definition: ossl.c:162
#define RSTRING_LENINT(str)
Definition: ruby.h:874
BIGNUM * GetBNPtr(VALUE obj)
Definition: ossl_bn.c:58
VALUE rb_define_module(const char *name)
Definition: class.c:617
VALUE cEC
VALUE cPKey
Definition: ossl_pkey.c:17
#define rb_intern(str)
#define SYMBOL_P(x)
Definition: ruby.h:362
#define NULL
Definition: _sdbm.c:103
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1344
VALUE rb_str_new2(const char *)
VALUE ossl_ec_new(EVP_PKEY *)
VALUE rb_eArgError
Definition: error.c:512
char ** argv
Definition: ruby.c:131
#define StringValue(v)
Definition: ruby.h:546
VALUE rb_str_new(const char *, long)
Definition: string.c:425