2 * lib/krb5/krb/rd_safe.c
4 * Copyright 1990,1991 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. M.I.T. makes no representations about the suitability of
20 * this software for any purpose. It is provided "as is" without express
21 * or implied warranty.
30 extern krb5_deltat krb5_clockskew;
31 #define in_clock_skew(date) (labs((date)-currenttime) < krb5_clockskew)
34 parses a KRB_SAFE message from inbuf, placing the integrity-protected user
37 key specifies the key to be used for decryption of the message.
39 sender_addr and recv_addr specify the full addresses (host and port) of
40 the sender and receiver.
42 outbuf points to allocated storage which the caller should free when finished.
44 returns system errors, integrity errors
46 static krb5_error_code
47 krb5_rd_safe_basic(context, inbuf, keyblock, recv_addr, sender_addr,
50 const krb5_data * inbuf;
51 const krb5_keyblock * keyblock;
52 const krb5_address * recv_addr;
53 const krb5_address * sender_addr;
54 krb5_replay_data * replaydata;
57 krb5_error_code retval;
59 krb5_checksum our_cksum, *his_cksum;
60 krb5_octet zero_octet = 0;
63 if (!krb5_is_krb_safe(inbuf))
64 return KRB5KRB_AP_ERR_MSG_TYPE;
66 if (retval = decode_krb5_safe(inbuf, &message))
69 if (!valid_cksumtype(message->checksum->checksum_type)) {
70 retval = KRB5_PROG_SUMTYPE_NOSUPP;
73 if (!is_coll_proof_cksum(message->checksum->checksum_type) ||
74 !is_keyed_cksum(message->checksum->checksum_type)) {
75 retval = KRB5KRB_AP_ERR_INAPP_CKSUM;
79 if (!krb5_address_compare(context, sender_addr, message->s_address)) {
80 retval = KRB5KRB_AP_ERR_BADADDR;
84 if (message->r_address) {
86 if (!krb5_address_compare(context, recv_addr, message->r_address)) {
87 retval = KRB5KRB_AP_ERR_BADADDR;
91 krb5_address **our_addrs;
93 if (retval = krb5_os_localaddr( &our_addrs))
96 if (!krb5_address_search(context, message->r_address, our_addrs)) {
97 krb5_free_addresses(context, our_addrs);
98 retval = KRB5KRB_AP_ERR_BADADDR;
101 krb5_free_addresses(context, our_addrs);
105 /* verify the checksum */
106 /* to do the checksum stuff, we need to re-encode the message with a
107 zero-length zero-type checksum, then checksum the encoding, and verify.
109 his_cksum = message->checksum;
111 our_cksum.length = 0;
112 our_cksum.checksum_type = 0;
113 our_cksum.contents = &zero_octet;
115 message->checksum = &our_cksum;
117 if (retval = encode_krb5_safe(message, &scratch))
120 message->checksum = his_cksum;
122 if (!(our_cksum.contents = (krb5_octet *)
123 malloc(krb5_checksum_size(context, his_cksum->checksum_type)))) {
128 retval = krb5_calculate_checksum(context, his_cksum->checksum_type,
129 scratch->data, scratch->length,
130 (krb5_pointer) keyblock->contents,
131 keyblock->length, &our_cksum);
132 (void) memset((char *)scratch->data, 0, scratch->length);
133 krb5_free_data(context, scratch);
139 if (our_cksum.length != his_cksum->length ||
140 memcmp((char *)our_cksum.contents, (char *)his_cksum->contents,
142 retval = KRB5KRB_AP_ERR_MODIFIED;
146 replaydata->timestamp = message->timestamp;
147 replaydata->usec = message->usec;
148 replaydata->seq = message->seq_number;
150 *outbuf = message->user_data;
151 message->user_data.data = NULL;
153 krb5_free_checksum(context, his_cksum);
157 krb5_xfree(our_cksum.contents);
160 krb5_free_safe(context, message);
165 krb5_rd_safe(context, auth_context, inbuf, outbuf, outdata)
166 krb5_context context;
167 krb5_auth_context * auth_context;
168 const krb5_data * inbuf;
170 krb5_replay_data * outdata;
172 krb5_error_code retval;
173 krb5_replay_data replaydata;
175 if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
176 (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) &&
178 /* Need a better error */
179 return KRB5_RC_REQUIRED;
181 if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) &&
182 (auth_context->rcache == NULL))
183 return KRB5_RC_REQUIRED;
185 if (retval = krb5_rd_safe_basic(context, inbuf, auth_context->keyblock,
186 auth_context->local_addr, auth_context->remote_addr,
187 &replaydata, outbuf))
190 if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) {
191 krb5_donot_replay replay;
192 krb5_timestamp currenttime;
194 if (retval = krb5_timeofday(context, ¤ttime))
197 if (!in_clock_skew(replaydata.timestamp)) {
198 retval = KRB5KRB_AP_ERR_SKEW;
202 if (retval = krb5_gen_replay_name(context, auth_context->remote_addr,
203 "_safe", &replay.client))
206 replay.server = ""; /* XXX */
207 replay.cusec = replaydata.usec;
208 replay.ctime = replaydata.timestamp;
209 if (retval = krb5_rc_store(context, auth_context->rcache, &replay)) {
210 krb5_xfree(replay.client);
213 krb5_xfree(replay.client);
216 if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) {
217 if (auth_context->remote_seq_number != replaydata.seq) {
218 retval = KRB5KRB_AP_ERR_BADORDER;
223 if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
224 (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) {
225 outdata->timestamp = replaydata.timestamp;
226 outdata->usec = replaydata.usec;
227 outdata->seq = replaydata.seq;
230 /* everything is ok - return data to the user */
234 krb5_xfree(outbuf->data);