| Index: components/crx_file/crx_file.cc
|
| diff --git a/components/crx_file/crx_file.cc b/components/crx_file/crx_file.cc
|
| deleted file mode 100644
|
| index c2b05f8e80b7467737a380f99d686e166a4e1ed0..0000000000000000000000000000000000000000
|
| --- a/components/crx_file/crx_file.cc
|
| +++ /dev/null
|
| @@ -1,220 +0,0 @@
|
| -// Copyright 2014 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "components/crx_file/crx_file.h"
|
| -
|
| -#include "base/base64.h"
|
| -#include "base/files/file_path.h"
|
| -#include "base/files/file_util.h"
|
| -#include "base/files/scoped_file.h"
|
| -#include "base/macros.h"
|
| -#include "base/memory/ptr_util.h"
|
| -#include "base/numerics/safe_math.h"
|
| -#include "base/strings/string_number_conversions.h"
|
| -#include "base/strings/string_util.h"
|
| -#include "components/crx_file/id_util.h"
|
| -#include "crypto/secure_hash.h"
|
| -#include "crypto/sha2.h"
|
| -#include "crypto/signature_verifier.h"
|
| -
|
| -namespace crx_file {
|
| -
|
| -namespace {
|
| -
|
| -// The current version of the crx format.
|
| -static const uint32_t kCurrentVersion = 2;
|
| -
|
| -// The current version of the crx diff format.
|
| -static const uint32_t kCurrentDiffVersion = 0;
|
| -
|
| -// The maximum size the crx parser will tolerate for a public key.
|
| -static const uint32_t kMaxPublicKeySize = 1 << 16;
|
| -
|
| -// The maximum size the crx parser will tolerate for a signature.
|
| -static const uint32_t kMaxSignatureSize = 1 << 16;
|
| -
|
| -// Helper function to read bytes into a buffer while also updating a hash with
|
| -// those bytes. Returns the number of bytes read.
|
| -size_t ReadAndHash(void* ptr,
|
| - size_t size,
|
| - size_t nmemb,
|
| - FILE* stream,
|
| - crypto::SecureHash* hash) {
|
| - size_t item_count = fread(ptr, size, nmemb, stream);
|
| - base::CheckedNumeric<size_t> byte_count(item_count);
|
| - byte_count *= size;
|
| - if (!byte_count.IsValid())
|
| - return 0;
|
| - if (item_count > 0 && hash) {
|
| - hash->Update(ptr, byte_count.ValueOrDie());
|
| - }
|
| - return byte_count.ValueOrDie();
|
| -}
|
| -
|
| -// Helper function to finish computing a hash and return an error if the
|
| -// result of the hash didn't meet an expected base64-encoded value.
|
| -CrxFile::ValidateError FinalizeHash(const std::string& extension_id,
|
| - crypto::SecureHash* hash,
|
| - const std::string& expected_hash) {
|
| - CHECK(hash != nullptr);
|
| - uint8_t output[crypto::kSHA256Length] = {};
|
| - hash->Finish(output, sizeof(output));
|
| - std::string hash_base64 =
|
| - base::ToLowerASCII(base::HexEncode(output, sizeof(output)));
|
| - if (hash_base64 != expected_hash) {
|
| - LOG(ERROR) << "Hash check failed for extension: " << extension_id
|
| - << ", expected " << expected_hash << ", got " << hash_base64;
|
| - return CrxFile::ValidateError::CRX_HASH_VERIFICATION_FAILED;
|
| - } else {
|
| - return CrxFile::ValidateError::NONE;
|
| - }
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -// The magic string embedded in the header.
|
| -const char kCrxFileHeaderMagic[] = "Cr24";
|
| -const char kCrxDiffFileHeaderMagic[] = "CrOD";
|
| -
|
| -std::unique_ptr<CrxFile> CrxFile::Parse(const CrxFile::Header& header,
|
| - CrxFile::Error* error) {
|
| - if (HeaderIsValid(header, error))
|
| - return base::WrapUnique(new CrxFile(header));
|
| - return nullptr;
|
| -}
|
| -
|
| -std::unique_ptr<CrxFile> CrxFile::Create(const uint32_t key_size,
|
| - const uint32_t signature_size,
|
| - CrxFile::Error* error) {
|
| - CrxFile::Header header;
|
| - memcpy(&header.magic, kCrxFileHeaderMagic, kCrxFileHeaderMagicSize);
|
| - header.version = kCurrentVersion;
|
| - header.key_size = key_size;
|
| - header.signature_size = signature_size;
|
| - if (HeaderIsValid(header, error))
|
| - return base::WrapUnique(new CrxFile(header));
|
| - return nullptr;
|
| -}
|
| -
|
| -bool CrxFile::HeaderIsDelta(const CrxFile::Header& header) {
|
| - return !strncmp(kCrxDiffFileHeaderMagic, header.magic, sizeof(header.magic));
|
| -}
|
| -
|
| -// static
|
| -CrxFile::ValidateError CrxFile::ValidateSignature(
|
| - const base::FilePath& crx_path,
|
| - const std::string& expected_hash,
|
| - std::string* public_key,
|
| - std::string* extension_id,
|
| - CrxFile::Header* header_out) {
|
| - base::ScopedFILE file(base::OpenFile(crx_path, "rb"));
|
| - std::unique_ptr<crypto::SecureHash> hash;
|
| - if (!expected_hash.empty())
|
| - hash = crypto::SecureHash::Create(crypto::SecureHash::SHA256);
|
| -
|
| - if (!file.get())
|
| - return ValidateError::CRX_FILE_NOT_READABLE;
|
| -
|
| - CrxFile::Header header;
|
| - size_t len = ReadAndHash(&header, sizeof(header), 1, file.get(), hash.get());
|
| - if (len != sizeof(header))
|
| - return ValidateError::CRX_HEADER_INVALID;
|
| - if (header_out)
|
| - *header_out = header;
|
| -
|
| - CrxFile::Error error;
|
| - std::unique_ptr<CrxFile> crx(CrxFile::Parse(header, &error));
|
| - if (!crx) {
|
| - switch (error) {
|
| - case CrxFile::kWrongMagic:
|
| - return ValidateError::CRX_MAGIC_NUMBER_INVALID;
|
| - case CrxFile::kInvalidVersion:
|
| - return ValidateError::CRX_VERSION_NUMBER_INVALID;
|
| -
|
| - case CrxFile::kInvalidKeyTooLarge:
|
| - case CrxFile::kInvalidSignatureTooLarge:
|
| - return ValidateError::CRX_EXCESSIVELY_LARGE_KEY_OR_SIGNATURE;
|
| -
|
| - case CrxFile::kInvalidKeyTooSmall:
|
| - return ValidateError::CRX_ZERO_KEY_LENGTH;
|
| - case CrxFile::kInvalidSignatureTooSmall:
|
| - return ValidateError::CRX_ZERO_SIGNATURE_LENGTH;
|
| -
|
| - default:
|
| - return ValidateError::CRX_HEADER_INVALID;
|
| - }
|
| - }
|
| -
|
| - std::vector<uint8_t> key(header.key_size);
|
| - len = ReadAndHash(&key.front(), sizeof(uint8_t), header.key_size, file.get(),
|
| - hash.get());
|
| - if (len != header.key_size)
|
| - return ValidateError::CRX_PUBLIC_KEY_INVALID;
|
| -
|
| - std::vector<uint8_t> signature(header.signature_size);
|
| - len = ReadAndHash(&signature.front(), sizeof(uint8_t), header.signature_size,
|
| - file.get(), hash.get());
|
| - if (len < header.signature_size)
|
| - return ValidateError::CRX_SIGNATURE_INVALID;
|
| -
|
| - crypto::SignatureVerifier verifier;
|
| - if (!verifier.VerifyInit(crypto::SignatureVerifier::RSA_PKCS1_SHA1,
|
| - signature.data(), signature.size(), key.data(),
|
| - key.size())) {
|
| - // Signature verification initialization failed. This is most likely
|
| - // caused by a public key in the wrong format (should encode algorithm).
|
| - return ValidateError::CRX_SIGNATURE_VERIFICATION_INITIALIZATION_FAILED;
|
| - }
|
| -
|
| - uint8_t buf[1 << 12] = {};
|
| - while ((len = ReadAndHash(buf, sizeof(buf[0]), arraysize(buf), file.get(),
|
| - hash.get())) > 0)
|
| - verifier.VerifyUpdate(buf, len);
|
| -
|
| - if (!verifier.VerifyFinal())
|
| - return ValidateError::CRX_SIGNATURE_VERIFICATION_FAILED;
|
| -
|
| - std::string public_key_bytes =
|
| - std::string(reinterpret_cast<char*>(&key.front()), key.size());
|
| - if (public_key)
|
| - base::Base64Encode(public_key_bytes, public_key);
|
| -
|
| - std::string id = id_util::GenerateId(public_key_bytes);
|
| - if (extension_id)
|
| - *extension_id = id;
|
| -
|
| - if (!expected_hash.empty())
|
| - return FinalizeHash(id, hash.get(), expected_hash);
|
| -
|
| - return ValidateError::NONE;
|
| -}
|
| -
|
| -CrxFile::CrxFile(const Header& header) : header_(header) {}
|
| -
|
| -bool CrxFile::HeaderIsValid(const CrxFile::Header& header,
|
| - CrxFile::Error* error) {
|
| - bool valid = false;
|
| - bool diffCrx = false;
|
| - if (!strncmp(kCrxDiffFileHeaderMagic, header.magic, sizeof(header.magic)))
|
| - diffCrx = true;
|
| - if (strncmp(kCrxFileHeaderMagic, header.magic, sizeof(header.magic)) &&
|
| - !diffCrx)
|
| - *error = kWrongMagic;
|
| - else if (header.version != kCurrentVersion
|
| - && !(diffCrx && header.version == kCurrentDiffVersion))
|
| - *error = kInvalidVersion;
|
| - else if (header.key_size > kMaxPublicKeySize)
|
| - *error = kInvalidKeyTooLarge;
|
| - else if (header.key_size == 0)
|
| - *error = kInvalidKeyTooSmall;
|
| - else if (header.signature_size > kMaxSignatureSize)
|
| - *error = kInvalidSignatureTooLarge;
|
| - else if (header.signature_size == 0)
|
| - *error = kInvalidSignatureTooSmall;
|
| - else
|
| - valid = true;
|
| - return valid;
|
| -}
|
| -
|
| -} // namespace crx_file
|
|
|