blob: 6fedfd85f7c67e153688ad2e98ce3ed633ff4beb [file] [log] [blame]
Shashank Mittalcd98d472011-08-02 14:29:24 -07001/*
Sridhar Parasuramb27e47c2015-05-27 14:33:54 -07002 * Copyright (c) 2011,2013-2015 The Linux Foundation. All rights reserved.
Shashank Mittalcd98d472011-08-02 14:29:24 -07003 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in
11 * the documentation and/or other materials provided with the
12 * distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
17 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
18 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
21 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
24 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27#include <x509.h>
vijay kumar4f4405f2014-08-08 11:49:53 +053028#include <err.h>
Shashank Mittalcd98d472011-08-02 14:29:24 -070029#include <certificate.h>
30#include <crypto_hash.h>
vijay kumar4f4405f2014-08-08 11:49:53 +053031#include <string.h>
AnilKumar Chimataaee53282017-08-05 00:20:10 +053032#include <platform.h>
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -080033#include <openssl/err.h>
Shashank Mittalcd98d472011-08-02 14:29:24 -070034#include "image_verify.h"
Amir Samuelov67ae1d32013-03-24 16:27:52 +020035#include "scm.h"
Shashank Mittalcd98d472011-08-02 14:29:24 -070036
AnilKumar Chimataaee53282017-08-05 00:20:10 +053037#include <LEOEMCertificate.h>
38
39const char hash_identifier[] = {
40 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
41 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20
42};
vijay kumar4f4405f2014-08-08 11:49:53 +053043
Shashank Mittalcd98d472011-08-02 14:29:24 -070044/*
45 * Returns -1 if decryption failed otherwise size of plain_text in bytes
46 */
Shashank Mittal64d04852014-08-28 15:02:46 -070047int image_decrypt_signature_rsa(unsigned char *signature_ptr,
48 unsigned char *plain_text, RSA *rsa_key)
49{
50 int ret = -1;
51
52 if (rsa_key == NULL) {
53 dprintf(CRITICAL, "ERROR: Boot Invalid, RSA_KEY is NULL!\n");
54 return ret;
55 }
56
57 ret = RSA_public_decrypt(SIGNATURE_SIZE, signature_ptr, plain_text,
58 rsa_key, RSA_PKCS1_PADDING);
59 dprintf(SPEW, "DEBUG openssl: Return of RSA_public_decrypt = %d\n",
60 ret);
61
62 return ret;
63}
64
65/*
66 * Returns -1 if decryption failed otherwise size of plain_text in bytes
67 */
Ajay Dudanib01e5062011-12-03 23:23:42 -080068static int
69image_decrypt_signature(unsigned char *signature_ptr, unsigned char *plain_text)
70{
Shashank Mittalcd98d472011-08-02 14:29:24 -070071 /*
72 * Extract Public Key and Decrypt Signature
73 */
74 int ret = -1;
75 X509 *x509_certificate = NULL;
AnilKumar Chimataaee53282017-08-05 00:20:10 +053076 const unsigned char *cert_ptr = NULL;
77 unsigned int cert_size = 0;
78
79 if (is_vb_le_enabled()) {
80 cert_ptr = (const unsigned char *)LE_OEM_CERTIFICATE;
81 cert_size = sizeof(LE_OEM_CERTIFICATE);
82 } else {
83 cert_ptr = (const unsigned char *)certBuffer;
84 cert_size = sizeof(certBuffer);
85 }
86
Shashank Mittalcd98d472011-08-02 14:29:24 -070087 EVP_PKEY *pub_key = NULL;
Ajay Dudanib01e5062011-12-03 23:23:42 -080088 RSA *rsa_key = NULL;
Shashank Mittalcd98d472011-08-02 14:29:24 -070089
90 /*
91 * Get Pubkey and Convert the internal EVP_PKEY to RSA internal struct
92 */
Ajay Dudanib01e5062011-12-03 23:23:42 -080093 if ((x509_certificate = d2i_X509(NULL, &cert_ptr, cert_size)) == NULL) {
Shashank Mittalcd98d472011-08-02 14:29:24 -070094 dprintf(CRITICAL,
95 "ERROR: Image Invalid, X509_Certificate is NULL!\n");
96 goto cleanup;
97 }
98 pub_key = X509_get_pubkey(x509_certificate);
Lijuan Gao0e2caf22014-07-15 18:36:18 +080099 if (pub_key == NULL) {
100 dprintf(CRITICAL, "ERROR: Boot Invalid, PUB_KEY is NULL!\n");
101 goto cleanup;
102 }
103
Shashank Mittalcd98d472011-08-02 14:29:24 -0700104 rsa_key = EVP_PKEY_get1_RSA(pub_key);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800105 if (rsa_key == NULL) {
106 dprintf(CRITICAL, "ERROR: Boot Invalid, RSA_KEY is NULL!\n");
Shashank Mittalcd98d472011-08-02 14:29:24 -0700107 goto cleanup;
108 }
109
Shashank Mittal64d04852014-08-28 15:02:46 -0700110 ret = image_decrypt_signature_rsa(signature_ptr, plain_text, rsa_key);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800111 dprintf(SPEW, "DEBUG openssl: Return of RSA_public_decrypt = %d\n",
112 ret);
Shashank Mittalcd98d472011-08-02 14:29:24 -0700113
Ajay Dudanib01e5062011-12-03 23:23:42 -0800114 cleanup:
Shashank Mittalcd98d472011-08-02 14:29:24 -0700115 if (rsa_key != NULL)
116 RSA_free(rsa_key);
117 if (x509_certificate != NULL)
118 X509_free(x509_certificate);
119 if (pub_key != NULL)
120 EVP_PKEY_free(pub_key);
121 return ret;
122}
123
Shashank Mittal64d04852014-08-28 15:02:46 -0700124/* Calculates digest of an image and save it in digest buffer */
125void image_find_digest(unsigned char *image_ptr, unsigned int image_size,
126 unsigned hash_type, unsigned char *digest)
127{
128 /*
129 * Calculate hash of image and save calculated hash on TZ.
130 */
131 hash_find(image_ptr, image_size, (unsigned char *)digest, hash_type);
Sridhar Parasuramb27e47c2015-05-27 14:33:54 -0700132}
133
Shashank Mittal64d04852014-08-28 15:02:46 -0700134#ifdef TZ_SAVE_KERNEL_HASH
Sridhar Parasuramb27e47c2015-05-27 14:33:54 -0700135void save_kernel_hash(unsigned char *digest, unsigned hash_type)
136{
Shashank Mittal64d04852014-08-28 15:02:46 -0700137 if (hash_type == CRYPTO_AUTH_ALG_SHA256) {
138 save_kernel_hash_cmd(digest);
139 dprintf(INFO, "Image hash saved.\n");
140 } else
141 dprintf(INFO, "image_verify: hash is not SHA-256.\n");
Shashank Mittal64d04852014-08-28 15:02:46 -0700142}
Sridhar Parasuramb27e47c2015-05-27 14:33:54 -0700143#endif
Shashank Mittal64d04852014-08-28 15:02:46 -0700144
Shashank Mittalcd98d472011-08-02 14:29:24 -0700145/*
146 * Returns 1 when image is signed and authorized.
147 * Returns 0 when image is unauthorized.
148 * Expects a pointer to the start of image and pointer to start of sig
149 */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800150int
151image_verify(unsigned char *image_ptr,
152 unsigned char *signature_ptr,
153 unsigned int image_size, unsigned hash_type)
154{
Shashank Mittalcd98d472011-08-02 14:29:24 -0700155
156 int ret = -1;
157 int auth = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800158 unsigned char *plain_text = NULL;
Shashank Mittalcd98d472011-08-02 14:29:24 -0700159 unsigned int digest[8];
vijay kumar4f4405f2014-08-08 11:49:53 +0530160 int hash_size;
Shashank Mittalcd98d472011-08-02 14:29:24 -0700161
Ajay Dudanib01e5062011-12-03 23:23:42 -0800162 plain_text = (unsigned char *)calloc(sizeof(char), SIGNATURE_SIZE);
163 if (plain_text == NULL) {
Shashank Mittalcd98d472011-08-02 14:29:24 -0700164 dprintf(CRITICAL, "ERROR: Calloc failed during verification\n");
165 goto cleanup;
166 }
167
Amir Samuelova3382942014-03-13 13:48:57 +0200168 /*
169 * Calculate hash of image and save calculated hash on TZ.
170 */
171 hash_size =
172 (hash_type == CRYPTO_AUTH_ALG_SHA256) ? SHA256_SIZE : SHA1_SIZE;
Shashank Mittal64d04852014-08-28 15:02:46 -0700173 image_find_digest(image_ptr, image_size, hash_type,
174 (unsigned char *)&digest);
Sridhar Parasuramb27e47c2015-05-27 14:33:54 -0700175#ifdef TZ_SAVE_KERNEL_HASH
176 save_kernel_hash((unsigned char *) &digest, hash_type);
177#endif
Amir Samuelova3382942014-03-13 13:48:57 +0200178
179 /*
180 * Decrypt the pre-calculated expected image hash.
Sundarajan Srinivasanf3908592014-04-21 14:14:30 -0700181 * Return value, ret should be equal to hash_size. Otherwise it means a failure. With this check
182 * we avoid a potential vulnerability due to trailing data placed at the end of digest.
Amir Samuelova3382942014-03-13 13:48:57 +0200183 */
Shashank Mittalcd98d472011-08-02 14:29:24 -0700184 ret = image_decrypt_signature(signature_ptr, plain_text);
AnilKumar Chimataaee53282017-08-05 00:20:10 +0530185 if (is_vb_le_enabled()) {
186 int sha256_pkcs1_hash_identifier_len = sizeof(hash_identifier);
187 if (ret != (hash_size + sha256_pkcs1_hash_identifier_len)) {
188 dprintf(CRITICAL, "ERROR: VB: Image Invalid! signature check failed! ret %d\n", ret);
189 goto cleanup;
190 }
191 /*
192 * Compare the expected hash with the calculated hash.
193 */
194 if (memcmp(plain_text, hash_identifier, sha256_pkcs1_hash_identifier_len) != 0) {
195 dprintf(CRITICAL,
196 "ERROR: VB: Hash identifier is wrong!\n");
197 goto cleanup;
198 }
199 if (memcmp(plain_text + sha256_pkcs1_hash_identifier_len, digest, hash_size) != 0) {
200 dprintf(CRITICAL,
201 "ERROR: VB: Image Invalid! Please use another image!\n");
202 goto cleanup;
203 }
204 } else {
205 if (ret != hash_size) {
206 dprintf(CRITICAL, "ERROR: Image Invalid! signature check failed! ret %d\n", ret);
207 goto cleanup;
208 }
209 /*
210 * Compare the expected hash with the calculated hash.
211 */
212 if (memcmp(plain_text, digest, hash_size) != 0) {
213 dprintf(CRITICAL,
214 "ERROR: Image Invalid! Please use another image!\n");
215 ret = -1;
216 goto cleanup;
217 }
Shashank Mittalcd98d472011-08-02 14:29:24 -0700218 }
219
AnilKumar Chimataaee53282017-08-05 00:20:10 +0530220 /* Authorized image */
221 auth = 1;
Shashank Mittalcd98d472011-08-02 14:29:24 -0700222
223 /* Cleanup after complete usage of openssl - cached data and objects */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800224 cleanup:
Shashank Mittalcd98d472011-08-02 14:29:24 -0700225 if (plain_text != NULL)
226 free(plain_text);
227 EVP_cleanup();
228 CRYPTO_cleanup_all_ex_data();
229 ERR_remove_thread_state(NULL);
230 return auth;
231}