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
63
64
65
66
use ring::{rand, signature};
use simple_asn1::BigUint;

use crate::algorithms::Algorithm;
use crate::errors::{ErrorKind, Result};
use crate::serialization::{b64_decode, b64_encode};

/// Only used internally when validating RSA, to map from our enum to the Ring param structs.
pub(crate) fn alg_to_rsa_parameters(alg: Algorithm) -> &'static signature::RsaParameters {
    match alg {
        Algorithm::RS256 => &signature::RSA_PKCS1_2048_8192_SHA256,
        Algorithm::RS384 => &signature::RSA_PKCS1_2048_8192_SHA384,
        Algorithm::RS512 => &signature::RSA_PKCS1_2048_8192_SHA512,
        Algorithm::PS256 => &signature::RSA_PSS_2048_8192_SHA256,
        Algorithm::PS384 => &signature::RSA_PSS_2048_8192_SHA384,
        Algorithm::PS512 => &signature::RSA_PSS_2048_8192_SHA512,
        _ => unreachable!("Tried to get RSA signature for a non-rsa algorithm"),
    }
}

/// Only used internally when signing with RSA, to map from our enum to the Ring signing structs.
pub(crate) fn alg_to_rsa_signing(alg: Algorithm) -> &'static dyn signature::RsaEncoding {
    match alg {
        Algorithm::RS256 => &signature::RSA_PKCS1_SHA256,
        Algorithm::RS384 => &signature::RSA_PKCS1_SHA384,
        Algorithm::RS512 => &signature::RSA_PKCS1_SHA512,
        Algorithm::PS256 => &signature::RSA_PSS_SHA256,
        Algorithm::PS384 => &signature::RSA_PSS_SHA384,
        Algorithm::PS512 => &signature::RSA_PSS_SHA512,
        _ => unreachable!("Tried to get RSA signature for a non-rsa algorithm"),
    }
}

/// The actual RSA signing + encoding
/// The key needs to be in PKCS8 format
/// Taken from Ring doc https://briansmith.org/rustdoc/ring/signature/index.html
pub(crate) fn sign(
    alg: &'static dyn signature::RsaEncoding,
    key: &[u8],
    message: &str,
) -> Result<String> {
    let key_pair = signature::RsaKeyPair::from_der(key).map_err(|_| ErrorKind::InvalidRsaKey)?;

    let mut signature = vec![0; key_pair.public_modulus_len()];
    let rng = rand::SystemRandom::new();
    key_pair
        .sign(alg, &rng, message.as_bytes(), &mut signature)
        .map_err(|_| ErrorKind::InvalidRsaKey)?;

    Ok(b64_encode(&signature))
}

/// Checks that a signature is valid based on the (n, e) RSA pubkey components
pub(crate) fn verify_from_components(
    alg: &'static signature::RsaParameters,
    signature: &str,
    message: &str,
    components: (&str, &str),
) -> Result<bool> {
    let signature_bytes = b64_decode(signature)?;
    let n = BigUint::from_bytes_be(&b64_decode(components.0)?).to_bytes_be();
    let e = BigUint::from_bytes_be(&b64_decode(components.1)?).to_bytes_be();
    let pubkey = signature::RsaPublicKeyComponents { n, e };
    let res = pubkey.verify(alg, message.as_ref(), &signature_bytes);
    Ok(res.is_ok())
}