~hartmans/moonshot/mech_eap-debian-dep-fix

« back to all changes in this revision

Viewing changes to mech_eap/init_sec_context.c

  • Committer: Sam Hartman
  • Date: 2013-09-27 12:52:03 UTC
  • mfrom: (1.10.131)
  • Revision ID: git-v1:b2002998eebfaec7e080c64b7c583150478dfaa4
Merge branch 'master' into debian

Conflicts:
        libeap/Makefile.am

Show diffs side-by-side

added added

removed removed

Lines of Context:
36
36
 */
37
37
 
38
38
#include "gssapiP_eap.h"
 
39
#include "radius/radius.h"
 
40
#include "util_radius.h"
 
41
#include "utils/radius_utils.h"
39
42
 
40
43
static OM_uint32
41
44
policyVariableToFlag(enum eapol_bool_var variable)
167
170
}
168
171
 
169
172
static const struct wpa_config_blob *
170
 
peerGetConfigBlob(void *ctx GSSEAP_UNUSED,
171
 
                  const char *name GSSEAP_UNUSED)
 
173
peerGetConfigBlob(void *ctx,
 
174
                  const char *name)
172
175
{
173
 
    return NULL;
 
176
    gss_ctx_id_t gssCtx = (gss_ctx_id_t)ctx;
 
177
    size_t index;
 
178
 
 
179
    if (strcmp(name, "client-cert") == 0)
 
180
        index = CONFIG_BLOB_CLIENT_CERT;
 
181
    else if (strcmp(name, "private-key") == 0)
 
182
        index = CONFIG_BLOB_PRIVATE_KEY;
 
183
    else
 
184
        return NULL;
 
185
 
 
186
    return &gssCtx->initiatorCtx.configBlobs[index];
174
187
}
175
188
 
176
189
static void
194
207
extern int wpa_debug_level;
195
208
#endif
196
209
 
 
210
#define CHBIND_SERVICE_NAME_FLAG        0x01
 
211
#define CHBIND_HOST_NAME_FLAG           0x02
 
212
#define CHBIND_SERVICE_SPECIFIC_FLAG    0x04
 
213
#define CHBIND_REALM_NAME_FLAG          0x08
 
214
 
 
215
static OM_uint32
 
216
peerInitEapChannelBinding(OM_uint32 *minor, gss_ctx_id_t ctx)
 
