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