Home | History | Annotate | Download | only in payload_consumer
      1 //
      2 // Copyright (C) 2014 The Android Open Source Project
      3 //
      4 // Licensed under the Apache License, Version 2.0 (the "License");
      5 // you may not use this file except in compliance with the License.
      6 // You may obtain a copy of the License at
      7 //
      8 //      http://www.apache.org/licenses/LICENSE-2.0
      9 //
     10 // Unless required by applicable law or agreed to in writing, software
     11 // distributed under the License is distributed on an "AS IS" BASIS,
     12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 // See the License for the specific language governing permissions and
     14 // limitations under the License.
     15 //
     16 
     17 #include "update_engine/payload_consumer/payload_verifier.h"
     18 
     19 #include <base/logging.h>
     20 #include <openssl/pem.h>
     21 
     22 #include "update_engine/common/hash_calculator.h"
     23 #include "update_engine/common/utils.h"
     24 #include "update_engine/update_metadata.pb.h"
     25 
     26 using std::string;
     27 
     28 namespace chromeos_update_engine {
     29 
     30 namespace {
     31 
     32 // The following is a standard PKCS1-v1_5 padding for SHA256 signatures, as
     33 // defined in RFC3447. It is prepended to the actual signature (32 bytes) to
     34 // form a sequence of 256 bytes (2048 bits) that is amenable to RSA signing. The
     35 // padded hash will look as follows:
     36 //
     37 //    0x00 0x01 0xff ... 0xff 0x00  ASN1HEADER  SHA256HASH
     38 //   |--------------205-----------||----19----||----32----|
     39 //
     40 // where ASN1HEADER is the ASN.1 description of the signed data. The complete 51
     41 // bytes of actual data (i.e. the ASN.1 header complete with the hash) are
     42 // packed as follows:
     43 //
     44 //  SEQUENCE(2+49) {
     45 //   SEQUENCE(2+13) {
     46 //    OBJECT(2+9) id-sha256
     47 //    NULL(2+0)
     48 //   }
     49 //   OCTET STRING(2+32) <actual signature bytes...>
     50 //  }
     51 const uint8_t kRSA2048SHA256Padding[] = {
     52   // PKCS1-v1_5 padding
     53   0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     54   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     55   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     56   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     57   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     58   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     59   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     60   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     61   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     62   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     63   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     64   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     65   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     66   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     67   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     68   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     69   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     70   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     71   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     72   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     73   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     74   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     75   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     76   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     77   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     78   0xff, 0xff, 0xff, 0xff, 0x00,
     79   // ASN.1 header
     80   0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
     81   0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
     82   0x00, 0x04, 0x20,
     83 };
     84 
     85 }  // namespace
     86 
     87 bool PayloadVerifier::VerifySignature(const brillo::Blob& signature_blob,
     88                                       const string& public_key_path,
     89                                       const brillo::Blob& hash_data) {
     90   TEST_AND_RETURN_FALSE(!public_key_path.empty());
     91 
     92   Signatures signatures;
     93   LOG(INFO) << "signature blob size = " <<  signature_blob.size();
     94   TEST_AND_RETURN_FALSE(signatures.ParseFromArray(signature_blob.data(),
     95                                                   signature_blob.size()));
     96 
     97   if (!signatures.signatures_size()) {
     98     LOG(ERROR) << "No signatures stored in the blob.";
     99     return false;
    100   }
    101 
    102   std::vector<brillo::Blob> tested_hashes;
    103   // Tries every signature in the signature blob.
    104   for (int i = 0; i < signatures.signatures_size(); i++) {
    105     const Signatures_Signature& signature = signatures.signatures(i);
    106     brillo::Blob sig_data(signature.data().begin(), signature.data().end());
    107     brillo::Blob sig_hash_data;
    108     if (!GetRawHashFromSignature(sig_data, public_key_path, &sig_hash_data))
    109       continue;
    110 
    111     if (hash_data == sig_hash_data) {
    112       LOG(INFO) << "Verified correct signature " << i + 1 << " out of "
    113                 << signatures.signatures_size() << " signatures.";
    114       return true;
    115     }
    116     tested_hashes.push_back(sig_hash_data);
    117   }
    118   LOG(ERROR) << "None of the " << signatures.signatures_size()
    119              << " signatures is correct. Expected:";
    120   utils::HexDumpVector(hash_data);
    121   LOG(ERROR) << "But found decrypted hashes:";
    122   for (const auto& sig_hash_data : tested_hashes) {
    123     utils::HexDumpVector(sig_hash_data);
    124   }
    125   return false;
    126 }
    127 
    128 
    129 bool PayloadVerifier::GetRawHashFromSignature(
    130     const brillo::Blob& sig_data,
    131     const string& public_key_path,
    132     brillo::Blob* out_hash_data) {
    133   TEST_AND_RETURN_FALSE(!public_key_path.empty());
    134 
    135   // The code below executes the equivalent of:
    136   //
    137   // openssl rsautl -verify -pubin -inkey |public_key_path|
    138   //   -in |sig_data| -out |out_hash_data|
    139 
    140   // Loads the public key.
    141   FILE* fpubkey = fopen(public_key_path.c_str(), "rb");
    142   if (!fpubkey) {
    143     LOG(ERROR) << "Unable to open public key file: " << public_key_path;
    144     return false;
    145   }
    146 
    147   char dummy_password[] = { ' ', 0 };  // Ensure no password is read from stdin.
    148   RSA* rsa = PEM_read_RSA_PUBKEY(fpubkey, nullptr, nullptr, dummy_password);
    149   fclose(fpubkey);
    150   TEST_AND_RETURN_FALSE(rsa != nullptr);
    151   unsigned int keysize = RSA_size(rsa);
    152   if (sig_data.size() > 2 * keysize) {
    153     LOG(ERROR) << "Signature size is too big for public key size.";
    154     RSA_free(rsa);
    155     return false;
    156   }
    157 
    158   // Decrypts the signature.
    159   brillo::Blob hash_data(keysize);
    160   int decrypt_size = RSA_public_decrypt(sig_data.size(),
    161                                         sig_data.data(),
    162                                         hash_data.data(),
    163                                         rsa,
    164                                         RSA_NO_PADDING);
    165   RSA_free(rsa);
    166   TEST_AND_RETURN_FALSE(decrypt_size > 0 &&
    167                         decrypt_size <= static_cast<int>(hash_data.size()));
    168   hash_data.resize(decrypt_size);
    169   out_hash_data->swap(hash_data);
    170   return true;
    171 }
    172 
    173 bool PayloadVerifier::PadRSA2048SHA256Hash(brillo::Blob* hash) {
    174   TEST_AND_RETURN_FALSE(hash->size() == 32);
    175   hash->insert(hash->begin(),
    176                reinterpret_cast<const char*>(kRSA2048SHA256Padding),
    177                reinterpret_cast<const char*>(kRSA2048SHA256Padding +
    178                                              sizeof(kRSA2048SHA256Padding)));
    179   TEST_AND_RETURN_FALSE(hash->size() == 256);
    180   return true;
    181 }
    182 
    183 }  // namespace chromeos_update_engine
    184