Logo Search packages:      
Sourcecode: openswan version File versions  Download package

ac.c

/* Support of X.509 attribute certificates
 * Copyright (C) 2002 Ueli Gallizzi, Ariane Seiler
 * Copyright (C) 2003 Martin Berner, Lukas Suter
 *
 * 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.c,v 1.7 2004-06-14 01:46:02 mcr Exp $
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <time.h>
#include <sys/types.h>

#include <openswan.h>

#include "constants.h"
#include "oswlog.h"

#include "defs.h"
#include "asn1.h"
#include "oid.h"
#include "ac.h"
#include "id.h"
#include "x509.h"
#include "pgp.h"
#include "certs.h"
#include "log.h"
#include "paths.h"
#include "whack.h"
#include "fetch.h"

/* chained list of X.509 attribute certificates */
 
static x509acert_t *x509acerts   = NULL;
 
/* chained list of ietfAttributes */
 
static ietfAttrList_t *ietfAttributes = NULL;

/* 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

/* 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_SEQUENCE,          ASN1_OBJ  }, /* 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       40
#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

const x509acert_t empty_ac = {
      NULL     , /* *next */
            0  , /* installed */
    { NULL, 0 }, /* certificate */
    { NULL, 0 }, /*   certificateInfo */
            1  , /*     version */
             /*     holder */
             /*       baseCertificateID */
    { NULL, 0 }, /*         holderIssuer */
    { NULL, 0 }, /*         holderSerial */
             /*       entityName */
    { NULL, 0 }, /*         generalNames */
             /*     v2Form */
    { NULL, 0 }, /*       issuerName */
                 /*     signature */
    OID_UNKNOWN, /*       sigAlg */
    { NULL, 0 }, /*     serialNumber */
                 /*     attrCertValidityPeriod */
            0  , /*       notBefore */
            0  , /*       notAfter */
             /*     attributes */
      NULL     , /*       charging */
      NULL     , /*       groups */
             /*     extensions */
    { NULL, 0 }, /*       authKeyID */
    { NULL, 0 }, /*       authKeySerialNumber */
      FALSE    , /*       noRevAvail */
             /*   signatureAlgorithm */
    OID_UNKNOWN, /*     algorithm */
    { NULL, 0 }, /*   signature */
};


/* Maximum length of ASN.1 distinquished name */

#define BUF_LEN         512

/*  compare two ietfAttributes, returns zero if a equals b
 *  negative/positive if a is earlier/later in the alphabet than b
 */
static int
cmp_ietfAttr(ietfAttr_t *a,ietfAttr_t *b)
{   
     int cmp_len, len, cmp_value;
       
     /* cannot compare OID with STRING or OCTETS attributes */
     if (a->kind == IETF_ATTRIBUTE_OID && b->kind != IETF_ATTRIBUTE_OID)
      return 1;
 
     cmp_len = a->value.len - b->value.len;
     len = (cmp_len < 0)? a->value.len : b->value.len;
     cmp_value = memcmp(a->value.ptr, b->value.ptr, len);
     
    return (cmp_value == 0)? cmp_len : cmp_value;
}     
    
/*
 *  add an ietfAttribute to the chained list
 */
static ietfAttr_t*
add_ietfAttr(ietfAttr_t *attr)
{
    ietfAttrList_t **listp = &ietfAttributes;
    ietfAttrList_t *list = *listp;
    int cmp = -1;
    
    while (list != NULL)
    {
      cmp = cmp_ietfAttr(attr, list->attr);
      if (cmp <= 0)
          break;
      listp = &list->next;
      list = *listp;
    }
    
    if (cmp == 0)
    {
      /* attribute already exists, increase count */
      pfree(attr);
      list->attr->count++;
      return list->attr;
    }
    else
    {
      ietfAttrList_t *el = alloc_thing(ietfAttrList_t, "ietfAttrList");
    
      /* new attribute, unshare value */
      attr->value.ptr = clone_bytes(attr->value.ptr, attr->value.len
          , "attr value");
      attr->count = 1;
      time(&attr->installed);
     
      el->attr = attr;
      el->next = list;
      *listp = el;
    
      return attr;
    }
}
      
/*   
 * decodes a comma separated list of group attributes
 */
