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