This commit is contained in:
Martin Willi
2006-04-28 10:51:19 +00:00
parent 51c3484a9f
commit 1029d84d23
514 changed files with 2 additions and 2 deletions
+154
View File
@@ -0,0 +1,154 @@
# Makefile for the openac attribute certificate generation tool
# Copyright (C) 2004 Andreas Steffen
# Zuercher Hochschule Winterthur
#
# 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: Makefile,v 1.16 2006/02/17 19:33:27 as Exp $
FREESWANSRCDIR=../..
include ${FREESWANSRCDIR}/Makefile.inc
CONFDIR=$(DESTDIR)/etc/openac
PLUTODIR=../pluto
PROGRAM=openac
EXTRA8PROC=${PROGRAM}.8
LIBS=${FREESWANLIB} $(LIBDESLITE) -lgmp
CFLAGS+= -DDEBUG -DNO_PLUTO
# This compile option activates the leak detective
ifeq ($(USE_LEAK_DETECTIVE),true)
CFLAGS+= -DLEAK_DETECTIVE
endif
X509_OBJS= ac.o asn1.o ca.o certs.o constants.o crl.o defs.o mp_defs.o fetch.o \
id.o keys.o lex.o md2.o md5.o ocsp.o oid.o pem.o pgp.o pkcs1.o \
rnd.o sha1.o smartcard.o x509.o
OBJS= build.o loglite.o ${X509_OBJS}
include ../Makefile.program
build.o : build.c build.h
$(CC) $(CFLAGS) -c -o $@ $<
loglite.o : loglite.c $(PLUTODIR)/log.h
$(CC) $(CFLAGS) -c -o $@ $<
# X.509 library
ac.o : $(PLUTODIR)/ac.c $(PLUTODIR)/ac.h
$(CC) $(CFLAGS) -c -o $@ $<
asn1.o : $(PLUTODIR)/asn1.c $(PLUTODIR)/asn1.h
$(CC) $(CFLAGS) -c -o $@ $<
ca.o : $(PLUTODIR)/ca.c $(PLUTODIR)/ca.h
$(CC) $(CFLAGS) -c -o $@ $<
certs.o : $(PLUTODIR)/certs.c $(PLUTODIR)/certs.h
$(CC) $(CFLAGS) -c -o $@ $<
constants.o : $(PLUTODIR)/constants.c $(PLUTODIR)/constants.h
$(CC) $(CFLAGS) -c -o $@ $<
crl.o : $(PLUTODIR)/crl.c $(PLUTODIR)/crl.h
$(CC) $(CFLAGS) -c -o $@ $<
defs.o : $(PLUTODIR)/defs.c $(PLUTODIR)/defs.h
$(CC) $(CFLAGS) -c -o $@ $<
mp_defs.o : $(PLUTODIR)/mp_defs.c $(PLUTODIR)/mp_defs.h
$(CC) $(CFLAGS) -c -o $@ $<
fetch.o : $(PLUTODIR)/fetch.c $(PLUTODIR)/fetch.h
$(CC) $(CFLAGS) -c -o $@ $<
id.o : $(PLUTODIR)/id.c $(PLUTODIR)/id.h
$(CC) $(CFLAGS) -c -o $@ $<
keys.o : $(PLUTODIR)/keys.c $(PLUTODIR)/keys.h
$(CC) $(CFLAGS) -c -o $@ $<
lex.o : $(PLUTODIR)/lex.c $(PLUTODIR)/lex.h
$(CC) $(CFLAGS) -c -o $@ $<
md2.o : $(PLUTODIR)/md2.c $(PLUTODIR)/md2.h
$(CC) $(CFLAGS) -c -o $@ $<
md5.o : $(PLUTODIR)/md5.c $(PLUTODIR)/md5.h
$(CC) $(CFLAGS) -c -o $@ $<
ocsp.o : $(PLUTODIR)/ocsp.c $(PLUTODIR)/ocsp.h
$(CC) $(CFLAGS) -c -o $@ $<
oid.o : $(PLUTODIR)/oid.c $(PLUTODIR)/oid.h
$(CC) $(CFLAGS) -c -o $@ $<
pem.o : $(PLUTODIR)/pem.c $(PLUTODIR)/pem.h
$(CC) $(CFLAGS) -c -o $@ $<
pgp.o : $(PLUTODIR)/pgp.c $(PLUTODIR)/pgp.h
$(CC) $(CFLAGS) -c -o $@ $<
pkcs1.o : $(PLUTODIR)/pkcs1.c $(PLUTODIR)/pkcs1.h
$(CC) $(CFLAGS) -c -o $@ $<
rnd.o : $(PLUTODIR)/rnd.c $(PLUTODIR)/rnd.h
$(CC) $(CFLAGS) -c -o $@ $<
sha1.o : $(PLUTODIR)/sha1.c $(PLUTODIR)/sha1.h
$(CC) $(CFLAGS) -c -o $@ $<
smartcard.o : $(PLUTODIR)/smartcard.c $(PLUTODIR)/smartcard.h
$(CC) $(CFLAGS) -c -o $@ $<
x509.o : $(PLUTODIR)/x509.c $(PLUTODIR)/x509.h
$(CC) $(CFLAGS) -c -o $@ $<
# Stolen from pluto/Makefile
gatherdeps:
@ls | grep '\.c$$' | sed -e 's/\(.*\)\.c$$/\1.o: \1.c/'
@echo
@ls | grep '\.c$$' | xargs grep '^#[ ]*include[ ]*"' | \
sed -e 's/\.c:#[ ]*include[ ]*"/.o: /' -e 's/".*//'
# Dependencies generated by "make gatherdeps":
build.o: build.c
loglite.o: loglite.c
openac.o: openac.c
build.o: ../pluto/constants.h
build.o: ../pluto/defs.h
build.o: ../pluto/oid.h
build.o: ../pluto/asn1.h
build.o: ../pluto/x509.h
build.o: ../pluto/log.h
build.o: build.h
loglite.o: ../pluto/constants.h
loglite.o: ../pluto/defs.h
loglite.o: ../pluto/log.h
loglite.o: ../pluto/whack.h
openac.o: ../pluto/constants.h
openac.o: ../pluto/defs.h
openac.o: ../pluto/mp_defs.h
openac.o: ../pluto/log.h
openac.o: ../pluto/asn1.h
openac.o: ../pluto/certs.h
openac.o: ../pluto/x509.h
openac.o: ../pluto/crl.h
openac.o: ../pluto/keys.h
openac.o: ../pluto/ac.h
openac.o: build.h
+242
View File
@@ -0,0 +1,242 @@
/* Build a X.509 attribute certificate
* 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: build.c,v 1.14 2005/09/06 11:47:57 as Exp $
*/
#include <stdlib.h>
#include <string.h>
#include <freeswan.h>
#include "../pluto/constants.h"
#include "../pluto/defs.h"
#include "../pluto/oid.h"
#include "../pluto/asn1.h"
#include "../pluto/x509.h"
#include "../pluto/log.h"
#include "build.h"
static u_char ASN1_group_oid_str[] = {
0x06, 0x08,
0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x0a ,0x04
};
static const chunk_t ASN1_group_oid = strchunk(ASN1_group_oid_str);
static u_char ASN1_authorityKeyIdentifier_oid_str[] = {
0x06, 0x03,
0x55, 0x1d, 0x23
};
static const chunk_t ASN1_authorityKeyIdentifier_oid
= strchunk(ASN1_authorityKeyIdentifier_oid_str);
static u_char ASN1_noRevAvail_ext_str[] = {
0x30, 0x09,
0x06, 0x03,
0x55, 0x1d, 0x38,
0x04, 0x02,
0x05, 0x00
};
static const chunk_t ASN1_noRevAvail_ext = strchunk(ASN1_noRevAvail_ext_str);
/*
* build directoryName
*/
static chunk_t
build_directoryName(asn1_t tag, chunk_t name)
{
return asn1_wrap(tag, "m"
, asn1_simple_object(ASN1_CONTEXT_C_4, name));
}
/*
* build holder
*/
static chunk_t
build_holder(void)
{
return asn1_wrap(ASN1_SEQUENCE, "mm"
, asn1_wrap(ASN1_CONTEXT_C_0, "mm"
, build_directoryName(ASN1_SEQUENCE, user->issuer)
, asn1_simple_object(ASN1_INTEGER, user->serialNumber)
)
, build_directoryName(ASN1_CONTEXT_C_1, user->subject));
}
/*
* build v2Form
*/
static chunk_t
build_v2_form(void)
{
return asn1_wrap(ASN1_CONTEXT_C_0, "m"
, build_directoryName(ASN1_SEQUENCE, signer->subject));
}
/*
* build attrCertValidityPeriod
*/
static chunk_t
build_attr_cert_validity(void)
{
return asn1_wrap(ASN1_SEQUENCE, "mm"
, timetoasn1(&notBefore, ASN1_GENERALIZEDTIME)
, timetoasn1(&notAfter, ASN1_GENERALIZEDTIME));
}
/*
* build attributes
*/
static chunk_t
build_ietfAttributes(ietfAttrList_t *list)
{
chunk_t ietfAttributes;
ietfAttrList_t *item = list;
size_t size = 0;
u_char *pos;
/* precalculate the total size of all values */
while (item != NULL)
{
size_t len = item->attr->value.len;
size += 1 + (len > 0) + (len >= 128) + (len >= 256) + (len >= 65536) + len;
item = item->next;
}
pos = build_asn1_object(&ietfAttributes, ASN1_SEQUENCE, size);
while (list != NULL)
{
ietfAttr_t *attr = list->attr;
asn1_t type = ASN1_NULL;
switch (attr->kind)
{
case IETF_ATTRIBUTE_OCTETS:
type = ASN1_OCTET_STRING;
break;
case IETF_ATTRIBUTE_STRING:
type = ASN1_UTF8STRING;
break;
case IETF_ATTRIBUTE_OID:
type = ASN1_OID;
break;
}
mv_chunk(&pos, asn1_simple_object(type, attr->value));
list = list->next;
}
return asn1_wrap(ASN1_SEQUENCE, "m", ietfAttributes);
}
/*
* build attribute type
*/
static chunk_t
build_attribute_type(const chunk_t type, chunk_t content)
{
return asn1_wrap(ASN1_SEQUENCE, "cm"
, type
, asn1_wrap(ASN1_SET, "m", content));
}
/*
* build attributes
*/
static chunk_t
build_attributes(void)
{
return asn1_wrap(ASN1_SEQUENCE, "m"
, build_attribute_type(ASN1_group_oid
, build_ietfAttributes(groups)));
}
/*
* build authorityKeyIdentifier
*/
static chunk_t
build_authorityKeyID(x509cert_t *signer)
{
chunk_t keyIdentifier = (signer->subjectKeyID.ptr == NULL)
? empty_chunk
: asn1_simple_object(ASN1_CONTEXT_S_0
, signer->subjectKeyID);
chunk_t authorityCertIssuer = build_directoryName(ASN1_CONTEXT_C_1
, signer->issuer);
chunk_t authorityCertSerialNumber = asn1_simple_object(ASN1_CONTEXT_S_2
, signer->serialNumber);
return asn1_wrap(ASN1_SEQUENCE, "cm"
, ASN1_authorityKeyIdentifier_oid
, asn1_wrap(ASN1_OCTET_STRING, "m"
, asn1_wrap(ASN1_SEQUENCE, "mmm"
, keyIdentifier
, authorityCertIssuer
, authorityCertSerialNumber
)
)
);
}
/*
* build extensions
*/
static chunk_t
build_extensions(void)
{
return asn1_wrap(ASN1_SEQUENCE, "mc"
, build_authorityKeyID(signer)
, ASN1_noRevAvail_ext);
}
/*
* build attributeCertificateInfo
*/
static chunk_t
build_attr_cert_info(void)
{
return asn1_wrap(ASN1_SEQUENCE, "cmmcmmmm"
, ASN1_INTEGER_1
, build_holder()
, build_v2_form()
, ASN1_sha1WithRSA_id
, asn1_simple_object(ASN1_INTEGER, serial)
, build_attr_cert_validity()
, build_attributes()
, build_extensions());
}
/*
* build an X.509 attribute certificate
*/
chunk_t
build_attr_cert(void)
{
chunk_t attributeCertificateInfo = build_attr_cert_info();
chunk_t signatureValue = pkcs1_build_signature(attributeCertificateInfo
, OID_SHA1, signerkey, TRUE);
return asn1_wrap(ASN1_SEQUENCE, "mcm"
, attributeCertificateInfo
, ASN1_sha1WithRSA_id
, signatureValue);
}
+47
View File
@@ -0,0 +1,47 @@
/* Build a X.509 attribute certificate
* 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: build.h,v 1.4 2004/11/03 14:28:52 as Exp $
*/
#ifndef _BUILD_H
#define _BUILD_H
#include <time.h>
#include "../pluto/x509.h"
#include "../pluto/keys.h"
#include "../pluto/ac.h"
/*
* global variables accessible by both main() and build.c
*/
extern x509cert_t *user;
extern x509cert_t *signer;
extern ietfAttrList_t *groups;
extern struct RSA_private_key *signerkey;
extern time_t notBefore;
extern time_t notAfter;
extern chunk_t serial;
/*
* exported functions
*/
extern chunk_t build_attr_cert(void);
#endif /* _BUILD_H */
+295
View File
@@ -0,0 +1,295 @@
/* error logging functions
* Copyright (C) 1997 Angelos D. Keromytis.
* Copyright (C) 1998-2001 D. Hugh Redelmeier.
*
* 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: loglite.c,v 1.2 2005/07/11 18:38:16 as Exp $
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdarg.h>
#include <syslog.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <signal.h> /* used only if MSG_NOSIGNAL not defined */
#include <libgen.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <freeswan.h>
#include "../pluto/constants.h"
#include "../pluto/defs.h"
#include "../pluto/log.h"
#include "../pluto/whack.h"
bool
log_to_stderr = FALSE, /* should log go to stderr? */
log_to_syslog = TRUE; /* should log go to syslog? */
void
init_log(const char *program)
{
if (log_to_stderr)
setbuf(stderr, NULL);
if (log_to_syslog)
openlog(program, LOG_CONS | LOG_NDELAY | LOG_PID, LOG_AUTHPRIV);
}
void
close_log(void)
{
if (log_to_syslog)
closelog();
}
void
plog(const char *message, ...)
{
va_list args;
char m[LOG_WIDTH]; /* longer messages will be truncated */
va_start(args, message);
vsnprintf(m, sizeof(m), message, args);
va_end(args);
if (log_to_stderr)
fprintf(stderr, "%s\n", m);
if (log_to_syslog)
syslog(LOG_WARNING, "%s", m);
}
void
loglog(int mess_no, const char *message, ...)
{
va_list args;
char m[LOG_WIDTH]; /* longer messages will be truncated */
va_start(args, message);
vsnprintf(m, sizeof(m), message, args);
va_end(args);
if (log_to_stderr)
fprintf(stderr, "%s\n", m);
if (log_to_syslog)
syslog(LOG_WARNING, "%s", m);
}
void
log_errno_routine(int e, const char *message, ...)
{
va_list args;
char m[LOG_WIDTH]; /* longer messages will be truncated */
va_start(args, message);
vsnprintf(m, sizeof(m), message, args);
va_end(args);
if (log_to_stderr)
fprintf(stderr, "ERROR: %s. Errno %d: %s\n", m, e, strerror(e));
if (log_to_syslog)
syslog(LOG_ERR, "ERROR: %s. Errno %d: %s", m, e, strerror(e));
}
void
exit_log(const char *message, ...)
{
va_list args;
char m[LOG_WIDTH]; /* longer messages will be truncated */
va_start(args, message);
vsnprintf(m, sizeof(m), message, args);
va_end(args);
if (log_to_stderr)
fprintf(stderr, "FATAL ERROR: %s\n", m);
if (log_to_syslog)
syslog(LOG_ERR, "FATAL ERROR: %s", m);
exit(1);
}
void
exit_log_errno_routine(int e, const char *message, ...)
{
va_list args;
char m[LOG_WIDTH]; /* longer messages will be truncated */
va_start(args, message);
vsnprintf(m, sizeof(m), message, args);
va_end(args);
if (log_to_stderr)
fprintf(stderr, "FATAL ERROR: %s. Errno %d: %s\n", m, e, strerror(e));
if (log_to_syslog)
syslog(LOG_ERR, "FATAL ERROR: %s. Errno %d: %s", m, e, strerror(e));
exit(1);
}
void
whack_log(int mess_no, const char *message, ...)
{
va_list args;
char m[LOG_WIDTH]; /* longer messages will be truncated */
va_start(args, message);
vsnprintf(m, sizeof(m), message, args);
va_end(args);
fprintf(stderr, "%s\n", m);
}
/* Build up a diagnostic in a static buffer.
* Although this would be a generally useful function, it is very
* hard to come up with a discipline that prevents different uses
* from interfering. It is intended that by limiting it to building
* diagnostics, we will avoid this problem.
* Juggling is performed to allow an argument to be a previous
* result: the new string may safely depend on the old one. This
* restriction is not checked in any way: violators will produce
* confusing results (without crashing!).
*/
char diag_space[sizeof(diag_space)];
err_t
builddiag(const char *fmt, ...)
{
static char diag_space[LOG_WIDTH]; /* longer messages will be truncated */
char t[sizeof(diag_space)]; /* build result here first */
va_list args;
va_start(args, fmt);
t[0] = '\0'; /* in case nothing terminates string */
vsnprintf(t, sizeof(t), fmt, args);
va_end(args);
strcpy(diag_space, t);
return diag_space;
}
/* Debugging message support */
#ifdef DEBUG
void
switch_fail(int n, const char *file_str, unsigned long line_no)
{
char buf[30];
snprintf(buf, sizeof(buf), "case %d unexpected", n);
passert_fail(buf, file_str, line_no);
}
void
passert_fail(const char *pred_str, const char *file_str, unsigned long line_no)
{
/* we will get a possibly unplanned prefix. Hope it works */
loglog(RC_LOG_SERIOUS, "ASSERTION FAILED at %s:%lu: %s", file_str, line_no, pred_str);
abort(); /* exiting correctly doesn't always work */
}
lset_t
base_debugging = DBG_NONE, /* default to reporting nothing */
cur_debugging = DBG_NONE;
void
pexpect_log(const char *pred_str, const char *file_str, unsigned long line_no)
{
/* we will get a possibly unplanned prefix. Hope it works */
loglog(RC_LOG_SERIOUS, "EXPECTATION FAILED at %s:%lu: %s", file_str, line_no, pred_str);
}
/* log a debugging message (prefixed by "| ") */
void
DBG_log(const char *message, ...)
{
va_list args;
char m[LOG_WIDTH]; /* longer messages will be truncated */
va_start(args, message);
vsnprintf(m, sizeof(m), message, args);
va_end(args);
if (log_to_stderr)
fprintf(stderr, "| %s\n", m);
if (log_to_syslog)
syslog(LOG_DEBUG, "| %s", m);
}
/* dump raw bytes in hex to stderr (for lack of any better destination) */
void
DBG_dump(const char *label, const void *p, size_t len)
{
# define DUMP_LABEL_WIDTH 20 /* arbitrary modest boundary */
# define DUMP_WIDTH (4 * (1 + 4 * 3) + 1)
char buf[DUMP_LABEL_WIDTH + DUMP_WIDTH];
char *bp;
const unsigned char *cp = p;
bp = buf;
if (label != NULL && label[0] != '\0')
{
/* Handle the label. Care must be taken to avoid buffer overrun. */
size_t llen = strlen(label);
if (llen + 1 > sizeof(buf))
{
DBG_log("%s", label);
}
else
{
strcpy(buf, label);
if (buf[llen-1] == '\n')
{
buf[llen-1] = '\0'; /* get rid of newline */
DBG_log("%s", buf);
}
else if (llen < DUMP_LABEL_WIDTH)
{
bp = buf + llen;
}
else
{
DBG_log("%s", buf);
}
}
}
do {
int i, j;
for (i = 0; len!=0 && i!=4; i++)
{
*bp++ = ' ';
for (j = 0; len!=0 && j!=4; len--, j++)
{
static const char hexdig[] = "0123456789abcdef";
*bp++ = ' ';
*bp++ = hexdig[(*cp >> 4) & 0xF];
*bp++ = hexdig[*cp & 0xF];
cp++;
}
}
*bp = '\0';
DBG_log("%s", buf);
bp = buf;
} while (len != 0);
# undef DUMP_LABEL_WIDTH
# undef DUMP_WIDTH
}
#endif /* DEBUG */
+180
View File
@@ -0,0 +1,180 @@
.TH IPSEC_OPENAC 8 "29 September 2005"
.SH NAME
ipsec openac \- Generation of X.509 attribute certificates
.SH SYNOPSIS
.B ipsec
.B openac
[
.B \-\-help
] [
.B \-\-version
] [
.B \-\-optionsfrom
\fIfilename\fP
] [
.B \-\-quiet
]
.br
\ \ \ [
.B \-\-debug\(hyall
] [
.B \-\-debug\(hyparsing
] [
.B \-\-debug\(hyraw
] [
.B \-\-debug\(hyprivate
]
.br
\ \ \ [
.B \-\-days
\fIdays\fP
] [
.B \-\-hours
\fIhours\fP
]
.br
\ \ \ [
.B \-\-startdate
\fIYYYYMMDDHHMMSSZ\fP
] [
.B \-\-stopdate
\fIYYYYMMDDHHMMSSZ\fP
]
.br
.B \ \ \ \-\-cert
\fIcertfile\fP
.B \-\-key
\fIkeyfile\fP
[
.B \-\-password
\fIpassword\fP
]
.br
.B \ \ \ \-\-usercert
\fIcertfile\fP
.B \-\-groups
\fIattr1,attr2,...\fP
.B \-\-out
\fIfilename\fP
.SH DESCRIPTION
.BR openac
is intended to be used by an Authorization Authority (AA) to generate and sign
X.509 attribute certificates. Currently only the inclusion of one ore several group
attributes is supported. An attribute certificate is linked to a holder by
including the issuer and serial number of the holder's X.509 certificate.
.SH OPTIONS
.TP
\fB\-\-help\fP
display the usage message.
.TP
\fB\-\-version\fP
display the version of \fBopenac\fP.
.TP
\fB\-\-optionsfrom\fP\ \fIfilename\fP
adds the contents of the file to the argument list.
If \fIfilename\fP is a relative path then the file is searched in the directory
\fI/etc/openac\fP.
.TP
\fB\-\-quiet\fP
By default \fBopenac\fP logs all control output both to syslog and stderr.
With the \fB\-\-quiet\fP option no output is written to stderr.
.TP
\fB\-\-days\fP\ \fIdays\fP
Validity of the X.509 attribute certificate in days. If neiter the \fB\-\-days\fP\ nor
the \fB\-\-hours\fP\ option is specified then a default validity interval of 1 day is assumed.
The \fB\-\-days\fP\ option can be combined with the \fB\-\-hours\fP\ option.
.TP
\fB\-\-hours\fP\ \fIhours\fP
Validity of the X.509 attribute certificate in hours. If neiter the \fB\-\-hours\fP\ nor
the \fB\-\-days\fP\ option is specified then a default validity interval of 24 hours is assumed.
The \fB\-\-hours\fP\ option can be combined with the \fB\-\-days\fP\ option.
.TP
\fB\-\-startdate\fP\ \fIYYYYMMDDHHMMSSZ\fP
defines the \fBnotBefore\fP date when the X.509 attribute certificate becomes valid.
The date \fIYYYYMMDDHHMMSS\fP must be specified in UTC (\fIZ\fPulu time).
If the \fB\-\-startdate\fP option is not specified then the current date is taken as a default.
.TP
\fB\-\-stopdate\fP\ \fIYYYYMMDDHHMMSSZ\fP
defines the \fBnotAfter\fP date when the X.509 attribute certificate will expire.
The date \fIYYYYMMDDHHMMSS\fP must be specified in UTC (\fIZ\fPulu time).
If the \fB\-\-stopdate\fP option is not specified then the default \fBnotAfter\fP value is computed
by adding the validity interval specified by the \fB\-\-days\fP\ and/or \fB\-\-days\fP\ options
to the \fBnotBefore\fP date.
.TP
\fB\-\-cert\fP\ \fIcertfile\fP
specifies the file containing the X.509 certificate of the Authorization Authority.
The certificate is stored either in PEM or DER format.
.TP
\fB\-\-key\fP\ \fIkeyfile\fP
specifies the encrypted file containing the private RSA key of the Authoritzation
Authority. The private key is stored in PKCS#1 format.
.TP
\fB\-\-password\fP\ \fIpassword\fP
specifies the password with which the private RSA keyfile defined by the
\fB\-\-key\fP option has been protected. If the option is missing then the
password is prompted for on the command line.
.TP
\fB\-\-usercert\fP\ \fIcertfile\fP
specifies file containing the X.509 certificate of the user to which the generated attribute
certificate will apply. The certificate file is stored either in PEM or DER format.
.TP
\fB\-\-groups\fP\ \fIattr1,attr2\fP
specifies a comma-separated list of group attributes that will go into the
X.509 attribute certificate.
.TP
\fB\-\-out\fP\ \fIfilename\fP
specifies the file where the generated X.509 attribute certificate will be stored to.
.SS Debugging
.LP
\fBopenac\fP produces a prodigious amount of debugging information. To do so,
it must be compiled with \-DDEBUG. There are several classes of debugging output,
and \fBopenac\fP may be directed to produce a selection of them. All lines of
debugging output are prefixed with ``|\ '' to distinguish them from error messages.
.LP
When \fBopenac\fP is invoked, it may be given arguments to specify
which classes to output. The current options are:
.TP
\fB\-\-debug-raw\fP
show the raw bytes of the parsed user and authorization authority certificates
as well as of the generated X.509 attribute certificate.
.TP
\fB\-\-debug-parsing\fP
show the parsed structure of user and authorization authority certificats
as well as of the generated X.509 attribute certificate.
.TP
\fB\-\-debug-all\fP
all of the above.
.TP
\fB\-\-debug-private\fP
enables debugging output of the authorization authority's private key.
.SH EXIT STATUS
.LP
The execution of \fBopenac\fP terminates with one of the following two exit codes:
.TP
0
means that the attribute certificate was successfully generated and stored.
.TP
1
means that something went wrong.
.SH FILES
\fI/etc/openac/serial\fP\ \ \ serial number of latest attribute certificate
.SH SEE ALSO
.LP
The X.509 attribute certificates generated with \fBopenac\fP can be used to
enforce group policies defined by \fIipsec.conf\fP(5). Use \fIipsec_auto\fP(8)
to load and list X.509 attribute certificates.
.LP
For more information on X.509 attribute certificates, refer to the following
IETF RFC:
.IP
RFC 3281 An Internet Attribute Certificate Profile for Authorization
.SH HISTORY
The \fBopenac\fP program was originally written by Ariane Seiler and Ueli Galizzi.
The software was recoded by Andreas Steffen using strongSwan's X.509 library and
the ASN.1 code synthesis functions written by Christoph Gysin and Christoph Zwahlen.
All authors were with the Zurich University of Applied Sciences in Winterthur,
Switzerland.
.LP
.SH BUGS
Bugs should be reported to the <[email protected]> mailing list.
+438
View File
@@ -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);
}