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