]> git.saurik.com Git - apple/security.git/blobdiff - SecurityTests/clxutils/certChain/certChain.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / SecurityTests / clxutils / certChain / certChain.cpp
diff --git a/SecurityTests/clxutils/certChain/certChain.cpp b/SecurityTests/clxutils/certChain/certChain.cpp
new file mode 100644 (file)
index 0000000..92bf38e
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * Given a cert, produce a complete ordered cert chain back to a root.
+ * Intermediate certs can be in any user keychain.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <security_cdsa_utils/cuFileIo.h>              /* private */
+#include <security_cdsa_utils/cuPrintCert.h>   /* private */
+#include <Security/Security.h>
+#include <Security/SecTrustPriv.h>  /* private */
+
+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;   // subject cert, raw data
+       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;                   // not used
+       CFArrayRef                                      certChain = NULL;   // constructed chain
+       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 form of subject cert */
+       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;
+       }
+       
+       /* make a one-element array */
+       subjCerts = CFArrayCreateMutable(NULL, 1, &kCFTypeArrayCallBacks);
+       CFArraySetValueAtIndex(subjCerts, 0, certRef);
+                       
+       /* the array owns the subject cert ref now */
+       CFRelease(certRef);
+       
+       /* Get a SecPolicyRef for generic X509 cert chain verification */
+       ortn = SecPolicySearchCreate(CSSM_CERT_X_509v3,
+               &CSSMOID_APPLE_X509_BASIC,
+               NULL,                           // value
+               &policySearch);
+       if(ortn) {
+               cssmPerror("SecPolicySearchCreate", ortn);
+               goto errOut;
+       }
+       ortn = SecPolicySearchCopyNext(policySearch, &policy);
+       if(ortn) {
+               cssmPerror("SecPolicySearchCopyNext", ortn);
+               goto errOut;
+       }
+
+       /* build a SecTrustRef for specified policy and certs */
+       ortn = SecTrustCreateWithCertificates(subjCerts,
+               policy, &secTrust);
+       if(ortn) {
+               cssmPerror("SecTrustCreateWithCertificates", ortn);
+               goto errOut;
+       }
+       
+       if(disableLocalIntermediates) {
+               /*
+                * Avoid searching user keychains for intermediate certs 
+                * by specifying an empty array of keychains
+                */
+               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);
+       }
+       
+       /* evaluate: GO */
+       ortn = SecTrustEvaluate(secTrust, &secTrustResult);
+       if(ortn) {
+               cssmPerror("SecTrustEvaluate", ortn);
+               goto errOut;
+       }
+       switch(secTrustResult) {
+               case kSecTrustResultUnspecified:
+                       /* cert chain valid, no special UserTrust assignments */
+               case kSecTrustResultProceed:
+                       /* cert chain valid AND user explicitly trusts this */
+                       break;
+               case kSecTrustResultDeny:
+               case kSecTrustResultConfirm:
+                       /*
+                        * Cert chain may well have verified OK, but user has flagged
+                        * one of these certs as untrustable.
+                        */
+                       printf("***User specified that a cert in this chain is untrusted.\n");
+                       goto errOut;
+                       
+               default:
+               {
+                       /* private SPI to get low-level CSSM error */
+                       OSStatus osCrtn;
+                       ortn = SecTrustGetCssmResultCode(secTrust, (OSStatus *)&crtn);
+                       if(ortn) {
+                               cssmPerror("SecTrustEvaluate", ortn);
+                               goto errOut;
+                       }
+               }
+       }
+       if(crtn) {      
+               /* get some detailed error info */
+               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;
+               }
+       }       /* SecTrustEvaluate error */
+
+       /* get resulting constructed cert chain */
+       ortn = SecTrustGetResult(secTrust, &secTrustResult, &certChain, &dummyEv);
+       if(ortn) {
+               cssmPerror("SecTrustEvaluate", ortn);
+               goto errOut;
+       }
+       
+       /* display the results */
+       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) {
+               /* mallocds by readFile() */
+               free(certData);
+       }
+       if(secTrust) {
+               CFRelease(secTrust);
+       }
+       if(subjCerts) {
+               CFRelease(subjCerts);
+       }
+       if(policy) {
+               CFRelease(policy);
+       }
+       if(policySearch) {
+               CFRelease(policySearch);
+       }
+       return (int)ortn;
+}