// Copyright 2023 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CHROME_UPDATER_CERTIFICATE_TAG_INTERNAL_H_ #define CHROME_UPDATER_CERTIFICATE_TAG_INTERNAL_H_ #include <cstdint> #include <cstring> #include <functional> #include <memory> #include <optional> #include <string> #include <utility> #include <vector> #include "base/containers/span.h" #include "base/gtest_prod_util.h" #include "base/memory/raw_span.h" #include "third_party/boringssl/src/include/openssl/bytestring.h" #include "third_party/boringssl/src/include/openssl/crypto.h" namespace updater::tagging::internal { // PEBinary represents a Windows PE binary and provides functions to extract and // set data outside of the signed area (called a "tag"). This allows a binary to // contain arbitrary data without invalidating any Authenticode signature. class PEBinary : public BinaryInterface { … }; #pragma pack(push) #pragma pack(1) // SectorFormat represents parameters of an MSI file sector. struct SectorFormat { … }; // MSIDirEntry represents a parsed MSI directory entry for a stream. struct MSIDirEntry { … }; // MSIHeader represents a parsed MSI header. struct MSIHeader { … }; struct SignedDataDir { … }; #pragma pack(pop) // MSIBinary represents a Windows MSI binary and provides functions to extract // and set a "tag" outside of the signed area. This allows the MSI to contain // arbitrary data without invalidating any Authenticode signature. class MSIBinary : public BinaryInterface { … }; // CBS is a structure from BoringSSL used for parsing binary and ASN.1-based // formats. This implementation detail is not exposed in the interface of this // code so these utility functions convert to/from base::span. CBS CBSFromSpan(base::span<const uint8_t> span); base::span<const uint8_t> SpanFromCBS(const CBS* cbs); // kTagOID contains the DER-serialised form of the extension OID that we stuff // the tag into: 1.3.6.1.4.1.11129.2.1.9999. inline constexpr uint8_t kTagOID[] = …; // Certificate constants. See // http://msdn.microsoft.com/en-us/library/ms920091.aspx. // // Despite MSDN claiming that 0x100 is the only, current revision - in // practice it's 0x200. inline constexpr uint16_t kAttributeCertificateRevision = …; inline constexpr uint16_t kAttributeCertificateTypePKCS7SignedData = …; // AddName appends an X.500 Name structure to |cbb| containing a single // commonName with the given value. bool AddName(CBB* cbb, const char* common_name); // CopyASN1 copies a single ASN.1 element from |in| to |out|. bool CopyASN1(CBB* out, CBS* in); struct ParseResult { … }; // Parses the `signed_data` PKCS7 object to find the final certificate in the // list and see whether it has an extension with `kTagOID`, and if so, returns a // `base::span` of the tag within this `signed_data`. `success` is set to `true` // if there were no parse errors, even if a tag could not be found. ParseResult ParseTagImpl(base::span<const uint8_t> signed_data); // Returns an updated version of the ContentInfo signedData PKCS7 object with // the given `tag` added, or `nullopt` on error. If the input `signed_data` // already contains a tag, then it will be replaced with `tag`. std::optional<std::vector<uint8_t>> SetTagImpl( base::span<const uint8_t> signed_data, base::span<const uint8_t> tag); // Compound file binary format constants. inline constexpr int kNumHeaderContentBytes = …; inline constexpr int kNumHeaderTotalBytes = …; inline constexpr int kNumDifatHeaderEntries = …; inline constexpr int kNumDirEntryBytes = …; inline constexpr int kMiniStreamSectorSize = …; inline constexpr int kMiniStreamCutoffSize = …; // An unallocated sector (used in the fat or difat). inline constexpr uint32_t kFatFreeSector = …; // End of a linked chain (in the fat); or end of difat sector chain. inline constexpr uint32_t kFatEndOfChain = …; // Used in the fat table to indicate a fat sector entry. inline constexpr uint32_t kFatFatSector = …; // Used in the fat table to indicate a difat sector entry. inline constexpr uint32_t kFatDifSector = …; // Reserved value. inline constexpr uint32_t kFatReserved = …; inline constexpr uint8_t kMsiHeaderSignature[] = …; inline constexpr uint8_t kMsiHeaderClsid[16] = …; // UTF-16 for "\05DigitalSignature". inline constexpr uint8_t kSignatureName[] = …; std::optional<SectorFormat> NewSectorFormat(uint16_t sector_shift); // Returns whether the index corresponds to the last entry in a sector. // // The last entry in each difat sector is a pointer to the next difat sector, or // is an end-of-chain marker. // This does not apply to the last entry stored in the MSI header. bool IsLastInSector(const SectorFormat& format, int index); } // namespace updater::tagging::internal #endif // CHROME_UPDATER_CERTIFICATE_TAG_INTERNAL_H_