uthenticode  2.0.1-cad1bfc
uthenticode.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <openssl/asn1.h>
4 #include <openssl/asn1t.h>
5 #include <openssl/crypto.h>
6 #include <openssl/x509.h>
7 #include <pe-parse/parse.h>
8 
9 #include <cstdint>
10 #include <exception>
11 #include <memory>
12 #include <optional>
13 #include <vector>
14 
20 namespace uthenticode {
21 
25 namespace impl {
26 typedef struct {
27  ASN1_OBJECT *type;
28  ASN1_TYPE *value;
30 
31 typedef struct {
32  X509_ALGOR *digestAlgorithm;
33  ASN1_OCTET_STRING *digest;
35 
36 typedef struct {
40 
41 /* Custom ASN.1 insanity is quarantined to the impl namespace.
42  */
44 DECLARE_ASN1_FUNCTIONS(Authenticode_DigestInfo)
45 DECLARE_ASN1_FUNCTIONS(Authenticode_SpcIndirectDataContent)
46 
47 /* OpenSSL defines OPENSSL_free as a macro, which we can't use with decltype.
48  * So we wrap it here for use with unique_ptr.
49  */
50 void OpenSSL_free(void *ptr);
51 
52 /* Since OpenSSL 3.0.0 SK_X509_free is defined as a macro, which we can't use with decltype.
53  * So we wrap it here for use with unique_ptr.
54  */
55 void SK_X509_free(stack_st_X509 *ptr);
56 
57 /* Convenient self-releasing aliases for libcrypto and custom ASN.1 types.
58  */
59 using BIO_ptr = std::unique_ptr<BIO, decltype(&BIO_free)>;
60 using ASN1_OBJECT_ptr = std::unique_ptr<ASN1_OBJECT, decltype(&ASN1_OBJECT_free)>;
61 using ASN1_TYPE_ptr = std::unique_ptr<ASN1_TYPE, decltype(&ASN1_TYPE_free)>;
62 using OpenSSL_ptr = std::unique_ptr<char, decltype(&OpenSSL_free)>;
63 using BN_ptr = std::unique_ptr<BIGNUM, decltype(&BN_free)>;
64 using STACK_OF_X509_ptr = std::unique_ptr<STACK_OF(X509), decltype(&SK_X509_free)>;
65 
66 using SectionList = std::vector<const peparse::bounded_buffer *>;
67 
68 constexpr auto SPC_INDIRECT_DATA_OID = "1.3.6.1.4.1.311.2.1.4";
69 constexpr auto SPC_NESTED_SIGNATURE_OID = "1.3.6.1.4.1.311.2.4.1";
70 } // namespace impl
71 
80 enum class certificate_revision : std::uint16_t {
81  CERT_REVISION_1_0 = 0x0100,
82  CERT_REVISION_2_0 = 0x0200,
83 };
84 
91 enum class certificate_type : std::uint16_t {
92  CERT_TYPE_X509 = 0x0001,
94  CERT_TYPE_RESERVED_1 = 0x0003,
95  CERT_TYPE_PKCS1_SIGN = 0x0009,
96 };
97 
101 enum class checksum_kind : std::uint8_t {
102  UNKNOWN,
103  MD5,
104  SHA1,
105  SHA256,
106 };
107 
108 std::ostream &operator<<(std::ostream &os, checksum_kind kind);
109 
114 using Checksum = std::tuple<checksum_kind, std::string>;
115 
119 struct FormatError : public std::runtime_error {
120  public:
121  FormatError(const char *msg) : std::runtime_error(msg) {
122  }
123 };
124 
131 class Certificate {
132  public:
133  friend class SignedData;
134 
138  const std::string &get_subject() const {
139  return subject_;
140  }
141 
145  const std::string &get_issuer() const {
146  return issuer_;
147  }
148 
152  const std::string &get_serial_number() const {
153  return serial_number_;
154  }
155 
156  /* TODO: Maybe add data_ and get_data(), with data_ populated from i2d_X509.
157  */
158 
159  private:
160  Certificate(X509 *cert);
161  std::string subject_;
162  std::string issuer_;
163  std::string serial_number_;
164 };
165 
169 class SignedData {
170  public:
176  SignedData(std::vector<std::uint8_t> cert_buf);
177  SignedData(SignedData &&s) noexcept;
178  SignedData(const SignedData &) = delete;
179  ~SignedData();
180 
186  bool verify_signature() const;
187 
193  Checksum get_checksum() const;
194 
200  std::vector<Certificate> get_signers() const;
201 
207  std::vector<Certificate> get_certificates() const;
208 
213  std::optional<SignedData> get_nested_signed_data() const;
214 
215  private:
216  impl::Authenticode_SpcIndirectDataContent *get_indirect_data() const;
217 
218  std::vector<std::uint8_t> cert_buf_;
219  PKCS7 *p7_{nullptr};
220  impl::Authenticode_SpcIndirectDataContent *indirect_data_{nullptr};
221 };
222 
231 class WinCert {
232  public:
233  WinCert(certificate_revision revision, certificate_type type, std::vector<std::uint8_t> cert_buf)
234  : revision_(revision), type_(type), cert_buf_(cert_buf) {
235  }
236 
240  std::size_t get_length() const {
241  return cert_buf_.size();
242  }
243 
248  return revision_;
249  }
250 
255  return type_;
256  }
257 
262  std::optional<SignedData> as_signed_data() const;
263 
264  private:
265  certificate_revision revision_;
266  certificate_type type_;
267  std::vector<std::uint8_t> cert_buf_;
268 };
269 
276 std::vector<WinCert> read_certs(peparse::parsed_pe *pe);
277 
284 std::vector<Checksum> get_checksums(peparse::parsed_pe *pe);
285 
296 std::optional<std::string> calculate_checksum(peparse::parsed_pe *pe, checksum_kind kind);
297 
310 bool verify(peparse::parsed_pe *pe);
311 
312 } // namespace uthenticode
Definition: uthenticode.h:131
const std::string & get_serial_number() const
Definition: uthenticode.h:152
const std::string & get_issuer() const
Definition: uthenticode.h:145
const std::string & get_subject() const
Definition: uthenticode.h:138
Definition: uthenticode.h:169
SignedData(const SignedData &)=delete
Definition: uthenticode.h:231
certificate_revision get_revision() const
Definition: uthenticode.h:247
std::size_t get_length() const
Definition: uthenticode.h:240
WinCert(certificate_revision revision, certificate_type type, std::vector< std::uint8_t > cert_buf)
Definition: uthenticode.h:233
certificate_type get_type() const
Definition: uthenticode.h:254
std::unique_ptr< ASN1_TYPE, decltype(&ASN1_TYPE_free)> ASN1_TYPE_ptr
Definition: uthenticode.h:61
std::unique_ptr< char, decltype(&OpenSSL_free)> OpenSSL_ptr
Definition: uthenticode.h:62
void SK_X509_free(stack_st_X509 *ptr)
void OpenSSL_free(void *ptr)
std::unique_ptr< ASN1_OBJECT, decltype(&ASN1_OBJECT_free)> ASN1_OBJECT_ptr
Definition: uthenticode.h:60
std::vector< const peparse::bounded_buffer * > SectionList
Definition: uthenticode.h:66
std::unique_ptr< BIGNUM, decltype(&BN_free)> BN_ptr
Definition: uthenticode.h:63
std::unique_ptr< BIO, decltype(&BIO_free)> BIO_ptr
Definition: uthenticode.h:59
constexpr auto SPC_NESTED_SIGNATURE_OID
Definition: uthenticode.h:69
std::unique_ptr< STACK_OF(X509), decltype(&SK_X509_free)> STACK_OF_X509_ptr
Definition: uthenticode.h:64
constexpr auto SPC_INDIRECT_DATA_OID
Definition: uthenticode.h:68
Definition: uthenticode.h:20
certificate_revision
Definition: uthenticode.h:80
std::optional< std::string > calculate_checksum(peparse::parsed_pe *pe, checksum_kind kind)
Definition: uthenticode.cpp:484
certificate_type
Definition: uthenticode.h:91
std::ostream & operator<<(std::ostream &os, checksum_kind kind)
Definition: uthenticode.cpp:130
bool verify(peparse::parsed_pe *pe)
Definition: uthenticode.cpp:633
checksum_kind
Definition: uthenticode.h:101
std::tuple< checksum_kind, std::string > Checksum
Definition: uthenticode.h:114
std::vector< WinCert > read_certs(peparse::parsed_pe *pe)
Definition: uthenticode.cpp:418
std::vector< Checksum > get_checksums(peparse::parsed_pe *pe)
Definition: uthenticode.cpp:465
Definition: uthenticode.h:119
FormatError(const char *msg)
Definition: uthenticode.h:121
Definition: uthenticode.h:31
X509_ALGOR * digestAlgorithm
Definition: uthenticode.h:32
ASN1_OCTET_STRING * digest
Definition: uthenticode.h:33
Authenticode_DigestInfo * messageDigest
Definition: uthenticode.h:38
Authenticode_SpcAttributeTypeAndOptionalValue * data
Definition: uthenticode.h:37