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::declare_iterator;
7 : use crate::pe::Algorithms;
8 :
9 : use super::{RsaInfo, VerificationFlags};
10 :
11 : /// Structure for a x509 certificate
12 : pub struct X509<'a> {
13 : ptr: cxx::UniquePtr<ffi::PE_x509>,
14 : _owner: PhantomData<&'a ffi::PE_SignerInfo>,
15 : }
16 :
17 : impl std::fmt::Debug for X509<'_> {
18 690 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19 690 : f.debug_struct("x509")
20 690 : .field("version", &self.version())
21 690 : .field("signature_algorithm", &self.signature_algorithm())
22 690 : .field("valid_from", &self.valid_from())
23 690 : .field("valid_to", &self.valid_to())
24 690 : .field("issuer", &self.issuer())
25 690 : .field("key_type", &self.key_type())
26 690 : .field("subject", &self.subject())
27 690 : .field("is_ca", &self.is_ca())
28 690 : .finish()
29 690 : }
30 : }
31 :
32 : impl<'a> FromFFI<ffi::PE_x509> for X509<'a> {
33 690 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_x509>) -> Self {
34 690 : X509 {
35 690 : ptr,
36 690 : _owner: PhantomData,
37 690 : }
38 690 : }
39 : }
40 :
41 : #[allow(non_camel_case_types)]
42 690 : #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
43 : /// Public key scheme
44 : pub enum KeyType {
45 : /// Unknown scheme
46 : NONE,
47 :
48 : /// RSA Scheme
49 : RSA,
50 :
51 : /// Elliptic-curve scheme
52 : ECKEY,
53 :
54 : /// Elliptic-curve Diffie-Hellman
55 : ECKEY_DH,
56 :
57 : /// Elliptic-curve Digital Signature Algorithm
58 : ECDSA,
59 :
60 : /// RSA scheme with an alternative implementation for signing and decrypting
61 : RSA_ALT,
62 :
63 : /// RSA Probabilistic signature scheme
64 : RSASSA_PSS,
65 : UNKNOWN(u32),
66 : }
67 :
68 : impl From<u32> for KeyType {
69 690 : fn from(value: u32) -> Self {
70 690 : match value {
71 0 : 0x00000000 => KeyType::NONE,
72 690 : 0x00000001 => KeyType::RSA,
73 0 : 0x00000002 => KeyType::ECKEY,
74 0 : 0x00000003 => KeyType::ECKEY_DH,
75 0 : 0x00000004 => KeyType::ECDSA,
76 0 : 0x00000005 => KeyType::RSA_ALT,
77 0 : 0x00000006 => KeyType::RSASSA_PSS,
78 0 : _ => KeyType::UNKNOWN(value),
79 : }
80 690 : }
81 : }
82 :
83 : impl X509<'_> {
84 : /// X.509 version. (1=v1, 2=v2, 3=v3)
85 690 : pub fn version(&self) -> u32 {
86 690 : self.ptr.version()
87 690 : }
88 :
89 : /// Unique id for certificate issued by a specific CA.
90 560 : pub fn serial_number(&self) -> Vec<u8> {
91 560 : Vec::from(self.ptr.serial_number().as_slice())
92 560 : }
93 :
94 : /// Signature algorithm (OID)
95 690 : pub fn signature_algorithm(&self) -> String {
96 690 : self.ptr.signature_algorithm().to_string()
97 690 : }
98 :
99 : /// Start time of certificate validity
100 690 : pub fn valid_from(&self) -> Vec<u64> {
101 690 : Vec::from(self.ptr.valid_from().as_slice())
102 690 : }
103 :
104 : /// End time of certificate validity
105 690 : pub fn valid_to(&self) -> Vec<u64> {
106 690 : Vec::from(self.ptr.valid_to().as_slice())
107 690 : }
108 :
109 : /// Issuer information
110 690 : pub fn issuer(&self) -> String {
111 690 : self.ptr.issuer().to_string()
112 690 : }
113 :
114 : /// Subject information
115 690 : pub fn subject(&self) -> String {
116 690 : self.ptr.subject().to_string()
117 690 : }
118 :
119 : /// The raw x509 bytes (DER encoded)
120 560 : pub fn raw(&self) -> Vec<u8> {
121 560 : Vec::from(self.ptr.raw().as_slice())
122 560 : }
123 :
124 : /// Return the underlying public-key scheme
125 690 : pub fn key_type(&self) -> KeyType {
126 690 : KeyType::from(self.ptr.key_type())
127 690 : }
128 690 : pub fn is_ca(&self) -> bool {
129 690 : self.ptr.is_ca()
130 690 : }
131 :
132 : /// The signature of the certificate
133 560 : pub fn signature(&self) -> Vec<u8> {
134 560 : Vec::from(self.ptr.signature().as_slice())
135 560 : }
136 :
137 : /// **If** the underlying public-key scheme is RSA, return the RSA information.
138 560 : pub fn rsa_info(&self) -> Option<RsaInfo> {
139 560 : into_optional(self.ptr.rsa_info())
140 560 : }
141 :
142 : /// Try to decrypt the given signature and check if it matches the given hash according to
143 : /// the hash algorithm provided
144 0 : pub fn check_signature(&self, hash: &[u8], signature: &[u8], digest: Algorithms) -> bool {
145 0 : unsafe {
146 0 : self.ptr.check_signature(
147 0 : hash.as_ptr(),
148 0 : hash.len(),
149 0 : signature.as_ptr(),
150 0 : signature.len(),
151 0 : digest.into(),
152 0 : )
153 0 : }
154 0 : }
155 :
156 : /// Verify that this certificate has been used **to trust** the given certificate
157 0 : pub fn verify(&self, ca: &X509) -> VerificationFlags {
158 0 : VerificationFlags::from(self.ptr.verify(ca.ptr.as_ref().unwrap()))
159 0 : }
160 : }
161 :
162 460 : declare_iterator!(
163 460 : Certificates,
164 460 : X509<'a>,
165 460 : ffi::PE_x509,
166 460 : ffi::PE_Signature,
167 460 : ffi::PE_Signature_it_certificates
168 460 : );
|