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