X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/SecurityTests/clxutils/caVerify/caVerify.cpp diff --git a/SecurityTests/clxutils/caVerify/caVerify.cpp b/SecurityTests/clxutils/caVerify/caVerify.cpp new file mode 100644 index 00000000..e19d3302 --- /dev/null +++ b/SecurityTests/clxutils/caVerify/caVerify.cpp @@ -0,0 +1,648 @@ +/* Copyright (c) 1998,2003-2006,2008 Apple Inc. + * + * caVerify.cpp + * + * Verify proper detection of basicConstraints.cA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* define nonzero to build on Puma */ +#define PUMA_BUILD 0 + +/* default key and signature algorithm */ +#define SIG_ALG_DEFAULT CSSM_ALGID_SHA1WithRSA +#define KEY_ALG_DEFAULT CSSM_ALGID_RSA + +#define NUM_CERTS_DEF 5 /* default is random from 2 to this */ +#define NUM_LOOPS_DEF 100 + +#if PUMA_BUILD +extern "C" { + void cssmPerror(const char *how, CSSM_RETURN error); +} +#endif /* PUMA_BUILD */ + +static void usage(char **argv) +{ + printf("Usage: %s [options]\n", argv[0]); + printf("Options:\n"); + printf(" n=numCerts (default=random from 2 to %d)\n", NUM_CERTS_DEF); + printf(" a=alg where alg is s(RSA/SHA1), 5(RSA/MD5), f(FEE/MD5), " + "F(FEE/SHA1), e(ECDSA), E(ANSI/ECDSA), 6(ECDSA/SHA256)\n"); + printf(" k=keySizeInBits\n"); + printf(" c (dump certs on error)\n"); + printf(" l=numLoops (default = %d)\n", NUM_LOOPS_DEF); + exit(1); +} + +void showCerts( + const CSSM_DATA *certs, + unsigned numCerts) +{ + unsigned i; + + for(i=0; i=0; dex--) { + thisCert = &certs[dex]; + + thisCert->Data = NULL; + thisCert->Length = 0; + + sprintf(nameStr, "%s%04d", nameBase, dex); + if(issuerName == NULL) { + /* last (root) cert - subject same as issuer */ + issuerName = CB_BuildX509Name(&nameOid, 1); + /* self-signed */ + signerKey = &privKeys[dex]; + } + else { + /* previous subject becomes current issuer */ + CB_FreeX509Name(issuerName); + issuerName = subjectName; + signerKey = &privKeys[dex+1]; + } + subjectName = CB_BuildX509Name(&nameOid, 1); + if((subjectName == NULL) || (issuerName == NULL)) { + printf("Error creating X509Names\n"); + crtn = CSSMERR_CSSM_MEMORY_ERROR; + break; + } + + /* + * not before/after in Y2k-compliant generalized time format. + * These come preformatted from our caller. + */ + notBefore = CB_BuildX509Time(0, notBeforeStr); + notAfter = CB_BuildX509Time(0, notAfterStr); + + /* + * Cook up cert template + * Note serial number would be app-specified in real world + */ + rawCert = CB_MakeCertTemplate(clHand, + 0x12345 + dex, // serial number + issuerName, + subjectName, + notBefore, + notAfter, + &pubKeys[dex], + sigAlg, + NULL, // subj unique ID + NULL, // issuer unique ID + extensions[dex], // extensions + numExtensions[dex]); // numExtensions + + if(rawCert == NULL) { + crtn = CSSM_ERRCODE_INTERNAL_ERROR; + break; + } + + /* Free the stuff we allocd to get here */ + CB_FreeX509Time(notBefore); + CB_FreeX509Time(notAfter); + + /**** sign the cert ****/ + /* 1. get a signing context */ + crtn = CSSM_CSP_CreateSignatureContext(cspHand, + sigAlg, + NULL, // no passphrase for now + signerKey, + &signContext); + if(crtn) { + printError("CreateSignatureContext", crtn); + break; + } + + /* 2. use CL to sign the cert */ + signedCert.Data = NULL; + signedCert.Length = 0; + crtn = CSSM_CL_CertSign(clHand, + signContext, + rawCert, // CertToBeSigned + NULL, // SignScope per spec + 0, // ScopeSize per spec + &signedCert); + if(crtn) { + printError("CSSM_CL_CertSign", crtn); + break; + } + + /* 3. delete signing context */ + crtn = CSSM_DeleteContext(signContext); + if(crtn) { + printError("CSSM_DeleteContext", crtn); + break; + } + + /* + * CSSM_CL_CertSign() returned us a mallocd CSSM_DATA. Copy + * its fields to caller's cert. + */ + certs[dex] = signedCert; + + /* and the raw unsigned cert as well */ + appFreeCssmData(rawCert, CSSM_TRUE); + rtn = 0; + } + + /* free resources */ + if(issuerName != NULL) { + CB_FreeX509Name(issuerName); + } + if(subjectName != NULL) { + CB_FreeX509Name(subjectName); + } + return crtn; +} + +static int doTest( + CSSM_CSP_HANDLE cspHand, // CSP handle + CSSM_CL_HANDLE clHand, // CL handle + CSSM_TP_HANDLE tpHand, // TP handle + unsigned numCerts, // >= 2 + CSSM_KEY_PTR pubKeys, + CSSM_KEY_PTR privKeys, + CSSM_ALGORITHMS sigAlg, + CSSM_BOOL expectFail, + CSSM_BOOL dumpCerts, + CSSM_BOOL quiet) +{ + CSSM_DATA_PTR certs; + CSSM_X509_EXTENSION **extens; + unsigned *numExtens; + char *notBeforeStr = genTimeAtNowPlus(0); + char *notAfterStr = genTimeAtNowPlus(10000); + unsigned certDex; + CE_BasicConstraints *bc; + CSSM_X509_EXTENSION *thisExten; + CE_BasicConstraints *thisBc; + const char *failMode = "not set - internal error"; + CSSM_RETURN crtn; + unsigned badCertDex = 0; + + certs = (CSSM_DATA_PTR)malloc(sizeof(CSSM_DATA) * numCerts); + memset(certs, 0, sizeof(CSSM_DATA) * numCerts); + + /* + * For now just zero or one extension per cert - basicConstraints. + * Eventually we'll want to test keyUsage as well. + */ + extens = (CSSM_X509_EXTENSION **)malloc(sizeof(CSSM_X509_EXTENSION *) * numCerts); + memset(extens, 0, sizeof(CSSM_X509_EXTENSION *) * numCerts); + numExtens = (unsigned *)malloc(sizeof(unsigned) * numCerts); + bc = (CE_BasicConstraints *)malloc(sizeof(CE_BasicConstraints) * numCerts); + + /* + * Set up all extensions for success + */ + for(certDex=0; certDexextnId = CSSMOID_BasicConstraints; + thisExten->critical = CSSM_TRUE; + thisExten->format = CSSM_X509_DATAFORMAT_PARSED; + thisExten->value.parsedValue = thisBc; + thisExten->BERvalue.Data = NULL; + thisExten->BERvalue.Length = 0; + + if(certDex == 0) { + /* leaf - flip coin to determine presence of basicConstraints */ + int coin = genRand(1,2); + if(coin == 1) { + /* basicConstraints, !cA */ + thisBc->cA = CSSM_FALSE; + thisBc->pathLenConstraintPresent = CSSM_FALSE; + thisBc->pathLenConstraint = 0; + } + else { + /* !basicConstraints, !cA by default */ + numExtens[certDex] = 0; + } + } + else if(certDex == (numCerts-1)) { + /* root - flip coin to determine presence of basicConstraints */ + int coin = genRand(1,2); + if(coin == 1) { + /* basicConstraints, cA */ + thisBc->cA = CSSM_TRUE; + /* flip coin to determine present of pathLenConstraint */ + coin = genRand(1,2); + if(coin == 1) { + thisBc->pathLenConstraintPresent = CSSM_FALSE; + thisBc->pathLenConstraint = 0; + } + else { + thisBc->pathLenConstraintPresent = CSSM_TRUE; + thisBc->pathLenConstraint = genRand(certDex-1, numCerts+1); + } + } + else { + /* !basicConstraints, cA by default */ + numExtens[certDex] = 0; + } + } + else { + /* intermediate = cA required */ + thisBc->cA = CSSM_TRUE; + /* flip coin to determine presence of pathLenConstraint */ + int coin = genRand(1,2); + if(coin == 1) { + thisBc->pathLenConstraintPresent = CSSM_FALSE; + thisBc->pathLenConstraint = 0; + } + else { + thisBc->pathLenConstraintPresent = CSSM_TRUE; + thisBc->pathLenConstraint = genRand(certDex-1, numCerts+1); + } + } + } + + if(expectFail) { + /* introduce a failure */ + if(numCerts == 2) { + /* only possible failure is explicit !cA in root */ + /* don't assume presence of BC exten */ + badCertDex = 1; + thisExten = extens[badCertDex]; + thisBc = &bc[badCertDex]; + thisBc->cA = CSSM_FALSE; + thisBc->pathLenConstraintPresent = CSSM_FALSE; + bc->pathLenConstraint = 0; + numExtens[badCertDex] = 1; + failMode = "Explicit !cA in root"; + } + else { + /* roll the dice to select an intermediate cert */ + badCertDex = genRand(1, numCerts-2); + thisExten = extens[badCertDex]; + if((thisExten == NULL) || (numExtens[badCertDex] == 0)) { + printf("***INTERNAL SCREWUP\n"); + exit(1); + } + thisBc = &bc[badCertDex]; + + /* + * roll die: fail by + * -- no BasicConstraints + * -- !cA + * -- bad pathLenConstraint + */ + int die = genRand(1,3); + if((die == 1) && + (badCertDex != 1)) { // last cA doesn't need pathLenConstraint + thisBc->pathLenConstraintPresent = CSSM_TRUE; + thisBc->pathLenConstraint = badCertDex - 2; // one short + failMode = "Short pathLenConstraint"; + } + else if(die == 2) { + thisBc->cA = CSSM_FALSE; + failMode = "Explicit !cA in intermediate"; + } + else { + /* no extension */ + numExtens[badCertDex] = 0; + failMode = "No BasicConstraints in intermediate"; + } + } + } + if(!quiet && expectFail) { + printf(" ...bad cert at index %d: %s\n", badCertDex, failMode); + } + + /* here we go - create cert chain */ + crtn = tpGenCertsExten(cspHand, + clHand, + sigAlg, + numCerts, + "caVerify", // nameBase + pubKeys, + privKeys, + extens, + numExtens, + certs, + notBeforeStr, + notAfterStr); + if(crtn) { + printError("tpGenCertsExten", crtn); + return crtn; // and leak like crazy + } + + CSSM_CERTGROUP cgrp; + memset(&cgrp, 0, sizeof(CSSM_CERTGROUP)); + cgrp.NumCerts = numCerts; + #if PUMA_BUILD + cgrp.CertGroupType = CSSM_CERTGROUP_ENCODED_CERT; + #else + /* Jaguar */ + cgrp.CertGroupType = CSSM_CERTGROUP_DATA; + #endif /* PUMA_BUILD */ + cgrp.CertType = CSSM_CERT_X_509v3; + cgrp.CertEncoding = CSSM_CERT_ENCODING_DER; + cgrp.GroupList.CertList = certs; + + #if PUMA_BUILD + crtn = tpCertGroupVerify(tpHand, + clHand, + cspHand, + NULL, // DlDbList + &CSSMOID_APPLE_X509_BASIC, // SSL requires built-in root match + &cgrp, + /* pass in OUR ROOT as anchors */ + (CSSM_DATA_PTR)&certs[numCerts-1], // anchorCerts + 1, + CSSM_TP_STOP_ON_POLICY, + CSSM_FALSE, // allowExpired + NULL); // vfyResult + #else + /* Jaguar */ + crtn = tpCertGroupVerify(tpHand, + clHand, + cspHand, + NULL, // DlDbList + &CSSMOID_APPLE_TP_SSL, // may want to parameterize this + NULL, // fieldOpts for server name + NULL, // actionDataPtr for allow expired + NULL, // policyOpts + &cgrp, + /* pass in OUR ROOT as anchors */ + (CSSM_DATA_PTR)&certs[numCerts-1], // anchorCerts + 1, + CSSM_TP_STOP_ON_POLICY, + NULL, // cssmTimeStr + NULL); // vfyResult + #endif /* PUMA_BUILD */ + if(expectFail) { + if(crtn != CSSMERR_TP_VERIFY_ACTION_FAILED) { + cssmPerror("***Expected error TP_VERIFY_ACTION_FAILED; got ", crtn); + printf(" Expected failure due to %s\n", failMode); + if(dumpCerts) { + showCerts(certs, numCerts); + writeCerts(certs, numCerts); + } + return testError(quiet); + } + } + else if(crtn) { + cssmPerror("Unexpected failure on tpCertGroupVerify", crtn); + if(dumpCerts) { + showCerts(certs, numCerts); + } + return testError(quiet); + } + + /* clean up */ + return 0; +} + +int main(int argc, char **argv) +{ + CSSM_CL_HANDLE clHand; // CL handle + CSSM_CSP_HANDLE cspHand; // CSP handle + CSSM_TP_HANDLE tpHand; + CSSM_KEY_PTR pubKeys; + CSSM_KEY_PTR privKeys; + CSSM_RETURN crtn; + int arg; + unsigned certDex; + unsigned loopNum; + unsigned maxCerts; + + /* user-spec'd variables */ + CSSM_ALGORITHMS keyAlg = KEY_ALG_DEFAULT; + CSSM_ALGORITHMS sigAlg = SIG_ALG_DEFAULT; + uint32 keySizeInBits = CSP_KEY_SIZE_DEFAULT; + unsigned numCerts = 0; // means random per loop + unsigned numLoops = NUM_LOOPS_DEF; + CSSM_BOOL quiet = CSSM_FALSE; + CSSM_BOOL dumpCerts = CSSM_FALSE; + + for(arg=1; arg