diff --git a/openssl/src/nid.rs b/openssl/src/nid.rs index c5b9e277446df584de229a7244b056145ce21f9d..81cc49759602dbc70b38526e9866891c6b0ebb71 100644 --- a/openssl/src/nid.rs +++ b/openssl/src/nid.rs @@ -1,5 +1,5 @@ #[allow(non_camel_case_types)] -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Hash, PartialEq, Eq)] #[repr(usize)] pub enum Nid { Undefined, diff --git a/openssl/src/x509/extension.rs b/openssl/src/x509/extension.rs index b7f5fc527da147ba3779de29d52e071fddf39f42..4f8a3c3bd917a28d979d1a84197c57fc8dec4a14 100644 --- a/openssl/src/x509/extension.rs +++ b/openssl/src/x509/extension.rs @@ -1,4 +1,11 @@ use std::fmt; +use nid::Nid; + +#[derive(Clone,Copy,Hash,PartialEq,Eq)] +pub enum ExtensionType { + KeyUsage, + ExtKeyUsage, +} #[derive(Clone)] pub enum Extension { @@ -6,6 +13,41 @@ pub enum Extension { ExtKeyUsage(Vec), } +impl Extension { + pub fn get_type(&self) -> ExtensionType { + match self { + &Extension::KeyUsage(_) => ExtensionType::KeyUsage, + &Extension::ExtKeyUsage(_) => ExtensionType::ExtKeyUsage, + } + } + + pub fn get_nid(&self) -> Nid { + match self { + &Extension::KeyUsage(_) => Nid::KeyUsage, + &Extension::ExtKeyUsage(_) => Nid::ExtendedKeyUsage, + } + } +} + +// FIXME: This would be nicer as a method on Iterator. This can +// eventually be replaced by the successor to std::slice::SliceConcatExt.connect +fn join,T: ToString>(iter: I, sep: &str) -> String { + iter.enumerate().fold(String::new(), |mut acc, (idx, v)| { + if idx > 0 { acc.push_str(sep) }; + acc.push_str(&v.to_string()); + acc + }) +} + +impl ToString for Extension { + fn to_string(&self) -> String { + match self { + &Extension::KeyUsage(ref purposes) => join(purposes.iter(),","), + &Extension::ExtKeyUsage(ref purposes) => join(purposes.iter(),","), + } + } +} + #[derive(Clone,Copy)] pub enum KeyUsageOption { DigitalSignature, diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index 864e94c804be229cbb21e7abe47d7284f48f90c6..7d936f7e43694d189a4970a87f78d1be65d18bd6 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -9,6 +9,7 @@ use std::ptr; use std::ops::Deref; use std::fmt; use std::str; +use std::collections::HashMap; use asn1::{Asn1Time}; use bio::{MemBio}; @@ -22,6 +23,8 @@ use nid; mod extension; +use self::extension::{ExtensionType,Extension}; + #[cfg(test)] mod tests; @@ -103,16 +106,6 @@ impl X509StoreContext { pub use self::extension::KeyUsageOption as KeyUsage; pub use self::extension::ExtKeyUsageOption as ExtKeyUsage; -// FIXME: This would be nicer as a method on Iterator. This can -// eventually be replaced by the successor to std::slice::SliceConcatExt.connect -fn join,T: ToString>(iter: I, sep: &str) -> String { - iter.enumerate().fold(String::new(), |mut acc, (idx, v)| { - if idx > 0 { acc.push_str(sep) }; - acc.push_str(&v.to_string()); - acc - }) -} - #[allow(non_snake_case)] /// Generator of private key/certificate pairs /// @@ -153,8 +146,8 @@ pub struct X509Generator { bits: u32, days: u32, CN: String, - key_usage: Vec, - ext_key_usage: Vec, + // RFC 3280 ยง4.2: A certificate MUST NOT include more than one instance of a particular extension. + extensions: HashMap, hash_type: HashType, } @@ -173,8 +166,7 @@ impl X509Generator { bits: 1024, days: 365, CN: "rust-openssl".to_string(), - key_usage: Vec::new(), - ext_key_usage: Vec::new(), + extensions: HashMap::new(), hash_type: HashType::SHA1 } } @@ -200,13 +192,13 @@ impl X509Generator { /// Sets what for certificate could be used pub fn set_usage(mut self, purposes: &[KeyUsage]) -> X509Generator { - self.key_usage = purposes.to_vec(); + self.extensions.insert(ExtensionType::KeyUsage,Extension::KeyUsage(purposes.to_owned())); self } /// Sets allowed extended usage of certificate pub fn set_ext_usage(mut self, purposes: &[ExtKeyUsage]) -> X509Generator { - self.ext_key_usage = purposes.to_vec(); + self.extensions.insert(ExtensionType::ExtKeyUsage,Extension::ExtKeyUsage(purposes.to_owned())); self } @@ -304,14 +296,8 @@ impl X509Generator { try!(X509Generator::add_name(name, "CN", &self.CN)); ffi::X509_set_issuer_name(x509.handle, name); - if self.key_usage.len() > 0 { - try!(X509Generator::add_extension(x509.handle, ffi::NID_key_usage, - &join(self.key_usage.iter(),","))); - } - - if self.ext_key_usage.len() > 0 { - try!(X509Generator::add_extension(x509.handle, ffi::NID_ext_key_usage, - &join(self.ext_key_usage.iter(),","))); + for ext in self.extensions.values() { + try!(X509Generator::add_extension(x509.handle, ext.get_nid() as c_int, &ext.to_string())); } let hash_fn = self.hash_type.evp_md();