Ruby 1.9.3p327(2012-11-10revision37606)
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             } else if (id == s_GF2m_simple) {
00761                 method = EC_GF2m_simple_method();
00762             }
00763 
00764             if (method) {
00765                 if ((group = EC_GROUP_new(method)) == NULL)
00766                     ossl_raise(eEC_GROUP, "EC_GROUP_new");
00767             } else {
00768                 ossl_raise(rb_eArgError, "unknown symbol, must be :GFp_simple, :GFp_mont, :GFp_nist or :GF2m_simple");
00769             }
00770         } else if (rb_obj_is_kind_of(arg1, cEC_GROUP)) {
00771             const EC_GROUP *arg1_group;
00772 
00773             SafeRequire_EC_GROUP(arg1, arg1_group);
00774             if ((group = EC_GROUP_dup(arg1_group)) == NULL)
00775                 ossl_raise(eEC_GROUP, "EC_GROUP_dup");
00776         } else {
00777             BIO *in = ossl_obj2bio(arg1);
00778 
00779             group = PEM_read_bio_ECPKParameters(in, NULL, NULL, NULL);
00780             if (!group) {
00781                 OSSL_BIO_reset(in);
00782                 group = d2i_ECPKParameters_bio(in, NULL);
00783             }
00784 
00785             BIO_free(in);
00786 
00787             if (!group) {
00788                 const char *name = StringValueCStr(arg1);
00789                 int nid = OBJ_sn2nid(name);
00790 
00791                 (void)ERR_get_error();
00792                 if (nid == NID_undef)
00793                     ossl_raise(eEC_GROUP, "unknown curve name (%s)", name);
00794 
00795                 group = EC_GROUP_new_by_curve_name(nid);
00796                 if (group == NULL)
00797                     ossl_raise(eEC_GROUP, "unable to create curve (%s)", name);
00798 
00799                 EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE);
00800                 EC_GROUP_set_point_conversion_form(group, POINT_CONVERSION_UNCOMPRESSED);
00801             }
00802         }
00803 
00804         break;
00805     case 4:
00806         if (SYMBOL_P(arg1)) {
00807             ID id = SYM2ID(arg1);
00808             EC_GROUP *(*new_curve)(const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *) = NULL;
00809             const BIGNUM *p = GetBNPtr(arg2);
00810             const BIGNUM *a = GetBNPtr(arg3);
00811             const BIGNUM *b = GetBNPtr(arg4);
00812 
00813             if (id == s_GFp) {
00814                 new_curve = EC_GROUP_new_curve_GFp;
00815             } else if (id == s_GF2m) {
00816                 new_curve = EC_GROUP_new_curve_GF2m;
00817             } else {
00818                 ossl_raise(rb_eArgError, "unknown symbol, must be :GFp or :GF2m");
00819             }
00820 
00821             if ((group = new_curve(p, a, b, ossl_bn_ctx)) == NULL)
00822                 ossl_raise(eEC_GROUP, "EC_GROUP_new_by_GF*");
00823         } else {
00824              ossl_raise(rb_eArgError, "unknown argument, must be :GFp or :GF2m");
00825         }
00826 
00827         break;
00828     default:
00829         ossl_raise(rb_eArgError, "wrong number of arguments");
00830     }
00831 
00832     if (group == NULL)
00833         ossl_raise(eEC_GROUP, "");
00834 
00835     ec_group->group = group;
00836 
00837     return self;
00838 }
00839 
00840 /*  call-seq:
00841  *     group1 == group2   => true | false
00842  *
00843  */
00844 static VALUE ossl_ec_group_eql(VALUE a, VALUE b)
00845 {
00846     EC_GROUP *group1 = NULL, *group2 = NULL;
00847 
00848     Require_EC_GROUP(a, group1);
00849     SafeRequire_EC_GROUP(b, group2);
00850 
00851     if (EC_GROUP_cmp(group1, group2, ossl_bn_ctx) == 1)
00852        return Qfalse;
00853 
00854     return Qtrue;
00855 }
00856 
00857 /*  call-seq:
00858  *     group.generator   => ec_point
00859  *
00860  *  See the OpenSSL documentation for EC_GROUP_get0_generator()
00861  */
00862 static VALUE ossl_ec_group_get_generator(VALUE self)
00863 {
00864     VALUE point_obj;
00865     EC_GROUP *group = NULL;
00866 
00867     Require_EC_GROUP(self, group);
00868 
00869     point_obj = ossl_ec_point_dup(EC_GROUP_get0_generator(group), self);
00870 
00871     return point_obj;
00872 }
00873 
00874 /*  call-seq:
00875  *     group.set_generator(generator, order, cofactor)   => self
00876  *
00877  *  See the OpenSSL documentation for EC_GROUP_set_generator()
00878  */
00879 static VALUE ossl_ec_group_set_generator(VALUE self, VALUE generator, VALUE order, VALUE cofactor)
00880 {
00881     EC_GROUP *group = NULL;
00882     const EC_POINT *point;
00883     const BIGNUM *o, *co;
00884 
00885     Require_EC_GROUP(self, group);
00886     SafeRequire_EC_POINT(generator, point);
00887     o = GetBNPtr(order);
00888     co = GetBNPtr(cofactor);
00889 
00890     if (EC_GROUP_set_generator(group, point, o, co) != 1)
00891         ossl_raise(eEC_GROUP, "EC_GROUP_set_generator");
00892 
00893     return self;
00894 }
00895 
00896 /*  call-seq:
00897  *     group.get_order   => order_bn
00898  *
00899  *  See the OpenSSL documentation for EC_GROUP_get_order()
00900  */
00901 static VALUE ossl_ec_group_get_order(VALUE self)
00902 {
00903     VALUE bn_obj;
00904     BIGNUM *bn;
00905     EC_GROUP *group = NULL;
00906 
00907     Require_EC_GROUP(self, group);
00908 
00909     bn_obj = ossl_bn_new(NULL);
00910     bn = GetBNPtr(bn_obj);
00911 
00912     if (EC_GROUP_get_order(group, bn, ossl_bn_ctx) != 1)
00913         ossl_raise(eEC_GROUP, "EC_GROUP_get_order");
00914 
00915     return bn_obj;
00916 }
00917 
00918 /*  call-seq:
00919  *     group.get_cofactor   => cofactor_bn
00920  *
00921  *  See the OpenSSL documentation for EC_GROUP_get_cofactor()
00922  */
00923 static VALUE ossl_ec_group_get_cofactor(VALUE self)
00924 {
00925     VALUE bn_obj;
00926     BIGNUM *bn;
00927     EC_GROUP *group = NULL;
00928 
00929     Require_EC_GROUP(self, group);
00930 
00931     bn_obj = ossl_bn_new(NULL);
00932     bn = GetBNPtr(bn_obj);
00933 
00934     if (EC_GROUP_get_cofactor(group, bn, ossl_bn_ctx) != 1)
00935         ossl_raise(eEC_GROUP, "EC_GROUP_get_cofactor");
00936 
00937     return bn_obj;
00938 }
00939 
00940 /*  call-seq:
00941  *     group.curve_name  => String
00942  *
00943  *  See the OpenSSL documentation for EC_GROUP_get_curve_name()
00944  */
00945 static VALUE ossl_ec_group_get_curve_name(VALUE self)
00946 {
00947     EC_GROUP *group = NULL;
00948     int nid;
00949 
00950     Get_EC_GROUP(self, group);
00951     if (group == NULL)
00952         return Qnil;
00953 
00954     nid = EC_GROUP_get_curve_name(group);
00955 
00956 /* BUG: an nid or asn1 object should be returned, maybe. */
00957     return rb_str_new2(OBJ_nid2sn(nid));
00958 }
00959 
00960 /*  call-seq:
00961  *     EC.builtin_curves => [[name, comment], ...]
00962  *
00963  *  See the OpenSSL documentation for EC_builtin_curves()
00964  */
00965 static VALUE ossl_s_builtin_curves(VALUE self)
00966 {
00967     EC_builtin_curve *curves = NULL;
00968     int n;
00969     int crv_len = rb_long2int(EC_get_builtin_curves(NULL, 0));
00970     VALUE ary, ret;
00971 
00972     curves = ALLOCA_N(EC_builtin_curve, crv_len);
00973     if (curves == NULL)
00974         return Qnil;
00975     if (!EC_get_builtin_curves(curves, crv_len))
00976         ossl_raise(rb_eRuntimeError, "EC_get_builtin_curves");
00977 
00978     ret = rb_ary_new2(crv_len);
00979 
00980     for (n = 0; n < crv_len; n++) {
00981         const char *sname = OBJ_nid2sn(curves[n].nid);
00982         const char *comment = curves[n].comment;
00983 
00984         ary = rb_ary_new2(2);
00985         rb_ary_push(ary, rb_str_new2(sname));
00986         rb_ary_push(ary, comment ? rb_str_new2(comment) : Qnil);
00987         rb_ary_push(ret, ary);
00988     }
00989 
00990     return ret;
00991 }
00992 
00993 /*  call-seq:
00994  *     group.asn1_flag  => Fixnum
00995  *
00996  *  See the OpenSSL documentation for EC_GROUP_get_asn1_flag()
00997  */
00998 static VALUE ossl_ec_group_get_asn1_flag(VALUE self)
00999 {
01000     EC_GROUP *group = NULL;
01001     int flag;
01002 
01003     Require_EC_GROUP(self, group);
01004 
01005     flag = EC_GROUP_get_asn1_flag(group);
01006 
01007     return INT2FIX(flag);
01008 }
01009 
01010 /*  call-seq:
01011  *     group.asn1_flag = Fixnum   => Fixnum
01012  *
01013  *  See the OpenSSL documentation for EC_GROUP_set_asn1_flag()
01014  */
01015 static VALUE ossl_ec_group_set_asn1_flag(VALUE self, VALUE flag_v)
01016 {
01017     EC_GROUP *group = NULL;
01018 
01019     Require_EC_GROUP(self, group);
01020 
01021     EC_GROUP_set_asn1_flag(group, NUM2INT(flag_v));
01022 
01023     return flag_v;
01024 }
01025 
01026 /*  call-seq:
01027  *     group.point_conversion_form  => :uncompressed | :compressed | :hybrid
01028  *
01029  *  See the OpenSSL documentation for EC_GROUP_get_point_conversion_form()
01030  */
01031 static VALUE ossl_ec_group_get_point_conversion_form(VALUE self)
01032 {
01033     EC_GROUP *group = NULL;
01034     point_conversion_form_t form;
01035     VALUE ret;
01036 
01037     Require_EC_GROUP(self, group);
01038 
01039     form = EC_GROUP_get_point_conversion_form(group);
01040 
01041     switch (form) {
01042     case POINT_CONVERSION_UNCOMPRESSED: ret = ID_uncompressed; break;
01043     case POINT_CONVERSION_COMPRESSED:   ret = ID_compressed; break;
01044     case POINT_CONVERSION_HYBRID:       ret = ID_hybrid; break;
01045     default:    ossl_raise(eEC_GROUP, "unsupported point conversion form: %d, this module should be updated", form);
01046     }
01047 
01048    return ID2SYM(ret);
01049 }
01050 
01051 /*  call-seq:
01052  *     group.point_conversion_form = form => form
01053  *
01054  *  See the OpenSSL documentation for EC_GROUP_set_point_conversion_form()
01055  */
01056 static VALUE ossl_ec_group_set_point_conversion_form(VALUE self, VALUE form_v)
01057 {
01058     EC_GROUP *group = NULL;
01059     point_conversion_form_t form;
01060     ID form_id = SYM2ID(form_v);
01061 
01062     Require_EC_GROUP(self, group);
01063 
01064     if (form_id == ID_uncompressed) {
01065         form = POINT_CONVERSION_UNCOMPRESSED;
01066     } else if (form_id == ID_compressed) {
01067         form = POINT_CONVERSION_COMPRESSED;
01068     } else if (form_id == ID_hybrid) {
01069         form = POINT_CONVERSION_HYBRID;
01070     } else {
01071         ossl_raise(rb_eArgError, "form must be :compressed, :uncompressed, or :hybrid");
01072     }
01073 
01074     EC_GROUP_set_point_conversion_form(group, form);
01075 
01076     return form_v;
01077 }
01078 
01079 /*  call-seq:
01080  *     group.seed   => String or nil
01081  *
01082  *  See the OpenSSL documentation for EC_GROUP_get0_seed()
01083  */
01084 static VALUE ossl_ec_group_get_seed(VALUE self)
01085 {
01086     EC_GROUP *group = NULL;
01087     size_t seed_len;
01088 
01089     Require_EC_GROUP(self, group);
01090 
01091     seed_len = EC_GROUP_get_seed_len(group);
01092 
01093     if (seed_len == 0)
01094         return Qnil;
01095 
01096     return rb_str_new((const char *)EC_GROUP_get0_seed(group), seed_len);
01097 }
01098 
01099 /*  call-seq:
01100  *     group.seed = seed  => seed
01101  *
01102  *  See the OpenSSL documentation for EC_GROUP_set_seed()
01103  */
01104 static VALUE ossl_ec_group_set_seed(VALUE self, VALUE seed)
01105 {
01106     EC_GROUP *group = NULL;
01107 
01108     Require_EC_GROUP(self, group);
01109     StringValue(seed);
01110 
01111     if (EC_GROUP_set_seed(group, (unsigned char *)RSTRING_PTR(seed), RSTRING_LEN(seed)) != (size_t)RSTRING_LEN(seed))
01112         ossl_raise(eEC_GROUP, "EC_GROUP_set_seed");
01113 
01114     return seed;
01115 }
01116 
01117 /* get/set curve GFp, GF2m */
01118 
01119 /*  call-seq:
01120  *     group.degree   => Fixnum
01121  *
01122  *  See the OpenSSL documentation for EC_GROUP_get_degree()
01123  */
01124 static VALUE ossl_ec_group_get_degree(VALUE self)
01125 {
01126     EC_GROUP *group = NULL;
01127 
01128     Require_EC_GROUP(self, group);
01129 
01130     return INT2NUM(EC_GROUP_get_degree(group));
01131 }
01132 
01133 static VALUE ossl_ec_group_to_string(VALUE self, int format)
01134 {
01135     EC_GROUP *group;
01136     BIO *out;
01137     int i = -1;
01138     VALUE str;
01139 
01140     Get_EC_GROUP(self, group);
01141 
01142     if (!(out = BIO_new(BIO_s_mem())))
01143         ossl_raise(eEC_GROUP, "BIO_new(BIO_s_mem())");
01144 
01145     switch(format) {
01146     case EXPORT_PEM:
01147         i = PEM_write_bio_ECPKParameters(out, group);
01148         break;
01149     case EXPORT_DER:
01150         i = i2d_ECPKParameters_bio(out, group);
01151         break;
01152     default:
01153         BIO_free(out);
01154         ossl_raise(rb_eRuntimeError, "unknown format (internal error)");
01155     }
01156 
01157     if (i != 1) {
01158         BIO_free(out);
01159         ossl_raise(eECError, NULL);
01160     }
01161 
01162     str = ossl_membio2str(out);
01163 
01164     return str;
01165 }
01166 
01167 /*  call-seq:
01168  *     group.to_pem   => String
01169  *
01170  *  See the OpenSSL documentation for PEM_write_bio_ECPKParameters()
01171  */
01172 static VALUE ossl_ec_group_to_pem(VALUE self)
01173 {
01174     return ossl_ec_group_to_string(self, EXPORT_PEM);
01175 }
01176 
01177 /*  call-seq:
01178  *     group.to_der   => String
01179  *
01180  *  See the OpenSSL documentation for i2d_ECPKParameters_bio()
01181  */
01182 static VALUE ossl_ec_group_to_der(VALUE self)
01183 {
01184     return ossl_ec_group_to_string(self, EXPORT_DER);
01185 }
01186 
01187 /*  call-seq:
01188  *     group.to_text   => String
01189  *
01190  *  See the OpenSSL documentation for ECPKParameters_print()
01191  */
01192 static VALUE ossl_ec_group_to_text(VALUE self)
01193 {
01194     EC_GROUP *group;
01195     BIO *out;
01196     VALUE str;
01197 
01198     Require_EC_GROUP(self, group);
01199     if (!(out = BIO_new(BIO_s_mem()))) {
01200         ossl_raise(eEC_GROUP, "BIO_new(BIO_s_mem())");
01201     }
01202     if (!ECPKParameters_print(out, group, 0)) {
01203         BIO_free(out);
01204         ossl_raise(eEC_GROUP, NULL);
01205     }
01206     str = ossl_membio2str(out);
01207 
01208     return str;
01209 }
01210 
01211 
01212 static void ossl_ec_point_free(ossl_ec_point *ec_point)
01213 {
01214     if (!ec_point->dont_free && ec_point->point)
01215         EC_POINT_clear_free(ec_point->point);
01216     ruby_xfree(ec_point);
01217 }
01218 
01219 static VALUE ossl_ec_point_alloc(VALUE klass)
01220 {
01221     ossl_ec_point *ec_point;
01222     VALUE obj;
01223 
01224     obj = Data_Make_Struct(klass, ossl_ec_point, 0, ossl_ec_point_free, ec_point);
01225 
01226     return obj;
01227 }
01228 
01229 /*
01230  *  call-seq:
01231  *     OpenSSL::PKey::EC::Point.new(point)
01232  *     OpenSSL::PKey::EC::Point.new(group)
01233  *     OpenSSL::PKey::EC::Point.new(group, bn)
01234  *
01235  *  See the OpenSSL documentation for EC_POINT_*
01236  */
01237 static VALUE ossl_ec_point_initialize(int argc, VALUE *argv, VALUE self)
01238 {
01239     ossl_ec_point *ec_point;
01240     EC_POINT *point = NULL;
01241     VALUE arg1, arg2;
01242     VALUE group_v = Qnil;
01243     const EC_GROUP *group = NULL;
01244 
01245     Data_Get_Struct(self, ossl_ec_point, ec_point);
01246     if (ec_point->point)
01247         ossl_raise(eEC_POINT, "EC_POINT already initialized");
01248 
01249     switch (rb_scan_args(argc, argv, "11", &arg1, &arg2)) {
01250     case 1:
01251         if (rb_obj_is_kind_of(arg1, cEC_POINT)) {
01252             const EC_POINT *arg_point;
01253 
01254             group_v = rb_iv_get(arg1, "@group");
01255             SafeRequire_EC_GROUP(group_v, group);
01256             SafeRequire_EC_POINT(arg1, arg_point);
01257 
01258             point = EC_POINT_dup(arg_point, group);
01259         } else if (rb_obj_is_kind_of(arg1, cEC_GROUP)) {
01260             group_v = arg1;
01261             SafeRequire_EC_GROUP(group_v, group);
01262 
01263             point = EC_POINT_new(group);
01264         } else {
01265             ossl_raise(eEC_POINT, "wrong argument type: must be OpenSSL::PKey::EC::Point or OpenSSL::Pkey::EC::Group");
01266         }
01267 
01268         break;
01269      case 2:
01270         if (!rb_obj_is_kind_of(arg1, cEC_GROUP))
01271             ossl_raise(rb_eArgError, "1st argument must be OpenSSL::PKey::EC::Group");
01272         group_v = arg1;
01273         SafeRequire_EC_GROUP(group_v, group);
01274 
01275         if (rb_obj_is_kind_of(arg2, cBN)) {
01276             const BIGNUM *bn = GetBNPtr(arg2);
01277 
01278             point = EC_POINT_bn2point(group, bn, NULL, ossl_bn_ctx);
01279         } else {
01280             BIO *in = ossl_obj2bio(arg1);
01281 
01282 /* BUG: finish me */
01283 
01284             BIO_free(in);
01285 
01286             if (point == NULL) {
01287                 ossl_raise(eEC_POINT, "unknown type for 2nd arg");
01288             }
01289         }
01290         break;
01291     default:
01292         ossl_raise(rb_eArgError, "wrong number of arguments");
01293     }
01294 
01295     if (point == NULL)
01296         ossl_raise(eEC_POINT, NULL);
01297 
01298     if (NIL_P(group_v))
01299         ossl_raise(rb_eRuntimeError, "missing group (internal error)");
01300 
01301     ec_point->point = point;
01302 
01303     rb_iv_set(self, "@group", group_v);
01304 
01305     return self;
01306 }
01307 
01308 /*
01309  *  call-seq:
01310  *     point1 == point2 => true | false
01311  *
01312  */
01313 static VALUE ossl_ec_point_eql(VALUE a, VALUE b)
01314 {
01315     EC_POINT *point1, *point2;
01316     VALUE group_v1 = rb_iv_get(a, "@group");
01317     VALUE group_v2 = rb_iv_get(b, "@group");
01318     const EC_GROUP *group;
01319 
01320     if (ossl_ec_group_eql(group_v1, group_v2) == Qfalse)
01321         return Qfalse;
01322 
01323     Require_EC_POINT(a, point1);
01324     SafeRequire_EC_POINT(b, point2);
01325     SafeRequire_EC_GROUP(group_v1, group);
01326 
01327     if (EC_POINT_cmp(group, point1, point2, ossl_bn_ctx) == 1)
01328         return Qfalse;
01329 
01330     return Qtrue;
01331 }
01332 
01333 /*
01334  *  call-seq:
01335  *     point.infinity? => true | false
01336  *
01337  */
01338 static VALUE ossl_ec_point_is_at_infinity(VALUE self)
01339 {
01340     EC_POINT *point;
01341     VALUE group_v = rb_iv_get(self, "@group");
01342     const EC_GROUP *group;
01343 
01344     Require_EC_POINT(self, point);
01345     SafeRequire_EC_GROUP(group_v, group);
01346 
01347     switch (EC_POINT_is_at_infinity(group, point)) {
01348     case 1: return Qtrue;
01349     case 0: return Qfalse;
01350     default: ossl_raise(cEC_POINT, "EC_POINT_is_at_infinity");
01351     }
01352 }
01353 
01354 /*
01355  *  call-seq:
01356  *     point.on_curve? => true | false
01357  *
01358  */
01359 static VALUE ossl_ec_point_is_on_curve(VALUE self)
01360 {
01361     EC_POINT *point;
01362     VALUE group_v = rb_iv_get(self, "@group");
01363     const EC_GROUP *group;
01364 
01365     Require_EC_POINT(self, point);
01366     SafeRequire_EC_GROUP(group_v, group);
01367 
01368     switch (EC_POINT_is_on_curve(group, point, ossl_bn_ctx)) {
01369     case 1: return Qtrue;
01370     case 0: return Qfalse;
01371     default: ossl_raise(cEC_POINT, "EC_POINT_is_on_curve");
01372     }
01373 }
01374 
01375 /*
01376  *  call-seq:
01377  *     point.make_affine! => self
01378  *
01379  */
01380 static VALUE ossl_ec_point_make_affine(VALUE self)
01381 {
01382     EC_POINT *point;
01383     VALUE group_v = rb_iv_get(self, "@group");
01384     const EC_GROUP *group;
01385 
01386     Require_EC_POINT(self, point);
01387     SafeRequire_EC_GROUP(group_v, group);
01388 
01389     if (EC_POINT_make_affine(group, point, ossl_bn_ctx) != 1)
01390         ossl_raise(cEC_POINT, "EC_POINT_make_affine");
01391 
01392     return self;
01393 }
01394 
01395 /*
01396  *  call-seq:
01397  *     point.invert! => self
01398  *
01399  */
01400 static VALUE ossl_ec_point_invert(VALUE self)
01401 {
01402     EC_POINT *point;
01403     VALUE group_v = rb_iv_get(self, "@group");
01404     const EC_GROUP *group;
01405 
01406     Require_EC_POINT(self, point);
01407     SafeRequire_EC_GROUP(group_v, group);
01408 
01409     if (EC_POINT_invert(group, point, ossl_bn_ctx) != 1)
01410         ossl_raise(cEC_POINT, "EC_POINT_invert");
01411 
01412     return self;
01413 }
01414 
01415 /*
01416  *  call-seq:
01417  *     point.set_to_infinity! => self
01418  *
01419  */
01420 static VALUE ossl_ec_point_set_to_infinity(VALUE self)
01421 {
01422     EC_POINT *point;
01423     VALUE group_v = rb_iv_get(self, "@group");
01424     const EC_GROUP *group;
01425 
01426     Require_EC_POINT(self, point);
01427     SafeRequire_EC_GROUP(group_v, group);
01428 
01429     if (EC_POINT_set_to_infinity(group, point) != 1)
01430         ossl_raise(cEC_POINT, "EC_POINT_set_to_infinity");
01431 
01432     return self;
01433 }
01434 
01435 /*
01436  *  call-seq:
01437  *     point.to_bn   => OpenSSL::BN
01438  *
01439  *  See the OpenSSL documentation for EC_POINT_point2bn()
01440  */
01441 static VALUE ossl_ec_point_to_bn(VALUE self)
01442 {
01443     EC_POINT *point;
01444     VALUE bn_obj;
01445     VALUE group_v = rb_iv_get(self, "@group");
01446     const EC_GROUP *group;
01447     point_conversion_form_t form;
01448     BIGNUM *bn;
01449 
01450     Require_EC_POINT(self, point);
01451     SafeRequire_EC_GROUP(group_v, group);
01452 
01453     form = EC_GROUP_get_point_conversion_form(group);
01454 
01455     bn_obj = rb_obj_alloc(cBN);
01456     bn = GetBNPtr(bn_obj);
01457 
01458     if (EC_POINT_point2bn(group, point, form, bn, ossl_bn_ctx) == NULL)
01459         ossl_raise(eEC_POINT, "EC_POINT_point2bn");
01460 
01461     return bn_obj;
01462 }
01463 
01464 static void no_copy(VALUE klass)
01465 {
01466     rb_undef_method(klass, "copy");
01467     rb_undef_method(klass, "clone");
01468     rb_undef_method(klass, "dup");
01469     rb_undef_method(klass, "initialize_copy");
01470 }
01471 
01472 void Init_ossl_ec()
01473 {
01474 #ifdef DONT_NEED_RDOC_WORKAROUND
01475     mOSSL = rb_define_module("OpenSSL");
01476     mPKey = rb_define_module_under(mOSSL, "PKey");
01477 #endif
01478 
01479     eECError = rb_define_class_under(mPKey, "ECError", ePKeyError);
01480 
01481     cEC = rb_define_class_under(mPKey, "EC", cPKey);
01482     cEC_GROUP = rb_define_class_under(cEC, "Group", rb_cObject);
01483     cEC_POINT = rb_define_class_under(cEC, "Point", rb_cObject);
01484     eEC_GROUP = rb_define_class_under(cEC_GROUP, "Error", eOSSLError);
01485     eEC_POINT = rb_define_class_under(cEC_POINT, "Error", eOSSLError);
01486 
01487     s_GFp = rb_intern("GFp");
01488     s_GF2m = rb_intern("GF2m");
01489     s_GFp_simple = rb_intern("GFp_simple");
01490     s_GFp_mont = rb_intern("GFp_mont");
01491     s_GFp_nist = rb_intern("GFp_nist");
01492     s_GF2m_simple = rb_intern("GF2m_simple");
01493 
01494     ID_uncompressed = rb_intern("uncompressed");
01495     ID_compressed = rb_intern("compressed");
01496     ID_hybrid = rb_intern("hybrid");
01497 
01498 #ifdef OPENSSL_EC_NAMED_CURVE
01499     rb_define_const(cEC, "NAMED_CURVE", ULONG2NUM(OPENSSL_EC_NAMED_CURVE));
01500 #endif
01501 
01502     rb_define_singleton_method(cEC, "builtin_curves", ossl_s_builtin_curves, 0);
01503 
01504     rb_define_method(cEC, "initialize", ossl_ec_key_initialize, -1);
01505 /* copy/dup/cmp */
01506 
01507     rb_define_method(cEC, "group", ossl_ec_key_get_group, 0);
01508     rb_define_method(cEC, "group=", ossl_ec_key_set_group, 1);
01509     rb_define_method(cEC, "private_key", ossl_ec_key_get_private_key, 0);
01510     rb_define_method(cEC, "private_key=", ossl_ec_key_set_private_key, 1);
01511     rb_define_method(cEC, "public_key", ossl_ec_key_get_public_key, 0);
01512     rb_define_method(cEC, "public_key=", ossl_ec_key_set_public_key, 1);
01513     rb_define_method(cEC, "private_key?", ossl_ec_key_is_private_key, 0);
01514     rb_define_method(cEC, "public_key?", ossl_ec_key_is_public_key, 0);
01515 /*  rb_define_method(cEC, "", ossl_ec_key_get_, 0);
01516     rb_define_method(cEC, "=", ossl_ec_key_set_ 1);
01517     set/get enc_flags
01518     set/get _conv_from
01519     set/get asn1_flag (can use ruby to call self.group.asn1_flag)
01520     set/get precompute_mult
01521 */
01522     rb_define_method(cEC, "generate_key", ossl_ec_key_generate_key, 0);
01523     rb_define_method(cEC, "check_key", ossl_ec_key_check_key, 0);
01524 
01525     rb_define_method(cEC, "dh_compute_key", ossl_ec_key_dh_compute_key, 1);
01526     rb_define_method(cEC, "dsa_sign_asn1", ossl_ec_key_dsa_sign_asn1, 1);
01527     rb_define_method(cEC, "dsa_verify_asn1", ossl_ec_key_dsa_verify_asn1, 2);
01528 /* do_sign/do_verify */
01529 
01530     rb_define_method(cEC, "to_pem", ossl_ec_key_to_pem, -1);
01531     rb_define_method(cEC, "to_der", ossl_ec_key_to_der, 0);
01532     rb_define_method(cEC, "to_text", ossl_ec_key_to_text, 0);
01533 
01534 
01535     rb_define_alloc_func(cEC_GROUP, ossl_ec_group_alloc);
01536     rb_define_method(cEC_GROUP, "initialize", ossl_ec_group_initialize, -1);
01537     rb_define_method(cEC_GROUP, "eql?", ossl_ec_group_eql, 1);
01538     rb_define_alias(cEC_GROUP, "==", "eql?");
01539 /* copy/dup/cmp */
01540 
01541     rb_define_method(cEC_GROUP, "generator", ossl_ec_group_get_generator, 0);
01542     rb_define_method(cEC_GROUP, "set_generator", ossl_ec_group_set_generator, 3);
01543     rb_define_method(cEC_GROUP, "order", ossl_ec_group_get_order, 0);
01544     rb_define_method(cEC_GROUP, "cofactor", ossl_ec_group_get_cofactor, 0);
01545 
01546     rb_define_method(cEC_GROUP, "curve_name", ossl_ec_group_get_curve_name, 0);
01547 /*    rb_define_method(cEC_GROUP, "curve_name=", ossl_ec_group_set_curve_name, 1); */
01548 
01549     rb_define_method(cEC_GROUP, "asn1_flag", ossl_ec_group_get_asn1_flag, 0);
01550     rb_define_method(cEC_GROUP, "asn1_flag=", ossl_ec_group_set_asn1_flag, 1);
01551 
01552     rb_define_method(cEC_GROUP, "point_conversion_form", ossl_ec_group_get_point_conversion_form, 0);
01553     rb_define_method(cEC_GROUP, "point_conversion_form=", ossl_ec_group_set_point_conversion_form, 1);
01554 
01555     rb_define_method(cEC_GROUP, "seed", ossl_ec_group_get_seed, 0);
01556     rb_define_method(cEC_GROUP, "seed=", ossl_ec_group_set_seed, 1);
01557 
01558 /* get/set GFp, GF2m */
01559 
01560     rb_define_method(cEC_GROUP, "degree", ossl_ec_group_get_degree, 0);
01561 
01562 /* check* */
01563 
01564 
01565     rb_define_method(cEC_GROUP, "to_pem", ossl_ec_group_to_pem, 0);
01566     rb_define_method(cEC_GROUP, "to_der", ossl_ec_group_to_der, 0);
01567     rb_define_method(cEC_GROUP, "to_text", ossl_ec_group_to_text, 0);
01568 
01569 
01570     rb_define_alloc_func(cEC_POINT, ossl_ec_point_alloc);
01571     rb_define_method(cEC_POINT, "initialize", ossl_ec_point_initialize, -1);
01572     rb_attr(cEC_POINT, rb_intern("group"), 1, 0, 0);
01573     rb_define_method(cEC_POINT, "eql?", ossl_ec_point_eql, 1);
01574     rb_define_alias(cEC_POINT, "==", "eql?");
01575 
01576     rb_define_method(cEC_POINT, "infinity?", ossl_ec_point_is_at_infinity, 0);
01577     rb_define_method(cEC_POINT, "on_curve?", ossl_ec_point_is_on_curve, 0);
01578     rb_define_method(cEC_POINT, "make_affine!", ossl_ec_point_make_affine, 0);
01579     rb_define_method(cEC_POINT, "invert!", ossl_ec_point_invert, 0);
01580     rb_define_method(cEC_POINT, "set_to_infinity!", ossl_ec_point_set_to_infinity, 0);
01581 /* all the other methods */
01582 
01583     rb_define_method(cEC_POINT, "to_bn", ossl_ec_point_to_bn, 0);
01584 
01585     no_copy(cEC);
01586     no_copy(cEC_GROUP);
01587     no_copy(cEC_POINT);
01588 }
01589 
01590 #else /* defined NO_EC */
01591 void Init_ossl_ec()
01592 {
01593 }
01594 #endif /* NO_EC */
01595