diff options
Diffstat (limited to 'src/openac/openac.c')
-rwxr-xr-x | src/openac/openac.c | 381 |
1 files changed, 227 insertions, 154 deletions
diff --git a/src/openac/openac.c b/src/openac/openac.c index e3f92fbd2..075f0039a 100755 --- a/src/openac/openac.c +++ b/src/openac/openac.c @@ -1,7 +1,14 @@ -/* Generation of X.509 attribute certificates +/** + * @file openac.c + * + * @brief Generation of X.509 attribute certificates. + * + */ + +/* * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler - * Copyright (C) 2004 Andreas Steffen - * Zuercher Hochschule Winterthur, Switzerland + * Copyright (C) 2004,2007 Andreas Steffen + * Hochschule fuer Technik Rapperswil, Switzerland * * 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 @@ -13,66 +20,52 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: openac.c,v 1.18 2006/01/04 21:12:33 as Exp $ + * RCSID $Id: openac.c 3305 2007-10-17 02:55:17Z andreas $ */ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <syslog.h> #include <unistd.h> #include <getopt.h> #include <ctype.h> #include <time.h> #include <gmp.h> -#include <freeswan.h> +#include <debug.h> +#include <asn1/asn1.h> +#include <asn1/ttodata.h> +#include <crypto/ac.h> +#include <crypto/ietf_attr_list.h> +#include <utils/optionsfrom.h> -#include "../pluto/constants.h" -#include "../pluto/defs.h" -#include "../pluto/mp_defs.h" -#include "../pluto/log.h" -#include "../pluto/asn1.h" -#include "../pluto/certs.h" -#include "../pluto/x509.h" -#include "../pluto/crl.h" -#include "../pluto/keys.h" -#include "../pluto/ac.h" +#ifdef INTEGRITY_TEST +#include <fips/fips.h> +#include <fips_signature.h> +#endif /* INTEGRITY_TEST */ #include "build.h" #define OPENAC_PATH IPSEC_CONFDIR "/openac" #define OPENAC_SERIAL IPSEC_CONFDIR "/openac/serial" -const char openac_version[] = "openac 0.3"; - -/* by default the CRL policy is lenient */ -bool strict_crl_policy = FALSE; - -/* by default pluto does not check crls dynamically */ -long crl_check_interval = 0; - -/* by default pluto logs out after every smartcard use */ -bool pkcs11_keep_state = FALSE; - -static void -usage(const char *mess) +/** + * @brief prints the usage of the program to the stderr + */ +static void usage(const char *message) { - if (mess != NULL && *mess != '\0') + if (message != NULL && *message != '\0') { - fprintf(stderr, "%s\n", mess); + fprintf(stderr, "%s\n", message); } fprintf(stderr, "Usage: openac" " [--help]" " [--version]" " [--optionsfrom <filename>]" " [--quiet]" -#ifdef DEBUG " \\\n\t" - " [--debug-all]" - " [--debug-parsing]" - " [--debug-raw]" - " [--debug-private]" -#endif + " [--debug <level 0..4>]" " \\\n\t" " [--days <days>]" " [--hours <hours>]" @@ -89,7 +82,27 @@ usage(const char *mess) " --out <filename>" "\n" ); - exit(mess == NULL? 0 : 1); +} + + +/** + * convert a chunk into a multi-precision integer + */ +static void chunk_to_mpz(chunk_t chunk, mpz_t number) +{ + mpz_import(number, chunk.len, 1, 1, 1, 0, chunk.ptr); +} + +/** + * convert a multi-precision integer into a chunk + */ +static chunk_t mpz_to_chunk(mpz_t number) +{ + chunk_t chunk; + + chunk.len = 1 + mpz_sizeinbase(number, 2)/BITS_PER_BYTE; + chunk.ptr = mpz_export(NULL, NULL, 1, chunk.len, 1, 0, number); + return chunk; } /** @@ -97,35 +110,35 @@ usage(const char *mess) */ static chunk_t read_serial(void) { - MP_INT number; + mpz_t number; - char buf[BUF_LEN]; - char bytes[BUF_LEN]; + char buf[BUF_LEN], buf1[BUF_LEN]; + chunk_t last_serial = { buf1, BUF_LEN}; + chunk_t serial; FILE *fd = fopen(OPENAC_SERIAL, "r"); - /* serial number defaults to 0 */ - size_t len = 1; - bytes[0] = 0x00; + /* last serial number defaults to 0 */ + *last_serial.ptr = 0x00; + last_serial.len = 1; if (fd) { if (fscanf(fd, "%s", buf)) { - err_t ugh = ttodata(buf, 0, 16, bytes, BUF_LEN, &len); + err_t ugh = ttodata(buf, 0, 16, last_serial.ptr, BUF_LEN, &last_serial.len); if (ugh != NULL) { - plog(" error reading serial number from %s: %s" - , OPENAC_SERIAL, ugh); + DBG1(" error reading serial number from %s: %s", + OPENAC_SERIAL, ugh); } } fclose(fd); } else { - plog(" file '%s' does not exist yet - serial number set to 01" - , OPENAC_SERIAL); + DBG1(" file '%s' does not exist yet - serial number set to 01", OPENAC_SERIAL); } /** @@ -133,10 +146,11 @@ static chunk_t read_serial(void) * and incrementing it by one * and representing it as a two's complement octet string */ - n_to_mpz(&number, bytes, len); - mpz_add_ui(&number, &number, 0x01); - serial = mpz_to_n(&number, 1 + mpz_sizeinbase(&number, 2)/BITS_PER_BYTE); - mpz_clear(&number); + mpz_init(number); + chunk_to_mpz(last_serial, number); + mpz_add_ui(number, number, 0x01); + serial = mpz_to_chunk(number); + mpz_clear(number); return serial; } @@ -146,65 +160,91 @@ static chunk_t read_serial(void) */ static void write_serial(chunk_t serial) { - char buf[BUF_LEN]; - FILE *fd = fopen(OPENAC_SERIAL, "w"); if (fd) { - datatot(serial.ptr, serial.len, 16, buf, BUF_LEN); - plog(" serial number is %s", buf); - fprintf(fd, "%s\n", buf); + DBG1(" serial number is %#B", &serial); + fprintf(fd, "%#B\n", &serial); fclose(fd); } else { - plog(" could not open file '%s' for writing", OPENAC_SERIAL); + DBG1(" could not open file '%s' for writing", OPENAC_SERIAL); } } /** * global variables accessible by both main() and build.c */ -x509cert_t *user = NULL; -x509cert_t *signer = NULL; +x509_t *usercert = NULL; +x509_t *signercert = NULL; -ietfAttrList_t *groups = NULL; -struct RSA_private_key *signerkey = NULL; +linked_list_t *groups = NULL; +rsa_private_key_t *signerkey = NULL; -time_t notBefore = 0; -time_t notAfter = 0; +time_t notBefore = UNDEFINED_TIME; +time_t notAfter = UNDEFINED_TIME; chunk_t serial; +static int debug_level = 1; +static bool stderr_quiet = FALSE; + +/** + * openac dbg function + */ +static void openac_dbg(int level, char *fmt, ...) +{ + int priority = LOG_INFO; + va_list args; + + if (level <= debug_level) + { + va_start(args, fmt); + if (!stderr_quiet) + { + vfprintf(stderr, fmt, args); + fprintf(stderr, "\n"); + } + vsyslog(priority, fmt, args); + va_end(args); + } +} + +/** + * @brief openac main program + * + * @param argc number of arguments + * @param argv pointer to the argument values + */ int main(int argc, char **argv) { char *keyfile = NULL; char *certfile = NULL; char *usercertfile = NULL; char *outfile = NULL; + char buf[BUF_LEN]; - cert_t signercert = empty_cert; - cert_t usercert = empty_cert; - - chunk_t attr_cert = empty_chunk; - x509acert_t *ac = NULL; + chunk_t passphrase = { buf, 0 }; + chunk_t attr_cert = chunk_empty; + x509ac_t *ac = NULL; const time_t default_validity = 24*3600; /* 24 hours */ time_t validity = 0; + int status = 1; + + /* enable openac debugging hook */ + dbg = openac_dbg; - prompt_pass_t pass; - - pass.secret[0] = '\0'; - pass.prompt = TRUE; - pass.fd = STDIN_FILENO; + passphrase.ptr[0] = '\0'; + groups = linked_list_create(); - log_to_stderr = TRUE; + openlog("openac", 0, LOG_AUTHPRIV); /* handle arguments */ for (;;) { -# define DBG_OFFSET 256 static const struct option long_opts[] = { /* name, has_arg, flag, val */ { "help", no_argument, NULL, 'h' }, @@ -212,7 +252,7 @@ int main(int argc, char **argv) { "optionsfrom", required_argument, NULL, '+' }, { "quiet", no_argument, NULL, 'q' }, { "cert", required_argument, NULL, 'c' }, - { "key", required_argument, NULL, 'k' }, + { "key", required_argument, NULL, 'k' }, { "password", required_argument, NULL, 'p' }, { "usercert", required_argument, NULL, 'u' }, { "groups", required_argument, NULL, 'g' }, @@ -221,16 +261,11 @@ int main(int argc, char **argv) { "startdate", required_argument, NULL, 'S' }, { "enddate", required_argument, NULL, 'E' }, { "out", required_argument, NULL, 'o' }, -#ifdef DEBUG - { "debug-all", no_argument, NULL, 'A' }, - { "debug-raw", no_argument, NULL, DBG_RAW + DBG_OFFSET }, - { "debug-parsing", no_argument, NULL, DBG_PARSING + DBG_OFFSET }, - { "debug-private", no_argument, NULL, DBG_PRIVATE + DBG_OFFSET }, -#endif + { "debug", required_argument, NULL, 'd' }, { 0,0,0,0 } }; - int c = getopt_long(argc, argv, "hv+:qc:k:p;u:g:D:H:S:E:o:", long_opts, NULL); + int c = getopt_long(argc, argv, "hv+:qc:k:p;u:g:D:H:S:E:o:d:", long_opts, NULL); /* Note: "breaking" from case terminates loop */ switch (c) @@ -243,33 +278,38 @@ int main(int argc, char **argv) case ':': /* diagnostic already printed by getopt_long */ case '?': /* diagnostic already printed by getopt_long */ - usage(NULL); - break; /* not actually reached */ - case 'h': /* --help */ usage(NULL); - break; /* not actually reached */ + status = 1; + goto end; case 'v': /* --version */ - printf("%s\n", openac_version); - exit(0); - break; /* not actually reached */ + printf("openac (strongSwan %s)\n", VERSION); + status = 0; + goto end; case '+': /* --optionsfrom <filename> */ { char path[BUF_LEN]; if (*optarg == '/') /* absolute pathname */ + { strncpy(path, optarg, BUF_LEN); + } else /* relative pathname */ + { snprintf(path, BUF_LEN, "%s/%s", OPENAC_PATH, optarg); - optionsfrom(path, &argc, &argv, optind, stderr); - /* does not return on error */ + } + if (!optionsfrom(path, &argc, &argv, optind)) + { + status = 1; + goto end; + } } continue; case 'q': /* --quiet */ - log_to_stderr = TRUE; + stderr_quiet = TRUE; continue; case 'c': /* --cert */ @@ -281,8 +321,13 @@ int main(int argc, char **argv) continue; case 'p': /* --key */ - pass.prompt = FALSE; - strncpy(pass.secret, optarg, sizeof(pass.secret)); + if (strlen(optarg) > BUF_LEN) + { + usage("passphrase too long"); + goto end; + } + strncpy(passphrase.ptr, optarg, BUF_LEN); + passphrase.len = min(strlen(optarg), BUF_LEN); continue; case 'u': /* --usercert */ @@ -290,151 +335,179 @@ int main(int argc, char **argv) continue; case 'g': /* --groups */ - decode_groups(optarg, &groups); + ietfAttr_list_create_from_string(optarg, groups); continue; case 'D': /* --days */ if (optarg == NULL || !isdigit(optarg[0])) + { usage("missing number of days"); + goto end; + } + else { char *endptr; long days = strtol(optarg, &endptr, 0); if (*endptr != '\0' || endptr == optarg || days <= 0) + { usage("<days> must be a positive number"); + goto end; + } validity += 24*3600*days; } continue; case 'H': /* --hours */ if (optarg == NULL || !isdigit(optarg[0])) + { usage("missing number of hours"); + goto end; + } + else { char *endptr; long hours = strtol(optarg, &endptr, 0); if (*endptr != '\0' || endptr == optarg || hours <= 0) + { usage("<hours> must be a positive number"); + goto end; + } validity += 3600*hours; } continue; case 'S': /* --startdate */ if (optarg == NULL || strlen(optarg) != 15 || optarg[14] != 'Z') + { usage("date format must be YYYYMMDDHHMMSSZ"); + goto end; + } + else { chunk_t date = { optarg, 15 }; + notBefore = asn1totime(&date, ASN1_GENERALIZEDTIME); } continue; case 'E': /* --enddate */ if (optarg == NULL || strlen(optarg) != 15 || optarg[14] != 'Z') + { usage("date format must be YYYYMMDDHHMMSSZ"); + goto end; + } + else { chunk_t date = { optarg, 15 }; notAfter = asn1totime(&date, ASN1_GENERALIZEDTIME); } continue; - case 'o': /* --outt */ + case 'o': /* --out */ outfile = optarg; continue; -#ifdef DEBUG - case 'A': /* --debug-all */ - base_debugging = DBG_ALL; + case 'd': /* --debug */ + debug_level = atoi(optarg); continue; -#endif + default: -#ifdef DEBUG - if (c >= DBG_OFFSET) - { - base_debugging |= c - DBG_OFFSET; - continue; - } -#undef DBG_OFFSET -#endif - bad_case(c); + usage(""); + status = 0; + goto end; } + /* break from loop */ break; } - init_log("openac"); - cur_debugging = base_debugging; - if (optind != argc) + { usage("unexpected argument"); + goto end; + } + + DBG1("starting openac (strongSwan Version %s)", VERSION); + +#ifdef INTEGRITY_TEST + DBG1("integrity test of libstrongswan code"); + if (fips_verify_hmac_signature(hmac_key, hmac_signature)) + { + DBG1(" integrity test passed"); + } + else + { + DBG1(" integrity test failed"); + status = 3; + goto end; + } +#endif /* INTEGRITY_TEST */ /* load the signer's RSA private key */ if (keyfile != NULL) { - err_t ugh = NULL; + signerkey = rsa_private_key_create_from_file(keyfile, &passphrase); - signerkey = alloc_thing(RSA_private_key_t, "RSA private key"); - ugh = load_rsa_private_key(keyfile, &pass, signerkey); - - if (ugh != NULL) + if (signerkey == NULL) { - free_RSA_private_content(signerkey); - pfree(signerkey); - plog("%s", ugh); - exit(1); + goto end; } } /* load the signer's X.509 certificate */ if (certfile != NULL) { - if (!load_cert(certfile, "signer cert", &signercert)) - exit(1); - signer = signercert.u.x509; + signercert = x509_create_from_file(certfile, "signer cert"); + + if (signercert == NULL) + { + goto end; + } } /* load the users's X.509 certificate */ if (usercertfile != NULL) { - if (!load_cert(usercertfile, "user cert", &usercert)) - exit(1); - user = usercert.u.x509; + usercert = x509_create_from_file(usercertfile, "user cert"); + + if (usercert == NULL) + { + goto end; + } } /* compute validity interval */ validity = (validity)? validity : default_validity; - notBefore = (notBefore) ? notBefore : time(NULL); - notAfter = (notAfter) ? notAfter : notBefore + validity; + notBefore = (notBefore == UNDEFINED_TIME) ? time(NULL) : notBefore; + notAfter = (notAfter == UNDEFINED_TIME) ? time(NULL) + validity : notAfter; /* build and parse attribute certificate */ - if (user != NULL && signer != NULL && signerkey != NULL) + if (usercert != NULL && signercert != NULL && signerkey != NULL) { /* read the serial number and increment it by one */ serial = read_serial(); attr_cert = build_attr_cert(); - ac = alloc_thing(x509acert_t, "x509acert"); - *ac = empty_ac; - parse_ac(attr_cert, ac); + ac = x509ac_create_from_chunk(attr_cert); /* write the attribute certificate to file */ - if (write_chunk(outfile, "attribute cert", attr_cert, 0022, TRUE)) - write_serial(serial); + if (chunk_write(attr_cert, outfile, "attribute cert", 0022, TRUE)) + { + write_serial(serial); + status = 0; + } } - /* delete all dynamic objects */ - if (signerkey != NULL) - { - free_RSA_private_content(signerkey); - pfree(signerkey); - } - free_x509cert(signercert.u.x509); - free_x509cert(usercert.u.x509); - free_ietfAttrList(groups); - free_acert(ac); - pfree(serial.ptr); - -#ifdef LEAK_DETECTIVE - report_leaks(); -#endif /* LEAK_DETECTIVE */ - close_log(); - exit(0); +end: + /* delete all dynamically allocated objects */ + DESTROY_IF(signerkey); + DESTROY_IF(signercert); + DESTROY_IF(usercert); + DESTROY_IF(ac); + ietfAttr_list_destroy(groups); + free(serial.ptr); + closelog(); + dbg = dbg_default; + exit(status); } |