static int p12MacParse(
	const NSS_P12_MacData &macData, 
	P12ParseInfo &pinfo,
	unsigned depth)		// print indent depth
{
	if(p12AlgIdParse(macData.mac.digestAlgorithm, NULL, pinfo, depth)) {
		return 1;
	}
	doIndent(depth);
	printf("Digest : ");
	printDataAsHex(&macData.mac.digest, 20);
	doIndent(depth);
	printf("Salt : ");
	printDataAsHex(&macData.macSalt, 16);
	const CSSM_DATA &iter = macData.iterations;
	
	if(iter.Length > 4) {
		doIndent(depth);
		printf("***Warning: malformed iteraton length (%u)\n",
			(unsigned)iter.Length);
	}
	unsigned i = dataToInt(iter);
	doIndent(depth);
	printf("Iterations = %u\n", i);
	return 0;
}
Example #2
0
void displayTSTInfo(SecAsn1TSATSTInfo *tstInfo)
{
#ifndef NDEBUG
    dtprintf("--- TSTInfo ---\n");
    if (!tstInfo)
        return;

    if (tstInfo->version.Data)
    {
        uint64_t vers = tsaDER_ToInt(&tstInfo->version);
        dtprintf("Version:\t\t%u\n", (int)vers);
    }

    if (tstInfo->serialNumber.Data)
    {
        uint64_t sn = tsaDER_ToInt(&tstInfo->serialNumber);
        dtprintf("SerialNumber:\t%llu\n", sn);
    }

    if (tstInfo->ordering.Data)
    {
        uint64_t ord = tsaDER_ToInt(&tstInfo->ordering);
        dtprintf("Ordering:\t\t%s\n", ord?"yes":"no");
    }

    if (tstInfo->nonce.Data)
    {
        uint64_t nonce = tsaDER_ToInt(&tstInfo->nonce);
        dtprintf("Nonce:\t\t%llu\n", nonce);
    }
    else
        dtprintf("Nonce:\t\tnot specified\n");

    if (tstInfo->genTime.Data)
    {
        char buf[tstInfo->genTime.Length+1];
        memcpy(buf, (const char *)tstInfo->genTime.Data, tstInfo->genTime.Length);
        buf[tstInfo->genTime.Length]=0;
        dtprintf("GenTime:\t\t%s\n", buf);
    }

    dtprintf("-- MessageImprint --\n");
    if (true)   // SecAsn1TSAMessageImprint
    {
        printDataAsHex(" Algorithm:",&tstInfo->messageImprint.hashAlgorithm.algorithm, 0);
        printDataAsHex(" Message  :", &tstInfo->messageImprint.hashedMessage, 0);//tstInfo->messageImprint.hashedMessage.Length);
    }
#endif
}
/*
 * Parse a NSS_P7_EncryptedData - specifically in the context
 * of a P12 in password privacy mode. (The latter assumption is
 * to enable us to infer CSSM_X509_ALGORITHM_IDENTIFIER.parameters
 * format). 
 */
static int encryptedDataParse(
	const NSS_P7_EncryptedData &edata,
	P12ParseInfo &pinfo,
	NSS_P12_PBE_Params *pbep,		// optional, RETURNED
	unsigned depth)					// print indent depth
{
	doIndent(depth);
	printf("version = %u\n", (unsigned)dataToInt(edata.version));
	const NSS_P7_EncrContentInfo &ci = edata.contentInfo;
	doIndent(depth);
	printf("contentType = %s\n", oidStr(ci.contentType, pinfo.mParser));
	
	/*
	 * Parse the alg ID, safe PBE params for when we do the 
	 * key unwrap
	 */
	const CSSM_X509_ALGORITHM_IDENTIFIER &algId = ci.encrAlg;
	if(p12AlgIdParse(algId, pbep, pinfo, depth)) {
		return 1;
	}
	
	doIndent(depth);
	printf("encrContent : ");
	printDataAsHex(&ci.encrContent, 12);
	return 0;
}
static int attrParse(
	const NSS_Attribute *attr,
	P12ParseInfo &pinfo, 
	unsigned depth)
{
	doIndent(depth);
	printf("attrType : %s\n", oidStr(attr->attrType, pinfo.mParser));
	unsigned numVals = nssArraySize((const void **)attr->attrValue);
	doIndent(depth);
	printf("numValues = %u\n", numVals);

	for(unsigned dex=0; dex<numVals; dex++) {
		doIndent(depth);
		printf("val[%u] : ", dex);
		
		/*
		 * Note: these two enumerated types should only have one att value 
		 * per PKCS9. Leave that to real apps, we want to see what's there
		 * in any case.
		 */
		if(nssCompareCssmData(&attr->attrType, &CSSMOID_PKCS9_FriendlyName)) {
			/* BMP string (UniCode) */
			CSSM_DATA ustr;
			if(pinfo.mCoder.decodeItem(*attr->attrValue[dex],
					kSecAsn1BMPStringTemplate, &ustr)) {
				printf("***Error decoding BMP string\n");
				continue;
			}
			printDataAsUnichars(ustr);
		}
		else if(nssCompareCssmData(&attr->attrType, 
					&CSSMOID_PKCS9_LocalKeyId)) {
			/* Octet string */
			CSSM_DATA ostr;
			if(pinfo.mCoder.decodeItem(*attr->attrValue[dex],
					kSecAsn1ObjectIDTemplate, &ostr)) {
				printf("***Error decoding LocalKeyId string\n");
				continue;
			}
			printDataAsHex(&ostr, 16);
		}
		else {
			printDataAsHex(attr->attrValue[dex], 8);
		}
	}
	return 0;
}
/*
 * Parse an CSSM_X509_ALGORITHM_IDENTIFIER specific to P12.
 * Decode the alg params as a NSS_P12_PBE_Params and parse and 
 * return the result if the pbeParams is non-NULL.
 */
