This commit is contained in:
@@ -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
|
||||
@@ -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(¬Before, ASN1_GENERALIZEDTIME)
|
||||
, timetoasn1(¬After, 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);
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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.
|
||||
Executable
+438
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user