1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
use crate::{vec, Vec};
use crate::{Voucher, Sign, VoucherError, SignatureAlgorithm};
use crate::debug_println;
use super::utils::minerva_mbedtls_utils::*;
use minerva_mbedtls::{psa_ifce::*, mbedtls_error};

impl Sign for Voucher {
    /// Signs the voucher using a PEM-encoded private key
    /// based on the signature algorithm `alg`.
    ///
    /// Returns a `&mut Self` reference if the voucher is signed.
    ///
    /// # Errors
    ///
    /// If the voucher is not signed, or the internal signing function fails, a `VoucherError::SigningFailed` is returned.
    ///
    /// # Examples
    ///
    /// ```
    /// use minerva_voucher::{Voucher, attr::*, SignatureAlgorithm, Sign};
    ///
    /// static KEY_PEM_F2_00_02: &[u8] = core::include_bytes!(
    ///     concat!(env!("CARGO_MANIFEST_DIR"), "/data/00-D0-E5-F2-00-02/key.pem"));
    ///
    /// // This is required when the `Sign` trait is backed by mbedtls.
    /// minerva_voucher::init_psa_crypto();
    ///
    /// let mut vrq = Voucher::new_vrq();
    ///
    /// vrq.set(Attr::Assertion(Assertion::Proximity))
    ///     .set(Attr::SerialNumber(b"00-D0-E5-F2-00-02".to_vec()));
    ///
    /// assert!(vrq.get_signature().is_none());
    /// vrq.sign(KEY_PEM_F2_00_02, SignatureAlgorithm::ES256).unwrap();
    /// assert!(vrq.get_signature().is_some());
    /// ```
    fn sign(&mut self, privkey_pem: &[u8], alg: SignatureAlgorithm) -> Result<&mut Self, VoucherError> {
        if let Err(err) = sign_with_mbedtls(privkey_pem, alg, self.to_sign(alg)) {
            debug_println!("sign(): mbedtls_error: {}", err);
            Err(VoucherError::SigningFailed)
        } else {
            Ok(self)
        }
    }
}

pub fn sign_with_mbedtls(
    privkey_pem: &[u8],
    alg: SignatureAlgorithm,
    (sig_out, sig_struct): (&mut Vec<u8>, &[u8])
) -> Result<(), mbedtls_error> {
    let mut sig = vec![];
    let (md_ty, ref hash) = compute_digest(sig_struct, &alg);

    let f_rng = Some(pk_context::test_f_rng_ptr());
    let mut pk = pk_from_privkey_pem(privkey_pem, f_rng)?;
    pk.sign(md_ty, hash, &mut sig, f_rng, core::ptr::null_mut())?;

    *sig_out = sig;

    Ok(())
}