1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/krb5/krb/rd_safe.c - definition of krb5_rd_safe() */
4 * Copyright 1990,1991,2007,2008 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 #include "int-proto.h"
33 parses a KRB_SAFE message from inbuf, placing the integrity-protected user
36 key specifies the key to be used for decryption of the message.
38 outbuf points to allocated storage which the caller should free when finished.
40 returns system errors, integrity errors
42 static krb5_error_code
43 rd_safe_basic(krb5_context context, krb5_auth_context ac,
44 const krb5_data *inbuf, krb5_key key,
45 krb5_replay_data *replaydata, krb5_data *outbuf)
47 krb5_error_code retval;
49 krb5_data *safe_body = NULL;
50 krb5_checksum our_cksum, *his_cksum;
51 krb5_octet zero_octet = 0;
54 struct krb5_safe_with_body swb;
56 if (!krb5_is_krb_safe(inbuf))
57 return KRB5KRB_AP_ERR_MSG_TYPE;
59 if ((retval = decode_krb5_safe_with_body(inbuf, &message, &safe_body)))
62 if (!krb5_c_valid_cksumtype(message->checksum->checksum_type)) {
63 retval = KRB5_PROG_SUMTYPE_NOSUPP;
66 if (!krb5_c_is_coll_proof_cksum(message->checksum->checksum_type) ||
67 !krb5_c_is_keyed_cksum(message->checksum->checksum_type)) {
68 retval = KRB5KRB_AP_ERR_INAPP_CKSUM;
72 retval = k5_privsafe_check_addrs(context, ac, message->s_address,
77 /* verify the checksum */
79 * In order to recreate what was checksummed, we regenerate the message
80 * without checksum and then have the cryptographic subsystem verify
81 * the checksum for us. This is because some checksum methods have
82 * a confounder encrypted as part of the checksum.
84 his_cksum = message->checksum;
87 our_cksum.checksum_type = 0;
88 our_cksum.contents = &zero_octet;
90 message->checksum = &our_cksum;
94 retval = encode_krb5_safe_with_body(&swb, &scratch);
95 message->checksum = his_cksum;
99 retval = krb5_k_verify_checksum(context, key,
100 KRB5_KEYUSAGE_KRB_SAFE_CKSUM,
101 scratch, his_cksum, &valid);
103 (void) memset(scratch->data, 0, scratch->length);
104 krb5_free_data(context, scratch);
108 * Checksum over only the KRB-SAFE-BODY, like RFC 1510 says, in
109 * case someone actually implements it correctly.
111 retval = krb5_k_verify_checksum(context, key,
112 KRB5_KEYUSAGE_KRB_SAFE_CKSUM,
113 safe_body, his_cksum, &valid);
115 retval = KRB5KRB_AP_ERR_MODIFIED;
120 replaydata->timestamp = message->timestamp;
121 replaydata->usec = message->usec;
122 replaydata->seq = message->seq_number;
124 *outbuf = message->user_data;
125 message->user_data.data = NULL;
129 krb5_free_safe(context, message);
130 krb5_free_data(context, safe_body);
134 krb5_error_code KRB5_CALLCONV
135 krb5_rd_safe(krb5_context context, krb5_auth_context auth_context,
136 const krb5_data *inbuf, krb5_data *outbuf,
137 krb5_replay_data *outdata)
139 krb5_error_code retval;
141 krb5_replay_data replaydata;
143 if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
144 (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) &&
146 /* Need a better error */
147 return KRB5_RC_REQUIRED;
149 if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) &&
150 (auth_context->remote_addr == NULL))
151 return KRB5_REMOTE_ADDR_REQUIRED;
153 if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) &&
154 (auth_context->rcache == NULL))
155 return KRB5_RC_REQUIRED;
158 if ((key = auth_context->recv_subkey) == NULL)
159 key = auth_context->key;
161 memset(&replaydata, 0, sizeof(replaydata));
162 retval = rd_safe_basic(context, auth_context, inbuf, key, &replaydata,
167 if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) {
168 krb5_donot_replay replay;
170 if ((retval = krb5_check_clockskew(context, replaydata.timestamp)))
173 if ((retval = krb5_gen_replay_name(context, auth_context->remote_addr,
174 "_safe", &replay.client)))
177 replay.server = ""; /* XXX */
178 replay.msghash = NULL;
179 replay.cusec = replaydata.usec;
180 replay.ctime = replaydata.timestamp;
181 if ((retval = krb5_rc_store(context, auth_context->rcache, &replay))) {
188 if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) {
189 if (!k5_privsafe_check_seqnum(context, auth_context, replaydata.seq)) {
190 retval = KRB5KRB_AP_ERR_BADORDER;
193 auth_context->remote_seq_number++;
196 if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
197 (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) {
198 outdata->timestamp = replaydata.timestamp;
199 outdata->usec = replaydata.usec;
200 outdata->seq = replaydata.seq;
203 /* everything is ok - return data to the user */