~ubuntu-branches/ubuntu/maverick/krb5/maverick

« back to all changes in this revision

Viewing changes to src/plugins/preauth/pkinit/pkinit_srv.c

  • Committer: Bazaar Package Importer
  • Author(s): Sam Hartman, Russ Allbery, Sam Hartman
  • Date: 2008-08-21 10:41:41 UTC
  • mfrom: (11.1.15 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080821104141-a0f9c4o4cpo8xd0o
Tags: 1.6.dfsg.4~beta1-4
[ Russ Allbery ]
* Translation updates:
  - Swedish, thanks Martin Bagge.  (Closes: #487669, #491774)
  - Italian, thanks Luca Monducci.  (Closes: #493962)

[ Sam Hartman ]
* Translation Updates:
    - Dutch, Thanks Vincent Zweije, Closes: #495733

Show diffs side-by-side

added added

removed removed

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