#include "cuCdsaUtils.h"
#include <stdio.h>
#include <stdlib.h>
#include <Security/oidscert.h>
#include <Security/oidscrl.h>
#include <Security/x509defs.h>
#include <Security/oidsattr.h>
#include <Security/oidsalg.h>
#include <Security/cssmapple.h>
#include <string.h>
#include "cuPrintCert.h"
#include "cuOidParser.h"
#include "cuTimeStr.h"
#include <Security/certextensions.h>
#include <Security/SecAsn1Coder.h>
#include <Security/keyTemplates.h>
static const char *months[] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
static void printTimeStr(const CSSM_DATA *cssmTime)
{
struct tm tm;
if(cuTimeStringToTm((char *)cssmTime->Data, (unsigned int)cssmTime->Length, &tm)) {
printf("***Bad time string format***\n");
return;
}
if(tm.tm_mon > 11) {
printf("***Bad time string format***\n");
return;
}
printf("%02d:%02d:%02d %s %d, %04d\n",
tm.tm_hour, tm.tm_min, tm.tm_sec,
months[tm.tm_mon], tm.tm_mday, tm.tm_year + 1900);
}
static void printTime(const CSSM_X509_TIME *cssmTime)
{
printTimeStr(&cssmTime->time);
}
static void printDataAsHex(
const CSSM_DATA *d,
unsigned maxToPrint = 0) {
unsigned i;
bool more = false;
uint32 len = (uint32)d->Length;
uint8 *cp = d->Data;
if((maxToPrint != 0) && (len > maxToPrint)) {
len = maxToPrint;
more = true;
}
for(i=0; i<len; i++) {
printf("%02X ", ((unsigned char *)cp)[i]);
}
if(more) {
printf("...\n");
}
else {
printf("\n");
}
}
static const char *tagTypeString(
CSSM_BER_TAG tagType)
{
static char unknownType[80];
switch(tagType) {
case BER_TAG_UNKNOWN:
return "BER_TAG_UNKNOWN";
case BER_TAG_BOOLEAN:
return "BER_TAG_BOOLEAN";
case BER_TAG_INTEGER:
return "BER_TAG_INTEGER";
case BER_TAG_BIT_STRING:
return "BER_TAG_BIT_STRING";
case BER_TAG_OCTET_STRING:
return "BER_TAG_OCTET_STRING";
case BER_TAG_NULL:
return "BER_TAG_NULL";
case BER_TAG_OID:
return "BER_TAG_OID";
case BER_TAG_SEQUENCE:
return "BER_TAG_SEQUENCE";
case BER_TAG_SET:
return "BER_TAG_SET";
case BER_TAG_PRINTABLE_STRING:
return "BER_TAG_PRINTABLE_STRING";
case BER_TAG_T61_STRING:
return "BER_TAG_T61_STRING";
case BER_TAG_IA5_STRING:
return "BER_TAG_IA5_STRING";
case BER_TAG_UTC_TIME:
return "BER_TAG_UTC_TIME";
case BER_TAG_GENERALIZED_TIME:
return "BER_TAG_GENERALIZED_TIME";
default:
sprintf(unknownType, "Other type (0x%x)", tagType);
return unknownType;
}
}
static void printOid(OidParser &parser, const CSSM_DATA *oid)
{
char strBuf[OID_PARSER_STRING_SIZE];
if(oid == NULL) {
printf("NULL\n");
return;
}
if((oid->Length == 0) || (oid->Data == NULL)) {
printf("EMPTY\n");
return;
}
parser.oidParse(oid->Data, (unsigned int)oid->Length, strBuf);
printf("%s\n", strBuf);
}
#define BLOB_LENGTH_PRINT 3
static void printBlobBytes(
const char *blobType,
const char *quanta, uint32 bytesToPrint,
const CSSM_DATA *thing)
{
uint32 dex;
uint32 toPrint = bytesToPrint;
if(toPrint > BLOB_LENGTH_PRINT) {
toPrint = BLOB_LENGTH_PRINT;
}
printf("%s; Length %u %s; data = ",
blobType, (unsigned)thing->Length, quanta);
for(dex=0; dex<toPrint; dex++) {
printf("0x%x ", thing->Data[dex]);
if(dex == (toPrint - 1)) {
break;
}
}
if(dex < bytesToPrint) {
printf(" ...\n");
}
else {
printf("\n");
}
}
static void printString(
const CSSM_DATA *str)
{
unsigned i;
char *cp = (char *)str->Data;
for(i=0; i<str->Length; i++) {
printf("%c", *cp++);
}
printf("\n");
}
static void printDerThing(
CSSM_BER_TAG tagType,
const CSSM_DATA *thing,
OidParser &parser)
{
switch(tagType) {
case BER_TAG_INTEGER:
printf("%d\n", cuDER_ToInt(thing));
return;
case BER_TAG_BOOLEAN:
if(thing->Length != 1) {
printf("***malformed BER_TAG_BOOLEAN: length %u data ",
(unsigned)thing->Length);
}
printf("%u\n", cuDER_ToInt(thing));
return;
case BER_TAG_PRINTABLE_STRING:
case BER_TAG_IA5_STRING:
case BER_TAG_T61_STRING:
case BER_TAG_PKIX_UTF8_STRING: printString(thing);
return;
case BER_TAG_OCTET_STRING:
printBlobBytes("Byte string", "bytes", (uint32)thing->Length, thing);
return;
case BER_TAG_BIT_STRING:
printBlobBytes("Bit string", "bits", (uint32)(thing->Length + 7) / 8, thing);
return;
case BER_TAG_SEQUENCE:
printBlobBytes("Sequence", "bytes", (uint32)thing->Length, thing);
return;
case BER_TAG_SET:
printBlobBytes("Set", "bytes", (uint32)thing->Length, thing);
return;
case BER_TAG_OID:
printf("OID = ");
printOid(parser, thing);
break;
default:
printf("not displayed (tagType = %s; length %u)\n",
tagTypeString(tagType), (unsigned)thing->Length);
break;
}
}
static CSSM_BOOL compareOids(
const CSSM_OID *oid1,
const CSSM_OID *oid2)
{
if((oid1 == NULL) || (oid2 == NULL)) {
return CSSM_FALSE;
}
if(oid1->Length != oid2->Length) {
return CSSM_FALSE;
}
if(memcmp(oid1->Data, oid2->Data, oid1->Length)) {
return CSSM_FALSE;
}
else {
return CSSM_TRUE;
}
}
static void printECDSA_SigAlgParams(
const CSSM_DATA *params,
OidParser &parser)
{
SecAsn1CoderRef coder = NULL;
if(SecAsn1CoderCreate(&coder)) {
printf("***Error in SecAsn1CoderCreate()\n");
return;
}
CSSM_X509_ALGORITHM_IDENTIFIER algParams;
memset(&algParams, 0, sizeof(algParams));
if(SecAsn1DecodeData(coder, params, kSecAsn1AlgorithmIDTemplate,
&algParams)) {
printf("***Error decoding CSSM_X509_ALGORITHM_IDENTIFIER\n");
goto errOut;
}
printOid(parser, &algParams.algorithm);
errOut:
SecAsn1CoderRelease(coder);
}
static void printSigAlg(
const CSSM_X509_ALGORITHM_IDENTIFIER *sigAlg,
OidParser &parser)
{
printOid(parser, &sigAlg->algorithm);
if(sigAlg->parameters.Data != NULL) {
printf(" alg params : ");
if(compareOids(&sigAlg->algorithm, &CSSMOID_ecPublicKey) &&
(sigAlg->parameters.Data[0] == BER_TAG_OID) &&
(sigAlg->parameters.Length > 2)) {
CSSM_OID curveOid = {sigAlg->parameters.Length-2, sigAlg->parameters.Data+2};
printOid(parser, &curveOid);
}
else if(compareOids(&sigAlg->algorithm, &CSSMOID_ECDSA_WithSpecified)) {
printECDSA_SigAlgParams(&sigAlg->parameters, parser);
}
else {
printDataAsHex(&sigAlg->parameters, 8);
}
}
}
static void printRdn(
const CSSM_X509_RDN *rdnp,
OidParser &parser)
{
CSSM_X509_TYPE_VALUE_PAIR *ptvp;
unsigned pairDex;
const char *fieldName;
for(pairDex=0; pairDex<rdnp->numberOfPairs; pairDex++) {
ptvp = &rdnp->AttributeTypeAndValue[pairDex];
if(compareOids(&ptvp->type, &CSSMOID_CountryName)) {
fieldName = "Country ";
}
else if(compareOids(&ptvp->type, &CSSMOID_OrganizationName)) {
fieldName = "Org ";
}
else if(compareOids(&ptvp->type, &CSSMOID_LocalityName)) {
fieldName = "Locality ";
}
else if(compareOids(&ptvp->type, &CSSMOID_OrganizationalUnitName)) {
fieldName = "OrgUnit ";
}
else if(compareOids(&ptvp->type, &CSSMOID_CommonName)) {
fieldName = "Common Name ";
}
else if(compareOids(&ptvp->type, &CSSMOID_Surname)) {
fieldName = "Surname ";
}
else if(compareOids(&ptvp->type, &CSSMOID_Title)) {
fieldName = "Title ";
}
else if(compareOids(&ptvp->type, &CSSMOID_Surname)) {
fieldName = "Surname ";
}
else if(compareOids(&ptvp->type, &CSSMOID_StateProvinceName)) {
fieldName = "State ";
}
else if(compareOids(&ptvp->type, &CSSMOID_CollectiveStateProvinceName)) {
fieldName = "Coll. State ";
}
else if(compareOids(&ptvp->type, &CSSMOID_EmailAddress)) {
fieldName = "Email addrs ";
}
else if(compareOids(&ptvp->type, &CSSMOID_Description)) {
fieldName = "Description ";
}
else {
fieldName = "Other name ";
}
printf(" %s : ", fieldName);
printDerThing(ptvp->valueType, &ptvp->value, parser);
}
}
static CSSM_RETURN printName(
const CSSM_X509_NAME *x509Name,
OidParser &parser)
{
CSSM_X509_RDN_PTR rdnp;
unsigned rdnDex;
for(rdnDex=0; rdnDex<x509Name->numberOfRDNs; rdnDex++) {
rdnp = &x509Name->RelativeDistinguishedName[rdnDex];
printRdn(rdnp, parser);
}
return CSSM_OK;
}
static void printKeyHeader(
const CSSM_KEYHEADER &hdr)
{
printf(" Algorithm : ");
switch(hdr.AlgorithmId) {
case CSSM_ALGID_RSA:
printf("RSA\n");
break;
case CSSM_ALGID_DSA:
printf("DSA\n");
break;
case CSSM_ALGID_FEE:
printf("FEE\n");
break;
case CSSM_ALGID_DH:
printf("Diffie-Hellman\n");
break;
case CSSM_ALGID_ECDSA:
printf("ECDSA\n");
break;
default:
printf("Unknown(%u(d), 0x%x)\n", (unsigned)hdr.AlgorithmId,
(unsigned)hdr.AlgorithmId);
}
printf(" Key Size : %u bits\n", (unsigned)hdr.LogicalKeySizeInBits);
printf(" Key Use : ");
CSSM_KEYUSE usage = hdr.KeyUsage;
if(usage & CSSM_KEYUSE_ANY) {
printf("CSSM_KEYUSE_ANY ");
}
if(usage & CSSM_KEYUSE_ENCRYPT) {
printf("CSSM_KEYUSE_ENCRYPT ");
}
if(usage & CSSM_KEYUSE_DECRYPT) {
printf("CSSM_KEYUSE_DECRYPT ");
}
if(usage & CSSM_KEYUSE_SIGN) {
printf("CSSM_KEYUSE_SIGN ");
}
if(usage & CSSM_KEYUSE_VERIFY) {
printf("CSSM_KEYUSE_VERIFY ");
}
if(usage & CSSM_KEYUSE_SIGN_RECOVER) {
printf("CSSM_KEYUSE_SIGN_RECOVER ");
}
if(usage & CSSM_KEYUSE_VERIFY_RECOVER) {
printf("CSSM_KEYUSE_VERIFY_RECOVER ");
}
if(usage & CSSM_KEYUSE_WRAP) {
printf("CSSM_KEYUSE_WRAP ");
}
if(usage & CSSM_KEYUSE_UNWRAP) {
printf("CSSM_KEYUSE_UNWRAP ");
}
if(usage & CSSM_KEYUSE_DERIVE) {
printf("CSSM_KEYUSE_DERIVE ");
}
printf("\n");
}
static void printGeneralName(
const CE_GeneralName *name,
OidParser &parser)
{
switch(name->nameType) {
case GNT_RFC822Name:
printf(" RFC822Name : ");
printString(&name->name);
break;
case GNT_DNSName:
printf(" DNSName : ");
printString(&name->name);
break;
case GNT_URI:
printf(" URI : ");
printString(&name->name);
break;
case GNT_IPAddress:
printf(" IP Address : ");
for(unsigned i=0; i<name->name.Length; i++) {
printf("%d", name->name.Data[i]);
if(i < (name->name.Length - 1)) {
printf(".");
}
}
printf("\n");
break;
case GNT_RegisteredID:
printf(" RegisteredID : ");
printOid(parser, &name->name);
break;
case GNT_X400Address:
printf(" X400Address : ");
printBlobBytes("Sequence", "bytes", (uint32)name->name.Length, &name->name);
break;
case GNT_DirectoryName:
if(!name->berEncoded) {
if(name->name.Length != sizeof(CSSM_X509_NAME)) {
printf("***MALFORMED GNT_DirectoryName\n");
break;
}
const CSSM_X509_NAME *x509Name =
(const CSSM_X509_NAME *)name->name.Data;
printf(" Dir Name :\n");
printName(x509Name, parser);
}
else {
printf(" Dir Name : ");
printBlobBytes("Byte string", "bytes",
(uint32)name->name.Length, &name->name);
}
break;
case GNT_EdiPartyName:
printf(" EdiPartyName : ");
printBlobBytes("Sequence", "bytes", (uint32)name->name.Length, &name->name);
break;
case GNT_OtherName:
{
printf(" OtherName :\n");
if(name->name.Length != sizeof(CE_OtherName)) {
printf("***Malformed CE_OtherName\n");
break;
}
CE_OtherName *other = (CE_OtherName *)name->name.Data;
printf(" typeID : ");
printOid(parser, &other->typeId);
printf(" value : ");
printDataAsHex(&other->value, 0);
break;
}
}
}
static void printGeneralNames(
const CE_GeneralNames *generalNames,
OidParser &parser)
{
unsigned i;
CE_GeneralName *name;
for(i=0; i<generalNames->numNames; i++) {
name = &generalNames->generalName[i];
printGeneralName(name, parser);
}
}
static int printCdsaExtensionCommon(
const CSSM_X509_EXTENSION *cssmExt,
OidParser &parser,
bool expectParsed,
CSSM_BOOL verbose,
bool extraIndent = false)
{
if(extraIndent) {
printf(" Extension : "); printOid(parser, &cssmExt->extnId);
printf(" Critical : %s\n", cssmExt->critical ? "TRUE" : "FALSE");
}
else {
printf("Extension struct : "); printOid(parser, &cssmExt->extnId);
printf(" Critical : %s\n", cssmExt->critical ? "TRUE" : "FALSE");
}
#if 0
if((cssmExt->BERvalue.Data == NULL) ||
(cssmExt->value.parsedValue == NULL)) {
printf("***Malformed CSSM_X509_EXTENSION (1)\n");
return 1;
}
#endif
switch(cssmExt->format) {
case CSSM_X509_DATAFORMAT_ENCODED:
if(expectParsed) {
printf("Bad CSSM_X509_EXTENSION; expected FORMAT_PARSED\n");
return 1;
}
break;
case CSSM_X509_DATAFORMAT_PARSED:
if(!expectParsed) {
printf("Bad CSSM_X509_EXTENSION; expected FORMAT_ENCODED\n");
return 1;
}
break;
case CSSM_X509_DATAFORMAT_PAIR:
printf("Bad CSSM_X509_EXTENSION format:FORMAT_PAIR\n");
return 1;
default:
printf("***Unknown CSSM_X509_EXTENSION.format\n");
return 1;
}
return 0;
}
static int printExtensionCommon(
const CSSM_DATA &value,
OidParser &parser,
CSSM_BOOL verbose,
bool expectParsed = true)
{
if(value.Length != sizeof(CSSM_X509_EXTENSION)) {
printf("***malformed CSSM_FIELD (1)\n");
return 1;
}
CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)value.Data;
return printCdsaExtensionCommon(cssmExt, parser, expectParsed, verbose);
}
static void printKeyUsage(
const CSSM_DATA &value)
{
CE_KeyUsage usage;
CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)value.Data;
usage = *((CE_KeyUsage *)cssmExt->value.parsedValue);
printf(" usage : ");
if(usage & CE_KU_DigitalSignature) {
printf("DigitalSignature ");
}
if(usage & CE_KU_NonRepudiation) {
printf("NonRepudiation ");
}
if(usage & CE_KU_KeyEncipherment) {
printf("KeyEncipherment ");
}
if(usage & CE_KU_DataEncipherment) {
printf("DataEncipherment ");
}
if(usage & CE_KU_KeyAgreement) {
printf("KeyAgreement ");
}
if(usage & CE_KU_KeyCertSign) {
printf("KeyCertSign ");
}
if(usage & CE_KU_CRLSign) {
printf("CRLSign ");
}
if(usage & CE_KU_EncipherOnly) {
printf("EncipherOnly ");
}
if(usage & CE_KU_DecipherOnly) {
printf("DecipherOnly ");
}
printf("\n");
}
static void printBasicConstraints(
const CSSM_DATA &value)
{
CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)value.Data;
CE_BasicConstraints *bc = (CE_BasicConstraints *)cssmExt->value.parsedValue;
printf(" CA : %s\n", bc->cA ? "TRUE" : "FALSE");
if(bc->pathLenConstraintPresent) {
printf(" pathLenConstr : %u\n", (unsigned)bc->pathLenConstraint);
}
}
static void printExtKeyUsage(
const CSSM_DATA &value,
OidParser &parser)
{
CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)value.Data;
CE_ExtendedKeyUsage *eku = (CE_ExtendedKeyUsage *)cssmExt->value.parsedValue;
unsigned oidDex;
for(oidDex=0; oidDex<eku->numPurposes; oidDex++) {
printf(" purpose %2d : ", oidDex);
printOid(parser, &eku->purposes[oidDex]);
}
}
static void printCssmAuthorityKeyId(
const CE_AuthorityKeyID *akid,
OidParser &parser)
{
if(akid->keyIdentifierPresent) {
printf(" Auth KeyID : ");
printDataAsHex(&akid->keyIdentifier,
8);
}
if(akid->generalNamesPresent) {
printGeneralNames(akid->generalNames, parser);
}
if(akid->serialNumberPresent) {
printf(" serialNumber : ");
printDataAsHex(&akid->serialNumber, 8);
}
}
static void printAuthorityKeyId(
const CSSM_DATA &value,
OidParser &parser)
{
CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)value.Data;
CE_AuthorityKeyID *akid = (CE_AuthorityKeyID *)cssmExt->value.parsedValue;
printCssmAuthorityKeyId(akid, parser);
}
static void printSubjectIssuerAltName(
const CSSM_DATA &value,
OidParser &parser)
{
CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)value.Data;
CE_GeneralNames *san = (CE_GeneralNames *)cssmExt->value.parsedValue;
printGeneralNames(san, parser);
}
static void printDistPointName(
const CE_DistributionPointName *dpn,
OidParser &parser)
{
switch(dpn->nameType) {
case CE_CDNT_FullName:
printGeneralNames(dpn->dpn.fullName, parser);
break;
case CE_CDNT_NameRelativeToCrlIssuer:
printRdn(dpn->dpn.rdn, parser);
break;
default:
printf("***BOGUS CE_DistributionPointName.nameType\n");
break;
}
}
static void printDistPoint(
const CE_CRLDistributionPoint *dp,
OidParser &parser)
{
if(dp->distPointName) {
printf(" Dist pt Name :\n");
printDistPointName(dp->distPointName, parser);
}
printf(" reasonsPresent : %s\n", dp->reasonsPresent ? "TRUE" : "FALSE");
if(dp->reasonsPresent) {
printf(" reasons : 0x%X\n", dp->reasons);
}
if(dp->crlIssuer) {
printf(" CRLIssuer :\n");
printGeneralNames(dp->crlIssuer, parser);
}
}
static void printDistributionPoints(
const CSSM_DATA &value,
OidParser &parser)
{
CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)value.Data;
CE_CRLDistPointsSyntax *dps = (CE_CRLDistPointsSyntax *)cssmExt->value.parsedValue;
for(unsigned dex=0; dex<dps->numDistPoints; dex++) {
printf(" Dist pt %d :\n", dex);
printDistPoint(&dps->distPoints[dex], parser);
}
}
static void printValueOrNotPresent(
CSSM_BOOL present,
CSSM_BOOL value)
{
if(!present) {
printf("<Not Present>\n");
}
else if(value) {
printf("TRUE\n");
}
else {
printf("FALSE");
}
}
static void printIssuingDistributionPoint(
const CE_IssuingDistributionPoint *idp,
OidParser &parser)
{
if(idp->distPointName) {
printf(" Dist pt :\n");
printDistPointName(idp->distPointName, parser);
}
printf(" Only user certs : ");
printValueOrNotPresent(idp->onlyUserCertsPresent, idp->onlyUserCerts);
printf(" Only CA certs : ");
printValueOrNotPresent(idp->onlyCACertsPresent, idp->onlyCACerts);
printf(" Only some reason: ");
printValueOrNotPresent(idp->onlySomeReasonsPresent, idp->onlySomeReasons);
printf(" Indirectl CRL : ");
printValueOrNotPresent(idp->indirectCrlPresent, idp->indirectCrl);
}
static void printCertPolicies(
const CSSM_DATA &value,
OidParser &parser)
{
CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)value.Data;
CE_CertPolicies *cdsaObj = (CE_CertPolicies *)cssmExt->value.parsedValue;
for(unsigned polDex=0; polDex<cdsaObj->numPolicies; polDex++) {
CE_PolicyInformation *cPolInfo = &cdsaObj->policies[polDex];
printf(" Policy %2d : ID ", polDex);
printOid(parser, &cPolInfo->certPolicyId);
for(unsigned qualDex=0; qualDex<cPolInfo->numPolicyQualifiers; qualDex++) {
CE_PolicyQualifierInfo *cQualInfo = &cPolInfo->policyQualifiers[qualDex];
printf(" Qual %2d : ID ", qualDex);
printOid(parser, &cQualInfo->policyQualifierId);
if(cuCompareCssmData(&cQualInfo->policyQualifierId,
&CSSMOID_QT_CPS)) {
printf(" CPS : ");
printString(&cQualInfo->qualifier);
}
else {
printf(" unparsed : ");
printDataAsHex(&cQualInfo->qualifier, 8);
}
}
}
}
static void printNetscapeCertType(
const CSSM_DATA &value)
{
CE_NetscapeCertType certType;
CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)value.Data;
certType = *((CE_NetscapeCertType *)cssmExt->value.parsedValue);
printf(" certType : ");
if(certType & CE_NCT_SSL_Client) {
printf("SSL_Client ");
}
if(certType & CE_NCT_SSL_Server) {
printf("SSL_Server ");
}
if(certType & CE_NCT_SMIME) {
printf("S/MIME ");
}
if(certType & CE_NCT_ObjSign) {
printf("ObjectSign ");
}
if(certType & CE_NCT_Reserved) {
printf("Reserved ");
}
if(certType & CE_NCT_SSL_CA) {
printf("SSL_CA ");
}
if(certType & CE_NCT_SMIME_CA) {
printf("SMIME_CA ");
}
if(certType & CE_NCT_ObjSignCA) {
printf("ObjSignCA ");
}
printf("\n");
}
static void printAuthorityInfoAccess(
const CSSM_DATA &value,
OidParser &parser)
{
CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)value.Data;
CE_AuthorityInfoAccess *info = (CE_AuthorityInfoAccess *)cssmExt->value.parsedValue;
printf(" numDescriptions : %lu\n", (unsigned long)info->numAccessDescriptions);
for(unsigned dex=0; dex<info->numAccessDescriptions; dex++) {
printf(" description %u : \n", dex);
printf(" accessMethod : ");
CE_AccessDescription *descr = &info->accessDescriptions[dex];
printOid(parser, &descr->accessMethod);
printGeneralName(&descr->accessLocation, parser);
}
}
static void printQualCertStatements(
const CSSM_DATA &value,
OidParser &parser)
{
CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)value.Data;
CE_QC_Statements *qcss = (CE_QC_Statements *)cssmExt->value.parsedValue;
printf(" numQCStatements : %lu\n", (unsigned long)qcss->numQCStatements);
for(unsigned dex=0; dex<qcss->numQCStatements; dex++) {
CE_QC_Statement *qcs = &qcss->qcStatements[dex];
printf(" statement %u : \n", dex);
printf(" statementId : ");
printOid(parser, &qcs->statementId);
if(qcs->semanticsInfo) {
printf(" semanticsInfo :\n");
CE_SemanticsInformation *si = qcs->semanticsInfo;
if(si->semanticsIdentifier) {
printf(" semanticsId : ");
printOid(parser, si->semanticsIdentifier);
}
if(si->nameRegistrationAuthorities) {
printf(" nameRegAuth :\n");
printGeneralNames(si->nameRegistrationAuthorities, parser);
}
}
if(qcs->otherInfo) {
printf(" otherInfo : "); printDataAsHex(qcs->otherInfo, 8);
}
}
}
void printCertField(
const CSSM_FIELD &field,
OidParser &parser,
CSSM_BOOL verbose)
{
const CSSM_DATA *thisData = &field.FieldValue;
const CSSM_OID *thisOid = &field.FieldOid;
if(cuCompareCssmData(thisOid, &CSSMOID_X509V1Version)) {
if(verbose) {
printf("Version : %u\n", cuDER_ToInt(thisData));
}
}
else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1SerialNumber)) {
printf("Serial Number : "); printDataAsHex(thisData, 0);
}
else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1IssuerNameCStruct)) {
printf("Issuer Name :\n");
CSSM_X509_NAME_PTR name = (CSSM_X509_NAME_PTR)thisData->Data;
if((name == NULL) || (thisData->Length != sizeof(CSSM_X509_NAME))) {
printf(" ***malformed CSSM_X509_NAME\n");
}
else {
printName(name, parser);
}
}
else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1SubjectNameCStruct)) {
printf("Subject Name :\n");
CSSM_X509_NAME_PTR name = (CSSM_X509_NAME_PTR)thisData->Data;
if((name == NULL) || (thisData->Length != sizeof(CSSM_X509_NAME))) {
printf(" ***malformed CSSM_X509_NAME\n");
}
else {
printName(name, parser);
}
}
else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1ValidityNotBefore)) {
CSSM_X509_TIME *cssmTime = (CSSM_X509_TIME *)thisData->Data;
if((cssmTime == NULL) || (thisData->Length != sizeof(CSSM_X509_TIME))) {
printf(" ***malformed CSSM_X509_TIME\n");
}
else if(verbose) {
printf("Not Before : "); printString(&cssmTime->time);
printf(" : ");
printTime(cssmTime);
}
else {
printf("Not Before : ");
printTime(cssmTime);
}
}
else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1ValidityNotAfter)) {
CSSM_X509_TIME *cssmTime = (CSSM_X509_TIME *)thisData->Data;
if((cssmTime == NULL) || (thisData->Length != sizeof(CSSM_X509_TIME))) {
printf(" ***malformed CSSM_X509_TIME\n");
}
else if(verbose) {
printf("Not After : "); printString(&cssmTime->time);
printf(" : ");
printTime(cssmTime);
}
else {
printf("Not After : ");
printTime(cssmTime);
}
}
else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1SignatureAlgorithmTBS)) {
if(verbose) {
printf("TBS Sig Algorithm : ");
CSSM_X509_ALGORITHM_IDENTIFIER *algId =
(CSSM_X509_ALGORITHM_IDENTIFIER *)thisData->Data;
if((algId == NULL) ||
(thisData->Length != sizeof(CSSM_X509_ALGORITHM_IDENTIFIER))) {
printf(" ***malformed CSSM_X509_ALGORITHM_IDENTIFIER\n");
}
else {
printSigAlg(algId, parser);
}
}
}
else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1SignatureAlgorithm)) {
printf("Cert Sig Algorithm : ");
CSSM_X509_ALGORITHM_IDENTIFIER *algId =
(CSSM_X509_ALGORITHM_IDENTIFIER *)thisData->Data;
if((algId == NULL) ||
(thisData->Length != sizeof(CSSM_X509_ALGORITHM_IDENTIFIER))) {
printf(" ***malformed CSSM_X509_ALGORITHM_IDENTIFIER\n");
}
else {
printSigAlg(algId, parser);
}
}
else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1CertificateIssuerUniqueId)) {
if(verbose) {
printf("Issuer UniqueId : ");
printDerThing(BER_TAG_BIT_STRING, thisData, parser);
}
}
else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1CertificateSubjectUniqueId)) {
if(verbose) {
printf("Subject UniqueId : ");
printDerThing(BER_TAG_BIT_STRING, thisData, parser);
}
}
else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1SubjectPublicKeyCStruct)) {
CSSM_X509_SUBJECT_PUBLIC_KEY_INFO *pubKeyInfo =
(CSSM_X509_SUBJECT_PUBLIC_KEY_INFO *)thisData->Data;
printf("Pub Key Algorithm : ");
if((pubKeyInfo == NULL) ||
(thisData->Length != sizeof(CSSM_X509_SUBJECT_PUBLIC_KEY_INFO))) {
printf(" ***malformed CSSM_X509_SUBJECT_PUBLIC_KEY_INFO\n");
}
else {
printSigAlg(&pubKeyInfo->algorithm, parser);
printf("Pub key Bytes : Length %u bytes : ",
(unsigned)pubKeyInfo->subjectPublicKey.Length);
printDataAsHex(&pubKeyInfo->subjectPublicKey, 8);
}
}
else if(cuCompareCssmData(thisOid, &CSSMOID_CSSMKeyStruct)) {
CSSM_KEY_PTR cssmKey = (CSSM_KEY_PTR)thisData->Data;
printf("CSSM Key :\n");
if((cssmKey == NULL) ||
(thisData->Length != sizeof(CSSM_KEY))) {
printf(" ***malformed CSSM_KEY\n");
}
else {
printKeyHeader(cssmKey->KeyHeader);
if(verbose) {
printf(" Key Blob : ");
printDataAsHex(&cssmKey->KeyData, 8);
}
}
}
else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1Signature)) {
printf("Signature : %u bytes : ", (unsigned)thisData->Length);
printDataAsHex(thisData, 8);
}
else if(cuCompareCssmData(thisOid, &CSSMOID_X509V3CertificateExtensionCStruct)) {
if(printExtensionCommon(*thisData, parser, verbose, false)) {
return;
}
CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)thisData->Data;
printf(" Unparsed data : "); printDataAsHex(&cssmExt->BERvalue, 8);
}
else if(cuCompareCssmData(thisOid, &CSSMOID_KeyUsage)) {
if(printExtensionCommon(*thisData, parser, verbose)) {
return;
}
printKeyUsage(*thisData);
}
else if(cuCompareCssmData(thisOid, &CSSMOID_BasicConstraints)) {
if(printExtensionCommon(*thisData, parser, verbose)) {
return;
}
printBasicConstraints(*thisData);
}
else if(cuCompareCssmData(thisOid, &CSSMOID_ExtendedKeyUsage)) {
if(printExtensionCommon(*thisData, parser, verbose)) {
return;
}
printExtKeyUsage(*thisData, parser);
}
else if(cuCompareCssmData(thisOid, &CSSMOID_SubjectKeyIdentifier)) {
if(printExtensionCommon(*thisData, parser, verbose)) {
return;
}
CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)thisData->Data;
CSSM_DATA_PTR cdata = (CSSM_DATA_PTR)cssmExt->value.parsedValue;
if((cdata == NULL) || (cdata->Data == NULL)) {
printf("****Malformed extension (no parsedValue)\n");
}
else {
printf(" Subject KeyID : "); printDataAsHex(cdata, 8);
}
}
else if(cuCompareCssmData(thisOid, &CSSMOID_AuthorityKeyIdentifier)) {
if(printExtensionCommon(*thisData, parser, verbose)) {
return;
}
printAuthorityKeyId(*thisData, parser);
}
else if(cuCompareCssmData(thisOid, &CSSMOID_SubjectAltName)) {
if(printExtensionCommon(*thisData, parser, verbose)) {
return;
}
printSubjectIssuerAltName(*thisData, parser);
}
else if(cuCompareCssmData(thisOid, &CSSMOID_IssuerAltName)) {
if(printExtensionCommon(*thisData, parser, verbose)) {
return;
}
printSubjectIssuerAltName(*thisData, parser);
}
else if(cuCompareCssmData(thisOid, &CSSMOID_CertificatePolicies)) {
if(printExtensionCommon(*thisData, parser, verbose)) {
return;
}
printCertPolicies(*thisData, parser);
}
else if(cuCompareCssmData(thisOid, &CSSMOID_NetscapeCertType)) {
if(printExtensionCommon(*thisData, parser, verbose)) {
return;
}
printNetscapeCertType(*thisData);
}
else if(cuCompareCssmData(thisOid, &CSSMOID_CrlDistributionPoints)) {
if(printExtensionCommon(*thisData, parser, verbose)) {
return;
}
printDistributionPoints(*thisData, parser);
}
else if(cuCompareCssmData(thisOid, &CSSMOID_AuthorityInfoAccess)) {
if(printExtensionCommon(*thisData, parser, verbose)) {
return;
}
printAuthorityInfoAccess(*thisData, parser);
}
else if(cuCompareCssmData(thisOid, &CSSMOID_SubjectInfoAccess)) {
if(printExtensionCommon(*thisData, parser, verbose)) {
return;
}
printAuthorityInfoAccess(*thisData, parser);
}
else if(cuCompareCssmData(thisOid, &CSSMOID_QC_Statements)) {
if(printExtensionCommon(*thisData, parser, verbose)) {
return;
}
printQualCertStatements(*thisData, parser);
}
else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1IssuerName)) {
if(verbose) {
printf("Normalized Issuer : ");
printDataAsHex(thisData, 8);
}
}
else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1SubjectName)) {
if(verbose) {
printf("Normalized Subject : ");
printDataAsHex(thisData, 8);
}
}
else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1IssuerNameStd)) {
if(verbose) {
printf("DER-encoded issuer : ");
printDataAsHex(thisData, 8);
}
}
else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1SubjectNameStd)) {
if(verbose) {
printf("DER-encoded subject: ");
printDataAsHex(thisData, 8);
}
}
else {
printf("Other field: : "); printOid(parser, thisOid);
}
}
static
void printCrlExten(
const CSSM_X509_EXTENSION *exten,
CSSM_BOOL verbose,
OidParser &parser)
{
const CSSM_OID *oid = &exten->extnId;
const void *thisData = exten->value.parsedValue;
if(exten->format == CSSM_X509_DATAFORMAT_ENCODED) {
if(printCdsaExtensionCommon(exten, parser, false, verbose)) {
return;
}
printf(" Unparsed data : "); printDataAsHex(&exten->BERvalue, 8);
}
else if(exten->format != CSSM_X509_DATAFORMAT_PARSED) {
printf("***Badly formatted CSSM_X509_EXTENSION\n");
return;
}
else if(cuCompareCssmData(oid, &CSSMOID_AuthorityKeyIdentifier)) {
if(printCdsaExtensionCommon(exten, parser, true, verbose)) {
return;
}
printCssmAuthorityKeyId((CE_AuthorityKeyID *)thisData, parser);
}
else if(cuCompareCssmData(oid, &CSSMOID_IssuerAltName)) {
if(printCdsaExtensionCommon(exten, parser, true, verbose)) {
return;
}
printGeneralNames((CE_GeneralNames *)thisData, parser);
}
else if(cuCompareCssmData(oid, &CSSMOID_CrlNumber)) {
if(printCdsaExtensionCommon(exten, parser, true, verbose)) {
return;
}
printf(" CRL Number : %u\n", *((unsigned *)thisData));
}
else if(cuCompareCssmData(oid, &CSSMOID_DeltaCrlIndicator)) {
if(printCdsaExtensionCommon(exten, parser, true, verbose)) {
return;
}
printf(" Delta CRL Base : %u\n", *((unsigned *)thisData));
}
else if(cuCompareCssmData(oid, &CSSMOID_IssuingDistributionPoint)) {
if(printCdsaExtensionCommon(exten, parser, true, verbose)) {
return;
}
printIssuingDistributionPoint((CE_IssuingDistributionPoint *)thisData,
parser);
}
else {
printf("UNKNOWN EXTENSION : "); printOid(parser, oid);
}
}
static
void printCrlEntryExten(
const CSSM_X509_EXTENSION *exten,
CSSM_BOOL verbose,
OidParser &parser)
{
const CSSM_OID *oid = &exten->extnId;
const void *thisData = exten->value.parsedValue;
if(exten->format == CSSM_X509_DATAFORMAT_ENCODED) {
if(printCdsaExtensionCommon(exten, parser, false, verbose, true)) {
return;
}
printf(" Unparsed data: "); printDataAsHex(&exten->BERvalue, 8);
}
else if(exten->format != CSSM_X509_DATAFORMAT_PARSED) {
printf("***Badly formatted CSSM_X509_EXTENSION\n");
return;
}
else if(cuCompareCssmData(oid, &CSSMOID_CrlReason)) {
if(printCdsaExtensionCommon(exten, parser, true, verbose, true)) {
return;
}
CE_CrlReason *cr = (CE_CrlReason *)thisData;
const char *reason = "UNKNOWN";
switch(*cr) {
case CE_CR_Unspecified:
reason = "CE_CR_Unspecified"; break;
case CE_CR_KeyCompromise:
reason = "CE_CR_KeyCompromise"; break;
case CE_CR_CACompromise:
reason = "CE_CR_CACompromise"; break;
case CE_CR_AffiliationChanged:
reason = "CE_CR_AffiliationChanged"; break;
case CE_CR_Superseded:
reason = "CE_CR_Superseded"; break;
case CE_CR_CessationOfOperation:
reason = "CE_CR_CessationOfOperation"; break;
case CE_CR_CertificateHold:
reason = "CE_CR_CertificateHold"; break;
case CE_CR_RemoveFromCRL:
reason = "CE_CR_RemoveFromCRL"; break;
default:
break;
}
printf(" CRL Reason : %s\n", reason);
}
else if(cuCompareCssmData(oid, &CSSMOID_HoldInstructionCode)) {
if(printCdsaExtensionCommon(exten, parser, true, verbose, true)) {
return;
}
printf(" Hold Instr : ");
printOid(parser, (CSSM_OID_PTR)thisData);
}
else if(cuCompareCssmData(oid, &CSSMOID_InvalidityDate)) {
if(printCdsaExtensionCommon(exten, parser, true, verbose, true)) {
return;
}
printf(" Invalid Date : ");
printTimeStr((CSSM_DATA_PTR)thisData);
}
else if(cuCompareCssmData(oid, &CSSMOID_CertIssuer)) {
if(printCdsaExtensionCommon(exten, parser, true, verbose, true)) {
return;
}
printGeneralNames((CE_GeneralNames *)thisData, parser);
}
else {
printf("UNKNOWN EXTENSION : "); printOid(parser, oid);
}
}
static
void printCrlFields(
const CSSM_X509_SIGNED_CRL *signedCrl,
CSSM_BOOL verbose,
OidParser &parser)
{
unsigned i;
const CSSM_X509_TBS_CERTLIST *tbsCrl = &signedCrl->tbsCertList;
if(tbsCrl->version.Data) {
printf("Version : %d\n", cuDER_ToInt(&tbsCrl->version));
}
printf("TBS Sig Algorithm : ");
const CSSM_X509_ALGORITHM_IDENTIFIER *algId = &tbsCrl->signature;
printSigAlg(algId, parser);
printf("Issuer Name :\n");
printName(&tbsCrl->issuer, parser);
printf("This Update : ");
printTime(&tbsCrl->thisUpdate);
printf("Next Update : ");
if(tbsCrl->nextUpdate.time.Data) {
printTime(&tbsCrl->nextUpdate);
}
else {
printf("<not present>\n");
}
CSSM_X509_REVOKED_CERT_LIST_PTR certList = tbsCrl->revokedCertificates;
if(certList) {
if(verbose) {
printf("Num Revoked Certs : %d\n",
(int)certList->numberOfRevokedCertEntries);
for(i=0; i<certList->numberOfRevokedCertEntries; i++) {
CSSM_X509_REVOKED_CERT_ENTRY_PTR entry;
entry = &certList->revokedCertEntry[i];
printf("Revoked Cert %d :\n", (int)i);
printf(" Serial number : ");
printDataAsHex(&entry->certificateSerialNumber, 0);
printf(" Revocation time : ");
printTime(&entry->revocationDate);
const CSSM_X509_EXTENSIONS *cssmExtens = &entry->extensions;
uint32 numExtens = cssmExtens->numberOfExtensions;
if(numExtens == 0) {
continue;
}
printf(" Num Extensions : %u\n", (unsigned)numExtens);
for(unsigned dex=0; dex<numExtens; dex++) {
printCrlEntryExten(&cssmExtens->extensions[dex], verbose,
parser);
}
}
}
else {
printf("Num Revoked Certs : %d (use verbose option to see)\n",
(int)certList->numberOfRevokedCertEntries);
}
}
const CSSM_X509_EXTENSIONS *crlExtens = &tbsCrl->extensions;
if(crlExtens->numberOfExtensions) {
printf("Num CRL Extensions : %d\n",
(int)crlExtens->numberOfExtensions);
for(i=0; i<crlExtens->numberOfExtensions; i++) {
printCrlExten(&crlExtens->extensions[i], verbose, parser);
}
}
const CSSM_X509_SIGNATURE *sig = &signedCrl->signature;
if(sig->encrypted.Data) {
printf("Signature : %u bytes : ", (unsigned)sig->encrypted.Length);
printDataAsHex(&sig->encrypted, 8);
}
}
static CSSM_CL_HANDLE clHand = 0;
int printCert(
const unsigned char *certData,
unsigned certLen,
CSSM_BOOL verbose)
{
CSSM_FIELD_PTR fieldPtr; uint32 i;
uint32 numFields;
OidParser parser;
CSSM_DATA cert;
if(clHand == 0) {
clHand = cuClStartup();
if(clHand == 0) {
printf("***Error connecting to CSSM cert module; aborting cert "
"display\n");
return 0;
}
}
cert.Data = (uint8 *)certData;
cert.Length = certLen;
CSSM_RETURN crtn = CSSM_CL_CertGetAllFields(clHand,
&cert,
&numFields,
&fieldPtr);
if(crtn) {
cuPrintError("CSSM_CL_CertGetAllFields", crtn);
return crtn;
}
for(i=0; i<numFields; i++) {
printCertField(fieldPtr[i], parser, verbose);
}
crtn = CSSM_CL_FreeFields(clHand, numFields, &fieldPtr);
if(crtn) {
cuPrintError("CSSM_CL_FreeFields", crtn);
return crtn;
}
return 0;
}
int printCrl(
const unsigned char *crlData,
unsigned crlLen,
CSSM_BOOL verbose)
{
CSSM_DATA_PTR value; uint32 numFields;
OidParser parser;
CSSM_DATA crl;
CSSM_HANDLE result;
if(clHand == 0) {
clHand = cuClStartup();
if(clHand == 0) {
printf("***Error connecting to CSSM cert module; aborting CRL"
"display\n");
return 0;
}
}
crl.Data = (uint8 *)crlData;
crl.Length = crlLen;
CSSM_RETURN crtn = CSSM_CL_CrlGetFirstFieldValue(clHand,
&crl,
&CSSMOID_X509V2CRLSignedCrlCStruct,
&result,
&numFields,
&value);
if(crtn) {
cuPrintError("CSSM_CL_CrlGetFirstFieldValue", crtn);
return crtn;
}
if(numFields != 1) {
printf("***CSSM_CL_CrlGetFirstFieldValue: numFields error\n");
printf(" expected 1, got %d\n", (int)numFields);
return 1;
}
crtn = CSSM_CL_CrlAbortQuery(clHand, result);
if(crtn) {
cuPrintError("CSSM_CL_CertAbortQuery", crtn);
return crtn;
}
if(value == NULL) {
printf("***CSSM_CL_CrlGetFirstFieldValue: value error (1)\n");
return 1;
}
if((value->Data == NULL) ||
(value->Length != sizeof(CSSM_X509_SIGNED_CRL))) {
printf("***CSSM_CL_CrlGetFirstFieldValue: value error (2)\n");
return 1;
}
const CSSM_X509_SIGNED_CRL *signedCrl =
(const CSSM_X509_SIGNED_CRL *)value->Data;
printCrlFields(signedCrl, verbose, parser);
crtn = CSSM_CL_FreeFieldValue(clHand,
&CSSMOID_X509V2CRLSignedCrlCStruct,
value);
if(crtn) {
cuPrintError("CSSM_CL_FreeFieldValue", crtn);
return crtn;
}
return 0;
}
void printCertShutdown()
{
if(clHand != 0) {
CSSM_ModuleDetach(clHand);
}
}