static int p12AlgIdParse(
	const CSSM_X509_ALGORITHM_IDENTIFIER &algId,
	NSS_P12_PBE_Params *pbeParams,		// optional
	P12ParseInfo &pinfo,
	unsigned depth)						// print indent depth
{
	doIndent(depth);
	printf("encrAlg = %s\n", oidStr(algId.algorithm, pinfo.mParser));
	const CSSM_DATA &param = algId.parameters;
	if(pbeParams == NULL) {
		/* alg params are uninterpreted */
		doIndent(depth);
		printf("Alg Params : ");
		printDataAsHex(&param);
		return 0;
	}
	
	if(param.Length == 0) {
		printf("===warning: no alg parameters, this is not optional\n");
		return 0;
	}
	
	memset(pbeParams, 0, sizeof(*pbeParams));
	if(pinfo.mCoder.decodeItem(param, 
			NSS_P12_PBE_ParamsTemplate, pbeParams)) {
		printf("***Error decoding NSS_P12_PBE_Params\n");
		return 1;
	}
	doIndent(depth);
	printf("Salt : ");
	printDataAsHex(&pbeParams->salt);
	doIndent(depth);
	if(pbeParams->iterations.Length > 4) {
		printf("warning: iterations greater than max int\n");
		doIndent(depth);
		printf("Iterations : ");
		printDataAsHex(&pbeParams->iterations);
	}
	else {
		printf("Iterations : %u\n", 
			(unsigned)dataToInt(pbeParams->iterations));
	}
	return 0;
}
static void dumpCertID(
	SecAsn1OCSPCertID *certID,
	int indent)
{
	doIndent(indent);
	printf("algId            : ");
	printDataAsHex(&certID->algId.algorithm);
	
	doIndent(indent);
	printf("issuerNameHash   : ");
	printDataAsHex(&certID->issuerNameHash);
	
	doIndent(indent);
	printf("issuerPubKeyHash : ");
	printDataAsHex(&certID->issuerPubKeyHash);
	
	doIndent(indent);
	printf("serialNumber     : ");
	printDataAsHex(&certID->serialNumber);
}
static void printTaggedItem(
	const NSS_TaggedItem &ti)
{
	switch(ti.tag) {
		case BER_TAG_PRINTABLE_STRING:
		case BER_TAG_T61_STRING:
		case BER_TAG_IA5_STRING:
		case BER_TAG_UTC_TIME:
		case BER_TAG_GENERALIZED_TIME:
			printString(&ti.item);
			break;
		default:
			printDataAsHex(&ti.item, 0);
	}
}
Example #8
0
static void debugShowContentTypeOID(SecCmsContentInfoRef contentInfo)
{
#ifndef NDEBUG

    CSSM_OID *typeOID = SecCmsContentInfoGetContentTypeOID(contentInfo);
    if (typeOID)
    {
        CFStringRef oidCFStr = SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault, typeOID);
        char *oidstr = cfStringToChar(oidCFStr);
        printDataAsHex("oid:", typeOID, (unsigned int)typeOID->Length);
        dtprintf("\toid: %s\n", oidstr);
        if (oidCFStr)
            CFRelease(oidCFStr);
        if (oidstr)
            free(oidstr);
    }