217
{
 
218
    struct wpabuf *buf = NULL;
 
219
    unsigned int chbindReqFlags = 0;
 
220
    krb5_principal princ = NULL;
 
221
    gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
 
222
    OM_uint32 major = GSS_S_COMPLETE;
 
223
    krb5_context krbContext = NULL;
 
224
 
 
225
    /* XXX is this check redundant? */
 
226
    if (ctx->acceptorName == GSS_C_NO_NAME) {
 
227
        major = GSS_S_BAD_NAME;
 
228
        *minor = GSSEAP_NO_ACCEPTOR_NAME;
 
229
        goto cleanup;
 
230
    }
 
231
 
 
232
    princ = ctx->acceptorName->krbPrincipal;
 
233
 
 
234
    krbPrincComponentToGssBuffer(princ, 0, &nameBuf);
 
235
    if (nameBuf.length > 0) {
 
236
        major = gssEapRadiusAddAttr(minor, &buf, PW_GSS_ACCEPTOR_SERVICE_NAME,
 
237
                                    0, &nameBuf);
 
238
        if (GSS_ERROR(major))
 
239
            goto cleanup;
 
240
 
 
241
        chbindReqFlags |= CHBIND_SERVICE_NAME_FLAG;
 
242
    }
 
243
 
 
244
    krbPrincComponentToGssBuffer(princ, 1, &nameBuf);
 
245
    if (nameBuf.length > 0) {
 
246
        major = gssEapRadiusAddAttr(minor, &buf, PW_GSS_ACCEPTOR_HOST_NAME,
 
247
                                    0, &nameBuf);
 
248
        if (GSS_ERROR(major))
 
249
            goto cleanup;
 
250
 
 
251
        chbindReqFlags |= CHBIND_HOST_NAME_FLAG;
 
252
    }
 
253
 
 
254
    GSSEAP_KRB_INIT(&krbContext);
 
255
 
 
256
    *minor = krbPrincUnparseServiceSpecifics(krbContext, princ, &nameBuf);
 
257
    if (*minor != 0)
 
258
        goto cleanup;
 
259
 
 
260
    if (nameBuf.length > 0) {
 
261
        major = gssEapRadiusAddAttr(minor, &buf,
 
262
                                    PW_GSS_ACCEPTOR_SERVICE_SPECIFICS,
 
263
                                    0, &nameBuf);
 
264
        if (GSS_ERROR(major))
 
265
            goto cleanup;
 
266
 
 
267
        chbindReqFlags |= CHBIND_SERVICE_SPECIFIC_FLAG;
 
268
    }
 
269
 
 
270
    krbFreeUnparsedName(krbContext, &nameBuf);
 
271
    krbPrincRealmToGssBuffer(princ, &nameBuf);
 
272
 
 
273
    if (nameBuf.length > 0) {
 
274
        major = gssEapRadiusAddAttr(minor, &buf,
 
275
                                    PW_GSS_ACCEPTOR_REALM_NAME,
 
276
                                    0, &nameBuf);
 
277
        chbindReqFlags |= CHBIND_REALM_NAME_FLAG;
 
278
    }
 
279
 
 
280
    if (chbindReqFlags == 0) {
 
281
        major = GSS_S_BAD_NAME;
 
282
        *minor = GSSEAP_BAD_ACCEPTOR_NAME;
 
283
        goto cleanup;
 
284
    }
 
285
 
 
286
    ctx->initiatorCtx.chbindData = buf;
 
287
    ctx->initiatorCtx.chbindReqFlags = chbindReqFlags;
 
288
 
 
289
    buf = NULL;
 
290
 
 
291
    major = GSS_S_COMPLETE;
 
292
    *minor = 0;
 
293
 
 
294
cleanup:
 
295
    krbFreeUnparsedName(krbContext, &nameBuf);
 
296
    wpabuf_free(buf);
 
297
 
 
298
    return major;
 
299
}
 
300
 
 
301
static void
 
302
peerProcessChbindResponse(void *context, int code, int nsid,
 
303
                          u8 *data, size_t len)
 
304
{
 
305
    radius_parser msg;
 
306
    gss_ctx_id_t ctx = (gss_ctx_id_t )context;
 
307
    void *vsadata;
 
308
    u8 type;
 
309
    u32 vendor_id;
 
310
    u32 chbindRetFlags = 0;
 
311
    size_t vsadata_len;
 
312
 
 
313
    if (nsid != CHBIND_NSID_RADIUS)
 
314
        return;
 
315
 
 
316
    if (data == NULL)
 
317
        return;
 
318
    msg = radius_parser_start(data, len);
 
319
    if (msg == NULL)
 
320
        return;
 
321
 
 
322
    while (radius_parser_parse_tlv(msg, &type, &vendor_id, &vsadata,
 
323
                                   &vsadata_len) == 0) {
 
324
        switch (type) {
 
325
        case PW_GSS_ACCEPTOR_SERVICE_NAME:
 
326
            chbindRetFlags |= CHBIND_SERVICE_NAME_FLAG;
 
327
            break;
 
328
        case PW_GSS_ACCEPTOR_HOST_NAME:
 
329
            chbindRetFlags |= CHBIND_HOST_NAME_FLAG;
 
330
            break;
 
331
        case PW_GSS_ACCEPTOR_SERVICE_SPECIFICS:
 
332
            chbindRetFlags |= CHBIND_SERVICE_SPECIFIC_FLAG;
 
333
            break;
 
334
        case PW_GSS_ACCEPTOR_REALM_NAME:
 
335
            chbindRetFlags |= CHBIND_REALM_NAME_FLAG;
 
336
            break;
 
337
        }
 
338
    }
 
339
 
 
340
    radius_parser_finish(msg);
 
341
 
 
342
    if (code == CHBIND_CODE_SUCCESS &&
 
343
        ((chbindRetFlags & ctx->initiatorCtx.chbindReqFlags) == ctx->initiatorCtx.chbindReqFlags)) {
 
344
        ctx->flags |= CTX_FLAG_EAP_CHBIND_ACCEPT;
 
345
        ctx->gssFlags |= GSS_C_MUTUAL_FLAG;
 
346
    } /* else log failures? */
 
347
}
 
