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