1*d3273b5bSchristos /* $NetBSD: rd_safe.c,v 1.2 2017/01/28 21:31:49 christos Exp $ */
2ca1c9b0cSelric
3ca1c9b0cSelric /*
4ca1c9b0cSelric * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
5ca1c9b0cSelric * (Royal Institute of Technology, Stockholm, Sweden).
6ca1c9b0cSelric * All rights reserved.
7ca1c9b0cSelric *
8ca1c9b0cSelric * Redistribution and use in source and binary forms, with or without
9ca1c9b0cSelric * modification, are permitted provided that the following conditions
10ca1c9b0cSelric * are met:
11ca1c9b0cSelric *
12ca1c9b0cSelric * 1. Redistributions of source code must retain the above copyright
13ca1c9b0cSelric * notice, this list of conditions and the following disclaimer.
14ca1c9b0cSelric *
15ca1c9b0cSelric * 2. Redistributions in binary form must reproduce the above copyright
16ca1c9b0cSelric * notice, this list of conditions and the following disclaimer in the
17ca1c9b0cSelric * documentation and/or other materials provided with the distribution.
18ca1c9b0cSelric *
19ca1c9b0cSelric * 3. Neither the name of the Institute nor the names of its contributors
20ca1c9b0cSelric * may be used to endorse or promote products derived from this software
21ca1c9b0cSelric * without specific prior written permission.
22ca1c9b0cSelric *
23ca1c9b0cSelric * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24ca1c9b0cSelric * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25ca1c9b0cSelric * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26ca1c9b0cSelric * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27ca1c9b0cSelric * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28ca1c9b0cSelric * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29ca1c9b0cSelric * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30ca1c9b0cSelric * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31ca1c9b0cSelric * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32ca1c9b0cSelric * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33ca1c9b0cSelric * SUCH DAMAGE.
34ca1c9b0cSelric */
35ca1c9b0cSelric
36ca1c9b0cSelric #include "krb5_locl.h"
37ca1c9b0cSelric
38ca1c9b0cSelric static krb5_error_code
verify_checksum(krb5_context context,krb5_auth_context auth_context,KRB_SAFE * safe)39ca1c9b0cSelric verify_checksum(krb5_context context,
40ca1c9b0cSelric krb5_auth_context auth_context,
41ca1c9b0cSelric KRB_SAFE *safe)
42ca1c9b0cSelric {
43ca1c9b0cSelric krb5_error_code ret;
44ca1c9b0cSelric u_char *buf;
45ca1c9b0cSelric size_t buf_size;
464f77a458Spettai size_t len = 0;
47ca1c9b0cSelric Checksum c;
48ca1c9b0cSelric krb5_crypto crypto;
49ca1c9b0cSelric krb5_keyblock *key;
50ca1c9b0cSelric
51ca1c9b0cSelric c = safe->cksum;
52ca1c9b0cSelric safe->cksum.cksumtype = 0;
53ca1c9b0cSelric safe->cksum.checksum.data = NULL;
54ca1c9b0cSelric safe->cksum.checksum.length = 0;
55ca1c9b0cSelric
56ca1c9b0cSelric ASN1_MALLOC_ENCODE(KRB_SAFE, buf, buf_size, safe, &len, ret);
57ca1c9b0cSelric if(ret)
58ca1c9b0cSelric return ret;
59ca1c9b0cSelric if(buf_size != len)
60ca1c9b0cSelric krb5_abortx(context, "internal error in ASN.1 encoder");
61ca1c9b0cSelric
62ca1c9b0cSelric if (auth_context->remote_subkey)
63ca1c9b0cSelric key = auth_context->remote_subkey;
64ca1c9b0cSelric else if (auth_context->local_subkey)
65ca1c9b0cSelric key = auth_context->local_subkey;
66ca1c9b0cSelric else
67ca1c9b0cSelric key = auth_context->keyblock;
68ca1c9b0cSelric
69ca1c9b0cSelric ret = krb5_crypto_init(context, key, 0, &crypto);
70ca1c9b0cSelric if (ret)
71ca1c9b0cSelric goto out;
72ca1c9b0cSelric ret = krb5_verify_checksum (context,
73ca1c9b0cSelric crypto,
74ca1c9b0cSelric KRB5_KU_KRB_SAFE_CKSUM,
75ca1c9b0cSelric buf + buf_size - len,
76ca1c9b0cSelric len,
77ca1c9b0cSelric &c);
78ca1c9b0cSelric krb5_crypto_destroy(context, crypto);
79ca1c9b0cSelric out:
80ca1c9b0cSelric safe->cksum = c;
81ca1c9b0cSelric free (buf);
82ca1c9b0cSelric return ret;
83ca1c9b0cSelric }
84ca1c9b0cSelric
85ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_rd_safe(krb5_context context,krb5_auth_context auth_context,const krb5_data * inbuf,krb5_data * outbuf,krb5_replay_data * outdata)86ca1c9b0cSelric krb5_rd_safe(krb5_context context,
87ca1c9b0cSelric krb5_auth_context auth_context,
88ca1c9b0cSelric const krb5_data *inbuf,
89ca1c9b0cSelric krb5_data *outbuf,
90ca1c9b0cSelric krb5_replay_data *outdata)
91ca1c9b0cSelric {
92ca1c9b0cSelric krb5_error_code ret;
93ca1c9b0cSelric KRB_SAFE safe;
94ca1c9b0cSelric size_t len;
95ca1c9b0cSelric
96ca1c9b0cSelric krb5_data_zero(outbuf);
97ca1c9b0cSelric
98ca1c9b0cSelric if ((auth_context->flags &
99ca1c9b0cSelric (KRB5_AUTH_CONTEXT_RET_TIME | KRB5_AUTH_CONTEXT_RET_SEQUENCE)))
100ca1c9b0cSelric {
101ca1c9b0cSelric if (outdata == NULL) {
102ca1c9b0cSelric krb5_set_error_message(context, KRB5_RC_REQUIRED,
103ca1c9b0cSelric N_("rd_safe: need outdata "
104ca1c9b0cSelric "to return data", ""));
105ca1c9b0cSelric return KRB5_RC_REQUIRED; /* XXX better error, MIT returns this */
106ca1c9b0cSelric }
107ca1c9b0cSelric /* if these fields are not present in the safe-part, silently
108ca1c9b0cSelric return zero */
109ca1c9b0cSelric memset(outdata, 0, sizeof(*outdata));
110ca1c9b0cSelric }
111ca1c9b0cSelric
112ca1c9b0cSelric ret = decode_KRB_SAFE (inbuf->data, inbuf->length, &safe, &len);
113ca1c9b0cSelric if (ret)
114ca1c9b0cSelric return ret;
115ca1c9b0cSelric if (safe.pvno != 5) {
116ca1c9b0cSelric ret = KRB5KRB_AP_ERR_BADVERSION;
117ca1c9b0cSelric krb5_clear_error_message (context);
118ca1c9b0cSelric goto failure;
119ca1c9b0cSelric }
120ca1c9b0cSelric if (safe.msg_type != krb_safe) {
121ca1c9b0cSelric ret = KRB5KRB_AP_ERR_MSG_TYPE;
122ca1c9b0cSelric krb5_clear_error_message (context);
123ca1c9b0cSelric goto failure;
124ca1c9b0cSelric }
125ca1c9b0cSelric if (!krb5_checksum_is_keyed(context, safe.cksum.cksumtype)
126ca1c9b0cSelric || !krb5_checksum_is_collision_proof(context, safe.cksum.cksumtype)) {
127ca1c9b0cSelric ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
128ca1c9b0cSelric krb5_clear_error_message (context);
129ca1c9b0cSelric goto failure;
130ca1c9b0cSelric }
131ca1c9b0cSelric
132ca1c9b0cSelric /* check sender address */
133ca1c9b0cSelric
134ca1c9b0cSelric if (safe.safe_body.s_address
135ca1c9b0cSelric && auth_context->remote_address
136ca1c9b0cSelric && !krb5_address_compare (context,
137ca1c9b0cSelric auth_context->remote_address,
138ca1c9b0cSelric safe.safe_body.s_address)) {
139ca1c9b0cSelric ret = KRB5KRB_AP_ERR_BADADDR;
140ca1c9b0cSelric krb5_clear_error_message (context);
141ca1c9b0cSelric goto failure;
142ca1c9b0cSelric }
143ca1c9b0cSelric
144ca1c9b0cSelric /* check receiver address */
145ca1c9b0cSelric
146ca1c9b0cSelric if (safe.safe_body.r_address
147ca1c9b0cSelric && auth_context->local_address
148ca1c9b0cSelric && !krb5_address_compare (context,
149ca1c9b0cSelric auth_context->local_address,
150ca1c9b0cSelric safe.safe_body.r_address)) {
151ca1c9b0cSelric ret = KRB5KRB_AP_ERR_BADADDR;
152ca1c9b0cSelric krb5_clear_error_message (context);
153ca1c9b0cSelric goto failure;
154ca1c9b0cSelric }
155ca1c9b0cSelric
156ca1c9b0cSelric /* check timestamp */
157ca1c9b0cSelric if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_TIME) {
158ca1c9b0cSelric krb5_timestamp sec;
159ca1c9b0cSelric
160ca1c9b0cSelric krb5_timeofday (context, &sec);
161ca1c9b0cSelric
162ca1c9b0cSelric if (safe.safe_body.timestamp == NULL ||
163ca1c9b0cSelric safe.safe_body.usec == NULL ||
164b9d004c6Schristos labs(*safe.safe_body.timestamp - sec) > context->max_skew) {
165ca1c9b0cSelric ret = KRB5KRB_AP_ERR_SKEW;
166ca1c9b0cSelric krb5_clear_error_message (context);
167ca1c9b0cSelric goto failure;
168ca1c9b0cSelric }
169ca1c9b0cSelric }
170ca1c9b0cSelric /* XXX - check replay cache */
171ca1c9b0cSelric
172ca1c9b0cSelric /* check sequence number. since MIT krb5 cannot generate a sequence
173ca1c9b0cSelric number of zero but instead generates no sequence number, we accept that
174ca1c9b0cSelric */
175ca1c9b0cSelric
176ca1c9b0cSelric if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) {
177ca1c9b0cSelric if ((safe.safe_body.seq_number == NULL
178ca1c9b0cSelric && auth_context->remote_seqnumber != 0)
179ca1c9b0cSelric || (safe.safe_body.seq_number != NULL
180ca1c9b0cSelric && *safe.safe_body.seq_number !=
181ca1c9b0cSelric auth_context->remote_seqnumber)) {
182ca1c9b0cSelric ret = KRB5KRB_AP_ERR_BADORDER;
183ca1c9b0cSelric krb5_clear_error_message (context);
184ca1c9b0cSelric goto failure;
185ca1c9b0cSelric }
186ca1c9b0cSelric auth_context->remote_seqnumber++;
187ca1c9b0cSelric }
188ca1c9b0cSelric
189ca1c9b0cSelric ret = verify_checksum (context, auth_context, &safe);
190ca1c9b0cSelric if (ret)
191ca1c9b0cSelric goto failure;
192ca1c9b0cSelric
193ca1c9b0cSelric outbuf->length = safe.safe_body.user_data.length;
194ca1c9b0cSelric outbuf->data = malloc(outbuf->length);
195ca1c9b0cSelric if (outbuf->data == NULL && outbuf->length != 0) {
196b9d004c6Schristos ret = krb5_enomem(context);
197ca1c9b0cSelric krb5_data_zero(outbuf);
198ca1c9b0cSelric goto failure;
199ca1c9b0cSelric }
200ca1c9b0cSelric memcpy (outbuf->data, safe.safe_body.user_data.data, outbuf->length);
201ca1c9b0cSelric
202ca1c9b0cSelric if ((auth_context->flags &
203ca1c9b0cSelric (KRB5_AUTH_CONTEXT_RET_TIME | KRB5_AUTH_CONTEXT_RET_SEQUENCE))) {
204ca1c9b0cSelric
205ca1c9b0cSelric if(safe.safe_body.timestamp)
206ca1c9b0cSelric outdata->timestamp = *safe.safe_body.timestamp;
207ca1c9b0cSelric if(safe.safe_body.usec)
208ca1c9b0cSelric outdata->usec = *safe.safe_body.usec;
209ca1c9b0cSelric if(safe.safe_body.seq_number)
210ca1c9b0cSelric outdata->seq = *safe.safe_body.seq_number;
211ca1c9b0cSelric }
212ca1c9b0cSelric
213ca1c9b0cSelric failure:
214ca1c9b0cSelric free_KRB_SAFE (&safe);
215ca1c9b0cSelric return ret;
216ca1c9b0cSelric }
217