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