blob: 3eb1da8b025b77284db175e5e09f5df9c8016e18 [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
Sen Jiang9b2f1782019-01-24 14:27:50 -080082bool PayloadVerifier::VerifySignature(const string& signature_proto,
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;
Sen Jiang9b2f1782019-01-24 14:27:50 -080086 LOG(INFO) << "signature blob size = " << signature_proto.size();
87 TEST_AND_RETURN_FALSE(signatures.ParseFromString(signature_proto));
Alex Deymo923d8fa2014-07-15 17:58:51 -070088
Alex Deymob552a682015-09-30 09:36:49 -070089 if (!signatures.signatures_size()) {
90 LOG(ERROR) << "No signatures stored in the blob.";
91 return false;
Alex Deymo923d8fa2014-07-15 17:58:51 -070092 }
Alex Deymo923d8fa2014-07-15 17:58:51 -070093
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -070094 std::vector<brillo::Blob> tested_hashes;
Alex Deymob552a682015-09-30 09:36:49 -070095 // Tries every signature in the signature blob.
96 for (int i = 0; i < signatures.signatures_size(); i++) {
Sen Jiang9b2f1782019-01-24 14:27:50 -080097 const Signatures::Signature& signature = signatures.signatures(i);
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -070098 brillo::Blob sig_data(signature.data().begin(), signature.data().end());
99 brillo::Blob sig_hash_data;
Sen Jiang08c6da12019-01-07 18:28:56 -0800100 if (!GetRawHashFromSignature(sig_data, pem_public_key, &sig_hash_data))
Alex Deymob552a682015-09-30 09:36:49 -0700101 continue;
Alex Deymo923d8fa2014-07-15 17:58:51 -0700102
Alex Deymob552a682015-09-30 09:36:49 -0700103 if (hash_data == sig_hash_data) {
104 LOG(INFO) << "Verified correct signature " << i + 1 << " out of "
105 << signatures.signatures_size() << " signatures.";
106 return true;
107 }
108 tested_hashes.push_back(sig_hash_data);
109 }
110 LOG(ERROR) << "None of the " << signatures.signatures_size()
111 << " signatures is correct. Expected:";
112 utils::HexDumpVector(hash_data);
113 LOG(ERROR) << "But found decrypted hashes:";
114 for (const auto& sig_hash_data : tested_hashes) {
115 utils::HexDumpVector(sig_hash_data);
116 }
117 return false;
Alex Deymo923d8fa2014-07-15 17:58:51 -0700118}
119
Sen Jiang08c6da12019-01-07 18:28:56 -0800120bool PayloadVerifier::GetRawHashFromSignature(const brillo::Blob& sig_data,
121 const string& pem_public_key,
122 brillo::Blob* out_hash_data) {
Alex Deymo923d8fa2014-07-15 17:58:51 -0700123 // The code below executes the equivalent of:
124 //
Sen Jiang08c6da12019-01-07 18:28:56 -0800125 // openssl rsautl -verify -pubin -inkey <(echo |pem_public_key|)
Alex Deymo923d8fa2014-07-15 17:58:51 -0700126 // -in |sig_data| -out |out_hash_data|
127
Sen Jiang08c6da12019-01-07 18:28:56 -0800128 BIO* bp = BIO_new_mem_buf(pem_public_key.data(), pem_public_key.size());
129 char dummy_password[] = {' ', 0}; // Ensure no password is read from stdin.
130 RSA* rsa = PEM_read_bio_RSA_PUBKEY(bp, nullptr, nullptr, dummy_password);
131 BIO_free(bp);
Alex Deymo923d8fa2014-07-15 17:58:51 -0700132
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700133 TEST_AND_RETURN_FALSE(rsa != nullptr);
Alex Deymo923d8fa2014-07-15 17:58:51 -0700134 unsigned int keysize = RSA_size(rsa);
135 if (sig_data.size() > 2 * keysize) {
136 LOG(ERROR) << "Signature size is too big for public key size.";
137 RSA_free(rsa);
138 return false;
139 }
140
141 // Decrypts the signature.
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700142 brillo::Blob hash_data(keysize);
Amin Hassani008c4582019-01-13 16:22:47 -0800143 int decrypt_size = RSA_public_decrypt(
144 sig_data.size(), sig_data.data(), hash_data.data(), rsa, RSA_NO_PADDING);
Alex Deymo923d8fa2014-07-15 17:58:51 -0700145 RSA_free(rsa);
146 TEST_AND_RETURN_FALSE(decrypt_size > 0 &&
147 decrypt_size <= static_cast<int>(hash_data.size()));
148 hash_data.resize(decrypt_size);
149 out_hash_data->swap(hash_data);
150 return true;
151}
152
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700153bool PayloadVerifier::PadRSA2048SHA256Hash(brillo::Blob* hash) {
Alex Deymo923d8fa2014-07-15 17:58:51 -0700154 TEST_AND_RETURN_FALSE(hash->size() == 32);
155 hash->insert(hash->begin(),
156 reinterpret_cast<const char*>(kRSA2048SHA256Padding),
157 reinterpret_cast<const char*>(kRSA2048SHA256Padding +
158 sizeof(kRSA2048SHA256Padding)));
159 TEST_AND_RETURN_FALSE(hash->size() == 256);
160 return true;
161}
162
163} // namespace chromeos_update_engine