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; |
+} |