1/* 2 * Copyright (c) 2001-2013 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 * EAPCertificateUtil.c 26 * - certificate utility functions 27 */ 28 29 30/* 31 * Modification History 32 * 33 * April 2, 2004 Dieter Siegmund (dieter@apple.com) 34 * - created 35 */ 36 37#include <stdio.h> 38#include <stdlib.h> 39#include <unistd.h> 40#include <TargetConditionals.h> 41#include <Security/SecItem.h> 42#if ! TARGET_OS_EMBEDDED 43#include <Security/SecIdentitySearch.h> 44#include <Security/SecKeychain.h> 45#include <Security/SecKeychainItem.h> 46#include <Security/SecKeychainItemPriv.h> 47#include <Security/SecKeychainSearch.h> 48#include <Security/SecPolicySearch.h> 49#include <Security/oidsalg.h> 50#include <Security/oidscert.h> 51#include <Security/oidsattr.h> 52#include <Security/cssmapi.h> 53#include <Security/cssmapple.h> 54#include <Security/certextensions.h> 55#include <Security/cssmtype.h> 56#include <Security/x509defs.h> 57#include <Security/SecCertificateOIDs.h> 58#endif /* TARGET_OS_EMBEDDED */ 59#include <Security/SecIdentity.h> 60#include <Security/SecCertificate.h> 61#include <Security/SecCertificatePriv.h> 62#include <Security/SecTrust.h> 63#include <CoreFoundation/CFDictionary.h> 64#include <CoreFoundation/CFString.h> 65#include <CoreFoundation/CFNumber.h> 66#include <SystemConfiguration/SCValidation.h> 67#include <string.h> 68#include "EAPLog.h" 69#include "EAPTLSUtil.h" 70#include "EAPCertificateUtil.h" 71#include "EAPSecurity.h" 72#include "myCFUtil.h" 73 74#define kEAPSecIdentityHandleType CFSTR("IdentityHandleType") 75#define kEAPSecIdentityHandleTypeCertificateData CFSTR("CertificateData") 76#define kEAPSecIdentityHandleData CFSTR("IdentityHandleData") 77 78static __inline__ SecCertificateRef 79_EAPCFDataCreateSecCertificate(CFDataRef data_cf) 80{ 81 return (SecCertificateCreateWithData(NULL, data_cf)); 82} 83 84OSStatus 85EAPSecIdentityListCreate(CFArrayRef * ret_array) 86{ 87 const void * keys[] = { 88 kSecClass, 89 kSecReturnRef, 90 kSecMatchLimit 91 }; 92 CFDictionaryRef query; 93 CFTypeRef results = NULL; 94 OSStatus status = noErr; 95 const void * values[] = { 96 kSecClassIdentity, 97 kCFBooleanTrue, 98 kSecMatchLimitAll 99 }; 100 101 query = CFDictionaryCreate(NULL, keys, values, 102 sizeof(keys) / sizeof(*keys), 103 &kCFTypeDictionaryKeyCallBacks, 104 &kCFTypeDictionaryValueCallBacks); 105 status = SecItemCopyMatching(query, &results); 106 CFRelease(query); 107 if (status == noErr) { 108 *ret_array = results; 109 } 110 return (status); 111} 112 113/* 114 * Function: IdentityCreateFromDictionary 115 * 116 * Purpose: 117 * This function locates a SecIdentityRef matching the passed in 118 * EAPSecIdentityHandle, in the form of a dictionary. It also handles the 119 * NULL case i.e. find the first identity. 120 * 121 * Old EAPSecIdentityHandle's used a dictionary with two key/value 122 * pairs, one for the type, the second for the data corresponding to the 123 * entire certificate. 124 * 125 * This function grabs all of the identities, then finds a match, either 126 * the first identity (dict == NULL), or one that matches the given 127 * certificate. 128 * Returns: 129 * noErr and a non-NULL SecIdentityRef in *ret_identity if an identity 130 * was found, non-noErr otherwise. 131 */ 132static OSStatus 133IdentityCreateFromDictionary(CFDictionaryRef dict, 134 SecIdentityRef * ret_identity) 135{ 136 SecCertificateRef cert_to_match = NULL; 137 CFIndex count; 138 int i; 139 CFArrayRef identity_list; 140 OSStatus status; 141 142 *ret_identity = NULL; 143 if (dict != NULL) { 144 CFStringRef certid_type; 145 CFDataRef certid_data; 146 147 status = EINVAL; 148 certid_type = CFDictionaryGetValue(dict, kEAPSecIdentityHandleType); 149 if (isA_CFString(certid_type) == NULL) { 150 goto done; 151 } 152 if (!CFEqual(certid_type, kEAPSecIdentityHandleTypeCertificateData)) { 153 goto done; 154 } 155 certid_data = CFDictionaryGetValue(dict, kEAPSecIdentityHandleData); 156 if (isA_CFData(certid_data) == NULL) { 157 goto done; 158 } 159 cert_to_match = _EAPCFDataCreateSecCertificate(certid_data); 160 if (cert_to_match == NULL) { 161 goto done; 162 } 163 } 164 status = EAPSecIdentityListCreate(&identity_list); 165 if (status != noErr) { 166 goto done; 167 } 168 count = CFArrayGetCount(identity_list); 169 for (i = 0; *ret_identity == NULL && i < count; i++) { 170 SecIdentityRef identity; 171 SecCertificateRef this_cert; 172 173 identity = (SecIdentityRef)CFArrayGetValueAtIndex(identity_list, i); 174 if (cert_to_match == NULL) { 175 /* just return the first one */ 176 CFRetain(identity); 177 *ret_identity = identity; 178 break; 179 } 180 status = SecIdentityCopyCertificate(identity, &this_cert); 181 if (this_cert == NULL) { 182 EAPLOG_FL(LOG_NOTICE, 183 "SecIdentityCopyCertificate failed, %s (%d)", 184 EAPSecurityErrorString(status), (int)status); 185 break; 186 } 187 if (CFEqual(cert_to_match, this_cert)) { 188 /* found a match */ 189 CFRetain(identity); 190 *ret_identity = identity; 191 } 192 CFRelease(this_cert); 193 } 194 CFRelease(identity_list); 195 196 done: 197 my_CFRelease(&cert_to_match); 198 return (status); 199} 200 201#if TARGET_OS_EMBEDDED 202 203static OSStatus 204IdentityCreateFromData(CFDataRef data, SecIdentityRef * ret_identity) 205{ 206 const void * keys[] = { 207 kSecClass, 208 kSecReturnRef, 209 kSecValuePersistentRef 210 }; 211 CFDictionaryRef query; 212 CFTypeRef results = NULL; 213 OSStatus status = noErr; 214 const void * values[] = { 215 kSecClassIdentity, 216 kCFBooleanTrue, 217 data 218 }; 219 220 *ret_identity = NULL; 221 query = CFDictionaryCreate(NULL, keys, values, 222 sizeof(keys) / sizeof(*keys), 223 &kCFTypeDictionaryKeyCallBacks, 224 &kCFTypeDictionaryValueCallBacks); 225 status = SecItemCopyMatching(query, &results); 226 CFRelease(query); 227 if (status == noErr) { 228 *ret_identity = (SecIdentityRef)results; 229 } 230 return (status); 231} 232 233#else /* TARGET_OS_EMBEDDED */ 234 235static OSStatus 236IdentityCreateFromData(CFDataRef data, SecIdentityRef * ret_identity) 237{ 238 SecKeychainItemRef cert; 239 OSStatus status; 240 241 status = SecKeychainItemCopyFromPersistentReference(data, &cert); 242 if (status != noErr) { 243 return (status); 244 } 245 status = SecIdentityCreateWithCertificate(NULL, 246 (SecCertificateRef) cert, 247 ret_identity); 248 CFRelease(cert); 249 return (status); 250} 251 252#endif /* TARGET_OS_EMBEDDED */ 253 254/* 255 * Function: EAPSecIdentityHandleCreateSecIdentity 256 * Purpose: 257 * Creates a SecIdentityRef for the given EAPSecIdentityHandle. 258 * 259 * The handle 'cert_id' is NULL, a non-NULL dictionary, or a non-NULL data. 260 * Any other input is invalid. 261 * 262 * Returns: 263 * noErr and !NULL *ret_identity on success, non-noErr otherwise. 264 */ 265OSStatus 266EAPSecIdentityHandleCreateSecIdentity(EAPSecIdentityHandleRef cert_id, 267 SecIdentityRef * ret_identity) 268{ 269 *ret_identity = NULL; 270 if (cert_id == NULL 271 || isA_CFDictionary(cert_id) != NULL) { 272 return (IdentityCreateFromDictionary(cert_id, ret_identity)); 273 } 274 if (isA_CFData(cert_id) != NULL) { 275 return (IdentityCreateFromData((CFDataRef)cert_id, ret_identity)); 276 } 277 return (EINVAL); 278} 279 280static OSStatus 281EAPSecIdentityCreateCertificateTrustChain(SecIdentityRef identity, 282 CFArrayRef * ret_chain) 283{ 284 SecCertificateRef cert; 285 CFArrayRef certs; 286 SecPolicyRef policy = NULL; 287 OSStatus status; 288 SecTrustRef trust = NULL; 289 SecTrustResultType trust_result; 290 291 *ret_chain = NULL; 292 status = EAPSecPolicyCopy(&policy); 293 if (status != noErr) { 294 EAPLOG_FL(LOG_NOTICE, "EAPSecPolicyCopy failed: %s (%d)", 295 EAPSecurityErrorString(status), (int)status); 296 goto done; 297 } 298 status = SecIdentityCopyCertificate(identity, &cert); 299 if (status != noErr) { 300 EAPLOG_FL(LOG_NOTICE, "SecIdentityCopyCertificate failed: %s (%d)", 301 EAPSecurityErrorString(status), (int)status); 302 goto done; 303 } 304 certs = CFArrayCreate(NULL, (const void **)&cert, 305 1, &kCFTypeArrayCallBacks); 306 my_CFRelease(&cert); 307 status = SecTrustCreateWithCertificates(certs, policy, &trust); 308 my_CFRelease(&certs); 309 if (status != noErr) { 310 EAPLOG_FL(LOG_NOTICE, "SecTrustCreateWithCertificates failed: %s (%d)", 311 EAPSecurityErrorString(status), (int)status); 312 goto done; 313 } 314 status = SecTrustEvaluate(trust, &trust_result); 315 if (status != noErr) { 316 EAPLOG_FL(LOG_NOTICE, "SecTrustEvaluate returned %s (%d)", 317 EAPSecurityErrorString(status), (int)status); 318 } 319 { 320 CFMutableArrayRef array; 321 CFIndex count = SecTrustGetCertificateCount(trust); 322 int i; 323 324 if (count == 0) { 325 EAPLOG_FL(LOG_NOTICE, "SecTrustGetCertificateCount returned 0"); 326 goto done; 327 } 328 array = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks); 329 for (i = 0; i < count; i++) { 330 SecCertificateRef s; 331 332 s = SecTrustGetCertificateAtIndex(trust, i); 333 CFArrayAppendValue(array, s); 334 } 335 *ret_chain = array; 336 } 337 338 done: 339 my_CFRelease(&trust); 340 my_CFRelease(&policy); 341 return (status); 342} 343 344/* 345 * Function: EAPSecIdentityCreateTrustChain 346 * 347 * Purpose: 348 * Turns an SecIdentityRef into the array required by 349 * SSLSetCertificates(). See the <Security/SecureTransport.h> for more 350 * information. 351 * 352 * Returns: 353 * noErr and *ret_array != NULL on success, non-noErr otherwise. 354 */ 355OSStatus 356EAPSecIdentityCreateTrustChain(SecIdentityRef identity, CFArrayRef * ret_array) 357{ 358 CFMutableArrayRef array = NULL; 359 CFIndex count; 360 OSStatus status; 361 CFArrayRef trust_chain = NULL; 362 363 *ret_array = NULL; 364 status = EAPSecIdentityCreateCertificateTrustChain(identity, 365 &trust_chain); 366 if (status != noErr) { 367 EAPLOG_FL(LOG_NOTICE, 368 "EAPSecIdentityCreateCertificateTrustChain failed: %s (%d)", 369 EAPSecurityErrorString(status), (int)status); 370 goto done; 371 } 372 373 count = CFArrayGetCount(trust_chain); 374 array = CFArrayCreateMutableCopy(NULL, count, trust_chain); 375 /* array[0] contains the identity's cert, replace it with the identity */ 376 CFArraySetValueAtIndex(array, 0, identity); 377 *ret_array = array; 378 379 done: 380 my_CFRelease(&trust_chain); 381 return (status); 382} 383 384/* 385 * Function: EAPSecIdentityHandleCreateSecIdentityTrustChain 386 * 387 * Purpose: 388 * Turns an EAPSecIdentityHandle into the array required by 389 * SSLSetCertificates(). See the <Security/SecureTransport.h> for more 390 * information. 391 * 392 * Returns: 393 * noErr and *ret_array != NULL on success, non-noErr otherwise. 394 */ 395OSStatus 396EAPSecIdentityHandleCreateSecIdentityTrustChain(EAPSecIdentityHandleRef cert_id, 397 CFArrayRef * ret_array) 398{ 399 SecIdentityRef identity = NULL; 400 OSStatus status; 401 402 *ret_array = NULL; 403 status = EAPSecIdentityHandleCreateSecIdentity(cert_id, &identity); 404 if (status != noErr) { 405 goto done; 406 } 407 status = EAPSecIdentityCreateTrustChain(identity, ret_array); 408 409 done: 410 my_CFRelease(&identity); 411 return (status); 412} 413 414/* 415 * Function: EAPSecIdentityHandleCreate 416 * Purpose: 417 * Return the persistent reference for a given SecIdentityRef. 418 * Returns: 419 * !NULL SecIdentityRef on success, NULL otherwise. 420 */ 421 422#if TARGET_OS_EMBEDDED 423EAPSecIdentityHandleRef 424EAPSecIdentityHandleCreate(SecIdentityRef identity) 425{ 426 const void * keys[] = { 427 kSecReturnPersistentRef, 428 kSecValueRef 429 }; 430 CFDictionaryRef query; 431 CFTypeRef results = NULL; 432 OSStatus status = noErr; 433 const void * values[] = { 434 kCFBooleanTrue, 435 identity 436 }; 437 438 query = CFDictionaryCreate(NULL, keys, values, 439 sizeof(keys) / sizeof(*keys), 440 &kCFTypeDictionaryKeyCallBacks, 441 &kCFTypeDictionaryValueCallBacks); 442 status = SecItemCopyMatching(query, &results); 443 if (status != noErr) { 444 results = NULL; 445 EAPLOG_FL(LOG_NOTICE, "EAPSecIdentityHandleCreate() failed, %d", 446 (int)status); 447 } 448 CFRelease(query); 449 return (results); 450} 451#else /* TARGET_OS_EMBEDDED */ 452EAPSecIdentityHandleRef 453EAPSecIdentityHandleCreate(SecIdentityRef identity) 454{ 455 SecCertificateRef cert; 456 CFDataRef data; 457 OSStatus status; 458 459 status = SecIdentityCopyCertificate(identity, &cert); 460 if (status != noErr) { 461 EAPLOG_FL(LOG_NOTICE, 462 "SecIdentityCopyCertificate failed, %s (%d)", 463 EAPSecurityErrorString(status), (int)status); 464 return (NULL); 465 } 466 status = SecKeychainItemCreatePersistentReference((SecKeychainItemRef)cert, 467 &data); 468 CFRelease(cert); 469 if (status != noErr) { 470 EAPLOG_FL(LOG_NOTICE, 471 "SecIdentityCopyCertificate failed, %s (%d)", 472 EAPSecurityErrorString(status), (int)status); 473 return (NULL); 474 } 475 return (data); 476} 477#endif /* TARGET_OS_EMBEDDED */ 478 479/* 480 * Function: EAPSecCertificateArrayCreateCFDataArray 481 * Purpose: 482 * Convert a CFArray[SecCertificate] to CFArray[CFData]. 483 */ 484CFArrayRef 485EAPSecCertificateArrayCreateCFDataArray(CFArrayRef certs) 486{ 487 CFMutableArrayRef array = NULL; 488 CFIndex count = CFArrayGetCount(certs); 489 int i; 490 491 array = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks); 492 for (i = 0; i < count; i++) { 493 SecCertificateRef cert; 494 CFDataRef data; 495 496 cert = (SecCertificateRef) 497 isA_SecCertificate(CFArrayGetValueAtIndex(certs, i)); 498 if (cert == NULL) { 499 continue; 500 } 501 data = SecCertificateCopyData(cert); 502 if (data == NULL) { 503 continue; 504 } 505 CFArrayAppendValue(array, data); 506 my_CFRelease(&data); 507 } 508 return (array); 509} 510 511/* 512 * Function: EAPCFDataArrayCreateSecCertificateArray 513 * Purpose: 514 * Convert a CFArray[CFData] to CFArray[SecCertificate]. 515 */ 516CFArrayRef 517EAPCFDataArrayCreateSecCertificateArray(CFArrayRef certs) 518{ 519 CFMutableArrayRef array = NULL; 520 CFIndex count = CFArrayGetCount(certs); 521 int i; 522 523 array = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks); 524 for (i = 0; i < count; i++) { 525 SecCertificateRef cert; 526 CFDataRef data; 527 528 data = isA_CFData((CFDataRef)CFArrayGetValueAtIndex(certs, i)); 529 if (data == NULL) { 530 goto failed; 531 } 532 cert = _EAPCFDataCreateSecCertificate(data); 533 if (cert == NULL) { 534 goto failed; 535 } 536 CFArrayAppendValue(array, cert); 537 my_CFRelease(&cert); 538 } 539 return (array); 540 541 failed: 542 my_CFRelease(&array); 543 return (NULL); 544} 545 546CFTypeRef 547isA_SecCertificate(CFTypeRef obj) 548{ 549 return (isA_CFType(obj, SecCertificateGetTypeID())); 550} 551 552 553#if TARGET_OS_EMBEDDED 554typedef CFArrayRef (*cert_names_func_t)(SecCertificateRef cert); 555static void 556dict_insert_cert_name_attr(CFMutableDictionaryRef dict, CFStringRef key, 557 cert_names_func_t func, SecCertificateRef cert) 558{ 559 CFArrayRef names; 560 561 names = (*func)(cert); 562 if (names != NULL) { 563 if (CFEqual(key, kEAPSecCertificateAttributeCommonName)) { 564 CFIndex count; 565 count = CFArrayGetCount(names); 566 CFDictionarySetValue(dict, 567 key, 568 CFArrayGetValueAtIndex(names, count - 1)); 569 } else { 570 CFDictionarySetValue(dict, 571 key, 572 CFArrayGetValueAtIndex(names, 0)); 573 } 574 CFRelease(names); 575 } 576 return; 577} 578typedef struct { 579 cert_names_func_t func; 580 CFStringRef key; 581} cert_names_func_info_t; 582 583CFDictionaryRef 584EAPSecCertificateCopyAttributesDictionary(const SecCertificateRef cert) 585{ 586 cert_names_func_info_t cert_names_info[] = { 587 { SecCertificateCopyRFC822Names, 588 kEAPSecCertificateAttributeRFC822Name }, 589 { SecCertificateCopyNTPrincipalNames, 590 kEAPSecCertificateAttributeNTPrincipalName }, 591 { SecCertificateCopyCommonNames, 592 kEAPSecCertificateAttributeCommonName }, 593 { NULL, NULL } 594 }; 595 CFMutableDictionaryRef dict = NULL; 596 bool is_root = false; 597 cert_names_func_info_t * scan; 598 599 dict = CFDictionaryCreateMutable(NULL, 0, 600 &kCFTypeDictionaryKeyCallBacks, 601 &kCFTypeDictionaryValueCallBacks); 602 for (scan = cert_names_info; scan->func != NULL; scan++) { 603 dict_insert_cert_name_attr(dict, scan->key, scan->func, cert); 604 } 605 if (is_root) { 606 CFDictionarySetValue(dict, kEAPSecCertificateAttributeIsRoot, 607 kCFBooleanTrue); 608 } 609 if (CFDictionaryGetCount(dict) == 0) { 610 CFRelease(dict); 611 dict = NULL; 612 } 613 return (dict); 614} 615 616CFStringRef 617EAPSecCertificateCopySHA1DigestString(SecCertificateRef cert) 618{ 619 const UInt8 * bytes; 620 CFIndex count; 621 CFIndex i; 622 CFDataRef hash; 623 CFMutableStringRef str; 624 625 hash = SecCertificateGetSHA1Digest(cert); 626 count = CFDataGetLength(hash); 627 bytes = CFDataGetBytePtr(hash); 628 str = CFStringCreateMutable(NULL, 0); 629 for (i = 0; i < count; i++) { 630 CFStringAppendFormat(str, NULL, CFSTR("%02x"), bytes[i]); 631 } 632 return (str); 633} 634 635#else /* TARGET_OS_EMBEDDED */ 636 637static void 638dictSetValue(CFMutableDictionaryRef dict, CFStringRef key, CFTypeRef val, 639 Boolean use_last) 640{ 641 if (isA_CFArray(val) != NULL) { 642 int count; 643 644 count = CFArrayGetCount(val); 645 if (count > 0) { 646 val = CFArrayGetValueAtIndex(val, use_last ? (count - 1) : 0); 647 } 648 } 649 if (isA_CFString(val) != NULL) { 650 CFDictionarySetValue(dict, key, val); 651 } 652} 653 654CFDictionaryRef 655EAPSecCertificateCopyAttributesDictionary(const SecCertificateRef cert) 656{ 657 CFDictionaryRef cert_values; 658 CFArrayRef cert_keys; 659 CFMutableDictionaryRef dict = NULL; 660 CFArrayRef email_addresses; 661 CFDictionaryRef entry; 662 int i; 663 CFTypeRef value; 664 const void * values[] = { 665 kSecOIDSubjectAltName, 666 kSecOIDCommonName, 667 }; 668 int values_count = (sizeof(values) 669 / sizeof(values[0])); 670 671 cert_keys = CFArrayCreate(NULL, values, values_count, 672 &kCFTypeArrayCallBacks); 673 674 cert_values = SecCertificateCopyValues(cert, cert_keys, NULL); 675 CFRelease(cert_keys); 676 if (cert_values == NULL) { 677 return (NULL); 678 } 679 dict = CFDictionaryCreateMutable(NULL, 0, 680 &kCFTypeDictionaryKeyCallBacks, 681 &kCFTypeDictionaryValueCallBacks); 682 683 /* get the common name */ 684 entry = CFDictionaryGetValue(cert_values, kSecOIDCommonName); 685 if (entry != NULL) { 686 value = CFDictionaryGetValue(entry, kSecPropertyKeyValue); 687 if (value != NULL) { 688 dictSetValue(dict, kEAPSecCertificateAttributeCommonName, 689 value, TRUE); 690 } 691 } 692 693 /* get the NTPrincipalName */ 694 entry = CFDictionaryGetValue(cert_values, kSecOIDSubjectAltName); 695 value = NULL; 696 if (entry != NULL) { 697 value = CFDictionaryGetValue(entry, kSecPropertyKeyValue); 698 } 699 if (isA_CFArray(value) != NULL) { 700 int count = CFArrayGetCount(value); 701 702 for (i = 0; i < count; i++) { 703 CFStringRef label; 704 CFDictionaryRef subj_alt = CFArrayGetValueAtIndex(value, i); 705 CFTypeRef this_val; 706 707 label = CFDictionaryGetValue(subj_alt, kSecPropertyKeyLabel); 708 this_val = CFDictionaryGetValue(subj_alt, kSecPropertyKeyValue); 709 if (label == NULL || this_val == NULL) { 710 continue; 711 } 712 /* NT Principal Name */ 713 if (CFEqual(label, kSecOIDMS_NTPrincipalName)) { 714 dictSetValue(dict, 715 kEAPSecCertificateAttributeNTPrincipalName, 716 this_val, FALSE); 717 } 718 } 719 } 720 email_addresses = NULL; 721 SecCertificateCopyEmailAddresses(cert, &email_addresses); 722 if (email_addresses != NULL) { 723 dictSetValue(dict, kEAPSecCertificateAttributeRFC822Name, 724 email_addresses, FALSE); 725 CFRelease(email_addresses); 726 } 727 CFRelease(cert_values); 728 return (dict); 729} 730#endif /* TARGET_OS_EMBEDDED */ 731 732CFStringRef 733EAPSecCertificateCopyUserNameString(SecCertificateRef cert) 734{ 735 CFStringRef attrs[] = { 736 kEAPSecCertificateAttributeNTPrincipalName, 737 kEAPSecCertificateAttributeCommonName, 738 kEAPSecCertificateAttributeRFC822Name, 739 NULL 740 }; 741 CFDictionaryRef dict = NULL; 742 int i; 743 CFStringRef user_name = NULL; 744 745 dict = EAPSecCertificateCopyAttributesDictionary(cert); 746 if (dict == NULL) { 747 goto done; 748 } 749 for (i = 0; attrs[i] != NULL; i++) { 750 user_name = CFDictionaryGetValue(dict, attrs[i]); 751 if (user_name != NULL) { 752 break; 753 } 754 } 755 done: 756 if (user_name != NULL) { 757 CFRetain(user_name); 758 } 759 my_CFRelease(&dict); 760 return (user_name); 761} 762 763 764#ifdef TEST_EAPSecCertificateCopyAttributesDictionary 765static void 766dump_as_xml(CFPropertyListRef p); 767 768static void 769dump_cert(SecCertificateRef cert); 770 771#if TARGET_OS_EMBEDDED 772static CFArrayRef 773copyAllCerts(void) 774{ 775 const void * keys[] = { 776 kSecClass, 777 kSecReturnRef, 778 kSecMatchLimit 779 }; 780 CFDictionaryRef query; 781 CFTypeRef results; 782 OSStatus status; 783 const void * values[] = { 784 kSecClassCertificate, 785 kCFBooleanTrue, 786 kSecMatchLimitAll 787 }; 788 789 query = CFDictionaryCreate(NULL, keys, values, 790 sizeof(keys) / sizeof(*keys), 791 &kCFTypeDictionaryKeyCallBacks, 792 &kCFTypeDictionaryValueCallBacks); 793 status = SecItemCopyMatching(query, &results); 794 CFRelease(query); 795 if (status == noErr) { 796 return (results); 797 } 798 return (NULL); 799} 800 801 802#else /* TARGET_OS_EMBEDDED */ 803 804static CFArrayRef 805copyAllCerts(void) 806{ 807 CFMutableArrayRef array = NULL; 808 SecKeychainAttributeList attr_list; 809 SecCertificateRef cert = NULL; 810 CSSM_DATA data; 811 SecKeychainItemRef item = NULL; 812 SecKeychainSearchRef search = NULL; 813 OSStatus status; 814 815 status = SecKeychainSearchCreateFromAttributes(NULL, 816 kSecCertificateItemClass, 817 NULL, 818 &search); 819 if (status != noErr) { 820 fprintf(stderr, "SecKeychainSearchCreateFromAttributes failed, %d", 821 (int)status); 822 goto failed; 823 } 824 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 825 do { 826 UInt32 this_len; 827 828 status = SecKeychainSearchCopyNext(search, &item); 829 if (status != noErr) { 830 break; 831 } 832 attr_list.count = 0; 833 attr_list.attr = NULL; 834 status = SecKeychainItemCopyContent(item, 835 NULL, /* item class */ 836 &attr_list, 837 &this_len, (void * *)(&data.Data)); 838 if (status != noErr) { 839 fprintf(stderr, "SecKeychainItemCopyContent failed, %d", (int)status); 840 break; 841 } 842 data.Length = this_len; 843 status = SecCertificateCreateFromData(&data, 844 CSSM_CERT_X_509v3, 845 CSSM_CERT_ENCODING_BER, &cert); 846 SecKeychainItemFreeContent(&attr_list, data.Data); 847 if (status != noErr) { 848 fprintf(stderr, "SecCertificateCreateFromData failed, %d", (int)status); 849 break; 850 } 851 CFArrayAppendValue(array, cert); 852 if (item != NULL) { 853 CFRelease(item); 854 } 855 if (cert != NULL) { 856 CFRelease(cert); 857 } 858 } while (1); 859 860 failed: 861 my_CFRelease(&search); 862 if (array != NULL && CFArrayGetCount(array) == 0) { 863 CFRelease(array); 864 array = NULL; 865 } 866 return (array); 867 868} 869#endif /* TARGET_OS_EMBEDDED */ 870 871static void 872showAllCerts(void) 873{ 874 CFArrayRef certs; 875 int count; 876 int i; 877 878 certs = copyAllCerts(); 879 if (certs == NULL) { 880 return; 881 } 882 count = CFArrayGetCount(certs); 883 for (i = 0; i < count; i++) { 884 SecCertificateRef cert; 885 886 cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, i); 887 dump_cert(cert); 888 } 889 CFRelease(certs); 890 return; 891} 892 893int 894main(int argc, const char * argv[]) 895{ 896 showAllCerts(); 897 if (argc > 1) { 898 sleep(120); 899 } 900 exit(0); 901 return (0); 902} 903#endif /* TEST_EAPSecCertificateCopyAttributesDictionary */ 904 905#if TEST_EAPSecIdentity || TEST_EAPSecCertificateCopyAttributesDictionary 906#include <SystemConfiguration/SCPrivate.h> 907 908static void 909dump_as_xml(CFPropertyListRef p) 910{ 911 CFDataRef xml; 912 913 xml = CFPropertyListCreateXMLData(NULL, p); 914 if (xml != NULL) { 915 fwrite(CFDataGetBytePtr(xml), CFDataGetLength(xml), 1, 916 stdout); 917 CFRelease(xml); 918 } 919 return; 920} 921 922static void 923dump_cert(SecCertificateRef cert) 924{ 925 CFDictionaryRef attrs = NULL; 926 927 attrs = EAPSecCertificateCopyAttributesDictionary(cert); 928 if (attrs != NULL) { 929 printf("Attributes:\n"); 930 dump_as_xml(attrs); 931 CFRelease(attrs); 932 } 933#if TARGET_OS_EMBEDDED 934 else { 935 CFStringRef summary; 936 937 summary = SecCertificateCopySubjectSummary(cert); 938 if (summary != NULL) { 939 printf("Summary:\n"); 940 dump_as_xml(summary); 941 CFRelease(summary); 942 } 943 } 944#endif /* TARGET_OS_EMBEDDED */ 945 { 946 CFStringRef username; 947 948 username = EAPSecCertificateCopyUserNameString(cert); 949 SCPrint(TRUE, stdout, CFSTR("Username = '%@'\n"), username); 950 my_CFRelease(&username); 951 } 952} 953#endif /* TEST_EAPSecIdentity || TEST_EAPSecCertificateCopyAttributesDictionary */ 954 955#ifdef TEST_EAPSecIdentity 956static void 957show_all_identities(void) 958{ 959 int count; 960 int i; 961 CFArrayRef list = NULL; 962 OSStatus status; 963 964 status = EAPSecIdentityListCreate(&list); 965 if (status != noErr) { 966 fprintf(stderr, "EAPSecIdentityListCreate failed, %s (%d)\n", 967 EAPSecurityErrorString(status), (int)status); 968 exit(1); 969 } 970 count = CFArrayGetCount(list); 971 for (i = 0; i < count; i++) { 972 SecCertificateRef cert = NULL; 973 EAPSecIdentityHandleRef handle = NULL; 974 SecIdentityRef identity; 975 SecIdentityRef new_id = NULL; 976 977 identity = (SecIdentityRef)CFArrayGetValueAtIndex(list, i); 978 handle = EAPSecIdentityHandleCreate(identity); 979 if (handle == NULL) { 980 fprintf(stderr, "EAPSecIdentityHandleCreate failed\n"); 981 exit(1); 982 } 983 status = EAPSecIdentityHandleCreateSecIdentity(handle, 984 &new_id); 985 if (status != noErr) { 986 fprintf(stderr, 987 "EAPSecIdentityHandleCreateSecIdentity failed %s (%d)\n", 988 EAPSecurityErrorString(status), (int)status); 989 exit(1); 990 } 991 status = SecIdentityCopyCertificate(new_id, &cert); 992 if (status != noErr) { 993 fprintf(stderr, "SecIdentityCopyCertificate failed %d\n", 994 (int)status); 995 exit(1); 996 } 997 printf("\nCertificate[%d]:\n", i); 998 dump_cert(cert); 999 printf("Handle:\n"); 1000 dump_as_xml(handle); 1001 1002 my_CFRelease(&cert); 1003 my_CFRelease(&new_id); 1004 my_CFRelease(&handle); 1005 } 1006 CFRelease(list); 1007 return; 1008} 1009 1010static void 1011get_identity(const char * filename) 1012{ 1013 SecCertificateRef cert; 1014 CFTypeRef handle; 1015 SecIdentityRef identity; 1016 OSStatus status; 1017 1018 handle = my_CFPropertyListCreateFromFile(filename); 1019 if (handle == NULL) { 1020 fprintf(stderr, "could not read '%s'\n", filename); 1021 exit(1); 1022 } 1023 status = EAPSecIdentityHandleCreateSecIdentity(handle, &identity); 1024 if (status != noErr) { 1025 fprintf(stderr, "could not turn handle into identity, %d\n", 1026 (int)status); 1027 exit(1); 1028 } 1029 status = SecIdentityCopyCertificate(identity, &cert); 1030 if (status != noErr) { 1031 fprintf(stderr, "SecIdentityCopyCertificate failed %d\n", 1032 (int)status); 1033 exit(1); 1034 } 1035 dump_cert(cert); 1036 CFRelease(cert); 1037 CFRelease(handle); 1038 CFRelease(identity); 1039 return; 1040} 1041 1042#if TARGET_OS_EMBEDDED 1043 1044static OSStatus 1045remove_identity(SecIdentityRef identity) 1046{ 1047 const void * keys[] = { 1048 kSecValueRef 1049 }; 1050 CFDictionaryRef query; 1051 OSStatus status = noErr; 1052 const void * values[] = { 1053 identity 1054 }; 1055 1056 query = CFDictionaryCreate(NULL, keys, values, 1057 sizeof(keys) / sizeof(*keys), 1058 &kCFTypeDictionaryKeyCallBacks, 1059 &kCFTypeDictionaryValueCallBacks); 1060 status = SecItemDelete(query); 1061 if (status != noErr) { 1062 fprintf(stderr, "SecItemDelete() failed, %d\n", (int)status); 1063 } 1064 CFRelease(query); 1065 return (status); 1066} 1067 1068static void 1069remove_all_identities(void) 1070{ 1071 int count; 1072 int i; 1073 CFArrayRef list = NULL; 1074 OSStatus status; 1075 1076 status = EAPSecIdentityListCreate(&list); 1077 if (status != noErr) { 1078 fprintf(stderr, "EAPSecIdentityListCreate failed, %s (%d)\n", 1079 EAPSecurityErrorString(status), (int)status); 1080 exit(1); 1081 } 1082 count = CFArrayGetCount(list); 1083 for (i = 0; i < count; i++) { 1084 SecCertificateRef cert = NULL; 1085 SecIdentityRef identity; 1086 1087 identity = (SecIdentityRef)CFArrayGetValueAtIndex(list, i); 1088 status = SecIdentityCopyCertificate(identity, &cert); 1089 if (status != noErr) { 1090 fprintf(stderr, "SecIdentityCopyCertificate failed %d\n", 1091 (int)status); 1092 exit(1); 1093 } 1094 printf("Removing:\n"); 1095 dump_cert(cert); 1096 my_CFRelease(&cert); 1097 remove_identity(identity); 1098 } 1099 CFRelease(list); 1100 return; 1101} 1102#endif /* TARGET_OS_EMBEDDED */ 1103 1104static void 1105usage(const char * progname) 1106{ 1107 fprintf(stderr, "%s: list\n", progname); 1108 fprintf(stderr, "%s: get <filename-containing-handle>\n", progname); 1109#if TARGET_OS_EMBEDDED 1110 fprintf(stderr, "%s: remove\n", progname); 1111#endif /* TARGET_OS_EMBEDDED */ 1112 exit(1); 1113 return; 1114} 1115 1116enum { 1117 kCommandList, 1118 kCommandGet, 1119 kCommandRemove 1120}; 1121 1122int 1123main(int argc, char * argv[]) 1124{ 1125 int command = kCommandList; 1126 1127 if (argc > 1) { 1128 if (strcmp(argv[1], "list") == 0) { 1129 ; 1130 } 1131 else if (strcmp(argv[1], "get") == 0) { 1132 if (argc < 3) { 1133 usage(argv[0]); 1134 } 1135 command = kCommandGet; 1136 } 1137#if TARGET_OS_EMBEDDED 1138 else if (strcmp(argv[1], "remove") == 0) { 1139 command = kCommandRemove; 1140 } 1141#endif /* TARGET_OS_EMBEDDED */ 1142 else { 1143 usage(argv[0]); 1144 } 1145 } 1146 1147 switch (command) { 1148 case kCommandList: 1149 show_all_identities(); 1150 break; 1151 case kCommandGet: 1152 get_identity(argv[2]); 1153 break; 1154#if TARGET_OS_EMBEDDED 1155 case kCommandRemove: 1156 remove_all_identities(); 1157 break; 1158#endif /* TARGET_OS_EMBEDDED */ 1159 } 1160 exit(0); 1161} 1162#endif /* TEST_EAPSecIdentity */ 1163 1164#ifdef TEST_EAPSecIdentityHandleCreateSecIdentityTrustChain 1165 1166int 1167main() 1168{ 1169 int count; 1170 int i; 1171 CFArrayRef list = NULL; 1172 CFArrayRef trust_chain; 1173 OSStatus status; 1174 1175 status = EAPSecIdentityHandleCreateSecIdentityTrustChain(NULL, 1176 &trust_chain); 1177 if (status != noErr) { 1178 fprintf(stderr, 1179 "EAPSecIdentityHandleCreateSecIdentityTrustChain" 1180 " failed %s (%d)\n", 1181 EAPSecurityErrorString(status), (int)status); 1182 exit(2); 1183 } 1184 CFShow(trust_chain); 1185 CFRelease(trust_chain); 1186 status = EAPSecIdentityListCreate(&list); 1187 if (status != noErr) { 1188 fprintf(stderr, 1189 "EAPSecIdentityListCreate" 1190 " failed %s (%d)\n", 1191 EAPSecurityErrorString(status), (int)status); 1192 exit(2); 1193 } 1194 count = CFArrayGetCount(list); 1195 for (i = 0; i < count; i++) { 1196 EAPSecIdentityHandleRef h; 1197 SecIdentityRef ident = (SecIdentityRef)CFArrayGetValueAtIndex(list, i); 1198 1199 h = EAPSecIdentityHandleCreate(ident); 1200 status = EAPSecIdentityHandleCreateSecIdentityTrustChain(h, 1201 &trust_chain); 1202 if (status != noErr) { 1203 fprintf(stderr, 1204 "EAPSecIdentityHandleCreateSecIdentityTrustChain" 1205 " failed %s (%d)\n", 1206 EAPSecurityErrorString(status), (int)status); 1207 exit(2); 1208 } 1209 CFRelease(h); 1210 fprintf(stderr, "[%d]:\n", i); 1211 CFShow(trust_chain); 1212 CFRelease(trust_chain); 1213 } 1214 exit(0); 1215 return (0); 1216} 1217 1218 1219#endif /* TEST_EAPSecIdentityHandleCreateSecIdentityTrustChain */ 1220