Mercurial > trustbridge
changeset 771:2798f1869eee
(issue43) Add first draft of signature verification for GNU/Linux
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Thu, 10 Jul 2014 19:15:22 +0200 |
parents | 7861950f7637 |
children | aec00847d86d |
files | common/binverify.c common/binverify.h |
diffstat | 2 files changed, 117 insertions(+), 6 deletions(-) [+] |
line wrap: on
line diff
--- a/common/binverify.c Thu Jul 10 19:14:22 2014 +0200 +++ b/common/binverify.c Thu Jul 10 19:15:22 2014 +0200 @@ -19,13 +19,12 @@ bin_verify_result verify_binary(const char *filename, size_t name_len) { + if (!filename || !name_len) + return VerifyUnknownError; #ifdef WIN32 return verify_binary_win(filename, name_len); #else - /* TODO */ - if (filename && name_len) - return VerifyValid; - return VerifyUnknownError; + return verify_binary_linux(filename, name_len); #endif } @@ -224,4 +223,103 @@ } return retval; } +#else /* WIN32 */ + +#include "listutil.h" + +#pragma GCC diagnostic ignored "-Wconversion" +/* Polarssl mh.h contains a conversion which gcc warns about */ +#include <polarssl/pk.h> +#include <polarssl/base64.h> +#include <polarssl/sha256.h> +#pragma GCC diagnostic pop + +bin_verify_result +verify_binary_linux(const char *filename, size_t name_len) +{ + int ret = -1; + const size_t sig_b64_size = TRUSTBRIDGE_RSA_KEY_SIZE / 8 * 4 / 3; + char *data = NULL, + signature_b64[sig_b64_size + 1]; + size_t data_size = 0, + sig_size = TRUSTBRIDGE_RSA_KEY_SIZE / 8; + unsigned char signature[sig_size], + hash[32]; + + bin_verify_result retval = VerifyUnknownError; + pk_context pub_key_ctx; + + if (strnlen(filename, name_len + 1) != name_len || name_len == 0) + { + ERRORPRINTF ("Invalid call to verify_binary_linux\n"); + return VerifyUnknownError; + } + + ret = read_file(filename, &data, &data_size, MAX_VALID_BIN_SIZE); + + if (ret != 0) + { + ERRORPRINTF ("Read file failed with error: %i\n", ret); + return VerifyReadFailed; + } + + /* Fetch the signature from the end of data */ + if (data_size < sig_b64_size + 4) + { + ERRORPRINTF ("File to small to contain a signature.\n"); + retval = VerifyInvalidSignature; + goto done; + } + + if (data[data_size - sig_b64_size - 1] != ':' || + data[data_size - sig_b64_size - 2] != 'S' || + data[data_size - sig_b64_size - 3] != '\n'|| + data[data_size - sig_b64_size - 4] != '\r') + { + ERRORPRINTF ("Failed to find valid signature line.\n"); + retval = VerifyInvalidSignature; + goto done; + } + + strncpy(signature_b64, data - sig_b64_size, sig_b64_size); + signature_b64[sig_b64_size] = '\0'; + + ret = base64_decode(signature, &sig_size, + (unsigned char *)signature_b64, sig_b64_size); + + if (ret != 0 || sig_size != TRUSTBRIDGE_RSA_KEY_SIZE / 8) + { + goto done; + } + + /* Hash is calculated over the data without the signature at the end. */ + sha256((unsigned char *)data, data_size - sig_b64_size - 4, hash, 0); + + pk_init(&pub_key_ctx); + + ret = pk_parse_public_key(&pub_key_ctx, public_key_codesign_pem, + public_key_codesign_pem_size); + if (ret != 0) + { + ERRORPRINTF ("pk_parse_public_key failed with -0x%04x\n\n", -ret); + pk_free(&pub_key_ctx); + return VerifyUnknownError; + } + + ret = pk_verify(&pub_key_ctx, POLARSSL_MD_SHA256, hash, 0, + signature, sig_size); + + if (ret != 0) + { + ERRORPRINTF ("pk_verify failed with -0x%04x\n\n", -ret); + } + pk_free(&pub_key_ctx); + + return VerifyValid; + +done: + xfree (data); + return retval; +} + #endif /* WIN32 */
--- a/common/binverify.h Thu Jul 10 19:14:22 2014 +0200 +++ b/common/binverify.h Thu Jul 10 19:15:22 2014 +0200 @@ -39,10 +39,15 @@ * Caution: This function works on file names only which could * be modified after this check. * - * The verification is done using Windows crypto API based on + * Windows verification is done using Windows crypto API based on * embedded PKCS 7 "authenticode" signatures embedded into the * file. * + * On Linux the last pattern of \r\nS: (0x0d0a533A) is looked up and + * afterwards a 3072 Bit Base64 encoded RSA signature is expected. + * The signature is verified against the built in codesigning key in + * the same certificate that is used for windows verification. + * * @param[in] filename absolute null terminated UTF-8 encoded path to the file. * @param[in] name_len length of the filename. * @@ -55,7 +60,15 @@ * @brief windows implementation of verify_binary */ bin_verify_result verify_binary_win(const char *filename, size_t name_len); -#endif /* WIN32 */ +#else /* WIN32 */ +/**@def Max size of a valid binary in byte */ +#define MAX_VALID_BIN_SIZE (32 * 1024 * 1024) + +/** + * @brief linux implementation of verify_binary + */ +bin_verify_result verify_binary_linux(const char *filename, size_t name_len); +#endif #ifdef __cplusplus }