blob: f3d46265f5a400729a18427ca28991a33f7ca506 [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// }
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -080053const uint8_t kRSA2048SHA256Padding[] = {
Alex Deymo923d8fa2014-07-15 17:58:51 -070054 // PKCS1-v1_5 padding
55 0x00, 0x01, 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, 0xff, 0xff, 0xff, 0xff,
79 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
80 0xff, 0xff, 0xff, 0xff, 0x00,
81 // ASN.1 header
82 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
83 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
84 0x00, 0x04, 0x20,
85};
86
87} // namespace
88
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -070089bool PayloadVerifier::VerifySignature(const brillo::Blob& signature_blob,
Sen Jiang08c6da12019-01-07 18:28:56 -080090 const string& pem_public_key,
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -070091 const brillo::Blob& hash_data) {
Alex Deymo923d8fa2014-07-15 17:58:51 -070092 Signatures signatures;
Alex Deymob552a682015-09-30 09:36:49 -070093 LOG(INFO) << "signature blob size = " << signature_blob.size();
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -080094 TEST_AND_RETURN_FALSE(signatures.ParseFromArray(signature_blob.data(),
Alex Deymo923d8fa2014-07-15 17:58:51 -070095 signature_blob.size()));
96
Alex Deymob552a682015-09-30 09:36:49 -070097 if (!signatures.signatures_size()) {
98 LOG(ERROR) << "No signatures stored in the blob.";
99 return false;
Alex Deymo923d8fa2014-07-15 17:58:51 -0700100 }
Alex Deymo923d8fa2014-07-15 17:58:51 -0700101
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700102 std::vector<brillo::Blob> tested_hashes;
Alex Deymob552a682015-09-30 09:36:49 -0700103 // 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);
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700106 brillo::Blob sig_data(signature.data().begin(), signature.data().end());
107 brillo::Blob sig_hash_data;
Sen Jiang08c6da12019-01-07 18:28:56 -0800108 if (!GetRawHashFromSignature(sig_data, pem_public_key, &sig_hash_data))
Alex Deymob552a682015-09-30 09:36:49 -0700109 continue;
Alex Deymo923d8fa2014-07-15 17:58:51 -0700110
Alex Deymob552a682015-09-30 09:36:49 -0700111 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;
Alex Deymo923d8fa2014-07-15 17:58:51 -0700126}
127
Sen Jiang08c6da12019-01-07 18:28:56 -0800128bool PayloadVerifier::GetRawHashFromSignature(const brillo::Blob& sig_data,
129 const string& pem_public_key,
130 brillo::Blob* out_hash_data) {
Alex Deymo923d8fa2014-07-15 17:58:51 -0700131 // The code below executes the equivalent of:
132 //
Sen Jiang08c6da12019-01-07 18:28:56 -0800133 // openssl rsautl -verify -pubin -inkey <(echo |pem_public_key|)
Alex Deymo923d8fa2014-07-15 17:58:51 -0700134 // -in |sig_data| -out |out_hash_data|
135
Sen Jiang08c6da12019-01-07 18:28:56 -0800136 BIO* bp = BIO_new_mem_buf(pem_public_key.data(), pem_public_key.size());
137 char dummy_password[] = {' ', 0}; // Ensure no password is read from stdin.
138 RSA* rsa = PEM_read_bio_RSA_PUBKEY(bp, nullptr, nullptr, dummy_password);
139 BIO_free(bp);
Alex Deymo923d8fa2014-07-15 17:58:51 -0700140
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700141 TEST_AND_RETURN_FALSE(rsa != nullptr);
Alex Deymo923d8fa2014-07-15 17:58:51 -0700142 unsigned int keysize = RSA_size(rsa);
143 if (sig_data.size() > 2 * keysize) {
144 LOG(ERROR) << "Signature size is too big for public key size.";
145 RSA_free(rsa);
146 return false;
147 }
148
149 // Decrypts the signature.
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700150 brillo::Blob hash_data(keysize);
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800151 int decrypt_size = RSA_public_decrypt(sig_data.size(),
152 sig_data.data(),
153 hash_data.data(),
154 rsa,
155 RSA_NO_PADDING);
Alex Deymo923d8fa2014-07-15 17:58:51 -0700156 RSA_free(rsa);
157 TEST_AND_RETURN_FALSE(decrypt_size > 0 &&
158 decrypt_size <= static_cast<int>(hash_data.size()));
159 hash_data.resize(decrypt_size);
160 out_hash_data->swap(hash_data);
161 return true;
162}
163
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700164bool PayloadVerifier::PadRSA2048SHA256Hash(brillo::Blob* hash) {
Alex Deymo923d8fa2014-07-15 17:58:51 -0700165 TEST_AND_RETURN_FALSE(hash->size() == 32);
166 hash->insert(hash->begin(),
167 reinterpret_cast<const char*>(kRSA2048SHA256Padding),
168 reinterpret_cast<const char*>(kRSA2048SHA256Padding +
169 sizeof(kRSA2048SHA256Padding)));
170 TEST_AND_RETURN_FALSE(hash->size() == 256);
171 return true;
172}
173
174} // namespace chromeos_update_engine