Ruby  2.1.10p492(2016-04-01revision54464)
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([cipher, pass_phrase]) => String
537  * key.to_pem([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.eql?(group2) => true | false
851  * group1 == group2 => true | false
852  *
853  */
854 static VALUE ossl_ec_group_eql(VALUE a, VALUE b)
855 {
856  EC_GROUP *group1 = NULL, *group2 = NULL;
857 
858  Require_EC_GROUP(a, group1);
859  SafeRequire_EC_GROUP(b, group2);
860 
861  if (EC_GROUP_cmp(group1, group2, ossl_bn_ctx) == 1)
862  return Qfalse;
863 
864  return Qtrue;
865 }
866 
867 /* call-seq:
868  * group.generator => ec_point
869  *
870  * See the OpenSSL documentation for EC_GROUP_get0_generator()
871  */
872 static VALUE ossl_ec_group_get_generator(VALUE self)
873 {
874  VALUE point_obj;
875  EC_GROUP *group = NULL;
876 
877  Require_EC_GROUP(self, group);
878 
879  point_obj = ossl_ec_point_dup(EC_GROUP_get0_generator(group), self);
880 
881  return point_obj;
882 }
883 
884 /* call-seq:
885  * group.set_generator(generator, order, cofactor) => self
886  *
887  * See the OpenSSL documentation for EC_GROUP_set_generator()
888  */
889 static VALUE ossl_ec_group_set_generator(VALUE self, VALUE generator, VALUE order, VALUE cofactor)
890 {
891  EC_GROUP *group = NULL;
892  const EC_POINT *point;
893  const BIGNUM *o, *co;
894 
895  Require_EC_GROUP(self, group);
896  SafeRequire_EC_POINT(generator, point);
897  o = GetBNPtr(order);
898  co = GetBNPtr(cofactor);
899 
900  if (EC_GROUP_set_generator(group, point, o, co) != 1)
901  ossl_raise(eEC_GROUP, "EC_GROUP_set_generator");
902 
903  return self;
904 }
905 
906 /* call-seq:
907  * group.get_order => order_bn
908  *
909  * See the OpenSSL documentation for EC_GROUP_get_order()
910  */
911 static VALUE ossl_ec_group_get_order(VALUE self)
912 {
913  VALUE bn_obj;
914  BIGNUM *bn;
915  EC_GROUP *group = NULL;
916 
917  Require_EC_GROUP(self, group);
918 
919  bn_obj = ossl_bn_new(NULL);
920  bn = GetBNPtr(bn_obj);
921 
922  if (EC_GROUP_get_order(group, bn, ossl_bn_ctx) != 1)
923  ossl_raise(eEC_GROUP, "EC_GROUP_get_order");
924 
925  return bn_obj;
926 }
927 
928 /* call-seq:
929  * group.get_cofactor => cofactor_bn
930  *
931  * See the OpenSSL documentation for EC_GROUP_get_cofactor()
932  */
933 static VALUE ossl_ec_group_get_cofactor(VALUE self)
934 {
935  VALUE bn_obj;
936  BIGNUM *bn;
937  EC_GROUP *group = NULL;
938 
939  Require_EC_GROUP(self, group);
940 
941  bn_obj = ossl_bn_new(NULL);
942  bn = GetBNPtr(bn_obj);
943 
944  if (EC_GROUP_get_cofactor(group, bn, ossl_bn_ctx) != 1)
945  ossl_raise(eEC_GROUP, "EC_GROUP_get_cofactor");
946 
947  return bn_obj;
948 }
949 
950 /* call-seq:
951  * group.curve_name => String
952  *
953  * See the OpenSSL documentation for EC_GROUP_get_curve_name()
954  */
955 static VALUE ossl_ec_group_get_curve_name(VALUE self)
956 {
957  EC_GROUP *group = NULL;
958  int nid;
959 
960  Get_EC_GROUP(self, group);
961  if (group == NULL)
962  return Qnil;
963 
964  nid = EC_GROUP_get_curve_name(group);
965 
966 /* BUG: an nid or asn1 object should be returned, maybe. */
967  return rb_str_new2(OBJ_nid2sn(nid));
968 }
969 
970 /* call-seq:
971  * EC.builtin_curves => [[name, comment], ...]
972  *
973  * See the OpenSSL documentation for EC_builtin_curves()
974  */
975 static VALUE ossl_s_builtin_curves(VALUE self)
976 {
977  EC_builtin_curve *curves = NULL;
978  int n;
979  int crv_len = rb_long2int(EC_get_builtin_curves(NULL, 0));
980  VALUE ary, ret;
981 
982  curves = ALLOCA_N(EC_builtin_curve, crv_len);
983  if (curves == NULL)
984  return Qnil;
985  if (!EC_get_builtin_curves(curves, crv_len))
986  ossl_raise(rb_eRuntimeError, "EC_get_builtin_curves");
987 
988  ret = rb_ary_new2(crv_len);
989 
990  for (n = 0; n < crv_len; n++) {
991  const char *sname = OBJ_nid2sn(curves[n].nid);
992  const char *comment = curves[n].comment;
993 
994  ary = rb_ary_new2(2);
995  rb_ary_push(ary, rb_str_new2(sname));
996  rb_ary_push(ary, comment ? rb_str_new2(comment) : Qnil);
997  rb_ary_push(ret, ary);
998  }
999 
1000  return ret;
1001 }
1002 
1003 /* call-seq:
1004  * group.asn1_flag => Fixnum
1005  *
1006  * See the OpenSSL documentation for EC_GROUP_get_asn1_flag()
1007  */
1008 static VALUE ossl_ec_group_get_asn1_flag(VALUE self)
1009 {
1010  EC_GROUP *group = NULL;
1011  int flag;
1012 
1013  Require_EC_GROUP(self, group);
1014 
1015  flag = EC_GROUP_get_asn1_flag(group);
1016 
1017  return INT2FIX(flag);
1018 }
1019 
1020 /* call-seq:
1021  * group.asn1_flag = Fixnum => Fixnum
1022  *
1023  * See the OpenSSL documentation for EC_GROUP_set_asn1_flag()
1024  */
1025 static VALUE ossl_ec_group_set_asn1_flag(VALUE self, VALUE flag_v)
1026 {
1027  EC_GROUP *group = NULL;
1028 
1029  Require_EC_GROUP(self, group);
1030 
1031  EC_GROUP_set_asn1_flag(group, NUM2INT(flag_v));
1032 
1033  return flag_v;
1034 }
1035 
1036 /* call-seq:
1037  * group.point_conversion_form => :uncompressed | :compressed | :hybrid
1038  *
1039  * See the OpenSSL documentation for EC_GROUP_get_point_conversion_form()
1040  */
1041 static VALUE ossl_ec_group_get_point_conversion_form(VALUE self)
1042 {
1043  EC_GROUP *group = NULL;
1044  point_conversion_form_t form;
1045  VALUE ret;
1046 
1047  Require_EC_GROUP(self, group);
1048 
1049  form = EC_GROUP_get_point_conversion_form(group);
1050 
1051  switch (form) {
1052  case POINT_CONVERSION_UNCOMPRESSED: ret = ID_uncompressed; break;
1053  case POINT_CONVERSION_COMPRESSED: ret = ID_compressed; break;
1054  case POINT_CONVERSION_HYBRID: ret = ID_hybrid; break;
1055  default: ossl_raise(eEC_GROUP, "unsupported point conversion form: %d, this module should be updated", form);
1056  }
1057 
1058  return ID2SYM(ret);
1059 }
1060 
1061 /* call-seq:
1062  * group.point_conversion_form = form => form
1063  *
1064  * See the OpenSSL documentation for EC_GROUP_set_point_conversion_form()
1065  */
1066 static VALUE ossl_ec_group_set_point_conversion_form(VALUE self, VALUE form_v)
1067 {
1068  EC_GROUP *group = NULL;
1069  point_conversion_form_t form;
1070  ID form_id = SYM2ID(form_v);
1071 
1072  Require_EC_GROUP(self, group);
1073 
1074  if (form_id == ID_uncompressed) {
1075  form = POINT_CONVERSION_UNCOMPRESSED;
1076  } else if (form_id == ID_compressed) {
1077  form = POINT_CONVERSION_COMPRESSED;
1078  } else if (form_id == ID_hybrid) {
1079  form = POINT_CONVERSION_HYBRID;
1080  } else {
1081  ossl_raise(rb_eArgError, "form must be :compressed, :uncompressed, or :hybrid");
1082  }
1083 
1084  EC_GROUP_set_point_conversion_form(group, form);
1085 
1086  return form_v;
1087 }
1088 
1089 /* call-seq:
1090  * group.seed => String or nil
1091  *
1092  * See the OpenSSL documentation for EC_GROUP_get0_seed()
1093  */
1094 static VALUE ossl_ec_group_get_seed(VALUE self)
1095 {
1096  EC_GROUP *group = NULL;
1097  size_t seed_len;
1098 
1099  Require_EC_GROUP(self, group);
1100 
1101  seed_len = EC_GROUP_get_seed_len(group);
1102 
1103  if (seed_len == 0)
1104  return Qnil;
1105 
1106  return rb_str_new((const char *)EC_GROUP_get0_seed(group), seed_len);
1107 }
1108 
1109 /* call-seq:
1110  * group.seed = seed => seed
1111  *
1112  * See the OpenSSL documentation for EC_GROUP_set_seed()
1113  */
1114 static VALUE ossl_ec_group_set_seed(VALUE self, VALUE seed)
1115 {
1116  EC_GROUP *group = NULL;
1117 
1118  Require_EC_GROUP(self, group);
1119  StringValue(seed);
1120 
1121  if (EC_GROUP_set_seed(group, (unsigned char *)RSTRING_PTR(seed), RSTRING_LEN(seed)) != (size_t)RSTRING_LEN(seed))
1122  ossl_raise(eEC_GROUP, "EC_GROUP_set_seed");
1123 
1124  return seed;
1125 }
1126 
1127 /* get/set curve GFp, GF2m */
1128 
1129 /* call-seq:
1130  * group.degree => Fixnum
1131  *
1132  * See the OpenSSL documentation for EC_GROUP_get_degree()
1133  */
1134 static VALUE ossl_ec_group_get_degree(VALUE self)
1135 {
1136  EC_GROUP *group = NULL;
1137 
1138  Require_EC_GROUP(self, group);
1139 
1140  return INT2NUM(EC_GROUP_get_degree(group));
1141 }
1142 
1143 static VALUE ossl_ec_group_to_string(VALUE self, int format)
1144 {
1145  EC_GROUP *group;
1146  BIO *out;
1147  int i = -1;
1148  VALUE str;
1149 
1150  Get_EC_GROUP(self, group);
1151 
1152  if (!(out = BIO_new(BIO_s_mem())))
1153  ossl_raise(eEC_GROUP, "BIO_new(BIO_s_mem())");
1154 
1155  switch(format) {
1156  case EXPORT_PEM:
1157  i = PEM_write_bio_ECPKParameters(out, group);
1158  break;
1159  case EXPORT_DER:
1160  i = i2d_ECPKParameters_bio(out, group);
1161  break;
1162  default:
1163  BIO_free(out);
1164  ossl_raise(rb_eRuntimeError, "unknown format (internal error)");
1165  }
1166 
1167  if (i != 1) {
1168  BIO_free(out);
1170  }
1171 
1172  str = ossl_membio2str(out);
1173 
1174  return str;
1175 }
1176 
1177 /* call-seq:
1178  * group.to_pem => String
1179  *
1180  * See the OpenSSL documentation for PEM_write_bio_ECPKParameters()
1181  */
1182 static VALUE ossl_ec_group_to_pem(VALUE self)
1183 {
1184  return ossl_ec_group_to_string(self, EXPORT_PEM);
1185 }
1186 
1187 /* call-seq:
1188  * group.to_der => String
1189  *
1190  * See the OpenSSL documentation for i2d_ECPKParameters_bio()
1191  */
1192 static VALUE ossl_ec_group_to_der(VALUE self)
1193 {
1194  return ossl_ec_group_to_string(self, EXPORT_DER);
1195 }
1196 
1197 /* call-seq:
1198  * group.to_text => String
1199  *
1200  * See the OpenSSL documentation for ECPKParameters_print()
1201  */
1202 static VALUE ossl_ec_group_to_text(VALUE self)
1203 {
1204  EC_GROUP *group;
1205  BIO *out;
1206  VALUE str;
1207 
1208  Require_EC_GROUP(self, group);
1209  if (!(out = BIO_new(BIO_s_mem()))) {
1210  ossl_raise(eEC_GROUP, "BIO_new(BIO_s_mem())");
1211  }
1212  if (!ECPKParameters_print(out, group, 0)) {
1213  BIO_free(out);
1215  }
1216  str = ossl_membio2str(out);
1217 
1218  return str;
1219 }
1220 
1221 
1222 static void ossl_ec_point_free(ossl_ec_point *ec_point)
1223 {
1224  if (!ec_point->dont_free && ec_point->point)
1225  EC_POINT_clear_free(ec_point->point);
1226  ruby_xfree(ec_point);
1227 }
1228 
1229 static VALUE ossl_ec_point_alloc(VALUE klass)
1230 {
1231  ossl_ec_point *ec_point;
1232  VALUE obj;
1233 
1234  obj = Data_Make_Struct(klass, ossl_ec_point, 0, ossl_ec_point_free, ec_point);
1235 
1236  return obj;
1237 }
1238 
1239 /*
1240  * call-seq:
1241  * OpenSSL::PKey::EC::Point.new(point)
1242  * OpenSSL::PKey::EC::Point.new(group)
1243  * OpenSSL::PKey::EC::Point.new(group, bn)
1244  *
1245  * See the OpenSSL documentation for EC_POINT_*
1246  */
1247 static VALUE ossl_ec_point_initialize(int argc, VALUE *argv, VALUE self)
1248 {
1249  ossl_ec_point *ec_point;
1250  EC_POINT *point = NULL;
1251  VALUE arg1, arg2;
1252  VALUE group_v = Qnil;
1253  const EC_GROUP *group = NULL;
1254 
1255  Data_Get_Struct(self, ossl_ec_point, ec_point);
1256  if (ec_point->point)
1257  ossl_raise(eEC_POINT, "EC_POINT already initialized");
1258 
1259  switch (rb_scan_args(argc, argv, "11", &arg1, &arg2)) {
1260  case 1:
1261  if (rb_obj_is_kind_of(arg1, cEC_POINT)) {
1262  const EC_POINT *arg_point;
1263 
1264  group_v = rb_iv_get(arg1, "@group");
1265  SafeRequire_EC_GROUP(group_v, group);
1266  SafeRequire_EC_POINT(arg1, arg_point);
1267 
1268  point = EC_POINT_dup(arg_point, group);
1269  } else if (rb_obj_is_kind_of(arg1, cEC_GROUP)) {
1270  group_v = arg1;
1271  SafeRequire_EC_GROUP(group_v, group);
1272 
1273  point = EC_POINT_new(group);
1274  } else {
1275  ossl_raise(eEC_POINT, "wrong argument type: must be OpenSSL::PKey::EC::Point or OpenSSL::Pkey::EC::Group");
1276  }
1277 
1278  break;
1279  case 2:
1280  if (!rb_obj_is_kind_of(arg1, cEC_GROUP))
1281  ossl_raise(rb_eArgError, "1st argument must be OpenSSL::PKey::EC::Group");
1282  group_v = arg1;
1283  SafeRequire_EC_GROUP(group_v, group);
1284 
1285  if (rb_obj_is_kind_of(arg2, cBN)) {
1286  const BIGNUM *bn = GetBNPtr(arg2);
1287 
1288  point = EC_POINT_bn2point(group, bn, NULL, ossl_bn_ctx);
1289  } else {
1290  BIO *in = ossl_obj2bio(arg1);
1291 
1292 /* BUG: finish me */
1293 
1294  BIO_free(in);
1295 
1296  if (point == NULL) {
1297  ossl_raise(eEC_POINT, "unknown type for 2nd arg");
1298  }
1299  }
1300  break;
1301  default:
1302  ossl_raise(rb_eArgError, "wrong number of arguments");
1303  }
1304 
1305  if (point == NULL)
1307 
1308  if (NIL_P(group_v))
1309  ossl_raise(rb_eRuntimeError, "missing group (internal error)");
1310 
1311  ec_point->point = point;
1312 
1313  rb_iv_set(self, "@group", group_v);
1314 
1315  return self;
1316 }
1317 
1318 /*
1319  * call-seq:
1320  * point1.eql?(point2) => true | false
1321  * point1 == point2 => true | false
1322  *
1323  */
1324 static VALUE ossl_ec_point_eql(VALUE a, VALUE b)
1325 {
1326  EC_POINT *point1, *point2;
1327  VALUE group_v1 = rb_iv_get(a, "@group");
1328  VALUE group_v2 = rb_iv_get(b, "@group");
1329  const EC_GROUP *group;
1330 
1331  if (ossl_ec_group_eql(group_v1, group_v2) == Qfalse)
1332  return Qfalse;
1333 
1334  Require_EC_POINT(a, point1);
1335  SafeRequire_EC_POINT(b, point2);
1336  SafeRequire_EC_GROUP(group_v1, group);
1337 
1338  if (EC_POINT_cmp(group, point1, point2, ossl_bn_ctx) == 1)
1339  return Qfalse;
1340 
1341  return Qtrue;
1342 }
1343 
1344 /*
1345  * call-seq:
1346  * point.infinity? => true | false
1347  *
1348  */
1349 static VALUE ossl_ec_point_is_at_infinity(VALUE self)
1350 {
1351  EC_POINT *point;
1352  VALUE group_v = rb_iv_get(self, "@group");
1353  const EC_GROUP *group;
1354 
1355  Require_EC_POINT(self, point);
1356  SafeRequire_EC_GROUP(group_v, group);
1357 
1358  switch (EC_POINT_is_at_infinity(group, point)) {
1359  case 1: return Qtrue;
1360  case 0: return Qfalse;
1361  default: ossl_raise(cEC_POINT, "EC_POINT_is_at_infinity");
1362  }
1363 
1364  UNREACHABLE;
1365 }
1366 
1367 /*
1368  * call-seq:
1369  * point.on_curve? => true | false
1370  *
1371  */
1372 static VALUE ossl_ec_point_is_on_curve(VALUE self)
1373 {
1374  EC_POINT *point;
1375  VALUE group_v = rb_iv_get(self, "@group");
1376  const EC_GROUP *group;
1377 
1378  Require_EC_POINT(self, point);
1379  SafeRequire_EC_GROUP(group_v, group);
1380 
1381  switch (EC_POINT_is_on_curve(group, point, ossl_bn_ctx)) {
1382  case 1: return Qtrue;
1383  case 0: return Qfalse;
1384  default: ossl_raise(cEC_POINT, "EC_POINT_is_on_curve");
1385  }
1386 
1387  UNREACHABLE;
1388 }
1389 
1390 /*
1391  * call-seq:
1392  * point.make_affine! => self
1393  *
1394  */
1395 static VALUE ossl_ec_point_make_affine(VALUE self)
1396 {
1397  EC_POINT *point;
1398  VALUE group_v = rb_iv_get(self, "@group");
1399  const EC_GROUP *group;
1400 
1401  Require_EC_POINT(self, point);
1402  SafeRequire_EC_GROUP(group_v, group);
1403 
1404  if (EC_POINT_make_affine(group, point, ossl_bn_ctx) != 1)
1405  ossl_raise(cEC_POINT, "EC_POINT_make_affine");
1406 
1407  return self;
1408 }
1409 
1410 /*
1411  * call-seq:
1412  * point.invert! => self
1413  *
1414  */
1415 static VALUE ossl_ec_point_invert(VALUE self)
1416 {
1417  EC_POINT *point;
1418  VALUE group_v = rb_iv_get(self, "@group");
1419  const EC_GROUP *group;
1420 
1421  Require_EC_POINT(self, point);
1422  SafeRequire_EC_GROUP(group_v, group);
1423 
1424  if (EC_POINT_invert(group, point, ossl_bn_ctx) != 1)
1425  ossl_raise(cEC_POINT, "EC_POINT_invert");
1426 
1427  return self;
1428 }
1429 
1430 /*
1431  * call-seq:
1432  * point.set_to_infinity! => self
1433  *
1434  */
1435 static VALUE ossl_ec_point_set_to_infinity(VALUE self)
1436 {
1437  EC_POINT *point;
1438  VALUE group_v = rb_iv_get(self, "@group");
1439  const EC_GROUP *group;
1440 
1441  Require_EC_POINT(self, point);
1442  SafeRequire_EC_GROUP(group_v, group);
1443 
1444  if (EC_POINT_set_to_infinity(group, point) != 1)
1445  ossl_raise(cEC_POINT, "EC_POINT_set_to_infinity");
1446 
1447  return self;
1448 }
1449 
1450 /*
1451  * call-seq:
1452  * point.to_bn => OpenSSL::BN
1453  *
1454  * See the OpenSSL documentation for EC_POINT_point2bn()
1455  */
1456 static VALUE ossl_ec_point_to_bn(VALUE self)
1457 {
1458  EC_POINT *point;
1459  VALUE bn_obj;
1460  VALUE group_v = rb_iv_get(self, "@group");
1461  const EC_GROUP *group;
1462  point_conversion_form_t form;
1463  BIGNUM *bn;
1464 
1465  Require_EC_POINT(self, point);
1466  SafeRequire_EC_GROUP(group_v, group);
1467 
1468  form = EC_GROUP_get_point_conversion_form(group);
1469 
1470  bn_obj = rb_obj_alloc(cBN);
1471  bn = GetBNPtr(bn_obj);
1472 
1473  if (EC_POINT_point2bn(group, point, form, bn, ossl_bn_ctx) == NULL)
1474  ossl_raise(eEC_POINT, "EC_POINT_point2bn");
1475 
1476  return bn_obj;
1477 }
1478 
1479 /*
1480  * call-seq:
1481  * point.mul(bn) => point
1482  * point.mul(bn, bn) => point
1483  * point.mul([bn], [point]) => point
1484  * point.mul([bn], [point], bn) => point
1485  */
1486 static VALUE ossl_ec_point_mul(int argc, VALUE *argv, VALUE self)
1487 {
1488  EC_POINT *point1, *point2;
1489  const EC_GROUP *group;
1490  VALUE group_v = rb_iv_get(self, "@group");
1491  VALUE bn_v1, bn_v2, r, points_v;
1492  BIGNUM *bn1 = NULL, *bn2 = NULL;
1493 
1494  Require_EC_POINT(self, point1);
1495  SafeRequire_EC_GROUP(group_v, group);
1496 
1497  r = rb_obj_alloc(cEC_POINT);
1498  ossl_ec_point_initialize(1, &group_v, r);
1499  Require_EC_POINT(r, point2);
1500 
1501  argc = rb_scan_args(argc, argv, "12", &bn_v1, &points_v, &bn_v2);
1502 
1503  if (rb_obj_is_kind_of(bn_v1, cBN)) {
1504  bn1 = GetBNPtr(bn_v1);
1505  if (argc >= 2) {
1506  bn2 = GetBNPtr(points_v);
1507  }
1508  if (EC_POINT_mul(group, point2, bn2, point1, bn1, ossl_bn_ctx) != 1)
1509  ossl_raise(eEC_POINT, "Multiplication failed");
1510  } else {
1511  size_t i, points_len, bignums_len;
1512  const EC_POINT **points;
1513  const BIGNUM **bignums;
1514 
1515  Check_Type(bn_v1, T_ARRAY);
1516  bignums_len = RARRAY_LEN(bn_v1);
1517  bignums = (const BIGNUM **)OPENSSL_malloc(bignums_len * (int)sizeof(BIGNUM *));
1518 
1519  for (i = 0; i < bignums_len; ++i) {
1520  bignums[i] = GetBNPtr(rb_ary_entry(bn_v1, i));
1521  }
1522 
1523  if (!rb_obj_is_kind_of(points_v, rb_cArray)) {
1524  OPENSSL_free((void *)bignums);
1525  rb_raise(rb_eTypeError, "Argument2 must be an array");
1526  }
1527 
1528  rb_ary_unshift(points_v, self);
1529  points_len = RARRAY_LEN(points_v);
1530  points = (const EC_POINT **)OPENSSL_malloc(points_len * (int)sizeof(EC_POINT *));
1531 
1532  for (i = 0; i < points_len; ++i) {
1533  Get_EC_POINT(rb_ary_entry(points_v, i), points[i]);
1534  }
1535 
1536  if (argc >= 3) {
1537  bn2 = GetBNPtr(bn_v2);
1538  }
1539  if (EC_POINTs_mul(group, point2, bn2, points_len, points, bignums, ossl_bn_ctx) != 1) {
1540  OPENSSL_free((void *)bignums);
1541  OPENSSL_free((void *)points);
1542  ossl_raise(eEC_POINT, "Multiplication failed");
1543  }
1544  OPENSSL_free((void *)bignums);
1545  OPENSSL_free((void *)points);
1546  }
1547 
1548  return r;
1549 }
1550 
1551 static void no_copy(VALUE klass)
1552 {
1553  rb_undef_method(klass, "copy");
1554  rb_undef_method(klass, "clone");
1555  rb_undef_method(klass, "dup");
1556  rb_undef_method(klass, "initialize_copy");
1557 }
1558 
1559 void Init_ossl_ec()
1560 {
1561 #ifdef DONT_NEED_RDOC_WORKAROUND
1562  mOSSL = rb_define_module("OpenSSL");
1563  mPKey = rb_define_module_under(mOSSL, "PKey");
1564 #endif
1565 
1567 
1573 
1574  s_GFp = rb_intern("GFp");
1575  s_GF2m = rb_intern("GF2m");
1576  s_GFp_simple = rb_intern("GFp_simple");
1577  s_GFp_mont = rb_intern("GFp_mont");
1578  s_GFp_nist = rb_intern("GFp_nist");
1579  s_GF2m_simple = rb_intern("GF2m_simple");
1580 
1581  ID_uncompressed = rb_intern("uncompressed");
1582  ID_compressed = rb_intern("compressed");
1583  ID_hybrid = rb_intern("hybrid");
1584 
1585 #ifdef OPENSSL_EC_NAMED_CURVE
1586  rb_define_const(cEC, "NAMED_CURVE", ULONG2NUM(OPENSSL_EC_NAMED_CURVE));
1587 #endif
1588 
1589  rb_define_singleton_method(cEC, "builtin_curves", ossl_s_builtin_curves, 0);
1590 
1591  rb_define_method(cEC, "initialize", ossl_ec_key_initialize, -1);
1592 /* copy/dup/cmp */
1593 
1594  rb_define_method(cEC, "group", ossl_ec_key_get_group, 0);
1595  rb_define_method(cEC, "group=", ossl_ec_key_set_group, 1);
1596  rb_define_method(cEC, "private_key", ossl_ec_key_get_private_key, 0);
1597  rb_define_method(cEC, "private_key=", ossl_ec_key_set_private_key, 1);
1598  rb_define_method(cEC, "public_key", ossl_ec_key_get_public_key, 0);
1599  rb_define_method(cEC, "public_key=", ossl_ec_key_set_public_key, 1);
1600  rb_define_method(cEC, "private_key?", ossl_ec_key_is_private_key, 0);
1601  rb_define_method(cEC, "public_key?", ossl_ec_key_is_public_key, 0);
1602 /* rb_define_method(cEC, "", ossl_ec_key_get_, 0);
1603  rb_define_method(cEC, "=", ossl_ec_key_set_ 1);
1604  set/get enc_flags
1605  set/get _conv_from
1606  set/get asn1_flag (can use ruby to call self.group.asn1_flag)
1607  set/get precompute_mult
1608 */
1609  rb_define_method(cEC, "generate_key", ossl_ec_key_generate_key, 0);
1610  rb_define_method(cEC, "check_key", ossl_ec_key_check_key, 0);
1611 
1612  rb_define_method(cEC, "dh_compute_key", ossl_ec_key_dh_compute_key, 1);
1613  rb_define_method(cEC, "dsa_sign_asn1", ossl_ec_key_dsa_sign_asn1, 1);
1614  rb_define_method(cEC, "dsa_verify_asn1", ossl_ec_key_dsa_verify_asn1, 2);
1615 /* do_sign/do_verify */
1616 
1617  rb_define_method(cEC, "export", ossl_ec_key_export, -1);
1618  rb_define_alias(cEC, "to_pem", "export");
1619  rb_define_method(cEC, "to_der", ossl_ec_key_to_der, 0);
1620  rb_define_method(cEC, "to_text", ossl_ec_key_to_text, 0);
1621 
1622 
1623  rb_define_alloc_func(cEC_GROUP, ossl_ec_group_alloc);
1624  rb_define_method(cEC_GROUP, "initialize", ossl_ec_group_initialize, -1);
1625  rb_define_method(cEC_GROUP, "eql?", ossl_ec_group_eql, 1);
1626  rb_define_alias(cEC_GROUP, "==", "eql?");
1627 /* copy/dup/cmp */
1628 
1629  rb_define_method(cEC_GROUP, "generator", ossl_ec_group_get_generator, 0);
1630  rb_define_method(cEC_GROUP, "set_generator", ossl_ec_group_set_generator, 3);
1631  rb_define_method(cEC_GROUP, "order", ossl_ec_group_get_order, 0);
1632  rb_define_method(cEC_GROUP, "cofactor", ossl_ec_group_get_cofactor, 0);
1633 
1634  rb_define_method(cEC_GROUP, "curve_name", ossl_ec_group_get_curve_name, 0);
1635 /* rb_define_method(cEC_GROUP, "curve_name=", ossl_ec_group_set_curve_name, 1); */
1636 
1637  rb_define_method(cEC_GROUP, "asn1_flag", ossl_ec_group_get_asn1_flag, 0);
1638  rb_define_method(cEC_GROUP, "asn1_flag=", ossl_ec_group_set_asn1_flag, 1);
1639 
1640  rb_define_method(cEC_GROUP, "point_conversion_form", ossl_ec_group_get_point_conversion_form, 0);
1641  rb_define_method(cEC_GROUP, "point_conversion_form=", ossl_ec_group_set_point_conversion_form, 1);
1642 
1643  rb_define_method(cEC_GROUP, "seed", ossl_ec_group_get_seed, 0);
1644  rb_define_method(cEC_GROUP, "seed=", ossl_ec_group_set_seed, 1);
1645 
1646 /* get/set GFp, GF2m */
1647 
1648  rb_define_method(cEC_GROUP, "degree", ossl_ec_group_get_degree, 0);
1649 
1650 /* check* */
1651 
1652 
1653  rb_define_method(cEC_GROUP, "to_pem", ossl_ec_group_to_pem, 0);
1654  rb_define_method(cEC_GROUP, "to_der", ossl_ec_group_to_der, 0);
1655  rb_define_method(cEC_GROUP, "to_text", ossl_ec_group_to_text, 0);
1656 
1657 
1658  rb_define_alloc_func(cEC_POINT, ossl_ec_point_alloc);
1659  rb_define_method(cEC_POINT, "initialize", ossl_ec_point_initialize, -1);
1660  rb_attr(cEC_POINT, rb_intern("group"), 1, 0, 0);
1661  rb_define_method(cEC_POINT, "eql?", ossl_ec_point_eql, 1);
1662  rb_define_alias(cEC_POINT, "==", "eql?");
1663 
1664  rb_define_method(cEC_POINT, "infinity?", ossl_ec_point_is_at_infinity, 0);
1665  rb_define_method(cEC_POINT, "on_curve?", ossl_ec_point_is_on_curve, 0);
1666  rb_define_method(cEC_POINT, "make_affine!", ossl_ec_point_make_affine, 0);
1667  rb_define_method(cEC_POINT, "invert!", ossl_ec_point_invert, 0);
1668  rb_define_method(cEC_POINT, "set_to_infinity!", ossl_ec_point_set_to_infinity, 0);
1669 /* all the other methods */
1670 
1671  rb_define_method(cEC_POINT, "to_bn", ossl_ec_point_to_bn, 0);
1672  rb_define_method(cEC_POINT, "mul", ossl_ec_point_mul, -1);
1673 
1674  no_copy(cEC);
1675  no_copy(cEC_GROUP);
1676  no_copy(cEC_POINT);
1677 }
1678 
1679 #else /* defined NO_EC */
1681 {
1682 }
1683 #endif /* NO_EC */
VALUE rb_ary_unshift(VALUE ary, VALUE item)
Definition: array.c:1161
VALUE mOSSL
Definition: ossl.c:259
VALUE rb_ary_entry(VALUE ary, long offset)
Definition: array.c:1179
#define RARRAY_LEN(a)
Definition: ruby.h:878
#define INT2NUM(x)
Definition: ruby.h:1296
#define NUM2INT(x)
Definition: ruby.h:630
VALUE eEC_GROUP
#define Data_Get_Struct(obj, type, sval)
Definition: ruby.h:1036
void rb_define_singleton_method(VALUE obj, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a singleton method for obj.
Definition: class.c:1646
VALUE mPKey
Definition: ossl_pkey.c:16
VALUE ePKeyError
Definition: ossl_pkey.c:18
#define Qtrue
Definition: ruby.h:426
VALUE rb_eTypeError
Definition: error.c:548
#define UNREACHABLE
Definition: ruby.h:42
#define ULONG2NUM(x)
Definition: ruby.h:1327
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:900
#define rb_long2int(n)
Definition: ruby.h:317
#define SYM2ID(x)
Definition: ruby.h:356
VALUE rb_funcall(VALUE, ID, int,...)
Calls a method.
Definition: vm_eval.c:781
VALUE rb_iv_set(VALUE, const char *, VALUE)
Definition: variable.c:2612
VALUE rb_iv_get(VALUE, const char *)
Definition: variable.c:2604
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:657
#define Check_Type(v, t)
Definition: ruby.h:532
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1857
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
VALUE rb_obj_is_kind_of(VALUE, VALUE)
Definition: object.c:646
VALUE eEC_POINT
#define GetPKey(obj, pkey)
Definition: ossl_pkey.h:30
#define T_ARRAY
Definition: ruby.h:484
VALUE ossl_membio2str(BIO *bio)
Definition: ossl_bio.c:77
void rb_undef_method(VALUE klass, const char *name)
Definition: class.c:1497
#define OSSL_MIN_PWD_LEN
Definition: ossl.h:81
#define rb_ary_new2
Definition: intern.h:90
RUBY_EXTERN VALUE rb_cObject
Definition: ruby.h:1561
VALUE rb_eRuntimeError
Definition: error.c:547
void rb_attr(VALUE, ID, int, int, int)
Definition: vm_method.c:872
#define OSSL_BIO_reset(bio)
Definition: ossl.h:155
#define NIL_P(v)
Definition: ruby.h:438
void rb_define_const(VALUE, const char *, VALUE)
Definition: variable.c:2228
VALUE eOSSLError
Definition: ossl.c:264
int argc
Definition: ruby.c:131
#define Qfalse
Definition: ruby.h:425
#define ALLOCA_N(type, n)
Definition: ruby.h:1345
#define rb_str_new2
Definition: intern.h:840
VALUE rb_obj_alloc(VALUE)
Definition: object.c:1804
const EVP_CIPHER * GetCipherPtr(VALUE obj)
Definition: ossl_cipher.c:45
VALUE rb_str_resize(VALUE, long)
Definition: string.c:2024
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:1688
#define RSTRING_LEN(str)
Definition: ruby.h:841
#define WrapPKey(klass, obj, pkey)
Definition: ossl_pkey.h:23
BIO * ossl_obj2bio(VALUE obj)
Definition: ossl_bio.c:17
void ruby_xfree(void *x)
Definition: gc.c:6245
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1719
VALUE cEC_GROUP
unsigned long ID
Definition: ruby.h:89
#define Qnil
Definition: ruby.h:427
unsigned long VALUE
Definition: ruby.h:88
VALUE cBN
Definition: ossl_bn.c:36
#define Data_Make_Struct(klass, type, mark, free, sval)
Definition: ruby.h:1021
VALUE rb_define_module_under(VALUE outer, const char *name)
Definition: class.c:747
#define StringValueCStr(v)
Definition: ruby.h:541
VALUE cEC_POINT
#define RSTRING_PTR(str)
Definition: ruby.h:845
#define INT2FIX(i)
Definition: ruby.h:231
VALUE eECError
BN_CTX * ossl_bn_ctx
Definition: ossl_bn.c:89
void ossl_raise(VALUE exc, const char *fmt,...)
Definition: ossl.c:333
VALUE rb_cArray
Definition: array.c:27
const char * name
Definition: nkf.c:208
#define ID2SYM(x)
Definition: ruby.h:355
VALUE ossl_bn_new(const BIGNUM *bn)
Definition: ossl_bn.c:43
#define StringValuePtr(v)
Definition: ruby.h:540
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:853
BIGNUM * GetBNPtr(VALUE obj)
Definition: ossl_bn.c:58
VALUE rb_define_module(const char *name)
Definition: class.c:727
VALUE cEC
VALUE cPKey
Definition: ossl_pkey.c:17
#define rb_intern(str)
#define SYMBOL_P(x)
Definition: ruby.h:354
#define NULL
Definition: _sdbm.c:102
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1479
VALUE ossl_ec_new(EVP_PKEY *)
VALUE rb_eArgError
Definition: error.c:549
char ** argv
Definition: ruby.c:132
#define StringValue(v)
Definition: ruby.h:539
VALUE rb_str_new(const char *, long)
Definition: string.c:534