Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/krb5/src/kdc/kdc_preauth_ec.c
34879 views
1
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
/* kdc/kdc_preauth_ec.c - Encrypted challenge kdcpreauth module */
3
/*
4
* Copyright (C) 2009 by the Massachusetts Institute of Technology.
5
* All rights reserved.
6
*
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.
11
*
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.
25
*/
26
27
/*
28
* Implement Encrypted Challenge fast factor from
29
* draft-ietf-krb-wg-preauth-framework
30
*/
31
32
#include <k5-int.h>
33
#include <krb5/kdcpreauth_plugin.h>
34
#include "kdc_util.h"
35
36
static void
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)
41
{
42
krb5_keyblock *armor_key = cb->fast_armor(context, rock);
43
44
/* Encrypted challenge only works with FAST, and requires a client key. */
45
if (armor_key == NULL || !cb->have_client_keys(context, rock))
46
(*respond)(arg, ENOENT, NULL);
47
else
48
(*respond)(arg, 0, NULL);
49
}
50
51
static void
52
ec_verify(krb5_context context, krb5_data *req_pkt, krb5_kdc_req *request,
53
krb5_enc_tkt_part *enc_tkt_reply, krb5_pa_data *data,
54
krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
55
krb5_kdcpreauth_moddata moddata,
56
krb5_kdcpreauth_verify_respond_fn respond, void *arg)
57
{
58
krb5_error_code ret;
59
krb5_enc_data *enc = NULL;
60
krb5_data der_enc_ts = empty_data(), der_enc_data;
61
krb5_keyblock *armor_key = cb->fast_armor(context, rock);
62
krb5_pa_enc_ts *ts = NULL;
63
krb5_keyblock *client_keys = NULL;
64
krb5_keyblock *challenge_key = NULL;
65
krb5_keyblock *kdc_challenge_key;
66
krb5_kdcpreauth_modreq modreq = NULL;
67
int i = 0;
68
char *ai = NULL, *realmstr = NULL;
69
krb5_data realm = request->server->realm;
70
71
if (armor_key == NULL) {
72
ret = ENOENT;
73
k5_setmsg(context, ret,
74
_("Encrypted Challenge used outside of FAST tunnel"));
75
goto cleanup;
76
}
77
78
der_enc_data = make_data(data->contents, data->length);
79
ret = decode_krb5_enc_data(&der_enc_data, &enc);
80
if (ret)
81
goto cleanup;
82
83
ret = alloc_data(&der_enc_ts, enc->ciphertext.length);
84
if (ret)
85
goto cleanup;
86
87
/* Check for a configured auth indicator. */
88
realmstr = k5memdup0(realm.data, realm.length, &ret);
89
if (realmstr == NULL)
90
goto cleanup;
91
ret = profile_get_string(context->profile, KRB5_CONF_REALMS, realmstr,
92
KRB5_CONF_ENCRYPTED_CHALLENGE_INDICATOR, NULL,
93
&ai);
94
if (ret)
95
goto cleanup;
96
97
ret = cb->client_keys(context, rock, &client_keys);
98
if (ret)
99
goto cleanup;
100
for (i = 0; client_keys[i].enctype != ENCTYPE_NULL; i++) {
101
ret = krb5_c_fx_cf2_simple(context, armor_key, "clientchallengearmor",
102
&client_keys[i], "challengelongterm",
103
&challenge_key);
104
if (ret)
105
goto cleanup;
106
ret = krb5_c_decrypt(context, challenge_key,
107
KRB5_KEYUSAGE_ENC_CHALLENGE_CLIENT, NULL, enc,
108
&der_enc_ts);
109
krb5_free_keyblock(context, challenge_key);
110
if (!ret)
111
break;
112
}
113
114
if (client_keys[i].enctype == ENCTYPE_NULL) {
115
ret = KRB5KDC_ERR_PREAUTH_FAILED;
116
k5_setmsg(context, ret,
117
_("Incorrect password in encrypted challenge"));
118
goto cleanup;
119
}
120
121
ret = decode_krb5_pa_enc_ts(&der_enc_ts, &ts);
122
if (ret)
123
goto cleanup;
124
ret = krb5_check_clockskew(context, ts->patimestamp);
125
if (ret)
126
goto cleanup;
127
128
enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH;
129
130
/*
131
* If this fails, we won't generate a reply to the client. That may cause
132
* the client to fail, but at this point the KDC has considered this a
133
* success, so the return value is ignored.
134
*/
135
if (krb5_c_fx_cf2_simple(context, armor_key, "kdcchallengearmor",
136
&client_keys[i], "challengelongterm",
137
&kdc_challenge_key) == 0) {
138
modreq = (krb5_kdcpreauth_modreq)kdc_challenge_key;
139
if (ai != NULL)
140
cb->add_auth_indicator(context, rock, ai);
141
}
142
143
cleanup:
144
cb->free_keys(context, rock, client_keys);
145
free(der_enc_ts.data);
146
krb5_free_enc_data(context, enc);
147
krb5_free_pa_enc_ts(context, ts);
148
free(realmstr);
149
free(ai);
150
151
(*respond)(arg, ret, modreq, NULL, NULL);
152
}
153
154
static krb5_error_code
155
ec_return(krb5_context context, krb5_pa_data *padata, krb5_data *req_pkt,
156
krb5_kdc_req *request, krb5_kdc_rep *reply,
157
krb5_keyblock *encrypting_key, krb5_pa_data **send_pa,
158
krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
159
krb5_kdcpreauth_moddata moddata, krb5_kdcpreauth_modreq modreq)
160
{
161
krb5_error_code ret;
162
krb5_keyblock *challenge_key = (krb5_keyblock *)modreq;
163
krb5_pa_enc_ts ts;
164
krb5_data *der_enc_ts = NULL, *der_enc_data = NULL;
165
krb5_enc_data enc;
166
krb5_pa_data *pa = NULL;
167
168
enc.ciphertext.data = NULL;
169
170
if (challenge_key == NULL)
171
return 0;
172
173
ret = krb5_us_timeofday(context, &ts.patimestamp, &ts.pausec);
174
if (ret)
175
goto cleanup;
176
ret = encode_krb5_pa_enc_ts(&ts, &der_enc_ts);
177
if (ret)
178
goto cleanup;
179
ret = krb5_encrypt_helper(context, challenge_key,
180
KRB5_KEYUSAGE_ENC_CHALLENGE_KDC, der_enc_ts,
181
&enc);
182
if (ret)
183
goto cleanup;
184
ret = encode_krb5_enc_data(&enc, &der_enc_data);
185
if (ret)
186
goto cleanup;
187
188
pa = k5alloc(sizeof(*pa), &ret);
189
if (pa == NULL)
190
goto cleanup;
191
pa->pa_type = KRB5_PADATA_ENCRYPTED_CHALLENGE;
192
pa->length = der_enc_data->length;
193
/* Steal the data pointer from der_enc_data. */
194
pa->contents = (unsigned char *)der_enc_data->data;
195
der_enc_data->data = NULL;
196
197
*send_pa = pa;
198
199
cleanup:
200
krb5_free_keyblock(context, challenge_key);
201
krb5_free_data(context, der_enc_data);
202
krb5_free_data(context, der_enc_ts);
203
krb5_free_data_contents(context, &enc.ciphertext);
204
return ret;
205
}
206
207
static krb5_preauthtype ec_types[] = {
208
KRB5_PADATA_ENCRYPTED_CHALLENGE, 0};
209
210
krb5_error_code
211
kdcpreauth_encrypted_challenge_initvt(krb5_context context, int maj_ver,
212
int min_ver, krb5_plugin_vtable vtable)
213
{
214
krb5_kdcpreauth_vtable vt;
215
216
if (maj_ver != 1)
217
return KRB5_PLUGIN_VER_NOTSUPP;
218
vt = (krb5_kdcpreauth_vtable)vtable;
219
vt->name = "encrypted_challenge";
220
vt->pa_type_list = ec_types;
221
vt->edata = ec_edata;
222
vt->verify = ec_verify;
223
vt->return_padata = ec_return;
224
return 0;
225
}
226
227