Add an X509ReqBuilder
This commit is contained in:
parent
597d05b8f8
commit
d78acc729b
|
|
@ -1685,6 +1685,10 @@ extern {
|
|||
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_nconf(ctx: *mut X509V3_CTX, conf: *mut CONF);
|
||||
|
||||
pub fn X509_REQ_new() -> *mut X509_REQ;
|
||||
pub fn X509_REQ_set_version(req: *mut X509_REQ, version: c_long) -> c_int;
|
||||
pub fn X509_REQ_set_subject_name(req: *mut X509_REQ, name: *mut X509_NAME) -> c_int;
|
||||
pub fn X509_REQ_set_pubkey(req: *mut X509_REQ, pkey: *mut EVP_PKEY) -> c_int;
|
||||
pub fn X509_REQ_add_extensions(req: *mut X509_REQ, exts: *mut stack_st_X509_EXTENSION) -> c_int;
|
||||
pub fn X509_REQ_sign(x: *mut X509_REQ, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> c_int;
|
||||
|
||||
|
|
|
|||
|
|
@ -597,6 +597,10 @@ impl<'a> X509v3Context<'a> {
|
|||
|
||||
type_!(X509Extension, X509ExtensionRef, ffi::X509_EXTENSION, ffi::X509_EXTENSION_free);
|
||||
|
||||
impl Stackable for X509Extension {
|
||||
type StackType = ffi::stack_st_X509_EXTENSION;
|
||||
}
|
||||
|
||||
impl X509Extension {
|
||||
pub fn new(conf: Option<&ConfRef>,
|
||||
context: Option<&X509v3Context>,
|
||||
|
|
@ -743,8 +747,86 @@ impl X509NameEntryRef {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct X509ReqBuilder(X509Req);
|
||||
|
||||
impl X509ReqBuilder {
|
||||
pub fn new() -> Result<X509ReqBuilder, ErrorStack> {
|
||||
unsafe { cvt_p(ffi::X509_REQ_new()).map(|p| X509ReqBuilder(X509Req(p))) }
|
||||
}
|
||||
|
||||
pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> {
|
||||
unsafe { cvt(ffi::X509_REQ_set_version(self.0.as_ptr(), version.into())).map(|_| ()) }
|
||||
}
|
||||
|
||||
pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::X509_REQ_set_subject_name(self.0.as_ptr(), subject_name.as_ptr())).map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_pubkey(&mut self, key: &PKeyRef) -> Result<(), ErrorStack> {
|
||||
unsafe { cvt(ffi::X509_REQ_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) }
|
||||
}
|
||||
|
||||
pub fn x509v3_context<'a>(&'a self,
|
||||
conf: Option<&'a ConfRef>)
|
||||
-> X509v3Context<'a> {
|
||||
unsafe {
|
||||
let mut ctx = mem::zeroed();
|
||||
|
||||
ffi::X509V3_set_ctx(&mut ctx,
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
self.0.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
0);
|
||||
|
||||
// nodb case taken care of since we zeroed ctx above
|
||||
if let Some(conf) = conf {
|
||||
ffi::X509V3_set_nconf(&mut ctx, conf.as_ptr());
|
||||
}
|
||||
|
||||
X509v3Context(ctx, PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_extensions(&mut self,
|
||||
extensions: &StackRef<X509Extension>)
|
||||
-> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::X509_REQ_add_extensions(self.0.as_ptr(), extensions.as_ptr())).map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sign(&mut self, key: &PKeyRef, hash: MessageDigest) -> Result<(), ErrorStack> {
|
||||
unsafe { cvt(ffi::X509_REQ_sign(self.0.as_ptr(), key.as_ptr(), hash.as_ptr())).map(|_| ()) }
|
||||
}
|
||||
|
||||
pub fn build(self) -> X509Req {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
type_!(X509Req, X509ReqRef, ffi::X509_REQ, ffi::X509_REQ_free);
|
||||
|
||||
impl X509Req {
|
||||
pub fn builder() -> Result<X509ReqBuilder, ErrorStack> {
|
||||
X509ReqBuilder::new()
|
||||
}
|
||||
|
||||
/// Reads CSR from PEM
|
||||
pub fn from_pem(buf: &[u8]) -> Result<X509Req, ErrorStack> {
|
||||
let mem_bio = try!(MemBioSlice::new(buf));
|
||||
unsafe {
|
||||
let handle = try!(cvt_p(ffi::PEM_read_bio_X509_REQ(mem_bio.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
ptr::null_mut())));
|
||||
Ok(X509Req::from_ptr(handle))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl X509ReqRef {
|
||||
/// Writes CSR as PEM
|
||||
pub fn to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
|
||||
|
|
@ -765,20 +847,6 @@ impl X509ReqRef {
|
|||
}
|
||||
}
|
||||
|
||||
impl X509Req {
|
||||
/// Reads CSR from PEM
|
||||
pub fn from_pem(buf: &[u8]) -> Result<X509Req, ErrorStack> {
|
||||
let mem_bio = try!(MemBioSlice::new(buf));
|
||||
unsafe {
|
||||
let handle = try!(cvt_p(ffi::PEM_read_bio_X509_REQ(mem_bio.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
ptr::null_mut())));
|
||||
Ok(X509Req::from_ptr(handle))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A collection of X.509 extensions.
|
||||
///
|
||||
/// Upholds the invariant that a certificate MUST NOT include more than one
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@ use bn::{BigNum, MSB_MAYBE_ZERO};
|
|||
use hash::MessageDigest;
|
||||
use pkey::PKey;
|
||||
use rsa::Rsa;
|
||||
use x509::{X509, X509Generator, X509Name};
|
||||
use stack::Stack;
|
||||
use x509::{X509, X509Generator, X509Name, X509Req};
|
||||
use x509::extension::{Extension, BasicConstraints, KeyUsage, ExtendedKeyUsage,
|
||||
SubjectKeyIdentifier, AuthorityKeyIdentifier, SubjectAlternativeName};
|
||||
use x509::extension::AltNameOption as SAN;
|
||||
|
|
@ -187,6 +188,7 @@ fn x509_builder() {
|
|||
let name = name.build();
|
||||
|
||||
let mut builder = X509::builder().unwrap();
|
||||
builder.set_version(2).unwrap();
|
||||
builder.set_subject_name(&name).unwrap();
|
||||
builder.set_issuer_name(&name).unwrap();
|
||||
builder.set_not_before(&Asn1Time::days_from_now(0).unwrap()).unwrap();
|
||||
|
|
@ -232,3 +234,29 @@ fn x509_builder() {
|
|||
let cn = x509.subject_name().entries_by_nid(nid::COMMONNAME).next().unwrap();
|
||||
assert_eq!("foobar.com".as_bytes(), cn.data().as_slice());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn x509_req_builder() {
|
||||
let pkey = pkey();
|
||||
|
||||
let mut name = X509Name::builder().unwrap();
|
||||
name.append_entry_by_nid(nid::COMMONNAME, "foobar.com").unwrap();
|
||||
let name = name.build();
|
||||
|
||||
let mut builder = X509Req::builder().unwrap();
|
||||
builder.set_version(2).unwrap();
|
||||
builder.set_subject_name(&name).unwrap();
|
||||
builder.set_pubkey(&pkey).unwrap();
|
||||
|
||||
let mut extensions = Stack::new().unwrap();
|
||||
let key_usage = KeyUsage::new().digital_signature().key_encipherment().build().unwrap();
|
||||
extensions.push(key_usage).unwrap();
|
||||
let subject_alternative_name = SubjectAlternativeName::new()
|
||||
.dns("example.com")
|
||||
.build(&builder.x509v3_context(None))
|
||||
.unwrap();
|
||||
extensions.push(subject_alternative_name).unwrap();
|
||||
builder.add_extensions(&extensions).unwrap();
|
||||
|
||||
builder.sign(&pkey, MessageDigest::sha256()).unwrap();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue