]> git.saurik.com Git - apple/security.git/blob - libsecurity_keychain/lib/Certificate.cpp
Security-55163.44.tar.gz
[apple/security.git] / libsecurity_keychain / lib / Certificate.cpp
1 /*
2 * Copyright (c) 2002-2007 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 //
25 // Certificate.cpp
26 //
27 #include <security_keychain/Certificate.h>
28 #include <security_cdsa_utilities/Schema.h>
29 #include <Security/oidscert.h>
30 #include <Security/oidsattr.h>
31 #include <Security/SecCertificate.h>
32 #include <Security/SecCertificatePriv.h>
33 #include <security_cdsa_client/cspclient.h>
34 #include <security_keychain/KeyItem.h>
35 #include <security_keychain/KCCursor.h>
36 #include <vector>
37 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
38 //#include "CLFieldsCommon.h"
39
40
41 using namespace KeychainCore;
42
43 CL
44 Certificate::clForType(CSSM_CERT_TYPE type)
45 {
46 return CL(gGuidAppleX509CL);
47 }
48
49 Certificate::Certificate(const CSSM_DATA &data, CSSM_CERT_TYPE type, CSSM_CERT_ENCODING encoding) :
50 ItemImpl(CSSM_DL_DB_RECORD_X509_CERTIFICATE, reinterpret_cast<SecKeychainAttributeList *>(NULL), UInt32(data.Length), reinterpret_cast<const void *>(data.Data)),
51 mHaveTypeAndEncoding(true),
52 mPopulated(false),
53 mType(type),
54 mEncoding(encoding),
55 mCL(clForType(type)),
56 mCertHandle(0),
57 mV1SubjectPublicKeyCStructValue(NULL),
58 mV1SubjectNameCStructValue(NULL),
59 mV1IssuerNameCStructValue(NULL)
60 {
61 if (data.Length == 0 || data.Data == NULL)
62 MacOSError::throwMe(paramErr);
63 }
64
65 // db item constructor
66 Certificate::Certificate(const Keychain &keychain, const PrimaryKey &primaryKey, const CssmClient::DbUniqueRecord &uniqueId) :
67 ItemImpl(keychain, primaryKey, uniqueId),
68 mHaveTypeAndEncoding(false),
69 mPopulated(false),
70 mCL(NULL),
71 mCertHandle(0),
72 mV1SubjectPublicKeyCStructValue(NULL),
73 mV1SubjectNameCStructValue(NULL),
74 mV1IssuerNameCStructValue(NULL)
75 {
76 }
77
78
79
80 Certificate* Certificate::make(const Keychain &keychain, const PrimaryKey &primaryKey, const CssmClient::DbUniqueRecord &uniqueId)
81 {
82 Certificate* c = new Certificate(keychain, primaryKey, uniqueId);
83 keychain->addItem(primaryKey, c);
84 return c;
85 }
86
87
88
89 Certificate* Certificate::make(const Keychain &keychain, const PrimaryKey &primaryKey)
90 {
91 Certificate* c = new Certificate(keychain, primaryKey);
92 keychain->addItem(primaryKey, c);
93 return c;
94 }
95
96
97
98
99 // PrimaryKey item constructor
100 Certificate::Certificate(const Keychain &keychain, const PrimaryKey &primaryKey) :
101 ItemImpl(keychain, primaryKey),
102 mHaveTypeAndEncoding(false),
103 mPopulated(false),
104 mCL(NULL),
105 mCertHandle(0),
106 mV1SubjectPublicKeyCStructValue(NULL),
107 mV1SubjectNameCStructValue(NULL),
108 mV1IssuerNameCStructValue(NULL)
109 {
110 // @@@ In this case we don't know the type...
111 }
112
113 Certificate::Certificate(Certificate &certificate) :
114 ItemImpl(certificate),
115 mHaveTypeAndEncoding(certificate.mHaveTypeAndEncoding),
116 mPopulated(false /* certificate.mPopulated */),
117 mType(certificate.mType),
118 mEncoding(certificate.mEncoding),
119 mCL(certificate.mCL),
120 mCertHandle(0),
121 mV1SubjectPublicKeyCStructValue(NULL),
122 mV1SubjectNameCStructValue(NULL),
123 mV1IssuerNameCStructValue(NULL)
124 {
125 }
126
127 Certificate::~Certificate() throw()
128 {
129 if (mV1SubjectPublicKeyCStructValue)
130 releaseFieldValue(CSSMOID_X509V1SubjectPublicKeyCStruct, mV1SubjectPublicKeyCStructValue);
131
132 if (mCertHandle && mCL)
133 CSSM_CL_CertAbortCache(mCL->handle(), mCertHandle);
134
135 if (mV1SubjectNameCStructValue)
136 releaseFieldValue(CSSMOID_X509V1SubjectNameCStruct, mV1SubjectNameCStructValue);
137
138 if (mV1IssuerNameCStructValue)
139 releaseFieldValue(CSSMOID_X509V1IssuerNameCStruct, mV1IssuerNameCStructValue);
140 }
141
142 CSSM_HANDLE
143 Certificate::certHandle()
144 {
145 StLock<Mutex>_(mMutex);
146 const CSSM_DATA *cert = &data();
147 if (!mCertHandle)
148 {
149 if (CSSM_RETURN retval = CSSM_CL_CertCache(clHandle(), cert, &mCertHandle))
150 CssmError::throwMe(retval);
151 }
152
153 return mCertHandle;
154 }
155
156 /* Return a zero terminated list of CSSM_DATA_PTR's with the values of the field specified by field. Caller must call releaseFieldValues to free the storage allocated by this call. */
157 CSSM_DATA_PTR *
158 Certificate::copyFieldValues(const CSSM_OID &field)
159 {
160 StLock<Mutex>_(mMutex);
161 CSSM_CL_HANDLE clh = clHandle();
162 CSSM_DATA_PTR fieldValue, *fieldValues;
163 CSSM_HANDLE resultsHandle = 0;
164 uint32 numberOfFields = 0;
165 CSSM_RETURN result;
166
167 result = CSSM_CL_CertGetFirstCachedFieldValue(clh, certHandle(), &field, &resultsHandle, &numberOfFields, &fieldValue);
168 if (result)
169 {
170 if (result == CSSMERR_CL_NO_FIELD_VALUES)
171 return NULL;
172
173 CssmError::throwMe(result);
174 }
175
176 fieldValues = new CSSM_DATA_PTR[numberOfFields + 1];
177 fieldValues[0] = fieldValue;
178 fieldValues[numberOfFields] = NULL;
179
180 for (uint32 value = 1; value < numberOfFields; ++value)
181 {
182 CSSM_RETURN cresult = CSSM_CL_CertGetNextCachedFieldValue(clh, resultsHandle, &fieldValues[value]);
183 if (cresult)
184 {
185 fieldValues[value] = NULL;
186 result = cresult;
187 break; // No point in continuing really.
188 }
189 }
190
191 CSSM_CL_CertAbortQuery(clh, resultsHandle);
192
193 if (result)
194 {
195 releaseFieldValues(field, fieldValues);
196 CssmError::throwMe(result);
197 }
198
199 return fieldValues;
200 }
201
202 void
203 Certificate::releaseFieldValues(const CSSM_OID &field, CSSM_DATA_PTR *fieldValues)
204 {
205 StLock<Mutex>_(mMutex);
206 if (fieldValues)
207 {
208 CSSM_CL_HANDLE clh = clHandle();
209
210 for (int ix = 0; fieldValues[ix]; ++ix)
211 CSSM_CL_FreeFieldValue(clh, &field, fieldValues[ix]);
212
213 delete[] fieldValues;
214 }
215 }
216
217 void
218 Certificate::addParsedAttribute(const CSSM_DB_ATTRIBUTE_INFO &info, const CSSM_OID &field)
219 {
220 StLock<Mutex>_(mMutex);
221 CSSM_DATA_PTR *fieldValues = copyFieldValues(field);
222 if (fieldValues)
223 {
224 CssmDbAttributeData &anAttr = mDbAttributes->add(info);
225 for (int ix = 0; fieldValues[ix]; ++ix)
226 anAttr.add(*fieldValues[ix], *mDbAttributes);
227
228 releaseFieldValues(field, fieldValues);
229 }
230 }
231
232 void
233 Certificate::addSubjectKeyIdentifier()
234 {
235 StLock<Mutex>_(mMutex);
236 const CSSM_DB_ATTRIBUTE_INFO &info = Schema::attributeInfo(kSecSubjectKeyIdentifierItemAttr);
237 const CSSM_OID &field = CSSMOID_SubjectKeyIdentifier;
238
239 CSSM_DATA_PTR *fieldValues = copyFieldValues(field);
240 if (fieldValues)
241 {
242 CssmDbAttributeData &anAttr = mDbAttributes->add(info);
243 for (int ix = 0; fieldValues[ix]; ++ix)
244 {
245 const CSSM_X509_EXTENSION *extension = reinterpret_cast<const CSSM_X509_EXTENSION *>(fieldValues[ix]->Data);
246 if (extension == NULL || fieldValues[ix]->Length != sizeof(CSSM_X509_EXTENSION))
247 {
248 assert(extension != NULL && fieldValues[ix]->Length == sizeof(CSSM_X509_EXTENSION));
249 continue;
250 }
251 const CE_SubjectKeyID *skid = reinterpret_cast<CE_SubjectKeyID *>(extension->value.parsedValue);
252 if (skid == NULL)
253 {
254 assert(skid != NULL);
255 continue;
256 }
257 anAttr.add(*skid, *mDbAttributes);
258 }
259
260 releaseFieldValues(field, fieldValues);
261 }
262 }
263
264 /* Return a CSSM_DATA_PTR with the value of the first field specified by field. Caller must call releaseFieldValue to free the storage allocated by this call. */
265 CSSM_DATA_PTR
266 Certificate::copyFirstFieldValue(const CSSM_OID &field)
267 {
268 StLock<Mutex>_(mMutex);
269 CSSM_CL_HANDLE clh = clHandle();
270 CSSM_DATA_PTR fieldValue;
271 CSSM_HANDLE resultsHandle = 0;
272 uint32 numberOfFields = 0;
273 CSSM_RETURN result;
274
275 result = CSSM_CL_CertGetFirstCachedFieldValue(clh, certHandle(), &field, &resultsHandle, &numberOfFields, &fieldValue);
276 if (result)
277 {
278 if (result == CSSMERR_CL_NO_FIELD_VALUES)
279 return NULL;
280
281 CssmError::throwMe(result);
282 }
283
284 result = CSSM_CL_CertAbortQuery(clh, resultsHandle);
285
286 if (result)
287 {
288 releaseFieldValue(field, fieldValue);
289 CssmError::throwMe(result);
290 }
291
292 return fieldValue;
293 }
294
295 void
296 Certificate::releaseFieldValue(const CSSM_OID &field, CSSM_DATA_PTR fieldValue)
297 {
298 StLock<Mutex>_(mMutex);
299 if (fieldValue)
300 {
301 CSSM_CL_HANDLE clh = clHandle();
302 CSSM_CL_FreeFieldValue(clh, &field, fieldValue);
303 }
304 }
305
306
307
308 /*
309 This method computes the keyIdentifier for the public key in the cert as
310 described below:
311
312 The keyIdentifier is composed of the 160-bit SHA-1 hash of the
313 value of the BIT STRING subjectPublicKey (excluding the tag,
314 length, and number of unused bits).
315 */
316 const CssmData &
317 Certificate::publicKeyHash()
318 {
319 StLock<Mutex>_(mMutex);
320 if (mPublicKeyHash.Length)
321 return mPublicKeyHash;
322
323 CSSM_DATA_PTR keyPtr = copyFirstFieldValue(CSSMOID_CSSMKeyStruct);
324 if (keyPtr && keyPtr->Data)
325 {
326 CssmClient::CSP csp(gGuidAppleCSP);
327 CssmClient::PassThrough passThrough(csp);
328 CSSM_KEY *key = reinterpret_cast<CSSM_KEY *>(keyPtr->Data);
329 void *outData;
330 CssmData *cssmData;
331
332 /* Given a CSSM_KEY_PTR in any format, obtain the SHA-1 hash of the
333 * associated key blob.
334 * Key is specified in CSSM_CSP_CreatePassThroughContext.
335 * Hash is allocated by the CSP, in the App's memory, and returned
336 * in *outData. */
337 passThrough.key(key);
338 passThrough(CSSM_APPLECSP_KEYDIGEST, NULL, &outData);
339 cssmData = reinterpret_cast<CssmData *>(outData);
340
341 assert(cssmData->Length <= sizeof(mPublicKeyHashBytes));
342 mPublicKeyHash.Data = mPublicKeyHashBytes;
343 mPublicKeyHash.Length = cssmData->Length;
344 memcpy(mPublicKeyHash.Data, cssmData->Data, cssmData->Length);
345 csp.allocator().free(cssmData->Data);
346 csp.allocator().free(cssmData);
347 }
348
349 releaseFieldValue(CSSMOID_CSSMKeyStruct, keyPtr);
350
351 return mPublicKeyHash;
352 }
353
354 const CssmData &
355 Certificate::subjectKeyIdentifier()
356 {
357 StLock<Mutex>_(mMutex);
358 if (mSubjectKeyID.Length)
359 return mSubjectKeyID;
360
361 CSSM_DATA_PTR fieldValue = copyFirstFieldValue(CSSMOID_SubjectKeyIdentifier);
362 if (fieldValue && fieldValue->Data && fieldValue->Length == sizeof(CSSM_X509_EXTENSION))
363 {
364 const CSSM_X509_EXTENSION *extension = reinterpret_cast<const CSSM_X509_EXTENSION *>(fieldValue->Data);
365 const CE_SubjectKeyID *skid = reinterpret_cast<CE_SubjectKeyID *>(extension->value.parsedValue); // CSSM_DATA
366
367 if (skid->Length <= sizeof(mSubjectKeyIDBytes))
368 {
369 mSubjectKeyID.Data = mSubjectKeyIDBytes;
370 mSubjectKeyID.Length = skid->Length;
371 memcpy(mSubjectKeyID.Data, skid->Data, skid->Length);
372 }
373 else
374 mSubjectKeyID.Length = 0;
375 }
376
377 releaseFieldValue(CSSMOID_SubjectKeyIdentifier, fieldValue);
378
379 return mSubjectKeyID;
380 }
381
382
383 /*
384 * Given an CSSM_X509_NAME, Find the first name/value pair with
385 * a printable value which matches the specified OID (e.g., CSSMOID_CommonName).
386 * Returns the CFString-style encoding associated with name component's BER tag.
387 * Returns NULL if none found.
388 */
389 static const CSSM_DATA *
390 findPrintableField(
391 const CSSM_X509_NAME &x509Name,
392 const CSSM_OID *tvpType, // NULL means "any printable field"
393 CFStringBuiltInEncodings *encoding) // RETURNED
394 {
395 for(uint32 rdnDex=0; rdnDex<x509Name.numberOfRDNs; rdnDex++) {
396 const CSSM_X509_RDN *rdnPtr =
397 &x509Name.RelativeDistinguishedName[rdnDex];
398 for(uint32 tvpDex=0; tvpDex<rdnPtr->numberOfPairs; tvpDex++) {
399 const CSSM_X509_TYPE_VALUE_PAIR *tvpPtr =
400 &rdnPtr->AttributeTypeAndValue[tvpDex];
401
402 /* type/value pair: match caller's specified type? */
403 if(tvpType != NULL && tvpType->Data != NULL) {
404 if(tvpPtr->type.Length != tvpType->Length) {
405 continue;
406 }
407 if(memcmp(tvpPtr->type.Data, tvpType->Data, tvpType->Length)) {
408 /* If we don't have a match but the requested OID is CSSMOID_UserID,
409 * look for a matching X.500 UserID OID: (0.9.2342.19200300.100.1.1) */
410 const char cssm_userid_oid[] = { 0x09,0x49,0x86,0x49,0x1f,0x12,0x8c,0xe4,0x81,0x81 };
411 const char x500_userid_oid[] = { 0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x01 };
412 if(!(tvpType->Length == sizeof(cssm_userid_oid) &&
413 !memcmp(tvpPtr->type.Data, x500_userid_oid, sizeof(x500_userid_oid)) &&
414 !memcmp(tvpType->Data, cssm_userid_oid, sizeof(cssm_userid_oid)))) {
415 continue;
416 }
417 }
418 }
419
420 /* printable? */
421 switch(tvpPtr->valueType) {
422 case BER_TAG_PRINTABLE_STRING:
423 case BER_TAG_IA5_STRING:
424 *encoding = kCFStringEncodingASCII;
425 return &tvpPtr->value;
426 case BER_TAG_PKIX_UTF8_STRING:
427 case BER_TAG_GENERAL_STRING:
428 case BER_TAG_PKIX_UNIVERSAL_STRING:
429 *encoding = kCFStringEncodingUTF8;
430 return &tvpPtr->value;
431 case BER_TAG_T61_STRING:
432 case BER_TAG_VIDEOTEX_STRING:
433 case BER_TAG_ISO646_STRING:
434 *encoding = kCFStringEncodingISOLatin1;
435 return &tvpPtr->value;
436 case BER_TAG_PKIX_BMP_STRING:
437 *encoding = kCFStringEncodingUnicode;
438 return &tvpPtr->value;
439 default:
440 /* not printable */
441 break;
442 }
443 } /* for each pair */
444 } /* for each RDN */
445
446 /* no printable component of specified type found */
447 return NULL;
448 }
449
450 /*
451 * Infer printable label for a given CSSM_X509_NAME. Returns NULL
452 * if no appropriate printable name found. Returns the CFString-style
453 * encoding associated with name component's BER tag. Also optionally
454 * returns Description component and its encoding if present and the
455 * returned name component was from CommonName.
456 */
457 static const CSSM_DATA *inferLabelFromX509Name(
458 const CSSM_X509_NAME *x509Name,
459 CFStringBuiltInEncodings *encoding, // RETURNED
460 const CSSM_DATA **description, // optionally RETURNED
461 CFStringBuiltInEncodings *descrEncoding) // RETURNED if description != NULL
462 {
463 const CSSM_DATA *printValue;
464 /*
465 * Search order (take the first one found with a printable
466 * value):
467 * -- common name
468 * -- Orgnaizational Unit
469 * -- Organization
470 * -- field of any kind
471 */
472 printValue = findPrintableField(*x509Name, &CSSMOID_CommonName, encoding);
473 if(printValue != NULL) {
474 if(description != NULL) {
475 *description = findPrintableField(*x509Name, &CSSMOID_Description, descrEncoding);
476 }
477 return printValue;
478 }
479 printValue = findPrintableField(*x509Name, &CSSMOID_OrganizationalUnitName, encoding);
480 if(printValue != NULL) {
481 return printValue;
482 }
483 printValue = findPrintableField(*x509Name, &CSSMOID_OrganizationName, encoding);
484 if(printValue != NULL) {
485 return printValue;
486 }
487 /* take anything */
488 return findPrintableField(*x509Name, NULL, encoding);
489 }
490
491 /*
492 * Infer printable label for a given an CSSM_X509_NAME. Returns NULL
493 * if no appropriate printable name found.
494 */
495 const CSSM_DATA *SecInferLabelFromX509Name(
496 const CSSM_X509_NAME *x509Name)
497 {
498 /* callees of this routine don't care about the encoding */
499 CFStringBuiltInEncodings encoding = kCFStringEncodingASCII;
500 return inferLabelFromX509Name(x509Name, &encoding, NULL, &encoding);
501 }
502
503
504 void
505 Certificate::inferLabel(bool addLabel, CFStringRef *rtnString)
506 {
507 StLock<Mutex>_(mMutex);
508 // Set PrintName and optionally the Alias attribute for this certificate, based on the
509 // X509 SubjectAltName and SubjectName.
510 const CSSM_DATA *printName = NULL;
511 const CSSM_DATA *description = NULL;
512 std::vector<CssmData> emailAddresses;
513 CSSM_DATA puntData;
514 CssmAutoData printPlusDescr(Allocator::standard());
515 CssmData printPlusDescData;
516 CFStringBuiltInEncodings printEncoding = kCFStringEncodingUTF8;
517 CFStringBuiltInEncodings descrEncoding = kCFStringEncodingUTF8;
518
519 // Find the SubjectAltName fields, if any, and extract all the GNT_RFC822Name entries from all of them
520 const CSSM_OID &sanOid = CSSMOID_SubjectAltName;
521 CSSM_DATA_PTR *sanValues = copyFieldValues(sanOid);
522 const CSSM_OID &snOid = CSSMOID_X509V1SubjectNameCStruct;
523 CSSM_DATA_PTR snValue = copyFirstFieldValue(snOid);
524
525 getEmailAddresses(sanValues, snValue, emailAddresses);
526
527 if (snValue && snValue->Data)
528 {
529 const CSSM_X509_NAME &x509Name = *(const CSSM_X509_NAME *)snValue->Data;
530 printName = inferLabelFromX509Name(&x509Name, &printEncoding,
531 &description, &descrEncoding);
532 if (printName)
533 {
534 /* Don't ever use "Thawte Freemail Member" as the label for a cert. Instead force
535 a fall back on the email address. */
536 const char tfm[] = "Thawte Freemail Member";
537 if ( (printName->Length == sizeof(tfm) - 1) &&
538 !memcmp(printName->Data, tfm, sizeof(tfm) - 1)) {
539 printName = NULL;
540 }
541 }
542 }
543
544 /* Do a check to see if a '\0' was at the end of printName and strip it. */
545 CssmData cleanedUpPrintName;
546 if((printName != NULL) &&
547 (printName->Length != 0) &&
548 (printEncoding != kCFStringEncodingISOLatin1) &&
549 (printEncoding != kCFStringEncodingUnicode) &&
550 (printName->Data[printName->Length - 1] == '\0')) {
551 cleanedUpPrintName.Data = printName->Data;
552 cleanedUpPrintName.Length = printName->Length - 1;
553 printName = &cleanedUpPrintName;
554 }
555
556 if((printName != NULL) && (description != NULL) && (description->Length != 0))
557 {
558 /*
559 * Munge Print Name (which in this case is the CommonName) and Description
560 * together with the Description in parentheses. We convert from whatever
561 * format Print Name and Description are in to UTF8 here.
562 */
563 CFRef<CFMutableStringRef> combo(CFStringCreateMutable(NULL, 0));
564 CFRef<CFStringRef> cfPrint(CFStringCreateWithBytes(NULL, printName->Data,
565 (CFIndex)printName->Length, printEncoding, true));
566 CssmData cleanedUpDescr(description->Data, description->Length);
567 if ((cleanedUpDescr.Data[cleanedUpDescr.Length - 1] == '\0') &&
568 (descrEncoding != kCFStringEncodingISOLatin1) &&
569 (descrEncoding != kCFStringEncodingUnicode)) {
570 cleanedUpDescr.Length--;
571 }
572 CFRef<CFStringRef> cfDesc(CFStringCreateWithBytes(NULL, cleanedUpDescr.Data,
573 (CFIndex)cleanedUpDescr.Length, descrEncoding, true));
574 CFStringAppend(combo, cfPrint);
575 CFStringAppendCString(combo, " (", kCFStringEncodingASCII);
576 CFStringAppend(combo, cfDesc);
577 CFStringAppendCString(combo, ")", kCFStringEncodingASCII);
578 CFRef<CFDataRef> comboData(CFStringCreateExternalRepresentation(NULL, combo,
579 kCFStringEncodingUTF8, 0));
580 printPlusDescr.copy(CFDataGetBytePtr(comboData), CFDataGetLength(comboData));
581 printPlusDescData = printPlusDescr;
582 printName = &printPlusDescData;
583 printEncoding = kCFStringEncodingUTF8;
584 }
585
586 if (printName == NULL)
587 {
588 /* If the we couldn't find a label use the emailAddress instead. */
589 if (!emailAddresses.empty())
590 printName = &emailAddresses[0];
591 else
592 {
593 /* punt! */
594 puntData.Data = (uint8 *)"X509 Certificate";
595 puntData.Length = 16;
596 printName = &puntData;
597 }
598 printEncoding = kCFStringEncodingUTF8;
599 }
600
601 /* If we couldn't find an email address just use the printName which might be the url or something else useful. */
602 if (emailAddresses.empty())
603 emailAddresses.push_back(CssmData::overlay(*printName));
604
605 /* What do we do with the inferred label - return it or add it mDbAttributes? */
606 if (addLabel)
607 {
608 mDbAttributes->add(Schema::kX509CertificatePrintName, *printName);
609 CssmDbAttributeData &attrData = mDbAttributes->add(Schema::kX509CertificateAlias);
610
611 /* Add the email addresses to attrData and normalize them. */
612 uint32 ix = 0;
613 for (std::vector<CssmData>::const_iterator it = emailAddresses.begin(); it != emailAddresses.end(); ++it, ++ix)
614 {
615 /* Add the email address using the allocator from mDbAttributes. */
616 attrData.add(*it, *mDbAttributes);
617 /* Normalize the emailAddresses in place since attrData already copied it. */
618 normalizeEmailAddress(attrData.Value[ix]);
619 }
620 }
621
622 if (rtnString)
623 {
624 CFStringBuiltInEncodings testEncoding = printEncoding;
625 if(testEncoding == kCFStringEncodingISOLatin1) {
626 // try UTF-8 first
627 testEncoding = kCFStringEncodingUTF8;
628 }
629 *rtnString = CFStringCreateWithBytes(NULL, printName->Data,
630 (CFIndex)printName->Length, testEncoding, true);
631 if(*rtnString == NULL && printEncoding == kCFStringEncodingISOLatin1) {
632 // string cannot be represented in UTF-8, fall back to ISO Latin 1
633 *rtnString = CFStringCreateWithBytes(NULL, printName->Data,
634 (CFIndex)printName->Length, printEncoding, true);
635 }
636 }
637
638 // Clean up
639 if (snValue)
640 releaseFieldValue(snOid, snValue);
641 if (sanValues)
642 releaseFieldValues(sanOid, sanValues);
643 }
644
645 void
646 Certificate::populateAttributes()
647 {
648 StLock<Mutex>_(mMutex);
649 if (mPopulated)
650 return;
651
652 addParsedAttribute(Schema::attributeInfo(kSecSubjectItemAttr), CSSMOID_X509V1SubjectName);
653 addParsedAttribute(Schema::attributeInfo(kSecIssuerItemAttr), CSSMOID_X509V1IssuerName);
654 addParsedAttribute(Schema::attributeInfo(kSecSerialNumberItemAttr), CSSMOID_X509V1SerialNumber);
655
656 addSubjectKeyIdentifier();
657
658 if(!mHaveTypeAndEncoding)
659 MacOSError::throwMe(errSecDataNotAvailable); // @@@ Or some other error.
660
661 // Adjust mType based on the actual version of the cert.
662 CSSM_DATA_PTR versionPtr = copyFirstFieldValue(CSSMOID_X509V1Version);
663 if (versionPtr && versionPtr->Data && versionPtr->Length == sizeof(uint32))
664 {
665 mType = CSSM_CERT_X_509v1 + (*reinterpret_cast<uint32 *>(versionPtr->Data));
666 }
667 else
668 mType = CSSM_CERT_X_509v1;
669
670 releaseFieldValue(CSSMOID_X509V1Version, versionPtr);
671
672 mDbAttributes->add(Schema::attributeInfo(kSecCertTypeItemAttr), mType);
673 mDbAttributes->add(Schema::attributeInfo(kSecCertEncodingItemAttr), mEncoding);
674 mDbAttributes->add(Schema::attributeInfo(kSecPublicKeyHashItemAttr), publicKeyHash());
675 inferLabel(true);
676
677 mPopulated = true;
678 }
679
680 const CssmData &
681 Certificate::data()
682 {
683 StLock<Mutex>_(mMutex);
684 CssmDataContainer *data = mData.get();
685 if (!data && mKeychain)
686 {
687 // Make sure mUniqueId is set.
688 dbUniqueRecord();
689 CssmDataContainer _data;
690 mData = NULL;
691 /* new data allocated by CSPDL, implicitly freed by CssmDataContainer */
692 mUniqueId->get(NULL, &_data);
693 /* this saves a copy to be freed at destruction and to be passed to caller */
694 setData(_data.length(), _data.data());
695 return *mData.get();
696 }
697
698 // If the data hasn't been set we can't return it.
699 if (!data)
700 MacOSError::throwMe(errSecDataNotAvailable);
701
702 return *data;
703 }
704
705 CSSM_CERT_TYPE
706 Certificate::type()
707 {
708 StLock<Mutex>_(mMutex);
709 if (!mHaveTypeAndEncoding)
710 {
711 SecKeychainAttribute attr;
712 attr.tag = kSecCertTypeItemAttr;
713 attr.data = &mType;
714 attr.length = sizeof(mType);
715 getAttribute(attr, NULL);
716 }
717
718 return mType;
719 }
720
721 CSSM_CERT_ENCODING
722 Certificate::encoding()
723 {
724 StLock<Mutex>_(mMutex);
725 if (!mHaveTypeAndEncoding)
726 {
727 SecKeychainAttribute attr;
728 attr.tag = kSecCertEncodingItemAttr;
729 attr.data = &mEncoding;
730 attr.length = sizeof(mEncoding);
731 getAttribute(attr, NULL);
732 }
733
734 return mEncoding;
735 }
736
737 const CSSM_X509_ALGORITHM_IDENTIFIER_PTR
738 Certificate::algorithmID()
739 {
740 StLock<Mutex>_(mMutex);
741 if (!mV1SubjectPublicKeyCStructValue)
742 mV1SubjectPublicKeyCStructValue = copyFirstFieldValue(CSSMOID_X509V1SubjectPublicKeyCStruct);
743
744 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO *info = (CSSM_X509_SUBJECT_PUBLIC_KEY_INFO *)mV1SubjectPublicKeyCStructValue->Data;
745 CSSM_X509_ALGORITHM_IDENTIFIER *algid = &info->algorithm;
746 return algid;
747 }
748
749 CFStringRef
750 Certificate::commonName()
751 {
752 StLock<Mutex>_(mMutex);
753 return distinguishedName(&CSSMOID_X509V1SubjectNameCStruct, &CSSMOID_CommonName);
754 }
755
756 CFStringRef
757 Certificate::distinguishedName(const CSSM_OID *sourceOid, const CSSM_OID *componentOid)
758 {
759 StLock<Mutex>_(mMutex);
760 CFStringRef rtnString = NULL;
761 CSSM_DATA_PTR fieldValue = copyFirstFieldValue(*sourceOid);
762 CSSM_X509_NAME_PTR x509Name = (CSSM_X509_NAME_PTR)fieldValue->Data;
763 const CSSM_DATA *printValue = NULL;
764 CFStringBuiltInEncodings encoding;
765
766 if (fieldValue && fieldValue->Data)
767 printValue = findPrintableField(*x509Name, componentOid, &encoding);
768
769 if (printValue)
770 rtnString = CFStringCreateWithBytes(NULL, printValue->Data,
771 CFIndex(printValue->Length), encoding, true);
772
773 releaseFieldValue(*sourceOid, fieldValue);
774
775 return rtnString;
776 }
777
778
779 /*
780 * Return a CFString containing the first email addresses for this certificate, based on the
781 * X509 SubjectAltName and SubjectName.
782 */
783 CFStringRef
784 Certificate::copyFirstEmailAddress()
785 {
786 StLock<Mutex>_(mMutex);
787 CFStringRef rtnString;
788
789 const CSSM_OID &sanOid = CSSMOID_SubjectAltName;
790 CSSM_DATA_PTR *sanValues = copyFieldValues(sanOid);
791 const CSSM_OID &snOid = CSSMOID_X509V1SubjectNameCStruct;
792 CSSM_DATA_PTR snValue = copyFirstFieldValue(snOid);
793 std::vector<CssmData> emailAddresses;
794
795 getEmailAddresses(sanValues, snValue, emailAddresses);
796 if (emailAddresses.empty())
797 rtnString = NULL;
798 else
799 {
800 /* Encoding is kCFStringEncodingUTF8 since the string is either
801 PRINTABLE_STRING, IA5_STRING, T61_STRING or PKIX_UTF8_STRING. */
802 rtnString = CFStringCreateWithBytes(NULL, emailAddresses[0].Data,
803 (CFIndex)emailAddresses[0].Length, kCFStringEncodingUTF8, true);
804 }
805
806 // Clean up
807 if (snValue)
808 releaseFieldValue(snOid, snValue);
809 if (sanValues)
810 releaseFieldValues(sanOid, sanValues);
811
812 return rtnString;
813 }
814
815 /*
816 * Return a CFArray containing the email addresses for this certificate, based on the
817 * X509 SubjectAltName and SubjectName.
818 */
819 CFArrayRef
820 Certificate::copyEmailAddresses()
821 {
822 StLock<Mutex>_(mMutex);
823 CFMutableArrayRef array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
824 std::vector<CssmData> emailAddresses;
825
826 // Find the SubjectAltName fields, if any, and extract all the GNT_RFC822Name entries from all of them
827 const CSSM_OID &sanOid = CSSMOID_SubjectAltName;
828 CSSM_DATA_PTR *sanValues = copyFieldValues(sanOid);
829
830 const CSSM_OID &snOid = CSSMOID_X509V1SubjectNameCStruct;
831 CSSM_DATA_PTR snValue = copyFirstFieldValue(snOid);
832
833 getEmailAddresses(sanValues, snValue, emailAddresses);
834
835 for (std::vector<CssmData>::const_iterator it = emailAddresses.begin(); it != emailAddresses.end(); ++it)
836 {
837 /* Encoding is kCFStringEncodingUTF8 since the string is either
838 PRINTABLE_STRING, IA5_STRING, T61_STRING or PKIX_UTF8_STRING. */
839 CFStringRef string = CFStringCreateWithBytes(NULL, it->Data, static_cast<CFIndex>(it->Length), kCFStringEncodingUTF8, true);
840 CFArrayAppendValue(array, string);
841 CFRelease(string);
842 }
843
844 // Clean up
845 if (snValue)
846 releaseFieldValue(snOid, snValue);
847 if (sanValues)
848 releaseFieldValues(sanOid, sanValues);
849
850 return array;
851 }
852
853 const CSSM_X509_NAME_PTR
854 Certificate::subjectName()
855 {
856 StLock<Mutex>_(mMutex);
857 if (!mV1SubjectNameCStructValue)
858 if ((mV1SubjectNameCStructValue = copyFirstFieldValue(CSSMOID_X509V1SubjectNameCStruct)) == NULL)
859 return NULL;
860
861 return (const CSSM_X509_NAME_PTR)mV1SubjectNameCStructValue->Data;
862 }
863
864 const CSSM_X509_NAME_PTR
865 Certificate::issuerName()
866 {
867 StLock<Mutex>_(mMutex);
868 if (!mV1IssuerNameCStructValue)
869 if ((mV1IssuerNameCStructValue = copyFirstFieldValue(CSSMOID_X509V1IssuerNameCStruct)) == NULL)
870 return NULL;
871
872 return (const CSSM_X509_NAME_PTR)mV1IssuerNameCStructValue->Data;
873 }
874
875 CSSM_CL_HANDLE
876 Certificate::clHandle()
877 {
878 StLock<Mutex>_(mMutex);
879 if (!mCL)
880 mCL = clForType(type());
881
882 return mCL->handle();
883 }
884
885 bool
886 Certificate::operator < (Certificate &other)
887 {
888 // Certificates in different keychains are considered equal if data is equal
889 // Note that the Identity '<' operator relies on this assumption.
890 return data() < other.data();
891 }
892
893 bool
894 Certificate::operator == (Certificate &other)
895 {
896 // Certificates in different keychains are considered equal if data is equal
897 // Note that the Identity '==' operator relies on this assumption.
898 return data() == other.data();
899 }
900
901 bool
902 Certificate::equal(SecCFObject &other)
903 {
904 return (*this) == (Certificate &)other;
905 }
906
907 void
908 Certificate::update()
909 {
910 ItemImpl::update();
911 }
912
913 Item
914 Certificate::copyTo(const Keychain &keychain, Access *newAccess)
915 {
916 StLock<Mutex>_(mMutex);
917 /* Certs can't have access controls. */
918 if (newAccess)
919 MacOSError::throwMe(errSecNoAccessForItem);
920
921 Item item(new Certificate(data(), type(), encoding()));
922 keychain->add(item);
923 return item;
924 }
925
926 void
927 Certificate::didModify()
928 {
929 }
930
931 PrimaryKey
932 Certificate::add(Keychain &keychain)
933 {
934 StLock<Mutex>_(mMutex);
935 // If we already have a Keychain we can't be added.
936 if (mKeychain)
937 MacOSError::throwMe(errSecDuplicateItem);
938
939 populateAttributes();
940
941 CSSM_DB_RECORDTYPE recordType = mDbAttributes->recordType();
942
943 Db db(keychain->database());
944 // add the item to the (regular) db
945 try
946 {
947 mUniqueId = db->insert(recordType, mDbAttributes.get(), mData.get());
948 }
949 catch (const CssmError &e)
950 {
951 if (e.osStatus() != CSSMERR_DL_INVALID_RECORDTYPE)
952 throw;
953
954 // Create the cert relation and try again.
955 db->createRelation(CSSM_DL_DB_RECORD_X509_CERTIFICATE,
956 "CSSM_DL_DB_RECORD_X509_CERTIFICATE",
957 Schema::X509CertificateSchemaAttributeCount,
958 Schema::X509CertificateSchemaAttributeList,
959 Schema::X509CertificateSchemaIndexCount,
960 Schema::X509CertificateSchemaIndexList);
961 keychain->keychainSchema()->didCreateRelation(
962 CSSM_DL_DB_RECORD_X509_CERTIFICATE,
963 "CSSM_DL_DB_RECORD_X509_CERTIFICATE",
964 Schema::X509CertificateSchemaAttributeCount,
965 Schema::X509CertificateSchemaAttributeList,
966 Schema::X509CertificateSchemaIndexCount,
967 Schema::X509CertificateSchemaIndexList);
968
969 mUniqueId = db->insert(recordType, mDbAttributes.get(), mData.get());
970 }
971
972 mPrimaryKey = keychain->makePrimaryKey(recordType, mUniqueId);
973 mKeychain = keychain;
974
975 return mPrimaryKey;
976 }
977
978 SecPointer<KeyItem>
979 Certificate::publicKey()
980 {
981 StLock<Mutex>_(mMutex);
982 SecPointer<KeyItem> keyItem;
983 // Return a CSSM_DATA_PTR with the value of the first field specified by field.
984 // Caller must call releaseFieldValue to free the storage allocated by this call.
985 // call OSStatus SecKeyGetCSSMKey(SecKeyRef key, const CSSM_KEY **cssmKey); to retrieve
986
987 CSSM_DATA_PTR keyPtr = copyFirstFieldValue(CSSMOID_CSSMKeyStruct);
988 if (keyPtr && keyPtr->Data)
989 {
990 CssmClient::CSP csp(gGuidAppleCSP);
991 CssmKey *cssmKey = reinterpret_cast<CssmKey *>(keyPtr->Data);
992 CssmClient::Key key(csp, *cssmKey);
993 keyItem = new KeyItem(key);
994 // Clear out KeyData since KeyItem() takes over ownership of the key, and we don't want it getting released.
995 cssmKey->KeyData.Data = NULL;
996 cssmKey->KeyData.Length = 0;
997 }
998
999 releaseFieldValue(CSSMOID_CSSMKeyStruct, keyPtr);
1000
1001 return keyItem;
1002 }
1003
1004 // This function "borrowed" from the X509 CL, which is (currently) linked into
1005 // the Security.framework as a built-in plugin.
1006 extern "C" bool getField_normRDN_NSS (
1007 const CSSM_DATA &derName,
1008 uint32 &numFields, // RETURNED (if successful, 0 or 1)
1009 CssmOwnedData &fieldValue); // RETURNED
1010
1011 KCCursor
1012 Certificate::cursorForIssuerAndSN(const StorageManager::KeychainList &keychains, const CssmData &issuer, const CssmData &serialNumber)
1013 {
1014 CssmAutoData fieldValue(Allocator::standard(Allocator::normal));
1015 uint32 numFields;
1016
1017 // We need to decode issuer, normalize it, then re-encode it
1018 if (!getField_normRDN_NSS(issuer, numFields, fieldValue))
1019 MacOSError::throwMe(errSecDataNotAvailable);
1020
1021 // Code basically copied from SecKeychainSearchCreateFromAttributes and SecKeychainSearchCopyNext:
1022 KCCursor cursor(keychains, kSecCertificateItemClass, NULL);
1023 cursor->conjunctive(CSSM_DB_AND);
1024 cursor->add(CSSM_DB_EQUAL, Schema::kX509CertificateIssuer, fieldValue.get());
1025 cursor->add(CSSM_DB_EQUAL, Schema::kX509CertificateSerialNumber, serialNumber);
1026
1027 return cursor;
1028 }
1029
1030 KCCursor
1031 Certificate::cursorForIssuerAndSN_CF(const StorageManager::KeychainList &keychains, CFDataRef issuer, CFDataRef serialNumber)
1032 {
1033 // This assumes a normalized issuer
1034 CSSM_DATA issuerCSSM, serialNumberCSSM;
1035
1036 issuerCSSM.Length = CFDataGetLength(issuer);
1037 issuerCSSM.Data = const_cast<uint8 *>(CFDataGetBytePtr(issuer));
1038
1039 serialNumberCSSM.Length = CFDataGetLength(serialNumber);
1040 serialNumberCSSM.Data = const_cast<uint8 *>(CFDataGetBytePtr(serialNumber));
1041
1042 // Code basically copied from SecKeychainSearchCreateFromAttributes and SecKeychainSearchCopyNext:
1043 KCCursor cursor(keychains, kSecCertificateItemClass, NULL);
1044 cursor->conjunctive(CSSM_DB_AND);
1045 cursor->add(CSSM_DB_EQUAL, Schema::kX509CertificateIssuer, issuerCSSM);
1046 cursor->add(CSSM_DB_EQUAL, Schema::kX509CertificateSerialNumber, serialNumberCSSM);
1047
1048 return cursor;
1049 }
1050
1051 KCCursor
1052 Certificate::cursorForSubjectKeyID(const StorageManager::KeychainList &keychains, const CssmData &subjectKeyID)
1053 {
1054 KCCursor cursor(keychains, kSecCertificateItemClass, NULL);
1055 cursor->conjunctive(CSSM_DB_AND);
1056 cursor->add(CSSM_DB_EQUAL, Schema::kX509CertificateSubjectKeyIdentifier, subjectKeyID);
1057
1058 return cursor;
1059 }
1060
1061 KCCursor
1062 Certificate::cursorForEmail(const StorageManager::KeychainList &keychains, const char *emailAddress)
1063 {
1064 KCCursor cursor(keychains, kSecCertificateItemClass, NULL);
1065 if (emailAddress)
1066 {
1067 cursor->conjunctive(CSSM_DB_AND);
1068 CssmSelectionPredicate &pred = cursor->add(CSSM_DB_EQUAL, Schema::kX509CertificateAlias, emailAddress);
1069 /* Normalize the emailAddresses in place since cursor already copied it. */
1070 normalizeEmailAddress(pred.Attribute.Value[0]);
1071 }
1072
1073 return cursor;
1074 }
1075
1076 SecPointer<Certificate>
1077 Certificate::findInKeychain(const StorageManager::KeychainList &keychains)
1078 {
1079 StLock<Mutex>_(mMutex);
1080 const CSSM_OID &issuerOid = CSSMOID_X509V1IssuerName;
1081 CSSM_DATA_PTR issuerPtr = copyFirstFieldValue(issuerOid);
1082 CssmData issuer(issuerPtr->Data, issuerPtr->Length);
1083
1084 const CSSM_OID &serialOid = CSSMOID_X509V1SerialNumber;
1085 CSSM_DATA_PTR serialPtr = copyFirstFieldValue(serialOid);
1086 CssmData serial(serialPtr->Data, serialPtr->Length);
1087
1088 SecPointer<Certificate> foundCert = NULL;
1089 try {
1090 foundCert = findByIssuerAndSN(keychains, issuer, serial);
1091 } catch (...) {
1092 foundCert = NULL;
1093 }
1094
1095 releaseFieldValue(issuerOid, issuerPtr);
1096 releaseFieldValue(serialOid, serialPtr);
1097
1098 return foundCert;
1099 }
1100
1101 SecPointer<Certificate>
1102 Certificate::findByIssuerAndSN(const StorageManager::KeychainList &keychains, const CssmData &issuer, const CssmData &serialNumber)
1103 {
1104 Item item;
1105 if (!cursorForIssuerAndSN(keychains, issuer, serialNumber)->next(item))
1106 CssmError::throwMe(errSecItemNotFound);
1107
1108 return static_cast<Certificate *>(&*item);
1109 }
1110
1111 SecPointer<Certificate>
1112 Certificate::findBySubjectKeyID(const StorageManager::KeychainList &keychains, const CssmData &subjectKeyID)
1113 {
1114 Item item;
1115 if (!cursorForSubjectKeyID(keychains, subjectKeyID)->next(item))
1116 CssmError::throwMe(errSecItemNotFound);
1117
1118 return static_cast<Certificate *>(&*item);
1119 }
1120
1121 SecPointer<Certificate>
1122 Certificate::findByEmail(const StorageManager::KeychainList &keychains, const char *emailAddress)
1123 {
1124 Item item;
1125 if (!cursorForEmail(keychains, emailAddress)->next(item))
1126 CssmError::throwMe(errSecItemNotFound);
1127
1128 return static_cast<Certificate *>(&*item);
1129 }
1130
1131 /* Normalize emailAddresses in place. */
1132 void
1133 Certificate::normalizeEmailAddress(CSSM_DATA &emailAddress)
1134 {
1135 /* Do a check to see if a '\0' was at the end of emailAddress and strip it. */
1136 if (emailAddress.Length && emailAddress.Data[emailAddress.Length - 1] == '\0')
1137 emailAddress.Length--;
1138 bool foundAt = false;
1139 for (uint32 ix = 0; ix < emailAddress.Length; ++ix)
1140 {
1141 uint8 ch = emailAddress.Data[ix];
1142 if (foundAt)
1143 {
1144 if ('A' <= ch && ch <= 'Z')
1145 emailAddress.Data[ix] = ch + 'a' - 'A';
1146 }
1147 else if (ch == '@')
1148 foundAt = true;
1149 }
1150 }
1151
1152 void
1153 Certificate::getEmailAddresses(CSSM_DATA_PTR *sanValues, CSSM_DATA_PTR snValue, std::vector<CssmData> &emailAddresses)
1154 {
1155 // Get the email addresses for this certificate, based on the
1156 // X509 SubjectAltName and SubjectName.
1157
1158 // Find the SubjectAltName fields, if any, and extract all the GNT_RFC822Name entries from all of them
1159 if (sanValues)
1160 {
1161 for (CSSM_DATA_PTR *sanIx = sanValues; *sanIx; ++sanIx)
1162 {
1163 CSSM_DATA_PTR sanValue = *sanIx;
1164 if (sanValue && sanValue->Data)
1165 {
1166 CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)sanValue->Data;
1167 CE_GeneralNames *parsedValue = (CE_GeneralNames *)cssmExt->value.parsedValue;
1168
1169 /* Grab all the values that are of type GNT_RFC822Name. */
1170 for (uint32 i = 0; i < parsedValue->numNames; ++i)
1171 {
1172 if (parsedValue->generalName[i].nameType == GNT_RFC822Name)
1173 {
1174 if (parsedValue->generalName[i].berEncoded) // can't handle this
1175 continue;
1176
1177 emailAddresses.push_back(CssmData::overlay(parsedValue->generalName[i].name));
1178 }
1179 }
1180 }
1181 }
1182 }
1183
1184 if (emailAddresses.empty() && snValue && snValue->Data)
1185 {
1186 const CSSM_X509_NAME &x509Name = *(const CSSM_X509_NAME *)snValue->Data;
1187 for (uint32 rdnDex = 0; rdnDex < x509Name.numberOfRDNs; rdnDex++)
1188 {
1189 const CSSM_X509_RDN *rdnPtr =
1190 &x509Name.RelativeDistinguishedName[rdnDex];
1191 for (uint32 tvpDex = 0; tvpDex < rdnPtr->numberOfPairs; tvpDex++)
1192 {
1193 const CSSM_X509_TYPE_VALUE_PAIR *tvpPtr =
1194 &rdnPtr->AttributeTypeAndValue[tvpDex];
1195
1196 /* type/value pair: match caller's specified type? */
1197 if (((tvpPtr->type.Length != CSSMOID_EmailAddress.Length) ||
1198 memcmp(tvpPtr->type.Data, CSSMOID_EmailAddress.Data, CSSMOID_EmailAddress.Length))) {
1199 continue;
1200 }
1201
1202 /* printable? */
1203 switch (tvpPtr->valueType)
1204 {
1205 case BER_TAG_PRINTABLE_STRING:
1206 case BER_TAG_IA5_STRING:
1207 case BER_TAG_T61_STRING:
1208 case BER_TAG_PKIX_UTF8_STRING:
1209 /* success */
1210 emailAddresses.push_back(CssmData::overlay(tvpPtr->value));
1211 break;
1212 default:
1213 break;
1214 }
1215 } /* for each pair */
1216 } /* for each RDN */
1217 }
1218 }
1219
1220 void Certificate::willRead()
1221 {
1222 populateAttributes();
1223 }
1224
1225 Boolean Certificate::isSelfSigned()
1226 {
1227 StLock<Mutex>_(mMutex);
1228 CSSM_DATA_PTR issuer = NULL;
1229 CSSM_DATA_PTR subject = NULL;
1230 OSStatus ortn = noErr;
1231 Boolean brtn = false;
1232
1233 issuer = copyFirstFieldValue(CSSMOID_X509V1IssuerNameStd);
1234 subject = copyFirstFieldValue(CSSMOID_X509V1SubjectNameStd);
1235 if((issuer == NULL) || (subject == NULL)) {
1236 ortn = paramErr;
1237 }
1238 else if((issuer->Length == subject->Length) &&
1239 !memcmp(issuer->Data, subject->Data, issuer->Length)) {
1240 brtn = true;
1241 }
1242 if(brtn) {
1243 /* names match: verify signature */
1244 CSSM_RETURN crtn;
1245 CSSM_DATA certData = data();
1246 crtn = CSSM_CL_CertVerify(clHandle(), 0,
1247 &certData, &certData, NULL, 0);
1248 if(crtn) {
1249 brtn = false;
1250 }
1251 }
1252 if(issuer) {
1253 releaseFieldValue(CSSMOID_X509V1IssuerNameStd, issuer);
1254 }
1255 if(subject) {
1256 releaseFieldValue(CSSMOID_X509V1SubjectNameStd, subject);
1257 }
1258 if(ortn) {
1259 MacOSError::throwMe(ortn);
1260 }
1261 return brtn;
1262 }