Index: third_party/omaha/src/base/extractor.cc |
diff --git a/third_party/omaha/src/base/extractor.cc b/third_party/omaha/src/base/extractor.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..4fca55d00ed7979004bdf1c3fc201e427e3909a1 |
--- /dev/null |
+++ b/third_party/omaha/src/base/extractor.cc |
@@ -0,0 +1,257 @@ |
+// Copyright 2005-2009 Google Inc. |
+// |
+// Licensed under the Apache License, Version 2.0 (the "License"); |
+// you may not use this file except in compliance with the License. |
+// You may obtain a copy of the License at |
+// |
+// http://www.apache.org/licenses/LICENSE-2.0 |
+// |
+// Unless required by applicable law or agreed to in writing, software |
+// distributed under the License is distributed on an "AS IS" BASIS, |
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
+// See the License for the specific language governing permissions and |
+// limitations under the License. |
+// ======================================================================== |
+ |
+#include "extractor.h" |
+ |
+#include <windows.h> |
+#include <wintrust.h> |
+#include <crtdbg.h> |
+#pragma warning(push) |
+// C4100: unreferenced formal parameter |
+// C4310: cast truncates constant value |
+// C4548: expression before comma has no effect |
+#pragma warning(disable : 4100 4310 4548) |
+#include "base/basictypes.h" |
+#pragma warning(pop) |
+ |
+namespace omaha { |
+ |
+#define AFFILIATE_ID_MAGIC "Gact" |
+ |
+TagExtractor::TagExtractor() |
+ : file_handle_(INVALID_HANDLE_VALUE), |
+ file_mapping_(NULL), |
+ file_base_(NULL), |
+ file_length_(0), |
+ cert_length_(0), |
+ cert_dir_base_(NULL) { |
+} |
+ |
+TagExtractor::~TagExtractor() { |
+ CloseFile(); |
+} |
+ |
+bool TagExtractor::OpenFile(const TCHAR* filename) { |
+ CloseFile(); |
+ file_handle_ = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, |
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); |
+ if (IsFileOpen()) { |
+ file_mapping_ = CreateFileMapping(file_handle_, NULL, PAGE_READONLY, |
+ 0, 0, NULL); |
+ if (file_mapping_ != NULL) { |
+ file_base_ = MapViewOfFile(file_mapping_, FILE_MAP_READ, 0, 0, 0); |
+ if (file_base_ != NULL) { |
+ MEMORY_BASIC_INFORMATION info = {0}; |
+ if (::VirtualQuery(file_base_, &info, sizeof(info))) { |
+ file_length_ = info.RegionSize; |
+ return true; |
+ } |
+ } |
+ CloseHandle(file_mapping_); |
+ } |
+ CloseFile(); |
+ } |
+ return false; |
+} |
+ |
+bool TagExtractor::IsFileOpen() const { |
+ return file_handle_ != INVALID_HANDLE_VALUE; |
+} |
+ |
+void TagExtractor::CloseFile() { |
+ if (file_base_ != NULL) { |
+ UnmapViewOfFile(file_base_); |
+ file_base_ = NULL; |
+ } |
+ if (file_mapping_ != NULL) { |
+ CloseHandle(file_mapping_); |
+ file_mapping_ = NULL; |
+ } |
+ if (IsFileOpen()) { |
+ CloseHandle(file_handle_); |
+ file_handle_ = INVALID_HANDLE_VALUE; |
+ } |
+} |
+ |
+bool TagExtractor::ExtractTag(const char* binary_file, |
+ size_t binary_file_length, |
+ char* tag_buffer, |
+ int* tag_buffer_len) { |
+ file_length_ = binary_file_length; |
+ return InternalExtractTag(binary_file, tag_buffer, tag_buffer_len); |
+} |
+ |
+bool TagExtractor::ExtractTag(char* tag_buffer, int* tag_buffer_len) { |
+ if (tag_buffer_len == NULL) { |
+ return false; |
+ } |
+ if (!IsFileOpen()) { |
+ return false; |
+ } |
+ |
+ return InternalExtractTag(static_cast<char*>(file_base_), |
+ tag_buffer, |
+ tag_buffer_len); |
+} |
+ |
+bool TagExtractor::InternalReadCertificate(const char* file_buffer) { |
+ if (!file_buffer) { |
+ return false; |
+ } |
+ |
+ const void* certificate_directory_pointer = |
+ GetCertificateDirectoryPointer(file_buffer); |
+ if (NULL == certificate_directory_pointer) { |
+ return false; |
+ } |
+ const void* asn1_signature_pointer = |
+ GetASN1SignaturePointer(certificate_directory_pointer); |
+ if (NULL == asn1_signature_pointer) { |
+ return false; |
+ } |
+ DWORD asn1_signature_length = |
+ GetASN1SignatureLength(asn1_signature_pointer); |
+ if (0 == asn1_signature_length) { |
+ return false; |
+ } |
+ |
+ cert_length_ = asn1_signature_length; |
+ cert_dir_base_ = certificate_directory_pointer; |
+ |
+ return true; |
+} |
+ |
+bool TagExtractor::InternalExtractTag(const char* file_buffer, |
+ char* tag_buffer, |
+ int* tag_buffer_len) { |
+ if (!file_buffer) { |
+ return false; |
+ } |
+ |
+ if (!InternalReadCertificate(file_buffer)) { |
+ return false; |
+ } |
+ |
+ const char* read_base = static_cast<const char*>(cert_dir_base_) + |
+ cert_length_; |
+ if (read_base >= file_buffer + file_length_) { |
+ // The file is not tagged. |
+ return false; |
+ } |
+ |
+ return ReadTag(read_base, tag_buffer, tag_buffer_len); |
+} |
+ |
+bool TagExtractor::ReadTag(const char* tag_pointer, |
+ char* tag_buffer, |
+ int* tag_buffer_len) const { |
+ int mc = memcmp(tag_pointer, |
+ AFFILIATE_ID_MAGIC, |
+ arraysize(AFFILIATE_ID_MAGIC) - 1); |
+ if (0 != mc) { |
+ return false; |
+ } |
+ tag_pointer += arraysize(AFFILIATE_ID_MAGIC) - 1; |
+ |
+ uint16 id_len = 0; |
+ const unsigned char* id_len_serialized = |
+ reinterpret_cast<const unsigned char*>(tag_pointer); |
+ id_len = id_len_serialized[0] << 8; |
+ // unsigned char and uint16 get promoted to int. |
+ id_len = static_cast<uint16>(id_len + id_len_serialized[1]); |
+ |
+ int buffer_size_required = id_len + 1; |
+ if (tag_buffer == NULL) { |
+ *tag_buffer_len = buffer_size_required; |
+ return true; |
+ } |
+ if (*tag_buffer_len < buffer_size_required) { |
+ return false; |
+ } |
+ tag_pointer += sizeof(id_len); |
+ memcpy(tag_buffer, tag_pointer, id_len); |
+ tag_buffer[id_len] = '\0'; |
+ return true; |
+} |
+ |
+const void* TagExtractor::GetCertificateDirectoryPointer( |
+ const void* base) const { |
+ const char* image_base = reinterpret_cast<const char*>(base); |
+ |
+ // Is this a PEF? |
+ const IMAGE_DOS_HEADER* dos_header = |
+ reinterpret_cast<const IMAGE_DOS_HEADER *>(image_base); |
+ if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) { |
+ return NULL; |
+ } |
+ |
+ // Get PE header. |
+ const IMAGE_NT_HEADERS* nt_headers = reinterpret_cast<const IMAGE_NT_HEADERS*> |
+ (image_base + dos_header->e_lfanew); |
+ |
+ // Again, is this a PEF? This code should get an F for not being endian- |
+ // safe, but it gets an A for working in the real world. |
+ if (nt_headers->Signature != IMAGE_NT_SIGNATURE) { |
+ return NULL; |
+ } |
+ |
+ const IMAGE_DATA_DIRECTORY* idd = |
+ reinterpret_cast<const IMAGE_DATA_DIRECTORY *> |
+ (&nt_headers-> |
+ OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]); |
+ if (idd->VirtualAddress != NULL) { |
+ return image_base + idd->VirtualAddress; |
+ } |
+ return NULL; |
+} |
+ |
+const void* TagExtractor::GetASN1SignaturePointer(const void* base) const { |
+ const WIN_CERTIFICATE* cert = |
+ reinterpret_cast<const WIN_CERTIFICATE *>(base); |
+ return cert->bCertificate; |
+} |
+ |
+int TagExtractor::GetASN1SignatureLength(const void* base) const { |
+ const unsigned char* sig_base = |
+ reinterpret_cast<const unsigned char*>(base); |
+ |
+ // No, this isn't a full ASN.1 parser. We're just doing the very bare |
+ // minimum to extract a length. |
+ if (*sig_base++ == 0x30 && *sig_base++ == 0x82) { |
+ int len = (*sig_base++ << 8); |
+ len += *sig_base++; |
+ // Windows pads the certificate directory to align at a 8-byte boundary. |
+ // This piece of code it trying to replicate the logic that is used to |
+ // calculate the padding to be added to the certificate. It returns |
+ // the entire length of the certificate directory from the windows |
+ // certificate directory start to the end of padding. |
+ // The windows certificate directory has the following structure |
+ // <WIN_CERTIFICATE><Certificate><Padding>. |
+ // WIN_CERTIFICATE is the windows certificate directory structure. |
+ // <Certificate> has the following format: |
+ // <Magic(2 bytes)><Cert length(2 bytes)><Certificate Data> |
+ // Note that the "Cert length" does not include the magic bytes or |
+ // the length. |
+ // |
+ // Hence the total length of the certificate is: |
+ // cert_length + "WIN_CERTIFICATE header size" + magic + length |
+ // + padding = (cert length + 8 + 2 + 2 + 7) & (0-8) |
+ return (len + 8 + 2 + 2 + 7) & 0xffffff8; |
+ } |
+ return 0; |
+} |
+ |
+} // namespace omaha |
+ |