1
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
/* kdc/kdc_preauth_ec.c - Encrypted challenge kdcpreauth module */
4
* Copyright (C) 2009 by the Massachusetts Institute of Technology.
7
* Export of this software from the United States of America may
8
* require a specific license from the United States Government.
9
* It is the responsibility of any person or organization contemplating
10
* export to obtain such a license before exporting.
12
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13
* distribute this software and its documentation for any purpose and
14
* without fee is hereby granted, provided that the above copyright
15
* notice appear in all copies and that both that copyright notice and
16
* this permission notice appear in supporting documentation, and that
17
* the name of M.I.T. not be used in advertising or publicity pertaining
18
* to distribution of the software without specific, written prior
19
* permission. Furthermore if you modify this software you must label
20
* your software as modified software and not distribute it in such a
21
* fashion that it might be confused with the original M.I.T. software.
22
* M.I.T. makes no representations about the suitability of
23
* this software for any purpose. It is provided "as is" without express
24
* or implied warranty.
28
* Implement Encrypted Challenge fast factor from
29
* draft-ietf-krb-wg-preauth-framework
33
#include <krb5/preauth_plugin.h>
37
ec_edata(krb5_context context, krb5_kdc_req *request,
38
krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
39
krb5_kdcpreauth_moddata moddata, krb5_preauthtype pa_type,
40
krb5_kdcpreauth_edata_respond_fn respond, void *arg)
42
krb5_keyblock *armor_key = cb->fast_armor(context, rock);
43
(*respond)(arg, (armor_key == NULL) ? ENOENT : 0, NULL);
47
ec_verify(krb5_context context, krb5_data *req_pkt, krb5_kdc_req *request,
48
krb5_enc_tkt_part *enc_tkt_reply, krb5_pa_data *data,
49
krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
50
krb5_kdcpreauth_moddata moddata,
51
krb5_kdcpreauth_verify_respond_fn respond, void *arg)
53
krb5_error_code retval = 0;
55
krb5_enc_data *enc = NULL;
56
krb5_data scratch, plain;
57
krb5_keyblock *armor_key = cb->fast_armor(context, rock);
58
krb5_pa_enc_ts *ts = NULL;
59
krb5_keyblock *client_keys = NULL;
60
krb5_keyblock *challenge_key = NULL;
61
krb5_keyblock *kdc_challenge_key;
62
krb5_kdcpreauth_modreq modreq = NULL;
67
if (armor_key == NULL) {
69
krb5_set_error_message(context, ENOENT,
70
_("Encrypted Challenge used outside of FAST "
73
scratch.data = (char *) data->contents;
74
scratch.length = data->length;
76
retval = decode_krb5_enc_data(&scratch, &enc);
78
plain.data = malloc(enc->ciphertext.length);
79
plain.length = enc->ciphertext.length;
80
if (plain.data == NULL)
84
retval = cb->client_keys(context, rock, &client_keys);
86
for (i = 0; client_keys[i].enctype&& (retval == 0); i++ ) {
87
retval = krb5_c_fx_cf2_simple(context,
88
armor_key, "clientchallengearmor",
89
&client_keys[i], "challengelongterm",
92
retval = krb5_c_decrypt(context, challenge_key,
93
KRB5_KEYUSAGE_ENC_CHALLENGE_CLIENT,
96
krb5_free_keyblock(context, challenge_key);
100
/*We failed to decrypt. Try next key*/
103
if (client_keys[i].enctype == 0) {
104
retval = KRB5KDC_ERR_PREAUTH_FAILED;
105
krb5_set_error_message(context, retval,
106
_("Incorrect password in encrypted "
111
retval = decode_krb5_pa_enc_ts(&plain, &ts);
113
retval = krb5_timeofday(context, &now);
115
if (labs(now-ts->patimestamp) < context->clockskew) {
116
enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH;
118
* If this fails, we won't generate a reply to the client. That
119
* may cause the client to fail, but at this point the KDC has
120
* considered this a success, so the return value is ignored.
122
if (krb5_c_fx_cf2_simple(context, armor_key, "kdcchallengearmor",
123
&client_keys[i], "challengelongterm",
124
&kdc_challenge_key) == 0)
125
modreq = (krb5_kdcpreauth_modreq)kdc_challenge_key;
127
retval = KRB5KRB_AP_ERR_SKEW;
130
cb->free_keys(context, rock, client_keys);
134
krb5_free_enc_data(context, enc);
136
krb5_free_pa_enc_ts(context, ts);
138
(*respond)(arg, retval, modreq, NULL, NULL);
141
static krb5_error_code
142
ec_return(krb5_context context, krb5_pa_data *padata, krb5_data *req_pkt,
143
krb5_kdc_req *request, krb5_kdc_rep *reply,
144
krb5_keyblock *encrypting_key, krb5_pa_data **send_pa,
145
krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
146
krb5_kdcpreauth_moddata moddata, krb5_kdcpreauth_modreq modreq)
148
krb5_error_code retval = 0;
149
krb5_keyblock *challenge_key = (krb5_keyblock *)modreq;
151
krb5_data *plain = NULL;
153
krb5_data *encoded = NULL;
154
krb5_pa_data *pa = NULL;
156
if (challenge_key == NULL)
158
enc.ciphertext.data = NULL; /* In case of error pass through */
160
retval = krb5_us_timeofday(context, &ts.patimestamp, &ts.pausec);
162
retval = encode_krb5_pa_enc_ts(&ts, &plain);
164
retval = krb5_encrypt_helper(context, challenge_key,
165
KRB5_KEYUSAGE_ENC_CHALLENGE_KDC,
168
retval = encode_krb5_enc_data(&enc, &encoded);
170
pa = calloc(1, sizeof(krb5_pa_data));
175
pa->pa_type = KRB5_PADATA_ENCRYPTED_CHALLENGE;
176
pa->contents = (unsigned char *) encoded->data;
177
pa->length = encoded->length;
178
encoded->data = NULL;
183
krb5_free_keyblock(context, challenge_key);
185
krb5_free_data(context, encoded);
187
krb5_free_data(context, plain);
188
if (enc.ciphertext.data)
189
krb5_free_data_contents(context, &enc.ciphertext);
193
static krb5_preauthtype ec_types[] = {
194
KRB5_PADATA_ENCRYPTED_CHALLENGE, 0};
197
kdcpreauth_encrypted_challenge_initvt(krb5_context context, int maj_ver,
198
int min_ver, krb5_plugin_vtable vtable)
200
krb5_kdcpreauth_vtable vt;
203
return KRB5_PLUGIN_VER_NOTSUPP;
204
vt = (krb5_kdcpreauth_vtable)vtable;
205
vt->name = "encrypted_challenge";
206
vt->pa_type_list = ec_types;
207
vt->edata = ec_edata;
208
vt->verify = ec_verify;
209
vt->return_padata = ec_return;