refactored openac and its attribute certificate factory
This commit is contained in:
@@ -34,6 +34,7 @@ credentials/keys/public_key.c credentials/keys/public_key.h \
|
|||||||
credentials/keys/shared_key.c credentials/keys/shared_key.h \
|
credentials/keys/shared_key.c credentials/keys/shared_key.h \
|
||||||
credentials/certificates/certificate.c credentials/certificates/certificate.h \
|
credentials/certificates/certificate.c credentials/certificates/certificate.h \
|
||||||
credentials/certificates/x509.h credentials/certificates/x509.c \
|
credentials/certificates/x509.h credentials/certificates/x509.c \
|
||||||
|
credentials/certificates/ac.h \
|
||||||
credentials/certificates/crl.h credentials/certificates/crl.c \
|
credentials/certificates/crl.h credentials/certificates/crl.c \
|
||||||
credentials/certificates/ocsp_request.h credentials/certificates/ocsp_request.c \
|
credentials/certificates/ocsp_request.h credentials/certificates/ocsp_request.c \
|
||||||
credentials/certificates/ocsp_response.h credentials/certificates/ocsp_response.c \
|
credentials/certificates/ocsp_response.h credentials/certificates/ocsp_response.c \
|
||||||
|
|||||||
@@ -56,6 +56,10 @@ enum builder_part_t {
|
|||||||
BUILD_ISSUER,
|
BUILD_ISSUER,
|
||||||
/** additional issuer name, identification_t* */
|
/** additional issuer name, identification_t* */
|
||||||
BUILD_ISSUER_ALTNAME,
|
BUILD_ISSUER_ALTNAME,
|
||||||
|
/** notBefore, time_t* */
|
||||||
|
BUILD_NOT_BEFORE_TIME,
|
||||||
|
/** notAfter, time_t* */
|
||||||
|
BUILD_NOT_AFTER_TIME,
|
||||||
/** a CA certificate, certificate_t* */
|
/** a CA certificate, certificate_t* */
|
||||||
BUILD_CA_CERT,
|
BUILD_CA_CERT,
|
||||||
/** a certificate, certificate_t* */
|
/** a certificate, certificate_t* */
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2002 Ueli Galizzi, Ariane Seiler
|
||||||
|
* Copyright (C) 2003 Martin Berner, Lukas Suter
|
||||||
|
* Copyright (C) 2007 Andreas Steffen
|
||||||
|
*
|
||||||
|
* Hochschule fuer Technik Rapperswil
|
||||||
|
*
|
||||||
|
* 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: ac.h 3300 2007-10-12 21:53:18Z andreas $
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup ac ac
|
||||||
|
* @{ @ingroup certificates
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef AC_H_
|
||||||
|
#define AC_H_
|
||||||
|
|
||||||
|
#include <library.h>
|
||||||
|
#include <credentials/certificates/certificate.h>
|
||||||
|
|
||||||
|
typedef struct ac_t ac_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* X.509 attribute certificate interface.
|
||||||
|
*
|
||||||
|
* This interface adds additional methods to the certificate_t type to
|
||||||
|
* allow further operations on these certificates.
|
||||||
|
*/
|
||||||
|
struct ac_t {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements the certificate_t interface
|
||||||
|
*/
|
||||||
|
certificate_t certificate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if two attribute certificates belong to the same holder
|
||||||
|
*
|
||||||
|
* @param this calling attribute certificate
|
||||||
|
* @param that other attribute certificate
|
||||||
|
* @return TRUE if same holder
|
||||||
|
*/
|
||||||
|
bool (*equals_holder) (const ac_t *this, const ac_t *other);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* AC_H_ @}*/
|
||||||
|
|
||||||
@@ -6,8 +6,11 @@ AM_CFLAGS = -rdynamic
|
|||||||
plugin_LTLIBRARIES = libstrongswan-x509.la
|
plugin_LTLIBRARIES = libstrongswan-x509.la
|
||||||
|
|
||||||
libstrongswan_x509_la_SOURCES = x509_plugin.h x509_plugin.c \
|
libstrongswan_x509_la_SOURCES = x509_plugin.h x509_plugin.c \
|
||||||
x509_cert.h x509_cert.c x509_crl.h x509_crl.c \
|
x509_cert.h x509_cert.c \
|
||||||
|
x509_crl.h x509_crl.c \
|
||||||
|
x509_ac.h x509_ac.c \
|
||||||
x509_ocsp_request.h x509_ocsp_request.c \
|
x509_ocsp_request.h x509_ocsp_request.c \
|
||||||
x509_ocsp_response.h x509_ocsp_response.c
|
x509_ocsp_response.h x509_ocsp_response.c \
|
||||||
|
ietf_attr_list.h ietf_attr_list.c
|
||||||
libstrongswan_x509_la_LDFLAGS = -module
|
libstrongswan_x509_la_LDFLAGS = -module
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,405 @@
|
|||||||
|
/**
|
||||||
|
* @file ietf_attr.c
|
||||||
|
*
|
||||||
|
* @brief Implementation of ietfAttr_t.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2007 Andreas Steffen, Hochschule fuer Technik Rapperswil
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <debug.h>
|
||||||
|
#include <asn1/asn1.h>
|
||||||
|
#include <utils/lexparser.h>
|
||||||
|
|
||||||
|
#include "ietf_attr_list.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private definition of ietfAttribute kinds
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
IETF_ATTRIBUTE_OCTETS = 0,
|
||||||
|
IETF_ATTRIBUTE_OID = 1,
|
||||||
|
IETF_ATTRIBUTE_STRING = 2
|
||||||
|
} ietfAttribute_t;
|
||||||
|
|
||||||
|
typedef struct ietfAttr_t ietfAttr_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private definition of an ietfAttribute
|
||||||
|
*/
|
||||||
|
struct ietfAttr_t {
|
||||||
|
/**
|
||||||
|
* IETF attribute kind
|
||||||
|
*/
|
||||||
|
ietfAttribute_t kind;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IETF attribute valuse
|
||||||
|
*/
|
||||||
|
chunk_t value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares two ietfAttributes
|
||||||
|
*
|
||||||
|
* return -1 if this is earlier in the alphabet than other
|
||||||
|
* return 0 if this equals other
|
||||||
|
* return +1 if this is later in the alphabet than other
|
||||||
|
*
|
||||||
|
* @param this calling object
|
||||||
|
* @param other other object
|
||||||
|
*/
|
||||||
|
int (*compare) (const ietfAttr_t *this ,const ietfAttr_t *other);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroys the ietfAttr_t object.
|
||||||
|
*
|
||||||
|
* @param this ietfAttr_t to destroy
|
||||||
|
*/
|
||||||
|
void (*destroy) (ietfAttr_t *this);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements ietfAttr_t.compare.
|
||||||
|
*/
|
||||||
|
static int ietfAttr_compare(const ietfAttr_t *this ,const ietfAttr_t *other)
|
||||||
|
{
|
||||||
|
int cmp_len, len, cmp_value;
|
||||||
|
|
||||||
|
/* OID attributes are appended after STRING and OCTETS attributes */
|
||||||
|
if (this->kind != IETF_ATTRIBUTE_OID && other->kind == IETF_ATTRIBUTE_OID)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (this->kind == IETF_ATTRIBUTE_OID && other->kind != IETF_ATTRIBUTE_OID)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmp_len = this->value.len - other->value.len;
|
||||||
|
len = (cmp_len < 0)? this->value.len : other->value.len;
|
||||||
|
cmp_value = memcmp(this->value.ptr, other->value.ptr, len);
|
||||||
|
|
||||||
|
return (cmp_value == 0)? cmp_len : cmp_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements ietfAttr_t.destroy.
|
||||||
|
*/
|
||||||
|
static void ietfAttr_destroy(ietfAttr_t *this)
|
||||||
|
{
|
||||||
|
free(this->value.ptr);
|
||||||
|
free(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an ietfAttr_t object.
|
||||||
|
*/
|
||||||
|
static ietfAttr_t *ietfAttr_create(ietfAttribute_t kind, chunk_t value)
|
||||||
|
{
|
||||||
|
ietfAttr_t *this = malloc_thing(ietfAttr_t);
|
||||||
|
|
||||||
|
/* initialize */
|
||||||
|
this->kind = kind;
|
||||||
|
this->value = chunk_clone(value);
|
||||||
|
|
||||||
|
/* function */
|
||||||
|
this->compare = ietfAttr_compare;
|
||||||
|
this->destroy = ietfAttr_destroy;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an ietfAttr_t object to a sorted linked list
|
||||||
|
*/
|
||||||
|
static void ietfAttr_add(linked_list_t *list, ietfAttr_t *attr)
|
||||||
|
{
|
||||||
|
iterator_t *iterator = list->create_iterator(list, TRUE);
|
||||||
|
ietfAttr_t *current_attr;
|
||||||
|
bool found = FALSE;
|
||||||
|
|
||||||
|
while (iterator->iterate(iterator, (void **)¤t_attr))
|
||||||
|
{
|
||||||
|
int cmp = attr->compare(attr, current_attr);
|
||||||
|
|
||||||
|
if (cmp > 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (cmp == 0)
|
||||||
|
{
|
||||||
|
attr->destroy(attr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
iterator->insert_before(iterator, attr);
|
||||||
|
}
|
||||||
|
found = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
iterator->destroy(iterator);
|
||||||
|
if (!found)
|
||||||
|
{
|
||||||
|
list->insert_last(list, attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Described in header.
|
||||||
|
*/
|
||||||
|
bool ietfAttr_list_equals(linked_list_t *list_a, linked_list_t *list_b)
|
||||||
|
{
|
||||||
|
bool result = TRUE;
|
||||||
|
|
||||||
|
/* lists must have the same number of attributes */
|
||||||
|
if (list_a->get_count(list_a) != list_b->get_count(list_b))
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
/* empty lists - no attributes */
|
||||||
|
if (list_a->get_count(list_a) == 0)
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* compare two alphabetically-sorted lists */
|
||||||
|
{
|
||||||
|
iterator_t *iterator_a = list_a->create_iterator(list_a, TRUE);
|
||||||
|
iterator_t *iterator_b = list_b->create_iterator(list_b, TRUE);
|
||||||
|
ietfAttr_t *attr_a, *attr_b;
|
||||||
|
|
||||||
|
while (iterator_a->iterate(iterator_a, (void **)&attr_a) &&
|
||||||
|
iterator_b->iterate(iterator_b, (void **)&attr_b))
|
||||||
|
{
|
||||||
|
if (attr_a->compare(attr_a, attr_b) != 0)
|
||||||
|
{
|
||||||
|
/* we have a mismatch */
|
||||||
|
result = FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iterator_a->destroy(iterator_a);
|
||||||
|
iterator_b->destroy(iterator_b);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Described in header.
|
||||||
|
*/
|
||||||
|
void ietfAttr_list_list(linked_list_t *list, FILE *out)
|
||||||
|
{
|
||||||
|
iterator_t *iterator = list->create_iterator(list, TRUE);
|
||||||
|
ietfAttr_t *attr;
|
||||||
|
bool first = TRUE;
|
||||||
|
|
||||||
|
while (iterator->iterate(iterator, (void **)&attr))
|
||||||
|
{
|
||||||
|
if (first)
|
||||||
|
{
|
||||||
|
first = FALSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(out, ", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (attr->kind)
|
||||||
|
{
|
||||||
|
case IETF_ATTRIBUTE_OCTETS:
|
||||||
|
case IETF_ATTRIBUTE_STRING:
|
||||||
|
fprintf(out, "%.*s", (int)attr->value.len, attr->value.ptr);
|
||||||
|
break;
|
||||||
|
case IETF_ATTRIBUTE_OID:
|
||||||
|
{
|
||||||
|
int oid = known_oid(attr->value);
|
||||||
|
|
||||||
|
if (oid == OID_UNKNOWN)
|
||||||
|
{
|
||||||
|
fprintf(out, "0x#B", &attr->value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(out, "%s", oid_names[oid]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iterator->destroy(iterator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Described in header.
|
||||||
|
*/
|
||||||
|
void ietfAttr_list_create_from_string(char *msg, linked_list_t *list)
|
||||||
|
{
|
||||||
|
chunk_t line = { msg, strlen(msg) };
|
||||||
|
|
||||||
|
while (eat_whitespace(&line))
|
||||||
|
{
|
||||||
|
chunk_t group;
|
||||||
|
|
||||||
|
/* extract the next comma-separated group attribute */
|
||||||
|
if (!extract_token(&group, ',', &line))
|
||||||
|
{
|
||||||
|
group = line;
|
||||||
|
line.len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remove any trailing spaces */
|
||||||
|
while (group.len > 0 && *(group.ptr + group.len - 1) == ' ')
|
||||||
|
{
|
||||||
|
group.len--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add the group attribute to the list */
|
||||||
|
if (group.len > 0)
|
||||||
|
{
|
||||||
|
ietfAttr_t *attr = ietfAttr_create(IETF_ATTRIBUTE_STRING, group);
|
||||||
|
|
||||||
|
ietfAttr_add(list, attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ASN.1 definition of ietfAttrSyntax
|
||||||
|
*/
|
||||||
|
static const asn1Object_t ietfAttrSyntaxObjects[] =
|
||||||
|
{
|
||||||
|
{ 0, "ietfAttrSyntax", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
|
||||||
|
{ 1, "policyAuthority", ASN1_CONTEXT_C_0, ASN1_OPT |
|
||||||
|
ASN1_BODY }, /* 1 */
|
||||||
|
{ 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */
|
||||||
|
{ 1, "values", ASN1_SEQUENCE, ASN1_LOOP }, /* 3 */
|
||||||
|
{ 2, "octets", ASN1_OCTET_STRING, ASN1_OPT |
|
||||||
|
ASN1_BODY }, /* 4 */
|
||||||
|
{ 2, "end choice", ASN1_EOC, ASN1_END }, /* 5 */
|
||||||
|
{ 2, "oid", ASN1_OID, ASN1_OPT |
|
||||||
|
ASN1_BODY }, /* 6 */
|
||||||
|
{ 2, "end choice", ASN1_EOC, ASN1_END }, /* 7 */
|
||||||
|
{ 2, "string", ASN1_UTF8STRING, ASN1_OPT |
|
||||||
|
ASN1_BODY }, /* 8 */
|
||||||
|
{ 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */
|
||||||
|
{ 1, "end loop", ASN1_EOC, ASN1_END } /* 10 */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define IETF_ATTR_OCTETS 4
|
||||||
|
#define IETF_ATTR_OID 6
|
||||||
|
#define IETF_ATTR_STRING 8
|
||||||
|
#define IETF_ATTR_ROOF 11
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Described in header.
|
||||||
|
*/
|
||||||
|
void ietfAttr_list_create_from_chunk(chunk_t chunk, linked_list_t *list, int level0)
|
||||||
|
{
|
||||||
|
asn1_ctx_t ctx;
|
||||||
|
chunk_t object;
|
||||||
|
u_int level;
|
||||||
|
int objectID = 0;
|
||||||
|
|
||||||
|
asn1_init(&ctx, chunk, level0, FALSE, FALSE);
|
||||||
|
|
||||||
|
while (objectID < IETF_ATTR_ROOF)
|
||||||
|
{
|
||||||
|
if (!extract_object(ietfAttrSyntaxObjects, &objectID, &object, &level, &ctx))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (objectID)
|
||||||
|
{
|
||||||
|
case IETF_ATTR_OCTETS:
|
||||||
|
case IETF_ATTR_OID:
|
||||||
|
case IETF_ATTR_STRING:
|
||||||
|
{
|
||||||
|
ietfAttribute_t kind = (objectID - IETF_ATTR_OCTETS) / 2;
|
||||||
|
ietfAttr_t *attr = ietfAttr_create(kind, object);
|
||||||
|
ietfAttr_add(list, attr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
objectID++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Described in header.
|
||||||
|
*/
|
||||||
|
chunk_t ietfAttr_list_encode(linked_list_t *list)
|
||||||
|
{
|
||||||
|
chunk_t ietfAttributes;
|
||||||
|
size_t size = 0;
|
||||||
|
u_char *pos;
|
||||||
|
iterator_t *iterator = list->create_iterator(list, TRUE);
|
||||||
|
ietfAttr_t *attr;
|
||||||
|
|
||||||
|
/* precalculate the total size of all values */
|
||||||
|
while (iterator->iterate(iterator, (void **)&attr))
|
||||||
|
{
|
||||||
|
size_t len = attr->value.len;
|
||||||
|
|
||||||
|
size += 1 + (len > 0) + (len >= 128) + (len >= 256) + (len >= 65536) + len;
|
||||||
|
}
|
||||||
|
iterator->destroy(iterator);
|
||||||
|
|
||||||
|
pos = build_asn1_object(&ietfAttributes, ASN1_SEQUENCE, size);
|
||||||
|
|
||||||
|
iterator = list->create_iterator(list, TRUE);
|
||||||
|
while (iterator->iterate(iterator, (void **)&attr))
|
||||||
|
{
|
||||||
|
chunk_t ietfAttribute;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
ietfAttribute = asn1_simple_object(type, attr->value);
|
||||||
|
|
||||||
|
/* copy ietfAttribute into ietfAttributes chunk */
|
||||||
|
memcpy(pos, ietfAttribute.ptr, ietfAttribute.len);
|
||||||
|
pos += ietfAttribute.len;
|
||||||
|
free(ietfAttribute.ptr);
|
||||||
|
}
|
||||||
|
iterator->destroy(iterator);
|
||||||
|
|
||||||
|
return asn1_wrap(ASN1_SEQUENCE, "m", ietfAttributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Described in header.
|
||||||
|
*/
|
||||||
|
void ietfAttr_list_destroy(linked_list_t *list)
|
||||||
|
{
|
||||||
|
list->destroy_offset(list, offsetof(ietfAttr_t, destroy));
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
/**
|
||||||
|
* @file ietf_attr_list.h
|
||||||
|
*
|
||||||
|
* @brief Handling of ietfAttr_t linked lists
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2007 Andreas Steffen
|
||||||
|
*
|
||||||
|
* Hochschule fuer Technik Rapperswil
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef IETF_ATTR_LIST_H_
|
||||||
|
#define IETF_ATTR_LIST_H_
|
||||||
|
|
||||||
|
#include <library.h>
|
||||||
|
#include <utils/linked_list.h>
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Compare two linked lists of ietfAttr_t objects for equality
|
||||||
|
*
|
||||||
|
* @param list_a first alphabetically-sorted list
|
||||||
|
* @param list_b second alphabetically-sorted list
|
||||||
|
* @return TRUE if equal
|
||||||
|
*
|
||||||
|
* @ingroup crypto
|
||||||
|
*/
|
||||||
|
bool ietfAttr_list_equals(linked_list_t *list_a, linked_list_t *list_b);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Lists a linked list of ietfAttr_t objects
|
||||||
|
*
|
||||||
|
* @param list alphabetically-sorted linked list of attributes
|
||||||
|
@param out output file
|
||||||
|
*
|
||||||
|
* @ingroup crypto
|
||||||
|
*/
|
||||||
|
void ietfAttr_list_list(linked_list_t *list, FILE *out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a linked list of ietfAttr_t objects from a string
|
||||||
|
*
|
||||||
|
* @param msg string with comma-separated group names
|
||||||
|
* @param list alphabetically-sorted linked list of attributes
|
||||||
|
*
|
||||||
|
* @ingroup crypto
|
||||||
|
*/
|
||||||
|
void ietfAttr_list_create_from_string(char *msg, linked_list_t *list);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a linked list of ietfAttr_t objects from an ASN.1-coded chunk
|
||||||
|
*
|
||||||
|
* @param chunk chunk containing ASN.1-coded attributes
|
||||||
|
* @param list alphabetically-sorted linked list of attributes
|
||||||
|
* @param level0 parsing level
|
||||||
|
*/
|
||||||
|
void ietfAttr_list_create_from_chunk(chunk_t chunk, linked_list_t *list, int level0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Encode a linked list of ietfAttr_t objects into an ASN.1-coded chunk
|
||||||
|
*
|
||||||
|
* @param list alphabetically-sorted linked list of attributes
|
||||||
|
* @return chunk containing ASN.1-coded attributes
|
||||||
|
*/
|
||||||
|
chunk_t ietfAttr_list_encode(linked_list_t *list);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Destroys a linked list of ietfAttr_t objects
|
||||||
|
*
|
||||||
|
* @param list list to be destroyed
|
||||||
|
*
|
||||||
|
* @ingroup crypto
|
||||||
|
*/
|
||||||
|
void ietfAttr_list_destroy(linked_list_t *list);
|
||||||
|
|
||||||
|
#endif /* IETF_ATTR_LIST_H_ */
|
||||||
|
|
||||||
@@ -0,0 +1,807 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2002 Ueli Galizzi, Ariane Seiler
|
||||||
|
* Copyright (C) 2003 Martin Berner, Lukas Suter
|
||||||
|
* Copyright (C) 2002-2008 Andreas Steffen
|
||||||
|
*
|
||||||
|
* Hochschule fuer Technik Rapperswil
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "x509_ac.h"
|
||||||
|
#include "ietf_attr_list.h"
|
||||||
|
|
||||||
|
#include <library.h>
|
||||||
|
#include <debug.h>
|
||||||
|
#include <asn1/oid.h>
|
||||||
|
#include <asn1/asn1.h>
|
||||||
|
#include <utils/identification.h>
|
||||||
|
#include <utils/linked_list.h>
|
||||||
|
#include <credentials/certificates/x509.h>
|
||||||
|
|
||||||
|
typedef struct private_x509_ac_t private_x509_ac_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* private data of x509_ac_t object
|
||||||
|
*/
|
||||||
|
struct private_x509_ac_t {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* public functions
|
||||||
|
*/
|
||||||
|
x509_ac_t public;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* X.509 attribute certificate in DER format
|
||||||
|
*/
|
||||||
|
chunk_t encoding;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* X.509 attribute certificate body over which signature is computed
|
||||||
|
*/
|
||||||
|
chunk_t certificateInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Version of the X.509 attribute certificate
|
||||||
|
*/
|
||||||
|
u_int version;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serial number of the X.509 attribute certificate
|
||||||
|
*/
|
||||||
|
chunk_t serialNumber;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID representing the issuer of the holder certificate
|
||||||
|
*/
|
||||||
|
identification_t *holderIssuer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serial number of the holder certificate
|
||||||
|
*/
|
||||||
|
chunk_t holderSerial;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID representing the holder
|
||||||
|
*/
|
||||||
|
identification_t *entityName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID representing the attribute certificate issuer
|
||||||
|
*/
|
||||||
|
identification_t *issuerName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signature algorithm
|
||||||
|
*/
|
||||||
|
int algorithm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start time of certificate validity
|
||||||
|
*/
|
||||||
|
time_t notBefore;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End time of certificate validity
|
||||||
|
*/
|
||||||
|
time_t notAfter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of charging attributes
|
||||||
|
*/
|
||||||
|
linked_list_t *charging;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of groub attributes
|
||||||
|
*/
|
||||||
|
linked_list_t *groups;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authority Key Identifier
|
||||||
|
*/
|
||||||
|
identification_t *authKeyIdentifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authority Key Serial Number
|
||||||
|
*/
|
||||||
|
chunk_t authKeySerialNumber;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* No revocation information available
|
||||||
|
*/
|
||||||
|
bool noRevAvail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signature
|
||||||
|
*/
|
||||||
|
chunk_t signature;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holder certificate
|
||||||
|
*/
|
||||||
|
x509_t *holder_cert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signer certificate
|
||||||
|
*/
|
||||||
|
x509_t *signer_cert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signer private key;
|
||||||
|
*/
|
||||||
|
private_key_t *signer_key;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* reference count
|
||||||
|
*/
|
||||||
|
refcount_t ref;
|
||||||
|
};
|
||||||
|
|
||||||
|
static u_char ASN1_group_oid_str[] = {
|
||||||
|
0x06, 0x08,
|
||||||
|
0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x0a ,0x04
|
||||||
|
};
|
||||||
|
|
||||||
|
static const chunk_t ASN1_group_oid = chunk_from_buf(ASN1_group_oid_str);
|
||||||
|
|
||||||
|
static u_char ASN1_authorityKeyIdentifier_oid_str[] = {
|
||||||
|
0x06, 0x03,
|
||||||
|
0x55, 0x1d, 0x23
|
||||||
|
};
|
||||||
|
|
||||||
|
static const chunk_t ASN1_authorityKeyIdentifier_oid =
|
||||||
|
chunk_from_buf(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 = chunk_from_buf(ASN1_noRevAvail_ext_str);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ASN.1 definition of roleSyntax
|
||||||
|
*/
|
||||||
|
static const asn1Object_t roleSyntaxObjects[] =
|
||||||
|
{
|
||||||
|
{ 0, "roleSyntax", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
|
||||||
|
{ 1, "roleAuthority", ASN1_CONTEXT_C_0, ASN1_OPT |
|
||||||
|
ASN1_OBJ }, /* 1 */
|
||||||
|
{ 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */
|
||||||
|
{ 1, "roleName", ASN1_CONTEXT_C_1, ASN1_OBJ } /* 3 */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ROLE_ROOF 4
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ASN.1 definition of an X509 attribute certificate
|
||||||
|
*/
|
||||||
|
static const asn1Object_t acObjects[] =
|
||||||
|
{
|
||||||
|
{ 0, "AttributeCertificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
|
||||||
|
{ 1, "AttributeCertificateInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
|
||||||
|
{ 2, "version", ASN1_INTEGER, ASN1_DEF |
|
||||||
|
ASN1_BODY }, /* 2 */
|
||||||
|
{ 2, "holder", ASN1_SEQUENCE, ASN1_NONE }, /* 3 */
|
||||||
|
{ 3, "baseCertificateID", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 4 */
|
||||||
|
{ 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */
|
||||||
|
{ 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 6 */
|
||||||
|
{ 4, "issuerUID", ASN1_BIT_STRING, ASN1_OPT |
|
||||||
|
ASN1_BODY }, /* 7 */
|
||||||
|
{ 4, "end opt", ASN1_EOC, ASN1_END }, /* 8 */
|
||||||
|
{ 3, "end opt", ASN1_EOC, ASN1_END }, /* 9 */
|
||||||
|
{ 3, "entityName", ASN1_CONTEXT_C_1, ASN1_OPT |
|
||||||
|
ASN1_OBJ }, /* 10 */
|
||||||
|
{ 3, "end opt", ASN1_EOC, ASN1_END }, /* 11 */
|
||||||
|
{ 3, "objectDigestInfo", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 12 */
|
||||||
|
{ 4, "digestedObjectType", ASN1_ENUMERATED, ASN1_BODY }, /* 13*/
|
||||||
|
{ 4, "otherObjectTypeID", ASN1_OID, ASN1_OPT |
|
||||||
|
ASN1_BODY }, /* 14 */
|
||||||
|
{ 4, "end opt", ASN1_EOC, ASN1_END }, /* 15*/
|
||||||
|
{ 4, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 16 */
|
||||||
|
{ 3, "end opt", ASN1_EOC, ASN1_END }, /* 17 */
|
||||||
|
{ 2, "v2Form", ASN1_CONTEXT_C_0, ASN1_NONE }, /* 18 */
|
||||||
|
{ 3, "issuerName", ASN1_SEQUENCE, ASN1_OPT |
|
||||||
|
ASN1_OBJ }, /* 19 */
|
||||||
|
{ 3, "end opt", ASN1_EOC, ASN1_END }, /* 20 */
|
||||||
|
{ 3, "baseCertificateID", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 21 */
|
||||||
|
{ 4, "issuerSerial", ASN1_SEQUENCE, ASN1_NONE }, /* 22 */
|
||||||
|
{ 5, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 23 */
|
||||||
|
{ 5, "serial", ASN1_INTEGER, ASN1_BODY }, /* 24 */
|
||||||
|
{ 5, "issuerUID", ASN1_BIT_STRING, ASN1_OPT |
|
||||||
|
ASN1_BODY }, /* 25 */
|
||||||
|
{ 5, "end opt", ASN1_EOC, ASN1_END }, /* 26 */
|
||||||
|
{ 3, "end opt", ASN1_EOC, ASN1_END }, /* 27 */
|
||||||
|
{ 3, "objectDigestInfo", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 28 */
|
||||||
|
{ 4, "digestInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 29 */
|
||||||
|
{ 5, "digestedObjectType", ASN1_ENUMERATED, ASN1_BODY }, /* 30 */
|
||||||
|
{ 5, "otherObjectTypeID", ASN1_OID, ASN1_OPT |
|
||||||
|
ASN1_BODY }, /* 31 */
|
||||||
|
{ 5, "end opt", ASN1_EOC, ASN1_END }, /* 32 */
|
||||||
|
{ 5, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 33 */
|
||||||
|
{ 3, "end opt", ASN1_EOC, ASN1_END }, /* 34 */
|
||||||
|
{ 2, "signature", ASN1_EOC, ASN1_RAW }, /* 35 */
|
||||||
|
{ 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 36 */
|
||||||
|
{ 2, "attrCertValidityPeriod", ASN1_SEQUENCE, ASN1_NONE }, /* 37 */
|
||||||
|
{ 3, "notBeforeTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 38 */
|
||||||
|
{ 3, "notAfterTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 39 */
|
||||||
|
{ 2, "attributes", ASN1_SEQUENCE, ASN1_LOOP }, /* 40 */
|
||||||
|
{ 3, "attribute", ASN1_SEQUENCE, ASN1_NONE }, /* 41 */
|
||||||
|
{ 4, "type", ASN1_OID, ASN1_BODY }, /* 42 */
|
||||||
|
{ 4, "values", ASN1_SET, ASN1_LOOP }, /* 43 */
|
||||||
|
{ 5, "value", ASN1_EOC, ASN1_RAW }, /* 44 */
|
||||||
|
{ 4, "end loop", ASN1_EOC, ASN1_END }, /* 45 */
|
||||||
|
{ 2, "end loop", ASN1_EOC, ASN1_END }, /* 46 */
|
||||||
|
{ 2, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 47 */
|
||||||
|
{ 3, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 48 */
|
||||||
|
{ 4, "extnID", ASN1_OID, ASN1_BODY }, /* 49 */
|
||||||
|
{ 4, "critical", ASN1_BOOLEAN, ASN1_DEF |
|
||||||
|
ASN1_BODY }, /* 50 */
|
||||||
|
{ 4, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 51 */
|
||||||
|
{ 2, "end loop", ASN1_EOC, ASN1_END }, /* 52 */
|
||||||
|
{ 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 53 */
|
||||||
|
{ 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY } /* 54 */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define AC_OBJ_CERTIFICATE 0
|
||||||
|
#define AC_OBJ_CERTIFICATE_INFO 1
|
||||||
|
#define AC_OBJ_VERSION 2
|
||||||
|
#define AC_OBJ_HOLDER_ISSUER 5
|
||||||
|
#define AC_OBJ_HOLDER_SERIAL 6
|
||||||
|
#define AC_OBJ_ENTITY_NAME 10
|
||||||
|
#define AC_OBJ_ISSUER_NAME 19
|
||||||
|
#define AC_OBJ_ISSUER 23
|
||||||
|
#define AC_OBJ_SIG_ALG 35
|
||||||
|
#define AC_OBJ_SERIAL_NUMBER 36
|
||||||
|
#define AC_OBJ_NOT_BEFORE 38
|
||||||
|
#define AC_OBJ_NOT_AFTER 39
|
||||||
|
#define AC_OBJ_ATTRIBUTE_TYPE 42
|
||||||
|
#define AC_OBJ_ATTRIBUTE_VALUE 44
|
||||||
|
#define AC_OBJ_EXTN_ID 49
|
||||||
|
#define AC_OBJ_CRITICAL 50
|
||||||
|
#define AC_OBJ_EXTN_VALUE 51
|
||||||
|
#define AC_OBJ_ALGORITHM 53
|
||||||
|
#define AC_OBJ_SIGNATURE 54
|
||||||
|
#define AC_OBJ_ROOF 55
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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(private_x509_ac_t *this)
|
||||||
|
{
|
||||||
|
x509_t *x509 = this->holder_cert;
|
||||||
|
certificate_t *cert = &x509->interface;
|
||||||
|
|
||||||
|
identification_t *issuer = cert->get_issuer(cert);
|
||||||
|
identification_t *subject = cert->get_subject(cert);
|
||||||
|
|
||||||
|
return asn1_wrap(ASN1_SEQUENCE, "mm",
|
||||||
|
asn1_wrap(ASN1_CONTEXT_C_0, "mm",
|
||||||
|
build_directoryName(ASN1_SEQUENCE, issuer->get_encoding(issuer)),
|
||||||
|
asn1_simple_object(ASN1_INTEGER, x509->get_serial(x509))
|
||||||
|
),
|
||||||
|
build_directoryName(ASN1_CONTEXT_C_1, subject->get_encoding(subject)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* build v2Form
|
||||||
|
*/
|
||||||
|
static chunk_t build_v2_form(private_x509_ac_t *this)
|
||||||
|
{
|
||||||
|
x509_t *x509 = this->signer_cert;
|
||||||
|
certificate_t *cert = &x509->interface;
|
||||||
|
identification_t *subject = cert->get_subject(cert);
|
||||||
|
|
||||||
|
return asn1_wrap(ASN1_CONTEXT_C_0, "m",
|
||||||
|
build_directoryName(ASN1_SEQUENCE, subject->get_encoding(subject)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* build attrCertValidityPeriod
|
||||||
|
*/
|
||||||
|
static chunk_t build_attr_cert_validity(private_x509_ac_t *this)
|
||||||
|
{
|
||||||
|
return asn1_wrap(ASN1_SEQUENCE, "mm",
|
||||||
|
timetoasn1(&this->notBefore, ASN1_GENERALIZEDTIME),
|
||||||
|
timetoasn1(&this->notAfter, ASN1_GENERALIZEDTIME));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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(private_x509_ac_t *this)
|
||||||
|
{
|
||||||
|
return asn1_wrap(ASN1_SEQUENCE, "m",
|
||||||
|
build_attribute_type(ASN1_group_oid, ietfAttr_list_encode(this->groups)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* build authorityKeyIdentifier
|
||||||
|
*/
|
||||||
|
static chunk_t build_authorityKeyIdentifier(private_x509_ac_t *this)
|
||||||
|
{
|
||||||
|
x509_t *x509 = this->signer_cert;
|
||||||
|
certificate_t *cert = &x509->interface;
|
||||||
|
identification_t *issuer = cert->get_issuer(cert);
|
||||||
|
public_key_t *public = cert->get_public_key(cert);
|
||||||
|
chunk_t keyIdentifier;
|
||||||
|
chunk_t authorityCertIssuer;
|
||||||
|
chunk_t authorityCertSerialNumber;
|
||||||
|
|
||||||
|
if (public)
|
||||||
|
{
|
||||||
|
this->authKeyIdentifier = public->get_id(public, ID_PUBKEY_SHA1);
|
||||||
|
public->destroy(public);
|
||||||
|
keyIdentifier = this->authKeyIdentifier->get_encoding(this->authKeyIdentifier);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
keyIdentifier = chunk_empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
authorityCertIssuer = build_directoryName(ASN1_CONTEXT_C_1,
|
||||||
|
issuer->get_encoding(issuer));
|
||||||
|
|
||||||
|
authorityCertSerialNumber = asn1_simple_object(ASN1_CONTEXT_S_2,
|
||||||
|
x509->get_serial(x509));
|
||||||
|
|
||||||
|
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(private_x509_ac_t *this)
|
||||||
|
{
|
||||||
|
return asn1_wrap(ASN1_SEQUENCE, "mc",
|
||||||
|
build_authorityKeyID(this),
|
||||||
|
ASN1_noRevAvail_ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* build attributeCertificateInfo
|
||||||
|
*/
|
||||||
|
static chunk_t build_attr_cert_info(private_x509_ac_t *this)
|
||||||
|
{
|
||||||
|
return asn1_wrap(ASN1_SEQUENCE, "cmmcmmmm",
|
||||||
|
ASN1_INTEGER_1,
|
||||||
|
build_holder(this),
|
||||||
|
build_v2_form(this),
|
||||||
|
asn1_algorithmIdentifier(OID_SHA1_WITH_RSA),
|
||||||
|
asn1_simple_object(ASN1_INTEGER, this->serialNumber),
|
||||||
|
build_attr_cert_validity(this),
|
||||||
|
build_attributes(this),
|
||||||
|
build_extensions(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* build an X.509 attribute certificate
|
||||||
|
*/
|
||||||
|
static chunk_t build_ac(private_x509_ac_t *this)
|
||||||
|
{
|
||||||
|
chunk_t signatureValue;
|
||||||
|
chunk_t attributeCertificateInfo = build_attr_cert_info(this);
|
||||||
|
/*
|
||||||
|
signerkey->build_emsa_pkcs1_signature(signerkey, HASH_SHA1,
|
||||||
|
attributeCertificateInfo, &signatureValue);
|
||||||
|
*/
|
||||||
|
return asn1_wrap(ASN1_SEQUENCE, "mcm",
|
||||||
|
attributeCertificateInfo,
|
||||||
|
asn1_algorithmIdentifier(OID_SHA1_WITH_RSA),
|
||||||
|
asn1_bitstring("m", signatureValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of certificate_t.get_type
|
||||||
|
*/
|
||||||
|
static certificate_type_t get_type(private_x509_ac_t *this)
|
||||||
|
{
|
||||||
|
return CERT_X509_AC;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of certificate_t.get_subject
|
||||||
|
*/
|
||||||
|
static identification_t* get_subject(private_x509_ac_t *this)
|
||||||
|
{
|
||||||
|
return this->entityName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of certificate_t.get_issuer
|
||||||
|
*/
|
||||||
|
static identification_t* get_issuer(private_x509_ac_t *this)
|
||||||
|
{
|
||||||
|
return this->issuerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of certificate_t.has_subject.
|
||||||
|
*/
|
||||||
|
static id_match_t has_subject(private_x509_ac_t *this, identification_t *subject)
|
||||||
|
{
|
||||||
|
return ID_MATCH_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of certificate_t.has_issuer.
|
||||||
|
*/
|
||||||
|
static id_match_t has_issuer(private_x509_ac_t *this, identification_t *issuer)
|
||||||
|
{
|
||||||
|
id_match_t match;
|
||||||
|
|
||||||
|
if (issuer->get_type(issuer) == ID_PUBKEY_SHA1)
|
||||||
|
{
|
||||||
|
if (this->authKeyIdentifier)
|
||||||
|
{
|
||||||
|
match = issuer->matches(issuer, this->authKeyIdentifier);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
match = ID_MATCH_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
match = this->issuerName->matches(this->issuerName, issuer);
|
||||||
|
}
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of certificate_t.issued_by
|
||||||
|
*/
|
||||||
|
static bool issued_by(private_x509_ac_t *this, certificate_t *issuer,
|
||||||
|
bool sigcheck)
|
||||||
|
{
|
||||||
|
public_key_t *key;
|
||||||
|
signature_scheme_t scheme;
|
||||||
|
bool valid;
|
||||||
|
x509_t *x509 = (x509_t*)issuer;
|
||||||
|
|
||||||
|
/* check if issuer is an X.509 AA certificate */
|
||||||
|
if (issuer->get_type(issuer) != CERT_X509)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if (!(x509->get_flags(x509) & X509_AA))
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get the public key of the issuer */
|
||||||
|
key = issuer->get_public_key(issuer);
|
||||||
|
|
||||||
|
/* compare keyIdentifiers if available, otherwise use DNs */
|
||||||
|
if (this->authKeyIdentifier && key)
|
||||||
|
{
|
||||||
|
identification_t *subjectKeyIdentifier = key->get_id(key, ID_PUBKEY_SHA1);
|
||||||
|
|
||||||
|
if (!subjectKeyIdentifier->equals(subjectKeyIdentifier,
|
||||||
|
this->authKeyIdentifier))
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!this->issuerName->equals(this->issuerName, issuer->get_subject(issuer)))
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sigcheck)
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
/* TODO: generic OID to scheme mapper? */
|
||||||
|
switch (this->algorithm)
|
||||||
|
{
|
||||||
|
case OID_MD5_WITH_RSA:
|
||||||
|
scheme = SIGN_RSA_EMSA_PKCS1_MD5;
|
||||||
|
break;
|
||||||
|
case OID_SHA1_WITH_RSA:
|
||||||
|
scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
|
||||||
|
break;
|
||||||
|
case OID_SHA256_WITH_RSA:
|
||||||
|
scheme = SIGN_RSA_EMSA_PKCS1_SHA256;
|
||||||
|
break;
|
||||||
|
case OID_SHA384_WITH_RSA:
|
||||||
|
scheme = SIGN_RSA_EMSA_PKCS1_SHA384;
|
||||||
|
break;
|
||||||
|
case OID_SHA512_WITH_RSA:
|
||||||
|
scheme = SIGN_RSA_EMSA_PKCS1_SHA512;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if (key == NULL)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
valid = key->verify(key, scheme, this->certificateInfo, this->signature);
|
||||||
|
key->destroy(key);
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of certificate_t.get_public_key.
|
||||||
|
*/
|
||||||
|
static public_key_t* get_public_key(private_x509_ac_t *this)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of certificate_t.get_ref.
|
||||||
|
*/
|
||||||
|
static private_x509_ac_t* get_ref(private_x509_ac_t *this)
|
||||||
|
{
|
||||||
|
ref_get(&this->ref);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of certificate_t.get_validity.
|
||||||
|
*/
|
||||||
|
static bool get_validity(private_x509_ac_t *this, time_t *when,
|
||||||
|
time_t *not_before, time_t *not_after)
|
||||||
|
{
|
||||||
|
time_t t;
|
||||||
|
|
||||||
|
if (when)
|
||||||
|
{
|
||||||
|
t = *when;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
t = time(NULL);
|
||||||
|
}
|
||||||
|
if (not_before)
|
||||||
|
{
|
||||||
|
*not_before = this->notBefore;
|
||||||
|
}
|
||||||
|
if (not_after)
|
||||||
|
{
|
||||||
|
*not_after = this->notAfter;
|
||||||
|
}
|
||||||
|
return (t >= this->notBefore && t <= this->notAfter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of certificate_t.is_newer.
|
||||||
|
*/
|
||||||
|
static bool is_newer(private_x509_ac_t *this, ac_t *that)
|
||||||
|
{
|
||||||
|
certificate_t *this_cert = &this->public.interface.certificate;
|
||||||
|
certificate_t *that_cert = &that->certificate;
|
||||||
|
time_t this_update, that_update, now = time(NULL);
|
||||||
|
bool new;
|
||||||
|
|
||||||
|
this_cert->get_validity(this_cert, &now, &this_update, NULL);
|
||||||
|
that_cert->get_validity(that_cert, &now, &that_update, NULL);
|
||||||
|
new = this_update > that_update;
|
||||||
|
DBG1(" attr cert from %#T is %s - existing attr_cert from %#T %s",
|
||||||
|
&this_update, FALSE, new ? "newer":"not newer",
|
||||||
|
&that_update, FALSE, new ? "replaced":"retained");
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of certificate_t.get_encoding.
|
||||||
|
*/
|
||||||
|
static chunk_t get_encoding(private_x509_ac_t *this)
|
||||||
|
{
|
||||||
|
return chunk_clone(this->encoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of certificate_t.equals.
|
||||||
|
*/
|
||||||
|
static bool equals(private_x509_ac_t *this, certificate_t *other)
|
||||||
|
{
|
||||||
|
if ((certificate_t*)this == other)
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
if (other->equals == (void*)equals)
|
||||||
|
{ /* same implementation */
|
||||||
|
return chunk_equals(this->signature,
|
||||||
|
((private_x509_ac_t*)other)->signature);
|
||||||
|
}
|
||||||
|
/* TODO: compare against other implementations */
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of x509_ac_t.destroy
|
||||||
|
*/
|
||||||
|
static void destroy(private_x509_ac_t *this)
|
||||||
|
{
|
||||||
|
if (ref_put(&this->ref))
|
||||||
|
{
|
||||||
|
DESTROY_IF(this->holderIssuer);
|
||||||
|
DESTROY_IF(this->entityName);
|
||||||
|
DESTROY_IF(this->issuerName);
|
||||||
|
DESTROY_IF(this->authKeyIdentifier);
|
||||||
|
ietfAttr_list_destroy(this->charging);
|
||||||
|
ietfAttr_list_destroy(this->groups);
|
||||||
|
free(this->encoding.ptr);
|
||||||
|
free(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create an empty but initialized X.509 attribute certificate
|
||||||
|
*/
|
||||||
|
static private_x509_ac_t *create_empty()
|
||||||
|
{
|
||||||
|
private_x509_ac_t *this = malloc_thing(private_x509_ac_t);
|
||||||
|
|
||||||
|
/* public functions */
|
||||||
|
this->public.interface.certificate.get_type = (certificate_type_t (*)(certificate_t *this))get_type;
|
||||||
|
this->public.interface.certificate.get_subject = (identification_t* (*)(certificate_t *this))get_subject;
|
||||||
|
this->public.interface.certificate.get_issuer = (identification_t* (*)(certificate_t *this))get_issuer;
|
||||||
|
this->public.interface.certificate.has_subject = (id_match_t(*)(certificate_t*, identification_t *subject))has_subject;
|
||||||
|
this->public.interface.certificate.has_issuer = (id_match_t(*)(certificate_t*, identification_t *issuer))has_issuer;
|
||||||
|
this->public.interface.certificate.issued_by = (bool (*)(certificate_t *this, certificate_t *issuer,bool))issued_by;
|
||||||
|
this->public.interface.certificate.get_public_key = (public_key_t* (*)(certificate_t *this))get_public_key;
|
||||||
|
this->public.interface.certificate.get_validity = (bool(*)(certificate_t*, time_t *when, time_t *, time_t*))get_validity;
|
||||||
|
this->public.interface.certificate.get_encoding = (chunk_t(*)(certificate_t*))get_encoding;
|
||||||
|
this->public.interface.certificate.equals = (bool(*)(certificate_t*, certificate_t *other))equals;
|
||||||
|
this->public.interface.certificate.get_ref = (certificate_t* (*)(certificate_t *this))get_ref;
|
||||||
|
this->public.interface.certificate.destroy = (void (*)(certificate_t *this))destroy;
|
||||||
|
|
||||||
|
/* initialize */
|
||||||
|
this->holderIssuer = NULL;
|
||||||
|
this->entityName = NULL;
|
||||||
|
this->issuerName = NULL;
|
||||||
|
this->authKeyIdentifier = NULL;
|
||||||
|
this->charging = linked_list_create();
|
||||||
|
this->groups = linked_list_create();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct private_builder_t private_builder_t;
|
||||||
|
/**
|
||||||
|
* Builder implementation for certificate loading
|
||||||
|
*/
|
||||||
|
struct private_builder_t {
|
||||||
|
/** implements the builder interface */
|
||||||
|
builder_t public;
|
||||||
|
/** X.509 attribute certificate to build */
|
||||||
|
private_x509_ac_t *ac;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of builder_t.build
|
||||||
|
*/
|
||||||
|
static x509_ac_t *build(private_builder_t *this)
|
||||||
|
{
|
||||||
|
private_x509_ac_t *ac;
|
||||||
|
|
||||||
|
ac = this->ac;
|
||||||
|
free(this);
|
||||||
|
if (ac->holder_cert && ac->signer_cert && ac->signer_key)
|
||||||
|
{
|
||||||
|
ac->encoding = build_ac(ac);
|
||||||
|
return &ac->public;
|
||||||
|
}
|
||||||
|
destroy(ac);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of builder_t.add
|
||||||
|
*/
|
||||||
|
static void add(private_builder_t *this, builder_part_t part, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
certificate_t *cert;
|
||||||
|
|
||||||
|
va_start(args, part);
|
||||||
|
switch (part)
|
||||||
|
{
|
||||||
|
case BUILD_NOT_BEFORE_TIME:
|
||||||
|
this->ac->notBefore = *va_arg(args, time_t*);
|
||||||
|
break;
|
||||||
|
case BUILD_NOT_AFTER_TIME:
|
||||||
|
this->ac->notAfter = *va_arg(args, time_t*);
|
||||||
|
break;
|
||||||
|
case BUILD_CERT:
|
||||||
|
cert = va_arg(args, certificate_t*);
|
||||||
|
if (cert->get_type(cert) == CERT_X509)
|
||||||
|
{
|
||||||
|
this->ac->holder_cert = (x509_t*)cert;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cert->destroy(cert);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BUILD_SIGNING_CERT:
|
||||||
|
if (cert->get_type(cert) == CERT_X509)
|
||||||
|
{
|
||||||
|
this->ac->signer_cert = (x509_t*)cert;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cert->destroy(cert);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BUILD_SIGNING_KEY:
|
||||||
|
this->ac->signer_key = va_arg(args, private_key_t*);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DBG1("ignoring unsupported build part %N", builder_part_names, part);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builder construction function
|
||||||
|
*/
|
||||||
|
builder_t *x509_ac_builder(certificate_type_t type)
|
||||||
|
{
|
||||||
|
private_builder_t *this;
|
||||||
|
|
||||||
|
if (type != CERT_X509_AC)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
this = malloc_thing(private_builder_t);
|
||||||
|
|
||||||
|
this->ac = create_empty();
|
||||||
|
this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add;
|
||||||
|
this->public.build = (void*(*)(builder_t *this))build;
|
||||||
|
|
||||||
|
return &this->public;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2002 Ueli Galizzi, Ariane Seiler
|
||||||
|
* Copyright (C) 2003 Martin Berner, Lukas Suter
|
||||||
|
* Copyright (C) 2002-2008 Andreas Steffen
|
||||||
|
*
|
||||||
|
* Hochschule fuer Technik Rapperswil
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup x509_ac x509_ac
|
||||||
|
* @{ @ingroup x509_p
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef X509_AC_H_
|
||||||
|
#define X509_AC_H_
|
||||||
|
|
||||||
|
#include <credentials/certificates/ac.h>
|
||||||
|
|
||||||
|
typedef struct x509_ac_t x509_ac_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of ocsp_request_t using own ASN1 parser.
|
||||||
|
*/
|
||||||
|
struct x509_ac_t {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements the ac_t interface
|
||||||
|
*/
|
||||||
|
ac_t interface;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the building facility for X.509 attribute certificates.
|
||||||
|
*
|
||||||
|
* The resulting builder accepts:
|
||||||
|
* BUILD_USER_CERT: user certificate, exactly one
|
||||||
|
* BUILD_SIGNER_CERT: signer certificate, exactly one
|
||||||
|
* BUILD_SIGNER_KEY: signer private key, exactly one
|
||||||
|
* BUILD_SERIAL: serial number, exactly one
|
||||||
|
* BUILD_GROUP_ATTR: group attribute, optional, several possible
|
||||||
|
*
|
||||||
|
* @param type certificate type, CERT_X509_AC only
|
||||||
|
* @return builder instance to build X.509 attribute certificates
|
||||||
|
*/
|
||||||
|
builder_t *x509_ac_builder(certificate_type_t type);
|
||||||
|
|
||||||
|
#endif /* X509_AC_H_ @}*/
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
ipsec_PROGRAMS = openac
|
ipsec_PROGRAMS = openac
|
||||||
openac_SOURCES = openac.c build.c build.h
|
openac_SOURCES = openac.c
|
||||||
dist_man_MANS = openac.8
|
dist_man_MANS = openac.8
|
||||||
|
|
||||||
INCLUDES = -I$(top_srcdir)/src/libstrongswan
|
INCLUDES = -I$(top_srcdir)/src/libstrongswan
|
||||||
|
|||||||
@@ -1,193 +0,0 @@
|
|||||||
/* Build a X.509 attribute certificate
|
|
||||||
* Copyright (C) 2002 Ueli Galizzi, Ariane Seiler
|
|
||||||
* 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
|
|
||||||
* 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$
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include <asn1/oid.h>
|
|
||||||
#include <asn1/asn1.h>
|
|
||||||
#include <crypto/ietf_attr_list.h>
|
|
||||||
#include <utils/identification.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 = chunk_from_buf(ASN1_group_oid_str);
|
|
||||||
|
|
||||||
static u_char ASN1_authorityKeyIdentifier_oid_str[] = {
|
|
||||||
0x06, 0x03,
|
|
||||||
0x55, 0x1d, 0x23
|
|
||||||
};
|
|
||||||
|
|
||||||
static const chunk_t ASN1_authorityKeyIdentifier_oid =
|
|
||||||
chunk_from_buf(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 = chunk_from_buf(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)
|
|
||||||
{
|
|
||||||
identification_t *issuer = usercert->get_issuer(usercert);
|
|
||||||
identification_t *subject = usercert->get_subject(usercert);
|
|
||||||
|
|
||||||
return asn1_wrap(ASN1_SEQUENCE, "mm",
|
|
||||||
asn1_wrap(ASN1_CONTEXT_C_0, "mm",
|
|
||||||
build_directoryName(ASN1_SEQUENCE, issuer->get_encoding(issuer)),
|
|
||||||
asn1_simple_object(ASN1_INTEGER, usercert->get_serialNumber(usercert))
|
|
||||||
),
|
|
||||||
build_directoryName(ASN1_CONTEXT_C_1, subject->get_encoding(subject)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* build v2Form
|
|
||||||
*/
|
|
||||||
static chunk_t build_v2_form(void)
|
|
||||||
{
|
|
||||||
identification_t *subject = signercert->get_subject(signercert);
|
|
||||||
|
|
||||||
return asn1_wrap(ASN1_CONTEXT_C_0, "m",
|
|
||||||
build_directoryName(ASN1_SEQUENCE, subject->get_encoding(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 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, ietfAttr_list_encode(groups)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* build authorityKeyIdentifier
|
|
||||||
*/
|
|
||||||
static chunk_t build_authorityKeyID(x509_t *signer)
|
|
||||||
{
|
|
||||||
identification_t *issuer = signer->get_issuer(signer);
|
|
||||||
chunk_t subjectKeyID = signer->get_subjectKeyID(signer);
|
|
||||||
|
|
||||||
chunk_t keyIdentifier = (subjectKeyID.ptr == NULL)
|
|
||||||
? chunk_empty
|
|
||||||
: asn1_simple_object(ASN1_CONTEXT_S_0, subjectKeyID);
|
|
||||||
|
|
||||||
chunk_t authorityCertIssuer = build_directoryName(ASN1_CONTEXT_C_1,
|
|
||||||
issuer->get_encoding(issuer));
|
|
||||||
|
|
||||||
chunk_t authorityCertSerialNumber = asn1_simple_object(ASN1_CONTEXT_S_2,
|
|
||||||
signer->get_serialNumber(signer));
|
|
||||||
|
|
||||||
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(signercert),
|
|
||||||
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_algorithmIdentifier(OID_SHA1_WITH_RSA),
|
|
||||||
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 signatureValue;
|
|
||||||
chunk_t attributeCertificateInfo = build_attr_cert_info();
|
|
||||||
|
|
||||||
signerkey->build_emsa_pkcs1_signature(signerkey, HASH_SHA1,
|
|
||||||
attributeCertificateInfo, &signatureValue);
|
|
||||||
|
|
||||||
return asn1_wrap(ASN1_SEQUENCE, "mcm",
|
|
||||||
attributeCertificateInfo,
|
|
||||||
asn1_algorithmIdentifier(OID_SHA1_WITH_RSA),
|
|
||||||
asn1_bitstring("m", signatureValue));
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
/* Build a X.509 attribute certificate
|
|
||||||
* Copyright (C) 2002 Ueli Galizzi, Ariane Seiler
|
|
||||||
* 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
|
|
||||||
* 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$
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _BUILD_H
|
|
||||||
#define _BUILD_H
|
|
||||||
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
#include <library.h>
|
|
||||||
#include <crypto/x509.h>
|
|
||||||
#include <crypto/rsa/rsa_private_key.h>
|
|
||||||
#include <utils/linked_list.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
* global variables accessible by both main() and build.c
|
|
||||||
*/
|
|
||||||
extern x509_t *usercert;
|
|
||||||
extern x509_t *signercert;
|
|
||||||
extern rsa_private_key_t *signerkey;
|
|
||||||
extern linked_list_t *groups;
|
|
||||||
extern time_t notBefore;
|
|
||||||
extern time_t notAfter;
|
|
||||||
extern chunk_t serial;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* exported functions
|
|
||||||
*/
|
|
||||||
extern chunk_t build_attr_cert(void);
|
|
||||||
|
|
||||||
#endif /* _BUILD_H */
|
|
||||||
+115
-36
@@ -36,8 +36,8 @@
|
|||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
#include <asn1/asn1.h>
|
#include <asn1/asn1.h>
|
||||||
#include <asn1/ttodata.h>
|
#include <asn1/ttodata.h>
|
||||||
#include <crypto/ac.h>
|
#include <credentials/certificates/x509.h>
|
||||||
#include <crypto/ietf_attr_list.h>
|
#include <credentials/certificates/ac.h>
|
||||||
#include <utils/optionsfrom.h>
|
#include <utils/optionsfrom.h>
|
||||||
|
|
||||||
#ifdef INTEGRITY_TEST
|
#ifdef INTEGRITY_TEST
|
||||||
@@ -47,8 +47,10 @@
|
|||||||
|
|
||||||
#include "build.h"
|
#include "build.h"
|
||||||
|
|
||||||
#define OPENAC_PATH IPSEC_CONFDIR "/openac"
|
#define OPENAC_PATH IPSEC_CONFDIR "/openac"
|
||||||
#define OPENAC_SERIAL IPSEC_CONFDIR "/openac/serial"
|
#define OPENAC_SERIAL IPSEC_CONFDIR "/openac/serial"
|
||||||
|
|
||||||
|
#define DEFAULT_VALIDITY 24*3600 /* seconds */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief prints the usage of the program to the stderr
|
* @brief prints the usage of the program to the stderr
|
||||||
@@ -174,19 +176,80 @@ static void write_serial(chunk_t serial)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load and parse a private key file
|
||||||
|
*/
|
||||||
|
static private_key_t* private_key_create_from_file(char *path, chunk_t *secret)
|
||||||
|
{
|
||||||
|
bool pgp = FALSE;
|
||||||
|
chunk_t chunk = chunk_empty;
|
||||||
|
private_key_t *key = NULL;
|
||||||
|
|
||||||
|
if (!pem_asn1_load_file(path, &secret, &chunk, &pgp))
|
||||||
|
{
|
||||||
|
DBG1(" could not load private key file '%s'", path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
|
||||||
|
BUILD_BLOB_ASN1_DER, chunk, BUILD_END);
|
||||||
|
if (key == NULL)
|
||||||
|
{
|
||||||
|
DBG1(" could not parse loaded private key file '%s'", path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
DBG1(" loaded private key file '%s'", path);
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load and parse an X.509 certificate file
|
||||||
|
*/
|
||||||
|
static x509_t* x509_create_from_file(char *path, char *label, x509_flag_t flag)
|
||||||
|
{
|
||||||
|
|
||||||
|
bool pgp = FALSE;
|
||||||
|
chunk_t chunk;
|
||||||
|
x509_t *x509;
|
||||||
|
certificate_t *cert;
|
||||||
|
time_t notBefore, notAfter, now;
|
||||||
|
|
||||||
|
if (!pem_asn1_load_file(path, NULL, &chunk, &pgp))
|
||||||
|
{
|
||||||
|
DBG1(" could not load %s file '%s'", label, path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
x509 = (x509_t*)lib->creds->create(lib->creds,
|
||||||
|
CRED_CERTIFICATE, CERT_X509,
|
||||||
|
BUILD_BLOB_ASN1_DER, chunk,
|
||||||
|
BUILD_X509_FLAG, flag,
|
||||||
|
BUILD_END);
|
||||||
|
if (x509 == NULL)
|
||||||
|
{
|
||||||
|
DBG1(" could not parse loaded %s file '%s'",label, path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
DBG1(" loaded %s file '%s'", label, path);
|
||||||
|
|
||||||
|
/* check validity */
|
||||||
|
cert = &x509->interface;
|
||||||
|
now = time(NULL);
|
||||||
|
cert->get_validity(cert, &now, ¬Before, ¬After);
|
||||||
|
if (now > notAfter)
|
||||||
|
{
|
||||||
|
DBG1(" certificate expired at %T, discarded", ¬After);
|
||||||
|
cert->destroy(cert);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (now < notBefore)
|
||||||
|
{
|
||||||
|
DBG1(" certificate not valid before %T", ¬Before);
|
||||||
|
}
|
||||||
|
return x509;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* global variables accessible by both main() and build.c
|
* global variables accessible by both main() and build.c
|
||||||
*/
|
*/
|
||||||
x509_t *usercert = NULL;
|
|
||||||
x509_t *signercert = NULL;
|
|
||||||
|
|
||||||
linked_list_t *groups = NULL;
|
|
||||||
rsa_private_key_t *signerkey = NULL;
|
|
||||||
|
|
||||||
time_t notBefore = UNDEFINED_TIME;
|
|
||||||
time_t notAfter = UNDEFINED_TIME;
|
|
||||||
|
|
||||||
chunk_t serial;
|
|
||||||
|
|
||||||
static int debug_level = 1;
|
static int debug_level = 1;
|
||||||
static bool stderr_quiet = FALSE;
|
static bool stderr_quiet = FALSE;
|
||||||
@@ -220,18 +283,26 @@ static void openac_dbg(int level, char *fmt, ...)
|
|||||||
*/
|
*/
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
certificate_t *attr_cert = NULL;
|
||||||
|
certificate_t *user_cert = NULL;
|
||||||
|
certificate_t *signer_cert = NULL;
|
||||||
|
private_key_t *signer_key = NULL;
|
||||||
|
|
||||||
|
time_t notBefore = UNDEFINED_TIME;
|
||||||
|
time_t notAfter = UNDEFINED_TIME;
|
||||||
|
time_t validity = 0;
|
||||||
|
|
||||||
char *keyfile = NULL;
|
char *keyfile = NULL;
|
||||||
char *certfile = NULL;
|
char *certfile = NULL;
|
||||||
char *usercertfile = NULL;
|
char *usercertfile = NULL;
|
||||||
char *outfile = NULL;
|
char *outfile = NULL;
|
||||||
|
char *groups = "";
|
||||||
char buf[BUF_LEN];
|
char buf[BUF_LEN];
|
||||||
|
|
||||||
|
chunk_t serial;
|
||||||
chunk_t passphrase = { buf, 0 };
|
chunk_t passphrase = { buf, 0 };
|
||||||
chunk_t attr_cert = chunk_empty;
|
chunk_t attr_chunk = chunk_empty;
|
||||||
x509ac_t *ac = NULL;
|
|
||||||
|
|
||||||
const time_t default_validity = 24*3600; /* 24 hours */
|
|
||||||
time_t validity = 0;
|
|
||||||
int status = 1;
|
int status = 1;
|
||||||
|
|
||||||
options_t *options = options_create();
|
options_t *options = options_create();
|
||||||
@@ -240,7 +311,6 @@ int main(int argc, char **argv)
|
|||||||
dbg = openac_dbg;
|
dbg = openac_dbg;
|
||||||
|
|
||||||
passphrase.ptr[0] = '\0';
|
passphrase.ptr[0] = '\0';
|
||||||
groups = linked_list_create();
|
|
||||||
|
|
||||||
openlog("openac", 0, LOG_AUTHPRIV);
|
openlog("openac", 0, LOG_AUTHPRIV);
|
||||||
|
|
||||||
@@ -337,7 +407,7 @@ int main(int argc, char **argv)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
case 'g': /* --groups */
|
case 'g': /* --groups */
|
||||||
ietfAttr_list_create_from_string(optarg, groups);
|
groups = optarg;
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case 'D': /* --days */
|
case 'D': /* --days */
|
||||||
@@ -449,9 +519,9 @@ int main(int argc, char **argv)
|
|||||||
/* load the signer's RSA private key */
|
/* load the signer's RSA private key */
|
||||||
if (keyfile != NULL)
|
if (keyfile != NULL)
|
||||||
{
|
{
|
||||||
signerkey = rsa_private_key_create_from_file(keyfile, &passphrase);
|
signer_key = private_key_create_from_file(keyfile, &passphrase);
|
||||||
|
|
||||||
if (signerkey == NULL)
|
if (signer_key == NULL)
|
||||||
{
|
{
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
@@ -460,41 +530,50 @@ int main(int argc, char **argv)
|
|||||||
/* load the signer's X.509 certificate */
|
/* load the signer's X.509 certificate */
|
||||||
if (certfile != NULL)
|
if (certfile != NULL)
|
||||||
{
|
{
|
||||||
signercert = x509_create_from_file(certfile, "signer cert");
|
x509_t *x509 = x509_create_from_file(certfile, "signer cert", 0);
|
||||||
|
|
||||||
if (signercert == NULL)
|
if (x509 == NULL)
|
||||||
{
|
{
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
signer_cert = &x509->interface;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* load the users's X.509 certificate */
|
/* load the users's X.509 certificate */
|
||||||
if (usercertfile != NULL)
|
if (usercertfile != NULL)
|
||||||
{
|
{
|
||||||
usercert = x509_create_from_file(usercertfile, "user cert");
|
x509_t *x509 = x509_create_from_file(usercertfile, "user cert", 0);
|
||||||
|
|
||||||
if (usercert == NULL)
|
if (x509 == NULL)
|
||||||
{
|
{
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
user_cert = &x509->interface;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* compute validity interval */
|
/* compute validity interval */
|
||||||
validity = (validity)? validity : default_validity;
|
validity = (validity)? validity : DEFAULT_VALIDITY;
|
||||||
notBefore = (notBefore == UNDEFINED_TIME) ? time(NULL) : notBefore;
|
notBefore = (notBefore == UNDEFINED_TIME) ? time(NULL) : notBefore;
|
||||||
notAfter = (notAfter == UNDEFINED_TIME) ? time(NULL) + validity : notAfter;
|
notAfter = (notAfter == UNDEFINED_TIME) ? time(NULL) + validity : notAfter;
|
||||||
|
|
||||||
/* build and parse attribute certificate */
|
/* build and parse attribute certificate */
|
||||||
if (usercert != NULL && signercert != NULL && signerkey != NULL)
|
if (user_cert != NULL && signer_cert != NULL && signer_key != NULL)
|
||||||
{
|
{
|
||||||
/* read the serial number and increment it by one */
|
/* read the serial number and increment it by one */
|
||||||
serial = read_serial();
|
serial = read_serial();
|
||||||
|
|
||||||
attr_cert = build_attr_cert();
|
attr_cert = lib->creds->create(lib->creds,
|
||||||
ac = x509ac_create_from_chunk(attr_cert);
|
CRED_CERTIFICATE, CERT_X509_AC,
|
||||||
|
BUILD_CERT, user_cert,
|
||||||
|
BUILD_NOT_BEFORE_TIME, ¬Before,
|
||||||
|
BUILD_NOT_AFTER_TIME, ¬After,
|
||||||
|
BUILD_SIGNING_CERT, signer_cert,
|
||||||
|
BUILD_SIGNING_KEY, signer_key,
|
||||||
|
BUILD_END);
|
||||||
|
attr_chunk = attr_cert->get_encoding(attr_cert);
|
||||||
|
|
||||||
/* write the attribute certificate to file */
|
/* write the attribute certificate to file */
|
||||||
if (chunk_write(attr_cert, outfile, "attribute cert", 0022, TRUE))
|
if (chunk_write(attr_chunk, outfile, "attribute cert", 0022, TRUE))
|
||||||
{
|
{
|
||||||
write_serial(serial);
|
write_serial(serial);
|
||||||
status = 0;
|
status = 0;
|
||||||
@@ -503,11 +582,11 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
end:
|
end:
|
||||||
/* delete all dynamically allocated objects */
|
/* delete all dynamically allocated objects */
|
||||||
DESTROY_IF(signerkey);
|
DESTROY_IF(signer_key);
|
||||||
DESTROY_IF(signercert);
|
DESTROY_IF(signer_cert);
|
||||||
DESTROY_IF(usercert);
|
DESTROY_IF(user_cert);
|
||||||
DESTROY_IF(ac);
|
DESTROY_IF(attr_cert);
|
||||||
ietfAttr_list_destroy(groups);
|
free(attr_chunk.ptr);
|
||||||
free(serial.ptr);
|
free(serial.ptr);
|
||||||
closelog();
|
closelog();
|
||||||
dbg = dbg_default;
|
dbg = dbg_default;
|
||||||
|
|||||||
Reference in New Issue
Block a user