#include <Security/cssm.h>
#include <Security/oidsalg.h>
#include <Security/cssmapple.h>
#include <Security/Security.h>
#include <Security/SecTrustPriv.h>
#include <Security/SecPolicyPriv.h>
#include <security_cdsa_utils/cuFileIo.h>
#include <utilLib/common.h>
#include <utilLib/cspwrap.h>
#include <clAppUtils/clutils.h>
#include <clAppUtils/tpUtils.h>
#include <clAppUtils/sslAppUtils.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
static void usage(char **argv)
{
printf("Usage: %s [options] certFile ..., leaf first\n", argv[0]);
printf("Options:\n");
printf(" -s SSL policy (default is basic)\n");
printf(" -e allow expired cert\n");
printf(" -E allow expired root\n");
printf(" -S serverName\n");
printf(" -t timeBaseString (default = now)\n");
printf(" -T use SecTrustEvaluate\n");
printf(" -v verbose\n");
exit(1);
}
static void printResult(
CSSM_RETURN crtn)
{
switch(crtn) {
case CSSM_OK:
printf(" ...successful verification\n");
break;
case CSSMERR_TP_INVALID_CERTIFICATE:
printf(" ...invalid leaf cert\n");
break;
case CSSMERR_TP_INVALID_ANCHOR_CERT:
printf(" ...cert chain valid (unknown root)\n");
break;
case CSSMERR_TP_NOT_TRUSTED:
printf(" ...no root cert found\n");
break;
case CSSMERR_TP_VERIFICATION_FAILURE:
printf(" ...bad root cert\n");
break;
case CSSMERR_TP_VERIFY_ACTION_FAILED:
printf(" ...policy verification failed\n");
break;
case CSSMERR_TP_CERT_EXPIRED:
printf(" ...expired cert in chain\n");
break;
case CSSMERR_TP_CERT_NOT_VALID_YET:
printf(" ...not-yet-valid cert in chain\n");
break;
default:
printError("tpCertGroupVerify", crtn);
break;
}
}
int main(int argc, char **argv)
{
CSSM_CL_HANDLE clHand; CSSM_TP_HANDLE tpHand; CSSM_CSP_HANDLE cspHand = 0; CSSM_DATA_PTR rawCerts = NULL;
unsigned numCerts; unsigned i;
CSSM_CERTGROUP cgrp;
const CSSM_OID *policyId = &CSSMOID_APPLE_X509_BASIC;
uint32 evidenceSize = 0;
CSSM_TP_VERIFY_CONTEXT_RESULT vfyResult;
CSSM_CERTGROUP_PTR outGrp = NULL;
int fileArg;
CSSM_RETURN crtn;
CSSM_BOOL allowExpiredCert = CSSM_FALSE;
bool allowExpiredRoot = false;
bool useSecTrust = false;
int arg;
CSSM_APPLE_TP_SSL_OPTIONS sslOpts;
CSSM_APPLE_TP_ACTION_DATA tpAction;
char *serverName = NULL;
bool verbose = false;
unsigned numEvidences = 0;
CSSM_DATA fieldOpts;
CSSM_DATA_PTR fieldOptsPtr = NULL;
CSSM_DATA actionData;
CSSM_DATA_PTR actionDataPtr = NULL;
char *cssmTimeStr = NULL;
SecTrustRef theTrust = NULL;
if(argc < 2) {
usage(argv);
}
for(arg=1; arg<argc; arg++) {
if(argv[arg][0] != '-') {
fileArg = arg;
break;
}
switch(argv[arg][1]) {
case 's':
policyId = &CSSMOID_APPLE_TP_SSL;
break;
case 'e':
allowExpiredCert = true;
break;
case 'E':
allowExpiredRoot = true;
break;
case 'v':
verbose = true;
break;
case 'S':
if(arg == (argc - 1)) {
usage(argv);
}
serverName = argv[++arg];
break;
case 't':
if(arg == (argc - 1)) {
usage(argv);
}
cssmTimeStr = argv[++arg];
break;
case 'T':
useSecTrust = true;
break;
default:
usage(argv);
}
}
if(policyId == &CSSMOID_APPLE_TP_SSL) {
sslOpts.Version = CSSM_APPLE_TP_SSL_OPTS_VERSION;
sslOpts.ServerName = serverName;
if(serverName) {
sslOpts.ServerNameLen = strlen(serverName) + 1;
}
else {
sslOpts.ServerNameLen = 0;
}
fieldOpts.Data = (uint8 *)&sslOpts;
fieldOpts.Length = sizeof(sslOpts);
fieldOptsPtr = &fieldOpts;
}
else if(serverName) {
printf("***Server name option only valid for SSL policy.\n");
usage(argv);
}
if(allowExpiredCert || allowExpiredRoot) {
tpAction.Version = CSSM_APPLE_TP_ACTION_VERSION;
tpAction.ActionFlags = 0;
if(allowExpiredCert) {
tpAction.ActionFlags |= CSSM_TP_ACTION_ALLOW_EXPIRED;
}
if(allowExpiredRoot) {
tpAction.ActionFlags |= CSSM_TP_ACTION_ALLOW_EXPIRED_ROOT;
}
actionData.Data = (uint8 *)&tpAction;
actionData.Length = sizeof(tpAction);
actionDataPtr = &actionData;
}
numCerts = argc - fileArg;
if(numCerts == 0) {
usage(argv);
}
rawCerts = (CSSM_DATA_PTR)CSSM_MALLOC(numCerts * sizeof(CSSM_DATA));
if(rawCerts == NULL) {
printf("malloc error\n");
goto abort;
}
for(i=0; i<numCerts; i++) {
CSSM_DATA_PTR c = &rawCerts[i];
unsigned len;
if(readFile(argv[fileArg], &c->Data, &len)) {
printf("Error reading %s=n", argv[fileArg]);
exit(1);
}
c->Length = len;
fileArg++;
}
if(useSecTrust) {
SecPolicyRef policy = NULL;
SecPolicySearchRef policySearch = NULL;
SecCertificateRef cert; SecTrustResultType secTrustResult;
OSStatus ortn;
const char *evalResStr = NULL;
CSSM_TP_APPLE_EVIDENCE_INFO *evidence = NULL;
CFMutableArrayRef certGroup = CFArrayCreateMutable(NULL, numCerts,
&kCFTypeArrayCallBacks);
for(i=0; i<numCerts; i++) {
ortn = SecCertificateCreateFromData(&rawCerts[i], CSSM_CERT_X_509v3,
CSSM_CERT_ENCODING_DER, &cert);
if(cert == NULL) {
printf("SecCertificateCreateFromData returned %s\n",
sslGetSSLErrString(ortn));
exit(1);
}
CFArrayAppendValue(certGroup, cert);
}
ortn = SecPolicySearchCreate(CSSM_CERT_X_509v3,
policyId, NULL, &policySearch);
if(ortn) {
printf("SecPolicySearchCreate returned %s\n",
sslGetSSLErrString(ortn));
exit(1);
}
ortn = SecPolicySearchCopyNext(policySearch, &policy);
if(ortn) {
printf("SecPolicySearchCopyNext returned %s\n",
sslGetSSLErrString(ortn));
exit(1);
}
if(fieldOptsPtr != NULL) {
ortn = SecPolicySetValue(policy, fieldOptsPtr);
if(ortn) {
printf("SecPolicySetValue returned %s\n",
sslGetSSLErrString(ortn));
exit(1);
}
}
ortn = SecTrustCreateWithCertificates(certGroup, policy, &theTrust);
if(ortn) {
printf("SecTrustCreateWithCertificates returned %s\n",
sslGetSSLErrString(ortn));
exit(1);
}
if(actionDataPtr) {
CFDataRef actionData =
CFDataCreate(NULL, actionDataPtr->Data, actionDataPtr->Length);
ortn = SecTrustSetParameters(theTrust, CSSM_TP_ACTION_DEFAULT,
actionData);
if(ortn) {
printf("SecTrustSetParameters returned %s\n", sslGetSSLErrString(ortn));
exit(1);
}
CFRelease(actionData);
}
ortn = SecTrustEvaluate(theTrust, &secTrustResult);
if(ortn) {
printf("SecTrustEvaluate returned %s\n", sslGetSSLErrString(ortn));
exit(1);
}
crtn = CSSM_OK;
switch(secTrustResult) {
case kSecTrustResultInvalid:
evalResStr = "kSecTrustResultInvalid";
break;
case kSecTrustResultProceed:
evalResStr = "kSecTrustResultProceed";
break;
case kSecTrustResultConfirm:
evalResStr = "kSecTrustResultConfirm";
break;
case kSecTrustResultDeny:
evalResStr = "kSecTrustResultDeny";
break;
case kSecTrustResultUnspecified:
evalResStr = "kSecTrustResultUnspecified";
break;
case kSecTrustResultRecoverableTrustFailure:
evalResStr = "kSecTrustResultRecoverableTrustFailure";
break;
case kSecTrustResultFatalTrustFailure:
evalResStr = "kSecTrustResultFatalTrustFailure";
break;
case kSecTrustResultOtherError:
evalResStr = "kSecTrustResultOtherError";
break;
default:
break;
}
printf("...SecTrustEvaluate result : ");
if(evalResStr != NULL) {
printf("%s\n", evalResStr);
}
else {
printf("UNKNOWN (%d)\n", (int)secTrustResult);
}
OSStatus ocrtn;
ortn = SecTrustGetCssmResultCode(theTrust, &ocrtn);
if(ortn) {
printf("SecTrustGetCssmResultCode returned %s\n", sslGetSSLErrString(ortn));
}
else {
printResult(ocrtn);
}
CFArrayRef dummy;
ortn = SecTrustGetResult(theTrust, &secTrustResult, &dummy,
&evidence);
if(ortn) {
printf("SecTrustGetResult returned %s\n", sslGetSSLErrString(ortn));
}
else {
unsigned numEvidences = CFArrayGetCount(dummy);
if(numEvidences && verbose) {
printCertInfo(numEvidences, evidence);
}
}
}
else {
cspHand = cspStartup();
if(cspHand == 0) {
exit(1);
}
clHand = clStartup();
if(clHand == 0) {
goto abort;
}
tpHand = tpStartup();
if(tpHand == 0) {
goto abort;
}
memset(&cgrp, 0, sizeof(CSSM_CERTGROUP));
cgrp.NumCerts = numCerts;
cgrp.CertGroupType = CSSM_CERTGROUP_DATA;
cgrp.CertType = CSSM_CERT_X_509v3;
cgrp.CertEncoding = CSSM_CERT_ENCODING_DER;
cgrp.GroupList.CertList = rawCerts;
crtn = tpCertGroupVerify(
tpHand,
clHand,
cspHand,
NULL, policyId,
fieldOptsPtr,
actionDataPtr,
NULL, &cgrp,
NULL, 0, CSSM_TP_STOP_ON_POLICY,
cssmTimeStr,
&vfyResult); printResult(crtn);
if((vfyResult.Evidence != NULL) && (vfyResult.Evidence->Evidence != NULL)) {
numEvidences = vfyResult.NumberOfEvidences;
if(numEvidences == 3) {
outGrp = (CSSM_CERTGROUP_PTR)vfyResult.Evidence[1].Evidence;
evidenceSize = outGrp->NumCerts;
}
else {
printf("***Expected numEvidences 3, got %u\n", numEvidences);
evidenceSize = 0;
}
}
printf(" num input certs %d; evidenceSize %u\n",
numCerts, (unsigned)evidenceSize);
if((numEvidences > 0) && verbose) {
dumpVfyResult(&vfyResult);
}
freeVfyResult(&vfyResult);
}
abort:
if(rawCerts != NULL) {
for(i=0; i<numCerts; i++) {
free(rawCerts[i].Data);
}
CSSM_FREE(rawCerts);
}
if(theTrust != NULL) {
CFRelease(theTrust);
}
return 0;
}