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