X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/SecurityTests/clxutils/sslSubjName/sslSubjName.cpp?ds=inline diff --git a/SecurityTests/clxutils/sslSubjName/sslSubjName.cpp b/SecurityTests/clxutils/sslSubjName/sslSubjName.cpp new file mode 100644 index 00000000..9ca1a34f --- /dev/null +++ b/SecurityTests/clxutils/sslSubjName/sslSubjName.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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; argtestDesc); + } + 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; +} + +