void
decode_groups(char *groups, ietfAttrList_t **listp)
{
    if (groups == NULL)
      return;
 
    while (strlen(groups) > 0)
    {
      char *end;
      char *next = strchr(groups, ',');

      if (next == NULL)
         end = next = groups + strlen(groups);
      else
         end = next++;
 
      /* eat preceeding whitespace */
      while (groups < end && *groups == ' ')
          groups++;
      
      /* eat trailing whitespace */
      while (end > groups && *(end-1) == ' ')
          end--;
      
      if (groups < end)
      {
          ietfAttr_t *attr   = alloc_thing(ietfAttr_t, "ietfAttr");
          ietfAttrList_t *el = alloc_thing(ietfAttrList_t, "ietfAttrList");
          
          attr->kind  = IETF_ATTRIBUTE_STRING;
          attr->value.ptr = groups;
          attr->value.len = end - groups;
          attr->count = 0;
      
          el->attr = add_ietfAttr(attr);
          el->next = *listp;
          *listp = el;
      }
          
      groups = next;
    }
}
          
void  
unshare_ietfAttrList(ietfAttrList_t **listp)
{
    ietfAttrList_t *list = *listp;
       
    while (list != NULL)
    {
      ietfAttrList_t *el = alloc_thing(ietfAttrList_t, "ietfAttrList");
 
      el->attr = list->attr;
      el->attr->count++;
      el->next = NULL;
      *listp = el;
      listp = &el->next;
      list = list->next;
    }
}
       
/*
 * parses ietfAttrSyntax
 */
static ietfAttrList_t*
parse_ietfAttrSyntax(chunk_t blob, int level0)
{
    asn1_ctx_t ctx;
    chunk_t object;
    u_int level;
    int objectID = 0;
    
    ietfAttrList_t *list = NULL;
      
    asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);

    while (objectID < IETF_ATTR_ROOF)
    {
       if (!extract_object(ietfAttrSyntaxObjects, &objectID, &object, &level, &ctx))
            return NULL;

       switch (objectID)
       {
       case IETF_ATTR_OCTETS:
       case IETF_ATTR_OID:
       case IETF_ATTR_STRING:
           {
               ietfAttr_t *attr   = alloc_thing(ietfAttr_t, "ietfAttr");
               ietfAttrList_t *el = alloc_thing(ietfAttrList_t, "ietfAttrList");
            
               attr->kind  = (objectID - IETF_ATTR_OCTETS) / 2;
               attr->value = object;
               attr->count = 0;
       
               el->attr = add_ietfAttr(attr);
               el->next = list;
               list = el;
           }
           break;
      default:
         break;
      }
      objectID++;
    }
    return list;
}

/*
 * parses roleSyntax
 */
static void
parse_roleSyntax(chunk_t blob, int level0)
{
    asn1_ctx_t ctx;
    chunk_t object;
    u_int level;
    int objectID = 0;

    asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);

    while (objectID < ROLE_ROOF)
    {
      if (!extract_object(roleSyntaxObjects, &objectID, &object, &level, &ctx))
           return;

      switch (objectID) {
      default:
          break;
      }
      objectID++;
    }
}

/*
 *  Parses an X.509 attribute certificate
 */
