Mercurial > trustbridge
view common/listutil.c @ 389:3be838c3e4d8
Handle installation success. Save / load last installed list.
This also adds a feature that you can specifiy the download
resource when release build is not set so that you can
update a list without modifying the server data.
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Tue, 15 Apr 2014 19:05:49 +0200 |
parents | f6ce186cebc2 |
children | 17e1c8f37d72 |
line wrap: on
line source
#include "listutil.h" #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <fcntl.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <string.h> #include "strhelp.h" #ifdef RELEASE_BUILD #include "pubkey-release.h" #else #include "pubkey-test.h" #endif #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 #define MAX_FILESIZE (MAX_LINE_LENGTH * MAX_LINES) /** * @brief Read a file into memory. * * The caller needs to free data * * @param[in] fileName Name of the file. * @param[out] data the file content * @param[out] size size in bytes of the file content. * @param[in] max_size the maximum amount of bytes to read. * * @return 0 on success an error code otherwise. */ #define READ_FILE_UNREADABLE -1 #define READ_FILE_TOO_LARGE -2 #define READ_FILE_NO_MEMORY -3 #define READ_FILE_READ_FAILED -4 #define READ_FILE_INVALID_CALL -5 static int read_file(const char *file_name, char **data, size_t *size, const size_t max_size) { FILE *f; long file_size; if (!file_name || !data || !size || !max_size) { return READ_FILE_INVALID_CALL; } f = fopen(file_name, "rb"); if (f == NULL) return READ_FILE_UNREADABLE; fseek(f, 0, SEEK_END); file_size = ftell(f); if (file_size <= 0){ fclose(f); return READ_FILE_UNREADABLE; } fseek(f, 0, SEEK_SET); if (file_size + 1 == 0) { fclose(f); return READ_FILE_TOO_LARGE; } *size = (size_t) file_size; if (*size > max_size) { fclose(f); return READ_FILE_TOO_LARGE; } *data = (char *) malloc( *size + 1 ); if (*data == NULL) { fclose(f); return READ_FILE_NO_MEMORY; } if (fread(*data, 1, *size, f) != *size) { free(*data); fclose(f); return READ_FILE_READ_FAILED; } fclose(f); (*data)[*size] = '\0'; return 0; } int verify_list(const char *data, const size_t size) { int ret = -1; pk_context pub_key_ctx; char *p; /* Fixed key size of 3072 implies the sizes*/ const size_t sig_b64_size = 512; size_t sig_size = 384; char signature_b64[sig_b64_size + 1]; unsigned char signature[sig_size]; /* Hash algroithm is sha256 */ unsigned char hash[32]; if (!data || !size) { return -1; } /* Fetch the signature from the first line od data */ p = strchr(data, '\r'); if (p == 0 || (unsigned int)(p - (data + 2)) != sig_b64_size) { /* printf("Invalid data. Signature might be too long.\n"); */ return -1; } strncpy(signature_b64, data + 2, 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 != 384) { /* printf("failed to decode signature\n"); */ return -1; } /* Hash is calculated over the data without the first line. * linebreaks are \r\n so the first char of the new line is * p+2 */ p += 2; /* Size of the data to hash is the size - signature line * signature line is sig_b64_size - "S:" and - "\r\n" so -4*/ sha256((unsigned char *)p, size - sig_b64_size - 4, hash, 0); pk_init(&pub_key_ctx); #if 0 { int i; FILE *foo = fopen("/tmp/testdump", "w"); FILE *foo2 = fopen("/tmp/rawdump", "w"); for (i=0; i< (int)(size - sig_b64_size - 2); i++) fprintf (foo, "%c", p[i]); for (i=0; i< (int)(size); i++) fprintf (foo2, "%c", data[i]); fclose(foo); printf ("Hash: \n"); for (i=0; i<32; i++) { printf ("%x", hash[i]); } printf("\n"); } #endif ret = pk_parse_public_key(&pub_key_ctx, public_key_pem, public_key_pem_size); if (ret != 0) { printf("pk_parse_public_key failed with -0x%04x\n\n", -ret); pk_free(&pub_key_ctx); return ret; } ret = pk_verify(&pub_key_ctx, POLARSSL_MD_SHA256, hash, 0, signature, sig_size); if (ret != 0) { printf("pk_verify failed with -0x%04x\n\n", -ret); } pk_free(&pub_key_ctx); return ret; } list_status_t read_and_verify_list(const char *file_name, char **data, size_t *size) { list_status_t retval = UnknownError; *data = NULL; *size = 0; int ret = 0; ret = read_file(file_name, data, size, MAX_FILESIZE); /* printf ("Ret: %i \n", ret); */ if (ret != 0) { if (ret == READ_FILE_TOO_LARGE) { return TooLarge; } if (ret == READ_FILE_UNREADABLE) { /* TODO: work with errno ? */ /* errsv = errno; */ /* perror("read_and_verify_list(), READ_FILE_UNREADABLE:"); */ return SeekFailed; } if (ret == READ_FILE_READ_FAILED) { /* TODO: work with ferror() or feof() ? */ return ReadFailed; } return UnknownError; } if (!*data || !*size) { /* File is probably empty */ return UnknownError; } if (**data != 'S') { retval = InvalidFormat; } else { ret = verify_list (*data, *size); if (ret == 0) { /* Hooray */ return Valid; } if (ret == -1) { /* our error */ retval = InvalidFormat; } else { retval = InvalidSignature; } } if (retval != Valid && *data) { free(*data); *data = NULL; *size = 0; } return retval; } char ** get_certs_from_list (char *data, const size_t size) { char *cur = data; char **retval = NULL; if (!data || !size) { printf ("Invalid call to get_certs_to_remove \n"); return NULL; } while (cur) { char *next = strchr(cur, '\n'); if (strlen(cur) > 3 && (cur[0] == 'I' || cur[0] == 'R') && next - cur > 4) { size_t len = (size_t) (next - cur - 3); /* Remove I: or R: at the beginning and \r\n at the end */ strv_append(&retval, cur + 2, len); } cur = next ? (next + 1) : NULL; } return retval; }