1use crate::algorithm::{AlgorithmType, SigningAlgorithm, VerifyingAlgorithm};
17use crate::error::Error;
18use crate::SEPARATOR;
19
20use openssl::bn::BigNum;
21use openssl::ecdsa::EcdsaSig;
22use openssl::hash::MessageDigest;
23use openssl::nid::Nid;
24use openssl::pkey::{Id, PKey, Private, Public};
25use openssl::sign::{Signer, Verifier};
26
27pub struct PKeyWithDigest<T> {
31 pub digest: MessageDigest,
32 pub key: PKey<T>,
33}
34
35impl<T> PKeyWithDigest<T> {
36 fn algorithm_type(&self) -> AlgorithmType {
37 match (self.key.id(), self.digest.type_()) {
38 (Id::RSA, Nid::SHA256) => AlgorithmType::Rs256,
39 (Id::RSA, Nid::SHA384) => AlgorithmType::Rs384,
40 (Id::RSA, Nid::SHA512) => AlgorithmType::Rs512,
41 (Id::EC, Nid::SHA256) => AlgorithmType::Es256,
42 (Id::EC, Nid::SHA384) => AlgorithmType::Es384,
43 (Id::EC, Nid::SHA512) => AlgorithmType::Es512,
44 _ => panic!("Invalid algorithm type"),
45 }
46 }
47}
48
49impl SigningAlgorithm for PKeyWithDigest<Private> {
50 fn algorithm_type(&self) -> AlgorithmType {
51 PKeyWithDigest::algorithm_type(self)
52 }
53
54 fn sign(&self, header: &str, claims: &str) -> Result<String, Error> {
55 let mut signer = Signer::new(self.digest.clone(), &self.key)?;
56 signer.update(header.as_bytes())?;
57 signer.update(SEPARATOR.as_bytes())?;
58 signer.update(claims.as_bytes())?;
59 let signer_signature = signer.sign_to_vec()?;
60
61 let signature = if self.key.id() == Id::EC {
62 der_to_jose(&signer_signature)?
63 } else {
64 signer_signature
65 };
66
67 Ok(base64::encode_config(&signature, base64::URL_SAFE_NO_PAD))
68 }
69}
70
71impl VerifyingAlgorithm for PKeyWithDigest<Public> {
72 fn algorithm_type(&self) -> AlgorithmType {
73 PKeyWithDigest::algorithm_type(self)
74 }
75
76 fn verify_bytes(&self, header: &str, claims: &str, signature: &[u8]) -> Result<bool, Error> {
77 let mut verifier = Verifier::new(self.digest.clone(), &self.key)?;
78 verifier.update(header.as_bytes())?;
79 verifier.update(SEPARATOR.as_bytes())?;
80 verifier.update(claims.as_bytes())?;
81
82 let verified = if self.key.id() == Id::EC {
83 let der = jose_to_der(signature)?;
84 verifier.verify(&der)?
85 } else {
86 verifier.verify(signature)?
87 };
88
89 Ok(verified)
90 }
91}
92
93fn der_to_jose(der: &[u8]) -> Result<Vec<u8>, Error> {
95 let signature = EcdsaSig::from_der(&der)?;
96 let r = signature.r().to_vec();
97 let s = signature.s().to_vec();
98 Ok([r, s].concat())
99}
100
101fn jose_to_der(jose: &[u8]) -> Result<Vec<u8>, Error> {
103 let (r, s) = jose.split_at(jose.len() / 2);
104 let ecdsa_signature =
105 EcdsaSig::from_private_components(BigNum::from_slice(r)?, BigNum::from_slice(s)?)?;
106 Ok(ecdsa_signature.to_der()?)
107}
108
109#[cfg(test)]
110mod tests {
111 use crate::algorithm::openssl::PKeyWithDigest;
112 use crate::algorithm::AlgorithmType::*;
113 use crate::algorithm::{SigningAlgorithm, VerifyingAlgorithm};
114 use crate::error::Error;
115 use crate::header::PrecomputedAlgorithmOnlyHeader as AlgOnly;
116 use crate::ToBase64;
117
118 use openssl::hash::MessageDigest;
119 use openssl::pkey::PKey;
120
121 const CLAIMS: &'static str =
123 "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9";
124
125 const RS256_SIGNATURE: &'static str =
126 "cQsAHF2jHvPGFP5zTD8BgoJrnzEx6JNQCpupebWLFnOc2r_punDDTylI6Ia4JZNkvy2dQP-7W-DEbFQ3oaarHsDndqUgwf9iYlDQxz4Rr2nEZX1FX0-FMEgFPeQpdwveCgjtTYUbVy37ijUySN_rW-xZTrsh_Ug-ica8t-zHRIw";
127
128 #[test]
129 fn rs256_sign() -> Result<(), Error> {
130 let pem = include_bytes!("../../test/rs256-private.pem");
131
132 let algorithm = PKeyWithDigest {
133 digest: MessageDigest::sha256(),
134 key: PKey::private_key_from_pem(pem)?,
135 };
136
137 let result = algorithm.sign(&AlgOnly(Rs256).to_base64()?, CLAIMS)?;
138 assert_eq!(result, RS256_SIGNATURE);
139 Ok(())
140 }
141
142 #[test]
143 fn rs256_verify() -> Result<(), Error> {
144 let pem = include_bytes!("../../test/rs256-public.pem");
145
146 let algorithm = PKeyWithDigest {
147 digest: MessageDigest::sha256(),
148 key: PKey::public_key_from_pem(pem)?,
149 };
150
151 let verification_result =
152 algorithm.verify(&AlgOnly(Rs256).to_base64()?, CLAIMS, RS256_SIGNATURE)?;
153 assert!(verification_result);
154 Ok(())
155 }
156
157 #[test]
158 fn es256() -> Result<(), Error> {
159 let private_pem = include_bytes!("../../test/es256-private.pem");
160 let private_key = PKeyWithDigest {
161 digest: MessageDigest::sha256(),
162 key: PKey::private_key_from_pem(private_pem)?,
163 };
164
165 let signature = private_key.sign(&AlgOnly(Es256).to_base64()?, CLAIMS)?;
166
167 let public_pem = include_bytes!("../../test/es256-public.pem");
168
169 let public_key = PKeyWithDigest {
170 digest: MessageDigest::sha256(),
171 key: PKey::public_key_from_pem(public_pem)?,
172 };
173
174 let verification_result =
175 public_key.verify(&AlgOnly(Es256).to_base64()?, CLAIMS, &*signature)?;
176 assert!(verification_result);
177 Ok(())
178 }
179}