--- /dev/null
+/*
+ * Copyright (c) 2000-2001 Apple Computer, 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.
+ *
+ * Created 9/1/2000 by Doug Mitchell.
+ * Copyright (c) 2000 by Apple Computer.
+ */
+
+#include "DecodedCert.h"
+#include "cldebugging.h"
+#include "CLCertExtensions.h"
+#include "clNssUtils.h"
+#include "clNameUtils.h"
+#include "CLFieldsCommon.h"
+#include <Security/oidscert.h>
+#include <Security/x509defs.h>
+#include <security_utilities/utilities.h>
+
+/***
+ *** 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<const DecodedCert &>(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<DecodedCert &>(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<const DecodedCert &>(item);
+ tbsGetCheck(cert.certificateToSign->version, index);
+}
+static void setField_Version (
+ DecodedItem &item,
+ const CssmData &fieldValue)
+{
+ DecodedCert &cert = dynamic_cast<DecodedCert &>(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<const DecodedCert &>(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<DecodedCert &>(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<const DecodedCert &>(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<DecodedCert &>(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<const DecodedCert &>(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<DecodedCert &>(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<const DecodedCert &>(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<const DecodedCert &>(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<const DecodedCert &>(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<const DecodedCert &>(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<const DecodedCert &>(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<DecodedCert &>(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<const DecodedCert &>(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<const DecodedCert &>(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<DecodedCert &>(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<const DecodedCert &>(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<DecodedCert &>(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<const DecodedCert &>(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<DecodedCert &>(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<const DecodedCert &>(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<DecodedCert &>(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<const DecodedCert &>(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<DecodedCert &>(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<const DecodedCert &>(item);
+ if(!tbsGetCheck(cert.mCert.tbs.subjectPublicKeyInfo.subjectPublicKey.Data,
+ index)) {
+ return false;
+ }
+ CSSM_KEY_PTR cssmKey = cert.extractCSSMKey(fieldValue.allocator);
+ fieldValue.set(reinterpret_cast<uint8 *>(cssmKey), sizeof(CSSM_KEY));
+ numFields = 1;
+ return true;
+}
+
+static void setField_PublicKeyStruct (
+ DecodedItem &item,
+ const CssmData &fieldValue)
+{
+ DecodedCert &cert = dynamic_cast<DecodedCert &>(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<const DecodedCert &>(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; i<NUM_KNOWN_FIELDS; i++) {
+ if(fieldId == CssmData::overlay(*fieldTable->fieldId)) {
+ return fieldTable;
+ }
+ fieldTable++;
+ }
+ 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; currOidDex<NUM_KNOWN_FIELDS; currOidDex++) {
+ const oidToFieldFuncs *fieldFuncs = &fieldFuncTable[currOidDex];
+ currOid = fieldFuncs->fieldId;
+ 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; fieldDex<numFields; fieldDex++) {
+ /* note this should always succeed */
+ bool brtn = fieldFuncs->getFcn(*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<NUM_KNOWN_FIELDS; i++) {
+ CssmAutoData oidCopy(alloc, *fieldFuncTable[i].fieldId);
+ oidList[i] = oidCopy.release();
+ }
+ NumberOfFields = NUM_KNOWN_FIELDS;
+ OidList = oidList;
+}