I need to sign/verify some data in an application and I would like my API to be implementation agnostic. I'm currently using OpenSSL, but that should be an implementation detail that developers do not need to know about, and if someone wants to switch the backend implementation I don't want the application code to suffer.
I want to wrap all the signing/verifying logic into something very straight-forward, along the line of (trimming some methods and implementation for brevity):
struct PrivKey { /* ... */ }
impl PrivKey {
pub fn new(gp: GenParams) -> Result<Self, Error> { /* ... */ }
pub fn pubkey(&self) -> Result<PubKey, Error> { /* ... */ }
pub fn signer(&self) -> Result<MySigner, Error> { /* ... */ }
}
pub struct MySigner { /* ... */ }
impl MySigner {
pub fn update(&mut self, buf: &[u8]) -> Result<(), Error> { /* ... */ }
pub fn finalize(mut self) -> Result<Vec<u8>, Error> { /* ... */ }
}
pub struct PubKey { /* ... */ }
impl PubKey {
pub fn verifier(&self) -> Result<MyVerifier, Error> { /* ... */ }
}
pub struct MyVerifier { /* ... */ }
impl MyVerifier {
pub fn update(&mut self, buf: &[u8]) -> Result<(), Error> { /* ... */ }
pub fn verify(mut self, sig: &[u8]) -> Result<bool, Error> { /* ... */ }
}
As it happens, the OpenSSL wrapper is not completely dissimilar from this, but it has one (for me) major caveat: When creating a OpenSSL's Signer
and Verifier
objects, it takes in a &'a PKeyRef
(PKey
, which hold private and public keys, objects can be deref'd into PKeyRef
). This ties the lifetime of the Signer
and Verifier
objects to the PKeyRef
. I would need to do this:
pub struct MySigner<'a> {
inner: sign::Signer<'a>
}
I would prefer not to introduce lifetimes to my simplified interface, and I would like the application to be able to pass around the MySigner
/MyVerifier
objects over channels. In an ideal world I would clone the public/private keys into MySigner
and MyVerifier
so they simply travel along with the Signer
/Verifier
objects, but it's obviously not that simple.
I feel that I need a fresh perspective on this. Given the boundary conditions:
- Use OpenSSL's sign module (i.e.
PKey
,PKeyRef
,Signer
,Verifier
). - Expose no explicit lifetimes to the application.
- Allow
MySigner
/MyVerifier
to be passed over channels.
Is it possible to achieve this, or do all these roads lead to self-referential structs or other nasty hairballs?