add more specific error handeling to certs
All checks were successful
Build and Test / account (push) Successful in 6m7s

This commit is contained in:
Maple 2026-04-27 19:08:46 +02:00
commit 6b96e1db51

View file

@ -15,6 +15,7 @@ use bytemuck::bytes_of;
use chrono::{NaiveDate, NaiveDateTime, Utc};
use openssl::bn::BigNum;
use openssl::ecdsa::EcdsaSig;
use openssl::error::ErrorStack;
use rand::Rng;
use rocket::http::Status;
use rocket::request::{FromRequest, Outcome};
@ -262,7 +263,7 @@ pub async fn link_certificate_to_pid(
sqlx::query(
"INSERT INTO certificate_pids (cert_hash, pid)
VALUES ($1, $2)
ON CONFLICT DO NOTHING"
ON CONFLICT DO NOTHING",
)
.bind(&hash[..])
.bind(pid)
@ -330,14 +331,17 @@ impl<'r> FromRequest<'r> for DeviceCert {
};
let cert = match Certificate::new(cert_header) {
Some(c) => c,
None => return Outcome::Error((Status::BadGateway, INVALID_TOKEN_ERRORS)),
Ok(c) => c,
Err(e) => {
println!("error occurred whilest getting cert data: {}", e);
return Outcome::Error((Status::BadGateway, INVALID_TOKEN_ERRORS));
}
};
let hash = cert.hash();
let existing = sqlx::query_as::<_, CertificateRecord>(
"SELECT hash, banned FROM certificates WHERE hash = $1"
"SELECT hash, banned FROM certificates WHERE hash = $1",
)
.bind(&hash[..])
.fetch_optional(pool)
@ -359,7 +363,7 @@ impl<'r> FromRequest<'r> for DeviceCert {
} else {
sqlx::query(
"INSERT INTO certificates (hash, banned)
VALUES ($1, false)"
VALUES ($1, false)",
)
.bind(&hash[..])
.execute(pool)
@ -396,19 +400,36 @@ MFIwEAYHKoZIzj0CAQYFK4EEABsDPgAEAP1WBBgs8XUJIQDDCK5IOZEbb5+h1TqV
rwgzSUcrAAFxMWm1kf/TDL9z2nZkuo0N+VtNEQREZDXA7aQv
-----END PUBLIC KEY-----"#;
#[derive(thiserror::Error, Debug)]
enum CertError {
#[error("unable to decode base64: {0}")]
Base64(#[from] base64::DecodeError),
#[error("unable to decode outer cert: {0}")]
OuterBinError(binrw::Error),
#[error("unable to decode inner cert: {0}")]
BinError(binrw::Error),
#[error("unable to create openssl ecdsa sig: {0}")]
EcdsaSig(ErrorStack),
#[error("error whilest validating signature: {0}")]
CryptoVerifError(ErrorStack),
#[error("certificate is not valid")]
ValidationError,
}
impl Certificate {
fn new(data: &str) -> Option<Self> {
let data = BASE64_STANDARD.decode(data).unwrap();
fn new(data: &str) -> Result<Self, CertError> {
let data = BASE64_STANDARD.decode(data)?;
let cert = OuterCertificate::read(&mut Cursor::new(&data)).ok()?;
let cert =
OuterCertificate::read(&mut Cursor::new(&data)).map_err(CertError::OuterBinError)?;
println!("key");
let key = openssl::ec::EcKey::public_key_from_pem(PUB_PEM).expect("invalid pem file");
let key = openssl::ec::EcKey::public_key_from_pem(PUB_PEM).ok()?;
let sig_components = read_p1363(&cert.signature)
.expect("unable to read signature despite fixed size signature");
let sig_components = read_p1363(&cert.signature)?;
let sig = EcdsaSig::from_private_components(sig_components.0, sig_components.1).unwrap();
let sig = EcdsaSig::from_private_components(sig_components.0, sig_components.1)
.map_err(CertError::EcdsaSig)?;
let mut hasher = openssl::sha::Sha256::new();
@ -416,11 +437,14 @@ impl Certificate {
let hash = hasher.finish();
if !sig.verify(&hash[..], &key).ok()? {
return None;
if !sig
.verify(&hash[..], &key)
.map_err(CertError::CryptoVerifError)?
{
return Err(CertError::ValidationError);
}
Certificate::read(&mut Cursor::new(cert.data)).ok()
Certificate::read(&mut Cursor::new(cert.data)).map_err(CertError::BinError)
}
pub fn hash(&self) -> [u8; 32] {
@ -446,3 +470,15 @@ fn read_p1363(data: &[u8]) -> Option<(BigNum, BigNum)> {
BigNum::from_slice(&data[half_len..]).ok()?,
))
}
#[cfg(test)]
mod test {
use crate::account::account::Certificate;
#[test]
fn test() {
const CERT: &str = "AAEABQAsTGvAP1XNwh6JO+z47AkwVvqPYHRDO9X11BdhYwCIEipUJne32JSWMAYsFe1LqWT+0AkSnaDCkMWK1QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABSb290LUNBMDAwMDAwMDMtTVMwMDAwMDAxMgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAk5HNDQ0Y2FiZmMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB1/THZAcTyFksveCuIl5fOM7Fb6ebi6mUqcVJlQQDqvsgMAW12aEaECJWV+Y6wXOL+E7yP5WJ/9VAd4jlgrvZQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
Certificate::new(CERT).unwrap();
}
}