#include <stdlib.h>
#include <stdio.h>
#include <security_cdsa_utils/cuFileIo.h>
#include <security_cdsa_utils/cuPrintCert.h>
#include <Security/Security.h>
#include <Security/SecTrustPriv.h>
static void usage(char **argv)
{
printf("Usage:\n");
printf(" %s certFileName [d(isable intermediates) [f filebase] [n(o cert dump)]\n", argv[0]);
exit(1);
}
int main(int argc, char **argv)
{
unsigned char *certData = NULL; unsigned certDataLen = 0;
OSStatus ortn;
SecTrustRef secTrust = NULL;
CFMutableArrayRef subjCerts = NULL;
SecPolicyRef policy = NULL;
SecPolicySearchRef policySearch = NULL;
SecTrustResultType secTrustResult;
CSSM_RETURN crtn = CSSM_OK;
CSSM_TP_APPLE_EVIDENCE_INFO *dummyEv; CFArrayRef certChain = NULL; CFIndex numCerts;
bool disableLocalIntermediates = false;
char *fileBase = NULL;
bool enableCertDump = true;
if(argc < 2) {
usage(argv);
}
if(readFile(argv[1], &certData, &certDataLen)) {
printf("***Error reading cert from %s. Aborting.\n", argv[1]);
exit(1);
}
for(int arg=2; arg<argc; arg++) {
char *argp = argv[arg];
switch(argp[0]) {
case 'd':
disableLocalIntermediates = true;
break;
case 'n':
enableCertDump = false;
break;
case 'f':
arg++;
if(arg == argc) {
usage(argv);
}
fileBase = argv[arg];
break;
default:
usage(argv);
}
}
SecCertificateRef certRef = NULL;
CSSM_DATA cdata = {(uint32)certDataLen, (uint8 *)certData};
ortn = SecCertificateCreateFromData(&cdata,
CSSM_CERT_X_509v3,
CSSM_CERT_ENCODING_DER,
&certRef);
if(ortn) {
cssmPerror("SecCertificateCreateFromData", ortn);
goto errOut;
}
subjCerts = CFArrayCreateMutable(NULL, 1, &kCFTypeArrayCallBacks);
CFArraySetValueAtIndex(subjCerts, 0, certRef);
CFRelease(certRef);
ortn = SecPolicySearchCreate(CSSM_CERT_X_509v3,
&CSSMOID_APPLE_X509_BASIC,
NULL, &policySearch);
if(ortn) {
cssmPerror("SecPolicySearchCreate", ortn);
goto errOut;
}
ortn = SecPolicySearchCopyNext(policySearch, &policy);
if(ortn) {
cssmPerror("SecPolicySearchCopyNext", ortn);
goto errOut;
}
ortn = SecTrustCreateWithCertificates(subjCerts,
policy, &secTrust);
if(ortn) {
cssmPerror("SecTrustCreateWithCertificates", ortn);
goto errOut;
}
if(disableLocalIntermediates) {
CFMutableArrayRef kcList;
kcList = CFArrayCreateMutable(NULL, 0, NULL);
if(kcList == NULL) {
printf("***CFArrayCreateMutable error\n");
ortn = -1;
goto errOut;
}
ortn = SecTrustSetKeychains(secTrust, kcList);
if(ortn) {
cssmPerror("SecTrustSetKeychains", ortn);
goto errOut;
}
CFRelease(kcList);
}
ortn = SecTrustEvaluate(secTrust, &secTrustResult);
if(ortn) {
cssmPerror("SecTrustEvaluate", ortn);
goto errOut;
}
switch(secTrustResult) {
case kSecTrustResultUnspecified:
case kSecTrustResultProceed:
break;
case kSecTrustResultDeny:
case kSecTrustResultConfirm:
printf("***User specified that a cert in this chain is untrusted.\n");
goto errOut;
default:
{
OSStatus osCrtn;
ortn = SecTrustGetCssmResultCode(secTrust, (OSStatus *)&crtn);
if(ortn) {
cssmPerror("SecTrustEvaluate", ortn);
goto errOut;
}
}
}
if(crtn) {
switch(crtn) {
case CSSMERR_TP_INVALID_ANCHOR_CERT:
printf("***Verified to unknown anchor cert\n");
break;
case CSSMERR_TP_NOT_TRUSTED:
printf("***Can not verify to a root cert \n");
break;
case CSSMERR_TP_CERT_EXPIRED:
printf("***A cert in this chain has expired\n");
break;
case CSSMERR_TP_CERT_NOT_VALID_YET:
printf("***A cert in this chain is not yet valid\n");
break;
default:
printf("Other error from SecTrustEvaluate\n");
cssmPerror("SecTrustEvaluate", crtn);
break;
}
}
ortn = SecTrustGetResult(secTrust, &secTrustResult, &certChain, &dummyEv);
if(ortn) {
cssmPerror("SecTrustEvaluate", ortn);
goto errOut;
}
numCerts = CFArrayGetCount(certChain);
printf("Number of certs in constructed cert chain = %d\n", (int)numCerts);
if(enableCertDump) {
for(unsigned i=0; i<numCerts; i++) {
CSSM_DATA cd;
certRef = (SecCertificateRef)CFArrayGetValueAtIndex(certChain, i);
ortn = SecCertificateGetData(certRef, &cd);
if(ortn) {
printf("***SecCertificateGetData returned %d\n", (int)ortn);
continue;
}
printf("\n================== Cert %d ===================\n\n", i);
printCert(cd.Data, cd.Length, CSSM_FALSE);
printf("\n=============== End of Cert %d ===============\n", i);
if((fileBase != NULL) & (i > 0)) {
char fname[200];
sprintf(fname, "%s_%u", fileBase, i);
if(writeFile(fname, cd.Data, cd.Length)) {
printf("***Error writing to %s\n", fname);
}
else {
printf("...write %lu bytes to %s\n", cd.Length, fname);
}
}
}
}
errOut:
if(certData) {
free(certData);
}
if(secTrust) {
CFRelease(secTrust);
}
if(subjCerts) {
CFRelease(subjCerts);
}
if(policy) {
CFRelease(policy);
}
if(policySearch) {
CFRelease(policySearch);
}
return (int)ortn;
}