diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 8503254962a94ec1bd51fda470cbfaa2a7f1c568..a1817803237869717330d7368d5a83039b913585 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -450,6 +450,8 @@ extern "C" { pub fn PEM_read_bio_X509(bio: *mut BIO, out: *mut *mut X509, callback: Option, user_data: *mut c_void) -> *mut X509; + pub fn PEM_read_bio_X509_REQ(bio: *mut BIO, out: *mut *mut X509_REQ, callback: Option, + user_data: *mut c_void) -> *mut X509_REQ; pub fn PEM_read_bio_PrivateKey(bio: *mut BIO, out: *mut *mut EVP_PKEY, callback: Option, user_data: *mut c_void) -> *mut X509; @@ -458,6 +460,7 @@ extern "C" { callback: Option, user_data: *mut c_void) -> c_int; pub fn PEM_write_bio_X509(bio: *mut BIO, x509: *mut X509) -> c_int; + pub fn PEM_write_bio_X509_REQ(bio: *mut BIO, x509: *mut X509_REQ) -> c_int; pub fn PKCS5_PBKDF2_HMAC_SHA1(pass: *const u8, passlen: c_int, salt: *const u8, saltlen: c_int, @@ -568,6 +571,7 @@ extern "C" { pub fn X509_add_ext(x: *mut X509, ext: *mut X509_EXTENSION, loc: c_int) -> c_int; pub fn X509_digest(x: *mut X509, digest: *const EVP_MD, buf: *mut c_char, len: *mut c_uint) -> c_int; pub fn X509_free(x: *mut X509); + pub fn X509_REQ_free(x: *mut X509_REQ); pub fn X509_get_serialNumber(x: *mut X509) -> *mut ASN1_INTEGER; pub fn X509_get_subject_name(x: *mut X509) -> *mut X509_NAME; pub fn X509_gmtime_adj(time: *mut ASN1_TIME, adj: c_long) -> *mut ASN1_TIME; @@ -579,6 +583,7 @@ extern "C" { pub fn X509_set_pubkey(x: *mut X509, pkey: *mut EVP_PKEY) -> c_int; pub fn X509_sign(x: *mut X509, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> c_int; pub fn X509_get_pubkey(x: *mut X509) -> *mut EVP_PKEY; + pub fn X509_to_X509_REQ(x: *mut X509, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> *mut X509_REQ; pub fn X509_EXTENSION_free(ext: *mut X509_EXTENSION); diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index 1af70c41d8c833b232a78fa2ecfc78aeabc455a1..5446f125990fbba3f9716195cc45df2d2d2cdf2e 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -391,6 +391,20 @@ impl X509Generator { Ok(x509) } } + + /// Obtain a certificate signing request (CSR) + pub fn request(&self, p_key: &PKey) -> Result { + let cert=match self.sign(p_key) { + Ok(c) => c, + Err(x) => return Err(x) + }; + + let hash_fn = self.hash_type.evp_md(); + let req = unsafe { ffi::X509_to_X509_REQ(cert.handle, p_key.get_handle(), hash_fn) }; + try_ssl_null!(req); + + Ok(X509Req::new(req)) + } } @@ -538,6 +552,49 @@ impl <'x> X509Name<'x> { } } +/// A certificate signing request +pub struct X509Req { + handle: *mut ffi::X509_REQ, +} + +impl X509Req { + /// Creates new from handle + pub fn new(handle: *mut ffi::X509_REQ) -> X509Req { + X509Req { + handle: handle, + } + } + + /// Reads CSR from PEM + pub fn from_pem(reader: &mut R) -> Result where R: Read { + let mut mem_bio = try!(MemBio::new()); + try!(io::copy(reader, &mut mem_bio).map_err(StreamError)); + + unsafe { + let handle = try_ssl_null!(ffi::PEM_read_bio_X509_REQ(mem_bio.get_handle(), + ptr::null_mut(), + None, ptr::null_mut())); + Ok(X509Req::new(handle)) + } + } + + /// Writes CSR as PEM + pub fn write_pem(&self, writer: &mut W) -> Result<(), SslError> where W: Write { + let mut mem_bio = try!(MemBio::new()); + unsafe { + try_ssl!(ffi::PEM_write_bio_X509_REQ(mem_bio.get_handle(), + self.handle)); + } + io::copy(&mut mem_bio, writer).map_err(StreamError).map(|_| ()) + } +} + +impl Drop for X509Req { + fn drop(&mut self) { + unsafe { ffi::X509_REQ_free(self.handle) }; + } +} + macro_rules! make_validation_error( ($ok_val:ident, $($name:ident = $val:ident,)+) => ( #[derive(Copy, Clone)]