summaryrefslogtreecommitdiff
path: root/src/openac/openac.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/openac/openac.c')
-rwxr-xr-xsrc/openac/openac.c381
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);
}