#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>
#define SUBJ_KEY_LABEL "subjectKey"
#define ROOT_KEY_LABEL "rootKey"
#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);
}
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 },
{ NULL, &CSSMOID_CommonName }
};
#define SUBJ_COMMON_NAME_DEX 1
#define NUM_SUBJ_NAMES (sizeof(subjRdn) / sizeof(CSSM_APPLE_TP_NAME_OID))
typedef struct {
const char *testDesc;
const char *certDnsName;
const char *certIpAddr;
const char *commonName;
const char *vfyHostName;
const char *expectErrStr;
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))
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++; str = nextDot + 1;
}
if(str == NULL) {
return 1;
}
*buf = atoi(str);
return 0;
}
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,
const char *subjIpAddr,
const char *subjDnsName,
const char *commonName,
CSSM_DATA &rootCert, CSSM_DATA &subjCert)
{
CSSM_DATA refId;
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];
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);
}
}
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;
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;
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;
}
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; certReq.notAfter = 10000; certReq.numExtensions = 2;
certReq.extensions = rootExts;
reqSet.NumberOfRequests = 1;
reqSet.Requests = &certReq;
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;
crtn = CSSM_TP_SubmitCredRequest(tpHand,
NULL, 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, &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;
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, 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, &estTime,
&confirmRequired,
&resultSet); 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; CSSM_CSP_HANDLE cspHand; CSSM_TP_HANDLE tpHand; CSSM_DATA rootCert;
CSSM_DATA subjCert;
CSSM_KEY subjPubKey; CSSM_KEY subjPrivKey; CSSM_KEY rootPubKey; CSSM_KEY rootPrivKey; 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);
clHand = clStartup();
if(clHand == 0) {
return 0;
}
tpHand = tpStartup();
if(tpHand == 0) {
return 0;
}
cspHand = cspStartup();
if(cspHand == 0) {
return 0;
}
crtn = cspGenKeyPair(cspHand,
KEY_ALG_DEFAULT,
SUBJ_KEY_LABEL,
strlen(SUBJ_KEY_LABEL),
KEY_SIZE_DEFAULT,
&subjPubKey,
CSSM_FALSE, CSSM_KEYUSE_VERIFY,
CSSM_KEYBLOB_RAW_FORMAT_NONE,
&subjPrivKey,
CSSM_TRUE, CSSM_KEYUSE_SIGN,
CSSM_KEYBLOB_RAW_FORMAT_NONE,
CSSM_FALSE);
if(crtn) {
return crtn;
}
crtn = cspGenKeyPair(cspHand,
KEY_ALG_DEFAULT,
ROOT_KEY_LABEL,
strlen(ROOT_KEY_LABEL),
KEY_SIZE_DEFAULT,
&rootPubKey,
CSSM_FALSE, CSSM_KEYUSE_VERIFY,
CSSM_KEYBLOB_RAW_FORMAT_NONE,
&rootPrivKey,
CSSM_TRUE, 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;
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, CSSM_FALSE, CSSM_FALSE, CVP_SSL,
testCase->vfyHostName,
CSSM_FALSE, NULL,
NULL,
testCase->expectErrStr,
testCase->certErrorStr ? 1 : 0,
testCase->certErrorStr ? (const char **)&testCase->certErrorStr :
NULL,
0, NULL, CSSM_FALSE, quiet,
verbose);
if(vfyRtn) {
if(testError(quiet)) {
break;
}
}
}
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;
}