| Index: host/lib/host_signature.c
|
| diff --git a/host/lib/host_signature.c b/host/lib/host_signature.c
|
| index c0d0f64f0b80d561eb897bec2d97f1f1d859dada..e00824fef0ab81c2b9c5118d8fa62d877001d60e 100644
|
| --- a/host/lib/host_signature.c
|
| +++ b/host/lib/host_signature.c
|
| @@ -14,6 +14,8 @@
|
|
|
| #include <stdio.h>
|
| #include <stdlib.h>
|
| +#include <sys/types.h>
|
| +#include <sys/wait.h>
|
| #include <unistd.h>
|
|
|
| #include "cryptolib.h"
|
| @@ -36,7 +38,7 @@ VbSignature* SignatureAlloc(uint64_t sig_size, uint64_t data_size) {
|
|
|
|
|
| void SignatureInit(VbSignature* sig, uint8_t* sig_data,
|
| - uint64_t sig_size, uint64_t data_size) {
|
| + uint64_t sig_size, uint64_t data_size) {
|
| sig->sig_offset = OffsetOf(sig, sig_data);
|
| sig->sig_size = sig_size;
|
| sig->data_size = data_size;
|
| @@ -77,7 +79,6 @@ VbSignature* CalculateChecksum(const uint8_t* data, uint64_t size) {
|
| return sig;
|
| }
|
|
|
| -
|
| VbSignature* CalculateSignature(const uint8_t* data, uint64_t size,
|
| const VbPrivateKey* key) {
|
|
|
| @@ -133,3 +134,150 @@ VbSignature* CalculateSignature(const uint8_t* data, uint64_t size,
|
| /* Return the signature */
|
| return sig;
|
| }
|
| +
|
| +/* 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.
|
| + */
|
| +int InvokeExternalSigner(uint64_t size,
|
| + const uint8_t* inbuf,
|
| + uint8_t* outbuf,
|
| + uint64_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;
|
| +
|
| + VBDEBUG(("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) {
|
| + VBDEBUG(("pipe() error\n"));
|
| + return -1;
|
| + }
|
| + if ((pid = fork()) < 0) {
|
| + VBDEBUG(("fork() error"));
|
| + 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) {
|
| + VBDEBUG(("write() error while providing input to external signer\n"));
|
| + rv = -1;
|
| + } else {
|
| + close(p_to_c[STDOUT_FILENO]); /* Send EOF to child (signer process). */
|
| + do {
|
| + n = read(c_to_p[STDIN_FILENO], outbuf, outbufsize);
|
| + outbuf += n;
|
| + outbufsize -= n;
|
| + } while (n > 0 && outbufsize);
|
| +
|
| + if (n < 0) {
|
| + VBDEBUG(("read() error while reading output from external signer\n"));
|
| + rv = -1;
|
| + }
|
| + }
|
| + if (waitpid(pid, NULL, 0) < 0) {
|
| + VBDEBUG(("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) {
|
| + VBDEBUG(("stdin dup2() failed (external signer)\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) {
|
| + VBDEBUG(("stdout dup2() failed (external signer)\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) {
|
| + VBDEBUG(("execl() of external signer failed\n"));
|
| + }
|
| + }
|
| + return rv;
|
| +}
|
| +
|
| +/* TODO(gauravsh): This could easily be integrated into CalculateSignature()
|
| + * since the code is almost a mirror - I have kept it as such to avoid changing
|
| + * the existing interface. */
|
| +VbSignature* CalculateSignature_external(const uint8_t* data, uint64_t size,
|
| + const char* key_file,
|
| + uint64_t key_algorithm,
|
| + const char* external_signer) {
|
| + uint8_t* digest;
|
| + uint64_t digest_size = hash_size_map[key_algorithm];
|
| +
|
| + const uint8_t* digestinfo = hash_digestinfo_map[key_algorithm];
|
| + uint64_t digestinfo_size = digestinfo_size_map[key_algorithm];
|
| +
|
| + uint8_t* signature_digest;
|
| + uint64_t signature_digest_len = digest_size + digestinfo_size;
|
| +
|
| + VbSignature* sig;
|
| + int rv;
|
| +
|
| + /* Calculate the digest */
|
| + /* TODO: rename param 3 of DigestBuf to hash_type */
|
| + digest = DigestBuf(data, size, hash_type_map[key_algorithm]);
|
| + if (!digest)
|
| + return NULL;
|
| +
|
| + /* Prepend the digest info to the digest */
|
| + signature_digest = Malloc(signature_digest_len);
|
| + if (!signature_digest) {
|
| + Free(digest);
|
| + return NULL;
|
| + }
|
| + Memcpy(signature_digest, digestinfo, digestinfo_size);
|
| + Memcpy(signature_digest + digestinfo_size, digest, digest_size);
|
| + Free(digest);
|
| +
|
| + /* Allocate output signature */
|
| + sig = SignatureAlloc(siglen_map[key_algorithm], size);
|
| + if (!sig) {
|
| + Free(signature_digest);
|
| + return NULL;
|
| + }
|
| +
|
| + /* Sign the signature_digest into our output buffer */
|
| + rv = InvokeExternalSigner(signature_digest_len, /* Input length */
|
| + signature_digest, /* Input data */
|
| + GetSignatureData(sig), /* Output sig */
|
| + (sizeof(VbSignature) + /* Max Output sig size. */
|
| + siglen_map[key_algorithm]) ,
|
| + key_file, /* Key file to use */
|
| + external_signer); /* External cmd to invoke */
|
| + Free(signature_digest);
|
| +
|
| + if (-1 == rv) {
|
| + VBDEBUG(("SignatureBuf(): RSA_private_encrypt() failed.\n"));
|
| + Free(sig);
|
| + return NULL;
|
| + }
|
| +
|
| + /* Return the signature */
|
| + return sig;
|
| +}
|
|
|