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