Implement "extensions" field in X509generator, and change existing extensions to use that

This commit is contained in:
Jethro Beekman 2015-06-30 18:54:48 -07:00
parent d5a4d48cab
commit 8d1abf5156
3 changed files with 53 additions and 25 deletions

View File

@ -1,5 +1,5 @@
#[allow(non_camel_case_types)]
#[derive(Copy, Clone)]
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
#[repr(usize)]
pub enum Nid {
Undefined,

View File

@ -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<ExtKeyUsageOption>),
}
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<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(),","),
}
}
}
#[derive(Clone,Copy)]
pub enum KeyUsageOption {
DigitalSignature,

View File

@ -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<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
})
}
#[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<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,
}
@ -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();