diff options
author | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2006-05-22 05:12:18 +0000 |
---|---|---|
committer | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2006-05-22 05:12:18 +0000 |
commit | aa0f5b38aec14428b4b80e06f90ff781f8bca5f1 (patch) | |
tree | 95f3d0c8cb0d59d88900dbbd72110d7ab6e15b2a /programs/openac/openac.c | |
parent | 7c383bc22113b23718be89fe18eeb251942d7356 (diff) | |
download | vyos-strongswan-aa0f5b38aec14428b4b80e06f90ff781f8bca5f1.tar.gz vyos-strongswan-aa0f5b38aec14428b4b80e06f90ff781f8bca5f1.zip |
Import initial strongswan 2.7.0 version into SVN.
Diffstat (limited to 'programs/openac/openac.c')
-rwxr-xr-x | programs/openac/openac.c | 438 |
1 files changed, 438 insertions, 0 deletions
diff --git a/programs/openac/openac.c b/programs/openac/openac.c new file mode 100755 index 000000000..524a302d7 --- /dev/null +++ b/programs/openac/openac.c @@ -0,0 +1,438 @@ +/* Generation of X.509 attribute certificates + * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler + * Copyright (C) 2004 Andreas Steffen + * Zuercher Hochschule Winterthur, 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 + * 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. + * + * RCSID $Id: openac.c,v 1.18 2006/01/04 21:12:33 as Exp $ + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <getopt.h> +#include <ctype.h> +#include <time.h> +#include <gmp.h> + +#include <freeswan.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" + +#include "build.h" + +#define OPENAC_PATH "/etc/openac" +#define OPENAC_SERIAL "/etc/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) +{ + if (mess != NULL && *mess != '\0') + fprintf(stderr, "%s\n", mess); + fprintf(stderr + , "Usage: openac" + " [--help]" + " [--version]" + " [--optionsfrom <filename>]" + " [--quiet]" +#ifdef DEBUG + " \\\n\t" + " [--debug-all]" + " [--debug-parsing]" + " [--debug-raw]" + " [--debug-private]" +#endif + " \\\n\t" + " [--days <days>]" + " [--hours <hours>]" + " \\\n\t" + " [--startdate <YYYYMMDDHHMMSSZ>]" + " [--enddate <YYYYMMDDHHMMSSZ>]" + " \\\n\t" + " --cert <certfile>" + " --key <keyfile>" + " [--password <password>]" + " \\\n\t" + " --usercert <certfile>" + " --groups <attr1,attr2,..>" + " --out <filename>" + "\n" + ); + exit(mess == NULL? 0 : 1); +} + +/* + * read the last serial number from file + */ +static chunk_t +read_serial(void) +{ + MP_INT number; + + char buf[BUF_LEN]; + char bytes[BUF_LEN]; + + FILE *fd = fopen(OPENAC_SERIAL, "r"); + + /* serial number defaults to 0 */ + size_t len = 1; + bytes[0] = 0x00; + + if (fd) + { + if (fscanf(fd, "%s", buf)) + { + err_t ugh = ttodata(buf, 0, 16, bytes, BUF_LEN, &len); + + if (ugh != NULL) + plog(" 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); + + /* conversion of read serial number to a multiprecision integer + * 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); + + return serial; +} + +/* + * write back the last serial number to file + */ +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); + fclose(fd); + } + else + plog(" 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; + +ietfAttrList_t *groups = NULL; +struct RSA_private_key *signerkey = NULL; + +time_t notBefore = 0; +time_t notAfter = 0; + +chunk_t serial; + + +int +main(int argc, char **argv) +{ + char *keyfile = NULL; + char *certfile = NULL; + char *usercertfile = NULL; + char *outfile = NULL; + + cert_t signercert = empty_cert; + cert_t usercert = empty_cert; + + chunk_t attr_cert = empty_chunk; + x509acert_t *ac = NULL; + + const time_t default_validity = 24*3600; /* 24 hours */ + time_t validity = 0; + + prompt_pass_t pass; + + pass.secret[0] = '\0'; + pass.prompt = TRUE; + pass.fd = STDIN_FILENO; + + log_to_stderr = TRUE; + + /* handle arguments */ + for (;;) + { +# define DBG_OFFSET 256 + static const struct option long_opts[] = { + /* name, has_arg, flag, val */ + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'v' }, + { "optionsfrom", required_argument, NULL, '+' }, + { "quiet", no_argument, NULL, 'q' }, + { "cert", required_argument, NULL, 'c' }, + { "key", required_argument, NULL, 'k' }, + { "password", required_argument, NULL, 'p' }, + { "usercert", required_argument, NULL, 'u' }, + { "groups", required_argument, NULL, 'g' }, + { "days", required_argument, NULL, 'D' }, + { "hours", required_argument, NULL, 'H' }, + { "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 + { 0,0,0,0 } + }; + + int c = getopt_long(argc, argv, "hv+:qc:k:p;u:g:D:H:S:E:o:", long_opts, NULL); + + /* Note: "breaking" from case terminates loop */ + switch (c) + { + case EOF: /* end of flags */ + break; + + case 0: /* long option already handled */ + continue; + + 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 */ + + case 'v': /* --version */ + printf("%s\n", openac_version); + exit(0); + break; /* not actually reached */ + + 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 */ + } + continue; + + case 'q': /* --quiet */ + log_to_stderr = TRUE; + continue; + + case 'c': /* --cert */ + certfile = optarg; + continue; + + case 'k': /* --key */ + keyfile = optarg; + continue; + + case 'p': /* --key */ + pass.prompt = FALSE; + strncpy(pass.secret, optarg, sizeof(pass.secret)); + continue; + + case 'u': /* --usercert */ + usercertfile = optarg; + continue; + + case 'g': /* --groups */ + decode_groups(optarg, &groups); + continue; + + case 'D': /* --days */ + if (optarg == NULL || !isdigit(optarg[0])) + usage("missing number of days"); + { + char *endptr; + long days = strtol(optarg, &endptr, 0); + + if (*endptr != '\0' || endptr == optarg + || days <= 0) + usage("<days> must be a positive number"); + validity += 24*3600*days; + } + continue; + + case 'H': /* --hours */ + if (optarg == NULL || !isdigit(optarg[0])) + usage("missing number of hours"); + { + char *endptr; + long hours = strtol(optarg, &endptr, 0); + + if (*endptr != '\0' || endptr == optarg + || hours <= 0) + usage("<hours> must be a positive number"); + validity += 3600*hours; + } + continue; + + case 'S': /* --startdate */ + if (optarg == NULL || strlen(optarg) != 15 || optarg[14] != 'Z') + usage("date format must be YYYYMMDDHHMMSSZ"); + { + 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"); + { + chunk_t date = { optarg, 15 }; + notAfter = asn1totime(&date, ASN1_GENERALIZEDTIME); + } + continue; + + case 'o': /* --outt */ + outfile = optarg; + continue ; + +#ifdef DEBUG + case 'A': /* --debug-all */ + base_debugging = DBG_ALL; + continue; +#endif + default: +#ifdef DEBUG + if (c >= DBG_OFFSET) + { + base_debugging |= c - DBG_OFFSET; + continue; + } +#undef DBG_OFFSET +#endif + bad_case(c); + } + break; + } + + init_log("openac"); + cur_debugging = base_debugging; + + if (optind != argc) + usage("unexpected argument"); + + /* load the signer's RSA private key */ + if (keyfile != NULL) + { + err_t ugh = NULL; + + signerkey = alloc_thing(RSA_private_key_t, "RSA private key"); + ugh = load_rsa_private_key(keyfile, &pass, signerkey); + + if (ugh != NULL) + { + free_RSA_private_content(signerkey); + pfree(signerkey); + plog("%s", ugh); + exit(1); + } + } + + /* load the signer's X.509 certificate */ + if (certfile != NULL) + { + if (!load_cert(certfile, "signer cert", &signercert)) + exit(1); + signer = signercert.u.x509; + } + + /* load the users's X.509 certificate */ + if (usercertfile != NULL) + { + if (!load_cert(usercertfile, "user cert", &usercert)) + exit(1); + user = usercert.u.x509; + } + + /* compute validity interval */ + validity = (validity)? validity : default_validity; + notBefore = (notBefore) ? notBefore : time(NULL); + notAfter = (notAfter) ? notAfter : notBefore + validity; + + /* build and parse attribute certificate */ + if (user != NULL && signer != 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); + + /* write the attribute certificate to file */ + if (write_chunk(outfile, "attribute cert", attr_cert, 0022, TRUE)) + write_serial(serial); + } + + /* 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); +} |