Ruby  2.0.0p247(2013-06-27revision41674)
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  } else if (id == s_GF2m_simple) {
766  method = EC_GF2m_simple_method();
767  }
768 
769  if (method) {
770  if ((group = EC_GROUP_new(method)) == NULL)
771  ossl_raise(eEC_GROUP, "EC_GROUP_new");
772  } else {
773  ossl_raise(rb_eArgError, "unknown symbol, must be :GFp_simple, :GFp_mont, :GFp_nist or :GF2m_simple");
774  }
775  } else if (rb_obj_is_kind_of(arg1, cEC_GROUP)) {
776  const EC_GROUP *arg1_group;
777 
778  SafeRequire_EC_GROUP(arg1, arg1_group);
779  if ((group = EC_GROUP_dup(arg1_group)) == NULL)
780  ossl_raise(eEC_GROUP, "EC_GROUP_dup");
781  } else {
782  BIO *in = ossl_obj2bio(arg1);
783 
784  group = PEM_read_bio_ECPKParameters(in, NULL, NULL, NULL);
785  if (!group) {
786  OSSL_BIO_reset(in);
787  group = d2i_ECPKParameters_bio(in, NULL);
788  }
789 
790  BIO_free(in);
791 
792  if (!group) {
793  const char *name = StringValueCStr(arg1);
794  int nid = OBJ_sn2nid(name);
795 
796  (void)ERR_get_error();
797  if (nid == NID_undef)
798  ossl_raise(eEC_GROUP, "unknown curve name (%s)", name);
799 
800  group = EC_GROUP_new_by_curve_name(nid);
801  if (group == NULL)
802  ossl_raise(eEC_GROUP, "unable to create curve (%s)", name);
803 
804  EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE);
805  EC_GROUP_set_point_conversion_form(group, POINT_CONVERSION_UNCOMPRESSED);
806  }
807  }
808 
809  break;
810  case 4:
811  if (SYMBOL_P(arg1)) {
812  ID id = SYM2ID(arg1);
813  EC_GROUP *(*new_curve)(const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *) = NULL;
814  const BIGNUM *p = GetBNPtr(arg2);
815  const BIGNUM *a = GetBNPtr(arg3);
816  const BIGNUM *b = GetBNPtr(arg4);
817 
818  if (id == s_GFp) {
819  new_curve = EC_GROUP_new_curve_GFp;
820  } else if (id == s_GF2m) {
821  new_curve = EC_GROUP_new_curve_GF2m;
822  } else {
823  ossl_raise(rb_eArgError, "unknown symbol, must be :GFp or :GF2m");
824  }
825 
826  if ((group = new_curve(p, a, b, ossl_bn_ctx)) == NULL)
827  ossl_raise(eEC_GROUP, "EC_GROUP_new_by_GF*");
828  } else {
829  ossl_raise(rb_eArgError, "unknown argument, must be :GFp or :GF2m");
830  }
831 
832  break;
833  default:
834  ossl_raise(rb_eArgError, "wrong number of arguments");
835  }
836 
837  if (group == NULL)
838  ossl_raise(eEC_GROUP, "");
839 
840  ec_group->group = group;
841 
842  return self;
843 }
844 
845 /* call-seq:
846  * group1 == group2 => true | false
847  *
848  */
849 static VALUE ossl_ec_group_eql(VALUE a, VALUE b)
850 {
851  EC_GROUP *group1 = NULL, *group2 = NULL;
852 
853  Require_EC_GROUP(a, group1);
854  SafeRequire_EC_GROUP(b, group2);
855 
856  if (EC_GROUP_cmp(group1, group2, ossl_bn_ctx) == 1)
857  return Qfalse;
858 
859  return Qtrue;
860 }
861 
862 /* call-seq:
863  * group.generator => ec_point
864  *
865  * See the OpenSSL documentation for EC_GROUP_get0_generator()
866  */
867 static VALUE ossl_ec_group_get_generator(VALUE self)
868 {
869  VALUE point_obj;
870  EC_GROUP *group = NULL;
871 
872  Require_EC_GROUP(self, group);
873 
874  point_obj = ossl_ec_point_dup(EC_GROUP_get0_generator(group), self);
875 
876  return point_obj;
877 }
878 
879 /* call-seq:
880  * group.set_generator(generator, order, cofactor) => self
881  *
882  * See the OpenSSL documentation for EC_GROUP_set_generator()
883  */
884 static VALUE ossl_ec_group_set_generator(VALUE self, VALUE generator, VALUE order, VALUE cofactor)
885 {
886  EC_GROUP *group = NULL;
887  const EC_POINT *point;
888  const BIGNUM *o, *co;
889 
890  Require_EC_GROUP(self, group);
891  SafeRequire_EC_POINT(generator, point);
892  o = GetBNPtr(order);
893  co = GetBNPtr(cofactor);
894 
895  if (EC_GROUP_set_generator(group, point, o, co) != 1)
896  ossl_raise(eEC_GROUP, "EC_GROUP_set_generator");
897 
898  return self;
899 }
900 
901 /* call-seq:
902  * group.get_order => order_bn
903  *
904  * See the OpenSSL documentation for EC_GROUP_get_order()
905  */
906 static VALUE ossl_ec_group_get_order(VALUE self)
907 {
908  VALUE bn_obj;
909  BIGNUM *bn;
910  EC_GROUP *group = NULL;
911 
912  Require_EC_GROUP(self, group);
913 
914  bn_obj = ossl_bn_new(NULL);
915  bn = GetBNPtr(bn_obj);
916 
917  if (EC_GROUP_get_order(group, bn, ossl_bn_ctx) != 1)
918  ossl_raise(eEC_GROUP, "EC_GROUP_get_order");
919 
920  return bn_obj;
921 }
922 
923 /* call-seq:
924  * group.get_cofactor => cofactor_bn
925  *
926  * See the OpenSSL documentation for EC_GROUP_get_cofactor()
927  */
928 static VALUE ossl_ec_group_get_cofactor(VALUE self)
929 {
930  VALUE bn_obj;
931  BIGNUM *bn;
932  EC_GROUP *group = NULL;
933 
934  Require_EC_GROUP(self, group);
935 
936  bn_obj = ossl_bn_new(NULL);
937  bn = GetBNPtr(bn_obj);
938 
939  if (EC_GROUP_get_cofactor(group, bn, ossl_bn_ctx) != 1)
940  ossl_raise(eEC_GROUP, "EC_GROUP_get_cofactor");
941 
942  return bn_obj;
943 }
944 
945 /* call-seq:
946  * group.curve_name => String
947  *
948  * See the OpenSSL documentation for EC_GROUP_get_curve_name()
949  */
950 static VALUE ossl_ec_group_get_curve_name(VALUE self)
951 {
952  EC_GROUP *group = NULL;
953  int nid;
954 
955  Get_EC_GROUP(self, group);
956  if (group == NULL)
957  return Qnil;
958 
959  nid = EC_GROUP_get_curve_name(group);
960 
961 /* BUG: an nid or asn1 object should be returned, maybe. */
962  return rb_str_new2(OBJ_nid2sn(nid));
963 }
964 
965 /* call-seq:
966  * EC.builtin_curves => [[name, comment], ...]
967  *
968  * See the OpenSSL documentation for EC_builtin_curves()
969  */
970 static VALUE ossl_s_builtin_curves(VALUE self)
971 {
972  EC_builtin_curve *curves = NULL;
973  int n;
974  int crv_len = rb_long2int(EC_get_builtin_curves(NULL, 0));
975  VALUE ary, ret;
976 
977  curves = ALLOCA_N(EC_builtin_curve, crv_len);
978  if (curves == NULL)
979  return Qnil;
980  if (!EC_get_builtin_curves(curves, crv_len))
981  ossl_raise(rb_eRuntimeError, "EC_get_builtin_curves");
982 
983  ret = rb_ary_new2(crv_len);
984 
985  for (n = 0; n < crv_len; n++) {
986  const char *sname = OBJ_nid2sn(curves[n].nid);
987  const char *comment = curves[n].comment;
988 
989  ary = rb_ary_new2(2);
990  rb_ary_push(ary, rb_str_new2(sname));
991  rb_ary_push(ary, comment ? rb_str_new2(comment) : Qnil);
992  rb_ary_push(ret, ary);
993  }
994 
995  return ret;
996 }
997 
998 /* call-seq:
999  * group.asn1_flag => Fixnum
1000  *
1001  * See the OpenSSL documentation for EC_GROUP_get_asn1_flag()
1002  */
1003 static VALUE ossl_ec_group_get_asn1_flag(VALUE self)
1004 {
1005  EC_GROUP *group = NULL;
1006  int flag;
1007 
1008  Require_EC_GROUP(self, group);
1009 
1010  flag = EC_GROUP_get_asn1_flag(group);
1011 
1012  return INT2FIX(flag);
1013 }
1014 
1015 /* call-seq:
1016  * group.asn1_flag = Fixnum => Fixnum
1017  *
1018  * See the OpenSSL documentation for EC_GROUP_set_asn1_flag()
1019  */
1020 static VALUE ossl_ec_group_set_asn1_flag(VALUE self, VALUE flag_v)
1021 {
1022  EC_GROUP *group = NULL;
1023 
1024  Require_EC_GROUP(self, group);
1025 
1026  EC_GROUP_set_asn1_flag(group, NUM2INT(flag_v));
1027 
1028  return flag_v;
1029 }
1030 
1031 /* call-seq:
1032  * group.point_conversion_form => :uncompressed | :compressed | :hybrid
1033  *
1034  * See the OpenSSL documentation for EC_GROUP_get_point_conversion_form()
1035  */
1036 static VALUE ossl_ec_group_get_point_conversion_form(VALUE self)
1037 {
1038  EC_GROUP *group = NULL;
1039  point_conversion_form_t form;
1040  VALUE ret;
1041 
1042  Require_EC_GROUP(self, group);
1043 
1044  form = EC_GROUP_get_point_conversion_form(group);
1045 
1046  switch (form) {
1047  case POINT_CONVERSION_UNCOMPRESSED: ret = ID_uncompressed; break;
1048  case POINT_CONVERSION_COMPRESSED: ret = ID_compressed; break;
1049  case POINT_CONVERSION_HYBRID: ret = ID_hybrid; break;
1050  default: ossl_raise(eEC_GROUP, "unsupported point conversion form: %d, this module should be updated", form);
1051  }
1052 
1053  return ID2SYM(ret);
1054 }
1055 
1056 /* call-seq:
1057  * group.point_conversion_form = form => form
1058  *
1059  * See the OpenSSL documentation for EC_GROUP_set_point_conversion_form()
1060  */
1061 static VALUE ossl_ec_group_set_point_conversion_form(VALUE self, VALUE form_v)
1062 {
1063  EC_GROUP *group = NULL;
1064  point_conversion_form_t form;
1065  ID form_id = SYM2ID(form_v);
1066 
1067  Require_EC_GROUP(self, group);
1068 
1069  if (form_id == ID_uncompressed) {
1070  form = POINT_CONVERSION_UNCOMPRESSED;
1071  } else if (form_id == ID_compressed) {
1072  form = POINT_CONVERSION_COMPRESSED;
1073  } else if (form_id == ID_hybrid) {
1074  form = POINT_CONVERSION_HYBRID;
1075  } else {
1076  ossl_raise(rb_eArgError, "form must be :compressed, :uncompressed, or :hybrid");
1077  }
1078 
1079  EC_GROUP_set_point_conversion_form(group, form);
1080 
1081  return form_v;
1082 }
1083 
1084 /* call-seq:
1085  * group.seed => String or nil
1086  *
1087  * See the OpenSSL documentation for EC_GROUP_get0_seed()
1088  */
1089 static VALUE ossl_ec_group_get_seed(VALUE self)
1090 {
1091  EC_GROUP *group = NULL;
1092  size_t seed_len;
1093 
1094  Require_EC_GROUP(self, group);
1095 
1096  seed_len = EC_GROUP_get_seed_len(group);
1097 
1098  if (seed_len == 0)
1099  return Qnil;
1100 
1101  return rb_str_new((const char *)EC_GROUP_get0_seed(group), seed_len);
1102 }
1103 
1104 /* call-seq:
1105  * group.seed = seed => seed
1106  *
1107  * See the OpenSSL documentation for EC_GROUP_set_seed()
1108  */
1109 static VALUE ossl_ec_group_set_seed(VALUE self, VALUE seed)
1110 {
1111  EC_GROUP *group = NULL;
1112 
1113  Require_EC_GROUP(self, group);
1114  StringValue(seed);
1115 
1116  if (EC_GROUP_set_seed(group, (unsigned char *)RSTRING_PTR(seed), RSTRING_LEN(seed)) != (size_t)RSTRING_LEN(seed))
1117  ossl_raise(eEC_GROUP, "EC_GROUP_set_seed");
1118 
1119  return seed;
1120 }
1121 
1122 /* get/set curve GFp, GF2m */
1123 
1124 /* call-seq:
1125  * group.degree => Fixnum
1126  *
1127  * See the OpenSSL documentation for EC_GROUP_get_degree()
1128  */
1129 static VALUE ossl_ec_group_get_degree(VALUE self)
1130 {
1131  EC_GROUP *group = NULL;
1132 
1133  Require_EC_GROUP(self, group);
1134 
1135  return INT2NUM(EC_GROUP_get_degree(group));
1136 }
1137 
1138 static VALUE ossl_ec_group_to_string(VALUE self, int format)
1139 {
1140  EC_GROUP *group;
1141  BIO *out;
1142  int i = -1;
1143  VALUE str;
1144 
1145  Get_EC_GROUP(self, group);
1146 
1147  if (!(out = BIO_new(BIO_s_mem())))
1148  ossl_raise(eEC_GROUP, "BIO_new(BIO_s_mem())");
1149 
1150  switch(format) {
1151  case EXPORT_PEM:
1152  i = PEM_write_bio_ECPKParameters(out, group);
1153  break;
1154  case EXPORT_DER:
1155  i = i2d_ECPKParameters_bio(out, group);
1156  break;
1157  default:
1158  BIO_free(out);
1159  ossl_raise(rb_eRuntimeError, "unknown format (internal error)");
1160  }
1161 
1162  if (i != 1) {
1163  BIO_free(out);
1165  }
1166 
1167  str = ossl_membio2str(out);
1168 
1169  return str;
1170 }
1171 
1172 /* call-seq:
1173  * group.to_pem => String
1174  *
1175  * See the OpenSSL documentation for PEM_write_bio_ECPKParameters()
1176  */
1177 static VALUE ossl_ec_group_to_pem(VALUE self)
1178 {
1179  return ossl_ec_group_to_string(self, EXPORT_PEM);
1180 }
1181 
1182 /* call-seq:
1183  * group.to_der => String
1184  *
1185  * See the OpenSSL documentation for i2d_ECPKParameters_bio()
1186  */
1187 static VALUE ossl_ec_group_to_der(VALUE self)
1188 {
1189  return ossl_ec_group_to_string(self, EXPORT_DER);
1190 }
1191 
1192 /* call-seq:
1193  * group.to_text => String
1194  *
1195  * See the OpenSSL documentation for ECPKParameters_print()
1196  */
1197 static VALUE ossl_ec_group_to_text(VALUE self)
1198 {
1199  EC_GROUP *group;
1200  BIO *out;
1201  VALUE str;
1202 
1203  Require_EC_GROUP(self, group);
1204  if (!(out = BIO_new(BIO_s_mem()))) {
1205  ossl_raise(eEC_GROUP, "BIO_new(BIO_s_mem())");
1206  }
1207  if (!ECPKParameters_print(out, group, 0)) {
1208  BIO_free(out);
1210  }
1211  str = ossl_membio2str(out);
1212 
1213  return str;
1214 }
1215 
1216 
1217 static void ossl_ec_point_free(ossl_ec_point *ec_point)
1218 {
1219  if (!ec_point->dont_free && ec_point->point)
1220  EC_POINT_clear_free(ec_point->point);
1221  ruby_xfree(ec_point);
1222 }
1223 
1224 static VALUE ossl_ec_point_alloc(VALUE klass)
1225 {
1226  ossl_ec_point *ec_point;
1227  VALUE obj;
1228 
1229  obj = Data_Make_Struct(klass, ossl_ec_point, 0, ossl_ec_point_free, ec_point);
1230 
1231  return obj;
1232 }
1233 
1234 /*
1235  * call-seq:
1236  * OpenSSL::PKey::EC::Point.new(point)
1237  * OpenSSL::PKey::EC::Point.new(group)
1238  * OpenSSL::PKey::EC::Point.new(group, bn)
1239  *
1240  * See the OpenSSL documentation for EC_POINT_*
1241  */
1242 static VALUE ossl_ec_point_initialize(int argc, VALUE *argv, VALUE self)
1243 {
1244  ossl_ec_point *ec_point;
1245  EC_POINT *point = NULL;
1246  VALUE arg1, arg2;
1247  VALUE group_v = Qnil;
1248  const EC_GROUP *group = NULL;
1249 
1250  Data_Get_Struct(self, ossl_ec_point, ec_point);
1251  if (ec_point->point)
1252  ossl_raise(eEC_POINT, "EC_POINT already initialized");
1253 
1254  switch (rb_scan_args(argc, argv, "11", &arg1, &arg2)) {
1255  case 1:
1256  if (rb_obj_is_kind_of(arg1, cEC_POINT)) {
1257  const EC_POINT *arg_point;
1258 
1259  group_v = rb_iv_get(arg1, "@group");
1260  SafeRequire_EC_GROUP(group_v, group);
1261  SafeRequire_EC_POINT(arg1, arg_point);
1262 
1263  point = EC_POINT_dup(arg_point, group);
1264  } else if (rb_obj_is_kind_of(arg1, cEC_GROUP)) {
1265  group_v = arg1;
1266  SafeRequire_EC_GROUP(group_v, group);
1267 
1268  point = EC_POINT_new(group);
1269  } else {
1270  ossl_raise(eEC_POINT, "wrong argument type: must be OpenSSL::PKey::EC::Point or OpenSSL::Pkey::EC::Group");
1271  }
1272 
1273  break;
1274  case 2:
1275  if (!rb_obj_is_kind_of(arg1, cEC_GROUP))
1276  ossl_raise(rb_eArgError, "1st argument must be OpenSSL::PKey::EC::Group");
1277  group_v = arg1;
1278  SafeRequire_EC_GROUP(group_v, group);
1279 
1280  if (rb_obj_is_kind_of(arg2, cBN)) {
1281  const BIGNUM *bn = GetBNPtr(arg2);
1282 
1283  point = EC_POINT_bn2point(group, bn, NULL, ossl_bn_ctx);
1284  } else {
1285  BIO *in = ossl_obj2bio(arg1);
1286 
1287 /* BUG: finish me */
1288 
1289  BIO_free(in);
1290 
1291  if (point == NULL) {
1292  ossl_raise(eEC_POINT, "unknown type for 2nd arg");
1293  }
1294  }
1295  break;
1296  default:
1297  ossl_raise(rb_eArgError, "wrong number of arguments");
1298  }
1299 
1300  if (point == NULL)
1302 
1303  if (NIL_P(group_v))
1304  ossl_raise(rb_eRuntimeError, "missing group (internal error)");
1305 
1306  ec_point->point = point;
1307 
1308  rb_iv_set(self, "@group", group_v);
1309 
1310  return self;
1311 }
1312 
1313 /*
1314  * call-seq:
1315  * point1 == point2 => true | false
1316  *
1317  */
1318 static VALUE ossl_ec_point_eql(VALUE a, VALUE b)
1319 {
1320  EC_POINT *point1, *point2;
1321  VALUE group_v1 = rb_iv_get(a, "@group");
1322  VALUE group_v2 = rb_iv_get(b, "@group");
1323  const EC_GROUP *group;
1324 
1325  if (ossl_ec_group_eql(group_v1, group_v2) == Qfalse)
1326  return Qfalse;
1327 
1328  Require_EC_POINT(a, point1);
1329  SafeRequire_EC_POINT(b, point2);
1330  SafeRequire_EC_GROUP(group_v1, group);
1331 
1332  if (EC_POINT_cmp(group, point1, point2, ossl_bn_ctx) == 1)
1333  return Qfalse;
1334 
1335  return Qtrue;
1336 }
1337 
1338 /*
1339  * call-seq:
1340  * point.infinity? => true | false
1341  *
1342  */
1343 static VALUE ossl_ec_point_is_at_infinity(VALUE self)
1344 {
1345  EC_POINT *point;
1346  VALUE group_v = rb_iv_get(self, "@group");
1347  const EC_GROUP *group;
1348 
1349  Require_EC_POINT(self, point);
1350  SafeRequire_EC_GROUP(group_v, group);
1351 
1352  switch (EC_POINT_is_at_infinity(group, point)) {
1353  case 1: return Qtrue;
1354  case 0: return Qfalse;
1355  default: ossl_raise(cEC_POINT, "EC_POINT_is_at_infinity");
1356  }
1357 
1358  UNREACHABLE;
1359 }
1360 
1361 /*
1362  * call-seq:
1363  * point.on_curve? => true | false
1364  *
1365  */
1366 static VALUE ossl_ec_point_is_on_curve(VALUE self)
1367 {
1368  EC_POINT *point;
1369  VALUE group_v = rb_iv_get(self, "@group");
1370  const EC_GROUP *group;
1371 
1372  Require_EC_POINT(self, point);
1373  SafeRequire_EC_GROUP(group_v, group);
1374 
1375  switch (EC_POINT_is_on_curve(group, point, ossl_bn_ctx)) {
1376  case 1: return Qtrue;
1377  case 0: return Qfalse;
1378  default: ossl_raise(cEC_POINT, "EC_POINT_is_on_curve");
1379  }
1380 
1381  UNREACHABLE;
1382 }
1383 
1384 /*
1385  * call-seq:
1386  * point.make_affine! => self
1387  *
1388  */
1389 static VALUE ossl_ec_point_make_affine(VALUE self)
1390 {
1391  EC_POINT *point;
1392  VALUE group_v = rb_iv_get(self, "@group");
1393  const EC_GROUP *group;
1394 
1395  Require_EC_POINT(self, point);
1396  SafeRequire_EC_GROUP(group_v, group);
1397 
1398  if (EC_POINT_make_affine(group, point, ossl_bn_ctx) != 1)
1399  ossl_raise(cEC_POINT, "EC_POINT_make_affine");
1400 
1401  return self;
1402 }
1403 
1404 /*
1405  * call-seq:
1406  * point.invert! => self
1407  *
1408  */
1409 static VALUE ossl_ec_point_invert(VALUE self)
1410 {
1411  EC_POINT *point;
1412  VALUE group_v = rb_iv_get(self, "@group");
1413  const EC_GROUP *group;
1414 
1415  Require_EC_POINT(self, point);
1416  SafeRequire_EC_GROUP(group_v, group);
1417 
1418  if (EC_POINT_invert(group, point, ossl_bn_ctx) != 1)
1419  ossl_raise(cEC_POINT, "EC_POINT_invert");
1420 
1421  return self;
1422 }
1423 
1424 /*
1425  * call-seq:
1426  * point.set_to_infinity! => self
1427  *
1428  */
1429 static VALUE ossl_ec_point_set_to_infinity(VALUE self)
1430 {
1431  EC_POINT *point;
1432  VALUE group_v = rb_iv_get(self, "@group");
1433  const EC_GROUP *group;
1434 
1435  Require_EC_POINT(self, point);
1436  SafeRequire_EC_GROUP(group_v, group);
1437 
1438  if (EC_POINT_set_to_infinity(group, point) != 1)
1439  ossl_raise(cEC_POINT, "EC_POINT_set_to_infinity");
1440 
1441  return self;
1442 }
1443 
1444 /*
1445  * call-seq:
1446  * point.to_bn => OpenSSL::BN
1447  *
1448  * See the OpenSSL documentation for EC_POINT_point2bn()
1449  */
1450 static VALUE ossl_ec_point_to_bn(VALUE self)
1451 {
1452  EC_POINT *point;
1453  VALUE bn_obj;
1454  VALUE group_v = rb_iv_get(self, "@group");
1455  const EC_GROUP *group;
1456  point_conversion_form_t form;
1457  BIGNUM *bn;
1458 
1459  Require_EC_POINT(self, point);
1460  SafeRequire_EC_GROUP(group_v, group);
1461 
1462  form = EC_GROUP_get_point_conversion_form(group);
1463 
1464  bn_obj = rb_obj_alloc(cBN);
1465  bn = GetBNPtr(bn_obj);
1466 
1467  if (EC_POINT_point2bn(group, point, form, bn, ossl_bn_ctx) == NULL)
1468  ossl_raise(eEC_POINT, "EC_POINT_point2bn");
1469 
1470  return bn_obj;
1471 }
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 
1545 static void no_copy(VALUE klass)
1546 {
1547  rb_undef_method(klass, "copy");
1548  rb_undef_method(klass, "clone");
1549  rb_undef_method(klass, "dup");
1550  rb_undef_method(klass, "initialize_copy");
1551 }
1552 
1553 void Init_ossl_ec()
1554 {
1555 #ifdef DONT_NEED_RDOC_WORKAROUND
1556  mOSSL = rb_define_module("OpenSSL");
1557  mPKey = rb_define_module_under(mOSSL, "PKey");
1558 #endif
1559 
1561 
1567 
1568  s_GFp = rb_intern("GFp");
1569  s_GF2m = rb_intern("GF2m");
1570  s_GFp_simple = rb_intern("GFp_simple");
1571  s_GFp_mont = rb_intern("GFp_mont");
1572  s_GFp_nist = rb_intern("GFp_nist");
1573  s_GF2m_simple = rb_intern("GF2m_simple");
1574 
1575  ID_uncompressed = rb_intern("uncompressed");
1576  ID_compressed = rb_intern("compressed");
1577  ID_hybrid = rb_intern("hybrid");
1578 
1579 #ifdef OPENSSL_EC_NAMED_CURVE
1580  rb_define_const(cEC, "NAMED_CURVE", ULONG2NUM(OPENSSL_EC_NAMED_CURVE));
1581 #endif
1582 
1583  rb_define_singleton_method(cEC, "builtin_curves", ossl_s_builtin_curves, 0);
1584 
1585  rb_define_method(cEC, "initialize", ossl_ec_key_initialize, -1);
1586 /* copy/dup/cmp */
1587 
1588  rb_define_method(cEC, "group", ossl_ec_key_get_group, 0);
1589  rb_define_method(cEC, "group=", ossl_ec_key_set_group, 1);
1590  rb_define_method(cEC, "private_key", ossl_ec_key_get_private_key, 0);
1591  rb_define_method(cEC, "private_key=", ossl_ec_key_set_private_key, 1);
1592  rb_define_method(cEC, "public_key", ossl_ec_key_get_public_key, 0);
1593  rb_define_method(cEC, "public_key=", ossl_ec_key_set_public_key, 1);
1594  rb_define_method(cEC, "private_key?", ossl_ec_key_is_private_key, 0);
1595  rb_define_method(cEC, "public_key?", ossl_ec_key_is_public_key, 0);
1596 /* rb_define_method(cEC, "", ossl_ec_key_get_, 0);
1597  rb_define_method(cEC, "=", ossl_ec_key_set_ 1);
1598  set/get enc_flags
1599  set/get _conv_from
1600  set/get asn1_flag (can use ruby to call self.group.asn1_flag)
1601  set/get precompute_mult
1602 */
1603  rb_define_method(cEC, "generate_key", ossl_ec_key_generate_key, 0);
1604  rb_define_method(cEC, "check_key", ossl_ec_key_check_key, 0);
1605 
1606  rb_define_method(cEC, "dh_compute_key", ossl_ec_key_dh_compute_key, 1);
1607  rb_define_method(cEC, "dsa_sign_asn1", ossl_ec_key_dsa_sign_asn1, 1);
1608  rb_define_method(cEC, "dsa_verify_asn1", ossl_ec_key_dsa_verify_asn1, 2);
1609 /* do_sign/do_verify */
1610 
1611  rb_define_method(cEC, "export", ossl_ec_key_export, -1);
1612  rb_define_alias(cEC, "to_pem", "export");
1613  rb_define_method(cEC, "to_der", ossl_ec_key_to_der, 0);
1614  rb_define_method(cEC, "to_text", ossl_ec_key_to_text, 0);
1615 
1616 
1617  rb_define_alloc_func(cEC_GROUP, ossl_ec_group_alloc);
1618  rb_define_method(cEC_GROUP, "initialize", ossl_ec_group_initialize, -1);
1619  rb_define_method(cEC_GROUP, "eql?", ossl_ec_group_eql, 1);
1620  rb_define_alias(cEC_GROUP, "==", "eql?");
1621 /* copy/dup/cmp */
1622 
1623  rb_define_method(cEC_GROUP, "generator", ossl_ec_group_get_generator, 0);
1624  rb_define_method(cEC_GROUP, "set_generator", ossl_ec_group_set_generator, 3);
1625  rb_define_method(cEC_GROUP, "order", ossl_ec_group_get_order, 0);
1626  rb_define_method(cEC_GROUP, "cofactor", ossl_ec_group_get_cofactor, 0);
1627 
1628  rb_define_method(cEC_GROUP, "curve_name", ossl_ec_group_get_curve_name, 0);
1629 /* rb_define_method(cEC_GROUP, "curve_name=", ossl_ec_group_set_curve_name, 1); */
1630 
1631  rb_define_method(cEC_GROUP, "asn1_flag", ossl_ec_group_get_asn1_flag, 0);
1632  rb_define_method(cEC_GROUP, "asn1_flag=", ossl_ec_group_set_asn1_flag, 1);
1633 
1634  rb_define_method(cEC_GROUP, "point_conversion_form", ossl_ec_group_get_point_conversion_form, 0);
1635  rb_define_method(cEC_GROUP, "point_conversion_form=", ossl_ec_group_set_point_conversion_form, 1);
1636 
1637  rb_define_method(cEC_GROUP, "seed", ossl_ec_group_get_seed, 0);
1638  rb_define_method(cEC_GROUP, "seed=", ossl_ec_group_set_seed, 1);
1639 
1640 /* get/set GFp, GF2m */
1641 
1642  rb_define_method(cEC_GROUP, "degree", ossl_ec_group_get_degree, 0);
1643 
1644 /* check* */
1645 
1646 
1647  rb_define_method(cEC_GROUP, "to_pem", ossl_ec_group_to_pem, 0);
1648  rb_define_method(cEC_GROUP, "to_der", ossl_ec_group_to_der, 0);
1649  rb_define_method(cEC_GROUP, "to_text", ossl_ec_group_to_text, 0);
1650 
1651 
1652  rb_define_alloc_func(cEC_POINT, ossl_ec_point_alloc);
1653  rb_define_method(cEC_POINT, "initialize", ossl_ec_point_initialize, -1);
1654  rb_attr(cEC_POINT, rb_intern("group"), 1, 0, 0);
1655  rb_define_method(cEC_POINT, "eql?", ossl_ec_point_eql, 1);
1656  rb_define_alias(cEC_POINT, "==", "eql?");
1657 
1658  rb_define_method(cEC_POINT, "infinity?", ossl_ec_point_is_at_infinity, 0);
1659  rb_define_method(cEC_POINT, "on_curve?", ossl_ec_point_is_on_curve, 0);
1660  rb_define_method(cEC_POINT, "make_affine!", ossl_ec_point_make_affine, 0);
1661  rb_define_method(cEC_POINT, "invert!", ossl_ec_point_invert, 0);
1662  rb_define_method(cEC_POINT, "set_to_infinity!", ossl_ec_point_set_to_infinity, 0);
1663 /* all the other methods */
1664 
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);
1667 
1668  no_copy(cEC);
1669  no_copy(cEC_GROUP);
1670  no_copy(cEC_POINT);
1671 }
1672 
1673 #else /* defined NO_EC */
1675 {
1676 }
1677 #endif /* NO_EC */
VALUE data
Definition: tcltklib.c:3368
VALUE rb_ary_unshift(VALUE ary, VALUE item)
Definition: array.c:1084
VALUE mOSSL
Definition: ossl.c:259
ssize_t n
Definition: bigdecimal.c:5655
volatile VALUE ary
Definition: tcltklib.c:9713
VALUE rb_ary_entry(VALUE ary, long offset)
Definition: array.c:1101
gz ec
Definition: zlib.c:2273
Win32OLEIDispatch * p
Definition: win32ole.c:786
VALUE rb_iv_set(VALUE, const char *, VALUE)
Definition: variable.c:2586
VALUE eEC_GROUP
void rb_define_singleton_method(VALUE obj, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a singleton method for obj.
Definition: class.c:1493
VALUE mPKey
Definition: ossl_pkey.c:16
C_block * out
Definition: crypt.c:308
VALUE ePKeyError
Definition: ossl_pkey.c:18
#define Data_Make_Struct(klass, type, mark, free, sval)
ssize_t i
Definition: bigdecimal.c:5655
int ret
Definition: tcltklib.c:280
VALUE rb_iv_get(VALUE, const char *)
Definition: variable.c:2578
Real * a
Definition: bigdecimal.c:1182
VALUE rb_eTypeError
Definition: error.c:511
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
#define UNREACHABLE
Definition: ruby.h:40
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:822
#define RSTRING_PTR(str)
NIL_P(eventloop_thread)
Definition: tcltklib.c:4068
#define T_ARRAY
int const char * in
Definition: crypt.c:639
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
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1780
return Qtrue
Definition: tcltklib.c:9610
VALUE eEC_POINT
#define GetPKey(obj, pkey)
Definition: ossl_pkey.h:30
r
Definition: bigdecimal.c:1196
#define rb_str_new2
VALUE ossl_membio2str(BIO *bio)
Definition: ossl_bio.c:77
#define ID2SYM(x)
void rb_undef_method(VALUE klass, const char *name)
Definition: class.c:1358
#define OSSL_MIN_PWD_LEN
Definition: ossl.h:81
flag
Definition: tcltklib.c:2048
return Qfalse
Definition: tcltklib.c:6779
#define RARRAY_LEN(a)
#define Qnil
Definition: tcltklib.c:1896
#define StringValuePtr(v)
VALUE rb_eRuntimeError
Definition: error.c:510
gz comment
Definition: zlib.c:2266
static VALUE char * str
Definition: tcltklib.c:3547
#define Check_Type(v, t)
#define StringValueCStr(v)
#define OSSL_BIO_reset(bio)
Definition: ossl.h:155
unsigned long ID
Definition: ripper.y:105
void rb_define_const(VALUE, const char *, VALUE)
Definition: variable.c:2197
static VALUE VALUE obj
Definition: tcltklib.c:3158
#define RSTRING_LEN(str)
#define INT2FIX(i)
VALUE eOSSLError
Definition: ossl.c:264
volatile ID method
Definition: tcltklib.c:3599
const EVP_CIPHER * GetCipherPtr(VALUE obj)
Definition: ossl_cipher.c:45
#define ALLOCA_N(type, n)
#define rb_long2int(n)
VALUE * argv
Definition: tcltklib.c:1971
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition: class.c:1535
VALUE rb_str_resize(VALUE, long)
Definition: string.c:1846
#define WrapPKey(klass, obj, pkey)
Definition: ossl_pkey.h:23
#define StringValue(v)
BIO * ossl_obj2bio(VALUE obj)
Definition: ossl_bio.c:17
void ruby_xfree(void *x)
Definition: gc.c:3649
VP_EXPORT void
Definition: bigdecimal.c:5083
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1566
void Init_ossl_ec(void)
VALUE cEC_GROUP
void rb_attr(VALUE, ID, int, int, int)
Definition: vm_method.c:791
int argc
Definition: tcltklib.c:1970
VALUE cBN
Definition: ossl_bn.c:36
Real * b
Definition: bigdecimal.c:1182
VALUE rb_define_module_under(VALUE outer, const char *name)
Definition: class.c:637
VALUE cEC_POINT
arg
Definition: ripper.y:1312
#define SYMBOL_P(x)
VALUE rb_obj_is_kind_of(VALUE, VALUE)
Definition: object.c:582
VALUE eECError
RUBY_EXTERN VALUE rb_cObject
Definition: ripper.y:1426
BN_CTX * ossl_bn_ctx
Definition: ossl_bn.c:89
klass
Definition: tcltklib.c:3504
#define INT2NUM(x)
#define Data_Get_Struct(obj, type, sval)
void ossl_raise(VALUE exc, const char *fmt,...)
Definition: ossl.c:328
VALUE rb_cArray
Definition: array.c:29
#define RSTRING_LENINT(str)
VALUE rb_ary_new2(long capa)
Definition: array.c:417
VALUE rb_str_new(const char *, long)
Definition: string.c:425
#define NUM2INT(x)
VALUE rb_obj_alloc(VALUE)
Definition: object.c:1702
VALUE ossl_bn_new(const BIGNUM *bn)
Definition: ossl_bn.c:43
unsigned long VALUE
Definition: ripper.y:104
int ossl_pem_passwd_cb(char *buf, int max_len, int flag, void *pwd)
Definition: ossl.c:162
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 NULL
Definition: _sdbm.c:103
const char * name
Definition: nkf.c:208
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1340
#define ULONG2NUM(x)
VALUE ossl_ec_new(EVP_PKEY *)
#define SYM2ID(x)
VALUE rb_eArgError
Definition: error.c:512