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