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