Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(244)

Unified Diff: host/lib/host_signature.c

Issue 4194003: Add support for using external signing application and .pem private key files to vbutil_keyblock. (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/vboot_reference.git
Patch Set: fix read() bug Created 10 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « host/lib/host_keyblock.c ('k') | tests/external_rsa_signer.sh » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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;
+}
« no previous file with comments | « host/lib/host_keyblock.c ('k') | tests/external_rsa_signer.sh » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698