#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <CdsaUtils/cuCdsaUtils.h>
#include <CdsaUtils/cuTimeStr.h>
#include <CdsaUtils/cuDbUtils.h>
#include <CdsaUtils/cuFileIo.h>
#include <strings.h>
#include "ldapFetch.h"
#include <Security/keychainacl.h>
#include <Security/cssmacl.h>
#include <Security/aclclient.h>
#include <Security/cssmdata.h>
#include <Security/SecTrust.h>
#define DEFAULT_STALE_DAYS 10
#define DEFAULT_EXPIRE_OVERLAP_SECONDS 3600
#define SECONDS_PER_DAY (60 * 60 * 24)
#define CRL_CACHE_DB "/var/db/crls/crlcache.db"
#define X509_CERT_DB "/System/Library/Keychains/X509Certificates"
#ifdef NDEBUG
#define DEBUG_PRINT 0
#else
#define DEBUG_PRINT 1
#endif
#if DEBUG_PRINT
#define dprintf(args...) fprintf(stderr, args)
#else
#define dprintf(args...)
#endif
static void usage(char **argv)
{
printf("Usage\n");
printf("Refresh : %s r [options]\n", argv[0]);
printf("Fetch CRL : %s f URI [options]\n", argv[0]);
printf("Fetch cert : %s F URI [options]\n", argv[0]);
printf("Refresh options:\n");
printf(" s=stale_period in DAYS; default=%d\n", DEFAULT_STALE_DAYS);
printf(" o=expire_overlap in SECONDS; default=%d\n",
DEFAULT_EXPIRE_OVERLAP_SECONDS);
printf(" p (Purge all entries, ensuring refresh with fresh CRLs)\n");
printf(" f (Full crypto CRL verification)\n");
printf(" k=keychainName (default=%s\n", CRL_CACHE_DB);
printf(" v(erbose)\n");
printf("Fetch options:\n");
printf(" F=outFileName (default is stdout)\n");
printf(" n (no write to cache after fetch)\n");
exit(1);
}
static void printString(
const CSSM_DATA *str)
{
unsigned i;
char *cp = (char *)str->Data;
for(i=0; i<str->Length; i++) {
printf("%c", *cp++);
}
}
#define DB_ATTRIBUTE(name, type) \
{ CSSM_DB_ATTRIBUTE_NAME_AS_STRING, \
{#name}, \
CSSM_DB_ATTRIBUTE_FORMAT_ ## type \
}
static const CSSM_DB_ATTRIBUTE_INFO x509CrlRecordAttrs[] = {
DB_ATTRIBUTE(CrlType, UINT32), DB_ATTRIBUTE(CrlEncoding, UINT32), DB_ATTRIBUTE(PrintName, BLOB), DB_ATTRIBUTE(Issuer, BLOB), DB_ATTRIBUTE(NextUpdate, BLOB), DB_ATTRIBUTE(URI, BLOB),
};
#define NUM_CRL_ATTRS \
(sizeof(x509CrlRecordAttrs) / sizeof(x509CrlRecordAttrs[0]))
#define ATTR_DEX_CRL_TYPE 0
#define ATTR_DEX_CRL_ENC 1
#define ATTR_DEX_PRINT_NAME 2
#define ATTR_DEX_ISSUER 3
#define ATTR_DEX_NEXT_UPDATE 4
#define ATTR_DEX_URI 5
static void freeAttrs(
CSSM_DB_ATTRIBUTE_DATA *attrs,
unsigned numAttrs)
{
unsigned i;
for(i=0; i<numAttrs; i++) {
CSSM_DB_ATTRIBUTE_DATA_PTR attrData = &attrs[i];
unsigned j;
for(j=0; j<attrData->NumberOfValues; j++) {
CSSM_DATA_PTR data = &attrData->Value[j];
if(data == NULL) {
printf("***freeAttrs screwup: NULL data\n");
return;
}
APP_FREE(data->Data);
data->Data = NULL;
data->Length = 0;
}
APP_FREE(attrData->Value);
attrData->Value = NULL;
}
}
int compareTimes(
const char *t1,
const char *t2)
{
for(unsigned dex=0; dex<CSSM_TIME_STRLEN; dex++, t1++, t2++) {
if(*t1 > *t2) {
return 1;
}
if(*t1 < *t2) {
return -1;
}
}
return 0;
}
class CrlInfo
{
public:
CrlInfo(
CSSM_DL_DB_HANDLE dlDbHand,
CSSM_DB_ATTRIBUTE_DATA *attrData, CSSM_DB_UNIQUE_RECORD_PTR record,
CSSM_DATA_PTR crlBlob); ~CrlInfo();
CSSM_DATA_PTR fetchValidAttr(
unsigned attrDex);
int fetchIntAttr(
unsigned dex,
uint32 &rtn);
bool isSameIssuer(
CrlInfo *other);
void printName();
void validateTimes(
const char *updateTime,
const char *staleTime,
unsigned dex);
bool mIsBadlyFormed; bool mIsExpired; bool mIsStale; bool mRefreshed;
CSSM_DATA mCrlBlob;
CSSM_DL_DB_HANDLE dlDbHand() { return mDlDbHand; }
CSSM_DB_ATTRIBUTE_DATA_PTR attrData() { return &mAttrData[0]; }
CSSM_DB_UNIQUE_RECORD_PTR record() { return mRecord; };
private:
CSSM_DL_DB_HANDLE mDlDbHand;
CSSM_DB_ATTRIBUTE_DATA mAttrData[NUM_CRL_ATTRS];
CSSM_DB_UNIQUE_RECORD_PTR mRecord;
};
CrlInfo::CrlInfo(
CSSM_DL_DB_HANDLE dlDbHand,
CSSM_DB_ATTRIBUTE_DATA *attrData, CSSM_DB_UNIQUE_RECORD_PTR record,
CSSM_DATA_PTR crlBlob) : mIsBadlyFormed(false),
mIsExpired(false),
mIsStale(false),
mRefreshed(false),
mDlDbHand(dlDbHand),
mRecord(record)
{
if(crlBlob) {
mCrlBlob = *crlBlob;
}
else {
mCrlBlob.Data = NULL;
mCrlBlob.Length = 0;
}
memmove(mAttrData, attrData,
sizeof(CSSM_DB_ATTRIBUTE_DATA) * NUM_CRL_ATTRS);
}
CrlInfo::~CrlInfo()
{
freeAttrs(&mAttrData[0], NUM_CRL_ATTRS);
CSSM_DL_FreeUniqueRecord(mDlDbHand, mRecord);
if(mCrlBlob.Data) {
APP_FREE(mCrlBlob.Data);
}
}
CSSM_DATA_PTR CrlInfo::fetchValidAttr(
unsigned attrDex)
{
if(mAttrData[attrDex].NumberOfValues != 1) {
return NULL;
}
return mAttrData[attrDex].Value;
}
int CrlInfo::fetchIntAttr(
unsigned dex,
uint32 &rtn)
{
CSSM_DATA *val = fetchValidAttr(dex);
if((val == NULL) || (val->Length != sizeof(uint32))) {
dprintf("***Badly formed uint32 attr at dex %u\n", dex);
mIsBadlyFormed = true;
return 1;
}
rtn = cuDER_ToInt(val);
return 0;
}
bool CrlInfo::isSameIssuer(
CrlInfo *other)
{
CSSM_DATA_PTR thisIssuer = fetchValidAttr(ATTR_DEX_ISSUER);
if(thisIssuer == NULL) {
return false;
}
CSSM_DATA_PTR otherIssuer = other->fetchValidAttr(ATTR_DEX_ISSUER);
if(otherIssuer == NULL) {
return false;
}
return cuCompareCssmData(thisIssuer, otherIssuer) ? true : false;
}
void CrlInfo::printName()
{
CSSM_DATA_PTR val = fetchValidAttr(ATTR_DEX_PRINT_NAME);
if(val == NULL) {
printf("X509 CRL\n");
}
else {
printString(val);
printf("\n");
}
}
void CrlInfo::validateTimes(
const char *updateTime, const char *staleTime, unsigned dex) {
CSSM_DATA *nextUpdateData = fetchValidAttr(ATTR_DEX_NEXT_UPDATE);
if((nextUpdateData == NULL) ||
(nextUpdateData->Length != CSSM_TIME_STRLEN)) {
printf("***Badly formed NextUpdate attr on CRL %u\n", dex);
mIsBadlyFormed = true;
return;
}
#if DEBUG_PRINT
printf("Crl %u NextUpdate : ", dex); printString(nextUpdateData);
printf("\n");
#endif
char *nextUpdate = (char *)nextUpdateData->Data;
if(compareTimes(nextUpdate, updateTime) < 0) {
dprintf("...CRL %u is expired\n", dex);
mIsExpired = true;
if(compareTimes(nextUpdate, staleTime) < 0) {
dprintf("...CRL %u is stale\n", dex);
mIsStale = true;
}
}
}
static CSSM_RETURN fetchAllCrls(
CSSM_DL_DB_HANDLE dlDbHand,
bool fetchBlobs, CrlInfo **&rtnCrlInfo, unsigned &numCrls) {
CSSM_QUERY query;
CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttrs;
CSSM_DB_UNIQUE_RECORD_PTR record = NULL;
CSSM_RETURN crtn;
CSSM_HANDLE resultHand;
unsigned attrDex;
CSSM_DB_ATTRIBUTE_DATA attrData[NUM_CRL_ATTRS];
CSSM_DATA_PTR crlDataPtr = NULL;
CSSM_DATA crlData;
numCrls = 0;
rtnCrlInfo = NULL;
memset(attrData, 0, sizeof(CSSM_DB_ATTRIBUTE_DATA) * NUM_CRL_ATTRS);
for(attrDex=0; attrDex<NUM_CRL_ATTRS; attrDex++) {
attrData[attrDex].Info = x509CrlRecordAttrs[attrDex];
}
recordAttrs.DataRecordType = CSSM_DL_DB_RECORD_X509_CRL;
recordAttrs.NumberOfAttributes = NUM_CRL_ATTRS;
recordAttrs.AttributeData = &attrData[0];
query.RecordType = CSSM_DL_DB_RECORD_X509_CRL;
query.Conjunctive = CSSM_DB_NONE;
query.NumSelectionPredicates = 0;
query.SelectionPredicate = NULL;
query.QueryLimits.TimeLimit = 0; query.QueryLimits.SizeLimit = 1; query.QueryFlags = 0;
if(fetchBlobs) {
crlDataPtr = &crlData;
}
crtn = CSSM_DL_DataGetFirst(dlDbHand,
&query,
&resultHand,
&recordAttrs,
crlDataPtr,
&record);
switch(crtn) {
case CSSM_OK:
break; case CSSMERR_DL_ENDOFDATA:
return CSSM_OK;
case CSSMERR_DL_INVALID_RECORDTYPE:
return CSSM_OK;
default:
cuPrintError("DataGetFirst", crtn);
return crtn;
}
CrlInfo *crlInfo = new CrlInfo(dlDbHand, &attrData[0], record, crlDataPtr);
rtnCrlInfo = (CrlInfo **)malloc(sizeof(CrlInfo*));
rtnCrlInfo[0] = crlInfo;
numCrls++;
for(;;) {
crtn = CSSM_DL_DataGetNext(dlDbHand,
resultHand,
&recordAttrs,
crlDataPtr,
&record);
switch(crtn) {
case CSSM_OK:
rtnCrlInfo = (CrlInfo **)realloc(rtnCrlInfo,
sizeof(CrlInfo *) * (numCrls + 1));
rtnCrlInfo[numCrls] = new CrlInfo(dlDbHand, &attrData[0], record,
crlDataPtr);
numCrls++;
break; case CSSMERR_DL_ENDOFDATA:
return CSSM_OK;
default:
cuPrintError("DataGetNext", crtn);
return crtn;
}
}
}
static void validateCrls(
CrlInfo **crlInfo,
unsigned numCrls,
bool verbose)
{
CrlInfo *crl;
for(unsigned dex=0; dex<numCrls; dex++) {
crl = crlInfo[dex];
uint32 i;
if(crl->fetchIntAttr(ATTR_DEX_CRL_TYPE, i)) {
continue;
}
switch(i) {
case CSSM_CRL_TYPE_X_509v1:
case CSSM_CRL_TYPE_X_509v2:
break;
default:
printf("***bad CRL type (%u) on CRL %u\n", (unsigned)i, dex);
crl->mIsBadlyFormed = true;
continue;
}
if(crl->fetchIntAttr(ATTR_DEX_CRL_ENC, i)) {
continue;
}
switch(i) {
case CSSM_CRL_ENCODING_BER:
case CSSM_CRL_ENCODING_DER:
break;
default:
printf("***bad CRL encoding (%u) on CRL %u\n",
(unsigned)i, dex);
crl->mIsBadlyFormed = true;
continue;
}
}
}
static void cryptoValidateCrls(
CrlInfo **crlInfo,
unsigned numCrls,
bool verbose,
CSSM_TP_HANDLE tpHand,
CSSM_CSP_HANDLE cspHand,
CSSM_CL_HANDLE clHand,
CSSM_DL_HANDLE dlHand)
{
CrlInfo *crl;
const CSSM_DATA *anchors;
uint32 anchorCount;
OSStatus ortn;
ortn = SecTrustGetCSSMAnchorCertificates(&anchors, &anchorCount);
if(ortn) {
printf("SecTrustGetCSSMAnchorCertificates returned %u\n", (int)ortn);
return;
}
CSSM_DL_DB_HANDLE certDb;
CSSM_DL_DB_HANDLE_PTR certDbPtr = NULL;
CSSM_RETURN crtn = CSSM_DL_DbOpen(dlHand,
X509_CERT_DB,
NULL, CSSM_DB_ACCESS_READ,
NULL, NULL, &certDb.DBHandle);
if(crtn) {
cuPrintError("CSSM_DL_DbOpen", crtn);
printf("***Error opening intermediate cert file %s.\n", X509_CERT_DB);
}
else {
certDb.DLHandle = dlHand;
certDbPtr = &certDb;
}
for(unsigned dex=0; dex<numCrls; dex++) {
crl = crlInfo[dex];
crtn = cuCrlVerify(tpHand, clHand, cspHand,
&crl->mCrlBlob,
certDbPtr,
anchors,
anchorCount);
switch(crtn) {
case CSSMERR_APPLETP_CRL_EXPIRED:
case CSSM_OK:
break;
default:
if(verbose) {
printf("...CRL %u FAILED crypto verify\n", dex);
}
crl->mIsBadlyFormed = true;
break;
}
}
CSSM_DL_DbClose(certDb);
}
int calcCurrent(
CrlInfo **crlInfo,
unsigned numCrls,
int expireOverlapSeconds,
int staleTimeSeconds)
{
if(expireOverlapSeconds > staleTimeSeconds) {
printf("***ExpireOverlap greater than StaleTime; aborting.\n");
return 1;
}
char *updateTime = cuTimeAtNowPlus(expireOverlapSeconds, TIME_CSSM);
char *staleTime = cuTimeAtNowPlus(-staleTimeSeconds, TIME_CSSM);
dprintf("updateTime : %s\n", updateTime);
dprintf("staleTime : %s\n", staleTime);
for(unsigned dex=0; dex<numCrls; dex++) {
crlInfo[dex]->validateTimes(updateTime, staleTime, dex);
}
APP_FREE(updateTime);
APP_FREE(staleTime);
return 0;
}
static void purgeAllCrls(
CrlInfo **crlInfo,
unsigned numCrls,
bool verbose)
{
for(unsigned dex=0; dex<numCrls; dex++) {
CrlInfo *crl = crlInfo[dex];
crl->mIsExpired = true;
crl->mIsStale = true;
}
}
static void deleteBadCrls(
CrlInfo **crlInfo,
unsigned numCrls,
bool verbose)
{
CrlInfo *crl;
for(unsigned dex=0; dex<numCrls; dex++) {
crl = crlInfo[dex];
if(crl->mIsBadlyFormed || crl->mIsStale) {
if(verbose || DEBUG_PRINT) {
printf("...deleting CRL %u from ", dex);
crl->printName();
}
CSSM_RETURN crtn = CSSM_DL_DataDelete(crl->dlDbHand(),
crl->record());
if(crtn) {
cuPrintError("CSSM_DL_DataDelete", crtn);
}
}
}
}
static void refreshExpiredCrls(
CrlInfo **crlInfo,
unsigned numCrls,
CSSM_CL_HANDLE clHand,
bool verbose)
{
CrlInfo *crl;
bool haveCurrent;
CSSM_DATA newCrl;
for(unsigned dex=0; dex<numCrls; dex++) {
crl = crlInfo[dex];
if(!crl->mIsExpired || crl->mRefreshed) {
continue;
}
haveCurrent = false;
for(unsigned i=0; i<numCrls; i++) {
if(i == dex) {
continue;
}
CrlInfo *checkCrl = crlInfo[i];
if(checkCrl->mIsBadlyFormed) {
continue;
}
if(checkCrl->mIsExpired && !checkCrl->mRefreshed) {
continue;
}
if(crl->isSameIssuer(checkCrl)) {
dprintf("up-to-date CRL at dex %u matching expired CRL %u\n",
i, dex);
haveCurrent = true;
break;
}
}
if(haveCurrent) {
continue;
}
CSSM_DATA_PTR uri = crl->fetchValidAttr(ATTR_DEX_URI);
if(uri == NULL) {
dprintf("Expired CRL with no URI at dex %u\n", dex);
continue;
}
if(verbose || DEBUG_PRINT) {
printf("...fetching new CRL from net to update CRL %u from ",
dex);
crl->printName();
}
CSSM_RETURN crtn = netFetch(*uri, LT_Crl, newCrl);
if(crtn) {
cuPrintError("netFetch", crtn);
continue;
}
crtn = cuAddCrlToDb(crl->dlDbHand(), clHand, &newCrl, uri);
switch(crtn) {
case CSSM_OK:
dprintf("...refreshed CRL added to DB to account "
"for expired CRL %u\n", dex);
break;
case CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA:
dprintf("...refreshed CRL is a dup of CRL %u; skipping\n",
dex);
break;
default:
continue;
}
crl->mRefreshed = true;
}
}
CSSM_RETURN openDatabase(
CSSM_DL_HANDLE dlHand,
const char *dbFileName,
bool verbose,
CSSM_DB_HANDLE &dbHand, bool &didCreate) {
didCreate = false;
CSSM_RETURN crtn = CSSM_DL_DbOpen(dlHand,
dbFileName,
NULL, CSSM_DB_ACCESS_READ | CSSM_DB_ACCESS_WRITE,
NULL, NULL, &dbHand);
switch(crtn) {
case CSSM_OK:
return CSSM_OK;
case CSSMERR_DL_DATASTORE_DOESNOT_EXIST:
break;
default:
cuPrintError("CSSM_DL_DbOpen", crtn);
return crtn;
}
if(verbose) {
printf("...creating database %s\n", dbFileName);
}
CSSM_DBINFO dbInfo;
memset(&dbInfo, 0, sizeof(CSSM_DBINFO));
CssmAllocator &alloc = CssmAllocator::standard();
CssmClient::AclFactory::PasswordChangeCredentials pCreds((StringData(dbFileName)), alloc);
const AccessCredentials* aa = pCreds;
TypedList subject(alloc, CSSM_ACL_SUBJECT_TYPE_ANY);
AclEntryPrototype protoType(subject);
AuthorizationGroup &authGroup = protoType.authorization();
CSSM_ACL_AUTHORIZATION_TAG tag = CSSM_ACL_AUTHORIZATION_ANY;
authGroup.NumberOfAuthTags = 1;
authGroup.AuthTags = &tag;
const ResourceControlContext rcc(protoType, const_cast<AccessCredentials *>(aa));
crtn = CSSM_DL_DbCreate(dlHand,
dbFileName,
NULL, &dbInfo,
CSSM_DB_ACCESS_PRIVILEGED,
&rcc, NULL, &dbHand);
if(crtn) {
cuPrintError("CSSM_DL_DbCreate", crtn);
return crtn;
}
else {
if(chmod(dbFileName, 0666)) {
perror(dbFileName);
crtn = CSSMERR_DL_DB_LOCKED;
}
didCreate = true;
}
return crtn;
}
static int writeFetchedItem(
LF_Type lfType,
const CSSM_DATA *itemData,
const CSSM_DATA *uriData)
{
if(lfType == LT_Cert) {
return 0;
}
CSSM_DL_DB_HANDLE dlDbHand = {0, 0};
CSSM_CL_HANDLE clHand = 0;
CSSM_RETURN crtn;
bool didCreate;
int ourRtn = 0;
clHand = cuClStartup();
if(clHand == 0) {
return 1;
}
dlDbHand.DLHandle = cuDlStartup();
if(dlDbHand.DLHandle == 0) {
ourRtn = 1;
goto done;
}
crtn = openDatabase(dlDbHand.DLHandle,
CRL_CACHE_DB,
false, dlDbHand.DBHandle,
didCreate);
if(crtn) {
dprintf("***Error opening keychain %s. Aborting.\n", CRL_CACHE_DB);
ourRtn = 1;
goto done;
}
crtn = cuAddCrlToDb(dlDbHand, clHand, itemData, uriData);
switch(crtn) {
case CSSM_OK:
dprintf("...fetched CRL added to DB\n");
break;
case CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA:
dprintf("...fetched CRL is a dup; skipping\n");
break;
default:
dprintf("Error writing CRL to cache\n");
ourRtn = 1;
break;
}
done:
if(dlDbHand.DBHandle) {
CSSM_DL_DbClose(dlDbHand);
}
if(dlDbHand.DLHandle) {
CSSM_ModuleDetach(dlDbHand.DLHandle);
}
if(clHand) {
CSSM_ModuleDetach(clHand);
}
return ourRtn;
}
int fetchItemFromNet(
LF_Type lfType,
const char *URI,
char *outFileName, bool writeToCache)
{
const CSSM_DATA uriData = {strlen(URI) + 1, (uint8 *)URI};
CSSM_DATA item;
CSSM_RETURN crtn;
int irtn;
dprintf("fetchItemFromNet %s outFile %s\n",
URI, outFileName ? outFileName : "stdout");
uriData.Data[uriData.Length - 1] = 0;
crtn = netFetch(uriData, lfType, item);
if(crtn) {
cuPrintError("netFetch", crtn);
return 1;
}
dprintf("fetchItemFromNet netFetch complete, %u bytes read\n",
(unsigned)item.Length);
if(outFileName == NULL) {
irtn = write(STDOUT_FILENO, item.Data, item.Length);
if(irtn != (int)item.Length) {
irtn = errno;
perror("write");
}
else {
irtn = 0;
}
}
else {
irtn = writeFile(outFileName, item.Data, item.Length);
if(irtn) {
perror(outFileName);
}
}
if((irtn == 0) && writeToCache) {
irtn = writeFetchedItem(lfType, &item, &uriData);
}
free(item.Data);
dprintf("fetchItemFromNet returning %d\n", irtn);
return irtn;
}
int main(int argc, char **argv)
{
CSSM_RETURN crtn;
CSSM_DL_DB_HANDLE dlDbHand;
CSSM_CL_HANDLE clHand;
CSSM_CSP_HANDLE cspHand = 0;
CSSM_TP_HANDLE tpHand = 0;
int arg;
char *argp;
bool didCreate = false;
int optArg;
bool verbose = false;
bool purgeAll = false;
bool fullCryptoValidation = false;
int staleDays = DEFAULT_STALE_DAYS;
int expireOverlapSeconds =
DEFAULT_EXPIRE_OVERLAP_SECONDS;
char *dbFileName = CRL_CACHE_DB;
LF_Type lfType = LT_Crl;
char *outFileName = NULL;
bool writeToCache = true;
char *uri = NULL;
if(argc < 2) {
usage(argv);
}
switch(argv[1][0]) {
case 'F':
lfType = LT_Cert;
case 'f':
if(argc < 3) {
usage(argv);
}
uri = argv[2];
optArg = 3;
break;
case 'r':
optArg = 2;
break;
default:
usage(argv);
}
for(arg=optArg; arg<argc; arg++) {
argp = argv[arg];
switch(argp[0]) {
case 's':
if(argp[1] != '=') {
usage(argv);
}
staleDays = atoi(&argp[2]);
break;
case 'o':
if(argp[1] != '=') {
usage(argv);
}
expireOverlapSeconds = atoi(&argp[2]);
break;
case 'p':
purgeAll = true;
break;
case 'f':
fullCryptoValidation = true;
break;
case 'k':
if(argp[1] != '=') {
usage(argv);
}
dbFileName = &argp[2];
break;
case 'n':
writeToCache = false;
break;
case 'F':
if(argp[1] != '=') {
usage(argv);
}
outFileName = &argp[2];
break;
case 'v':
verbose = true;
break;
default:
usage(argv);
}
}
if(argv[1][0] != 'r') {
return fetchItemFromNet(lfType, uri, outFileName, writeToCache);
}
dprintf("...staleDays %d expireOverlapSeconds %d\n",
staleDays, expireOverlapSeconds);
dlDbHand.DLHandle = cuDlStartup();
if(dlDbHand.DLHandle == 0) {
exit(1);
}
crtn = openDatabase(dlDbHand.DLHandle,
dbFileName,
verbose,
dlDbHand.DBHandle,
didCreate);
if(crtn) {
printf("***Error opening keychain %s. Aborting.\n", dbFileName);
exit(1);
}
if(didCreate) {
CSSM_DL_DbClose(dlDbHand);
CSSM_ModuleDetach(dlDbHand.DLHandle);
return 0;
}
clHand = cuClStartup();
if(clHand == 0) {
exit(1);
}
if(fullCryptoValidation) {
cspHand = cuCspStartup(CSSM_TRUE);
if(cspHand == 0) {
exit(1);
}
tpHand = cuTpStartup();
if(tpHand == 0) {
exit(1);
}
}
CrlInfo **crlInfo;
unsigned numCrls;
crtn = fetchAllCrls(dlDbHand, fullCryptoValidation, crlInfo, numCrls);
if(crtn) {
printf("***Error reading CRLs from %s. Aborting.\n", dbFileName);
exit(1);
}
dprintf("...%u CRLs found\n", numCrls);
validateCrls(crlInfo, numCrls, verbose);
if(fullCryptoValidation) {
cryptoValidateCrls(crlInfo, numCrls, verbose,
tpHand, cspHand, clHand, dlDbHand.DLHandle);
}
if(calcCurrent(crlInfo, numCrls, expireOverlapSeconds,
staleDays * SECONDS_PER_DAY)) {
printf("***Error calculating CRL times. Aborting\n");
exit(1);
}
if(purgeAll) {
purgeAllCrls(crlInfo, numCrls, verbose);
}
deleteBadCrls(crlInfo, numCrls, verbose);
refreshExpiredCrls(crlInfo, numCrls, clHand, verbose);
for(unsigned dex=0; dex<numCrls; dex++) {
delete crlInfo[dex];
}
free(crlInfo);
CSSM_DL_DbClose(dlDbHand);
CSSM_ModuleDetach(dlDbHand.DLHandle);
CSSM_ModuleDetach(clHand);
if(tpHand) {
CSSM_ModuleDetach(tpHand);
}
if(cspHand) {
CSSM_ModuleDetach(cspHand);
}
return 0;
}