blob: ab5238c39aba163ce04e739f4fb4dcce494bc678 [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
19#include <base/logging.h>
20#include <openssl/pem.h>
21
Alex Deymo39910dc2015-11-09 17:04:30 -080022#include "update_engine/common/hash_calculator.h"
23#include "update_engine/common/utils.h"
Alex Deymo923d8fa2014-07-15 17:58:51 -070024#include "update_engine/update_metadata.pb.h"
Alex Deymo923d8fa2014-07-15 17:58:51 -070025
26using std::string;
Alex Deymo923d8fa2014-07-15 17:58:51 -070027
28namespace chromeos_update_engine {
29
Alex Deymo923d8fa2014-07-15 17:58:51 -070030namespace {
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// }
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -080051const uint8_t kRSA2048SHA256Padding[] = {
Alex Deymo923d8fa2014-07-15 17:58:51 -070052 // 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
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -070087bool PayloadVerifier::VerifySignature(const brillo::Blob& signature_blob,
Alex Deymof329b932014-10-30 01:37:48 -070088 const string& public_key_path,
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -070089 const brillo::Blob& hash_data) {
Alex Deymo923d8fa2014-07-15 17:58:51 -070090 TEST_AND_RETURN_FALSE(!public_key_path.empty());
91
92 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;
Alex Deymob552a682015-09-30 09:36:49 -0700108 if (!GetRawHashFromSignature(sig_data, public_key_path, &sig_hash_data))
109 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
128
129bool PayloadVerifier::GetRawHashFromSignature(
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700130 const brillo::Blob& sig_data,
Alex Deymof329b932014-10-30 01:37:48 -0700131 const string& public_key_path,
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700132 brillo::Blob* out_hash_data) {
Alex Deymo923d8fa2014-07-15 17:58:51 -0700133 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.
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700148 RSA* rsa = PEM_read_RSA_PUBKEY(fpubkey, nullptr, nullptr, dummy_password);
Alex Deymo923d8fa2014-07-15 17:58:51 -0700149 fclose(fpubkey);
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700150 TEST_AND_RETURN_FALSE(rsa != nullptr);
Alex Deymo923d8fa2014-07-15 17:58:51 -0700151 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.
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700159 brillo::Blob hash_data(keysize);
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800160 int decrypt_size = RSA_public_decrypt(sig_data.size(),
161 sig_data.data(),
162 hash_data.data(),
163 rsa,
164 RSA_NO_PADDING);
Alex Deymo923d8fa2014-07-15 17:58:51 -0700165 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
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700173bool PayloadVerifier::PadRSA2048SHA256Hash(brillo::Blob* hash) {
Alex Deymo923d8fa2014-07-15 17:58:51 -0700174 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