uthenticode  2.0.1-19005f0
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 #ifndef UTHENTICODE_DEFAULT_XN_FLAGS
160  static constexpr unsigned long const default_xn_flags =
161  XN_FLAG_RFC2253 | ASN1_STRFLGS_UTF8_CONVERT;
162 #else
163  static constexpr unsigned long const default_xn_flags = (UTHENTICODE_DEFAULT_XN_FLAGS);
164 #endif
165  static_assert((default_xn_flags & XN_FLAG_COMPAT) == 0,
166  "Logic is incompatible with XN_FLAG_COMPAT");
167 
168  private:
169  explicit Certificate(X509 *cert);
170  std::string subject_;
171  std::string issuer_;
172  std::string serial_number_;
173 };
174 
178 class SignedData {
179  public:
185  SignedData(std::vector<std::uint8_t> cert_buf);
186  SignedData(SignedData &&s) noexcept;
187  SignedData(const SignedData &) = delete;
188  ~SignedData();
189 
195  bool verify_signature() const;
196 
202  Checksum get_checksum() const;
203 
209  std::vector<Certificate> get_signers() const;
210 
216  std::vector<Certificate> get_certificates() const;
217 
222  std::optional<SignedData> get_nested_signed_data() const;
223 
227  std::vector<std::uint8_t> const &get_raw_data() const;
228 
229  private:
230  impl::Authenticode_SpcIndirectDataContent *get_indirect_data() const;
231 
232  std::vector<std::uint8_t> cert_buf_;
233  PKCS7 *p7_{nullptr};
234  impl::Authenticode_SpcIndirectDataContent *indirect_data_{nullptr};
235 };
236 
245 class WinCert {
246  public:
247  WinCert(certificate_revision revision, certificate_type type, std::vector<std::uint8_t> cert_buf)
248  : revision_(revision), type_(type), cert_buf_(cert_buf) {
249  }
250 
254  std::size_t get_length() const {
255  return cert_buf_.size();
256  }
257 
262  return revision_;
263  }
264 
269  return type_;
270  }
271 
276  std::optional<SignedData> as_signed_data() const;
277 
278  private:
279  certificate_revision revision_;
280  certificate_type type_;
281  std::vector<std::uint8_t> cert_buf_;
282 };
283 
290 std::vector<WinCert> read_certs(peparse::parsed_pe *pe);
291 
298 std::vector<Checksum> get_checksums(peparse::parsed_pe *pe);
299 
310 std::optional<std::string> calculate_checksum(peparse::parsed_pe *pe, checksum_kind kind);
311 
324 bool verify(peparse::parsed_pe *pe);
325 
326 } // 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:178
SignedData(const SignedData &)=delete
Definition: uthenticode.h:245
certificate_revision get_revision() const
Definition: uthenticode.h:261
std::size_t get_length() const
Definition: uthenticode.h:254
WinCert(certificate_revision revision, certificate_type type, std::vector< std::uint8_t > cert_buf)
Definition: uthenticode.h:247
certificate_type get_type() const
Definition: uthenticode.h:268
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:498
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:647
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:432
std::vector< Checksum > get_checksums(peparse::parsed_pe *pe)
Definition: uthenticode.cpp:479
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