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
24VbSignature* 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
36void 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
44int 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
54VbSignature* 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
78VbSignature* 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
104VbSignature* 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 */
165int 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. */
248VbSignature* 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