summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authortechnorama <technorama@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2007-04-03 07:02:44 +0000
committertechnorama <technorama@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2007-04-03 07:02:44 +0000
commit8b95ee24de750995a0ffa7881b0c190315a98598 (patch)
tree933795acd0d6fc95e1f98cfd05ee98b9a2d4fc08 /ext
parenteed46ac6337e995196430b18eca10c9cb15317da (diff)
* ext/openssl/ossl_bn.c: More documentation.
* ext/openssl/lib/ossl_{pkey,pkey_ec}.[ch]: Add elliptic curves. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12139 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ext')
-rw-r--r--ext/openssl/ossl_bn.c12
-rw-r--r--ext/openssl/ossl_bn.h5
-rw-r--r--ext/openssl/ossl_pkey.c7
-rw-r--r--ext/openssl/ossl_pkey.h13
-rw-r--r--ext/openssl/ossl_pkey_ec.c1438
-rw-r--r--ext/openssl/ossl_pkey_rsa.c1
6 files changed, 1472 insertions, 4 deletions
diff --git a/ext/openssl/ossl_bn.c b/ext/openssl/ossl_bn.c
index ec1f37222a..13aed7f4be 100644
--- a/ext/openssl/ossl_bn.c
+++ b/ext/openssl/ossl_bn.c
@@ -40,7 +40,7 @@ VALUE eBNError;
* Public
*/
VALUE
-ossl_bn_new(BIGNUM *bn)
+ossl_bn_new(const BIGNUM *bn)
{
BIGNUM *newbn;
VALUE obj;
@@ -100,6 +100,12 @@ ossl_bn_alloc(VALUE klass)
return obj;
}
+/*
+ * call-seq:
+ * BN.new => aBN
+ * BN.new(bn) => aBN
+ * BN.new(string, 0 | 2 | 10 | 16) => aBN
+ */
static VALUE
ossl_bn_initialize(int argc, VALUE *argv, VALUE self)
{
@@ -189,6 +195,10 @@ ossl_bn_to_s(int argc, VALUE *argv, VALUE self)
return str;
}
+/*
+ * call-seq:
+ * bn.to_i => integer
+ */
static VALUE
ossl_bn_to_i(VALUE self)
{
diff --git a/ext/openssl/ossl_bn.h b/ext/openssl/ossl_bn.h
index 12aa484873..d6c396227b 100644
--- a/ext/openssl/ossl_bn.h
+++ b/ext/openssl/ossl_bn.h
@@ -14,9 +14,12 @@
extern VALUE cBN;
extern VALUE eBNError;
-VALUE ossl_bn_new(BIGNUM *);
+extern BN_CTX *ossl_bn_ctx;
+
+VALUE ossl_bn_new(const BIGNUM *);
BIGNUM *GetBNPtr(VALUE);
void Init_ossl_bn(void);
+
#endif /* _OSS_BN_H_ */
diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c
index b85d1133fe..b295cfc25e 100644
--- a/ext/openssl/ossl_pkey.c
+++ b/ext/openssl/ossl_pkey.c
@@ -55,6 +55,10 @@ ossl_pkey_new(EVP_PKEY *pkey)
case EVP_PKEY_DH:
return ossl_dh_new(pkey);
#endif
+#if !defined(OPENSSL_NO_EC) && (OPENSSL_VERSION_NUMBER >= 0x0090802fL)
+ case EVP_PKEY_EC:
+ return ossl_ec_new(pkey);
+#endif
default:
ossl_raise(ePKeyError, "unsupported key type");
}
@@ -226,10 +230,11 @@ Init_ossl_pkey()
id_private_q = rb_intern("private?");
/*
- * INIT rsa, dsa
+ * INIT rsa, dsa, dh, ec
*/
Init_ossl_rsa();
Init_ossl_dsa();
Init_ossl_dh();
+ Init_ossl_ec();
}
diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h
index 5057843fd1..67ff1fddd0 100644
--- a/ext/openssl/ossl_pkey.h
+++ b/ext/openssl/ossl_pkey.h
@@ -77,6 +77,19 @@ extern DH *OSSL_DEFAULT_DH_1024;
VALUE ossl_dh_new(EVP_PKEY *);
void Init_ossl_dh(void);
+/*
+ * EC
+ */
+extern VALUE cEC;
+extern VALUE eECError;
+extern VALUE cEC_GROUP;
+extern VALUE eEC_GROUP;
+extern VALUE cEC_POINT;
+extern VALUE eEC_POINT;
+VALUE ossl_ec_new(EVP_PKEY *);
+void Init_ossl_ec(void);
+
+
#define OSSL_PKEY_BN(keytype, name) \
/* \
* call-seq: \
diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c
new file mode 100644
index 0000000000..5f00fc001d
--- /dev/null
+++ b/ext/openssl/ossl_pkey_ec.c
@@ -0,0 +1,1438 @@
+/*
+ * 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) {
+ BIO_reset(in);
+ ec = PEM_read_bio_EC_PUBKEY(in, NULL, NULL, NULL);
+ }
+ if (!ec) {
+ BIO_reset(in);
+ ec = d2i_ECPrivateKey_bio(in, NULL);
+ }
+ if (!ec) {
+ 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);
+ }
+ }
+ }
+
+ 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_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;
+}
+
+static VALUE ossl_ec_key_to_public_key(VALUE self)
+{
+ EC_KEY *ec;
+
+ VALUE new_obj;
+
+ Require_EC_KEY(self, ec);
+
+ new_obj = rb_obj_alloc(cEC);
+
+/* BUG: finish .to_public_key */
+rb_notimplement();
+
+
+ return new_obj;
+}
+
+/*
+ * 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;
+ 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, RSTRING_PTR(data), RSTRING_LEN(data), 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, RSTRING_PTR(data), RSTRING_LEN(data), 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);
+ free(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) {
+ 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);
+ }
+ }
+
+ 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:
+ * 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(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, 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);
+ free(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:
+ * 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");
+
+ 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, 2);
+ 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);
+/* 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);
+/* 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 */
+# warning >>> OpenSSL is compiled without EC support <<<
+
+void Init_ossl_ec()
+{
+}
+
+#endif /* NO_EC */
diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c
index 783a77f6de..4a690a7cb5 100644
--- a/ext/openssl/ossl_pkey_rsa.c
+++ b/ext/openssl/ossl_pkey_rsa.c
@@ -493,7 +493,6 @@ ossl_rsa_to_public_key(VALUE self)
/*
* TODO: Test me
-extern BN_CTX *ossl_bn_ctx;
static VALUE
ossl_rsa_blinding_on(VALUE self)