lib/extensions/openssl/ext/ossl_pkey_ec.c in rhodes-5.5.18 vs lib/extensions/openssl/ext/ossl_pkey_ec.c in rhodes-6.0.11
- old
+ new
@@ -18,76 +18,78 @@
#define EXPORT_PEM 0
#define EXPORT_DER 1
+static const rb_data_type_t ossl_ec_group_type;
+static const rb_data_type_t ossl_ec_point_type;
#define GetPKeyEC(obj, pkey) do { \
- GetPKey(obj, pkey); \
- if (EVP_PKEY_type(pkey->type) != EVP_PKEY_EC) { \
+ 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); \
+ OSSL_Check_Kind((obj), cEC_GROUP); \
+ TypedData_Get_Struct((obj), ossl_ec_group, &ossl_ec_group_type, (group)); \
} while(0)
#define Get_EC_KEY(obj, key) do { \
EVP_PKEY *pkey; \
- GetPKeyEC(obj, pkey); \
- key = pkey->pkey.ec; \
+ 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"); \
+ Get_EC_KEY((obj), (key)); \
+ if ((key) == NULL) \
+ ossl_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); \
+ 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); \
+ TypedData_Get_Struct((obj), ossl_ec_group, &ossl_ec_group_type, ec_group); \
if (ec_group == NULL) \
- rb_raise(eEC_GROUP, "missing ossl_ec_group structure"); \
- g = ec_group->group; \
+ ossl_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"); \
+ Get_EC_GROUP((obj), (group)); \
+ if ((group) == NULL) \
+ ossl_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); \
+ 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); \
+ TypedData_Get_Struct((obj), ossl_ec_point, &ossl_ec_point_type, ec_point); \
if (ec_point == NULL) \
- rb_raise(eEC_POINT, "missing ossl_ec_point structure"); \
- p = ec_point->point; \
+ ossl_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"); \
+ Get_EC_POINT((obj), (point)); \
+ if ((point) == NULL) \
+ ossl_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); \
+ OSSL_Check_Kind((obj), cEC_POINT); \
+ Require_EC_POINT((obj), (point)); \
} while(0)
VALUE cEC;
VALUE eECError;
VALUE cEC_GROUP;
@@ -112,18 +114,19 @@
VALUE obj;
if (!ec) {
return Qfalse;
}
+ obj = NewPKey(klass);
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);
+ SetPKey(obj, pkey);
return obj;
}
VALUE ossl_ec_new(EVP_PKEY *pkey)
@@ -131,14 +134,15 @@
VALUE obj;
if (!pkey) {
obj = ec_instance(cEC, EC_KEY_new());
} else {
+ obj = NewPKey(cEC);
if (EVP_PKEY_type(pkey->type) != EVP_PKEY_EC) {
ossl_raise(rb_eTypeError, "Not a EC key!");
}
- WrapPKey(cEC, obj, pkey);
+ SetPKey(obj, pkey);
}
if (obj == Qfalse) {
ossl_raise(eECError, NULL);
}
@@ -150,10 +154,11 @@
* 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(pem_string [, pwd])
* OpenSSL::PKey::EC.new(der_string)
*
* See the OpenSSL documentation for:
* EC_KEY_*
*/
@@ -161,14 +166,15 @@
{
EVP_PKEY *pkey;
EC_KEY *ec = NULL;
VALUE arg, pass;
VALUE group = Qnil;
+ char *passwd = NULL;
GetPKey(self, pkey);
if (pkey->pkey.ec)
- rb_raise(eECError, "EC_KEY already initialized");
+ ossl_raise(eECError, "EC_KEY already initialized");
rb_scan_args(argc, argv, "02", &arg, &pass);
if (NIL_P(arg)) {
ec = EC_KEY_new();
@@ -182,24 +188,24 @@
ec = EC_KEY_new();
group = arg;
} else {
BIO *in = ossl_obj2bio(arg);
- ec = PEM_read_bio_ECPrivateKey(in, NULL, NULL, NULL);
+ if (!NIL_P(pass)) {
+ passwd = StringValuePtr(pass);
+ }
+ ec = PEM_read_bio_ECPrivateKey(in, NULL, ossl_pem_passwd_cb, passwd);
if (!ec) {
- (void)BIO_reset(in);
- (void)ERR_get_error();
- ec = PEM_read_bio_EC_PUBKEY(in, NULL, NULL, NULL);
+ OSSL_BIO_reset(in);
+ ec = PEM_read_bio_EC_PUBKEY(in, NULL, ossl_pem_passwd_cb, passwd);
}
if (!ec) {
- (void)BIO_reset(in);
- (void)ERR_get_error();
+ OSSL_BIO_reset(in);
ec = d2i_ECPrivateKey_bio(in, NULL);
}
if (!ec) {
- (void)BIO_reset(in);
- (void)ERR_get_error();
+ OSSL_BIO_reset(in);
ec = d2i_EC_PUBKEY_bio(in, NULL);
}
BIO_free(in);
@@ -365,11 +371,11 @@
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);
+ TypedData_Get_Struct(obj, ossl_ec_point, &ossl_ec_point_type, new_point);
SafeRequire_EC_GROUP(group_v, group);
new_point->point = EC_POINT_dup(point, group);
if (new_point->point == NULL)
@@ -459,77 +465,64 @@
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)
+static VALUE ossl_ec_key_to_string(VALUE self, VALUE ciph, VALUE pass, int format)
{
EC_KEY *ec;
BIO *out;
int i = -1;
int private = 0;
-#if 0 /* unused now */
- EVP_CIPHER *cipher = NULL;
char *password = NULL;
-#endif
VALUE str;
+ const EVP_CIPHER *cipher = NULL;
Require_EC_KEY(self, ec);
if (EC_KEY_get0_public_key(ec) == NULL)
- rb_raise(eECError, "can't export - no public key set");
+ ossl_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 (!NIL_P(ciph)) {
+ cipher = GetCipherPtr(ciph);
+ if (!NIL_P(pass)) {
+ StringValue(pass);
+ if (RSTRING_LENINT(pass) < OSSL_MIN_PWD_LEN)
+ ossl_raise(eOSSLError, "OpenSSL requires passwords to be at least four characters long");
+ password = RSTRING_PTR(pass);
+ }
+ }
+
if (!(out = BIO_new(BIO_s_mem())))
ossl_raise(eECError, "BIO_new(BIO_s_mem())");
switch(format) {
case EXPORT_PEM:
if (private) {
-#if 0 /* unused now */
- if (cipher || password)
-/* BUG: finish cipher/password key export */
- rb_notimplement();
i = PEM_write_bio_ECPrivateKey(out, ec, cipher, NULL, 0, NULL, password);
-#endif
- i = PEM_write_bio_ECPrivateKey(out, ec, NULL, NULL, 0, NULL, NULL);
} else {
-#if 0 /* unused now */
- if (cipher || password)
- rb_raise(rb_eArgError, "encryption is not supported when exporting this key type");
-#endif
-
i = PEM_write_bio_EC_PUBKEY(out, ec);
}
break;
case EXPORT_DER:
if (private) {
-#if 0 /* unused now */
- if (cipher || password)
- rb_raise(rb_eArgError, "encryption is not supported when exporting this key type");
-#endif
-
i = i2d_ECPrivateKey_bio(out, ec);
} else {
-#if 0 /* unused now */
- if (cipher || password)
- rb_raise(rb_eArgError, "encryption is not supported when exporting this key type");
-#endif
-
i = i2d_EC_PUBKEY_bio(out, ec);
}
break;
default:
BIO_free(out);
- rb_raise(rb_eRuntimeError, "unknown format (internal error)");
+ ossl_raise(rb_eRuntimeError, "unknown format (internal error)");
}
if (i != 1) {
BIO_free(out);
ossl_raise(eECError, "outlen=%d", i);
@@ -540,28 +533,36 @@
return str;
}
/*
* call-seq:
- * key.to_pem => String
+ * key.export([cipher, pass_phrase]) => String
+ * key.to_pem([cipher, pass_phrase]) => String
*
- * See the OpenSSL documentation for PEM_write_bio_ECPrivateKey()
+ * Outputs the EC key in PEM encoding. If +cipher+ and +pass_phrase+ are
+ * given they will be used to encrypt the key. +cipher+ must be an
+ * OpenSSL::Cipher::Cipher instance. Note that encryption will only be
+ * effective for a private key, public keys will always be encoded in plain
+ * text.
+ *
*/
-static VALUE ossl_ec_key_to_pem(VALUE self)
+static VALUE ossl_ec_key_export(int argc, VALUE *argv, VALUE self)
{
- return ossl_ec_key_to_string(self, EXPORT_PEM);
+ VALUE cipher, passwd;
+ rb_scan_args(argc, argv, "02", &cipher, &passwd);
+ return ossl_ec_key_to_string(self, cipher, passwd, 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);
+ return ossl_ec_key_to_string(self, Qnil, Qnil, EXPORT_DER);
}
/*
* call-seq:
* key.to_text => String
@@ -673,11 +674,11 @@
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)
+ if (ECDSA_sign(0, (unsigned char *) RSTRING_PTR(data), RSTRING_LENINT(data), (unsigned char *) RSTRING_PTR(str), &buf_len, ec) != 1)
ossl_raise(eECError, "ECDSA_sign");
rb_str_resize(str, buf_len);
return str;
@@ -695,32 +696,43 @@
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)) {
+ switch (ECDSA_verify(0, (unsigned char *) RSTRING_PTR(data), RSTRING_LENINT(data), (unsigned char *) RSTRING_PTR(sig), (int)RSTRING_LEN(sig), ec)) {
case 1: return Qtrue;
case 0: return Qfalse;
default: break;
}
ossl_raise(eECError, "ECDSA_verify");
+
+ UNREACHABLE;
}
-static void ossl_ec_group_free(ossl_ec_group *ec_group)
+static void ossl_ec_group_free(void *ptr)
{
+ ossl_ec_group *ec_group = ptr;
if (!ec_group->dont_free && ec_group->group)
EC_GROUP_clear_free(ec_group->group);
ruby_xfree(ec_group);
}
+static const rb_data_type_t ossl_ec_group_type = {
+ "OpenSSL/ec_group",
+ {
+ 0, ossl_ec_group_free,
+ },
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
+};
+
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);
+ obj = TypedData_Make_Struct(klass, ossl_ec_group, &ossl_ec_group_type, ec_group);
return obj;
}
/* call-seq:
@@ -743,13 +755,13 @@
{
VALUE arg1, arg2, arg3, arg4;
ossl_ec_group *ec_group;
EC_GROUP *group = NULL;
- Data_Get_Struct(self, ossl_ec_group, ec_group);
+ TypedData_Get_Struct(self, ossl_ec_group, &ossl_ec_group_type, ec_group);
if (ec_group->group != NULL)
- rb_raise(rb_eRuntimeError, "EC_GROUP is already initialized");
+ ossl_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;
@@ -759,19 +771,21 @@
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();
+#if !defined(OPENSSL_NO_EC2M)
} else if (id == s_GF2m_simple) {
method = EC_GF2m_simple_method();
+#endif
}
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");
+ ossl_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);
@@ -780,20 +794,21 @@
} else {
BIO *in = ossl_obj2bio(arg1);
group = PEM_read_bio_ECPKParameters(in, NULL, NULL, NULL);
if (!group) {
- (void)BIO_reset(in);
+ OSSL_BIO_reset(in);
group = d2i_ECPKParameters_bio(in, NULL);
}
BIO_free(in);
if (!group) {
const char *name = StringValueCStr(arg1);
int nid = OBJ_sn2nid(name);
+ (void)ERR_get_error();
if (nid == NID_undef)
ossl_raise(eEC_GROUP, "unknown curve name (%s)", name);
group = EC_GROUP_new_by_curve_name(nid);
if (group == NULL)
@@ -813,25 +828,27 @@
const BIGNUM *a = GetBNPtr(arg3);
const BIGNUM *b = GetBNPtr(arg4);
if (id == s_GFp) {
new_curve = EC_GROUP_new_curve_GFp;
+#if !defined(OPENSSL_NO_EC2M)
} else if (id == s_GF2m) {
new_curve = EC_GROUP_new_curve_GF2m;
+#endif
} else {
- rb_raise(rb_eArgError, "unknown symbol, must be :GFp or :GF2m");
+ ossl_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");
+ ossl_raise(rb_eArgError, "unknown argument, must be :GFp or :GF2m");
}
break;
default:
- rb_raise(rb_eArgError, "wrong number of arguments");
+ ossl_raise(rb_eArgError, "wrong number of arguments");
}
if (group == NULL)
ossl_raise(eEC_GROUP, "");
@@ -839,10 +856,11 @@
return self;
}
/* call-seq:
+ * group1.eql?(group2) => true | false
* group1 == group2 => true | false
*
*/
static VALUE ossl_ec_group_eql(VALUE a, VALUE b)
{
@@ -967,11 +985,11 @@
*/
static VALUE ossl_s_builtin_curves(VALUE self)
{
EC_builtin_curve *curves = NULL;
int n;
- int crv_len = EC_get_builtin_curves(NULL, 0);
+ int crv_len = rb_long2int(EC_get_builtin_curves(NULL, 0));
VALUE ary, ret;
curves = ALLOCA_N(EC_builtin_curve, crv_len);
if (curves == NULL)
return Qnil;
@@ -1043,11 +1061,11 @@
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);
+ default: ossl_raise(eEC_GROUP, "unsupported point conversion form: %d, this module should be updated", form);
}
return ID2SYM(ret);
}
@@ -1069,11 +1087,11 @@
} 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");
+ ossl_raise(rb_eArgError, "form must be :compressed, :uncompressed, or :hybrid");
}
EC_GROUP_set_point_conversion_form(group, form);
return form_v;
@@ -1109,11 +1127,11 @@
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))
+ if (EC_GROUP_set_seed(group, (unsigned char *)RSTRING_PTR(seed), RSTRING_LEN(seed)) != (size_t)RSTRING_LEN(seed))
ossl_raise(eEC_GROUP, "EC_GROUP_set_seed");
return seed;
}
@@ -1152,11 +1170,11 @@
case EXPORT_DER:
i = i2d_ECPKParameters_bio(out, group);
break;
default:
BIO_free(out);
- rb_raise(rb_eRuntimeError, "unknown format (internal error)");
+ ossl_raise(rb_eRuntimeError, "unknown format (internal error)");
}
if (i != 1) {
BIO_free(out);
ossl_raise(eECError, NULL);
@@ -1210,23 +1228,32 @@
return str;
}
-static void ossl_ec_point_free(ossl_ec_point *ec_point)
+static void ossl_ec_point_free(void *ptr)
{
+ ossl_ec_point *ec_point = ptr;
if (!ec_point->dont_free && ec_point->point)
EC_POINT_clear_free(ec_point->point);
ruby_xfree(ec_point);
}
+static const rb_data_type_t ossl_ec_point_type = {
+ "OpenSSL/ec_point",
+ {
+ 0, ossl_ec_point_free,
+ },
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
+};
+
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);
+ obj = TypedData_Make_Struct(klass, ossl_ec_point, &ossl_ec_point_type, ec_point);
return obj;
}
/*
@@ -1243,13 +1270,13 @@
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);
+ TypedData_Get_Struct(self, ossl_ec_point, &ossl_ec_point_type, ec_point);
if (ec_point->point)
- rb_raise(eEC_POINT, "EC_POINT already initialized");
+ ossl_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;
@@ -1263,17 +1290,17 @@
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");
+ ossl_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");
+ ossl_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);
@@ -1290,28 +1317,29 @@
ossl_raise(eEC_POINT, "unknown type for 2nd arg");
}
}
break;
default:
- rb_raise(rb_eArgError, "wrong number of arguments");
+ ossl_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)");
+ ossl_raise(rb_eRuntimeError, "missing group (internal error)");
ec_point->point = point;
rb_iv_set(self, "@group", group_v);
return self;
}
/*
* call-seq:
+ * point1.eql?(point2) => true | false
* point1 == point2 => true | false
*
*/
static VALUE ossl_ec_point_eql(VALUE a, VALUE b)
{
@@ -1350,10 +1378,12 @@
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");
}
+
+ UNREACHABLE;
}
/*
* call-seq:
* point.on_curve? => true | false
@@ -1371,10 +1401,12 @@
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");
}
+
+ UNREACHABLE;
}
/*
* call-seq:
* point.make_affine! => self
@@ -1462,19 +1494,91 @@
ossl_raise(eEC_POINT, "EC_POINT_point2bn");
return bn_obj;
}
+/*
+ * call-seq:
+ * point.mul(bn) => point
+ * point.mul(bn, bn) => point
+ * point.mul([bn], [point]) => point
+ * point.mul([bn], [point], bn) => point
+ */
+static VALUE ossl_ec_point_mul(int argc, VALUE *argv, VALUE self)
+{
+ EC_POINT *point1, *point2;
+ const EC_GROUP *group;
+ VALUE group_v = rb_iv_get(self, "@group");
+ VALUE bn_v1, bn_v2, r, points_v;
+ BIGNUM *bn1 = NULL, *bn2 = NULL;
+
+ Require_EC_POINT(self, point1);
+ SafeRequire_EC_GROUP(group_v, group);
+
+ r = rb_obj_alloc(cEC_POINT);
+ ossl_ec_point_initialize(1, &group_v, r);
+ Require_EC_POINT(r, point2);
+
+ argc = rb_scan_args(argc, argv, "12", &bn_v1, &points_v, &bn_v2);
+
+ if (rb_obj_is_kind_of(bn_v1, cBN)) {
+ bn1 = GetBNPtr(bn_v1);
+ if (argc >= 2) {
+ bn2 = GetBNPtr(points_v);
+ }
+ if (EC_POINT_mul(group, point2, bn2, point1, bn1, ossl_bn_ctx) != 1)
+ ossl_raise(eEC_POINT, "Multiplication failed");
+ } else {
+ size_t i, points_len, bignums_len;
+ const EC_POINT **points;
+ const BIGNUM **bignums;
+
+ Check_Type(bn_v1, T_ARRAY);
+ bignums_len = RARRAY_LEN(bn_v1);
+ bignums = (const BIGNUM **)OPENSSL_malloc(bignums_len * (int)sizeof(BIGNUM *));
+
+ for (i = 0; i < bignums_len; ++i) {
+ bignums[i] = GetBNPtr(rb_ary_entry(bn_v1, i));
+ }
+
+ if (!rb_obj_is_kind_of(points_v, rb_cArray)) {
+ OPENSSL_free((void *)bignums);
+ rb_raise(rb_eTypeError, "Argument2 must be an array");
+ }
+
+ rb_ary_unshift(points_v, self);
+ points_len = RARRAY_LEN(points_v);
+ points = (const EC_POINT **)OPENSSL_malloc(points_len * (int)sizeof(EC_POINT *));
+
+ for (i = 0; i < points_len; ++i) {
+ Get_EC_POINT(rb_ary_entry(points_v, i), points[i]);
+ }
+
+ if (argc >= 3) {
+ bn2 = GetBNPtr(bn_v2);
+ }
+ if (EC_POINTs_mul(group, point2, bn2, points_len, points, bignums, ossl_bn_ctx) != 1) {
+ OPENSSL_free((void *)bignums);
+ OPENSSL_free((void *)points);
+ ossl_raise(eEC_POINT, "Multiplication failed");
+ }
+ OPENSSL_free((void *)bignums);
+ OPENSSL_free((void *)points);
+ }
+
+ return r;
+}
+
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()
+void Init_ossl_ec(void)
{
#ifdef DONT_NEED_RDOC_WORKAROUND
mOSSL = rb_define_module("OpenSSL");
mPKey = rb_define_module_under(mOSSL, "PKey");
#endif
@@ -1528,11 +1632,12 @@
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, "export", ossl_ec_key_export, -1);
+ rb_define_alias(cEC, "to_pem", "export");
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);
@@ -1582,16 +1687,17 @@
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);
+ rb_define_method(cEC_POINT, "mul", ossl_ec_point_mul, -1);
no_copy(cEC);
no_copy(cEC_GROUP);
no_copy(cEC_POINT);
}
#else /* defined NO_EC */
-void Init_ossl_ec()
+void Init_ossl_ec(void)
{
}
#endif /* NO_EC */