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