]> git.saurik.com Git - apple/ipsec.git/blob - ipsec-tools/racoon/eap_aka.c
ipsec-258.100.1.tar.gz
[apple/ipsec.git] / ipsec-tools / racoon / eap_aka.c
1 /*
2 * Copyright (c) 2012 Apple Computer, 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 #include <stdio.h>
25 #include <sys/types.h>
26 #include <sys/uio.h>
27 #include <unistd.h>
28 #include <syslog.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>
43 #include "plog.h"
44 #include "eap.h"
45 #include "eap_sim.h"
46
47 /*---------------------------------------------------------------------------
48 ** Internal routines
49 **---------------------------------------------------------------------------
50 */
51
52 static CFBundleRef bundle = 0; /* our bundle ref */
53 static char eapaka_unique[17];
54
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;
60
61 extern EAPClientPluginFuncRef
62 eapaka_introspect(EAPClientPluginFuncName name);
63
64 /* ------------------------------------------------------------------------------------
65 get the EAP dictionary from the options
66 ------------------------------------------------------------------------------------ */
67 static void
68 EAPAKAGetOptions (void)
69 {
70 if (eapOptions)
71 return;
72
73 // no option, use empty dictionary
74 if (!eapOptions)
75 eapOptions = CFDictionaryCreate(0, 0, 0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
76 }
77
78 /* ------------------------------------------------------------------------------------
79 ------------------------------------------------------------------------------------ */
80 static int
81 EAPAKALoad (void)
82 {
83 EAPClientModuleStatus status;
84
85 if (eapRef)
86 return EAP_NO_ERROR;
87
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;
92 }
93
94 eapRef = EAPClientModuleLookup(kEAPTypeEAPAKA);
95 if (eapRef == NULL) {
96 plog(ASL_LEVEL_INFO, "EAP-AKA: EAPClientModuleLookup(eapaka) failed\n");
97 return EAP_ERROR_GENERIC;
98 }
99
100 return EAP_NO_ERROR;
101 }
102
103 /* ------------------------------------------------------------------------------------
104 ------------------------------------------------------------------------------------ */
105 int EAPAKAIdentity (char *identity, int maxlen)
106 {
107 CFStringRef identRef = NULL;
108 int error;
109 int ret = EAP_ERROR_GENERIC;
110
111 error = EAPAKALoad();
112 if (error)
113 return error;
114
115 EAPAKAGetOptions();
116 if (eapOptions == NULL)
117 return ret;
118
119 identRef = EAPClientModulePluginUserName(eapRef, eapOptions);
120 if (identRef) {
121 if (CFStringGetCString(identRef, identity, maxlen, kCFStringEncodingUTF8))
122 ret = EAP_NO_ERROR;
123 CFRelease(identRef);
124 }
125
126 return ret;
127 }
128
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 ------------------------------------------------------------------------------------ */
136 int
137 EAPAKAInit (EAP_Input_t *eap_in, void **context, CFDictionaryRef eapOptions)
138 {
139 int error;
140 EAPClientModuleStatus status;
141 int ret = EAP_ERROR_GENERIC;
142
143 error = EAPAKALoad();
144 if (error)
145 return error;
146
147 bundle = (CFBundleRef)eap_in->data;
148 if (bundle)
149 CFRetain(bundle);
150
151 EAPAKAGetOptions();
152
153 bzero(&eapData, sizeof(eapData));
154
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 */
163
164 arc4random_buf(eapaka_unique, sizeof(eapaka_unique) - 1);
165 eapaka_unique[sizeof(eapaka_unique)-1] = 0;
166
167 eapData.unique_id = eapaka_unique; /* used for TLS session resumption??? */
168 *((uint32_t *)&eapData.unique_id_length) = strlen(eapData.unique_id);
169
170 if (eapOptions) {
171 CFTypeRef value = CFDictionaryGetValue(eapOptions, kEAPPropertiesTypeEAPAKA);
172 if (value && CFGetTypeID(value) == CFDictionaryGetTypeID()) {
173 eapProperties = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, (CFDictionaryRef)value);
174 } else {
175 eapProperties = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, eapOptions);
176 }
177 } else
178 eapProperties = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
179 if (eapProperties == NULL) {
180 plog(ASL_LEVEL_ERR, "EAP-AKA: Cannot allocate memory\n");
181 goto failed;
182 }
183
184 *((CFDictionaryRef *)&eapData.properties) = (CFDictionaryRef)eapProperties;
185
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);
189 goto failed;
190 }
191
192 eapSavePacket = NULL;
193
194 return EAP_NO_ERROR;
195
196 failed:
197
198 return ret;
199 }
200
201 /* ------------------------------------------------------------------------------------
202 ------------------------------------------------------------------------------------ */
203 int EAPAKADispose (void *context)
204 {
205
206 EAPClientModulePluginFree(eapRef, &eapData);
207 eapRef = 0;
208
209 if (bundle) {
210 CFRelease(bundle);
211 bundle = 0;
212 }
213
214 if (eapOptions) {
215 CFRelease(eapOptions);
216 eapOptions = 0;
217 }
218
219 if (eapProperties) {
220 CFRelease(eapProperties);
221 eapProperties = 0;
222 }
223
224 if (eapSavePacket) {
225 free(eapSavePacket);
226 eapSavePacket = 0;
227 }
228
229 return EAP_NO_ERROR;
230 }
231
232 /* ------------------------------------------------------------------------------------
233 ------------------------------------------------------------------------------------ */
234 int
235 EAPAKAProcess (void *context, EAP_Input_t *eap_in, EAP_Output_t *eap_out)
236 {
237 struct EAP_Packet *pkt_in = NULL;
238 struct EAP_Packet *pkt_out = NULL;
239 EAPClientStatus status;
240 EAPClientState state;
241 EAPClientDomainSpecificError error;
242 int do_process = 0;
243
244 // by default, ignore the message
245 eap_out->action = EAP_ACTION_NONE;
246 eap_out->data = 0;
247 eap_out->data_len = 0;
248
249 switch (eap_in->notification) {
250
251 case EAP_NOTIFICATION_DATA_FROM_UI:
252 plog(ASL_LEVEL_ERR, "unexpected EAP UI event");
253 break;
254
255 case EAP_NOTIFICATION_PACKET:
256
257 pkt_in = (struct EAP_Packet *)eap_in->data;
258 do_process = 1;
259 break;
260 }
261
262 if (do_process) {
263
264 state = EAPClientModulePluginProcess(eapRef, &eapData, (EAPPacketRef)pkt_in, (EAPPacketRef*)&pkt_out, &status, &error);
265 switch(state) {
266 case kEAPClientStateAuthenticating:
267 switch (status) {
268
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;
273 break;
274
275 case kEAPClientStatusUserInputRequired:
276 plog(ASL_LEVEL_ERR, "unsupported EAP UI input");
277 default:
278 eap_out->action = EAP_ACTION_ACCESS_DENIED;
279 }
280 break;
281
282 case kEAPClientStateSuccess:
283 eap_out->action = EAP_ACTION_ACCESS_GRANTED;
284 break;
285
286 default:
287 case kEAPClientStateFailure:
288 eap_out->action = EAP_ACTION_ACCESS_DENIED;
289 break;
290 }
291 }
292
293 if (eapSavePacket) {
294 free(eapSavePacket);
295 eapSavePacket = 0;
296 }
297
298 return 0;
299 }
300
301 /* ------------------------------------------------------------------------------------
302 ------------------------------------------------------------------------------------ */
303 int
304 EAPAKAFree (void *context, EAP_Output_t *eap_out)
305 {
306
307 EAPClientModulePluginFreePacket(eapRef, &eapData, eap_out->data);
308 return EAP_NO_ERROR;
309 }
310
311 /* ------------------------------------------------------------------------------------
312 ------------------------------------------------------------------------------------ */
313 int
314 EAPAKAGetAttribute (void *context, EAP_Attribute_t *eap_attr)
315 {
316 void *data = NULL;
317 int len = 0;
318
319 eap_attr->data = 0;
320
321 switch (eap_attr->type) {
322
323 case EAP_ATTRIBUTE_MPPE_SEND_KEY:
324 data = EAPClientModulePluginSessionKey(eapRef, &eapData, &len);
325 break;
326 case EAP_ATTRIBUTE_MPPE_RECV_KEY:
327 data = EAPClientModulePluginServerKey(eapRef, &eapData, &len);
328 break;
329 }
330
331 if (data == NULL)
332 return -1;
333
334 eap_attr->data = data;
335 if (len == 32)
336 eap_attr->data_len = 64;
337 else
338 eap_attr->data_len = len;
339 return 0;
340 }