static bool
parse_ac(chunk_t blob, x509acert_t *ac)
{
    asn1_ctx_t ctx;
    bool critical;
    chunk_t extnID;
    chunk_t type;
    chunk_t object;
    u_int level;
    int objectID = 0;

    asn1_init(&ctx, blob, 0, FALSE, DBG_RAW);

    while (objectID < AC_OBJ_ROOF) {

      if (!extract_object(acObjects, &objectID, &object, &level, &ctx))
           return FALSE;

      /* those objects which will parsed further need the next higher level */
      level++;

      switch (objectID)
      {
      case AC_OBJ_CERTIFICATE:
          ac->certificate = object;
          break;
      case AC_OBJ_CERTIFICATE_INFO:
          ac->certificateInfo = object;
          break;
      case AC_OBJ_VERSION:
          ac->version = (object.len) ? (1 + (u_int)*object.ptr) : 1;
          DBG(DBG_PARSING,
            DBG_log("  v%d", ac->version);
          )
          if (ac->version != 2)
          {
            openswan_log("v%d attribute certificates are not supported"
                , ac->version);
            return FALSE;
          }
          break;
      case AC_OBJ_HOLDER_ISSUER:
          ac->holderIssuer = get_directoryName(object, level, FALSE);
          break;
      case AC_OBJ_HOLDER_SERIAL:
          ac->holderSerial = object;
          break;
      case AC_OBJ_ENTITY_NAME:
          ac->entityName = get_directoryName(object, level, TRUE);
          break;
      case AC_OBJ_ISSUER_NAME:
          ac->issuerName = get_directoryName(object, level, FALSE);
          break;
      case AC_OBJ_SIG_ALG:
          ac->sigAlg = parse_algorithmIdentifier(object, level);
          break;
      case AC_OBJ_SERIAL_NUMBER:
          ac->serialNumber = object;
          break;
      case AC_OBJ_NOT_BEFORE:
          ac->notBefore = asn1totime(&object, ASN1_GENERALIZEDTIME);
          break;
      case AC_OBJ_NOT_AFTER:
          ac->notAfter = asn1totime(&object, ASN1_GENERALIZEDTIME);
          break;
      case AC_OBJ_ATTRIBUTE_TYPE:
          type = object;
          break;
      case AC_OBJ_ATTRIBUTE_VALUE:
          {
            u_int type_oid = known_oid(type);

            switch (type_oid) {
            case OID_AUTHENTICATION_INFO:
                DBG(DBG_PARSING,
                  DBG_log("  need to parse authenticationInfo")
                )
                break;
            case OID_ACCESS_IDENTITY:
                DBG(DBG_PARSING,
                  DBG_log("  need to parse accessIdentity")
                )
                break;
            case OID_CHARGING_IDENTITY:
                ac->charging = parse_ietfAttrSyntax(object, level);
                break;
            case OID_GROUP:
                ac->groups = parse_ietfAttrSyntax(object, level);
                break;
            case OID_ROLE:
                parse_roleSyntax(object, level);
                break;
            default:
                break;
            }
          }
          break;
      case AC_OBJ_EXTN_ID:
          extnID = object;
          break;
      case AC_OBJ_CRITICAL:
          critical = object.len && *object.ptr;
          DBG(DBG_PARSING,
            DBG_log("  %s",(critical)?"TRUE":"FALSE");
          )
          break;
      case AC_OBJ_EXTN_VALUE:
          {
            u_int extn_oid = known_oid(extnID);

            switch (extn_oid) {
            case OID_CRL_DISTRIBUTION_POINTS:
                DBG(DBG_PARSING,
                  DBG_log("  need to parse crlDistributionPoints")
                )
                break;
            case OID_AUTHORITY_KEY_ID:
                parse_authorityKeyIdentifier(object, level
                  , &ac->authKeyID, &ac->authKeySerialNumber);
                break;
            case OID_TARGET_INFORMATION:
                DBG(DBG_PARSING,
                  DBG_log("  need to parse targetInformation")
                )
                break;
            case OID_NO_REV_AVAIL:
                ac->noRevAvail = TRUE;
                break;
            default:
                break;
            }
          }
          break;
      case AC_OBJ_ALGORITHM:
          ac->algorithm = parse_algorithmIdentifier(object, level);
          break;
      case AC_OBJ_SIGNATURE:
          ac->signature = object;
          break;

      default:
          break;
      }
      objectID++;
    }
    time(&ac->installed);
    return TRUE;
}

/*
 *  compare two X.509 attribute certificates by comparing their signatures
 */
static bool
same_x509acert(x509acert_t *a, x509acert_t *b)
{
    return a->signature.len == b->signature.len &&
      memcmp(a->signature.ptr, b->signature.ptr, b->signature.len) == 0;
}

/*
 *  release an ietfAttribute, free it if count reaches zero
 */
static void
release_ietfAttr(ietfAttr_t* attr)
{
    if (--attr->count == 0)
    {
      ietfAttrList_t **plist = &ietfAttributes;
      ietfAttrList_t *list = *plist;

      while (list->attr != attr)
      {
          plist = &list->next;
          list = *plist;
      }
        *plist = list->next;
      
      pfree(attr->value.ptr);
      pfree(attr);
      pfree(list);
    }
}

/*
 *  free an ietfAttrList
 */
void
free_ietfAttrList(ietfAttrList_t* list)
{
    while (list != NULL)
    {
      ietfAttrList_t *el = list;

      release_ietfAttr(el->attr);
      list = list->next;
      pfree(el);
    }
}

