#include "clNameUtils.h"
#include "clNssUtils.h"
#include "cldebugging.h"
#include <security_utilities/utilities.h>
#pragma mark ----- NSS_Name <--> CSSM_X509_NAME -----
static
void CL_nssAtvToCssm(
const NSS_ATV &nssObj,
CSSM_X509_TYPE_VALUE_PAIR &cssmObj,
Allocator &alloc)
{
cssmObj.valueType = nssObj.value.tag;
clAllocCopyData(alloc, nssObj.value.item, cssmObj.value);
clAllocCopyData(alloc, nssObj.type, cssmObj.type);
}
void CL_nssRdnToCssm(
const NSS_RDN &nssObj,
CSSM_X509_RDN &cssmObj,
Allocator &alloc,
SecNssCoder &coder) {
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<numAtvs; dex++) {
CL_nssAtvToCssm(*(nssObj.atvs[dex]), cssmAtvs[dex], alloc);
}
return;
}
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) {
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;
for(unsigned dex=0; dex<numRdns; dex++) {
CL_nssRdnToCssm(*(nssObj.rdns[dex]), cssmRdns[dex], alloc, coder);
}
return;
}
void CL_cssmAtvToNss(
const CSSM_X509_TYPE_VALUE_PAIR &cssmObj,
NSS_ATV &nssObj,
SecNssCoder &coder)
{
memset(&nssObj, 0, sizeof(nssObj));
coder.allocCopyItem(cssmObj.type, nssObj.type);
nssObj.value.tag = cssmObj.valueType;
coder.allocCopyItem(cssmObj.value, nssObj.value.item);
}
void CL_cssmRdnToNss(
const CSSM_X509_RDN &cssmObj,
NSS_RDN &nssObj,
SecNssCoder &coder)
{
memset(&nssObj, 0, sizeof(nssObj));
unsigned numAtvs = cssmObj.numberOfPairs;
unsigned size = (numAtvs + 1) * sizeof(void *);
nssObj.atvs = (NSS_ATV **)coder.malloc(size);
memset(nssObj.atvs, 0, size);
for(unsigned atvDex=0; atvDex<numAtvs; atvDex++) {
nssObj.atvs[atvDex] = (NSS_ATV *)coder.malloc(sizeof(NSS_ATV));
CL_cssmAtvToNss(cssmObj.AttributeTypeAndValue[atvDex],
*nssObj.atvs[atvDex], coder);
}
}
void CL_cssmNameToNss(
const CSSM_X509_NAME &cssmObj,
NSS_Name &nssObj,
SecNssCoder &coder)
{
memset(&nssObj, 0, sizeof(nssObj));
unsigned numRdns = cssmObj.numberOfRDNs;
nssObj.rdns = (NSS_RDN **)clNssNullArray(numRdns, coder);
for(unsigned rdnDex=0; rdnDex<numRdns; rdnDex++) {
nssObj.rdns[rdnDex] = (NSS_RDN *)coder.malloc(sizeof(NSS_RDN));
CL_cssmRdnToNss(cssmObj.RelativeDistinguishedName[rdnDex],
*nssObj.rdns[rdnDex], coder);
}
}
#pragma mark ----- Name Normalization -----
void CL_normalizeString(
char *strPtr,
int &strLen) {
char *pCh = strPtr; char *pD = pCh; char *pEos = pCh + strLen - 1;
if(strLen == 0) {
return;
}
while(*pEos == 0) {
pEos--;
}
while(isspace(*pEos)) {
pEos--;
}
pEos++;
while(pCh < pEos) {
*pCh = toupper(*pCh);
pCh++;
}
pCh = pD;
while(isspace(*pCh) && (pCh < pEos)) {
pCh++;
}
char ch;
while(pCh < pEos) {
ch = *pCh++;
*pD++ = ch; if( isspace(ch) ){
while(isspace(*pCh) && (pCh < pEos)) {
pCh++;
}
}
};
strLen = (int)(pD - strPtr);
}
void CL_normalizeX509NameNSS(
NSS_Name &nssName,
SecNssCoder &coder)
{
unsigned numRdns = clNssArraySize((const void **)nssName.rdns);
if(numRdns == 0) {
return;
}
for(unsigned rdnDex=0; rdnDex<numRdns; rdnDex++) {
NSS_RDN *rdn = nssName.rdns[rdnDex];
assert(rdn != NULL);
unsigned numAttrs = clNssArraySize((const void **)rdn->atvs);
if(numAttrs == 0) {
clFieldLog("clNormalizeX509Name: zero numAttrs at index %d", rdnDex);
continue;
}
for(unsigned attrDex=0; attrDex<numAttrs; attrDex++) {
NSS_ATV *attr = rdn->atvs[attrDex];
assert(attr != NULL);
NSS_TaggedItem &attrVal = attr->value;
if(attrVal.tag != SEC_ASN1_PRINTABLE_STRING) {
continue;
}
char *strPtr = (char *)attrVal.item.Data;
int newLen = (int)attrVal.item.Length;
CL_normalizeString(strPtr, newLen);
attrVal.item.Length = newLen;
}
}
}
#pragma mark ----- CE_GeneralNames <--> NSS_GeneralNames -----
void CL_nssGeneralNameToCssm(
NSS_GeneralName &nssObj,
CE_GeneralName &cdsaObj,
SecNssCoder &coder, Allocator &alloc) {
memset(&cdsaObj, 0, sizeof(cdsaObj));
PRErrorCode prtn;
CSSM_BOOL berEncoded = CSSM_FALSE;
CE_GeneralNameType cdsaTag;
bool doCopy = true;
switch(nssObj.tag) {
case NGT_OtherName: {
cdsaTag = GNT_OtherName;
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);
}
clAllocData(alloc, cdsaObj.name, sizeof(CE_OtherName));
clCopyOtherName(*nssOther, *((CE_OtherName *)cdsaObj.name.Data),
alloc);
doCopy = false;
break;
}
case NGT_RFC822Name: cdsaTag = GNT_RFC822Name;
break;
case NGT_DNSName: cdsaTag = GNT_DNSName;
break;
case NGT_X400Address: cdsaTag = GNT_X400Address;
berEncoded = CSSM_TRUE;
break;
case NGT_DirectoryName: {
cdsaTag = GNT_DirectoryName;
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);
}
clAllocData(alloc, cdsaObj.name, sizeof(CSSM_X509_NAME));
CL_nssNameToCssm(*nssName,
*((CSSM_X509_NAME *)cdsaObj.name.Data), alloc);
doCopy = false;
break;
}
case NGT_EdiPartyName: cdsaTag = GNT_EdiPartyName;
berEncoded = CSSM_TRUE;
break;
case NGT_URI: cdsaTag = GNT_URI;
break;
case NGT_IPAddress: cdsaTag = GNT_IPAddress;
break;
case NGT_RegisteredID: 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, Allocator &alloc) {
memset(&cdsaObj, 0, sizeof(cdsaObj));
unsigned numNames = clNssArraySize((const void **)nssObj.names);
if(numNames == 0) {
return;
}
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; dex<numNames; dex++) {
if(coder.decodeItem(*nssObj.names[dex], kSecAsn1GeneralNameTemplate,
&names[dex])) {
clErrorLog("***CL_nssGeneralNamesToCssm: Error decoding "
"General.name\n");
CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
}
CL_nssGeneralNameToCssm(names[dex],
cdsaObj.generalName[dex],
coder, alloc);
}
}
void CL_cssmGeneralNameToNss(
CE_GeneralName &cdsaObj,
NSS_GeneralName &nssObj, SecNssCoder &coder) {
memset(&nssObj, 0, sizeof(nssObj));
nssObj.item = cdsaObj.name;
unsigned char itemTag; bool doCopy = false; unsigned char overrideTag; PRErrorCode prtn;
switch(cdsaObj.nameType) {
case GNT_OtherName:
if((cdsaObj.name.Length != sizeof(CE_OtherName)) ||
(cdsaObj.name.Data == NULL)) {
clErrorLog("CL_cssmGeneralNameToNss: OtherName.Length"
" error\n");
CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
}
prtn = coder.encodeItem(cdsaObj.name.Data,
kSecAsn1OtherNameTemplate, nssObj.item);
if(prtn) {
clErrorLog("CL_cssmGeneralNameToNss: OtherName encode"
" error\n");
CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR);
}
itemTag = NGT_OtherName;
break;
case GNT_RFC822Name: itemTag = NGT_RFC822Name;
break;
case GNT_DNSName: itemTag = NGT_DNSName;
break;
case GNT_X400Address:
itemTag = GNT_X400Address;
if(!cdsaObj.berEncoded) {
clErrorLog("CL_cssmGeneralNameToNss: X400Address must"
" be BER-encoded\n");
CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
}
overrideTag = SEC_ASN1_CONTEXT_SPECIFIC |
SEC_ASN1_CONSTRUCTED | NGT_X400Address;
doCopy = true;
break;
case GNT_DirectoryName:
{
if((cdsaObj.name.Length != sizeof(CSSM_X509_NAME)) ||
(cdsaObj.name.Data == NULL)) {
clErrorLog("CL_cssmGeneralNameToNss: DirectoryName.Length"
" error\n");
CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
}
NSS_Name nssName;
CSSM_X509_NAME_PTR cdsaName =
(CSSM_X509_NAME_PTR)cdsaObj.name.Data;
CL_cssmNameToNss(*cdsaName, nssName, coder);
prtn = coder.encodeItem(&nssName,
kSecAsn1NameTemplate, nssObj.item);
if(prtn) {
clErrorLog("CL_cssmGeneralNameToNss: X509Name encode"
" error\n");
CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR);
}
itemTag = GNT_DirectoryName;
break;
}
case GNT_EdiPartyName:
itemTag = GNT_EdiPartyName;
if(!cdsaObj.berEncoded) {
clErrorLog("CL_cssmGeneralNameToNss: EdiPartyName must"
" be BER-encoded\n");
CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
}
overrideTag = SEC_ASN1_CONTEXT_SPECIFIC | NGT_X400Address;
doCopy = true;
break;
case GNT_URI: itemTag = GNT_URI;
break;
case GNT_IPAddress: itemTag = NGT_IPAddress;
break;
case GNT_RegisteredID: itemTag = NGT_RegisteredID;
break;
default:
clErrorLog("CL_cssmGeneralNameToNss: bad name tag\n");
CssmError::throwMe(CSSMERR_CL_UNKNOWN_TAG);
}
if(doCopy) {
coder.allocCopyItem(cdsaObj.name, nssObj.item);
nssObj.item.Data[0] = overrideTag;
}
nssObj.tag = itemTag;
}
void CL_cssmGeneralNamesToNss(
const CE_GeneralNames &cdsaObj,
NSS_GeneralNames &nssObj,
SecNssCoder &coder)
{
uint32 numNames = cdsaObj.numNames;
nssObj.names = (CSSM_DATA **)clNssNullArray(numNames, coder);
NSS_GeneralName *names =
(NSS_GeneralName *)coder.malloc(sizeof(NSS_GeneralName) * numNames);
memset(names, 0, sizeof(NSS_GeneralName) * numNames);
for(unsigned dex=0; dex<cdsaObj.numNames; dex++) {
nssObj.names[dex] = (CSSM_DATA_PTR)coder.malloc(sizeof(CSSM_DATA));
memset(nssObj.names[dex], 0, sizeof(CSSM_DATA));
CL_cssmGeneralNameToNss(cdsaObj.generalName[dex],
names[dex], coder);
if(coder.encodeItem(&names[dex], kSecAsn1GeneralNameTemplate,
*nssObj.names[dex])) {
clErrorLog("***Error encoding General.name\n");
CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR);
}
}
}
void clCopyOtherName(
const CE_OtherName &src,
CE_OtherName &dst,
Allocator &alloc)
{
clAllocCopyData(alloc, src.typeId, dst.typeId);
clAllocCopyData(alloc, src.value, dst.value);
}
#pragma mark ----- Name-related Free -----
void CL_freeAuthorityKeyId(
CE_AuthorityKeyID &cdsaObj,
Allocator &alloc)
{
alloc.free(cdsaObj.keyIdentifier.Data);
CL_freeCssmGeneralNames(cdsaObj.generalNames, alloc);
alloc.free(cdsaObj.generalNames);
alloc.free(cdsaObj.serialNumber.Data);
memset(&cdsaObj, 0, sizeof(CE_AuthorityKeyID));
}
void CL_freeCssmGeneralName(
CE_GeneralName &genName,
Allocator &alloc)
{
switch(genName.nameType) {
case GNT_DirectoryName:
if((!genName.berEncoded) && (genName.name.Length ==
sizeof(CSSM_X509_NAME))) { CL_freeX509Name((CSSM_X509_NAME_PTR)genName.name.Data, alloc);
}
break;
case GNT_OtherName:
if((!genName.berEncoded) && (genName.name.Length ==
sizeof(CE_OtherName))) { CE_OtherName *con = (CE_OtherName *)genName.name.Data;
CL_freeOtherName(con, alloc);
}
break;
default:
break;
}
alloc.free(genName.name.Data);
}
void CL_freeCssmGeneralNames(
CE_GeneralNames *cdsaObj,
Allocator &alloc)
{
if(cdsaObj == NULL) {
return;
}
for(unsigned i=0; i<cdsaObj->numNames; 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; dex<cssmDps->numDistPoints; 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));
}
void CL_freeX509Name(
CSSM_X509_NAME_PTR x509Name,
Allocator &alloc)
{
if(x509Name == NULL) {
return;
}
for(unsigned rdnDex=0; rdnDex<x509Name->numberOfRDNs; 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; atvDex<rdn->numberOfPairs; 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);
}