From b2de36049a7687da00870e714c2e299ac5a903cd Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 20:19:38 +0000 Subject: [PATCH 01/12] Add Some more elliptic curve functionality --- openssl-sys/src/lib.rs | 25 +++++++++ openssl/src/ec_key.rs | 114 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 138 insertions(+), 1 deletion(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 4ba706f9..11fa46df 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -26,6 +26,9 @@ pub enum BN_GENCB {} pub enum CONF {} pub enum COMP_METHOD {} pub enum EC_KEY {} +pub enum EC_GROUP {} +pub enum EC_METHOD {} +pub enum EC_POINT {} pub enum ENGINE {} pub enum EVP_CIPHER_CTX {} pub enum EVP_MD {} @@ -1372,8 +1375,30 @@ extern { pub fn DH_get_2048_256() -> *mut DH; pub fn EC_KEY_new_by_curve_name(nid: c_int) -> *mut EC_KEY; + pub fn EC_KEY_get0_group(key: *const EC_KEY) -> *const EC_GROUP; + pub fn EC_KEY_get0_public_key(key: *const EC_KEY) -> *const EC_POINT; + pub fn EC_KEY_get0_private_key(key: *const EC_KEY) -> *const BIGNUM; pub fn EC_KEY_free(key: *mut EC_KEY); + pub fn EC_GFp_simple_method() -> *const EC_METHOD; + pub fn EC_GFp_mont_method() -> *const EC_METHOD; + pub fn EC_GFp_nist_method() -> *const EC_METHOD; + pub fn EC_GFp_nistp224_method() -> *const EC_METHOD; + pub fn EC_GFp_nistp256_method() -> *const EC_METHOD; + pub fn EC_GFp_nistp521_method() -> *const EC_METHOD; + + pub fn EC_GF2m_simple_method() -> *const EC_METHOD; + + pub fn EC_GROUP_new(meth: *const EC_METHOD) -> *mut EC_GROUP; + pub fn EC_GROUP_new_curve_GFp(p: *const BIGNUM, a: *const BIGNUM, b: *const BIGNUM, ctx: *mut BN_CTX) -> *mut EC_GROUP; + pub fn EC_GROUP_new_curve_GF2m(p: *const BIGNUM, a: *const BIGNUM, b: *const BIGNUM, ctx: *mut BN_CTX) -> *mut EC_GROUP; + pub fn EC_GROUP_new_by_curve_name(nid: c_int) -> *mut EC_GROUP; + pub fn EC_GROUP_get_curve_GFp(group: *const EC_GROUP, p: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn EC_GROUP_get_curve_GF2m(group: *const EC_GROUP, p: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn EC_GROUP_free(group: *mut EC_GROUP); + + pub fn EC_POINT_free(point: *mut EC_POINT); + pub fn ERR_get_error() -> c_ulong; pub fn ERR_lib_error_string(err: c_ulong) -> *const c_char; pub fn ERR_func_error_string(err: c_ulong) -> *const c_char; diff --git a/openssl/src/ec_key.rs b/openssl/src/ec_key.rs index 268a6fd2..3b6349b5 100644 --- a/openssl/src/ec_key.rs +++ b/openssl/src/ec_key.rs @@ -2,15 +2,115 @@ use ffi; use std::ptr; use {cvt, cvt_p, init}; +use bn::{BigNumRef, BigNumContextRef}; use error::ErrorStack; use nid::Nid; use types::OpenSslTypeRef; +type_!(EcGroup, EcGroupRef, ffi::EC_GROUP, ffi::EC_GROUP_free); + +impl EcGroup { + /// Returns the group of a standard named curve. + pub fn from_curve_name(nid: Nid) -> Result { + unsafe { + init(); + cvt_p(ffi::EC_GROUP_new_by_curve_name(nid.as_raw())).map(EcGroup) + } + } + + /// Constructs a curve over a prime field from its components. + pub fn from_components_gfp(p: &BigNumRef, + a: &BigNumRef, + b: &BigNumRef, + ctx: &mut BigNumContextRef) + -> Result { + unsafe { + cvt_p(ffi::EC_GROUP_new_curve_GFp(p.as_ptr(), a.as_ptr(), b.as_ptr(), ctx.as_ptr())) + .map(EcGroup) + } + } + + /// Constructs a curve over a binary field from its components. + pub fn from_components_gf2m(p: &BigNumRef, + a: &BigNumRef, + b: &BigNumRef, + ctx: &mut BigNumContextRef) + -> Result { + unsafe { + cvt_p(ffi::EC_GROUP_new_curve_GF2m(p.as_ptr(), a.as_ptr(), b.as_ptr(), ctx.as_ptr())) + .map(EcGroup) + } + } + + /// Places the components of a curve over a prime field in the provided `BigNum`s. + pub fn components_gfp(&self, + p: &mut BigNumRef, + a: &mut BigNumRef, + b: &mut BigNumRef, + ctx: &mut BigNumContextRef) + -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_GROUP_get_curve_GFp(self.as_ptr(), + p.as_ptr(), + a.as_ptr(), + b.as_ptr(), + ctx.as_ptr())) + .map(|_| ()) + } + } + + /// Places the components of a curve over a binary field in the provided `BigNum`s. + pub fn components_gf2m(&self, + p: &mut BigNumRef, + a: &mut BigNumRef, + b: &mut BigNumRef, + ctx: &mut BigNumContextRef) + -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_GROUP_get_curve_GF2m(self.as_ptr(), + p.as_ptr(), + a.as_ptr(), + b.as_ptr(), + ctx.as_ptr())) + .map(|_| ()) + } + } +} + +type_!(EcPoint, EcPointRef, ffi::EC_POINT, ffi::EC_POINT_free); + type_!(EcKey, EcKeyRef, ffi::EC_KEY, ffi::EC_KEY_free); impl EcKeyRef { private_key_to_pem!(ffi::PEM_write_bio_ECPrivateKey); private_key_to_der!(ffi::i2d_ECPrivateKey); + + pub fn group(&self) -> &EcGroupRef { + unsafe { + let ptr = ffi::EC_KEY_get0_group(self.as_ptr()); + assert!(!ptr.is_null()); + EcGroupRef::from_ptr(ptr as *mut _) + } + } + + pub fn public_key(&self) -> &EcPointRef { + unsafe { + let ptr = ffi::EC_KEY_get0_public_key(self.as_ptr()); + assert!(!ptr.is_null()); + EcPointRef::from_ptr(ptr as *mut _) + } + } + + pub fn private_key(&self) -> Option<&BigNumRef> { + unsafe { + let ptr = ffi::EC_KEY_get0_private_key(self.as_ptr()); + if ptr.is_null() { + None + } else { + Some(BigNumRef::from_ptr(ptr as *mut _)) + } + } + } } impl EcKey { @@ -27,11 +127,23 @@ impl EcKey { #[cfg(test)] mod test { + use bn::{BigNum, BigNumContext}; use nid; use super::*; #[test] - fn new_by_curve_name() { + fn key_new_by_curve_name() { EcKey::new_by_curve_name(nid::X9_62_PRIME256V1).unwrap(); } + + #[test] + fn round_trip_prime256v1() { + let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); + let mut p = BigNum::new().unwrap(); + let mut a = BigNum::new().unwrap(); + let mut b = BigNum::new().unwrap(); + let mut ctx = BigNumContext::new().unwrap(); + group.components_gfp(&mut p, &mut a, &mut b, &mut ctx).unwrap(); + EcGroup::from_components_gfp(&p, &a, &b, &mut ctx).unwrap(); + } } From 0d0b5080e25fb0a2f9ada042810b98d28f5e0414 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 20:21:44 +0000 Subject: [PATCH 02/12] Rename new_by_curve_name to from_curve_name --- openssl/src/ec_key.rs | 9 +++++++-- openssl/src/pkey.rs | 2 +- openssl/src/ssl/connector.rs | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/openssl/src/ec_key.rs b/openssl/src/ec_key.rs index 3b6349b5..ba9ed762 100644 --- a/openssl/src/ec_key.rs +++ b/openssl/src/ec_key.rs @@ -114,13 +114,18 @@ impl EcKeyRef { } impl EcKey { - pub fn new_by_curve_name(nid: Nid) -> Result { + pub fn from_curve_name(nid: Nid) -> Result { unsafe { init(); cvt_p(ffi::EC_KEY_new_by_curve_name(nid.as_raw())).map(EcKey) } } + #[deprecated(since = "0.9.2", note = "use from_curve_name")] + pub fn new_by_curve_name(nid: Nid) -> Result { + EcKey::from_curve_name(nid) + } + private_key_from_pem!(EcKey, ffi::PEM_read_bio_ECPrivateKey); private_key_from_der!(EcKey, ffi::d2i_ECPrivateKey); } @@ -133,7 +138,7 @@ mod test { #[test] fn key_new_by_curve_name() { - EcKey::new_by_curve_name(nid::X9_62_PRIME256V1).unwrap(); + EcKey::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); } #[test] diff --git a/openssl/src/pkey.rs b/openssl/src/pkey.rs index ee564836..5739a5ed 100644 --- a/openssl/src/pkey.rs +++ b/openssl/src/pkey.rs @@ -221,7 +221,7 @@ mod tests { #[test] fn test_ec_key_accessor() { - let ec_key = EcKey::new_by_curve_name(nid::X9_62_PRIME256V1).unwrap(); + let ec_key = EcKey::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); let pkey = PKey::from_ec_key(ec_key).unwrap(); pkey.ec_key().unwrap(); assert!(pkey.rsa().is_err()); diff --git a/openssl/src/ssl/connector.rs b/openssl/src/ssl/connector.rs index 07c44ce7..c002b966 100644 --- a/openssl/src/ssl/connector.rs +++ b/openssl/src/ssl/connector.rs @@ -218,7 +218,7 @@ fn setup_curves(ctx: &mut SslContextBuilder) -> Result<(), ErrorStack> { use ec_key::EcKey; use nid; - let curve = try!(EcKey::new_by_curve_name(nid::X9_62_PRIME256V1)); + let curve = try!(EcKey::from_curve_name(nid::X9_62_PRIME256V1)); ctx.set_tmp_ecdh(&curve) } From 3d31539ba9f0c1f57869d7e50e433a0ef5850138 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 20:31:44 +0000 Subject: [PATCH 03/12] Public keys are not always present --- openssl/src/ec_key.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openssl/src/ec_key.rs b/openssl/src/ec_key.rs index ba9ed762..22082b42 100644 --- a/openssl/src/ec_key.rs +++ b/openssl/src/ec_key.rs @@ -93,7 +93,7 @@ impl EcKeyRef { } } - pub fn public_key(&self) -> &EcPointRef { + pub fn public_key(&self) -> Option<&EcPointRef> { unsafe { let ptr = ffi::EC_KEY_get0_public_key(self.as_ptr()); assert!(!ptr.is_null()); From 1a52649516e5b3924917314ee503523d59ed528b Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 20:46:01 +0000 Subject: [PATCH 04/12] More functionality --- openssl-sys/src/lib.rs | 5 +++++ openssl/src/ec_key.rs | 28 ++++++++++++++++++++++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 11fa46df..230c0148 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1374,10 +1374,15 @@ extern { #[cfg(not(ossl101))] pub fn DH_get_2048_256() -> *mut DH; + pub fn EC_KEY_new() -> *mut EC_KEY; pub fn EC_KEY_new_by_curve_name(nid: c_int) -> *mut EC_KEY; + pub fn EC_KEY_set_group(key: *mut EC_KEY, group: *const EC_GROUP) -> c_int; pub fn EC_KEY_get0_group(key: *const EC_KEY) -> *const EC_GROUP; + pub fn EC_KEY_set_public_key(key: *mut EC_KEY, key: *const EC_POINT) -> c_int; pub fn EC_KEY_get0_public_key(key: *const EC_KEY) -> *const EC_POINT; + pub fn EC_KEY_set_private_key(key: *mut EC_KEY, key: *const BIGNUM) -> c_int; pub fn EC_KEY_get0_private_key(key: *const EC_KEY) -> *const BIGNUM; + pub fn EC_KEY_generate_key(key: *mut EC_KEY) -> c_int; pub fn EC_KEY_free(key: *mut EC_KEY); pub fn EC_GFp_simple_method() -> *const EC_METHOD; diff --git a/openssl/src/ec_key.rs b/openssl/src/ec_key.rs index 22082b42..e7e92d7a 100644 --- a/openssl/src/ec_key.rs +++ b/openssl/src/ec_key.rs @@ -96,8 +96,11 @@ impl EcKeyRef { pub fn public_key(&self) -> Option<&EcPointRef> { unsafe { let ptr = ffi::EC_KEY_get0_public_key(self.as_ptr()); - assert!(!ptr.is_null()); - EcPointRef::from_ptr(ptr as *mut _) + if ptr.is_null() { + None + } else { + Some(EcPointRef::from_ptr(ptr as *mut _)) + } } } @@ -114,6 +117,9 @@ impl EcKeyRef { } impl EcKey { + /// Constructs an `EcKey` corresponding to a known curve. + /// + /// It will not have an associated public or private key. pub fn from_curve_name(nid: Nid) -> Result { unsafe { init(); @@ -121,6 +127,16 @@ impl EcKey { } } + /// Generates a new public/private key pair on the specified curve. + pub fn generate(group: &EcGroupRef) -> Result { + unsafe { + let key = EcKey(try!(cvt_p(ffi::EC_KEY_new()))); + try!(cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr()))); + try!(cvt(ffi::EC_KEY_generate_key(key.as_ptr()))); + Ok(key) + } + } + #[deprecated(since = "0.9.2", note = "use from_curve_name")] pub fn new_by_curve_name(nid: Nid) -> Result { EcKey::from_curve_name(nid) @@ -151,4 +167,12 @@ mod test { group.components_gfp(&mut p, &mut a, &mut b, &mut ctx).unwrap(); EcGroup::from_components_gfp(&p, &a, &b, &mut ctx).unwrap(); } + + #[test] + fn generate() { + let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); + let key = EcKey::generate(&group).unwrap(); + key.public_key().unwrap(); + key.private_key().unwrap(); + } } From 35f11d555eefd4a122b7d4688d589dcc1e918fcf Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 22:06:18 +0000 Subject: [PATCH 05/12] More functionality --- openssl-sys/src/lib.rs | 17 +++++ openssl/src/ec_key.rs | 157 ++++++++++++++++++++++++++++++++++++++++- systest/build.rs | 2 +- 3 files changed, 173 insertions(+), 3 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 230c0148..6ba8668e 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -60,6 +60,14 @@ pub enum BN_BLINDING {} pub enum DSA_METHOD {} pub enum EVP_PKEY_ASN1_METHOD {} +#[repr(C)] +#[derive(Copy, Clone)] +pub enum point_conversion_form_t { + POINT_CONVERSION_COMPRESSED = 2, + POINT_CONVERSION_UNCOMPRESSED = 4, + POINT_CONVERSION_HYBRID = 6, +} + #[repr(C)] pub struct GENERAL_NAME { pub type_: c_int, @@ -1400,8 +1408,17 @@ extern { pub fn EC_GROUP_new_by_curve_name(nid: c_int) -> *mut EC_GROUP; pub fn EC_GROUP_get_curve_GFp(group: *const EC_GROUP, p: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; pub fn EC_GROUP_get_curve_GF2m(group: *const EC_GROUP, p: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn EC_GROUP_get_degree(group: *const EC_GROUP) -> c_int; + pub fn EC_GROUP_get_order(group: *const EC_GROUP, order: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn EC_GROUP_free(group: *mut EC_GROUP); + pub fn EC_POINT_new(group: *const EC_GROUP) -> *mut EC_POINT; + pub fn EC_POINT_add(group: *const EC_GROUP, r: *mut EC_POINT, a: *const EC_POINT, b: *const EC_POINT, ctx: *mut BN_CTX) -> c_int; + pub fn EC_POINT_mul(group: *const EC_GROUP, r: *mut EC_POINT, n: *const BIGNUM, q: *const EC_POINT, m: *const BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn EC_POINT_point2oct(group: *const EC_GROUP, p: *const EC_POINT, form: point_conversion_form_t, buf: *mut c_uchar, len: size_t, ctx: *mut BN_CTX) -> size_t; + pub fn EC_POINT_oct2point(group: *const EC_GROUP, p: *mut EC_POINT, buf: *const c_uchar, len: size_t, ctx: *mut BN_CTX) -> c_int; + pub fn EC_POINT_cmp(group: *const EC_GROUP, a: *const EC_POINT, b: *const EC_POINT, ctx: *mut BN_CTX) -> c_int; pub fn EC_POINT_free(point: *mut EC_POINT); pub fn ERR_get_error() -> c_ulong; diff --git a/openssl/src/ec_key.rs b/openssl/src/ec_key.rs index e7e92d7a..f9b8f58c 100644 --- a/openssl/src/ec_key.rs +++ b/openssl/src/ec_key.rs @@ -1,12 +1,24 @@ use ffi; use std::ptr; -use {cvt, cvt_p, init}; +use {cvt, cvt_n, cvt_p, init}; use bn::{BigNumRef, BigNumContextRef}; use error::ErrorStack; use nid::Nid; use types::OpenSslTypeRef; +pub const POINT_CONVERSION_COMPRESSED: PointConversionForm = + PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_COMPRESSED); + +pub const POINT_CONVERSION_UNCOMPRESSED: PointConversionForm = + PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_UNCOMPRESSED); + +pub const POINT_CONVERSION_HYBRID: PointConversionForm = + PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_HYBRID); + +#[derive(Copy, Clone)] +pub struct PointConversionForm(ffi::point_conversion_form_t); + type_!(EcGroup, EcGroupRef, ffi::EC_GROUP, ffi::EC_GROUP_free); impl EcGroup { @@ -75,10 +87,133 @@ impl EcGroup { .map(|_| ()) } } + + /// Returns the degree of the curve. + pub fn degree(&self) -> u32 { + unsafe { ffi::EC_GROUP_get_degree(self.as_ptr()) as u32 } + } + + /// Places the order of the curve in the provided `BigNum`. + pub fn order(&self, + order: &mut BigNumRef, + ctx: &mut BigNumContextRef) + -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_GROUP_get_order(self.as_ptr(), order.as_ptr(), ctx.as_ptr())).map(|_| ()) + } + } } type_!(EcPoint, EcPointRef, ffi::EC_POINT, ffi::EC_POINT_free); +impl EcPointRef { + /// Computes `a + b`, storing the result in `self`. + pub fn add(&mut self, + group: &EcGroupRef, + a: &EcPointRef, + b: &EcPointRef, + ctx: &mut BigNumContextRef) + -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_POINT_add(group.as_ptr(), + self.as_ptr(), + a.as_ptr(), + b.as_ptr(), + ctx.as_ptr())) + .map(|_| ()) + } + } + + /// Computes `generator * n + q * m`, storing the result in `self`. + /// + /// If `n` is `None`, `q * m` will be computed instead. + pub fn mul(&mut self, + group: &EcGroupRef, + n: Option<&BigNumRef>, + q: &EcPointRef, + m: &BigNumRef, + ctx: &mut BigNumContextRef) + -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_POINT_mul(group.as_ptr(), + self.as_ptr(), + n.map_or(ptr::null(), |n| n.as_ptr()), + q.as_ptr(), + m.as_ptr(), + ctx.as_ptr())) + .map(|_| ()) + } + } + + /// Serializes the point to a binary representation. + pub fn to_bytes(&self, + group: &EcGroupRef, + form: PointConversionForm, + ctx: &mut BigNumContextRef) + -> Result, ErrorStack> { + unsafe { + let len = ffi::EC_POINT_point2oct(group.as_ptr(), + self.as_ptr(), + form.0, + ptr::null_mut(), + 0, + ctx.as_ptr()); + if len == 0 { + return Err(ErrorStack::get()); + } + let mut buf = vec![0; len]; + let len = ffi::EC_POINT_point2oct(group.as_ptr(), + self.as_ptr(), + form.0, + buf.as_mut_ptr(), + len, + ctx.as_ptr()); + if len == 0 { + Err(ErrorStack::get()) + } else { + Ok(buf) + } + } + } + + /// Determines if this point is equal to another. + pub fn eq(&self, + group: &EcGroupRef, + other: &EcPointRef, + ctx: &mut BigNumContextRef) + -> Result { + unsafe { + let res = try!(cvt_n(ffi::EC_POINT_cmp(group.as_ptr(), + self.as_ptr(), + other.as_ptr(), + ctx.as_ptr()))); + Ok(res == 0) + } + } +} + +impl EcPoint { + /// Creates a new point on the specified curve. + pub fn new(group: &EcGroupRef) -> Result { + unsafe { cvt_p(ffi::EC_POINT_new(group.as_ptr())).map(EcPoint) } + } + + pub fn from_bytes(group: &EcGroupRef, + buf: &[u8], + ctx: &mut BigNumContextRef) + -> Result { + let point = try!(EcPoint::new(group)); + unsafe { + try!(cvt(ffi::EC_POINT_oct2point(group.as_ptr(), + point.as_ptr(), + buf.as_ptr(), + buf.len(), + ctx.as_ptr()))); + } + Ok(point) + } +} + type_!(EcKey, EcKeyRef, ffi::EC_KEY, ffi::EC_KEY_free); impl EcKeyRef { @@ -119,7 +254,8 @@ impl EcKeyRef { impl EcKey { /// Constructs an `EcKey` corresponding to a known curve. /// - /// It will not have an associated public or private key. + /// It will not have an associated public or private key. This kind of key is primarily useful + /// to be provided to the `set_tmp_ecdh` methods on `Ssl` and `SslContextBuilder`. pub fn from_curve_name(nid: Nid) -> Result { unsafe { init(); @@ -175,4 +311,21 @@ mod test { key.public_key().unwrap(); key.private_key().unwrap(); } + + #[test] + fn point_new() { + let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); + EcPoint::new(&group).unwrap(); + } + + #[test] + fn point_bytes() { + let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); + let key = EcKey::generate(&group).unwrap(); + let point = key.public_key().unwrap(); + let mut ctx = BigNumContext::new().unwrap(); + let bytes = point.to_bytes(&group, POINT_CONVERSION_COMPRESSED, &mut ctx).unwrap(); + let point2 = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap(); + assert!(point.eq(&group, &point2, &mut ctx).unwrap()); + } } diff --git a/systest/build.rs b/systest/build.rs index 81907a57..120f103e 100644 --- a/systest/build.rs +++ b/systest/build.rs @@ -52,7 +52,7 @@ fn main() { format!("bio_info_cb*") } else if s == "_STACK" { format!("struct stack_st") - } else if is_struct && s.chars().next().unwrap().is_lowercase() { + } else if is_struct && s != "point_conversion_form_t" && s.chars().next().unwrap().is_lowercase() { format!("struct {}", s) } else { format!("{}", s) From 82eb3c4f516e1457ec2fec56a4233aa4542957cc Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 22:10:52 +0000 Subject: [PATCH 06/12] Add EcKey::check_key --- openssl-sys/src/lib.rs | 1 + openssl/src/ec_key.rs | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 6ba8668e..74d1d03f 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1391,6 +1391,7 @@ extern { pub fn EC_KEY_set_private_key(key: *mut EC_KEY, key: *const BIGNUM) -> c_int; pub fn EC_KEY_get0_private_key(key: *const EC_KEY) -> *const BIGNUM; pub fn EC_KEY_generate_key(key: *mut EC_KEY) -> c_int; + pub fn EC_KEY_check_key(key: *const EC_KEY) -> c_int; pub fn EC_KEY_free(key: *mut EC_KEY); pub fn EC_GFp_simple_method() -> *const EC_METHOD; diff --git a/openssl/src/ec_key.rs b/openssl/src/ec_key.rs index f9b8f58c..6cc95d11 100644 --- a/openssl/src/ec_key.rs +++ b/openssl/src/ec_key.rs @@ -249,6 +249,11 @@ impl EcKeyRef { } } } + + /// Checks the key for validity. + pub fn check_key(&self) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::EC_KEY_check_key(self.as_ptr())).map(|_| ()) } + } } impl EcKey { From e9e58b27dcbac5d456d4a080b0df31d9b8a5e236 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 22:14:10 +0000 Subject: [PATCH 07/12] Remove EC_METHOD functions Some appear not to be defined anywhere and they're not used anyway --- openssl-sys/src/lib.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 74d1d03f..5e90ed4f 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1394,13 +1394,6 @@ extern { pub fn EC_KEY_check_key(key: *const EC_KEY) -> c_int; pub fn EC_KEY_free(key: *mut EC_KEY); - pub fn EC_GFp_simple_method() -> *const EC_METHOD; - pub fn EC_GFp_mont_method() -> *const EC_METHOD; - pub fn EC_GFp_nist_method() -> *const EC_METHOD; - pub fn EC_GFp_nistp224_method() -> *const EC_METHOD; - pub fn EC_GFp_nistp256_method() -> *const EC_METHOD; - pub fn EC_GFp_nistp521_method() -> *const EC_METHOD; - pub fn EC_GF2m_simple_method() -> *const EC_METHOD; pub fn EC_GROUP_new(meth: *const EC_METHOD) -> *mut EC_GROUP; From 4c60aa005d1bcce1a0cb41df82422d9ac7c55815 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 14 Nov 2016 19:20:08 +0100 Subject: [PATCH 08/12] Fix non-static EcGroup method locations --- openssl/src/ec_key.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openssl/src/ec_key.rs b/openssl/src/ec_key.rs index 6cc95d11..215a89b5 100644 --- a/openssl/src/ec_key.rs +++ b/openssl/src/ec_key.rs @@ -53,7 +53,9 @@ impl EcGroup { .map(EcGroup) } } +} +impl EcGroupRef { /// Places the components of a curve over a prime field in the provided `BigNum`s. pub fn components_gfp(&self, p: &mut BigNumRef, From e929e092169dba0dfda26a957a38c61fa3e33eb2 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 14 Nov 2016 19:44:20 +0100 Subject: [PATCH 09/12] Add EcPoint::invert --- openssl-sys/src/lib.rs | 1 + openssl/src/ec_key.rs | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 5e90ed4f..33d06e4e 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1410,6 +1410,7 @@ extern { pub fn EC_POINT_new(group: *const EC_GROUP) -> *mut EC_POINT; pub fn EC_POINT_add(group: *const EC_GROUP, r: *mut EC_POINT, a: *const EC_POINT, b: *const EC_POINT, ctx: *mut BN_CTX) -> c_int; pub fn EC_POINT_mul(group: *const EC_GROUP, r: *mut EC_POINT, n: *const BIGNUM, q: *const EC_POINT, m: *const BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn EC_POINT_invert(group: *const EC_GROUP, r: *mut EC_POINT, ctx: *mut BN_CTX) -> c_int; pub fn EC_POINT_point2oct(group: *const EC_GROUP, p: *const EC_POINT, form: point_conversion_form_t, buf: *mut c_uchar, len: size_t, ctx: *mut BN_CTX) -> size_t; pub fn EC_POINT_oct2point(group: *const EC_GROUP, p: *mut EC_POINT, buf: *const c_uchar, len: size_t, ctx: *mut BN_CTX) -> c_int; pub fn EC_POINT_cmp(group: *const EC_GROUP, a: *const EC_POINT, b: *const EC_POINT, ctx: *mut BN_CTX) -> c_int; diff --git a/openssl/src/ec_key.rs b/openssl/src/ec_key.rs index 215a89b5..3b40496a 100644 --- a/openssl/src/ec_key.rs +++ b/openssl/src/ec_key.rs @@ -147,6 +147,13 @@ impl EcPointRef { } } + /// Inverts `self`. + pub fn invert(&mut self, group: &EcGroupRef, ctx: &BigNumContextRef) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_POINT_invert(group.as_ptr(), self.as_ptr(), ctx.as_ptr())).map(|_| ()) + } + } + /// Serializes the point to a binary representation. pub fn to_bytes(&self, group: &EcGroupRef, From 90acfaea513ad079119e7b3485a9a2e35702ad33 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 14 Nov 2016 22:08:04 +0100 Subject: [PATCH 10/12] Split EcKey::mul --- openssl/src/ec_key.rs | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/openssl/src/ec_key.rs b/openssl/src/ec_key.rs index 3b40496a..ae712430 100644 --- a/openssl/src/ec_key.rs +++ b/openssl/src/ec_key.rs @@ -126,20 +126,36 @@ impl EcPointRef { } } - /// Computes `generator * n + q * m`, storing the result in `self`. - /// - /// If `n` is `None`, `q * m` will be computed instead. + /// Computes `q * m`, storing the result in `self`. pub fn mul(&mut self, group: &EcGroupRef, - n: Option<&BigNumRef>, q: &EcPointRef, m: &BigNumRef, - ctx: &mut BigNumContextRef) + ctx: &BigNumContextRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EC_POINT_mul(group.as_ptr(), self.as_ptr(), - n.map_or(ptr::null(), |n| n.as_ptr()), + ptr::null(), + q.as_ptr(), + m.as_ptr(), + ctx.as_ptr())) + .map(|_| ()) + } + } + + /// Computes `generator * n + q * m`, storing the result in `self`. + pub fn mul_generator(&mut self, + group: &EcGroupRef, + n: &BigNumRef, + q: &EcPointRef, + m: &BigNumRef, + ctx: &mut BigNumContextRef) + -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_POINT_mul(group.as_ptr(), + self.as_ptr(), + n.as_ptr(), q.as_ptr(), m.as_ptr(), ctx.as_ptr())) From 6794a45d602def6812a70841f8b012445f62c7ac Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 14 Nov 2016 22:37:01 +0100 Subject: [PATCH 11/12] Rename ec_key to ec --- openssl/src/ec.rs | 361 ++++++++++++++++++++++++++++++++++ openssl/src/ec_key.rs | 362 +---------------------------------- openssl/src/lib.rs | 1 + openssl/src/pkey.rs | 4 +- openssl/src/ssl/connector.rs | 2 +- openssl/src/ssl/mod.rs | 4 +- openssl/src/ssl/tests/mod.rs | 4 +- 7 files changed, 371 insertions(+), 367 deletions(-) create mode 100644 openssl/src/ec.rs diff --git a/openssl/src/ec.rs b/openssl/src/ec.rs new file mode 100644 index 00000000..ae712430 --- /dev/null +++ b/openssl/src/ec.rs @@ -0,0 +1,361 @@ +use ffi; +use std::ptr; + +use {cvt, cvt_n, cvt_p, init}; +use bn::{BigNumRef, BigNumContextRef}; +use error::ErrorStack; +use nid::Nid; +use types::OpenSslTypeRef; + +pub const POINT_CONVERSION_COMPRESSED: PointConversionForm = + PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_COMPRESSED); + +pub const POINT_CONVERSION_UNCOMPRESSED: PointConversionForm = + PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_UNCOMPRESSED); + +pub const POINT_CONVERSION_HYBRID: PointConversionForm = + PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_HYBRID); + +#[derive(Copy, Clone)] +pub struct PointConversionForm(ffi::point_conversion_form_t); + +type_!(EcGroup, EcGroupRef, ffi::EC_GROUP, ffi::EC_GROUP_free); + +impl EcGroup { + /// Returns the group of a standard named curve. + pub fn from_curve_name(nid: Nid) -> Result { + unsafe { + init(); + cvt_p(ffi::EC_GROUP_new_by_curve_name(nid.as_raw())).map(EcGroup) + } + } + + /// Constructs a curve over a prime field from its components. + pub fn from_components_gfp(p: &BigNumRef, + a: &BigNumRef, + b: &BigNumRef, + ctx: &mut BigNumContextRef) + -> Result { + unsafe { + cvt_p(ffi::EC_GROUP_new_curve_GFp(p.as_ptr(), a.as_ptr(), b.as_ptr(), ctx.as_ptr())) + .map(EcGroup) + } + } + + /// Constructs a curve over a binary field from its components. + pub fn from_components_gf2m(p: &BigNumRef, + a: &BigNumRef, + b: &BigNumRef, + ctx: &mut BigNumContextRef) + -> Result { + unsafe { + cvt_p(ffi::EC_GROUP_new_curve_GF2m(p.as_ptr(), a.as_ptr(), b.as_ptr(), ctx.as_ptr())) + .map(EcGroup) + } + } +} + +impl EcGroupRef { + /// Places the components of a curve over a prime field in the provided `BigNum`s. + pub fn components_gfp(&self, + p: &mut BigNumRef, + a: &mut BigNumRef, + b: &mut BigNumRef, + ctx: &mut BigNumContextRef) + -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_GROUP_get_curve_GFp(self.as_ptr(), + p.as_ptr(), + a.as_ptr(), + b.as_ptr(), + ctx.as_ptr())) + .map(|_| ()) + } + } + + /// Places the components of a curve over a binary field in the provided `BigNum`s. + pub fn components_gf2m(&self, + p: &mut BigNumRef, + a: &mut BigNumRef, + b: &mut BigNumRef, + ctx: &mut BigNumContextRef) + -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_GROUP_get_curve_GF2m(self.as_ptr(), + p.as_ptr(), + a.as_ptr(), + b.as_ptr(), + ctx.as_ptr())) + .map(|_| ()) + } + } + + /// Returns the degree of the curve. + pub fn degree(&self) -> u32 { + unsafe { ffi::EC_GROUP_get_degree(self.as_ptr()) as u32 } + } + + /// Places the order of the curve in the provided `BigNum`. + pub fn order(&self, + order: &mut BigNumRef, + ctx: &mut BigNumContextRef) + -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_GROUP_get_order(self.as_ptr(), order.as_ptr(), ctx.as_ptr())).map(|_| ()) + } + } +} + +type_!(EcPoint, EcPointRef, ffi::EC_POINT, ffi::EC_POINT_free); + +impl EcPointRef { + /// Computes `a + b`, storing the result in `self`. + pub fn add(&mut self, + group: &EcGroupRef, + a: &EcPointRef, + b: &EcPointRef, + ctx: &mut BigNumContextRef) + -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_POINT_add(group.as_ptr(), + self.as_ptr(), + a.as_ptr(), + b.as_ptr(), + ctx.as_ptr())) + .map(|_| ()) + } + } + + /// Computes `q * m`, storing the result in `self`. + pub fn mul(&mut self, + group: &EcGroupRef, + q: &EcPointRef, + m: &BigNumRef, + ctx: &BigNumContextRef) + -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_POINT_mul(group.as_ptr(), + self.as_ptr(), + ptr::null(), + q.as_ptr(), + m.as_ptr(), + ctx.as_ptr())) + .map(|_| ()) + } + } + + /// Computes `generator * n + q * m`, storing the result in `self`. + pub fn mul_generator(&mut self, + group: &EcGroupRef, + n: &BigNumRef, + q: &EcPointRef, + m: &BigNumRef, + ctx: &mut BigNumContextRef) + -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_POINT_mul(group.as_ptr(), + self.as_ptr(), + n.as_ptr(), + q.as_ptr(), + m.as_ptr(), + ctx.as_ptr())) + .map(|_| ()) + } + } + + /// Inverts `self`. + pub fn invert(&mut self, group: &EcGroupRef, ctx: &BigNumContextRef) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_POINT_invert(group.as_ptr(), self.as_ptr(), ctx.as_ptr())).map(|_| ()) + } + } + + /// Serializes the point to a binary representation. + pub fn to_bytes(&self, + group: &EcGroupRef, + form: PointConversionForm, + ctx: &mut BigNumContextRef) + -> Result, ErrorStack> { + unsafe { + let len = ffi::EC_POINT_point2oct(group.as_ptr(), + self.as_ptr(), + form.0, + ptr::null_mut(), + 0, + ctx.as_ptr()); + if len == 0 { + return Err(ErrorStack::get()); + } + let mut buf = vec![0; len]; + let len = ffi::EC_POINT_point2oct(group.as_ptr(), + self.as_ptr(), + form.0, + buf.as_mut_ptr(), + len, + ctx.as_ptr()); + if len == 0 { + Err(ErrorStack::get()) + } else { + Ok(buf) + } + } + } + + /// Determines if this point is equal to another. + pub fn eq(&self, + group: &EcGroupRef, + other: &EcPointRef, + ctx: &mut BigNumContextRef) + -> Result { + unsafe { + let res = try!(cvt_n(ffi::EC_POINT_cmp(group.as_ptr(), + self.as_ptr(), + other.as_ptr(), + ctx.as_ptr()))); + Ok(res == 0) + } + } +} + +impl EcPoint { + /// Creates a new point on the specified curve. + pub fn new(group: &EcGroupRef) -> Result { + unsafe { cvt_p(ffi::EC_POINT_new(group.as_ptr())).map(EcPoint) } + } + + pub fn from_bytes(group: &EcGroupRef, + buf: &[u8], + ctx: &mut BigNumContextRef) + -> Result { + let point = try!(EcPoint::new(group)); + unsafe { + try!(cvt(ffi::EC_POINT_oct2point(group.as_ptr(), + point.as_ptr(), + buf.as_ptr(), + buf.len(), + ctx.as_ptr()))); + } + Ok(point) + } +} + +type_!(EcKey, EcKeyRef, ffi::EC_KEY, ffi::EC_KEY_free); + +impl EcKeyRef { + private_key_to_pem!(ffi::PEM_write_bio_ECPrivateKey); + private_key_to_der!(ffi::i2d_ECPrivateKey); + + pub fn group(&self) -> &EcGroupRef { + unsafe { + let ptr = ffi::EC_KEY_get0_group(self.as_ptr()); + assert!(!ptr.is_null()); + EcGroupRef::from_ptr(ptr as *mut _) + } + } + + pub fn public_key(&self) -> Option<&EcPointRef> { + unsafe { + let ptr = ffi::EC_KEY_get0_public_key(self.as_ptr()); + if ptr.is_null() { + None + } else { + Some(EcPointRef::from_ptr(ptr as *mut _)) + } + } + } + + pub fn private_key(&self) -> Option<&BigNumRef> { + unsafe { + let ptr = ffi::EC_KEY_get0_private_key(self.as_ptr()); + if ptr.is_null() { + None + } else { + Some(BigNumRef::from_ptr(ptr as *mut _)) + } + } + } + + /// Checks the key for validity. + pub fn check_key(&self) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::EC_KEY_check_key(self.as_ptr())).map(|_| ()) } + } +} + +impl EcKey { + /// Constructs an `EcKey` corresponding to a known curve. + /// + /// It will not have an associated public or private key. This kind of key is primarily useful + /// to be provided to the `set_tmp_ecdh` methods on `Ssl` and `SslContextBuilder`. + pub fn from_curve_name(nid: Nid) -> Result { + unsafe { + init(); + cvt_p(ffi::EC_KEY_new_by_curve_name(nid.as_raw())).map(EcKey) + } + } + + /// Generates a new public/private key pair on the specified curve. + pub fn generate(group: &EcGroupRef) -> Result { + unsafe { + let key = EcKey(try!(cvt_p(ffi::EC_KEY_new()))); + try!(cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr()))); + try!(cvt(ffi::EC_KEY_generate_key(key.as_ptr()))); + Ok(key) + } + } + + #[deprecated(since = "0.9.2", note = "use from_curve_name")] + pub fn new_by_curve_name(nid: Nid) -> Result { + EcKey::from_curve_name(nid) + } + + private_key_from_pem!(EcKey, ffi::PEM_read_bio_ECPrivateKey); + private_key_from_der!(EcKey, ffi::d2i_ECPrivateKey); +} + +#[cfg(test)] +mod test { + use bn::{BigNum, BigNumContext}; + use nid; + use super::*; + + #[test] + fn key_new_by_curve_name() { + EcKey::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); + } + + #[test] + fn round_trip_prime256v1() { + let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); + let mut p = BigNum::new().unwrap(); + let mut a = BigNum::new().unwrap(); + let mut b = BigNum::new().unwrap(); + let mut ctx = BigNumContext::new().unwrap(); + group.components_gfp(&mut p, &mut a, &mut b, &mut ctx).unwrap(); + EcGroup::from_components_gfp(&p, &a, &b, &mut ctx).unwrap(); + } + + #[test] + fn generate() { + let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); + let key = EcKey::generate(&group).unwrap(); + key.public_key().unwrap(); + key.private_key().unwrap(); + } + + #[test] + fn point_new() { + let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); + EcPoint::new(&group).unwrap(); + } + + #[test] + fn point_bytes() { + let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); + let key = EcKey::generate(&group).unwrap(); + let point = key.public_key().unwrap(); + let mut ctx = BigNumContext::new().unwrap(); + let bytes = point.to_bytes(&group, POINT_CONVERSION_COMPRESSED, &mut ctx).unwrap(); + let point2 = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap(); + assert!(point.eq(&group, &point2, &mut ctx).unwrap()); + } +} diff --git a/openssl/src/ec_key.rs b/openssl/src/ec_key.rs index ae712430..cb7c4996 100644 --- a/openssl/src/ec_key.rs +++ b/openssl/src/ec_key.rs @@ -1,361 +1,3 @@ -use ffi; -use std::ptr; +#![deprecated(since = "0.9.2", note = "renamed to `ec`")] -use {cvt, cvt_n, cvt_p, init}; -use bn::{BigNumRef, BigNumContextRef}; -use error::ErrorStack; -use nid::Nid; -use types::OpenSslTypeRef; - -pub const POINT_CONVERSION_COMPRESSED: PointConversionForm = - PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_COMPRESSED); - -pub const POINT_CONVERSION_UNCOMPRESSED: PointConversionForm = - PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_UNCOMPRESSED); - -pub const POINT_CONVERSION_HYBRID: PointConversionForm = - PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_HYBRID); - -#[derive(Copy, Clone)] -pub struct PointConversionForm(ffi::point_conversion_form_t); - -type_!(EcGroup, EcGroupRef, ffi::EC_GROUP, ffi::EC_GROUP_free); - -impl EcGroup { - /// Returns the group of a standard named curve. - pub fn from_curve_name(nid: Nid) -> Result { - unsafe { - init(); - cvt_p(ffi::EC_GROUP_new_by_curve_name(nid.as_raw())).map(EcGroup) - } - } - - /// Constructs a curve over a prime field from its components. - pub fn from_components_gfp(p: &BigNumRef, - a: &BigNumRef, - b: &BigNumRef, - ctx: &mut BigNumContextRef) - -> Result { - unsafe { - cvt_p(ffi::EC_GROUP_new_curve_GFp(p.as_ptr(), a.as_ptr(), b.as_ptr(), ctx.as_ptr())) - .map(EcGroup) - } - } - - /// Constructs a curve over a binary field from its components. - pub fn from_components_gf2m(p: &BigNumRef, - a: &BigNumRef, - b: &BigNumRef, - ctx: &mut BigNumContextRef) - -> Result { - unsafe { - cvt_p(ffi::EC_GROUP_new_curve_GF2m(p.as_ptr(), a.as_ptr(), b.as_ptr(), ctx.as_ptr())) - .map(EcGroup) - } - } -} - -impl EcGroupRef { - /// Places the components of a curve over a prime field in the provided `BigNum`s. - pub fn components_gfp(&self, - p: &mut BigNumRef, - a: &mut BigNumRef, - b: &mut BigNumRef, - ctx: &mut BigNumContextRef) - -> Result<(), ErrorStack> { - unsafe { - cvt(ffi::EC_GROUP_get_curve_GFp(self.as_ptr(), - p.as_ptr(), - a.as_ptr(), - b.as_ptr(), - ctx.as_ptr())) - .map(|_| ()) - } - } - - /// Places the components of a curve over a binary field in the provided `BigNum`s. - pub fn components_gf2m(&self, - p: &mut BigNumRef, - a: &mut BigNumRef, - b: &mut BigNumRef, - ctx: &mut BigNumContextRef) - -> Result<(), ErrorStack> { - unsafe { - cvt(ffi::EC_GROUP_get_curve_GF2m(self.as_ptr(), - p.as_ptr(), - a.as_ptr(), - b.as_ptr(), - ctx.as_ptr())) - .map(|_| ()) - } - } - - /// Returns the degree of the curve. - pub fn degree(&self) -> u32 { - unsafe { ffi::EC_GROUP_get_degree(self.as_ptr()) as u32 } - } - - /// Places the order of the curve in the provided `BigNum`. - pub fn order(&self, - order: &mut BigNumRef, - ctx: &mut BigNumContextRef) - -> Result<(), ErrorStack> { - unsafe { - cvt(ffi::EC_GROUP_get_order(self.as_ptr(), order.as_ptr(), ctx.as_ptr())).map(|_| ()) - } - } -} - -type_!(EcPoint, EcPointRef, ffi::EC_POINT, ffi::EC_POINT_free); - -impl EcPointRef { - /// Computes `a + b`, storing the result in `self`. - pub fn add(&mut self, - group: &EcGroupRef, - a: &EcPointRef, - b: &EcPointRef, - ctx: &mut BigNumContextRef) - -> Result<(), ErrorStack> { - unsafe { - cvt(ffi::EC_POINT_add(group.as_ptr(), - self.as_ptr(), - a.as_ptr(), - b.as_ptr(), - ctx.as_ptr())) - .map(|_| ()) - } - } - - /// Computes `q * m`, storing the result in `self`. - pub fn mul(&mut self, - group: &EcGroupRef, - q: &EcPointRef, - m: &BigNumRef, - ctx: &BigNumContextRef) - -> Result<(), ErrorStack> { - unsafe { - cvt(ffi::EC_POINT_mul(group.as_ptr(), - self.as_ptr(), - ptr::null(), - q.as_ptr(), - m.as_ptr(), - ctx.as_ptr())) - .map(|_| ()) - } - } - - /// Computes `generator * n + q * m`, storing the result in `self`. - pub fn mul_generator(&mut self, - group: &EcGroupRef, - n: &BigNumRef, - q: &EcPointRef, - m: &BigNumRef, - ctx: &mut BigNumContextRef) - -> Result<(), ErrorStack> { - unsafe { - cvt(ffi::EC_POINT_mul(group.as_ptr(), - self.as_ptr(), - n.as_ptr(), - q.as_ptr(), - m.as_ptr(), - ctx.as_ptr())) - .map(|_| ()) - } - } - - /// Inverts `self`. - pub fn invert(&mut self, group: &EcGroupRef, ctx: &BigNumContextRef) -> Result<(), ErrorStack> { - unsafe { - cvt(ffi::EC_POINT_invert(group.as_ptr(), self.as_ptr(), ctx.as_ptr())).map(|_| ()) - } - } - - /// Serializes the point to a binary representation. - pub fn to_bytes(&self, - group: &EcGroupRef, - form: PointConversionForm, - ctx: &mut BigNumContextRef) - -> Result, ErrorStack> { - unsafe { - let len = ffi::EC_POINT_point2oct(group.as_ptr(), - self.as_ptr(), - form.0, - ptr::null_mut(), - 0, - ctx.as_ptr()); - if len == 0 { - return Err(ErrorStack::get()); - } - let mut buf = vec![0; len]; - let len = ffi::EC_POINT_point2oct(group.as_ptr(), - self.as_ptr(), - form.0, - buf.as_mut_ptr(), - len, - ctx.as_ptr()); - if len == 0 { - Err(ErrorStack::get()) - } else { - Ok(buf) - } - } - } - - /// Determines if this point is equal to another. - pub fn eq(&self, - group: &EcGroupRef, - other: &EcPointRef, - ctx: &mut BigNumContextRef) - -> Result { - unsafe { - let res = try!(cvt_n(ffi::EC_POINT_cmp(group.as_ptr(), - self.as_ptr(), - other.as_ptr(), - ctx.as_ptr()))); - Ok(res == 0) - } - } -} - -impl EcPoint { - /// Creates a new point on the specified curve. - pub fn new(group: &EcGroupRef) -> Result { - unsafe { cvt_p(ffi::EC_POINT_new(group.as_ptr())).map(EcPoint) } - } - - pub fn from_bytes(group: &EcGroupRef, - buf: &[u8], - ctx: &mut BigNumContextRef) - -> Result { - let point = try!(EcPoint::new(group)); - unsafe { - try!(cvt(ffi::EC_POINT_oct2point(group.as_ptr(), - point.as_ptr(), - buf.as_ptr(), - buf.len(), - ctx.as_ptr()))); - } - Ok(point) - } -} - -type_!(EcKey, EcKeyRef, ffi::EC_KEY, ffi::EC_KEY_free); - -impl EcKeyRef { - private_key_to_pem!(ffi::PEM_write_bio_ECPrivateKey); - private_key_to_der!(ffi::i2d_ECPrivateKey); - - pub fn group(&self) -> &EcGroupRef { - unsafe { - let ptr = ffi::EC_KEY_get0_group(self.as_ptr()); - assert!(!ptr.is_null()); - EcGroupRef::from_ptr(ptr as *mut _) - } - } - - pub fn public_key(&self) -> Option<&EcPointRef> { - unsafe { - let ptr = ffi::EC_KEY_get0_public_key(self.as_ptr()); - if ptr.is_null() { - None - } else { - Some(EcPointRef::from_ptr(ptr as *mut _)) - } - } - } - - pub fn private_key(&self) -> Option<&BigNumRef> { - unsafe { - let ptr = ffi::EC_KEY_get0_private_key(self.as_ptr()); - if ptr.is_null() { - None - } else { - Some(BigNumRef::from_ptr(ptr as *mut _)) - } - } - } - - /// Checks the key for validity. - pub fn check_key(&self) -> Result<(), ErrorStack> { - unsafe { cvt(ffi::EC_KEY_check_key(self.as_ptr())).map(|_| ()) } - } -} - -impl EcKey { - /// Constructs an `EcKey` corresponding to a known curve. - /// - /// It will not have an associated public or private key. This kind of key is primarily useful - /// to be provided to the `set_tmp_ecdh` methods on `Ssl` and `SslContextBuilder`. - pub fn from_curve_name(nid: Nid) -> Result { - unsafe { - init(); - cvt_p(ffi::EC_KEY_new_by_curve_name(nid.as_raw())).map(EcKey) - } - } - - /// Generates a new public/private key pair on the specified curve. - pub fn generate(group: &EcGroupRef) -> Result { - unsafe { - let key = EcKey(try!(cvt_p(ffi::EC_KEY_new()))); - try!(cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr()))); - try!(cvt(ffi::EC_KEY_generate_key(key.as_ptr()))); - Ok(key) - } - } - - #[deprecated(since = "0.9.2", note = "use from_curve_name")] - pub fn new_by_curve_name(nid: Nid) -> Result { - EcKey::from_curve_name(nid) - } - - private_key_from_pem!(EcKey, ffi::PEM_read_bio_ECPrivateKey); - private_key_from_der!(EcKey, ffi::d2i_ECPrivateKey); -} - -#[cfg(test)] -mod test { - use bn::{BigNum, BigNumContext}; - use nid; - use super::*; - - #[test] - fn key_new_by_curve_name() { - EcKey::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); - } - - #[test] - fn round_trip_prime256v1() { - let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); - let mut p = BigNum::new().unwrap(); - let mut a = BigNum::new().unwrap(); - let mut b = BigNum::new().unwrap(); - let mut ctx = BigNumContext::new().unwrap(); - group.components_gfp(&mut p, &mut a, &mut b, &mut ctx).unwrap(); - EcGroup::from_components_gfp(&p, &a, &b, &mut ctx).unwrap(); - } - - #[test] - fn generate() { - let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); - let key = EcKey::generate(&group).unwrap(); - key.public_key().unwrap(); - key.private_key().unwrap(); - } - - #[test] - fn point_new() { - let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); - EcPoint::new(&group).unwrap(); - } - - #[test] - fn point_bytes() { - let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); - let key = EcKey::generate(&group).unwrap(); - let point = key.public_key().unwrap(); - let mut ctx = BigNumContext::new().unwrap(); - let bytes = point.to_bytes(&group, POINT_CONVERSION_COMPRESSED, &mut ctx).unwrap(); - let point2 = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap(); - assert!(point.eq(&group, &point2, &mut ctx).unwrap()); - } -} +pub use ec::{EcKey, EcKeyRef}; diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs index c2c559dc..995df34d 100644 --- a/openssl/src/lib.rs +++ b/openssl/src/lib.rs @@ -29,6 +29,7 @@ pub mod bn; pub mod crypto; pub mod dh; pub mod dsa; +pub mod ec; pub mod ec_key; pub mod error; pub mod hash; diff --git a/openssl/src/pkey.rs b/openssl/src/pkey.rs index 5739a5ed..7f031244 100644 --- a/openssl/src/pkey.rs +++ b/openssl/src/pkey.rs @@ -7,7 +7,7 @@ use {cvt, cvt_p}; use bio::MemBioSlice; use dh::Dh; use dsa::Dsa; -use ec_key::EcKey; +use ec::EcKey; use rsa::Rsa; use error::ErrorStack; use util::{CallbackState, invoke_passwd_cb_old}; @@ -153,7 +153,7 @@ mod tests { use symm::Cipher; use dh::Dh; use dsa::Dsa; - use ec_key::EcKey; + use ec::EcKey; use rsa::Rsa; use nid; diff --git a/openssl/src/ssl/connector.rs b/openssl/src/ssl/connector.rs index c002b966..043014c4 100644 --- a/openssl/src/ssl/connector.rs +++ b/openssl/src/ssl/connector.rs @@ -215,7 +215,7 @@ impl SslAcceptorBuilder { #[cfg(ossl101)] fn setup_curves(ctx: &mut SslContextBuilder) -> Result<(), ErrorStack> { - use ec_key::EcKey; + use ec::EcKey; use nid; let curve = try!(EcKey::from_curve_name(nid::X9_62_PRIME256V1)); diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 2c444400..ac41dec6 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -92,9 +92,9 @@ use std::sync::Mutex; use {init, cvt, cvt_p}; use dh::{Dh, DhRef}; -use ec_key::EcKeyRef; +use ec::EcKeyRef; #[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))] -use ec_key::EcKey; +use ec::EcKey; use x509::{X509StoreContextRef, X509FileType, X509, X509Ref, X509VerifyError, X509Name}; use x509::store::X509StoreBuilderRef; #[cfg(any(ossl102, ossl110))] diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index fb9a96b9..2f6bbe1f 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -1269,7 +1269,7 @@ fn tmp_dh_callback() { #[test] #[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))] fn tmp_ecdh_callback() { - use ec_key::EcKey; + use ec::EcKey; use nid; static CALLED_BACK: AtomicBool = ATOMIC_BOOL_INIT; @@ -1332,7 +1332,7 @@ fn tmp_dh_callback_ssl() { #[test] #[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))] fn tmp_ecdh_callback_ssl() { - use ec_key::EcKey; + use ec::EcKey; use nid; static CALLED_BACK: AtomicBool = ATOMIC_BOOL_INIT; From 6026396423c7239bd230a7bf9eb64c5d1b892799 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 15 Nov 2016 10:34:32 +0100 Subject: [PATCH 12/12] Add a note that the systest logic is kind of busted --- systest/build.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/systest/build.rs b/systest/build.rs index 120f103e..b0ca3250 100644 --- a/systest/build.rs +++ b/systest/build.rs @@ -52,6 +52,7 @@ fn main() { format!("bio_info_cb*") } else if s == "_STACK" { format!("struct stack_st") + // This logic should really be cleaned up } else if is_struct && s != "point_conversion_form_t" && s.chars().next().unwrap().is_lowercase() { format!("struct {}", s) } else {