http_sig/algorithm/
openssl.rs

1use std::fmt;
2
3use openssl::hash::MessageDigest;
4use openssl::pkey::{PKey, Private, Public};
5use openssl::rsa::Padding;
6use openssl::rsa::Rsa;
7use openssl::sign::{Signer, Verifier};
8
9use crate::{HttpSignatureSign, HttpSignatureVerify};
10
11macro_rules! rsa_signature {
12    ({$sign_name:ident, $verify_name:ident}($hash_alg:ident) = $name:literal) => {
13        #[doc = "Implementation of the signing half of the '"]
14        #[doc = $name]
15        #[doc = "' HTTP signature scheme."]
16        pub struct $sign_name(PKey<Private>);
17
18        impl fmt::Debug for $sign_name {
19            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
20                f.write_str(stringify!($sign_name))
21            }
22        }
23
24        #[doc = "Implementation of the verification half of the '"]
25        #[doc = $name]
26        #[doc = "' HTTP signature scheme."]
27        pub struct $verify_name(PKey<Public>);
28
29        impl fmt::Debug for $verify_name {
30            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
31                f.write_str(stringify!($verify_name))
32            }
33        }
34
35        impl $sign_name {
36            /// Create a new instance of the signature scheme using the
37            /// provided private key.
38            pub fn new_pkcs8(private_key: &[u8]) -> Result<Self, Box<dyn std::error::Error>> {
39                Ok(Self(PKey::private_key_from_pkcs8(private_key)?))
40            }
41            /// Create a new instance of the signature scheme using the
42            /// provided private key.
43            pub fn new_der(private_key: &[u8]) -> Result<Self, Box<dyn std::error::Error>> {
44                Ok(Self(PKey::from_rsa(Rsa::private_key_from_der(
45                    private_key,
46                )?)?))
47            }
48            /// Create a new instance of the signature scheme using the
49            /// provided private key.
50            pub fn new_pem(private_key: &[u8]) -> Result<Self, Box<dyn std::error::Error>> {
51                Ok(Self(PKey::from_rsa(Rsa::private_key_from_pem(
52                    private_key,
53                )?)?))
54            }
55        }
56
57        impl $verify_name {
58            /// Create a new instance of the signature scheme using the
59            /// provided public key.
60            pub fn new_der(public_key: &[u8]) -> Result<Self, Box<dyn std::error::Error>> {
61                Ok(Self(PKey::from_rsa(Rsa::public_key_from_der(public_key)?)?))
62            }
63            /// Create a new instance of the signature scheme using the
64            /// provided public key.
65            pub fn new_pem(public_key: &[u8]) -> Result<Self, Box<dyn std::error::Error>> {
66                Ok(Self(PKey::from_rsa(Rsa::public_key_from_pem(public_key)?)?))
67            }
68        }
69
70        impl HttpSignatureSign for $sign_name {
71            fn http_sign(&self, bytes_to_sign: &[u8]) -> String {
72                let mut signer = Signer::new(MessageDigest::$hash_alg(), &self.0).unwrap();
73                signer.set_rsa_padding(Padding::PKCS1).unwrap();
74                let tag = signer
75                    .sign_oneshot_to_vec(bytes_to_sign)
76                    .expect("Signing to be infallible");
77                base64::encode(&tag)
78            }
79        }
80        impl HttpSignatureVerify for $verify_name {
81            fn http_verify(&self, bytes_to_verify: &[u8], signature: &str) -> bool {
82                let tag = match base64::decode(signature) {
83                    Ok(tag) => tag,
84                    Err(_) => return false,
85                };
86                let mut verifier = Verifier::new(MessageDigest::$hash_alg(), &self.0).unwrap();
87                verifier.set_rsa_padding(Padding::PKCS1).unwrap();
88                match verifier.verify_oneshot(&tag, bytes_to_verify) {
89                    Ok(true) => true,
90                    Ok(false) => false,
91                    Err(e) => {
92                        dbg!(e);
93                        false
94                    }
95                }
96            }
97        }
98    };
99}
100
101rsa_signature!({RsaSha256Sign, RsaSha256Verify}(sha256) = "rsa-sha256");
102rsa_signature!({RsaSha512Sign, RsaSha512Verify}(sha512) = "rsa-sha512");