opentitanlib/crypto/
rsa.rs

1// Copyright lowRISC contributors (OpenTitan project).
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5use anyhow::{Context, Result, anyhow, bail, ensure};
6use num_bigint_dig::{BigInt, BigUint, Sign::Minus, traits::ModInverse};
7use rand::rngs::OsRng;
8use rsa::pkcs1::{DecodeRsaPublicKey, EncodeRsaPublicKey};
9use rsa::pkcs1v15::Pkcs1v15Sign;
10use rsa::pkcs8::{DecodePrivateKey, DecodePublicKey, EncodePrivateKey};
11use rsa::traits::PublicKeyParts;
12use serde::{Deserialize, Serialize};
13use serde_annotate::Annotate;
14use sha2::Sha256;
15use std::fs::File;
16use std::io::{Read, Write};
17use std::ops::Deref;
18use std::ops::Shl;
19use std::path::{Path, PathBuf};
20use std::str::FromStr;
21
22use super::Error;
23use crate::crypto::sha256::Sha256Digest;
24use crate::util::bigint::fixed_size_bigint;
25
26const MODULUS_BIT_LEN: usize = 3072;
27const EXPONENT_BIT_LEN: usize = 17;
28const SIGNATURE_BIT_LEN: usize = 3072;
29const RR_BIT_LEN: usize = 3072;
30const OTBN_BITS: usize = 256;
31
32fixed_size_bigint!(Modulus, MODULUS_BIT_LEN);
33fixed_size_bigint!(Exponent, EXPONENT_BIT_LEN);
34fixed_size_bigint!(Signature, at_most SIGNATURE_BIT_LEN);
35fixed_size_bigint!(RR, at_most RR_BIT_LEN);
36fixed_size_bigint!(N0Inv, at_most OTBN_BITS);
37
38/// Ensure the components of `key` have the correct bit length.
39fn validate_key(key: &impl PublicKeyParts) -> Result<()> {
40    if key.n().bits() != MODULUS_BIT_LEN || key.e() != &BigUint::from(65537u32) {
41        bail!(Error::InvalidPublicKey(anyhow!("bad modulus or exponent")));
42    } else {
43        Ok(())
44    }
45}
46
47/// RSA Public Key used in OpenTitan signing operations.
48///
49/// This is a wrapper for handling RSA public keys as they're used in OpenTitan images.
50#[derive(Debug)]
51pub struct RsaPublicKey {
52    key: rsa::RsaPublicKey,
53}
54
55impl RsaPublicKey {
56    /// Construct a new public key with modulus = n and e = 65537.
57    pub fn new(n: Modulus) -> Result<RsaPublicKey> {
58        Ok(RsaPublicKey {
59            key: rsa::RsaPublicKey::new(
60                BigUint::from_bytes_le(n.to_le_bytes().as_slice()),
61                BigUint::from(65537u32),
62            )
63            .map_err(|e| Error::InvalidPublicKey(anyhow!(e)))?,
64        })
65    }
66
67    /// Construct a new public key from a PKCS1 encoded DER file.
68    pub fn from_pkcs1_der_file<P: Into<PathBuf>>(der_file: P) -> Result<RsaPublicKey> {
69        let der_file = der_file.into();
70        match rsa::RsaPublicKey::read_pkcs1_der_file(&der_file)
71            .or_else(|_| rsa::RsaPublicKey::read_public_key_der_file(&der_file))
72        {
73            Ok(key) => {
74                validate_key(&key)?;
75                Ok(Self { key })
76            }
77            Err(err) => bail!(Error::InvalidDerFile {
78                der: der_file,
79                source: anyhow!(err),
80            }),
81        }
82    }
83
84    /// Write public key to a PKCS1 encoded DER file.
85    pub fn to_pkcs1_der_file<P: Into<PathBuf>>(&self, der_file: P) -> Result<()> {
86        let der_file = der_file.into();
87        self.key
88            .write_pkcs1_der_file(&der_file)
89            .map_err(|e| Error::WriteFailed {
90                file: der_file.to_owned(),
91                source: anyhow!(e),
92            })?;
93        Ok(())
94    }
95
96    /// Extract the public key components from a given private key.
97    pub fn from_private_key(private_key: &RsaPrivateKey) -> Self {
98        Self {
99            key: rsa::RsaPublicKey::from(&private_key.key),
100        }
101    }
102
103    /// Bit length for this key.
104    pub fn modulus_num_bits(&self) -> usize {
105        self.key.n().bits()
106    }
107
108    /// Modulus for this key.
109    pub fn modulus(&self) -> Modulus {
110        // All RSA keys have their bit length checked so `unwrap()` here is safe.
111        Modulus::from_le_bytes(self.key.n().to_bytes_le()).unwrap()
112    }
113
114    /// Public exponent for this key.
115    pub fn exponent(&self) -> Exponent {
116        // All RSA keys have their bit length checked so `unwrap()` here is safe.
117        Exponent::from_le_bytes(self.key.e().to_bytes_le()).unwrap()
118    }
119
120    /// Computes the OTBN montgomery parameter: -1 / n\[0\] mod 2^256.
121    pub fn n0_inv(&self) -> Result<N0Inv> {
122        let base = BigInt::from(1u8) << OTBN_BITS;
123        let n_neg = BigInt::from_biguint(Minus, self.key.n().to_owned());
124        let n0_inv = n_neg
125            .mod_inverse(&base)
126            .and_then(|v| v.to_biguint())
127            .ok_or(Error::KeyComponentComputeFailed)?;
128        Ok(N0Inv::from_le_bytes(n0_inv.to_bytes_le())?)
129    }
130
131    /// The montgomery parameter RR.
132    pub fn rr(&self) -> RR {
133        let rr = BigUint::from(1u8).shl(2 * self.modulus_num_bits()) % self.key.n();
134        // `rr` < `n`, so `rr` will always fit in `RR` and thus `unwrap()` here is safe.
135        RR::from_le_bytes(rr.to_bytes_le()).unwrap()
136    }
137
138    /// Verify a `signature` is valid for a given `digest` under this key.
139    pub fn verify(&self, digest: &Sha256Digest, signature: &Signature) -> Result<()> {
140        self.key
141            .verify(
142                Pkcs1v15Sign::new::<Sha256>(),
143                digest.to_be_bytes().as_slice(),
144                signature.to_be_bytes().as_slice(),
145            )
146            .map_err(|e| anyhow!(Error::VerifyFailed(anyhow!(e))))
147    }
148}
149
150/// RSA Private Key used in OpenTitan signing operations.
151///
152/// This is a wrapper for handling RSA priavate keys as they're used in OpenTitan images.
153#[derive(Debug, Clone)]
154pub struct RsaPrivateKey {
155    key: rsa::RsaPrivateKey,
156}
157
158impl RsaPrivateKey {
159    /// Construct a new 3072-bit private key with e = 65537.
160    pub fn new() -> Result<Self> {
161        let mut rng = OsRng;
162        Ok(Self {
163            key: rsa::RsaPrivateKey::new_with_exp(&mut rng, 3072, &BigUint::from(65537u32))
164                .map_err(|e| Error::GenerateFailed(anyhow!(e)))?,
165        })
166    }
167
168    /// Construct a new private key from a PKCS8 encoded DER file.
169    pub fn from_pkcs8_der_file<P: Into<PathBuf>>(der_file: P) -> Result<Self> {
170        let der_file = der_file.into();
171        match rsa::RsaPrivateKey::read_pkcs8_der_file(&der_file) {
172            Ok(key) => {
173                validate_key(&key)?;
174                Ok(Self { key })
175            }
176            Err(err) => bail!(Error::InvalidDerFile {
177                der: der_file,
178                source: anyhow!(err),
179            }),
180        }
181    }
182
183    /// Write private key to a PKCS8 encoded DER file.
184    pub fn to_pkcs8_der_file<P: Into<PathBuf>>(&self, der_file: P) -> Result<()> {
185        let der_file = der_file.into();
186        self.key
187            .write_pkcs8_der_file(&der_file)
188            .map_err(|e| Error::WriteFailed {
189                file: der_file,
190                source: anyhow!(e),
191            })?;
192        Ok(())
193    }
194
195    /// Signs a SHA256 `digest` using PKCS1v15 padding scheme.
196    pub fn sign(&self, digest: &Sha256Digest) -> Result<Signature> {
197        let signature = self
198            .key
199            .sign(Pkcs1v15Sign::new::<Sha256>(), &digest.to_be_bytes())
200            .map_err(|e| Error::SignFailed(anyhow!(e)))?;
201        Ok(Signature::from_be_bytes(signature)?)
202    }
203}
204
205impl Signature {
206    /// Creates an `Signature` from a given input file.
207    pub fn read_from_file(path: &Path) -> Result<Signature> {
208        let err = |e: std::io::Error| Error::ReadFailed {
209            file: path.to_owned(),
210            source: anyhow!(e),
211        };
212        let mut file = File::open(path).map_err(err)?;
213        let mut buf = Vec::<u8>::new();
214        file.read_to_end(&mut buf).map_err(err)?;
215        Ok(Signature::from_le_bytes(buf.as_slice())?)
216    }
217
218    /// Write out the `Signature` to a file at the given `path`.
219    pub fn write_to_file(&self, path: &Path) -> Result<()> {
220        let err = |e: std::io::Error| Error::WriteFailed {
221            file: path.to_owned(),
222            source: anyhow!(e),
223        };
224        let mut file = File::create(path).map_err(err)?;
225        file.write_all(self.to_le_bytes().as_mut_slice())
226            .map_err(err)?;
227        Ok(())
228    }
229}
230
231impl Deref for RsaPublicKey {
232    type Target = rsa::RsaPublicKey;
233
234    fn deref(&self) -> &Self::Target {
235        &self.key
236    }
237}
238
239impl Deref for RsaPrivateKey {
240    type Target = rsa::RsaPrivateKey;
241
242    fn deref(&self) -> &Self::Target {
243        &self.key
244    }
245}
246
247#[derive(Debug, Serialize, Deserialize, Annotate)]
248pub struct RsaRawPublicKey {
249    #[serde(with = "serde_bytes")]
250    #[annotate(format = hexstr)]
251    pub modulus: Vec<u8>,
252    #[serde(with = "serde_bytes")]
253    #[annotate(format = hexstr)]
254    pub n0_inv: Vec<u8>,
255}
256
257impl Default for RsaRawPublicKey {
258    fn default() -> Self {
259        Self {
260            modulus: vec![0; 384],
261            n0_inv: vec![0; 32],
262        }
263    }
264}
265
266impl TryFrom<&RsaPublicKey> for RsaRawPublicKey {
267    type Error = Error;
268    fn try_from(v: &RsaPublicKey) -> Result<Self, Self::Error> {
269        Ok(Self {
270            modulus: v.modulus().to_le_bytes().to_vec(),
271            n0_inv: v.n0_inv().map_err(Error::Other)?.to_le_bytes().to_vec(),
272        })
273    }
274}
275
276impl TryFrom<RsaPublicKey> for RsaRawPublicKey {
277    type Error = Error;
278    fn try_from(v: RsaPublicKey) -> Result<Self, Self::Error> {
279        RsaRawPublicKey::try_from(&v)
280    }
281}
282
283impl FromStr for RsaRawPublicKey {
284    type Err = Error;
285    fn from_str(s: &str) -> Result<Self, Self::Err> {
286        let key = RsaPublicKey::from_pkcs1_der_file(s)
287            .with_context(|| format!("Failed to load {s}"))
288            .map_err(Error::Other)?;
289        RsaRawPublicKey::try_from(&key)
290    }
291}
292
293impl RsaRawPublicKey {
294    pub const SIZE: usize = 384 + 32;
295    pub fn read(src: &mut impl Read) -> Result<Self> {
296        let mut key = Self::default();
297        src.read_exact(&mut key.modulus)?;
298        src.read_exact(&mut key.n0_inv)?;
299        Ok(key)
300    }
301
302    pub fn write(&self, dest: &mut impl Write) -> Result<()> {
303        ensure!(
304            self.modulus.len() == 384,
305            Error::InvalidPublicKey(anyhow!("bad modulus length: {}", self.modulus.len()))
306        );
307        ensure!(
308            self.n0_inv.len() == 32,
309            Error::InvalidPublicKey(anyhow!("bad n0_inv length: {}", self.n0_inv.len()))
310        );
311        dest.write_all(&self.modulus)?;
312        dest.write_all(&self.n0_inv)?;
313        Ok(())
314    }
315}