#endif
}
/*
 * ShroudedKeyBag parser w/decrypt
 */
static int shroudedKeyBagParse(
	const NSS_P12_ShroudedKeyBag *keyBag,
	P12ParseInfo &pinfo,
	unsigned depth)
{
	const CSSM_X509_ALGORITHM_IDENTIFIER &algId = keyBag->algorithm;
	NSS_P12_PBE_Params pbep;
	if(p12AlgIdParse(algId, &pbep, pinfo, depth)) {
		return 1;
	}
	if(pinfo.mPwd.Data == NULL) {
		doIndent(depth);
		printf("=== Key not decrypted (no passphrase)===\n");
		return 0;
	}

	/*
	 * Prepare for decryption
	 */
	CSSM_ALGORITHMS		keyAlg;			// e.g., CSSM_ALGID_DES
	CSSM_ALGORITHMS		encrAlg;		// e.g., CSSM_ALGID_3DES_3KEY_EDE
	CSSM_ALGORITHMS		pbeHashAlg;		// SHA1 or MD5
	uint32				keySizeInBits;
	uint32				blockSizeInBytes;	// for IV, optional
	CSSM_PADDING		padding;		// CSSM_PADDING_PKCS7, etc.
	CSSM_ENCRYPT_MODE	mode;			// CSSM_ALGMODE_CBCPadIV8, etc.
	#if IMPORT_EXPORT_COMPLETE
	PKCS_Which			pkcs;
	
	bool found = pkcsOidToParams(&algId.algorithm,
		keyAlg, encrAlg, pbeHashAlg, keySizeInBits, blockSizeInBytes,
		padding, mode, pkcs);
	#else
	bool found = pkcsOidToParams(&algId.algorithm,
		keyAlg, encrAlg, pbeHashAlg, keySizeInBits, blockSizeInBytes,
		padding, mode);
	#endif
	
	if(!found) {
		printf("***ShroudedKeyBag encrAlg not understood\n");
		return 1;
	}

	unsigned iterCount = dataToInt(pbep.iterations);
	CSSM_DATA berPrivKey;
	
	/* decrypt, result is BER encoded private key */
	CSSM_RETURN crtn = p12Decrypt_app(pinfo.mCspHand,
		keyBag->encryptedData,
		keyAlg, encrAlg, pbeHashAlg,
		keySizeInBits, blockSizeInBytes,
		padding, mode,
		iterCount, pbep.salt,
		pinfo.mPwd,
		pinfo.mCoder, 
		berPrivKey);
	if(crtn) {
		doIndent(depth);
		printf("***Error decrypting private key\n");
		return 1;
	}

	/* decode */
	NSS_PrivateKeyInfo privKey;
	memset(&privKey, 0, sizeof(privKey));
	if(pinfo.mCoder.decodeItem(berPrivKey,
			kSecAsn1PrivateKeyInfoTemplate, &privKey)) {
		doIndent(depth);
		printf("***Error decoding decrypted private key\n");
		return 1;
	}
	
	/* 
	 * in P12 library, we'd convert the result into a CSSM_KEY
	 * or a SecItem...
	 */
	CSSM_X509_ALGORITHM_IDENTIFIER &privAlg = privKey.algorithm;
	doIndent(depth);
	printf("Priv Key Alg  : %s\n", oidStr(privAlg.algorithm, pinfo.mParser));
	doIndent(depth);
	printf("Priv Key Blob : ");
	printDataAsHex(&privKey.privateKey, 16);
	
	unsigned numAttrs = nssArraySize((const void**)privKey.attributes);
	if(numAttrs) {
		doIndent(depth+3);
		printf("numAttrs = %u\n", numAttrs);
		for(unsigned i=0; i<numAttrs; i++) {
			doIndent(depth+3);
			printf("attr[%u]:\n", i);
			attrParse(privKey.attributes[i], pinfo, depth+6);
		}
	}
	return 0;
}
static int parseOcspResp(
	CSSM_CL_HANDLE clHand, 
	unsigned char *inFile, 
	unsigned inFileLen,
	bool verbose)
{
	SecAsn1OCSPResponse topResp;
	SecAsn1CoderRef coder;
	OSStatus ortn;
	int indent = 0;
	const char *str;
	SecAsn1OCSPBasicResponse basicResp;
	unsigned numCerts = 0;
	
	SecAsn1CoderCreate(&coder);	
	memset(&topResp, 0, sizeof(topResp));
	ortn = SecAsn1Decode(coder, inFile, inFileLen, kSecAsn1OCSPResponseTemplate,
		&topResp);
	if(ortn) {
		printf("***Error decoding SecAsn1OCSPResponse\n");
		goto errOut;
	}
	printf("OCSPResponse:\n");
	indent += 2;
	doIndent(indent);
	printf("responseStatus: ");
	if(topResp.responseStatus.Length == 0) {
		printf("**MALFORMED**\n");
	}
	else {
		switch(topResp.responseStatus.Data[0]) {
			case RS_Success: str = "RS_Success"; break;
			case RS_MalformedRequest: str = "RS_MalformedRequest"; break;
			case RS_InternalError: str = "RS_InternalError"; break;
			case RS_TryLater: str = "RS_TryLater"; break;
			case RS_Unused: str = "RS_Unused"; break;
			case RS_SigRequired: str = "RS_SigRequired"; break;
			case RS_Unauthorized: str = "RS_Unauthorized"; break;
			default: str = "MALFORMED (unknown enum)\n"; break;
		}
		printf("%s (%u(d))\n", str, topResp.responseStatus.Data[0]);
	}
	doIndent(indent);
	printf("ResponseBytes: ");
	if(topResp.responseBytes == NULL) {
		printf("empty\n");
		goto errOut;
	}
	printf("\n");
	indent += 2;
	doIndent(indent);
	printf("responseType: ");
	if(appCompareCssmData(&topResp.responseBytes->responseType,
			&CSSMOID_PKIX_OCSP_BASIC)) {
		str = "ocsp-basic";
	}
	else {
		str = "Unknown type\n";
	}
	printf("%s\n", str);
		
	/* decode the BasicOCSPResponse */
	memset(&basicResp, 0, sizeof(basicResp));
	ortn = SecAsn1DecodeData(coder, &topResp.responseBytes->response,
		kSecAsn1OCSPBasicResponseTemplate, &basicResp);
	if(ortn) {
		printf("***Error decoding BasicOCSPResponse\n");
		goto errOut;
	}
	
	doIndent(indent);
	printf("BasicOCSPResponse:\n");
	indent += 2;
	doIndent(indent);
	printf("ResponseData:\n");
	parseResponseData(coder, indent + 2, basicResp.tbsResponseData);
	doIndent(indent);
	printf("sig: ");
	printDataAsHex(&basicResp.sig, 8);
	numCerts = ocspdArraySize((const void **)basicResp.certs);
	doIndent(indent);
	printf("Num Certs: %u\n", numCerts);
	
	if(verbose) {
		for(unsigned dex=0; dex<numCerts; dex++) {
			printf("+++++++++++++++++++++++++ Cert %u +++++++++++++++++++++++++\n", dex);
			printCert(basicResp.certs[dex]->Data, basicResp.certs[dex]->Length, 
				CSSM_FALSE);
			printf("+++++++++++++++++++++++ End Cert %u +++++++++++++++++++++++\n", dex);
		}
	}
	indent -= 2;		// end of BasicOCSPResponse
	indent -= 2;		// end of ResponseBytes
	indent -= 2;		// end of OCSPResponse
errOut:
	SecAsn1CoderRelease(coder);
	return ortn;
}
/* decode and parse tbsResponseData, sitting in SecAsn1OCSPBasicResponse as an 
 * ASN_ANY */