/*
 *  free a X.509 attribute certificate
 */
static void
free_acert(x509acert_t *ac)
{
    if (ac != NULL)
    {
      free_ietfAttrList(ac->charging);
      free_ietfAttrList(ac->groups);
      pfreeany(ac->certificate.ptr);
      pfree(ac);
    }
}

/*
 *  add a X.509 attribute certificate to the chained list
 */
static void
add_acert(x509acert_t *acert)
{
    x509acert_t *ac = x509acerts;

    while (ac != NULL)
    {
      if (same_x509acert(acert, ac)) /* already in chain, free cert */
      {
          free_acert(acert);
      }
      ac = ac->next;
    }

    /* insert new ac at the root of the chain */
    acert->next = x509acerts;
    x509acerts = acert;
}

/* verify the validity of an attribute certificate by
 * checking the notBefore and notAfter dates
 */
static err_t
check_ac_validity(const x509acert_t *ac)
{
    time_t current_time;

    time(&current_time);
    DBG(DBG_CONTROL | DBG_PARSING,
      char tbuf[TIMETOA_BUF];

      DBG_log("  not before  : %s", timetoa(&ac->notBefore, TRUE, tbuf, sizeof(tbuf)));
      DBG_log("  current time: %s", timetoa(&current_time, TRUE, tbuf, sizeof(tbuf)));
      DBG_log("  not after   : %s", timetoa(&ac->notAfter, TRUE, tbuf, sizeof(tbuf)));
    )

    if (current_time < ac->notBefore)
      return "attribute certificate is not valid yet";
    if (current_time > ac->notAfter)
      return "attribute certificate has expired";
    else
      return NULL;
}

/*
 * verifies a X.509 attribute certificate
 */
static bool
verify_x509acert(x509acert_t *ac, bool strict)
{
    u_char buf[BUF_LEN];
    x509cert_t *aacert;
    err_t ugh = NULL;
    time_t valid_until = ac->notAfter;

    DBG(DBG_CONTROL,
      dntoa(buf, BUF_LEN, ac->entityName);
      DBG_log("holder: '%s'",buf);
      dntoa(buf, BUF_LEN, ac->issuerName);
      DBG_log("issuer: '%s'",buf);
    )
    
    ugh = check_ac_validity(ac);

    if (ugh != NULL)
    {
      plog("%s", ugh);
      return FALSE;
    }
    DBG(DBG_CONTROL,
      DBG_log("attribute certificate is valid")
    )

    lock_authcert_list("verify_x509acert");
    aacert = get_authcert(ac->issuerName, ac->authKeySerialNumber
      , ac->authKeyID, AUTH_AA);
    unlock_authcert_list("verify_x509acert");

    if (aacert == NULL)
    {
      plog("issuer aacert not found");
      return FALSE;
    }
    DBG(DBG_CONTROL,
      DBG_log("issuer aacert found")
    )

    if (!check_signature(ac->certificateInfo, ac->signature
                   , ac->algorithm, aacert))
    {
      plog("attribute certificate signature is invalid");
      return FALSE;
    }
    DBG(DBG_CONTROL,
      DBG_log("attribute certificate signature is valid");
    )

    return verify_x509cert(aacert, strict, &valid_until);
}

/*
 * Loads X.509 attribute certificates
 */
void
load_acerts(void)
{
    u_char buf[BUF_LEN];

    /* change directory to specified path */
    u_char *save_dir = getcwd(buf, BUF_LEN);

    if (!chdir(A_CERT_PATH))
    {
      struct dirent **filelist;
      int n;

      openswan_log("Changing to directory '%s'",A_CERT_PATH);
      n = scandir(A_CERT_PATH, &filelist, file_select, alphasort);

      if (n > 0)
      {
          while (n--)
          {
            chunk_t blob = empty_chunk;
            bool pgp = FALSE;

            if (load_coded_file(filelist[n]->d_name, NULL, "acert", &blob, &pgp))
            {
                x509acert_t *ac = alloc_thing(x509acert_t, "x509acert");
                
                *ac = empty_ac;

                if (parse_ac(blob, ac)
                && verify_x509acert(ac, strict_crl_policy))
                  add_acert(ac);
                else
                  free_acert(ac);
            }
            free(filelist[n]);
          }
          free(filelist);
      }
    }
    /* restore directory path */
    chdir(save_dir);
}

