]> git.saurik.com Git - apple/security.git/blobdiff - SecurityTests/clxutils/sslSubjName/sslSubjName.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / SecurityTests / clxutils / sslSubjName / sslSubjName.cpp
diff --git a/SecurityTests/clxutils/sslSubjName/sslSubjName.cpp b/SecurityTests/clxutils/sslSubjName/sslSubjName.cpp
new file mode 100644 (file)
index 0000000..9ca1a34
--- /dev/null
@@ -0,0 +1,595 @@
+/* Copyright (c) 2002-2004,2006,2008 Apple Inc.
+ *
+ * sslSubjName.c
+ *
+ * Verify comparision of app-specified host name vs. various
+ * forms of hostname in a cert.
+ *
+ */
+
+#include <utilLib/common.h>
+#include <utilLib/cspwrap.h>
+#include <clAppUtils/clutils.h>
+#include <clAppUtils/certVerify.h>
+#include <clAppUtils/BlobList.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <Security/cssm.h>
+#include <Security/x509defs.h>
+#include <Security/oidsattr.h>
+#include <Security/oidscert.h>
+#include <Security/oidsalg.h>
+#include <Security/certextensions.h>
+#include <Security/cssmapple.h>
+#include <string.h>
+#include <security_cdsa_utils/cuFileIo.h>
+
+/* key labels */
+#define SUBJ_KEY_LABEL         "subjectKey"
+#define ROOT_KEY_LABEL         "rootKey"
+
+/* key and signature algorithm - shouldn't matter for this test */
+#define SIG_ALG_DEFAULT                CSSM_ALGID_SHA1WithRSA
+#define SIG_OID_DEFAULT                CSSMOID_SHA1WithRSA
+#define KEY_ALG_DEFAULT                CSSM_ALGID_RSA
+
+#define KEY_SIZE_DEFAULT       512
+
+#define CERT_FILE              "sslCert.cer"
+
+static void usage(char **argv)
+{
+       printf("Usage: %s [options]\n", argv[0]);
+       printf("Options:\n");
+       printf("    w(write certs)\n");
+       printf("    q(uiet)\n");
+       printf("    v(erbose)\n");
+       exit(1);
+}
+
+/*
+ * RDN components for root, subject
+ */
+CSSM_APPLE_TP_NAME_OID rootRdn[] = 
+{
+       { "Apple Computer",                                     &CSSMOID_OrganizationName },
+       { "The Big Cheese",                                     &CSSMOID_Title }
+};
+#define NUM_ROOT_NAMES (sizeof(rootRdn) / sizeof(CSSM_APPLE_TP_NAME_OID))
+
+#define SUBJ_COMMON_NAME       "something.org"
+
+CSSM_APPLE_TP_NAME_OID subjRdn[] = 
+{
+       { "Apple Computer",                                     &CSSMOID_OrganizationName },
+       /* overridden when creating the cert */
+       { NULL,                                                         &CSSMOID_CommonName }
+};
+#define SUBJ_COMMON_NAME_DEX   1
+
+#define NUM_SUBJ_NAMES (sizeof(subjRdn) / sizeof(CSSM_APPLE_TP_NAME_OID))
+
+
+/*
+ * Test cases
+ */
+typedef struct {
+       /* test description */
+       const char              *testDesc;
+       
+       /* host names for leaf cert - zero or one of these */
+       const char              *certDnsName;
+       const char              *certIpAddr;
+       
+       /* subject common name */
+       const char              *commonName;
+       
+       /* host name for CertGroupVerify */
+       const char              *vfyHostName;
+       
+       /* expected error - NULL or e.g. "CSSMERR_APPLETP_CRL_NOT_TRUSTED" */
+       const char              *expectErrStr;
+       
+       /* one optional per-cert error string */
+       const char              *certErrorStr;
+       
+} SSN_TestCase;
+
+SSN_TestCase testCases[] = 
+{
+       {
+               "DNS Name foo.bar, vfyName foo.bar",
+               "foo.bar", NULL, SUBJ_COMMON_NAME, "foo.bar",
+               NULL, 
+               NULL
+       },
+       {
+               "DNS Name foo.bar, vfyName something.org, expect fail due to "
+                       "DNS present",
+               "foo.bar", NULL, SUBJ_COMMON_NAME, "something.org",
+               "CSSMERR_APPLETP_HOSTNAME_MISMATCH", 
+               "0:CSSMERR_APPLETP_HOSTNAME_MISMATCH"
+       },
+       {
+               "DNS Name foo.bar, vfyName foo.foo.bar, expect fail",
+               "foo.bar", NULL, SUBJ_COMMON_NAME, "foo.foo.bar",
+               "CSSMERR_APPLETP_HOSTNAME_MISMATCH", 
+               "0:CSSMERR_APPLETP_HOSTNAME_MISMATCH"
+       },
+       {
+               "IP Name 1.0.5.8, vfyName 1.0.5.8",
+               NULL, "1.0.5.8", SUBJ_COMMON_NAME, "1.0.5.8",
+               NULL, 
+               NULL
+       },
+       {
+               "IP Name 1.0.5.8, vfyName 1.00.5.008",
+               NULL, "1.0.5.8", SUBJ_COMMON_NAME, "1.00.5.008",
+               NULL, 
+               NULL
+       },
+       {
+               "IP Name 1.0.5.8, vfyName something.org",
+               NULL, "1.0.5.8", SUBJ_COMMON_NAME, "something.org",
+               NULL, 
+               NULL
+       },
+       {
+               "IP Name 1.0.5.8, vfyName 2.0.5.8, expect fail",
+               NULL, "1.0.5.8", SUBJ_COMMON_NAME, "2.0.5.8",
+               "CSSMERR_APPLETP_HOSTNAME_MISMATCH", 
+               "0:CSSMERR_APPLETP_HOSTNAME_MISMATCH"
+       },
+       {
+               "DNS Name *.foo.bar, vfyName bar.foo.bar",
+               "*.foo.bar", NULL, SUBJ_COMMON_NAME, "bar.foo.bar",
+               NULL, 
+               NULL
+       },
+       {
+               "DNS Name *.foo.bar, vfyName foo.bar, expect fail",
+               "*.foo.bar", NULL, SUBJ_COMMON_NAME, "foo.bar",
+               "CSSMERR_APPLETP_HOSTNAME_MISMATCH", 
+               "0:CSSMERR_APPLETP_HOSTNAME_MISMATCH"
+       },
+       {
+               "DNS Name *foo.bar, vfyName barfoo.bar",
+               "*foo.bar", NULL, SUBJ_COMMON_NAME, "barfoo.bar",
+               NULL, 
+               NULL
+       },
+       {
+               "DNS Name *foo*.bar, vfyName barfoo.bar",
+               "*foo*.bar", NULL, SUBJ_COMMON_NAME, "barfoo.bar",
+               NULL, 
+               NULL
+       },
+       {
+               "DNS Name *foo*.bar, vfyName foobar.bar",
+               "*foo*.bar", NULL, SUBJ_COMMON_NAME, "foobar.bar",
+               NULL, 
+               NULL
+       },
+       {
+               "DNS Name *foo*.bar, vfyName foo.bar",
+               "*foo*.bar", NULL, SUBJ_COMMON_NAME, "foo.bar",
+               NULL, 
+               NULL
+       },
+       {
+               "DNS Name *foo.bar, vfyName bar.foo.bar, should fail",
+               "*foo.bar", NULL, SUBJ_COMMON_NAME, "bar.foo.bar",
+               "CSSMERR_APPLETP_HOSTNAME_MISMATCH", 
+               "0:CSSMERR_APPLETP_HOSTNAME_MISMATCH"
+       },
+       {
+               "DNS Name *foo.bar, vfyName foobar.bar, should fail",
+               "*foo.bar", NULL, SUBJ_COMMON_NAME, "foobar.bar",
+               "CSSMERR_APPLETP_HOSTNAME_MISMATCH", 
+               "0:CSSMERR_APPLETP_HOSTNAME_MISMATCH"
+       },
+       {
+               "No DNS or IP name, commonName = vfyName = 1.0.5.8",
+               NULL, NULL, "1.0.5.8", "1.0.5.8",
+               "CSSMERR_APPLETP_HOSTNAME_MISMATCH", 
+               "0:CSSMERR_APPLETP_HOSTNAME_MISMATCH"
+       },
+};
+
+#define NUM_TEST_CASES (sizeof(testCases) / sizeof(SSN_TestCase))
+
+/*
+ * Convert a string containing a dotted IP address to 4 bytes.
+ * Returns nonzero on error.
+ * FIXME - should handle 16-byte IP addresses. 
+ */
+static int convertIp(
+       const char      *str,
+       uint8           *buf)
+{
+       char cbuf[4];
+       for(unsigned dex=0; dex<3; dex++) {
+               char *nextDot = strchr(str, '.');
+               if(nextDot == NULL) {
+                       return 1;
+               }
+               memset(cbuf, 0, sizeof(cbuf));
+               memmove(cbuf, str, nextDot - str);
+               *buf = atoi(cbuf);
+               buf++;                          // next out char
+               str = nextDot + 1;      // next in char after dot
+               
+       }
+       /* str points to last char */
+       if(str == NULL) {
+               return 1;
+       }
+       *buf = atoi(str);
+       return 0;
+}
+
+/*
+ * Generate a pair of certs.
+ */
+static CSSM_RETURN genCerts(
+       CSSM_CL_HANDLE  clHand,
+       CSSM_CSP_HANDLE cspHand,        
+       CSSM_TP_HANDLE  tpHand, 
+       CSSM_KEY_PTR    rootPrivKey,
+       CSSM_KEY_PTR    rootPubKey,
+       CSSM_KEY_PTR    subjPubKey,
+       /* one of these goes into leaf's subjectAltName */
+       const char              *subjIpAddr,
+       const char              *subjDnsName,
+       const char              *commonName,
+       CSSM_DATA               &rootCert,              // RETURNED
+       CSSM_DATA               &subjCert)              // RETURNED
+       
+{
+       CSSM_DATA                                       refId;  
+                                                               // mallocd by CSSM_TP_SubmitCredRequest
+       CSSM_RETURN                                     crtn;
+       CSSM_APPLE_TP_CERT_REQUEST      certReq;
+       CSSM_TP_REQUEST_SET                     reqSet;
+       sint32                                          estTime;
+       CSSM_BOOL                                       confirmRequired;
+       CSSM_TP_RESULT_SET_PTR          resultSet;
+       CSSM_ENCODED_CERT                       *encCert;
+       CSSM_TP_CALLERAUTH_CONTEXT      CallerAuthContext;
+       CSSM_FIELD                                      policyId;
+       CE_GeneralNames                         genNames;
+       CE_GeneralName                          genName;
+       uint8                                           ipNameBuf[4];
+       /* 
+        * Two extensions. Subject has two (KeyUsage and possibly 
+        * subjectAltName); root has KeyUsage and  BasicConstraints.
+        */
+       CE_DataAndType                          rootExts[2];
+       CE_DataAndType                          leafExts[2];
+       unsigned                                        numLeafExts;
+       
+       if(subjIpAddr && subjDnsName) {
+               printf("***Max of one of {subjIpAddr, subjDnsName} at a "
+                       "time, please.\n");
+               exit(1);
+       }
+       if(subjIpAddr) {
+               if(convertIp(subjIpAddr, ipNameBuf)) {
+                       printf("**Malformed IP address. Aborting.\n");
+                       exit(1);
+               }
+       }
+       
+       /* A KeyUsage extension for both certs */
+       rootExts[0].type = DT_KeyUsage;
+       rootExts[0].critical = CSSM_FALSE;
+       rootExts[0].extension.keyUsage = 
+               CE_KU_DigitalSignature | CE_KU_KeyCertSign;
+
+       leafExts[0].type = DT_KeyUsage;
+       leafExts[0].critical = CSSM_FALSE;
+       leafExts[0].extension.keyUsage =  CE_KU_DigitalSignature;
+
+       /* BasicConstraints for root only */
+       rootExts[1].type = DT_BasicConstraints;
+       rootExts[1].critical = CSSM_TRUE;
+       rootExts[1].extension.basicConstraints.cA = CSSM_TRUE;
+       rootExts[1].extension.basicConstraints.pathLenConstraintPresent = 
+                       CSSM_TRUE;
+       rootExts[1].extension.basicConstraints.pathLenConstraint = 2;
+
+       /* possible subjectAltName for leaf */
+       numLeafExts = 1;
+       if(subjIpAddr || subjDnsName) {
+               numLeafExts++;
+               leafExts[1].type = DT_SubjectAltName;
+               leafExts[1].critical = CSSM_TRUE;
+               
+               genName.berEncoded = CSSM_FALSE;
+               if(subjIpAddr) {
+                       genName.name.Data = (uint8 *)ipNameBuf;
+                       genName.name.Length = 4;
+                       genName.nameType = GNT_IPAddress;
+               }
+               else {
+                       genName.name.Data = (uint8 *)subjDnsName;
+                       genName.nameType = GNT_DNSName;
+                       genName.name.Length = strlen(subjDnsName);
+               }
+               genNames.numNames = 1;
+               genNames.generalName = &genName;
+               leafExts[1].extension.subjectAltName = genNames;
+       }
+       
+       /* certReq for root */
+       memset(&certReq, 0, sizeof(CSSM_APPLE_TP_CERT_REQUEST));
+       certReq.cspHand = cspHand;
+       certReq.clHand = clHand;
+       certReq.serialNumber = 0x12345678;
+       certReq.numSubjectNames = NUM_ROOT_NAMES;
+       certReq.subjectNames = rootRdn;
+       certReq.numIssuerNames = 0;
+       certReq.issuerNames = NULL;
+       certReq.certPublicKey = rootPubKey;
+       certReq.issuerPrivateKey = rootPrivKey;
+       certReq.signatureAlg = SIG_ALG_DEFAULT;
+       certReq.signatureOid = SIG_OID_DEFAULT;
+       certReq.notBefore = 0;                  // now
+       certReq.notAfter = 10000;               // seconds from now
+       certReq.numExtensions = 2;
+       certReq.extensions = rootExts;
+       
+       reqSet.NumberOfRequests = 1;
+       reqSet.Requests = &certReq;
+       
+       /* a big CSSM_TP_CALLERAUTH_CONTEXT just to specify an OID */
+       memset(&CallerAuthContext, 0, sizeof(CSSM_TP_CALLERAUTH_CONTEXT));
+       memset(&policyId, 0, sizeof(CSSM_FIELD));
+       policyId.FieldOid = CSSMOID_APPLE_TP_LOCAL_CERT_GEN;
+       CallerAuthContext.Policy.NumberOfPolicyIds = 1;
+       CallerAuthContext.Policy.PolicyIds = &policyId;
+       
+       /* generate root cert */
+       crtn = CSSM_TP_SubmitCredRequest(tpHand,
+               NULL,                           // PreferredAuthority
+               CSSM_TP_AUTHORITY_REQUEST_CERTISSUE,
+               &reqSet,
+               &CallerAuthContext,     
+               &estTime,
+               &refId);
+       if(crtn) {
+               printError("CSSM_TP_SubmitCredRequest", crtn);
+               return crtn;
+       }
+       crtn = CSSM_TP_RetrieveCredResult(tpHand,
+               &refId,
+               NULL,                           // CallerAuthCredentials
+               &estTime,
+               &confirmRequired,
+               &resultSet);
+       if(crtn) {
+               printError("CSSM_TP_RetrieveCredResult", crtn);
+               return crtn;
+       }
+       if(resultSet == NULL) {
+               printf("***CSSM_TP_RetrieveCredResult returned NULL result set.\n");
+               return crtn;
+       }
+       encCert = (CSSM_ENCODED_CERT *)resultSet->Results;
+       rootCert = encCert->CertBlob;
+
+       /* now a subject cert signed by the root cert */
+       certReq.serialNumber = 0x8765;
+       certReq.numSubjectNames = NUM_SUBJ_NAMES;
+       subjRdn[SUBJ_COMMON_NAME_DEX].string = commonName;
+       certReq.subjectNames = subjRdn;
+       certReq.numIssuerNames = NUM_ROOT_NAMES;
+       certReq.issuerNames = rootRdn;
+       certReq.certPublicKey = subjPubKey;
+       certReq.issuerPrivateKey = rootPrivKey;
+       certReq.numExtensions = numLeafExts;
+       certReq.extensions = leafExts;
+
+       crtn = CSSM_TP_SubmitCredRequest(tpHand,
+               NULL,                           // PreferredAuthority
+               CSSM_TP_AUTHORITY_REQUEST_CERTISSUE,
+               &reqSet,
+               &CallerAuthContext,
+               &estTime,
+               &refId);
+       if(crtn) {
+               printError("CSSM_TP_SubmitCredRequest (2)", crtn);
+               return crtn;
+       }
+       crtn = CSSM_TP_RetrieveCredResult(tpHand,
+               &refId,
+               NULL,                           // CallerAuthCredentials
+               &estTime,
+               &confirmRequired,
+               &resultSet);            // leaks.....
+       if(crtn) {
+               printError("CSSM_TP_RetrieveCredResult (2)", crtn);
+               return crtn;
+       }
+       if(resultSet == NULL) {
+               printf("***CSSM_TP_RetrieveCredResult (2) returned NULL "
+                               "result set.\n");
+               return crtn;
+       }
+       encCert = (CSSM_ENCODED_CERT *)resultSet->Results;
+       subjCert = encCert->CertBlob;
+
+       return CSSM_OK;
+}
+
+int main(int argc, char **argv)
+{
+       CSSM_CL_HANDLE  clHand;                 // CL handle
+       CSSM_CSP_HANDLE cspHand;                // CSP handle
+       CSSM_TP_HANDLE  tpHand;                 // TP handle
+       CSSM_DATA               rootCert;               
+       CSSM_DATA               subjCert;       
+       CSSM_KEY                subjPubKey;             // subject's RSA public key blob
+       CSSM_KEY                subjPrivKey;    // subject's RSA private key - ref format
+       CSSM_KEY                rootPubKey;             // root's RSA public key blob
+       CSSM_KEY                rootPrivKey;    // root's RSA private key - ref format
+       CSSM_RETURN             crtn = CSSM_OK;
+       int                             vfyRtn = 0;
+       int                             arg;
+       SSN_TestCase    *testCase;
+       unsigned                testNum;
+       
+       CSSM_BOOL               quiet = CSSM_FALSE;
+       CSSM_BOOL               verbose = CSSM_FALSE;
+       CSSM_BOOL               writeCerts = CSSM_FALSE;
+       
+       for(arg=1; arg<argc; arg++) {
+               char *argp = argv[arg];
+               switch(argp[0]) {
+                       case 'q':
+                               quiet = CSSM_TRUE;
+                               break;
+                       case 'v':
+                               verbose = CSSM_TRUE;
+                               break;
+                       case 'w':
+                               writeCerts = CSSM_TRUE;
+                               break;
+                       default:
+                               usage(argv);
+               }
+       }
+       
+       testStartBanner("sslSubjName", argc, argv);
+       
+       /* connect to CL, TP, and CSP */
+       clHand = clStartup();
+       if(clHand == 0) {
+               return 0;
+       }
+       tpHand = tpStartup();
+       if(tpHand == 0) {
+               return 0;
+       }
+       cspHand = cspStartup();
+       if(cspHand == 0) {
+               return 0;
+       }
+
+       /* subsequent errors to abort: to detach */
+       
+       /* cook up an RSA key pair for the subject */
+       crtn = cspGenKeyPair(cspHand,
+               KEY_ALG_DEFAULT,
+               SUBJ_KEY_LABEL,
+               strlen(SUBJ_KEY_LABEL),
+               KEY_SIZE_DEFAULT,
+               &subjPubKey,
+               CSSM_FALSE,                     // pubIsRef
+               CSSM_KEYUSE_VERIFY,
+               CSSM_KEYBLOB_RAW_FORMAT_NONE,
+               &subjPrivKey,
+               CSSM_TRUE,                      // privIsRef - doesn't matter
+               CSSM_KEYUSE_SIGN,
+               CSSM_KEYBLOB_RAW_FORMAT_NONE,
+               CSSM_FALSE);
+       if(crtn) {
+               return crtn;
+       }
+
+       /* and the root */
+       crtn = cspGenKeyPair(cspHand,
+               KEY_ALG_DEFAULT,
+               ROOT_KEY_LABEL,
+               strlen(ROOT_KEY_LABEL),
+               KEY_SIZE_DEFAULT,
+               &rootPubKey,
+               CSSM_FALSE,                     // pubIsRef
+               CSSM_KEYUSE_VERIFY,
+               CSSM_KEYBLOB_RAW_FORMAT_NONE,
+               &rootPrivKey,
+               CSSM_TRUE,                      // privIsRef - doesn't matter
+               CSSM_KEYUSE_SIGN,
+               CSSM_KEYBLOB_RAW_FORMAT_NONE,
+               CSSM_FALSE);
+       if(crtn) {
+               goto abort;
+       }
+
+       for(testNum=0; testNum<NUM_TEST_CASES; testNum++) {
+               testCase = &testCases[testNum];
+               if(!quiet) {
+                       printf("%s\n", testCase->testDesc);
+               }
+               crtn = genCerts(clHand, cspHand, tpHand,
+                       &rootPrivKey, &rootPubKey, &subjPubKey,
+                       testCase->certIpAddr, testCase->certDnsName, testCase->commonName,
+                       rootCert, subjCert);
+               BlobList leaf;
+               BlobList root;
+               /* BlobList uses regular free() on the referent of the blobs */
+               leaf.addBlob(subjCert, CSSM_TRUE);
+               root.addBlob(rootCert, CSSM_TRUE);
+               if(crtn) {
+                       if(testError(quiet)) {
+                               break;
+                       }
+               }
+               if(writeCerts) {
+                       if(writeFile(CERT_FILE, subjCert.Data, subjCert.Length)) {
+                               printf("***Error writing cert to %s\n", CERT_FILE);
+                       }
+                       else {
+                               printf("...wrote %lu bytes to %s\n", subjCert.Length, CERT_FILE);
+                       }
+               }
+               vfyRtn = certVerifySimple(tpHand, clHand, cspHand,
+                       leaf, root,
+                       CSSM_FALSE,             // useSystemAnchors
+                       CSSM_FALSE,             // leafCertIsCA
+                       CSSM_FALSE,             // allow expired root
+                       CVP_SSL,
+                       testCase->vfyHostName,
+                       CSSM_FALSE,             // sslClient
+                       NULL,
+                       NULL,
+                       testCase->expectErrStr,
+                       testCase->certErrorStr ? 1 : 0,
+                       testCase->certErrorStr ? (const char **)&testCase->certErrorStr :
+                               NULL,
+                       0, NULL,                // certStatus
+                       CSSM_FALSE,             // trustSettings
+                       quiet,
+                       verbose);
+               if(vfyRtn) {
+                       if(testError(quiet)) {
+                               break;
+                       }
+               }
+               /* cert data freed by ~BlobList */
+       }
+
+       /* free keys */
+       cspFreeKey(cspHand, &rootPubKey);
+       cspFreeKey(cspHand, &rootPrivKey);
+       cspFreeKey(cspHand, &subjPubKey);
+       cspFreeKey(cspHand, &subjPrivKey);
+
+abort:
+       if(cspHand != 0) {
+               CSSM_ModuleDetach(cspHand);
+       }
+       if(clHand != 0) {
+               CSSM_ModuleDetach(clHand);
+       }
+       if(tpHand != 0) {
+               CSSM_ModuleDetach(tpHand);
+       }
+       if(!vfyRtn && !crtn && !quiet) {
+               printf("...test passed\n");
+       }
+       return 0;
+}
+
+