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;
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;
92 swb.body = &safe_body;
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);
133 krb5_error_code KRB5_CALLCONV
134 krb5_rd_safe(krb5_context context, krb5_auth_context auth_context,
135 const krb5_data *inbuf, krb5_data *outbuf,
136 krb5_replay_data *outdata)
138 krb5_error_code retval;
140 krb5_replay_data replaydata;
142 if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
143 (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) &&
145 /* Need a better error */
146 return KRB5_RC_REQUIRED;
148 if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) &&
149 (auth_context->rcache == NULL))
150 return KRB5_RC_REQUIRED;
152 if (!auth_context->remote_addr)
153 return KRB5_REMOTE_ADDR_REQUIRED;
156 if ((key = auth_context->recv_subkey) == NULL)
157 key = auth_context->key;
159 memset(&replaydata, 0, sizeof(replaydata));
160 retval = rd_safe_basic(context, auth_context, inbuf, key, &replaydata,
165 if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) {
166 krb5_donot_replay replay;
168 if ((retval = krb5int_check_clockskew(context, replaydata.timestamp)))
171 if ((retval = krb5_gen_replay_name(context, auth_context->remote_addr,
172 "_safe", &replay.client)))
175 replay.server = ""; /* XXX */
176 replay.msghash = NULL;
177 replay.cusec = replaydata.usec;
178 replay.ctime = replaydata.timestamp;
179 if ((retval = krb5_rc_store(context, auth_context->rcache, &replay))) {
186 if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) {
187 if (!k5_privsafe_check_seqnum(context, auth_context, replaydata.seq)) {
188 retval = KRB5KRB_AP_ERR_BADORDER;
191 auth_context->remote_seq_number++;
194 if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
195 (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) {
196 outdata->timestamp = replaydata.timestamp;
197 outdata->usec = replaydata.usec;
198 outdata->seq = replaydata.seq;
201 /* everything is ok - return data to the user */