/*
 * Free all attribute certificates in the chained list
 */
void
free_acerts(void)
{
    while (x509acerts != NULL)
    {
      x509acert_t *ac = x509acerts;
      x509acerts = ac->next;
      free_acert(ac);
    }
}

/*
 *  list all X.509 attribute certificates in the chained list
 */
void
list_acerts(bool utc)
{
    x509acert_t *ac = x509acerts;
    time_t now;

    /* determine the current time */
    time(&now);

    if (ac != NULL)
    {
      whack_log(RC_COMMENT, " ");
      whack_log(RC_COMMENT, "List of X.509 Attribute Certificates:");
      whack_log(RC_COMMENT, " ");
    }

    while (ac != NULL)
    {
      u_char buf[BUF_LEN];
      char   tbuf[TIMETOA_BUF];

      whack_log(RC_COMMENT, "%s",timetoa(&ac->installed, utc, tbuf, sizeof(tbuf)));
      if (ac->entityName.ptr != NULL)
      {
          dntoa(buf, BUF_LEN, ac->entityName);
          whack_log(RC_COMMENT, "       holder:  '%s'", buf);
      }
      if (ac->holderIssuer.ptr != NULL)
      {
          dntoa(buf, BUF_LEN, ac->holderIssuer);
          whack_log(RC_COMMENT, "       hissuer: '%s'", buf);
      }
      if (ac->holderSerial.ptr != NULL)
      {
          datatot(ac->holderSerial.ptr, ac->holderSerial.len, ':'
            , buf, BUF_LEN);
          whack_log(RC_COMMENT, "       hserial:  %s", buf);
      }
      dntoa(buf, BUF_LEN, ac->issuerName);
      whack_log(RC_COMMENT, "       issuer:  '%s'", buf);
      datatot(ac->serialNumber.ptr, ac->serialNumber.len, ':'
          , buf, BUF_LEN);
      whack_log(RC_COMMENT, "       serial:   %s", buf);

      if (ac->groups != NULL)
      {
          bool first = TRUE;
          char *pos = buf;

          ietfAttrList_t *list = ac->groups;

          while (list != NULL)
          {
            ietfAttr_t *attr = list->attr;

            if (attr->kind != IETF_ATTRIBUTE_OID)
            {
                int n = snprintf(pos, BUF_LEN, "%s%.*s", (first? "":", ")
                  , (int)attr->value.len, attr->value.ptr);
                
                if (n == -1) /* print buffer is full */
                  break;
                pos += n;
                first = FALSE;
            }
            list = list->next;
          }

          whack_log(RC_COMMENT, "       groups:   %s", buf);
      }

      whack_log(RC_COMMENT, "       validity: not before %s %s",
            timetoa(&ac->notBefore, utc, tbuf, sizeof(tbuf)),
            (ac->notBefore < now)?"ok":"fatal (not valid yet)");
      whack_log(RC_COMMENT, "                 not after  %s %s",
            timetoa(&ac->notAfter, utc, tbuf, sizeof(tbuf)),
            check_expiry(ac->notAfter, ACERT_WARNING_INTERVAL, TRUE));

      ac = ac->next;
    }
}

/*
 *  list all group attributes in alphabetical order
 */
void
list_groups(bool utc)
{
    ietfAttrList_t *list = ietfAttributes;
    
    if (list != NULL)
    {
      whack_log(RC_COMMENT, " ");
      whack_log(RC_COMMENT, "List of Group Attributes:");
      whack_log(RC_COMMENT, " ");
    }

    while (list != NULL)
    {
      ietfAttr_t *attr = list->attr;
      char   tbuf[TIMETOA_BUF];

      whack_log(RC_COMMENT, "%s, count: %d", timetoa(&attr->installed, utc, tbuf, sizeof(tbuf)),
            attr->count);
      
      switch (attr->kind)
      {
      case IETF_ATTRIBUTE_OCTETS:
      case IETF_ATTRIBUTE_STRING:
          whack_log(RC_COMMENT, "       %.*s", (int)attr->value.len, attr->value.ptr);
          break;
      case IETF_ATTRIBUTE_OID:
          whack_log(RC_COMMENT, "       OID");
          break;
      default:
          break;
        }

      list = list->next;
    }
}

Generated by  Doxygen 1.6.0   Back to index