~ubuntu-branches/ubuntu/precise/krb5/precise-updates

« back to all changes in this revision

Viewing changes to src/kdc/kdc_preauth_ec.c

  • Committer: Package Import Robot
  • Author(s): Sam Hartman
  • Date: 2011-12-01 19:34:41 UTC
  • mfrom: (28.1.14 sid)
  • Revision ID: package-import@ubuntu.com-20111201193441-9tipg3aru1jsidyv
Tags: 1.10+dfsg~alpha1-6
* Fix segfault with unknown hostnames in krb5_sname_to_principal,
  Closes: #650671
* Indicate that this library breaks libsmbclient versions that depend on
  krb5_locate_kdc, Closes: #650603, #650611

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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/preauth_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
    (*respond)(arg, (armor_key == NULL) ? ENOENT : 0, NULL);
 
44
}
 
45
 
 
46
static void
 
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)
 
52
{
 
53
    krb5_error_code retval = 0;
 
54
    krb5_timestamp now;
 
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;
 
63
    int i = 0;
 
64
 
 
65
    plain.data = NULL;
 
66
 
 
67
    if (armor_key == NULL) {
 
68
        retval = ENOENT;
 
69
        krb5_set_error_message(context, ENOENT,
 
70
                               _("Encrypted Challenge used outside of FAST "
 
71
                                 "tunnel"));
 
72
    }
 
73
    scratch.data = (char *) data->contents;
 
74
    scratch.length = data->length;
 
75
    if (retval == 0)
 
76
        retval = decode_krb5_enc_data(&scratch, &enc);
 
77
    if (retval == 0) {
 
78
        plain.data =  malloc(enc->ciphertext.length);
 
79
        plain.length = enc->ciphertext.length;
 
80
        if (plain.data == NULL)
 
81
            retval = ENOMEM;
 
82
    }
 
83
    if (retval == 0)
 
84
        retval = cb->client_keys(context, rock, &client_keys);
 
85
    if (retval == 0) {
 
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",
 
90
                                          &challenge_key);
 
91
            if (retval == 0)
 
92
                retval  = krb5_c_decrypt(context, challenge_key,
 
93
                                         KRB5_KEYUSAGE_ENC_CHALLENGE_CLIENT,
 
94
                                         NULL, enc, &plain);
 
95
            if (challenge_key)
 
96
                krb5_free_keyblock(context, challenge_key);
 
97
            challenge_key = NULL;
 
98
            if (retval == 0)
 
99
                break;
 
100
            /*We failed to decrypt. Try next key*/
 
101
            retval = 0;
 
102
        }
 
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 "
 
107
                                     "challenge"));
 
108
        }
 
109
    }
 
110
    if (retval == 0)
 
111
        retval = decode_krb5_pa_enc_ts(&plain, &ts);
 
112
    if (retval == 0)
 
113
        retval = krb5_timeofday(context, &now);
 
114
    if (retval == 0) {
 
115
        if (labs(now-ts->patimestamp) < context->clockskew) {
 
116
            enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH;
 
117
            /*
 
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.
 
121
             */
 
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;
 
126
        } else { /*skew*/
 
127
            retval = KRB5KRB_AP_ERR_SKEW;
 
128
        }
 
129
    }
 
130
    cb->free_keys(context, rock, client_keys);
 
131
    if (plain.data)
 
132
        free(plain.data);
 
133
    if (enc)
 
134
        krb5_free_enc_data(context, enc);
 
135
    if (ts)
 
136
        krb5_free_pa_enc_ts(context, ts);
 
137
 
 
138
    (*respond)(arg, retval, modreq, NULL, NULL);
 
139
}
 
140
 
 
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)
 
147
{
 
148
    krb5_error_code retval = 0;
 
149
    krb5_keyblock *challenge_key = (krb5_keyblock *)modreq;
 
150
    krb5_pa_enc_ts ts;
 
151
    krb5_data *plain = NULL;
 
152
    krb5_enc_data enc;
 
153
    krb5_data *encoded = NULL;
 
154
    krb5_pa_data *pa = NULL;
 
155
 
 
156
    if (challenge_key == NULL)
 
157
        return 0;
 
158
    enc.ciphertext.data = NULL; /* In case of error pass through */
 
159
 
 
160
    retval = krb5_us_timeofday(context, &ts.patimestamp, &ts.pausec);
 
161
    if (retval == 0)
 
162
        retval = encode_krb5_pa_enc_ts(&ts, &plain);
 
163
    if (retval == 0)
 
164
        retval = krb5_encrypt_helper(context, challenge_key,
 
165
                                     KRB5_KEYUSAGE_ENC_CHALLENGE_KDC,
 
166
                                     plain, &enc);
 
167
    if (retval == 0)
 
168
        retval = encode_krb5_enc_data(&enc, &encoded);
 
169
    if (retval == 0) {
 
170
        pa = calloc(1, sizeof(krb5_pa_data));
 
171
        if (pa == NULL)
 
172
            retval = ENOMEM;
 
173
    }
 
174
    if (retval == 0) {
 
175
        pa->pa_type = KRB5_PADATA_ENCRYPTED_CHALLENGE;
 
176
        pa->contents = (unsigned char *) encoded->data;
 
177
        pa->length = encoded->length;
 
178
        encoded->data = NULL;
 
179
        *send_pa = pa;
 
180
        pa = NULL;
 
181
    }
 
182
    if (challenge_key)
 
183
        krb5_free_keyblock(context, challenge_key);
 
184
    if (encoded)
 
185
        krb5_free_data(context, encoded);
 
186
    if (plain)
 
187
        krb5_free_data(context, plain);
 
188
    if (enc.ciphertext.data)
 
189
        krb5_free_data_contents(context, &enc.ciphertext);
 
190
    return retval;
 
191
}
 
192
 
 
193
static krb5_preauthtype ec_types[] = {
 
194
    KRB5_PADATA_ENCRYPTED_CHALLENGE, 0};
 
195
 
 
196
krb5_error_code
 
197
kdcpreauth_encrypted_challenge_initvt(krb5_context context, int maj_ver,
 
198
                                      int min_ver, krb5_plugin_vtable vtable)
 
199
{
 
200
    krb5_kdcpreauth_vtable vt;
 
201
 
 
202
    if (maj_ver != 1)
 
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;
 
210
    return 0;
 
211
}