diff options
Diffstat (limited to 'host')
-rw-r--r-- | host/Makefile | 5 | ||||
-rw-r--r-- | host/include/file_keys.h | 43 | ||||
-rw-r--r-- | host/include/signature_digest.h | 35 | ||||
-rw-r--r-- | host/lib/file_keys.c | 121 | ||||
-rw-r--r-- | host/lib/signature_digest.c | 74 | ||||
-rw-r--r-- | host/linktest/main.c | 13 |
6 files changed, 289 insertions, 2 deletions
diff --git a/host/Makefile b/host/Makefile index 7f1c9f15..29b8231c 100644 --- a/host/Makefile +++ b/host/Makefile @@ -14,12 +14,13 @@ INCLUDES += \ # find ./lib -iname '*.c' | sort ALL_SRCS = \ + ./lib/file_keys.c \ ./lib/host_common.c \ ./lib/host_key.c \ ./lib/host_keyblock.c \ ./lib/host_misc.c \ - ./lib/host_signature.c - + ./lib/host_signature.c \ + ./lib/signature_digest.c test : $(HOSTLIB) $(CC) $(CFLAGS) $(INCLUDES) -o $(BUILD_ROOT)/a.out $(TESTDIR)/main.c \ diff --git a/host/include/file_keys.h b/host/include/file_keys.h new file mode 100644 index 00000000..285a3e5b --- /dev/null +++ b/host/include/file_keys.h @@ -0,0 +1,43 @@ +/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Utility functions for file and key handling. + */ + +#ifndef VBOOT_REFERENCE_FILE_KEYS_H_ +#define VBOOT_REFERENCE_FILE_KEYS_H_ + +#include "cryptolib.h" + +/* Read file named [input_file] into a buffer and stores the length into + * [len]. + * + * Returns a pointer to the buffer. Caller owns the returned pointer and + * must free it. + */ +uint8_t* BufferFromFile(const char* input_file, uint64_t* len); + +/* Read a pre-processed RSA Public Key from file [input_file]. + * + * Returns a pointer to the read key. Caller owns the returned pointer and + * must free it. + */ +RSAPublicKey* RSAPublicKeyFromFile(const char* input_file); + +/* Returns the appropriate digest for the data in [input_file] + * based on the signature [algorithm]. + * Caller owns the returned digest and must free it. + */ +uint8_t* DigestFile(char* input_file, int sig_algorithm); + +/* Helper function to invoke external program to calculate signature on + * [input_file] using private key [key_file] and signature algorithm + * [algorithm]. + * + * Returns the signature. Caller owns the buffer and must Free() it. + */ +uint8_t* SignatureFile(const char* input_file, const char* key_file, + int algorithm); + +#endif /* VBOOT_REFERENCE_FILE_KEYS_H_ */ diff --git a/host/include/signature_digest.h b/host/include/signature_digest.h new file mode 100644 index 00000000..55662b94 --- /dev/null +++ b/host/include/signature_digest.h @@ -0,0 +1,35 @@ +/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef VBOOT_REFERENCE_SIGNATURE_DIGEST_H_ +#define VBOOT_REFERENCE_SIGNATURE_DIGEST_H_ + +#include <inttypes.h> + +/* Returns a buffer with DigestInfo (which depends on [algorithm]) + * prepended to [digest]. + */ +uint8_t* PrependDigestInfo(int algorithm, uint8_t* digest); + +/* Function that outputs the message digest of the contents of a buffer in a + * format that can be used as input to OpenSSL for an RSA signature. + * Needed until the stable OpenSSL release supports SHA-256/512 digests for + * RSA signatures. + * + * Returns DigestInfo || Digest where DigestInfo is the OID depending on the + * choice of the hash algorithm (see padding.c). Caller owns the returned + * pointer and must Free() it. + */ +uint8_t* SignatureDigest(const uint8_t* buf, uint64_t len, int algorithm); + +/* Calculates the signature on a buffer [buf] of length [len] using + * the private RSA key file from [key_file] and signature algorithm + * [algorithm]. + * + * Returns the signature. Caller owns the buffer and must Free() it. + */ +uint8_t* SignatureBuf(const uint8_t* buf, uint64_t len, const char* key_file, + int algorithm); +#endif /* VBOOT_REFERENCE_SIGNATURE_DIGEST_H_ */ diff --git a/host/lib/file_keys.c b/host/lib/file_keys.c new file mode 100644 index 00000000..c7774306 --- /dev/null +++ b/host/lib/file_keys.c @@ -0,0 +1,121 @@ +/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Utility functions for file and key handling. + */ + +#include "file_keys.h" + +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include "cryptolib.h" +#include "signature_digest.h" +#include "utility.h" + +uint8_t* BufferFromFile(const char* input_file, uint64_t* len) { + int fd; + struct stat stat_fd; + uint8_t* buf = NULL; + + if ((fd = open(input_file, O_RDONLY)) == -1) { + debug("Couldn't open file %s\n", input_file); + return NULL; + } + + if (-1 == fstat(fd, &stat_fd)) { + debug("Couldn't stat file %s\n", input_file); + return NULL; + } + *len = stat_fd.st_size; + + buf = (uint8_t*) Malloc(*len); + if (!buf) { + error("Couldn't allocate %ld bytes for file %s\n", *len, input_file); + return NULL; + } + + if (*len != read(fd, buf, *len)) { + debug("Couldn't read file %s into a buffer\n", input_file); + return NULL; + } + + close(fd); + return buf; +} + +RSAPublicKey* RSAPublicKeyFromFile(const char* input_file) { + uint64_t len; + RSAPublicKey* key = NULL; + uint8_t* buf = BufferFromFile(input_file, &len); + if (buf) + key = RSAPublicKeyFromBuf(buf, len); + Free(buf); + return key; +} + +uint8_t* DigestFile(char* input_file, int sig_algorithm) { + int input_fd, len; + uint8_t data[SHA1_BLOCK_SIZE]; + uint8_t* digest = NULL; + DigestContext ctx; + + if( (input_fd = open(input_file, O_RDONLY)) == -1 ) { + debug("Couldn't open %s\n", input_file); + return NULL; + } + DigestInit(&ctx, sig_algorithm); + while ( (len = read(input_fd, data, SHA1_BLOCK_SIZE)) == + SHA1_BLOCK_SIZE) + DigestUpdate(&ctx, data, len); + if (len != -1) + DigestUpdate(&ctx, data, len); + digest = DigestFinal(&ctx); + close(input_fd); + return digest; +} + +uint8_t* SignatureFile(const char* input_file, const char* key_file, + int algorithm) { + char* sign_utility = "./sign_data.sh"; + char* cmd; /* Command line to invoke. */ + int cmd_len; + FILE* cmd_out; /* File descriptor to command output. */ + uint8_t* signature = NULL; + int signature_size = siglen_map[algorithm]; + + /* Build command line: + * sign_data.sh <algorithm> <key file> <input file> + */ + cmd_len = (strlen(sign_utility) + 1 + /* +1 for space. */ + 2 + 1 + /* For [algorithm]. */ + strlen(key_file) + 1 + /* +1 for space. */ + strlen(input_file) + + 1); /* For the trailing '\0'. */ + cmd = (char*) Malloc(cmd_len); + snprintf(cmd, cmd_len, "%s %d %s %s", sign_utility, algorithm, key_file, + input_file); + cmd_out = popen(cmd, "r"); + Free(cmd); + if (!cmd_out) { + debug("Couldn't execute: %s\n", cmd); + return NULL; + } + + signature = (uint8_t*) Malloc(signature_size); + if (fread(signature, signature_size, 1, cmd_out) != 1) { + debug("Couldn't read signature.\n"); + pclose(cmd_out); + Free(signature); + return NULL; + } + + pclose(cmd_out); + return signature; +} diff --git a/host/lib/signature_digest.c b/host/lib/signature_digest.c new file mode 100644 index 00000000..4dba95a6 --- /dev/null +++ b/host/lib/signature_digest.c @@ -0,0 +1,74 @@ +/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "signature_digest.h" +#define OPENSSL_NO_SHA +#include <openssl/engine.h> +#include <openssl/pem.h> +#include <openssl/rsa.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include "cryptolib.h" +#include "utility.h" + +uint8_t* PrependDigestInfo(int algorithm, uint8_t* digest) { + const int digest_size = hash_size_map[algorithm]; + const int digestinfo_size = digestinfo_size_map[algorithm]; + const uint8_t* digestinfo = hash_digestinfo_map[algorithm]; + uint8_t* p = Malloc(digestinfo_size + digest_size); + Memcpy(p, digestinfo, digestinfo_size); + Memcpy(p + digestinfo_size, digest, digest_size); + return p; +} + +uint8_t* SignatureDigest(const uint8_t* buf, uint64_t len, int algorithm) { + uint8_t* info_digest = NULL; + uint8_t* digest = NULL; + + if (algorithm >= kNumAlgorithms) { + debug("SignatureDigest() called with invalid algorithm!\n"); + } else if ((digest = DigestBuf(buf, len, algorithm))) { + info_digest = PrependDigestInfo(algorithm, digest); + } + Free(digest); + return info_digest; +} + +uint8_t* SignatureBuf(const uint8_t* buf, uint64_t len, const char* key_file, + int algorithm) { + FILE* key_fp = NULL; + RSA* key = NULL; + uint8_t* signature = NULL; + uint8_t* signature_digest = SignatureDigest(buf, len, algorithm); + int signature_digest_len = (hash_size_map[algorithm] + + digestinfo_size_map[algorithm]); + key_fp = fopen(key_file, "r"); + if (!key_fp) { + debug("SignatureBuf(): Couldn't open key file: %s\n", key_file); + Free(signature_digest); + return NULL; + } + if ((key = PEM_read_RSAPrivateKey(key_fp, NULL, NULL, NULL))) + signature = (uint8_t*) Malloc(siglen_map[algorithm]); + else + debug("SignatureBuf(): Couldn't read private key from file: %s\n", + key_file); + if (signature) { + if (-1 == RSA_private_encrypt(signature_digest_len, /* Input length. */ + signature_digest, /* Input data. */ + signature, /* Output signature. */ + key, /* Key to use. */ + RSA_PKCS1_PADDING)) /* Padding to use. */ + debug("SignatureBuf(): RSA_private_encrypt() failed.\n"); + } + fclose(key_fp); + if (key) + RSA_free(key); + Free(signature_digest); + return signature; +} diff --git a/host/linktest/main.c b/host/linktest/main.c index 5fb7dd3d..93c5ac2a 100644 --- a/host/linktest/main.c +++ b/host/linktest/main.c @@ -1,6 +1,8 @@ #include <stdio.h> #include "host_common.h" +#include "file_keys.h" +#include "signature_digest.h" int main(void) { @@ -32,5 +34,16 @@ int main(void) CreateFirmwarePreamble(0, 0, 0, 0); CreateKernelPreamble(0, 0, 0, 0, 0, 0, 0); + /* file_keys.h */ + BufferFromFile(0, 0); + RSAPublicKeyFromFile(0); + DigestFile(0, 0); + SignatureFile(0, 0, 0); + + /* signature_digest.h */ + PrependDigestInfo(0, 0); + SignatureDigest(0, 0, 0); + SignatureBuf(0, 0, 0, 0); + return 0; } |