Ruby  1.9.3p537(2014-02-19revision0)
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                     password = StringValuePtr(pass);
00497                 }
00498             }
00499             else {
00500                 cipher = NULL;
00501             }
00502             i = PEM_write_bio_ECPrivateKey(out, ec, cipher, NULL, 0, NULL, password);
00503         } else {
00504             i = PEM_write_bio_EC_PUBKEY(out, ec);
00505         }
00506 
00507         break;
00508     case EXPORT_DER:
00509         if (private) {
00510             i = i2d_ECPrivateKey_bio(out, ec);
00511         } else {
00512             i = i2d_EC_PUBKEY_bio(out, ec);
00513         }
00514 
00515         break;
00516     default:
00517         BIO_free(out);
00518         ossl_raise(rb_eRuntimeError, "unknown format (internal error)");
00519     }
00520 
00521     if (i != 1) {
00522         BIO_free(out);
00523         ossl_raise(eECError, "outlen=%d", i);
00524     }
00525 
00526     str = ossl_membio2str(out);
00527 
00528     return str;
00529 }
00530 
00531 /*
00532  *  call-seq:
00533  *     key.to_pem   => String
00534  *     key.to_pem(cipher, pass_phrase) => String
00535  *
00536  * Outputs the EC key in PEM encoding.  If +cipher+ and +pass_phrase+ are
00537  * given they will be used to encrypt the key.  +cipher+ must be an
00538  * OpenSSL::Cipher::Cipher instance. Note that encryption will only be
00539  * effective for a private key, public keys will always be encoded in plain
00540  * text.
00541  *
00542  */
00543 static VALUE ossl_ec_key_to_pem(int argc, VALUE *argv, VALUE self)
00544 {
00545     VALUE cipher, passwd;
00546     rb_scan_args(argc, argv, "02", &cipher, &passwd);
00547     return ossl_ec_key_to_string(self, cipher, passwd, EXPORT_PEM);
00548 }
00549 
00550 /*
00551  *  call-seq:
00552  *     key.to_der   => String
00553  *
00554  *  See the OpenSSL documentation for i2d_ECPrivateKey_bio()
00555  */
00556 static VALUE ossl_ec_key_to_der(VALUE self)
00557 {
00558     return ossl_ec_key_to_string(self, Qnil, Qnil, EXPORT_DER);
00559 }
00560 
00561 /*
00562  *  call-seq:
00563  *     key.to_text   => String
00564  *
00565  *  See the OpenSSL documentation for EC_KEY_print()
00566  */
00567 static VALUE ossl_ec_key_to_text(VALUE self)
00568 {
00569     EC_KEY *ec;
00570     BIO *out;
00571     VALUE str;
00572 
00573     Require_EC_KEY(self, ec);
00574     if (!(out = BIO_new(BIO_s_mem()))) {
00575         ossl_raise(eECError, "BIO_new(BIO_s_mem())");
00576     }
00577     if (!EC_KEY_print(out, ec, 0)) {
00578         BIO_free(out);
00579         ossl_raise(eECError, "EC_KEY_print");
00580     }
00581     str = ossl_membio2str(out);
00582 
00583     return str;
00584 }
00585 
00586 /*
00587  *  call-seq:
00588  *     key.generate_key   => self
00589  *
00590  *  See the OpenSSL documentation for EC_KEY_generate_key()
00591  */
00592 static VALUE ossl_ec_key_generate_key(VALUE self)
00593 {
00594     EC_KEY *ec;
00595 
00596     Require_EC_KEY(self, ec);
00597 
00598     if (EC_KEY_generate_key(ec) != 1)
00599         ossl_raise(eECError, "EC_KEY_generate_key");
00600 
00601     return self;
00602 }
00603 
00604 /*
00605  *  call-seq:
00606  *     key.check_key   => true
00607  *
00608  *  Raises an exception if the key is invalid.
00609  *
00610  *  See the OpenSSL documentation for EC_KEY_check_key()
00611  */
00612 static VALUE ossl_ec_key_check_key(VALUE self)
00613 {
00614     EC_KEY *ec;
00615 
00616     Require_EC_KEY(self, ec);
00617 
00618     if (EC_KEY_check_key(ec) != 1)
00619         ossl_raise(eECError, "EC_KEY_check_key");
00620 
00621     return Qtrue;
00622 }
00623 
00624 /*
00625  *  call-seq:
00626  *     key.dh_compute_key(pubkey)   => String
00627  *
00628  *  See the OpenSSL documentation for ECDH_compute_key()
00629  */
00630 static VALUE ossl_ec_key_dh_compute_key(VALUE self, VALUE pubkey)
00631 {
00632     EC_KEY *ec;
00633     EC_POINT *point;
00634     int buf_len;
00635     VALUE str;
00636 
00637     Require_EC_KEY(self, ec);
00638     SafeRequire_EC_POINT(pubkey, point);
00639 
00640 /* BUG: need a way to figure out the maximum string size */
00641     buf_len = 1024;
00642     str = rb_str_new(0, buf_len);
00643 /* BUG: take KDF as a block */
00644     buf_len = ECDH_compute_key(RSTRING_PTR(str), buf_len, point, ec, NULL);
00645     if (buf_len < 0)
00646          ossl_raise(eECError, "ECDH_compute_key");
00647 
00648     rb_str_resize(str, buf_len);
00649 
00650     return str;
00651 }
00652 
00653 /* sign_setup */
00654 
00655 /*
00656  *  call-seq:
00657  *     key.dsa_sign_asn1(data)   => String
00658  *
00659  *  See the OpenSSL documentation for ECDSA_sign()
00660  */
00661 static VALUE ossl_ec_key_dsa_sign_asn1(VALUE self, VALUE data)
00662 {
00663     EC_KEY *ec;
00664     unsigned int buf_len;
00665     VALUE str;
00666 
00667     Require_EC_KEY(self, ec);
00668     StringValue(data);
00669 
00670     if (EC_KEY_get0_private_key(ec) == NULL)
00671         ossl_raise(eECError, "Private EC key needed!");
00672 
00673     str = rb_str_new(0, ECDSA_size(ec) + 16);
00674     if (ECDSA_sign(0, (unsigned char *) RSTRING_PTR(data), RSTRING_LENINT(data), (unsigned char *) RSTRING_PTR(str), &buf_len, ec) != 1)
00675          ossl_raise(eECError, "ECDSA_sign");
00676 
00677     rb_str_resize(str, buf_len);
00678 
00679     return str;
00680 }
00681 
00682 /*
00683  *  call-seq:
00684  *     key.dsa_verify_asn1(data, sig)   => true or false
00685  *
00686  *  See the OpenSSL documentation for ECDSA_verify()
00687  */
00688 static VALUE ossl_ec_key_dsa_verify_asn1(VALUE self, VALUE data, VALUE sig)
00689 {
00690     EC_KEY *ec;
00691 
00692     Require_EC_KEY(self, ec);
00693     StringValue(data);
00694     StringValue(sig);
00695 
00696     switch (ECDSA_verify(0, (unsigned char *) RSTRING_PTR(data), RSTRING_LENINT(data), (unsigned char *) RSTRING_PTR(sig), (int)RSTRING_LEN(sig), ec)) {
00697     case 1:     return Qtrue;
00698     case 0:     return Qfalse;
00699     default:    break;
00700     }
00701 
00702     ossl_raise(eECError, "ECDSA_verify");
00703 }
00704 
00705 static void ossl_ec_group_free(ossl_ec_group *ec_group)
00706 {
00707     if (!ec_group->dont_free && ec_group->group)
00708         EC_GROUP_clear_free(ec_group->group);
00709     ruby_xfree(ec_group);
00710 }
00711 
00712 static VALUE ossl_ec_group_alloc(VALUE klass)
00713 {
00714     ossl_ec_group *ec_group;
00715     VALUE obj;
00716 
00717     obj = Data_Make_Struct(klass, ossl_ec_group, 0, ossl_ec_group_free, ec_group);
00718 
00719     return obj;
00720 }
00721 
00722 /*  call-seq:
00723  *     OpenSSL::PKey::EC::Group.new("secp112r1")
00724  *     OpenSSL::PKey::EC::Group.new(ec_group)
00725  *     OpenSSL::PKey::EC::Group.new(pem_string)
00726  *     OpenSSL::PKey::EC::Group.new(der_string)
00727  *     OpenSSL::PKey::EC::Group.new(pem_file)
00728  *     OpenSSL::PKey::EC::Group.new(der_file)
00729  *     OpenSSL::PKey::EC::Group.new(:GFp_simple)
00730  *     OpenSSL::PKey::EC::Group.new(:GFp_mult)
00731  *     OpenSSL::PKey::EC::Group.new(:GFp_nist)
00732  *     OpenSSL::PKey::EC::Group.new(:GF2m_simple)
00733  *     OpenSSL::PKey::EC::Group.new(:GFp, bignum_p, bignum_a, bignum_b)
00734  *     OpenSSL::PKey::EC::Group.new(:GF2m, bignum_p, bignum_a, bignum_b)
00735  *
00736  *  See the OpenSSL documentation for EC_GROUP_*
00737  */
00738 static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self)
00739 {
00740     VALUE arg1, arg2, arg3, arg4;
00741     ossl_ec_group *ec_group;
00742     EC_GROUP *group = NULL;
00743 
00744     Data_Get_Struct(self, ossl_ec_group, ec_group);
00745     if (ec_group->group != NULL)
00746         ossl_raise(rb_eRuntimeError, "EC_GROUP is already initialized");
00747 
00748     switch (rb_scan_args(argc, argv, "13", &arg1, &arg2, &arg3, &arg4)) {
00749     case 1:
00750         if (SYMBOL_P(arg1)) {
00751             const EC_METHOD *method = NULL;
00752             ID id = SYM2ID(arg1);
00753 
00754             if (id == s_GFp_simple) {
00755                 method = EC_GFp_simple_method();
00756             } else if (id == s_GFp_mont) {
00757                 method = EC_GFp_mont_method();
00758             } else if (id == s_GFp_nist) {
00759                 method = EC_GFp_nist_method();
00760 #if !defined(OPENSSL_NO_EC2M)
00761             } else if (id == s_GF2m_simple) {
00762                 method = EC_GF2m_simple_method();
00763 #endif
00764             }
00765 
00766             if (method) {
00767                 if ((group = EC_GROUP_new(method)) == NULL)
00768                     ossl_raise(eEC_GROUP, "EC_GROUP_new");
00769             } else {
00770                 ossl_raise(rb_eArgError, "unknown symbol, must be :GFp_simple, :GFp_mont, :GFp_nist or :GF2m_simple");
00771             }
00772         } else if (rb_obj_is_kind_of(arg1, cEC_GROUP)) {
00773             const EC_GROUP *arg1_group;
00774 
00775             SafeRequire_EC_GROUP(arg1, arg1_group);
00776             if ((group = EC_GROUP_dup(arg1_group)) == NULL)
00777                 ossl_raise(eEC_GROUP, "EC_GROUP_dup");
00778         } else {
00779             BIO *in = ossl_obj2bio(arg1);
00780 
00781             group = PEM_read_bio_ECPKParameters(in, NULL, NULL, NULL);
00782             if (!group) {
00783                 OSSL_BIO_reset(in);
00784                 group = d2i_ECPKParameters_bio(in, NULL);
00785             }
00786 
00787             BIO_free(in);
00788 
00789             if (!group) {
00790                 const char *name = StringValueCStr(arg1);
00791                 int nid = OBJ_sn2nid(name);
00792 
00793                 (void)ERR_get_error();
00794                 if (nid == NID_undef)
00795                     ossl_raise(eEC_GROUP, "unknown curve name (%s)", name);
00796 
00797                 group = EC_GROUP_new_by_curve_name(nid);
00798                 if (group == NULL)
00799                     ossl_raise(eEC_GROUP, "unable to create curve (%s)", name);
00800 
00801                 EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE);
00802                 EC_GROUP_set_point_conversion_form(group, POINT_CONVERSION_UNCOMPRESSED);
00803             }
00804         }
00805 
00806         break;
00807     case 4:
00808         if (SYMBOL_P(arg1)) {
00809             ID id = SYM2ID(arg1);
00810             EC_GROUP *(*new_curve)(const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *) = NULL;
00811             const BIGNUM *p = GetBNPtr(arg2);
00812             const BIGNUM *a = GetBNPtr(arg3);
00813             const BIGNUM *b = GetBNPtr(arg4);
00814 
00815             if (id == s_GFp) {
00816                 new_curve = EC_GROUP_new_curve_GFp;
00817 #if !defined(OPENSSL_NO_EC2M)
00818             } else if (id == s_GF2m) {
00819                 new_curve = EC_GROUP_new_curve_GF2m;
00820 #endif
00821             } else {
00822                 ossl_raise(rb_eArgError, "unknown symbol, must be :GFp or :GF2m");
00823             }
00824 
00825             if ((group = new_curve(p, a, b, ossl_bn_ctx)) == NULL)
00826                 ossl_raise(eEC_GROUP, "EC_GROUP_new_by_GF*");
00827         } else {
00828              ossl_raise(rb_eArgError, "unknown argument, must be :GFp or :GF2m");
00829         }
00830 
00831         break;
00832     default:
00833         ossl_raise(rb_eArgError, "wrong number of arguments");
00834     }
00835 
00836     if (group == NULL)
00837         ossl_raise(eEC_GROUP, "");
00838 
00839     ec_group->group = group;
00840 
00841     return self;
00842 }
00843 
00844 /*  call-seq:
00845  *     group1 == group2   => true | false
00846  *
00847  */
00848 static VALUE ossl_ec_group_eql(VALUE a, VALUE b)
00849 {
00850     EC_GROUP *group1 = NULL, *group2 = NULL;
00851 
00852     Require_EC_GROUP(a, group1);
00853     SafeRequire_EC_GROUP(b, group2);
00854 
00855     if (EC_GROUP_cmp(group1, group2, ossl_bn_ctx) == 1)
00856        return Qfalse;
00857 
00858     return Qtrue;
00859 }
00860 
00861 /*  call-seq:
00862  *     group.generator   => ec_point
00863  *
00864  *  See the OpenSSL documentation for EC_GROUP_get0_generator()
00865  */
00866 static VALUE ossl_ec_group_get_generator(VALUE self)
00867 {
00868     VALUE point_obj;
00869     EC_GROUP *group = NULL;
00870 
00871     Require_EC_GROUP(self, group);
00872 
00873     point_obj = ossl_ec_point_dup(EC_GROUP_get0_generator(group), self);
00874 
00875     return point_obj;
00876 }
00877 
00878 /*  call-seq:
00879  *     group.set_generator(generator, order, cofactor)   => self
00880  *
00881  *  See the OpenSSL documentation for EC_GROUP_set_generator()
00882  */
00883 static VALUE ossl_ec_group_set_generator(VALUE self, VALUE generator, VALUE order, VALUE cofactor)
00884 {
00885     EC_GROUP *group = NULL;
00886     const EC_POINT *point;
00887     const BIGNUM *o, *co;
00888 
00889     Require_EC_GROUP(self, group);
00890     SafeRequire_EC_POINT(generator, point);
00891     o = GetBNPtr(order);
00892     co = GetBNPtr(cofactor);
00893 
00894     if (EC_GROUP_set_generator(group, point, o, co) != 1)
00895         ossl_raise(eEC_GROUP, "EC_GROUP_set_generator");
00896 
00897     return self;
00898 }
00899 
00900 /*  call-seq:
00901  *     group.get_order   => order_bn
00902  *
00903  *  See the OpenSSL documentation for EC_GROUP_get_order()
00904  */
00905 static VALUE ossl_ec_group_get_order(VALUE self)
00906 {
00907     VALUE bn_obj;
00908     BIGNUM *bn;
00909     EC_GROUP *group = NULL;
00910 
00911     Require_EC_GROUP(self, group);
00912 
00913     bn_obj = ossl_bn_new(NULL);
00914     bn = GetBNPtr(bn_obj);
00915 
00916     if (EC_GROUP_get_order(group, bn, ossl_bn_ctx) != 1)
00917         ossl_raise(eEC_GROUP, "EC_GROUP_get_order");
00918 
00919     return bn_obj;
00920 }
00921 
00922 /*  call-seq:
00923  *     group.get_cofactor   => cofactor_bn
00924  *
00925  *  See the OpenSSL documentation for EC_GROUP_get_cofactor()
00926  */
00927 static VALUE ossl_ec_group_get_cofactor(VALUE self)
00928 {
00929     VALUE bn_obj;
00930     BIGNUM *bn;
00931     EC_GROUP *group = NULL;
00932 
00933     Require_EC_GROUP(self, group);
00934 
00935     bn_obj = ossl_bn_new(NULL);
00936     bn = GetBNPtr(bn_obj);
00937 
00938     if (EC_GROUP_get_cofactor(group, bn, ossl_bn_ctx) != 1)
00939         ossl_raise(eEC_GROUP, "EC_GROUP_get_cofactor");
00940 
00941     return bn_obj;
00942 }
00943 
00944 /*  call-seq:
00945  *     group.curve_name  => String
00946  *
00947  *  See the OpenSSL documentation for EC_GROUP_get_curve_name()
00948  */
00949 static VALUE ossl_ec_group_get_curve_name(VALUE self)
00950 {
00951     EC_GROUP *group = NULL;
00952     int nid;
00953 
00954     Get_EC_GROUP(self, group);
00955     if (group == NULL)
00956         return Qnil;
00957 
00958     nid = EC_GROUP_get_curve_name(group);
00959 
00960 /* BUG: an nid or asn1 object should be returned, maybe. */
00961     return rb_str_new2(OBJ_nid2sn(nid));
00962 }
00963 
00964 /*  call-seq:
00965  *     EC.builtin_curves => [[name, comment], ...]
00966  *
00967  *  See the OpenSSL documentation for EC_builtin_curves()
00968  */
00969 static VALUE ossl_s_builtin_curves(VALUE self)
00970 {
00971     EC_builtin_curve *curves = NULL;
00972     int n;
00973     int crv_len = rb_long2int(EC_get_builtin_curves(NULL, 0));
00974     VALUE ary, ret;
00975 
00976     curves = ALLOCA_N(EC_builtin_curve, crv_len);
00977     if (curves == NULL)
00978         return Qnil;
00979     if (!EC_get_builtin_curves(curves, crv_len))
00980         ossl_raise(rb_eRuntimeError, "EC_get_builtin_curves");
00981 
00982     ret = rb_ary_new2(crv_len);
00983 
00984     for (n = 0; n < crv_len; n++) {
00985         const char *sname = OBJ_nid2sn(curves[n].nid);
00986         const char *comment = curves[n].comment;
00987 
00988         ary = rb_ary_new2(2);
00989         rb_ary_push(ary, rb_str_new2(sname));
00990         rb_ary_push(ary, comment ? rb_str_new2(comment) : Qnil);
00991         rb_ary_push(ret, ary);
00992     }
00993 
00994     return ret;
00995 }
00996 
00997 /*  call-seq:
00998  *     group.asn1_flag  => Fixnum
00999  *
01000  *  See the OpenSSL documentation for EC_GROUP_get_asn1_flag()
01001  */
01002 static VALUE ossl_ec_group_get_asn1_flag(VALUE self)
01003 {
01004     EC_GROUP *group = NULL;
01005     int flag;
01006 
01007     Require_EC_GROUP(self, group);
01008 
01009     flag = EC_GROUP_get_asn1_flag(group);
01010 
01011     return INT2FIX(flag);
01012 }
01013 
01014 /*  call-seq:
01015  *     group.asn1_flag = Fixnum   => Fixnum
01016  *
01017  *  See the OpenSSL documentation for EC_GROUP_set_asn1_flag()
01018  */
01019 static VALUE ossl_ec_group_set_asn1_flag(VALUE self, VALUE flag_v)
01020 {
01021     EC_GROUP *group = NULL;
01022 
01023     Require_EC_GROUP(self, group);
01024 
01025     EC_GROUP_set_asn1_flag(group, NUM2INT(flag_v));
01026 
01027     return flag_v;
01028 }
01029 
01030 /*  call-seq:
01031  *     group.point_conversion_form  => :uncompressed | :compressed | :hybrid
01032  *
01033  *  See the OpenSSL documentation for EC_GROUP_get_point_conversion_form()
01034  */
01035 static VALUE ossl_ec_group_get_point_conversion_form(VALUE self)
01036 {
01037     EC_GROUP *group = NULL;
01038     point_conversion_form_t form;
01039     VALUE ret;
01040 
01041     Require_EC_GROUP(self, group);
01042 
01043     form = EC_GROUP_get_point_conversion_form(group);
01044 
01045     switch (form) {
01046     case POINT_CONVERSION_UNCOMPRESSED: ret = ID_uncompressed; break;
01047     case POINT_CONVERSION_COMPRESSED:   ret = ID_compressed; break;
01048     case POINT_CONVERSION_HYBRID:       ret = ID_hybrid; break;
01049     default:    ossl_raise(eEC_GROUP, "unsupported point conversion form: %d, this module should be updated", form);
01050     }
01051 
01052    return ID2SYM(ret);
01053 }
01054 
01055 /*  call-seq:
01056  *     group.point_conversion_form = form => form
01057  *
01058  *  See the OpenSSL documentation for EC_GROUP_set_point_conversion_form()
01059  */
01060 static VALUE ossl_ec_group_set_point_conversion_form(VALUE self, VALUE form_v)
01061 {
01062     EC_GROUP *group = NULL;
01063     point_conversion_form_t form;
01064     ID form_id = SYM2ID(form_v);
01065 
01066     Require_EC_GROUP(self, group);
01067 
01068     if (form_id == ID_uncompressed) {
01069         form = POINT_CONVERSION_UNCOMPRESSED;
01070     } else if (form_id == ID_compressed) {
01071         form = POINT_CONVERSION_COMPRESSED;
01072     } else if (form_id == ID_hybrid) {
01073         form = POINT_CONVERSION_HYBRID;
01074     } else {
01075         ossl_raise(rb_eArgError, "form must be :compressed, :uncompressed, or :hybrid");
01076     }
01077 
01078     EC_GROUP_set_point_conversion_form(group, form);
01079 
01080     return form_v;
01081 }
01082 
01083 /*  call-seq:
01084  *     group.seed   => String or nil
01085  *
01086  *  See the OpenSSL documentation for EC_GROUP_get0_seed()
01087  */
01088 static VALUE ossl_ec_group_get_seed(VALUE self)
01089 {
01090     EC_GROUP *group = NULL;
01091     size_t seed_len;
01092 
01093     Require_EC_GROUP(self, group);
01094 
01095     seed_len = EC_GROUP_get_seed_len(group);
01096 
01097     if (seed_len == 0)
01098         return Qnil;
01099 
01100     return rb_str_new((const char *)EC_GROUP_get0_seed(group), seed_len);
01101 }
01102 
01103 /*  call-seq:
01104  *     group.seed = seed  => seed
01105  *
01106  *  See the OpenSSL documentation for EC_GROUP_set_seed()
01107  */
01108 static VALUE ossl_ec_group_set_seed(VALUE self, VALUE seed)
01109 {
01110     EC_GROUP *group = NULL;
01111 
01112     Require_EC_GROUP(self, group);
01113     StringValue(seed);
01114 
01115     if (EC_GROUP_set_seed(group, (unsigned char *)RSTRING_PTR(seed), RSTRING_LEN(seed)) != (size_t)RSTRING_LEN(seed))
01116         ossl_raise(eEC_GROUP, "EC_GROUP_set_seed");
01117 
01118     return seed;
01119 }
01120 
01121 /* get/set curve GFp, GF2m */
01122 
01123 /*  call-seq:
01124  *     group.degree   => Fixnum
01125  *
01126  *  See the OpenSSL documentation for EC_GROUP_get_degree()
01127  */
01128 static VALUE ossl_ec_group_get_degree(VALUE self)
01129 {
01130     EC_GROUP *group = NULL;
01131 
01132     Require_EC_GROUP(self, group);
01133 
01134     return INT2NUM(EC_GROUP_get_degree(group));
01135 }
01136 
01137 static VALUE ossl_ec_group_to_string(VALUE self, int format)
01138 {
01139     EC_GROUP *group;
01140     BIO *out;
01141     int i = -1;
01142     VALUE str;
01143 
01144     Get_EC_GROUP(self, group);
01145 
01146     if (!(out = BIO_new(BIO_s_mem())))
01147         ossl_raise(eEC_GROUP, "BIO_new(BIO_s_mem())");
01148 
01149     switch(format) {
01150     case EXPORT_PEM:
01151         i = PEM_write_bio_ECPKParameters(out, group);
01152         break;
01153     case EXPORT_DER:
01154         i = i2d_ECPKParameters_bio(out, group);
01155         break;
01156     default:
01157         BIO_free(out);
01158         ossl_raise(rb_eRuntimeError, "unknown format (internal error)");
01159     }
01160 
01161     if (i != 1) {
01162         BIO_free(out);
01163         ossl_raise(eECError, NULL);
01164     }
01165 
01166     str = ossl_membio2str(out);
01167 
01168     return str;
01169 }
01170 
01171 /*  call-seq:
01172  *     group.to_pem   => String
01173  *
01174  *  See the OpenSSL documentation for PEM_write_bio_ECPKParameters()
01175  */
01176 static VALUE ossl_ec_group_to_pem(VALUE self)
01177 {
01178     return ossl_ec_group_to_string(self, EXPORT_PEM);
01179 }
01180 
01181 /*  call-seq:
01182  *     group.to_der   => String
01183  *
01184  *  See the OpenSSL documentation for i2d_ECPKParameters_bio()
01185  */
01186 static VALUE ossl_ec_group_to_der(VALUE self)
01187 {
01188     return ossl_ec_group_to_string(self, EXPORT_DER);
01189 }
01190 
01191 /*  call-seq:
01192  *     group.to_text   => String
01193  *
01194  *  See the OpenSSL documentation for ECPKParameters_print()
01195  */
01196 static VALUE ossl_ec_group_to_text(VALUE self)
01197 {
01198     EC_GROUP *group;
01199     BIO *out;
01200     VALUE str;
01201 
01202     Require_EC_GROUP(self, group);
01203     if (!(out = BIO_new(BIO_s_mem()))) {
01204         ossl_raise(eEC_GROUP, "BIO_new(BIO_s_mem())");
01205     }
01206     if (!ECPKParameters_print(out, group, 0)) {
01207         BIO_free(out);
01208         ossl_raise(eEC_GROUP, NULL);
01209     }
01210     str = ossl_membio2str(out);
01211 
01212     return str;
01213 }
01214 
01215 
01216 static void ossl_ec_point_free(ossl_ec_point *ec_point)
01217 {
01218     if (!ec_point->dont_free && ec_point->point)
01219         EC_POINT_clear_free(ec_point->point);
01220     ruby_xfree(ec_point);
01221 }
01222 
01223 static VALUE ossl_ec_point_alloc(VALUE klass)
01224 {
01225     ossl_ec_point *ec_point;
01226     VALUE obj;
01227 
01228     obj = Data_Make_Struct(klass, ossl_ec_point, 0, ossl_ec_point_free, ec_point);
01229 
01230     return obj;
01231 }
01232 
01233 /*
01234  *  call-seq:
01235  *     OpenSSL::PKey::EC::Point.new(point)
01236  *     OpenSSL::PKey::EC::Point.new(group)
01237  *     OpenSSL::PKey::EC::Point.new(group, bn)
01238  *
01239  *  See the OpenSSL documentation for EC_POINT_*
01240  */
01241 static VALUE ossl_ec_point_initialize(int argc, VALUE *argv, VALUE self)
01242 {
01243     ossl_ec_point *ec_point;
01244     EC_POINT *point = NULL;
01245     VALUE arg1, arg2;
01246     VALUE group_v = Qnil;
01247     const EC_GROUP *group = NULL;
01248 
01249     Data_Get_Struct(self, ossl_ec_point, ec_point);
01250     if (ec_point->point)
01251         ossl_raise(eEC_POINT, "EC_POINT already initialized");
01252 
01253     switch (rb_scan_args(argc, argv, "11", &arg1, &arg2)) {
01254     case 1:
01255         if (rb_obj_is_kind_of(arg1, cEC_POINT)) {
01256             const EC_POINT *arg_point;
01257 
01258             group_v = rb_iv_get(arg1, "@group");
01259             SafeRequire_EC_GROUP(group_v, group);
01260             SafeRequire_EC_POINT(arg1, arg_point);
01261 
01262             point = EC_POINT_dup(arg_point, group);
01263         } else if (rb_obj_is_kind_of(arg1, cEC_GROUP)) {
01264             group_v = arg1;
01265             SafeRequire_EC_GROUP(group_v, group);
01266 
01267             point = EC_POINT_new(group);
01268         } else {
01269             ossl_raise(eEC_POINT, "wrong argument type: must be OpenSSL::PKey::EC::Point or OpenSSL::Pkey::EC::Group");
01270         }
01271 
01272         break;
01273      case 2:
01274         if (!rb_obj_is_kind_of(arg1, cEC_GROUP))
01275             ossl_raise(rb_eArgError, "1st argument must be OpenSSL::PKey::EC::Group");
01276         group_v = arg1;
01277         SafeRequire_EC_GROUP(group_v, group);
01278 
01279         if (rb_obj_is_kind_of(arg2, cBN)) {
01280             const BIGNUM *bn = GetBNPtr(arg2);
01281 
01282             point = EC_POINT_bn2point(group, bn, NULL, ossl_bn_ctx);
01283         } else {
01284             BIO *in = ossl_obj2bio(arg1);
01285 
01286 /* BUG: finish me */
01287 
01288             BIO_free(in);
01289 
01290             if (point == NULL) {
01291                 ossl_raise(eEC_POINT, "unknown type for 2nd arg");
01292             }
01293         }
01294         break;
01295     default:
01296         ossl_raise(rb_eArgError, "wrong number of arguments");
01297     }
01298 
01299     if (point == NULL)
01300         ossl_raise(eEC_POINT, NULL);
01301 
01302     if (NIL_P(group_v))
01303         ossl_raise(rb_eRuntimeError, "missing group (internal error)");
01304 
01305     ec_point->point = point;
01306 
01307     rb_iv_set(self, "@group", group_v);
01308 
01309     return self;
01310 }
01311 
01312 /*
01313  *  call-seq:
01314  *     point1 == point2 => true | false
01315  *
01316  */
01317 static VALUE ossl_ec_point_eql(VALUE a, VALUE b)
01318 {
01319     EC_POINT *point1, *point2;
01320     VALUE group_v1 = rb_iv_get(a, "@group");
01321     VALUE group_v2 = rb_iv_get(b, "@group");
01322     const EC_GROUP *group;
01323 
01324     if (ossl_ec_group_eql(group_v1, group_v2) == Qfalse)
01325         return Qfalse;
01326 
01327     Require_EC_POINT(a, point1);
01328     SafeRequire_EC_POINT(b, point2);
01329     SafeRequire_EC_GROUP(group_v1, group);
01330 
01331     if (EC_POINT_cmp(group, point1, point2, ossl_bn_ctx) == 1)
01332         return Qfalse;
01333 
01334     return Qtrue;
01335 }
01336 
01337 /*
01338  *  call-seq:
01339  *     point.infinity? => true | false
01340  *
01341  */
01342 static VALUE ossl_ec_point_is_at_infinity(VALUE self)
01343 {
01344     EC_POINT *point;
01345     VALUE group_v = rb_iv_get(self, "@group");
01346     const EC_GROUP *group;
01347 
01348     Require_EC_POINT(self, point);
01349     SafeRequire_EC_GROUP(group_v, group);
01350 
01351     switch (EC_POINT_is_at_infinity(group, point)) {
01352     case 1: return Qtrue;
01353     case 0: return Qfalse;
01354     default: ossl_raise(cEC_POINT, "EC_POINT_is_at_infinity");
01355     }
01356 }
01357 
01358 /*
01359  *  call-seq:
01360  *     point.on_curve? => true | false
01361  *
01362  */
01363 static VALUE ossl_ec_point_is_on_curve(VALUE self)
01364 {
01365     EC_POINT *point;
01366     VALUE group_v = rb_iv_get(self, "@group");
01367     const EC_GROUP *group;
01368 
01369     Require_EC_POINT(self, point);
01370     SafeRequire_EC_GROUP(group_v, group);
01371 
01372     switch (EC_POINT_is_on_curve(group, point, ossl_bn_ctx)) {
01373     case 1: return Qtrue;
01374     case 0: return Qfalse;
01375     default: ossl_raise(cEC_POINT, "EC_POINT_is_on_curve");
01376     }
01377 }
01378 
01379 /*
01380  *  call-seq:
01381  *     point.make_affine! => self
01382  *
01383  */
01384 static VALUE ossl_ec_point_make_affine(VALUE self)
01385 {
01386     EC_POINT *point;
01387     VALUE group_v = rb_iv_get(self, "@group");
01388     const EC_GROUP *group;
01389 
01390     Require_EC_POINT(self, point);
01391     SafeRequire_EC_GROUP(group_v, group);
01392 
01393     if (EC_POINT_make_affine(group, point, ossl_bn_ctx) != 1)
01394         ossl_raise(cEC_POINT, "EC_POINT_make_affine");
01395 
01396     return self;
01397 }
01398 
01399 /*
01400  *  call-seq:
01401  *     point.invert! => self
01402  *
01403  */
01404 static VALUE ossl_ec_point_invert(VALUE self)
01405 {
01406     EC_POINT *point;
01407     VALUE group_v = rb_iv_get(self, "@group");
01408     const EC_GROUP *group;
01409 
01410     Require_EC_POINT(self, point);
01411     SafeRequire_EC_GROUP(group_v, group);
01412 
01413     if (EC_POINT_invert(group, point, ossl_bn_ctx) != 1)
01414         ossl_raise(cEC_POINT, "EC_POINT_invert");
01415 
01416     return self;
01417 }
01418 
01419 /*
01420  *  call-seq:
01421  *     point.set_to_infinity! => self
01422  *
01423  */
01424 static VALUE ossl_ec_point_set_to_infinity(VALUE self)
01425 {
01426     EC_POINT *point;
01427     VALUE group_v = rb_iv_get(self, "@group");
01428     const EC_GROUP *group;
01429 
01430     Require_EC_POINT(self, point);
01431     SafeRequire_EC_GROUP(group_v, group);
01432 
01433     if (EC_POINT_set_to_infinity(group, point) != 1)
01434         ossl_raise(cEC_POINT, "EC_POINT_set_to_infinity");
01435 
01436     return self;
01437 }
01438 
01439 /*
01440  *  call-seq:
01441  *     point.to_bn   => OpenSSL::BN
01442  *
01443  *  See the OpenSSL documentation for EC_POINT_point2bn()
01444  */
01445 static VALUE ossl_ec_point_to_bn(VALUE self)
01446 {
01447     EC_POINT *point;
01448     VALUE bn_obj;
01449     VALUE group_v = rb_iv_get(self, "@group");
01450     const EC_GROUP *group;
01451     point_conversion_form_t form;
01452     BIGNUM *bn;
01453 
01454     Require_EC_POINT(self, point);
01455     SafeRequire_EC_GROUP(group_v, group);
01456 
01457     form = EC_GROUP_get_point_conversion_form(group);
01458 
01459     bn_obj = rb_obj_alloc(cBN);
01460     bn = GetBNPtr(bn_obj);
01461 
01462     if (EC_POINT_point2bn(group, point, form, bn, ossl_bn_ctx) == NULL)
01463         ossl_raise(eEC_POINT, "EC_POINT_point2bn");
01464 
01465     return bn_obj;
01466 }
01467 
01468 static void no_copy(VALUE klass)
01469 {
01470     rb_undef_method(klass, "copy");
01471     rb_undef_method(klass, "clone");
01472     rb_undef_method(klass, "dup");
01473     rb_undef_method(klass, "initialize_copy");
01474 }
01475 
01476 void Init_ossl_ec()
01477 {
01478 #ifdef DONT_NEED_RDOC_WORKAROUND
01479     mOSSL = rb_define_module("OpenSSL");
01480     mPKey = rb_define_module_under(mOSSL, "PKey");
01481 #endif
01482 
01483     eECError = rb_define_class_under(mPKey, "ECError", ePKeyError);
01484 
01485     cEC = rb_define_class_under(mPKey, "EC", cPKey);
01486     cEC_GROUP = rb_define_class_under(cEC, "Group", rb_cObject);
01487     cEC_POINT = rb_define_class_under(cEC, "Point", rb_cObject);
01488     eEC_GROUP = rb_define_class_under(cEC_GROUP, "Error", eOSSLError);
01489     eEC_POINT = rb_define_class_under(cEC_POINT, "Error", eOSSLError);
01490 
01491     s_GFp = rb_intern("GFp");
01492     s_GF2m = rb_intern("GF2m");
01493     s_GFp_simple = rb_intern("GFp_simple");
01494     s_GFp_mont = rb_intern("GFp_mont");
01495     s_GFp_nist = rb_intern("GFp_nist");
01496     s_GF2m_simple = rb_intern("GF2m_simple");
01497 
01498     ID_uncompressed = rb_intern("uncompressed");
01499     ID_compressed = rb_intern("compressed");
01500     ID_hybrid = rb_intern("hybrid");
01501 
01502 #ifdef OPENSSL_EC_NAMED_CURVE
01503     rb_define_const(cEC, "NAMED_CURVE", ULONG2NUM(OPENSSL_EC_NAMED_CURVE));
01504 #endif
01505 
01506     rb_define_singleton_method(cEC, "builtin_curves", ossl_s_builtin_curves, 0);
01507 
01508     rb_define_method(cEC, "initialize", ossl_ec_key_initialize, -1);
01509 /* copy/dup/cmp */
01510 
01511     rb_define_method(cEC, "group", ossl_ec_key_get_group, 0);
01512     rb_define_method(cEC, "group=", ossl_ec_key_set_group, 1);
01513     rb_define_method(cEC, "private_key", ossl_ec_key_get_private_key, 0);
01514     rb_define_method(cEC, "private_key=", ossl_ec_key_set_private_key, 1);
01515     rb_define_method(cEC, "public_key", ossl_ec_key_get_public_key, 0);
01516     rb_define_method(cEC, "public_key=", ossl_ec_key_set_public_key, 1);
01517     rb_define_method(cEC, "private_key?", ossl_ec_key_is_private_key, 0);
01518     rb_define_method(cEC, "public_key?", ossl_ec_key_is_public_key, 0);
01519 /*  rb_define_method(cEC, "", ossl_ec_key_get_, 0);
01520     rb_define_method(cEC, "=", ossl_ec_key_set_ 1);
01521     set/get enc_flags
01522     set/get _conv_from
01523     set/get asn1_flag (can use ruby to call self.group.asn1_flag)
01524     set/get precompute_mult
01525 */
01526     rb_define_method(cEC, "generate_key", ossl_ec_key_generate_key, 0);
01527     rb_define_method(cEC, "check_key", ossl_ec_key_check_key, 0);
01528 
01529     rb_define_method(cEC, "dh_compute_key", ossl_ec_key_dh_compute_key, 1);
01530     rb_define_method(cEC, "dsa_sign_asn1", ossl_ec_key_dsa_sign_asn1, 1);
01531     rb_define_method(cEC, "dsa_verify_asn1", ossl_ec_key_dsa_verify_asn1, 2);
01532 /* do_sign/do_verify */
01533 
01534     rb_define_method(cEC, "to_pem", ossl_ec_key_to_pem, -1);
01535     rb_define_method(cEC, "to_der", ossl_ec_key_to_der, 0);
01536     rb_define_method(cEC, "to_text", ossl_ec_key_to_text, 0);
01537 
01538 
01539     rb_define_alloc_func(cEC_GROUP, ossl_ec_group_alloc);
01540     rb_define_method(cEC_GROUP, "initialize", ossl_ec_group_initialize, -1);
01541     rb_define_method(cEC_GROUP, "eql?", ossl_ec_group_eql, 1);
01542     rb_define_alias(cEC_GROUP, "==", "eql?");
01543 /* copy/dup/cmp */
01544 
01545     rb_define_method(cEC_GROUP, "generator", ossl_ec_group_get_generator, 0);
01546     rb_define_method(cEC_GROUP, "set_generator", ossl_ec_group_set_generator, 3);
01547     rb_define_method(cEC_GROUP, "order", ossl_ec_group_get_order, 0);
01548     rb_define_method(cEC_GROUP, "cofactor", ossl_ec_group_get_cofactor, 0);
01549 
01550     rb_define_method(cEC_GROUP, "curve_name", ossl_ec_group_get_curve_name, 0);
01551 /*    rb_define_method(cEC_GROUP, "curve_name=", ossl_ec_group_set_curve_name, 1); */
01552 
01553     rb_define_method(cEC_GROUP, "asn1_flag", ossl_ec_group_get_asn1_flag, 0);
01554     rb_define_method(cEC_GROUP, "asn1_flag=", ossl_ec_group_set_asn1_flag, 1);
01555 
01556     rb_define_method(cEC_GROUP, "point_conversion_form", ossl_ec_group_get_point_conversion_form, 0);
01557     rb_define_method(cEC_GROUP, "point_conversion_form=", ossl_ec_group_set_point_conversion_form, 1);
01558 
01559     rb_define_method(cEC_GROUP, "seed", ossl_ec_group_get_seed, 0);
01560     rb_define_method(cEC_GROUP, "seed=", ossl_ec_group_set_seed, 1);
01561 
01562 /* get/set GFp, GF2m */
01563 
01564     rb_define_method(cEC_GROUP, "degree", ossl_ec_group_get_degree, 0);
01565 
01566 /* check* */
01567 
01568 
01569     rb_define_method(cEC_GROUP, "to_pem", ossl_ec_group_to_pem, 0);
01570     rb_define_method(cEC_GROUP, "to_der", ossl_ec_group_to_der, 0);
01571     rb_define_method(cEC_GROUP, "to_text", ossl_ec_group_to_text, 0);
01572 
01573 
01574     rb_define_alloc_func(cEC_POINT, ossl_ec_point_alloc);
01575     rb_define_method(cEC_POINT, "initialize", ossl_ec_point_initialize, -1);
01576     rb_attr(cEC_POINT, rb_intern("group"), 1, 0, 0);
01577     rb_define_method(cEC_POINT, "eql?", ossl_ec_point_eql, 1);
01578     rb_define_alias(cEC_POINT, "==", "eql?");
01579 
01580     rb_define_method(cEC_POINT, "infinity?", ossl_ec_point_is_at_infinity, 0);
01581     rb_define_method(cEC_POINT, "on_curve?", ossl_ec_point_is_on_curve, 0);
01582     rb_define_method(cEC_POINT, "make_affine!", ossl_ec_point_make_affine, 0);
01583     rb_define_method(cEC_POINT, "invert!", ossl_ec_point_invert, 0);
01584     rb_define_method(cEC_POINT, "set_to_infinity!", ossl_ec_point_set_to_infinity, 0);
01585 /* all the other methods */
01586 
01587     rb_define_method(cEC_POINT, "to_bn", ossl_ec_point_to_bn, 0);
01588 
01589     no_copy(cEC);
01590     no_copy(cEC_GROUP);
01591     no_copy(cEC_POINT);
01592 }
01593 
01594 #else /* defined NO_EC */
01595 void Init_ossl_ec()
01596 {
01597 }
01598 #endif /* NO_EC */
01599