X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/Security/libsecurity_cdsa_utils/lib/cuPrintCert.cpp diff --git a/Security/libsecurity_cdsa_utils/lib/cuPrintCert.cpp b/Security/libsecurity_cdsa_utils/lib/cuPrintCert.cpp new file mode 100644 index 00000000..5f0281ba --- /dev/null +++ b/Security/libsecurity_cdsa_utils/lib/cuPrintCert.cpp @@ -0,0 +1,1504 @@ +/* + * Copyright (c) 2002,2011-2012,2014 Apple Inc. All Rights Reserved. + * + * The contents of this file constitute Original Code as defined in and are + * subject to the Apple Public Source License Version 1.2 (the 'License'). + * You may not use this file except in compliance with the License. Please obtain + * a copy of the License at http://www.apple.com/publicsource and read it before + * using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS + * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT + * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the + * specific language governing rights and limitations under the License. + */ + +/* + * cuPrintCert.cpp - Parse a cert or CRL, dump contents. + */ +#include "cuCdsaUtils.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cuPrintCert.h" +#include "cuOidParser.h" +#include "cuTimeStr.h" +#include +#include +#include + +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; + + /* ignore cssmTime->timeType for now */ + 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) +{ + /* ignore cssmTime->timeType for now */ + printTimeStr(&cssmTime->time); +} + +static void printDataAsHex( + const CSSM_DATA *d, + unsigned maxToPrint = 0) // optional, 0 means print it all +{ + 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; iLength + * Tag is implied + */ +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); +} + +/* + * Used to print generic blobs which we don't really understand. + * The bytesToPrint argument is usually thing->Length; it's here because snacc + * peports lengths of bit strings in BITS. Caller knows this and + * modifies bytesToPrint accordingly. In any case, bytesToPrint is the + * max number of valid bytes in *thing->Data. + */ +#define BLOB_LENGTH_PRINT 3 + +static void printBlobBytes( + const char *blobType, + const char *quanta, // e.g., "bytes', "bits" + 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; dexData[dex]); + if(dex == (toPrint - 1)) { + break; + } + } + if(dex < bytesToPrint) { + printf(" ...\n"); + } + else { + printf("\n"); + } +} + +/* + * Print an IA5String or Printable string. Null terminator is not assumed. + * Trailing newline is printed. + */ +static void printString( + const CSSM_DATA *str) +{ + unsigned i; + char *cp = (char *)str->Data; + for(i=0; iLength; 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: // mostly printable.... + 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; + + } +} + +/* compare two OIDs, return CSSM_TRUE if identical */ +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; + } +} + +/* + * Following a CSSMOID_ECDSA_WithSpecified algorithm is another encoded + * CSSM_X509_ALGORITHM_IDENTIFIER containing the digest algorithm OID. + * Decode and print the OID. + */ +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)) { + /* + * An OID accompanying an ECDSA public key. The OID is an ECDSA curve. + * Do a quickie DER-decode of the OID - it's here in encoded form + * because this field is an ASN_ANY - and print the resulting OID. + */ + CSSM_OID curveOid = {sigAlg->parameters.Length-2, sigAlg->parameters.Data+2}; + printOid(parser, &curveOid); + } + else if(compareOids(&sigAlg->algorithm, &CSSMOID_ECDSA_WithSpecified)) { + /* + * The accompanying params specify the digest algorithm. + */ + printECDSA_SigAlgParams(&sigAlg->parameters, parser); + } + else { + /* All others - ASN_ANY - punt */ + 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; pairDexnumberOfPairs; 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)) { + /* deprecated, used by Thawte */ + 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); + } /* for each type/value pair */ +} + +static CSSM_RETURN printName( + const CSSM_X509_NAME *x509Name, + OidParser &parser) +{ + CSSM_X509_RDN_PTR rdnp; + unsigned rdnDex; + + for(rdnDex=0; rdnDexnumberOfRDNs; 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"); + +} + +/* + * Print contents of a CE_GeneralName as best we can. + */ +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; iname.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: + /* ORAddress, a very complicated struct - punt */ + printf(" X400Address : "); + printBlobBytes("Sequence", "bytes", (uint32)name->name.Length, &name->name); + break; + case GNT_DirectoryName: + if(!name->berEncoded) { + /* CL parsed it for us into an CSSM_X509_NAME */ + 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 { + /* encoded Name (i.e. CSSM_X509_NAME) */ + printf(" Dir Name : "); + printBlobBytes("Byte string", "bytes", + (uint32)name->name.Length, &name->name); + } + break; + case GNT_EdiPartyName: + /* sequence 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; + } + } +} + + +/* + * Print contents of a CE_GeneralNames as best we can. + */ +static void printGeneralNames( + const CE_GeneralNames *generalNames, + OidParser &parser) +{ + unsigned i; + CE_GeneralName *name; + + for(i=0; inumNames; 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"); + } + + /* currently (since Radar 3593624), these are both always valid */ + #if 0 + /* this prevents printing pre-encoded extensions in clxutils/extenTest */ + if((cssmExt->BERvalue.Data == NULL) || + (cssmExt->value.parsedValue == NULL)) { /* actually, one of three variants */ + 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: + /* unsupported */ + 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; oidDexnumPurposes; 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) { + /* FIXME - parse */ + 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; dexnumDistPoints; dex++) { + printf(" Dist pt %d :\n", dex); + printDistPoint(&dps->distPoints[dex], parser); + } +} + +static void printValueOrNotPresent( + CSSM_BOOL present, + CSSM_BOOL value) +{ + if(!present) { + printf("\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; polDexnumPolicies; polDex++) { + CE_PolicyInformation *cPolInfo = &cdsaObj->policies[polDex]; + printf(" Policy %2d : ID ", polDex); + printOid(parser, &cPolInfo->certPolicyId); + for(unsigned qualDex=0; qualDexnumPolicyQualifiers; 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; dexnumAccessDescriptions; 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; dexnumQCStatements; 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); + } + } +} + +/* print one field */ +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) { + /* normally skip, it's the same as TBS sig alg */ + 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 { + /* should never happen - we're out of sync with the CL */ + 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 { + /* should never happen - we're out of sync with the CL */ + 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("\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; inumberOfRevokedCertEntries; 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; dexextensions[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; inumberOfExtensions; 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); + } +} + + +/* connect to CSSM/CL lazily, once */ +static CSSM_CL_HANDLE clHand = 0; + +int printCert( + const unsigned char *certData, + unsigned certLen, + CSSM_BOOL verbose) +{ + CSSM_FIELD_PTR fieldPtr; // mallocd by CL + 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; iData == 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); + } +}