Merge pull request #233 from jethrogb/topic/x509_extension
Allow setting of arbitrary X509 extensions
This commit is contained in:
commit
3229296105
|
|
@ -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 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_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 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;
|
pub fn i2d_RSA_PUBKEY(k: *mut RSA, buf: *const *mut u8) -> c_int;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
|
||||||
#[repr(usize)]
|
#[repr(usize)]
|
||||||
pub enum Nid {
|
pub enum Nid {
|
||||||
Undefined,
|
Undefined,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,212 @@
|
||||||
|
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",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -9,6 +9,7 @@ use std::ptr;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use asn1::{Asn1Time};
|
use asn1::{Asn1Time};
|
||||||
use bio::{MemBio};
|
use bio::{MemBio};
|
||||||
|
|
@ -20,6 +21,9 @@ use ffi;
|
||||||
use ssl::error::{SslError, StreamError};
|
use ssl::error::{SslError, StreamError};
|
||||||
use nid;
|
use nid;
|
||||||
|
|
||||||
|
pub mod extension;
|
||||||
|
|
||||||
|
use self::extension::{ExtensionType,Extension};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
@ -98,92 +102,9 @@ impl X509StoreContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
// Backwards-compatibility
|
||||||
trait AsStr<'a> {
|
pub use self::extension::KeyUsageOption as KeyUsage;
|
||||||
fn as_str(&self) -> &'a str;
|
pub use self::extension::ExtKeyUsageOption as ExtKeyUsage;
|
||||||
}
|
|
||||||
|
|
||||||
#[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
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
/// Generator of private key/certificate pairs
|
/// Generator of private key/certificate pairs
|
||||||
|
|
@ -225,8 +146,8 @@ pub struct X509Generator {
|
||||||
bits: u32,
|
bits: u32,
|
||||||
days: u32,
|
days: u32,
|
||||||
CN: String,
|
CN: String,
|
||||||
key_usage: Vec<KeyUsage>,
|
// RFC 3280 §4.2: A certificate MUST NOT include more than one instance of a particular extension.
|
||||||
ext_key_usage: Vec<ExtKeyUsage>,
|
extensions: HashMap<ExtensionType,Extension>,
|
||||||
hash_type: HashType,
|
hash_type: HashType,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -245,8 +166,7 @@ impl X509Generator {
|
||||||
bits: 1024,
|
bits: 1024,
|
||||||
days: 365,
|
days: 365,
|
||||||
CN: "rust-openssl".to_string(),
|
CN: "rust-openssl".to_string(),
|
||||||
key_usage: Vec::new(),
|
extensions: HashMap::new(),
|
||||||
ext_key_usage: Vec::new(),
|
|
||||||
hash_type: HashType::SHA1
|
hash_type: HashType::SHA1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -270,15 +190,50 @@ impl X509Generator {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets what for certificate could be used
|
/// (deprecated) Sets what for certificate could be used
|
||||||
pub fn set_usage(mut self, purposes: &[KeyUsage]) -> X509Generator {
|
///
|
||||||
self.key_usage = purposes.to_vec();
|
/// 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
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets allowed extended usage of certificate
|
/// Add multiple extensions to a certificate
|
||||||
pub fn set_ext_usage(mut self, purposes: &[ExtKeyUsage]) -> X509Generator {
|
///
|
||||||
self.ext_key_usage = purposes.to_vec();
|
/// 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
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -287,17 +242,22 @@ impl X509Generator {
|
||||||
self
|
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 {
|
unsafe {
|
||||||
let mut ctx: ffi::X509V3_CTX = mem::zeroed();
|
let mut ctx: ffi::X509V3_CTX = mem::zeroed();
|
||||||
ffi::X509V3_set_ctx(&mut ctx, x509, x509,
|
ffi::X509V3_set_ctx(&mut ctx, x509, x509,
|
||||||
ptr::null_mut(), ptr::null_mut(), 0);
|
ptr::null_mut(), ptr::null_mut(), 0);
|
||||||
let value = CString::new(value.as_bytes()).unwrap();
|
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),
|
mem::transmute(&ctx),
|
||||||
extension,
|
nid as c_int,
|
||||||
value.as_ptr() as *mut c_char);
|
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;
|
let mut success = false;
|
||||||
if ext != ptr::null_mut() {
|
if ext != ptr::null_mut() {
|
||||||
success = ffi::X509_add_ext(x509, ext, -1) != 0;
|
success = ffi::X509_add_ext(x509, ext, -1) != 0;
|
||||||
|
|
@ -376,14 +336,8 @@ impl X509Generator {
|
||||||
try!(X509Generator::add_name(name, "CN", &self.CN));
|
try!(X509Generator::add_name(name, "CN", &self.CN));
|
||||||
ffi::X509_set_issuer_name(x509.handle, name);
|
ffi::X509_set_issuer_name(x509.handle, name);
|
||||||
|
|
||||||
if self.key_usage.len() > 0 {
|
for (exttype,ext) in self.extensions.iter() {
|
||||||
try!(X509Generator::add_extension(x509.handle, ffi::NID_key_usage,
|
try!(X509Generator::add_extension_internal(x509.handle, exttype, &ext.to_string()));
|
||||||
&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()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let hash_fn = self.hash_type.evp_md();
|
let hash_fn = self.hash_type.evp_md();
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,10 @@ use std::fs::File;
|
||||||
|
|
||||||
use crypto::hash::Type::{SHA256};
|
use crypto::hash::Type::{SHA256};
|
||||||
use x509::{X509, X509Generator};
|
use x509::{X509, X509Generator};
|
||||||
use x509::KeyUsage::{DigitalSignature, KeyEncipherment};
|
use x509::extension::Extension::{KeyUsage,ExtKeyUsage,SubjectAltName,OtherNid,OtherStr};
|
||||||
use x509::ExtKeyUsage::{ClientAuth, ServerAuth};
|
use x509::extension::AltNameOption as SAN;
|
||||||
|
use x509::extension::KeyUsageOption::{DigitalSignature, KeyEncipherment};
|
||||||
|
use x509::extension::ExtKeyUsageOption::{self, ClientAuth, ServerAuth};
|
||||||
use nid::Nid;
|
use nid::Nid;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -16,16 +18,15 @@ fn test_cert_gen() {
|
||||||
.set_valid_period(365*2)
|
.set_valid_period(365*2)
|
||||||
.set_CN("test_me")
|
.set_CN("test_me")
|
||||||
.set_sign_hash(SHA256)
|
.set_sign_hash(SHA256)
|
||||||
.set_usage(&[DigitalSignature, KeyEncipherment])
|
.add_extension(KeyUsage(vec![DigitalSignature, KeyEncipherment]))
|
||||||
.set_ext_usage(&[ClientAuth, ServerAuth]);
|
.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 res = gen.generate();
|
let (cert, pkey) = gen.generate().unwrap();
|
||||||
assert!(res.is_ok());
|
cert.write_pem(&mut io::sink()).unwrap();
|
||||||
|
pkey.write_pem(&mut io::sink()).unwrap();
|
||||||
let (cert, pkey) = res.unwrap();
|
|
||||||
|
|
||||||
assert!(cert.write_pem(&mut io::sink()).is_ok());
|
|
||||||
assert!(pkey.write_pem(&mut io::sink()).is_ok());
|
|
||||||
|
|
||||||
// FIXME: check data in result to be correct, needs implementation
|
// FIXME: check data in result to be correct, needs implementation
|
||||||
// of X509 getters
|
// of X509 getters
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue