]> git.saurik.com Git - apple/security.git/blobdiff - SecurityTests/clxutils/certLabelTest/certLabelTest.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / SecurityTests / clxutils / certLabelTest / certLabelTest.cpp
diff --git a/SecurityTests/clxutils/certLabelTest/certLabelTest.cpp b/SecurityTests/clxutils/certLabelTest/certLabelTest.cpp
new file mode 100644 (file)
index 0000000..e3ab6e3
--- /dev/null
@@ -0,0 +1,426 @@
+/*
+ * certLabelTest.cpp - test SecCertificateInferLabel(), in particular, Radar 
+ *                                        3529689 (teletex strings) and 4746055 (add Description 
+ *                                        in parentheses)
+ */
+#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");
+       /* etc. */
+       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"
+
+/* 
+ * Here's the definitive string for Radar 3529689.
+ * BER tag = Teletex/T61, encoding = kCFStringEncodingISOLatin1.
+ * I hope Herr Petersen does not mind. 
+ */
+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
+};
+
+/*
+ * Name/OID pair used in buildX509Name().
+ * This logic is like the CB_BuildX509Name() code in clAppUtils/CertBuilderApp.cpp,
+ * with the addition of the berTag specification, and data is specified as a void *
+ * and size_t. 
+ */
+typedef struct {
+       const void                      *nameVal;
+       CSSM_SIZE                       nameLen;
+       const CSSM_OID          *oid;
+       CSSM_BER_TAG            berTag;
+} NameOid;
+
+/*
+ * Build up a CSSM_X509_NAME from an arbitrary list of name/OID/tag triplets.
+ * We do one a/v pair per RDN.
+ */
+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;
+}
+
+/* just make these static and reuse them */
+static CSSM_X509_TIME *notBefore;
+static CSSM_X509_TIME *notAfter;
+
+/* 
+ * Core test routine.
+ * -- build a cert with issuer and subject as per specified name components
+ * -- extract inferred label 
+ * -- compare inferred label to expected value 
+ * -- if labelIsCommonName true, verify that SecCertificateCopyCommonName() yields
+ *    the same string as inferred label
+ */
+static int doTest(
+       const char                      *testName,
+       bool                            quiet,
+       CSSM_CSP_HANDLE         cspHand,
+       CSSM_CL_HANDLE          clHand,
+       CSSM_KEY_PTR            privKey,
+       CSSM_KEY_PTR            pubKey,
+       
+       /* input names - one or two */
+       const void                      *name1Val,
+       CSSM_SIZE                       name1Len,
+       CSSM_BER_TAG            berTag1,
+       const CSSM_OID          *name1Oid,
+       const void                      *name2Val,              // optional 
+       CSSM_SIZE                       name2Len,
+       CSSM_BER_TAG            berTag2,
+       const CSSM_OID          *name2Oid,
+       
+       /* expected label */
+       CFStringRef                     expectedLabel,
+       bool                            labelIsCommonName)
+{
+       if(!quiet) {
+               printf("...%s\n", testName);
+       }
+       
+       /* build the subject/issuer name */
+       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;
+       }
+       
+       /* build the cert template */
+       CSSM_DATA_PTR certTemp = CB_MakeCertTemplate(
+               clHand, 0x123456,
+               name, name,
+               notBefore, notAfter,
+               pubKey, SIG_ALG,
+               NULL, NULL,             // subject/issuer UniqueID
+               NULL, 0);               // extensions 
+       if(certTemp == NULL) {
+               printf("***CB_MakeCertTemplate screwup\n");
+               return -1;
+       }
+       
+       /* sign the cert */
+       CSSM_DATA signedCert = {0, NULL};
+       CSSM_CC_HANDLE sigHand;
+       CSSM_RETURN crtn = CSSM_CSP_CreateSignatureContext(cspHand,
+                       SIG_ALG,
+                       NULL,                   // no passphrase for now
+                       privKey,
+                       &sigHand);
+       if(crtn) {
+               /* should never happen */
+               cssmPerror("CSSM_CSP_CreateSignatureContext", crtn);
+               return 1;
+       }
+       crtn = CSSM_CL_CertSign(clHand,
+               sigHand,
+               certTemp,                       // CertToBeSigned
+               NULL,                           // SignScope per spec
+               0,                                      // ScopeSize per spec
+               &signedCert);
+       if(crtn) {
+               cssmPerror("CSSM_CL_CertSign", crtn);
+               return 1;
+       }
+       CSSM_DeleteContext(sigHand);
+       CSSM_FREE(certTemp->Data);
+       CSSM_FREE(certTemp);
+
+       /* 
+        * OK, we have a signed cert. 
+        * Turn it into a SecCertificateRef and get the inferred label.
+        */
+       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();
+       
+       /* create a key pair */
+       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);
+       }
+       
+       /* common params, reused for each test */
+       notBefore = CB_BuildX509Time(0);
+       notAfter = CB_BuildX509Time(100000);
+       
+       /* 
+        * Grind thru test cases.
+        */
+       int ourRtn;
+       
+       /* very basic */
+       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);
+       }
+       
+       /* test concatentation of description */
+       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);
+       }
+
+       /* basic, specifying UTF8 (should be same as PRINTABLE) */
+       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);
+       }
+
+       /* label from org name instead of common name */
+       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);
+       }
+
+       /* label from orgUnit name instead of common name */
+       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);
+       }
+
+       /* label from orgUnit name, description is ignored (it's only used if the 
+        * label comes from CommonName) */
+       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);
+       }
+
+       /* Radar 3529689: T61/Teletex, ISOLatin encoding, commonName only */
+       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);
+       }
+       
+       /* Now convert that ISOLatin into Unicode and try with that */
+       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);
+       
+       /* Mix up ISOLatin Common Name and ASCII Description to ensure that the encodings
+        * of the two components are handled separately */
+       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;
+}