static int 	parseResponseData(
	SecAsn1CoderRef coder,
	int indent, 
	const CSSM_DATA &tbsResponseData)
{
	SecAsn1OCSPResponseData	respData;
	SecAsn1OCSPResponderID responderID;
	uint8 tag;
	const SecAsn1Template *templ;
	unsigned numExts;
	
	memset(&respData, 0, sizeof(respData));
	OSStatus ortn = SecAsn1DecodeData(coder, &tbsResponseData,
		kSecAsn1OCSPResponseDataTemplate, &respData);
	if(ortn) {
		printf("***Error decoding ResponseData\n");
		return 1;
	}
	if(respData.version && respData.version->Data) {
		doIndent(indent);
		printf("version: %u\n", respData.version->Data[0]);
	}
	doIndent(indent);
	printf("ResponderID:\n");
	indent += 2;
	memset(&responderID, 0, sizeof(responderID));
	if(respData.responderID.Data == NULL) {
		doIndent(indent);
		printf("***Malformed(empty)***\n");
		return 1;
	}
	
	/* lame-o choice processing */
	tag = respData.responderID.Data[0] & SEC_ASN1_TAGNUM_MASK;
	switch(tag) {
		case RIT_Name: 
			templ = kSecAsn1OCSPResponderIDAsNameTemplate; 
			break;
		case RIT_Key: 
			templ = kSecAsn1OCSPResponderIDAsKeyTemplate; 
			break;
		default:
			doIndent(indent);
			printf("**Unknown tag for ResponderID (%u)\n", tag);
			return 1;
	}
	ortn = SecAsn1DecodeData(coder, &respData.responderID, templ, &responderID);
	if(ortn) {
		doIndent(indent);
		printf("***Error decoding ResponderID\n");
		return 1;
	}
	doIndent(indent);
	switch(tag) {
		case RIT_Name:
			printf("byName:\n");
			printName((NSS_Name &)responderID.byName, indent + 2);
			break;
		case RIT_Key:
			printf("byKey : ");
			printDataAsHex(&responderID.byKey);
			break;
	}
	indent -= 2;		// end of ResponderID
	
	doIndent(indent);
	printf("producedAt: ");
	printString(&respData.producedAt);
	unsigned numResps = ocspdArraySize((const void **)respData.responses);
	doIndent(indent);
	printf("Num responses: %u\n", numResps);
	for(unsigned dex=0; dex<numResps; dex++) {
		SecAsn1OCSPSingleResponse *resp = respData.responses[dex];
		doIndent(indent);
		printf("Response %u:\n", dex);
		indent += 2;
		doIndent(indent);
		printf("CertID:\n");
		dumpCertID(&resp->certID, indent + 2);
		
		doIndent(indent);
		printf("certStatus: ");
		/* lame-o choice processing */
		tag = resp->certStatus.Data[0] & SEC_ASN1_TAGNUM_MASK;
		switch(tag) {
			case CS_Good:
				printf("Good\n");
				break;
			case CS_Unknown:
				printf("Unknown\n");
				break;
			default:
				printf("**MALFORMED cert status tag (%u)\n", tag);
				break;
			case CS_Revoked:
			{
				printf("Revoked\n");
				doIndent(indent);
				SecAsn1OCSPCertStatus certStatus;
				memset(&certStatus, 0, sizeof(certStatus));
				ortn = SecAsn1DecodeData(coder, &resp->certStatus, 
					kSecAsn1OCSPCertStatusRevokedTemplate, &certStatus);
				if(ortn) {
					doIndent(indent);
					printf("***error parsing RevokedInfo\n");
					break;
				}
				if(certStatus.revokedInfo == NULL) {
					doIndent(indent);
					printf("***GAK! Malformed (empty) revokedInfo\n");break;
				}
				printf("RevokedIndfo:\n");
				indent += 2;
				doIndent(indent);
				printf("revocationTime: ");
				printString(&certStatus.revokedInfo->revocationTime);
				if(certStatus.revokedInfo->revocationReason) {
					doIndent(indent);
					printf("reason: %u\n", 
						certStatus.revokedInfo->revocationReason->Data[0]);
				}
				indent -= 2;		// end of RevokedInfo
				break;
			}
		}	/* switch cert status tag */
		
		doIndent(indent);
		printf("thisUpdate: ");
		printString(&resp->thisUpdate);
		
		if(resp->nextUpdate) {
			doIndent(indent);
			printf("nextUpdate: ");
			printString(resp->nextUpdate);
		}

		numExts = ocspdArraySize((const void **)resp->singleExtensions);
		for(unsigned extDex=0; extDex<numExts; extDex++) {
			doIndent(indent);
			printf("singleExtensions[%u]\n", extDex);
			printOcspExt(coder, resp->singleExtensions[extDex], indent + 2);
		}
		
		indent -= 2;		// end of resp[dex]
	}
	
	numExts = ocspdArraySize((const void **)respData.responseExtensions);
	for(unsigned extDex=0; extDex<numExts; extDex++) {
		doIndent(indent);
		printf("responseExtensions[%u]\n", extDex);
		printOcspExt(coder, respData.responseExtensions[extDex], indent + 2);
	}
	return 0;
}
static int parseOcspReq(
	CSSM_CL_HANDLE clHand, 
	unsigned char *inFile, 
	unsigned inFileLen,
	bool verbose)
{
	SecAsn1CoderRef coder;
	SecAsn1OCSPSignedRequest signedReq;
	SecAsn1OCSPTbsRequest &tbs = signedReq.tbsRequest;
	OSStatus ortn;
	int indent;
	unsigned numExts;
	unsigned numReqs;
	
	SecAsn1CoderCreate(&coder);
	memset(&signedReq, 0, sizeof(signedReq));
	
	ortn = SecAsn1Decode(coder, inFile, inFileLen, kSecAsn1OCSPSignedRequestTemplate,
		&signedReq);
	if(ortn) {
		printf("***Error decoding SecAsn1OCSPSignedRequest\n");
		goto errOut;
	}
	printf("SecAsn1OCSPSignedRequest:\n");
	
	printf("SecAsn1OCSPTbsRequest:\n");
	indent = 2;
	if(tbs.version) {
		doIndent(indent);
		printf("Version : ");
		printDataAsHex(tbs.version);
	}
	if(tbs.requestorName) {
		doIndent(indent);
		printf("NSS_GeneralName found; print it later maybe\n");
	}
	numReqs = ocspdArraySize((const void **)tbs.requestList);
	for(unsigned dex=0; dex<numReqs; dex++) {
		SecAsn1OCSPRequest *req = tbs.requestList[dex];
		doIndent(indent);
		printf("Request List Entry %u\n", dex);
		indent += 2;
		doIndent(indent);
		printf("CertID:\n");
		indent += 2;
		SecAsn1OCSPCertID *certID = &req->reqCert;
		dumpCertID(certID, indent);
		indent -= 2;
		numExts = ocspdArraySize((const void **)req->extensions);
		for(unsigned extDex=0; extDex<numExts; extDex++) {
			doIndent(indent);
			printf("singleExtension[%u]\n", extDex);
			printOcspExt(coder, req->extensions[dex], indent + 2);
		}
		indent -= 2;
	}

	numExts = ocspdArraySize((const void **)tbs.requestExtensions);
	for(unsigned extDex=0; extDex<numExts; extDex++) {
		doIndent(indent);
		printf("requestExtension[%u]\n", extDex);
		printOcspExt(coder, tbs.requestExtensions[extDex], indent + 2);
	}

	indent -= 2;
	
	if(signedReq.signature) {
		printf("SecAsn1OCSPSignature:\n");
		indent += 2;
		doIndent(indent);
		printf("==unparsed for now ==\n");
		/* ... */
		indent -= 2;
	}
errOut:
	SecAsn1CoderRelease(coder);
	return ortn;
}
static void printOcspExt(
	SecAsn1CoderRef coder,
	NSS_CertExtension *nssExt, 
	int indent)
{
	OCSPExtension *ocspExt = NULL;
	try {
		ocspExt = OCSPExtension::createFromNSS(coder, *nssExt);
	}
	catch(...) {
		doIndent(indent);
		printf("***Error thrown parsing extension\n");
		return;
	}
	switch(ocspExt->tag()) {
		case OET_Unknown: 
			doIndent(indent);
			printf("Extension type: Unknown\n");
			printCritical(indent, ocspExt);
			return;
		case OET_Nonce: 
		{
			doIndent(indent);
			printf("Extension type     : Nonce\n");
			printCritical(indent, ocspExt);
			doIndent(indent);
			OCSPNonce *nonce = dynamic_cast<OCSPNonce *>(ocspExt);
			if(nonce == NULL) {
				printf("***dynamic_cast failure in OCSPNonce!\n");
				return;
			}
			printf("nonce value        : ");
			printDataAsHex(&nonce->nonce());
			break;
		}
		case OET_CrlReference: 
			doIndent(indent);
			printf("Extension type     : CrlReference");
			printCritical(indent, ocspExt);
			/* TBD */
			return;
		case OET_AcceptResponse: 
			doIndent(indent);
			printf("Extension type     : AcceptResponse");
			printCritical(indent, ocspExt);
			/* TBD */
			return;
		case OET_ArchiveCutoff:
			doIndent(indent);
			printf("Extension type     : ArchiveCutoff");
			printCritical(indent, ocspExt);
			/* TBD */
			return;
		case OET_ServiceLocator:
			doIndent(indent);
			printf("Extension type     : ServiceLocator");
			printCritical(indent, ocspExt);
			/* TBD */
			return;
		default:
			/* this code is out of sync with ocspExtensions.{h,cpp} */
			doIndent(indent);
			printf("Extension type     : unrecognized - code sync error");
			printCritical(indent, ocspExt);
			return;
			
	}
}