1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
|
/* Copyright 2011 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* Host functions for signature generation.
*/
/* TODO: change all 'return 0', 'return 1' into meaningful return codes */
#include <openssl/rsa.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include "2common.h"
#include "2rsa.h"
#include "2sha.h"
#include "2sysincludes.h"
#include "host_common.h"
#include "host_signature21.h"
/* Invoke [external_signer] command with [pem_file] as an argument, contents of
* [inbuf] passed redirected to stdin, and the stdout of the command is put
* back into [outbuf]. Returns -1 on error, 0 on success.
*/
static int sign_external(uint32_t size, const uint8_t *inbuf, uint8_t *outbuf,
uint32_t outbufsize, const char *pem_file,
const char *external_signer)
{
int rv = 0, n;
int p_to_c[2], c_to_p[2]; /* pipe descriptors */
pid_t pid;
VB2_DEBUG("Will invoke \"%s %s\" to perform signing.\n"
"Input to the signer will be provided on standard in.\n"
"Output of the signer will be read from standard out.\n",
external_signer, pem_file);
/* Need two pipes since we want to invoke the external_signer as
* a co-process writing to its stdin and reading from its stdout. */
if (pipe(p_to_c) < 0 || pipe(c_to_p) < 0) {
VB2_DEBUG("pipe() error\n");
return -1;
}
if ((pid = fork()) < 0) {
VB2_DEBUG("fork() error\n");
return -1;
} else if (pid > 0) { /* Parent. */
close(p_to_c[STDIN_FILENO]);
close(c_to_p[STDOUT_FILENO]);
/* We provide input to the child process (external signer). */
if (write(p_to_c[STDOUT_FILENO], inbuf, size) != size) {
VB2_DEBUG("write() error\n");
rv = -1;
} else {
/* Send EOF to child (signer process). */
close(p_to_c[STDOUT_FILENO]);
do {
n = read(c_to_p[STDIN_FILENO], outbuf,
outbufsize);
outbuf += n;
outbufsize -= n;
} while (n > 0 && outbufsize);
if (n < 0) {
VB2_DEBUG("read() error\n");
rv = -1;
}
}
if (waitpid(pid, NULL, 0) < 0) {
VB2_DEBUG("waitpid() error\n");
rv = -1;
}
} else { /* Child. */
close (p_to_c[STDOUT_FILENO]);
close (c_to_p[STDIN_FILENO]);
/* Map the stdin to the first pipe (this pipe gets input
* from the parent) */
if (STDIN_FILENO != p_to_c[STDIN_FILENO]) {
if (dup2(p_to_c[STDIN_FILENO], STDIN_FILENO) !=
STDIN_FILENO) {
VB2_DEBUG("stdin dup2() failed\n");
close(p_to_c[0]);
return -1;
}
}
/* Map the stdout to the second pipe (this pipe sends back
* signer output to the parent) */
if (STDOUT_FILENO != c_to_p[STDOUT_FILENO]) {
if (dup2(c_to_p[STDOUT_FILENO], STDOUT_FILENO) !=
STDOUT_FILENO) {
VB2_DEBUG("stdout dup2() failed\n");
close(c_to_p[STDOUT_FILENO]);
return -1;
}
}
/* External signer is invoked here. */
if (execl(external_signer, external_signer, pem_file,
(char *) 0) < 0) {
VB2_DEBUG("execl() of external signer failed\n");
}
}
return rv;
}
struct vb2_signature *vb2_external_signature(const uint8_t *data, uint32_t size,
const char *key_file,
uint32_t key_algorithm,
const char *external_signer)
{
struct vb2_hash hash;
/* Calculate the digest */
if (VB2_SUCCESS != vb2_hash_calculate(false, data, size,
vb2_crypto_to_hash(key_algorithm),
&hash))
return NULL;
uint32_t digest_info_size = 0;
const uint8_t *digest_info = NULL;
if (VB2_SUCCESS != vb2_digest_info(hash.algo,
&digest_info, &digest_info_size))
return NULL;
int digest_size = vb2_digest_size(hash.algo);
uint8_t *signature_digest;
uint64_t signature_digest_len = digest_size + digest_info_size;
int rv;
/* Prepend the digest info to the digest */
signature_digest = calloc(signature_digest_len, 1);
if (!signature_digest)
return NULL;
memcpy(signature_digest, digest_info, digest_info_size);
memcpy(signature_digest + digest_info_size, hash.raw, digest_size);
/* Allocate output signature */
uint32_t sig_size =
vb2_rsa_sig_size(vb2_crypto_to_signature(key_algorithm));
struct vb2_signature *sig = vb2_alloc_signature(sig_size, size);
if (!sig) {
free(signature_digest);
return NULL;
}
/* Sign the signature_digest into our output buffer */
rv = sign_external(signature_digest_len, /* Input length */
signature_digest, /* Input data */
vb2_signature_data_mutable(sig), /* Output sig */
sig_size, /* Max Output sig size */
key_file, /* Key file to use */
external_signer); /* External cmd to invoke */
free(signature_digest);
if (-1 == rv) {
VB2_DEBUG("RSA_private_encrypt() failed.\n");
free(sig);
return NULL;
}
/* Return the signature */
return sig;
}
|