Ruby 1.9.2p136(2010-12-25revision30365)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# 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         rb_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         rb_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         rb_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         rb_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         rb_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(der_string)
    00156  *
    00157  *  See the OpenSSL documentation for:
    00158  *     EC_KEY_*
    00159  */
    00160 static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self)
    00161 {
    00162     EVP_PKEY *pkey;
    00163     EC_KEY *ec = NULL;
    00164     VALUE arg, pass;
    00165     VALUE group = Qnil;
    00166
    00167     GetPKey(self, pkey);
    00168     if (pkey->pkey.ec)
    00169         rb_raise(eECError, "EC_KEY already initialized");
    00170
    00171     rb_scan_args(argc, argv, "02", &arg, &pass);
    00172
    00173     if (NIL_P(arg)) {
    00174         ec = EC_KEY_new();
    00175     } else {
    00176         if (rb_obj_is_kind_of(arg, cEC)) {
    00177             EC_KEY *other_ec = NULL;
    00178
    00179             SafeRequire_EC_KEY(arg, other_ec);
    00180             ec = EC_KEY_dup(other_ec);
    00181         } else if (rb_obj_is_kind_of(arg, cEC_GROUP)) {
    00182                 ec = EC_KEY_new();
    00183                 group = arg;
    00184         } else {
    00185             BIO *in = ossl_obj2bio(arg);
    00186
    00187             ec = PEM_read_bio_ECPrivateKey(in, NULL, NULL, NULL);
    00188             if (!ec) {
    00189                 (void)BIO_reset(in);
    00190                 ec = PEM_read_bio_EC_PUBKEY(in, NULL, NULL, NULL);
    00191             }
    00192             if (!ec) {
    00193                 (void)BIO_reset(in);
    00194                 ec = d2i_ECPrivateKey_bio(in, NULL);
    00195             }
    00196             if (!ec) {
    00197                 (void)BIO_reset(in);
    00198                 ec = d2i_EC_PUBKEY_bio(in, NULL);
    00199             }
    00200
    00201             BIO_free(in);
    00202
    00203             if (ec == NULL) {
    00204                 const char *name = StringValueCStr(arg);
    00205                 int nid = OBJ_sn2nid(name);
    00206
    00207                 if (nid == NID_undef)
    00208                     ossl_raise(eECError, "unknown curve name (%s)\n", name);
    00209
    00210                 if ((ec = EC_KEY_new_by_curve_name(nid)) == NULL)
    00211                     ossl_raise(eECError, "unable to create curve (%s)\n", name);
    00212
    00213                 EC_KEY_set_asn1_flag(ec, OPENSSL_EC_NAMED_CURVE);
    00214                 EC_KEY_set_conv_form(ec, POINT_CONVERSION_UNCOMPRESSED);
    00215             }
    00216         }
    00217     }
    00218
    00219     if (ec == NULL)
    00220         ossl_raise(eECError, NULL);
    00221
    00222     if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) {
    00223         EC_KEY_free(ec);
    00224         ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY");
    00225     }
    00226
    00227     rb_iv_set(self, "@group", Qnil);
    00228
    00229     if (!NIL_P(group))
    00230         rb_funcall(self, rb_intern("group="), 1, arg);
    00231
    00232     return self;
    00233 }
    00234
    00235 /*
    00236  *  call-seq:
    00237  *     key.group   => group
    00238  *
    00239  *  Returns a constant <code>OpenSSL::EC::Group</code> that is tied to the key.
    00240  *  Modifying the returned group can make the key invalid.
    00241  */
    00242 static VALUE ossl_ec_key_get_group(VALUE self)
    00243 {
    00244     VALUE group_v;
    00245     EC_KEY *ec;
    00246     ossl_ec_group *ec_group;
    00247     EC_GROUP *group;
    00248
    00249     Require_EC_KEY(self, ec);
    00250
    00251     group_v = rb_iv_get(self, "@group");
    00252     if (!NIL_P(group_v))
    00253         return group_v;
    00254
    00255     if ((group = (EC_GROUP *)EC_KEY_get0_group(ec)) != NULL) {
    00256         group_v = rb_obj_alloc(cEC_GROUP);
    00257         SafeGet_ec_group(group_v, ec_group);
    00258         ec_group->group = group;
    00259         ec_group->dont_free = 1;
    00260         rb_iv_set(group_v, "@key", self);
    00261         rb_iv_set(self, "@group", group_v);
    00262         return group_v;
    00263     }
    00264
    00265     return Qnil;
    00266 }
    00267
    00268 /*
    00269  *  call-seq:
    00270  *     key.group = group   => group
    00271  *
    00272  *  Returns the same object passed, not the group object associated with the key.
    00273  *  If you wish to access the group object tied to the key call key.group after setting
    00274  *  the group.
    00275  *
    00276  *  Setting the group will immediately destroy any previously assigned group object.
    00277  *  The group is internally copied by OpenSSL.  Modifying the original group after
    00278  *  assignment will not effect the internal key structure.
    00279  *  (your changes may be lost).  BE CAREFUL.
    00280  *
    00281  *  EC_KEY_set_group calls EC_GROUP_free(key->group) then EC_GROUP_dup(), not EC_GROUP_copy.
    00282  *  This documentation is accurate for OpenSSL 0.9.8b.
    00283  */
    00284 static VALUE ossl_ec_key_set_group(VALUE self, VALUE group_v)
    00285 {
    00286     VALUE old_group_v;
    00287     EC_KEY *ec;
    00288     EC_GROUP *group;
    00289
    00290     Require_EC_KEY(self, ec);
    00291     SafeRequire_EC_GROUP(group_v, group);
    00292
    00293     old_group_v = rb_iv_get(self, "@group");
    00294     if (!NIL_P(old_group_v)) {
    00295         ossl_ec_group *old_ec_group;
    00296         SafeGet_ec_group(old_group_v, old_ec_group);
    00297
    00298         old_ec_group->group = NULL;
    00299         old_ec_group->dont_free = 0;
    00300         rb_iv_set(old_group_v, "@key", Qnil);
    00301     }
    00302
    00303     rb_iv_set(self, "@group", Qnil);
    00304
    00305     if (EC_KEY_set_group(ec, group) != 1)
    00306         ossl_raise(eECError, "EC_KEY_set_group");
    00307
    00308     return group_v;
    00309 }
    00310
    00311 /*
    00312  *  call-seq:
    00313  *     key.private_key   => OpenSSL::BN
    00314  *
    00315  *  See the OpenSSL documentation for EC_KEY_get0_private_key()
    00316  */
    00317 static VALUE ossl_ec_key_get_private_key(VALUE self)
    00318 {
    00319     EC_KEY *ec;
    00320     const BIGNUM *bn;
    00321
    00322     Require_EC_KEY(self, ec);
    00323
    00324     if ((bn = EC_KEY_get0_private_key(ec)) == NULL)
    00325         return Qnil;
    00326
    00327     return ossl_bn_new(bn);
    00328 }
    00329
    00330 /*
    00331  *  call-seq:
    00332  *     key.private_key = openssl_bn
    00333  *
    00334  *  See the OpenSSL documentation for EC_KEY_set_private_key()
    00335  */
    00336 static VALUE ossl_ec_key_set_private_key(VALUE self, VALUE private_key)
    00337 {
    00338     EC_KEY *ec;
    00339     BIGNUM *bn = NULL;
    00340
    00341     Require_EC_KEY(self, ec);
    00342     if (!NIL_P(private_key))
    00343         bn = GetBNPtr(private_key);
    00344
    00345     switch (EC_KEY_set_private_key(ec, bn)) {
    00346     case 1:
    00347         break;
    00348     case 0:
    00349         if (bn == NULL)
    00350             break;
    00351     default:
    00352         ossl_raise(eECError, "EC_KEY_set_private_key");
    00353     }
    00354
    00355     return private_key;
    00356 }
    00357
    00358
    00359 static VALUE ossl_ec_point_dup(const EC_POINT *point, VALUE group_v)
    00360 {
    00361     VALUE obj;
    00362     const EC_GROUP *group;
    00363     ossl_ec_point *new_point;
    00364
    00365     obj = rb_obj_alloc(cEC_POINT);
    00366     Data_Get_Struct(obj, ossl_ec_point, new_point);
    00367
    00368     SafeRequire_EC_GROUP(group_v, group);
    00369
    00370     new_point->point = EC_POINT_dup(point, group);
    00371     if (new_point->point == NULL)
    00372         ossl_raise(eEC_POINT, "EC_POINT_dup");
    00373     rb_iv_set(obj, "@group", group_v);
    00374
    00375     return obj;
    00376 }
    00377
    00378 /*
    00379  *  call-seq:
    00380  *     key.public_key   => OpenSSL::PKey::EC::Point
    00381  *
    00382  *  See the OpenSSL documentation for EC_KEY_get0_public_key()
    00383  */
    00384 static VALUE ossl_ec_key_get_public_key(VALUE self)
    00385 {
    00386     EC_KEY *ec;
    00387     const EC_POINT *point;
    00388     VALUE group;
    00389
    00390     Require_EC_KEY(self, ec);
    00391
    00392     if ((point = EC_KEY_get0_public_key(ec)) == NULL)
    00393         return Qnil;
    00394
    00395     group = rb_funcall(self, rb_intern("group"), 0);
    00396     if (NIL_P(group))
    00397         ossl_raise(eECError, "EC_KEY_get0_get0_group (has public_key but no group???");
    00398
    00399     return ossl_ec_point_dup(point, group);
    00400 }
    00401
    00402 /*
    00403  *  call-seq:
    00404  *     key.public_key = ec_point
    00405  *
    00406  *  See the OpenSSL documentation for EC_KEY_set_public_key()
    00407  */
    00408 static VALUE ossl_ec_key_set_public_key(VALUE self, VALUE public_key)
    00409 {
    00410     EC_KEY *ec;
    00411     EC_POINT *point = NULL;
    00412
    00413     Require_EC_KEY(self, ec);
    00414     if (!NIL_P(public_key))
    00415         SafeRequire_EC_POINT(public_key, point);
    00416
    00417     switch (EC_KEY_set_public_key(ec, point)) {
    00418     case 1:
    00419         break;
    00420     case 0:
    00421         if (point == NULL)
    00422             break;
    00423     default:
    00424         ossl_raise(eECError, "EC_KEY_set_public_key");
    00425     }
    00426
    00427     return public_key;
    00428 }
    00429
    00430 /*
    00431  *  call-seq:
    00432  *     key.public_key? => true or false
    00433  *
    00434  *  Both public_key? and private_key? may return false at the same time unlike other PKey classes.
    00435  */
    00436 static VALUE ossl_ec_key_is_public_key(VALUE self)
    00437 {
    00438     EC_KEY *ec;
    00439
    00440     Require_EC_KEY(self, ec);
    00441
    00442     return (EC_KEY_get0_public_key(ec) ? Qtrue : Qfalse);
    00443 }
    00444
    00445 /*
    00446  *  call-seq:
    00447  *     key.private_key? => true or false
    00448  *
    00449  *  Both public_key? and private_key? may return false at the same time unlike other PKey classes.
    00450  */
    00451 static VALUE ossl_ec_key_is_private_key(VALUE self)
    00452 {
    00453     EC_KEY *ec;
    00454
    00455     Require_EC_KEY(self, ec);
    00456
    00457     return (EC_KEY_get0_private_key(ec) ? Qtrue : Qfalse);
    00458 }
    00459
    00460 static VALUE ossl_ec_key_to_string(VALUE self, int format)
    00461 {
    00462     EC_KEY *ec;
    00463     BIO *out;
    00464     int i = -1;
    00465     int private = 0;
    00466 #if 0  /* unused now */
    00467     EVP_CIPHER *cipher = NULL;
    00468     char *password = NULL;
    00469 #endif
    00470     VALUE str;
    00471
    00472     Require_EC_KEY(self, ec);
    00473
    00474     if (EC_KEY_get0_public_key(ec) == NULL)
    00475         rb_raise(eECError, "can't export - no public key set");
    00476
    00477     if (EC_KEY_check_key(ec) != 1)
    00478         ossl_raise(eECError, "can't export - EC_KEY_check_key failed");
    00479
    00480     if (EC_KEY_get0_private_key(ec))
    00481         private = 1;
    00482
    00483     if (!(out = BIO_new(BIO_s_mem())))
    00484         ossl_raise(eECError, "BIO_new(BIO_s_mem())");
    00485
    00486     switch(format) {
    00487     case EXPORT_PEM:
    00488         if (private) {
    00489 #if 0  /* unused now */
    00490             if (cipher || password)
    00491 /* BUG: finish cipher/password key export */
    00492                 rb_notimplement();
    00493             i = PEM_write_bio_ECPrivateKey(out, ec, cipher, NULL, 0, NULL, password);
    00494 #endif
    00495             i = PEM_write_bio_ECPrivateKey(out, ec, NULL, NULL, 0, NULL, NULL);
    00496         } else {
    00497 #if 0  /* unused now */
    00498             if (cipher || password)
    00499                 rb_raise(rb_eArgError, "encryption is not supported when exporting this key type");
    00500 #endif
    00501
    00502             i = PEM_write_bio_EC_PUBKEY(out, ec);
    00503         }
    00504
    00505         break;
    00506     case EXPORT_DER:
    00507         if (private) {
    00508 #if 0  /* unused now */
    00509             if (cipher || password)
    00510                 rb_raise(rb_eArgError, "encryption is not supported when exporting this key type");
    00511 #endif
    00512
    00513             i = i2d_ECPrivateKey_bio(out, ec);
    00514         } else {
    00515 #if 0  /* unused now */
    00516             if (cipher || password)
    00517                 rb_raise(rb_eArgError, "encryption is not supported when exporting this key type");
    00518 #endif
    00519
    00520             i = i2d_EC_PUBKEY_bio(out, ec);
    00521         }
    00522
    00523         break;
    00524     default:
    00525         BIO_free(out);
    00526         rb_raise(rb_eRuntimeError, "unknown format (internal error)");
    00527     }
    00528
    00529     if (i != 1) {
    00530         BIO_free(out);
    00531         ossl_raise(eECError, "outlen=%d", i);
    00532     }
    00533
    00534     str = ossl_membio2str(out);
    00535
    00536     return str;
    00537 }
    00538
    00539 /*
    00540  *  call-seq:
    00541  *     key.to_pem   => String
    00542  *
    00543  *  See the OpenSSL documentation for PEM_write_bio_ECPrivateKey()
    00544  */
    00545 static VALUE ossl_ec_key_to_pem(VALUE self)
    00546 {
    00547     return ossl_ec_key_to_string(self, 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, 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_LEN(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_LEN(data), (unsigned char *) RSTRING_PTR(sig), 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         rb_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                 rb_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                 (void)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                 if (nid == NID_undef)
    00792                     ossl_raise(eEC_GROUP, "unknown curve name (%s)", name);
    00793
    00794                 group = EC_GROUP_new_by_curve_name(nid);
    00795                 if (group == NULL)
    00796                     ossl_raise(eEC_GROUP, "unable to create curve (%s)", name);
    00797
    00798                 EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE);
    00799                 EC_GROUP_set_point_conversion_form(group, POINT_CONVERSION_UNCOMPRESSED);
    00800             }
    00801         }
    00802
    00803         break;
    00804     case 4:
    00805         if (SYMBOL_P(arg1)) {
    00806             ID id = SYM2ID(arg1);
    00807             EC_GROUP *(*new_curve)(const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *) = NULL;
    00808             const BIGNUM *p = GetBNPtr(arg2);
    00809             const BIGNUM *a = GetBNPtr(arg3);
    00810             const BIGNUM *b = GetBNPtr(arg4);
    00811
    00812             if (id == s_GFp) {
    00813                 new_curve = EC_GROUP_new_curve_GFp;
    00814             } else if (id == s_GF2m) {
    00815                 new_curve = EC_GROUP_new_curve_GF2m;
    00816             } else {
    00817                 rb_raise(rb_eArgError, "unknown symbol, must be :GFp or :GF2m");
    00818             }
    00819
    00820             if ((group = new_curve(p, a, b, ossl_bn_ctx)) == NULL)
    00821                 ossl_raise(eEC_GROUP, "EC_GROUP_new_by_GF*");
    00822         } else {
    00823              rb_raise(rb_eArgError, "unknown argument, must be :GFp or :GF2m");
    00824         }
    00825
    00826         break;
    00827     default:
    00828         rb_raise(rb_eArgError, "wrong number of arguments");
    00829     }
    00830
    00831     if (group == NULL)
    00832         ossl_raise(eEC_GROUP, "");
    00833
    00834     ec_group->group = group;
    00835
    00836     return self;
    00837 }
    00838
    00839 /*  call-seq:
    00840  *     group1 == group2   => true | false
    00841  *
    00842  */
    00843 static VALUE ossl_ec_group_eql(VALUE a, VALUE b)
    00844 {
    00845     EC_GROUP *group1 = NULL, *group2 = NULL;
    00846
    00847     Require_EC_GROUP(a, group1);
    00848     SafeRequire_EC_GROUP(b, group2);
    00849
    00850     if (EC_GROUP_cmp(group1, group2, ossl_bn_ctx) == 1)
    00851        return Qfalse;
    00852
    00853     return Qtrue;
    00854 }
    00855
    00856 /*  call-seq:
    00857  *     group.generator   => ec_point
    00858  *
    00859  *  See the OpenSSL documentation for EC_GROUP_get0_generator()
    00860  */
    00861 static VALUE ossl_ec_group_get_generator(VALUE self)
    00862 {
    00863     VALUE point_obj;
    00864     EC_GROUP *group = NULL;
    00865
    00866     Require_EC_GROUP(self, group);
    00867
    00868     point_obj = ossl_ec_point_dup(EC_GROUP_get0_generator(group), self);
    00869
    00870     return point_obj;
    00871 }
    00872
    00873 /*  call-seq:
    00874  *     group.set_generator(generator, order, cofactor)   => self
    00875  *
    00876  *  See the OpenSSL documentation for EC_GROUP_set_generator()
    00877  */
    00878 static VALUE ossl_ec_group_set_generator(VALUE self, VALUE generator, VALUE order, VALUE cofactor)
    00879 {
    00880     EC_GROUP *group = NULL;
    00881     const EC_POINT *point;
    00882     const BIGNUM *o, *co;
    00883
    00884     Require_EC_GROUP(self, group);
    00885     SafeRequire_EC_POINT(generator, point);
    00886     o = GetBNPtr(order);
    00887     co = GetBNPtr(cofactor);
    00888
    00889     if (EC_GROUP_set_generator(group, point, o, co) != 1)
    00890         ossl_raise(eEC_GROUP, "EC_GROUP_set_generator");
    00891
    00892     return self;
    00893 }
    00894
    00895 /*  call-seq:
    00896  *     group.get_order   => order_bn
    00897  *
    00898  *  See the OpenSSL documentation for EC_GROUP_get_order()
    00899  */
    00900 static VALUE ossl_ec_group_get_order(VALUE self)
    00901 {
    00902     VALUE bn_obj;
    00903     BIGNUM *bn;
    00904     EC_GROUP *group = NULL;
    00905
    00906     Require_EC_GROUP(self, group);
    00907
    00908     bn_obj = ossl_bn_new(NULL);
    00909     bn = GetBNPtr(bn_obj);
    00910
    00911     if (EC_GROUP_get_order(group, bn, ossl_bn_ctx) != 1)
    00912         ossl_raise(eEC_GROUP, "EC_GROUP_get_order");
    00913
    00914     return bn_obj;
    00915 }
    00916
    00917 /*  call-seq:
    00918  *     group.get_cofactor   => cofactor_bn
    00919  *
    00920  *  See the OpenSSL documentation for EC_GROUP_get_cofactor()
    00921  */
    00922 static VALUE ossl_ec_group_get_cofactor(VALUE self)
    00923 {
    00924     VALUE bn_obj;
    00925     BIGNUM *bn;
    00926     EC_GROUP *group = NULL;
    00927
    00928     Require_EC_GROUP(self, group);
    00929
    00930     bn_obj = ossl_bn_new(NULL);
    00931     bn = GetBNPtr(bn_obj);
    00932
    00933     if (EC_GROUP_get_cofactor(group, bn, ossl_bn_ctx) != 1)
    00934         ossl_raise(eEC_GROUP, "EC_GROUP_get_cofactor");
    00935
    00936     return bn_obj;
    00937 }
    00938
    00939 /*  call-seq:
    00940  *     group.curve_name  => String
    00941  *
    00942  *  See the OpenSSL documentation for EC_GROUP_get_curve_name()
    00943  */
    00944 static VALUE ossl_ec_group_get_curve_name(VALUE self)
    00945 {
    00946     EC_GROUP *group = NULL;
    00947     int nid;
    00948
    00949     Get_EC_GROUP(self, group);
    00950     if (group == NULL)
    00951         return Qnil;
    00952
    00953     nid = EC_GROUP_get_curve_name(group);
    00954
    00955 /* BUG: an nid or asn1 object should be returned, maybe. */
    00956     return rb_str_new2(OBJ_nid2sn(nid));
    00957 }
    00958
    00959 /*  call-seq:
    00960  *     EC.builtin_curves => [[name, comment], ...]
    00961  *
    00962  *  See the OpenSSL documentation for EC_builtin_curves()
    00963  */
    00964 static VALUE ossl_s_builtin_curves(VALUE self)
    00965 {
    00966     EC_builtin_curve *curves = NULL;
    00967     int n;
    00968     int crv_len = EC_get_builtin_curves(NULL, 0);
    00969     VALUE ary, ret;
    00970
    00971     curves = ALLOCA_N(EC_builtin_curve, crv_len);
    00972     if (curves == NULL)
    00973         return Qnil;
    00974     if (!EC_get_builtin_curves(curves, crv_len))
    00975         ossl_raise(rb_eRuntimeError, "EC_get_builtin_curves");
    00976
    00977     ret = rb_ary_new2(crv_len);
    00978
    00979     for (n = 0; n < crv_len; n++) {
    00980         const char *sname = OBJ_nid2sn(curves[n].nid);
    00981         const char *comment = curves[n].comment;
    00982
    00983         ary = rb_ary_new2(2);
    00984         rb_ary_push(ary, rb_str_new2(sname));
    00985         rb_ary_push(ary, comment ? rb_str_new2(comment) : Qnil);
    00986         rb_ary_push(ret, ary);
    00987     }
    00988
    00989     return ret;
    00990 }
    00991
    00992 /*  call-seq:
    00993  *     group.asn1_flag  => Fixnum
    00994  *
    00995  *  See the OpenSSL documentation for EC_GROUP_get_asn1_flag()
    00996  */
    00997 static VALUE ossl_ec_group_get_asn1_flag(VALUE self)
    00998 {
    00999     EC_GROUP *group = NULL;
    01000     int flag;
    01001
    01002     Require_EC_GROUP(self, group);
    01003
    01004     flag = EC_GROUP_get_asn1_flag(group);
    01005
    01006     return INT2FIX(flag);
    01007 }
    01008
    01009 /*  call-seq:
    01010  *     group.asn1_flag = Fixnum   => Fixnum
    01011  *
    01012  *  See the OpenSSL documentation for EC_GROUP_set_asn1_flag()
    01013  */
    01014 static VALUE ossl_ec_group_set_asn1_flag(VALUE self, VALUE flag_v)
    01015 {
    01016     EC_GROUP *group = NULL;
    01017
    01018     Require_EC_GROUP(self, group);
    01019
    01020     EC_GROUP_set_asn1_flag(group, NUM2INT(flag_v));
    01021
    01022     return flag_v;
    01023 }
    01024
    01025 /*  call-seq:
    01026  *     group.point_conversion_form  => :uncompressed | :compressed | :hybrid
    01027  *
    01028  *  See the OpenSSL documentation for EC_GROUP_get_point_conversion_form()
    01029  */
    01030 static VALUE ossl_ec_group_get_point_conversion_form(VALUE self)
    01031 {
    01032     EC_GROUP *group = NULL;
    01033     point_conversion_form_t form;
    01034     VALUE ret;
    01035
    01036     Require_EC_GROUP(self, group);
    01037
    01038     form = EC_GROUP_get_point_conversion_form(group);
    01039
    01040     switch (form) {
    01041     case POINT_CONVERSION_UNCOMPRESSED: ret = ID_uncompressed; break;
    01042     case POINT_CONVERSION_COMPRESSED:   ret = ID_compressed; break;
    01043     case POINT_CONVERSION_HYBRID:       ret = ID_hybrid; break;
    01044     default:    rb_raise(eEC_GROUP, "unsupported point conversion form: %d, this module should be updated", form);
    01045     }
    01046
    01047    return ID2SYM(ret);
    01048 }
    01049
    01050 /*  call-seq:
    01051  *     group.point_conversion_form = form => form
    01052  *
    01053  *  See the OpenSSL documentation for EC_GROUP_set_point_conversion_form()
    01054  */
    01055 static VALUE ossl_ec_group_set_point_conversion_form(VALUE self, VALUE form_v)
    01056 {
    01057     EC_GROUP *group = NULL;
    01058     point_conversion_form_t form;
    01059     ID form_id = SYM2ID(form_v);
    01060
    01061     Require_EC_GROUP(self, group);
    01062
    01063     if (form_id == ID_uncompressed) {
    01064         form = POINT_CONVERSION_UNCOMPRESSED;
    01065     } else if (form_id == ID_compressed) {
    01066         form = POINT_CONVERSION_COMPRESSED;
    01067     } else if (form_id == ID_hybrid) {
    01068         form = POINT_CONVERSION_HYBRID;
    01069     } else {
    01070         rb_raise(rb_eArgError, "form must be :compressed, :uncompressed, or :hybrid");
    01071     }
    01072
    01073     EC_GROUP_set_point_conversion_form(group, form);
    01074
    01075     return form_v;
    01076 }
    01077
    01078 /*  call-seq:
    01079  *     group.seed   => String or nil
    01080  *
    01081  *  See the OpenSSL documentation for EC_GROUP_get0_seed()
    01082  */
    01083 static VALUE ossl_ec_group_get_seed(VALUE self)
    01084 {
    01085     EC_GROUP *group = NULL;
    01086     size_t seed_len;
    01087
    01088     Require_EC_GROUP(self, group);
    01089
    01090     seed_len = EC_GROUP_get_seed_len(group);
    01091
    01092     if (seed_len == 0)
    01093         return Qnil;
    01094
    01095     return rb_str_new((const char *)EC_GROUP_get0_seed(group), seed_len);
    01096 }
    01097
    01098 /*  call-seq:
    01099  *     group.seed = seed  => seed
    01100  *
    01101  *  See the OpenSSL documentation for EC_GROUP_set_seed()
    01102  */
    01103 static VALUE ossl_ec_group_set_seed(VALUE self, VALUE seed)
    01104 {
    01105     EC_GROUP *group = NULL;
    01106
    01107     Require_EC_GROUP(self, group);
    01108     StringValue(seed);
    01109
    01110     if (EC_GROUP_set_seed(group, (unsigned char *)RSTRING_PTR(seed), RSTRING_LEN(seed)) != RSTRING_LEN(seed))
    01111         ossl_raise(eEC_GROUP, "EC_GROUP_set_seed");
    01112
    01113     return seed;
    01114 }
    01115
    01116 /* get/set curve GFp, GF2m */
    01117
    01118 /*  call-seq:
    01119  *     group.degree   => Fixnum
    01120  *
    01121  *  See the OpenSSL documentation for EC_GROUP_get_degree()
    01122  */
    01123 static VALUE ossl_ec_group_get_degree(VALUE self)
    01124 {
    01125     EC_GROUP *group = NULL;
    01126
    01127     Require_EC_GROUP(self, group);
    01128
    01129     return INT2NUM(EC_GROUP_get_degree(group));
    01130 }
    01131
    01132 static VALUE ossl_ec_group_to_string(VALUE self, int format)
    01133 {
    01134     EC_GROUP *group;
    01135     BIO *out;
    01136     int i = -1;
    01137     VALUE str;
    01138
    01139     Get_EC_GROUP(self, group);
    01140
    01141     if (!(out = BIO_new(BIO_s_mem())))
    01142         ossl_raise(eEC_GROUP, "BIO_new(BIO_s_mem())");
    01143
    01144     switch(format) {
    01145     case EXPORT_PEM:
    01146         i = PEM_write_bio_ECPKParameters(out, group);
    01147         break;
    01148     case EXPORT_DER:
    01149         i = i2d_ECPKParameters_bio(out, group);
    01150         break;
    01151     default:
    01152         BIO_free(out);
    01153         rb_raise(rb_eRuntimeError, "unknown format (internal error)");
    01154     }
    01155
    01156     if (i != 1) {
    01157         BIO_free(out);
    01158         ossl_raise(eECError, NULL);
    01159     }
    01160
    01161     str = ossl_membio2str(out);
    01162
    01163     return str;
    01164 }
    01165
    01166 /*  call-seq:
    01167  *     group.to_pem   => String
    01168  *
    01169  *  See the OpenSSL documentation for PEM_write_bio_ECPKParameters()
    01170  */
    01171 static VALUE ossl_ec_group_to_pem(VALUE self)
    01172 {
    01173     return ossl_ec_group_to_string(self, EXPORT_PEM);
    01174 }
    01175
    01176 /*  call-seq:
    01177  *     group.to_der   => String
    01178  *
    01179  *  See the OpenSSL documentation for i2d_ECPKParameters_bio()
    01180  */
    01181 static VALUE ossl_ec_group_to_der(VALUE self)
    01182 {
    01183     return ossl_ec_group_to_string(self, EXPORT_DER);
    01184 }
    01185
    01186 /*  call-seq:
    01187  *     group.to_text   => String
    01188  *
    01189  *  See the OpenSSL documentation for ECPKParameters_print()
    01190  */
    01191 static VALUE ossl_ec_group_to_text(VALUE self)
    01192 {
    01193     EC_GROUP *group;
    01194     BIO *out;
    01195     VALUE str;
    01196
    01197     Require_EC_GROUP(self, group);
    01198     if (!(out = BIO_new(BIO_s_mem()))) {
    01199         ossl_raise(eEC_GROUP, "BIO_new(BIO_s_mem())");
    01200     }
    01201     if (!ECPKParameters_print(out, group, 0)) {
    01202         BIO_free(out);
    01203         ossl_raise(eEC_GROUP, NULL);
    01204     }
    01205     str = ossl_membio2str(out);
    01206
    01207     return str;
    01208 }
    01209
    01210
    01211 static void ossl_ec_point_free(ossl_ec_point *ec_point)
    01212 {
    01213     if (!ec_point->dont_free && ec_point->point)
    01214         EC_POINT_clear_free(ec_point->point);
    01215     ruby_xfree(ec_point);
    01216 }
    01217
    01218 static VALUE ossl_ec_point_alloc(VALUE klass)
    01219 {
    01220     ossl_ec_point *ec_point;
    01221     VALUE obj;
    01222
    01223     obj = Data_Make_Struct(klass, ossl_ec_point, 0, ossl_ec_point_free, ec_point);
    01224
    01225     return obj;
    01226 }
    01227
    01228 /*
    01229  *  call-seq:
    01230  *     OpenSSL::PKey::EC::Point.new(point)
    01231  *     OpenSSL::PKey::EC::Point.new(group)
    01232  *     OpenSSL::PKey::EC::Point.new(group, bn)
    01233  *
    01234  *  See the OpenSSL documentation for EC_POINT_*
    01235  */
    01236 static VALUE ossl_ec_point_initialize(int argc, VALUE *argv, VALUE self)
    01237 {
    01238     ossl_ec_point *ec_point;
    01239     EC_POINT *point = NULL;
    01240     VALUE arg1, arg2;
    01241     VALUE group_v = Qnil;
    01242     const EC_GROUP *group = NULL;
    01243
    01244     Data_Get_Struct(self, ossl_ec_point, ec_point);
    01245     if (ec_point->point)
    01246         rb_raise(eEC_POINT, "EC_POINT already initialized");
    01247
    01248     switch (rb_scan_args(argc, argv, "11", &arg1, &arg2)) {
    01249     case 1:
    01250         if (rb_obj_is_kind_of(arg1, cEC_POINT)) {
    01251             const EC_POINT *arg_point;
    01252
    01253             group_v = rb_iv_get(arg1, "@group");
    01254             SafeRequire_EC_GROUP(group_v, group);
    01255             SafeRequire_EC_POINT(arg1, arg_point);
    01256
    01257             point = EC_POINT_dup(arg_point, group);
    01258         } else if (rb_obj_is_kind_of(arg1, cEC_GROUP)) {
    01259             group_v = arg1;
    01260             SafeRequire_EC_GROUP(group_v, group);
    01261
    01262             point = EC_POINT_new(group);
    01263         } else {
    01264             rb_raise(eEC_POINT, "wrong argument type: must be OpenSSL::PKey::EC::Point or OpenSSL::Pkey::EC::Group");
    01265         }
    01266
    01267         break;
    01268      case 2:
    01269         if (!rb_obj_is_kind_of(arg1, cEC_GROUP))
    01270             rb_raise(rb_eArgError, "1st argument must be OpenSSL::PKey::EC::Group");
    01271         group_v = arg1;
    01272         SafeRequire_EC_GROUP(group_v, group);
    01273
    01274         if (rb_obj_is_kind_of(arg2, cBN)) {
    01275             const BIGNUM *bn = GetBNPtr(arg2);
    01276
    01277             point = EC_POINT_bn2point(group, bn, NULL, ossl_bn_ctx);
    01278         } else {
    01279             BIO *in = ossl_obj2bio(arg1);
    01280
    01281 /* BUG: finish me */
    01282
    01283             BIO_free(in);
    01284
    01285             if (point == NULL) {
    01286                 ossl_raise(eEC_POINT, "unknown type for 2nd arg");
    01287             }
    01288         }
    01289         break;
    01290     default:
    01291         rb_raise(rb_eArgError, "wrong number of arguments");
    01292     }
    01293
    01294     if (point == NULL)
    01295         ossl_raise(eEC_POINT, NULL);
    01296
    01297     if (NIL_P(group_v))
    01298         rb_raise(rb_eRuntimeError, "missing group (internal error)");
    01299
    01300     ec_point->point = point;
    01301
    01302     rb_iv_set(self, "@group", group_v);
    01303
    01304     return self;
    01305 }
    01306
    01307 /*
    01308  *  call-seq:
    01309  *     point1 == point2 => true | false
    01310  *
    01311  */
    01312 static VALUE ossl_ec_point_eql(VALUE a, VALUE b)
    01313 {
    01314     EC_POINT *point1, *point2;
    01315     VALUE group_v1 = rb_iv_get(a, "@group");
    01316     VALUE group_v2 = rb_iv_get(b, "@group");
    01317     const EC_GROUP *group;
    01318
    01319     if (ossl_ec_group_eql(group_v1, group_v2) == Qfalse)
    01320         return Qfalse;
    01321
    01322     Require_EC_POINT(a, point1);
    01323     SafeRequire_EC_POINT(b, point2);
    01324     SafeRequire_EC_GROUP(group_v1, group);
    01325
    01326     if (EC_POINT_cmp(group, point1, point2, ossl_bn_ctx) == 1)
    01327         return Qfalse;
    01328
    01329     return Qtrue;
    01330 }
    01331
    01332 /*
    01333  *  call-seq:
    01334  *     point.infinity? => true | false
    01335  *
    01336  */
    01337 static VALUE ossl_ec_point_is_at_infinity(VALUE self)
    01338 {
    01339     EC_POINT *point;
    01340     VALUE group_v = rb_iv_get(self, "@group");
    01341     const EC_GROUP *group;
    01342
    01343     Require_EC_POINT(self, point);
    01344     SafeRequire_EC_GROUP(group_v, group);
    01345
    01346     switch (EC_POINT_is_at_infinity(group, point)) {
    01347     case 1: return Qtrue;
    01348     case 0: return Qfalse;
    01349     default: ossl_raise(cEC_POINT, "EC_POINT_is_at_infinity");
    01350     }
    01351 }
    01352
    01353 /*
    01354  *  call-seq:
    01355  *     point.on_curve? => true | false
    01356  *
    01357  */
    01358 static VALUE ossl_ec_point_is_on_curve(VALUE self)
    01359 {
    01360     EC_POINT *point;
    01361     VALUE group_v = rb_iv_get(self, "@group");
    01362     const EC_GROUP *group;
    01363
    01364     Require_EC_POINT(self, point);
    01365     SafeRequire_EC_GROUP(group_v, group);
    01366
    01367     switch (EC_POINT_is_on_curve(group, point, ossl_bn_ctx)) {
    01368     case 1: return Qtrue;
    01369     case 0: return Qfalse;
    01370     default: ossl_raise(cEC_POINT, "EC_POINT_is_on_curve");
    01371     }
    01372 }
    01373
    01374 /*
    01375  *  call-seq:
    01376  *     point.make_affine! => self
    01377  *
    01378  */
    01379 static VALUE ossl_ec_point_make_affine(VALUE self)
    01380 {
    01381     EC_POINT *point;
    01382     VALUE group_v = rb_iv_get(self, "@group");
    01383     const EC_GROUP *group;
    01384
    01385     Require_EC_POINT(self, point);
    01386     SafeRequire_EC_GROUP(group_v, group);
    01387
    01388     if (EC_POINT_make_affine(group, point, ossl_bn_ctx) != 1)
    01389         ossl_raise(cEC_POINT, "EC_POINT_make_affine");
    01390
    01391     return self;
    01392 }
    01393
    01394 /*
    01395  *  call-seq:
    01396  *     point.invert! => self
    01397  *
    01398  */
    01399 static VALUE ossl_ec_point_invert(VALUE self)
    01400 {
    01401     EC_POINT *point;
    01402     VALUE group_v = rb_iv_get(self, "@group");
    01403     const EC_GROUP *group;
    01404
    01405     Require_EC_POINT(self, point);
    01406     SafeRequire_EC_GROUP(group_v, group);
    01407
    01408     if (EC_POINT_invert(group, point, ossl_bn_ctx) != 1)
    01409         ossl_raise(cEC_POINT, "EC_POINT_invert");
    01410
    01411     return self;
    01412 }
    01413
    01414 /*
    01415  *  call-seq:
    01416  *     point.set_to_infinity! => self
    01417  *
    01418  */
    01419 static VALUE ossl_ec_point_set_to_infinity(VALUE self)
    01420 {
    01421     EC_POINT *point;
    01422     VALUE group_v = rb_iv_get(self, "@group");
    01423     const EC_GROUP *group;
    01424
    01425     Require_EC_POINT(self, point);
    01426     SafeRequire_EC_GROUP(group_v, group);
    01427
    01428     if (EC_POINT_set_to_infinity(group, point) != 1)
    01429         ossl_raise(cEC_POINT, "EC_POINT_set_to_infinity");
    01430
    01431     return self;
    01432 }
    01433
    01434 /*
    01435  *  call-seq:
    01436  *     point.to_bn   => OpenSSL::BN
    01437  *
    01438  *  See the OpenSSL documentation for EC_POINT_point2bn()
    01439  */
    01440 static VALUE ossl_ec_point_to_bn(VALUE self)
    01441 {
    01442     EC_POINT *point;
    01443     VALUE bn_obj;
    01444     VALUE group_v = rb_iv_get(self, "@group");
    01445     const EC_GROUP *group;
    01446     point_conversion_form_t form;
    01447     BIGNUM *bn;
    01448
    01449     Require_EC_POINT(self, point);
    01450     SafeRequire_EC_GROUP(group_v, group);
    01451
    01452     form = EC_GROUP_get_point_conversion_form(group);
    01453
    01454     bn_obj = rb_obj_alloc(cBN);
    01455     bn = GetBNPtr(bn_obj);
    01456
    01457     if (EC_POINT_point2bn(group, point, form, bn, ossl_bn_ctx) == NULL)
    01458         ossl_raise(eEC_POINT, "EC_POINT_point2bn");
    01459
    01460     return bn_obj;
    01461 }
    01462
    01463 static void no_copy(VALUE klass)
    01464 {
    01465     rb_undef_method(klass, "copy");
    01466     rb_undef_method(klass, "clone");
    01467     rb_undef_method(klass, "dup");
    01468     rb_undef_method(klass, "initialize_copy");
    01469 }
    01470
    01471 void Init_ossl_ec()
    01472 {
    01473 #ifdef DONT_NEED_RDOC_WORKAROUND
    01474     mOSSL = rb_define_module("OpenSSL");
    01475     mPKey = rb_define_module_under(mOSSL, "PKey");
    01476 #endif
    01477
    01478     eECError = rb_define_class_under(mPKey, "ECError", ePKeyError);
    01479
    01480     cEC = rb_define_class_under(mPKey, "EC", cPKey);
    01481     cEC_GROUP = rb_define_class_under(cEC, "Group", rb_cObject);
    01482     cEC_POINT = rb_define_class_under(cEC, "Point", rb_cObject);
    01483     eEC_GROUP = rb_define_class_under(cEC_GROUP, "Error", eOSSLError);
    01484     eEC_POINT = rb_define_class_under(cEC_POINT, "Error", eOSSLError);
    01485
    01486     s_GFp = rb_intern("GFp");
    01487     s_GF2m = rb_intern("GF2m");
    01488     s_GFp_simple = rb_intern("GFp_simple");
    01489     s_GFp_mont = rb_intern("GFp_mont");
    01490     s_GFp_nist = rb_intern("GFp_nist");
    01491     s_GF2m_simple = rb_intern("GF2m_simple");
    01492
    01493     ID_uncompressed = rb_intern("uncompressed");
    01494     ID_compressed = rb_intern("compressed");
    01495     ID_hybrid = rb_intern("hybrid");
    01496
    01497 #ifdef OPENSSL_EC_NAMED_CURVE
    01498     rb_define_const(cEC, "NAMED_CURVE", ULONG2NUM(OPENSSL_EC_NAMED_CURVE));
    01499 #endif
    01500
    01501     rb_define_singleton_method(cEC, "builtin_curves", ossl_s_builtin_curves, 0);
    01502
    01503     rb_define_method(cEC, "initialize", ossl_ec_key_initialize, -1);
    01504 /* copy/dup/cmp */
    01505
    01506     rb_define_method(cEC, "group", ossl_ec_key_get_group, 0);
    01507     rb_define_method(cEC, "group=", ossl_ec_key_set_group, 1);
    01508     rb_define_method(cEC, "private_key", ossl_ec_key_get_private_key, 0);
    01509     rb_define_method(cEC, "private_key=", ossl_ec_key_set_private_key, 1);
    01510     rb_define_method(cEC, "public_key", ossl_ec_key_get_public_key, 0);
    01511     rb_define_method(cEC, "public_key=", ossl_ec_key_set_public_key, 1);
    01512     rb_define_method(cEC, "private_key?", ossl_ec_key_is_private_key, 0);
    01513     rb_define_method(cEC, "public_key?", ossl_ec_key_is_public_key, 0);
    01514 /*  rb_define_method(cEC, "", ossl_ec_key_get_, 0);
    01515     rb_define_method(cEC, "=", ossl_ec_key_set_ 1);
    01516     set/get enc_flags
    01517     set/get _conv_from
    01518     set/get asn1_flag (can use ruby to call self.group.asn1_flag)
    01519     set/get precompute_mult
    01520 */
    01521     rb_define_method(cEC, "generate_key", ossl_ec_key_generate_key, 0);
    01522     rb_define_method(cEC, "check_key", ossl_ec_key_check_key, 0);
    01523
    01524     rb_define_method(cEC, "dh_compute_key", ossl_ec_key_dh_compute_key, 1);
    01525     rb_define_method(cEC, "dsa_sign_asn1", ossl_ec_key_dsa_sign_asn1, 1);
    01526     rb_define_method(cEC, "dsa_verify_asn1", ossl_ec_key_dsa_verify_asn1, 2);
    01527 /* do_sign/do_verify */
    01528
    01529     rb_define_method(cEC, "to_pem", ossl_ec_key_to_pem, 0);
    01530     rb_define_method(cEC, "to_der", ossl_ec_key_to_der, 0);
    01531     rb_define_method(cEC, "to_text", ossl_ec_key_to_text, 0);
    01532
    01533
    01534     rb_define_alloc_func(cEC_GROUP, ossl_ec_group_alloc);
    01535     rb_define_method(cEC_GROUP, "initialize", ossl_ec_group_initialize, -1);
    01536     rb_define_method(cEC_GROUP, "eql?", ossl_ec_group_eql, 1);
    01537     rb_define_alias(cEC_GROUP, "==", "eql?");
    01538 /* copy/dup/cmp */
    01539
    01540     rb_define_method(cEC_GROUP, "generator", ossl_ec_group_get_generator, 0);
    01541     rb_define_method(cEC_GROUP, "set_generator", ossl_ec_group_set_generator, 3);
    01542     rb_define_method(cEC_GROUP, "order", ossl_ec_group_get_order, 0);
    01543     rb_define_method(cEC_GROUP, "cofactor", ossl_ec_group_get_cofactor, 0);
    01544
    01545     rb_define_method(cEC_GROUP, "curve_name", ossl_ec_group_get_curve_name, 0);
    01546 /*    rb_define_method(cEC_GROUP, "curve_name=", ossl_ec_group_set_curve_name, 1); */
    01547
    01548     rb_define_method(cEC_GROUP, "asn1_flag", ossl_ec_group_get_asn1_flag, 0);
    01549     rb_define_method(cEC_GROUP, "asn1_flag=", ossl_ec_group_set_asn1_flag, 1);
    01550
    01551     rb_define_method(cEC_GROUP, "point_conversion_form", ossl_ec_group_get_point_conversion_form, 0);
    01552     rb_define_method(cEC_GROUP, "point_conversion_form=", ossl_ec_group_set_point_conversion_form, 1);
    01553
    01554     rb_define_method(cEC_GROUP, "seed", ossl_ec_group_get_seed, 0);
    01555     rb_define_method(cEC_GROUP, "seed=", ossl_ec_group_set_seed, 1);
    01556
    01557 /* get/set GFp, GF2m */
    01558
    01559     rb_define_method(cEC_GROUP, "degree", ossl_ec_group_get_degree, 0);
    01560
    01561 /* check* */
    01562
    01563
    01564     rb_define_method(cEC_GROUP, "to_pem", ossl_ec_group_to_pem, 0);
    01565     rb_define_method(cEC_GROUP, "to_der", ossl_ec_group_to_der, 0);
    01566     rb_define_method(cEC_GROUP, "to_text", ossl_ec_group_to_text, 0);
    01567
    01568
    01569     rb_define_alloc_func(cEC_POINT, ossl_ec_point_alloc);
    01570     rb_define_method(cEC_POINT, "initialize", ossl_ec_point_initialize, -1);
    01571     rb_attr(cEC_POINT, rb_intern("group"), 1, 0, 0);
    01572     rb_define_method(cEC_POINT, "eql?", ossl_ec_point_eql, 1);
    01573     rb_define_alias(cEC_POINT, "==", "eql?");
    01574
    01575     rb_define_method(cEC_POINT, "infinity?", ossl_ec_point_is_at_infinity, 0);
    01576     rb_define_method(cEC_POINT, "on_curve?", ossl_ec_point_is_on_curve, 0);
    01577     rb_define_method(cEC_POINT, "make_affine!", ossl_ec_point_make_affine, 0);
    01578     rb_define_method(cEC_POINT, "invert!", ossl_ec_point_invert, 0);
    01579     rb_define_method(cEC_POINT, "set_to_infinity!", ossl_ec_point_set_to_infinity, 0);
    01580 /* all the other methods */
    01581
    01582     rb_define_method(cEC_POINT, "to_bn", ossl_ec_point_to_bn, 0);
    01583
    01584     no_copy(cEC);
    01585     no_copy(cEC_GROUP);
    01586     no_copy(cEC_POINT);
    01587 }
    01588
    01589 #else /* defined NO_EC */
    01590 void Init_ossl_ec()
    01591 {
    01592 }
    01593 #endif /* NO_EC */
    01594