1#[macro_use]
2extern crate log;
3
4mod winapi;
5
6extern crate widestring;
7
8use std::ptr::{null_mut, null, read};
9use widestring::WideCString;
10use winapi::*;
11
12#[derive(Clone,Default,Debug)]
13pub struct CodeSigned {
14 pub path: String,
15 pub signed: Option<bool>,
16 pub catalog: bool,
17 pub issuer_name: String,
18 pub subject_name: String,
19 pub timestamp_issuer_name: String,
20 pub timestamp_subject_name: String,
21 pub serial_number: String,
22}
23
24impl CodeSigned {
25 pub fn file(&mut self, path: &str) {
26 self.path = path.to_owned();
27 if let Ok(path) = WideCString::from_str(path) {
28 let mut file_info = WinTrustFileInfo::from_path(&path);
29 let mut win_trust_data = WinTrustData::default();
30 win_trust_data.data = &mut file_info;
31
32 let action = Guid::wintrust_action_generic_verify_v2();
33 match unsafe {
34 WinVerifyTrust(null(), &action, &win_trust_data)
35 } {
36 0 => self.embedded(&path),
37 _ => self.catalog(&path)
38 }
39
40 win_trust_data.state_action = WTD_STATEACTION_CLOSE;
41 unsafe { WinVerifyTrust(null(), &action, &win_trust_data); }
42 }
43 }
44
45 fn embedded(&mut self, path: &WideCString) {
46 let mut encoding: u32 = 0;
47 let mut content_type: u32 = 0;
48 let mut format_type: u32 = 0;
49 let mut h_store: *mut u8 = null_mut();
50 let mut h_msg: *mut u8 = null_mut();
51
52
53 match unsafe {
54 CryptQueryObject(
55 CERT_QUERY_OBJECT_FILE,
56 path.as_ptr() as *const _,
57 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
58 CERT_QUERY_FORMAT_FLAG_BINARY,
59 0,
60 &mut encoding,
61 &mut content_type,
62 &mut format_type,
63 &mut h_store,
64 &mut h_msg,
65 null_mut()
66 )
67 } {
68 0 => { },
69 _ => {
70 let mut data_len: u32 = 0;
71 unsafe {
72 CryptMsgGetParam(
73 h_msg,
74 CMSG_SIGNER_INFO_PARAM,
75 0,
76 null_mut(),
77 &mut data_len
78 );
79 }
80
81 let mut data: Vec<u8> = vec![0; data_len as usize];
82 match unsafe {
83 CryptMsgGetParam(
84 h_msg,
85 CMSG_SIGNER_INFO_PARAM,
86 0,
87 data.as_mut_ptr(),
88 &mut data_len
89 )
90 } {
91 0 => { },
92 _ => {
93 let msg: MsgSignerInfo = unsafe {
94 read(data.as_mut_ptr() as *const _)
95 };
96
97 let mut cert_info = CertInfo::default();
98 cert_info.serial_number.from(&msg.serial_number);
99 cert_info.issuer.from(&msg.issuer);
100
101 let context = CertStoreContext::new(unsafe {
102 CertFindCertificateInStore(
103 h_store,
104 ENCODING,
105 0,
106 CERT_FIND_SUBJECT_CERT,
107 &cert_info,
108 null()
109 )
110 });
111
112 let needed: u32 = unsafe {
113 CertGetNameStringA(
114 context.context(),
115 CERT_NAME_SIMPLE_DISPLAY_TYPE,
116 0,
117 null(),
118 null(),
119 0
120 )
121 };
122 let mut subject_name_data: Vec<u8> = vec![0; needed as usize];
123 unsafe {
124 CertGetNameStringA(
125 context.context(),
126 CERT_NAME_SIMPLE_DISPLAY_TYPE,
127 0,
128 null(),
129 subject_name_data.as_mut_ptr(),
130 needed as u32
131 );
132 }
133
134 self.serial_number = msg.serial_number.to_string();
135 self.issuer_name = msg.issuer.to_string();
136 self.subject_name = String::from_utf8((&subject_name_data[0..needed as usize -1]).to_vec()).unwrap_or("(unknown)".to_owned());
137 self.signed = Some(true);
138 unsafe {
139 CryptMsgClose(h_msg);
140 CertCloseStore(h_store, 2);
141 }
142 }
143 }
144 }
145 }
146 }
147
148 fn catalog(&mut self, path: &WideCString) {
149 let f = FileHandle::new().with_file(&path);
150 if let Some(handle) = f.handle() {
151 let mut hash_length: u32 = 0;
152 match unsafe {
153 CryptCATAdminCalcHashFromFileHandle(
154 handle,
155 &mut hash_length,
156 null_mut(),
157 0
158 )
159 } {
160 0 => warn!("Could not obtain file hash for {}", path.to_string_lossy()),
161 _ => {
162 self.signed = Some(false);
163 let mut hash_data: Vec<u8> = vec![0; hash_length as usize];
164 unsafe {
165 CryptCATAdminCalcHashFromFileHandle(
166 handle,
167 &mut hash_length,
168 hash_data.as_mut_ptr(),
169 0
170 );
171 }
172
173 let driver_action = Guid::driver_action_verify();
174 let mut admin_context: *mut u8 = null_mut();
175 if unsafe { CryptCATAdminAcquireContext(&mut admin_context, &driver_action, 0) } == 0 {
176 return;
178 }
179
180 let mut cat = unsafe { CryptCATAdminEnumCatalogFromHash(admin_context, hash_data.as_ptr(), hash_length, 0, null_mut()) };
181 loop {
182 let mut cat_info = CatalogInfo::default();
183 if 0 == unsafe { CryptCATCatalogInfoFromContext(cat, &mut cat_info, 0) } {
184 break;
186 }
187 let cat_path = unsafe { WideCString::from_ptr_str(&cat_info.catalog_file as *const u16) };
188 self.catalog = true;
189 self.embedded(&cat_path);
190 cat = unsafe { CryptCATAdminEnumCatalogFromHash(admin_context, hash_data.as_ptr(), hash_length, 0, &mut cat) };
191 if cat == null_mut() { break; }
192 }
193
194 unsafe {
195 CryptCATAdminReleaseCatalogContext(admin_context, cat, 0);
196 CryptCATAdminReleaseContext(admin_context, 0);
197 }
198 }
199 }
200 }
201 }
202}