diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 4ba706f9ebdf4d33822da0df5771913986895db9..33d06e4e8e718728200cf2a0f2a79dd4b734f2de 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 {} @@ -57,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, @@ -1371,9 +1382,40 @@ 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_check_key(key: *const EC_KEY) -> c_int; pub fn EC_KEY_free(key: *mut EC_KEY); + 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_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_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; + 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.rs b/openssl/src/ec.rs new file mode 100644 index 0000000000000000000000000000000000000000..ae712430ed63b1b4db70d945dcfa350949315961 --- /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 268a6fd2306a9fc20a2379d83032e8be9b9c546b..cb7c49960e02d27ab738f930d2c988b34db3a33f 100644 --- a/openssl/src/ec_key.rs +++ b/openssl/src/ec_key.rs @@ -1,37 +1,3 @@ -use ffi; -use std::ptr; +#![deprecated(since = "0.9.2", note = "renamed to `ec`")] -use {cvt, cvt_p, init}; -use error::ErrorStack; -use nid::Nid; -use types::OpenSslTypeRef; - -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); -} - -impl EcKey { - pub fn new_by_curve_name(nid: Nid) -> Result { - unsafe { - init(); - cvt_p(ffi::EC_KEY_new_by_curve_name(nid.as_raw())).map(EcKey) - } - } - - private_key_from_pem!(EcKey, ffi::PEM_read_bio_ECPrivateKey); - private_key_from_der!(EcKey, ffi::d2i_ECPrivateKey); -} - -#[cfg(test)] -mod test { - use nid; - use super::*; - - #[test] - fn new_by_curve_name() { - EcKey::new_by_curve_name(nid::X9_62_PRIME256V1).unwrap(); - } -} +pub use ec::{EcKey, EcKeyRef}; diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs index c2c559dc87379be58b67bd093f2d3066277f4df7..995df34df6151d1bc019a2bed8f11c95932dcf50 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 ee564836e9a6b7282d42b0bd12503b37725358fa..7f03124416d95dda055937b2bab052486a537406 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; @@ -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 07c44ce7adb59563c8c1d4e179eb6b90a90d30a9..043014c43ba9293b74eb68421de79415f8805ec8 100644 --- a/openssl/src/ssl/connector.rs +++ b/openssl/src/ssl/connector.rs @@ -215,10 +215,10 @@ 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::new_by_curve_name(nid::X9_62_PRIME256V1)); + let curve = try!(EcKey::from_curve_name(nid::X9_62_PRIME256V1)); ctx.set_tmp_ecdh(&curve) } diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 2c4444001cfbfca1204b813d933cb32dc93a5b50..ac41dec6dc7bbb6e9529728f7d61dc01fd19cff1 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 fb9a96b902204d92d11aa19cbd4e7df39e24b71e..2f6bbe1fbb9bce217b66b9da932cfba0cd33b610 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; diff --git a/systest/build.rs b/systest/build.rs index 81907a57a851330c447e841135d6b07ff9de22c3..b0ca3250e52972f96cd06320397a499efc4ecdd1 100644 --- a/systest/build.rs +++ b/systest/build.rs @@ -52,7 +52,8 @@ fn main() { format!("bio_info_cb*") } else if s == "_STACK" { format!("struct stack_st") - } else if is_struct && s.chars().next().unwrap().is_lowercase() { + // 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 { format!("{}", s)