blob: e2736f95ae5db6310ae4ffc23ed087a613070077 [file] [log] [blame]
Randall Spangler32a65262011-06-27 10:49:11 -07001/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
Randall Spanglerd1836442010-06-10 09:59:04 -07002 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 *
5 * Host functions for keys.
6 */
7
8/* TODO: change all 'return 0', 'return 1' into meaningful return codes */
9
10#define OPENSSL_NO_SHA
11#include <openssl/engine.h>
12#include <openssl/pem.h>
13#include <openssl/rsa.h>
Bill Richardsonabf05502010-07-01 10:22:06 -070014#include <openssl/x509.h>
Randall Spanglerd1836442010-06-10 09:59:04 -070015
16#include <stdio.h>
17#include <stdlib.h>
18#include <unistd.h>
19
Randall Spanglerd1836442010-06-10 09:59:04 -070020#include "cryptolib.h"
Randall Spangler32a65262011-06-27 10:49:11 -070021#include "host_common.h"
22#include "host_key.h"
Randall Spanglerd55c6452010-06-10 12:43:51 -070023#include "host_misc.h"
Randall Spanglerd1836442010-06-10 09:59:04 -070024#include "vboot_common.h"
25
26
Bill Richardsona08b5c92010-06-30 21:59:43 -070027VbPrivateKey* PrivateKeyReadPem(const char* filename, uint64_t algorithm) {
Randall Spanglerd1836442010-06-10 09:59:04 -070028
29 VbPrivateKey* key;
30 RSA* rsa_key;
31 FILE* f;
32
33 if (algorithm >= kNumAlgorithms) {
Bill Richardsonabf05502010-07-01 10:22:06 -070034 VBDEBUG(("%s() called with invalid algorithm!\n", __FUNCTION__));
Randall Spanglerd1836442010-06-10 09:59:04 -070035 return NULL;
36 }
37
38 /* Read private key */
39 f = fopen(filename, "r");
40 if (!f) {
Bill Richardsonabf05502010-07-01 10:22:06 -070041 VBDEBUG(("%s(): Couldn't open key file: %s\n", __FUNCTION__, filename));
Randall Spanglerd1836442010-06-10 09:59:04 -070042 return NULL;
43 }
44 rsa_key = PEM_read_RSAPrivateKey(f, NULL, NULL, NULL);
45 fclose(f);
46 if (!rsa_key) {
Bill Richardsonabf05502010-07-01 10:22:06 -070047 VBDEBUG(("%s(): Couldn't read private key from file: %s\n", __FUNCTION__,
48 filename));
Randall Spanglerd1836442010-06-10 09:59:04 -070049 return NULL;
50 }
51
52 /* Store key and algorithm in our struct */
Randall Spangler32a65262011-06-27 10:49:11 -070053 key = (VbPrivateKey*)malloc(sizeof(VbPrivateKey));
Randall Spanglerd1836442010-06-10 09:59:04 -070054 if (!key) {
55 RSA_free(rsa_key);
56 return NULL;
57 }
58 key->rsa_private_key = rsa_key;
59 key->algorithm = algorithm;
60
61 /* Return the key */
62 return key;
63}
64
65
66void PrivateKeyFree(VbPrivateKey* key) {
67 if (!key)
68 return;
69 if (key->rsa_private_key)
70 RSA_free(key->rsa_private_key);
Randall Spangler32a65262011-06-27 10:49:11 -070071 free(key);
Randall Spanglerd1836442010-06-10 09:59:04 -070072}
73
74
Bill Richardsonabf05502010-07-01 10:22:06 -070075/* Write a private key to a file in .vbprivk format. */
76int PrivateKeyWrite(const char* filename, const VbPrivateKey* key) {
77 uint8_t *outbuf = 0;
78 int buflen;
79 FILE *f;
80
81 buflen = i2d_RSAPrivateKey(key->rsa_private_key, &outbuf);
82 if (buflen <= 0) {
Randall Spangler32a65262011-06-27 10:49:11 -070083 VbExError("Unable to write private key buffer\n");
Bill Richardsonabf05502010-07-01 10:22:06 -070084 return 1;
85 }
86
87 f = fopen(filename, "wb");
88 if (!f) {
Randall Spangler32a65262011-06-27 10:49:11 -070089 VbExError("Unable to open file %s\n", filename);
90 free(outbuf);
Bill Richardsonabf05502010-07-01 10:22:06 -070091 return 1;
92 }
93
94 if (1 != fwrite(&key->algorithm, sizeof(key->algorithm), 1, f)) {
Randall Spangler32a65262011-06-27 10:49:11 -070095 VbExError("Unable to write to file %s\n", filename);
Bill Richardsonabf05502010-07-01 10:22:06 -070096 fclose(f);
Randall Spangler32a65262011-06-27 10:49:11 -070097 free(outbuf);
Bill Richardsonabf05502010-07-01 10:22:06 -070098 unlink(filename); /* Delete any partial file */
99 }
100
101 if (1 != fwrite(outbuf, buflen, 1, f)) {
Randall Spangler32a65262011-06-27 10:49:11 -0700102 VbExError("Unable to write to file %s\n", filename);
Bill Richardsonabf05502010-07-01 10:22:06 -0700103 fclose(f);
104 unlink(filename); /* Delete any partial file */
Randall Spangler32a65262011-06-27 10:49:11 -0700105 free(outbuf);
Bill Richardsonabf05502010-07-01 10:22:06 -0700106 }
107
108 fclose(f);
Randall Spangler32a65262011-06-27 10:49:11 -0700109 free(outbuf);
Bill Richardsonabf05502010-07-01 10:22:06 -0700110 return 0;
111}
112
113VbPrivateKey* PrivateKeyRead(const char* filename) {
114 VbPrivateKey *key;
115 uint64_t filelen = 0;
116 uint8_t *buffer;
117 const unsigned char *start;
Gaurav Shah47b593d2010-08-17 15:48:22 -0700118
Bill Richardsonabf05502010-07-01 10:22:06 -0700119 buffer = ReadFile(filename, &filelen);
120 if (!buffer) {
Randall Spangler32a65262011-06-27 10:49:11 -0700121 VbExError("unable to read from file %s\n", filename);
Bill Richardsonabf05502010-07-01 10:22:06 -0700122 return 0;
123 }
124
Randall Spangler32a65262011-06-27 10:49:11 -0700125 key = (VbPrivateKey*)malloc(sizeof(VbPrivateKey));
Bill Richardsonabf05502010-07-01 10:22:06 -0700126 if (!key) {
Randall Spangler32a65262011-06-27 10:49:11 -0700127 VbExError("Unable to allocate VbPrivateKey\n");
128 free(buffer);
Bill Richardsonabf05502010-07-01 10:22:06 -0700129 return 0;
130 }
131
132 key->algorithm = *(typeof(key->algorithm) *)buffer;
133 start = buffer + sizeof(key->algorithm);
134
135 key->rsa_private_key = d2i_RSAPrivateKey(0, &start,
136 filelen - sizeof(key->algorithm));
137
138 if (!key->rsa_private_key) {
Randall Spangler32a65262011-06-27 10:49:11 -0700139 VbExError("Unable to parse RSA private key\n");
140 free(buffer);
141 free(key);
Bill Richardsonabf05502010-07-01 10:22:06 -0700142 return 0;
143 }
144
Randall Spangler32a65262011-06-27 10:49:11 -0700145 free(buffer);
Bill Richardsonabf05502010-07-01 10:22:06 -0700146 return key;
147}
148
149
Randall Spanglerd55c6452010-06-10 12:43:51 -0700150/* Allocate a new public key with space for a [key_size] byte key. */
Randall Spanglerd1836442010-06-10 09:59:04 -0700151VbPublicKey* PublicKeyAlloc(uint64_t key_size, uint64_t algorithm,
152 uint64_t version) {
Randall Spangler32a65262011-06-27 10:49:11 -0700153 VbPublicKey* key = (VbPublicKey*)malloc(sizeof(VbPublicKey) + key_size);
Randall Spanglerd1836442010-06-10 09:59:04 -0700154 if (!key)
155 return NULL;
156
157 key->algorithm = algorithm;
158 key->key_version = version;
159 key->key_size = key_size;
160 key->key_offset = sizeof(VbPublicKey);
161 return key;
162}
163
Randall Spanglerd55c6452010-06-10 12:43:51 -0700164VbPublicKey* PublicKeyReadKeyb(const char* filename, uint64_t algorithm,
165 uint64_t version) {
Randall Spanglerd1836442010-06-10 09:59:04 -0700166 VbPublicKey* key;
167 uint8_t* key_data;
168 uint64_t key_size;
Gaurav Shahd583a302011-03-25 14:02:13 -0700169 uint64_t expected_key_size;
Randall Spanglerd1836442010-06-10 09:59:04 -0700170
171 if (algorithm >= kNumAlgorithms) {
Bill Richardsonabf05502010-07-01 10:22:06 -0700172 VBDEBUG(("PublicKeyReadKeyb() called with invalid algorithm!\n"));
Randall Spanglerd1836442010-06-10 09:59:04 -0700173 return NULL;
174 }
175 if (version > 0xFFFF) {
176 /* Currently, TPM only supports 16-bit version */
Bill Richardsonabf05502010-07-01 10:22:06 -0700177 VBDEBUG(("PublicKeyReadKeyb() called with invalid version!\n"));
Randall Spanglerd1836442010-06-10 09:59:04 -0700178 return NULL;
179 }
180
Randall Spanglerd55c6452010-06-10 12:43:51 -0700181 key_data = ReadFile(filename, &key_size);
Randall Spanglerd1836442010-06-10 09:59:04 -0700182 if (!key_data)
183 return NULL;
184
Gaurav Shah47b593d2010-08-17 15:48:22 -0700185 if (!RSAProcessedKeySize(algorithm, &expected_key_size) ||
186 expected_key_size != key_size) {
Bill Richardsonabf05502010-07-01 10:22:06 -0700187 VBDEBUG(("PublicKeyReadKeyb() wrong key size for algorithm\n"));
Randall Spangler32a65262011-06-27 10:49:11 -0700188 free(key_data);
Randall Spanglerd55c6452010-06-10 12:43:51 -0700189 return NULL;
190 }
Randall Spanglerd1836442010-06-10 09:59:04 -0700191
192 key = PublicKeyAlloc(key_size, algorithm, version);
193 if (!key) {
Randall Spangler32a65262011-06-27 10:49:11 -0700194 free(key_data);
Randall Spanglerd1836442010-06-10 09:59:04 -0700195 return NULL;
196 }
197 Memcpy(GetPublicKeyData(key), key_data, key_size);
198
Randall Spangler32a65262011-06-27 10:49:11 -0700199 free(key_data);
Randall Spanglerd1836442010-06-10 09:59:04 -0700200 return key;
201}
Randall Spanglerd55c6452010-06-10 12:43:51 -0700202
203
204VbPublicKey* PublicKeyRead(const char* filename) {
205 VbPublicKey* key;
206 uint64_t file_size;
Gaurav Shahd583a302011-03-25 14:02:13 -0700207 uint64_t key_size;
Randall Spanglerd55c6452010-06-10 12:43:51 -0700208
209 key = (VbPublicKey*)ReadFile(filename, &file_size);
210 if (!key)
211 return NULL;
212
213 do {
214 /* Sanity-check key data */
215 if (0 != VerifyPublicKeyInside(key, file_size, key)) {
Bill Richardsonabf05502010-07-01 10:22:06 -0700216 VBDEBUG(("PublicKeyRead() not a VbPublicKey\n"));
Randall Spanglerd55c6452010-06-10 12:43:51 -0700217 break;
218 }
219 if (key->algorithm >= kNumAlgorithms) {
Bill Richardsonabf05502010-07-01 10:22:06 -0700220 VBDEBUG(("PublicKeyRead() invalid algorithm\n"));
Randall Spanglerd55c6452010-06-10 12:43:51 -0700221 break;
222 }
223 if (key->key_version > 0xFFFF) {
Bill Richardsonabf05502010-07-01 10:22:06 -0700224 VBDEBUG(("PublicKeyRead() invalid version\n"));
Randall Spanglerd55c6452010-06-10 12:43:51 -0700225 break; /* Currently, TPM only supports 16-bit version */
226 }
Gaurav Shah47b593d2010-08-17 15:48:22 -0700227 if (!RSAProcessedKeySize(key->algorithm, &key_size) ||
228 key_size != key->key_size) {
Bill Richardsonabf05502010-07-01 10:22:06 -0700229 VBDEBUG(("PublicKeyRead() wrong key size for algorithm\n"));
Randall Spanglerd55c6452010-06-10 12:43:51 -0700230 break;
231 }
232
233 /* Success */
234 return key;
235
236 } while(0);
237
238 /* Error */
Randall Spangler32a65262011-06-27 10:49:11 -0700239 free(key);
Randall Spanglerd55c6452010-06-10 12:43:51 -0700240 return NULL;
241}
242
Randall Spanglerd55c6452010-06-10 12:43:51 -0700243int PublicKeyWrite(const char* filename, const VbPublicKey* key) {
Randall Spangler6a97b3e2010-06-10 17:55:02 -0700244 VbPublicKey* kcopy;
245 int rv;
Randall Spanglerd55c6452010-06-10 12:43:51 -0700246
Randall Spangler6a97b3e2010-06-10 17:55:02 -0700247 /* Copy the key, so its data is contiguous with the header */
248 kcopy = PublicKeyAlloc(key->key_size, 0, 0);
249 if (!kcopy)
250 return 1;
251 if (0 != PublicKeyCopy(kcopy, key)) {
Randall Spangler32a65262011-06-27 10:49:11 -0700252 free(kcopy);
Randall Spangler6a97b3e2010-06-10 17:55:02 -0700253 return 1;
254 }
Randall Spanglerd55c6452010-06-10 12:43:51 -0700255
Randall Spangler6a97b3e2010-06-10 17:55:02 -0700256 /* Write the copy, then free it */
257 rv = WriteFile(filename, kcopy, kcopy->key_offset + kcopy->key_size);
Randall Spangler32a65262011-06-27 10:49:11 -0700258 free(kcopy);
Randall Spanglerd55c6452010-06-10 12:43:51 -0700259 return rv;
260}