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