Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RSA PSS signing #71

Merged
merged 11 commits into from
Nov 21, 2023
6 changes: 0 additions & 6 deletions integration_tests/tests/self_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use simple_https_client::tls13client;
use simple_https_server::tls13server;

#[test]
#[should_panic]
fn test_sha256_chacha20_poly1305_rsa_pss_rsa_sha256_x25519() {
self_test_algorithm(simple_https_client::SHA256_Chacha20Poly1305_RsaPssRsaSha256_X25519);
}
Expand All @@ -17,7 +16,6 @@ fn test_sha256_chacha20_poly1305_ecdsa_secp256r1_sha256_p256() {
self_test_algorithm(simple_https_client::SHA256_Chacha20Poly1305_EcdsaSecp256r1Sha256_P256);
}
#[test]
#[should_panic]
fn test_sha256_chacha20_poly1305_rsa_pss_rsa_sha256_p256() {
self_test_algorithm(simple_https_client::SHA256_Chacha20Poly1305_RsaPssRsaSha256_P256);
}
Expand All @@ -34,14 +32,12 @@ fn test_sha256_aes128_gcm_ecdsa_secp256r1_sha256_x25519() {
}
}
#[test]
#[should_panic]
fn test_sha256_aes128_gcm_rsa_pss_rsa_sha256_p256() {
if libcrux_platform::aes_ni_support() {
self_test_algorithm(simple_https_client::SHA256_Aes128Gcm_RsaPssRsaSha256_P256);
}
}
#[test]
#[should_panic]
fn test_sha256_aes128_gcm_rsa_pss_rsa_sha256_x25519() {
if libcrux_platform::aes_ni_support() {
self_test_algorithm(simple_https_client::SHA256_Aes128Gcm_RsaPssRsaSha256_X25519);
Expand All @@ -60,14 +56,12 @@ fn test_sha384_aes256_gcm_ecdsa_secp256r1_sha256_x25519() {
}
}
#[test]
#[should_panic]
fn test_sha384_aes256_gcm_rsa_pss_rsa_sha256_p256() {
if libcrux_platform::aes_ni_support() {
self_test_algorithm(simple_https_client::SHA384_Aes256Gcm_RsaPssRsaSha256_P256);
}
}
#[test]
#[should_panic]
fn test_sha384_aes256_gcm_rsa_pss_rsa_sha256_x25519() {
if libcrux_platform::aes_ni_support() {
self_test_algorithm(simple_https_client::SHA384_Aes256Gcm_RsaPssRsaSha256_X25519);
Expand Down
92 changes: 70 additions & 22 deletions src/tls13crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ use libcrux::{
};

use crate::{
eq, tlserr, Bytes, Declassify, TLSError, CRYPTO_ERROR, INVALID_SIGNATURE, UNSUPPORTED_ALGORITHM,
eq, tls13cert, tlserr, Bytes, Declassify, TLSError, CRYPTO_ERROR, INVALID_SIGNATURE,
UNSUPPORTED_ALGORITHM,
};

pub type Random = Bytes; //was [U8;32]
Expand Down Expand Up @@ -226,7 +227,9 @@ pub enum SignatureScheme {

pub fn to_libcrux_sig_alg(a: &SignatureScheme) -> Result<signature::Algorithm, TLSError> {
match a {
SignatureScheme::RsaPssRsaSha256 => tlserr(UNSUPPORTED_ALGORITHM),
SignatureScheme::RsaPssRsaSha256 => Ok(signature::Algorithm::RsaPss(
signature::DigestAlgorithm::Sha256,
)),
SignatureScheme::ED25519 => Ok(signature::Algorithm::Ed25519),
SignatureScheme::EcdsaSecp256r1Sha256 => Ok(signature::Algorithm::EcDsaP256(
signature::DigestAlgorithm::Sha256,
Expand All @@ -237,15 +240,48 @@ pub fn to_libcrux_sig_alg(a: &SignatureScheme) -> Result<signature::Algorithm, T
pub fn sign(
alg: &SignatureScheme,
sk: &Bytes,
cert: &Bytes, // TODO: `cert` added to allow reconstructing full signing key for RSA-PSS. Rework this. (cf. issue #72)
input: &Bytes,
ent: Bytes,
ent: Bytes, // TODO: Rework handling of randomness, `libcrux` may want an `impl CryptoRng + RngCore` instead of raw bytes. (cf. issue #73)
) -> Result<Bytes, TLSError> {
let sig = signature::sign(
to_libcrux_sig_alg(alg)?,
&input.declassify(),
&sk.declassify(),
&mut rand::thread_rng(),
);
let sig = match alg {
SignatureScheme::EcdsaSecp256r1Sha256 | SignatureScheme::ED25519 => signature::sign(
to_libcrux_sig_alg(alg)?,
&input.declassify(),
&sk.declassify(),
&mut rand::thread_rng(),
),
SignatureScheme::RsaPssRsaSha256 => {
// salt must be same length as digest ouput length
let mut salt = [0u8; 32];
use rand::RngCore;
rand::thread_rng().fill_bytes(&mut salt);
let (cert_scheme, cert_slice) = tls13cert::verification_key_from_cert(cert)?;
if !matches!(cert_scheme, SignatureScheme::RsaPssRsaSha256) {
return tlserr(CRYPTO_ERROR); // XXX: Right error type?
}
let (pk_modulus, pk_exponent) = tls13cert::rsa_public_key(cert, cert_slice)?;

if !valid_rsa_exponent(pk_exponent.declassify()) {
return tlserr(UNSUPPORTED_ALGORITHM);
}

let key_size = supported_rsa_key_size(&pk_modulus)?;

let pk = RsaPssPublicKey::new(key_size, &pk_modulus.declassify()[1..])
.map_err(|_| CRYPTO_ERROR)?;

let sk = signature::rsa_pss::RsaPssPrivateKey::new(&pk, &sk.declassify())
.map_err(|_| CRYPTO_ERROR)?;

sk.sign(
signature::DigestAlgorithm::Sha256,
&salt,
&input.declassify(),
)
.map(signature::Signature::RsaPss)
}
};
match sig {
Ok(signature::Signature::Ed25519(sig)) => Ok(sig.as_bytes().into()),
Ok(signature::Signature::EcDsaP256(sig)) => {
Expand Down Expand Up @@ -292,21 +328,12 @@ pub fn verify(
}
}
(SignatureScheme::RsaPssRsaSha256, PublicVerificationKey::Rsa((n, e))) => {
let e = e.declassify();
if !(e.len() == 3 && e[0] == 0x1 && e[1] == 0x0 && e[2] == 0x1) {
// libcrux only supports `e = 3`
if !valid_rsa_exponent(e.declassify()) {
tlserr(UNSUPPORTED_ALGORITHM)
} else {
let key_size = match n.len() {
// The format includes an extra 0-byte in front to disambiguate from negative numbers
257 => RsaPssKeySize::N2048,
385 => RsaPssKeySize::N3072,
513 => RsaPssKeySize::N4096,
769 => RsaPssKeySize::N6144,
1025 => RsaPssKeySize::N8192,
_ => return tlserr(UNSUPPORTED_ALGORITHM),
};
let pk = RsaPssPublicKey::new(key_size, &n.declassify()[1..]).unwrap();
let key_size = supported_rsa_key_size(n)?;
let pk = RsaPssPublicKey::new(key_size, &n.declassify()[1..])
.map_err(|_| CRYPTO_ERROR)?;
let res = pk.verify(
signature::DigestAlgorithm::Sha256,
&sig.declassify().into(),
Expand All @@ -323,6 +350,27 @@ pub fn verify(
}
}

/// Determine if given modulus conforms to one of the key sizes supported by
/// `libcrux`.
fn supported_rsa_key_size(n: &Bytes) -> Result<RsaPssKeySize, u8> {
let key_size = match n.len() {
// The format includes an extra 0-byte in front to disambiguate from negative numbers
257 => RsaPssKeySize::N2048,
385 => RsaPssKeySize::N3072,
513 => RsaPssKeySize::N4096,
769 => RsaPssKeySize::N6144,
1025 => RsaPssKeySize::N8192,
_ => return tlserr(UNSUPPORTED_ALGORITHM),
};
Ok(key_size)
}

/// Determine if given public exponent is supported by `libcrux`, i.e. whether
/// `e == 0x010001`.
fn valid_rsa_exponent(e: Vec<u8>) -> bool {
e.len() == 3 && e[0] == 0x1 && e[1] == 0x0 && e[2] == 0x1
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum KemScheme {
X25519,
Expand Down
20 changes: 13 additions & 7 deletions src/tls13formats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -906,13 +906,19 @@ fn parse_ecdsa_signature(sig: Bytes) -> Result<Bytes, TLSError> {
}
}
pub fn certificate_verify(algs: &Algorithms, cv: &Bytes) -> Result<HandshakeData, TLSError> {
if cv.len() != 64 {
tlserr(parse_failed())
} else {
let sv = ecdsa_signature(cv)?;
let sig = signature_algorithm(algs)?.concat(&lbytes2(&sv)?);
Ok(handshake_message(HandshakeType::CertificateVerify, &sig)?)
}
let sv = match algs.2 {
SignatureScheme::RsaPssRsaSha256 => cv.clone(),
SignatureScheme::EcdsaSecp256r1Sha256 | SignatureScheme::ED25519 => {
if cv.len() != 64 {
return tlserr(parse_failed());
} else {
ecdsa_signature(cv)?
}
}
};

let sig = signature_algorithm(algs)?.concat(&lbytes2(&sv)?);
handshake_message(HandshakeType::CertificateVerify, &sig)
}

pub fn parse_certificate_verify(algs: &Algorithms, cv: &HandshakeData) -> Result<Bytes, TLSError> {
Expand Down
2 changes: 1 addition & 1 deletion src/tls13handshake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@ fn get_server_signature(
let tx = transcript_add1(tx, &sc);
let th = get_transcript_hash(&tx)?;
let sigval = Bytes::from_slice(&PREFIX_SERVER_SIGNATURE).concat(&th);
let sig = sign(&sig_alg(&algs), &sigk, &sigval, ent)?;
let sig = sign(&sig_alg(&algs), &sigk, &cert, &sigval, ent)?;
let scv = certificate_verify(&algs, &sig)?;
let tx = transcript_add1(tx, &scv);
Ok((
Expand Down
Loading