blob: 2f7c133ad12672f56c8b4949d00c6a67b66ccc77 [file] [log] [blame]
Alex Deymoaea4c1c2015-08-19 20:24:43 -07001//
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//
Alex Deymo923d8fa2014-07-15 17:58:51 -070016
Alex Deymo39910dc2015-11-09 17:04:30 -080017#include "update_engine/payload_consumer/payload_verifier.h"
Alex Deymo923d8fa2014-07-15 17:58:51 -070018
Sen Jiang08c6da12019-01-07 18:28:56 -080019#include <vector>
20
Alex Deymo923d8fa2014-07-15 17:58:51 -070021#include <base/logging.h>
22#include <openssl/pem.h>
23
Alex Deymo39910dc2015-11-09 17:04:30 -080024#include "update_engine/common/hash_calculator.h"
25#include "update_engine/common/utils.h"
Alex Deymo923d8fa2014-07-15 17:58:51 -070026#include "update_engine/update_metadata.pb.h"
Alex Deymo923d8fa2014-07-15 17:58:51 -070027
28using std::string;
Alex Deymo923d8fa2014-07-15 17:58:51 -070029
30namespace chromeos_update_engine {
31
Alex Deymo923d8fa2014-07-15 17:58:51 -070032namespace {
33
34// The following is a standard PKCS1-v1_5 padding for SHA256 signatures, as
35// defined in RFC3447. It is prepended to the actual signature (32 bytes) to
36// form a sequence of 256 bytes (2048 bits) that is amenable to RSA signing. The
37// padded hash will look as follows:
38//
39// 0x00 0x01 0xff ... 0xff 0x00 ASN1HEADER SHA256HASH
40// |--------------205-----------||----19----||----32----|
41//
42// where ASN1HEADER is the ASN.1 description of the signed data. The complete 51
43// bytes of actual data (i.e. the ASN.1 header complete with the hash) are
44// packed as follows:
45//
46// SEQUENCE(2+49) {
47// SEQUENCE(2+13) {
48// OBJECT(2+9) id-sha256
49// NULL(2+0)
50// }
51// OCTET STRING(2+32) <actual signature bytes...>
52// }
Amin Hassani008c4582019-01-13 16:22:47 -080053// clang-format off
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -080054const uint8_t kRSA2048SHA256Padding[] = {
Amin Hassani008c4582019-01-13 16:22:47 -080055 // PKCS1-v1_5 padding
56 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
57 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
58 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
59 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
60 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
61 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
62 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
63 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
64 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
65 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
66 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
67 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
68 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
69 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
70 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
71 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
72 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
73 0x00,
74 // ASN.1 header
75 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
76 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20,
Alex Deymo923d8fa2014-07-15 17:58:51 -070077};
Amin Hassani008c4582019-01-13 16:22:47 -080078// clang-format on
Alex Deymo923d8fa2014-07-15 17:58:51 -070079
80} // namespace
81
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -070082bool PayloadVerifier::VerifySignature(const brillo::Blob& signature_blob,
Sen Jiang08c6da12019-01-07 18:28:56 -080083 const string& pem_public_key,
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -070084 const brillo::Blob& hash_data) {
Alex Deymo923d8fa2014-07-15 17:58:51 -070085 Signatures signatures;
Amin Hassani008c4582019-01-13 16:22:47 -080086 LOG(INFO) << "signature blob size = " << signature_blob.size();
87 TEST_AND_RETURN_FALSE(
88 signatures.ParseFromArray(signature_blob.data(), signature_blob.size()));
Alex Deymo923d8fa2014-07-15 17:58:51 -070089
Alex Deymob552a682015-09-30 09:36:49 -070090 if (!signatures.signatures_size()) {
91 LOG(ERROR) << "No signatures stored in the blob.";
92 return false;
Alex Deymo923d8fa2014-07-15 17:58:51 -070093 }
Alex Deymo923d8fa2014-07-15 17:58:51 -070094
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -070095 std::vector<brillo::Blob> tested_hashes;
Alex Deymob552a682015-09-30 09:36:49 -070096 // Tries every signature in the signature blob.
97 for (int i = 0; i < signatures.signatures_size(); i++) {
98 const Signatures_Signature& signature = signatures.signatures(i);
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -070099 brillo::Blob sig_data(signature.data().begin(), signature.data().end());
100 brillo::Blob sig_hash_data;
Sen Jiang08c6da12019-01-07 18:28:56 -0800101 if (!GetRawHashFromSignature(sig_data, pem_public_key, &sig_hash_data))
Alex Deymob552a682015-09-30 09:36:49 -0700102 continue;
Alex Deymo923d8fa2014-07-15 17:58:51 -0700103
Alex Deymob552a682015-09-30 09:36:49 -0700104 if (hash_data == sig_hash_data) {
105 LOG(INFO) << "Verified correct signature " << i + 1 << " out of "
106 << signatures.signatures_size() << " signatures.";
107 return true;
108 }
109 tested_hashes.push_back(sig_hash_data);
110 }
111 LOG(ERROR) << "None of the " << signatures.signatures_size()
112 << " signatures is correct. Expected:";
113 utils::HexDumpVector(hash_data);
114 LOG(ERROR) << "But found decrypted hashes:";
115 for (const auto& sig_hash_data : tested_hashes) {
116 utils::HexDumpVector(sig_hash_data);
117 }
118 return false;
Alex Deymo923d8fa2014-07-15 17:58:51 -0700119}
120
Sen Jiang08c6da12019-01-07 18:28:56 -0800121bool PayloadVerifier::GetRawHashFromSignature(const brillo::Blob& sig_data,
122 const string& pem_public_key,
123 brillo::Blob* out_hash_data) {
Alex Deymo923d8fa2014-07-15 17:58:51 -0700124 // The code below executes the equivalent of:
125 //
Sen Jiang08c6da12019-01-07 18:28:56 -0800126 // openssl rsautl -verify -pubin -inkey <(echo |pem_public_key|)
Alex Deymo923d8fa2014-07-15 17:58:51 -0700127 // -in |sig_data| -out |out_hash_data|
128
Sen Jiang08c6da12019-01-07 18:28:56 -0800129 BIO* bp = BIO_new_mem_buf(pem_public_key.data(), pem_public_key.size());
130 char dummy_password[] = {' ', 0}; // Ensure no password is read from stdin.
131 RSA* rsa = PEM_read_bio_RSA_PUBKEY(bp, nullptr, nullptr, dummy_password);
132 BIO_free(bp);
Alex Deymo923d8fa2014-07-15 17:58:51 -0700133
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700134 TEST_AND_RETURN_FALSE(rsa != nullptr);
Alex Deymo923d8fa2014-07-15 17:58:51 -0700135 unsigned int keysize = RSA_size(rsa);
136 if (sig_data.size() > 2 * keysize) {
137 LOG(ERROR) << "Signature size is too big for public key size.";
138 RSA_free(rsa);
139 return false;
140 }
141
142 // Decrypts the signature.
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700143 brillo::Blob hash_data(keysize);
Amin Hassani008c4582019-01-13 16:22:47 -0800144 int decrypt_size = RSA_public_decrypt(
145 sig_data.size(), sig_data.data(), hash_data.data(), rsa, RSA_NO_PADDING);
Alex Deymo923d8fa2014-07-15 17:58:51 -0700146 RSA_free(rsa);
147 TEST_AND_RETURN_FALSE(decrypt_size > 0 &&
148 decrypt_size <= static_cast<int>(hash_data.size()));
149 hash_data.resize(decrypt_size);
150 out_hash_data->swap(hash_data);
151 return true;
152}
153
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700154bool PayloadVerifier::PadRSA2048SHA256Hash(brillo::Blob* hash) {
Alex Deymo923d8fa2014-07-15 17:58:51 -0700155 TEST_AND_RETURN_FALSE(hash->size() == 32);
156 hash->insert(hash->begin(),
157 reinterpret_cast<const char*>(kRSA2048SHA256Padding),
158 reinterpret_cast<const char*>(kRSA2048SHA256Padding +
159 sizeof(kRSA2048SHA256Padding)));
160 TEST_AND_RETURN_FALSE(hash->size() == 256);
161 return true;
162}
163
164} // namespace chromeos_update_engine