sfackler / rust-openssl

OpenSSL bindings for Rust
1.4k stars 752 forks source link

Creating an X.509 certificate from a CSR #345

Open jimmycuadra opened 8 years ago

jimmycuadra commented 8 years ago

Right now X509Generator only creates self-signed certificates. I'd like to be able to use a self-signed certificate to create a new certificate from a CSR. If I were to work on some new APIs to do this, does it make any sense to try to add this additional functionality to X509Generator? I'm imagining ultimately being able to do something like this:

fn generate_server_cert() -> Result<X509> {
    let (ca_cert, ca_key) = X509Generator::new().generate().unwrap();
    let mut server_key = PKey::new();
    server_key.gen(2048);
    let csr = X509Generator::new().add_name("CN".to_owned(), "example.com".to_owned()).request(&server_key).unwrap();
    X509Generator::new().sign_cert(&ca_key, &csr)
}

X509Generator seems very awkward for this type of API—it's not clear exactly what its responsibility is. Any suggestions on how to approach this?

phifty commented 8 years ago

I could imagine something like

fn generate_server_cert() -> Result<X509> {
    let (ca_cert, ca_key) = X509Generator::new().generate().unwrap();
    let (server_cert, server_key) = X509Generator::new().generate().unwrap();
    let request = server_cert.generate_signing_request().unwrap();
    let signed_server_cert = ca_cert.sign(&request, &ca_key).unwrap();
}

But I'd be fine with another design too. This feature is currently really missing. +1

dbrgn commented 8 years ago

I could use this feature too :) +1 from my side.

albx79 commented 8 years ago

This issue is blocking progress on one of our projects. We are happy to try and fix it, but no one in my team is an openssl expert, nor a rust expert, so we could use some pointers.

About the API, how would you like it to look? We were thinking something like this:

X509Req {
  pub fn sign(self, cert: &X509, key: &PKey) -> Result<X509, ErrorStack>
}

However, it would greatly speed up our progress if you can point us to the relevant openssl API.

sfackler commented 8 years ago

I am not particularly familiar with this side of OpenSSL either. I'd probably recommend looking at the implementation of the openssl x509 tool, since it can sign a CSR.

fzgregor commented 7 years ago

Any progress on this?

sfackler commented 7 years ago

Still just needs someone to track down the right APIs and bind them.

juanibiapina commented 6 years ago

This issue seems out of date because X509Generator is not there anymore.

softprops commented 6 years ago

I was looking for a way to emulate ssh-keygen -t rsa -b 4096 -C "foo@bar.com" and it looked like this was the closest thing but I also noticed X509Generator was not a type. Does there currently exist a way to do this with released versions of rust openssl?

rustonaut commented 5 years ago

Ignoring the change in interface (X509Generator -> X509Builder) . The issue seems to be boiling down to following features missing:

The usage of the OpenSSL x509 x509_certify function can be found here:

https://github.com/openssl/openssl/blob/c31950b964a2f3f7b9e6ad98076954178ee1e77d/apps/x509.c#L858-L861

It should be noted that the certificate x there is not the parsed CSR but a new X509 cert created by copying fields over from the X509 req as far as I understood it (but its pretty late and I normally don't work with C so I might have mixed thinks up).

There is a X509_to_X509_REQ function but I'm not sure if there is a X509_REQ_to_X509 function. It surely would be helpful.

Also the documentation for this function seem to be pretty sparse.

rustonaut commented 5 years ago

Turns out X509_certify is also part of openssl/apps so no wonder that it's not exposed.

Anyway we do have sing, which allows signing the cert with the CA certs private key, but there is no nice/simple way to put some of the issuer info in (e.g. for the X509v3 Authority Key Identifier).

Or am I missing something?

EDIT: To clearify. There is a way to set the Authority Key Identifier extension, but only to the values like in the conifg. When used with openssl x509 this will automatically pull in data leading to something like:

    X509v3 Authority Key Identifier
                keyid:EB:53:F0:62:FD:46:A9:25:B7:02:41:A6:47:11:44:E3:48:19:11:A4
                DirName:/CN=RandomExampleCert
                serial:CE:A4:4E:1E:A2:3B:E3:67

Where keyid, dirname and serial are from the issuing cert. But we only pass the private key to sign, not the certificate.