Ruby 2.0.0p247(2013-06-27revision41674)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

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