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