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