1 /* Copyright (c) 2011 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  * Host functions for keys.
6  */
7 
8 /* TODO: change all 'return 0', 'return 1' into meaningful return codes */
9 
10 #include <openssl/pem.h>
11 
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <unistd.h>
15 
16 #include "cryptolib.h"
17 #include "host_common.h"
18 #include "host_key.h"
19 #include "host_misc.h"
20 #include "vboot_common.h"
21 
22 
PrivateKeyReadPem(const char * filename,uint64_t algorithm)23 VbPrivateKey* PrivateKeyReadPem(const char* filename, uint64_t algorithm) {
24 
25   VbPrivateKey* key;
26   RSA* rsa_key;
27   FILE* f;
28 
29   if (algorithm >= kNumAlgorithms) {
30     VBDEBUG(("%s() called with invalid algorithm!\n", __FUNCTION__));
31     return NULL;
32   }
33 
34   /* Read private key */
35   f = fopen(filename, "r");
36   if (!f) {
37     VBDEBUG(("%s(): Couldn't open key file: %s\n", __FUNCTION__, filename));
38     return NULL;
39   }
40   rsa_key = PEM_read_RSAPrivateKey(f, NULL, NULL, NULL);
41   fclose(f);
42   if (!rsa_key) {
43     VBDEBUG(("%s(): Couldn't read private key from file: %s\n", __FUNCTION__,
44              filename));
45     return NULL;
46   }
47 
48   /* Store key and algorithm in our struct */
49   key = (VbPrivateKey*)malloc(sizeof(VbPrivateKey));
50   if (!key) {
51     RSA_free(rsa_key);
52     return NULL;
53   }
54   key->rsa_private_key = rsa_key;
55   key->algorithm = algorithm;
56 
57   /* Return the key */
58   return key;
59 }
60 
61 
PrivateKeyFree(VbPrivateKey * key)62 void PrivateKeyFree(VbPrivateKey* key) {
63   if (!key)
64     return;
65   if (key->rsa_private_key)
66     RSA_free(key->rsa_private_key);
67   free(key);
68 }
69 
70 
71 /* Write a private key to a file in .vbprivk format. */
PrivateKeyWrite(const char * filename,const VbPrivateKey * key)72 int PrivateKeyWrite(const char* filename, const VbPrivateKey* key) {
73   uint8_t *outbuf = 0;
74   int buflen;
75   FILE *f;
76 
77   buflen = i2d_RSAPrivateKey(key->rsa_private_key, &outbuf);
78   if (buflen <= 0) {
79     VbExError("Unable to write private key buffer\n");
80     return 1;
81   }
82 
83   f = fopen(filename, "wb");
84   if (!f) {
85     VbExError("Unable to open file %s\n", filename);
86     free(outbuf);
87     return 1;
88   }
89 
90   if (1 != fwrite(&key->algorithm, sizeof(key->algorithm), 1, f)) {
91     VbExError("Unable to write to file %s\n", filename);
92     fclose(f);
93     free(outbuf);
94     unlink(filename);  /* Delete any partial file */
95   }
96 
97   if (1 != fwrite(outbuf, buflen, 1, f)) {
98     VbExError("Unable to write to file %s\n", filename);
99     fclose(f);
100     unlink(filename);  /* Delete any partial file */
101     free(outbuf);
102   }
103 
104   fclose(f);
105   free(outbuf);
106   return 0;
107 }
108 
PrivateKeyRead(const char * filename)109 VbPrivateKey* PrivateKeyRead(const char* filename) {
110   VbPrivateKey *key;
111   uint64_t filelen = 0;
112   uint8_t *buffer;
113   const unsigned char *start;
114 
115   buffer = ReadFile(filename, &filelen);
116   if (!buffer) {
117     VbExError("unable to read from file %s\n", filename);
118     return 0;
119   }
120 
121   key = (VbPrivateKey*)malloc(sizeof(VbPrivateKey));
122   if (!key) {
123     VbExError("Unable to allocate VbPrivateKey\n");
124     free(buffer);
125     return 0;
126   }
127 
128   key->algorithm = *(typeof(key->algorithm) *)buffer;
129   start = buffer + sizeof(key->algorithm);
130 
131   key->rsa_private_key = d2i_RSAPrivateKey(0, &start,
132                                            filelen - sizeof(key->algorithm));
133 
134   if (!key->rsa_private_key) {
135     VbExError("Unable to parse RSA private key\n");
136     free(buffer);
137     free(key);
138     return 0;
139   }
140 
141   free(buffer);
142   return key;
143 }
144 
145 
146 /* Allocate a new public key with space for a [key_size] byte key. */
PublicKeyAlloc(uint64_t key_size,uint64_t algorithm,uint64_t version)147 VbPublicKey* PublicKeyAlloc(uint64_t key_size, uint64_t algorithm,
148                             uint64_t version) {
149   VbPublicKey* key = (VbPublicKey*)malloc(sizeof(VbPublicKey) + key_size);
150   if (!key)
151     return NULL;
152 
153   key->algorithm = algorithm;
154   key->key_version = version;
155   key->key_size = key_size;
156   key->key_offset = sizeof(VbPublicKey);
157   return key;
158 }
159 
PublicKeyReadKeyb(const char * filename,uint64_t algorithm,uint64_t version)160 VbPublicKey* PublicKeyReadKeyb(const char* filename, uint64_t algorithm,
161                                uint64_t version) {
162   VbPublicKey* key;
163   uint8_t* key_data;
164   uint64_t key_size;
165   uint64_t expected_key_size;
166 
167   if (algorithm >= kNumAlgorithms) {
168     VBDEBUG(("PublicKeyReadKeyb() called with invalid algorithm!\n"));
169     return NULL;
170   }
171   if (version > 0xFFFF) {
172     /* Currently, TPM only supports 16-bit version */
173     VBDEBUG(("PublicKeyReadKeyb() called with invalid version!\n"));
174     return NULL;
175   }
176 
177   key_data = ReadFile(filename, &key_size);
178   if (!key_data)
179     return NULL;
180 
181   if (!RSAProcessedKeySize(algorithm, &expected_key_size) ||
182       expected_key_size != key_size) {
183     VBDEBUG(("PublicKeyReadKeyb() wrong key size for algorithm\n"));
184     free(key_data);
185     return NULL;
186   }
187 
188   key = PublicKeyAlloc(key_size, algorithm, version);
189   if (!key) {
190     free(key_data);
191     return NULL;
192   }
193   Memcpy(GetPublicKeyData(key), key_data, key_size);
194 
195   free(key_data);
196   return key;
197 }
198 
199 
PublicKeyLooksOkay(VbPublicKey * key,uint64_t file_size)200 int PublicKeyLooksOkay(VbPublicKey *key, uint64_t file_size)
201 {
202   uint64_t key_size;
203 
204   /* Sanity-check key data */
205   if (0 != VerifyPublicKeyInside(key, file_size, key)) {
206     VBDEBUG(("PublicKeyRead() not a VbPublicKey\n"));
207     return 0;
208   }
209   if (key->algorithm >= kNumAlgorithms) {
210     VBDEBUG(("PublicKeyRead() invalid algorithm\n"));
211     return 0;
212   }
213   if (key->key_version > 0xFFFF) {
214     VBDEBUG(("PublicKeyRead() invalid version\n"));
215     return 0;  /* Currently, TPM only supports 16-bit version */
216   }
217   if (!RSAProcessedKeySize(key->algorithm, &key_size) ||
218       key_size != key->key_size) {
219     VBDEBUG(("PublicKeyRead() wrong key size for algorithm\n"));
220     return 0;
221   }
222 
223   /* Success */
224   return 1;
225 }
226 
227 
228 
PublicKeyRead(const char * filename)229 VbPublicKey* PublicKeyRead(const char* filename) {
230   VbPublicKey* key;
231   uint64_t file_size;
232 
233   key = (VbPublicKey*)ReadFile(filename, &file_size);
234   if (!key)
235     return NULL;
236 
237   if (PublicKeyLooksOkay(key, file_size))
238       return key;
239 
240   /* Error */
241   free(key);
242   return NULL;
243 }
244 
PublicKeyWrite(const char * filename,const VbPublicKey * key)245 int PublicKeyWrite(const char* filename, const VbPublicKey* key) {
246   VbPublicKey* kcopy;
247   int rv;
248 
249   /* Copy the key, so its data is contiguous with the header */
250   kcopy = PublicKeyAlloc(key->key_size, 0, 0);
251   if (!kcopy)
252     return 1;
253   if (0 != PublicKeyCopy(kcopy, key)) {
254     free(kcopy);
255     return 1;
256   }
257 
258   /* Write the copy, then free it */
259   rv = WriteFile(filename, kcopy, kcopy->key_offset + kcopy->key_size);
260   free(kcopy);
261   return rv;
262 }
263