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
#![deny(warnings)]
extern crate libc;
#[cfg(target_os = "macos")]
extern crate core_foundation;
#[cfg(target_os = "macos")]
extern crate security_framework;
#[cfg(windows)]
extern crate crypt32;
#[cfg(windows)]
extern crate winapi;
#[derive(PartialEq, Debug)]
pub enum ValidationResult {
Trusted = 1,
NotTrusted,
MalformedCertificateInChain,
UnableToBuildTrustStore,
ErrorDuringValidation,
MissingFunctionality,
UserAuthenticationRequired,
MalformedHostname,
}
pub use self::platform::validate_cert_chain;
mod platform;
#[cfg(windows)]
mod windows;
#[cfg(target_os = "macos")]
mod osx;
#[cfg(test)]
mod test {
use validate_cert_chain;
use ValidationResult;
pub fn certifi_chain() -> Vec<&'static[u8]> {
let leaf = include_bytes!("../fixtures/certifi/leaf.crt");
let first_inter = include_bytes!("../fixtures/certifi/first-intermediate.crt");
let second_inter = include_bytes!("../fixtures/certifi/second-intermediate.crt");
vec![leaf, first_inter, second_inter]
}
pub fn expired_chain() -> Vec<&'static[u8]> {
let leaf = include_bytes!("../fixtures/expired/leaf.crt");
let first_inter = include_bytes!("../fixtures/expired/first-intermediate.crt");
let second_inter = include_bytes!("../fixtures/expired/second-intermediate.crt");
vec![leaf, first_inter, second_inter]
}
pub fn self_signed_chain() -> Vec<&'static[u8]> {
let leaf = include_bytes!("../fixtures/self-signed/leaf.crt");
vec![leaf]
}
#[test]
fn can_validate_good_chain() {
let chain = certifi_chain();
let valid = validate_cert_chain(&chain, "certifi.io");
assert_eq!(valid, ValidationResult::Trusted);
}
#[test]
fn fails_on_bad_hostname() {
let chain = certifi_chain();
let valid = validate_cert_chain(&chain, "lukasa.co.uk");
assert_eq!(valid, ValidationResult::NotTrusted);
}
#[test]
fn fails_on_bad_cert() {
let mut good_chain = certifi_chain();
let originals = good_chain.split_first_mut().unwrap();
let leaf = originals.0;
let intermediates = originals.1;
let mut certs = vec![&leaf[1..50]];
certs.extend(intermediates.iter());
let valid = validate_cert_chain(&certs, "certifi.io");
assert!(
(valid == ValidationResult::MalformedCertificateInChain) ||
(valid == ValidationResult::NotTrusted)
);
}
#[test]
fn fails_on_expired_cert() {
let chain = expired_chain();
let valid = validate_cert_chain(&chain, "expired.badssl.com");
assert_eq!(valid, ValidationResult::NotTrusted);
}
#[test]
fn test_fails_on_self_signed() {
let chain = self_signed_chain();
let valid = validate_cert_chain(&chain, "self-signed.badssl.com");
assert_eq!(valid, ValidationResult::NotTrusted);
}
}