-/*
- * Copyright (c) 2002-2010 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.
- */
-
-
-/*
- * CLFieldsCommon.h - get/set/free routines common to certs and CRLs
- */
-
-#include "CLFieldsCommon.h"
-#include "clNameUtils.h"
-#include "clNssUtils.h"
-#include "AppleX509CLSession.h"
-#include <Security/cssmapple.h>
-#include <Security/oidscert.h>
-#include <Security/nameTemplates.h>
-#include <Security/certExtensionTemplates.h>
-#include <Security/SecAsn1Templates.h>
-
-/*
- * Table to map an OID to the info needed to decode the
- * associated extension
- */
-typedef struct {
- const CSSM_OID &oid;
- unsigned nssObjLen;
- const SecAsn1Template *templ;
-} NssExtenInfo;
-
-static const NssExtenInfo nssExtenInfo[] = {
- { CSSMOID_KeyUsage,
- sizeof(CSSM_DATA),
- kSecAsn1KeyUsageTemplate },
- { CSSMOID_BasicConstraints,
- sizeof(NSS_BasicConstraints),
- kSecAsn1BasicConstraintsTemplate },
- { CSSMOID_ExtendedKeyUsage,
- sizeof(NSS_ExtKeyUsage),
- kSecAsn1ExtKeyUsageTemplate },
- { CSSMOID_SubjectKeyIdentifier,
- sizeof(CSSM_DATA),
- kSecAsn1SubjectKeyIdTemplate },
- { CSSMOID_AuthorityKeyIdentifier,
- sizeof(NSS_AuthorityKeyId),
- kSecAsn1AuthorityKeyIdTemplate },
- { CSSMOID_SubjectAltName,
- sizeof(NSS_GeneralNames),
- kSecAsn1GeneralNamesTemplate },
- { CSSMOID_IssuerAltName,
- sizeof(NSS_GeneralNames),
- kSecAsn1GeneralNamesTemplate },
- { CSSMOID_CertificatePolicies,
- sizeof(NSS_CertPolicies),
- kSecAsn1CertPoliciesTemplate },
- { CSSMOID_NetscapeCertType,
- sizeof(CSSM_DATA),
- kSecAsn1NetscapeCertTypeTemplate },
- { CSSMOID_CrlDistributionPoints,
- sizeof(NSS_CRLDistributionPoints),
- kSecAsn1CRLDistributionPointsTemplate },
- { CSSMOID_CertIssuer,
- sizeof(NSS_GeneralNames),
- kSecAsn1GeneralNamesTemplate },
- { CSSMOID_AuthorityInfoAccess,
- sizeof(NSS_AuthorityInfoAccess),
- kSecAsn1AuthorityInfoAccessTemplate },
- { CSSMOID_SubjectInfoAccess,
- sizeof(NSS_AuthorityInfoAccess),
- kSecAsn1AuthorityInfoAccessTemplate },
- /* CRL extensions */
- { CSSMOID_CrlNumber,
- sizeof(CSSM_DATA),
- kSecAsn1IntegerTemplate },
- { CSSMOID_IssuingDistributionPoint,
- sizeof(NSS_IssuingDistributionPoint),
- kSecAsn1IssuingDistributionPointTemplate },
- { CSSMOID_HoldInstructionCode,
- sizeof(CSSM_OID),
- kSecAsn1ObjectIDTemplate },
- { CSSMOID_CrlReason,
- sizeof(CSSM_DATA),
- kSecAsn1EnumeratedTemplate },
- { CSSMOID_DeltaCrlIndicator,
- sizeof(CSSM_DATA),
- kSecAsn1IntegerTemplate },
- { CSSMOID_InvalidityDate,
- sizeof(CSSM_DATA),
- kSecAsn1GeneralizedTimeTemplate },
- { CSSMOID_QC_Statements,
- sizeof(NSS_QC_Statements),
- kSecAsn1QC_StatementsTemplate },
- { CSSMOID_NameConstraints,
- sizeof(NSS_NameConstraints),
- kSecAsn1NameConstraintsTemplate },
- { CSSMOID_PolicyMappings,
- sizeof(NSS_PolicyMappings),
- kSecAsn1PolicyMappingsTemplate },
- { CSSMOID_PolicyConstraints,
- sizeof(NSS_PolicyConstraints),
- kSecAsn1PolicyConstraintsTemplate },
- { CSSMOID_InhibitAnyPolicy,
- sizeof(CSSM_DATA),
- kSecAsn1IntegerTemplate },
-};
-
-#define NUM_NSS_EXTEN_INFOS (sizeof(nssExtenInfo) / sizeof(nssExtenInfo[0]))
-
-/*
- * Returns true if we find the OID.
- */
-bool clOidToNssInfo(
- const CSSM_OID &oid,
- unsigned &nssObjLen, // RETURNED
- const SecAsn1Template *&templ) // RETURNED
-{
- for(unsigned dex=0; dex<NUM_NSS_EXTEN_INFOS; dex++) {
- const NssExtenInfo &info = nssExtenInfo[dex];
- if(clCompareCssmData(&info.oid, &oid)) {
- nssObjLen = info.nssObjLen;
- templ = info.templ;
- return true;
- }
- }
- return false;
-}
-
-
-
-/*
- * Common code to pass info from a DecodedExten back to app.
- * Called from getField*().
- */
-void getFieldExtenCommon(
- void *cdsaObj, // e.g. CE_KeyUsage
- // NULL for berEncoded
- const DecodedExten &decodedExt,
- CssmOwnedData &fieldValue)
-{
- CSSM_X509_EXTENSION_PTR cssmExt;
- Allocator &alloc = fieldValue.allocator;
- CssmData &fdata = fieldValue.get();
-
- cssmExt = (CSSM_X509_EXTENSION_PTR)alloc.
- malloc(sizeof(CSSM_X509_EXTENSION));
- fdata.Data = (uint8 *)cssmExt;
- fdata.Length = sizeof(CSSM_X509_EXTENSION);
- decodedExt.convertToCdsa(cdsaObj, cssmExt, alloc);
-}
-
-/*
- * Common code for top of setField* and freeField*().
- */
-CSSM_X509_EXTENSION_PTR verifySetFreeExtension(
- const CssmData &fieldValue,
- bool berEncoded) // false: value in value.parsedValue
- // true : value in BERValue
-{
- if(fieldValue.length() != sizeof(CSSM_X509_EXTENSION)) {
- clFieldLog("Set/FreeExtension: bad length : exp %d got %d",
- (int)sizeof(CSSM_X509_EXTENSION), (int)fieldValue.length());
- CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
- }
- CSSM_X509_EXTENSION_PTR cssmExt =
- reinterpret_cast<CSSM_X509_EXTENSION_PTR>(fieldValue.data());
- if(berEncoded) {
- if(cssmExt->BERvalue.Data == NULL) {
- CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
- }
- }
- else {
- if(cssmExt->value.parsedValue == NULL) {
- CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
- }
- }
- return cssmExt;
-}
-
-/*
- * Common free code for all extensions. Extension-specific code must
- * free anything beyond cdsaExt->Value.parsedValue, then we free everything
- * else (except the extension struct itself, which is freed by
- * DecodedCert::freeCertFieldData()).
- * The value union may contain a parsed value, or a CSSM_X509EXT_TAGandVALUE;
- * wed ont' care, we just free it.
- */
-void freeFieldExtenCommon(
- CSSM_X509_EXTENSION_PTR exten,
- Allocator &alloc)
-{
- alloc.free(exten->extnId.Data);
- alloc.free(exten->BERvalue.Data); // may be NULL
- alloc.free(exten->value.parsedValue); // may be NULL
-}
-
-/*
- * One common free for extensions whose parsed value doesn't go any deeper
- * than cssmExt->value.parsedValue.
- */
-void freeFieldSimpleExtension (
- CssmOwnedData &fieldValue)
-{
- CSSM_X509_EXTENSION_PTR cssmExt = verifySetFreeExtension(fieldValue,
- false);
- freeFieldExtenCommon(cssmExt, fieldValue.allocator);
-}
-
-
-/***
- *** Common code for get/set subject/issuer name (C struct version)
- *** Format = CSSM_X509_NAME
- *** class Name from sm_x501if
- ***/
-bool getField_RDN_NSS (
- const NSS_Name &nssName,
- CssmOwnedData &fieldValue) // RETURNED
-{
- /* alloc top-level CSSM_X509_NAME */
- Allocator &alloc = fieldValue.allocator;
- fieldValue.malloc(sizeof(CSSM_X509_NAME));
- CSSM_X509_NAME_PTR cssmName = (CSSM_X509_NAME_PTR)fieldValue.data();
-
- CL_nssNameToCssm(nssName, *cssmName, alloc);
- return true;
-}
-
-void freeField_RDN (
- CssmOwnedData &fieldValue)
-{
- if(fieldValue.data() == NULL) {
- return;
- }
- if(fieldValue.length() != sizeof(CSSM_X509_NAME)) {
- CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
- }
- Allocator &alloc = fieldValue.allocator;
- CSSM_X509_NAME_PTR x509Name = (CSSM_X509_NAME_PTR)fieldValue.data();
- CL_freeX509Name(x509Name, alloc);
-
- /* top-level x509Name pointer freed by freeCertFieldData() */
-}
-
-/***
- *** Common code for Issuer Name, Subject Name (normalized and encoded
- *** version)
- *** Format = CSSM_DATA containing the DER encoding of the normalized name
- ***/
-bool getField_normRDN_NSS (
- const CSSM_DATA &derName,
- uint32 &numFields, // RETURNED (if successful, 0 or 1)
- CssmOwnedData &fieldValue) // RETURNED
-{
- if(derName.Data == NULL) {
- /* This can happen during CertGetAllTemplateFields() because
- * the normalized fields are only set up during cert/CRL decode */
- return false;
- }
-
- /*
- * First make a temp decoded copy which we'll be manipulating.
- */
- SecNssCoder coder;
- NSS_Name decodedName;
-
- memset(&decodedName, 0, sizeof(decodedName));
- PRErrorCode prtn = coder.decodeItem(derName, kSecAsn1NameTemplate, &decodedName);
- if(prtn) {
- /*
- * Actually should never happen since this same bag of bits successfully
- * decoded when the cert as a whole was decoded...
- */
- clErrorLog("getField_normRDN decode error\n");
- CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
-
- }
-
- /* normalize */
- CL_normalizeX509NameNSS(decodedName, coder);
-
- /* encode result */
- prtn = SecNssEncodeItemOdata(&decodedName, kSecAsn1NameTemplate, fieldValue);
- if(prtn) {
- clErrorLog("getField_normRDN encode error\n");
- CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR);
- }
- numFields = 1;
- return true;
-}
-
-/***
- *** Common code for Time fields - Validity not before, Not After,
- *** This Update, Next Update
- *** Format: CSSM_X509_TIME
- ***/
-bool getField_TimeNSS (
- const NSS_Time &nssTime,
- unsigned index, // which occurrence (0 = first)
- uint32 &numFields, // RETURNED
- CssmOwnedData &fieldValue) // RETURNED
-{
- if(!tbsGetCheck(nssTime.item.Data, index)) {
- return false;
- }
- Allocator &alloc = fieldValue.allocator;
- fieldValue.malloc(sizeof(CSSM_X509_TIME));
- CSSM_X509_TIME *cssmTime =
- (CSSM_X509_TIME *)fieldValue.data();
- if(CL_nssTimeToCssm(nssTime, *cssmTime, alloc)) {
- numFields = 1;
- return true;
- }
- else {
- return false;
- }
-}
-
-void setField_TimeNSS (
- const CssmData &fieldValue,
- NSS_Time &nssTime,
- SecNssCoder &coder)
-{
- CSSM_X509_TIME *cssmTime =
- (CSSM_X509_TIME *)fieldValue.data();
- CL_cssmTimeToNss(*cssmTime, nssTime, coder);
-}
-
-void freeField_Time (
- CssmOwnedData &fieldValue)
-{
- CSSM_X509_TIME *cssmTime = (CSSM_X509_TIME *)fieldValue.data();
- if(cssmTime == NULL) {
- return;
- }
- if(fieldValue.length() != sizeof(CSSM_X509_TIME)) {
- CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
- }
- CL_freeCssmTime(cssmTime, fieldValue.allocator);
-}
-
-/***
- *** TBS AlgId, Signature AlgId
- *** Format = CSSM_X509_ALGORITHM_IDENTIFIER
- ***/
-void getField_AlgIdNSS (
- const CSSM_X509_ALGORITHM_IDENTIFIER &srcAlgId,
- CssmOwnedData &fieldValue) // RETURNED
-{
- Allocator &alloc = fieldValue.allocator;
- fieldValue.malloc(sizeof(CSSM_X509_ALGORITHM_IDENTIFIER));
- CSSM_X509_ALGORITHM_IDENTIFIER *destAlgId =
- (CSSM_X509_ALGORITHM_IDENTIFIER *)fieldValue.data();
- CL_copyAlgId(srcAlgId, *destAlgId, alloc);
-}
-
-void setField_AlgIdNSS (
- const CssmData &fieldValue,
- CSSM_X509_ALGORITHM_IDENTIFIER &dstAlgId,
- SecNssCoder &coder)
-{
- CSSM_X509_ALGORITHM_IDENTIFIER *srcAlgId =
- (CSSM_X509_ALGORITHM_IDENTIFIER *)fieldValue.data();
- /* allocator for this coder */
- ArenaAllocator areanAlloc(coder);
- CL_copyAlgId(*srcAlgId, dstAlgId, areanAlloc);
-}
-
-void freeField_AlgId (
- CssmOwnedData &fieldValue)
-{
- CSSM_X509_ALGORITHM_IDENTIFIER *cssmAlgId =
- (CSSM_X509_ALGORITHM_IDENTIFIER *)fieldValue.data();
- if(cssmAlgId == NULL) {
- return;
- }
- if(fieldValue.length() != sizeof(CSSM_X509_ALGORITHM_IDENTIFIER)) {
- CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
- }
- Allocator &alloc = fieldValue.allocator;
- alloc.free(cssmAlgId->algorithm.Data);
- alloc.free(cssmAlgId->parameters.Data);
- memset(cssmAlgId, 0, sizeof(CSSM_X509_ALGORITHM_IDENTIFIER));
-}
-
-/*
- * Routines for common validity checking for certificateToSign fields.
- *
- * Call from setField*: verify field isn't already set, optionally validate
- * input length
- */
-void tbsSetCheck(
- void *fieldToSet,
- const CssmData &fieldValue,
- uint32 expLength,
- const char *op)
-{
- if(fieldToSet != NULL) {
- /* can't add another */
- clErrorLog("setField(%s): field already set", op);
- CssmError::throwMe(CSSMERR_CL_INVALID_NUMBER_OF_FIELDS);
- }
- if((expLength != 0) && (fieldValue.length() != expLength)) {
- clErrorLog("setField(%s): bad length : exp %d got %d",
- op, (int)expLength, (int)fieldValue.length());
- CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
- }
-}
-
-/*
- * Call from getField* for unique fields - detect missing field or
- * index out of bounds.
- */
-bool tbsGetCheck(
- const void *requiredField,
- uint32 reqIndex)
-{
- if((requiredField == NULL) || (reqIndex != 0)) {
- return false;
- }
- else {
- return true;
- }
-}
-
-/***
- *** unknown extensions
- *** CDSA format: raw bytes in a CSSM_DATA. This data is the BER-encoding of
- *** some extension struct we don't know about.
- *** NSS format CSSM_DATA
- *** OID CSSMOID_X509V3CertificateExtensionCStruct
- ***/
-
-void setFieldUnknownExt(
- DecodedItem &cert,
- const CssmData &fieldValue)
-{
- CSSM_X509_EXTENSION_PTR cssmExt = verifySetFreeExtension(fieldValue, true);
- SecNssCoder &coder = cert.coder();
- CSSM_DATA *rawExtn = (CSSM_DATA *)coder.malloc(sizeof(CSSM_DATA));
- coder.allocCopyItem(cssmExt->BERvalue, *rawExtn);
- cert.addExtension(NULL, cssmExt->extnId, cssmExt->critical,
- true, NULL /* no template */, rawExtn);
-}
-
-bool getFieldUnknownExt(
- DecodedItem &cert,
- unsigned index, // which occurrence (0 = first)
- uint32 &numFields, // RETURNED
- CssmOwnedData &fieldValue)
-{
- uint8 noOidDataLikeThis[2] = {1, 2}; // a dummy argument
- CSSM_OID noOidLikeThis = {2, noOidDataLikeThis};
- const DecodedExten *decodedExt =
- cert.DecodedItem::findDecodedExt(noOidLikeThis,
- true, index, numFields);
- if(decodedExt == NULL) {
- return false;
- }
- getFieldExtenCommon(NULL, *decodedExt, fieldValue);
- return true;
-}
-
-void freeFieldUnknownExt (
- CssmOwnedData &fieldValue)
-{
- CSSM_X509_EXTENSION_PTR cssmExt = verifySetFreeExtension(fieldValue, true);
- Allocator &alloc = fieldValue.allocator;
- freeFieldExtenCommon(cssmExt, alloc); // frees extnId, parsedValue, BERvalue
-}
-
-/* setField for read-only OIDs (i.e., the ones in cert/CRL, not TBS) */
-void setField_ReadOnly (
- DecodedItem &item,
- const CssmData &fieldValue)
-{
- clErrorLog("Attempt to set a read-only field");
- CssmError::throwMe(CSSMERR_CL_UNKNOWN_TAG);
-}
-
-bool getField_Unimplemented (
- DecodedItem &item,
- unsigned index, // which occurrence (0 = first)
- uint32 &numFields, // RETURNED
- CssmOwnedData &fieldValue) // RETURNED
-{
- clErrorLog("Attempt to get an unimplemented field");
- CssmError::throwMe(CSSMERR_CL_UNKNOWN_TAG);
-}
-
-
-