• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
SignatureAlloc(uint64_t sig_size,uint64_t data_size)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 
SignatureInit(VbSignature * sig,uint8_t * sig_data,uint64_t sig_size,uint64_t data_size)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 
SignatureCopy(VbSignature * dest,const VbSignature * src)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 
CalculateChecksum(const uint8_t * data,uint64_t size)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 
CalculateHash(const uint8_t * data,uint64_t size,const VbPrivateKey * key)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 
CalculateSignature(const uint8_t * data,uint64_t size,const VbPrivateKey * key)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  */
InvokeExternalSigner(uint64_t size,const uint8_t * inbuf,uint8_t * outbuf,uint64_t outbufsize,const char * pem_file,const char * external_signer)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. */
CalculateSignature_external(const uint8_t * data,uint64_t size,const char * key_file,uint64_t key_algorithm,const char * external_signer)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