use super::crypto::hash::{Digest, Sha256};
use super::crypto::{ecdsa, ed25519, rsa};
use super::x509::der::{expect_sequence, read_element};
use super::{Identity, TlsError, TlsResult};
use alloc::vec::Vec;
const OID_RSA_ENCRYPTION: &[u8] = &[0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01];
const OID_ED25519: &[u8] = &[0x2b, 0x65, 0x70];
const OID_EC_PUBLIC_KEY: &[u8] = &[0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01];
const OID_P256: &[u8] = &[0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07];
enum ParsedKey {
Rsa { n: Vec<u8>, d: Vec<u8> },
Ed25519([u8; 32]),
EcP256 { d: [u8; 32] },
}
pub(crate) fn sign_server_cert_verify(
identity: &Identity,
message: &[u8],
) -> TlsResult<Option<(u16, Vec<u8>)>> {
let key = parse_private_key(&identity.private_key)?;
match key {
ParsedKey::Rsa { n, d } => {
let mut h: super::crypto::hash::BoxDigest = Box::<Sha256>::default();
if let Some(sig) = rsa::sign_pss(h.as_mut(), &n, &d, message, 32) {
return Ok(Some((0x0804, sig)));
}
let mut h: super::crypto::hash::BoxDigest = Box::<Sha256>::default();
let digest = {
h.update(message);
h.finalize()
};
if let Some(sig) = rsa::sign_pkcs1v15(&n, &d, rsa::DIGEST_INFO_SHA256, &digest) {
return Ok(Some((0x0401, sig)));
}
Err(TlsError::Certificate("RSA signing failed".into()))
}
ParsedKey::Ed25519(seed) => {
let sig = ed25519::sign(&seed, message);
Ok(Some((0x0807, sig.to_vec())))
}
ParsedKey::EcP256 { d } => {
let mut h = Sha256::new();
let digest = {
h.update(message);
let out = h.finalize();
let mut d32 = [0u8; 32];
d32.copy_from_slice(&out);
d32
};
match ecdsa::sign(&d, &digest) {
Some((r, s)) => {
let der = encode_ecdsa_sig(&r, &s);
Ok(Some((0x0403, der)))
}
None => Err(TlsError::Certificate("ECDSA signing failed".into())),
}
}
}
}
fn encode_ecdsa_sig(r: &[u8], s: &[u8]) -> Vec<u8> {
fn enc_int(v: &[u8]) -> Vec<u8> {
let mut body = v.to_vec();
while body.len() > 1 && body[0] == 0 {
body.remove(0);
}
if body[0] & 0x80 != 0 {
body.insert(0, 0);
}
let mut out = Vec::with_capacity(2 + body.len());
out.push(0x02);
out.push(body.len() as u8);
out.extend_from_slice(&body);
out
}
let r_der = enc_int(r);
let s_der = enc_int(s);
let mut out = Vec::with_capacity(2 + r_der.len() + s_der.len());
out.push(0x30);
out.push((r_der.len() + s_der.len()) as u8);
out.extend_from_slice(&r_der);
out.extend_from_slice(&s_der);
out
}
fn parse_private_key(der: &[u8]) -> TlsResult<ParsedKey> {
if let Some(k) = parse_pkcs8(der) {
return Ok(k);
}
if let Some(k) = parse_pkcs1_rsa(der) {
return Ok(k);
}
Err(TlsError::Certificate(
"unsupported private key format".into(),
))
}
fn parse_pkcs8(der: &[u8]) -> Option<ParsedKey> {
let mut pos = 0usize;
let seq = expect_sequence(der, &mut pos)?;
if pos != der.len() {
return None;
}
let mut p = 0usize;
let version = read_element(seq, &mut p)?;
if version.tag != 0x02 {
return None;
}
let alg = read_element(seq, &mut p)?;
if alg.tag != 0x30 {
return None;
}
let mut a = 0usize;
let oid = read_element(alg.content, &mut a)?;
if oid.tag != 0x06 {
return None;
}
let key = read_element(seq, &mut p)?;
if key.tag != 0x04 {
return None;
}
if oid.content == OID_RSA_ENCRYPTION {
return parse_pkcs1_rsa(key.content);
}
if oid.content == OID_ED25519 {
let seed_bytes = if key.content.len() == 32 {
key.content
} else if key.content.len() == 34 && key.content[0] == 0x04 && key.content[1] == 0x20 {
&key.content[2..]
} else {
return None;
};
let mut seed = [0u8; 32];
seed.copy_from_slice(seed_bytes);
return Some(ParsedKey::Ed25519(seed));
}
if oid.content == OID_EC_PUBLIC_KEY {
let params = read_element(alg.content, &mut a)?;
if params.tag != 0x06 || params.content != OID_P256 {
return None;
}
let mut e = 0usize;
let ec_seq = expect_sequence(key.content, &mut e)?;
let mut ep = 0usize;
let ver = read_element(ec_seq, &mut ep)?;
if ver.tag != 0x02 {
return None;
}
let d_oct = read_element(ec_seq, &mut ep)?;
if d_oct.tag != 0x04 || d_oct.content.len() != 32 {
return None;
}
let mut d = [0u8; 32];
d.copy_from_slice(d_oct.content);
return Some(ParsedKey::EcP256 { d });
}
None
}
fn parse_pkcs1_rsa(der: &[u8]) -> Option<ParsedKey> {
let mut pos = 0usize;
let seq = expect_sequence(der, &mut pos)?;
if pos != der.len() {
return None;
}
let mut p = 0usize;
let ver = read_element(seq, &mut p)?;
if ver.tag != 0x02 {
return None;
}
let n = read_element(seq, &mut p)?;
if n.tag != 0x02 {
return None;
}
let e = read_element(seq, &mut p)?;
if e.tag != 0x02 {
return None;
}
let d = read_element(seq, &mut p)?;
if d.tag != 0x02 {
return None;
}
let nv = strip_int(n.content);
let dv = strip_int(d.content);
Some(ParsedKey::Rsa {
n: nv.to_vec(),
d: dv.to_vec(),
})
}
fn strip_int(v: &[u8]) -> &[u8] {
if v.len() > 1 && v[0] == 0 {
&v[1..]
} else {
v
}
}
#[cfg(test)]
mod tests {
use super::*;
fn hex(s: &str) -> Vec<u8> {
let s = s.replace(' ', "");
(0..s.len())
.step_by(2)
.map(|i| u8::from_str_radix(&s[i..i + 2], 16).unwrap())
.collect()
}
fn to_hex(v: &[u8]) -> String {
v.iter().map(|b| format!("{:02x}", b)).collect()
}
#[test]
fn ed25519_sign_verify_roundtrip() {
let seed: [u8; 32] =
hex("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60")
.try_into()
.unwrap();
let msg = b"";
let sig = ed25519::sign(&seed, msg);
assert_eq!(
to_hex(&sig),
"e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e06522490155\
5fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b"
);
let pk: [u8; 32] = hex("d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a")
.try_into()
.unwrap();
assert!(ed25519::verify(&pk, msg, &sig));
assert!(!ed25519::verify(&pk, b"tampered", &sig));
}
#[test]
fn ecdsa_p256_sign_verify_roundtrip() {
let d: [u8; 32] = hex("C9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721")
.try_into()
.unwrap();
let digest: [u8; 32] =
hex("af2bdbe1aa9b6ec1e2ade1d694f41fc71a831d0268e9891562113d8a62add1bf")
.try_into()
.unwrap();
let (r, s) = ecdsa::sign(&d, &digest).expect("sign");
let qx: [u8; 32] = hex("60FED4BA255A9D31C961EB74C6356D68C049B8923B61FA6CE669622E60F29FB6")
.try_into()
.unwrap();
let qy: [u8; 32] = hex("7903FE1008B8BC99A41AE9E95628BC64F2F1B20C2D7E9F5177A3C294D4462299")
.try_into()
.unwrap();
let der = encode_ecdsa_sig(&r, &s);
assert!(super::super::crypto::ecdsa::verify_der(
&qx, &qy, &digest, &der
));
let mut bad = digest;
bad[0] ^= 1;
assert!(!super::super::crypto::ecdsa::verify_der(
&qx, &qy, &bad, &der
));
}
#[test]
fn rsa_sign_verify_roundtrip() {
let n: Vec<u8> = hex(
"a643f09b73976142b45694f8a8ae222e00926aae43f8ac9ed9e3828535e19e8d\
57e435a703e47fd795ba13836faa2121e40abe6768b16a3c930e004f2c0e73f2\
56e61598ea9fb2e3501ecef756e5465d99a1435a38997167ec54152a777dd2d9\
2035cfd55e444fb1a14b804ff40b8a23d46c9fab0a451d21af837f5799d57809",
);
let d: Vec<u8> = hex(
"775819235c4b72f2f0839d97076d46f7824d96e9d3bc721bec06d4af4dc7cf89\
61675be3b0759a16635117a4a6c895d3bfdebe6177d2b1911d75555f7f1e38b6\
b38050ddc7c619086cca42cf319313c7adf92a4a8e17c3e7f6789208bbf65c09\
cacd0b3cb16eb3b70838379844509fae17818045f34953e5201fdf1c65a1a5a1",
);
let msg = b"TLS 1.3 server CertificateVerify";
let mut h = Sha256::new();
let digest = {
h.update(msg);
h.finalize()
};
let sig = rsa::sign_pkcs1v15(&n, &d, rsa::DIGEST_INFO_SHA256, &digest).expect("sign pkcs1");
let key = super::super::crypto::rsa::RsaPublicKey {
n: n.clone(),
e: vec![0x01, 0x00, 0x01],
};
assert!(key.verify_pkcs1v15(rsa::DIGEST_INFO_SHA256, &digest, &sig));
let mut h = Sha256::new();
let sig = rsa::sign_pss(&mut h, &n, &d, msg, 32).expect("sign pss");
let mut h = Sha256::new();
assert!(key.verify_pss(&mut h, msg, 32, &sig));
}
}