1 /* Copyright (C) 2019-2020 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 // written by Pierre Chifflier  <chifflier@wzdftpd.net>
19 
20 use crate::common::rust_string_to_c;
21 use nom;
22 use std;
23 use std::os::raw::c_char;
24 use x509_parser::{error::X509Error, parse_x509_der, X509Certificate};
25 
26 #[repr(u32)]
27 pub enum X509DecodeError {
28     Success = 0,
29     /// Generic decoding error
30     InvalidCert,
31     /// Some length does not match, or certificate is incomplete
32     InvalidLength,
33     InvalidVersion,
34     InvalidSerial,
35     InvalidAlgorithmIdentifier,
36     InvalidX509Name,
37     InvalidDate,
38     InvalidExtensions,
39     /// DER structure is invalid
40     InvalidDER,
41 }
42 
43 pub struct X509(X509Certificate<'static>);
44 
45 /// Attempt to parse a X.509 from input, and return a pointer to the parsed object if successful.
46 ///
47 /// # Safety
48 ///
49 /// input must be a valid buffer of at least input_len bytes
50 #[no_mangle]
rs_x509_decode( input: *const u8, input_len: u32, err_code: *mut u32, ) -> *mut X50951 pub unsafe extern "C" fn rs_x509_decode(
52     input: *const u8,
53     input_len: u32,
54     err_code: *mut u32,
55 ) -> *mut X509 {
56     let slice = std::slice::from_raw_parts(input, input_len as usize);
57     let res = parse_x509_der(slice);
58     match res {
59         Ok((_rem, cert)) => Box::into_raw(Box::new(X509(cert))),
60         Err(e) => {
61             let error = x509_parse_error_to_errcode(&e);
62             *err_code = error as u32;
63             std::ptr::null_mut()
64         }
65     }
66 }
67 
68 #[no_mangle]
rs_x509_get_subject(ptr: *const X509) -> *mut c_char69 pub extern "C" fn rs_x509_get_subject(ptr: *const X509) -> *mut c_char {
70     if ptr.is_null() {
71         return std::ptr::null_mut();
72     }
73     let x509 = cast_pointer! {ptr, X509};
74     let subject = x509.0.tbs_certificate.subject.to_string();
75     rust_string_to_c(subject)
76 }
77 
78 #[no_mangle]
rs_x509_get_issuer(ptr: *const X509) -> *mut c_char79 pub extern "C" fn rs_x509_get_issuer(ptr: *const X509) -> *mut c_char {
80     if ptr.is_null() {
81         return std::ptr::null_mut();
82     }
83     let x509 = cast_pointer! {ptr, X509};
84     let issuer = x509.0.tbs_certificate.issuer.to_string();
85     rust_string_to_c(issuer)
86 }
87 
88 #[no_mangle]
rs_x509_get_serial(ptr: *const X509) -> *mut c_char89 pub extern "C" fn rs_x509_get_serial(ptr: *const X509) -> *mut c_char {
90     if ptr.is_null() {
91         return std::ptr::null_mut();
92     }
93     let x509 = cast_pointer! {ptr, X509};
94     let raw_serial = x509.0.tbs_certificate.raw_serial();
95     let v: Vec<_> = raw_serial.iter().map(|x| format!("{:02X}", x)).collect();
96     let serial = v.join(":");
97     rust_string_to_c(serial)
98 }
99 
100 /// Extract validity from input X.509 object
101 ///
102 /// # Safety
103 ///
104 /// ptr must be a valid object obtained using `rs_x509_decode`
105 #[no_mangle]
rs_x509_get_validity( ptr: *const X509, not_before: *mut i64, not_after: *mut i64, ) -> i32106 pub unsafe extern "C" fn rs_x509_get_validity(
107     ptr: *const X509,
108     not_before: *mut i64,
109     not_after: *mut i64,
110 ) -> i32 {
111     if ptr.is_null() {
112         return -1;
113     }
114     let x509 = &*ptr;
115     let n_b = x509.0.tbs_certificate.validity.not_before.to_timespec().sec;
116     let n_a = x509.0.tbs_certificate.validity.not_after.to_timespec().sec;
117     *not_before = n_b;
118     *not_after = n_a;
119     0
120 }
121 
122 /// Free a X.509 object allocated by Rust
123 ///
124 /// # Safety
125 ///
126 /// ptr must be a valid object obtained using `rs_x509_decode`
127 #[no_mangle]
rs_x509_free(ptr: *mut X509)128 pub unsafe extern "C" fn rs_x509_free(ptr: *mut X509) {
129     if ptr.is_null() {
130         return;
131     }
132     drop(Box::from_raw(ptr));
133 }
134 
x509_parse_error_to_errcode(e: &nom::Err<X509Error>) -> X509DecodeError135 fn x509_parse_error_to_errcode(e: &nom::Err<X509Error>) -> X509DecodeError {
136     match e {
137         nom::Err::Incomplete(_) => X509DecodeError::InvalidLength,
138         nom::Err::Error(e) | nom::Err::Failure(e) => match e {
139             X509Error::InvalidVersion => X509DecodeError::InvalidVersion,
140             X509Error::InvalidSerial => X509DecodeError::InvalidSerial,
141             X509Error::InvalidAlgorithmIdentifier => X509DecodeError::InvalidAlgorithmIdentifier,
142             X509Error::InvalidX509Name => X509DecodeError::InvalidX509Name,
143             X509Error::InvalidDate => X509DecodeError::InvalidDate,
144             X509Error::InvalidExtensions => X509DecodeError::InvalidExtensions,
145             X509Error::Der(_) => X509DecodeError::InvalidDER,
146             _ => X509DecodeError::InvalidCert,
147         },
148     }
149 }
150