view common/listutil.c @ 28:e783fd99a9eb

Add public key parsing
author Andre Heinecke <aheinecke@intevation.de>
date Thu, 13 Mar 2014 12:01:33 +0000
parents bc302bbceaf5
children 37fc66967517
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>

#ifdef RELEASE
#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>
#pragma GCC diagnostic pop

#define MAX_FILESIZE_KB 1024

void handle_errno()
{
    printf("Error: %s \n", strerror(errno));
}

list_status_t read_list (const char *file_name, char **data, size_t *size)
{
    int fd = -1;
    struct stat file_stat;
    int rc = 0;
    ssize_t bRead = 0;

    memset(&file_stat, 0, sizeof(file_stat));

    list_status_t retval = UnknownError;

    fd = open(file_name, O_RDONLY);
    if (fd == -1) {
        handle_errno();
        retval = StatFailed;
        goto cleanup;
    }

    rc = fstat(fd, &file_stat);
    if (rc < 0) {
        printf ("Stat failed with rc: %i\n", rc);
        retval = StatFailed;
        goto cleanup;
    }

    // Check the size of the file
    if (!file_stat.st_size) {
        printf("Size zero\n");
        retval = StatFailed;
        goto cleanup;
    }

    if (file_stat.st_size / 1024 > MAX_FILESIZE_KB &&
            file_stat.st_size > 0) {
        printf("File too large\n");
        retval = TooLarge;
        goto cleanup;
    }

    *size = (size_t) file_stat.st_size;

    *data = (char*) malloc(*size);

    if (*data == NULL) {
        printf("Malloc failed\n");
        retval = UnknownError;
        goto cleanup;
    }

    bRead = read(fd, *data, *size);

    if (bRead < 0 || (size_t) bRead != *size) {
        printf("Read failed\n");
        if (bRead == -1) {
            handle_errno();
        }
        retval = UnknownError;
        *size = 0;
        if (*data) {
            free(*data);
            printf("Nulling data\n");
            *data = NULL;
        }
        goto cleanup;
    }

    retval = UnknownValidity;
cleanup:

    if (fd && fd != -1) {
        close(fd);
        fd = -1;
    }

    return retval;
}

/** @brief verify the certificate list
 *
 * The public key to verify against is the static publicKeyPEM data defined
 * in the pubkey header.
 *
 *  @param [in] data the list data
 *  @param [in] size the size of the data
 *
 *  @returns 0 if the list is valid a polarssl error or -1 otherwise
 */
int verify_list(char *data, size_t size)
{
//    char *sigstart = data;
    int ret = -1;
    pk_context pub_key_ctx;
    size_t lenpem = strlen((const char*)publicKeyPEM);

    pk_init(&pub_key_ctx);

    ret = pk_parse_public_key(&pub_key_ctx, publicKeyPEM, lenpem);

    if (ret != 0) {
        printf("pk_parse_public_key failed with -0x%04x\n\n", -ret);
        goto done;
    }

done:
    pk_free(&pub_key_ctx);
    return ret;
}

list_status_t read_and_verify_list(const char *file_name, char **data,
                                   size_t *size)
{
    char * signature = NULL;

    list_status_t retval = UnknownError;
    *data = NULL;
    *size = 0;

    retval = read_list(file_name, data, size);

    if (retval != UnknownValidity) {
        printf("Readlist failed\n");
        return retval;
    }

    if (!data || !*size) {
        // should not have happend if read_list works as specified
        return UnknownError;
    }

    signature = *data;

    if (*signature != 'S') {
        printf("Does not start with S\n");
        retval = InvalidFormat;
        goto cleanup;
    }

    retval = verify_list (*data, *size);

cleanup:
    if (retval != Valid && *data) {
        free(*data);
        *data = NULL;
        *size = 0;
    }
    return retval;
}

http://wald.intevation.org/projects/trustbridge/