1/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 *
5 * Tests for firmware image library.
6 */
7
8#include <stdint.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12
13#include "cryptolib.h"
14#include "file_keys.h"
15#include "host_common.h"
16#include "test_common.h"
17#include "vboot_common.h"
18
19static void VerifyPublicKeyToRSA(const VbPublicKey *orig_key)
20{
21	RSAPublicKey *rsa;
22	VbPublicKey *key = PublicKeyAlloc(orig_key->key_size, 0, 0);
23
24	PublicKeyCopy(key, orig_key);
25	key->algorithm = kNumAlgorithms;
26	TEST_EQ((size_t)PublicKeyToRSA(key), 0,
27		"PublicKeyToRSA() invalid algorithm");
28
29	PublicKeyCopy(key, orig_key);
30	key->key_size -= 1;
31	TEST_EQ((size_t)PublicKeyToRSA(key), 0,
32		"PublicKeyToRSA() invalid size");
33
34	rsa = PublicKeyToRSA(orig_key);
35	TEST_NEQ((size_t)rsa, 0, "PublicKeyToRSA() ok");
36	if (rsa) {
37		TEST_EQ((int)rsa->algorithm, (int)key->algorithm,
38			"PublicKeyToRSA() algorithm");
39		RSAPublicKeyFree(rsa);
40	}
41}
42
43static void VerifyDataTest(const VbPublicKey *public_key,
44                           const VbPrivateKey *private_key)
45{
46	const uint8_t test_data[] = "This is some test data to sign.";
47	const uint64_t test_size = sizeof(test_data);
48	VbSignature *sig;
49	RSAPublicKey *rsa;
50
51	sig = CalculateSignature(test_data, test_size, private_key);
52	TEST_PTR_NEQ(sig, 0, "VerifyData() calculate signature");
53
54	rsa = PublicKeyToRSA(public_key);
55	TEST_PTR_NEQ(rsa, 0, "VerifyData() calculate rsa");
56
57	if (!sig || !rsa)
58		return;
59
60	TEST_EQ(VerifyData(test_data, test_size, sig, rsa), 0,
61		"VerifyData() ok");
62
63	sig->sig_size -= 16;
64	TEST_EQ(VerifyData(test_data, test_size, sig, rsa), 1,
65		"VerifyData() wrong sig size");
66	sig->sig_size += 16;
67
68	TEST_EQ(VerifyData(test_data, test_size - 1, sig, rsa), 1,
69		"VerifyData() input buffer too small");
70
71	GetSignatureData(sig)[0] ^= 0x5A;
72	TEST_EQ(VerifyData(test_data, test_size, sig, rsa), 1,
73		"VerifyData() wrong sig");
74
75	RSAPublicKeyFree(rsa);
76	free(sig);
77}
78
79static void VerifyDigestTest(const VbPublicKey *public_key,
80                             const VbPrivateKey *private_key)
81{
82	const uint8_t test_data[] = "This is some other test data to sign.";
83	VbSignature *sig;
84	RSAPublicKey *rsa;
85	uint8_t *digest;
86
87	sig = CalculateSignature(test_data, sizeof(test_data), private_key);
88	rsa = PublicKeyToRSA(public_key);
89	digest = DigestBuf(test_data, sizeof(test_data),
90			   (int)public_key->algorithm);
91	TEST_NEQ(sig && rsa && digest, 0, "VerifyData() prerequisites");
92	if (!sig || !rsa || !digest)
93		return;
94
95	TEST_EQ(VerifyDigest(digest, sig, rsa), 0, "VerifyDigest() ok");
96
97	GetSignatureData(sig)[0] ^= 0x5A;
98	TEST_EQ(VerifyDigest(digest, sig, rsa), 1, "VerifyDigest() wrong sig");
99
100	sig->sig_size = 1;
101	TEST_EQ(VerifyDigest(digest, sig, rsa), 1, "VerifyDigest() sig size");
102
103	RSAPublicKeyFree(rsa);
104	free(sig);
105	VbExFree(digest);
106}
107
108static void ReSignKernelPreamble(VbKernelPreambleHeader *h,
109                                 const VbPrivateKey *key)
110{
111	VbSignature *sig = CalculateSignature((const uint8_t *)h,
112			h->preamble_signature.data_size, key);
113
114	SignatureCopy(&h->preamble_signature, sig);
115	free(sig);
116}
117
118static void VerifyKernelPreambleTest(const VbPublicKey *public_key,
119                                     const VbPrivateKey *private_key)
120{
121	VbKernelPreambleHeader *hdr;
122	VbKernelPreambleHeader *h;
123	RSAPublicKey *rsa;
124	unsigned hsize;
125
126	/* Create a dummy signature */
127	VbSignature *body_sig = SignatureAlloc(56, 78);
128
129	rsa = PublicKeyToRSA(public_key);
130	hdr = CreateKernelPreamble(0x1234, 0x100000, 0x300000, 0x4000, body_sig,
131				   0, 0, 0, 0, private_key);
132	TEST_NEQ(hdr && rsa, 0, "VerifyKernelPreamble() prerequisites");
133	if (!hdr)
134		return;
135	hsize = (unsigned) hdr->preamble_size;
136	h = (VbKernelPreambleHeader *)malloc(hsize + 16384);
137
138	TEST_EQ(VerifyKernelPreamble(hdr, hsize, rsa), 0,
139		"VerifyKernelPreamble() ok using key");
140	TEST_NEQ(VerifyKernelPreamble(hdr, hsize - 1, rsa), 0,
141		 "VerifyKernelPreamble() size--");
142	TEST_NEQ(VerifyKernelPreamble(hdr, 4, rsa), 0,
143		 "VerifyKernelPreamble() size tiny");
144	TEST_EQ(VerifyKernelPreamble(hdr, hsize + 1, rsa), 0,
145		"VerifyKernelPreamble() size++");
146
147	/* Care about major version but not minor */
148	Memcpy(h, hdr, hsize);
149	h->header_version_major++;
150	ReSignKernelPreamble(h, private_key);
151	TEST_NEQ(VerifyKernelPreamble(h, hsize, rsa), 0,
152		 "VerifyKernelPreamble() major++");
153
154	Memcpy(h, hdr, hsize);
155	h->header_version_major--;
156	ReSignKernelPreamble(h, private_key);
157	TEST_NEQ(VerifyKernelPreamble(h, hsize, rsa), 0,
158		 "VerifyKernelPreamble() major--");
159
160	Memcpy(h, hdr, hsize);
161	h->header_version_minor++;
162	ReSignKernelPreamble(h, private_key);
163	TEST_EQ(VerifyKernelPreamble(h, hsize, rsa), 0,
164		"VerifyKernelPreamble() minor++");
165
166	Memcpy(h, hdr, hsize);
167	h->header_version_minor--;
168	ReSignKernelPreamble(h, private_key);
169	TEST_EQ(VerifyKernelPreamble(h, hsize, rsa), 0,
170		"VerifyKernelPreamble() minor--");
171
172	/* Check signature */
173	Memcpy(h, hdr, hsize);
174	h->preamble_signature.sig_offset = hsize;
175	ReSignKernelPreamble(h, private_key);
176	TEST_NEQ(VerifyKernelPreamble(h, hsize, rsa), 0,
177		 "VerifyKernelPreamble() sig off end");
178
179	Memcpy(h, hdr, hsize);
180	h->preamble_signature.sig_size--;
181	ReSignKernelPreamble(h, private_key);
182	TEST_NEQ(VerifyKernelPreamble(h, hsize, rsa), 0,
183		 "VerifyKernelPreamble() sig too small");
184
185	Memcpy(h, hdr, hsize);
186	GetSignatureData(&h->body_signature)[0] ^= 0x34;
187	TEST_NEQ(VerifyKernelPreamble(h, hsize, rsa), 0,
188		 "VerifyKernelPreamble() sig mismatch");
189
190	/* Check that we signed header and body sig */
191	Memcpy(h, hdr, hsize);
192	h->preamble_signature.data_size = 4;
193	h->body_signature.sig_offset = 0;
194	h->body_signature.sig_size = 0;
195	ReSignKernelPreamble(h, private_key);
196	TEST_NEQ(VerifyKernelPreamble(h, hsize, rsa), 0,
197		 "VerifyKernelPreamble() didn't sign header");
198
199	Memcpy(h, hdr, hsize);
200	h->body_signature.sig_offset = hsize;
201	ReSignKernelPreamble(h, private_key);
202	TEST_NEQ(VerifyKernelPreamble(h, hsize, rsa), 0,
203		 "VerifyKernelPreamble() body sig off end");
204
205	/* TODO: verify parser can support a bigger header. */
206
207	free(h);
208	RSAPublicKeyFree(rsa);
209	free(hdr);
210}
211
212int test_algorithm(int key_algorithm, const char *keys_dir)
213{
214	char filename[1024];
215	int rsa_len = siglen_map[key_algorithm] * 8;
216
217	VbPrivateKey *private_key = NULL;
218	VbPublicKey *public_key = NULL;
219
220	printf("***Testing algorithm: %s\n", algo_strings[key_algorithm]);
221
222	sprintf(filename, "%s/key_rsa%d.pem", keys_dir, rsa_len);
223	private_key = PrivateKeyReadPem(filename, key_algorithm);
224	if (!private_key) {
225		fprintf(stderr, "Error reading private_key: %s\n", filename);
226		return 1;
227	}
228
229	sprintf(filename, "%s/key_rsa%d.keyb", keys_dir, rsa_len);
230	public_key = PublicKeyReadKeyb(filename, key_algorithm, 1);
231	if (!public_key) {
232		fprintf(stderr, "Error reading public_key: %s\n", filename);
233		return 1;
234	}
235
236	VerifyPublicKeyToRSA(public_key);
237	VerifyDataTest(public_key, private_key);
238	VerifyDigestTest(public_key, private_key);
239	VerifyKernelPreambleTest(public_key, private_key);
240
241	if (public_key)
242		free(public_key);
243	if (private_key)
244		free(private_key);
245
246	return 0;
247}
248
249/*
250 * Test only the algorithms we use:
251 * 4 (rsa2048 sha256)
252 * 7 (rsa4096 sha256)
253 * 11 (rsa8192 sha512)
254 */
255const int key_algs[] = {4, 7, 11};
256
257int main(int argc, char *argv[]) {
258	if (argc == 2) {
259		int i;
260
261		for (i = 0; i < ARRAY_SIZE(key_algs); i++) {
262			if (test_algorithm(key_algs[i], argv[1]))
263				return 1;
264		}
265
266	} else if (argc == 3 && !strcasecmp(argv[2], "--all")) {
267		/* Test all the algorithms */
268		int alg;
269
270		for (alg = 0; alg < kNumAlgorithms; alg++) {
271			if (test_algorithm(alg, argv[1]))
272				return 1;
273		}
274
275	} else {
276		fprintf(stderr, "Usage: %s <keys_dir> [--all]", argv[0]);
277		return -1;
278	}
279
280	if (vboot_api_stub_check_memory())
281		return 255;
282
283	return gTestSuccess ? 0 : 255;
284}
285