diff options
Diffstat (limited to 'trunk/ext/openssl/ossl_pkey_ec.c')
-rw-r--r-- | trunk/ext/openssl/ossl_pkey_ec.c | 1582 |
1 files changed, 0 insertions, 1582 deletions
diff --git a/trunk/ext/openssl/ossl_pkey_ec.c b/trunk/ext/openssl/ossl_pkey_ec.c deleted file mode 100644 index d4285f2069..0000000000 --- a/trunk/ext/openssl/ossl_pkey_ec.c +++ /dev/null @@ -1,1582 +0,0 @@ -/* - * Copyright (C) 2006-2007 Technorama Ltd. <oss-ruby@technorama.net> - */ - -#include "ossl.h" - -#if !defined(OPENSSL_NO_EC) && (OPENSSL_VERSION_NUMBER >= 0x0090802fL) - -typedef struct { - EC_GROUP *group; - int dont_free; -} ossl_ec_group; - -typedef struct { - EC_POINT *point; - int dont_free; -} ossl_ec_point; - - -#define EXPORT_PEM 0 -#define EXPORT_DER 1 - - -#define GetPKeyEC(obj, pkey) do { \ - GetPKey(obj, pkey); \ - if (EVP_PKEY_type(pkey->type) != EVP_PKEY_EC) { \ - ossl_raise(rb_eRuntimeError, "THIS IS NOT A EC PKEY!"); \ - } \ -} while (0) - -#define SafeGet_ec_group(obj, group) do { \ - OSSL_Check_Kind(obj, cEC_GROUP); \ - Data_Get_Struct(obj, ossl_ec_group, group); \ -} while(0) - -#define Get_EC_KEY(obj, key) do { \ - EVP_PKEY *pkey; \ - GetPKeyEC(obj, pkey); \ - key = pkey->pkey.ec; \ -} while(0) - -#define Require_EC_KEY(obj, key) do { \ - Get_EC_KEY(obj, key); \ - if (key == NULL) \ - rb_raise(eECError, "EC_KEY is not initialized"); \ -} while(0) - -#define SafeRequire_EC_KEY(obj, key) do { \ - OSSL_Check_Kind(obj, cEC); \ - Require_EC_KEY(obj, key); \ -} while (0) - -#define Get_EC_GROUP(obj, g) do { \ - ossl_ec_group *ec_group; \ - Data_Get_Struct(obj, ossl_ec_group, ec_group); \ - if (ec_group == NULL) \ - rb_raise(eEC_GROUP, "missing ossl_ec_group structure"); \ - g = ec_group->group; \ -} while(0) - -#define Require_EC_GROUP(obj, group) do { \ - Get_EC_GROUP(obj, group); \ - if (group == NULL) \ - rb_raise(eEC_GROUP, "EC_GROUP is not initialized"); \ -} while(0) - -#define SafeRequire_EC_GROUP(obj, group) do { \ - OSSL_Check_Kind(obj, cEC_GROUP); \ - Require_EC_GROUP(obj, group); \ -} while(0) - -#define Get_EC_POINT(obj, p) do { \ - ossl_ec_point *ec_point; \ - Data_Get_Struct(obj, ossl_ec_point, ec_point); \ - if (ec_point == NULL) \ - rb_raise(eEC_POINT, "missing ossl_ec_point structure"); \ - p = ec_point->point; \ -} while(0) - -#define Require_EC_POINT(obj, point) do { \ - Get_EC_POINT(obj, point); \ - if (point == NULL) \ - rb_raise(eEC_POINT, "EC_POINT is not initialized"); \ -} while(0) - -#define SafeRequire_EC_POINT(obj, point) do { \ - OSSL_Check_Kind(obj, cEC_POINT); \ - Require_EC_POINT(obj, point); \ -} while(0) - -VALUE cEC; -VALUE eECError; -VALUE cEC_GROUP; -VALUE eEC_GROUP; -VALUE cEC_POINT; -VALUE eEC_POINT; - -static ID s_GFp; -static ID s_GFp_simple; -static ID s_GFp_mont; -static ID s_GFp_nist; -static ID s_GF2m; -static ID s_GF2m_simple; - -static ID ID_uncompressed; -static ID ID_compressed; -static ID ID_hybrid; - -static VALUE ec_instance(VALUE klass, EC_KEY *ec) -{ - EVP_PKEY *pkey; - VALUE obj; - - if (!ec) { - return Qfalse; - } - if (!(pkey = EVP_PKEY_new())) { - return Qfalse; - } - if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) { - EVP_PKEY_free(pkey); - return Qfalse; - } - WrapPKey(klass, obj, pkey); - - return obj; -} - -VALUE ossl_ec_new(EVP_PKEY *pkey) -{ - VALUE obj; - - if (!pkey) { - obj = ec_instance(cEC, EC_KEY_new()); - } else { - if (EVP_PKEY_type(pkey->type) != EVP_PKEY_EC) { - ossl_raise(rb_eTypeError, "Not a EC key!"); - } - WrapPKey(cEC, obj, pkey); - } - if (obj == Qfalse) { - ossl_raise(eECError, NULL); - } - - return obj; -} - - -/* call-seq: - * OpenSSL::PKey::EC.new() - * OpenSSL::PKey::EC.new(ec_key) - * OpenSSL::PKey::EC.new(ec_group) - * OpenSSL::PKey::EC.new("secp112r1") - * OpenSSL::PKey::EC.new(pem_string) - * OpenSSL::PKey::EC.new(der_string) - * - * See the OpenSSL documentation for: - * EC_KEY_* - */ -static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self) -{ - EVP_PKEY *pkey; - EC_KEY *ec = NULL; - VALUE arg, pass; - VALUE group = Qnil; - - GetPKey(self, pkey); - if (pkey->pkey.ec) - rb_raise(eECError, "EC_KEY already initialized"); - - rb_scan_args(argc, argv, "02", &arg, &pass); - - if (NIL_P(arg)) { - ec = EC_KEY_new(); - } else { - if (rb_obj_is_kind_of(arg, cEC)) { - EC_KEY *other_ec = NULL; - - SafeRequire_EC_KEY(arg, other_ec); - ec = EC_KEY_dup(other_ec); - } else if (rb_obj_is_kind_of(arg, cEC_GROUP)) { - ec = EC_KEY_new(); - group = arg; - } else { - BIO *in = ossl_obj2bio(arg); - - ec = PEM_read_bio_ECPrivateKey(in, NULL, NULL, NULL); - if (!ec) { - (void)BIO_reset(in); - ec = PEM_read_bio_EC_PUBKEY(in, NULL, NULL, NULL); - } - if (!ec) { - (void)BIO_reset(in); - ec = d2i_ECPrivateKey_bio(in, NULL); - } - if (!ec) { - (void)BIO_reset(in); - ec = d2i_EC_PUBKEY_bio(in, NULL); - } - - BIO_free(in); - - if (ec == NULL) { - const char *name = STR2CSTR(arg); - int nid = OBJ_sn2nid(name); - - if (nid == NID_undef) - ossl_raise(eECError, "unknown curve name (%s)\n", name); - - if ((ec = EC_KEY_new_by_curve_name(nid)) == NULL) - ossl_raise(eECError, "unable to create curve (%s)\n", name); - - EC_KEY_set_asn1_flag(ec, OPENSSL_EC_NAMED_CURVE); - EC_KEY_set_conv_form(ec, POINT_CONVERSION_UNCOMPRESSED); - } - } - } - - if (ec == NULL) - ossl_raise(eECError, NULL); - - if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) { - EC_KEY_free(ec); - ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY"); - } - - rb_iv_set(self, "@group", Qnil); - - if (!NIL_P(group)) - rb_funcall(self, rb_intern("group="), 1, arg); - - return self; -} - -/* - * call-seq: - * key.group => group - * - * Returns a constant <code>OpenSSL::EC::Group</code> that is tied to the key. - * Modifying the returned group can make the key invalid. - */ -static VALUE ossl_ec_key_get_group(VALUE self) -{ - VALUE group_v; - EC_KEY *ec; - ossl_ec_group *ec_group; - EC_GROUP *group; - - Require_EC_KEY(self, ec); - - group_v = rb_iv_get(self, "@group"); - if (!NIL_P(group_v)) - return group_v; - - if ((group = (EC_GROUP *)EC_KEY_get0_group(ec)) != NULL) { - group_v = rb_obj_alloc(cEC_GROUP); - SafeGet_ec_group(group_v, ec_group); - ec_group->group = group; - ec_group->dont_free = 1; - rb_iv_set(group_v, "@key", self); - rb_iv_set(self, "@group", group_v); - return group_v; - } - - return Qnil; -} - -/* - * call-seq: - * key.group = group => group - * - * Returns the same object passed, not the group object associated with the key. - * If you wish to access the group object tied to the key call key.group after setting - * the group. - * - * Setting the group will immediately destroy any previously assigned group object. - * The group is internally copied by OpenSSL. Modifying the original group after - * assignment will not effect the internal key structure. - * (your changes may be lost). BE CAREFUL. - * - * EC_KEY_set_group calls EC_GROUP_free(key->group) then EC_GROUP_dup(), not EC_GROUP_copy. - * This documentation is accurate for OpenSSL 0.9.8b. - */ -static VALUE ossl_ec_key_set_group(VALUE self, VALUE group_v) -{ - VALUE old_group_v; - EC_KEY *ec; - EC_GROUP *group; - - Require_EC_KEY(self, ec); - SafeRequire_EC_GROUP(group_v, group); - - old_group_v = rb_iv_get(self, "@group"); - if (!NIL_P(old_group_v)) { - ossl_ec_group *old_ec_group; - SafeGet_ec_group(old_group_v, old_ec_group); - - old_ec_group->group = NULL; - old_ec_group->dont_free = 0; - rb_iv_set(old_group_v, "@key", Qnil); - } - - rb_iv_set(self, "@group", Qnil); - - if (EC_KEY_set_group(ec, group) != 1) - ossl_raise(eECError, "EC_KEY_set_group"); - - return group_v; -} - -/* - * call-seq: - * key.private_key => OpenSSL::BN - * - * See the OpenSSL documentation for EC_KEY_get0_private_key() - */ -static VALUE ossl_ec_key_get_private_key(VALUE self) -{ - EC_KEY *ec; - const BIGNUM *bn; - - Require_EC_KEY(self, ec); - - if ((bn = EC_KEY_get0_private_key(ec)) == NULL) - return Qnil; - - return ossl_bn_new(bn); -} - -/* - * call-seq: - * key.private_key = openssl_bn - * - * See the OpenSSL documentation for EC_KEY_set_private_key() - */ -static VALUE ossl_ec_key_set_private_key(VALUE self, VALUE private_key) -{ - EC_KEY *ec; - BIGNUM *bn = NULL; - - Require_EC_KEY(self, ec); - if (!NIL_P(private_key)) - bn = GetBNPtr(private_key); - - switch (EC_KEY_set_private_key(ec, bn)) { - case 1: - break; - case 0: - if (bn == NULL) - break; - default: - ossl_raise(eECError, "EC_KEY_set_private_key"); - } - - return private_key; -} - - -static VALUE ossl_ec_point_dup(const EC_POINT *point, VALUE group_v) -{ - VALUE obj; - const EC_GROUP *group; - ossl_ec_point *new_point; - - obj = rb_obj_alloc(cEC_POINT); - Data_Get_Struct(obj, ossl_ec_point, new_point); - - SafeRequire_EC_GROUP(group_v, group); - - new_point->point = EC_POINT_dup(point, group); - if (new_point->point == NULL) - ossl_raise(eEC_POINT, "EC_POINT_dup"); - rb_iv_set(obj, "@group", group_v); - - return obj; -} - -/* - * call-seq: - * key.public_key => OpenSSL::PKey::EC::Point - * - * See the OpenSSL documentation for EC_KEY_get0_public_key() - */ -static VALUE ossl_ec_key_get_public_key(VALUE self) -{ - EC_KEY *ec; - const EC_POINT *point; - VALUE group; - - Require_EC_KEY(self, ec); - - if ((point = EC_KEY_get0_public_key(ec)) == NULL) - return Qnil; - - group = rb_funcall(self, rb_intern("group"), 0); - if (NIL_P(group)) - ossl_raise(eECError, "EC_KEY_get0_get0_group (has public_key but no group???"); - - return ossl_ec_point_dup(point, group); -} - -/* - * call-seq: - * key.public_key = ec_point - * - * See the OpenSSL documentation for EC_KEY_set_public_key() - */ -static VALUE ossl_ec_key_set_public_key(VALUE self, VALUE public_key) -{ - EC_KEY *ec; - EC_POINT *point = NULL; - - Require_EC_KEY(self, ec); - if (!NIL_P(public_key)) - SafeRequire_EC_POINT(public_key, point); - - switch (EC_KEY_set_public_key(ec, point)) { - case 1: - break; - case 0: - if (point == NULL) - break; - default: - ossl_raise(eECError, "EC_KEY_set_public_key"); - } - - return public_key; -} - -/* - * call-seq: - * key.public_key? => true or false - * - * Both public_key? and private_key? may return false at the same time unlike other PKey classes. - */ -static VALUE ossl_ec_key_is_public_key(VALUE self) -{ - EC_KEY *ec; - - Require_EC_KEY(self, ec); - - return (EC_KEY_get0_public_key(ec) ? Qtrue : Qfalse); -} - -/* - * call-seq: - * key.private_key? => true or false - * - * Both public_key? and private_key? may return false at the same time unlike other PKey classes. - */ -static VALUE ossl_ec_key_is_private_key(VALUE self) -{ - EC_KEY *ec; - - Require_EC_KEY(self, ec); - - return (EC_KEY_get0_private_key(ec) ? Qtrue : Qfalse); -} - -static VALUE ossl_ec_key_to_string(VALUE self, int format) -{ - EC_KEY *ec; - BIO *out; - int i = -1; - int private = 0; - EVP_CIPHER *cipher = NULL; - char *password = NULL; - VALUE str; - - Require_EC_KEY(self, ec); - - if (EC_KEY_get0_public_key(ec) == NULL) - rb_raise(eECError, "can't export - no public key set"); - - if (EC_KEY_check_key(ec) != 1) - ossl_raise(eECError, "can't export - EC_KEY_check_key failed"); - - if (EC_KEY_get0_private_key(ec)) - private = 1; - - if (!(out = BIO_new(BIO_s_mem()))) - ossl_raise(eECError, "BIO_new(BIO_s_mem())"); - - switch(format) { - case EXPORT_PEM: - if (private) { - if (cipher || password) -/* BUG: finish cipher/password key export */ - rb_notimplement(); - i = PEM_write_bio_ECPrivateKey(out, ec, cipher, NULL, 0, NULL, password); - } else { - if (cipher || password) - rb_raise(rb_eArgError, "encryption is not supported when exporting this key type"); - - i = PEM_write_bio_EC_PUBKEY(out, ec); - } - - break; - case EXPORT_DER: - if (private) { - if (cipher || password) - rb_raise(rb_eArgError, "encryption is not supported when exporting this key type"); - - i = i2d_ECPrivateKey_bio(out, ec); - } else { - if (cipher || password) - rb_raise(rb_eArgError, "encryption is not supported when exporting this key type"); - - i = i2d_EC_PUBKEY_bio(out, ec); - } - - break; - default: - BIO_free(out); - rb_raise(rb_eRuntimeError, "unknown format (internal error)"); - } - - if (i != 1) { - BIO_free(out); - ossl_raise(eECError, "outlen=%d", i); - } - - str = ossl_membio2str(out); - - return str; -} - -/* - * call-seq: - * key.to_pem => String - * - * See the OpenSSL documentation for PEM_write_bio_ECPrivateKey() - */ -static VALUE ossl_ec_key_to_pem(VALUE self) -{ - return ossl_ec_key_to_string(self, EXPORT_PEM); -} - -/* - * call-seq: - * key.to_der => String - * - * See the OpenSSL documentation for i2d_ECPrivateKey_bio() - */ -static VALUE ossl_ec_key_to_der(VALUE self) -{ - return ossl_ec_key_to_string(self, EXPORT_DER); -} - -/* - * call-seq: - * key.to_text => String - * - * See the OpenSSL documentation for EC_KEY_print() - */ -static VALUE ossl_ec_key_to_text(VALUE self) -{ - EC_KEY *ec; - BIO *out; - VALUE str; - - Require_EC_KEY(self, ec); - if (!(out = BIO_new(BIO_s_mem()))) { - ossl_raise(eECError, "BIO_new(BIO_s_mem())"); - } - if (!EC_KEY_print(out, ec, 0)) { - BIO_free(out); - ossl_raise(eECError, "EC_KEY_print"); - } - str = ossl_membio2str(out); - - return str; -} - -/* - * call-seq: - * key.generate_key => self - * - * See the OpenSSL documentation for EC_KEY_generate_key() - */ -static VALUE ossl_ec_key_generate_key(VALUE self) -{ - EC_KEY *ec; - - Require_EC_KEY(self, ec); - - if (EC_KEY_generate_key(ec) != 1) - ossl_raise(eECError, "EC_KEY_generate_key"); - - return self; -} - -/* - * call-seq: - * key.check_key => true - * - * Raises an exception if the key is invalid. - * - * See the OpenSSL documentation for EC_KEY_check_key() - */ -static VALUE ossl_ec_key_check_key(VALUE self) -{ - EC_KEY *ec; - - Require_EC_KEY(self, ec); - - if (EC_KEY_check_key(ec) != 1) - ossl_raise(eECError, "EC_KEY_check_key"); - - return Qtrue; -} - -/* - * call-seq: - * key.dh_compute_key(pubkey) => String - * - * See the OpenSSL documentation for ECDH_compute_key() - */ -static VALUE ossl_ec_key_dh_compute_key(VALUE self, VALUE pubkey) -{ - EC_KEY *ec; - EC_POINT *point; - int buf_len; - VALUE str; - - Require_EC_KEY(self, ec); - SafeRequire_EC_POINT(pubkey, point); - -/* BUG: need a way to figure out the maximum string size */ - buf_len = 1024; - str = rb_str_new(0, buf_len); -/* BUG: take KDF as a block */ - buf_len = ECDH_compute_key(RSTRING_PTR(str), buf_len, point, ec, NULL); - if (buf_len < 0) - ossl_raise(eECError, "ECDH_compute_key"); - - rb_str_resize(str, buf_len); - - return str; -} - -/* sign_setup */ - -/* - * call-seq: - * key.dsa_sign_asn1(data) => String - * - * See the OpenSSL documentation for ECDSA_sign() - */ -static VALUE ossl_ec_key_dsa_sign_asn1(VALUE self, VALUE data) -{ - EC_KEY *ec; - unsigned int buf_len; - VALUE str; - - Require_EC_KEY(self, ec); - StringValue(data); - - if (EC_KEY_get0_private_key(ec) == NULL) - ossl_raise(eECError, "Private EC key needed!"); - - str = rb_str_new(0, ECDSA_size(ec) + 16); - if (ECDSA_sign(0, (unsigned char *) RSTRING_PTR(data), RSTRING_LEN(data), (unsigned char *) RSTRING_PTR(str), &buf_len, ec) != 1) - ossl_raise(eECError, "ECDSA_sign"); - - rb_str_resize(str, buf_len); - - return str; -} - -/* - * call-seq: - * key.dsa_verify(data, sig) => true or false - * - * See the OpenSSL documentation for ECDSA_verify() - */ -static VALUE ossl_ec_key_dsa_verify_asn1(VALUE self, VALUE data, VALUE sig) -{ - EC_KEY *ec; - - Require_EC_KEY(self, ec); - StringValue(data); - StringValue(sig); - - switch (ECDSA_verify(0, (unsigned char *) RSTRING_PTR(data), RSTRING_LEN(data), (unsigned char *) RSTRING_PTR(sig), RSTRING_LEN(sig), ec)) { - case 1: return Qtrue; - case 0: return Qfalse; - default: break; - } - - ossl_raise(eECError, "ECDSA_verify"); -} - -static void ossl_ec_group_free(ossl_ec_group *ec_group) -{ - if (!ec_group->dont_free && ec_group->group) - EC_GROUP_clear_free(ec_group->group); - ruby_xfree(ec_group); -} - -static VALUE ossl_ec_group_alloc(VALUE klass) -{ - ossl_ec_group *ec_group; - VALUE obj; - - obj = Data_Make_Struct(klass, ossl_ec_group, 0, ossl_ec_group_free, ec_group); - - return obj; -} - -/* call-seq: - * OpenSSL::PKey::EC::Group.new("secp112r1") - * OpenSSL::PKey::EC::Group.new(ec_group) - * OpenSSL::PKey::EC::Group.new(pem_string) - * OpenSSL::PKey::EC::Group.new(der_string) - * OpenSSL::PKey::EC::Group.new(pem_file) - * OpenSSL::PKey::EC::Group.new(der_file) - * OpenSSL::PKey::EC::Group.new(:GFp_simple) - * OpenSSL::PKey::EC::Group.new(:GFp_mult) - * OpenSSL::PKey::EC::Group.new(:GFp_nist) - * OpenSSL::PKey::EC::Group.new(:GF2m_simple) - * OpenSSL::PKey::EC::Group.new(:GFp, bignum_p, bignum_a, bignum_b) - * OpenSSL::PKey::EC::Group.new(:GF2m, bignum_p, bignum_a, bignum_b) - * - * See the OpenSSL documentation for EC_GROUP_* - */ -static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self) -{ - VALUE arg1, arg2, arg3, arg4; - ossl_ec_group *ec_group; - EC_GROUP *group = NULL; - - Data_Get_Struct(self, ossl_ec_group, ec_group); - if (ec_group->group != NULL) - rb_raise(rb_eRuntimeError, "EC_GROUP is already initialized"); - - switch (rb_scan_args(argc, argv, "13", &arg1, &arg2, &arg3, &arg4)) { - case 1: - if (SYMBOL_P(arg1)) { - const EC_METHOD *method = NULL; - ID id = SYM2ID(arg1); - - if (id == s_GFp_simple) { - method = EC_GFp_simple_method(); - } else if (id == s_GFp_mont) { - method = EC_GFp_mont_method(); - } else if (id == s_GFp_nist) { - method = EC_GFp_nist_method(); - } else if (id == s_GF2m_simple) { - method = EC_GF2m_simple_method(); - } - - if (method) { - if ((group = EC_GROUP_new(method)) == NULL) - ossl_raise(eEC_GROUP, "EC_GROUP_new"); - } else { - rb_raise(rb_eArgError, "unknown symbol, must be :GFp_simple, :GFp_mont, :GFp_nist or :GF2m_simple"); - } - } else if (rb_obj_is_kind_of(arg1, cEC_GROUP)) { - const EC_GROUP *arg1_group; - - SafeRequire_EC_GROUP(arg1, arg1_group); - if ((group = EC_GROUP_dup(arg1_group)) == NULL) - ossl_raise(eEC_GROUP, "EC_GROUP_dup"); - } else { - BIO *in = ossl_obj2bio(arg1); - - group = PEM_read_bio_ECPKParameters(in, NULL, NULL, NULL); - if (!group) { - (void)BIO_reset(in); - group = d2i_ECPKParameters_bio(in, NULL); - } - - BIO_free(in); - - if (!group) { - const char *name = STR2CSTR(arg1); - int nid = OBJ_sn2nid(name); - - if (nid == NID_undef) - ossl_raise(eEC_GROUP, "unknown curve name (%s)", name); - - group = EC_GROUP_new_by_curve_name(nid); - if (group == NULL) - ossl_raise(eEC_GROUP, "unable to create curve (%s)", name); - - EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE); - EC_GROUP_set_point_conversion_form(group, POINT_CONVERSION_UNCOMPRESSED); - } - } - - break; - case 4: - if (SYMBOL_P(arg1)) { - ID id = SYM2ID(arg1); - EC_GROUP *(*new_curve)(const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *) = NULL; - const BIGNUM *p = GetBNPtr(arg2); - const BIGNUM *a = GetBNPtr(arg3); - const BIGNUM *b = GetBNPtr(arg4); - - if (id == s_GFp) { - new_curve = EC_GROUP_new_curve_GFp; - } else if (id == s_GF2m) { - new_curve = EC_GROUP_new_curve_GF2m; - } else { - rb_raise(rb_eArgError, "unknown symbol, must be :GFp or :GF2m"); - } - - if ((group = new_curve(p, a, b, ossl_bn_ctx)) == NULL) - ossl_raise(eEC_GROUP, "EC_GROUP_new_by_GF*"); - } else { - rb_raise(rb_eArgError, "unknown argument, must be :GFp or :GF2m"); - } - - break; - default: - rb_raise(rb_eArgError, "wrong number of arguments"); - } - - if (group == NULL) - ossl_raise(eEC_GROUP, ""); - - ec_group->group = group; - - return self; -} - -/* call-seq: - * group1 == group2 => true | false - * - */ -static VALUE ossl_ec_group_eql(VALUE a, VALUE b) -{ - EC_GROUP *group1 = NULL, *group2 = NULL; - - Require_EC_GROUP(a, group1); - SafeRequire_EC_GROUP(b, group2); - - if (EC_GROUP_cmp(group1, group2, ossl_bn_ctx) == 1) - return Qfalse; - - return Qtrue; -} - -/* call-seq: - * group.generator => ec_point - * - * See the OpenSSL documentation for EC_GROUP_get0_generator() - */ -static VALUE ossl_ec_group_get_generator(VALUE self) -{ - VALUE point_obj; - EC_GROUP *group = NULL; - - Require_EC_GROUP(self, group); - - point_obj = ossl_ec_point_dup(EC_GROUP_get0_generator(group), self); - - return point_obj; -} - -/* call-seq: - * group.set_generator(generator, order, cofactor) => self - * - * See the OpenSSL documentation for EC_GROUP_set_generator() - */ -static VALUE ossl_ec_group_set_generator(VALUE self, VALUE generator, VALUE order, VALUE cofactor) -{ - EC_GROUP *group = NULL; - const EC_POINT *point; - const BIGNUM *o, *co; - - Require_EC_GROUP(self, group); - SafeRequire_EC_POINT(generator, point); - o = GetBNPtr(order); - co = GetBNPtr(cofactor); - - if (EC_GROUP_set_generator(group, point, o, co) != 1) - ossl_raise(eEC_GROUP, "EC_GROUP_set_generator"); - - return self; -} - -/* call-seq: - * group.get_order => order_bn - * - * See the OpenSSL documentation for EC_GROUP_get_order() - */ -static VALUE ossl_ec_group_get_order(VALUE self) -{ - VALUE bn_obj; - BIGNUM *bn; - EC_GROUP *group = NULL; - - Require_EC_GROUP(self, group); - - bn_obj = ossl_bn_new(NULL); - bn = GetBNPtr(bn_obj); - - if (EC_GROUP_get_order(group, bn, ossl_bn_ctx) != 1) - ossl_raise(eEC_GROUP, "EC_GROUP_get_order"); - - return bn_obj; -} - -/* call-seq: - * group.get_cofactor => cofactor_bn - * - * See the OpenSSL documentation for EC_GROUP_get_cofactor() - */ -static VALUE ossl_ec_group_get_cofactor(VALUE self) -{ - VALUE bn_obj; - BIGNUM *bn; - EC_GROUP *group = NULL; - - Require_EC_GROUP(self, group); - - bn_obj = ossl_bn_new(NULL); - bn = GetBNPtr(bn_obj); - - if (EC_GROUP_get_cofactor(group, bn, ossl_bn_ctx) != 1) - ossl_raise(eEC_GROUP, "EC_GROUP_get_cofactor"); - - return bn_obj; -} - -/* call-seq: - * group.curve_name => String - * - * See the OpenSSL documentation for EC_GROUP_get_curve_name() - */ -static VALUE ossl_ec_group_get_curve_name(VALUE self) -{ - EC_GROUP *group = NULL; - int nid; - - Get_EC_GROUP(self, group); - if (group == NULL) - return Qnil; - - nid = EC_GROUP_get_curve_name(group); - -/* BUG: an nid or asn1 object should be returned, maybe. */ - return rb_str_new2(OBJ_nid2sn(nid)); -} - -/* call-seq: - * EC.builtin_curves => [[name, comment], ...] - * - * See the OpenSSL documentation for EC_builtin_curves() - */ -static VALUE ossl_s_builtin_curves(VALUE self) -{ - EC_builtin_curve *curves = NULL; - int n; - int crv_len = EC_get_builtin_curves(NULL, 0); - VALUE ary, ret; - - curves = ALLOCA_N(EC_builtin_curve, crv_len); - if (curves == NULL) - return Qnil; - if (!EC_get_builtin_curves(curves, crv_len)) - ossl_raise(rb_eRuntimeError, "EC_get_builtin_curves"); - - ret = rb_ary_new2(crv_len); - - for (n = 0; n < crv_len; n++) { - const char *sname = OBJ_nid2sn(curves[n].nid); - const char *comment = curves[n].comment; - - ary = rb_ary_new2(2); - rb_ary_push(ary, rb_str_new2(sname)); - rb_ary_push(ary, comment ? rb_str_new2(comment) : Qnil); - rb_ary_push(ret, ary); - } - - return ret; -} - -/* call-seq: - * group.asn1_flag => Fixnum - * - * See the OpenSSL documentation for EC_GROUP_get_asn1_flag() - */ -static VALUE ossl_ec_group_get_asn1_flag(VALUE self) -{ - EC_GROUP *group = NULL; - int flag; - - Require_EC_GROUP(self, group); - - flag = EC_GROUP_get_asn1_flag(group); - - return INT2FIX(flag); -} - -/* call-seq: - * group.asn1_flag = Fixnum => Fixnum - * - * See the OpenSSL documentation for EC_GROUP_set_asn1_flag() - */ -static VALUE ossl_ec_group_set_asn1_flag(VALUE self, VALUE flag_v) -{ - EC_GROUP *group = NULL; - - Require_EC_GROUP(self, group); - - EC_GROUP_set_asn1_flag(group, NUM2INT(flag_v)); - - return flag_v; -} - -/* call-seq: - * group.point_conversion_form => :uncompressed | :compressed | :hybrid - * - * See the OpenSSL documentation for EC_GROUP_get_point_conversion_form() - */ -static VALUE ossl_ec_group_get_point_conversion_form(VALUE self) -{ - EC_GROUP *group = NULL; - point_conversion_form_t form; - VALUE ret; - - Require_EC_GROUP(self, group); - - form = EC_GROUP_get_point_conversion_form(group); - - switch (form) { - case POINT_CONVERSION_UNCOMPRESSED: ret = ID_uncompressed; break; - case POINT_CONVERSION_COMPRESSED: ret = ID_compressed; break; - case POINT_CONVERSION_HYBRID: ret = ID_hybrid; break; - default: rb_raise(eEC_GROUP, "unsupported point conversion form: %d, this module should be updated", form); - } - - return ID2SYM(ret); -} - -/* call-seq: - * group.point_conversion_form = form => form - * - * See the OpenSSL documentation for EC_GROUP_set_point_conversion_form() - */ -static VALUE ossl_ec_group_set_point_conversion_form(VALUE self, VALUE form_v) -{ - EC_GROUP *group = NULL; - point_conversion_form_t form; - ID form_id = SYM2ID(form_v); - - Require_EC_GROUP(self, group); - - if (form_id == ID_uncompressed) { - form = POINT_CONVERSION_UNCOMPRESSED; - } else if (form_id == ID_compressed) { - form = POINT_CONVERSION_COMPRESSED; - } else if (form_id == ID_hybrid) { - form = POINT_CONVERSION_HYBRID; - } else { - rb_raise(rb_eArgError, "form must be :compressed, :uncompressed, or :hybrid"); - } - - EC_GROUP_set_point_conversion_form(group, form); - - return form_v; -} - -/* call-seq: - * group.seed => String or nil - * - * See the OpenSSL documentation for EC_GROUP_get0_seed() - */ -static VALUE ossl_ec_group_get_seed(VALUE self) -{ - EC_GROUP *group = NULL; - size_t seed_len; - - Require_EC_GROUP(self, group); - - seed_len = EC_GROUP_get_seed_len(group); - - if (seed_len == 0) - return Qnil; - - return rb_str_new((const char *)EC_GROUP_get0_seed(group), seed_len); -} - -/* call-seq: - * group.seed = seed => seed - * - * See the OpenSSL documentation for EC_GROUP_set_seed() - */ -static VALUE ossl_ec_group_set_seed(VALUE self, VALUE seed) -{ - EC_GROUP *group = NULL; - - Require_EC_GROUP(self, group); - StringValue(seed); - - if (EC_GROUP_set_seed(group, (unsigned char *)RSTRING_PTR(seed), RSTRING_LEN(seed)) != RSTRING_LEN(seed)) - ossl_raise(eEC_GROUP, "EC_GROUP_set_seed"); - - return seed; -} - -/* get/set curve GFp, GF2m */ - -/* call-seq: - * group.degree => Fixnum - * - * See the OpenSSL documentation for EC_GROUP_get_degree() - */ -static VALUE ossl_ec_group_get_degree(VALUE self) -{ - EC_GROUP *group = NULL; - - Require_EC_GROUP(self, group); - - return INT2NUM(EC_GROUP_get_degree(group)); -} - -static VALUE ossl_ec_group_to_string(VALUE self, int format) -{ - EC_GROUP *group; - BIO *out; - int i = -1; - VALUE str; - - Get_EC_GROUP(self, group); - - if (!(out = BIO_new(BIO_s_mem()))) - ossl_raise(eEC_GROUP, "BIO_new(BIO_s_mem())"); - - switch(format) { - case EXPORT_PEM: - i = PEM_write_bio_ECPKParameters(out, group); - break; - case EXPORT_DER: - i = i2d_ECPKParameters_bio(out, group); - break; - default: - BIO_free(out); - rb_raise(rb_eRuntimeError, "unknown format (internal error)"); - } - - if (i != 1) { - BIO_free(out); - ossl_raise(eECError, NULL); - } - - str = ossl_membio2str(out); - - return str; -} - -/* call-seq: - * group.to_pem => String - * - * See the OpenSSL documentation for PEM_write_bio_ECPKParameters() - */ -static VALUE ossl_ec_group_to_pem(VALUE self) -{ - return ossl_ec_group_to_string(self, EXPORT_PEM); -} - -/* call-seq: - * group.to_der => String - * - * See the OpenSSL documentation for i2d_ECPKParameters_bio() - */ -static VALUE ossl_ec_group_to_der(VALUE self) -{ - return ossl_ec_group_to_string(self, EXPORT_DER); -} - -/* call-seq: - * group.to_text => String - * - * See the OpenSSL documentation for ECPKParameters_print() - */ -static VALUE ossl_ec_group_to_text(VALUE self) -{ - EC_GROUP *group; - BIO *out; - VALUE str; - - Require_EC_GROUP(self, group); - if (!(out = BIO_new(BIO_s_mem()))) { - ossl_raise(eEC_GROUP, "BIO_new(BIO_s_mem())"); - } - if (!ECPKParameters_print(out, group, 0)) { - BIO_free(out); - ossl_raise(eEC_GROUP, NULL); - } - str = ossl_membio2str(out); - - return str; -} - - -static void ossl_ec_point_free(ossl_ec_point *ec_point) -{ - if (!ec_point->dont_free && ec_point->point) - EC_POINT_clear_free(ec_point->point); - ruby_xfree(ec_point); -} - -static VALUE ossl_ec_point_alloc(VALUE klass) -{ - ossl_ec_point *ec_point; - VALUE obj; - - obj = Data_Make_Struct(klass, ossl_ec_point, 0, ossl_ec_point_free, ec_point); - - return obj; -} - -/* - * call-seq: - * OpenSSL::PKey::EC::Point.new(point) - * OpenSSL::PKey::EC::Point.new(group) - * OpenSSL::PKey::EC::Point.new(group, bn) - * - * See the OpenSSL documentation for EC_POINT_* - */ -static VALUE ossl_ec_point_initialize(int argc, VALUE *argv, VALUE self) -{ - ossl_ec_point *ec_point; - EC_POINT *point = NULL; - VALUE arg1, arg2; - VALUE group_v = Qnil; - const EC_GROUP *group = NULL; - - Data_Get_Struct(self, ossl_ec_point, ec_point); - if (ec_point->point) - rb_raise(eEC_POINT, "EC_POINT already initialized"); - - switch (rb_scan_args(argc, argv, "11", &arg1, &arg2)) { - case 1: - if (rb_obj_is_kind_of(arg1, cEC_POINT)) { - const EC_POINT *arg_point; - - group_v = rb_iv_get(arg1, "@group"); - SafeRequire_EC_GROUP(group_v, group); - SafeRequire_EC_POINT(arg1, arg_point); - - point = EC_POINT_dup(arg_point, group); - } else if (rb_obj_is_kind_of(arg1, cEC_GROUP)) { - group_v = arg1; - SafeRequire_EC_GROUP(group_v, group); - - point = EC_POINT_new(group); - } else { - rb_raise(eEC_POINT, "wrong argument type: must be OpenSSL::PKey::EC::Point or OpenSSL::Pkey::EC::Group"); - } - - break; - case 2: - if (!rb_obj_is_kind_of(arg1, cEC_GROUP)) - rb_raise(rb_eArgError, "1st argument must be OpenSSL::PKey::EC::Group"); - group_v = arg1; - SafeRequire_EC_GROUP(group_v, group); - - if (rb_obj_is_kind_of(arg2, cBN)) { - const BIGNUM *bn = GetBNPtr(arg2); - - point = EC_POINT_bn2point(group, bn, NULL, ossl_bn_ctx); - } else { - BIO *in = ossl_obj2bio(arg1); - -/* BUG: finish me */ - - BIO_free(in); - - if (point == NULL) { - ossl_raise(eEC_POINT, "unknown type for 2nd arg"); - } - } - break; - default: - rb_raise(rb_eArgError, "wrong number of arguments"); - } - - if (point == NULL) - ossl_raise(eEC_POINT, NULL); - - if (NIL_P(group_v)) - rb_raise(rb_eRuntimeError, "missing group (internal error)"); - - ec_point->point = point; - - rb_iv_set(self, "@group", group_v); - - return self; -} - -/* - * call-seq: - * point1 == point2 => true | false - * - */ -static VALUE ossl_ec_point_eql(VALUE a, VALUE b) -{ - EC_POINT *point1, *point2; - VALUE group_v1 = rb_iv_get(a, "@group"); - VALUE group_v2 = rb_iv_get(b, "@group"); - const EC_GROUP *group; - - if (ossl_ec_group_eql(group_v1, group_v2) == Qfalse) - return Qfalse; - - Require_EC_POINT(a, point1); - SafeRequire_EC_POINT(b, point2); - SafeRequire_EC_GROUP(group_v1, group); - - if (EC_POINT_cmp(group, point1, point2, ossl_bn_ctx) == 1) - return Qfalse; - - return Qtrue; -} - -/* - * call-seq: - * point.infinity? => true | false - * - */ -static VALUE ossl_ec_point_is_at_infinity(VALUE self) -{ - EC_POINT *point; - VALUE group_v = rb_iv_get(self, "@group"); - const EC_GROUP *group; - - Require_EC_POINT(self, point); - SafeRequire_EC_GROUP(group_v, group); - - switch (EC_POINT_is_at_infinity(group, point)) { - case 1: return Qtrue; - case 0: return Qfalse; - default: ossl_raise(cEC_POINT, "EC_POINT_is_at_infinity"); - } -} - -/* - * call-seq: - * point.on_curve? => true | false - * - */ -static VALUE ossl_ec_point_is_on_curve(VALUE self) -{ - EC_POINT *point; - VALUE group_v = rb_iv_get(self, "@group"); - const EC_GROUP *group; - - Require_EC_POINT(self, point); - SafeRequire_EC_GROUP(group_v, group); - - switch (EC_POINT_is_on_curve(group, point, ossl_bn_ctx)) { - case 1: return Qtrue; - case 0: return Qfalse; - default: ossl_raise(cEC_POINT, "EC_POINT_is_on_curve"); - } -} - -/* - * call-seq: - * point.make_affine! => self - * - */ -static VALUE ossl_ec_point_make_affine(VALUE self) -{ - EC_POINT *point; - VALUE group_v = rb_iv_get(self, "@group"); - const EC_GROUP *group; - - Require_EC_POINT(self, point); - SafeRequire_EC_GROUP(group_v, group); - - if (EC_POINT_make_affine(group, point, ossl_bn_ctx) != 1) - ossl_raise(cEC_POINT, "EC_POINT_make_affine"); - - return self; -} - -/* - * call-seq: - * point.invert! => self - * - */ -static VALUE ossl_ec_point_invert(VALUE self) -{ - EC_POINT *point; - VALUE group_v = rb_iv_get(self, "@group"); - const EC_GROUP *group; - - Require_EC_POINT(self, point); - SafeRequire_EC_GROUP(group_v, group); - - if (EC_POINT_invert(group, point, ossl_bn_ctx) != 1) - ossl_raise(cEC_POINT, "EC_POINT_invert"); - - return self; -} - -/* - * call-seq: - * point.set_to_infinity! => self - * - */ -static VALUE ossl_ec_point_set_to_infinity(VALUE self) -{ - EC_POINT *point; - VALUE group_v = rb_iv_get(self, "@group"); - const EC_GROUP *group; - - Require_EC_POINT(self, point); - SafeRequire_EC_GROUP(group_v, group); - - if (EC_POINT_set_to_infinity(group, point) != 1) - ossl_raise(cEC_POINT, "EC_POINT_set_to_infinity"); - - return self; -} - -/* - * call-seq: - * point.to_bn => OpenSSL::BN - * - * See the OpenSSL documentation for EC_POINT_point2bn() - */ -static VALUE ossl_ec_point_to_bn(VALUE self) -{ - EC_POINT *point; - VALUE bn_obj; - VALUE group_v = rb_iv_get(self, "@group"); - const EC_GROUP *group; - point_conversion_form_t form; - BIGNUM *bn; - - Require_EC_POINT(self, point); - SafeRequire_EC_GROUP(group_v, group); - - form = EC_GROUP_get_point_conversion_form(group); - - bn_obj = rb_obj_alloc(cBN); - bn = GetBNPtr(bn_obj); - - if (EC_POINT_point2bn(group, point, form, bn, ossl_bn_ctx) == NULL) - ossl_raise(eEC_POINT, "EC_POINT_point2bn"); - - return bn_obj; -} - -static void no_copy(VALUE klass) -{ - rb_undef_method(klass, "copy"); - rb_undef_method(klass, "clone"); - rb_undef_method(klass, "dup"); - rb_undef_method(klass, "initialize_copy"); -} - -void Init_ossl_ec() -{ -#ifdef DONT_NEED_RDOC_WORKAROUND - mOSSL = rb_define_module("OpenSSL"); - mPKey = rb_define_module_under(mOSSL, "PKey"); -#endif - - eECError = rb_define_class_under(mPKey, "ECError", ePKeyError); - - cEC = rb_define_class_under(mPKey, "EC", cPKey); - cEC_GROUP = rb_define_class_under(cEC, "Group", rb_cObject); - cEC_POINT = rb_define_class_under(cEC, "Point", rb_cObject); - eEC_GROUP = rb_define_class_under(cEC_GROUP, "Error", eOSSLError); - eEC_POINT = rb_define_class_under(cEC_POINT, "Error", eOSSLError); - - s_GFp = rb_intern("GFp"); - s_GF2m = rb_intern("GF2m"); - s_GFp_simple = rb_intern("GFp_simple"); - s_GFp_mont = rb_intern("GFp_mont"); - s_GFp_nist = rb_intern("GFp_nist"); - s_GF2m_simple = rb_intern("GF2m_simple"); - - ID_uncompressed = rb_intern("uncompressed"); - ID_compressed = rb_intern("compressed"); - ID_hybrid = rb_intern("hybrid"); - -#ifdef OPENSSL_EC_NAMED_CURVE - rb_define_const(cEC, "NAMED_CURVE", ULONG2NUM(OPENSSL_EC_NAMED_CURVE)); -#endif - - rb_define_singleton_method(cEC, "builtin_curves", ossl_s_builtin_curves, 0); - - rb_define_method(cEC, "initialize", ossl_ec_key_initialize, -1); -/* copy/dup/cmp */ - - rb_define_method(cEC, "group", ossl_ec_key_get_group, 0); - rb_define_method(cEC, "group=", ossl_ec_key_set_group, 1); - rb_define_method(cEC, "private_key", ossl_ec_key_get_private_key, 0); - rb_define_method(cEC, "private_key=", ossl_ec_key_set_private_key, 1); - rb_define_method(cEC, "public_key", ossl_ec_key_get_public_key, 0); - rb_define_method(cEC, "public_key=", ossl_ec_key_set_public_key, 1); - rb_define_method(cEC, "private_key?", ossl_ec_key_is_private_key, 0); - rb_define_method(cEC, "public_key?", ossl_ec_key_is_public_key, 0); -/* rb_define_method(cEC, "", ossl_ec_key_get_, 0); - rb_define_method(cEC, "=", ossl_ec_key_set_ 1); - set/get enc_flags - set/get _conv_from - set/get asn1_flag (can use ruby to call self.group.asn1_flag) - set/get precompute_mult -*/ - rb_define_method(cEC, "generate_key", ossl_ec_key_generate_key, 0); - rb_define_method(cEC, "check_key", ossl_ec_key_check_key, 0); - - rb_define_method(cEC, "dh_compute_key", ossl_ec_key_dh_compute_key, 1); - rb_define_method(cEC, "dsa_sign_asn1", ossl_ec_key_dsa_sign_asn1, 1); - rb_define_method(cEC, "dsa_verify_asn1", ossl_ec_key_dsa_verify_asn1, 2); -/* do_sign/do_verify */ - - rb_define_method(cEC, "to_pem", ossl_ec_key_to_pem, 0); - rb_define_method(cEC, "to_der", ossl_ec_key_to_der, 0); - rb_define_method(cEC, "to_text", ossl_ec_key_to_text, 0); - - - rb_define_alloc_func(cEC_GROUP, ossl_ec_group_alloc); - rb_define_method(cEC_GROUP, "initialize", ossl_ec_group_initialize, -1); - rb_define_method(cEC_GROUP, "eql?", ossl_ec_group_eql, 1); - rb_define_alias(cEC_GROUP, "==", "eql?"); -/* copy/dup/cmp */ - - rb_define_method(cEC_GROUP, "generator", ossl_ec_group_get_generator, 0); - rb_define_method(cEC_GROUP, "set_generator", ossl_ec_group_set_generator, 3); - rb_define_method(cEC_GROUP, "order", ossl_ec_group_get_order, 0); - rb_define_method(cEC_GROUP, "cofactor", ossl_ec_group_get_cofactor, 0); - - rb_define_method(cEC_GROUP, "curve_name", ossl_ec_group_get_curve_name, 0); -/* rb_define_method(cEC_GROUP, "curve_name=", ossl_ec_group_set_curve_name, 1); */ - - rb_define_method(cEC_GROUP, "asn1_flag", ossl_ec_group_get_asn1_flag, 0); - rb_define_method(cEC_GROUP, "asn1_flag=", ossl_ec_group_set_asn1_flag, 1); - - rb_define_method(cEC_GROUP, "point_conversion_form", ossl_ec_group_get_point_conversion_form, 0); - rb_define_method(cEC_GROUP, "point_conversion_form=", ossl_ec_group_set_point_conversion_form, 1); - - rb_define_method(cEC_GROUP, "seed", ossl_ec_group_get_seed, 0); - rb_define_method(cEC_GROUP, "seed=", ossl_ec_group_set_seed, 1); - -/* get/set GFp, GF2m */ - - rb_define_method(cEC_GROUP, "degree", ossl_ec_group_get_degree, 0); - -/* check* */ - - - rb_define_method(cEC_GROUP, "to_pem", ossl_ec_group_to_pem, 0); - rb_define_method(cEC_GROUP, "to_der", ossl_ec_group_to_der, 0); - rb_define_method(cEC_GROUP, "to_text", ossl_ec_group_to_text, 0); - - - rb_define_alloc_func(cEC_POINT, ossl_ec_point_alloc); - rb_define_method(cEC_POINT, "initialize", ossl_ec_point_initialize, -1); - rb_attr(cEC_POINT, rb_intern("group"), 1, 0, 0); - rb_define_method(cEC_POINT, "eql?", ossl_ec_point_eql, 1); - rb_define_alias(cEC_POINT, "==", "eql?"); - - rb_define_method(cEC_POINT, "infinity?", ossl_ec_point_is_at_infinity, 0); - rb_define_method(cEC_POINT, "on_curve?", ossl_ec_point_is_on_curve, 0); - rb_define_method(cEC_POINT, "make_affine!", ossl_ec_point_make_affine, 0); - rb_define_method(cEC_POINT, "invert!", ossl_ec_point_invert, 0); - rb_define_method(cEC_POINT, "set_to_infinity!", ossl_ec_point_set_to_infinity, 0); -/* all the other methods */ - - rb_define_method(cEC_POINT, "to_bn", ossl_ec_point_to_bn, 0); - - no_copy(cEC); - no_copy(cEC_GROUP); - no_copy(cEC_POINT); -} - -#else /* defined NO_EC */ -void Init_ossl_ec() -{ -} -#endif /* NO_EC */ |