~ubuntu-branches/ubuntu/trusty/krb5/trusty

« back to all changes in this revision

Viewing changes to .pc/cve-2013-1016.patch/src/plugins/preauth/pkinit/pkinit_srv.c

  • Committer: Package Import Robot
  • Author(s): Michael Gilbert
  • Date: 2013-03-15 04:15:27 UTC
  • Revision ID: package-import@ubuntu.com-20130315041527-2qm79ckq792r0qhk
Tags: 1.10.1+dfsg-4+nmu1
* Non-maintainer upload by the Security Team.
* Fix cve-2013-1016: null pointer derefence when handling a draft9 request
  (closes: #702633).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
 
2
/*
 
3
 * COPYRIGHT (C) 2006,2007
 
4
 * THE REGENTS OF THE UNIVERSITY OF MICHIGAN
 
5
 * ALL RIGHTS RESERVED
 
6
 *
 
7
 * Permission is granted to use, copy, create derivative works
 
8
 * and redistribute this software and such derivative works
 
9
 * for any purpose, so long as the name of The University of
 
10
 * Michigan is not used in any advertising or publicity
 
11
 * pertaining to the use of distribution of this software
 
12
 * without specific, written prior authorization.  If the
 
13
 * above copyright notice or any other identification of the
 
14
 * University of Michigan is included in any copy of any
 
15
 * portion of this software, then the disclaimer below must
 
16
 * also be included.
 
17
 *
 
18
 * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
 
19
 * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
 
20
 * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
 
21
 * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
 
22
 * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
 
23
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
 
24
 * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
 
25
 * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
 
26
 * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
 
27
 * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
 
28
 * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
 
29
 * SUCH DAMAGES.
 
30
 */
 
31
 
 
32
#include <stdio.h>
 
33
#include <stdlib.h>
 
34
#include <errno.h>
 
35
#include <string.h>
 
36
 
 
37
#include <k5-int.h>
 
38
#include "pkinit.h"
 
39
 
 
40
static krb5_error_code
 
41
pkinit_init_kdc_req_context(krb5_context, pkinit_kdc_req_context *blob);
 
42
 
 
43
static void
 
44
pkinit_fini_kdc_req_context(krb5_context context, void *blob);
 
45
 
 
46
static void
 
47
pkinit_server_plugin_fini_realm(krb5_context context,
 
48
                                pkinit_kdc_context plgctx);
 
49
 
 
50
static void
 
51
pkinit_server_plugin_fini(krb5_context context,
 
52
                          krb5_kdcpreauth_moddata moddata);
 
53
 
 
54
static pkinit_kdc_context
 
55
pkinit_find_realm_context(krb5_context context,
 
56
                          krb5_kdcpreauth_moddata moddata,
 
57
                          krb5_principal princ);
 
58
 
 
59
static krb5_error_code
 
60
pkinit_create_edata(krb5_context context,
 
61
                    pkinit_plg_crypto_context plg_cryptoctx,
 
62
                    pkinit_req_crypto_context req_cryptoctx,
 
63
                    pkinit_identity_crypto_context id_cryptoctx,
 
64
                    pkinit_plg_opts *opts,
 
65
                    krb5_error_code err_code,
 
66
                    krb5_pa_data ***e_data_out)
 
67
{
 
68
    krb5_error_code retval = KRB5KRB_ERR_GENERIC;
 
69
 
 
70
    pkiDebug("pkinit_create_edata: creating edata for error %d (%s)\n",
 
71
             err_code, error_message(err_code));
 
72
    switch(err_code) {
 
73
    case KRB5KDC_ERR_CANT_VERIFY_CERTIFICATE:
 
74
        retval = pkinit_create_td_trusted_certifiers(context,
 
75
                                                     plg_cryptoctx, req_cryptoctx, id_cryptoctx, e_data_out);
 
76
        break;
 
77
    case KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED:
 
78
        retval = pkinit_create_td_dh_parameters(context, plg_cryptoctx,
 
79
                                                req_cryptoctx, id_cryptoctx, opts, e_data_out);
 
80
        break;
 
81
    case KRB5KDC_ERR_INVALID_CERTIFICATE:
 
82
    case KRB5KDC_ERR_REVOKED_CERTIFICATE:
 
83
        retval = pkinit_create_td_invalid_certificate(context,
 
84
                                                      plg_cryptoctx, req_cryptoctx, id_cryptoctx, e_data_out);
 
85
        break;
 
86
    default:
 
87
        pkiDebug("no edata needed for error %d (%s)\n",
 
88
                 err_code, error_message(err_code));
 
89
        retval = 0;
 
90
        goto cleanup;
 
91
    }
 
92
 
 
93
cleanup:
 
94
 
 
95
    return retval;
 
96
}
 
97
 
 
98
static void
 
99
pkinit_server_get_edata(krb5_context context,
 
100
                        krb5_kdc_req *request,
 
101
                        krb5_kdcpreauth_callbacks cb,
 
102
                        krb5_kdcpreauth_rock rock,
 
103
                        krb5_kdcpreauth_moddata moddata,
 
104
                        krb5_preauthtype pa_type,
 
105
                        krb5_kdcpreauth_edata_respond_fn respond,
 
106
                        void *arg)
 
107
{
 
108
    krb5_error_code retval = 0;
 
109
    pkinit_kdc_context plgctx = NULL;
 
110
 
 
111
    pkiDebug("pkinit_server_get_edata: entered!\n");
 
112
 
 
113
 
 
114
    /*
 
115
     * If we don't have a realm context for the given realm,
 
116
     * don't tell the client that we support pkinit!
 
117
     */
 
118
    plgctx = pkinit_find_realm_context(context, moddata, request->server);
 
119
    if (plgctx == NULL)
 
120
        retval = EINVAL;
 
121
 
 
122
    (*respond)(arg, retval, NULL);
 
123
}
 
124
 
 
125
static krb5_error_code
 
126
verify_client_san(krb5_context context,
 
127
                  pkinit_kdc_context plgctx,
 
128
                  pkinit_kdc_req_context reqctx,
 
129
                  krb5_principal client,
 
130
                  int *valid_san)
 
131
{
 
132
    krb5_error_code retval;
 
133
    krb5_principal *princs = NULL;
 
134
    krb5_principal *upns = NULL;
 
135
    int i;
 
136
#ifdef DEBUG_SAN_INFO
 
137
    char *client_string = NULL, *san_string;
 
138
#endif
 
139
 
 
140
    retval = crypto_retrieve_cert_sans(context, plgctx->cryptoctx,
 
141
                                       reqctx->cryptoctx, plgctx->idctx,
 
142
                                       &princs,
 
143
                                       plgctx->opts->allow_upn ? &upns : NULL,
 
144
                                       NULL);
 
145
    if (retval) {
 
146
        pkiDebug("%s: error from retrieve_certificate_sans()\n", __FUNCTION__);
 
147
        retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
 
148
        goto out;
 
149
    }
 
150
    /* XXX Verify this is consistent with client side XXX */
 
151
#if 0
 
152
    retval = call_san_checking_plugins(context, plgctx, reqctx, princs,
 
153
                                       upns, NULL, &plugin_decision, &ignore);
 
154
    pkiDebug("%s: call_san_checking_plugins() returned retval %d\n",
 
155
             __FUNCTION__);
 
156
    if (retval) {
 
157
        retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
 
158
        goto cleanup;
 
159
    }
 
160
    pkiDebug("%s: call_san_checking_plugins() returned decision %d\n",
 
161
             __FUNCTION__, plugin_decision);
 
162
    if (plugin_decision != NO_DECISION) {
 
163
        retval = plugin_decision;
 
164
        goto out;
 
165
    }
 
166
#endif
 
167
 
 
168
#ifdef DEBUG_SAN_INFO
 
169
    krb5_unparse_name(context, client, &client_string);
 
170
#endif
 
171
    pkiDebug("%s: Checking pkinit sans\n", __FUNCTION__);
 
172
    for (i = 0; princs != NULL && princs[i] != NULL; i++) {
 
173
#ifdef DEBUG_SAN_INFO
 
174
        krb5_unparse_name(context, princs[i], &san_string);
 
175
        pkiDebug("%s: Comparing client '%s' to pkinit san value '%s'\n",
 
176
                 __FUNCTION__, client_string, san_string);
 
177
        krb5_free_unparsed_name(context, san_string);
 
178
#endif
 
179
        if (krb5_principal_compare(context, princs[i], client)) {
 
180
            pkiDebug("%s: pkinit san match found\n", __FUNCTION__);
 
181
            *valid_san = 1;
 
182
            retval = 0;
 
183
            goto out;
 
184
        }
 
185
    }
 
186
    pkiDebug("%s: no pkinit san match found\n", __FUNCTION__);
 
187
    /*
 
188
     * XXX if cert has names but none match, should we
 
189
     * be returning KRB5KDC_ERR_CLIENT_NAME_MISMATCH here?
 
190
     */
 
191
 
 
192
    if (upns == NULL) {
 
193
        pkiDebug("%s: no upn sans (or we wouldn't accept them anyway)\n",
 
194
                 __FUNCTION__);
 
195
        retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
 
196
        goto out;
 
197
    }
 
198
 
 
199
    pkiDebug("%s: Checking upn sans\n", __FUNCTION__);
 
200
    for (i = 0; upns[i] != NULL; i++) {
 
201
#ifdef DEBUG_SAN_INFO
 
202
        krb5_unparse_name(context, upns[i], &san_string);
 
203
        pkiDebug("%s: Comparing client '%s' to upn san value '%s'\n",
 
204
                 __FUNCTION__, client_string, san_string);
 
205
        krb5_free_unparsed_name(context, san_string);
 
206
#endif
 
207
        if (krb5_principal_compare(context, upns[i], client)) {
 
208
            pkiDebug("%s: upn san match found\n", __FUNCTION__);
 
209
            *valid_san = 1;
 
210
            retval = 0;
 
211
            goto out;
 
212
        }
 
213
    }
 
214
    pkiDebug("%s: no upn san match found\n", __FUNCTION__);
 
215
 
 
216
    /* We found no match */
 
217
    if (princs != NULL || upns != NULL) {
 
218
        *valid_san = 0;
 
219
        /* XXX ??? If there was one or more name in the cert, but
 
220
         * none matched the client name, then return mismatch? */
 
221
        retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
 
222
    }
 
223
    retval = 0;
 
224
 
 
225
out:
 
226
    if (princs != NULL) {
 
227
        for (i = 0; princs[i] != NULL; i++)
 
228
            krb5_free_principal(context, princs[i]);
 
229
        free(princs);
 
230
    }
 
231
    if (upns != NULL) {
 
232
        for (i = 0; upns[i] != NULL; i++)
 
233
            krb5_free_principal(context, upns[i]);
 
234
        free(upns);
 
235
    }
 
236
#ifdef DEBUG_SAN_INFO
 
237
    if (client_string != NULL)
 
238
        krb5_free_unparsed_name(context, client_string);
 
239
#endif
 
240
    pkiDebug("%s: returning retval %d, valid_san %d\n",
 
241
             __FUNCTION__, retval, *valid_san);
 
242
    return retval;
 
243
}
 
244
 
 
245
static krb5_error_code
 
246
verify_client_eku(krb5_context context,
 
247
                  pkinit_kdc_context plgctx,
 
248
                  pkinit_kdc_req_context reqctx,
 
249
                  int *eku_accepted)
 
250
{
 
251
    krb5_error_code retval;
 
252
 
 
253
    *eku_accepted = 0;
 
254
 
 
255
    if (plgctx->opts->require_eku == 0) {
 
256
        pkiDebug("%s: configuration requests no EKU checking\n", __FUNCTION__);
 
257
        *eku_accepted = 1;
 
258
        retval = 0;
 
259
        goto out;
 
260
    }
 
261
 
 
262
    retval = crypto_check_cert_eku(context, plgctx->cryptoctx,
 
263
                                   reqctx->cryptoctx, plgctx->idctx,
 
264
                                   0, /* kdc cert */
 
265
                                   plgctx->opts->accept_secondary_eku,
 
266
                                   eku_accepted);
 
267
    if (retval) {
 
268
        pkiDebug("%s: Error from crypto_check_cert_eku %d (%s)\n",
 
269
                 __FUNCTION__, retval, error_message(retval));
 
270
        goto out;
 
271
    }
 
272
 
 
273
out:
 
274
    pkiDebug("%s: returning retval %d, eku_accepted %d\n",
 
275
             __FUNCTION__, retval, *eku_accepted);
 
276
    return retval;
 
277
}
 
278
 
 
279
static void
 
280
pkinit_server_verify_padata(krb5_context context,
 
281
                            krb5_data *req_pkt,
 
282
                            krb5_kdc_req * request,
 
283
                            krb5_enc_tkt_part * enc_tkt_reply,
 
284
                            krb5_pa_data * data,
 
285
                            krb5_kdcpreauth_callbacks cb,
 
286
                            krb5_kdcpreauth_rock rock,
 
287
                            krb5_kdcpreauth_moddata moddata,
 
288
                            krb5_kdcpreauth_verify_respond_fn respond,
 
289
                            void *arg)
 
290
{
 
291
    krb5_error_code retval = 0;
 
292
    krb5_octet_data authp_data = {0, 0, NULL}, krb5_authz = {0, 0, NULL};
 
293
    krb5_pa_pk_as_req *reqp = NULL;
 
294
    krb5_pa_pk_as_req_draft9 *reqp9 = NULL;
 
295
    krb5_auth_pack *auth_pack = NULL;
 
296
    krb5_auth_pack_draft9 *auth_pack9 = NULL;
 
297
    pkinit_kdc_context plgctx = NULL;
 
298
    pkinit_kdc_req_context reqctx = NULL;
 
299
    krb5_checksum cksum = {0, 0, 0, NULL};
 
300
    krb5_data *der_req = NULL;
 
301
    int valid_eku = 0, valid_san = 0;
 
302
    krb5_kdc_req *tmp_as_req = NULL;
 
303
    krb5_data k5data;
 
304
    int is_signed = 1;
 
305
    krb5_pa_data **e_data = NULL;
 
306
    krb5_kdcpreauth_modreq modreq = NULL;
 
307
 
 
308
    pkiDebug("pkinit_verify_padata: entered!\n");
 
309
    if (data == NULL || data->length <= 0 || data->contents == NULL) {
 
310
        (*respond)(arg, 0, NULL, NULL, NULL);
 
311
        return;
 
312
    }
 
313
 
 
314
 
 
315
    if (moddata == NULL) {
 
316
        (*respond)(arg, EINVAL, NULL, NULL, NULL);
 
317
        return;
 
318
    }
 
319
 
 
320
    plgctx = pkinit_find_realm_context(context, moddata, request->server);
 
321
    if (plgctx == NULL) {
 
322
        (*respond)(arg, 0, NULL, NULL, NULL);
 
323
        return;
 
324
    }
 
325
 
 
326
#ifdef DEBUG_ASN1
 
327
    print_buffer_bin(data->contents, data->length, "/tmp/kdc_as_req");
 
328
#endif
 
329
    /* create a per-request context */
 
330
    retval = pkinit_init_kdc_req_context(context, &reqctx);
 
331
    if (retval)
 
332
        goto cleanup;
 
333
    reqctx->pa_type = data->pa_type;
 
334
 
 
335
    PADATA_TO_KRB5DATA(data, &k5data);
 
336
 
 
337
    switch ((int)data->pa_type) {
 
338
    case KRB5_PADATA_PK_AS_REQ:
 
339
        pkiDebug("processing KRB5_PADATA_PK_AS_REQ\n");
 
340
        retval = k5int_decode_krb5_pa_pk_as_req(&k5data, &reqp);
 
341
        if (retval) {
 
342
            pkiDebug("decode_krb5_pa_pk_as_req failed\n");
 
343
            goto cleanup;
 
344
        }
 
345
#ifdef DEBUG_ASN1
 
346
        print_buffer_bin(reqp->signedAuthPack.data,
 
347
                         reqp->signedAuthPack.length,
 
348
                         "/tmp/kdc_signed_data");
 
349
#endif
 
350
        retval = cms_signeddata_verify(context, plgctx->cryptoctx,
 
351
                                       reqctx->cryptoctx, plgctx->idctx, CMS_SIGN_CLIENT,
 
352
                                       plgctx->opts->require_crl_checking,
 
353
                                       reqp->signedAuthPack.data, reqp->signedAuthPack.length,
 
354
                                       &authp_data.data, &authp_data.length, &krb5_authz.data,
 
355
                                       &krb5_authz.length, &is_signed);
 
356
        break;
 
357
    case KRB5_PADATA_PK_AS_REP_OLD:
 
358
    case KRB5_PADATA_PK_AS_REQ_OLD:
 
359
        pkiDebug("processing KRB5_PADATA_PK_AS_REQ_OLD\n");
 
360
        retval = k5int_decode_krb5_pa_pk_as_req_draft9(&k5data, &reqp9);
 
361
        if (retval) {
 
362
            pkiDebug("decode_krb5_pa_pk_as_req_draft9 failed\n");
 
363
            goto cleanup;
 
364
        }
 
365
#ifdef DEBUG_ASN1
 
366
        print_buffer_bin(reqp9->signedAuthPack.data,
 
367
                         reqp9->signedAuthPack.length,
 
368
                         "/tmp/kdc_signed_data_draft9");
 
369
#endif
 
370
 
 
371
        retval = cms_signeddata_verify(context, plgctx->cryptoctx,
 
372
                                       reqctx->cryptoctx, plgctx->idctx, CMS_SIGN_DRAFT9,
 
373
                                       plgctx->opts->require_crl_checking,
 
374
                                       reqp9->signedAuthPack.data, reqp9->signedAuthPack.length,
 
375
                                       &authp_data.data, &authp_data.length, &krb5_authz.data,
 
376
                                       &krb5_authz.length, NULL);
 
377
        break;
 
378
    default:
 
379
        pkiDebug("unrecognized pa_type = %d\n", data->pa_type);
 
380
        retval = EINVAL;
 
381
        goto cleanup;
 
382
    }
 
383
    if (retval) {
 
384
        pkiDebug("pkcs7_signeddata_verify failed\n");
 
385
        goto cleanup;
 
386
    }
 
387
    if (is_signed) {
 
388
 
 
389
        retval = verify_client_san(context, plgctx, reqctx, request->client,
 
390
                                   &valid_san);
 
391
        if (retval)
 
392
            goto cleanup;
 
393
        if (!valid_san) {
 
394
            pkiDebug("%s: did not find an acceptable SAN in user "
 
395
                     "certificate\n", __FUNCTION__);
 
396
            retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
 
397
            goto cleanup;
 
398
        }
 
399
        retval = verify_client_eku(context, plgctx, reqctx, &valid_eku);
 
400
        if (retval)
 
401
            goto cleanup;
 
402
 
 
403
        if (!valid_eku) {
 
404
            pkiDebug("%s: did not find an acceptable EKU in user "
 
405
                     "certificate\n", __FUNCTION__);
 
406
            retval = KRB5KDC_ERR_INCONSISTENT_KEY_PURPOSE;
 
407
            goto cleanup;
 
408
        }
 
409
    } else { /* !is_signed */
 
410
        if (!krb5_principal_compare(context, request->client,
 
411
                                    krb5_anonymous_principal())) {
 
412
            retval = KRB5KDC_ERR_PREAUTH_FAILED;
 
413
            krb5_set_error_message(context, retval,
 
414
                                   _("Pkinit request not signed, but client "
 
415
                                     "not anonymous."));
 
416
            goto cleanup;
 
417
        }
 
418
    }
 
419
#ifdef DEBUG_ASN1
 
420
    print_buffer_bin(authp_data.data, authp_data.length, "/tmp/kdc_auth_pack");
 
421
#endif
 
422
 
 
423
    OCTETDATA_TO_KRB5DATA(&authp_data, &k5data);
 
424
    switch ((int)data->pa_type) {
 
425
    case KRB5_PADATA_PK_AS_REQ:
 
426
        retval = k5int_decode_krb5_auth_pack(&k5data, &auth_pack);
 
427
        if (retval) {
 
428
            pkiDebug("failed to decode krb5_auth_pack\n");
 
429
            goto cleanup;
 
430
        }
 
431
 
 
432
        /* check dh parameters */
 
433
        if (auth_pack->clientPublicValue != NULL) {
 
434
            retval = server_check_dh(context, plgctx->cryptoctx,
 
435
                                     reqctx->cryptoctx, plgctx->idctx,
 
436
                                     &auth_pack->clientPublicValue->algorithm.parameters,
 
437
                                     plgctx->opts->dh_min_bits);
 
438
 
 
439
            if (retval) {
 
440
                pkiDebug("bad dh parameters\n");
 
441
                goto cleanup;
 
442
            }
 
443
        } else if (!is_signed) {
 
444
            /*Anonymous pkinit requires DH*/
 
445
            retval = KRB5KDC_ERR_PREAUTH_FAILED;
 
446
            krb5_set_error_message(context, retval,
 
447
                                   _("Anonymous pkinit without DH public "
 
448
                                     "value not supported."));
 
449
            goto cleanup;
 
450
        }
 
451
        der_req = cb->request_body(context, rock);
 
452
        retval = krb5_c_make_checksum(context, CKSUMTYPE_NIST_SHA, NULL,
 
453
                                      0, der_req, &cksum);
 
454
        if (retval) {
 
455
            pkiDebug("unable to calculate AS REQ checksum\n");
 
456
            goto cleanup;
 
457
        }
 
458
        if (cksum.length != auth_pack->pkAuthenticator.paChecksum.length ||
 
459
            memcmp(cksum.contents,
 
460
                   auth_pack->pkAuthenticator.paChecksum.contents,
 
461
                   cksum.length)) {
 
462
            pkiDebug("failed to match the checksum\n");
 
463
#ifdef DEBUG_CKSUM
 
464
            pkiDebug("calculating checksum on buf size (%d)\n",
 
465
                     req_pkt->length);
 
466
            print_buffer(req_pkt->data, req_pkt->length);
 
467
            pkiDebug("received checksum type=%d size=%d ",
 
468
                     auth_pack->pkAuthenticator.paChecksum.checksum_type,
 
469
                     auth_pack->pkAuthenticator.paChecksum.length);
 
470
            print_buffer(auth_pack->pkAuthenticator.paChecksum.contents,
 
471
                         auth_pack->pkAuthenticator.paChecksum.length);
 
472
            pkiDebug("expected checksum type=%d size=%d ",
 
473
                     cksum.checksum_type, cksum.length);
 
474
            print_buffer(cksum.contents, cksum.length);
 
475
#endif
 
476
 
 
477
            retval = KRB5KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED;
 
478
            goto cleanup;
 
479
        }
 
480
 
 
481
        /* check if kdcPkId present and match KDC's subjectIdentifier */
 
482
        if (reqp->kdcPkId.data != NULL) {
 
483
            int valid_kdcPkId = 0;
 
484
            retval = pkinit_check_kdc_pkid(context, plgctx->cryptoctx,
 
485
                                           reqctx->cryptoctx, plgctx->idctx,
 
486
                                           reqp->kdcPkId.data, reqp->kdcPkId.length, &valid_kdcPkId);
 
487
            if (retval)
 
488
                goto cleanup;
 
489
            if (!valid_kdcPkId)
 
490
                pkiDebug("kdcPkId in AS_REQ does not match KDC's cert"
 
491
                         "RFC says to ignore and proceed\n");
 
492
 
 
493
        }
 
494
        /* remember the decoded auth_pack for verify_padata routine */
 
495
        reqctx->rcv_auth_pack = auth_pack;
 
496
        auth_pack = NULL;
 
497
        break;
 
498
    case KRB5_PADATA_PK_AS_REP_OLD:
 
499
    case KRB5_PADATA_PK_AS_REQ_OLD:
 
500
        retval = k5int_decode_krb5_auth_pack_draft9(&k5data, &auth_pack9);
 
501
        if (retval) {
 
502
            pkiDebug("failed to decode krb5_auth_pack_draft9\n");
 
503
            goto cleanup;
 
504
        }
 
505
        if (auth_pack9->clientPublicValue != NULL) {
 
506
            retval = server_check_dh(context, plgctx->cryptoctx,
 
507
                                     reqctx->cryptoctx, plgctx->idctx,
 
508
                                     &auth_pack9->clientPublicValue->algorithm.parameters,
 
509
                                     plgctx->opts->dh_min_bits);
 
510
 
 
511
            if (retval) {
 
512
                pkiDebug("bad dh parameters\n");
 
513
                goto cleanup;
 
514
            }
 
515
        }
 
516
        /* remember the decoded auth_pack for verify_padata routine */
 
517
        reqctx->rcv_auth_pack9 = auth_pack9;
 
518
        auth_pack9 = NULL;
 
519
        break;
 
520
    }
 
521
 
 
522
    /* remember to set the PREAUTH flag in the reply */
 
523
    enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH;
 
524
    modreq = (krb5_kdcpreauth_modreq)reqctx;
 
525
    reqctx = NULL;
 
526
 
 
527
cleanup:
 
528
    if (retval && data->pa_type == KRB5_PADATA_PK_AS_REQ) {
 
529
        pkiDebug("pkinit_verify_padata failed: creating e-data\n");
 
530
        if (pkinit_create_edata(context, plgctx->cryptoctx, reqctx->cryptoctx,
 
531
                                plgctx->idctx, plgctx->opts, retval, &e_data))
 
532
            pkiDebug("pkinit_create_edata failed\n");
 
533
    }
 
534
 
 
535
    switch ((int)data->pa_type) {
 
536
    case KRB5_PADATA_PK_AS_REQ:
 
537
        free_krb5_pa_pk_as_req(&reqp);
 
538
        free(cksum.contents);
 
539
        break;
 
540
    case KRB5_PADATA_PK_AS_REP_OLD:
 
541
    case KRB5_PADATA_PK_AS_REQ_OLD:
 
542
        free_krb5_pa_pk_as_req_draft9(&reqp9);
 
543
    }
 
544
    if (tmp_as_req != NULL)
 
545
        k5int_krb5_free_kdc_req(context, tmp_as_req);
 
546
    free(authp_data.data);
 
547
    free(krb5_authz.data);
 
548
    if (reqctx != NULL)
 
549
        pkinit_fini_kdc_req_context(context, reqctx);
 
550
    if (auth_pack != NULL)
 
551
        free_krb5_auth_pack(&auth_pack);
 
552
    if (auth_pack9 != NULL)
 
553
        free_krb5_auth_pack_draft9(context, &auth_pack9);
 
554
 
 
555
    (*respond)(arg, retval, modreq, e_data, NULL);
 
556
}
 
557
static krb5_error_code
 
558
return_pkinit_kx(krb5_context context, krb5_kdc_req *request,
 
559
                 krb5_kdc_rep *reply, krb5_keyblock *encrypting_key,
 
560
                 krb5_pa_data **out_padata)
 
561
{
 
562
    krb5_error_code ret = 0;
 
563
    krb5_keyblock *session = reply->ticket->enc_part2->session;
 
564
    krb5_keyblock *new_session = NULL;
 
565
    krb5_pa_data *pa = NULL;
 
566
    krb5_enc_data enc;
 
567
    krb5_data *scratch = NULL;
 
568
 
 
569
    *out_padata = NULL;
 
570
    enc.ciphertext.data = NULL;
 
571
    if (!krb5_principal_compare(context, request->client,
 
572
                                krb5_anonymous_principal()))
 
573
        return 0;
 
574
    /*
 
575
     * The KDC contribution key needs to be a fresh key of an enctype supported
 
576
     * by the client and server. The existing session key meets these
 
577
     * requirements so we use it.
 
578
     */
 
579
    ret = krb5_c_fx_cf2_simple(context, session, "PKINIT",
 
580
                               encrypting_key, "KEYEXCHANGE",
 
581
                               &new_session);
 
582
    if (ret)
 
583
        goto cleanup;
 
584
    ret = encode_krb5_encryption_key( session, &scratch);
 
585
    if (ret)
 
586
        goto cleanup;
 
587
    ret = krb5_encrypt_helper(context, encrypting_key,
 
588
                              KRB5_KEYUSAGE_PA_PKINIT_KX, scratch, &enc);
 
589
    if (ret)
 
590
        goto cleanup;
 
591
    memset(scratch->data, 0, scratch->length);
 
592
    krb5_free_data(context, scratch);
 
593
    scratch = NULL;
 
594
    ret = encode_krb5_enc_data(&enc, &scratch);
 
595
    if (ret)
 
596
        goto cleanup;
 
597
    pa = malloc(sizeof(krb5_pa_data));
 
598
    if (pa == NULL) {
 
599
        ret = ENOMEM;
 
600
        goto cleanup;
 
601
    }
 
602
    pa->pa_type = KRB5_PADATA_PKINIT_KX;
 
603
    pa->length = scratch->length;
 
604
    pa->contents = (krb5_octet *) scratch->data;
 
605
    *out_padata = pa;
 
606
    scratch->data = NULL;
 
607
    memset(session->contents, 0, session->length);
 
608
    krb5_free_keyblock_contents(context, session);
 
609
    *session = *new_session;
 
610
    new_session->contents = NULL;
 
611
cleanup:
 
612
    krb5_free_data_contents(context, &enc.ciphertext);
 
613
    krb5_free_keyblock(context, new_session);
 
614
    krb5_free_data(context, scratch);
 
615
    return ret;
 
616
}
 
617
 
 
618
static krb5_error_code
 
619
pkinit_pick_kdf_alg(krb5_context context,
 
620
                    krb5_octet_data **kdf_list,
 
621
                    krb5_octet_data **alg_oid)
 
622
{
 
623
    krb5_error_code retval = 0;
 
624
    krb5_octet_data *req_oid = NULL;
 
625
    const krb5_octet_data *supp_oid = NULL;
 
626
    krb5_octet_data *tmp_oid = NULL;
 
627
    int i, j = 0;
 
628
 
 
629
    /* if we don't find a match, return NULL value */
 
630
    *alg_oid = NULL;
 
631
 
 
632
    /* for each of the OIDs that the server supports... */
 
633
    for (i = 0; NULL != (supp_oid = supported_kdf_alg_ids[i]); i++) {
 
634
        /* if the requested OID is in the client's list, use it. */
 
635
        for (j = 0; NULL != (req_oid = kdf_list[j]); j++) {
 
636
            if ((req_oid->length == supp_oid->length) &&
 
637
                (0 == memcmp(req_oid->data, supp_oid->data, req_oid->length))) {
 
638
                tmp_oid = k5alloc(sizeof(krb5_octet_data), &retval);
 
639
                if (retval)
 
640
                    goto cleanup;
 
641
                tmp_oid->data = k5alloc(supp_oid->length, &retval);
 
642
                if (retval)
 
643
                    goto cleanup;
 
644
                tmp_oid->length = supp_oid->length;
 
645
                memcpy(tmp_oid->data, supp_oid->data, tmp_oid->length);
 
646
                *alg_oid = tmp_oid;
 
647
                /* don't free the OID in clean-up if we are returning it */
 
648
                tmp_oid = NULL;
 
649
                goto cleanup;
 
650
            }
 
651
        }
 
652
    }
 
653
cleanup:
 
654
    if (tmp_oid)
 
655
        krb5_free_octet_data(context, tmp_oid);
 
656
    return retval;
 
657
}
 
658
 
 
659
static krb5_error_code
 
660
pkinit_server_return_padata(krb5_context context,
 
661
                            krb5_pa_data * padata,
 
662
                            krb5_data *req_pkt,
 
663
                            krb5_kdc_req * request,
 
664
                            krb5_kdc_rep * reply,
 
665
                            krb5_keyblock * encrypting_key,
 
666
                            krb5_pa_data ** send_pa,
 
667
                            krb5_kdcpreauth_callbacks cb,
 
668
                            krb5_kdcpreauth_rock rock,
 
669
                            krb5_kdcpreauth_moddata moddata,
 
670
                            krb5_kdcpreauth_modreq modreq)
 
671
{
 
672
    krb5_error_code retval = 0;
 
673
    krb5_data scratch = {0, 0, NULL};
 
674
    krb5_pa_pk_as_req *reqp = NULL;
 
675
    krb5_pa_pk_as_req_draft9 *reqp9 = NULL;
 
676
    int i = 0;
 
677
 
 
678
    unsigned char *subjectPublicKey = NULL;
 
679
    unsigned char *dh_pubkey = NULL, *server_key = NULL;
 
680
    unsigned int subjectPublicKey_len = 0;
 
681
    unsigned int server_key_len = 0, dh_pubkey_len = 0;
 
682
 
 
683
    krb5_kdc_dh_key_info dhkey_info;
 
684
    krb5_data *encoded_dhkey_info = NULL;
 
685
    krb5_pa_pk_as_rep *rep = NULL;
 
686
    krb5_pa_pk_as_rep_draft9 *rep9 = NULL;
 
687
    krb5_data *out_data = NULL;
 
688
    krb5_octet_data secret;
 
689
 
 
690
    krb5_enctype enctype = -1;
 
691
 
 
692
    krb5_reply_key_pack *key_pack = NULL;
 
693
    krb5_reply_key_pack_draft9 *key_pack9 = NULL;
 
694
    krb5_data *encoded_key_pack = NULL;
 
695
 
 
696
    pkinit_kdc_context plgctx;
 
697
    pkinit_kdc_req_context reqctx;
 
698
 
 
699
    int fixed_keypack = 0;
 
700
 
 
701
    *send_pa = NULL;
 
702
    if (padata->pa_type == KRB5_PADATA_PKINIT_KX) {
 
703
        return return_pkinit_kx(context, request, reply,
 
704
                                encrypting_key, send_pa);
 
705
    }
 
706
    if (padata->length <= 0 || padata->contents == NULL)
 
707
        return 0;
 
708
 
 
709
    if (modreq == NULL) {
 
710
        pkiDebug("missing request context \n");
 
711
        return EINVAL;
 
712
    }
 
713
 
 
714
    plgctx = pkinit_find_realm_context(context, moddata, request->server);
 
715
    if (plgctx == NULL) {
 
716
        pkiDebug("Unable to locate correct realm context\n");
 
717
        return ENOENT;
 
718
    }
 
719
 
 
720
    pkiDebug("pkinit_return_padata: entered!\n");
 
721
    reqctx = (pkinit_kdc_req_context)modreq;
 
722
 
 
723
    if (encrypting_key->contents) {
 
724
        free(encrypting_key->contents);
 
725
        encrypting_key->length = 0;
 
726
        encrypting_key->contents = NULL;
 
727
    }
 
728
 
 
729
    for(i = 0; i < request->nktypes; i++) {
 
730
        enctype = request->ktype[i];
 
731
        if (!krb5_c_valid_enctype(enctype))
 
732
            continue;
 
733
        else {
 
734
            pkiDebug("KDC picked etype = %d\n", enctype);
 
735
            break;
 
736
        }
 
737
    }
 
738
 
 
739
    if (i == request->nktypes) {
 
740
        retval = KRB5KDC_ERR_ETYPE_NOSUPP;
 
741
        goto cleanup;
 
742
    }
 
743
 
 
744
    switch((int)reqctx->pa_type) {
 
745
    case KRB5_PADATA_PK_AS_REQ:
 
746
        init_krb5_pa_pk_as_rep(&rep);
 
747
        if (rep == NULL) {
 
748
            retval = ENOMEM;
 
749
            goto cleanup;
 
750
        }
 
751
        /* let's assume it's RSA. we'll reset it to DH if needed */
 
752
        rep->choice = choice_pa_pk_as_rep_encKeyPack;
 
753
        break;
 
754
    case KRB5_PADATA_PK_AS_REP_OLD:
 
755
    case KRB5_PADATA_PK_AS_REQ_OLD:
 
756
        init_krb5_pa_pk_as_rep_draft9(&rep9);
 
757
        if (rep9 == NULL) {
 
758
            retval = ENOMEM;
 
759
            goto cleanup;
 
760
        }
 
761
        rep9->choice = choice_pa_pk_as_rep_draft9_encKeyPack;
 
762
        break;
 
763
    default:
 
764
        retval = KRB5KDC_ERR_PREAUTH_FAILED;
 
765
        goto cleanup;
 
766
    }
 
767
 
 
768
    if (reqctx->rcv_auth_pack != NULL &&
 
769
        reqctx->rcv_auth_pack->clientPublicValue != NULL) {
 
770
        subjectPublicKey =
 
771
            reqctx->rcv_auth_pack->clientPublicValue->subjectPublicKey.data;
 
772
        subjectPublicKey_len =
 
773
            reqctx->rcv_auth_pack->clientPublicValue->subjectPublicKey.length;
 
774
        rep->choice = choice_pa_pk_as_rep_dhInfo;
 
775
    } else if (reqctx->rcv_auth_pack9 != NULL &&
 
776
               reqctx->rcv_auth_pack9->clientPublicValue != NULL) {
 
777
        subjectPublicKey =
 
778
            reqctx->rcv_auth_pack9->clientPublicValue->subjectPublicKey.data;
 
779
        subjectPublicKey_len =
 
780
            reqctx->rcv_auth_pack9->clientPublicValue->subjectPublicKey.length;
 
781
        rep9->choice = choice_pa_pk_as_rep_draft9_dhSignedData;
 
782
    }
 
783
 
 
784
    /* if this DH, then process finish computing DH key */
 
785
    if (rep != NULL && (rep->choice == choice_pa_pk_as_rep_dhInfo ||
 
786
                        rep->choice == choice_pa_pk_as_rep_draft9_dhSignedData)) {
 
787
        pkiDebug("received DH key delivery AS REQ\n");
 
788
        retval = server_process_dh(context, plgctx->cryptoctx,
 
789
                                   reqctx->cryptoctx, plgctx->idctx, subjectPublicKey,
 
790
                                   subjectPublicKey_len, &dh_pubkey, &dh_pubkey_len,
 
791
                                   &server_key, &server_key_len);
 
792
        if (retval) {
 
793
            pkiDebug("failed to process/create dh paramters\n");
 
794
            goto cleanup;
 
795
        }
 
796
    }
 
797
    if ((rep9 != NULL &&
 
798
         rep9->choice == choice_pa_pk_as_rep_draft9_dhSignedData) ||
 
799
        (rep != NULL && rep->choice == choice_pa_pk_as_rep_dhInfo)) {
 
800
 
 
801
        /*
 
802
         * This is DH, so don't generate the key until after we
 
803
         * encode the reply, because the encoded reply is needed
 
804
         * to generate the key in some cases.
 
805
         */
 
806
 
 
807
        dhkey_info.subjectPublicKey.length = dh_pubkey_len;
 
808
        dhkey_info.subjectPublicKey.data = dh_pubkey;
 
809
        dhkey_info.nonce = request->nonce;
 
810
        dhkey_info.dhKeyExpiration = 0;
 
811
 
 
812
        retval = k5int_encode_krb5_kdc_dh_key_info(&dhkey_info,
 
813
                                                   &encoded_dhkey_info);
 
814
        if (retval) {
 
815
            pkiDebug("encode_krb5_kdc_dh_key_info failed\n");
 
816
            goto cleanup;
 
817
        }
 
818
#ifdef DEBUG_ASN1
 
819
        print_buffer_bin((unsigned char *)encoded_dhkey_info->data,
 
820
                         encoded_dhkey_info->length,
 
821
                         "/tmp/kdc_dh_key_info");
 
822
#endif
 
823
 
 
824
        switch ((int)padata->pa_type) {
 
825
        case KRB5_PADATA_PK_AS_REQ:
 
826
            retval = cms_signeddata_create(context, plgctx->cryptoctx,
 
827
                                           reqctx->cryptoctx, plgctx->idctx, CMS_SIGN_SERVER, 1,
 
828
                                           (unsigned char *)encoded_dhkey_info->data,
 
829
                                           encoded_dhkey_info->length,
 
830
                                           &rep->u.dh_Info.dhSignedData.data,
 
831
                                           &rep->u.dh_Info.dhSignedData.length);
 
832
            if (retval) {
 
833
                pkiDebug("failed to create pkcs7 signed data\n");
 
834
                goto cleanup;
 
835
            }
 
836
            break;
 
837
        case KRB5_PADATA_PK_AS_REP_OLD:
 
838
        case KRB5_PADATA_PK_AS_REQ_OLD:
 
839
            retval = cms_signeddata_create(context, plgctx->cryptoctx,
 
840
                                           reqctx->cryptoctx, plgctx->idctx, CMS_SIGN_DRAFT9, 1,
 
841
                                           (unsigned char *)encoded_dhkey_info->data,
 
842
                                           encoded_dhkey_info->length,
 
843
                                           &rep9->u.dhSignedData.data,
 
844
                                           &rep9->u.dhSignedData.length);
 
845
            if (retval) {
 
846
                pkiDebug("failed to create pkcs7 signed data\n");
 
847
                goto cleanup;
 
848
            }
 
849
            break;
 
850
        }
 
851
 
 
852
    } else {
 
853
        pkiDebug("received RSA key delivery AS REQ\n");
 
854
 
 
855
        retval = krb5_c_make_random_key(context, enctype, encrypting_key);
 
856
        if (retval) {
 
857
            pkiDebug("unable to make a session key\n");
 
858
            goto cleanup;
 
859
        }
 
860
 
 
861
        /* check if PA_TYPE of 132 is present which means the client is
 
862
         * requesting that a checksum is send back instead of the nonce
 
863
         */
 
864
        for (i = 0; request->padata[i] != NULL; i++) {
 
865
            pkiDebug("%s: Checking pa_type 0x%08x\n",
 
866
                     __FUNCTION__, request->padata[i]->pa_type);
 
867
            if (request->padata[i]->pa_type == 132)
 
868
                fixed_keypack = 1;
 
869
        }
 
870
        pkiDebug("%s: return checksum instead of nonce = %d\n",
 
871
                 __FUNCTION__, fixed_keypack);
 
872
 
 
873
        /* if this is an RFC reply or draft9 client requested a checksum
 
874
         * in the reply instead of the nonce, create an RFC-style keypack
 
875
         */
 
876
        if ((int)padata->pa_type == KRB5_PADATA_PK_AS_REQ || fixed_keypack) {
 
877
            init_krb5_reply_key_pack(&key_pack);
 
878
            if (key_pack == NULL) {
 
879
                retval = ENOMEM;
 
880
                goto cleanup;
 
881
            }
 
882
 
 
883
            retval = krb5_c_make_checksum(context, 0,
 
884
                                          encrypting_key, KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM,
 
885
                                          req_pkt, &key_pack->asChecksum);
 
886
            if (retval) {
 
887
                pkiDebug("unable to calculate AS REQ checksum\n");
 
888
                goto cleanup;
 
889
            }
 
890
#ifdef DEBUG_CKSUM
 
891
            pkiDebug("calculating checksum on buf size = %d\n", req_pkt->length);
 
892
            print_buffer(req_pkt->data, req_pkt->length);
 
893
            pkiDebug("checksum size = %d\n", key_pack->asChecksum.length);
 
894
            print_buffer(key_pack->asChecksum.contents,
 
895
                         key_pack->asChecksum.length);
 
896
            pkiDebug("encrypting key (%d)\n", encrypting_key->length);
 
897
            print_buffer(encrypting_key->contents, encrypting_key->length);
 
898
#endif
 
899
 
 
900
            krb5_copy_keyblock_contents(context, encrypting_key,
 
901
                                        &key_pack->replyKey);
 
902
 
 
903
            retval = k5int_encode_krb5_reply_key_pack(key_pack,
 
904
                                                      &encoded_key_pack);
 
905
            if (retval) {
 
906
                pkiDebug("failed to encode reply_key_pack\n");
 
907
                goto cleanup;
 
908
            }
 
909
        }
 
910
 
 
911
        switch ((int)padata->pa_type) {
 
912
        case KRB5_PADATA_PK_AS_REQ:
 
913
            rep->choice = choice_pa_pk_as_rep_encKeyPack;
 
914
            retval = cms_envelopeddata_create(context, plgctx->cryptoctx,
 
915
                                              reqctx->cryptoctx, plgctx->idctx, padata->pa_type, 1,
 
916
                                              (unsigned char *)encoded_key_pack->data,
 
917
                                              encoded_key_pack->length,
 
918
                                              &rep->u.encKeyPack.data, &rep->u.encKeyPack.length);
 
919
            break;
 
920
        case KRB5_PADATA_PK_AS_REP_OLD:
 
921
        case KRB5_PADATA_PK_AS_REQ_OLD:
 
922
            /* if the request is from the broken draft9 client that
 
923
             * expects back a nonce, create it now
 
924
             */
 
925
            if (!fixed_keypack) {
 
926
                init_krb5_reply_key_pack_draft9(&key_pack9);
 
927
                if (key_pack9 == NULL) {
 
928
                    retval = ENOMEM;
 
929
                    goto cleanup;
 
930
                }
 
931
                key_pack9->nonce = reqctx->rcv_auth_pack9->pkAuthenticator.nonce;
 
932
                krb5_copy_keyblock_contents(context, encrypting_key,
 
933
                                            &key_pack9->replyKey);
 
934
 
 
935
                retval = k5int_encode_krb5_reply_key_pack_draft9(key_pack9,
 
936
                                                                 &encoded_key_pack);
 
937
                if (retval) {
 
938
                    pkiDebug("failed to encode reply_key_pack\n");
 
939
                    goto cleanup;
 
940
                }
 
941
            }
 
942
 
 
943
            rep9->choice = choice_pa_pk_as_rep_draft9_encKeyPack;
 
944
            retval = cms_envelopeddata_create(context, plgctx->cryptoctx,
 
945
                                              reqctx->cryptoctx, plgctx->idctx, padata->pa_type, 1,
 
946
                                              (unsigned char *)encoded_key_pack->data,
 
947
                                              encoded_key_pack->length,
 
948
                                              &rep9->u.encKeyPack.data, &rep9->u.encKeyPack.length);
 
949
            break;
 
950
        }
 
951
        if (retval) {
 
952
            pkiDebug("failed to create pkcs7 enveloped data: %s\n",
 
953
                     error_message(retval));
 
954
            goto cleanup;
 
955
        }
 
956
#ifdef DEBUG_ASN1
 
957
        print_buffer_bin((unsigned char *)encoded_key_pack->data,
 
958
                         encoded_key_pack->length,
 
959
                         "/tmp/kdc_key_pack");
 
960
        switch ((int)padata->pa_type) {
 
961
        case KRB5_PADATA_PK_AS_REQ:
 
962
            print_buffer_bin(rep->u.encKeyPack.data,
 
963
                             rep->u.encKeyPack.length,
 
964
                             "/tmp/kdc_enc_key_pack");
 
965
            break;
 
966
        case KRB5_PADATA_PK_AS_REP_OLD:
 
967
        case KRB5_PADATA_PK_AS_REQ_OLD:
 
968
            print_buffer_bin(rep9->u.encKeyPack.data,
 
969
                             rep9->u.encKeyPack.length,
 
970
                             "/tmp/kdc_enc_key_pack");
 
971
            break;
 
972
        }
 
973
#endif
 
974
    }
 
975
 
 
976
    if ((rep != NULL && rep->choice == choice_pa_pk_as_rep_dhInfo) &&
 
977
        ((reqctx->rcv_auth_pack != NULL &&
 
978
          reqctx->rcv_auth_pack->supportedKDFs != NULL))) {
 
979
 
 
980
        /* If using the alg-agility KDF, put the algorithm in the reply
 
981
         * before encoding it.
 
982
         */
 
983
        if (reqctx->rcv_auth_pack != NULL &&
 
984
            reqctx->rcv_auth_pack->supportedKDFs != NULL) {
 
985
            retval = pkinit_pick_kdf_alg(context, reqctx->rcv_auth_pack->supportedKDFs,
 
986
                                         &(rep->u.dh_Info.kdfID));
 
987
            if (retval) {
 
988
                pkiDebug("pkinit_pick_kdf_alg failed: %s\n",
 
989
                         error_message(retval));
 
990
                goto cleanup;
 
991
            }
 
992
        }
 
993
    }
 
994
 
 
995
    switch ((int)padata->pa_type) {
 
996
    case KRB5_PADATA_PK_AS_REQ:
 
997
        retval = k5int_encode_krb5_pa_pk_as_rep(rep, &out_data);
 
998
        break;
 
999
    case KRB5_PADATA_PK_AS_REP_OLD:
 
1000
    case KRB5_PADATA_PK_AS_REQ_OLD:
 
1001
        retval = k5int_encode_krb5_pa_pk_as_rep_draft9(rep9, &out_data);
 
1002
        break;
 
1003
    }
 
1004
    if (retval) {
 
1005
        pkiDebug("failed to encode AS_REP\n");
 
1006
        goto cleanup;
 
1007
    }
 
1008
#ifdef DEBUG_ASN1
 
1009
    if (out_data != NULL)
 
1010
        print_buffer_bin((unsigned char *)out_data->data, out_data->length,
 
1011
                         "/tmp/kdc_as_rep");
 
1012
#endif
 
1013
 
 
1014
    /* If this is DH, we haven't computed the key yet, so do it now. */
 
1015
    if ((rep9 != NULL &&
 
1016
         rep9->choice == choice_pa_pk_as_rep_draft9_dhSignedData) ||
 
1017
        (rep != NULL && rep->choice == choice_pa_pk_as_rep_dhInfo)) {
 
1018
 
 
1019
        /* If mutually supported KDFs were found, use the alg agility KDF */
 
1020
        if (rep->u.dh_Info.kdfID) {
 
1021
            secret.data = server_key;
 
1022
            secret.length = server_key_len;
 
1023
 
 
1024
            retval = pkinit_alg_agility_kdf(context, &secret,
 
1025
                                            rep->u.dh_Info.kdfID,
 
1026
                                            request->client, request->server,
 
1027
                                            enctype,
 
1028
                                            (krb5_octet_data *)req_pkt,
 
1029
                                            (krb5_octet_data *)out_data,
 
1030
                                            encrypting_key);
 
1031
            if (retval) {
 
1032
                pkiDebug("pkinit_alg_agility_kdf failed: %s\n",
 
1033
                         error_message(retval));
 
1034
                goto cleanup;
 
1035
            }
 
1036
 
 
1037
            /* Otherwise, use the older octetstring2key() function */
 
1038
        } else {
 
1039
            retval = pkinit_octetstring2key(context, enctype, server_key,
 
1040
                                            server_key_len, encrypting_key);
 
1041
            if (retval) {
 
1042
                pkiDebug("pkinit_octetstring2key failed: %s\n",
 
1043
                         error_message(retval));
 
1044
                goto cleanup;
 
1045
            }
 
1046
        }
 
1047
    }
 
1048
 
 
1049
    *send_pa = malloc(sizeof(krb5_pa_data));
 
1050
    if (*send_pa == NULL) {
 
1051
        retval = ENOMEM;
 
1052
        free(out_data->data);
 
1053
        free(out_data);
 
1054
        out_data = NULL;
 
1055
        goto cleanup;
 
1056
    }
 
1057
    (*send_pa)->magic = KV5M_PA_DATA;
 
1058
    switch ((int)padata->pa_type) {
 
1059
    case KRB5_PADATA_PK_AS_REQ:
 
1060
        (*send_pa)->pa_type = KRB5_PADATA_PK_AS_REP;
 
1061
        break;
 
1062
    case KRB5_PADATA_PK_AS_REQ_OLD:
 
1063
    case KRB5_PADATA_PK_AS_REP_OLD:
 
1064
        (*send_pa)->pa_type = KRB5_PADATA_PK_AS_REP_OLD;
 
1065
        break;
 
1066
    }
 
1067
    (*send_pa)->length = out_data->length;
 
1068
    (*send_pa)->contents = (krb5_octet *) out_data->data;
 
1069
 
 
1070
cleanup:
 
1071
    pkinit_fini_kdc_req_context(context, reqctx);
 
1072
    free(scratch.data);
 
1073
    free(out_data);
 
1074
    if (encoded_dhkey_info != NULL)
 
1075
        krb5_free_data(context, encoded_dhkey_info);
 
1076
    if (encoded_key_pack != NULL)
 
1077
        krb5_free_data(context, encoded_key_pack);
 
1078
    free(dh_pubkey);
 
1079
    free(server_key);
 
1080
 
 
1081
    switch ((int)padata->pa_type) {
 
1082
    case KRB5_PADATA_PK_AS_REQ:
 
1083
        free_krb5_pa_pk_as_req(&reqp);
 
1084
        free_krb5_pa_pk_as_rep(&rep);
 
1085
        free_krb5_reply_key_pack(&key_pack);
 
1086
        break;
 
1087
    case KRB5_PADATA_PK_AS_REP_OLD:
 
1088
    case KRB5_PADATA_PK_AS_REQ_OLD:
 
1089
        free_krb5_pa_pk_as_req_draft9(&reqp9);
 
1090
        free_krb5_pa_pk_as_rep_draft9(&rep9);
 
1091
        if (!fixed_keypack)
 
1092
            free_krb5_reply_key_pack_draft9(&key_pack9);
 
1093
        else
 
1094
            free_krb5_reply_key_pack(&key_pack);
 
1095
        break;
 
1096
    }
 
1097
 
 
1098
    if (retval)
 
1099
        pkiDebug("pkinit_verify_padata failure");
 
1100
 
 
1101
    return retval;
 
1102
}
 
1103
 
 
1104
static int
 
1105
pkinit_server_get_flags(krb5_context kcontext, krb5_preauthtype patype)
 
1106
{
 
1107
    if (patype == KRB5_PADATA_PKINIT_KX)
 
1108
        return PA_INFO;
 
1109
    return PA_SUFFICIENT | PA_REPLACES_KEY | PA_TYPED_E_DATA;
 
1110
}
 
1111
 
 
1112
static krb5_preauthtype supported_server_pa_types[] = {
 
1113
    KRB5_PADATA_PK_AS_REQ,
 
1114
    KRB5_PADATA_PK_AS_REQ_OLD,
 
1115
    KRB5_PADATA_PK_AS_REP_OLD,
 
1116
    KRB5_PADATA_PKINIT_KX,
 
1117
    0
 
1118
};
 
1119
 
 
1120
static void
 
1121
pkinit_fini_kdc_profile(krb5_context context, pkinit_kdc_context plgctx)
 
1122
{
 
1123
    /*
 
1124
     * There is nothing currently allocated by pkinit_init_kdc_profile()
 
1125
     * which needs to be freed here.
 
1126
     */
 
1127
}
 
1128
 
 
1129
static krb5_error_code
 
1130
pkinit_init_kdc_profile(krb5_context context, pkinit_kdc_context plgctx)
 
1131
{
 
1132
    krb5_error_code retval;
 
1133
    char *eku_string = NULL;
 
1134
 
 
1135
    pkiDebug("%s: entered for realm %s\n", __FUNCTION__, plgctx->realmname);
 
1136
    retval = pkinit_kdcdefault_string(context, plgctx->realmname,
 
1137
                                      KRB5_CONF_PKINIT_IDENTITY,
 
1138
                                      &plgctx->idopts->identity);
 
1139
    if (retval != 0 || NULL == plgctx->idopts->identity) {
 
1140
        retval = EINVAL;
 
1141
        krb5_set_error_message(context, retval,
 
1142
                               _("No pkinit_identity supplied for realm %s"),
 
1143
                               plgctx->realmname);
 
1144
        goto errout;
 
1145
    }
 
1146
 
 
1147
    retval = pkinit_kdcdefault_strings(context, plgctx->realmname,
 
1148
                                       KRB5_CONF_PKINIT_ANCHORS,
 
1149
                                       &plgctx->idopts->anchors);
 
1150
    if (retval != 0 || NULL == plgctx->idopts->anchors) {
 
1151
        retval = EINVAL;
 
1152
        krb5_set_error_message(context, retval,
 
1153
                               _("No pkinit_anchors supplied for realm %s"),
 
1154
                               plgctx->realmname);
 
1155
        goto errout;
 
1156
    }
 
1157
 
 
1158
    pkinit_kdcdefault_strings(context, plgctx->realmname,
 
1159
                              KRB5_CONF_PKINIT_POOL,
 
1160
                              &plgctx->idopts->intermediates);
 
1161
 
 
1162
    pkinit_kdcdefault_strings(context, plgctx->realmname,
 
1163
                              KRB5_CONF_PKINIT_REVOKE,
 
1164
                              &plgctx->idopts->crls);
 
1165
 
 
1166
    pkinit_kdcdefault_string(context, plgctx->realmname,
 
1167
                             KRB5_CONF_PKINIT_KDC_OCSP,
 
1168
                             &plgctx->idopts->ocsp);
 
1169
 
 
1170
    pkinit_kdcdefault_string(context, plgctx->realmname,
 
1171
                             KRB5_CONF_PKINIT_MAPPING_FILE,
 
1172
                             &plgctx->idopts->dn_mapping_file);
 
1173
 
 
1174
    pkinit_kdcdefault_integer(context, plgctx->realmname,
 
1175
                              KRB5_CONF_PKINIT_DH_MIN_BITS,
 
1176
                              PKINIT_DEFAULT_DH_MIN_BITS,
 
1177
                              &plgctx->opts->dh_min_bits);
 
1178
    if (plgctx->opts->dh_min_bits < PKINIT_DEFAULT_DH_MIN_BITS) {
 
1179
        pkiDebug("%s: invalid value (%d) for pkinit_dh_min_bits, "
 
1180
                 "using default value (%d) instead\n", __FUNCTION__,
 
1181
                 plgctx->opts->dh_min_bits, PKINIT_DEFAULT_DH_MIN_BITS);
 
1182
        plgctx->opts->dh_min_bits = PKINIT_DEFAULT_DH_MIN_BITS;
 
1183
    }
 
1184
 
 
1185
    pkinit_kdcdefault_boolean(context, plgctx->realmname,
 
1186
                              KRB5_CONF_PKINIT_ALLOW_UPN,
 
1187
                              0, &plgctx->opts->allow_upn);
 
1188
 
 
1189
    pkinit_kdcdefault_boolean(context, plgctx->realmname,
 
1190
                              KRB5_CONF_PKINIT_REQUIRE_CRL_CHECKING,
 
1191
                              0, &plgctx->opts->require_crl_checking);
 
1192
 
 
1193
    pkinit_kdcdefault_string(context, plgctx->realmname,
 
1194
                             KRB5_CONF_PKINIT_EKU_CHECKING,
 
1195
                             &eku_string);
 
1196
    if (eku_string != NULL) {
 
1197
        if (strcasecmp(eku_string, "kpClientAuth") == 0) {
 
1198
            plgctx->opts->require_eku = 1;
 
1199
            plgctx->opts->accept_secondary_eku = 0;
 
1200
        } else if (strcasecmp(eku_string, "scLogin") == 0) {
 
1201
            plgctx->opts->require_eku = 1;
 
1202
            plgctx->opts->accept_secondary_eku = 1;
 
1203
        } else if (strcasecmp(eku_string, "none") == 0) {
 
1204
            plgctx->opts->require_eku = 0;
 
1205
            plgctx->opts->accept_secondary_eku = 0;
 
1206
        } else {
 
1207
            pkiDebug("%s: Invalid value for pkinit_eku_checking: '%s'\n",
 
1208
                     __FUNCTION__, eku_string);
 
1209
        }
 
1210
        free(eku_string);
 
1211
    }
 
1212
 
 
1213
 
 
1214
    return 0;
 
1215
errout:
 
1216
    pkinit_fini_kdc_profile(context, plgctx);
 
1217
    return retval;
 
1218
}
 
1219
 
 
1220
static pkinit_kdc_context
 
1221
pkinit_find_realm_context(krb5_context context,
 
1222
                          krb5_kdcpreauth_moddata moddata,
 
1223
                          krb5_principal princ)
 
1224
{
 
1225
    int i;
 
1226
    pkinit_kdc_context *realm_contexts = (pkinit_kdc_context *)moddata;
 
1227
 
 
1228
    if (moddata == NULL)
 
1229
        return NULL;
 
1230
 
 
1231
    for (i = 0; realm_contexts[i] != NULL; i++) {
 
1232
        pkinit_kdc_context p = realm_contexts[i];
 
1233
 
 
1234
        if ((p->realmname_len == princ->realm.length) &&
 
1235
            (strncmp(p->realmname, princ->realm.data, p->realmname_len) == 0)) {
 
1236
            pkiDebug("%s: returning context at %p for realm '%s'\n",
 
1237
                     __FUNCTION__, p, p->realmname);
 
1238
            return p;
 
1239
        }
 
1240
    }
 
1241
    pkiDebug("%s: unable to find realm context for realm '%.*s'\n",
 
1242
             __FUNCTION__, princ->realm.length, princ->realm.data);
 
1243
    return NULL;
 
1244
}
 
1245
 
 
1246
static int
 
1247
pkinit_server_plugin_init_realm(krb5_context context, const char *realmname,
 
1248
                                pkinit_kdc_context *pplgctx)
 
1249
{
 
1250
    krb5_error_code retval = ENOMEM;
 
1251
    pkinit_kdc_context plgctx = NULL;
 
1252
 
 
1253
    *pplgctx = NULL;
 
1254
 
 
1255
    plgctx = calloc(1, sizeof(*plgctx));
 
1256
    if (plgctx == NULL)
 
1257
        goto errout;
 
1258
 
 
1259
    pkiDebug("%s: initializing context at %p for realm '%s'\n",
 
1260
             __FUNCTION__, plgctx, realmname);
 
1261
    memset(plgctx, 0, sizeof(*plgctx));
 
1262
    plgctx->magic = PKINIT_CTX_MAGIC;
 
1263
 
 
1264
    plgctx->realmname = strdup(realmname);
 
1265
    if (plgctx->realmname == NULL)
 
1266
        goto errout;
 
1267
    plgctx->realmname_len = strlen(plgctx->realmname);
 
1268
 
 
1269
    retval = pkinit_init_plg_crypto(&plgctx->cryptoctx);
 
1270
    if (retval)
 
1271
        goto errout;
 
1272
 
 
1273
    retval = pkinit_init_plg_opts(&plgctx->opts);
 
1274
    if (retval)
 
1275
        goto errout;
 
1276
 
 
1277
    retval = pkinit_init_identity_crypto(&plgctx->idctx);
 
1278
    if (retval)
 
1279
        goto errout;
 
1280
 
 
1281
    retval = pkinit_init_identity_opts(&plgctx->idopts);
 
1282
    if (retval)
 
1283
        goto errout;
 
1284
 
 
1285
    retval = pkinit_init_kdc_profile(context, plgctx);
 
1286
    if (retval)
 
1287
        goto errout;
 
1288
 
 
1289
    retval = pkinit_identity_initialize(context, plgctx->cryptoctx, NULL,
 
1290
                                        plgctx->idopts, plgctx->idctx, 0, NULL);
 
1291
    if (retval)
 
1292
        goto errout;
 
1293
 
 
1294
    pkiDebug("%s: returning context at %p for realm '%s'\n",
 
1295
             __FUNCTION__, plgctx, realmname);
 
1296
    *pplgctx = plgctx;
 
1297
    retval = 0;
 
1298
 
 
1299
errout:
 
1300
    if (retval)
 
1301
        pkinit_server_plugin_fini_realm(context, plgctx);
 
1302
 
 
1303
    return retval;
 
1304
}
 
1305
 
 
1306
static int
 
1307
pkinit_server_plugin_init(krb5_context context,
 
1308
                          krb5_kdcpreauth_moddata *moddata_out,
 
1309
                          const char **realmnames)
 
1310
{
 
1311
    krb5_error_code retval = ENOMEM;
 
1312
    pkinit_kdc_context plgctx, *realm_contexts = NULL;
 
1313
    size_t  i, j;
 
1314
    size_t numrealms;
 
1315
 
 
1316
    retval = pkinit_accessor_init();
 
1317
    if (retval)
 
1318
        return retval;
 
1319
 
 
1320
    /* Determine how many realms we may need to support */
 
1321
    for (i = 0; realmnames[i] != NULL; i++) {};
 
1322
    numrealms = i;
 
1323
 
 
1324
    realm_contexts = calloc(numrealms+1, sizeof(pkinit_kdc_context));
 
1325
    if (realm_contexts == NULL)
 
1326
        return ENOMEM;
 
1327
 
 
1328
    for (i = 0, j = 0; i < numrealms; i++) {
 
1329
        pkiDebug("%s: processing realm '%s'\n", __FUNCTION__, realmnames[i]);
 
1330
        retval = pkinit_server_plugin_init_realm(context, realmnames[i], &plgctx);
 
1331
        if (retval == 0 && plgctx != NULL)
 
1332
            realm_contexts[j++] = plgctx;
 
1333
    }
 
1334
 
 
1335
    if (j == 0) {
 
1336
        retval = EINVAL;
 
1337
        krb5_set_error_message(context, retval,
 
1338
                               _("No realms configured correctly for pkinit "
 
1339
                                 "support"));
 
1340
        goto errout;
 
1341
    }
 
1342
 
 
1343
    *moddata_out = (krb5_kdcpreauth_moddata)realm_contexts;
 
1344
    retval = 0;
 
1345
    pkiDebug("%s: returning context at %p\n", __FUNCTION__, realm_contexts);
 
1346
 
 
1347
errout:
 
1348
    if (retval) {
 
1349
        pkinit_server_plugin_fini(context,
 
1350
                                  (krb5_kdcpreauth_moddata)realm_contexts);
 
1351
    }
 
1352
 
 
1353
    return retval;
 
1354
}
 
1355
 
 
1356
static void
 
1357
pkinit_server_plugin_fini_realm(krb5_context context, pkinit_kdc_context plgctx)
 
1358
{
 
1359
    if (plgctx == NULL)
 
1360
        return;
 
1361
 
 
1362
    pkinit_fini_kdc_profile(context, plgctx);
 
1363
    pkinit_fini_identity_opts(plgctx->idopts);
 
1364
    pkinit_fini_identity_crypto(plgctx->idctx);
 
1365
    pkinit_fini_plg_crypto(plgctx->cryptoctx);
 
1366
    pkinit_fini_plg_opts(plgctx->opts);
 
1367
    free(plgctx->realmname);
 
1368
    free(plgctx);
 
1369
}
 
1370
 
 
1371
static void
 
1372
pkinit_server_plugin_fini(krb5_context context,
 
1373
                          krb5_kdcpreauth_moddata moddata)
 
1374
{
 
1375
    pkinit_kdc_context *realm_contexts = (pkinit_kdc_context *)moddata;
 
1376
    int i;
 
1377
 
 
1378
    if (realm_contexts == NULL)
 
1379
        return;
 
1380
 
 
1381
    for (i = 0; realm_contexts[i] != NULL; i++) {
 
1382
        pkinit_server_plugin_fini_realm(context, realm_contexts[i]);
 
1383
    }
 
1384
    pkiDebug("%s: freeing   context at %p\n", __FUNCTION__, realm_contexts);
 
1385
    free(realm_contexts);
 
1386
}
 
1387
 
 
1388
static krb5_error_code
 
1389
pkinit_init_kdc_req_context(krb5_context context, pkinit_kdc_req_context *ctx)
 
1390
{
 
1391
    krb5_error_code retval = ENOMEM;
 
1392
    pkinit_kdc_req_context reqctx = NULL;
 
1393
 
 
1394
    reqctx = malloc(sizeof(*reqctx));
 
1395
    if (reqctx == NULL)
 
1396
        return retval;
 
1397
    memset(reqctx, 0, sizeof(*reqctx));
 
1398
    reqctx->magic = PKINIT_CTX_MAGIC;
 
1399
 
 
1400
    retval = pkinit_init_req_crypto(&reqctx->cryptoctx);
 
1401
    if (retval)
 
1402
        goto cleanup;
 
1403
    reqctx->rcv_auth_pack = NULL;
 
1404
    reqctx->rcv_auth_pack9 = NULL;
 
1405
 
 
1406
    pkiDebug("%s: returning reqctx at %p\n", __FUNCTION__, reqctx);
 
1407
    *ctx = reqctx;
 
1408
    retval = 0;
 
1409
cleanup:
 
1410
    if (retval)
 
1411
        pkinit_fini_kdc_req_context(context, reqctx);
 
1412
 
 
1413
    return retval;
 
1414
}
 
1415
 
 
1416
static void
 
1417
pkinit_fini_kdc_req_context(krb5_context context, void *ctx)
 
1418
{
 
1419
    pkinit_kdc_req_context reqctx = (pkinit_kdc_req_context)ctx;
 
1420
 
 
1421
    if (reqctx == NULL || reqctx->magic != PKINIT_CTX_MAGIC) {
 
1422
        pkiDebug("pkinit_fini_kdc_req_context: got bad reqctx (%p)!\n", reqctx);
 
1423
        return;
 
1424
    }
 
1425
    pkiDebug("%s: freeing   reqctx at %p\n", __FUNCTION__, reqctx);
 
1426
 
 
1427
    pkinit_fini_req_crypto(reqctx->cryptoctx);
 
1428
    if (reqctx->rcv_auth_pack != NULL)
 
1429
        free_krb5_auth_pack(&reqctx->rcv_auth_pack);
 
1430
    if (reqctx->rcv_auth_pack9 != NULL)
 
1431
        free_krb5_auth_pack_draft9(context, &reqctx->rcv_auth_pack9);
 
1432
 
 
1433
    free(reqctx);
 
1434
}
 
1435
 
 
1436
krb5_error_code
 
1437
kdcpreauth_pkinit_initvt(krb5_context context, int maj_ver, int min_ver,
 
1438
                         krb5_plugin_vtable vtable);
 
1439
 
 
1440
krb5_error_code
 
1441
kdcpreauth_pkinit_initvt(krb5_context context, int maj_ver, int min_ver,
 
1442
                         krb5_plugin_vtable vtable)
 
1443
{
 
1444
    krb5_kdcpreauth_vtable vt;
 
1445
 
 
1446
    if (maj_ver != 1)
 
1447
        return KRB5_PLUGIN_VER_NOTSUPP;
 
1448
    vt = (krb5_kdcpreauth_vtable)vtable;
 
1449
    vt->name = "pkinit";
 
1450
    vt->pa_type_list = supported_server_pa_types;
 
1451
    vt->init = pkinit_server_plugin_init;
 
1452
    vt->fini = pkinit_server_plugin_fini;
 
1453
    vt->flags = pkinit_server_get_flags;
 
1454
    vt->edata = pkinit_server_get_edata;
 
1455
    vt->verify = pkinit_server_verify_padata;
 
1456
    vt->return_padata = pkinit_server_return_padata;
 
1457
    return 0;
 
1458
}