348
 
197
349
static OM_uint32
198
350
peerConfigInit(OM_uint32 *minor, gss_ctx_id_t ctx)
199
351
{
200
352
    OM_uint32 major;
201
353
    krb5_context krbContext;
202
354
    struct eap_peer_config *eapPeerConfig = &ctx->initiatorCtx.eapPeerConfig;
 
355
    struct wpa_config_blob *configBlobs = ctx->initiatorCtx.configBlobs;
203
356
    gss_buffer_desc identity = GSS_C_EMPTY_BUFFER;
204
357
    gss_buffer_desc realm = GSS_C_EMPTY_BUFFER;
205
358
    gss_cred_id_t cred = ctx->cred;
250
403
    eapPeerConfig->anonymous_identity_len = 1 + realm.length;
251
404
 
252
405
    /* password */
253
 
    eapPeerConfig->password = (unsigned char *)cred->password.value;
254
 
    eapPeerConfig->password_len = cred->password.length;
 
406
    if ((cred->flags & CRED_FLAG_CERTIFICATE) == 0) {
 
407
        eapPeerConfig->password = (unsigned char *)cred->password.value;
 
408
        eapPeerConfig->password_len = cred->password.length;
 
409
    }
255
410
 
256
411
    /* certs */
257
412
    eapPeerConfig->ca_cert = (unsigned char *)cred->caCertificate.value;
258
413
    eapPeerConfig->subject_match = (unsigned char *)cred->subjectNameConstraint.value;
259
414
    eapPeerConfig->altsubject_match = (unsigned char *)cred->subjectAltNameConstraint.value;
260
415
 
 
416
    /* eap channel binding */
 
417
    if (ctx->initiatorCtx.chbindData != NULL) {
 
418
        struct eap_peer_chbind_config *chbind_config =
 
419
            (struct eap_peer_chbind_config *)GSSEAP_MALLOC(sizeof(struct eap_peer_chbind_config));
 
420
        if (chbind_config == NULL) {
 
421
            *minor = ENOMEM;
 
422
            return GSS_S_FAILURE;
 
423
        }
 
424
 
 
425
        chbind_config->req_data = wpabuf_mhead_u8(ctx->initiatorCtx.chbindData);
 
426
        chbind_config->req_data_len = wpabuf_len(ctx->initiatorCtx.chbindData);
 
427
        chbind_config->nsid = CHBIND_NSID_RADIUS;
 
428
        chbind_config->response_cb = &peerProcessChbindResponse;
 
429
        chbind_config->ctx = ctx;
 
430
        eapPeerConfig->chbind_config = chbind_config;
 
431
        eapPeerConfig->chbind_config_len = 1;
 
432
    } else {
 
433
        eapPeerConfig->chbind_config = NULL;
 
434
        eapPeerConfig->chbind_config_len = 0;
 
435
    }
 
436
    if (cred->flags & CRED_FLAG_CERTIFICATE) {
 
437
        /*
 
438
         * CRED_FLAG_CONFIG_BLOB is an internal flag which will be used in the
 
439
         * future to directly pass certificate and private key data to the
 
440
         * EAP implementation, rather than an indirected string pointer.
 
441
         */
 
442
        if (cred->flags & CRED_FLAG_CONFIG_BLOB) {
 
443
            eapPeerConfig->client_cert = (unsigned char *)"blob://client-cert";
 
444
            configBlobs[CONFIG_BLOB_CLIENT_CERT].data = cred->clientCertificate.value;
 
445
            configBlobs[CONFIG_BLOB_CLIENT_CERT].len  = cred->clientCertificate.length;
 
446
 
 
447
            eapPeerConfig->client_cert = (unsigned char *)"blob://private-key";
 
448
            configBlobs[CONFIG_BLOB_PRIVATE_KEY].data = cred->clientCertificate.value;
 
449
            configBlobs[CONFIG_BLOB_PRIVATE_KEY].len  = cred->privateKey.length;
 
450
        } else {
 
451
            eapPeerConfig->client_cert = (unsigned char *)cred->clientCertificate.value;
 
452
            eapPeerConfig->private_key = (unsigned char *)cred->privateKey.value;
 
453
        }
 
454
        eapPeerConfig->private_key_passwd = (unsigned char *)cred->password.value;
 
455
    }
 
456
 
261
457
    *minor = 0;
262
458
    return GSS_S_COMPLETE;
263
459
}
288
484
 * Mark an initiator context as ready for cryptographic operations
