strongswan/src/libpts/plugins/imv_attestation/attest.c

472 lines
10 KiB
C

/*
* Copyright (C) 2011-2013 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#define _GNU_SOURCE
#include <getopt.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <syslog.h>
#include <libgen.h>
#include <library.h>
#include <utils/debug.h>
#include <imcv.h>
#include <libpts.h>
#include <pts/pts_meas_algo.h>
#include "attest_db.h"
#include "attest_usage.h"
/**
* global debug output variables
*/
static int debug_level = 1;
static bool stderr_quiet = TRUE;
/**
* attest dbg function
*/
static void attest_dbg(debug_t group, level_t level, char *fmt, ...)
{
int priority = LOG_INFO;
char buffer[8192];
char *current = buffer, *next;
va_list args;
if (level <= debug_level)
{
if (!stderr_quiet)
{
va_start(args, fmt);
vfprintf(stderr, fmt, args);
fprintf(stderr, "\n");
va_end(args);
}
/* write in memory buffer first */
va_start(args, fmt);
vsnprintf(buffer, sizeof(buffer), fmt, args);
va_end(args);
/* do a syslog with every line */
while (current)
{
next = strchr(current, '\n');
if (next)
{
*(next++) = '\0';
}
syslog(priority, "%s\n", current);
current = next;
}
}
}
/**
* global attestation database object
*/
attest_db_t *attest;
/**
* atexit handler to close db on shutdown
*/
static void cleanup(void)
{
attest->destroy(attest);
libpts_deinit();
libimcv_deinit();
closelog();
}
static void do_args(int argc, char *argv[])
{
enum {
OP_UNDEF,
OP_USAGE,
OP_KEYS,
OP_COMPONENTS,
OP_DEVICES,
OP_DIRECTORIES,
OP_FILES,
OP_HASHES,
OP_MEASUREMENTS,
OP_PACKAGES,
OP_PRODUCTS,
OP_SESSIONS,
OP_ADD,
OP_DEL,
} op = OP_UNDEF;
/* reinit getopt state */
optind = 0;
while (TRUE)
{
int c;
struct option long_opts[] = {
{ "help", no_argument, NULL, 'h' },
{ "components", no_argument, NULL, 'c' },
{ "devices", no_argument, NULL, 'e' },
{ "directories", no_argument, NULL, 'd' },
{ "dirs", no_argument, NULL, 'd' },
{ "files", no_argument, NULL, 'f' },
{ "keys", no_argument, NULL, 'k' },
{ "packages", no_argument, NULL, 'g' },
{ "products", no_argument, NULL, 'p' },
{ "hashes", no_argument, NULL, 'H' },
{ "measurements", no_argument, NULL, 'm' },
{ "sessions", no_argument, NULL, 's' },
{ "add", no_argument, NULL, 'a' },
{ "delete", no_argument, NULL, 'r' },
{ "del", no_argument, NULL, 'r' },
{ "remove", no_argument, NULL, 'r' },
{ "aik", required_argument, NULL, 'A' },
{ "blacklist", no_argument, NULL, 'B' },
{ "component", required_argument, NULL, 'C' },
{ "comp", required_argument, NULL, 'C' },
{ "directory", required_argument, NULL, 'D' },
{ "dir", required_argument, NULL, 'D' },
{ "file", required_argument, NULL, 'F' },
{ "sha1-ima", no_argument, NULL, 'I' },
{ "package", required_argument, NULL, 'G' },
{ "key", required_argument, NULL, 'K' },
{ "owner", required_argument, NULL, 'O' },
{ "product", required_argument, NULL, 'P' },
{ "relative", no_argument, NULL, 'R' },
{ "rel", no_argument, NULL, 'R' },
{ "sequence", required_argument, NULL, 'S' },
{ "seq", required_argument, NULL, 'S' },
{ "utc", no_argument, NULL, 'U' },
{ "version", required_argument, NULL, 'V' },
{ "security", no_argument, NULL, 'Y' },
{ "sha1", no_argument, NULL, '1' },
{ "sha256", no_argument, NULL, '2' },
{ "sha384", no_argument, NULL, '3' },
{ "did", required_argument, NULL, '4' },
{ "fid", required_argument, NULL, '5' },
{ "pid", required_argument, NULL, '6' },
{ "cid", required_argument, NULL, '7' },
{ "kid", required_argument, NULL, '8' },
{ "gid", required_argument, NULL, '9' },
{ 0,0,0,0 }
};
c = getopt_long(argc, argv, "", long_opts, NULL);
switch (c)
{
case EOF:
break;
case 'h':
op = OP_USAGE;
break;
case 'c':
op = OP_COMPONENTS;
continue;
case 'd':
op = OP_DIRECTORIES;
continue;
case 'e':
op = OP_DEVICES;
continue;
case 'f':
op = OP_FILES;
continue;
case 'g':
op = OP_PACKAGES;
continue;
case 'k':
op = OP_KEYS;
continue;
case 'p':
op = OP_PRODUCTS;
continue;
case 'H':
op = OP_HASHES;
continue;
case 'm':
op = OP_MEASUREMENTS;
continue;
case 's':
op = OP_SESSIONS;
continue;
case 'a':
op = OP_ADD;
continue;
case 'r':
op = OP_DEL;
continue;
case 'A':
{
certificate_t *aik_cert;
public_key_t *aik_key;
chunk_t aik;
aik_cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
CERT_X509, BUILD_FROM_FILE, optarg, BUILD_END);
if (!aik_cert)
{
printf("AIK certificate '%s' could not be loaded\n", optarg);
exit(EXIT_FAILURE);
}
aik_key = aik_cert->get_public_key(aik_cert);
aik_cert->destroy(aik_cert);
if (!aik_key)
{
printf("AIK public key could not be retrieved\n");
exit(EXIT_FAILURE);
}
if (!aik_key->get_fingerprint(aik_key, KEYID_PUBKEY_INFO_SHA1,
&aik))
{
printf("AIK fingerprint could not be computed\n");
aik_key->destroy(aik_key);
exit(EXIT_FAILURE);
}
aik = chunk_clone(aik);
aik_key->destroy(aik_key);
if (!attest->set_key(attest, aik, op == OP_ADD))
{
exit(EXIT_FAILURE);
}
continue;
}
case 'B':
attest->set_package_state(attest, OS_PACKAGE_STATE_BLACKLIST);
continue;
case 'C':
if (!attest->set_component(attest, optarg, op == OP_ADD))
{
exit(EXIT_FAILURE);
}
continue;
case 'D':
if (!attest->set_directory(attest, optarg, op == OP_ADD))
{
exit(EXIT_FAILURE);
}
continue;
case 'F':
{
char *path = strdup(optarg);
char *dir = dirname(path);
char *file = basename(optarg);
if (*dir != '.')
{
if (!attest->set_directory(attest, dir, op == OP_ADD))
{
free(path);
exit(EXIT_FAILURE);
}
}
free(path);
if (!attest->set_file(attest, file, op == OP_ADD))
{
exit(EXIT_FAILURE);
}
continue;
}
case 'G':
if (!attest->set_package(attest, optarg, op == OP_ADD))
{
exit(EXIT_FAILURE);
}
continue;
case 'I':
attest->set_algo(attest, PTS_MEAS_ALGO_SHA1_IMA);
continue;
case 'K':
{
chunk_t aik;
aik = chunk_from_hex(chunk_create(optarg, strlen(optarg)), NULL);
if (!attest->set_key(attest, aik, op == OP_ADD))
{
exit(EXIT_FAILURE);
}
continue;
}
case 'O':
attest->set_owner(attest, optarg);
continue;
case 'P':
if (!attest->set_product(attest, optarg, op == OP_ADD))
{
exit(EXIT_FAILURE);
}
continue;
case 'R':
attest->set_relative(attest);
continue;
case 'S':
attest->set_sequence(attest, atoi(optarg));
continue;
case 'U':
attest->set_utc(attest);
continue;
case 'V':
if (!attest->set_version(attest, optarg))
{
exit(EXIT_FAILURE);
}
continue;
case 'Y':
attest->set_package_state(attest, OS_PACKAGE_STATE_SECURITY);
continue;
case '1':
attest->set_algo(attest, PTS_MEAS_ALGO_SHA1);
continue;
case '2':
attest->set_algo(attest, PTS_MEAS_ALGO_SHA256);
continue;
case '3':
attest->set_algo(attest, PTS_MEAS_ALGO_SHA384);
continue;
case '4':
if (!attest->set_did(attest, atoi(optarg)))
{
exit(EXIT_FAILURE);
}
continue;
case '5':
if (!attest->set_fid(attest, atoi(optarg)))
{
exit(EXIT_FAILURE);
}
continue;
case '6':
if (!attest->set_pid(attest, atoi(optarg)))
{
exit(EXIT_FAILURE);
}
continue;
case '7':
if (!attest->set_cid(attest, atoi(optarg)))
{
exit(EXIT_FAILURE);
}
continue;
case '8':
if (!attest->set_kid(attest, atoi(optarg)))
{
exit(EXIT_FAILURE);
}
continue;
case '9':
if (!attest->set_gid(attest, atoi(optarg)))
{
exit(EXIT_FAILURE);
}
continue;
}
break;
}
switch (op)
{
case OP_USAGE:
usage();
break;
case OP_PACKAGES:
attest->list_packages(attest);
break;
case OP_PRODUCTS:
attest->list_products(attest);
break;
case OP_KEYS:
attest->list_keys(attest);
break;
case OP_COMPONENTS:
attest->list_components(attest);
break;
case OP_DEVICES:
attest->list_devices(attest);
break;
case OP_DIRECTORIES:
attest->list_directories(attest);
break;
case OP_FILES:
attest->list_files(attest);
break;
case OP_HASHES:
attest->list_hashes(attest);
break;
case OP_MEASUREMENTS:
attest->list_measurements(attest);
break;
case OP_SESSIONS:
attest->list_sessions(attest);
break;
case OP_ADD:
attest->add(attest);
break;
case OP_DEL:
attest->delete(attest);
break;
default:
usage();
exit(EXIT_FAILURE);
}
}
int main(int argc, char *argv[])
{
char *uri;
/* enable attest debugging hook */
dbg = attest_dbg;
openlog("attest", 0, LOG_DEBUG);
atexit(library_deinit);
/* initialize library */
if (!library_init(NULL, "attest"))
{
exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
}
if (!lib->plugins->load(lib->plugins,
lib->settings->get_str(lib->settings, "attest.load", PLUGINS)))
{
exit(SS_RC_INITIALIZATION_FAILED);
}
uri = lib->settings->get_str(lib->settings, "attest.database", NULL);
if (!uri)
{
fprintf(stderr, "database URI attest.database not set.\n");
exit(SS_RC_INITIALIZATION_FAILED);
}
attest = attest_db_create(uri);
if (!attest)
{
exit(SS_RC_INITIALIZATION_FAILED);
}
atexit(cleanup);
libimcv_init(FALSE);
libpts_init();
do_args(argc, argv);
exit(EXIT_SUCCESS);
}