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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
use super::{x509, SignatureError, Verification};
use async_trait::async_trait;
use hex;
use ring::digest::{Context, SHA256};
use ring::signature;
use x509_parser::time::ASN1Time;
pub struct RingVerifier {}
impl RingVerifier {}
#[async_trait]
impl Verification for RingVerifier {
fn verify_nist384p_chain(
&self,
epoch_seconds: u64,
pem_bytes: &[u8],
root_hash: &str,
subject_cn: &str,
message: &[u8],
signature: &[u8],
) -> Result<(), SignatureError> {
let pems = match x509::parse_certificate_chain(pem_bytes) {
Ok(pems) => pems,
Err(err) => return Err(SignatureError::CertificateContentError(err.to_string())),
};
let certs: Vec<x509::X509Certificate> = match pems
.iter()
.map(|pem| match x509::parse_x509_certificate(pem) {
Ok(cert) => Ok(cert),
Err(e) => Err(e),
})
.collect::<Result<Vec<x509::X509Certificate>, _>>()
{
Ok(certs) => certs,
Err(err) => return Err(SignatureError::CertificateContentError(err.to_string())),
};
let root_hash_bytes = hex::decode(&root_hash.replace(":", ""))
.map_err(|err| SignatureError::RootHashFormatError(err.to_string()))?;
let root_pem = pems.first().unwrap();
let mut root_fingerprint_hash = Context::new(&SHA256);
root_fingerprint_hash.update(&root_pem.contents);
let root_fingerprint_bytes = root_fingerprint_hash.finish().as_ref().to_vec();
if root_fingerprint_bytes != root_hash_bytes {
return Err(SignatureError::InvalidCertificateIssuer(hex::encode(
root_fingerprint_bytes,
)));
}
let now = match ASN1Time::from_timestamp(epoch_seconds as i64) {
Ok(t) => t,
Err(_) => return Err(SignatureError::CertificateExpired),
};
for cert in &certs {
if !cert.tbs_certificate.validity.is_valid_at(now) {
return Err(SignatureError::CertificateExpired);
}
}
for pair in certs.windows(2) {
if let [parent, child] = pair {
let signature_alg = &child.signature_algorithm.algorithm;
let verification_alg: &dyn signature::VerificationAlgorithm = if *signature_alg
== x509_parser::oid_registry::OID_PKCS1_SHA256WITHRSA
{
&signature::RSA_PKCS1_2048_8192_SHA256
} else if *signature_alg == x509_parser::oid_registry::OID_PKCS1_SHA384WITHRSA {
&signature::RSA_PKCS1_2048_8192_SHA384
} else if *signature_alg == x509_parser::oid_registry::OID_PKCS1_SHA512WITHRSA {
&signature::RSA_PKCS1_2048_8192_SHA512
} else if *signature_alg == x509_parser::oid_registry::OID_SIG_ECDSA_WITH_SHA256 {
&signature::ECDSA_P256_SHA256_ASN1
} else if *signature_alg == x509_parser::oid_registry::OID_SIG_ECDSA_WITH_SHA384 {
&signature::ECDSA_P384_SHA384_ASN1
} else {
return Err(SignatureError::UnsupportedSignatureAlgorithm);
};
let parent_pk_bytes = &parent.tbs_certificate.subject_pki.subject_public_key.data;
let child_der_bytes = child.tbs_certificate.as_ref();
let child_sig_bytes = &child.signature_value.data;
let public_key =
signature::UnparsedPublicKey::new(verification_alg, &parent_pk_bytes);
public_key
.verify(child_der_bytes, &child_sig_bytes)
.or(Err(SignatureError::CertificateTrustError))?;
}
}
let leaf_cert = certs.last().unwrap();
let leaf_subject = leaf_cert
.tbs_certificate
.subject
.iter_common_name()
.next()
.and_then(|cn| cn.as_str().ok())
.unwrap_or("")
.to_string();
if leaf_subject != subject_cn {
return Err(SignatureError::InvalidCertificateSubject(leaf_subject));
}
let public_key_bytes = &leaf_cert
.tbs_certificate
.subject_pki
.subject_public_key
.data;
let signature_alg = &signature::ECDSA_P384_SHA384_FIXED;
let public_key = signature::UnparsedPublicKey::new(signature_alg, &public_key_bytes);
let decoded_signature = match base64::decode_config(&signature, base64::URL_SAFE) {
Ok(s) => s,
Err(err) => return Err(SignatureError::BadSignatureContent(err.to_string())),
};
match public_key.verify(message, &decoded_signature) {
Ok(_) => Ok(()),
Err(err) => Err(SignatureError::MismatchError(err.to_string())),
}
}
fn verify_sha256_hash(&self, content: &[u8], expected: &[u8]) -> Result<(), SignatureError> {
let actual = ring::digest::digest(&ring::digest::SHA256, content);
if expected == actual.as_ref() {
Ok(())
} else {
Err(SignatureError::MismatchError(
"content did not match expected sha256 hash".to_string(),
))
}
}
}