289
485
 */
290
486
static OM_uint32
291
 
initReady(OM_uint32 *minor, gss_ctx_id_t ctx, OM_uint32 reqFlags)
 
487
initReady(OM_uint32 *minor, gss_ctx_id_t ctx)
292
488
{
293
489
    OM_uint32 major;
294
490
    const unsigned char *key;
295
491
    size_t keyLength;
296
492
 
297
 
#if 1
298
 
    /* XXX actually check for mutual auth */
299
 
    if (reqFlags & GSS_C_MUTUAL_FLAG)
300
 
        ctx->gssFlags |= GSS_C_MUTUAL_FLAG;
301
 
#endif
302
 
 
303
493
    /* Cache encryption type derived from selected mechanism OID */
304
494
    major = gssEapOidToEnctype(minor, ctx->mechanismUsed, &ctx->encryptionType);
305
495
    if (GSS_ERROR(major))
609
799
        return GSS_S_FAILURE;
610
800
    }
611
801
 
 
802
    /*
 
803
     * Generate channel binding data
 
804
     */
 
805
    if (ctx->initiatorCtx.chbindData == NULL) {
 
806
        major = peerInitEapChannelBinding(minor, ctx);
 
807
        if (GSS_ERROR(major))
 
808
            return major;
 
809
    }
 
810
 
612
811
    return GSS_S_CONTINUE_NEEDED;
613
812
}
614
813
 
709
908
 
710
909
        resp = eap_get_eapRespData(ctx->initiatorCtx.eap);
711
910
    } else if (ctx->flags & CTX_FLAG_EAP_SUCCESS) {
712
 
        major = initReady(minor, ctx, reqFlags);
 
911
        major = initReady(minor, ctx);
713
912
        if (GSS_ERROR(major))
714
913
            goto cleanup;
715
914
 
902
1101
    if (GSS_ERROR(major))
903
1102
        return major;
904
1103
 
 
1104
    /*
 
1105
     * As a temporary measure, force mutual authentication until channel binding is
 
1106
     * more widely deployed.
 
1107
     */
 
1108
    ctx->gssFlags |= GSS_C_MUTUAL_FLAG;
905
1109
    GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ESTABLISHED);
906
1110
 
907
1111
    *minor = 0;
1071
1275
            goto cleanup;
1072
1276
        }
1073
1277
    }
 
1278
 
1074
1279
    if (ret_flags != NULL)
1075
1280
        *ret_flags = ctx->gssFlags;
 
1281
 
1076
1282
    if (time_rec != NULL)
1077
1283
        gssEapContextTime(&tmpMinor, ctx, time_rec);
1078
1284