X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/5dd5f9ec28f304ca377c42fd7f711d6cf12b90e1..5c19dc3ae3bd8e40a9c028b0deddd50ff337692c:/OSX/libsecurity_apple_x509_cl/lib/clNameUtils.cpp diff --git a/OSX/libsecurity_apple_x509_cl/lib/clNameUtils.cpp b/OSX/libsecurity_apple_x509_cl/lib/clNameUtils.cpp new file mode 100644 index 00000000..4eb46399 --- /dev/null +++ b/OSX/libsecurity_apple_x509_cl/lib/clNameUtils.cpp @@ -0,0 +1,747 @@ +/* + * Copyright (c) 2003,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. + */ + +/* + * clNameUtils.cpp - support for Name, GeneralizedName, all sorts of names + */ + +#include "clNameUtils.h" +#include "clNssUtils.h" +#include "cldebugging.h" +#include + +#pragma mark ----- NSS_Name <--> CSSM_X509_NAME ----- + +/* + * NSS_ATV --> CSSM_X509_TYPE_VALUE_PAIR + */ +static +void CL_nssAtvToCssm( + const NSS_ATV &nssObj, + CSSM_X509_TYPE_VALUE_PAIR &cssmObj, + Allocator &alloc) +{ + /* tag and decoded data */ + cssmObj.valueType = nssObj.value.tag; + clAllocCopyData(alloc, nssObj.value.item, cssmObj.value); + /* the OID */ + clAllocCopyData(alloc, nssObj.type, cssmObj.type); +} + +/* NSS_RDN --> CSSM_X509_RDN */ +void CL_nssRdnToCssm( + const NSS_RDN &nssObj, + CSSM_X509_RDN &cssmObj, + Allocator &alloc, + SecNssCoder &coder) // conversion requires further decoding +{ + memset(&cssmObj, 0, sizeof(cssmObj)); + unsigned numAtvs = clNssArraySize((const void **)nssObj.atvs); + if(numAtvs == 0) { + return; + } + + size_t len = numAtvs * sizeof(CSSM_X509_TYPE_VALUE_PAIR); + cssmObj.AttributeTypeAndValue = + (CSSM_X509_TYPE_VALUE_PAIR_PTR)alloc.malloc(len); + cssmObj.numberOfPairs = numAtvs; + CSSM_X509_TYPE_VALUE_PAIR_PTR cssmAtvs = cssmObj.AttributeTypeAndValue; + memset(cssmAtvs, 0, len); + + for(unsigned dex=0; dex CSSM_X509_NAME */ +void CL_nssNameToCssm( + const NSS_Name &nssObj, + CSSM_X509_NAME &cssmObj, + Allocator &alloc) +{ + memset(&cssmObj, 0, sizeof(cssmObj)); + unsigned numRdns = clNssArraySize((const void **)nssObj.rdns); + if(numRdns == 0) { + /* not technically an error */ + return; + } + + size_t len = numRdns * sizeof(CSSM_X509_RDN); + cssmObj.RelativeDistinguishedName = (CSSM_X509_RDN_PTR)alloc.malloc(len); + cssmObj.numberOfRDNs = numRdns; + CSSM_X509_RDN_PTR cssmRdns = cssmObj.RelativeDistinguishedName; + memset(cssmRdns, 0, len); + + SecNssCoder coder; // conversion requires further decoding + + for(unsigned dex=0; dex NSS_ATV + */ +void CL_cssmAtvToNss( + const CSSM_X509_TYPE_VALUE_PAIR &cssmObj, + NSS_ATV &nssObj, + SecNssCoder &coder) +{ + memset(&nssObj, 0, sizeof(nssObj)); + + /* copy the OID */ + coder.allocCopyItem(cssmObj.type, nssObj.type); + + /* tag and value */ + nssObj.value.tag = cssmObj.valueType; + coder.allocCopyItem(cssmObj.value, nssObj.value.item); +} + +/* CSSM_X509_RDN --> NSS_RDN */ +void CL_cssmRdnToNss( + const CSSM_X509_RDN &cssmObj, + NSS_RDN &nssObj, + SecNssCoder &coder) +{ + memset(&nssObj, 0, sizeof(nssObj)); + + /* alloc NULL-terminated array of ATV pointers */ + unsigned numAtvs = cssmObj.numberOfPairs; + unsigned size = (numAtvs + 1) * sizeof(void *); + nssObj.atvs = (NSS_ATV **)coder.malloc(size); + memset(nssObj.atvs, 0, size); + + /* grind thru the elements */ + for(unsigned atvDex=0; atvDex NSS_Name */ +void CL_cssmNameToNss( + const CSSM_X509_NAME &cssmObj, + NSS_Name &nssObj, + SecNssCoder &coder) +{ + memset(&nssObj, 0, sizeof(nssObj)); + + /* alloc NULL-terminated array of RDN pointers */ + unsigned numRdns = cssmObj.numberOfRDNs; + nssObj.rdns = (NSS_RDN **)clNssNullArray(numRdns, coder); + + /* grind thru the elements */ + for(unsigned rdnDex=0; rdnDexatvs); + if(numAttrs == 0) { + clFieldLog("clNormalizeX509Name: zero numAttrs at index %d", rdnDex); + continue; + } + + /* descend into array of attribute/values */ + for(unsigned attrDex=0; attrDexatvs[attrDex]; + assert(attr != NULL); + + /* + * attr->value is an ASN_ANY containing an encoded + * string. We only normalize Prinatable String types. + * If we find one, decode it, normalize it, encode the + * result, and put the encoding back in attr->value. + * We temporarily "leak" the original string, which only + * has a lifetime of the incoming SecNssCoder. + */ + NSS_TaggedItem &attrVal = attr->value; + if(attrVal.tag != SEC_ASN1_PRINTABLE_STRING) { + /* skip it */ + continue; + } + + /* normalize */ + char *strPtr = (char *)attrVal.item.Data; + int newLen = (int)attrVal.item.Length; + CL_normalizeString(strPtr, newLen); + + /* possible length adjustment */ + attrVal.item.Length = newLen; + } /* for each attribute/value */ + } /* for each RDN */ +} + +#pragma mark ----- CE_GeneralNames <--> NSS_GeneralNames ----- + +void CL_nssGeneralNameToCssm( + NSS_GeneralName &nssObj, + CE_GeneralName &cdsaObj, + SecNssCoder &coder, // for temp decoding + Allocator &alloc) // destination +{ + memset(&cdsaObj, 0, sizeof(cdsaObj)); + PRErrorCode prtn; + + /* for caller's CE_GeneralName */ + CSSM_BOOL berEncoded = CSSM_FALSE; + CE_GeneralNameType cdsaTag; + + /* + * At this point, depending on the decoded object's tag, we either + * have the final bytes to copy out, or we need to decode further. + * After this switch, if doCopy is true, give the caller a copy + * of nssObj.item. + */ + bool doCopy = true; + switch(nssObj.tag) { + case NGT_OtherName: // ASN_ANY -> CE_OtherName + { + cdsaTag = GNT_OtherName; + + /* decode to coder memory */ + CE_OtherName *nssOther = + (CE_OtherName *)coder.malloc(sizeof(CE_OtherName)); + memset(nssOther, 0, sizeof(CE_OtherName)); + prtn = coder.decodeItem(nssObj.item, + kSecAsn1GenNameOtherNameTemplate, + nssOther); + if(prtn) { + clErrorLog("CL_nssGeneralNameToCssm: error decoding " + "OtherName\n"); + CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); + } + + /* copy out to caller */ + clAllocData(alloc, cdsaObj.name, sizeof(CE_OtherName)); + clCopyOtherName(*nssOther, *((CE_OtherName *)cdsaObj.name.Data), + alloc); + doCopy = false; + break; + } + case NGT_RFC822Name: // IA5String, done + cdsaTag = GNT_RFC822Name; + break; + case NGT_DNSName: // IA5String + cdsaTag = GNT_DNSName; + break; + case NGT_X400Address: // ASY_ANY, leave alone + cdsaTag = GNT_X400Address; + berEncoded = CSSM_TRUE; + break; + case NGT_DirectoryName: // ASN_ANY --> NSS_Name + { + cdsaTag = GNT_DirectoryName; + + /* Decode to coder memory */ + NSS_Name *nssName = (NSS_Name *)coder.malloc(sizeof(NSS_Name)); + memset(nssName, 0, sizeof(NSS_Name)); + prtn = coder.decodeItem(nssObj.item, kSecAsn1NameTemplate, nssName); + if(prtn) { + clErrorLog("CL_nssGeneralNameToCssm: error decoding " + "NSS_Name\n"); + CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); + } + + /* convert & copy out to caller */ + clAllocData(alloc, cdsaObj.name, sizeof(CSSM_X509_NAME)); + CL_nssNameToCssm(*nssName, + *((CSSM_X509_NAME *)cdsaObj.name.Data), alloc); + doCopy = false; + break; + } + case NGT_EdiPartyName: // ASN_ANY, leave alone + cdsaTag = GNT_EdiPartyName; + berEncoded = CSSM_TRUE; + break; + case NGT_URI: // IA5String + cdsaTag = GNT_URI; + break; + case NGT_IPAddress: // OCTET_STRING + cdsaTag = GNT_IPAddress; + break; + case NGT_RegisteredID: // OID + cdsaTag = GNT_RegisteredID; + break; + default: + clErrorLog("CL_nssGeneralNameToCssm: bad name tag\n"); + CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); + } + + cdsaObj.nameType = cdsaTag; + cdsaObj.berEncoded = berEncoded; + if(doCopy) { + clAllocCopyData(alloc, nssObj.item, cdsaObj.name); + } +} + +void CL_nssGeneralNamesToCssm( + const NSS_GeneralNames &nssObj, + CE_GeneralNames &cdsaObj, + SecNssCoder &coder, // for temp decoding + Allocator &alloc) // destination +{ + memset(&cdsaObj, 0, sizeof(cdsaObj)); + unsigned numNames = clNssArraySize((const void **)nssObj.names); + if(numNames == 0) { + return; + } + + /* + * Decode each name element, currently a raw ASN_ANY blob. + * Then convert each result into CDSA form. + * This array of (NSS_GeneralName)s is temporary, it doesn't + * persist outside of this routine other than the fact that it's + * mallocd by the coder arena pool. + */ + NSS_GeneralName *names = + (NSS_GeneralName *)coder.malloc(sizeof(NSS_GeneralName) * numNames); + memset(names, 0, sizeof(NSS_GeneralName) * numNames); + cdsaObj.generalName = (CE_GeneralName *)alloc.malloc( + sizeof(CE_GeneralName) * numNames); + cdsaObj.numNames = numNames; + + for(unsigned dex=0; dexnumNames; i++) { + CL_freeCssmGeneralName(cdsaObj->generalName[i], alloc); + } + if(cdsaObj->numNames) { + memset(cdsaObj->generalName, 0, cdsaObj->numNames * sizeof(CE_GeneralName)); + alloc.free(cdsaObj->generalName); + } + memset(cdsaObj, 0, sizeof(CE_GeneralNames)); +} + +void CL_freeCssmDistPointName( + CE_DistributionPointName *cssmDpn, + Allocator &alloc) +{ + if(cssmDpn == NULL) { + return; + } + switch(cssmDpn->nameType) { + case CE_CDNT_FullName: + CL_freeCssmGeneralNames(cssmDpn->dpn.fullName, alloc); + alloc.free(cssmDpn->dpn.fullName); + break; + case CE_CDNT_NameRelativeToCrlIssuer: + CL_freeX509Rdn(cssmDpn->dpn.rdn, alloc); + alloc.free(cssmDpn->dpn.rdn); + break; + } + memset(cssmDpn, 0, sizeof(*cssmDpn)); +} + +void CL_freeCssmDistPoints( + CE_CRLDistPointsSyntax *cssmDps, + Allocator &alloc) +{ + if(cssmDps == NULL) { + return; + } + for(unsigned dex=0; dexnumDistPoints; dex++) { + CE_CRLDistributionPoint *cssmDp = &cssmDps->distPoints[dex]; + if(cssmDp->distPointName) { + CL_freeCssmDistPointName(cssmDp->distPointName, alloc); + alloc.free(cssmDp->distPointName); + } + if(cssmDp->crlIssuer) { + CL_freeCssmGeneralNames(cssmDp->crlIssuer, alloc); + alloc.free(cssmDp->crlIssuer); + } + } + memset(cssmDps->distPoints, 0, + cssmDps->numDistPoints * sizeof(CE_CRLDistributionPoint)); + alloc.free(cssmDps->distPoints); + memset(cssmDps, 0, sizeof(*cssmDps)); +} + +/* free contents of an CSSM_X509_NAME */ +void CL_freeX509Name( + CSSM_X509_NAME_PTR x509Name, + Allocator &alloc) +{ + if(x509Name == NULL) { + return; + } + for(unsigned rdnDex=0; rdnDexnumberOfRDNs; rdnDex++) { + CSSM_X509_RDN_PTR rdn = &x509Name->RelativeDistinguishedName[rdnDex]; + CL_freeX509Rdn(rdn, alloc); + } + alloc.free(x509Name->RelativeDistinguishedName); + memset(x509Name, 0, sizeof(CSSM_X509_NAME)); +} + +void CL_freeX509Rdn( + CSSM_X509_RDN_PTR rdn, + Allocator &alloc) +{ + if(rdn == NULL) { + return; + } + for(unsigned atvDex=0; atvDexnumberOfPairs; atvDex++) { + CSSM_X509_TYPE_VALUE_PAIR_PTR atv = + &rdn->AttributeTypeAndValue[atvDex]; + alloc.free(atv->type.Data); + alloc.free(atv->value.Data); + memset(atv, 0, sizeof(CSSM_X509_TYPE_VALUE_PAIR)); + } + alloc.free(rdn->AttributeTypeAndValue); + memset(rdn, 0, sizeof(CSSM_X509_RDN)); +} + +void CL_freeOtherName( + CE_OtherName *cssmOther, + Allocator &alloc) +{ + if(cssmOther == NULL) { + return; + } + alloc.free(cssmOther->typeId.Data); + alloc.free(cssmOther->value.Data); + memset(cssmOther, 0, sizeof(*cssmOther)); +} + +void CL_freeCssmIssuingDistPoint( + CE_IssuingDistributionPoint *cssmIdp, + Allocator &alloc) +{ + CL_freeCssmDistPointName(cssmIdp->distPointName, alloc); +} +