X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/Security/libsecurity_apple_x509_cl/lib/CertFields.cpp diff --git a/Security/libsecurity_apple_x509_cl/lib/CertFields.cpp b/Security/libsecurity_apple_x509_cl/lib/CertFields.cpp new file mode 100644 index 00000000..1ba276eb --- /dev/null +++ b/Security/libsecurity_apple_x509_cl/lib/CertFields.cpp @@ -0,0 +1,863 @@ +/* + * Copyright (c) 2000-2001,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. + */ + + +/* + * CertFields.cpp - convert between NSS-based Certificate components and CDSA-style + * fields. A major component of DecodedCert. + * + * Copyright (c) 2000,2011-2012,2014 Apple Inc. + */ + +#include "DecodedCert.h" +#include "cldebugging.h" +#include "CLCertExtensions.h" +#include "clNssUtils.h" +#include "clNameUtils.h" +#include "CLFieldsCommon.h" +#include +#include +#include + +/*** + *** Version + *** Format = DER-encoded int (max of four bytes in this case) + ***/ +static bool getField_Version ( + DecodedItem &item, + unsigned index, // which occurrence (0 = first) + uint32 &numFields, // RETURNED + CssmOwnedData &fieldValue) // RETURNED +{ + const DecodedCert &cert = dynamic_cast(item); + const CSSM_DATA &vers = cert.mCert.tbs.version; + if(!tbsGetCheck(vers.Data, index)) { + /* not present, optional */ + return false; + } + fieldValue.copy(vers.Data, vers.Length); + numFields = 1; + return true; +} + +static void setField_Version ( + DecodedItem &item, + const CssmData &fieldValue) +{ + DecodedCert &cert = dynamic_cast(item); + CSSM_DATA &vers = cert.mCert.tbs.version; + tbsSetCheck(vers.Data, fieldValue, 0, "version"); + cert.coder().allocCopyItem(fieldValue, vers); +} + + +#if this_is_a_template +/*** + *** Version + *** Format = DER-encoded int (always four bytes in this case) + ***/ +static bool getField_Version ( + DecodedItem &item, + unsigned index, // which occurrence (0 = first) + uint32 &numFields, // RETURNED + CssmOwnedData &fieldValue) // RETURNED +{ + const DecodedCert &cert = dynamic_cast(item); + tbsGetCheck(cert.certificateToSign->version, index); +} +static void setField_Version ( + DecodedItem &item, + const CssmData &fieldValue) +{ + DecodedCert &cert = dynamic_cast(item); + tbsSetCheck(cert.certificateToSign->version, fieldValue, sizeof(uint32), + "version"); + +} +static void freeField_Version ( + CssmOwnedData &fieldValue) +{ +} +#endif + +/*** + *** Serial Number + *** Format = DER-encoded int, variable length + ***/ +static bool getField_SerialNumber ( + DecodedItem &item, + unsigned index, // which occurrence (0 = first) + uint32 &numFields, // RETURNED + CssmOwnedData &fieldValue) // RETURNED +{ + const DecodedCert &cert = dynamic_cast(item); + const CSSM_DATA &sn = cert.mCert.tbs.serialNumber; + if(!tbsGetCheck(sn.Data, index)) { + return false; + } + fieldValue.copy(sn.Data, sn.Length); + numFields = 1; + return true; +} + +static void setField_SerialNumber ( + DecodedItem &item, + const CssmData &fieldValue) +{ + DecodedCert &cert = dynamic_cast(item); + CSSM_DATA &sn = cert.mCert.tbs.serialNumber; + tbsSetCheck(sn.Data, fieldValue, 0, "SerialNumber"); + cert.coder().allocCopyItem(fieldValue, sn); +} + +/*** issuer/subject + *** Format = CSSM_X509_NAME + *** class Name from sm_x501if + ***/ +static bool getField_Issuer ( + DecodedItem &item, + unsigned index, // which occurrence (0 = first) + uint32 &numFields, // RETURNED + CssmOwnedData &fieldValue) // RETURNED +{ + if(index != 0) { + return false; + } + + bool brtn; + + const DecodedCert &cert = dynamic_cast(item); + try { + brtn = getField_RDN_NSS(cert.mCert.tbs.issuer, fieldValue); + if(brtn) { + numFields = 1; + } + } + catch (...) { + freeField_RDN(fieldValue); + throw; + } + return brtn; +} + +static void setField_Issuer ( + DecodedItem &item, + const CssmData &fieldValue) +{ + DecodedCert &cert = dynamic_cast(item); + const CSSM_X509_NAME *cssmName = (const CSSM_X509_NAME *)fieldValue.Data; + NSS_Name &nssName = cert.mCert.tbs.issuer; + tbsSetCheck(nssName.rdns, fieldValue, sizeof(CSSM_X509_NAME), + "IssuerName"); + CL_cssmNameToNss(*cssmName, nssName, cert.coder()); +} + +/*** subject ***/ +static bool getField_Subject ( + DecodedItem &item, + unsigned index, // which occurrence (0 = first) + uint32 &numFields, // RETURNED + CssmOwnedData &fieldValue) // RETURNED +{ + if(index != 0) { + return false; + } + + bool brtn; + + const DecodedCert &cert = dynamic_cast(item); + try { + brtn = getField_RDN_NSS(cert.mCert.tbs.subject, fieldValue); + if(brtn) { + numFields = 1; + } + } + catch (...) { + freeField_RDN(fieldValue); + throw; + } + return brtn; +} + +static void setField_Subject ( + DecodedItem &item, + const CssmData &fieldValue) +{ + DecodedCert &cert = dynamic_cast(item); + const CSSM_X509_NAME *cssmName = (const CSSM_X509_NAME *)fieldValue.Data; + NSS_Name &nssName = cert.mCert.tbs.subject; + tbsSetCheck(nssName.rdns, fieldValue, sizeof(CSSM_X509_NAME), + "SubjectName"); + CL_cssmNameToNss(*cssmName, nssName, cert.coder()); +} + +/*** + *** Issuer Name, Subject Name (normalized and encoded version) + *** Format = CSSM_DATA containing the DER encoding of the normalized name + ***/ +static bool getFieldSubjectNorm( + DecodedItem &item, + unsigned index, // which occurrence (0 = first) + uint32 &numFields, // RETURNED + CssmOwnedData &fieldValue) // RETURNED +{ + if(index != 0) { + return false; + } + const DecodedCert &cert = dynamic_cast(item); + return getField_normRDN_NSS(cert.mCert.tbs.derSubject, numFields, + fieldValue); +} + +static bool getFieldIssuerNorm( + DecodedItem &item, + unsigned index, // which occurrence (0 = first) + uint32 &numFields, // RETURNED + CssmOwnedData &fieldValue) // RETURNED +{ + if(index != 0) { + return false; + } + const DecodedCert &cert = dynamic_cast(item); + return getField_normRDN_NSS(cert.mCert.tbs.derIssuer, numFields, fieldValue); +} + +/*** + *** Issuer Name, Subject Name (encoded, NON-normalized version) + *** Format = CSSM_DATA containing the DER encoding of the name + ***/ +static bool getFieldSubjectStd( + DecodedItem &item, + unsigned index, // which occurrence (0 = first) + uint32 &numFields, // RETURNED + CssmOwnedData &fieldValue) // RETURNED +{ + if(index != 0) { + return false; + } + const DecodedCert &cert = dynamic_cast(item); + fieldValue.copy(cert.mCert.tbs.derSubject); + numFields = 1; + return true; +} + +static bool getFieldIssuerStd( + DecodedItem &item, + unsigned index, // which occurrence (0 = first) + uint32 &numFields, // RETURNED + CssmOwnedData &fieldValue) // RETURNED +{ + if(index != 0) { + return false; + } + const DecodedCert &cert = dynamic_cast(item); + fieldValue.copy(cert.mCert.tbs.derIssuer); + numFields = 1; + return true; +} + +/*** + *** TBS AlgId, Signature AlgId + *** Format = CSSM_X509_ALGORITHM_IDENTIFIER + ***/ +/* TBS AlgId */ +static bool getField_TbsAlgId ( + DecodedItem &item, + unsigned index, // which occurrence (0 = first) + uint32 &numFields, // RETURNED + CssmOwnedData &fieldValue) // RETURNED +{ + const DecodedCert &cert = dynamic_cast(item); + const CSSM_X509_ALGORITHM_IDENTIFIER &srcAlgId = cert.mCert.tbs.signature; + if(!tbsGetCheck(srcAlgId.algorithm.Data, index)) { + return false; + } + getField_AlgIdNSS(srcAlgId, fieldValue); + numFields = 1; + return true; +} + +static void setField_TbsAlgId ( + DecodedItem &item, + const CssmData &fieldValue) +{ + DecodedCert &cert = dynamic_cast(item); + CSSM_X509_ALGORITHM_IDENTIFIER &dstAlgId = cert.mCert.tbs.signature; + tbsSetCheck(dstAlgId.algorithm.Data, fieldValue, + sizeof(CSSM_X509_ALGORITHM_IDENTIFIER), "TBS_AlgId"); + setField_AlgIdNSS(fieldValue, dstAlgId, cert.coder()); +} + +/* Cert AlgId - read only */ +static bool getField_CertAlgId ( + DecodedItem &item, + unsigned index, // which occurrence (0 = first) + uint32 &numFields, // RETURNED + CssmOwnedData &fieldValue) // RETURNED +{ + const DecodedCert &cert = dynamic_cast(item); + const CSSM_X509_ALGORITHM_IDENTIFIER &srcAlgId = cert.mCert.signatureAlgorithm; + if(!tbsGetCheck(srcAlgId.algorithm.Data, index)) { + return false; + } + getField_AlgIdNSS(srcAlgId, fieldValue); + numFields = 1; + return true; +} + +/*** + *** Validity not before, not after + *** Format: CSSM_X509_TIME + ***/ + +/*** not before ***/ +static bool getField_NotBefore ( + DecodedItem &item, + unsigned index, // which occurrence (0 = first) + uint32 &numFields, // RETURNED + CssmOwnedData &fieldValue) // RETURNED +{ + const DecodedCert &cert = dynamic_cast(item); + const NSS_Time &srcTime = cert.mCert.tbs.validity.notBefore; + return getField_TimeNSS(srcTime, index, numFields, fieldValue); +} + +static void setField_NotBefore ( + DecodedItem &item, + const CssmData &fieldValue) +{ + DecodedCert &cert = dynamic_cast(item); + NSS_Time &dstTime = cert.mCert.tbs.validity.notBefore; + tbsSetCheck(dstTime.item.Data, fieldValue, + sizeof(CSSM_X509_TIME), "NotBefore"); + setField_TimeNSS(fieldValue, dstTime, cert.coder()); +} + +/*** not after ***/ +static bool getField_NotAfter ( + DecodedItem &item, + unsigned index, // which occurrence (0 = first) + uint32 &numFields, // RETURNED + CssmOwnedData &fieldValue) // RETURNED +{ + const DecodedCert &cert = dynamic_cast(item); + const NSS_Time &srcTime = cert.mCert.tbs.validity.notAfter; + return getField_TimeNSS(srcTime, index, numFields, fieldValue); +} + +static void setField_NotAfter ( + DecodedItem &item, + const CssmData &fieldValue) +{ + DecodedCert &cert = dynamic_cast(item); + NSS_Time &dstTime = cert.mCert.tbs.validity.notAfter; + tbsSetCheck(dstTime.item.Data, fieldValue, + sizeof(CSSM_X509_TIME), "NotAfter"); + setField_TimeNSS(fieldValue, dstTime, cert.coder()); +} + +/*** + *** Subject/issuer unique ID + *** Format: Raw bytes. It's stored in the cert as an ASN bit string; the decoded + *** bytes are present at this level (i.e., not tag and length in the bytes). + *** NOTE: this is not quite accurate in that we only provide byte-aligned size, + *** not bit-aligned. This field is rarely if ever used so I think it's O, but + *** beware. + ***/ +static bool getField_SubjectUniqueId ( + DecodedItem &item, + unsigned index, // which occurrence (0 = first) + uint32 &numFields, // RETURNED + CssmOwnedData &fieldValue) // RETURNED +{ + const DecodedCert &cert = dynamic_cast(item); + const CSSM_DATA &srcBits = cert.mCert.tbs.subjectID; + if(!tbsGetCheck(srcBits.Data, index)) { + return false; + } + + /* That CSSM_DATA is a decoded BITSTRING; its length is in bits */ + CSSM_DATA tmp = srcBits; + tmp.Length = (tmp.Length + 7) / 8; + fieldValue.copy(tmp.Data, tmp.Length); + numFields = 1; + return true; +} + +static void setField_SubjectUniqueId ( + DecodedItem &item, + const CssmData &fieldValue) +{ + DecodedCert &cert = dynamic_cast(item); + CSSM_DATA &dstBits = cert.mCert.tbs.subjectID; + tbsSetCheck(dstBits.Data, fieldValue, 0, "SubjectUniqueID"); + cert.coder().allocCopyItem(fieldValue, dstBits); + dstBits.Length *= 8; +} + +static bool getField_IssuerUniqueId ( + DecodedItem &item, + unsigned index, // which occurrence (0 = first) + uint32 &numFields, // RETURNED + CssmOwnedData &fieldValue) // RETURNED +{ + const DecodedCert &cert = dynamic_cast(item); + const CSSM_DATA &srcBits = cert.mCert.tbs.issuerID; + if(!tbsGetCheck(srcBits.Data, index)) { + return false; + } + + /* That CSSM_DATA is a decoded BITSTRING; its length is in bits */ + CSSM_DATA tmp = srcBits; + tmp.Length = (tmp.Length + 7) / 8; + fieldValue.copy(tmp.Data, tmp.Length); + numFields = 1; + return true; +} + +static void setField_IssuerUniqueId ( + DecodedItem &item, + const CssmData &fieldValue) +{ + DecodedCert &cert = dynamic_cast(item); + CSSM_DATA &dstBits = cert.mCert.tbs.issuerID; + tbsSetCheck(dstBits.Data, fieldValue, 0, "IssuerUniqueID"); + cert.coder().allocCopyItem(fieldValue, dstBits); + dstBits.Length *= 8; +} + +/*** + *** Public key info + *** Format = CSSM_X509_SUBJECT_PUBLIC_KEY_INFO + ***/ +static bool getField_PublicKeyInfo ( + DecodedItem &item, + unsigned index, // which occurrence (0 = first) + uint32 &numFields, // RETURNED + CssmOwnedData &fieldValue) // RETURNED +{ + const DecodedCert &cert = dynamic_cast(item); + const CSSM_X509_SUBJECT_PUBLIC_KEY_INFO &srcInfo = + cert.mCert.tbs.subjectPublicKeyInfo; + if(!tbsGetCheck(srcInfo.subjectPublicKey.Data, index)) { + return false; + } + + Allocator &alloc = fieldValue.allocator; + fieldValue.malloc(sizeof(CSSM_X509_SUBJECT_PUBLIC_KEY_INFO)); + CSSM_X509_SUBJECT_PUBLIC_KEY_INFO *dstInfo = + (CSSM_X509_SUBJECT_PUBLIC_KEY_INFO *)fieldValue.data(); + + CL_copySubjPubKeyInfo(srcInfo, true, // length in bits here + *dstInfo, false, // length in bytes + alloc); + + numFields = 1; + return true; +} + +static void setField_PublicKeyInfo ( + DecodedItem &item, + const CssmData &fieldValue) +{ + DecodedCert &cert = dynamic_cast(item); + CSSM_X509_SUBJECT_PUBLIC_KEY_INFO &dstKeyInfo = + cert.mCert.tbs.subjectPublicKeyInfo; + tbsSetCheck(dstKeyInfo.subjectPublicKey.Data, fieldValue, + sizeof(CSSM_X509_SUBJECT_PUBLIC_KEY_INFO), "PubKeyInfo"); + + CSSM_X509_SUBJECT_PUBLIC_KEY_INFO *srcKeyInfo = + (CSSM_X509_SUBJECT_PUBLIC_KEY_INFO *)fieldValue.Data; + if((srcKeyInfo->subjectPublicKey.Data == NULL) || + (srcKeyInfo->subjectPublicKey.Length == 0)) { + CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER); + } + + ArenaAllocator arenaAlloc(cert.coder()); + CL_copySubjPubKeyInfo(*srcKeyInfo, false, // length in bytes here + dstKeyInfo, true, // length in bits + arenaAlloc); +} + +static void freeField_PublicKeyInfo ( + CssmOwnedData &fieldValue) +{ + CSSM_X509_SUBJECT_PUBLIC_KEY_INFO *cssmKeyInfo = + (CSSM_X509_SUBJECT_PUBLIC_KEY_INFO *)fieldValue.data(); + if(cssmKeyInfo == NULL) { + return; + } + Allocator &alloc = fieldValue.allocator; + CL_freeCssmAlgId(&cssmKeyInfo->algorithm, alloc); + alloc.free(cssmKeyInfo->subjectPublicKey.Data); + memset(cssmKeyInfo, 0, sizeof(CSSM_X509_SUBJECT_PUBLIC_KEY_INFO));} + +/*** + *** key info from CSSM_KEY + *** Format = CSSM_KEY + ***/ +static bool getField_PublicKeyStruct ( + DecodedItem &item, + unsigned index, // which occurrence (0 = first) + uint32 &numFields, // RETURNED + CssmOwnedData &fieldValue) // RETURNED +{ + const DecodedCert &cert = dynamic_cast(item); + if(!tbsGetCheck(cert.mCert.tbs.subjectPublicKeyInfo.subjectPublicKey.Data, + index)) { + return false; + } + CSSM_KEY_PTR cssmKey = cert.extractCSSMKey(fieldValue.allocator); + fieldValue.set(reinterpret_cast(cssmKey), sizeof(CSSM_KEY)); + numFields = 1; + return true; +} + +static void setField_PublicKeyStruct ( + DecodedItem &item, + const CssmData &fieldValue) +{ + DecodedCert &cert = dynamic_cast(item); + CSSM_X509_SUBJECT_PUBLIC_KEY_INFO &dstKeyInfo = + cert.mCert.tbs.subjectPublicKeyInfo; + tbsSetCheck(dstKeyInfo.subjectPublicKey.Data, fieldValue, + sizeof(CSSM_KEY), "PubKeyStruct"); + + CSSM_KEY_PTR cssmKey = (CSSM_KEY_PTR)fieldValue.data(); + if((cssmKey->KeyData.Data == NULL) || + (cssmKey->KeyData.Data == 0)) { + CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER); + } + CL_CSSMKeyToSubjPubKeyInfoNSS(*cssmKey, dstKeyInfo, cert.coder()); +} + +static void freeField_PublicKeyStruct ( + CssmOwnedData &fieldValue) +{ + CSSM_KEY_PTR cssmKey = (CSSM_KEY_PTR)fieldValue.data(); + CL_freeCSSMKey(cssmKey, fieldValue.allocator, false); +} + +/*** + *** Signature + *** Format = raw bytes + *** read-only + ***/ +static bool getField_Signature ( + DecodedItem &item, + unsigned index, // which occurrence (0 = first) + uint32 &numFields, // RETURNED + CssmOwnedData &fieldValue) // RETURNED +{ + const DecodedCert &cert = dynamic_cast(item); + const CSSM_DATA &sigBits = cert.mCert.signature; + if(!tbsGetCheck(sigBits.Data, index)) { + return false; + } + fieldValue.copy(sigBits.Data, (sigBits.Length + 7) / 8); + numFields = 1; + return true; +} + +/*** + *** end of field-specific triplets + ***/ + +/* + * Table to map OID to {get,set,free}field + */ +typedef struct { + const CSSM_OID *fieldId; + getItemFieldFcn *getFcn; + setItemFieldFcn *setFcn; + freeFieldFcn *freeFcn; // OPTIONAL - NULL means just free the + // top-level data +} oidToFieldFuncs; + +static const oidToFieldFuncs fieldFuncTable[] = { + { &CSSMOID_X509V1Version, + &getField_Version, &setField_Version, NULL }, + { &CSSMOID_X509V1SerialNumber, + &getField_SerialNumber, &setField_SerialNumber, NULL }, + { &CSSMOID_X509V1IssuerNameCStruct, + &getField_Issuer, &setField_Issuer, &freeField_RDN }, + { &CSSMOID_X509V1SubjectNameCStruct, + &getField_Subject, &setField_Subject, &freeField_RDN }, + { &CSSMOID_X509V1SignatureAlgorithmTBS, + &getField_TbsAlgId, &setField_TbsAlgId, &freeField_AlgId }, + { &CSSMOID_X509V1SignatureAlgorithm, + &getField_CertAlgId, &setField_ReadOnly, &freeField_AlgId }, + { &CSSMOID_X509V1ValidityNotBefore, + &getField_NotBefore, &setField_NotBefore, &freeField_Time }, + { &CSSMOID_X509V1ValidityNotAfter, + &getField_NotAfter, &setField_NotAfter, &freeField_Time }, + { &CSSMOID_X509V1CertificateIssuerUniqueId, + &getField_IssuerUniqueId, &setField_IssuerUniqueId, NULL }, + { &CSSMOID_X509V1CertificateSubjectUniqueId, + &getField_SubjectUniqueId, &setField_SubjectUniqueId, NULL }, + { &CSSMOID_X509V1SubjectPublicKeyCStruct, + &getField_PublicKeyInfo, &setField_PublicKeyInfo, &freeField_PublicKeyInfo }, + { &CSSMOID_CSSMKeyStruct, + &getField_PublicKeyStruct, &setField_PublicKeyStruct, + &freeField_PublicKeyStruct }, + { &CSSMOID_X509V1Signature, + &getField_Signature, &setField_ReadOnly, NULL }, + { &CSSMOID_X509V1IssuerName, + getFieldIssuerNorm, &setField_ReadOnly, NULL }, + { &CSSMOID_X509V1SubjectName, + getFieldSubjectNorm, &setField_ReadOnly, NULL }, + { &CSSMOID_X509V1IssuerNameStd, + getFieldIssuerStd, &setField_ReadOnly, NULL }, + { &CSSMOID_X509V1SubjectNameStd, + getFieldSubjectStd, &setField_ReadOnly, NULL }, + + /* + * Extensions, implemented in CLCertExtensions.cpp + * When adding new ones, also add to: + * -- clOidToNssInfo() in CLFieldsCommon.cpp + * -- get/set/free functions in CLCertExtensions.{cpp,h} + */ + { &CSSMOID_KeyUsage, &getFieldKeyUsage, &setFieldKeyUsage, + &freeFieldSimpleExtension }, + { &CSSMOID_BasicConstraints, &getFieldBasicConstraints, + &setFieldBasicConstraints, &freeFieldSimpleExtension }, + { &CSSMOID_ExtendedKeyUsage, &getFieldExtKeyUsage, + &setFieldExtKeyUsage, &freeFieldExtKeyUsage } , + { &CSSMOID_SubjectKeyIdentifier, &getFieldSubjectKeyId, + &setFieldSubjectKeyId, &freeFieldSubjectKeyId } , + { &CSSMOID_AuthorityKeyIdentifier, &getFieldAuthorityKeyId, + &setFieldAuthorityKeyId, &freeFieldAuthorityKeyId } , + { &CSSMOID_SubjectAltName, &getFieldSubjAltName, + &setFieldSubjIssuerAltName, &freeFieldSubjIssuerAltName } , + { &CSSMOID_IssuerAltName, &getFieldIssuerAltName, + &setFieldSubjIssuerAltName, &freeFieldSubjIssuerAltName } , + { &CSSMOID_CertificatePolicies, &getFieldCertPolicies, + &setFieldCertPolicies, &freeFieldCertPolicies } , + { &CSSMOID_NetscapeCertType, &getFieldNetscapeCertType, + &setFieldNetscapeCertType, &freeFieldSimpleExtension } , + { &CSSMOID_CrlDistributionPoints, &getFieldCrlDistPoints, + &setFieldCrlDistPoints, &freeFieldCrlDistPoints }, + { &CSSMOID_X509V3CertificateExtensionCStruct, &getFieldUnknownExt, + &setFieldUnknownExt, &freeFieldUnknownExt }, + { &CSSMOID_AuthorityInfoAccess, &getFieldAuthInfoAccess, + &setFieldAuthInfoAccess, &freeFieldInfoAccess }, + { &CSSMOID_SubjectInfoAccess, &getFieldSubjInfoAccess, + &setFieldAuthInfoAccess, &freeFieldInfoAccess }, + { &CSSMOID_QC_Statements, &getFieldQualCertStatements, + &setFieldQualCertStatements, &freeFieldQualCertStatements }, + + { &CSSMOID_NameConstraints, &getFieldNameConstraints, + &setFieldNameConstraints, &freeFieldNameConstraints }, + { &CSSMOID_PolicyMappings, &getFieldPolicyMappings, + &setFieldPolicyMappings, &freeFieldPolicyMappings }, + { &CSSMOID_PolicyConstraints, &getFieldPolicyConstraints, + &setFieldPolicyConstraints, &freeFieldPolicyConstraints }, + { &CSSMOID_InhibitAnyPolicy, &getFieldInhibitAnyPolicy, + &setFieldInhibitAnyPolicy, &freeFieldSimpleExtension }, + +}; + +#define NUM_KNOWN_FIELDS (sizeof(fieldFuncTable) / sizeof(oidToFieldFuncs)) +#define NUM_STD_CERT_FIELDS 17 /* not including extensions */ + +/* map an OID to an oidToFieldFuncs */ +static const oidToFieldFuncs *oidToFields( + const CssmOid &fieldId) +{ + const oidToFieldFuncs *fieldTable = fieldFuncTable; + for(unsigned i=0; ifieldId)) { + return fieldTable; + } + fieldTable++; + } +#ifndef NDEBUG + clErrorLog("oidToFields: unknown OID (len=%d): %s\n", + (int)fieldId.length(), fieldId.toHex().c_str()); +#endif + CssmError::throwMe(CSSMERR_CL_UNKNOWN_TAG); +} + + +/*** + *** Public functions + ***/ + +/* + * Obtain the index'th occurrence of field specified by fieldId in specified cert. + * Format of the returned field depends on fieldId. + * Returns total number of fieldId fields in the cert if index is 0. + * FieldValue assumed to be empty on entry. + * Returns true if specified field was found, else returns false. + */ +bool DecodedCert::getCertFieldData( + const CssmOid &fieldId, // which field + unsigned index, // which occurrence (0 = first) + uint32 &numFields, // RETURNED + CssmOwnedData &fieldValue) // RETURNED +{ + switch(mState) { + case IS_Empty: + case IS_Building: + clErrorLog("DecodedCert::getCertField: can't parse undecoded cert!"); + CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR); + case IS_DecodedAll: + case IS_DecodedTBS: + break; + } + const oidToFieldFuncs *fieldFuncs = oidToFields(fieldId); + return fieldFuncs->getFcn(*this, index, numFields, fieldValue); +} + +/* + * Set the field specified by fieldId in the specified Cert. + * Note no index - individual field routines either append (for extensions) + * or if field already set ::throwMe(for all others) + */ +void DecodedCert::setCertField( + const CssmOid &fieldId, // which field + const CssmData &fieldValue) +{ + switch(mState) { + case IS_Empty: // first time thru + mState = IS_Building; + break; + case IS_Building: // subsequent passes + break; + case IS_DecodedAll: + case IS_DecodedTBS: + clErrorLog("DecodedCert::setCertField: can't build on a decoded cert!"); + CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR); + } + if((fieldValue.data() == NULL) || (fieldValue.length() == 0)) { + CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER); + } + const oidToFieldFuncs *fieldFuncs = oidToFields(fieldId); + const CssmData &value = CssmData::overlay(fieldValue); + fieldFuncs->setFcn(*this, value); +} + +/* + * Free the fieldId-specific data referred to by fieldValue->Data. + */ +void DecodedCert::freeCertFieldData( + const CssmOid &fieldId, + CssmOwnedData &fieldValue) +{ + if((fieldValue.data() == NULL) || (fieldValue.length() == 0)) { + CssmError::throwMe(CSSM_ERRCODE_INVALID_FIELD_POINTER); + } + const oidToFieldFuncs *fieldFuncs = oidToFields(fieldId); + if(fieldFuncs->freeFcn != NULL) { + /* optional - simple cases handled below */ + fieldFuncs->freeFcn(fieldValue); + } + fieldValue.reset(); + fieldValue.release(); + +} + + +/* + * Common means to get all fields from a decoded cert. Used in + * CertGetAllTemplateFields and CertGetAllFields. + */ +void DecodedCert::getAllParsedCertFields( + uint32 &NumberOfFields, // RETURNED + CSSM_FIELD_PTR &CertFields) // RETURNED +{ + /* this is the max - some might be missing */ + uint32 maxFields = NUM_STD_CERT_FIELDS + mDecodedExtensions.numExtensions(); + CSSM_FIELD_PTR outFields = (CSSM_FIELD_PTR)mAlloc.malloc(maxFields * sizeof(CSSM_FIELD)); + + /* + * We'll be copying oids and values for fields we find into + * outFields; current number of valid fields found in numOutFields. + */ + memset(outFields, 0, maxFields * sizeof(CSSM_FIELD)); + uint32 numOutFields = 0; + CSSM_FIELD_PTR currOutField; + uint32 currOidDex; + const CSSM_OID *currOid; + CssmAutoData aData(mAlloc); // for malloc/copy of outgoing data + + /* query for each OID we know about */ + for(currOidDex=0; currOidDexfieldId; + uint32 numFields; // for THIS oid + + /* + * Return false if field not there, which is not an error here. + * Actual exceptions are fatal. + */ + if(!fieldFuncs->getFcn(*this, + 0, // index - looking for first one + numFields, + aData)) { + continue; + } + + /* got some data for this oid - copy it and oid to outgoing CertFields */ + assert(numOutFields < maxFields); + currOutField = &outFields[numOutFields]; + currOutField->FieldValue = aData.release(); + aData.copy(*currOid); + currOutField->FieldOid = aData.release(); + numOutFields++; + + /* if more fields are available for this OID, snag them too */ + for(uint32 fieldDex=1; fieldDexgetFcn(*this, + fieldDex, + numFields, // shouldn't change + aData); + if(!brtn) { + clErrorLog("getAllParsedCertFields: index screwup"); + CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR); + } + assert(numOutFields < maxFields); + currOutField = &outFields[numOutFields]; + currOutField->FieldValue = aData.release(); + aData.copy(*currOid); + currOutField->FieldOid = aData.release(); + numOutFields++; + } /* multiple fields for currOid */ + } /* for each known OID */ + + NumberOfFields = numOutFields; + CertFields = outFields; +} + +void +DecodedCert::describeFormat( + Allocator &alloc, + uint32 &NumberOfFields, + CSSM_OID_PTR &OidList) +{ + /* malloc in app's space, do deep copy (including ->Data) */ + CSSM_OID_PTR oidList = (CSSM_OID_PTR)alloc.malloc( + NUM_KNOWN_FIELDS * sizeof(CSSM_OID)); + memset(oidList, 0, NUM_KNOWN_FIELDS * sizeof(CSSM_OID)); + for(unsigned i=0; i