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 * eaptls_plugin.c 26 * - EAP-TLS client using SecureTransport API's 27 */ 28 29/* 30 * Modification History 31 * 32 * August 26, 2002 Dieter Siegmund (dieter@apple) 33 * - created 34 * 35 * September 8, 2004 Dieter Siegmund (dieter@apple) 36 * - use SecTrustEvaluate, and enable user interaction to decide whether to 37 * proceed or not, instead of just generating an error 38 */ 39 40#include <unistd.h> 41#include <stdlib.h> 42#include <string.h> 43#include <stdio.h> 44#include <SystemConfiguration/SCValidation.h> 45#include <CoreFoundation/CFArray.h> 46#include <CoreFoundation/CFDictionary.h> 47#include <EAP8021X/EAPClientPlugin.h> 48#include <EAP8021X/EAPClientProperties.h> 49#include <EAP8021X/EAPTLSUtil.h> 50#include <EAP8021X/EAPCertificateUtil.h> 51#include <EAP8021X/EAPUtil.h> 52#include <Security/SecureTransport.h> 53#include <Security/SecCertificate.h> 54#include <Security/SecIdentity.h> 55#include <Security/SecureTransportPriv.h> 56#include "myCFUtil.h" 57#include "printdata.h" 58#include "EAPLog.h" 59 60/* 61 * Declare these here to ensure that the compiler 62 * generates appropriate errors/warnings 63 */ 64EAPClientPluginFuncIntrospect eaptls_introspect; 65static EAPClientPluginFuncVersion eaptls_version; 66static EAPClientPluginFuncEAPType eaptls_type; 67static EAPClientPluginFuncEAPName eaptls_name; 68static EAPClientPluginFuncInit eaptls_init; 69static EAPClientPluginFuncFree eaptls_free; 70static EAPClientPluginFuncProcess eaptls_process; 71static EAPClientPluginFuncFreePacket eaptls_free_packet; 72static EAPClientPluginFuncSessionKey eaptls_session_key; 73static EAPClientPluginFuncServerKey eaptls_server_key; 74static EAPClientPluginFuncRequireProperties eaptls_require_props; 75static EAPClientPluginFuncPublishProperties eaptls_publish_props; 76static EAPClientPluginFuncUserName eaptls_user_name_copy; 77static EAPClientPluginFuncCopyPacketDescription eaptls_copy_packet_description; 78 79typedef enum { 80 kRequestTypeStart, 81 kRequestTypeAck, 82 kRequestTypeData, 83} RequestType; 84 85typedef struct { 86 SSLContextRef ssl_context; 87 memoryBuffer read_buffer; 88 memoryBuffer write_buffer; 89 int last_write_size; 90 int previous_identifier; 91 memoryIO mem_io; 92 EAPClientState plugin_state; 93 bool cert_is_required; 94 CFArrayRef certs; 95 int mtu; 96 OSStatus last_ssl_error; 97 EAPClientStatus last_client_status; 98 OSStatus trust_ssl_error; 99 EAPClientStatus trust_status; 100 bool trust_proceed; 101 bool key_data_valid; 102 char key_data[128]; 103 bool resume_sessions; 104 bool server_auth_completed; 105 CFArrayRef server_certs; 106 bool session_was_resumed; 107} EAPTLSPluginData, * EAPTLSPluginDataRef; 108 109enum { 110 kAvoidDenialOfServiceSize = 128 * 1024 111}; 112 113#define BAD_IDENTIFIER (-1) 114 115#define kEAPTLSClientLabel "client EAP encryption" 116#define kEAPTLSClientLabelLength (sizeof(kEAPTLSClientLabel) - 1) 117 118static bool 119eaptls_compute_session_key(EAPTLSPluginDataRef context) 120{ 121 OSStatus status; 122 123 context->key_data_valid = FALSE; 124 status = EAPTLSComputeKeyData(context->ssl_context, 125 kEAPTLSClientLabel, 126 kEAPTLSClientLabelLength, 127 context->key_data, 128 sizeof(context->key_data)); 129 if (status != noErr) { 130 EAPLOG_FL(LOG_NOTICE, "EAPTLSComputeSessionKey failed, %s", 131 EAPSSLErrorString(status)); 132 return (FALSE); 133 } 134 context->key_data_valid = TRUE; 135 return (TRUE); 136} 137 138static void 139eaptls_free_context(EAPTLSPluginDataRef context) 140{ 141 if (context->ssl_context != NULL) { 142 CFRelease(context->ssl_context); 143 context->ssl_context = NULL; 144 } 145 my_CFRelease(&context->certs); 146 my_CFRelease(&context->server_certs); 147 memoryIOClearBuffers(&context->mem_io); 148 free(context); 149 return; 150} 151 152static OSStatus 153eaptls_start(EAPClientPluginDataRef plugin) 154{ 155 EAPTLSPluginDataRef context = (EAPTLSPluginDataRef)plugin->private; 156 SSLContextRef ssl_context = NULL; 157 OSStatus status = noErr; 158 159 if (context->ssl_context != NULL) { 160 CFRelease(context->ssl_context); 161 context->ssl_context = NULL; 162 } 163 my_CFRelease(&context->server_certs); 164 memoryIOClearBuffers(&context->mem_io); 165 ssl_context = EAPTLSMemIOContextCreate(FALSE, &context->mem_io, NULL, 166 &status); 167 if (ssl_context == NULL) { 168 EAPLOG_FL(LOG_NOTICE, "EAPTLSMemIOContextCreate failed, %s", 169 EAPSSLErrorString(status)); 170 goto failed; 171 } 172 if (context->resume_sessions && plugin->unique_id != NULL) { 173 status = SSLSetPeerID(ssl_context, plugin->unique_id, 174 plugin->unique_id_length); 175 if (status != noErr) { 176 EAPLOG_FL(LOG_NOTICE, 177 "SSLSetPeerID failed, %s", EAPSSLErrorString(status)); 178 goto failed; 179 } 180 } 181 if (context->cert_is_required) { 182 if (context->certs == NULL) { 183 status = EAPTLSCopyIdentityTrustChain(plugin->sec_identity, 184 plugin->properties, 185 &context->certs); 186 if (status != noErr) { 187 EAPLOG_FL(LOG_NOTICE, 188 "failed to find client cert/identity, %s (%ld)", 189 EAPSSLErrorString(status), (long)status); 190 goto failed; 191 } 192 } 193 status = SSLSetCertificate(ssl_context, context->certs); 194 if (status != noErr) { 195 EAPLOG_FL(LOG_NOTICE, 196 "SSLSetCertificate failed, %s", 197 EAPSSLErrorString(status)); 198 goto failed; 199 } 200 } 201 context->ssl_context = ssl_context; 202 context->plugin_state = kEAPClientStateAuthenticating; 203 context->previous_identifier = BAD_IDENTIFIER; 204 context->last_ssl_error = noErr; 205 context->last_client_status = kEAPClientStatusOK; 206 context->trust_proceed = FALSE; 207 context->server_auth_completed = FALSE; 208 context->key_data_valid = FALSE; 209 context->last_write_size = 0; 210 context->session_was_resumed = FALSE; 211 return (status); 212 failed: 213 if (ssl_context != NULL) { 214 CFRelease(ssl_context); 215 } 216 return (status); 217 218} 219 220static EAPClientStatus 221eaptls_init(EAPClientPluginDataRef plugin, CFArrayRef * required_props, 222 EAPClientDomainSpecificError * error) 223{ 224 EAPTLSPluginDataRef context = NULL; 225 226 context = malloc(sizeof(*context)); 227 bzero(context, sizeof(*context)); 228 context->cert_is_required 229 = my_CFDictionaryGetBooleanValue(plugin->properties, 230 kEAPClientPropTLSCertificateIsRequired, 231 TRUE); 232 context->mtu = plugin->mtu; 233 context->resume_sessions 234 = my_CFDictionaryGetBooleanValue(plugin->properties, 235 kEAPClientPropTLSEnableSessionResumption, 236 TRUE); 237 /* memoryIOInit() initializes the memoryBuffer structures as well */ 238 memoryIOInit(&context->mem_io, &context->read_buffer, 239 &context->write_buffer); 240 //memoryIOSetDebug(&context->mem_io, TRUE); 241 242 plugin->private = context; 243 *error = 0; 244 return (kEAPClientStatusOK); 245} 246 247static void 248eaptls_free(EAPClientPluginDataRef plugin) 249{ 250 EAPTLSPluginDataRef context = (EAPTLSPluginDataRef)plugin->private; 251 252 if (context != NULL) { 253 eaptls_free_context(context); 254 plugin->private = NULL; 255 } 256 return; 257} 258 259static void 260eaptls_free_packet(EAPClientPluginDataRef plugin, EAPPacketRef arg) 261{ 262 if (arg != NULL) { 263 free(arg); 264 } 265 return; 266} 267 268static EAPPacketRef 269EAPTLSPacketCreateAck(u_char identifier) 270{ 271 return (EAPTLSPacketCreate(kEAPCodeResponse, kEAPTypeTLS, 272 identifier, 0, NULL, NULL)); 273} 274 275static EAPPacketRef 276eaptls_verify_server(EAPClientPluginDataRef plugin, 277 int identifier, EAPClientStatus * client_status) 278{ 279 EAPTLSPluginDataRef context = (EAPTLSPluginDataRef)plugin->private; 280 EAPPacketRef pkt = NULL; 281 memoryBufferRef write_buf = &context->write_buffer; 282 283 context->trust_status 284 = EAPTLSVerifyServerCertificateChain(plugin->properties, 285 context->server_certs, 286 &context->trust_ssl_error); 287 if (context->trust_status != kEAPClientStatusOK) { 288 EAPLOG_FL(LOG_NOTICE, "server certificate not trusted status %d %d", 289 context->trust_status, 290 (int)context->trust_ssl_error); 291 } 292 switch (context->trust_status) { 293 case kEAPClientStatusOK: 294 context->trust_proceed = TRUE; 295 break; 296 case kEAPClientStatusUserInputRequired: 297 /* ask user whether to proceed or not */ 298 *client_status = context->last_client_status 299 = kEAPClientStatusUserInputRequired; 300 break; 301 default: 302 *client_status = context->trust_status; 303 context->last_ssl_error = context->trust_ssl_error; 304 context->plugin_state = kEAPClientStateFailure; 305 SSLClose(context->ssl_context); 306 pkt = EAPTLSPacketCreate(kEAPCodeResponse, 307 kEAPTypeTLS, 308 identifier, 309 context->mtu, 310 write_buf, 311 &context->last_write_size); 312 break; 313 } 314 return (pkt); 315} 316 317static void 318eaptls_set_session_was_resumed(EAPTLSPluginDataRef context) 319{ 320 char buf[MAX_SESSION_ID_LENGTH]; 321 size_t buf_len = sizeof(buf); 322 Boolean resumed = FALSE; 323 OSStatus status; 324 325 status = SSLGetResumableSessionInfo(context->ssl_context, 326 &resumed, buf, &buf_len); 327 if (status == noErr) { 328 context->session_was_resumed = resumed; 329 } 330 return; 331} 332 333static EAPPacketRef 334eaptls_handshake(EAPClientPluginDataRef plugin, 335 int identifier, EAPClientStatus * client_status) 336 337{ 338 EAPTLSPluginDataRef context = (EAPTLSPluginDataRef)plugin->private; 339 EAPPacketRef eaptls_out = NULL; 340 OSStatus status = noErr; 341 memoryBufferRef write_buf = &context->write_buffer; 342 343 if (context->server_auth_completed && context->trust_proceed == FALSE) { 344 eaptls_out 345 = eaptls_verify_server(plugin, identifier, client_status); 346 if (context->trust_proceed == FALSE) { 347 goto done; 348 } 349 } 350 351 status = SSLHandshake(context->ssl_context); 352 if (status == errSSLServerAuthCompleted) { 353 if (context->server_auth_completed) { 354 /* this should not happen */ 355 EAPLOG_FL(LOG_NOTICE, "AuthCompleted again?"); 356 goto done; 357 } 358 context->server_auth_completed = TRUE; 359 my_CFRelease(&context->server_certs); 360 (void)EAPSSLCopyPeerCertificates(context->ssl_context, 361 &context->server_certs); 362 eaptls_out = eaptls_verify_server(plugin, identifier, client_status); 363 if (context->trust_proceed == FALSE) { 364 goto done; 365 } 366 /* handshake again to get past the AuthCompleted status */ 367 status = SSLHandshake(context->ssl_context); 368 } 369 switch (status) { 370 case noErr: 371 /* handshake complete */ 372 if (context->trust_proceed == FALSE) { 373 my_CFRelease(&context->server_certs); 374 (void)EAPSSLCopyPeerCertificates(context->ssl_context, 375 &context->server_certs); 376 eaptls_out = eaptls_verify_server(plugin, identifier, 377 client_status); 378 if (context->trust_proceed == FALSE) { 379 /* this should not happen */ 380 EAPLOG_FL(LOG_NOTICE, "trust_proceed is FALSE?"); 381 break; 382 } 383 } 384 eaptls_compute_session_key(context); 385 eaptls_set_session_was_resumed(context); 386 eaptls_out = EAPTLSPacketCreate(kEAPCodeResponse, 387 kEAPTypeTLS, 388 identifier, 389 context->mtu, 390 write_buf, 391 &context->last_write_size); 392 break; 393 default: 394 EAPLOG_FL(LOG_NOTICE, "SSLHandshake failed, %s", 395 EAPSSLErrorString(status)); 396 context->last_ssl_error = status; 397 my_CFRelease(&context->server_certs); 398 (void)EAPSSLCopyPeerCertificates(context->ssl_context, 399 &context->server_certs); 400 /* close_up_shop */ 401 context->plugin_state = kEAPClientStateFailure; 402 SSLClose(context->ssl_context); 403 /* FALL THROUGH */ 404 case errSSLWouldBlock: 405 if (write_buf->data == NULL) { 406 if (status == errSSLFatalAlert) { 407 /* send an ACK if we received a fatal alert message */ 408 eaptls_out 409 = EAPTLSPacketCreateAck(identifier); 410 } 411 } 412 else { 413 eaptls_out = EAPTLSPacketCreate(kEAPCodeResponse, 414 kEAPTypeTLS, 415 identifier, 416 context->mtu, 417 write_buf, 418 &context->last_write_size); 419 } 420 break; 421 } 422 423 done: 424 return (eaptls_out); 425} 426 427static EAPPacketRef 428eaptls_request(EAPClientPluginDataRef plugin, 429 const EAPPacketRef in_pkt, 430 EAPClientStatus * client_status) 431{ 432 EAPTLSPluginDataRef context = (EAPTLSPluginDataRef)plugin->private; 433 EAPTLSPacketRef eaptls_in = (EAPTLSPacketRef)in_pkt; 434 EAPTLSLengthIncludedPacketRef eaptls_in_l; 435 EAPPacketRef eaptls_out = NULL; 436 int in_data_length; 437 void * in_data_ptr = NULL; 438 u_int16_t in_length = EAPPacketGetLength(in_pkt); 439 memoryBufferRef write_buf = &context->write_buffer; 440 memoryBufferRef read_buf = &context->read_buffer; 441 SSLSessionState ssl_state = kSSLIdle; 442 OSStatus status = noErr; 443 u_int32_t tls_message_length = 0; 444 RequestType type; 445 446 /* ALIGN: void * cast OK, we don't expect proper alignment */ 447 eaptls_in_l = (EAPTLSLengthIncludedPacketRef)(void *)in_pkt; 448 if (in_length < sizeof(*eaptls_in)) { 449 EAPLOG(LOG_NOTICE, "eaptls_request: length %d < %ld", 450 in_length, sizeof(*eaptls_in)); 451 goto done; 452 } 453 if (context->ssl_context != NULL) { 454 status = SSLGetSessionState(context->ssl_context, &ssl_state); 455 if (status != noErr) { 456 EAPLOG_FL(LOG_NOTICE, "SSLGetSessionState failed, %s", 457 EAPSSLErrorString(status)); 458 context->plugin_state = kEAPClientStateFailure; 459 context->last_ssl_error = status; 460 goto done; 461 } 462 } 463 in_data_ptr = eaptls_in->tls_data; 464 tls_message_length = in_data_length = in_length - sizeof(EAPTLSPacket); 465 466 type = kRequestTypeData; 467 if ((eaptls_in->flags & kEAPTLSPacketFlagsStart) != 0) { 468 type = kRequestTypeStart; 469 /* only reset our state if this is not a re-transmitted Start packet */ 470 if (ssl_state != kSSLHandshake 471 || write_buf->data == NULL 472 || in_pkt->identifier != context->previous_identifier) { 473 ssl_state = kSSLIdle; 474 } 475 } 476 else if (in_length == sizeof(*eaptls_in)) { 477 type = kRequestTypeAck; 478 } 479 else if ((eaptls_in->flags & kEAPTLSPacketFlagsLengthIncluded) != 0) { 480 if (in_length < sizeof(EAPTLSLengthIncludedPacket)) { 481 EAPLOG_FL(LOG_NOTICE, 482 "packet too short %d < %ld", 483 in_length, sizeof(EAPTLSLengthIncludedPacket)); 484 goto done; 485 } 486 in_data_ptr = eaptls_in_l->tls_data; 487 in_data_length = in_length - sizeof(EAPTLSLengthIncludedPacket); 488 tls_message_length = EAPTLSLengthIncludedPacketGetMessageLength(eaptls_in_l); 489 if (tls_message_length > kAvoidDenialOfServiceSize) { 490 EAPLOG_FL(LOG_NOTICE, 491 "received message too large, %d > %d", 492 tls_message_length, kAvoidDenialOfServiceSize); 493 context->plugin_state = kEAPClientStateFailure; 494 goto done; 495 } 496 if (tls_message_length == 0) { 497 type = kRequestTypeAck; 498 } 499 } 500 501 switch (ssl_state) { 502 case kSSLClosed: 503 case kSSLAborted: 504 break; 505 506 case kSSLIdle: 507 if (type != kRequestTypeStart) { 508 /* ignore it: XXX should this be an error? */ 509 EAPLOG_FL(LOG_NOTICE, 510 "ignoring non EAP-TLS start frame"); 511 goto done; 512 } 513 status = eaptls_start(plugin); 514 if (status != noErr) { 515 context->last_ssl_error = status; 516 context->plugin_state = kEAPClientStateFailure; 517 goto done; 518 } 519 status = SSLHandshake(context->ssl_context); 520 if (status != errSSLWouldBlock) { 521 EAPLOG_FL(LOG_NOTICE, 522 "SSLHandshake failed, %s (%d)", 523 EAPSSLErrorString(status), (int)status); 524 context->last_ssl_error = status; 525 context->plugin_state = kEAPClientStateFailure; 526 goto done; 527 } 528 eaptls_out = EAPTLSPacketCreate(kEAPCodeResponse, 529 kEAPTypeTLS, 530 eaptls_in->identifier, 531 context->mtu, 532 write_buf, 533 &context->last_write_size); 534 break; 535 case kSSLHandshake: 536 case kSSLConnected: 537 if (write_buf->data != NULL) { 538 /* we have data to write */ 539 if (in_pkt->identifier == context->previous_identifier) { 540 /* resend the existing fragment */ 541 eaptls_out = EAPTLSPacketCreate(kEAPCodeResponse, 542 kEAPTypeTLS, 543 in_pkt->identifier, 544 context->mtu, 545 write_buf, 546 &context->last_write_size); 547 break; 548 } 549 if ((write_buf->offset + context->last_write_size) 550 < write_buf->length) { 551 /* advance the offset, and send the next fragment */ 552 write_buf->offset += context->last_write_size; 553 eaptls_out = EAPTLSPacketCreate(kEAPCodeResponse, 554 kEAPTypeTLS, 555 in_pkt->identifier, 556 context->mtu, 557 write_buf, 558 &context->last_write_size); 559 break; 560 } 561 /* we're done, release the write buffer */ 562 memoryBufferClear(write_buf); 563 context->last_write_size = 0; 564 } 565 if (type != kRequestTypeData) { 566 EAPLOG_FL(LOG_NOTICE, "unexpected %s frame", 567 type == kRequestTypeAck ? "Ack" : "Start"); 568 goto done; 569 } 570 if (in_pkt->identifier == context->previous_identifier) { 571 if ((eaptls_in->flags & kEAPTLSPacketFlagsMoreFragments) != 0) { 572 /* just ack it, we've already seen the fragment */ 573 eaptls_out = EAPTLSPacketCreateAck(eaptls_in->identifier); 574 break; 575 } 576 } 577 else { 578 if (read_buf->data == NULL) { 579 memoryBufferAllocate(read_buf, tls_message_length); 580 } 581 if (memoryBufferAddData(read_buf, in_data_ptr, in_data_length) 582 == FALSE) { 583 EAPLOG_FL(LOG_NOTICE, "fragment too large %d", in_data_length); 584 goto done; 585 } 586 if (memoryBufferIsComplete(read_buf) == FALSE) { 587 if ((eaptls_in->flags & kEAPTLSPacketFlagsMoreFragments) == 0) { 588 EAPLOG_FL(LOG_NOTICE, 589 "expecting more data but " 590 "more fragments bit is not set, ignoring"); 591 goto done; 592 } 593 /* we haven't received the entire TLS message */ 594 eaptls_out = EAPTLSPacketCreateAck(eaptls_in->identifier); 595 break; 596 } 597 } 598 /* we've got the whole TLS message, process it */ 599 eaptls_out = eaptls_handshake(plugin, eaptls_in->identifier, 600 client_status); 601 break; 602 default: 603 break; 604 } 605 context->previous_identifier = in_pkt->identifier; 606 done: 607 return (eaptls_out); 608} 609 610static EAPClientState 611eaptls_process(EAPClientPluginDataRef plugin, 612 const EAPPacketRef in_pkt, 613 EAPPacketRef * out_pkt_p, 614 EAPClientStatus * client_status, 615 EAPClientDomainSpecificError * error) 616{ 617 EAPTLSPluginDataRef context = (EAPTLSPluginDataRef)plugin->private; 618 619 *client_status = kEAPClientStatusOK; 620 *error = 0; 621 *out_pkt_p = NULL; 622 switch (in_pkt->code) { 623 case kEAPCodeRequest: 624 *out_pkt_p = eaptls_request(plugin, in_pkt, client_status); 625 break; 626 case kEAPCodeSuccess: 627 if (context->trust_proceed) { 628 context->plugin_state = kEAPClientStateSuccess; 629 } 630 break; 631 case kEAPCodeFailure: 632 context->plugin_state = kEAPClientStateFailure; 633 break; 634 case kEAPCodeResponse: 635 default: 636 break; 637 } 638 if (context->plugin_state == kEAPClientStateFailure) { 639 if (context->last_ssl_error == noErr) { 640 if (context->server_certs != NULL) { 641 *client_status = kEAPClientStatusFailed; 642 } 643 else { 644 *client_status = kEAPClientStatusProtocolError; 645 } 646 } 647 else { 648 *error = context->last_ssl_error; 649 *client_status = kEAPClientStatusSecurityError; 650 } 651 } 652 return (context->plugin_state); 653} 654 655static const char * 656eaptls_failure_string(EAPClientPluginDataRef plugin) 657{ 658 return (NULL); 659} 660 661static void * 662eaptls_session_key(EAPClientPluginDataRef plugin, int * key_length) 663{ 664 EAPTLSPluginDataRef context = (EAPTLSPluginDataRef)plugin->private; 665 666 *key_length = 0; 667 if (context->key_data_valid == FALSE) { 668 return (NULL); 669 } 670 671 /* return the first 32 bytes of key data */ 672 *key_length = 32; 673 return (context->key_data); 674} 675 676static void * 677eaptls_server_key(EAPClientPluginDataRef plugin, int * key_length) 678{ 679 EAPTLSPluginDataRef context = (EAPTLSPluginDataRef)plugin->private; 680 681 *key_length = 0; 682 if (context->key_data_valid == FALSE) { 683 return (NULL); 684 } 685 686 /* return the second 32 bytes of key data */ 687 *key_length = 32; 688 return (context->key_data + 32); 689} 690 691static CFArrayRef 692eaptls_require_props(EAPClientPluginDataRef plugin) 693{ 694 CFArrayRef array = NULL; 695 EAPTLSPluginDataRef context = (EAPTLSPluginDataRef)plugin->private; 696 697 if (context->last_client_status != kEAPClientStatusUserInputRequired) { 698 goto done; 699 } 700 if (context->trust_proceed == FALSE) { 701 CFStringRef str = kEAPClientPropTLSUserTrustProceedCertificateChain; 702 array = CFArrayCreate(NULL, (const void **)&str, 703 1, &kCFTypeArrayCallBacks); 704 } 705 done: 706 return (array); 707} 708 709static CFDictionaryRef 710eaptls_publish_props(EAPClientPluginDataRef plugin) 711{ 712 CFArrayRef cert_list; 713 SSLCipherSuite cipher = SSL_NULL_WITH_NULL_NULL; 714 EAPTLSPluginDataRef context = (EAPTLSPluginDataRef)plugin->private; 715 CFMutableDictionaryRef dict; 716 717 if (context->server_certs == NULL) { 718 return (NULL); 719 } 720 cert_list = EAPSecCertificateArrayCreateCFDataArray(context->server_certs); 721 if (cert_list == NULL) { 722 return (NULL); 723 } 724 dict = CFDictionaryCreateMutable(NULL, 0, 725 &kCFTypeDictionaryKeyCallBacks, 726 &kCFTypeDictionaryValueCallBacks); 727 CFDictionarySetValue(dict, kEAPClientPropTLSServerCertificateChain, 728 cert_list); 729 my_CFRelease(&cert_list); 730 CFDictionarySetValue(dict, kEAPClientPropTLSSessionWasResumed, 731 context->session_was_resumed 732 ? kCFBooleanTrue 733 : kCFBooleanFalse); 734 (void)SSLGetNegotiatedCipher(context->ssl_context, &cipher); 735 if (cipher != SSL_NULL_WITH_NULL_NULL) { 736 CFNumberRef c; 737 int tmp = cipher; 738 739 c = CFNumberCreate(NULL, kCFNumberIntType, &tmp); 740 CFDictionarySetValue(dict, kEAPClientPropTLSNegotiatedCipher, c); 741 CFRelease(c); 742 } 743 if (context->last_client_status == kEAPClientStatusUserInputRequired 744 && context->trust_proceed == FALSE) { 745 CFNumberRef num; 746 num = CFNumberCreate(NULL, kCFNumberSInt32Type, 747 &context->trust_status); 748 CFDictionarySetValue(dict, kEAPClientPropTLSTrustClientStatus, num); 749 CFRelease(num); 750 } 751 return (dict); 752} 753 754static CFStringRef 755eaptls_copy_packet_description(const EAPPacketRef pkt, bool * packet_is_valid) 756{ 757 EAPTLSPacketRef eaptls_pkt = (EAPTLSPacketRef)pkt; 758 759 return (EAPTLSPacketCopyDescription(eaptls_pkt, packet_is_valid)); 760} 761 762static EAPType 763eaptls_type() 764{ 765 return (kEAPTypeTLS); 766} 767 768static const char * 769eaptls_name() 770{ 771 return (EAPTypeStr(kEAPTypeTLS)); 772} 773 774static EAPClientPluginVersion 775eaptls_version() 776{ 777 return (kEAPClientPluginVersion); 778} 779 780static CFStringRef 781eaptls_user_name_copy(CFDictionaryRef properties) 782{ 783 SecCertificateRef cert = NULL; 784 EAPSecIdentityHandleRef id_handle = NULL; 785 SecIdentityRef identity = NULL; 786 OSStatus status; 787 CFStringRef user_name = NULL; 788 789 if (properties != NULL) { 790 id_handle = CFDictionaryGetValue(properties, 791 kEAPClientPropTLSIdentityHandle); 792 } 793 status = EAPSecIdentityHandleCreateSecIdentity(id_handle, &identity); 794 if (status != noErr) { 795 goto done; 796 } 797 status = SecIdentityCopyCertificate(identity, &cert); 798 if (status != noErr) { 799 goto done; 800 } 801 user_name = EAPSecCertificateCopyUserNameString(cert); 802 done: 803 my_CFRelease(&cert); 804 my_CFRelease(&identity); 805 return (user_name); 806} 807 808static struct func_table_ent { 809 const char * name; 810 void * func; 811} func_table[] = { 812#if 0 813 { kEAPClientPluginFuncNameIntrospect, eaptls_introspect }, 814#endif /* 0 */ 815 { kEAPClientPluginFuncNameVersion, eaptls_version }, 816 { kEAPClientPluginFuncNameEAPType, eaptls_type }, 817 { kEAPClientPluginFuncNameEAPName, eaptls_name }, 818 { kEAPClientPluginFuncNameInit, eaptls_init }, 819 { kEAPClientPluginFuncNameFree, eaptls_free }, 820 { kEAPClientPluginFuncNameProcess, eaptls_process }, 821 { kEAPClientPluginFuncNameFreePacket, eaptls_free_packet }, 822 { kEAPClientPluginFuncNameFailureString, eaptls_failure_string }, 823 { kEAPClientPluginFuncNameSessionKey, eaptls_session_key }, 824 { kEAPClientPluginFuncNameServerKey, eaptls_server_key }, 825 { kEAPClientPluginFuncNameRequireProperties, eaptls_require_props }, 826 { kEAPClientPluginFuncNamePublishProperties, eaptls_publish_props }, 827 { kEAPClientPluginFuncNameUserName, eaptls_user_name_copy }, 828 { kEAPClientPluginFuncNameCopyPacketDescription, 829 eaptls_copy_packet_description }, 830 { NULL, NULL}, 831}; 832 833 834EAPClientPluginFuncRef 835eaptls_introspect(EAPClientPluginFuncName name) 836{ 837 struct func_table_ent * scan; 838 839 840 for (scan = func_table; scan->name != NULL; scan++) { 841 if (strcmp(name, scan->name) == 0) { 842 return (scan->func); 843 } 844 } 845 return (NULL); 846} 847