Ruby  2.0.0p247(2013-06-27revision41674)
ext/openssl/ossl_pkey_ec.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006-2007 Technorama Ltd. <oss-ruby@technorama.net>
00003  */
00004 
00005 #include "ossl.h"
00006 
00007 #if !defined(OPENSSL_NO_EC) && (OPENSSL_VERSION_NUMBER >= 0x0090802fL)
00008 
00009 typedef struct {
00010         EC_GROUP *group;
00011         int dont_free;
00012 } ossl_ec_group;
00013 
00014 typedef struct {
00015         EC_POINT *point;
00016         int dont_free;
00017 } ossl_ec_point;
00018 
00019 
00020 #define EXPORT_PEM 0
00021 #define EXPORT_DER 1
00022 
00023 
00024 #define GetPKeyEC(obj, pkey) do { \
00025     GetPKey((obj), (pkey)); \
00026     if (EVP_PKEY_type((pkey)->type) != EVP_PKEY_EC) { \
00027         ossl_raise(rb_eRuntimeError, "THIS IS NOT A EC PKEY!"); \
00028     } \
00029 } while (0)
00030 
00031 #define SafeGet_ec_group(obj, group) do { \
00032     OSSL_Check_Kind((obj), cEC_GROUP); \
00033     Data_Get_Struct((obj), ossl_ec_group, (group)); \
00034 } while(0)
00035 
00036 #define Get_EC_KEY(obj, key) do { \
00037     EVP_PKEY *pkey; \
00038     GetPKeyEC((obj), pkey); \
00039     (key) = pkey->pkey.ec; \
00040 } while(0)
00041 
00042 #define Require_EC_KEY(obj, key) do { \
00043     Get_EC_KEY((obj), (key)); \
00044     if ((key) == NULL) \
00045         ossl_raise(eECError, "EC_KEY is not initialized"); \
00046 } while(0)
00047 
00048 #define SafeRequire_EC_KEY(obj, key) do { \
00049     OSSL_Check_Kind((obj), cEC); \
00050     Require_EC_KEY((obj), (key)); \
00051 } while (0)
00052 
00053 #define Get_EC_GROUP(obj, g) do { \
00054     ossl_ec_group *ec_group; \
00055     Data_Get_Struct((obj), ossl_ec_group, ec_group); \
00056     if (ec_group == NULL) \
00057         ossl_raise(eEC_GROUP, "missing ossl_ec_group structure"); \
00058     (g) = ec_group->group; \
00059 } while(0)
00060 
00061 #define Require_EC_GROUP(obj, group) do { \
00062     Get_EC_GROUP((obj), (group)); \
00063     if ((group) == NULL) \
00064         ossl_raise(eEC_GROUP, "EC_GROUP is not initialized"); \
00065 } while(0)
00066 
00067 #define SafeRequire_EC_GROUP(obj, group) do { \
00068     OSSL_Check_Kind((obj), cEC_GROUP); \
00069     Require_EC_GROUP((obj), (group)); \
00070 } while(0)
00071 
00072 #define Get_EC_POINT(obj, p) do { \
00073     ossl_ec_point *ec_point; \
00074     Data_Get_Struct((obj), ossl_ec_point, ec_point); \
00075     if (ec_point == NULL) \
00076         ossl_raise(eEC_POINT, "missing ossl_ec_point structure"); \
00077     (p) = ec_point->point; \
00078 } while(0)
00079 
00080 #define Require_EC_POINT(obj, point) do { \
00081     Get_EC_POINT((obj), (point)); \
00082     if ((point) == NULL) \
00083         ossl_raise(eEC_POINT, "EC_POINT is not initialized"); \
00084 } while(0)
00085 
00086 #define SafeRequire_EC_POINT(obj, point) do { \
00087     OSSL_Check_Kind((obj), cEC_POINT); \
00088     Require_EC_POINT((obj), (point)); \
00089 } while(0)
00090 
00091 VALUE cEC;
00092 VALUE eECError;
00093 VALUE cEC_GROUP;
00094 VALUE eEC_GROUP;
00095 VALUE cEC_POINT;
00096 VALUE eEC_POINT;
00097 
00098 static ID s_GFp;
00099 static ID s_GFp_simple;
00100 static ID s_GFp_mont;
00101 static ID s_GFp_nist;
00102 static ID s_GF2m;
00103 static ID s_GF2m_simple;
00104 
00105 static ID ID_uncompressed;
00106 static ID ID_compressed;
00107 static ID ID_hybrid;
00108 
00109 static VALUE ec_instance(VALUE klass, EC_KEY *ec)
00110 {
00111     EVP_PKEY *pkey;
00112     VALUE obj;
00113 
00114     if (!ec) {
00115         return Qfalse;
00116     }
00117     if (!(pkey = EVP_PKEY_new())) {
00118         return Qfalse;
00119     }
00120     if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) {
00121         EVP_PKEY_free(pkey);
00122         return Qfalse;
00123     }
00124     WrapPKey(klass, obj, pkey);
00125 
00126     return obj;
00127 }
00128 
00129 VALUE ossl_ec_new(EVP_PKEY *pkey)
00130 {
00131     VALUE obj;
00132 
00133     if (!pkey) {
00134         obj = ec_instance(cEC, EC_KEY_new());
00135     } else {
00136         if (EVP_PKEY_type(pkey->type) != EVP_PKEY_EC) {
00137             ossl_raise(rb_eTypeError, "Not a EC key!");
00138         }
00139         WrapPKey(cEC, obj, pkey);
00140     }
00141     if (obj == Qfalse) {
00142         ossl_raise(eECError, NULL);
00143     }
00144 
00145     return obj;
00146 }
00147 
00148 
00149 /*  call-seq:
00150  *     OpenSSL::PKey::EC.new()
00151  *     OpenSSL::PKey::EC.new(ec_key)
00152  *     OpenSSL::PKey::EC.new(ec_group)
00153  *     OpenSSL::PKey::EC.new("secp112r1")
00154  *     OpenSSL::PKey::EC.new(pem_string)
00155  *     OpenSSL::PKey::EC.new(pem_string [, pwd])
00156  *     OpenSSL::PKey::EC.new(der_string)
00157  *
00158  *  See the OpenSSL documentation for:
00159  *     EC_KEY_*
00160  */
00161 static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self)
00162 {
00163     EVP_PKEY *pkey;
00164     EC_KEY *ec = NULL;
00165     VALUE arg, pass;
00166     VALUE group = Qnil;
00167     char *passwd = NULL;
00168 
00169     GetPKey(self, pkey);
00170     if (pkey->pkey.ec)
00171         ossl_raise(eECError, "EC_KEY already initialized");
00172 
00173     rb_scan_args(argc, argv, "02", &arg, &pass);
00174 
00175     if (NIL_P(arg)) {
00176         ec = EC_KEY_new();
00177     } else {
00178         if (rb_obj_is_kind_of(arg, cEC)) {
00179             EC_KEY *other_ec = NULL;
00180 
00181             SafeRequire_EC_KEY(arg, other_ec);
00182             ec = EC_KEY_dup(other_ec);
00183         } else if (rb_obj_is_kind_of(arg, cEC_GROUP)) {
00184                 ec = EC_KEY_new();
00185                 group = arg;
00186         } else {
00187             BIO *in = ossl_obj2bio(arg);
00188 
00189             if (!NIL_P(pass)) {
00190                 passwd = StringValuePtr(pass);
00191             }
00192             ec = PEM_read_bio_ECPrivateKey(in, NULL, ossl_pem_passwd_cb, passwd);
00193             if (!ec) {
00194                 OSSL_BIO_reset(in);
00195                 ec = PEM_read_bio_EC_PUBKEY(in, NULL, ossl_pem_passwd_cb, passwd);
00196             }
00197             if (!ec) {
00198                 OSSL_BIO_reset(in);
00199                 ec = d2i_ECPrivateKey_bio(in, NULL);
00200             }
00201             if (!ec) {
00202                 OSSL_BIO_reset(in);
00203                 ec = d2i_EC_PUBKEY_bio(in, NULL);
00204             }
00205 
00206             BIO_free(in);
00207 
00208             if (ec == NULL) {
00209                 const char *name = StringValueCStr(arg);
00210                 int nid = OBJ_sn2nid(name);
00211 
00212                 (void)ERR_get_error();
00213                 if (nid == NID_undef)
00214                     ossl_raise(eECError, "unknown curve name (%s)\n", name);
00215 
00216                 if ((ec = EC_KEY_new_by_curve_name(nid)) == NULL)
00217                     ossl_raise(eECError, "unable to create curve (%s)\n", name);
00218 
00219                 EC_KEY_set_asn1_flag(ec, OPENSSL_EC_NAMED_CURVE);
00220                 EC_KEY_set_conv_form(ec, POINT_CONVERSION_UNCOMPRESSED);
00221             }
00222         }
00223     }
00224 
00225     if (ec == NULL)
00226         ossl_raise(eECError, NULL);
00227 
00228     if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) {
00229         EC_KEY_free(ec);
00230         ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY");
00231     }
00232 
00233     rb_iv_set(self, "@group", Qnil);
00234 
00235     if (!NIL_P(group))
00236         rb_funcall(self, rb_intern("group="), 1, arg);
00237 
00238     return self;
00239 }
00240 
00241 /*
00242  *  call-seq:
00243  *     key.group   => group
00244  *
00245  *  Returns a constant <code>OpenSSL::EC::Group</code> that is tied to the key.
00246  *  Modifying the returned group can make the key invalid.
00247  */
00248 static VALUE ossl_ec_key_get_group(VALUE self)
00249 {
00250     VALUE group_v;
00251     EC_KEY *ec;
00252     ossl_ec_group *ec_group;
00253     EC_GROUP *group;
00254 
00255     Require_EC_KEY(self, ec);
00256 
00257     group_v = rb_iv_get(self, "@group");
00258     if (!NIL_P(group_v))
00259         return group_v;
00260 
00261     if ((group = (EC_GROUP *)EC_KEY_get0_group(ec)) != NULL) {
00262         group_v = rb_obj_alloc(cEC_GROUP);
00263         SafeGet_ec_group(group_v, ec_group);
00264         ec_group->group = group;
00265         ec_group->dont_free = 1;
00266         rb_iv_set(group_v, "@key", self);
00267         rb_iv_set(self, "@group", group_v);
00268         return group_v;
00269     }
00270 
00271     return Qnil;
00272 }
00273 
00274 /*
00275  *  call-seq:
00276  *     key.group = group   => group
00277  *
00278  *  Returns the same object passed, not the group object associated with the key.
00279  *  If you wish to access the group object tied to the key call key.group after setting
00280  *  the group.
00281  *
00282  *  Setting the group will immediately destroy any previously assigned group object.
00283  *  The group is internally copied by OpenSSL.  Modifying the original group after
00284  *  assignment will not effect the internal key structure.
00285  *  (your changes may be lost).  BE CAREFUL.
00286  *
00287  *  EC_KEY_set_group calls EC_GROUP_free(key->group) then EC_GROUP_dup(), not EC_GROUP_copy.
00288  *  This documentation is accurate for OpenSSL 0.9.8b.
00289  */
00290 static VALUE ossl_ec_key_set_group(VALUE self, VALUE group_v)
00291 {
00292     VALUE old_group_v;
00293     EC_KEY *ec;
00294     EC_GROUP *group;
00295 
00296     Require_EC_KEY(self, ec);
00297     SafeRequire_EC_GROUP(group_v, group);
00298 
00299     old_group_v = rb_iv_get(self, "@group");
00300     if (!NIL_P(old_group_v)) {
00301         ossl_ec_group *old_ec_group;
00302         SafeGet_ec_group(old_group_v, old_ec_group);
00303 
00304         old_ec_group->group = NULL;
00305         old_ec_group->dont_free = 0;
00306         rb_iv_set(old_group_v, "@key", Qnil);
00307     }
00308 
00309     rb_iv_set(self, "@group", Qnil);
00310 
00311     if (EC_KEY_set_group(ec, group) != 1)
00312         ossl_raise(eECError, "EC_KEY_set_group");
00313 
00314     return group_v;
00315 }
00316 
00317 /*
00318  *  call-seq:
00319  *     key.private_key   => OpenSSL::BN
00320  *
00321  *  See the OpenSSL documentation for EC_KEY_get0_private_key()
00322  */
00323 static VALUE ossl_ec_key_get_private_key(VALUE self)
00324 {
00325     EC_KEY *ec;
00326     const BIGNUM *bn;
00327 
00328     Require_EC_KEY(self, ec);
00329 
00330     if ((bn = EC_KEY_get0_private_key(ec)) == NULL)
00331         return Qnil;
00332 
00333     return ossl_bn_new(bn);
00334 }
00335 
00336 /*
00337  *  call-seq:
00338  *     key.private_key = openssl_bn
00339  *
00340  *  See the OpenSSL documentation for EC_KEY_set_private_key()
00341  */
00342 static VALUE ossl_ec_key_set_private_key(VALUE self, VALUE private_key)
00343 {
00344     EC_KEY *ec;
00345     BIGNUM *bn = NULL;
00346 
00347     Require_EC_KEY(self, ec);
00348     if (!NIL_P(private_key))
00349         bn = GetBNPtr(private_key);
00350 
00351     switch (EC_KEY_set_private_key(ec, bn)) {
00352     case 1:
00353         break;
00354     case 0:
00355         if (bn == NULL)
00356             break;
00357     default:
00358         ossl_raise(eECError, "EC_KEY_set_private_key");
00359     }
00360 
00361     return private_key;
00362 }
00363 
00364 
00365 static VALUE ossl_ec_point_dup(const EC_POINT *point, VALUE group_v)
00366 {
00367     VALUE obj;
00368     const EC_GROUP *group;
00369     ossl_ec_point *new_point;
00370 
00371     obj = rb_obj_alloc(cEC_POINT);
00372     Data_Get_Struct(obj, ossl_ec_point, new_point);
00373 
00374     SafeRequire_EC_GROUP(group_v, group);
00375 
00376     new_point->point = EC_POINT_dup(point, group);
00377     if (new_point->point == NULL)
00378         ossl_raise(eEC_POINT, "EC_POINT_dup");
00379     rb_iv_set(obj, "@group", group_v);
00380 
00381     return obj;
00382 }
00383 
00384 /*
00385  *  call-seq:
00386  *     key.public_key   => OpenSSL::PKey::EC::Point
00387  *
00388  *  See the OpenSSL documentation for EC_KEY_get0_public_key()
00389  */
00390 static VALUE ossl_ec_key_get_public_key(VALUE self)
00391 {
00392     EC_KEY *ec;
00393     const EC_POINT *point;
00394     VALUE group;
00395 
00396     Require_EC_KEY(self, ec);
00397 
00398     if ((point = EC_KEY_get0_public_key(ec)) == NULL)
00399         return Qnil;
00400 
00401     group = rb_funcall(self, rb_intern("group"), 0);
00402     if (NIL_P(group))
00403         ossl_raise(eECError, "EC_KEY_get0_get0_group (has public_key but no group???");
00404 
00405     return ossl_ec_point_dup(point, group);
00406 }
00407 
00408 /*
00409  *  call-seq:
00410  *     key.public_key = ec_point
00411  *
00412  *  See the OpenSSL documentation for EC_KEY_set_public_key()
00413  */
00414 static VALUE ossl_ec_key_set_public_key(VALUE self, VALUE public_key)
00415 {
00416     EC_KEY *ec;
00417     EC_POINT *point = NULL;
00418 
00419     Require_EC_KEY(self, ec);
00420     if (!NIL_P(public_key))
00421         SafeRequire_EC_POINT(public_key, point);
00422 
00423     switch (EC_KEY_set_public_key(ec, point)) {
00424     case 1:
00425         break;
00426     case 0:
00427         if (point == NULL)
00428             break;
00429     default:
00430         ossl_raise(eECError, "EC_KEY_set_public_key");
00431     }
00432 
00433     return public_key;
00434 }
00435 
00436 /*
00437  *  call-seq:
00438  *     key.public_key? => true or false
00439  *
00440  *  Both public_key? and private_key? may return false at the same time unlike other PKey classes.
00441  */
00442 static VALUE ossl_ec_key_is_public_key(VALUE self)
00443 {
00444     EC_KEY *ec;
00445 
00446     Require_EC_KEY(self, ec);
00447 
00448     return (EC_KEY_get0_public_key(ec) ? Qtrue : Qfalse);
00449 }
00450 
00451 /*
00452  *  call-seq:
00453  *     key.private_key? => true or false
00454  *
00455  *  Both public_key? and private_key? may return false at the same time unlike other PKey classes.
00456  */
00457 static VALUE ossl_ec_key_is_private_key(VALUE self)
00458 {
00459     EC_KEY *ec;
00460 
00461     Require_EC_KEY(self, ec);
00462 
00463     return (EC_KEY_get0_private_key(ec) ? Qtrue : Qfalse);
00464 }
00465 
00466 static VALUE ossl_ec_key_to_string(VALUE self, VALUE ciph, VALUE pass, int format)
00467 {
00468     EC_KEY *ec;
00469     BIO *out;
00470     int i = -1;
00471     int private = 0;
00472     char *password = NULL;
00473     VALUE str;
00474 
00475     Require_EC_KEY(self, ec);
00476 
00477     if (EC_KEY_get0_public_key(ec) == NULL)
00478         ossl_raise(eECError, "can't export - no public key set");
00479 
00480     if (EC_KEY_check_key(ec) != 1)
00481         ossl_raise(eECError, "can't export - EC_KEY_check_key failed");
00482 
00483     if (EC_KEY_get0_private_key(ec))
00484         private = 1;
00485 
00486     if (!(out = BIO_new(BIO_s_mem())))
00487         ossl_raise(eECError, "BIO_new(BIO_s_mem())");
00488 
00489     switch(format) {
00490     case EXPORT_PEM:
00491         if (private) {
00492             const EVP_CIPHER *cipher;
00493             if (!NIL_P(ciph)) {
00494                 cipher = GetCipherPtr(ciph);
00495                 if (!NIL_P(pass)) {
00496                     StringValue(pass);
00497                     if (RSTRING_LENINT(pass) < OSSL_MIN_PWD_LEN)
00498                         ossl_raise(eOSSLError, "OpenSSL requires passwords to be at least four characters long");
00499                     password = RSTRING_PTR(pass);
00500                 }
00501             }
00502             else {
00503                 cipher = NULL;
00504             }
00505             i = PEM_write_bio_ECPrivateKey(out, ec, cipher, NULL, 0, NULL, password);
00506         } else {
00507             i = PEM_write_bio_EC_PUBKEY(out, ec);
00508         }
00509 
00510         break;
00511     case EXPORT_DER:
00512         if (private) {
00513             i = i2d_ECPrivateKey_bio(out, ec);
00514         } else {
00515             i = i2d_EC_PUBKEY_bio(out, ec);
00516         }
00517 
00518         break;
00519     default:
00520         BIO_free(out);
00521         ossl_raise(rb_eRuntimeError, "unknown format (internal error)");
00522     }
00523 
00524     if (i != 1) {
00525         BIO_free(out);
00526         ossl_raise(eECError, "outlen=%d", i);
00527     }
00528 
00529     str = ossl_membio2str(out);
00530 
00531     return str;
00532 }
00533 
00534 /*
00535  *  call-seq:
00536  *     key.export   => String
00537  *     key.export(cipher, pass_phrase) => String
00538  *
00539  * Outputs the EC key in PEM encoding.  If +cipher+ and +pass_phrase+ are
00540  * given they will be used to encrypt the key.  +cipher+ must be an
00541  * OpenSSL::Cipher::Cipher instance. Note that encryption will only be
00542  * effective for a private key, public keys will always be encoded in plain
00543  * text.
00544  *
00545  */
00546 static VALUE ossl_ec_key_export(int argc, VALUE *argv, VALUE self)
00547 {
00548     VALUE cipher, passwd;
00549     rb_scan_args(argc, argv, "02", &cipher, &passwd);
00550     return ossl_ec_key_to_string(self, cipher, passwd, EXPORT_PEM);
00551 }
00552 
00553 /*
00554  *  call-seq:
00555  *     key.to_der   => String
00556  *
00557  *  See the OpenSSL documentation for i2d_ECPrivateKey_bio()
00558  */
00559 static VALUE ossl_ec_key_to_der(VALUE self)
00560 {
00561     return ossl_ec_key_to_string(self, Qnil, Qnil, EXPORT_DER);
00562 }
00563 
00564 /*
00565  *  call-seq:
00566  *     key.to_text   => String
00567  *
00568  *  See the OpenSSL documentation for EC_KEY_print()
00569  */
00570 static VALUE ossl_ec_key_to_text(VALUE self)
00571 {
00572     EC_KEY *ec;
00573     BIO *out;
00574     VALUE str;
00575 
00576     Require_EC_KEY(self, ec);
00577     if (!(out = BIO_new(BIO_s_mem()))) {
00578         ossl_raise(eECError, "BIO_new(BIO_s_mem())");
00579     }
00580     if (!EC_KEY_print(out, ec, 0)) {
00581         BIO_free(out);
00582         ossl_raise(eECError, "EC_KEY_print");
00583     }
00584     str = ossl_membio2str(out);
00585 
00586     return str;
00587 }
00588 
00589 /*
00590  *  call-seq:
00591  *     key.generate_key   => self
00592  *
00593  *  See the OpenSSL documentation for EC_KEY_generate_key()
00594  */
00595 static VALUE ossl_ec_key_generate_key(VALUE self)
00596 {
00597     EC_KEY *ec;
00598 
00599     Require_EC_KEY(self, ec);
00600 
00601     if (EC_KEY_generate_key(ec) != 1)
00602         ossl_raise(eECError, "EC_KEY_generate_key");
00603 
00604     return self;
00605 }
00606 
00607 /*
00608  *  call-seq:
00609  *     key.check_key   => true
00610  *
00611  *  Raises an exception if the key is invalid.
00612  *
00613  *  See the OpenSSL documentation for EC_KEY_check_key()
00614  */
00615 static VALUE ossl_ec_key_check_key(VALUE self)
00616 {
00617     EC_KEY *ec;
00618 
00619     Require_EC_KEY(self, ec);
00620 
00621     if (EC_KEY_check_key(ec) != 1)
00622         ossl_raise(eECError, "EC_KEY_check_key");
00623 
00624     return Qtrue;
00625 }
00626 
00627 /*
00628  *  call-seq:
00629  *     key.dh_compute_key(pubkey)   => String
00630  *
00631  *  See the OpenSSL documentation for ECDH_compute_key()
00632  */
00633 static VALUE ossl_ec_key_dh_compute_key(VALUE self, VALUE pubkey)
00634 {
00635     EC_KEY *ec;
00636     EC_POINT *point;
00637     int buf_len;
00638     VALUE str;
00639 
00640     Require_EC_KEY(self, ec);
00641     SafeRequire_EC_POINT(pubkey, point);
00642 
00643 /* BUG: need a way to figure out the maximum string size */
00644     buf_len = 1024;
00645     str = rb_str_new(0, buf_len);
00646 /* BUG: take KDF as a block */
00647     buf_len = ECDH_compute_key(RSTRING_PTR(str), buf_len, point, ec, NULL);
00648     if (buf_len < 0)
00649          ossl_raise(eECError, "ECDH_compute_key");
00650 
00651     rb_str_resize(str, buf_len);
00652 
00653     return str;
00654 }
00655 
00656 /* sign_setup */
00657 
00658 /*
00659  *  call-seq:
00660  *     key.dsa_sign_asn1(data)   => String
00661  *
00662  *  See the OpenSSL documentation for ECDSA_sign()
00663  */
00664 static VALUE ossl_ec_key_dsa_sign_asn1(VALUE self, VALUE data)
00665 {
00666     EC_KEY *ec;
00667     unsigned int buf_len;
00668     VALUE str;
00669 
00670     Require_EC_KEY(self, ec);
00671     StringValue(data);
00672 
00673     if (EC_KEY_get0_private_key(ec) == NULL)
00674         ossl_raise(eECError, "Private EC key needed!");
00675 
00676     str = rb_str_new(0, ECDSA_size(ec) + 16);
00677     if (ECDSA_sign(0, (unsigned char *) RSTRING_PTR(data), RSTRING_LENINT(data), (unsigned char *) RSTRING_PTR(str), &buf_len, ec) != 1)
00678          ossl_raise(eECError, "ECDSA_sign");
00679 
00680     rb_str_resize(str, buf_len);
00681 
00682     return str;
00683 }
00684 
00685 /*
00686  *  call-seq:
00687  *     key.dsa_verify_asn1(data, sig)   => true or false
00688  *
00689  *  See the OpenSSL documentation for ECDSA_verify()
00690  */
00691 static VALUE ossl_ec_key_dsa_verify_asn1(VALUE self, VALUE data, VALUE sig)
00692 {
00693     EC_KEY *ec;
00694 
00695     Require_EC_KEY(self, ec);
00696     StringValue(data);
00697     StringValue(sig);
00698 
00699     switch (ECDSA_verify(0, (unsigned char *) RSTRING_PTR(data), RSTRING_LENINT(data), (unsigned char *) RSTRING_PTR(sig), (int)RSTRING_LEN(sig), ec)) {
00700     case 1:     return Qtrue;
00701     case 0:     return Qfalse;
00702     default:    break;
00703     }
00704 
00705     ossl_raise(eECError, "ECDSA_verify");
00706 
00707     UNREACHABLE;
00708 }
00709 
00710 static void ossl_ec_group_free(ossl_ec_group *ec_group)
00711 {
00712     if (!ec_group->dont_free && ec_group->group)
00713         EC_GROUP_clear_free(ec_group->group);
00714     ruby_xfree(ec_group);
00715 }
00716 
00717 static VALUE ossl_ec_group_alloc(VALUE klass)
00718 {
00719     ossl_ec_group *ec_group;
00720     VALUE obj;
00721 
00722     obj = Data_Make_Struct(klass, ossl_ec_group, 0, ossl_ec_group_free, ec_group);
00723 
00724     return obj;
00725 }
00726 
00727 /*  call-seq:
00728  *     OpenSSL::PKey::EC::Group.new("secp112r1")
00729  *     OpenSSL::PKey::EC::Group.new(ec_group)
00730  *     OpenSSL::PKey::EC::Group.new(pem_string)
00731  *     OpenSSL::PKey::EC::Group.new(der_string)
00732  *     OpenSSL::PKey::EC::Group.new(pem_file)
00733  *     OpenSSL::PKey::EC::Group.new(der_file)
00734  *     OpenSSL::PKey::EC::Group.new(:GFp_simple)
00735  *     OpenSSL::PKey::EC::Group.new(:GFp_mult)
00736  *     OpenSSL::PKey::EC::Group.new(:GFp_nist)
00737  *     OpenSSL::PKey::EC::Group.new(:GF2m_simple)
00738  *     OpenSSL::PKey::EC::Group.new(:GFp, bignum_p, bignum_a, bignum_b)
00739  *     OpenSSL::PKey::EC::Group.new(:GF2m, bignum_p, bignum_a, bignum_b)
00740  *
00741  *  See the OpenSSL documentation for EC_GROUP_*
00742  */
00743 static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self)
00744 {
00745     VALUE arg1, arg2, arg3, arg4;
00746     ossl_ec_group *ec_group;
00747     EC_GROUP *group = NULL;
00748 
00749     Data_Get_Struct(self, ossl_ec_group, ec_group);
00750     if (ec_group->group != NULL)
00751         ossl_raise(rb_eRuntimeError, "EC_GROUP is already initialized");
00752 
00753     switch (rb_scan_args(argc, argv, "13", &arg1, &arg2, &arg3, &arg4)) {
00754     case 1:
00755         if (SYMBOL_P(arg1)) {
00756             const EC_METHOD *method = NULL;
00757             ID id = SYM2ID(arg1);
00758 
00759             if (id == s_GFp_simple) {
00760                 method = EC_GFp_simple_method();
00761             } else if (id == s_GFp_mont) {
00762                 method = EC_GFp_mont_method();
00763             } else if (id == s_GFp_nist) {
00764                 method = EC_GFp_nist_method();
00765             } else if (id == s_GF2m_simple) {
00766                 method = EC_GF2m_simple_method();
00767             }
00768 
00769             if (method) {
00770                 if ((group = EC_GROUP_new(method)) == NULL)
00771                     ossl_raise(eEC_GROUP, "EC_GROUP_new");
00772             } else {
00773                 ossl_raise(rb_eArgError, "unknown symbol, must be :GFp_simple, :GFp_mont, :GFp_nist or :GF2m_simple");
00774             }
00775         } else if (rb_obj_is_kind_of(arg1, cEC_GROUP)) {
00776             const EC_GROUP *arg1_group;
00777 
00778             SafeRequire_EC_GROUP(arg1, arg1_group);
00779             if ((group = EC_GROUP_dup(arg1_group)) == NULL)
00780                 ossl_raise(eEC_GROUP, "EC_GROUP_dup");
00781         } else {
00782             BIO *in = ossl_obj2bio(arg1);
00783 
00784             group = PEM_read_bio_ECPKParameters(in, NULL, NULL, NULL);
00785             if (!group) {
00786                 OSSL_BIO_reset(in);
00787                 group = d2i_ECPKParameters_bio(in, NULL);
00788             }
00789 
00790             BIO_free(in);
00791 
00792             if (!group) {
00793                 const char *name = StringValueCStr(arg1);
00794                 int nid = OBJ_sn2nid(name);
00795 
00796                 (void)ERR_get_error();
00797                 if (nid == NID_undef)
00798                     ossl_raise(eEC_GROUP, "unknown curve name (%s)", name);
00799 
00800                 group = EC_GROUP_new_by_curve_name(nid);
00801                 if (group == NULL)
00802                     ossl_raise(eEC_GROUP, "unable to create curve (%s)", name);
00803 
00804                 EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE);
00805                 EC_GROUP_set_point_conversion_form(group, POINT_CONVERSION_UNCOMPRESSED);
00806             }
00807         }
00808 
00809         break;
00810     case 4:
00811         if (SYMBOL_P(arg1)) {
00812             ID id = SYM2ID(arg1);
00813             EC_GROUP *(*new_curve)(const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *) = NULL;
00814             const BIGNUM *p = GetBNPtr(arg2);
00815             const BIGNUM *a = GetBNPtr(arg3);
00816             const BIGNUM *b = GetBNPtr(arg4);
00817 
00818             if (id == s_GFp) {
00819                 new_curve = EC_GROUP_new_curve_GFp;
00820             } else if (id == s_GF2m) {
00821                 new_curve = EC_GROUP_new_curve_GF2m;
00822             } else {
00823                 ossl_raise(rb_eArgError, "unknown symbol, must be :GFp or :GF2m");
00824             }
00825 
00826             if ((group = new_curve(p, a, b, ossl_bn_ctx)) == NULL)
00827                 ossl_raise(eEC_GROUP, "EC_GROUP_new_by_GF*");
00828         } else {
00829              ossl_raise(rb_eArgError, "unknown argument, must be :GFp or :GF2m");
00830         }
00831 
00832         break;
00833     default:
00834         ossl_raise(rb_eArgError, "wrong number of arguments");
00835     }
00836 
00837     if (group == NULL)
00838         ossl_raise(eEC_GROUP, "");
00839 
00840     ec_group->group = group;
00841 
00842     return self;
00843 }
00844 
00845 /*  call-seq:
00846  *     group1 == group2   => true | false
00847  *
00848  */
00849 static VALUE ossl_ec_group_eql(VALUE a, VALUE b)
00850 {
00851     EC_GROUP *group1 = NULL, *group2 = NULL;
00852 
00853     Require_EC_GROUP(a, group1);
00854     SafeRequire_EC_GROUP(b, group2);
00855 
00856     if (EC_GROUP_cmp(group1, group2, ossl_bn_ctx) == 1)
00857        return Qfalse;
00858 
00859     return Qtrue;
00860 }
00861 
00862 /*  call-seq:
00863  *     group.generator   => ec_point
00864  *
00865  *  See the OpenSSL documentation for EC_GROUP_get0_generator()
00866  */
00867 static VALUE ossl_ec_group_get_generator(VALUE self)
00868 {
00869     VALUE point_obj;
00870     EC_GROUP *group = NULL;
00871 
00872     Require_EC_GROUP(self, group);
00873 
00874     point_obj = ossl_ec_point_dup(EC_GROUP_get0_generator(group), self);
00875 
00876     return point_obj;
00877 }
00878 
00879 /*  call-seq:
00880  *     group.set_generator(generator, order, cofactor)   => self
00881  *
00882  *  See the OpenSSL documentation for EC_GROUP_set_generator()
00883  */
00884 static VALUE ossl_ec_group_set_generator(VALUE self, VALUE generator, VALUE order, VALUE cofactor)
00885 {
00886     EC_GROUP *group = NULL;
00887     const EC_POINT *point;
00888     const BIGNUM *o, *co;
00889 
00890     Require_EC_GROUP(self, group);
00891     SafeRequire_EC_POINT(generator, point);
00892     o = GetBNPtr(order);
00893     co = GetBNPtr(cofactor);
00894 
00895     if (EC_GROUP_set_generator(group, point, o, co) != 1)
00896         ossl_raise(eEC_GROUP, "EC_GROUP_set_generator");
00897 
00898     return self;
00899 }
00900 
00901 /*  call-seq:
00902  *     group.get_order   => order_bn
00903  *
00904  *  See the OpenSSL documentation for EC_GROUP_get_order()
00905  */
00906 static VALUE ossl_ec_group_get_order(VALUE self)
00907 {
00908     VALUE bn_obj;
00909     BIGNUM *bn;
00910     EC_GROUP *group = NULL;
00911 
00912     Require_EC_GROUP(self, group);
00913 
00914     bn_obj = ossl_bn_new(NULL);
00915     bn = GetBNPtr(bn_obj);
00916 
00917     if (EC_GROUP_get_order(group, bn, ossl_bn_ctx) != 1)
00918         ossl_raise(eEC_GROUP, "EC_GROUP_get_order");
00919 
00920     return bn_obj;
00921 }
00922 
00923 /*  call-seq:
00924  *     group.get_cofactor   => cofactor_bn
00925  *
00926  *  See the OpenSSL documentation for EC_GROUP_get_cofactor()
00927  */
00928 static VALUE ossl_ec_group_get_cofactor(VALUE self)
00929 {
00930     VALUE bn_obj;
00931     BIGNUM *bn;
00932     EC_GROUP *group = NULL;
00933 
00934     Require_EC_GROUP(self, group);
00935 
00936     bn_obj = ossl_bn_new(NULL);
00937     bn = GetBNPtr(bn_obj);
00938 
00939     if (EC_GROUP_get_cofactor(group, bn, ossl_bn_ctx) != 1)
00940         ossl_raise(eEC_GROUP, "EC_GROUP_get_cofactor");
00941 
00942     return bn_obj;
00943 }
00944 
00945 /*  call-seq:
00946  *     group.curve_name  => String
00947  *
00948  *  See the OpenSSL documentation for EC_GROUP_get_curve_name()
00949  */
00950 static VALUE ossl_ec_group_get_curve_name(VALUE self)
00951 {
00952     EC_GROUP *group = NULL;
00953     int nid;
00954 
00955     Get_EC_GROUP(self, group);
00956     if (group == NULL)
00957         return Qnil;
00958 
00959     nid = EC_GROUP_get_curve_name(group);
00960 
00961 /* BUG: an nid or asn1 object should be returned, maybe. */
00962     return rb_str_new2(OBJ_nid2sn(nid));
00963 }
00964 
00965 /*  call-seq:
00966  *     EC.builtin_curves => [[name, comment], ...]
00967  *
00968  *  See the OpenSSL documentation for EC_builtin_curves()
00969  */
00970 static VALUE ossl_s_builtin_curves(VALUE self)
00971 {
00972     EC_builtin_curve *curves = NULL;
00973     int n;
00974     int crv_len = rb_long2int(EC_get_builtin_curves(NULL, 0));
00975     VALUE ary, ret;
00976 
00977     curves = ALLOCA_N(EC_builtin_curve, crv_len);
00978     if (curves == NULL)
00979         return Qnil;
00980     if (!EC_get_builtin_curves(curves, crv_len))
00981         ossl_raise(rb_eRuntimeError, "EC_get_builtin_curves");
00982 
00983     ret = rb_ary_new2(crv_len);
00984 
00985     for (n = 0; n < crv_len; n++) {
00986         const char *sname = OBJ_nid2sn(curves[n].nid);
00987         const char *comment = curves[n].comment;
00988 
00989         ary = rb_ary_new2(2);
00990         rb_ary_push(ary, rb_str_new2(sname));
00991         rb_ary_push(ary, comment ? rb_str_new2(comment) : Qnil);
00992         rb_ary_push(ret, ary);
00993     }
00994 
00995     return ret;
00996 }
00997 
00998 /*  call-seq:
00999  *     group.asn1_flag  => Fixnum
01000  *
01001  *  See the OpenSSL documentation for EC_GROUP_get_asn1_flag()
01002  */
01003 static VALUE ossl_ec_group_get_asn1_flag(VALUE self)
01004 {
01005     EC_GROUP *group = NULL;
01006     int flag;
01007 
01008     Require_EC_GROUP(self, group);
01009 
01010     flag = EC_GROUP_get_asn1_flag(group);
01011 
01012     return INT2FIX(flag);
01013 }
01014 
01015 /*  call-seq:
01016  *     group.asn1_flag = Fixnum   => Fixnum
01017  *
01018  *  See the OpenSSL documentation for EC_GROUP_set_asn1_flag()
01019  */
01020 static VALUE ossl_ec_group_set_asn1_flag(VALUE self, VALUE flag_v)
01021 {
01022     EC_GROUP *group = NULL;
01023 
01024     Require_EC_GROUP(self, group);
01025 
01026     EC_GROUP_set_asn1_flag(group, NUM2INT(flag_v));
01027 
01028     return flag_v;
01029 }
01030 
01031 /*  call-seq:
01032  *     group.point_conversion_form  => :uncompressed | :compressed | :hybrid
01033  *
01034  *  See the OpenSSL documentation for EC_GROUP_get_point_conversion_form()
01035  */
01036 static VALUE ossl_ec_group_get_point_conversion_form(VALUE self)
01037 {
01038     EC_GROUP *group = NULL;
01039     point_conversion_form_t form;
01040     VALUE ret;
01041 
01042     Require_EC_GROUP(self, group);
01043 
01044     form = EC_GROUP_get_point_conversion_form(group);
01045 
01046     switch (form) {
01047     case POINT_CONVERSION_UNCOMPRESSED: ret = ID_uncompressed; break;
01048     case POINT_CONVERSION_COMPRESSED:   ret = ID_compressed; break;
01049     case POINT_CONVERSION_HYBRID:       ret = ID_hybrid; break;
01050     default:    ossl_raise(eEC_GROUP, "unsupported point conversion form: %d, this module should be updated", form);
01051     }
01052 
01053    return ID2SYM(ret);
01054 }
01055 
01056 /*  call-seq:
01057  *     group.point_conversion_form = form => form
01058  *
01059  *  See the OpenSSL documentation for EC_GROUP_set_point_conversion_form()
01060  */
01061 static VALUE ossl_ec_group_set_point_conversion_form(VALUE self, VALUE form_v)
01062 {
01063     EC_GROUP *group = NULL;
01064     point_conversion_form_t form;
01065     ID form_id = SYM2ID(form_v);
01066 
01067     Require_EC_GROUP(self, group);
01068 
01069     if (form_id == ID_uncompressed) {
01070         form = POINT_CONVERSION_UNCOMPRESSED;
01071     } else if (form_id == ID_compressed) {
01072         form = POINT_CONVERSION_COMPRESSED;
01073     } else if (form_id == ID_hybrid) {
01074         form = POINT_CONVERSION_HYBRID;
01075     } else {
01076         ossl_raise(rb_eArgError, "form must be :compressed, :uncompressed, or :hybrid");
01077     }
01078 
01079     EC_GROUP_set_point_conversion_form(group, form);
01080 
01081     return form_v;
01082 }
01083 
01084 /*  call-seq:
01085  *     group.seed   => String or nil
01086  *
01087  *  See the OpenSSL documentation for EC_GROUP_get0_seed()
01088  */
01089 static VALUE ossl_ec_group_get_seed(VALUE self)
01090 {
01091     EC_GROUP *group = NULL;
01092     size_t seed_len;
01093 
01094     Require_EC_GROUP(self, group);
01095 
01096     seed_len = EC_GROUP_get_seed_len(group);
01097 
01098     if (seed_len == 0)
01099         return Qnil;
01100 
01101     return rb_str_new((const char *)EC_GROUP_get0_seed(group), seed_len);
01102 }
01103 
01104 /*  call-seq:
01105  *     group.seed = seed  => seed
01106  *
01107  *  See the OpenSSL documentation for EC_GROUP_set_seed()
01108  */
01109 static VALUE ossl_ec_group_set_seed(VALUE self, VALUE seed)
01110 {
01111     EC_GROUP *group = NULL;
01112 
01113     Require_EC_GROUP(self, group);
01114     StringValue(seed);
01115 
01116     if (EC_GROUP_set_seed(group, (unsigned char *)RSTRING_PTR(seed), RSTRING_LEN(seed)) != (size_t)RSTRING_LEN(seed))
01117         ossl_raise(eEC_GROUP, "EC_GROUP_set_seed");
01118 
01119     return seed;
01120 }
01121 
01122 /* get/set curve GFp, GF2m */
01123 
01124 /*  call-seq:
01125  *     group.degree   => Fixnum
01126  *
01127  *  See the OpenSSL documentation for EC_GROUP_get_degree()
01128  */
01129 static VALUE ossl_ec_group_get_degree(VALUE self)
01130 {
01131     EC_GROUP *group = NULL;
01132 
01133     Require_EC_GROUP(self, group);
01134 
01135     return INT2NUM(EC_GROUP_get_degree(group));
01136 }
01137 
01138 static VALUE ossl_ec_group_to_string(VALUE self, int format)
01139 {
01140     EC_GROUP *group;
01141     BIO *out;
01142     int i = -1;
01143     VALUE str;
01144 
01145     Get_EC_GROUP(self, group);
01146 
01147     if (!(out = BIO_new(BIO_s_mem())))
01148         ossl_raise(eEC_GROUP, "BIO_new(BIO_s_mem())");
01149 
01150     switch(format) {
01151     case EXPORT_PEM:
01152         i = PEM_write_bio_ECPKParameters(out, group);
01153         break;
01154     case EXPORT_DER:
01155         i = i2d_ECPKParameters_bio(out, group);
01156         break;
01157     default:
01158         BIO_free(out);
01159         ossl_raise(rb_eRuntimeError, "unknown format (internal error)");
01160     }
01161 
01162     if (i != 1) {
01163         BIO_free(out);
01164         ossl_raise(eECError, NULL);
01165     }
01166 
01167     str = ossl_membio2str(out);
01168 
01169     return str;
01170 }
01171 
01172 /*  call-seq:
01173  *     group.to_pem   => String
01174  *
01175  *  See the OpenSSL documentation for PEM_write_bio_ECPKParameters()
01176  */
01177 static VALUE ossl_ec_group_to_pem(VALUE self)
01178 {
01179     return ossl_ec_group_to_string(self, EXPORT_PEM);
01180 }
01181 
01182 /*  call-seq:
01183  *     group.to_der   => String
01184  *
01185  *  See the OpenSSL documentation for i2d_ECPKParameters_bio()
01186  */
01187 static VALUE ossl_ec_group_to_der(VALUE self)
01188 {
01189     return ossl_ec_group_to_string(self, EXPORT_DER);
01190 }
01191 
01192 /*  call-seq:
01193  *     group.to_text   => String
01194  *
01195  *  See the OpenSSL documentation for ECPKParameters_print()
01196  */
01197 static VALUE ossl_ec_group_to_text(VALUE self)
01198 {
01199     EC_GROUP *group;
01200     BIO *out;
01201     VALUE str;
01202 
01203     Require_EC_GROUP(self, group);
01204     if (!(out = BIO_new(BIO_s_mem()))) {
01205         ossl_raise(eEC_GROUP, "BIO_new(BIO_s_mem())");
01206     }
01207     if (!ECPKParameters_print(out, group, 0)) {
01208         BIO_free(out);
01209         ossl_raise(eEC_GROUP, NULL);
01210     }
01211     str = ossl_membio2str(out);
01212 
01213     return str;
01214 }
01215 
01216 
01217 static void ossl_ec_point_free(ossl_ec_point *ec_point)
01218 {
01219     if (!ec_point->dont_free && ec_point->point)
01220         EC_POINT_clear_free(ec_point->point);
01221     ruby_xfree(ec_point);
01222 }
01223 
01224 static VALUE ossl_ec_point_alloc(VALUE klass)
01225 {
01226     ossl_ec_point *ec_point;
01227     VALUE obj;
01228 
01229     obj = Data_Make_Struct(klass, ossl_ec_point, 0, ossl_ec_point_free, ec_point);
01230 
01231     return obj;
01232 }
01233 
01234 /*
01235  *  call-seq:
01236  *     OpenSSL::PKey::EC::Point.new(point)
01237  *     OpenSSL::PKey::EC::Point.new(group)
01238  *     OpenSSL::PKey::EC::Point.new(group, bn)
01239  *
01240  *  See the OpenSSL documentation for EC_POINT_*
01241  */
01242 static VALUE ossl_ec_point_initialize(int argc, VALUE *argv, VALUE self)
01243 {
01244     ossl_ec_point *ec_point;
01245     EC_POINT *point = NULL;
01246     VALUE arg1, arg2;
01247     VALUE group_v = Qnil;
01248     const EC_GROUP *group = NULL;
01249 
01250     Data_Get_Struct(self, ossl_ec_point, ec_point);
01251     if (ec_point->point)
01252         ossl_raise(eEC_POINT, "EC_POINT already initialized");
01253 
01254     switch (rb_scan_args(argc, argv, "11", &arg1, &arg2)) {
01255     case 1:
01256         if (rb_obj_is_kind_of(arg1, cEC_POINT)) {
01257             const EC_POINT *arg_point;
01258 
01259             group_v = rb_iv_get(arg1, "@group");
01260             SafeRequire_EC_GROUP(group_v, group);
01261             SafeRequire_EC_POINT(arg1, arg_point);
01262 
01263             point = EC_POINT_dup(arg_point, group);
01264         } else if (rb_obj_is_kind_of(arg1, cEC_GROUP)) {
01265             group_v = arg1;
01266             SafeRequire_EC_GROUP(group_v, group);
01267 
01268             point = EC_POINT_new(group);
01269         } else {
01270             ossl_raise(eEC_POINT, "wrong argument type: must be OpenSSL::PKey::EC::Point or OpenSSL::Pkey::EC::Group");
01271         }
01272 
01273         break;
01274      case 2:
01275         if (!rb_obj_is_kind_of(arg1, cEC_GROUP))
01276             ossl_raise(rb_eArgError, "1st argument must be OpenSSL::PKey::EC::Group");
01277         group_v = arg1;
01278         SafeRequire_EC_GROUP(group_v, group);
01279 
01280         if (rb_obj_is_kind_of(arg2, cBN)) {
01281             const BIGNUM *bn = GetBNPtr(arg2);
01282 
01283             point = EC_POINT_bn2point(group, bn, NULL, ossl_bn_ctx);
01284         } else {
01285             BIO *in = ossl_obj2bio(arg1);
01286 
01287 /* BUG: finish me */
01288 
01289             BIO_free(in);
01290 
01291             if (point == NULL) {
01292                 ossl_raise(eEC_POINT, "unknown type for 2nd arg");
01293             }
01294         }
01295         break;
01296     default:
01297         ossl_raise(rb_eArgError, "wrong number of arguments");
01298     }
01299 
01300     if (point == NULL)
01301         ossl_raise(eEC_POINT, NULL);
01302 
01303     if (NIL_P(group_v))
01304         ossl_raise(rb_eRuntimeError, "missing group (internal error)");
01305 
01306     ec_point->point = point;
01307 
01308     rb_iv_set(self, "@group", group_v);
01309 
01310     return self;
01311 }
01312 
01313 /*
01314  *  call-seq:
01315  *     point1 == point2 => true | false
01316  *
01317  */
01318 static VALUE ossl_ec_point_eql(VALUE a, VALUE b)
01319 {
01320     EC_POINT *point1, *point2;
01321     VALUE group_v1 = rb_iv_get(a, "@group");
01322     VALUE group_v2 = rb_iv_get(b, "@group");
01323     const EC_GROUP *group;
01324 
01325     if (ossl_ec_group_eql(group_v1, group_v2) == Qfalse)
01326         return Qfalse;
01327 
01328     Require_EC_POINT(a, point1);
01329     SafeRequire_EC_POINT(b, point2);
01330     SafeRequire_EC_GROUP(group_v1, group);
01331 
01332     if (EC_POINT_cmp(group, point1, point2, ossl_bn_ctx) == 1)
01333         return Qfalse;
01334 
01335     return Qtrue;
01336 }
01337 
01338 /*
01339  *  call-seq:
01340  *     point.infinity? => true | false
01341  *
01342  */
01343 static VALUE ossl_ec_point_is_at_infinity(VALUE self)
01344 {
01345     EC_POINT *point;
01346     VALUE group_v = rb_iv_get(self, "@group");
01347     const EC_GROUP *group;
01348 
01349     Require_EC_POINT(self, point);
01350     SafeRequire_EC_GROUP(group_v, group);
01351 
01352     switch (EC_POINT_is_at_infinity(group, point)) {
01353     case 1: return Qtrue;
01354     case 0: return Qfalse;
01355     default: ossl_raise(cEC_POINT, "EC_POINT_is_at_infinity");
01356     }
01357 
01358     UNREACHABLE;
01359 }
01360 
01361 /*
01362  *  call-seq:
01363  *     point.on_curve? => true | false
01364  *
01365  */
01366 static VALUE ossl_ec_point_is_on_curve(VALUE self)
01367 {
01368     EC_POINT *point;
01369     VALUE group_v = rb_iv_get(self, "@group");
01370     const EC_GROUP *group;
01371 
01372     Require_EC_POINT(self, point);
01373     SafeRequire_EC_GROUP(group_v, group);
01374 
01375     switch (EC_POINT_is_on_curve(group, point, ossl_bn_ctx)) {
01376     case 1: return Qtrue;
01377     case 0: return Qfalse;
01378     default: ossl_raise(cEC_POINT, "EC_POINT_is_on_curve");
01379     }
01380 
01381     UNREACHABLE;
01382 }
01383 
01384 /*
01385  *  call-seq:
01386  *     point.make_affine! => self
01387  *
01388  */
01389 static VALUE ossl_ec_point_make_affine(VALUE self)
01390 {
01391     EC_POINT *point;
01392     VALUE group_v = rb_iv_get(self, "@group");
01393     const EC_GROUP *group;
01394 
01395     Require_EC_POINT(self, point);
01396     SafeRequire_EC_GROUP(group_v, group);
01397 
01398     if (EC_POINT_make_affine(group, point, ossl_bn_ctx) != 1)
01399         ossl_raise(cEC_POINT, "EC_POINT_make_affine");
01400 
01401     return self;
01402 }
01403 
01404 /*
01405  *  call-seq:
01406  *     point.invert! => self
01407  *
01408  */
01409 static VALUE ossl_ec_point_invert(VALUE self)
01410 {
01411     EC_POINT *point;
01412     VALUE group_v = rb_iv_get(self, "@group");
01413     const EC_GROUP *group;
01414 
01415     Require_EC_POINT(self, point);
01416     SafeRequire_EC_GROUP(group_v, group);
01417 
01418     if (EC_POINT_invert(group, point, ossl_bn_ctx) != 1)
01419         ossl_raise(cEC_POINT, "EC_POINT_invert");
01420 
01421     return self;
01422 }
01423 
01424 /*
01425  *  call-seq:
01426  *     point.set_to_infinity! => self
01427  *
01428  */
01429 static VALUE ossl_ec_point_set_to_infinity(VALUE self)
01430 {
01431     EC_POINT *point;
01432     VALUE group_v = rb_iv_get(self, "@group");
01433     const EC_GROUP *group;
01434 
01435     Require_EC_POINT(self, point);
01436     SafeRequire_EC_GROUP(group_v, group);
01437 
01438     if (EC_POINT_set_to_infinity(group, point) != 1)
01439         ossl_raise(cEC_POINT, "EC_POINT_set_to_infinity");
01440 
01441     return self;
01442 }
01443 
01444 /*
01445  *  call-seq:
01446  *     point.to_bn   => OpenSSL::BN
01447  *
01448  *  See the OpenSSL documentation for EC_POINT_point2bn()
01449  */
01450 static VALUE ossl_ec_point_to_bn(VALUE self)
01451 {
01452     EC_POINT *point;
01453     VALUE bn_obj;
01454     VALUE group_v = rb_iv_get(self, "@group");
01455     const EC_GROUP *group;
01456     point_conversion_form_t form;
01457     BIGNUM *bn;
01458 
01459     Require_EC_POINT(self, point);
01460     SafeRequire_EC_GROUP(group_v, group);
01461 
01462     form = EC_GROUP_get_point_conversion_form(group);
01463 
01464     bn_obj = rb_obj_alloc(cBN);
01465     bn = GetBNPtr(bn_obj);
01466 
01467     if (EC_POINT_point2bn(group, point, form, bn, ossl_bn_ctx) == NULL)
01468         ossl_raise(eEC_POINT, "EC_POINT_point2bn");
01469 
01470     return bn_obj;
01471 }
01472 
01473 /*
01474  *  call-seq:
01475  *     point.mul(bn)  => point
01476  *     point.mul(bn, bn) => point
01477  *     point.mul([bn], [point]) => point
01478  *     point.mul([bn], [point], bn) => point
01479  */
01480 static VALUE ossl_ec_point_mul(int argc, VALUE *argv, VALUE self)
01481 {
01482     EC_POINT *point1, *point2;
01483     const EC_GROUP *group;
01484     VALUE group_v = rb_iv_get(self, "@group");
01485     VALUE bn_v1, bn_v2, r, points_v;
01486     BIGNUM *bn1 = NULL, *bn2 = NULL;
01487 
01488     Require_EC_POINT(self, point1);
01489     SafeRequire_EC_GROUP(group_v, group);
01490 
01491     r = rb_obj_alloc(cEC_POINT);
01492     ossl_ec_point_initialize(1, &group_v, r);
01493     Require_EC_POINT(r, point2);
01494 
01495     argc = rb_scan_args(argc, argv, "12", &bn_v1, &points_v, &bn_v2);
01496 
01497     if (rb_obj_is_kind_of(bn_v1, cBN)) {
01498         bn1 = GetBNPtr(bn_v1);
01499         if (argc >= 2) {
01500             bn2 = GetBNPtr(points_v);
01501         }
01502         if (EC_POINT_mul(group, point2, bn2, point1, bn1, ossl_bn_ctx) != 1)
01503             ossl_raise(eEC_POINT, "Multiplication failed");
01504     } else {
01505         size_t i, points_len, bignums_len;
01506         const EC_POINT **points;
01507         const BIGNUM **bignums;
01508 
01509         Check_Type(bn_v1, T_ARRAY);
01510         bignums_len = RARRAY_LEN(bn_v1);
01511         bignums = (const BIGNUM **)OPENSSL_malloc(bignums_len * (int)sizeof(BIGNUM *));
01512 
01513         for (i = 0; i < bignums_len; ++i) {
01514             bignums[i] = GetBNPtr(rb_ary_entry(bn_v1, i));
01515         }
01516 
01517         if (!rb_obj_is_kind_of(points_v, rb_cArray)) {
01518             OPENSSL_free((void *)bignums);
01519             rb_raise(rb_eTypeError, "Argument2 must be an array");
01520         }
01521 
01522         rb_ary_unshift(points_v, self);
01523         points_len = RARRAY_LEN(points_v);
01524         points = (const EC_POINT **)OPENSSL_malloc(points_len * (int)sizeof(EC_POINT *));
01525 
01526         for (i = 0; i < points_len; ++i) {
01527             Get_EC_POINT(rb_ary_entry(points_v, i), points[i]);
01528         }
01529 
01530         if (argc >= 3) {
01531             bn2 = GetBNPtr(bn_v2);
01532         }
01533         if (EC_POINTs_mul(group, point2, bn2, points_len, points, bignums, ossl_bn_ctx) != 1) {
01534             OPENSSL_free((void *)bignums);
01535             OPENSSL_free((void *)points);
01536             ossl_raise(eEC_POINT, "Multiplication failed");
01537         }
01538         OPENSSL_free((void *)bignums);
01539         OPENSSL_free((void *)points);
01540     }
01541 
01542     return r;
01543 }
01544 
01545 static void no_copy(VALUE klass)
01546 {
01547     rb_undef_method(klass, "copy");
01548     rb_undef_method(klass, "clone");
01549     rb_undef_method(klass, "dup");
01550     rb_undef_method(klass, "initialize_copy");
01551 }
01552 
01553 void Init_ossl_ec()
01554 {
01555 #ifdef DONT_NEED_RDOC_WORKAROUND
01556     mOSSL = rb_define_module("OpenSSL");
01557     mPKey = rb_define_module_under(mOSSL, "PKey");
01558 #endif
01559 
01560     eECError = rb_define_class_under(mPKey, "ECError", ePKeyError);
01561 
01562     cEC = rb_define_class_under(mPKey, "EC", cPKey);
01563     cEC_GROUP = rb_define_class_under(cEC, "Group", rb_cObject);
01564     cEC_POINT = rb_define_class_under(cEC, "Point", rb_cObject);
01565     eEC_GROUP = rb_define_class_under(cEC_GROUP, "Error", eOSSLError);
01566     eEC_POINT = rb_define_class_under(cEC_POINT, "Error", eOSSLError);
01567 
01568     s_GFp = rb_intern("GFp");
01569     s_GF2m = rb_intern("GF2m");
01570     s_GFp_simple = rb_intern("GFp_simple");
01571     s_GFp_mont = rb_intern("GFp_mont");
01572     s_GFp_nist = rb_intern("GFp_nist");
01573     s_GF2m_simple = rb_intern("GF2m_simple");
01574 
01575     ID_uncompressed = rb_intern("uncompressed");
01576     ID_compressed = rb_intern("compressed");
01577     ID_hybrid = rb_intern("hybrid");
01578 
01579 #ifdef OPENSSL_EC_NAMED_CURVE
01580     rb_define_const(cEC, "NAMED_CURVE", ULONG2NUM(OPENSSL_EC_NAMED_CURVE));
01581 #endif
01582 
01583     rb_define_singleton_method(cEC, "builtin_curves", ossl_s_builtin_curves, 0);
01584 
01585     rb_define_method(cEC, "initialize", ossl_ec_key_initialize, -1);
01586 /* copy/dup/cmp */
01587 
01588     rb_define_method(cEC, "group", ossl_ec_key_get_group, 0);
01589     rb_define_method(cEC, "group=", ossl_ec_key_set_group, 1);
01590     rb_define_method(cEC, "private_key", ossl_ec_key_get_private_key, 0);
01591     rb_define_method(cEC, "private_key=", ossl_ec_key_set_private_key, 1);
01592     rb_define_method(cEC, "public_key", ossl_ec_key_get_public_key, 0);
01593     rb_define_method(cEC, "public_key=", ossl_ec_key_set_public_key, 1);
01594     rb_define_method(cEC, "private_key?", ossl_ec_key_is_private_key, 0);
01595     rb_define_method(cEC, "public_key?", ossl_ec_key_is_public_key, 0);
01596 /*  rb_define_method(cEC, "", ossl_ec_key_get_, 0);
01597     rb_define_method(cEC, "=", ossl_ec_key_set_ 1);
01598     set/get enc_flags
01599     set/get _conv_from
01600     set/get asn1_flag (can use ruby to call self.group.asn1_flag)
01601     set/get precompute_mult
01602 */
01603     rb_define_method(cEC, "generate_key", ossl_ec_key_generate_key, 0);
01604     rb_define_method(cEC, "check_key", ossl_ec_key_check_key, 0);
01605 
01606     rb_define_method(cEC, "dh_compute_key", ossl_ec_key_dh_compute_key, 1);
01607     rb_define_method(cEC, "dsa_sign_asn1", ossl_ec_key_dsa_sign_asn1, 1);
01608     rb_define_method(cEC, "dsa_verify_asn1", ossl_ec_key_dsa_verify_asn1, 2);
01609 /* do_sign/do_verify */
01610 
01611     rb_define_method(cEC, "export", ossl_ec_key_export, -1);
01612     rb_define_alias(cEC, "to_pem", "export");
01613     rb_define_method(cEC, "to_der", ossl_ec_key_to_der, 0);
01614     rb_define_method(cEC, "to_text", ossl_ec_key_to_text, 0);
01615 
01616 
01617     rb_define_alloc_func(cEC_GROUP, ossl_ec_group_alloc);
01618     rb_define_method(cEC_GROUP, "initialize", ossl_ec_group_initialize, -1);
01619     rb_define_method(cEC_GROUP, "eql?", ossl_ec_group_eql, 1);
01620     rb_define_alias(cEC_GROUP, "==", "eql?");
01621 /* copy/dup/cmp */
01622 
01623     rb_define_method(cEC_GROUP, "generator", ossl_ec_group_get_generator, 0);
01624     rb_define_method(cEC_GROUP, "set_generator", ossl_ec_group_set_generator, 3);
01625     rb_define_method(cEC_GROUP, "order", ossl_ec_group_get_order, 0);
01626     rb_define_method(cEC_GROUP, "cofactor", ossl_ec_group_get_cofactor, 0);
01627 
01628     rb_define_method(cEC_GROUP, "curve_name", ossl_ec_group_get_curve_name, 0);
01629 /*    rb_define_method(cEC_GROUP, "curve_name=", ossl_ec_group_set_curve_name, 1); */
01630 
01631     rb_define_method(cEC_GROUP, "asn1_flag", ossl_ec_group_get_asn1_flag, 0);
01632     rb_define_method(cEC_GROUP, "asn1_flag=", ossl_ec_group_set_asn1_flag, 1);
01633 
01634     rb_define_method(cEC_GROUP, "point_conversion_form", ossl_ec_group_get_point_conversion_form, 0);
01635     rb_define_method(cEC_GROUP, "point_conversion_form=", ossl_ec_group_set_point_conversion_form, 1);
01636 
01637     rb_define_method(cEC_GROUP, "seed", ossl_ec_group_get_seed, 0);
01638     rb_define_method(cEC_GROUP, "seed=", ossl_ec_group_set_seed, 1);
01639 
01640 /* get/set GFp, GF2m */
01641 
01642     rb_define_method(cEC_GROUP, "degree", ossl_ec_group_get_degree, 0);
01643 
01644 /* check* */
01645 
01646 
01647     rb_define_method(cEC_GROUP, "to_pem", ossl_ec_group_to_pem, 0);
01648     rb_define_method(cEC_GROUP, "to_der", ossl_ec_group_to_der, 0);
01649     rb_define_method(cEC_GROUP, "to_text", ossl_ec_group_to_text, 0);
01650 
01651 
01652     rb_define_alloc_func(cEC_POINT, ossl_ec_point_alloc);
01653     rb_define_method(cEC_POINT, "initialize", ossl_ec_point_initialize, -1);
01654     rb_attr(cEC_POINT, rb_intern("group"), 1, 0, 0);
01655     rb_define_method(cEC_POINT, "eql?", ossl_ec_point_eql, 1);
01656     rb_define_alias(cEC_POINT, "==", "eql?");
01657 
01658     rb_define_method(cEC_POINT, "infinity?", ossl_ec_point_is_at_infinity, 0);
01659     rb_define_method(cEC_POINT, "on_curve?", ossl_ec_point_is_on_curve, 0);
01660     rb_define_method(cEC_POINT, "make_affine!", ossl_ec_point_make_affine, 0);
01661     rb_define_method(cEC_POINT, "invert!", ossl_ec_point_invert, 0);
01662     rb_define_method(cEC_POINT, "set_to_infinity!", ossl_ec_point_set_to_infinity, 0);
01663 /* all the other methods */
01664 
01665     rb_define_method(cEC_POINT, "to_bn", ossl_ec_point_to_bn, 0);
01666     rb_define_method(cEC_POINT, "mul", ossl_ec_point_mul, -1);
01667 
01668     no_copy(cEC);
01669     no_copy(cEC_GROUP);
01670     no_copy(cEC_POINT);
01671 }
01672 
01673 #else /* defined NO_EC */
01674 void Init_ossl_ec()
01675 {
01676 }
01677 #endif /* NO_EC */
01678