#include <stdlib.h>
#include <strings.h>
#include <stdio.h>
#include <unistd.h>
#include <Security/Security.h>
#include <Security/SecCertificatePriv.h>
#include <clAppUtils/clutils.h>
#include <clAppUtils/CertBuilderApp.h>
#include <utilLib/common.h>
#include <utilLib/cspwrap.h>
#include <security_cdsa_utils/cuFileIo.h>
static void usage(char **argv)
{
printf("usage: %s [options]\n", argv[0]);
printf("Options:\n");
printf(" -p -- pause for leaks check\n");
printf(" -q -- quiet\n");
exit(1);
}
#define KEY_SIZE 1024
#define KEY_ALG CSSM_ALGID_RSA
#define SIG_ALG CSSM_ALGID_SHA1WithRSA
#define CERT_FILE_OUT "/tmp/certLabelTest.cer"
static const unsigned char JurgenPetersen[] =
{
0x4a, 0xf8, 0x72, 0x67, 0x65, 0x6e, 0x20, 0x4e,
0xf8, 0x72, 0x67, 0x61, 0x61, 0x72, 0x64, 0x20,
0x50, 0x65, 0x74, 0x65, 0x72, 0x73, 0x65, 0x6e
};
typedef struct {
const void *nameVal;
CSSM_SIZE nameLen;
const CSSM_OID *oid;
CSSM_BER_TAG berTag;
} NameOid;
static CSSM_X509_NAME *buildX509Name(
const NameOid *nameArray,
unsigned numNames)
{
CSSM_X509_NAME *top = (CSSM_X509_NAME *)appMalloc(sizeof(CSSM_X509_NAME), 0);
if(top == NULL) {
return NULL;
}
top->numberOfRDNs = numNames;
top->RelativeDistinguishedName =
(CSSM_X509_RDN_PTR)appMalloc(sizeof(CSSM_X509_RDN) * numNames, 0);
if(top->RelativeDistinguishedName == NULL) {
return NULL;
}
CSSM_X509_RDN_PTR rdn;
const NameOid *nameOid;
unsigned nameDex;
for(nameDex=0; nameDex<numNames; nameDex++) {
rdn = &top->RelativeDistinguishedName[nameDex];
nameOid = &nameArray[nameDex];
rdn->numberOfPairs = 1;
rdn->AttributeTypeAndValue = (CSSM_X509_TYPE_VALUE_PAIR_PTR)
appMalloc(sizeof(CSSM_X509_TYPE_VALUE_PAIR), 0);
CSSM_X509_TYPE_VALUE_PAIR_PTR atvp = rdn->AttributeTypeAndValue;
if(atvp == NULL) {
return NULL;
}
appCopyCssmData(nameOid->oid, &atvp->type);
atvp->valueType = nameOid->berTag;
atvp->value.Length = nameOid->nameLen;
atvp->value.Data = (uint8 *)CSSM_MALLOC(nameOid->nameLen);
memmove(atvp->value.Data, nameOid->nameVal, nameOid->nameLen);
}
return top;
}
static CSSM_X509_TIME *notBefore;
static CSSM_X509_TIME *notAfter;
static int doTest(
const char *testName,
bool quiet,
CSSM_CSP_HANDLE cspHand,
CSSM_CL_HANDLE clHand,
CSSM_KEY_PTR privKey,
CSSM_KEY_PTR pubKey,
const void *name1Val,
CSSM_SIZE name1Len,
CSSM_BER_TAG berTag1,
const CSSM_OID *name1Oid,
const void *name2Val, CSSM_SIZE name2Len,
CSSM_BER_TAG berTag2,
const CSSM_OID *name2Oid,
CFStringRef expectedLabel,
bool labelIsCommonName)
{
if(!quiet) {
printf("...%s\n", testName);
}
NameOid nameArray[2] = { {name1Val, name1Len, name1Oid, berTag1 },
{name2Val, name2Len, name2Oid, berTag2 } };
unsigned numNames = name2Val ? 2 : 1;
CSSM_X509_NAME *name = buildX509Name(nameArray, numNames);
if(name == NULL) {
printf("***buildX509Name screwup\n");
return -1;
}
CSSM_DATA_PTR certTemp = CB_MakeCertTemplate(
clHand, 0x123456,
name, name,
notBefore, notAfter,
pubKey, SIG_ALG,
NULL, NULL, NULL, 0); if(certTemp == NULL) {
printf("***CB_MakeCertTemplate screwup\n");
return -1;
}
CSSM_DATA signedCert = {0, NULL};
CSSM_CC_HANDLE sigHand;
CSSM_RETURN crtn = CSSM_CSP_CreateSignatureContext(cspHand,
SIG_ALG,
NULL, privKey,
&sigHand);
if(crtn) {
cssmPerror("CSSM_CSP_CreateSignatureContext", crtn);
return 1;
}
crtn = CSSM_CL_CertSign(clHand,
sigHand,
certTemp, NULL, 0, &signedCert);
if(crtn) {
cssmPerror("CSSM_CL_CertSign", crtn);
return 1;
}
CSSM_DeleteContext(sigHand);
CSSM_FREE(certTemp->Data);
CSSM_FREE(certTemp);
OSStatus ortn;
SecCertificateRef certRef;
ortn = SecCertificateCreateFromData(&signedCert,
CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER,
&certRef);
if(ortn) {
cssmPerror("SecCertificateCreateFromData", ortn);
return -1;
}
CFStringRef inferredLabel;
ortn = SecCertificateInferLabel(certRef, &inferredLabel);
if(ortn) {
cssmPerror("SecCertificateCreateFromData", ortn);
return -1;
}
CFComparisonResult res = CFStringCompare(inferredLabel, expectedLabel, 0);
if(res != kCFCompareEqualTo) {
fprintf(stderr, "*** label miscompare in test '%s' ***\n", testName);
fprintf(stderr, "expected label : ");
CFShow(expectedLabel);
fprintf(stderr, "inferred label : ");
CFShow(inferredLabel);
if(writeFile(CERT_FILE_OUT, signedCert.Data, signedCert.Length)) {
fprintf(stderr, "***Error writing cert to %s\n", CERT_FILE_OUT);
}
else {
fprintf(stderr, "...write %lu bytes to %s\n", (unsigned long)signedCert.Length,
CERT_FILE_OUT);
}
return -1;
}
if(labelIsCommonName) {
CFStringRef commonName = NULL;
ortn = SecCertificateCopyCommonName(certRef, &commonName);
if(ortn) {
cssmPerror("SecCertificateCopyCommonName", ortn);
return -1;
}
res = CFStringCompare(inferredLabel, commonName, 0);
if(res != kCFCompareEqualTo) {
printf("*** CommonName miscompare in test '%s' ***\n", testName);
printf("Common Name : '");
CFShow(commonName);
printf("'\n");
printf("inferred label : '");
CFShow(inferredLabel);
printf("'\n");
if(writeFile(CERT_FILE_OUT, signedCert.Data, signedCert.Length)) {
printf("***Error writing cert to %s\n", CERT_FILE_OUT);
}
else {
printf("...write %lu bytes to %s\n", (unsigned long)signedCert.Length,
CERT_FILE_OUT);
}
return -1;
}
CFRelease(commonName);
}
CFRelease(certRef);
CSSM_FREE(signedCert.Data);
CB_FreeX509Name(name);
CFRelease(inferredLabel);
return 0;
}
int main(int argc, char **argv)
{
bool quiet = false;
bool doPause = false;
int arg;
while ((arg = getopt(argc, argv, "pqh")) != -1) {
switch (arg) {
case 'q':
quiet = true;
break;
case 'p':
doPause = true;
break;
case 'h':
usage(argv);
}
}
if(optind != argc) {
usage(argv);
}
testStartBanner("certLabelTest", argc, argv);
CSSM_CL_HANDLE clHand = clStartup();
CSSM_CSP_HANDLE cspHand = cspStartup();
CSSM_RETURN crtn;
CSSM_KEY pubKey;
CSSM_KEY privKey;
crtn = cspGenKeyPair(cspHand, KEY_ALG,
"someLabel", 8,
KEY_SIZE,
&pubKey, CSSM_FALSE, CSSM_KEYUSE_ANY, CSSM_KEYBLOB_RAW_FORMAT_NONE,
&privKey, CSSM_FALSE, CSSM_KEYUSE_ANY, CSSM_KEYBLOB_RAW_FORMAT_NONE,
CSSM_FALSE);
if(crtn) {
printf("***Error generating RSA key pair. Aborting.\n");
exit(1);
}
notBefore = CB_BuildX509Time(0);
notAfter = CB_BuildX509Time(100000);
int ourRtn;
ourRtn = doTest("simple ASCII common name", quiet,
cspHand, clHand, &privKey, &pubKey,
"Simple Name", strlen("Simple Name"), BER_TAG_PRINTABLE_STRING, &CSSMOID_CommonName,
NULL, 0, BER_TAG_UNKNOWN, NULL,
CFSTR("Simple Name"), true);
if(ourRtn) {
exit(1);
}
ourRtn = doTest("ASCII common name plus ASCII description", quiet,
cspHand, clHand, &privKey, &pubKey,
"Simple Name", strlen("Simple Name"), BER_TAG_PRINTABLE_STRING, &CSSMOID_CommonName,
"Description", strlen("Description"), BER_TAG_PRINTABLE_STRING, &CSSMOID_Description,
CFSTR("Simple Name (Description)"), false);
if(ourRtn) {
exit(1);
}
ourRtn = doTest("simple UTF8 common name", quiet,
cspHand, clHand, &privKey, &pubKey,
"Simple Name", strlen("Simple Name"), BER_TAG_PKIX_UTF8_STRING, &CSSMOID_CommonName,
NULL, 0, BER_TAG_UNKNOWN, NULL,
CFSTR("Simple Name"), true);
if(ourRtn) {
exit(1);
}
ourRtn = doTest("label from OrgName", quiet,
cspHand, clHand, &privKey, &pubKey,
"Simple Name", strlen("Simple Name"), BER_TAG_PRINTABLE_STRING, &CSSMOID_OrganizationName,
NULL, 0, BER_TAG_UNKNOWN, NULL,
CFSTR("Simple Name"), false);
if(ourRtn) {
exit(1);
}
ourRtn = doTest("label from OrgUnit", quiet,
cspHand, clHand, &privKey, &pubKey,
"Simple Name", strlen("Simple Name"), BER_TAG_PRINTABLE_STRING, &CSSMOID_OrganizationalUnitName,
NULL, 0, BER_TAG_UNKNOWN, NULL,
CFSTR("Simple Name"), false);
if(ourRtn) {
exit(1);
}
ourRtn = doTest("label from OrgUnit, description is ignored", quiet,
cspHand, clHand, &privKey, &pubKey,
"Simple Name", strlen("Simple Name"), BER_TAG_PRINTABLE_STRING, &CSSMOID_OrganizationalUnitName,
"Description", strlen("Description"), BER_TAG_PRINTABLE_STRING, &CSSMOID_Description,
CFSTR("Simple Name"), false);
if(ourRtn) {
exit(1);
}
CFStringRef t61Str = CFStringCreateWithBytes(NULL, JurgenPetersen, sizeof(JurgenPetersen),
kCFStringEncodingISOLatin1, true);
ourRtn = doTest("T61/Teletex name from Radar 3529689", quiet,
cspHand, clHand, &privKey, &pubKey,
JurgenPetersen, sizeof(JurgenPetersen), BER_TAG_TELETEX_STRING, &CSSMOID_CommonName,
NULL, 0, BER_TAG_UNKNOWN, NULL,
t61Str, true);
if(ourRtn) {
exit(1);
}
CFDataRef unicodeStr = CFStringCreateExternalRepresentation(NULL, t61Str,
kCFStringEncodingUnicode, 0);
if(unicodeStr == NULL) {
printf("***Error converting to Unicode\n");
exit(1);
}
ourRtn = doTest("Unicode CommonName", quiet,
cspHand, clHand, &privKey, &pubKey,
CFDataGetBytePtr(unicodeStr), CFDataGetLength(unicodeStr),
BER_TAG_PKIX_BMP_STRING, &CSSMOID_CommonName,
NULL, 0, BER_TAG_UNKNOWN, NULL,
t61Str, true);
if(ourRtn) {
exit(1);
}
CFRelease(unicodeStr);
CFMutableStringRef combo = CFStringCreateMutable(NULL, 0);
CFStringAppend(combo, t61Str);
CFStringAppendCString(combo, " (Description)", kCFStringEncodingASCII);
ourRtn = doTest("ISOLatin Common Name and ASCII Description", quiet,
cspHand, clHand, &privKey, &pubKey,
JurgenPetersen, sizeof(JurgenPetersen), BER_TAG_TELETEX_STRING, &CSSMOID_CommonName,
"Description", strlen("Description"), BER_TAG_PRINTABLE_STRING, &CSSMOID_Description,
combo, false);
if(ourRtn) {
exit(1);
}
CFRelease(combo);
CFRelease(t61Str);
if(doPause) {
fpurge(stdin);
printf("Pausing for leaks testing; CR to continue: ");
getchar();
}
if(!quiet) {
printf("...success\n");
}
return 0;
}