--- /dev/null
+/* Copyright (c) 2006 Apple Computer, Inc.
+ *
+ * certSerialEncodeTest.cpp
+ *
+ * Verify proper encoding of unsigned integer as a DER_encoded signed integer.
+ * Verifies Radar 4471281.
+ *
+ */
+
+#include <utilLib/common.h>
+#include <utilLib/cspwrap.h>
+#include <security_cdsa_utils/cuFileIo.h>
+#include <clAppUtils/clutils.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>
+
+#define SUBJ_KEY_LABEL "subjectKey"
+#define ROOT_KEY_LABEL "rootKey"
+/* default key and signature algorithm */
+#define SIG_ALG_DEFAULT CSSM_ALGID_SHA1WithRSA
+#define SIG_OID_DEFAULT CSSMOID_SHA1WithRSA
+#define KEY_ALG_DEFAULT CSSM_ALGID_RSA
+
+/* for write certs/keys option */
+#define ROOT_CERT_FILE_NAME "ssRootCert.cer"
+#define SUBJ_CERT_FILE_NAME "ssSubjCert.cer"
+
+/* public key in ref form, TP supports this as of 1/30/02 */
+#define PUB_KEY_IS_REF CSSM_TRUE
+
+static void usage(char **argv)
+{
+ printf("Usage: %s [options]\n", argv[0]);
+ printf("Options:\n");
+ printf(" w[rite certs]\n");
+ printf(" p(ause for MallocDebug)\n");
+ printf(" q(uiet)\n");
+ exit(1);
+}
+
+/*
+ * RDN components
+ */
+static CSSM_APPLE_TP_NAME_OID rootRdn[] =
+{
+ { "Apple Computer", &CSSMOID_OrganizationName },
+ { "The Big Cheesy Debug Root", &CSSMOID_CommonName }
+};
+#define NUM_ROOT_NAMES (sizeof(rootRdn) / sizeof(CSSM_APPLE_TP_NAME_OID))
+
+/* test cases */
+typedef struct {
+ uint32 serialIn; /* --> CSSM_TP_SubmitCredRequest */
+ CSSM_SIZE expectLen;
+ const uint8 *expect;
+} SerialNumber;
+
+/* 0x7f */
+static const uint8 sn0_Data[1] = {0x7f};
+static const SerialNumber sn0 = {0x7f, 1, sn0_Data };
+
+/* 0x80 */
+static const uint8 sn1_Data[2] = {0x00, 0x80};
+static const SerialNumber sn1 = {0x80, 2, sn1_Data };
+
+/* 0x7ff */
+static const uint8 sn2_Data[2] = {0x07, 0xff};
+static const SerialNumber sn2 = {0x7ff, 2, sn2_Data };
+
+/* 0x80ff */
+static const uint8 sn3_Data[3] = {0x00, 0x80, 0xff};
+static const SerialNumber sn3 = {0x80ff, 3, sn3_Data };
+
+/* 0xfffffff */
+static const uint8 sn4_Data[4] = {0x0f, 0xff, 0xff, 0xff};
+static const SerialNumber sn4 = {0xfffffff, 4, sn4_Data };
+
+/* 0x0fffffff */
+static const uint8 sn5_Data[4] = {0x0f, 0xff, 0xff, 0xff};
+static const SerialNumber sn5 = {0x0fffffff, 4, sn5_Data };
+
+/* 0x80000000 */
+static const uint8 sn6_Data[5] = {0x00, 0x80, 0x00, 0x00, 0x00};
+static const SerialNumber sn6 = {0x80000000, 5, sn6_Data };
+
+static const SerialNumber *serialNumbers[] = {
+ &sn0, &sn1, &sn2, &sn3, &sn4, &sn5, &sn6
+};
+#define NUM_SERIAL_NUMS (sizeof(serialNumbers) / sizeof(serialNumbers[0]))
+
+static int doTest(
+ CSSM_CL_HANDLE clHand, // CL handle
+ CSSM_CSP_HANDLE cspHand, // CSP handle
+ CSSM_TP_HANDLE tpHand, // TP handle
+ CSSM_KEY_PTR subjPubKey,
+ CSSM_KEY_PTR signerPrivKey,
+ uint32 serialNumIn,
+ CSSM_SIZE serialNumExpLen,
+ const uint8 *serialNumExp,
+ CSSM_BOOL quiet,
+ CSSM_BOOL writeBlobs)
+{
+ CSSM_DATA refId; // mallocd by CSSM_TP_SubmitCredRequest
+ 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;
+ CSSM_RETURN crtn;
+ CSSM_DATA *signedRootCert;
+ int ourRtn = 0;
+ CSSM_DATA_PTR foundSerial = NULL;
+ CSSM_HANDLE resultHand = 0;
+ uint32 numFields;
+
+ /* certReq for root */
+ memset(&certReq, 0, sizeof(CSSM_APPLE_TP_CERT_REQUEST));
+ certReq.cspHand = cspHand;
+ certReq.clHand = clHand;
+ certReq.serialNumber = serialNumIn;
+ certReq.numSubjectNames = NUM_ROOT_NAMES;
+ certReq.subjectNames = rootRdn;
+ certReq.numIssuerNames = 0;
+ certReq.issuerNames = NULL;
+ certReq.certPublicKey = subjPubKey;
+ certReq.issuerPrivateKey = signerPrivKey;
+ certReq.signatureAlg = CSSM_ALGID_SHA1WithRSA;
+ certReq.signatureOid = CSSMOID_SHA1WithRSA;
+ certReq.notBefore = 0; // now
+ certReq.notAfter = 10000; // seconds from now
+ certReq.numExtensions = 0;
+ certReq.extensions = NULL;
+
+ 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 */
+ if(!quiet) {
+ printf("Creating root cert...\n");
+ }
+ crtn = CSSM_TP_SubmitCredRequest(tpHand,
+ NULL, // PreferredAuthority
+ CSSM_TP_AUTHORITY_REQUEST_CERTISSUE,
+ &reqSet,
+ &CallerAuthContext,
+ &estTime,
+ &refId);
+ if(crtn) {
+ printError("CSSM_TP_SubmitCredRequest", crtn);
+ ourRtn = -1;
+ goto errOut;
+ }
+ crtn = CSSM_TP_RetrieveCredResult(tpHand,
+ &refId,
+ NULL, // CallerAuthCredentials
+ &estTime,
+ &confirmRequired,
+ &resultSet);
+ if(crtn) {
+ printError("CSSM_TP_RetrieveCredResult", crtn);
+ ourRtn = -1;
+ goto errOut;
+ }
+ if(resultSet == NULL) {
+ printf("***CSSM_TP_RetrieveCredResult returned NULL result set.\n");
+ ourRtn = -1;
+ goto errOut;
+ }
+ encCert = (CSSM_ENCODED_CERT *)resultSet->Results;
+ signedRootCert = &encCert->CertBlob;
+ if(writeBlobs) {
+ writeFile(ROOT_CERT_FILE_NAME, signedRootCert->Data, signedRootCert->Length);
+ printf("...wrote %lu bytes to %s\n", signedRootCert->Length,
+ ROOT_CERT_FILE_NAME);
+ }
+
+ /* make sure it self-verifies */
+ crtn = CSSM_CL_CertVerify(clHand, 0 /* CCHandle */,
+ signedRootCert, signedRootCert,
+ NULL, 0);
+ if(crtn) {
+ cssmPerror("CSSM_CL_CertVerify", crtn);
+ printf("***Created cert does not self-verify\n");
+ ourRtn = -1;
+ goto errOut;
+ }
+
+ /* extract the field we're interested in verifying */
+ crtn = CSSM_CL_CertGetFirstFieldValue(clHand, signedRootCert,
+ &CSSMOID_X509V1SerialNumber, &resultHand, &numFields, &foundSerial);
+ if(crtn) {
+ cssmPerror("CSSM_CL_CertGetFirstFieldValue(serialNumber)", crtn);
+ printf("***Can't obtain serial number\n");
+ ourRtn = -1;
+ goto errOut;
+ }
+ CSSM_CL_CertAbortQuery(clHand, resultHand);
+ if(foundSerial->Length != serialNumExpLen) {
+ printf("***expected serialNumber len 0x%lu, got 0x%lu\n",
+ (unsigned long)serialNumExpLen, (unsigned long)foundSerial->Length);
+ ourRtn = -1;
+ goto errOut;
+ }
+ for(unsigned dex=0; dex<serialNumExpLen; dex++) {
+ if(foundSerial->Data[dex] != serialNumExp[dex]) {
+ printf("***SerialNumber mismatch at index %u: exp %02X got %02X\n",
+ dex, (unsigned)serialNumExp[dex],
+ (unsigned)foundSerial->Data[dex]);
+ ourRtn = -1;
+ }
+ }
+ /* free retrieved serial number and the result set itself */
+ CSSM_CL_FreeFieldValue(clHand, &CSSMOID_X509V1SerialNumber, foundSerial);
+ CSSM_FREE(signedRootCert->Data);
+ CSSM_FREE(encCert);
+ CSSM_FREE(resultSet);
+ /* Per the spec, this is supposed to be Opaque to us and the TP is supposed to free
+ * it when it goes out of scope...but libsecurity_keychains's
+ * CertificateRequest::submitDotMac() frees this...that would have to change
+ * in order for the TP to free this properly. Someday maybe. No big deal.
+ */
+ CSSM_FREE(refId.Data);
+errOut:
+ return ourRtn;
+}
+
+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_KEY rootPubKey; // root's RSA public key blob
+ CSSM_KEY rootPrivKey; // root's RSA private key - ref format
+ CSSM_RETURN crtn;
+ int arg;
+ unsigned dex;
+ int ourRtn = 0;
+ uint32 keySizeInBits = 512;
+ CSSM_BOOL doPause = CSSM_FALSE;
+
+ /* user-spec'd variables */
+ CSSM_BOOL writeBlobs = CSSM_FALSE;
+ CSSM_BOOL quiet = CSSM_FALSE;
+
+ for(arg=1; arg<argc; arg++) {
+ switch(argv[arg][0]) {
+ case 'w':
+ writeBlobs = CSSM_TRUE;
+ break;
+ case 'q':
+ quiet = CSSM_TRUE;
+ break;
+ case 'p':
+ doPause = CSSM_TRUE;
+ break;
+ default:
+ usage(argv);
+ }
+ }
+
+ testStartBanner("certSerialEncodeTest", argc, argv);
+
+
+ /* connect to CL, TP, and CSP */
+ clHand = clStartup();
+ if(clHand == 0) {
+ return -1;
+ }
+ tpHand = tpStartup();
+ if(tpHand == 0) {
+ return -1;
+ }
+ cspHand = cspStartup();
+ if(cspHand == 0) {
+ return -1;
+ }
+
+ /* cook up key pair for self-signed cert */
+ crtn = cspGenKeyPair(cspHand,
+ CSSM_ALGID_RSA,
+ ROOT_KEY_LABEL,
+ strlen(ROOT_KEY_LABEL),
+ keySizeInBits,
+ &rootPubKey,
+ CSSM_FALSE, // pubIsRef - should work both ways, but not yet
+ CSSM_KEYUSE_VERIFY,
+ CSSM_KEYBLOB_RAW_FORMAT_NONE,
+ &rootPrivKey,
+ writeBlobs ? CSSM_FALSE : CSSM_TRUE, // privIsRef
+ CSSM_KEYUSE_SIGN,
+ CSSM_KEYBLOB_RAW_FORMAT_NONE,
+ CSSM_FALSE);
+ if(crtn) {
+ ourRtn = -1;
+ goto abort;
+ }
+
+ for(dex=0; dex<NUM_SERIAL_NUMS; dex++) {
+ const SerialNumber *sn = serialNumbers[dex];
+ if(!quiet) {
+ printf("...testing serial number 0x%lx\n", (unsigned long)sn->serialIn);
+ }
+ ourRtn = doTest(clHand, cspHand, tpHand,
+ &rootPubKey, &rootPrivKey,
+ sn->serialIn, sn->expectLen, sn->expect,
+ quiet, writeBlobs);
+ if(ourRtn) {
+ break;
+ }
+ if(doPause) {
+ fpurge(stdin);
+ printf("Pausing for MallocDebug. a to abort, anything else to continue: ");
+ if(getchar() == 'a') {
+ break;
+ }
+ }
+ }
+
+ cspFreeKey(cspHand, &rootPubKey);
+ cspFreeKey(cspHand, &rootPrivKey);
+
+abort:
+ if(cspHand != 0) {
+ CSSM_ModuleDetach(cspHand);
+ }
+ if(clHand != 0) {
+ CSSM_ModuleDetach(clHand);
+ }
+ if(tpHand != 0) {
+ CSSM_ModuleDetach(tpHand);
+ }
+
+ if((ourRtn == 0) && !quiet) {
+ printf("certSerialEncodeTest test succeeded\n");
+ }
+ return ourRtn;
+}
+
+