/*
* Copyright (c) 2002-2007 Apple Inc. All Rights Reserved.
- *
+ *
* @APPLE_LICENSE_HEADER_START@
- *
+ *
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
- *
+ *
* The 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,
* 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.
- *
+ *
* @APPLE_LICENSE_HEADER_END@
*/
if (mCertHandle && mCL)
CSSM_CL_CertAbortCache(mCL->handle(), mCertHandle);
-
+
if (mV1SubjectNameCStructValue)
releaseFieldValue(CSSMOID_X509V1SubjectNameCStruct, mV1SubjectNameCStructValue);
if (fieldValues)
{
CSSM_CL_HANDLE clh = clHandle();
-
+
for (int ix = 0; fieldValues[ix]; ++ix)
CSSM_CL_FreeFieldValue(clh, &field, fieldValues[ix]);
-
+
delete[] fieldValues;
}
}
CssmDbAttributeData &anAttr = mDbAttributes->add(info);
for (int ix = 0; fieldValues[ix]; ++ix)
anAttr.add(*fieldValues[ix], *mDbAttributes);
-
+
releaseFieldValues(field, fieldValues);
}
}
StLock<Mutex>_(mMutex);
const CSSM_DB_ATTRIBUTE_INFO &info = Schema::attributeInfo(kSecSubjectKeyIdentifierItemAttr);
const CSSM_OID &field = CSSMOID_SubjectKeyIdentifier;
-
+
CSSM_DATA_PTR *fieldValues = copyFieldValues(field);
if (fieldValues)
{
}
anAttr.add(*skid, *mDbAttributes);
}
-
+
releaseFieldValues(field, fieldValues);
}
}
/*
This method computes the keyIdentifier for the public key in the cert as
described below:
-
+
The keyIdentifier is composed of the 160-bit SHA-1 hash of the
value of the BIT STRING subjectPublicKey (excluding the tag,
length, and number of unused bits).
void *outData;
CssmData *cssmData;
- /* Given a CSSM_KEY_PTR in any format, obtain the SHA-1 hash of the
- * associated key blob.
+ /* Given a CSSM_KEY_PTR in any format, obtain the SHA-1 hash of the
+ * associated key blob.
* Key is specified in CSSM_CSP_CreatePassThroughContext.
* Hash is allocated by the CSP, in the App's memory, and returned
* in *outData. */
csp.allocator().free(cssmData->Data);
csp.allocator().free(cssmData);
}
-
+
releaseFieldValue(CSSMOID_CSSMKeyStruct, keyPtr);
return mPublicKeyHash;
else
mSubjectKeyID.Length = 0;
}
-
+
releaseFieldValue(CSSMOID_SubjectKeyIdentifier, fieldValue);
return mSubjectKeyID;
/*
- * Given an CSSM_X509_NAME, Find the first name/value pair with
- * a printable value which matches the specified OID (e.g., CSSMOID_CommonName).
+ * Given an CSSM_X509_NAME, Find the first (or last) name/value pair with
+ * a printable value which matches the specified OID (e.g., CSSMOID_CommonName).
* Returns the CFString-style encoding associated with name component's BER tag.
- * Returns NULL if none found.
+ * Returns NULL if none found.
*/
static const CSSM_DATA *
findPrintableField(
const CSSM_X509_NAME &x509Name,
const CSSM_OID *tvpType, // NULL means "any printable field"
+ bool lastInstance, // false means return first instance
CFStringBuiltInEncodings *encoding) // RETURNED
{
+ const CSSM_DATA *result = NULL;
for(uint32 rdnDex=0; rdnDex<x509Name.numberOfRDNs; rdnDex++) {
- const CSSM_X509_RDN *rdnPtr =
+ const CSSM_X509_RDN *rdnPtr =
&x509Name.RelativeDistinguishedName[rdnDex];
for(uint32 tvpDex=0; tvpDex<rdnPtr->numberOfPairs; tvpDex++) {
- const CSSM_X509_TYPE_VALUE_PAIR *tvpPtr =
+ const CSSM_X509_TYPE_VALUE_PAIR *tvpPtr =
&rdnPtr->AttributeTypeAndValue[tvpDex];
-
+
/* type/value pair: match caller's specified type? */
if(tvpType != NULL && tvpType->Data != NULL) {
if(tvpPtr->type.Length != tvpType->Length) {
}
}
}
-
+
/* printable? */
switch(tvpPtr->valueType) {
case BER_TAG_PRINTABLE_STRING:
case BER_TAG_IA5_STRING:
*encoding = kCFStringEncodingASCII;
- return &tvpPtr->value;
+ result = &tvpPtr->value;
+ break;
case BER_TAG_PKIX_UTF8_STRING:
case BER_TAG_GENERAL_STRING:
case BER_TAG_PKIX_UNIVERSAL_STRING:
*encoding = kCFStringEncodingUTF8;
- return &tvpPtr->value;
+ result = &tvpPtr->value;
+ break;
case BER_TAG_T61_STRING:
case BER_TAG_VIDEOTEX_STRING:
case BER_TAG_ISO646_STRING:
*encoding = kCFStringEncodingISOLatin1;
- return &tvpPtr->value;
+ result = &tvpPtr->value;
+ break;
case BER_TAG_PKIX_BMP_STRING:
*encoding = kCFStringEncodingUnicode;
- return &tvpPtr->value;
+ result = &tvpPtr->value;
+ break;
default:
/* not printable */
break;
}
+ /* if we found a result and we want the first instance, return it now. */
+ if(result && !lastInstance) {
+ return result;
+ }
+
} /* for each pair */
} /* for each RDN */
-
- /* no printable component of specified type found */
- return NULL;
+
+ /* result is NULL if no printable component was found */
+ return result;
}
/*
* Infer printable label for a given CSSM_X509_NAME. Returns NULL
* if no appropriate printable name found. Returns the CFString-style
- * encoding associated with name component's BER tag. Also optionally
- * returns Description component and its encoding if present and the
- * returned name component was from CommonName.
+ * encoding associated with name component's BER tag. Also optionally
+ * returns Description component and its encoding if present and the
+ * returned name component was one we explicitly requested.
*/
static const CSSM_DATA *inferLabelFromX509Name(
const CSSM_X509_NAME *x509Name,
CFStringBuiltInEncodings *descrEncoding) // RETURNED if description != NULL
{
const CSSM_DATA *printValue;
+ if(description != NULL) {
+ *description = findPrintableField(*x509Name, &CSSMOID_Description, false, descrEncoding);
+ }
/*
* Search order (take the first one found with a printable
* value):
* -- common name
- * -- Orgnaizational Unit
+ * -- Organizational Unit
* -- Organization
+ * -- email address
* -- field of any kind
*/
- printValue = findPrintableField(*x509Name, &CSSMOID_CommonName, encoding);
+ printValue = findPrintableField(*x509Name, &CSSMOID_CommonName, true, encoding);
if(printValue != NULL) {
- if(description != NULL) {
- *description = findPrintableField(*x509Name, &CSSMOID_Description, descrEncoding);
- }
return printValue;
}
- printValue = findPrintableField(*x509Name, &CSSMOID_OrganizationalUnitName, encoding);
+ printValue = findPrintableField(*x509Name, &CSSMOID_OrganizationalUnitName, false, encoding);
if(printValue != NULL) {
return printValue;
}
- printValue = findPrintableField(*x509Name, &CSSMOID_OrganizationName, encoding);
+ printValue = findPrintableField(*x509Name, &CSSMOID_OrganizationName, false, encoding);
if(printValue != NULL) {
return printValue;
}
+ printValue = findPrintableField(*x509Name, &CSSMOID_EmailAddress, false, encoding);
+ if(printValue != NULL) {
+ return printValue;
+ }
+ /* if we didn't get one of the above names, don't append description */
+ if(description != NULL) {
+ *description = NULL;
+ }
/* take anything */
- return findPrintableField(*x509Name, NULL, encoding);
+ return findPrintableField(*x509Name, NULL, false, encoding);
}
/*
Certificate::inferLabel(bool addLabel, CFStringRef *rtnString)
{
StLock<Mutex>_(mMutex);
- // Set PrintName and optionally the Alias attribute for this certificate, based on the
+ // Set PrintName and optionally the Alias attribute for this certificate, based on the
// X509 SubjectAltName and SubjectName.
const CSSM_DATA *printName = NULL;
const CSSM_DATA *description = NULL;
CssmData printPlusDescData;
CFStringBuiltInEncodings printEncoding = kCFStringEncodingUTF8;
CFStringBuiltInEncodings descrEncoding = kCFStringEncodingUTF8;
-
+
// Find the SubjectAltName fields, if any, and extract all the GNT_RFC822Name entries from all of them
const CSSM_OID &sanOid = CSSMOID_SubjectAltName;
CSSM_DATA_PTR *sanValues = copyFieldValues(sanOid);
if (snValue && snValue->Data)
{
const CSSM_X509_NAME &x509Name = *(const CSSM_X509_NAME *)snValue->Data;
- printName = inferLabelFromX509Name(&x509Name, &printEncoding,
+ printName = inferLabelFromX509Name(&x509Name, &printEncoding,
&description, &descrEncoding);
if (printName)
{
/* Don't ever use "Thawte Freemail Member" as the label for a cert. Instead force
a fall back on the email address. */
const char tfm[] = "Thawte Freemail Member";
- if ( (printName->Length == sizeof(tfm) - 1) &&
+ if ( (printName->Length == sizeof(tfm) - 1) &&
!memcmp(printName->Data, tfm, sizeof(tfm) - 1)) {
printName = NULL;
}
/* Do a check to see if a '\0' was at the end of printName and strip it. */
CssmData cleanedUpPrintName;
- if((printName != NULL) &&
+ if((printName != NULL) &&
(printName->Length != 0) &&
(printEncoding != kCFStringEncodingISOLatin1) &&
(printEncoding != kCFStringEncodingUnicode) &&
cleanedUpPrintName.Length = printName->Length - 1;
printName = &cleanedUpPrintName;
}
-
- if((printName != NULL) && (description != NULL) && (description->Length != 0))
+
+ if((printName != NULL) && (description != NULL) && (description->Length != 0))
{
- /*
- * Munge Print Name (which in this case is the CommonName) and Description
+ /*
+ * Munge Print Name (which in this case is the CommonName) and Description
* together with the Description in parentheses. We convert from whatever
- * format Print Name and Description are in to UTF8 here.
+ * format Print Name and Description are in to UTF8 here.
*/
CFRef<CFMutableStringRef> combo(CFStringCreateMutable(NULL, 0));
CFRef<CFStringRef> cfPrint(CFStringCreateWithBytes(NULL, printName->Data,
printName = &printPlusDescData;
printEncoding = kCFStringEncodingUTF8;
}
-
+
if (printName == NULL)
{
/* If the we couldn't find a label use the emailAddress instead. */
CssmDataContainer _data;
mData = NULL;
/* new data allocated by CSPDL, implicitly freed by CssmDataContainer */
- mUniqueId->get(NULL, &_data);
+ mUniqueId->get(NULL, &_data);
/* this saves a copy to be freed at destruction and to be passed to caller */
setData(_data.length(), _data.data());
return *mData.get();
CSSM_X509_NAME_PTR x509Name = (CSSM_X509_NAME_PTR)fieldValue->Data;
const CSSM_DATA *printValue = NULL;
CFStringBuiltInEncodings encoding;
-
+
if (fieldValue && fieldValue->Data)
- printValue = findPrintableField(*x509Name, componentOid, &encoding);
+ printValue = findPrintableField(*x509Name, componentOid, true, &encoding);
if (printValue)
rtnString = CFStringCreateWithBytes(NULL, printValue->Data,
/*
- * Return a CFString containing the first email addresses for this certificate, based on the
+ * Return a CFString containing the first email addresses for this certificate, based on the
* X509 SubjectAltName and SubjectName.
*/
CFStringRef
}
/*
- * Return a CFArray containing the email addresses for this certificate, based on the
+ * Return a CFArray containing the email addresses for this certificate, based on the
* X509 SubjectAltName and SubjectName.
*/
CFArrayRef
{
CssmAutoData fieldValue(Allocator::standard(Allocator::normal));
uint32 numFields;
-
+
// We need to decode issuer, normalize it, then re-encode it
if (!getField_normRDN_NSS(issuer, numFields, fieldValue))
MacOSError::throwMe(errSecDataNotAvailable);
-
+
// Code basically copied from SecKeychainSearchCreateFromAttributes and SecKeychainSearchCopyNext:
KCCursor cursor(keychains, kSecCertificateItemClass, NULL);
cursor->conjunctive(CSSM_DB_AND);
cursor->add(CSSM_DB_EQUAL, Schema::kX509CertificateIssuer, fieldValue.get());
cursor->add(CSSM_DB_EQUAL, Schema::kX509CertificateSerialNumber, serialNumber);
-
+
return cursor;
}
{
// This assumes a normalized issuer
CSSM_DATA issuerCSSM, serialNumberCSSM;
-
+
issuerCSSM.Length = CFDataGetLength(issuer);
issuerCSSM.Data = const_cast<uint8 *>(CFDataGetBytePtr(issuer));
-
+
serialNumberCSSM.Length = CFDataGetLength(serialNumber);
serialNumberCSSM.Data = const_cast<uint8 *>(CFDataGetBytePtr(serialNumber));
cursor->conjunctive(CSSM_DB_AND);
cursor->add(CSSM_DB_EQUAL, Schema::kX509CertificateIssuer, issuerCSSM);
cursor->add(CSSM_DB_EQUAL, Schema::kX509CertificateSerialNumber, serialNumberCSSM);
-
+
return cursor;
}
}
releaseFieldValue(issuerOid, issuerPtr);
- releaseFieldValue(serialOid, serialPtr);
+ releaseFieldValue(serialOid, serialPtr);
return foundCert;
}
void
Certificate::getEmailAddresses(CSSM_DATA_PTR *sanValues, CSSM_DATA_PTR snValue, std::vector<CssmData> &emailAddresses)
{
- // Get the email addresses for this certificate, based on the
+ // Get the email addresses for this certificate, based on the
// X509 SubjectAltName and SubjectName.
// Find the SubjectAltName fields, if any, and extract all the GNT_RFC822Name entries from all of them
{
CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)sanValue->Data;
CE_GeneralNames *parsedValue = (CE_GeneralNames *)cssmExt->value.parsedValue;
-
+
/* Grab all the values that are of type GNT_RFC822Name. */
for (uint32 i = 0; i < parsedValue->numNames; ++i)
{
{
if (parsedValue->generalName[i].berEncoded) // can't handle this
continue;
-
+
emailAddresses.push_back(CssmData::overlay(parsedValue->generalName[i].name));
}
}
const CSSM_X509_NAME &x509Name = *(const CSSM_X509_NAME *)snValue->Data;
for (uint32 rdnDex = 0; rdnDex < x509Name.numberOfRDNs; rdnDex++)
{
- const CSSM_X509_RDN *rdnPtr =
+ const CSSM_X509_RDN *rdnPtr =
&x509Name.RelativeDistinguishedName[rdnDex];
for (uint32 tvpDex = 0; tvpDex < rdnPtr->numberOfPairs; tvpDex++)
{
- const CSSM_X509_TYPE_VALUE_PAIR *tvpPtr =
+ const CSSM_X509_TYPE_VALUE_PAIR *tvpPtr =
&rdnPtr->AttributeTypeAndValue[tvpDex];
-
+
/* type/value pair: match caller's specified type? */
if (((tvpPtr->type.Length != CSSMOID_EmailAddress.Length) ||
memcmp(tvpPtr->type.Data, CSSMOID_EmailAddress.Data, CSSMOID_EmailAddress.Length))) {
}
Boolean Certificate::isSelfSigned()
-{
+{
StLock<Mutex>_(mMutex);
CSSM_DATA_PTR issuer = NULL;
CSSM_DATA_PTR subject = NULL;