RSA signing and verification in an Iron webapp


#1

I’m trying to prove out Rust as the language for the Let’s Auth project (a sort of follow-up to Mozilla’s Persona). Basically, it’s an OpenID Connect-like service; this means using the RS256 (RSASSA-PKCS1-v1_5 using SHA-256) algorithm for JWT signing.

So far, it seems like the only crypto library that can support RSA signing is rust-openssl. I’d prefer to use ring, actually, but that doesn’t seem to have implemented signing yet.

However, I’ve been having lots of trouble passing the RSA private key into my Iron handlers. Here’s one attempt:

struct PrivKey {
    priv_key: Arc<RSA>,
}

impl PrivKey {
    fn new(priv_key: Arc<RSA>) -> PrivKey {
        PrivKey { priv_key: priv_key }
    }
}

impl Handler for PrivKey {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
    return json_response(&ObjectBuilder::new()
        .insert_array("keys", |builder| {
            builder.push_object(|builder| {
                builder
                    .insert("kty", "RSA")
                    .insert("alg", "RS256")
                    .insert("use", "sig")
                    .insert("kid", "base")
                    .insert("n", json_big_num(&self.priv_key.n().unwrap()))
                    .insert("e", json_big_num(&self.priv_key.e().unwrap()))
            })
        }).unwrap());
        
    }
}

This fails like this:

   Compiling ladaemon v0.1.0 (file:///home/djc/src/ladaemon)
src/main.rs:77:6: 77:13 error: the trait bound `*mut openssl_sys::RSA: std::marker::Send` is not satisfied [E0277]
src/main.rs:77 impl Handler for PrivKey {
                    ^~~~~~~
src/main.rs:77:6: 77:13 help: run `rustc --explain E0277` to see a detailed explanation
src/main.rs:77:6: 77:13 note: `*mut openssl_sys::RSA` cannot be sent between threads safely
src/main.rs:77:6: 77:13 note: required because it appears within the type `openssl::crypto::rsa::RSA`
src/main.rs:77:6: 77:13 note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<openssl::crypto::rsa::RSA>`
src/main.rs:77:6: 77:13 note: required because it appears within the type `PrivKey`
src/main.rs:77:6: 77:13 note: required by `iron::Handler`
src/main.rs:77:6: 77:13 error: the trait bound `*mut openssl_sys::RSA: std::marker::Sync` is not satisfied [E0277]
src/main.rs:77 impl Handler for PrivKey {
                    ^~~~~~~
src/main.rs:77:6: 77:13 help: run `rustc --explain E0277` to see a detailed explanation
src/main.rs:77:6: 77:13 note: `*mut openssl_sys::RSA` cannot be shared between threads safely
src/main.rs:77:6: 77:13 note: required because it appears within the type `openssl::crypto::rsa::RSA`
src/main.rs:77:6: 77:13 note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<openssl::crypto::rsa::RSA>`
src/main.rs:77:6: 77:13 note: required because it appears within the type `PrivKey`
src/main.rs:77:6: 77:13 note: required by `iron::Handler`
error: aborting due to 2 previous errors
error: Could not compile `ladaemon`.

To learn more, run the command again with --verbose.

Any advice on how to do get this done? Since all the underlying rust-openssl data structures seem to be *mut, I have no clue how to work with this.


#2

You probably could wrap the RSA in a Mutex, but I believe you are using the lower level openssl FFI (the types that directly correspond to the OpenSSL C types) while there is a higher-level API that would hopefully be more useful to you, specifically PKey documented here: http://sfackler.github.io/rust-openssl/doc/v0.7.13/openssl/crypto/pkey/struct.PKey.html. While it doesn’t have RSA in the struct name, it does perform RSA signing and encryption.


#3

Awesome! Using PKey instead of the low-level thing made it work immediately. Not sure how I missed it… I guess that, looking through the rust-openssl docs, I went looking for RSA-specific stuff.

Thanks!