]> git.saurik.com Git - apple/security.git/blob - libsecurity_keychain/lib/Certificate.cpp
Security-55179.13.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 (or last) 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 bool lastInstance, // false means return first instance
394 CFStringBuiltInEncodings *encoding) // RETURNED
395 {
396 const CSSM_DATA *result = NULL;
397 for(uint32 rdnDex=0; rdnDex<x509Name.numberOfRDNs; rdnDex++) {
398 const CSSM_X509_RDN *rdnPtr =
399 &x509Name.RelativeDistinguishedName[rdnDex];
400 for(uint32 tvpDex=0; tvpDex<rdnPtr->numberOfPairs; tvpDex++) {
401 const CSSM_X509_TYPE_VALUE_PAIR *tvpPtr =
402 &rdnPtr->AttributeTypeAndValue[tvpDex];
403
404 /* type/value pair: match caller's specified type? */
405 if(tvpType != NULL && tvpType->Data != NULL) {
406 if(tvpPtr->type.Length != tvpType->Length) {
407 continue;
408 }
409 if(memcmp(tvpPtr->type.Data, tvpType->Data, tvpType->Length)) {
410 /* If we don't have a match but the requested OID is CSSMOID_UserID,
411 * look for a matching X.500 UserID OID: (0.9.2342.19200300.100.1.1) */
412 const char cssm_userid_oid[] = { 0x09,0x49,0x86,0x49,0x1f,0x12,0x8c,0xe4,0x81,0x81 };
413 const char x500_userid_oid[] = { 0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x01 };
414 if(!(tvpType->Length == sizeof(cssm_userid_oid) &&
415 !memcmp(tvpPtr->type.Data, x500_userid_oid, sizeof(x500_userid_oid)) &&
416 !memcmp(tvpType->Data, cssm_userid_oid, sizeof(cssm_userid_oid)))) {
417 continue;
418 }
419 }
420 }
421
422 /* printable? */
423 switch(tvpPtr->valueType) {
424 case BER_TAG_PRINTABLE_STRING:
425 case BER_TAG_IA5_STRING:
426 *encoding = kCFStringEncodingASCII;
427 result = &tvpPtr->value;
428 break;
429 case BER_TAG_PKIX_UTF8_STRING:
430 case BER_TAG_GENERAL_STRING:
431 case BER_TAG_PKIX_UNIVERSAL_STRING:
432 *encoding = kCFStringEncodingUTF8;
433 result = &tvpPtr->value;
434 break;
435 case BER_TAG_T61_STRING:
436 case BER_TAG_VIDEOTEX_STRING:
437 case BER_TAG_ISO646_STRING:
438 *encoding = kCFStringEncodingISOLatin1;
439 result = &tvpPtr->value;
440 break;
441 case BER_TAG_PKIX_BMP_STRING:
442 *encoding = kCFStringEncodingUnicode;
443 result = &tvpPtr->value;
444 break;
445 default:
446 /* not printable */
447 break;
448 }
449 /* if we found a result and we want the first instance, return it now. */
450 if(result && !lastInstance) {
451 return result;
452 }
453
454 } /* for each pair */
455 } /* for each RDN */
456
457 /* result is NULL if no printable component was found */
458 return result;
459 }
460
461 /*
462 * Infer printable label for a given CSSM_X509_NAME. Returns NULL
463 * if no appropriate printable name found. Returns the CFString-style
464 * encoding associated with name component's BER tag. Also optionally
465 * returns Description component and its encoding if present and the
466 * returned name component was one we explicitly requested.
467 */
468 static const CSSM_DATA *inferLabelFromX509Name(
469 const CSSM_X509_NAME *x509Name,
470 CFStringBuiltInEncodings *encoding, // RETURNED
471 const CSSM_DATA **description, // optionally RETURNED
472 CFStringBuiltInEncodings *descrEncoding) // RETURNED if description != NULL
473 {
474 const CSSM_DATA *printValue;
475 if(description != NULL) {
476 *description = findPrintableField(*x509Name, &CSSMOID_Description, false, descrEncoding);
477 }
478 /*
479 * Search order (take the first one found with a printable
480 * value):
481 * -- common name
482 * -- Organizational Unit
483 * -- Organization
484 * -- email address
485 * -- field of any kind
486 */
487 printValue = findPrintableField(*x509Name, &CSSMOID_CommonName, true, encoding);
488 if(printValue != NULL) {
489 return printValue;
490 }
491 printValue = findPrintableField(*x509Name, &CSSMOID_OrganizationalUnitName, false, encoding);
492 if(printValue != NULL) {
493 return printValue;
494 }
495 printValue = findPrintableField(*x509Name, &CSSMOID_OrganizationName, false, encoding);
496 if(printValue != NULL) {
497 return printValue;
498 }
499 printValue = findPrintableField(*x509Name, &CSSMOID_EmailAddress, false, encoding);
500 if(printValue != NULL) {
501 return printValue;
502 }
503 /* if we didn't get one of the above names, don't append description */
504 if(description != NULL) {
505 *description = NULL;
506 }
507 /* take anything */
508 return findPrintableField(*x509Name, NULL, false, encoding);
509 }
510
511 /*
512 * Infer printable label for a given an CSSM_X509_NAME. Returns NULL
513 * if no appropriate printable name found.
514 */
515 const CSSM_DATA *SecInferLabelFromX509Name(
516 const CSSM_X509_NAME *x509Name)
517 {
518 /* callees of this routine don't care about the encoding */
519 CFStringBuiltInEncodings encoding = kCFStringEncodingASCII;
520 return inferLabelFromX509Name(x509Name, &encoding, NULL, &encoding);
521 }
522
523
524 void
525 Certificate::inferLabel(bool addLabel, CFStringRef *rtnString)
526 {
527 StLock<Mutex>_(mMutex);
528 // Set PrintName and optionally the Alias attribute for this certificate, based on the
529 // X509 SubjectAltName and SubjectName.
530 const CSSM_DATA *printName = NULL;
531 const CSSM_DATA *description = NULL;
532 std::vector<CssmData> emailAddresses;
533 CSSM_DATA puntData;
534 CssmAutoData printPlusDescr(Allocator::standard());
535 CssmData printPlusDescData;
536 CFStringBuiltInEncodings printEncoding = kCFStringEncodingUTF8;
537 CFStringBuiltInEncodings descrEncoding = kCFStringEncodingUTF8;
538
539 // Find the SubjectAltName fields, if any, and extract all the GNT_RFC822Name entries from all of them
540 const CSSM_OID &sanOid = CSSMOID_SubjectAltName;
541 CSSM_DATA_PTR *sanValues = copyFieldValues(sanOid);
542 const CSSM_OID &snOid = CSSMOID_X509V1SubjectNameCStruct;
543 CSSM_DATA_PTR snValue = copyFirstFieldValue(snOid);
544
545 getEmailAddresses(sanValues, snValue, emailAddresses);
546
547 if (snValue && snValue->Data)
548 {
549 const CSSM_X509_NAME &x509Name = *(const CSSM_X509_NAME *)snValue->Data;
550 printName = inferLabelFromX509Name(&x509Name, &printEncoding,
551 &description, &descrEncoding);
552 if (printName)
553 {
554 /* Don't ever use "Thawte Freemail Member" as the label for a cert. Instead force
555 a fall back on the email address. */
556 const char tfm[] = "Thawte Freemail Member";
557 if ( (printName->Length == sizeof(tfm) - 1) &&
558 !memcmp(printName->Data, tfm, sizeof(tfm) - 1)) {
559 printName = NULL;
560 }
561 }
562 }
563
564 /* Do a check to see if a '\0' was at the end of printName and strip it. */
565 CssmData cleanedUpPrintName;
566 if((printName != NULL) &&
567 (printName->Length != 0) &&
568 (printEncoding != kCFStringEncodingISOLatin1) &&
569 (printEncoding != kCFStringEncodingUnicode) &&
570 (printName->Data[printName->Length - 1] == '\0')) {
571 cleanedUpPrintName.Data = printName->Data;
572 cleanedUpPrintName.Length = printName->Length - 1;
573 printName = &cleanedUpPrintName;
574 }
575
576 if((printName != NULL) && (description != NULL) && (description->Length != 0))
577 {
578 /*
579 * Munge Print Name (which in this case is the CommonName) and Description
580 * together with the Description in parentheses. We convert from whatever
581 * format Print Name and Description are in to UTF8 here.
582 */
583 CFRef<CFMutableStringRef> combo(CFStringCreateMutable(NULL, 0));
584 CFRef<CFStringRef> cfPrint(CFStringCreateWithBytes(NULL, printName->Data,
585 (CFIndex)printName->Length, printEncoding, true));
586 CssmData cleanedUpDescr(description->Data, description->Length);
587 if ((cleanedUpDescr.Data[cleanedUpDescr.Length - 1] == '\0') &&
588 (descrEncoding != kCFStringEncodingISOLatin1) &&
589 (descrEncoding != kCFStringEncodingUnicode)) {
590 cleanedUpDescr.Length--;
591 }
592 CFRef<CFStringRef> cfDesc(CFStringCreateWithBytes(NULL, cleanedUpDescr.Data,
593 (CFIndex)cleanedUpDescr.Length, descrEncoding, true));
594 CFStringAppend(combo, cfPrint);
595 CFStringAppendCString(combo, " (", kCFStringEncodingASCII);
596 CFStringAppend(combo, cfDesc);
597 CFStringAppendCString(combo, ")", kCFStringEncodingASCII);
598 CFRef<CFDataRef> comboData(CFStringCreateExternalRepresentation(NULL, combo,
599 kCFStringEncodingUTF8, 0));
600 printPlusDescr.copy(CFDataGetBytePtr(comboData), CFDataGetLength(comboData));
601 printPlusDescData = printPlusDescr;
602 printName = &printPlusDescData;
603 printEncoding = kCFStringEncodingUTF8;
604 }
605
606 if (printName == NULL)
607 {
608 /* If the we couldn't find a label use the emailAddress instead. */
609 if (!emailAddresses.empty())
610 printName = &emailAddresses[0];
611 else
612 {
613 /* punt! */
614 puntData.Data = (uint8 *)"X509 Certificate";
615 puntData.Length = 16;
616 printName = &puntData;
617 }
618 printEncoding = kCFStringEncodingUTF8;
619 }
620
621 /* If we couldn't find an email address just use the printName which might be the url or something else useful. */
622 if (emailAddresses.empty())
623 emailAddresses.push_back(CssmData::overlay(*printName));
624
625 /* What do we do with the inferred label - return it or add it mDbAttributes? */
626 if (addLabel)
627 {
628 mDbAttributes->add(Schema::kX509CertificatePrintName, *printName);
629 CssmDbAttributeData &attrData = mDbAttributes->add(Schema::kX509CertificateAlias);
630
631 /* Add the email addresses to attrData and normalize them. */
632 uint32 ix = 0;
633 for (std::vector<CssmData>::const_iterator it = emailAddresses.begin(); it != emailAddresses.end(); ++it, ++ix)
634 {
635 /* Add the email address using the allocator from mDbAttributes. */
636 attrData.add(*it, *mDbAttributes);
637 /* Normalize the emailAddresses in place since attrData already copied it. */
638 normalizeEmailAddress(attrData.Value[ix]);
639 }
640 }
641
642 if (rtnString)
643 {
644 CFStringBuiltInEncodings testEncoding = printEncoding;
645 if(testEncoding == kCFStringEncodingISOLatin1) {
646 // try UTF-8 first
647 testEncoding = kCFStringEncodingUTF8;
648 }
649 *rtnString = CFStringCreateWithBytes(NULL, printName->Data,
650 (CFIndex)printName->Length, testEncoding, true);
651 if(*rtnString == NULL && printEncoding == kCFStringEncodingISOLatin1) {
652 // string cannot be represented in UTF-8, fall back to ISO Latin 1
653 *rtnString = CFStringCreateWithBytes(NULL, printName->Data,
654 (CFIndex)printName->Length, printEncoding, true);
655 }
656 }
657
658 // Clean up
659 if (snValue)
660 releaseFieldValue(snOid, snValue);
661 if (sanValues)
662 releaseFieldValues(sanOid, sanValues);
663 }
664
665 void
666 Certificate::populateAttributes()
667 {
668 StLock<Mutex>_(mMutex);
669 if (mPopulated)
670 return;
671
672 addParsedAttribute(Schema::attributeInfo(kSecSubjectItemAttr), CSSMOID_X509V1SubjectName);
673 addParsedAttribute(Schema::attributeInfo(kSecIssuerItemAttr), CSSMOID_X509V1IssuerName);
674 addParsedAttribute(Schema::attributeInfo(kSecSerialNumberItemAttr), CSSMOID_X509V1SerialNumber);
675
676 addSubjectKeyIdentifier();
677
678 if(!mHaveTypeAndEncoding)
679 MacOSError::throwMe(errSecDataNotAvailable); // @@@ Or some other error.
680
681 // Adjust mType based on the actual version of the cert.
682 CSSM_DATA_PTR versionPtr = copyFirstFieldValue(CSSMOID_X509V1Version);
683 if (versionPtr && versionPtr->Data && versionPtr->Length == sizeof(uint32))
684 {
685 mType = CSSM_CERT_X_509v1 + (*reinterpret_cast<uint32 *>(versionPtr->Data));
686 }
687 else
688 mType = CSSM_CERT_X_509v1;
689
690 releaseFieldValue(CSSMOID_X509V1Version, versionPtr);
691
692 mDbAttributes->add(Schema::attributeInfo(kSecCertTypeItemAttr), mType);
693 mDbAttributes->add(Schema::attributeInfo(kSecCertEncodingItemAttr), mEncoding);
694 mDbAttributes->add(Schema::attributeInfo(kSecPublicKeyHashItemAttr), publicKeyHash());
695 inferLabel(true);
696
697 mPopulated = true;
698 }
699
700 const CssmData &
701 Certificate::data()
702 {
703 StLock<Mutex>_(mMutex);
704 CssmDataContainer *data = mData.get();
705 if (!data && mKeychain)
706 {
707 // Make sure mUniqueId is set.
708 dbUniqueRecord();
709 CssmDataContainer _data;
710 mData = NULL;
711 /* new data allocated by CSPDL, implicitly freed by CssmDataContainer */
712 mUniqueId->get(NULL, &_data);
713 /* this saves a copy to be freed at destruction and to be passed to caller */
714 setData(_data.length(), _data.data());
715 return *mData.get();
716 }
717
718 // If the data hasn't been set we can't return it.
719 if (!data)
720 MacOSError::throwMe(errSecDataNotAvailable);
721
722 return *data;
723 }
724
725 CSSM_CERT_TYPE
726 Certificate::type()
727 {
728 StLock<Mutex>_(mMutex);
729 if (!mHaveTypeAndEncoding)
730 {
731 SecKeychainAttribute attr;
732 attr.tag = kSecCertTypeItemAttr;
733 attr.data = &mType;
734 attr.length = sizeof(mType);
735 getAttribute(attr, NULL);
736 }
737
738 return mType;
739 }
740
741 CSSM_CERT_ENCODING
742 Certificate::encoding()
743 {
744 StLock<Mutex>_(mMutex);
745 if (!mHaveTypeAndEncoding)
746 {
747 SecKeychainAttribute attr;
748 attr.tag = kSecCertEncodingItemAttr;
749 attr.data = &mEncoding;
750 attr.length = sizeof(mEncoding);
751 getAttribute(attr, NULL);
752 }
753
754 return mEncoding;
755 }
756
757 const CSSM_X509_ALGORITHM_IDENTIFIER_PTR
758 Certificate::algorithmID()
759 {
760 StLock<Mutex>_(mMutex);
761 if (!mV1SubjectPublicKeyCStructValue)
762 mV1SubjectPublicKeyCStructValue = copyFirstFieldValue(CSSMOID_X509V1SubjectPublicKeyCStruct);
763
764 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO *info = (CSSM_X509_SUBJECT_PUBLIC_KEY_INFO *)mV1SubjectPublicKeyCStructValue->Data;
765 CSSM_X509_ALGORITHM_IDENTIFIER *algid = &info->algorithm;
766 return algid;
767 }
768
769 CFStringRef
770 Certificate::commonName()
771 {
772 StLock<Mutex>_(mMutex);
773 return distinguishedName(&CSSMOID_X509V1SubjectNameCStruct, &CSSMOID_CommonName);
774 }
775
776 CFStringRef
777 Certificate::distinguishedName(const CSSM_OID *sourceOid, const CSSM_OID *componentOid)
778 {
779 StLock<Mutex>_(mMutex);
780 CFStringRef rtnString = NULL;
781 CSSM_DATA_PTR fieldValue = copyFirstFieldValue(*sourceOid);
782 CSSM_X509_NAME_PTR x509Name = (CSSM_X509_NAME_PTR)fieldValue->Data;
783 const CSSM_DATA *printValue = NULL;
784 CFStringBuiltInEncodings encoding;
785
786 if (fieldValue && fieldValue->Data)
787 printValue = findPrintableField(*x509Name, componentOid, true, &encoding);
788
789 if (printValue)
790 rtnString = CFStringCreateWithBytes(NULL, printValue->Data,
791 CFIndex(printValue->Length), encoding, true);
792
793 releaseFieldValue(*sourceOid, fieldValue);
794
795 return rtnString;
796 }
797
798
799 /*
800 * Return a CFString containing the first email addresses for this certificate, based on the
801 * X509 SubjectAltName and SubjectName.
802 */
803 CFStringRef
804 Certificate::copyFirstEmailAddress()
805 {
806 StLock<Mutex>_(mMutex);
807 CFStringRef rtnString;
808
809 const CSSM_OID &sanOid = CSSMOID_SubjectAltName;
810 CSSM_DATA_PTR *sanValues = copyFieldValues(sanOid);
811 const CSSM_OID &snOid = CSSMOID_X509V1SubjectNameCStruct;
812 CSSM_DATA_PTR snValue = copyFirstFieldValue(snOid);
813 std::vector<CssmData> emailAddresses;
814
815 getEmailAddresses(sanValues, snValue, emailAddresses);
816 if (emailAddresses.empty())
817 rtnString = NULL;
818 else
819 {
820 /* Encoding is kCFStringEncodingUTF8 since the string is either
821 PRINTABLE_STRING, IA5_STRING, T61_STRING or PKIX_UTF8_STRING. */
822 rtnString = CFStringCreateWithBytes(NULL, emailAddresses[0].Data,
823 (CFIndex)emailAddresses[0].Length, kCFStringEncodingUTF8, true);
824 }
825
826 // Clean up
827 if (snValue)
828 releaseFieldValue(snOid, snValue);
829 if (sanValues)
830 releaseFieldValues(sanOid, sanValues);
831
832 return rtnString;
833 }
834
835 /*
836 * Return a CFArray containing the email addresses for this certificate, based on the
837 * X509 SubjectAltName and SubjectName.
838 */
839 CFArrayRef
840 Certificate::copyEmailAddresses()
841 {
842 StLock<Mutex>_(mMutex);
843 CFMutableArrayRef array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
844 std::vector<CssmData> emailAddresses;
845
846 // Find the SubjectAltName fields, if any, and extract all the GNT_RFC822Name entries from all of them
847 const CSSM_OID &sanOid = CSSMOID_SubjectAltName;
848 CSSM_DATA_PTR *sanValues = copyFieldValues(sanOid);
849
850 const CSSM_OID &snOid = CSSMOID_X509V1SubjectNameCStruct;
851 CSSM_DATA_PTR snValue = copyFirstFieldValue(snOid);
852
853 getEmailAddresses(sanValues, snValue, emailAddresses);
854
855 for (std::vector<CssmData>::const_iterator it = emailAddresses.begin(); it != emailAddresses.end(); ++it)
856 {
857 /* Encoding is kCFStringEncodingUTF8 since the string is either
858 PRINTABLE_STRING, IA5_STRING, T61_STRING or PKIX_UTF8_STRING. */
859 CFStringRef string = CFStringCreateWithBytes(NULL, it->Data, static_cast<CFIndex>(it->Length), kCFStringEncodingUTF8, true);
860 CFArrayAppendValue(array, string);
861 CFRelease(string);
862 }
863
864 // Clean up
865 if (snValue)
866 releaseFieldValue(snOid, snValue);
867 if (sanValues)
868 releaseFieldValues(sanOid, sanValues);
869
870 return array;
871 }
872
873 const CSSM_X509_NAME_PTR
874 Certificate::subjectName()
875 {
876 StLock<Mutex>_(mMutex);
877 if (!mV1SubjectNameCStructValue)
878 if ((mV1SubjectNameCStructValue = copyFirstFieldValue(CSSMOID_X509V1SubjectNameCStruct)) == NULL)
879 return NULL;
880
881 return (const CSSM_X509_NAME_PTR)mV1SubjectNameCStructValue->Data;
882 }
883
884 const CSSM_X509_NAME_PTR
885 Certificate::issuerName()
886 {
887 StLock<Mutex>_(mMutex);
888 if (!mV1IssuerNameCStructValue)
889 if ((mV1IssuerNameCStructValue = copyFirstFieldValue(CSSMOID_X509V1IssuerNameCStruct)) == NULL)
890 return NULL;
891
892 return (const CSSM_X509_NAME_PTR)mV1IssuerNameCStructValue->Data;
893 }
894
895 CSSM_CL_HANDLE
896 Certificate::clHandle()
897 {
898 StLock<Mutex>_(mMutex);
899 if (!mCL)
900 mCL = clForType(type());
901
902 return mCL->handle();
903 }
904
905 bool
906 Certificate::operator < (Certificate &other)
907 {
908 // Certificates in different keychains are considered equal if data is equal
909 // Note that the Identity '<' operator relies on this assumption.
910 return data() < other.data();
911 }
912
913 bool
914 Certificate::operator == (Certificate &other)
915 {
916 // Certificates in different keychains are considered equal if data is equal
917 // Note that the Identity '==' operator relies on this assumption.
918 return data() == other.data();
919 }
920
921 bool
922 Certificate::equal(SecCFObject &other)
923 {
924 return (*this) == (Certificate &)other;
925 }
926
927 void
928 Certificate::update()
929 {
930 ItemImpl::update();
931 }
932
933 Item
934 Certificate::copyTo(const Keychain &keychain, Access *newAccess)
935 {
936 StLock<Mutex>_(mMutex);
937 /* Certs can't have access controls. */
938 if (newAccess)
939 MacOSError::throwMe(errSecNoAccessForItem);
940
941 Item item(new Certificate(data(), type(), encoding()));
942 keychain->add(item);
943 return item;
944 }
945
946 void
947 Certificate::didModify()
948 {
949 }
950
951 PrimaryKey
952 Certificate::add(Keychain &keychain)
953 {
954 StLock<Mutex>_(mMutex);
955 // If we already have a Keychain we can't be added.
956 if (mKeychain)
957 MacOSError::throwMe(errSecDuplicateItem);
958
959 populateAttributes();
960
961 CSSM_DB_RECORDTYPE recordType = mDbAttributes->recordType();
962
963 Db db(keychain->database());
964 // add the item to the (regular) db
965 try
966 {
967 mUniqueId = db->insert(recordType, mDbAttributes.get(), mData.get());
968 }
969 catch (const CssmError &e)
970 {
971 if (e.osStatus() != CSSMERR_DL_INVALID_RECORDTYPE)
972 throw;
973
974 // Create the cert relation and try again.
975 db->createRelation(CSSM_DL_DB_RECORD_X509_CERTIFICATE,
976 "CSSM_DL_DB_RECORD_X509_CERTIFICATE",
977 Schema::X509CertificateSchemaAttributeCount,
978 Schema::X509CertificateSchemaAttributeList,
979 Schema::X509CertificateSchemaIndexCount,
980 Schema::X509CertificateSchemaIndexList);
981 keychain->keychainSchema()->didCreateRelation(
982 CSSM_DL_DB_RECORD_X509_CERTIFICATE,
983 "CSSM_DL_DB_RECORD_X509_CERTIFICATE",
984 Schema::X509CertificateSchemaAttributeCount,
985 Schema::X509CertificateSchemaAttributeList,
986 Schema::X509CertificateSchemaIndexCount,
987 Schema::X509CertificateSchemaIndexList);
988
989 mUniqueId = db->insert(recordType, mDbAttributes.get(), mData.get());
990 }
991
992 mPrimaryKey = keychain->makePrimaryKey(recordType, mUniqueId);
993 mKeychain = keychain;
994
995 return mPrimaryKey;
996 }
997
998 SecPointer<KeyItem>
999 Certificate::publicKey()
1000 {
1001 StLock<Mutex>_(mMutex);
1002 SecPointer<KeyItem> keyItem;
1003 // Return a CSSM_DATA_PTR with the value of the first field specified by field.
1004 // Caller must call releaseFieldValue to free the storage allocated by this call.
1005 // call OSStatus SecKeyGetCSSMKey(SecKeyRef key, const CSSM_KEY **cssmKey); to retrieve
1006
1007 CSSM_DATA_PTR keyPtr = copyFirstFieldValue(CSSMOID_CSSMKeyStruct);
1008 if (keyPtr && keyPtr->Data)
1009 {
1010 CssmClient::CSP csp(gGuidAppleCSP);
1011 CssmKey *cssmKey = reinterpret_cast<CssmKey *>(keyPtr->Data);
1012 CssmClient::Key key(csp, *cssmKey);
1013 keyItem = new KeyItem(key);
1014 // Clear out KeyData since KeyItem() takes over ownership of the key, and we don't want it getting released.
1015 cssmKey->KeyData.Data = NULL;
1016 cssmKey->KeyData.Length = 0;
1017 }
1018
1019 releaseFieldValue(CSSMOID_CSSMKeyStruct, keyPtr);
1020
1021 return keyItem;
1022 }
1023
1024 // This function "borrowed" from the X509 CL, which is (currently) linked into
1025 // the Security.framework as a built-in plugin.
1026 extern "C" bool getField_normRDN_NSS (
1027 const CSSM_DATA &derName,
1028 uint32 &numFields, // RETURNED (if successful, 0 or 1)
1029 CssmOwnedData &fieldValue); // RETURNED
1030
1031 KCCursor
1032 Certificate::cursorForIssuerAndSN(const StorageManager::KeychainList &keychains, const CssmData &issuer, const CssmData &serialNumber)
1033 {
1034 CssmAutoData fieldValue(Allocator::standard(Allocator::normal));
1035 uint32 numFields;
1036
1037 // We need to decode issuer, normalize it, then re-encode it
1038 if (!getField_normRDN_NSS(issuer, numFields, fieldValue))
1039 MacOSError::throwMe(errSecDataNotAvailable);
1040
1041 // Code basically copied from SecKeychainSearchCreateFromAttributes and SecKeychainSearchCopyNext:
1042 KCCursor cursor(keychains, kSecCertificateItemClass, NULL);
1043 cursor->conjunctive(CSSM_DB_AND);
1044 cursor->add(CSSM_DB_EQUAL, Schema::kX509CertificateIssuer, fieldValue.get());
1045 cursor->add(CSSM_DB_EQUAL, Schema::kX509CertificateSerialNumber, serialNumber);
1046
1047 return cursor;
1048 }
1049
1050 KCCursor
1051 Certificate::cursorForIssuerAndSN_CF(const StorageManager::KeychainList &keychains, CFDataRef issuer, CFDataRef serialNumber)
1052 {
1053 // This assumes a normalized issuer
1054 CSSM_DATA issuerCSSM, serialNumberCSSM;
1055
1056 issuerCSSM.Length = CFDataGetLength(issuer);
1057 issuerCSSM.Data = const_cast<uint8 *>(CFDataGetBytePtr(issuer));
1058
1059 serialNumberCSSM.Length = CFDataGetLength(serialNumber);
1060 serialNumberCSSM.Data = const_cast<uint8 *>(CFDataGetBytePtr(serialNumber));
1061
1062 // Code basically copied from SecKeychainSearchCreateFromAttributes and SecKeychainSearchCopyNext:
1063 KCCursor cursor(keychains, kSecCertificateItemClass, NULL);
1064 cursor->conjunctive(CSSM_DB_AND);
1065 cursor->add(CSSM_DB_EQUAL, Schema::kX509CertificateIssuer, issuerCSSM);
1066 cursor->add(CSSM_DB_EQUAL, Schema::kX509CertificateSerialNumber, serialNumberCSSM);
1067
1068 return cursor;
1069 }
1070
1071 KCCursor
1072 Certificate::cursorForSubjectKeyID(const StorageManager::KeychainList &keychains, const CssmData &subjectKeyID)
1073 {
1074 KCCursor cursor(keychains, kSecCertificateItemClass, NULL);
1075 cursor->conjunctive(CSSM_DB_AND);
1076 cursor->add(CSSM_DB_EQUAL, Schema::kX509CertificateSubjectKeyIdentifier, subjectKeyID);
1077
1078 return cursor;
1079 }
1080
1081 KCCursor
1082 Certificate::cursorForEmail(const StorageManager::KeychainList &keychains, const char *emailAddress)
1083 {
1084 KCCursor cursor(keychains, kSecCertificateItemClass, NULL);
1085 if (emailAddress)
1086 {
1087 cursor->conjunctive(CSSM_DB_AND);
1088 CssmSelectionPredicate &pred = cursor->add(CSSM_DB_EQUAL, Schema::kX509CertificateAlias, emailAddress);
1089 /* Normalize the emailAddresses in place since cursor already copied it. */
1090 normalizeEmailAddress(pred.Attribute.Value[0]);
1091 }
1092
1093 return cursor;
1094 }
1095
1096 SecPointer<Certificate>
1097 Certificate::findInKeychain(const StorageManager::KeychainList &keychains)
1098 {
1099 StLock<Mutex>_(mMutex);
1100 const CSSM_OID &issuerOid = CSSMOID_X509V1IssuerName;
1101 CSSM_DATA_PTR issuerPtr = copyFirstFieldValue(issuerOid);
1102 CssmData issuer(issuerPtr->Data, issuerPtr->Length);
1103
1104 const CSSM_OID &serialOid = CSSMOID_X509V1SerialNumber;
1105 CSSM_DATA_PTR serialPtr = copyFirstFieldValue(serialOid);
1106 CssmData serial(serialPtr->Data, serialPtr->Length);
1107
1108 SecPointer<Certificate> foundCert = NULL;
1109 try {
1110 foundCert = findByIssuerAndSN(keychains, issuer, serial);
1111 } catch (...) {
1112 foundCert = NULL;
1113 }
1114
1115 releaseFieldValue(issuerOid, issuerPtr);
1116 releaseFieldValue(serialOid, serialPtr);
1117
1118 return foundCert;
1119 }
1120
1121 SecPointer<Certificate>
1122 Certificate::findByIssuerAndSN(const StorageManager::KeychainList &keychains, const CssmData &issuer, const CssmData &serialNumber)
1123 {
1124 Item item;
1125 if (!cursorForIssuerAndSN(keychains, issuer, serialNumber)->next(item))
1126 CssmError::throwMe(errSecItemNotFound);
1127
1128 return static_cast<Certificate *>(&*item);
1129 }
1130
1131 SecPointer<Certificate>
1132 Certificate::findBySubjectKeyID(const StorageManager::KeychainList &keychains, const CssmData &subjectKeyID)
1133 {
1134 Item item;
1135 if (!cursorForSubjectKeyID(keychains, subjectKeyID)->next(item))
1136 CssmError::throwMe(errSecItemNotFound);
1137
1138 return static_cast<Certificate *>(&*item);
1139 }
1140
1141 SecPointer<Certificate>
1142 Certificate::findByEmail(const StorageManager::KeychainList &keychains, const char *emailAddress)
1143 {
1144 Item item;
1145 if (!cursorForEmail(keychains, emailAddress)->next(item))
1146 CssmError::throwMe(errSecItemNotFound);
1147
1148 return static_cast<Certificate *>(&*item);
1149 }
1150
1151 /* Normalize emailAddresses in place. */
1152 void
1153 Certificate::normalizeEmailAddress(CSSM_DATA &emailAddress)
1154 {
1155 /* Do a check to see if a '\0' was at the end of emailAddress and strip it. */
1156 if (emailAddress.Length && emailAddress.Data[emailAddress.Length - 1] == '\0')
1157 emailAddress.Length--;
1158 bool foundAt = false;
1159 for (uint32 ix = 0; ix < emailAddress.Length; ++ix)
1160 {
1161 uint8 ch = emailAddress.Data[ix];
1162 if (foundAt)
1163 {
1164 if ('A' <= ch && ch <= 'Z')
1165 emailAddress.Data[ix] = ch + 'a' - 'A';
1166 }
1167 else if (ch == '@')
1168 foundAt = true;
1169 }
1170 }
1171
1172 void
1173 Certificate::getEmailAddresses(CSSM_DATA_PTR *sanValues, CSSM_DATA_PTR snValue, std::vector<CssmData> &emailAddresses)
1174 {
1175 // Get the email addresses for this certificate, based on the
1176 // X509 SubjectAltName and SubjectName.
1177
1178 // Find the SubjectAltName fields, if any, and extract all the GNT_RFC822Name entries from all of them
1179 if (sanValues)
1180 {
1181 for (CSSM_DATA_PTR *sanIx = sanValues; *sanIx; ++sanIx)
1182 {
1183 CSSM_DATA_PTR sanValue = *sanIx;
1184 if (sanValue && sanValue->Data)
1185 {
1186 CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)sanValue->Data;
1187 CE_GeneralNames *parsedValue = (CE_GeneralNames *)cssmExt->value.parsedValue;
1188
1189 /* Grab all the values that are of type GNT_RFC822Name. */
1190 for (uint32 i = 0; i < parsedValue->numNames; ++i)
1191 {
1192 if (parsedValue->generalName[i].nameType == GNT_RFC822Name)
1193 {
1194 if (parsedValue->generalName[i].berEncoded) // can't handle this
1195 continue;
1196
1197 emailAddresses.push_back(CssmData::overlay(parsedValue->generalName[i].name));
1198 }
1199 }
1200 }
1201 }
1202 }
1203
1204 if (emailAddresses.empty() && snValue && snValue->Data)
1205 {
1206 const CSSM_X509_NAME &x509Name = *(const CSSM_X509_NAME *)snValue->Data;
1207 for (uint32 rdnDex = 0; rdnDex < x509Name.numberOfRDNs; rdnDex++)
1208 {
1209 const CSSM_X509_RDN *rdnPtr =
1210 &x509Name.RelativeDistinguishedName[rdnDex];
1211 for (uint32 tvpDex = 0; tvpDex < rdnPtr->numberOfPairs; tvpDex++)
1212 {
1213 const CSSM_X509_TYPE_VALUE_PAIR *tvpPtr =
1214 &rdnPtr->AttributeTypeAndValue[tvpDex];
1215
1216 /* type/value pair: match caller's specified type? */
1217 if (((tvpPtr->type.Length != CSSMOID_EmailAddress.Length) ||
1218 memcmp(tvpPtr->type.Data, CSSMOID_EmailAddress.Data, CSSMOID_EmailAddress.Length))) {
1219 continue;
1220 }
1221
1222 /* printable? */
1223 switch (tvpPtr->valueType)
1224 {
1225 case BER_TAG_PRINTABLE_STRING:
1226 case BER_TAG_IA5_STRING:
1227 case BER_TAG_T61_STRING:
1228 case BER_TAG_PKIX_UTF8_STRING:
1229 /* success */
1230 emailAddresses.push_back(CssmData::overlay(tvpPtr->value));
1231 break;
1232 default:
1233 break;
1234 }
1235 } /* for each pair */
1236 } /* for each RDN */
1237 }
1238 }
1239
1240 void Certificate::willRead()
1241 {
1242 populateAttributes();
1243 }
1244
1245 Boolean Certificate::isSelfSigned()
1246 {
1247 StLock<Mutex>_(mMutex);
1248 CSSM_DATA_PTR issuer = NULL;
1249 CSSM_DATA_PTR subject = NULL;
1250 OSStatus ortn = noErr;
1251 Boolean brtn = false;
1252
1253 issuer = copyFirstFieldValue(CSSMOID_X509V1IssuerNameStd);
1254 subject = copyFirstFieldValue(CSSMOID_X509V1SubjectNameStd);
1255 if((issuer == NULL) || (subject == NULL)) {
1256 ortn = paramErr;
1257 }
1258 else if((issuer->Length == subject->Length) &&
1259 !memcmp(issuer->Data, subject->Data, issuer->Length)) {
1260 brtn = true;
1261 }
1262 if(brtn) {
1263 /* names match: verify signature */
1264 CSSM_RETURN crtn;
1265 CSSM_DATA certData = data();
1266 crtn = CSSM_CL_CertVerify(clHandle(), 0,
1267 &certData, &certData, NULL, 0);
1268 if(crtn) {
1269 brtn = false;
1270 }
1271 }
1272 if(issuer) {
1273 releaseFieldValue(CSSMOID_X509V1IssuerNameStd, issuer);
1274 }
1275 if(subject) {
1276 releaseFieldValue(CSSMOID_X509V1SubjectNameStd, subject);
1277 }
1278 if(ortn) {
1279 MacOSError::throwMe(ortn);
1280 }
1281 return brtn;
1282 }