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

Generated on 19 Jul 2016 for Ruby by  doxygen 1.4.7