1/* 2 * Copyright (c) 2002-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 * tlsutil.c 26 * - utility functions for dealing with Secure Transport API's 27 */ 28 29/* 30 * Modification History 31 * 32 * August 26, 2002 Dieter Siegmund (dieter@apple) 33 * - created 34 */ 35 36#include <stdio.h> 37#include <stdlib.h> 38#include <string.h> 39#include <time.h> 40#include <ctype.h> 41 42#include <Security/SecureTransport.h> 43#if !TARGET_OS_EMBEDDED 44#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h> 45#endif 46#include <CoreFoundation/CFArray.h> 47#include <CoreFoundation/CFBase.h> 48#include <CoreFoundation/CFData.h> 49#include <Security/SecureTransportPriv.h> 50#include <TargetConditionals.h> 51#if TARGET_OS_EMBEDDED 52#include <Security/SecCertificatePriv.h> 53#include <Security/SecPolicyPriv.h> 54#else /* TARGET_OS_EMBEDDED */ 55#include <Security/oidsalg.h> 56#include <Security/SecKeychain.h> 57#include <Security/SecPolicySearch.h> 58#endif /* TARGET_OS_EMBEDDED */ 59#include <Security/SecTrustPriv.h> 60#include <SystemConfiguration/SCValidation.h> 61#include <Security/SecPolicy.h> 62#include "EAPUtil.h" 63#include "EAPClientProperties.h" 64#include "EAPCertificateUtil.h" 65#include "EAPTLSUtil.h" 66#include "EAPSIMAKAPersistentState.h" 67#include "EAPSecurity.h" 68#include "printdata.h" 69#include "myCFUtil.h" 70#include "nbo.h" 71#include "EAPLog.h" 72 73#ifdef __IPHONE_OS_VERSION_MIN_REQUIRED 74#if __IPHONE_OS_VERSION_MIN_REQUIRED < 70000 75#define NEED_TO_DISABLE_ONE_BYTE_OPTION 0 76#endif /* __IPHONE_OS_VERSION_MIN_REQUIRED < 70000 */ 77#endif /* __IPHONE_OS_VERSION_MIN_REQUIRED */ 78 79#ifndef NEED_TO_DISABLE_ONE_BYTE_OPTION 80#define NEED_TO_DISABLE_ONE_BYTE_OPTION 1 81#endif /* NEED_TO_DISABLE_ONE_BYTE_OPTION */ 82 83/* set a 12-hour session cache timeout */ 84#define kEAPTLSSessionCacheTimeoutSeconds (12 * 60 * 60) 85 86uint32_t 87EAPTLSLengthIncludedPacketGetMessageLength(EAPTLSLengthIncludedPacketRef pkt) 88{ 89 return (net_uint32_get(pkt->tls_message_length)); 90} 91 92void 93EAPTLSLengthIncludedPacketSetMessageLength(EAPTLSLengthIncludedPacketRef pkt, 94 uint32_t length) 95{ 96 return (net_uint32_set(pkt->tls_message_length, length)); 97} 98 99#ifdef NOTYET 100/* 101 * Lists of SSLCipherSuites used in setCipherRestrictions. Note that the 102 * SecureTransport library does not implement all of these; we only specify 103 * the ones it claims to support. 104 */ 105static SSLCipherSuite suites40[] = { 106 SSL_RSA_EXPORT_WITH_RC4_40_MD5, 107 SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5, 108 SSL_RSA_EXPORT_WITH_DES40_CBC_SHA, 109 SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA, 110 SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA, 111 SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, 112 SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, 113 SSL_DH_anon_EXPORT_WITH_RC4_40_MD5, 114 SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA, 115 SSL_NO_SUCH_CIPHERSUITE 116}; 117static SSLCipherSuite suitesDES[] = { 118 SSL_RSA_WITH_DES_CBC_SHA, 119 SSL_DH_DSS_WITH_DES_CBC_SHA, 120 SSL_DH_RSA_WITH_DES_CBC_SHA, 121 SSL_DHE_DSS_WITH_DES_CBC_SHA, 122 SSL_DHE_RSA_WITH_DES_CBC_SHA, 123 SSL_DH_anon_WITH_DES_CBC_SHA, 124 SSL_RSA_WITH_DES_CBC_MD5, 125 SSL_NO_SUCH_CIPHERSUITE 126}; 127static SSLCipherSuite suitesDES40[] = { 128 SSL_RSA_EXPORT_WITH_DES40_CBC_SHA, 129 SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA, 130 SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA, 131 SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, 132 SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, 133 SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA, 134 SSL_NO_SUCH_CIPHERSUITE 135}; 136static SSLCipherSuite suites3DES[] = { 137 SSL_RSA_WITH_3DES_EDE_CBC_SHA, 138 SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA, 139 SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA, 140 SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, 141 SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, 142 SSL_DH_anon_WITH_3DES_EDE_CBC_SHA, 143 SSL_RSA_WITH_3DES_EDE_CBC_MD5, 144 SSL_NO_SUCH_CIPHERSUITE 145}; 146static SSLCipherSuite suitesRC4[] = { 147 SSL_RSA_WITH_RC4_128_MD5, 148 SSL_RSA_WITH_RC4_128_SHA, 149 SSL_DH_anon_WITH_RC4_128_MD5, 150 SSL_NO_SUCH_CIPHERSUITE 151}; 152static SSLCipherSuite suitesRC4_40[] = { 153 SSL_RSA_EXPORT_WITH_RC4_40_MD5, 154 SSL_DH_anon_EXPORT_WITH_RC4_40_MD5, 155 SSL_NO_SUCH_CIPHERSUITE 156}; 157static SSLCipherSuite suitesRC2[] = { 158 SSL_RSA_WITH_RC2_CBC_MD5, 159 SSL_NO_SUCH_CIPHERSUITE 160}; 161 162const char * 163EAPSSLCipherSuiteString(SSLCipherSuite cs) 164{ 165 switch(cs) { 166 case SSL_NULL_WITH_NULL_NULL: 167 return "SSL_NULL_WITH_NULL_NULL"; 168 case SSL_RSA_WITH_NULL_MD5: 169 return "SSL_RSA_WITH_NULL_MD5"; 170 case SSL_RSA_WITH_NULL_SHA: 171 return "SSL_RSA_WITH_NULL_SHA"; 172 case SSL_RSA_EXPORT_WITH_RC4_40_MD5: 173 return "SSL_RSA_EXPORT_WITH_RC4_40_MD5"; 174 case SSL_RSA_WITH_RC4_128_MD5: 175 return "SSL_RSA_WITH_RC4_128_MD5"; 176 case SSL_RSA_WITH_RC4_128_SHA: 177 return "SSL_RSA_WITH_RC4_128_SHA"; 178 case SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5: 179 return "SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5"; 180 case SSL_RSA_WITH_IDEA_CBC_SHA: 181 return "SSL_RSA_WITH_IDEA_CBC_SHA"; 182 case SSL_RSA_EXPORT_WITH_DES40_CBC_SHA: 183 return "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA"; 184 case SSL_RSA_WITH_DES_CBC_SHA: 185 return "SSL_RSA_WITH_DES_CBC_SHA"; 186 case SSL_RSA_WITH_3DES_EDE_CBC_SHA: 187 return "SSL_RSA_WITH_3DES_EDE_CBC_SHA"; 188 case SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA: 189 return "SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA"; 190 case SSL_DH_DSS_WITH_DES_CBC_SHA: 191 return "SSL_DH_DSS_WITH_DES_CBC_SHA"; 192 case SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA: 193 return "SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA"; 194 case SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA: 195 return "SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA"; 196 case SSL_DH_RSA_WITH_DES_CBC_SHA: 197 return "SSL_DH_RSA_WITH_DES_CBC_SHA"; 198 case SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA: 199 return "SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA"; 200 case SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA: 201 return "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"; 202 case SSL_DHE_DSS_WITH_DES_CBC_SHA: 203 return "SSL_DHE_DSS_WITH_DES_CBC_SHA"; 204 case SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA: 205 return "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA"; 206 case SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA: 207 return "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA"; 208 case SSL_DHE_RSA_WITH_DES_CBC_SHA: 209 return "SSL_DHE_RSA_WITH_DES_CBC_SHA"; 210 case SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA: 211 return "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA"; 212 case SSL_DH_anon_EXPORT_WITH_RC4_40_MD5: 213 return "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5"; 214 case SSL_DH_anon_WITH_RC4_128_MD5: 215 return "SSL_DH_anon_WITH_RC4_128_MD5"; 216 case SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA: 217 return "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA"; 218 case SSL_DH_anon_WITH_DES_CBC_SHA: 219 return "SSL_DH_anon_WITH_DES_CBC_SHA"; 220 case SSL_DH_anon_WITH_3DES_EDE_CBC_SHA: 221 return "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA"; 222 case SSL_FORTEZZA_DMS_WITH_NULL_SHA: 223 return "SSL_FORTEZZA_DMS_WITH_NULL_SHA"; 224 case SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA: 225 return "SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA"; 226 case SSL_RSA_WITH_RC2_CBC_MD5: 227 return "SSL_RSA_WITH_RC2_CBC_MD5"; 228 case SSL_RSA_WITH_IDEA_CBC_MD5: 229 return "SSL_RSA_WITH_IDEA_CBC_MD5"; 230 case SSL_RSA_WITH_DES_CBC_MD5: 231 return "SSL_RSA_WITH_DES_CBC_MD5"; 232 case SSL_RSA_WITH_3DES_EDE_CBC_MD5: 233 return "SSL_RSA_WITH_3DES_EDE_CBC_MD5"; 234 case SSL_NO_SUCH_CIPHERSUITE: 235 return "SSL_NO_SUCH_CIPHERSUITE"; 236 default: 237 return "<unknown>"; 238 } 239} 240 241/* 242 * Given a SSLProtocolVersion - typically from SSLGetProtocolVersion - 243 * return a string representation. 244 */ 245const char * 246EAPSSLProtocolVersionString(SSLProtocol prot) 247{ 248 switch(prot) { 249 case kSSLProtocolUnknown: 250 return "kSSLProtocolUnknown"; 251 case kSSLProtocol2: 252 return "kSSLProtocol2"; 253 case kSSLProtocol3: 254 return "kSSLProtocol3"; 255 case kSSLProtocol3Only: 256 return "kSSLProtocol3Only"; 257 case kTLSProtocol1: 258 return "kTLSProtocol1"; 259 case kTLSProtocol1Only: 260 return "kTLSProtocol1Only"; 261 default: 262 return "<unknown>"; 263 } 264} 265 266/* 267 * Given an SSLContextRef and an array of SSLCipherSuites, terminated by 268 * SSL_NO_SUCH_CIPHERSUITE, select those SSLCipherSuites which the library 269 * supports and do a SSLSetEnabledCiphers() specifying those. 270 */ 271static OSStatus 272setEnabledCiphers(SSLContextRef ctx, 273 const SSLCipherSuite * ciphers) 274{ 275 UInt32 numSupported; 276 OSStatus ortn = noErr; 277 SSLCipherSuite *supported = NULL; 278 SSLCipherSuite *enabled = NULL; 279 unsigned enabledDex = 0; // index into enabled 280 unsigned supportedDex = 0; // index into supported 281 unsigned inDex = 0; // index into ciphers 282 283 /* first get all the supported ciphers */ 284 ortn = SSLGetNumberSupportedCiphers(ctx, &numSupported); 285 if (ortn) { 286 goto done; 287 } 288 supported = (SSLCipherSuite *)malloc(numSupported * sizeof(SSLCipherSuite)); 289 ortn = SSLGetSupportedCiphers(ctx, supported, &numSupported); 290 if (ortn) { 291 goto done; 292 } 293 294 /* 295 * Malloc an array we'll use for SSLGetEnabledCiphers - this will be 296 * bigger than the number of suites we actually specify 297 */ 298 enabled = (SSLCipherSuite *)malloc(numSupported * sizeof(SSLCipherSuite)); 299 300 /* 301 * For each valid suite in ciphers, see if it's in the list of 302 * supported ciphers. If it is, add it to the list of ciphers to be 303 * enabled. 304 */ 305 for(inDex=0; ciphers[inDex] != SSL_NO_SUCH_CIPHERSUITE; inDex++) { 306 for(supportedDex=0; supportedDex<numSupported; supportedDex++) { 307 if(ciphers[inDex] == supported[supportedDex]) { 308 enabled[enabledDex++] = ciphers[inDex]; 309 break; 310 } 311 } 312 } 313 314 /* send it on down. */ 315 ortn = SSLSetEnabledCiphers(ctx, enabled, enabledDex); 316 done: 317 if (enabled != NULL) { 318 free(enabled); 319 } 320 if (supported != NULL) { 321 free(supported); 322 } 323 return ortn; 324} 325 326/* 327 * Specify a restricted set of cipherspecs. 328 */ 329OSStatus 330EAPSSLContextSetCipherRestrictions(SSLContextRef ctx, char cipherRestrict) 331{ 332 OSStatus ortn = noErr; 333 334 switch(cipherRestrict) { 335 case 'e': 336 ortn = setEnabledCiphers(ctx, suites40); 337 break; 338 case 'd': 339 ortn = setEnabledCiphers(ctx, suitesDES); 340 break; 341 case 'D': 342 ortn = setEnabledCiphers(ctx, suitesDES40); 343 break; 344 case '3': 345 ortn = setEnabledCiphers(ctx, suites3DES); 346 break; 347 case '4': 348 ortn = setEnabledCiphers(ctx, suitesRC4); 349 break; 350 case '$': 351 ortn = setEnabledCiphers(ctx, suitesRC4_40); 352 break; 353 case '2': 354 ortn = setEnabledCiphers(ctx, suitesRC2); 355 break; 356 default: 357 break; 358 } 359 return ortn; 360} 361 362#endif /* NOTYET */ 363 364const char * 365EAPSSLErrorString(OSStatus err) 366{ 367 return (EAPSecurityErrorString(err)); 368} 369 370SSLContextRef 371EAPSSLContextCreate(SSLProtocol protocol, bool is_server, 372 SSLReadFunc func_read, SSLWriteFunc func_write, 373 void * handle, char * peername, OSStatus * ret_status) 374{ 375 SSLContextRef ctx; 376 OSStatus status; 377 378 *ret_status = noErr; 379 ctx = SSLCreateContext(NULL, is_server ? kSSLServerSide : kSSLClientSide, 380 kSSLStreamType); 381 status = SSLSetIOFuncs(ctx, func_read, func_write); 382 if (status) { 383 goto cleanup; 384 } 385 status = SSLSetProtocolVersionMin(ctx, protocol); 386 if (status) { 387 goto cleanup; 388 } 389 status = SSLSetProtocolVersionMax(ctx, protocol); 390 if (status) { 391 goto cleanup; 392 } 393 status = SSLSetConnection(ctx, handle); 394 if (status) { 395 goto cleanup; 396 } 397 if (peername != NULL) { 398 status = SSLSetPeerDomainName(ctx, peername, strlen(peername) + 1); 399 if (status) { 400 goto cleanup; 401 } 402 } 403#if NEED_TO_DISABLE_ONE_BYTE_OPTION 404 SSLSetSessionOption(ctx, kSSLSessionOptionSendOneByteRecord, FALSE); 405#endif /* NEED_TO_DISABLE_ONE_BYTE_OPTION */ 406 if (is_server == FALSE) { 407 status = SSLSetSessionOption(ctx, 408 kSSLSessionOptionBreakOnServerAuth, 409 TRUE); 410 if (status != noErr) { 411 goto cleanup; 412 } 413 } 414 (void)SSLSetSessionCacheTimeout(ctx, kEAPTLSSessionCacheTimeoutSeconds); 415 return (ctx); 416 417 cleanup: 418 if (ctx != NULL) { 419 CFRelease(ctx); 420 } 421 *ret_status = status; 422 return (NULL); 423} 424 425SSLContextRef 426EAPTLSMemIOContextCreate(bool is_server, memoryIORef mem_io, 427 char * peername, OSStatus * ret_status) 428{ 429 return(EAPSSLContextCreate(kTLSProtocol1, is_server, 430 EAPSSLMemoryIORead, EAPSSLMemoryIOWrite, 431 mem_io, peername, ret_status)); 432} 433 434OSStatus 435EAPSSLMemoryIORead(SSLConnectionRef connection, void * data_buf, 436 size_t * data_length) 437{ 438 size_t bytes_left; 439 size_t length = *data_length; 440 memoryIORef mem_io = (memoryIORef)connection; 441 memoryBufferRef mem_buf = mem_io->read; 442 443 if (mem_buf == NULL) { 444 if (mem_io->debug) { 445 EAPLOG_FL(LOG_DEBUG, "Read not initialized"); 446 } 447 *data_length = 0; 448 return (noErr); 449 } 450 bytes_left = mem_buf->length - mem_buf->offset; 451 if (mem_buf->data == NULL 452 || mem_buf->length == 0 || bytes_left == 0) { 453 *data_length = 0; 454 if (mem_io->debug) { 455 EAPLOG_FL(LOG_DEBUG, "Read would block"); 456 } 457 return (errSSLWouldBlock); 458 } 459 if (length > bytes_left) { 460 length = bytes_left; 461 } 462 bcopy(mem_buf->data + mem_buf->offset, data_buf, length); 463 mem_buf->offset += length; 464 if (mem_buf->offset == mem_buf->length) { 465 free(mem_buf->data); 466 bzero(mem_buf, sizeof(*mem_buf)); 467 } 468 *data_length = length; 469 if (mem_io->debug) { 470 CFMutableStringRef str; 471 472 str = CFStringCreateMutable(NULL, 0); 473 print_data_cfstr(str, data_buf, length); 474 EAPLOG_FL(-LOG_DEBUG, "Read %d bytes:\n%@", (int)length, 475 str); 476 CFRelease(str); 477 } 478 return (noErr); 479} 480 481OSStatus 482EAPSSLMemoryIOWrite(SSLConnectionRef connection, const void * data_buf, 483 size_t * data_length) 484{ 485 bool additional = FALSE; 486 size_t length = *data_length; 487 memoryIORef mem_io = (memoryIORef)connection; 488 memoryBufferRef mem_buf = mem_io->write; 489 490 if (mem_buf == NULL) { 491 if (mem_io->debug) { 492 EAPLOG_FL(LOG_DEBUG, "Write not initialized"); 493 } 494 *data_length = 0; 495 return (noErr); 496 } 497 if (mem_buf->data == NULL) { 498 mem_buf->data = malloc(length); 499 mem_buf->offset = 0; 500 mem_buf->length = length; 501 bcopy(data_buf, mem_buf->data, length); 502 } 503 else { 504 additional = TRUE; 505 mem_buf->data = realloc(mem_buf->data, length + mem_buf->length); 506 bcopy(data_buf, mem_buf->data + mem_buf->length, length); 507 mem_buf->length += length; 508 } 509 if (mem_io->debug) { 510 CFMutableStringRef str; 511 512 str = CFStringCreateMutable(NULL, 0); 513 print_data_cfstr(str, data_buf, length); 514 EAPLOG_FL(-LOG_DEBUG, "Wrote %s%d bytes:\n%@", 515 additional ? "additional " : "", 516 (int)length, str); 517 CFRelease(str); 518 } 519 return (noErr); 520} 521 522void 523memoryBufferInit(memoryBufferRef buf) 524{ 525 bzero(buf, sizeof(*buf)); 526 return; 527} 528 529void 530memoryBufferClear(memoryBufferRef buf) 531{ 532 if (buf == NULL) { 533 return; 534 } 535 if (buf->data != NULL) { 536 free(buf->data); 537 } 538 bzero(buf, sizeof(*buf)); 539 return; 540} 541 542void 543memoryBufferAllocate(memoryBufferRef buf, size_t length) 544{ 545 buf->data = malloc(length); 546 buf->length = length; 547 buf->offset = 0; 548 buf->complete = FALSE; 549 return; 550} 551 552bool 553memoryBufferIsComplete(memoryBufferRef buf) 554{ 555 return (buf->complete); 556} 557 558bool 559memoryBufferAddData(memoryBufferRef buf, const void * data, size_t length) 560{ 561 if ((buf->offset + length) > buf->length) { 562 return (FALSE); 563 } 564 bcopy(data, buf->data + buf->offset, length); 565 buf->offset += length; 566 if (buf->offset == buf->length) { 567 buf->offset = 0; 568 buf->complete = TRUE; 569 } 570 return (TRUE); 571} 572 573void 574memoryIOClearBuffers(memoryIORef mem_io) 575{ 576 memoryBufferClear(mem_io->read); 577 memoryBufferClear(mem_io->write); 578 return; 579} 580 581void 582memoryIOInit(memoryIORef mem_io, memoryBufferRef read_buf, 583 memoryBufferRef write_buf) 584{ 585 bzero(mem_io, sizeof(*mem_io)); 586 memoryBufferInit(read_buf); 587 memoryBufferInit(write_buf); 588 mem_io->read = read_buf; 589 mem_io->write = write_buf; 590 return; 591} 592 593void 594memoryIOSetDebug(memoryIORef mem_io, bool debug) 595{ 596 mem_io->debug = debug; 597 return; 598} 599 600OSStatus 601EAPTLSComputeKeyData(SSLContextRef ssl_context, 602 const void * label, int label_length, 603 void * key, int key_length) 604{ 605 char master_secret[SSL_MASTER_SECRET_SIZE]; 606 size_t master_secret_length; 607 size_t offset; 608 char random[SSL_CLIENT_SRVR_RAND_SIZE * 2]; 609 size_t random_size = 0; 610 size_t size; 611 OSStatus status; 612 613 offset = 0; 614 size = sizeof(random); 615 status = SSLInternalClientRandom(ssl_context, random, &size); 616 if (status != noErr) { 617 EAPLOG_FL(LOG_NOTICE, 618 "SSLInternalClientRandom failed, %s", 619 EAPSSLErrorString(status)); 620 return (status); 621 } 622 offset += size; 623 random_size += size; 624 if ((size + SSL_CLIENT_SRVR_RAND_SIZE) > sizeof(random)) { 625 EAPLOG_FL(LOG_NOTICE, 626 "buffer overflow %ld >= %ld", 627 size + SSL_CLIENT_SRVR_RAND_SIZE, sizeof(random)); 628 return (errSSLBufferOverflow); 629 } 630 size = sizeof(random) - size; 631 status = SSLInternalServerRandom(ssl_context, random + offset, &size); 632 if (status != noErr) { 633 EAPLOG_FL(LOG_NOTICE, 634 "SSLInternalServerRandom failed, %s", 635 EAPSSLErrorString(status)); 636 return (status); 637 } 638 random_size += size; 639 master_secret_length = sizeof(master_secret); 640 status = SSLInternalMasterSecret(ssl_context, master_secret, 641 &master_secret_length); 642 if (status != noErr) { 643 EAPLOG_FL(LOG_NOTICE, 644 "SSLInternalMasterSecret failed, %s", 645 EAPSSLErrorString(status)); 646 return (status); 647 } 648 status = SSLInternal_PRF(ssl_context, 649 master_secret, master_secret_length, 650 label, label_length, 651 random, random_size, 652 key, key_length); 653 if (status != noErr) { 654 EAPLOG_FL(LOG_NOTICE, 655 "SSLInternal_PRF failed, %s", EAPSSLErrorString(status)); 656 return (status); 657 } 658 return (status); 659} 660 661EAPPacket * 662EAPTLSPacketCreate2(EAPCode code, int type, u_char identifier, int mtu, 663 memoryBufferRef buf, int * ret_fraglen, 664 bool always_mark_first) 665{ 666 bool first_fragment = FALSE; 667 bool more_fragments = FALSE; 668 EAPTLSPacket * eaptls = NULL; 669 int pkt_size; 670 size_t fraglen = 0; 671 672 if (buf != NULL && buf->data != NULL && buf->offset < buf->length) { 673 int max_payload; 674 675 if (buf->offset == 0 && always_mark_first) { 676 first_fragment = TRUE; 677 pkt_size = sizeof(EAPTLSLengthIncludedPacket); 678 } 679 else { 680 pkt_size = sizeof(EAPTLSPacket); 681 } 682 max_payload = mtu - pkt_size; 683 fraglen = buf->length - buf->offset; 684 if (fraglen > max_payload) { 685 if (buf->offset == 0 && always_mark_first == FALSE) { 686 first_fragment = TRUE; 687 pkt_size = sizeof(EAPTLSLengthIncludedPacket); 688 max_payload = mtu - pkt_size; 689 } 690 more_fragments = TRUE; 691 fraglen = max_payload; 692 } 693 } 694 else { 695 pkt_size = sizeof(EAPTLSPacket); 696 } 697 698 if (ret_fraglen != NULL) { 699 *ret_fraglen = fraglen; 700 } 701 pkt_size += fraglen; 702 eaptls = malloc(pkt_size); 703 if (eaptls == NULL) { 704 return (NULL); 705 } 706 eaptls->code = code; 707 eaptls->identifier = identifier; 708 EAPPacketSetLength((EAPPacketRef)eaptls, pkt_size); 709 eaptls->type = type; 710 eaptls->flags = 0; 711 if (fraglen != 0) { 712 void * dest; 713 714 dest = eaptls->tls_data; 715 if (more_fragments) { 716 eaptls->flags = kEAPTLSPacketFlagsMoreFragments; 717 } 718 if (first_fragment) { 719 EAPTLSLengthIncludedPacket * first; 720 721 /* ALIGN: void * cast OK, 722 * we don't expect proper alignment */ 723 first = (EAPTLSLengthIncludedPacket *)(void *)eaptls; 724 eaptls->flags |= kEAPTLSPacketFlagsLengthIncluded; 725 EAPTLSLengthIncludedPacketSetMessageLength(first, 726 buf->length); 727 dest = first->tls_data; 728 } 729 bcopy(buf->data + buf->offset, dest, fraglen); 730 } 731 return ((EAPPacket *)eaptls); 732} 733 734EAPPacket * 735EAPTLSPacketCreate(EAPCode code, int type, u_char identifier, int mtu, 736 memoryBufferRef buf, int * ret_fraglen) 737{ 738 return (EAPTLSPacketCreate2(code, type, identifier, mtu, 739 buf, ret_fraglen, TRUE)); 740} 741 742OSStatus 743EAPSSLCopyPeerCertificates(SSLContextRef context, CFArrayRef * certs) 744{ 745 CFMutableArrayRef array = NULL; 746 int count = 0; 747 int i; 748 OSStatus status; 749 SecTrustRef trust = NULL; 750 751 status = SSLCopyPeerTrust(context, &trust); 752 if (status != noErr) { 753 EAPLOG_FL(LOG_NOTICE, "SSLCopyPeerTrust returned NULL"); 754 goto done; 755 } 756 count = SecTrustGetCertificateCount(trust); 757 if (count == 0) { 758 /* this should not happen */ 759 status = errSecItemNotFound; 760 EAPLOG_FL(LOG_NOTICE, "SecTrustGetCertificateCount returned 0"); 761 goto done; 762 } 763 array = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks); 764 for (i = 0; i < count; i++) { 765 SecCertificateRef s; 766 767 s = SecTrustGetCertificateAtIndex(trust, i); 768 CFArrayAppendValue(array, s); 769 } 770 done: 771 my_CFRelease(&trust); 772 *certs = array; 773 return (status); 774} 775 776enum { 777 kAvoidDenialOfServiceSize = 128 * 1024 778}; 779 780CFStringRef 781EAPTLSPacketCopyDescription(EAPTLSPacketRef eaptls_pkt, bool * packet_is_valid) 782{ 783 EAPTLSLengthIncludedPacketRef eaptls_pkt_l; 784 int data_length; 785 void * data_ptr = NULL; 786 u_int16_t length = EAPPacketGetLength((EAPPacketRef)eaptls_pkt); 787 CFMutableStringRef str; 788 u_int32_t tls_message_length = 0; 789 790 *packet_is_valid = FALSE; 791 switch (eaptls_pkt->code) { 792 case kEAPCodeRequest: 793 case kEAPCodeResponse: 794 break; 795 default: 796 return (NULL); 797 } 798 str = CFStringCreateMutable(NULL, 0); 799 if (length < sizeof(*eaptls_pkt)) { 800 STRING_APPEND(str, "EAPTLSPacket header truncated %d < %d\n", 801 length, (int)sizeof(*eaptls_pkt)); 802 goto done; 803 } 804 STRING_APPEND(str, "%s %s: Identifier %d Length %d Flags 0x%x%s", 805 EAPTypeStr(eaptls_pkt->type), 806 eaptls_pkt->code == kEAPCodeRequest ? "Request" : "Response", 807 eaptls_pkt->identifier, length, eaptls_pkt->flags, 808 eaptls_pkt->flags != 0 ? " [" : ""); 809 810 /* ALIGN: void * cast OK, we don't expect proper alignment */ 811 eaptls_pkt_l = (EAPTLSLengthIncludedPacketRef)(void *)eaptls_pkt; 812 data_ptr = eaptls_pkt->tls_data; 813 tls_message_length = data_length = length - sizeof(EAPTLSPacket); 814 815 if ((eaptls_pkt->flags & kEAPTLSPacketFlagsStart) != 0) { 816 STRING_APPEND(str, " start"); 817 } 818 if ((eaptls_pkt->flags & kEAPTLSPacketFlagsLengthIncluded) != 0) { 819 if (length < sizeof(EAPTLSLengthIncludedPacket)) { 820 STRING_APPEND(str, "\nEAPTLSLengthIncludedPacket " 821 "header truncated %d < %d\n", 822 length, (int)sizeof(EAPTLSLengthIncludedPacket)); 823 goto done; 824 } 825 data_ptr = eaptls_pkt_l->tls_data; 826 data_length = length - sizeof(EAPTLSLengthIncludedPacket); 827 tls_message_length 828 = EAPTLSLengthIncludedPacketGetMessageLength(eaptls_pkt_l); 829 STRING_APPEND(str, " length=%u", tls_message_length); 830 831 } 832 if ((eaptls_pkt->flags & kEAPTLSPacketFlagsMoreFragments) != 0) { 833 STRING_APPEND(str, " more"); 834 } 835 STRING_APPEND(str, "%s Data Length %d\n", 836 eaptls_pkt->flags != 0 ? " ]" : "", data_length); 837 if (tls_message_length > kAvoidDenialOfServiceSize) { 838 STRING_APPEND(str, "rejecting packet to avoid DOS attack %u > %d\n", 839 tls_message_length, kAvoidDenialOfServiceSize); 840 goto done; 841 } 842 print_data_cfstr(str, data_ptr, data_length); 843 *packet_is_valid = TRUE; 844 845 done: 846 return (str); 847 848} 849 850OSStatus 851EAPSecPolicyCopy(SecPolicyRef * ret_policy) 852{ 853#if TARGET_OS_EMBEDDED 854 *ret_policy = SecPolicyCreateEAP(FALSE, NULL); 855#else /* TARGET_OS_EMBEDDED */ 856 *ret_policy = SecPolicyCreateWithProperties(kSecPolicyAppleEAP, NULL); 857#endif /* TARGET_OS_EMBEDDED */ 858 if (*ret_policy != NULL) { 859 return (noErr); 860 } 861 return (-1); 862} 863 864static CFArrayRef 865copy_cert_list(CFDictionaryRef properties, CFStringRef prop_name) 866{ 867 CFArrayRef data_list; 868 869 if (properties == NULL) { 870 return (NULL); 871 } 872 data_list = CFDictionaryGetValue(properties, prop_name); 873 if (isA_CFArray(data_list) == NULL) { 874 return (NULL); 875 } 876 return (EAPCFDataArrayCreateSecCertificateArray(data_list)); 877} 878 879static CFArrayRef 880copy_user_trust_proceed_certs(CFDictionaryRef properties) 881{ 882 CFArrayRef p; 883 884 p = CFDictionaryGetValue(properties, 885 kEAPClientPropTLSUserTrustProceedCertificateChain); 886 if (p != NULL) { 887 p = EAPCFDataArrayCreateSecCertificateArray(p); 888 } 889 return (p); 890} 891 892static CFArrayRef 893get_trusted_server_names(CFDictionaryRef properties) 894{ 895 int count; 896 int i; 897 CFArrayRef list; 898 899 list = CFDictionaryGetValue(properties, 900 kEAPClientPropTLSTrustedServerNames); 901 if (list == NULL) { 902 list = CFDictionaryGetValue(properties, 903 CFSTR("TLSTrustedServerCommonNames")); 904 if (list == NULL) { 905 return (NULL); 906 } 907 } 908 if (isA_CFArray(list) == NULL) { 909 EAPLOG_FL(LOG_NOTICE, 910 "TLSTrustedServerNames is not an array"); 911 return (NULL); 912 } 913 count = CFArrayGetCount(list); 914 if (count == 0) { 915 EAPLOG_FL(LOG_NOTICE, 916 "TLSTrustedServerNames is empty"); 917 return (NULL); 918 } 919 for (i = 0; i < count; i++) { 920 CFStringRef name = CFArrayGetValueAtIndex(list, i); 921 922 if (isA_CFString(name) == NULL) { 923 EAPLOG_FL(LOG_NOTICE, 924 "TLSTrustedServerNames contains a non-string value"); 925 return (NULL); 926 } 927 } 928 return (list); 929} 930 931#if TARGET_OS_EMBEDDED 932#include <CoreFoundation/CFPreferences.h> 933#include <notify.h> 934 935#define kEAPTLSTrustExceptionsID "com.apple.network.eapclient.tls.TrustExceptions" 936#define kEAPTLSTrustExceptionsApplicationID CFSTR(kEAPTLSTrustExceptionsID) 937 938static int token; 939static bool token_valid; 940 941static void 942exceptions_change_check(void) 943{ 944 int check = 0; 945 uint32_t status; 946 947 if (!token_valid) { 948 status = notify_register_check(kEAPTLSTrustExceptionsID, &token); 949 if (status != NOTIFY_STATUS_OK) { 950 EAPLOG_FL(LOG_NOTICE, 951 "notify_register_check returned %d", 952 status); 953 return; 954 } 955 token_valid = TRUE; 956 } 957 status = notify_check(token, &check); 958 if (status != NOTIFY_STATUS_OK) { 959 EAPLOG_FL(LOG_NOTICE, 960 "notify_check returned %d", 961 status); 962 return; 963 } 964 if (check != 0) { 965 CFPreferencesSynchronize(kEAPTLSTrustExceptionsApplicationID, 966 kCFPreferencesCurrentUser, 967 kCFPreferencesAnyHost); 968 } 969 return; 970} 971 972static void 973exceptions_change_notify(void) 974{ 975 uint32_t status; 976 977 status = notify_post(kEAPTLSTrustExceptionsID); 978 if (status != NOTIFY_STATUS_OK) { 979 EAPLOG_FL(LOG_NOTICE, 980 "notify_post returned %d", 981 status); 982 } 983 return; 984} 985 986static void 987EAPTLSTrustExceptionsSave(CFStringRef domain, CFStringRef identifier, 988 CFStringRef hash_str, CFDataRef exceptions) 989{ 990 CFDictionaryRef domain_list; 991 CFDictionaryRef exceptions_list = NULL; 992 bool store_exceptions = TRUE; 993 994 exceptions_change_check(); 995 domain_list = CFPreferencesCopyValue(domain, 996 kEAPTLSTrustExceptionsApplicationID, 997 kCFPreferencesCurrentUser, 998 kCFPreferencesAnyHost); 999 if (domain_list != NULL && isA_CFDictionary(domain_list) == NULL) { 1000 CFRelease(domain_list); 1001 domain_list = NULL; 1002 } 1003 if (domain_list != NULL) { 1004 exceptions_list = CFDictionaryGetValue(domain_list, identifier); 1005 exceptions_list = isA_CFDictionary(exceptions_list); 1006 if (exceptions_list != NULL) { 1007 CFDataRef stored_exceptions; 1008 1009 stored_exceptions = CFDictionaryGetValue(exceptions_list, hash_str); 1010 if (isA_CFData(stored_exceptions) != NULL 1011 && CFEqual(stored_exceptions, exceptions)) { 1012 /* stored exceptions are correct, don't store them again */ 1013 store_exceptions = FALSE; 1014 } 1015 } 1016 } 1017 if (store_exceptions) { 1018 if (exceptions_list == NULL) { 1019 /* no exceptions for this identifier yet, create one */ 1020 exceptions_list 1021 = CFDictionaryCreate(NULL, 1022 (const void * * )&hash_str, 1023 (const void * *)&exceptions, 1024 1, 1025 &kCFTypeDictionaryKeyCallBacks, 1026 &kCFTypeDictionaryValueCallBacks); 1027 } 1028 else { 1029 /* update existing exceptions with this one */ 1030 CFMutableDictionaryRef new_exceptions_list; 1031 1032 new_exceptions_list 1033 = CFDictionaryCreateMutableCopy(NULL, 0, 1034 exceptions_list); 1035 CFDictionarySetValue(new_exceptions_list, hash_str, exceptions); 1036 /* don't CFRelease(exceptions_list), it's from domain_list */ 1037 exceptions_list = (CFDictionaryRef)new_exceptions_list; 1038 1039 } 1040 if (domain_list == NULL) { 1041 domain_list 1042 = CFDictionaryCreate(NULL, 1043 (const void * *)&identifier, 1044 (const void * *)&exceptions_list, 1045 1, 1046 &kCFTypeDictionaryKeyCallBacks, 1047 &kCFTypeDictionaryValueCallBacks); 1048 } 1049 else { 1050 CFMutableDictionaryRef new_domain_list; 1051 1052 new_domain_list 1053 = CFDictionaryCreateMutableCopy(NULL, 0, 1054 domain_list); 1055 CFDictionarySetValue(new_domain_list, identifier, exceptions_list); 1056 CFRelease(domain_list); 1057 domain_list = (CFDictionaryRef)new_domain_list; 1058 1059 } 1060 CFRelease(exceptions_list); 1061 CFPreferencesSetValue(domain, domain_list, 1062 kEAPTLSTrustExceptionsApplicationID, 1063 kCFPreferencesCurrentUser, 1064 kCFPreferencesAnyHost); 1065 CFPreferencesSynchronize(kEAPTLSTrustExceptionsApplicationID, 1066 kCFPreferencesCurrentUser, 1067 kCFPreferencesAnyHost); 1068 exceptions_change_notify(); 1069 } 1070 my_CFRelease(&domain_list); 1071 return; 1072} 1073 1074/* 1075 * Function: EAPTLSSecTrustSaveExceptions 1076 * Purpose: 1077 * Given the evaluated SecTrustRef object, save an exceptions binding for the 1078 * given domain, identifier, and server_hash_str, all of which must be 1079 * specified. 1080 * Returns: 1081 * FALSE if the trust object was not in a valid state, 1082 * TRUE otherwise. 1083 */ 1084bool 1085EAPTLSSecTrustSaveExceptionsBinding(SecTrustRef trust, 1086 CFStringRef domain, CFStringRef identifier, 1087 CFStringRef server_hash_str) 1088{ 1089 CFDataRef exceptions; 1090 1091 exceptions = SecTrustCopyExceptions(trust); 1092 if (exceptions == NULL) { 1093 EAPLOG_FL(LOG_NOTICE, "failed to copy exceptions"); 1094 return (FALSE); 1095 } 1096 EAPTLSTrustExceptionsSave(domain, identifier, server_hash_str, 1097 exceptions); 1098 CFRelease(exceptions); 1099 return (TRUE); 1100} 1101 1102/* 1103 * Function: EAPTLSRemoveTrustExceptionsBindings 1104 * Purpose: 1105 * Remove all of the trust exceptions bindings for the given 1106 * trust domain and identifier. 1107 * 1108 * Example: 1109 * EAPTLSRemoveTrustExceptionsBindings(kEAPTLSTrustExceptionsDomainWirelessSSID, 1110 * ssid); 1111 */ 1112void 1113EAPTLSRemoveTrustExceptionsBindings(CFStringRef domain, CFStringRef identifier) 1114{ 1115 CFDictionaryRef domain_list; 1116 CFDictionaryRef exceptions_list; 1117 1118 /* 1119 * Remove the saved EAP-SIM/EAP-AKA information as well. 1120 * XXX: this call should be moved into a common "EAP cleanup" function. 1121 */ 1122 if (my_CFEqual(domain, kEAPTLSTrustExceptionsDomainWirelessSSID)) { 1123 EAPSIMAKAPersistentStateForgetSSID(identifier); 1124 } 1125 1126 exceptions_change_check(); 1127 domain_list = CFPreferencesCopyValue(domain, 1128 kEAPTLSTrustExceptionsApplicationID, 1129 kCFPreferencesCurrentUser, 1130 kCFPreferencesAnyHost); 1131 if (domain_list != NULL && isA_CFDictionary(domain_list) == NULL) { 1132 CFRelease(domain_list); 1133 domain_list = NULL; 1134 } 1135 if (domain_list == NULL) { 1136 return; 1137 } 1138 exceptions_list = CFDictionaryGetValue(domain_list, identifier); 1139 if (exceptions_list != NULL) { 1140 CFMutableDictionaryRef new_domain_list; 1141 1142 new_domain_list 1143 = CFDictionaryCreateMutableCopy(NULL, 0, 1144 domain_list); 1145 CFDictionaryRemoveValue(new_domain_list, identifier); 1146 CFPreferencesSetValue(domain, new_domain_list, 1147 kEAPTLSTrustExceptionsApplicationID, 1148 kCFPreferencesCurrentUser, 1149 kCFPreferencesAnyHost); 1150 CFPreferencesSynchronize(kEAPTLSTrustExceptionsApplicationID, 1151 kCFPreferencesCurrentUser, 1152 kCFPreferencesAnyHost); 1153 exceptions_change_notify(); 1154 CFRelease(new_domain_list); 1155 } 1156 CFRelease(domain_list); 1157 return; 1158} 1159 1160static CFDataRef 1161EAPTLSTrustExceptionsCopy(CFStringRef domain, CFStringRef identifier, 1162 CFStringRef hash_str) 1163{ 1164 CFDataRef exceptions = NULL; 1165 CFDictionaryRef domain_list; 1166 1167 exceptions_change_check(); 1168 domain_list = CFPreferencesCopyValue(domain, 1169 kEAPTLSTrustExceptionsApplicationID, 1170 kCFPreferencesCurrentUser, 1171 kCFPreferencesAnyHost); 1172 if (isA_CFDictionary(domain_list) != NULL) { 1173 CFDictionaryRef exceptions_list; 1174 1175 exceptions_list = CFDictionaryGetValue(domain_list, identifier); 1176 if (isA_CFDictionary(exceptions_list) != NULL) { 1177 exceptions = isA_CFData(CFDictionaryGetValue(exceptions_list, 1178 hash_str)); 1179 if (exceptions != NULL) { 1180 CFRetain(exceptions); 1181 } 1182 } 1183 } 1184 my_CFRelease(&domain_list); 1185 return (exceptions); 1186} 1187 1188/* 1189 * Function: EAPTLSSecTrustApplyExceptionsBinding 1190 * Purpose: 1191 * Finds a stored trust exceptions object for the given domain, identifier, 1192 * and server_cert_hash. If it exists, sets the exceptions on the given 1193 * trust object. 1194 */ 1195void 1196EAPTLSSecTrustApplyExceptionsBinding(SecTrustRef trust, CFStringRef domain, 1197 CFStringRef identifier, 1198 CFStringRef server_cert_hash) 1199{ 1200 CFDataRef exceptions; 1201 1202 exceptions = EAPTLSTrustExceptionsCopy(domain, identifier, 1203 server_cert_hash); 1204 if (exceptions != NULL) { 1205 if (SecTrustSetExceptions(trust, exceptions) == FALSE) { 1206 EAPLOG_FL(LOG_NOTICE, "SecTrustSetExceptions failed"); 1207 } 1208 } 1209 my_CFRelease(&exceptions); 1210 return; 1211} 1212 1213static SecTrustRef 1214_EAPTLSCreateSecTrust(CFDictionaryRef properties, 1215 CFArrayRef server_certs, 1216 OSStatus * ret_status, 1217 EAPClientStatus * ret_client_status, 1218 bool * ret_allow_exceptions, 1219 bool * ret_has_server_certs_or_names, 1220 CFStringRef * ret_server_hash_str) 1221{ 1222 bool allow_exceptions; 1223 EAPClientStatus client_status; 1224 int count; 1225 CFStringRef domain = NULL; 1226 CFStringRef identifier = NULL; 1227 SecPolicyRef policy = NULL; 1228 OSStatus status = noErr; 1229 CFStringRef server_hash_str = NULL; 1230 CFArrayRef trusted_certs = NULL; 1231 CFArrayRef trusted_server_names; 1232 SecTrustRef trust = NULL; 1233 1234 client_status = kEAPClientStatusInternalError; 1235 if (server_certs == NULL) { 1236 goto done; 1237 } 1238 count = CFArrayGetCount(server_certs); 1239 if (count == 0) { 1240 goto done; 1241 } 1242 client_status = kEAPClientStatusSecurityError; 1243 trusted_server_names = get_trusted_server_names(properties); 1244 policy = SecPolicyCreateEAP(FALSE, trusted_server_names); 1245 if (policy == NULL) { 1246 goto done; 1247 } 1248 status = SecTrustCreateWithCertificates(server_certs, policy, &trust); 1249 if (status != noErr) { 1250 EAPLOG_FL(LOG_NOTICE, 1251 "SecTrustCreateWithCertificates failed, %s (%d)", 1252 EAPSecurityErrorString(status), (int)status); 1253 goto done; 1254 } 1255 trusted_certs = copy_cert_list(properties, 1256 kEAPClientPropTLSTrustedCertificates); 1257 if (trusted_certs != NULL) { 1258 status = SecTrustSetAnchorCertificates(trust, trusted_certs); 1259 if (status != noErr) { 1260 EAPLOG_FL(LOG_NOTICE, 1261 " SecTrustSetAnchorCertificates failed, %s (%d)", 1262 EAPSecurityErrorString(status), (int)status); 1263 goto done; 1264 } 1265 } 1266 1267 /* 1268 * Don't allow exceptions by default if either trusted certs or trusted 1269 * server names is specified. Trust exceptions must be explicitly enabled 1270 * in that case using the kEAPClientPropTLSAllowTrustExceptions property. 1271 */ 1272 if (trusted_certs != NULL || trusted_server_names != NULL) { 1273 allow_exceptions = FALSE; 1274 } 1275 else { 1276 allow_exceptions = TRUE; 1277 } 1278 allow_exceptions 1279 = my_CFDictionaryGetBooleanValue(properties, 1280 kEAPClientPropTLSAllowTrustExceptions, 1281 allow_exceptions); 1282 1283 /* both the trust exception domain and identifier must be specified */ 1284 domain 1285 = CFDictionaryGetValue(properties, 1286 kEAPClientPropTLSTrustExceptionsDomain); 1287 identifier 1288 = CFDictionaryGetValue(properties, 1289 kEAPClientPropTLSTrustExceptionsID); 1290 if (isA_CFString(domain) == NULL || isA_CFString(identifier) == NULL) { 1291 allow_exceptions = FALSE; 1292 } 1293 if (allow_exceptions) { 1294 SecCertificateRef server; 1295 1296 server = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs, 0); 1297 server_hash_str = EAPSecCertificateCopySHA1DigestString(server); 1298 EAPTLSSecTrustApplyExceptionsBinding(trust, domain, identifier, 1299 server_hash_str); 1300 } 1301 client_status = kEAPClientStatusOK; 1302 1303 done: 1304 if (client_status == kEAPClientStatusOK) { 1305 if (ret_allow_exceptions != NULL) { 1306 *ret_allow_exceptions = allow_exceptions; 1307 } 1308 if (ret_has_server_certs_or_names != NULL) { 1309 *ret_has_server_certs_or_names 1310 = (trusted_certs != NULL || trusted_server_names != NULL); 1311 } 1312 if (ret_server_hash_str != NULL) { 1313 *ret_server_hash_str = server_hash_str; 1314 } 1315 else { 1316 my_CFRelease(&server_hash_str); 1317 } 1318 } 1319 else { 1320 my_CFRelease(&trust); 1321 } 1322 if (ret_status != NULL) { 1323 *ret_status = status; 1324 } 1325 if (ret_client_status != NULL) { 1326 *ret_client_status = client_status; 1327 } 1328 my_CFRelease(&policy); 1329 my_CFRelease(&trusted_certs); 1330 return (trust); 1331} 1332 1333SecTrustRef 1334EAPTLSCreateSecTrust(CFDictionaryRef properties, CFArrayRef server_certs, 1335 CFStringRef domain, CFStringRef identifier) 1336{ 1337 CFMutableDictionaryRef dict; 1338 SecTrustRef trust; 1339 1340 dict = CFDictionaryCreateMutableCopy(NULL, 0, properties); 1341 CFDictionarySetValue(dict, kEAPClientPropTLSTrustExceptionsDomain, domain); 1342 CFDictionarySetValue(dict, kEAPClientPropTLSTrustExceptionsID, identifier); 1343 trust = _EAPTLSCreateSecTrust(dict, server_certs, 1344 NULL, NULL, NULL, NULL, NULL); 1345 my_CFRelease(&dict); 1346 return (trust); 1347} 1348 1349EAPClientStatus 1350EAPTLSVerifyServerCertificateChain(CFDictionaryRef properties, 1351 CFArrayRef server_certs, 1352 OSStatus * ret_status) 1353{ 1354 bool allow_exceptions = FALSE; 1355 bool has_server_certs_or_names = FALSE; 1356 EAPClientStatus client_status; 1357 OSStatus status; 1358 CFStringRef server_hash_str = NULL; 1359 SecTrustRef trust = NULL; 1360 SecTrustResultType trust_result; 1361 1362 1363 trust = _EAPTLSCreateSecTrust(properties, 1364 server_certs, 1365 &status, 1366 &client_status, 1367 &allow_exceptions, 1368 &has_server_certs_or_names, 1369 &server_hash_str); 1370 if (trust == NULL) { 1371 goto done; 1372 } 1373 client_status = kEAPClientStatusSecurityError; 1374 status = SecTrustEvaluate(trust, &trust_result); 1375 if (status != noErr) { 1376 EAPLOG_FL(LOG_NOTICE, 1377 "SecTrustEvaluate failed, %s (%d)", 1378 EAPSecurityErrorString(status), (int)status); 1379 goto done; 1380 } 1381 switch (trust_result) { 1382 case kSecTrustResultProceed: 1383 client_status = kEAPClientStatusOK; 1384 break; 1385 case kSecTrustResultUnspecified: 1386 if (has_server_certs_or_names) { 1387 /* trusted certs or server names specified, it's OK to proceed */ 1388 client_status = kEAPClientStatusOK; 1389 break; 1390 } 1391 /* FALL THROUGH */ 1392 case kSecTrustResultRecoverableTrustFailure: 1393 if (allow_exceptions) { 1394 client_status = kEAPClientStatusUserInputRequired; 1395 break; 1396 } 1397 /* FALL THROUGH */ 1398 case kSecTrustResultDeny: 1399 default: 1400 status = errSSLXCertChainInvalid; 1401 break; 1402 } 1403 1404 /* if the trust is recoverable, check whether the user already said OK */ 1405 if (client_status == kEAPClientStatusUserInputRequired) { 1406 CFArrayRef proceed; 1407 1408 proceed = copy_user_trust_proceed_certs(properties); 1409 if (proceed != NULL 1410 && CFEqual(proceed, server_certs)) { 1411 bool save_it; 1412 1413 client_status = kEAPClientStatusOK; 1414 save_it = my_CFDictionaryGetBooleanValue(properties, 1415 kEAPClientPropTLSSaveTrustExceptions, 1416 FALSE); 1417 if (save_it && server_hash_str != NULL) { 1418 CFStringRef domain; 1419 CFStringRef identifier; 1420 1421 domain 1422 = CFDictionaryGetValue(properties, 1423 kEAPClientPropTLSTrustExceptionsDomain); 1424 identifier 1425 = CFDictionaryGetValue(properties, 1426 kEAPClientPropTLSTrustExceptionsID); 1427 EAPTLSSecTrustSaveExceptionsBinding(trust, domain, identifier, 1428 server_hash_str); 1429 } 1430 } 1431 my_CFRelease(&proceed); 1432 } 1433 1434 done: 1435 if (ret_status != NULL) { 1436 *ret_status = status; 1437 } 1438 my_CFRelease(&trust); 1439 my_CFRelease(&server_hash_str); 1440 return (client_status); 1441} 1442 1443#else /* TARGET_OS_EMBEDDED */ 1444 1445static bool 1446cert_list_contains_cert(CFArrayRef list, SecCertificateRef cert) 1447{ 1448 int count; 1449 int i; 1450 1451 count = CFArrayGetCount(list); 1452 for (i = 0; i < count; i++) { 1453 SecCertificateRef this_cert; 1454 1455 this_cert = (SecCertificateRef)CFArrayGetValueAtIndex(list, i); 1456 if (CFEqual(cert, this_cert)) { 1457 return (TRUE); 1458 } 1459 } 1460 return (FALSE); 1461} 1462 1463static CFArrayRef 1464EAPSecTrustCopyCertificateChain(SecTrustRef trust) 1465{ 1466 CFMutableArrayRef array = NULL; 1467 int count = SecTrustGetCertificateCount(trust); 1468 int i; 1469 1470 if (count == 0) { 1471 EAPLOG_FL(LOG_NOTICE, "SecTrustGetCertificateCount returned 0"); 1472 goto done; 1473 } 1474 array = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks); 1475 for (i = 0; i < count; i++) { 1476 SecCertificateRef s; 1477 1478 s = SecTrustGetCertificateAtIndex(trust, i); 1479 CFArrayAppendValue(array, s); 1480 } 1481 done: 1482 return (array); 1483} 1484 1485static bool 1486server_cert_chain_is_trusted(SecTrustRef trust, CFArrayRef trusted_certs) 1487{ 1488 CFArrayRef cert_chain; 1489 int count; 1490 int i; 1491 bool ret = FALSE; 1492 1493 cert_chain = EAPSecTrustCopyCertificateChain(trust); 1494 if (cert_chain != NULL) { 1495 count = CFArrayGetCount(cert_chain); 1496 } 1497 else { 1498 count = 0; 1499 } 1500 if (count == 0) { 1501 EAPLOG_FL(LOG_NOTICE, "failed to get evidence chain"); 1502 goto done; 1503 } 1504 for (i = 0; i < count; i++) { 1505 SecCertificateRef cert; 1506 1507 cert = (SecCertificateRef)CFArrayGetValueAtIndex(cert_chain, i); 1508 if (cert_list_contains_cert(trusted_certs, cert)) { 1509 ret = TRUE; 1510 break; 1511 } 1512 } 1513 1514 done: 1515 my_CFRelease(&cert_chain); 1516 return (ret); 1517} 1518 1519static bool 1520server_name_matches_server_names(CFStringRef name, 1521 CFArrayRef trusted_server_names) 1522{ 1523 int count; 1524 int i; 1525 bool trusted = FALSE; 1526 1527 count = CFArrayGetCount(trusted_server_names); 1528 for (i = 0; i < count; i++) { 1529 CFStringRef this_name = CFArrayGetValueAtIndex(trusted_server_names, 1530 i); 1531 if (CFEqual(name, this_name)) { 1532 trusted = TRUE; 1533 break; 1534 } 1535 if (CFStringHasPrefix(this_name, CFSTR("*."))) { 1536 bool match = FALSE; 1537 CFMutableStringRef suffix; 1538 1539 suffix = CFStringCreateMutableCopy(NULL, 0, this_name); 1540 CFStringDelete(suffix, CFRangeMake(0, 1)); /* remove dot */ 1541 if (CFStringHasSuffix(name, suffix)) { 1542 match = TRUE; 1543 } 1544 CFRelease(suffix); 1545 if (match) { 1546 trusted = TRUE; 1547 break; 1548 } 1549 } 1550 } 1551 return (trusted); 1552} 1553 1554static bool 1555server_cert_matches_server_names(SecCertificateRef cert, 1556 CFArrayRef trusted_server_names) 1557{ 1558 CFDictionaryRef attrs; 1559 bool match = FALSE; 1560 CFStringRef name; 1561 1562 attrs = EAPSecCertificateCopyAttributesDictionary(cert); 1563 if (attrs == NULL) { 1564 goto done; 1565 } 1566 name = CFDictionaryGetValue(attrs, kEAPSecCertificateAttributeCommonName); 1567 if (name == NULL) { 1568 goto done; 1569 } 1570 match = server_name_matches_server_names(name, trusted_server_names); 1571 1572 done: 1573 my_CFRelease(&attrs); 1574 return (match); 1575} 1576 1577/* 1578 * Function: verify_server_certs 1579 * Purpose: 1580 * If the trusted_server_names list is specified, verify that the server 1581 * cert name matches. Similarly, if the trusted_certs list is specified, 1582 * make sure that one of the certs in the cert chain in the SecTrust object 1583 * is in the trusted_certs list. 1584 * Notes: 1585 * The assumption here is that TrustSettings are already in place, and 1586 * we perform additional checks to validate the cert chain on top of that. 1587 */ 1588static bool 1589verify_server_certs(SecTrustRef trust, 1590 CFArrayRef server_certs, 1591 CFArrayRef trusted_certs, 1592 CFArrayRef trusted_server_names) 1593{ 1594 if (trusted_server_names != NULL) { 1595 SecCertificateRef cert; 1596 1597 cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs, 0); 1598 if (server_cert_matches_server_names(cert, trusted_server_names) 1599 == FALSE) { 1600 return (FALSE); 1601 } 1602 } 1603 if (trusted_certs != NULL 1604 && server_cert_chain_is_trusted(trust, trusted_certs) == FALSE) { 1605 return (FALSE); 1606 } 1607 return (TRUE); 1608} 1609 1610EAPClientStatus 1611EAPTLSVerifyServerCertificateChain(CFDictionaryRef properties, 1612 CFArrayRef server_certs, 1613 OSStatus * ret_status) 1614{ 1615 bool allow_trust_decisions; 1616 EAPClientStatus client_status; 1617 int count; 1618 bool is_recoverable; 1619 SecPolicyRef policy = NULL; 1620 CFStringRef profileID; 1621 OSStatus status = noErr; 1622 SecTrustRef trust = NULL; 1623 SecTrustResultType trust_result; 1624 CFArrayRef trusted_certs = NULL; 1625 CFArrayRef trusted_server_names; 1626 1627 client_status = kEAPClientStatusInternalError; 1628 1629 /* don't bother verifying server's identity */ 1630 if (my_CFDictionaryGetBooleanValue(properties, 1631 kEAPClientPropTLSVerifyServerCertificate, 1632 TRUE) == FALSE) { 1633 client_status = kEAPClientStatusOK; 1634 } 1635 else { 1636 CFArrayRef proceed; 1637 1638 proceed = copy_user_trust_proceed_certs(properties); 1639 if (proceed != NULL 1640 && CFEqual(proceed, server_certs)) { 1641 /* user said it was OK to go */ 1642 client_status = kEAPClientStatusOK; 1643 } 1644 my_CFRelease(&proceed); 1645 } 1646 if (client_status == kEAPClientStatusOK) { 1647 goto done; 1648 } 1649 if (server_certs == NULL) { 1650 goto done; 1651 } 1652 count = CFArrayGetCount(server_certs); 1653 if (count == 0) { 1654 goto done; 1655 } 1656 profileID = CFDictionaryGetValue(properties, kEAPClientPropProfileID); 1657 trusted_certs = copy_cert_list(properties, 1658 kEAPClientPropTLSTrustedCertificates); 1659 trusted_server_names = get_trusted_server_names(properties); 1660 1661 /* 1662 * Don't allow trust decisions by the user by default if either trusted 1663 * certs or trusted server names is specified. Trust decisions must be 1664 * explicitly enabled in that case using the 1665 * kEAPClientPropTLSAllowTrustDecisions property. 1666 */ 1667 if (trusted_certs != NULL || trusted_server_names != NULL) { 1668 allow_trust_decisions = FALSE; 1669 } 1670 else { 1671 allow_trust_decisions = TRUE; 1672 } 1673 allow_trust_decisions 1674 = my_CFDictionaryGetBooleanValue(properties, 1675 kEAPClientPropTLSAllowTrustDecisions, 1676 allow_trust_decisions); 1677 client_status = kEAPClientStatusSecurityError; 1678 status = EAPSecPolicyCopy(&policy); 1679 if (status != noErr) { 1680 goto done; 1681 } 1682 status = SecTrustCreateWithCertificates(server_certs, policy, &trust); 1683 if (status != noErr) { 1684 EAPLOG_FL(LOG_NOTICE, 1685 "SecTrustCreateWithCertificates failed, %s (%d)", 1686 EAPSecurityErrorString(status), (int)status); 1687 goto done; 1688 } 1689 if (profileID != NULL && trusted_certs != NULL) { 1690 status = SecTrustSetAnchorCertificates(trust, trusted_certs); 1691 if (status != noErr) { 1692 EAPLOG_FL(LOG_NOTICE, 1693 "SecTrustSetAnchorCertificates failed, %s (%d)", 1694 EAPSecurityErrorString(status), (int)status); 1695 goto done; 1696 } 1697 } 1698 status = SecTrustEvaluate(trust, &trust_result); 1699 switch (status) { 1700 case noErr: 1701 break; 1702 case errSecNoDefaultKeychain: 1703 status = SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem); 1704 if (status != noErr) { 1705 EAPLOG_FL(LOG_NOTICE, 1706 "SecKeychainSetPreferenceDomain failed, %s (%d)", 1707 EAPSecurityErrorString(status), (int)status); 1708 goto done; 1709 } 1710 status = SecTrustEvaluate(trust, &trust_result); 1711 if (status == noErr) { 1712 break; 1713 } 1714 /* FALL THROUGH */ 1715 default: 1716 EAPLOG_FL(LOG_NOTICE, 1717 "SecTrustEvaluate failed, %s (%d)", 1718 EAPSecurityErrorString(status), (int)status); 1719 goto done; 1720 break; 1721 } 1722 is_recoverable = FALSE; 1723 switch (trust_result) { 1724 case kSecTrustResultProceed: 1725 if (verify_server_certs(trust, server_certs, trusted_certs, 1726 trusted_server_names)) { 1727 /* the chain and/or name is valid */ 1728 client_status = kEAPClientStatusOK; 1729 break; 1730 } 1731 is_recoverable = TRUE; 1732 break; 1733 case kSecTrustResultUnspecified: 1734 if (profileID != NULL 1735 && (trusted_certs != NULL || trusted_server_names != NULL)) { 1736 /* still need to check server names */ 1737 if (trusted_server_names != NULL) { 1738 if (verify_server_certs(NULL, server_certs, NULL, 1739 trusted_server_names)) { 1740 client_status = kEAPClientStatusOK; 1741 break; 1742 } 1743 } 1744 else { 1745 client_status = kEAPClientStatusOK; 1746 break; 1747 } 1748 } 1749 is_recoverable = TRUE; 1750 break; 1751 case kSecTrustResultRecoverableTrustFailure: 1752 is_recoverable = TRUE; 1753 break; 1754 case kSecTrustResultDeny: 1755 default: 1756 status = errSSLXCertChainInvalid; 1757 break; 1758 } 1759 if (is_recoverable) { 1760 if (allow_trust_decisions == FALSE) { 1761 client_status = kEAPClientStatusServerCertificateNotTrusted; 1762 } 1763 else { 1764 client_status = kEAPClientStatusUserInputRequired; 1765 } 1766 } 1767 1768 done: 1769 if (ret_status != NULL) { 1770 *ret_status = status; 1771 } 1772 my_CFRelease(&policy); 1773 my_CFRelease(&trust); 1774 my_CFRelease(&trusted_certs); 1775 return (client_status); 1776} 1777 1778#endif /* TARGET_OS_EMBEDDED */ 1779 1780OSStatus 1781EAPTLSCopyIdentityTrustChain(SecIdentityRef sec_identity, 1782 CFDictionaryRef properties, 1783 CFArrayRef * ret_array) 1784{ 1785 if (sec_identity != NULL) { 1786 return (EAPSecIdentityCreateTrustChain(sec_identity, ret_array)); 1787 } 1788 if (properties != NULL) { 1789 EAPSecIdentityHandleRef id_handle; 1790 1791 id_handle = CFDictionaryGetValue(properties, 1792 kEAPClientPropTLSIdentityHandle); 1793 if (id_handle != NULL) { 1794 return (EAPSecIdentityHandleCreateSecIdentityTrustChain(id_handle, 1795 ret_array)); 1796 } 1797 } 1798 *ret_array = NULL; 1799 return (errSecParam); 1800} 1801 1802 1803#if defined(TEST_TRUST_EXCEPTIONS) || defined(TEST_EAPTLSVerifyServerCertificateChain) 1804 1805#include <sys/types.h> 1806#include <sys/uio.h> 1807#include <unistd.h> 1808#include <fcntl.h> 1809#include <sys/stat.h> 1810 1811static CFDataRef 1812file_create_data(const char * filename) 1813{ 1814 CFMutableDataRef data = NULL; 1815 size_t len = 0; 1816 int fd = -1; 1817 struct stat sb; 1818 1819 if (stat(filename, &sb) < 0) { 1820 goto done; 1821 } 1822 len = sb.st_size; 1823 if (len == 0) { 1824 goto done; 1825 } 1826 data = CFDataCreateMutable(NULL, len); 1827 if (data == NULL) { 1828 goto done; 1829 } 1830 fd = open(filename, O_RDONLY); 1831 if (fd < 0) { 1832 goto done; 1833 } 1834 CFDataSetLength(data, len); 1835 if (read(fd, CFDataGetMutableBytePtr(data), len) != len) { 1836 goto done; 1837 } 1838 done: 1839 if (fd >= 0) { 1840 close(fd); 1841 } 1842 return (data); 1843} 1844 1845static SecCertificateRef 1846file_create_certificate(const char * filename) 1847{ 1848 CFDataRef data; 1849 SecCertificateRef cert; 1850 1851 data = file_create_data(filename); 1852 if (data == NULL) { 1853 return (NULL); 1854 } 1855 cert = SecCertificateCreateWithData(NULL, data); 1856 CFRelease(data); 1857 return (cert); 1858} 1859#endif /* defined(TEST_TRUST_EXCEPTIONS) || defined(TEST_EAPTLSVerifyServerCertificateChain) */ 1860 1861#ifdef TEST_TRUST_EXCEPTIONS 1862#if TARGET_OS_EMBEDDED 1863#include <SystemConfiguration/SCPrivate.h> 1864 1865static void 1866usage(const char * progname) 1867{ 1868 fprintf(stderr, "usage:\n%s get <domain> <identifier> <cert-file>\n", 1869 progname); 1870 fprintf(stderr, "%s remove_all <domain> <identifier>\n", progname); 1871 exit(1); 1872 return; 1873} 1874enum { 1875 kCommandGet, 1876 kCommandRemoveAll 1877}; 1878 1879static CFStringRef 1880file_create_certificate_hash(const char * filename) 1881{ 1882 SecCertificateRef cert; 1883 CFStringRef str; 1884 1885 cert = file_create_certificate(filename); 1886 if (cert == NULL) { 1887 return (NULL); 1888 } 1889 str = EAPSecCertificateCopySHA1DigestString(cert); 1890 CFRelease(cert); 1891 return (str); 1892} 1893 1894static void 1895getTrustExceptions(char * domain, char * identifier, char * cert_file) 1896{ 1897 CFStringRef domain_cf; 1898 CFDataRef exceptions; 1899 CFStringRef identifier_cf; 1900 CFStringRef cert_hash; 1901 1902 domain_cf 1903 = CFStringCreateWithCStringNoCopy(NULL, 1904 domain, 1905 kCFStringEncodingUTF8, 1906 kCFAllocatorNull); 1907 identifier_cf 1908 = CFStringCreateWithCStringNoCopy(NULL, 1909 identifier, 1910 kCFStringEncodingUTF8, 1911 kCFAllocatorNull); 1912 cert_hash = file_create_certificate_hash(cert_file); 1913 if (cert_hash == NULL) { 1914 fprintf(stderr, "error reading certificate file '%s', %s\n", 1915 cert_file, strerror(errno)); 1916 exit(1); 1917 } 1918 exceptions = EAPTLSTrustExceptionsCopy(domain_cf, 1919 identifier_cf, 1920 cert_hash); 1921 if (exceptions != NULL) { 1922 SCPrint(TRUE, stdout, 1923 CFSTR("Exceptions for %@/%@/%@ are defined:\n%@\n"), 1924 domain_cf, identifier_cf, cert_hash, 1925 exceptions); 1926 } 1927 else { 1928 SCPrint(TRUE, stdout, 1929 CFSTR("No exceptions for %@/%@/%@ are defined\n"), 1930 domain_cf, identifier_cf, cert_hash); 1931 } 1932 return; 1933} 1934 1935static void 1936removeAllTrustExceptions(char * domain, char * identifier) 1937{ 1938 CFStringRef domain_cf; 1939 CFStringRef identifier_cf; 1940 1941 domain_cf 1942 = CFStringCreateWithCStringNoCopy(NULL, 1943 domain, 1944 kCFStringEncodingUTF8, 1945 kCFAllocatorNull); 1946 identifier_cf 1947 = CFStringCreateWithCStringNoCopy(NULL, 1948 identifier, 1949 kCFStringEncodingUTF8, 1950 kCFAllocatorNull); 1951 EAPTLSRemoveTrustExceptionsBindings(domain_cf, identifier_cf); 1952 CFRelease(domain_cf); 1953 CFRelease(identifier_cf); 1954 return; 1955} 1956 1957int 1958main(int argc, char * argv[]) 1959{ 1960 int command; 1961 1962 if (argc < 2) { 1963 usage(argv[0]); 1964 } 1965 if (strcmp(argv[1], "get") == 0) { 1966 command = kCommandGet; 1967 } 1968 else if (strcmp(argv[1], "remove_all") == 0) { 1969 command = kCommandRemoveAll; 1970 } 1971 else { 1972 usage(argv[0]); 1973 } 1974 switch (command) { 1975 case kCommandGet: 1976 if (argc < 5) { 1977 usage(argv[0]); 1978 } 1979 getTrustExceptions(argv[2], argv[3], argv[4]); 1980 break; 1981 case kCommandRemoveAll: 1982 if (argc < 4) { 1983 usage(argv[0]); 1984 } 1985 removeAllTrustExceptions(argv[2], argv[3]); 1986 break; 1987 } 1988 exit(0); 1989 return (0); 1990} 1991 1992#else /* TARGET_OS_EMBEDDED */ 1993 1994#error "TrustExceptions are only available with TARGET_OS_EMBEDDED" 1995#endif /* TARGET_OS_EMBEDDED */ 1996#endif /* TEST_TRUST_EXCEPTIONS */ 1997 1998#ifdef TEST_SEC_TRUST 1999 2000#if TARGET_OS_EMBEDDED 2001#include <sys/types.h> 2002#include <sys/uio.h> 2003#include <unistd.h> 2004#include <fcntl.h> 2005#include <sys/stat.h> 2006#include <SystemConfiguration/SCPrivate.h> 2007 2008static CFDictionaryRef 2009read_dictionary(const char * filename) 2010{ 2011 CFDictionaryRef dict; 2012 2013 dict = my_CFPropertyListCreateFromFile(filename); 2014 if (dict != NULL) { 2015 if (isA_CFDictionary(dict) == NULL) { 2016 CFRelease(dict); 2017 dict = NULL; 2018 } 2019 } 2020 return (dict); 2021} 2022 2023static CFArrayRef 2024read_array(const char * filename) 2025{ 2026 CFArrayRef array; 2027 2028 array = my_CFPropertyListCreateFromFile(filename); 2029 if (array != NULL) { 2030 if (isA_CFArray(array) == NULL) { 2031 CFRelease(array); 2032 array = NULL; 2033 } 2034 } 2035 return (array); 2036} 2037 2038static void 2039usage(const char * progname) 2040{ 2041 fprintf(stderr, "usage: %s <domain> <identifier> <config> <certs>\n", 2042 progname); 2043 exit(1); 2044 return; 2045} 2046 2047int 2048main(int argc, char * argv[]) 2049{ 2050 CFArrayRef certs; 2051 CFArrayRef certs_data; 2052 CFDictionaryRef config; 2053 const char * domain; 2054 CFStringRef domain_cf; 2055 const char * identifier; 2056 CFStringRef identifier_cf; 2057 const char * result_str; 2058 OSStatus status; 2059 SecTrustRef trust; 2060 SecTrustResultType trust_result; 2061 2062 if (argc < 5) { 2063 usage(argv[0]); 2064 } 2065 domain = argv[1]; 2066 identifier = argv[2]; 2067 config = read_dictionary(argv[3]); 2068 if (config == NULL) { 2069 fprintf(stderr, "failed to load '%s'\n", 2070 argv[3]); 2071 exit(1); 2072 } 2073 certs_data = read_array(argv[4]); 2074 if (certs_data == NULL) { 2075 fprintf(stderr, "failed to load '%s'\n", 2076 argv[4]); 2077 exit(1); 2078 } 2079 certs = EAPCFDataArrayCreateSecCertificateArray(certs_data); 2080 if (certs == NULL) { 2081 fprintf(stderr, 2082 "the file '%s' does not contain a certificate array data\n", 2083 argv[4]); 2084 exit(1); 2085 } 2086 domain_cf 2087 = CFStringCreateWithCStringNoCopy(NULL, 2088 domain, 2089 kCFStringEncodingUTF8, 2090 kCFAllocatorNull); 2091 identifier_cf 2092 = CFStringCreateWithCStringNoCopy(NULL, 2093 identifier, 2094 kCFStringEncodingUTF8, 2095 kCFAllocatorNull); 2096 trust = EAPTLSCreateSecTrust(config, certs, domain_cf, identifier_cf); 2097 if (trust == NULL) { 2098 fprintf(stderr, "EAPTLSCreateSecTrustFailed failed\n"); 2099 exit(1); 2100 } 2101 status = SecTrustEvaluate(trust, &trust_result); 2102 if (status != noErr) { 2103 fprintf(stderr, "SecTrustEvaluate failed, %s (%d)", 2104 EAPSecurityErrorString(status), (int)status); 2105 exit(1); 2106 } 2107 switch (trust_result) { 2108 case kSecTrustResultProceed: 2109 result_str = "Proceed"; 2110 break; 2111 case kSecTrustResultUnspecified: 2112 result_str = "Unspecified"; 2113 break; 2114 case kSecTrustResultRecoverableTrustFailure: 2115 result_str = "RecoverableTrustFailure"; 2116 break; 2117 case kSecTrustResultDeny: 2118 result_str = "Deny"; 2119 break; 2120 default: 2121 result_str = "<unknown>"; 2122 break; 2123 } 2124 printf("Trust result is %s\n", result_str); 2125 CFRelease(domain_cf); 2126 CFRelease(identifier_cf); 2127 CFRelease(certs_data); 2128 CFRelease(certs); 2129 CFRelease(trust); 2130 exit(0); 2131 return (0); 2132} 2133 2134#else /* TARGET_OS_EMBEDDED */ 2135 2136#error "SecTrust test is only available with TARGET_OS_EMBEDDED" 2137#endif /* TARGET_OS_EMBEDDED */ 2138#endif /* TEST_SEC_TRUST */ 2139 2140#ifdef TEST_SERVER_NAMES 2141#if TARGET_OS_EMBEDDED 2142#error "Can't test server names with TARGET_OS_EMBEDDED" 2143#else /* TARGET_OS_EMBEDDED */ 2144 2145#include <SystemConfiguration/SCPrivate.h> 2146 2147int 2148main() 2149{ 2150 const void * name_list[] = { 2151 CFSTR("siegdi.apple.com"), 2152 CFSTR("radius1.testing123.org"), 2153 CFSTR("apple.com"), 2154 CFSTR("radius1.foo.bar.nellie.joe.edu"), 2155 NULL 2156 }; 2157 int i; 2158 CFStringRef match1 = CFSTR("*.apple.com"); 2159 CFStringRef match2 = CFSTR("*.testing123.org"); 2160 CFStringRef match3 = CFSTR("*.foo.bar.nellie.joe.edu"); 2161 CFStringRef match4 = CFSTR("apple.com"); 2162 const void * vlist[3] = { match1, match2, match4 }; 2163 CFArrayRef list[3] = { NULL, NULL, NULL }; 2164 2165 list[0] = CFArrayCreate(NULL, (const void **)&match1, 2166 1, &kCFTypeArrayCallBacks); 2167 list[1] = CFArrayCreate(NULL, vlist, 3, &kCFTypeArrayCallBacks); 2168 list[2] = CFArrayCreate(NULL, (const void **)&match3, 1, 2169 &kCFTypeArrayCallBacks); 2170 SCPrint(TRUE, stdout, CFSTR("list[0] = %@\n"), list[0]); 2171 SCPrint(TRUE, stdout, CFSTR("list[1] = %@\n"), list[1]); 2172 SCPrint(TRUE, stdout, CFSTR("list[2] = %@\n"), list[2]); 2173 for (i = 0; name_list[i] != NULL; i++) { 2174 int j; 2175 for (j = 0; j < 3; j++) { 2176 if (server_name_matches_server_names(name_list[i], 2177 list[j])) { 2178 SCPrint(TRUE, stdout, CFSTR("%@ matches list[%d]\n"), 2179 name_list[i], j); 2180 } 2181 else { 2182 SCPrint(TRUE, stdout, CFSTR("%@ does not match list[%d]\n"), 2183 name_list[i], j); 2184 } 2185 } 2186 } 2187 exit(0); 2188 return (0); 2189} 2190 2191#endif /* TARGET_OS_EMBEDDED */ 2192#endif /* TEST_SERVER_NAMES */ 2193 2194#ifdef TEST_EAPTLSVerifyServerCertificateChain 2195 2196static CFDictionaryRef 2197read_dictionary(const char * filename) 2198{ 2199 CFDictionaryRef dict; 2200 2201 dict = my_CFPropertyListCreateFromFile(filename); 2202 if (dict != NULL) { 2203 if (isA_CFDictionary(dict) == NULL) { 2204 CFRelease(dict); 2205 dict = NULL; 2206 } 2207 } 2208 return (dict); 2209} 2210 2211int 2212main(int argc, char * argv[]) 2213{ 2214 CFArrayRef array; 2215 CFDictionaryRef properties; 2216 OSStatus sec_status; 2217 SecCertificateRef server_cert; 2218 EAPClientStatus status; 2219 2220 if (argc < 3) { 2221 fprintf(stderr, "usage: verify_server <cert-file> <properties>\n"); 2222 exit(1); 2223 } 2224 server_cert = file_create_certificate(argv[1]); 2225 if (server_cert == NULL) { 2226 fprintf(stderr, "failed to load cert file\n"); 2227 exit(2); 2228 } 2229 properties = read_dictionary(argv[2]); 2230 if (properties == NULL) { 2231 fprintf(stderr, "failed to load properties\n"); 2232 exit(2); 2233 } 2234 array = CFArrayCreate(NULL, (const void **)&server_cert, 1, 2235 &kCFTypeArrayCallBacks); 2236 2237 status = EAPTLSVerifyServerCertificateChain(properties, 2238 array, 2239 &sec_status); 2240 printf("status is %d, sec status is %d\n", 2241 status, sec_status); 2242 exit(0); 2243} 2244#endif /* TEST_EAPTLSVerifyServerCertificateChain */ 2245