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 23VbPrivateKey* 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 62void 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. */ 72int 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 109VbPrivateKey* 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. */ 147VbPublicKey* 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 160VbPublicKey* 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 200int 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 229VbPublicKey* 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 245int 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