Line data Source code
1 : use std::marker::PhantomData;
2 :
3 : use lief_ffi as ffi;
4 :
5 : use crate::common::{into_optional, FromFFI};
6 : use crate::pe::Algorithms;
7 : use crate::to_slice;
8 :
9 : pub struct ContentInfo<'a> {
10 : ptr: cxx::UniquePtr<ffi::PE_ContentInfo>,
11 : _owner: PhantomData<&'a ffi::PE_Signature>,
12 : }
13 :
14 : /// ContentInfo as described in the RFC2315 <https://tools.ietf.org/html/rfc2315#section-7>
15 : impl ContentInfo<'_> {
16 : /// Return the OID that describes the content wrapped by this object.
17 : /// It should match `SPC_INDIRECT_DATA_OBJID` (`1.3.6.1.4.1.311.2.1.4`)
18 325 : pub fn content_type(&self) -> String {
19 325 : self.ptr.content_type().to_string()
20 325 : }
21 :
22 325 : pub fn value(&self) -> Option<Content<'_>> {
23 325 : into_optional(self.ptr.value())
24 325 : }
25 :
26 : /// Return the digest (authentihash) if the underlying content type is `SPC_INDIRECT_DATA_OBJID`
27 : /// Otherwise, return an empty vector
28 0 : pub fn digest(&self) -> Vec<u8> {
29 0 : Vec::from(self.ptr.digest().as_slice())
30 0 : }
31 :
32 : /// Return the digest used to hash the file
33 0 : pub fn digest_algorithm(&self) -> Algorithms {
34 0 : Algorithms::from(self.ptr.digest_algorithm())
35 0 : }
36 : }
37 :
38 : impl std::fmt::Debug for ContentInfo<'_> {
39 325 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40 325 : f.debug_struct("ContentInfo")
41 325 : .field("content_type", &self.content_type())
42 325 : .finish()
43 325 : }
44 : }
45 :
46 : impl<'a> FromFFI<ffi::PE_ContentInfo> for ContentInfo<'a> {
47 650 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_ContentInfo>) -> Self {
48 650 : ContentInfo {
49 650 : ptr,
50 650 : _owner: PhantomData,
51 650 : }
52 650 : }
53 : }
54 :
55 325 : #[derive(Debug)]
56 : pub enum Content<'a> {
57 : SpcIndirectData(SpcIndirectData<'a>),
58 : PKCS9TSTInfo(PKCS9TSTInfo<'a>),
59 : Generic(Generic<'a>),
60 : }
61 :
62 : impl<'a> FromFFI<ffi::PE_ContentInfo_Content> for Content<'a> {
63 325 : fn from_ffi(ffi_entry: cxx::UniquePtr<ffi::PE_ContentInfo_Content>) -> Self {
64 325 : unsafe {
65 325 : let content_ref = ffi_entry.as_ref().unwrap();
66 325 : if ffi::PE_SpcIndirectData::classof(content_ref) {
67 208 : let raw = {
68 208 : type From = cxx::UniquePtr<ffi::PE_ContentInfo_Content>;
69 208 : type To = cxx::UniquePtr<ffi::PE_SpcIndirectData>;
70 208 : std::mem::transmute::<From, To>(ffi_entry)
71 208 : };
72 208 : Content::SpcIndirectData(SpcIndirectData::from_ffi(raw))
73 117 : } else if ffi::PE_PKCS9TSTInfo::classof(content_ref) {
74 117 : let raw = {
75 117 : type From = cxx::UniquePtr<ffi::PE_ContentInfo_Content>;
76 117 : type To = cxx::UniquePtr<ffi::PE_PKCS9TSTInfo>;
77 117 : std::mem::transmute::<From, To>(ffi_entry)
78 117 : };
79 117 : Content::PKCS9TSTInfo(PKCS9TSTInfo::from_ffi(raw))
80 : } else {
81 0 : let raw = {
82 0 : type From = cxx::UniquePtr<ffi::PE_ContentInfo_Content>;
83 0 : type To = cxx::UniquePtr<ffi::PE_GenericContent>;
84 0 : std::mem::transmute::<From, To>(ffi_entry)
85 0 : };
86 0 : Content::Generic(Generic::from_ffi(raw))
87 : }
88 : }
89 325 : }
90 : }
91 :
92 : pub trait ContentTrait {
93 : #[doc(hidden)]
94 : fn as_generic(&self) -> &ffi::PE_ContentInfo_Content;
95 :
96 : /// Return the OID that describes this content info.
97 : /// In the case of the PE authenticode, it should return `SPC_INDIRECT_DATA_OBJID (1.3.6.1.4.1.311.2.1.4)`
98 0 : fn content_type(&self) -> String {
99 0 : self.as_generic().content_type().to_string()
100 0 : }
101 : }
102 :
103 : pub struct SpcIndirectData<'a> {
104 : ptr: cxx::UniquePtr<ffi::PE_SpcIndirectData>,
105 : _owner: PhantomData<&'a ffi::PE_ContentInfo>,
106 : }
107 :
108 : impl SpcIndirectData<'_> {
109 416 : pub fn file(&self) -> String {
110 416 : self.ptr.file().to_string()
111 416 : }
112 :
113 416 : pub fn url(&self) -> String {
114 416 : self.ptr.url().to_string()
115 416 : }
116 :
117 : /// PE's authentihash
118 : ///
119 : /// See: [`crate::pe::Binary::authentihash`]
120 208 : pub fn digest(&self) -> &[u8] {
121 208 : to_slice!(self.ptr.digest());
122 208 : }
123 :
124 : /// Digest used to hash the file
125 416 : pub fn digest_algorithm(&self) -> Algorithms {
126 416 : Algorithms::from(self.ptr.digest_algorithm())
127 416 : }
128 : }
129 :
130 : impl std::fmt::Debug for SpcIndirectData<'_> {
131 416 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
132 416 : f.debug_struct("SpcIndirectData")
133 416 : .field("file", &self.file())
134 416 : .field("url", &self.url())
135 416 : .field("digest_algorithm", &self.digest_algorithm())
136 416 : .finish()
137 416 : }
138 : }
139 :
140 : impl FromFFI<ffi::PE_SpcIndirectData> for SpcIndirectData<'_> {
141 208 : fn from_ffi(cmd: cxx::UniquePtr<ffi::PE_SpcIndirectData>) -> Self {
142 208 : Self {
143 208 : ptr: cmd,
144 208 : _owner: PhantomData,
145 208 : }
146 208 : }
147 : }
148 :
149 : impl ContentTrait for SpcIndirectData<'_> {
150 0 : fn as_generic(&self) -> &ffi::PE_ContentInfo_Content {
151 0 : self.ptr.as_ref().unwrap().as_ref()
152 0 : }
153 : }
154 :
155 : pub struct PKCS9TSTInfo<'a> {
156 : ptr: cxx::UniquePtr<ffi::PE_PKCS9TSTInfo>,
157 : _owner: PhantomData<&'a ffi::PE_ContentInfo>,
158 : }
159 :
160 : impl PKCS9TSTInfo<'_> {
161 : // TODO(romain): Add API
162 : }
163 :
164 : impl std::fmt::Debug for PKCS9TSTInfo<'_> {
165 117 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
166 117 : f.debug_struct("PKCS9TSTInfo").finish()
167 117 : }
168 : }
169 :
170 : impl FromFFI<ffi::PE_PKCS9TSTInfo> for PKCS9TSTInfo<'_> {
171 117 : fn from_ffi(cmd: cxx::UniquePtr<ffi::PE_PKCS9TSTInfo>) -> Self {
172 117 : Self {
173 117 : ptr: cmd,
174 117 : _owner: PhantomData,
175 117 : }
176 117 : }
177 : }
178 :
179 : impl ContentTrait for PKCS9TSTInfo<'_> {
180 0 : fn as_generic(&self) -> &ffi::PE_ContentInfo_Content {
181 0 : self.ptr.as_ref().unwrap().as_ref()
182 0 : }
183 : }
184 :
185 : pub struct Generic<'a> {
186 : ptr: cxx::UniquePtr<ffi::PE_GenericContent>,
187 : _owner: PhantomData<&'a ffi::PE_ContentInfo>,
188 : }
189 :
190 : impl Generic<'_> {
191 0 : pub fn raw(&self) -> &[u8] {
192 0 : to_slice!(self.ptr.raw());
193 0 : }
194 :
195 0 : pub fn oid(&self) -> String {
196 0 : self.ptr.oid().to_string()
197 0 : }
198 : }
199 :
200 : impl std::fmt::Debug for Generic<'_> {
201 0 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
202 0 : f.debug_struct("Generic").finish()
203 0 : }
204 : }
205 :
206 : impl FromFFI<ffi::PE_GenericContent> for Generic<'_> {
207 0 : fn from_ffi(cmd: cxx::UniquePtr<ffi::PE_GenericContent>) -> Self {
208 0 : Self {
209 0 : ptr: cmd,
210 0 : _owner: PhantomData,
211 0 : }
212 0 : }
213 : }
214 :
215 : impl ContentTrait for Generic<'_> {
216 0 : fn as_generic(&self) -> &ffi::PE_ContentInfo_Content {
217 0 : self.ptr.as_ref().unwrap().as_ref()
218 0 : }
219 : }
|