Home | History | Annotate | Download | only in lib
      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 
     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 
     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. */
     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 
    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. */
    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 
    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 
    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 
    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 
    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