2 * Copyright (c) 2012 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 #include <sys/types.h>
29 #include <sys/fcntl.h>
30 #include <CoreFoundation/CoreFoundation.h>
31 #include <CoreFoundation/CFBundle.h>
32 #include <mach/mach.h>
33 #include <EAP8021X/EAP.h>
34 #include <EAP8021X/EAPClientModule.h>
35 #include <EAP8021X/EAPClientProperties.h>
36 #if !TARGET_OS_EMBEDDED // This file is not built for Embedded
37 #include <Security/SecKeychain.h>
38 #include <Security/SecKeychainSearch.h>
39 #include <Security/SecKeychainItem.h>
40 #include <Security/SecIdentity.h>
41 #endif /* TARGET_OS_EMBEDDED */
42 #include <SystemConfiguration/SCNetworkConnection.h>
47 /*---------------------------------------------------------------------------
49 **---------------------------------------------------------------------------
52 static CFBundleRef bundle
= 0; /* our bundle ref */
53 static char eapaka_unique
[17];
55 static EAPClientModuleRef eapRef
= NULL
;
56 static EAPClientPluginData eapData
;
57 static CFMutableDictionaryRef eapProperties
= NULL
;
58 static CFDictionaryRef eapOptions
= NULL
;
59 static struct EAP_Packet
*eapSavePacket
= NULL
;
61 extern EAPClientPluginFuncRef
62 eapaka_introspect(EAPClientPluginFuncName name
);
64 /* ------------------------------------------------------------------------------------
65 get the EAP dictionary from the options
66 ------------------------------------------------------------------------------------ */
68 EAPAKAGetOptions (void)
73 // no option, use empty dictionary
75 eapOptions
= CFDictionaryCreate(0, 0, 0, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
78 /* ------------------------------------------------------------------------------------
79 ------------------------------------------------------------------------------------ */
83 EAPClientModuleStatus status
;
88 status
= EAPClientModuleAddBuiltinModule(eapaka_introspect
);
89 if (status
!= kEAPClientModuleStatusOK
) {
90 plog(ASL_LEVEL_INFO
, "EAP-AKA: EAPClientAddBuiltinModule(eapaka) failed %d\n", status
);
91 return EAP_ERROR_GENERIC
;
94 eapRef
= EAPClientModuleLookup(kEAPTypeEAPAKA
);
96 plog(ASL_LEVEL_INFO
, "EAP-AKA: EAPClientModuleLookup(eapaka) failed\n");
97 return EAP_ERROR_GENERIC
;
103 /* ------------------------------------------------------------------------------------
104 ------------------------------------------------------------------------------------ */
105 int EAPAKAIdentity (char *identity
, int maxlen
)
107 CFStringRef identRef
= NULL
;
109 int ret
= EAP_ERROR_GENERIC
;
111 error
= EAPAKALoad();
116 if (eapOptions
== NULL
)
119 identRef
= EAPClientModulePluginUserName(eapRef
, eapOptions
);
121 if (CFStringGetCString(identRef
, identity
, maxlen
, kCFStringEncodingUTF8
))
129 /* ------------------------------------------------------------------------------------
130 Init routine called by the EAP engine when it needs the module.
131 Identity of the peer is known at this point.
132 mode is 0 for client, 1 for server.
133 cookie is the EAP engine context, to pass to subsequent calls to EAP.
134 context is EAP module context, that will be passed to subsequent calls to the module
135 ------------------------------------------------------------------------------------ */
137 EAPAKAInit (EAP_Input_t
*eap_in
, void **context
, CFDictionaryRef eapOptions
)
140 EAPClientModuleStatus status
;
141 int ret
= EAP_ERROR_GENERIC
;
143 error
= EAPAKALoad();
147 bundle
= (CFBundleRef
)eap_in
->data
;
153 bzero(&eapData
, sizeof(eapData
));
155 /* remaining fields are read-only: */
156 uint32_t username_len
= strlen(eap_in
->username
);
157 eapData
.username
= (uint8_t *)strndup(eap_in
->username
, username_len
);
158 memcpy((void*)&eapData
.username_length
, &username_len
, sizeof(uint32_t));
159 *((bool *)&eapData
.log_enabled
) = 1;
160 *((uint32_t *)&eapData
.log_level
) = LOG_NOTICE
;
161 *((uint32_t *)&eapData
.mtu
) = eap_in
->mtu
;
162 *((uint32_t *)&eapData
.generation
) = 0;/* changed when user updates */
164 arc4random_buf(eapaka_unique
, sizeof(eapaka_unique
) - 1);
165 eapaka_unique
[sizeof(eapaka_unique
)-1] = 0;
167 eapData
.unique_id
= eapaka_unique
; /* used for TLS session resumption??? */
168 *((uint32_t *)&eapData
.unique_id_length
) = strlen(eapData
.unique_id
);
171 CFTypeRef value
= CFDictionaryGetValue(eapOptions
, kEAPPropertiesTypeEAPAKA
);
172 if (value
&& CFGetTypeID(value
) == CFDictionaryGetTypeID()) {
173 eapProperties
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, (CFDictionaryRef
)value
);
175 eapProperties
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, eapOptions
);
178 eapProperties
= CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
179 if (eapProperties
== NULL
) {
180 plog(ASL_LEVEL_ERR
, "EAP-AKA: Cannot allocate memory\n");
184 *((CFDictionaryRef
*)&eapData
.properties
) = (CFDictionaryRef
)eapProperties
;
186 status
= EAPClientModulePluginInit(eapRef
, &eapData
, NULL
, &error
);
187 if (status
!= kEAPClientStatusOK
) {
188 plog(ASL_LEVEL_ERR
, "EAP-AKA: EAPClientPluginInit(eapaka) failed, error %d\n", status
);
192 eapSavePacket
= NULL
;
201 /* ------------------------------------------------------------------------------------
202 ------------------------------------------------------------------------------------ */
203 int EAPAKADispose (void *context
)
206 EAPClientModulePluginFree(eapRef
, &eapData
);
215 CFRelease(eapOptions
);
220 CFRelease(eapProperties
);
232 /* ------------------------------------------------------------------------------------
233 ------------------------------------------------------------------------------------ */
235 EAPAKAProcess (void *context
, EAP_Input_t
*eap_in
, EAP_Output_t
*eap_out
)
237 struct EAP_Packet
*pkt_in
= NULL
;
238 struct EAP_Packet
*pkt_out
= NULL
;
239 EAPClientStatus status
;
240 EAPClientState state
;
241 EAPClientDomainSpecificError error
;
244 // by default, ignore the message
245 eap_out
->action
= EAP_ACTION_NONE
;
247 eap_out
->data_len
= 0;
249 switch (eap_in
->notification
) {
251 case EAP_NOTIFICATION_DATA_FROM_UI
:
252 plog(ASL_LEVEL_ERR
, "unexpected EAP UI event");
255 case EAP_NOTIFICATION_PACKET
:
257 pkt_in
= (struct EAP_Packet
*)eap_in
->data
;
264 state
= EAPClientModulePluginProcess(eapRef
, &eapData
, (EAPPacketRef
)pkt_in
, (EAPPacketRef
*)&pkt_out
, &status
, &error
);
266 case kEAPClientStateAuthenticating
:
269 case kEAPClientStatusOK
:
270 eap_out
->data
= pkt_out
;
271 eap_out
->data_len
= ntohs(pkt_out
->len
);
272 eap_out
->action
= EAP_ACTION_SEND
;
275 case kEAPClientStatusUserInputRequired
:
276 plog(ASL_LEVEL_ERR
, "unsupported EAP UI input");
278 eap_out
->action
= EAP_ACTION_ACCESS_DENIED
;
282 case kEAPClientStateSuccess
:
283 eap_out
->action
= EAP_ACTION_ACCESS_GRANTED
;
287 case kEAPClientStateFailure
:
288 eap_out
->action
= EAP_ACTION_ACCESS_DENIED
;
301 /* ------------------------------------------------------------------------------------
302 ------------------------------------------------------------------------------------ */
304 EAPAKAFree (void *context
, EAP_Output_t
*eap_out
)
307 EAPClientModulePluginFreePacket(eapRef
, &eapData
, eap_out
->data
);
311 /* ------------------------------------------------------------------------------------
312 ------------------------------------------------------------------------------------ */
314 EAPAKAGetAttribute (void *context
, EAP_Attribute_t
*eap_attr
)
321 switch (eap_attr
->type
) {
323 case EAP_ATTRIBUTE_MPPE_SEND_KEY
:
324 data
= EAPClientModulePluginSessionKey(eapRef
, &eapData
, &len
);
326 case EAP_ATTRIBUTE_MPPE_RECV_KEY
:
327 data
= EAPClientModulePluginServerKey(eapRef
, &eapData
, &len
);
334 eap_attr
->data
= data
;
336 eap_attr
->data_len
= 64;
338 eap_attr
->data_len
= len
;