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 signature generation.
      6  */
      7 
      8 /* TODO: change all 'return 0', 'return 1' into meaningful return codes */
      9 
     10 #include <openssl/rsa.h>
     11 
     12 #include <stdio.h>
     13 #include <stdlib.h>
     14 #include <sys/types.h>
     15 #include <sys/wait.h>
     16 #include <unistd.h>
     17 
     18 #include "cryptolib.h"
     19 #include "file_keys.h"
     20 #include "host_common.h"
     21 #include "vboot_common.h"
     22 
     23 
     24 VbSignature* SignatureAlloc(uint64_t sig_size, uint64_t data_size) {
     25   VbSignature* sig = (VbSignature*)malloc(sizeof(VbSignature) + sig_size);
     26   if (!sig)
     27     return NULL;
     28 
     29   sig->sig_offset = sizeof(VbSignature);
     30   sig->sig_size = sig_size;
     31   sig->data_size = data_size;
     32   return sig;
     33 }
     34 
     35 
     36 void SignatureInit(VbSignature* sig, uint8_t* sig_data,
     37                    uint64_t sig_size, uint64_t data_size) {
     38   sig->sig_offset = OffsetOf(sig, sig_data);
     39   sig->sig_size = sig_size;
     40   sig->data_size = data_size;
     41 }
     42 
     43 
     44 int SignatureCopy(VbSignature* dest, const VbSignature* src) {
     45   if (dest->sig_size < src->sig_size)
     46     return 1;
     47   dest->sig_size = src->sig_size;
     48   dest->data_size = src->data_size;
     49   Memcpy(GetSignatureData(dest), GetSignatureDataC(src), src->sig_size);
     50   return 0;
     51 }
     52 
     53 
     54 VbSignature* CalculateChecksum(const uint8_t* data, uint64_t size) {
     55 
     56   uint8_t* header_checksum;
     57   VbSignature* sig;
     58 
     59   header_checksum = DigestBuf(data, size, SHA512_DIGEST_ALGORITHM);
     60   if (!header_checksum)
     61     return NULL;
     62 
     63   sig = SignatureAlloc(SHA512_DIGEST_SIZE, 0);
     64   if (!sig) {
     65     VbExFree(header_checksum);
     66     return NULL;
     67   }
     68   sig->sig_offset = sizeof(VbSignature);
     69   sig->sig_size = SHA512_DIGEST_SIZE;
     70   sig->data_size = size;
     71 
     72   /* Signature data immediately follows the header */
     73   Memcpy(GetSignatureData(sig), header_checksum, SHA512_DIGEST_SIZE);
     74   VbExFree(header_checksum);
     75   return sig;
     76 }
     77 
     78 VbSignature* CalculateHash(const uint8_t* data, uint64_t size,
     79                            const VbPrivateKey* key) {
     80   uint8_t* digest = NULL;
     81   int digest_size = hash_size_map[key->algorithm];
     82   VbSignature* sig = NULL;
     83 
     84   /* Calculate the digest */
     85   digest = DigestBuf(data, size, key->algorithm);
     86   if (!digest)
     87     return NULL;
     88 
     89   /* Allocate output signature */
     90   sig = SignatureAlloc(digest_size, size);
     91   if (!sig) {
     92     free(digest);
     93     return NULL;
     94   }
     95 
     96   /* The digest itself is the signature data */
     97   Memcpy(GetSignatureData(sig), digest, digest_size);
     98   free(digest);
     99 
    100   /* Return the signature */
    101   return sig;
    102 }
    103 
    104 VbSignature* CalculateSignature(const uint8_t* data, uint64_t size,
    105                                 const VbPrivateKey* key) {
    106 
    107   uint8_t* digest;
    108   int digest_size = hash_size_map[key->algorithm];
    109 
    110   const uint8_t* digestinfo = hash_digestinfo_map[key->algorithm];
    111   int digestinfo_size = digestinfo_size_map[key->algorithm];
    112 
    113   uint8_t* signature_digest;
    114   int signature_digest_len = digest_size + digestinfo_size;
    115 
    116   VbSignature* sig;
    117   int rv;
    118 
    119   /* Calculate the digest */
    120   /* TODO: rename param 3 of DigestBuf to hash_type */
    121   digest = DigestBuf(data, size, hash_type_map[key->algorithm]);
    122   if (!digest)
    123     return NULL;
    124 
    125   /* Prepend the digest info to the digest */
    126   signature_digest = malloc(signature_digest_len);
    127   if (!signature_digest) {
    128     VbExFree(digest);
    129     return NULL;
    130   }
    131   Memcpy(signature_digest, digestinfo, digestinfo_size);
    132   Memcpy(signature_digest + digestinfo_size, digest, digest_size);
    133   VbExFree(digest);
    134 
    135   /* Allocate output signature */
    136   sig = SignatureAlloc(siglen_map[key->algorithm], size);
    137   if (!sig) {
    138     free(signature_digest);
    139     return NULL;
    140   }
    141 
    142   /* Sign the signature_digest into our output buffer */
    143   rv = RSA_private_encrypt(signature_digest_len,   /* Input length */
    144                            signature_digest,       /* Input data */
    145                            GetSignatureData(sig),  /* Output sig */
    146                            key->rsa_private_key,   /* Key to use */
    147                            RSA_PKCS1_PADDING);     /* Padding to use */
    148   free(signature_digest);
    149 
    150   if (-1 == rv) {
    151     VBDEBUG(("SignatureBuf(): RSA_private_encrypt() failed.\n"));
    152     free(sig);
    153     return NULL;
    154   }
    155 
    156   /* Return the signature */
    157   return sig;
    158 }
    159 
    160 /* Invoke [external_signer] command with [pem_file] as
    161  * an argument, contents of [inbuf] passed redirected to stdin,
    162  * and the stdout of the command is put back into [outbuf].
    163  * Returns -1 on error, 0 on success.
    164  */
    165 int InvokeExternalSigner(uint64_t size,
    166                          const uint8_t* inbuf,
    167                          uint8_t* outbuf,
    168                          uint64_t outbufsize,
    169                          const char* pem_file,
    170                          const char* external_signer) {
    171 
    172   int rv = 0, n;
    173   int p_to_c[2], c_to_p[2];  /* pipe descriptors */
    174   pid_t pid;
    175 
    176   VBDEBUG(("Will invoke \"%s %s\" to perform signing.\n"
    177            "Input to the signer will be provided on standard in.\n"
    178            "Output of the signer will be read from standard out.\n",
    179            external_signer, pem_file));
    180 
    181   /* Need two pipes since we want to invoke the external_signer as
    182    * a co-process writing to its stdin and reading from its stdout. */
    183   if (pipe(p_to_c) < 0 || pipe(c_to_p) < 0) {
    184     VBDEBUG(("pipe() error\n"));
    185     return -1;
    186   }
    187   if ((pid = fork()) < 0) {
    188     VBDEBUG(("fork() error"));
    189     return -1;
    190   }
    191   else if (pid > 0) {  /* Parent. */
    192     close(p_to_c[STDIN_FILENO]);
    193     close(c_to_p[STDOUT_FILENO]);
    194 
    195     /* We provide input to the child process (external signer). */
    196     if (write(p_to_c[STDOUT_FILENO], inbuf, size) != size) {
    197       VBDEBUG(("write() error while providing input to external signer\n"));
    198       rv = -1;
    199     } else {
    200       close(p_to_c[STDOUT_FILENO]);  /* Send EOF to child (signer process). */
    201       do {
    202         n = read(c_to_p[STDIN_FILENO], outbuf, outbufsize);
    203         outbuf += n;
    204         outbufsize -= n;
    205       } while (n > 0 && outbufsize);
    206 
    207       if (n < 0) {
    208         VBDEBUG(("read() error while reading output from external signer\n"));
    209         rv = -1;
    210       }
    211     }
    212     if (waitpid(pid, NULL, 0) < 0) {
    213       VBDEBUG(("waitpid() error\n"));
    214       rv = -1;
    215     }
    216   } else {  /* Child. */
    217     close (p_to_c[STDOUT_FILENO]);
    218     close (c_to_p[STDIN_FILENO]);
    219     /* Map the stdin to the first pipe (this pipe gets input
    220      * from the parent) */
    221     if (STDIN_FILENO != p_to_c[STDIN_FILENO]) {
    222       if (dup2(p_to_c[STDIN_FILENO], STDIN_FILENO) != STDIN_FILENO) {
    223         VBDEBUG(("stdin dup2() failed (external signer)\n"));
    224         close(p_to_c[0]);
    225         return -1;
    226       }
    227     }
    228     /* Map the stdout to the second pipe (this pipe sends back
    229      * signer output to the parent) */
    230     if (STDOUT_FILENO != c_to_p[STDOUT_FILENO]) {
    231       if (dup2(c_to_p[STDOUT_FILENO], STDOUT_FILENO) != STDOUT_FILENO) {
    232         VBDEBUG(("stdout dup2() failed (external signer)\n"));
    233         close(c_to_p[STDOUT_FILENO]);
    234         return -1;
    235       }
    236     }
    237     /* External signer is invoked here. */
    238     if (execl(external_signer, external_signer, pem_file, (char *) 0) < 0) {
    239       VBDEBUG(("execl() of external signer failed\n"));
    240     }
    241   }
    242   return rv;
    243 }
    244 
    245 /* TODO(gauravsh): This could easily be integrated into CalculateSignature()
    246  * since the code is almost a mirror - I have kept it as such to avoid changing
    247  * the existing interface. */
    248 VbSignature* CalculateSignature_external(const uint8_t* data, uint64_t size,
    249                                          const char* key_file,
    250                                          uint64_t key_algorithm,
    251                                          const char* external_signer) {
    252   uint8_t* digest;
    253   uint64_t digest_size = hash_size_map[key_algorithm];
    254 
    255   const uint8_t* digestinfo = hash_digestinfo_map[key_algorithm];
    256   uint64_t digestinfo_size = digestinfo_size_map[key_algorithm];
    257 
    258   uint8_t* signature_digest;
    259   uint64_t signature_digest_len = digest_size + digestinfo_size;
    260 
    261   VbSignature* sig;
    262   int rv;
    263 
    264   /* Calculate the digest */
    265   /* TODO: rename param 3 of DigestBuf to hash_type */
    266   digest = DigestBuf(data, size, hash_type_map[key_algorithm]);
    267   if (!digest)
    268     return NULL;
    269 
    270   /* Prepend the digest info to the digest */
    271   signature_digest = malloc(signature_digest_len);
    272   if (!signature_digest) {
    273     free(digest);
    274     return NULL;
    275   }
    276   Memcpy(signature_digest, digestinfo, digestinfo_size);
    277   Memcpy(signature_digest + digestinfo_size, digest, digest_size);
    278   free(digest);
    279 
    280   /* Allocate output signature */
    281   sig = SignatureAlloc(siglen_map[key_algorithm], size);
    282   if (!sig) {
    283     free(signature_digest);
    284     return NULL;
    285   }
    286 
    287   /* Sign the signature_digest into our output buffer */
    288   rv = InvokeExternalSigner(signature_digest_len, /* Input length */
    289                             signature_digest,     /* Input data */
    290                             GetSignatureData(sig), /* Output sig */
    291                             siglen_map[key_algorithm], /* Max Output sig size */
    292                             key_file,             /* Key file to use */
    293                             external_signer);     /* External cmd to invoke */
    294   free(signature_digest);
    295 
    296   if (-1 == rv) {
    297     VBDEBUG(("SignatureBuf(): RSA_private_encrypt() failed.\n"));
    298     free(sig);
    299     return NULL;
    300   }
    301 
    302   /* Return the signature */
    303   return sig;
    304 }
    305