1use der_parser::der::Tag;
2use der_parser::oid::Oid;
3use nom::HexDisplay;
4use std::cmp::min;
5use std::convert::TryFrom;
6use std::env;
7use std::io;
8use std::net::{Ipv4Addr, Ipv6Addr};
9use x509_parser::prelude::*;
10use x509_parser::public_key::PublicKey;
11use x509_parser::signature_algorithm::SignatureAlgorithm;
12
13const PARSE_ERRORS_FATAL: bool = false;
14#[cfg(feature = "validate")]
15const VALIDATE_ERRORS_FATAL: bool = false;
16
17fn print_hex_dump(bytes: &[u8], max_len: usize) {
18 let m = min(bytes.len(), max_len);
19 print!("{}", &bytes[..m].to_hex(16));
20 if bytes.len() > max_len {
21 println!("... <continued>");
22 }
23}
24
25fn format_oid(oid: &Oid) -> String {
26 match oid2sn(oid, oid_registry()) {
27 Ok(s) => s.to_owned(),
28 _ => format!("{}", oid),
29 }
30}
31
32fn generalname_to_string(gn: &GeneralName) -> String {
33 match gn {
34 GeneralName::DNSName(name) => format!("DNSName:{}", name),
35 GeneralName::DirectoryName(n) => format!("DirName:{}", n),
36 GeneralName::EDIPartyName(obj) => format!("EDIPartyName:{:?}", obj),
37 GeneralName::IPAddress(n) => format!("IPAddress:{:?}", n),
38 GeneralName::OtherName(oid, n) => format!("OtherName:{}, {:?}", oid, n),
39 GeneralName::RFC822Name(n) => format!("RFC822Name:{}", n),
40 GeneralName::RegisteredID(oid) => format!("RegisteredID:{}", oid),
41 GeneralName::URI(n) => format!("URI:{}", n),
42 GeneralName::X400Address(obj) => format!("X400Address:{:?}", obj),
43 }
44}
45
46fn print_x509_extension(oid: &Oid, ext: &X509Extension) {
47 println!(
48 " [crit:{} l:{}] {}: ",
49 ext.critical,
50 ext.value.len(),
51 format_oid(oid)
52 );
53 match ext.parsed_extension() {
54 ParsedExtension::AuthorityKeyIdentifier(aki) => {
55 println!(" X509v3 Authority Key Identifier");
56 if let Some(key_id) = &aki.key_identifier {
57 println!(" Key Identifier: {:x}", key_id);
58 }
59 if let Some(issuer) = &aki.authority_cert_issuer {
60 for name in issuer {
61 println!(" Cert Issuer: {}", name);
62 }
63 }
64 if let Some(serial) = aki.authority_cert_serial {
65 println!(" Cert Serial: {}", format_serial(serial));
66 }
67 }
68 ParsedExtension::BasicConstraints(bc) => {
69 println!(" X509v3 CA: {}", bc.ca);
70 }
71 ParsedExtension::CRLDistributionPoints(points) => {
72 println!(" X509v3 CRL Distribution Points:");
73 for point in points.iter() {
74 if let Some(name) = &point.distribution_point {
75 println!(" Full Name: {:?}", name);
76 }
77 if let Some(reasons) = &point.reasons {
78 println!(" Reasons: {}", reasons);
79 }
80 if let Some(crl_issuer) = &point.crl_issuer {
81 print!(" CRL Issuer: ");
82 for gn in crl_issuer {
83 print!("{} ", generalname_to_string(gn));
84 }
85 println!();
86 }
87 println!();
88 }
89 }
90 ParsedExtension::KeyUsage(ku) => {
91 println!(" X509v3 Key Usage: {}", ku);
92 }
93 ParsedExtension::NSCertType(ty) => {
94 println!(" Netscape Cert Type: {}", ty);
95 }
96 ParsedExtension::SubjectAlternativeName(san) => {
97 for name in &san.general_names {
98 let s = match name {
99 GeneralName::DNSName(s) => {
100 format!("DNS:{}", s)
101 }
102 GeneralName::IPAddress(b) => {
103 let ip = match b.len() {
104 4 => {
105 let b = <[u8; 4]>::try_from(*b).unwrap();
106 let ip = Ipv4Addr::from(b);
107 format!("{}", ip)
108 }
109 16 => {
110 let b = <[u8; 16]>::try_from(*b).unwrap();
111 let ip = Ipv6Addr::from(b);
112 format!("{}", ip)
113 }
114 l => format!("invalid (len={})", l),
115 };
116 format!("IP Address:{}", ip)
117 }
118 _ => {
119 format!("{:?}", name)
120 }
121 };
122 println!(" X509v3 SAN: {}", s);
123 }
124 }
125 ParsedExtension::SubjectKeyIdentifier(id) => {
126 println!(" X509v3 Subject Key Identifier: {:x}", id);
127 }
128 x => println!(" {:?}", x),
129 }
130}
131
132fn print_x509_digest_algorithm(alg: &AlgorithmIdentifier, level: usize) {
133 println!(
134 "{:indent$}Oid: {}",
135 "",
136 format_oid(&alg.algorithm),
137 indent = level
138 );
139 if let Some(parameter) = &alg.parameters {
140 let s = match parameter.tag() {
141 Tag::Oid => {
142 let oid = parameter.as_oid().unwrap();
143 format_oid(&oid)
144 }
145 _ => format!("{}", parameter.tag()),
146 };
147 println!("{:indent$}Parameter: <PRESENT> {}", "", s, indent = level);
148 let bytes = parameter.as_bytes();
149 print_hex_dump(bytes, 32);
150 } else {
151 println!("{:indent$}Parameter: <ABSENT>", "", indent = level);
152 }
153}
154
155fn print_x509_info(x509: &X509Certificate) -> io::Result<()> {
156 let version = x509.version();
157 if version.0 < 3 {
158 println!(" Version: {}", version);
159 } else {
160 println!(" Version: INVALID({})", version.0);
161 }
162 println!(" Serial: {}", x509.tbs_certificate.raw_serial_as_string());
163 println!(" Subject: {}", x509.subject());
164 println!(" Issuer: {}", x509.issuer());
165 println!(" Validity:");
166 println!(" NotBefore: {}", x509.validity().not_before);
167 println!(" NotAfter: {}", x509.validity().not_after);
168 println!(" is_valid: {}", x509.validity().is_valid());
169 println!(" Subject Public Key Info:");
170 print_x509_ski(x509.public_key());
171 print_x509_signature_algorithm(&x509.signature_algorithm, 4);
172
173 println!(" Signature Value:");
174 for l in format_number_to_hex_with_colon(&x509.signature_value.data, 16) {
175 println!(" {}", l);
176 }
177 println!(" Extensions:");
178 for ext in x509.extensions() {
179 print_x509_extension(&ext.oid, ext);
180 }
181 println!();
182 print!("Structure validation status: ");
183 #[cfg(feature = "validate")]
184 {
185 let mut logger = VecLogger::default();
186 let ok = X509StructureValidator
188 .chain(X509CertificateValidator)
189 .validate(x509, &mut logger);
190 if ok {
191 println!("Ok");
192 } else {
193 println!("FAIL");
194 }
195 for warning in logger.warnings() {
196 println!(" [W] {}", warning);
197 }
198 for error in logger.errors() {
199 println!(" [E] {}", error);
200 }
201 println!();
202 if VALIDATE_ERRORS_FATAL && !logger.errors().is_empty() {
203 return Err(io::Error::new(io::ErrorKind::Other, "validation failed"));
204 }
205 }
206 #[cfg(not(feature = "validate"))]
207 {
208 println!("Unknown (feature 'validate' not enabled)");
209 }
210 #[cfg(feature = "verify")]
211 {
212 print!("Signature verification: ");
213 if x509.subject() == x509.issuer() {
214 if x509.verify_signature(None).is_ok() {
215 println!("OK");
216 println!(" [I] certificate is self-signed");
217 } else if x509.subject() == x509.issuer() {
218 println!("FAIL");
219 println!(" [W] certificate looks self-signed, but signature verification failed");
220 }
221 } else {
222 println!("N/A");
224 }
225 }
226 Ok(())
227}
228
229fn print_x509_signature_algorithm(signature_algorithm: &AlgorithmIdentifier, indent: usize) {
230 match SignatureAlgorithm::try_from(signature_algorithm) {
231 Ok(sig_alg) => {
232 print!(" Signature Algorithm: ");
233 match sig_alg {
234 SignatureAlgorithm::DSA => println!("DSA"),
235 SignatureAlgorithm::ECDSA => println!("ECDSA"),
236 SignatureAlgorithm::ED25519 => println!("ED25519"),
237 SignatureAlgorithm::RSA => println!("RSA"),
238 SignatureAlgorithm::RSASSA_PSS(params) => {
239 println!("RSASSA-PSS");
240 let indent_s = format!("{:indent$}", "", indent = indent + 2);
241 println!(
242 "{}Hash Algorithm: {}",
243 indent_s,
244 format_oid(params.hash_algorithm_oid()),
245 );
246 print!("{}Mask Generation Function: ", indent_s);
247 if let Ok(mask_gen) = params.mask_gen_algorithm() {
248 println!(
249 "{}/{}",
250 format_oid(&mask_gen.mgf),
251 format_oid(&mask_gen.hash),
252 );
253 } else {
254 println!("INVALID");
255 }
256 println!("{}Salt Length: {}", indent_s, params.salt_length());
257 }
258 SignatureAlgorithm::RSAAES_OAEP(params) => {
259 println!("RSAAES-OAEP");
260 let indent_s = format!("{:indent$}", "", indent = indent + 2);
261 println!(
262 "{}Hash Algorithm: {}",
263 indent_s,
264 format_oid(params.hash_algorithm_oid()),
265 );
266 print!("{}Mask Generation Function: ", indent_s);
267 if let Ok(mask_gen) = params.mask_gen_algorithm() {
268 println!(
269 "{}/{}",
270 format_oid(&mask_gen.mgf),
271 format_oid(&mask_gen.hash),
272 );
273 } else {
274 println!("INVALID");
275 }
276 println!(
277 "{}pSourceFunc: {}",
278 indent_s,
279 format_oid(¶ms.p_source_alg().algorithm),
280 );
281 }
282 }
283 }
284 Err(e) => {
285 eprintln!("Could not parse signature algorithm: {}", e);
286 println!(" Signature Algorithm:");
287 print_x509_digest_algorithm(signature_algorithm, indent);
288 }
289 }
290}
291
292fn print_x509_ski(public_key: &SubjectPublicKeyInfo) {
293 println!(" Public Key Algorithm:");
294 print_x509_digest_algorithm(&public_key.algorithm, 6);
295 match public_key.parsed() {
296 Ok(PublicKey::RSA(rsa)) => {
297 println!(" RSA Public Key: ({} bit)", rsa.key_size());
298 for l in format_number_to_hex_with_colon(rsa.modulus, 16) {
300 println!(" {}", l);
301 }
302 if let Ok(e) = rsa.try_exponent() {
303 println!(" exponent: 0x{:x} ({})", e, e);
304 } else {
305 println!(" exponent: <INVALID>:");
306 print_hex_dump(rsa.exponent, 32);
307 }
308 }
309 Ok(PublicKey::EC(ec)) => {
310 println!(" EC Public Key: ({} bit)", ec.key_size());
311 for l in format_number_to_hex_with_colon(ec.data(), 16) {
312 println!(" {}", l);
313 }
314 }
328 Ok(PublicKey::DSA(y)) => {
329 println!(" DSA Public Key: ({} bit)", 8 * y.len());
330 for l in format_number_to_hex_with_colon(y, 16) {
331 println!(" {}", l);
332 }
333 }
334 Ok(PublicKey::GostR3410(y)) => {
335 println!(" GOST R 34.10-94 Public Key: ({} bit)", 8 * y.len());
336 for l in format_number_to_hex_with_colon(y, 16) {
337 println!(" {}", l);
338 }
339 }
340 Ok(PublicKey::GostR3410_2012(y)) => {
341 println!(" GOST R 34.10-2012 Public Key: ({} bit)", 8 * y.len());
342 for l in format_number_to_hex_with_colon(y, 16) {
343 println!(" {}", l);
344 }
345 }
346 Ok(PublicKey::Unknown(b)) => {
347 println!(" Unknown key type");
348 print_hex_dump(b, 256);
349 if let Ok((rem, res)) = der_parser::parse_der(b) {
350 eprintln!("rem: {} bytes", rem.len());
351 eprintln!("{:?}", res);
352 } else {
353 eprintln!(" <Could not parse key as DER>");
354 }
355 }
356 Err(_) => {
357 println!(" INVALID PUBLIC KEY");
358 }
359 }
360 }
363
364fn format_number_to_hex_with_colon(b: &[u8], row_size: usize) -> Vec<String> {
365 let mut v = Vec::with_capacity(1 + b.len() / row_size);
366 for r in b.chunks(row_size) {
367 let s = r.iter().fold(String::with_capacity(3 * r.len()), |a, b| {
368 a + &format!("{:02x}:", b)
369 });
370 v.push(s)
371 }
372 v
373}
374
375fn handle_certificate(file_name: &str, data: &[u8]) -> io::Result<()> {
376 match parse_x509_certificate(data) {
377 Ok((_, x509)) => {
378 print_x509_info(&x509)?;
379 Ok(())
380 }
381 Err(e) => {
382 let s = format!("Error while parsing {}: {}", file_name, e);
383 if PARSE_ERRORS_FATAL {
384 Err(io::Error::new(io::ErrorKind::Other, s))
385 } else {
386 eprintln!("{}", s);
387 Ok(())
388 }
389 }
390 }
391}
392
393pub fn main() -> io::Result<()> {
394 for file_name in env::args().skip(1) {
395 println!("File: {}", file_name);
396 let data = std::fs::read(file_name.clone()).expect("Unable to read file");
397 if matches!((data[0], data[1]), (0x30, 0x81..=0x83)) {
398 handle_certificate(&file_name, &data)?;
400 } else {
401 for (n, pem) in Pem::iter_from_buffer(&data).enumerate() {
403 match pem {
404 Ok(pem) => {
405 let data = &pem.contents;
406 println!("Certificate [{}]", n);
407 handle_certificate(&file_name, data)?;
408 }
409 Err(e) => {
410 eprintln!("Error while decoding PEM entry {}: {}", n, e);
411 }
412 }
413 }
414 }
415 }
416 Ok(())
417}