Loading openssl-sys/src/lib.rs +1 −0 Original line number Diff line number Diff line Loading @@ -603,6 +603,7 @@ extern "C" { pub fn X509_STORE_CTX_get_ex_data(ctx: *mut X509_STORE_CTX, idx: c_int) -> *mut c_void; pub fn X509V3_EXT_conf_nid(conf: *mut c_void, ctx: *mut X509V3_CTX, ext_nid: c_int, value: *mut c_char) -> *mut X509_EXTENSION; pub fn X509V3_EXT_conf(conf: *mut c_void, ctx: *mut X509V3_CTX, name: *mut c_char, value: *mut c_char) -> *mut X509_EXTENSION; pub fn X509V3_set_ctx(ctx: *mut X509V3_CTX, issuer: *mut X509, subject: *mut X509, req: *mut X509_REQ, crl: *mut X509_CRL, flags: c_int); pub fn i2d_RSA_PUBKEY(k: *mut RSA, buf: *const *mut u8) -> c_int; Loading openssl/src/nid.rs +1 −1 Original line number Diff line number Diff line #[allow(non_camel_case_types)] #[derive(Copy, Clone)] #[derive(Copy, Clone, Hash, PartialEq, Eq)] #[repr(usize)] pub enum Nid { Undefined, Loading openssl/src/x509/extension.rs 0 → 100644 +212 −0 Original line number Diff line number Diff line use std::fmt; use nid::Nid; /// Type-only version of the `Extension` enum. /// /// See the `Extension` documentation for more information on the different /// variants. #[derive(Clone,Hash,PartialEq,Eq)] pub enum ExtensionType { KeyUsage, ExtKeyUsage, SubjectAltName, IssuerAltName, OtherNid(Nid), OtherStr(String), } /// A X.509 v3 certificate extension. /// /// Only one extension of each type is allow in a certificate. /// See RFC 3280 for more information about extensions. #[derive(Clone)] pub enum Extension { /// The purposes of the key contained in the certificate KeyUsage(Vec<KeyUsageOption>), /// The extended purposes of the key contained in the certificate ExtKeyUsage(Vec<ExtKeyUsageOption>), /// Subject Alternative Names SubjectAltName(Vec<(AltNameOption,String)>), /// Issuer Alternative Names IssuerAltName(Vec<(AltNameOption,String)>), /// Arbitrary extensions by NID. See `man x509v3_config` for value syntax. /// /// You must not use this to add extensions which this enum can express directly. /// /// ``` /// use openssl::x509::extension::Extension::*; /// use openssl::nid::Nid; /// /// # let generator = openssl::x509::X509Generator::new(); /// generator.add_extension(OtherNid(Nid::BasicConstraints,"critical,CA:TRUE".to_owned())); /// ``` OtherNid(Nid,String), /// Arbitrary extensions by OID string. See `man ASN1_generate_nconf` for value syntax. /// /// You must not use this to add extensions which this enum can express directly. /// /// ``` /// use openssl::x509::extension::Extension::*; /// /// # let generator = openssl::x509::X509Generator::new(); /// generator.add_extension(OtherStr("2.999.2".to_owned(),"ASN1:UTF8:example value".to_owned())); /// ``` OtherStr(String,String), } impl Extension { pub fn get_type(&self) -> ExtensionType { match self { &Extension::KeyUsage(_) => ExtensionType::KeyUsage, &Extension::ExtKeyUsage(_) => ExtensionType::ExtKeyUsage, &Extension::SubjectAltName(_) => ExtensionType::SubjectAltName, &Extension::IssuerAltName(_) => ExtensionType::IssuerAltName, &Extension::OtherNid(nid,_) => ExtensionType::OtherNid(nid), &Extension::OtherStr(ref s,_) => ExtensionType::OtherStr(s.clone()), } } } impl ExtensionType { pub fn get_nid(&self) -> Option<Nid> { match self { &ExtensionType::KeyUsage => Some(Nid::KeyUsage), &ExtensionType::ExtKeyUsage => Some(Nid::ExtendedKeyUsage), &ExtensionType::SubjectAltName => Some(Nid::SubjectAltName), &ExtensionType::IssuerAltName => Some(Nid::IssuerAltName), &ExtensionType::OtherNid(nid) => Some(nid), &ExtensionType::OtherStr(_) => None, } } pub fn get_name<'a>(&'a self) -> Option<&'a str> { match self { &ExtensionType::OtherStr(ref s) => Some(s), _ => None, } } } // FIXME: This would be nicer as a method on Iterator<Item=ToString>. This can // eventually be replaced by the successor to std::slice::SliceConcatExt.connect fn join<I: Iterator<Item=T>,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(),","), &Extension::SubjectAltName(ref names) => join(names.iter().map(|&(ref opt,ref val)|opt.to_string()+":"+&val),","), &Extension::IssuerAltName(ref names) => join(names.iter().map(|&(ref opt,ref val)|opt.to_string()+":"+&val),","), &Extension::OtherNid(_,ref value) => value.clone(), &Extension::OtherStr(_,ref value) => value.clone(), } } } #[derive(Clone,Copy)] pub enum KeyUsageOption { DigitalSignature, NonRepudiation, KeyEncipherment, DataEncipherment, KeyAgreement, KeyCertSign, CRLSign, EncipherOnly, DecipherOnly, } impl fmt::Display for KeyUsageOption { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { f.pad(match self { &KeyUsageOption::DigitalSignature => "digitalSignature", &KeyUsageOption::NonRepudiation => "nonRepudiation", &KeyUsageOption::KeyEncipherment => "keyEncipherment", &KeyUsageOption::DataEncipherment => "dataEncipherment", &KeyUsageOption::KeyAgreement => "keyAgreement", &KeyUsageOption::KeyCertSign => "keyCertSign", &KeyUsageOption::CRLSign => "cRLSign", &KeyUsageOption::EncipherOnly => "encipherOnly", &KeyUsageOption::DecipherOnly => "decipherOnly", }) } } #[derive(Clone)] pub enum ExtKeyUsageOption { ServerAuth, ClientAuth, CodeSigning, EmailProtection, TimeStamping, MsCodeInd, MsCodeCom, MsCtlSign, MsSgc, MsEfs, NsSgc, /// An arbitrary key usage by OID. Other(String), } impl fmt::Display for ExtKeyUsageOption { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { f.pad(match self { &ExtKeyUsageOption::ServerAuth => "serverAuth", &ExtKeyUsageOption::ClientAuth => "clientAuth", &ExtKeyUsageOption::CodeSigning => "codeSigning", &ExtKeyUsageOption::EmailProtection => "emailProtection", &ExtKeyUsageOption::TimeStamping => "timeStamping", &ExtKeyUsageOption::MsCodeInd => "msCodeInd", &ExtKeyUsageOption::MsCodeCom => "msCodeCom", &ExtKeyUsageOption::MsCtlSign => "msCTLSign", &ExtKeyUsageOption::MsSgc => "msSGC", &ExtKeyUsageOption::MsEfs => "msEFS", &ExtKeyUsageOption::NsSgc =>"nsSGC", &ExtKeyUsageOption::Other(ref s) => &s[..], }) } } #[derive(Clone, Copy)] pub enum AltNameOption { /// The value is specified as OID;content. See `man ASN1_generate_nconf` for more information on the content syntax. /// /// ``` /// use openssl::x509::extension::Extension::*; /// use openssl::x509::extension::AltNameOption::Other as OtherName; /// /// # let generator = openssl::x509::X509Generator::new(); /// generator.add_extension(SubjectAltName(vec![(OtherName,"2.999.3;ASN1:UTF8:some other name".to_owned())])); /// ``` Other, Email, DNS, //X400, // Not supported by OpenSSL Directory, //EDIParty, // Not supported by OpenSSL URI, IPAddress, RegisteredID, } impl fmt::Display for AltNameOption { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { f.pad(match self { &AltNameOption::Other => "otherName", &AltNameOption::Email => "email", &AltNameOption::DNS => "DNS", &AltNameOption::Directory => "dirName", &AltNameOption::URI => "URI", &AltNameOption::IPAddress => "IP", &AltNameOption::RegisteredID => "RID", }) } } openssl/src/x509/mod.rs +63 −109 Original line number Diff line number Diff line Loading @@ -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}; Loading @@ -20,6 +21,9 @@ use ffi; use ssl::error::{SslError, StreamError}; use nid; pub mod extension; use self::extension::{ExtensionType,Extension}; #[cfg(test)] mod tests; Loading Loading @@ -98,92 +102,9 @@ impl X509StoreContext { } } #[doc(hidden)] trait AsStr<'a> { fn as_str(&self) -> &'a str; } #[derive(Clone, Copy)] pub enum KeyUsage { DigitalSignature, NonRepudiation, KeyEncipherment, DataEncipherment, KeyAgreement, KeyCertSign, CRLSign, EncipherOnly, DecipherOnly } impl AsStr<'static> for KeyUsage { fn as_str(&self) -> &'static str { match self { &KeyUsage::DigitalSignature => "digitalSignature", &KeyUsage::NonRepudiation => "nonRepudiation", &KeyUsage::KeyEncipherment => "keyEncipherment", &KeyUsage::DataEncipherment => "dataEncipherment", &KeyUsage::KeyAgreement => "keyAgreement", &KeyUsage::KeyCertSign => "keyCertSign", &KeyUsage::CRLSign => "cRLSign", &KeyUsage::EncipherOnly => "encipherOnly", &KeyUsage::DecipherOnly => "decipherOnly" } } } #[derive(Clone, Copy)] pub enum ExtKeyUsage { ServerAuth, ClientAuth, CodeSigning, EmailProtection, TimeStamping, MsCodeInd, MsCodeCom, MsCtlSign, MsSgc, MsEfs, NsSgc } impl AsStr<'static> for ExtKeyUsage { fn as_str(&self) -> &'static str { match self { &ExtKeyUsage::ServerAuth => "serverAuth", &ExtKeyUsage::ClientAuth => "clientAuth", &ExtKeyUsage::CodeSigning => "codeSigning", &ExtKeyUsage::EmailProtection => "emailProtection", &ExtKeyUsage::TimeStamping => "timeStamping", &ExtKeyUsage::MsCodeInd => "msCodeInd", &ExtKeyUsage::MsCodeCom => "msCodeCom", &ExtKeyUsage::MsCtlSign => "msCTLSign", &ExtKeyUsage::MsSgc => "msSGC", &ExtKeyUsage::MsEfs => "msEFS", &ExtKeyUsage::NsSgc =>"nsSGC" } } } // FIXME: a dirty hack as there is no way to // implement ToString for Vec as both are defined // in another crate #[doc(hidden)] trait ToStr { fn to_str(&self) -> String; } impl<'a, T: AsStr<'a>> ToStr for Vec<T> { fn to_str(&self) -> String { self.iter().enumerate().fold(String::new(), |mut acc, (idx, v)| { if idx > 0 { acc.push(',') }; acc.push_str(v.as_str()); acc }) } } // Backwards-compatibility pub use self::extension::KeyUsageOption as KeyUsage; pub use self::extension::ExtKeyUsageOption as ExtKeyUsage; #[allow(non_snake_case)] /// Generator of private key/certificate pairs Loading Loading @@ -225,8 +146,8 @@ pub struct X509Generator { bits: u32, days: u32, CN: String, key_usage: Vec<KeyUsage>, ext_key_usage: Vec<ExtKeyUsage>, // RFC 3280 §4.2: A certificate MUST NOT include more than one instance of a particular extension. extensions: HashMap<ExtensionType,Extension>, hash_type: HashType, } Loading @@ -245,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 } } Loading @@ -270,15 +190,50 @@ impl X509Generator { self } /// Sets what for certificate could be used pub fn set_usage(mut self, purposes: &[KeyUsage]) -> X509Generator { self.key_usage = purposes.to_vec(); /// (deprecated) Sets what for certificate could be used /// /// This function is deprecated, use `X509Generator.add_extension` instead. pub fn set_usage(self, purposes: &[KeyUsage]) -> X509Generator { self.add_extension(Extension::KeyUsage(purposes.to_owned())) } /// (deprecated) Sets allowed extended usage of certificate /// /// This function is deprecated, use `X509Generator.add_extension` instead. pub fn set_ext_usage(self, purposes: &[ExtKeyUsage]) -> X509Generator { self.add_extension(Extension::ExtKeyUsage(purposes.to_owned())) } /// Add an extension to a certificate /// /// If the extension already exists, it will be replaced. /// /// ``` /// use openssl::x509::extension::Extension::*; /// use openssl::x509::extension::KeyUsageOption::*; /// /// # let generator = openssl::x509::X509Generator::new(); /// generator.add_extension(KeyUsage(vec![DigitalSignature, KeyEncipherment])); /// ``` pub fn add_extension(mut self, ext: extension::Extension) -> X509Generator { self.extensions.insert(ext.get_type(),ext); self } /// Sets allowed extended usage of certificate pub fn set_ext_usage(mut self, purposes: &[ExtKeyUsage]) -> X509Generator { self.ext_key_usage = purposes.to_vec(); /// Add multiple extensions to a certificate /// /// If any of the extensions already exist, they will be replaced. /// /// ``` /// use openssl::x509::extension::Extension::*; /// use openssl::x509::extension::KeyUsageOption::*; /// /// # let generator = openssl::x509::X509Generator::new(); /// generator.add_extensions(vec![KeyUsage(vec![DigitalSignature, KeyEncipherment])]); /// ``` pub fn add_extensions<I>(mut self, exts: I) -> X509Generator where I: IntoIterator<Item=extension::Extension> { self.extensions.extend(exts.into_iter().map(|ext|(ext.get_type(),ext))); self } Loading @@ -287,17 +242,22 @@ impl X509Generator { self } fn add_extension(x509: *mut ffi::X509, extension: c_int, value: &str) -> Result<(), SslError> { fn add_extension_internal(x509: *mut ffi::X509, exttype: &extension::ExtensionType, value: &str) -> Result<(), SslError> { unsafe { let mut ctx: ffi::X509V3_CTX = mem::zeroed(); ffi::X509V3_set_ctx(&mut ctx, x509, x509, ptr::null_mut(), ptr::null_mut(), 0); let value = CString::new(value.as_bytes()).unwrap(); let ext = ffi::X509V3_EXT_conf_nid(ptr::null_mut(), let ext=match exttype.get_nid() { Some(nid) => ffi::X509V3_EXT_conf_nid(ptr::null_mut(), mem::transmute(&ctx), extension, value.as_ptr() as *mut c_char); nid as c_int, value.as_ptr() as *mut c_char), None => ffi::X509V3_EXT_conf(ptr::null_mut(), mem::transmute(&ctx), exttype.get_name().unwrap().as_ptr() as *mut c_char, value.as_ptr() as *mut c_char), }; let mut success = false; if ext != ptr::null_mut() { success = ffi::X509_add_ext(x509, ext, -1) != 0; Loading Loading @@ -376,14 +336,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, &self.key_usage.to_str())); } if self.ext_key_usage.len() > 0 { try!(X509Generator::add_extension(x509.handle, ffi::NID_ext_key_usage, &self.ext_key_usage.to_str())); for (exttype,ext) in self.extensions.iter() { try!(X509Generator::add_extension_internal(x509.handle, exttype, &ext.to_string())); } let hash_fn = self.hash_type.evp_md(); Loading openssl/src/x509/tests.rs +13 −12 Original line number Diff line number Diff line Loading @@ -5,8 +5,10 @@ use std::fs::File; use crypto::hash::Type::{SHA256}; use x509::{X509, X509Generator}; use x509::KeyUsage::{DigitalSignature, KeyEncipherment}; use x509::ExtKeyUsage::{ClientAuth, ServerAuth}; use x509::extension::Extension::{KeyUsage,ExtKeyUsage,SubjectAltName,OtherNid,OtherStr}; use x509::extension::AltNameOption as SAN; use x509::extension::KeyUsageOption::{DigitalSignature, KeyEncipherment}; use x509::extension::ExtKeyUsageOption::{self, ClientAuth, ServerAuth}; use nid::Nid; #[test] Loading @@ -16,16 +18,15 @@ fn test_cert_gen() { .set_valid_period(365*2) .set_CN("test_me") .set_sign_hash(SHA256) .set_usage(&[DigitalSignature, KeyEncipherment]) .set_ext_usage(&[ClientAuth, ServerAuth]); let res = gen.generate(); assert!(res.is_ok()); let (cert, pkey) = res.unwrap(); assert!(cert.write_pem(&mut io::sink()).is_ok()); assert!(pkey.write_pem(&mut io::sink()).is_ok()); .add_extension(KeyUsage(vec![DigitalSignature, KeyEncipherment])) .add_extension(ExtKeyUsage(vec![ClientAuth, ServerAuth, ExtKeyUsageOption::Other("2.999.1".to_owned())])) .add_extension(SubjectAltName(vec![(SAN::DNS,"example.com".to_owned())])) .add_extension(OtherNid(Nid::BasicConstraints,"critical,CA:TRUE".to_owned())) .add_extension(OtherStr("2.999.2".to_owned(),"ASN1:UTF8:example value".to_owned())); let (cert, pkey) = gen.generate().unwrap(); cert.write_pem(&mut io::sink()).unwrap(); pkey.write_pem(&mut io::sink()).unwrap(); // FIXME: check data in result to be correct, needs implementation // of X509 getters Loading Loading
openssl-sys/src/lib.rs +1 −0 Original line number Diff line number Diff line Loading @@ -603,6 +603,7 @@ extern "C" { pub fn X509_STORE_CTX_get_ex_data(ctx: *mut X509_STORE_CTX, idx: c_int) -> *mut c_void; pub fn X509V3_EXT_conf_nid(conf: *mut c_void, ctx: *mut X509V3_CTX, ext_nid: c_int, value: *mut c_char) -> *mut X509_EXTENSION; pub fn X509V3_EXT_conf(conf: *mut c_void, ctx: *mut X509V3_CTX, name: *mut c_char, value: *mut c_char) -> *mut X509_EXTENSION; pub fn X509V3_set_ctx(ctx: *mut X509V3_CTX, issuer: *mut X509, subject: *mut X509, req: *mut X509_REQ, crl: *mut X509_CRL, flags: c_int); pub fn i2d_RSA_PUBKEY(k: *mut RSA, buf: *const *mut u8) -> c_int; Loading
openssl/src/nid.rs +1 −1 Original line number Diff line number Diff line #[allow(non_camel_case_types)] #[derive(Copy, Clone)] #[derive(Copy, Clone, Hash, PartialEq, Eq)] #[repr(usize)] pub enum Nid { Undefined, Loading
openssl/src/x509/extension.rs 0 → 100644 +212 −0 Original line number Diff line number Diff line use std::fmt; use nid::Nid; /// Type-only version of the `Extension` enum. /// /// See the `Extension` documentation for more information on the different /// variants. #[derive(Clone,Hash,PartialEq,Eq)] pub enum ExtensionType { KeyUsage, ExtKeyUsage, SubjectAltName, IssuerAltName, OtherNid(Nid), OtherStr(String), } /// A X.509 v3 certificate extension. /// /// Only one extension of each type is allow in a certificate. /// See RFC 3280 for more information about extensions. #[derive(Clone)] pub enum Extension { /// The purposes of the key contained in the certificate KeyUsage(Vec<KeyUsageOption>), /// The extended purposes of the key contained in the certificate ExtKeyUsage(Vec<ExtKeyUsageOption>), /// Subject Alternative Names SubjectAltName(Vec<(AltNameOption,String)>), /// Issuer Alternative Names IssuerAltName(Vec<(AltNameOption,String)>), /// Arbitrary extensions by NID. See `man x509v3_config` for value syntax. /// /// You must not use this to add extensions which this enum can express directly. /// /// ``` /// use openssl::x509::extension::Extension::*; /// use openssl::nid::Nid; /// /// # let generator = openssl::x509::X509Generator::new(); /// generator.add_extension(OtherNid(Nid::BasicConstraints,"critical,CA:TRUE".to_owned())); /// ``` OtherNid(Nid,String), /// Arbitrary extensions by OID string. See `man ASN1_generate_nconf` for value syntax. /// /// You must not use this to add extensions which this enum can express directly. /// /// ``` /// use openssl::x509::extension::Extension::*; /// /// # let generator = openssl::x509::X509Generator::new(); /// generator.add_extension(OtherStr("2.999.2".to_owned(),"ASN1:UTF8:example value".to_owned())); /// ``` OtherStr(String,String), } impl Extension { pub fn get_type(&self) -> ExtensionType { match self { &Extension::KeyUsage(_) => ExtensionType::KeyUsage, &Extension::ExtKeyUsage(_) => ExtensionType::ExtKeyUsage, &Extension::SubjectAltName(_) => ExtensionType::SubjectAltName, &Extension::IssuerAltName(_) => ExtensionType::IssuerAltName, &Extension::OtherNid(nid,_) => ExtensionType::OtherNid(nid), &Extension::OtherStr(ref s,_) => ExtensionType::OtherStr(s.clone()), } } } impl ExtensionType { pub fn get_nid(&self) -> Option<Nid> { match self { &ExtensionType::KeyUsage => Some(Nid::KeyUsage), &ExtensionType::ExtKeyUsage => Some(Nid::ExtendedKeyUsage), &ExtensionType::SubjectAltName => Some(Nid::SubjectAltName), &ExtensionType::IssuerAltName => Some(Nid::IssuerAltName), &ExtensionType::OtherNid(nid) => Some(nid), &ExtensionType::OtherStr(_) => None, } } pub fn get_name<'a>(&'a self) -> Option<&'a str> { match self { &ExtensionType::OtherStr(ref s) => Some(s), _ => None, } } } // FIXME: This would be nicer as a method on Iterator<Item=ToString>. This can // eventually be replaced by the successor to std::slice::SliceConcatExt.connect fn join<I: Iterator<Item=T>,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(),","), &Extension::SubjectAltName(ref names) => join(names.iter().map(|&(ref opt,ref val)|opt.to_string()+":"+&val),","), &Extension::IssuerAltName(ref names) => join(names.iter().map(|&(ref opt,ref val)|opt.to_string()+":"+&val),","), &Extension::OtherNid(_,ref value) => value.clone(), &Extension::OtherStr(_,ref value) => value.clone(), } } } #[derive(Clone,Copy)] pub enum KeyUsageOption { DigitalSignature, NonRepudiation, KeyEncipherment, DataEncipherment, KeyAgreement, KeyCertSign, CRLSign, EncipherOnly, DecipherOnly, } impl fmt::Display for KeyUsageOption { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { f.pad(match self { &KeyUsageOption::DigitalSignature => "digitalSignature", &KeyUsageOption::NonRepudiation => "nonRepudiation", &KeyUsageOption::KeyEncipherment => "keyEncipherment", &KeyUsageOption::DataEncipherment => "dataEncipherment", &KeyUsageOption::KeyAgreement => "keyAgreement", &KeyUsageOption::KeyCertSign => "keyCertSign", &KeyUsageOption::CRLSign => "cRLSign", &KeyUsageOption::EncipherOnly => "encipherOnly", &KeyUsageOption::DecipherOnly => "decipherOnly", }) } } #[derive(Clone)] pub enum ExtKeyUsageOption { ServerAuth, ClientAuth, CodeSigning, EmailProtection, TimeStamping, MsCodeInd, MsCodeCom, MsCtlSign, MsSgc, MsEfs, NsSgc, /// An arbitrary key usage by OID. Other(String), } impl fmt::Display for ExtKeyUsageOption { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { f.pad(match self { &ExtKeyUsageOption::ServerAuth => "serverAuth", &ExtKeyUsageOption::ClientAuth => "clientAuth", &ExtKeyUsageOption::CodeSigning => "codeSigning", &ExtKeyUsageOption::EmailProtection => "emailProtection", &ExtKeyUsageOption::TimeStamping => "timeStamping", &ExtKeyUsageOption::MsCodeInd => "msCodeInd", &ExtKeyUsageOption::MsCodeCom => "msCodeCom", &ExtKeyUsageOption::MsCtlSign => "msCTLSign", &ExtKeyUsageOption::MsSgc => "msSGC", &ExtKeyUsageOption::MsEfs => "msEFS", &ExtKeyUsageOption::NsSgc =>"nsSGC", &ExtKeyUsageOption::Other(ref s) => &s[..], }) } } #[derive(Clone, Copy)] pub enum AltNameOption { /// The value is specified as OID;content. See `man ASN1_generate_nconf` for more information on the content syntax. /// /// ``` /// use openssl::x509::extension::Extension::*; /// use openssl::x509::extension::AltNameOption::Other as OtherName; /// /// # let generator = openssl::x509::X509Generator::new(); /// generator.add_extension(SubjectAltName(vec![(OtherName,"2.999.3;ASN1:UTF8:some other name".to_owned())])); /// ``` Other, Email, DNS, //X400, // Not supported by OpenSSL Directory, //EDIParty, // Not supported by OpenSSL URI, IPAddress, RegisteredID, } impl fmt::Display for AltNameOption { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { f.pad(match self { &AltNameOption::Other => "otherName", &AltNameOption::Email => "email", &AltNameOption::DNS => "DNS", &AltNameOption::Directory => "dirName", &AltNameOption::URI => "URI", &AltNameOption::IPAddress => "IP", &AltNameOption::RegisteredID => "RID", }) } }
openssl/src/x509/mod.rs +63 −109 Original line number Diff line number Diff line Loading @@ -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}; Loading @@ -20,6 +21,9 @@ use ffi; use ssl::error::{SslError, StreamError}; use nid; pub mod extension; use self::extension::{ExtensionType,Extension}; #[cfg(test)] mod tests; Loading Loading @@ -98,92 +102,9 @@ impl X509StoreContext { } } #[doc(hidden)] trait AsStr<'a> { fn as_str(&self) -> &'a str; } #[derive(Clone, Copy)] pub enum KeyUsage { DigitalSignature, NonRepudiation, KeyEncipherment, DataEncipherment, KeyAgreement, KeyCertSign, CRLSign, EncipherOnly, DecipherOnly } impl AsStr<'static> for KeyUsage { fn as_str(&self) -> &'static str { match self { &KeyUsage::DigitalSignature => "digitalSignature", &KeyUsage::NonRepudiation => "nonRepudiation", &KeyUsage::KeyEncipherment => "keyEncipherment", &KeyUsage::DataEncipherment => "dataEncipherment", &KeyUsage::KeyAgreement => "keyAgreement", &KeyUsage::KeyCertSign => "keyCertSign", &KeyUsage::CRLSign => "cRLSign", &KeyUsage::EncipherOnly => "encipherOnly", &KeyUsage::DecipherOnly => "decipherOnly" } } } #[derive(Clone, Copy)] pub enum ExtKeyUsage { ServerAuth, ClientAuth, CodeSigning, EmailProtection, TimeStamping, MsCodeInd, MsCodeCom, MsCtlSign, MsSgc, MsEfs, NsSgc } impl AsStr<'static> for ExtKeyUsage { fn as_str(&self) -> &'static str { match self { &ExtKeyUsage::ServerAuth => "serverAuth", &ExtKeyUsage::ClientAuth => "clientAuth", &ExtKeyUsage::CodeSigning => "codeSigning", &ExtKeyUsage::EmailProtection => "emailProtection", &ExtKeyUsage::TimeStamping => "timeStamping", &ExtKeyUsage::MsCodeInd => "msCodeInd", &ExtKeyUsage::MsCodeCom => "msCodeCom", &ExtKeyUsage::MsCtlSign => "msCTLSign", &ExtKeyUsage::MsSgc => "msSGC", &ExtKeyUsage::MsEfs => "msEFS", &ExtKeyUsage::NsSgc =>"nsSGC" } } } // FIXME: a dirty hack as there is no way to // implement ToString for Vec as both are defined // in another crate #[doc(hidden)] trait ToStr { fn to_str(&self) -> String; } impl<'a, T: AsStr<'a>> ToStr for Vec<T> { fn to_str(&self) -> String { self.iter().enumerate().fold(String::new(), |mut acc, (idx, v)| { if idx > 0 { acc.push(',') }; acc.push_str(v.as_str()); acc }) } } // Backwards-compatibility pub use self::extension::KeyUsageOption as KeyUsage; pub use self::extension::ExtKeyUsageOption as ExtKeyUsage; #[allow(non_snake_case)] /// Generator of private key/certificate pairs Loading Loading @@ -225,8 +146,8 @@ pub struct X509Generator { bits: u32, days: u32, CN: String, key_usage: Vec<KeyUsage>, ext_key_usage: Vec<ExtKeyUsage>, // RFC 3280 §4.2: A certificate MUST NOT include more than one instance of a particular extension. extensions: HashMap<ExtensionType,Extension>, hash_type: HashType, } Loading @@ -245,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 } } Loading @@ -270,15 +190,50 @@ impl X509Generator { self } /// Sets what for certificate could be used pub fn set_usage(mut self, purposes: &[KeyUsage]) -> X509Generator { self.key_usage = purposes.to_vec(); /// (deprecated) Sets what for certificate could be used /// /// This function is deprecated, use `X509Generator.add_extension` instead. pub fn set_usage(self, purposes: &[KeyUsage]) -> X509Generator { self.add_extension(Extension::KeyUsage(purposes.to_owned())) } /// (deprecated) Sets allowed extended usage of certificate /// /// This function is deprecated, use `X509Generator.add_extension` instead. pub fn set_ext_usage(self, purposes: &[ExtKeyUsage]) -> X509Generator { self.add_extension(Extension::ExtKeyUsage(purposes.to_owned())) } /// Add an extension to a certificate /// /// If the extension already exists, it will be replaced. /// /// ``` /// use openssl::x509::extension::Extension::*; /// use openssl::x509::extension::KeyUsageOption::*; /// /// # let generator = openssl::x509::X509Generator::new(); /// generator.add_extension(KeyUsage(vec![DigitalSignature, KeyEncipherment])); /// ``` pub fn add_extension(mut self, ext: extension::Extension) -> X509Generator { self.extensions.insert(ext.get_type(),ext); self } /// Sets allowed extended usage of certificate pub fn set_ext_usage(mut self, purposes: &[ExtKeyUsage]) -> X509Generator { self.ext_key_usage = purposes.to_vec(); /// Add multiple extensions to a certificate /// /// If any of the extensions already exist, they will be replaced. /// /// ``` /// use openssl::x509::extension::Extension::*; /// use openssl::x509::extension::KeyUsageOption::*; /// /// # let generator = openssl::x509::X509Generator::new(); /// generator.add_extensions(vec![KeyUsage(vec![DigitalSignature, KeyEncipherment])]); /// ``` pub fn add_extensions<I>(mut self, exts: I) -> X509Generator where I: IntoIterator<Item=extension::Extension> { self.extensions.extend(exts.into_iter().map(|ext|(ext.get_type(),ext))); self } Loading @@ -287,17 +242,22 @@ impl X509Generator { self } fn add_extension(x509: *mut ffi::X509, extension: c_int, value: &str) -> Result<(), SslError> { fn add_extension_internal(x509: *mut ffi::X509, exttype: &extension::ExtensionType, value: &str) -> Result<(), SslError> { unsafe { let mut ctx: ffi::X509V3_CTX = mem::zeroed(); ffi::X509V3_set_ctx(&mut ctx, x509, x509, ptr::null_mut(), ptr::null_mut(), 0); let value = CString::new(value.as_bytes()).unwrap(); let ext = ffi::X509V3_EXT_conf_nid(ptr::null_mut(), let ext=match exttype.get_nid() { Some(nid) => ffi::X509V3_EXT_conf_nid(ptr::null_mut(), mem::transmute(&ctx), extension, value.as_ptr() as *mut c_char); nid as c_int, value.as_ptr() as *mut c_char), None => ffi::X509V3_EXT_conf(ptr::null_mut(), mem::transmute(&ctx), exttype.get_name().unwrap().as_ptr() as *mut c_char, value.as_ptr() as *mut c_char), }; let mut success = false; if ext != ptr::null_mut() { success = ffi::X509_add_ext(x509, ext, -1) != 0; Loading Loading @@ -376,14 +336,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, &self.key_usage.to_str())); } if self.ext_key_usage.len() > 0 { try!(X509Generator::add_extension(x509.handle, ffi::NID_ext_key_usage, &self.ext_key_usage.to_str())); for (exttype,ext) in self.extensions.iter() { try!(X509Generator::add_extension_internal(x509.handle, exttype, &ext.to_string())); } let hash_fn = self.hash_type.evp_md(); Loading
openssl/src/x509/tests.rs +13 −12 Original line number Diff line number Diff line Loading @@ -5,8 +5,10 @@ use std::fs::File; use crypto::hash::Type::{SHA256}; use x509::{X509, X509Generator}; use x509::KeyUsage::{DigitalSignature, KeyEncipherment}; use x509::ExtKeyUsage::{ClientAuth, ServerAuth}; use x509::extension::Extension::{KeyUsage,ExtKeyUsage,SubjectAltName,OtherNid,OtherStr}; use x509::extension::AltNameOption as SAN; use x509::extension::KeyUsageOption::{DigitalSignature, KeyEncipherment}; use x509::extension::ExtKeyUsageOption::{self, ClientAuth, ServerAuth}; use nid::Nid; #[test] Loading @@ -16,16 +18,15 @@ fn test_cert_gen() { .set_valid_period(365*2) .set_CN("test_me") .set_sign_hash(SHA256) .set_usage(&[DigitalSignature, KeyEncipherment]) .set_ext_usage(&[ClientAuth, ServerAuth]); let res = gen.generate(); assert!(res.is_ok()); let (cert, pkey) = res.unwrap(); assert!(cert.write_pem(&mut io::sink()).is_ok()); assert!(pkey.write_pem(&mut io::sink()).is_ok()); .add_extension(KeyUsage(vec![DigitalSignature, KeyEncipherment])) .add_extension(ExtKeyUsage(vec![ClientAuth, ServerAuth, ExtKeyUsageOption::Other("2.999.1".to_owned())])) .add_extension(SubjectAltName(vec![(SAN::DNS,"example.com".to_owned())])) .add_extension(OtherNid(Nid::BasicConstraints,"critical,CA:TRUE".to_owned())) .add_extension(OtherStr("2.999.2".to_owned(),"ASN1:UTF8:example value".to_owned())); let (cert, pkey) = gen.generate().unwrap(); cert.write_pem(&mut io::sink()).unwrap(); pkey.write_pem(&mut io::sink()).unwrap(); // FIXME: check data in result to be correct, needs implementation // of X509 getters Loading