Loading openssl-sys/src/lib.rs +4 −0 Original line number Diff line number Diff line Loading @@ -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; Loading openssl/src/x509/mod.rs +81 −13 Original line number Diff line number Diff line Loading @@ -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>, Loading Loading @@ -743,29 +747,73 @@ impl X509NameEntryRef { } } type_!(X509Req, X509ReqRef, ffi::X509_REQ, ffi::X509_REQ_free); pub struct X509ReqBuilder(X509Req); impl X509ReqRef { /// Writes CSR as PEM pub fn to_pem(&self) -> Result<Vec<u8>, ErrorStack> { let mem_bio = try!(MemBio::new()); if unsafe { ffi::PEM_write_bio_X509_REQ(mem_bio.as_ptr(), self.as_ptr()) } != 1 { return Err(ErrorStack::get()); impl X509ReqBuilder { pub fn new() -> Result<X509ReqBuilder, ErrorStack> { unsafe { cvt_p(ffi::X509_REQ_new()).map(|p| X509ReqBuilder(X509Req(p))) } } Ok(mem_bio.get_buf().to_owned()) pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_REQ_set_version(self.0.as_ptr(), version.into())).map(|_| ()) } } /// Returns a DER serialized form of the CSR pub fn to_der(&self) -> Result<Vec<u8>, ErrorStack> { let mem_bio = try!(MemBio::new()); pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> { unsafe { ffi::i2d_X509_REQ_bio(mem_bio.as_ptr(), self.as_ptr()); cvt(ffi::X509_REQ_set_subject_name(self.0.as_ptr(), subject_name.as_ptr())).map(|_| ()) } Ok(mem_bio.get_buf().to_owned()) } 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)); Loading @@ -779,6 +827,26 @@ impl X509Req { } } impl X509ReqRef { /// Writes CSR as PEM pub fn to_pem(&self) -> Result<Vec<u8>, ErrorStack> { let mem_bio = try!(MemBio::new()); if unsafe { ffi::PEM_write_bio_X509_REQ(mem_bio.as_ptr(), self.as_ptr()) } != 1 { return Err(ErrorStack::get()); } Ok(mem_bio.get_buf().to_owned()) } /// Returns a DER serialized form of the CSR pub fn to_der(&self) -> Result<Vec<u8>, ErrorStack> { let mem_bio = try!(MemBio::new()); unsafe { ffi::i2d_X509_REQ_bio(mem_bio.as_ptr(), self.as_ptr()); } Ok(mem_bio.get_buf().to_owned()) } } /// A collection of X.509 extensions. /// /// Upholds the invariant that a certificate MUST NOT include more than one Loading openssl/src/x509/tests.rs +29 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); Loading Loading @@ -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
openssl-sys/src/lib.rs +4 −0 Original line number Diff line number Diff line Loading @@ -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; Loading
openssl/src/x509/mod.rs +81 −13 Original line number Diff line number Diff line Loading @@ -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>, Loading Loading @@ -743,29 +747,73 @@ impl X509NameEntryRef { } } type_!(X509Req, X509ReqRef, ffi::X509_REQ, ffi::X509_REQ_free); pub struct X509ReqBuilder(X509Req); impl X509ReqRef { /// Writes CSR as PEM pub fn to_pem(&self) -> Result<Vec<u8>, ErrorStack> { let mem_bio = try!(MemBio::new()); if unsafe { ffi::PEM_write_bio_X509_REQ(mem_bio.as_ptr(), self.as_ptr()) } != 1 { return Err(ErrorStack::get()); impl X509ReqBuilder { pub fn new() -> Result<X509ReqBuilder, ErrorStack> { unsafe { cvt_p(ffi::X509_REQ_new()).map(|p| X509ReqBuilder(X509Req(p))) } } Ok(mem_bio.get_buf().to_owned()) pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_REQ_set_version(self.0.as_ptr(), version.into())).map(|_| ()) } } /// Returns a DER serialized form of the CSR pub fn to_der(&self) -> Result<Vec<u8>, ErrorStack> { let mem_bio = try!(MemBio::new()); pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> { unsafe { ffi::i2d_X509_REQ_bio(mem_bio.as_ptr(), self.as_ptr()); cvt(ffi::X509_REQ_set_subject_name(self.0.as_ptr(), subject_name.as_ptr())).map(|_| ()) } Ok(mem_bio.get_buf().to_owned()) } 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)); Loading @@ -779,6 +827,26 @@ impl X509Req { } } impl X509ReqRef { /// Writes CSR as PEM pub fn to_pem(&self) -> Result<Vec<u8>, ErrorStack> { let mem_bio = try!(MemBio::new()); if unsafe { ffi::PEM_write_bio_X509_REQ(mem_bio.as_ptr(), self.as_ptr()) } != 1 { return Err(ErrorStack::get()); } Ok(mem_bio.get_buf().to_owned()) } /// Returns a DER serialized form of the CSR pub fn to_der(&self) -> Result<Vec<u8>, ErrorStack> { let mem_bio = try!(MemBio::new()); unsafe { ffi::i2d_X509_REQ_bio(mem_bio.as_ptr(), self.as_ptr()); } Ok(mem_bio.get_buf().to_owned()) } } /// A collection of X.509 extensions. /// /// Upholds the invariant that a certificate MUST NOT include more than one Loading
openssl/src/x509/tests.rs +29 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); Loading Loading @@ -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(); }