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