1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 /* lib/krb5/krb/ser_actx.c - Serialize krb5_auth_context structure */ 3 /* 4 * Copyright 1995, 2008 by the Massachusetts Institute of Technology. 5 * All Rights Reserved. 6 * 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. 11 * 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. 25 */ 26 27 #include "k5-int.h" 28 #include "int-proto.h" 29 #include "auth_con.h" 30 31 #define TOKEN_RADDR 950916 32 #define TOKEN_RPORT 950917 33 #define TOKEN_LADDR 950918 34 #define TOKEN_LPORT 950919 35 #define TOKEN_KEYBLOCK 950920 36 #define TOKEN_LSKBLOCK 950921 37 #define TOKEN_RSKBLOCK 950922 38 39 krb5_error_code 40 k5_size_auth_context(krb5_auth_context auth_context, size_t *sizep) 41 { 42 krb5_error_code kret; 43 size_t required; 44 45 /* 46 * krb5_auth_context requires at minimum: 47 * krb5_int32 for KV5M_AUTH_CONTEXT 48 * krb5_int32 for auth_context_flags 49 * krb5_int32 for remote_seq_number 50 * krb5_int32 for local_seq_number 51 * krb5_int32 for req_cksumtype 52 * krb5_int32 for safe_cksumtype 53 * krb5_int32 for size of i_vector 54 * krb5_int32 for KV5M_AUTH_CONTEXT 55 */ 56 kret = EINVAL; 57 if (auth_context != NULL) { 58 kret = 0; 59 60 required = auth_context->cstate.length; 61 required += sizeof(krb5_int32)*8; 62 63 /* Calculate size required by remote_addr, if appropriate */ 64 if (!kret && auth_context->remote_addr) { 65 kret = k5_size_address(auth_context->remote_addr, &required); 66 if (!kret) 67 required += sizeof(krb5_int32); 68 } 69 70 /* Calculate size required by remote_port, if appropriate */ 71 if (!kret && auth_context->remote_port) { 72 kret = k5_size_address(auth_context->remote_port, &required); 73 if (!kret) 74 required += sizeof(krb5_int32); 75 } 76 77 /* Calculate size required by local_addr, if appropriate */ 78 if (!kret && auth_context->local_addr) { 79 kret = k5_size_address(auth_context->local_addr, &required); 80 if (!kret) 81 required += sizeof(krb5_int32); 82 } 83 84 /* Calculate size required by local_port, if appropriate */ 85 if (!kret && auth_context->local_port) { 86 kret = k5_size_address(auth_context->local_port, &required); 87 if (!kret) 88 required += sizeof(krb5_int32); 89 } 90 91 /* Calculate size required by key, if appropriate */ 92 if (!kret && auth_context->key) { 93 kret = k5_size_keyblock(&auth_context->key->keyblock, &required); 94 if (!kret) 95 required += sizeof(krb5_int32); 96 } 97 98 /* Calculate size required by send_subkey, if appropriate */ 99 if (!kret && auth_context->send_subkey) { 100 kret = k5_size_keyblock(&auth_context->send_subkey->keyblock, 101 &required); 102 if (!kret) 103 required += sizeof(krb5_int32); 104 } 105 106 /* Calculate size required by recv_subkey, if appropriate */ 107 if (!kret && auth_context->recv_subkey) { 108 kret = k5_size_keyblock(&auth_context->recv_subkey->keyblock, 109 &required); 110 if (!kret) 111 required += sizeof(krb5_int32); 112 } 113 114 /* Calculate size required by authentp, if appropriate */ 115 if (!kret && auth_context->authentp) 116 kret = k5_size_authenticator(auth_context->authentp, &required); 117 118 } 119 if (!kret) 120 *sizep += required; 121 return(kret); 122 } 123 124 krb5_error_code 125 k5_externalize_auth_context(krb5_auth_context auth_context, 126 krb5_octet **buffer, size_t *lenremain) 127 { 128 krb5_error_code kret; 129 size_t required; 130 krb5_octet *bp; 131 size_t remain; 132 133 required = 0; 134 bp = *buffer; 135 remain = *lenremain; 136 kret = EINVAL; 137 if (auth_context != NULL) { 138 kret = ENOMEM; 139 if (!k5_size_auth_context(auth_context, &required) && 140 required <= remain) { 141 142 /* Write fixed portion */ 143 (void) krb5_ser_pack_int32(KV5M_AUTH_CONTEXT, &bp, &remain); 144 (void) krb5_ser_pack_int32(auth_context->auth_context_flags, 145 &bp, &remain); 146 (void) krb5_ser_pack_int32(auth_context->remote_seq_number, 147 &bp, &remain); 148 (void) krb5_ser_pack_int32(auth_context->local_seq_number, 149 &bp, &remain); 150 (void) krb5_ser_pack_int32((krb5_int32) auth_context->req_cksumtype, 151 &bp, &remain); 152 (void) krb5_ser_pack_int32((krb5_int32) auth_context->safe_cksumtype, 153 &bp, &remain); 154 155 /* Write the cipher state */ 156 (void) krb5_ser_pack_int32(auth_context->cstate.length, &bp, 157 &remain); 158 (void) krb5_ser_pack_bytes((krb5_octet *)auth_context->cstate.data, 159 auth_context->cstate.length, 160 &bp, &remain); 161 162 kret = 0; 163 164 /* Now handle remote_addr, if appropriate */ 165 if (!kret && auth_context->remote_addr) { 166 (void) krb5_ser_pack_int32(TOKEN_RADDR, &bp, &remain); 167 kret = k5_externalize_address(auth_context->remote_addr, 168 &bp, &remain); 169 } 170 171 /* Now handle remote_port, if appropriate */ 172 if (!kret && auth_context->remote_port) { 173 (void) krb5_ser_pack_int32(TOKEN_RPORT, &bp, &remain); 174 kret = k5_externalize_address(auth_context->remote_addr, 175 &bp, &remain); 176 } 177 178 /* Now handle local_addr, if appropriate */ 179 if (!kret && auth_context->local_addr) { 180 (void) krb5_ser_pack_int32(TOKEN_LADDR, &bp, &remain); 181 kret = k5_externalize_address(auth_context->local_addr, 182 &bp, &remain); 183 } 184 185 /* Now handle local_port, if appropriate */ 186 if (!kret && auth_context->local_port) { 187 (void) krb5_ser_pack_int32(TOKEN_LPORT, &bp, &remain); 188 kret = k5_externalize_address(auth_context->local_addr, 189 &bp, &remain); 190 } 191 192 /* Now handle keyblock, if appropriate */ 193 if (!kret && auth_context->key) { 194 (void) krb5_ser_pack_int32(TOKEN_KEYBLOCK, &bp, &remain); 195 kret = k5_externalize_keyblock(&auth_context->key->keyblock, 196 &bp, &remain); 197 } 198 199 /* Now handle subkey, if appropriate */ 200 if (!kret && auth_context->send_subkey) { 201 (void) krb5_ser_pack_int32(TOKEN_LSKBLOCK, &bp, &remain); 202 kret = k5_externalize_keyblock(&auth_context-> 203 send_subkey->keyblock, 204 &bp, &remain); 205 } 206 207 /* Now handle subkey, if appropriate */ 208 if (!kret && auth_context->recv_subkey) { 209 (void) krb5_ser_pack_int32(TOKEN_RSKBLOCK, &bp, &remain); 210 kret = k5_externalize_keyblock(&auth_context-> 211 recv_subkey->keyblock, 212 &bp, &remain); 213 } 214 215 /* Now handle authentp, if appropriate */ 216 if (!kret && auth_context->authentp) 217 kret = k5_externalize_authenticator(auth_context->authentp, 218 &bp, &remain); 219 220 /* 221 * If we were successful, write trailer then update the pointer and 222 * remaining length; 223 */ 224 if (!kret) { 225 /* Write our trailer */ 226 (void) krb5_ser_pack_int32(KV5M_AUTH_CONTEXT, &bp, &remain); 227 *buffer = bp; 228 *lenremain = remain; 229 } 230 } 231 } 232 return(kret); 233 } 234 235 /* Internalize a keyblock and convert it to a key. */ 236 static krb5_error_code 237 intern_key(krb5_key *key, krb5_octet **bp, size_t *sp) 238 { 239 krb5_keyblock *keyblock; 240 krb5_error_code ret; 241 242 ret = k5_internalize_keyblock(&keyblock, bp, sp); 243 if (ret != 0) 244 return ret; 245 ret = krb5_k_create_key(NULL, keyblock, key); 246 krb5_free_keyblock(NULL, keyblock); 247 return ret; 248 } 249 250 krb5_error_code 251 k5_internalize_auth_context(krb5_auth_context *argp, 252 krb5_octet **buffer, size_t *lenremain) 253 { 254 krb5_error_code kret; 255 krb5_auth_context auth_context; 256 krb5_int32 ibuf; 257 krb5_octet *bp; 258 size_t remain; 259 krb5_int32 cstate_len; 260 krb5_int32 tag; 261 262 bp = *buffer; 263 remain = *lenremain; 264 kret = EINVAL; 265 /* Read our magic number */ 266 if (krb5_ser_unpack_int32(&ibuf, &bp, &remain)) 267 ibuf = 0; 268 if (ibuf == KV5M_AUTH_CONTEXT) { 269 kret = ENOMEM; 270 271 /* Get memory for the auth_context */ 272 if ((remain >= (5*sizeof(krb5_int32))) && 273 (auth_context = (krb5_auth_context) 274 calloc(1, sizeof(struct _krb5_auth_context)))) { 275 276 /* Get auth_context_flags */ 277 (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain); 278 auth_context->auth_context_flags = ibuf; 279 280 /* Get remote_seq_number */ 281 (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain); 282 auth_context->remote_seq_number = ibuf; 283 284 /* Get local_seq_number */ 285 (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain); 286 auth_context->local_seq_number = ibuf; 287 288 /* Get req_cksumtype */ 289 (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain); 290 auth_context->req_cksumtype = (krb5_cksumtype) ibuf; 291 292 /* Get safe_cksumtype */ 293 (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain); 294 auth_context->safe_cksumtype = (krb5_cksumtype) ibuf; 295 296 /* Get length of cstate */ 297 (void) krb5_ser_unpack_int32(&cstate_len, &bp, &remain); 298 299 if (cstate_len) { 300 kret = alloc_data(&auth_context->cstate, cstate_len); 301 if (!kret) { 302 kret = krb5_ser_unpack_bytes((krb5_octet *) 303 auth_context->cstate.data, 304 cstate_len, &bp, &remain); 305 } 306 } 307 else 308 kret = 0; 309 310 /* Peek at next token */ 311 tag = 0; 312 if (!kret) 313 kret = krb5_ser_unpack_int32(&tag, &bp, &remain); 314 315 /* This is the remote_addr */ 316 if (!kret && (tag == TOKEN_RADDR)) { 317 if (!(kret = k5_internalize_address(&auth_context->remote_addr, 318 &bp, &remain))) 319 kret = krb5_ser_unpack_int32(&tag, &bp, &remain); 320 } 321 322 /* This is the remote_port */ 323 if (!kret && (tag == TOKEN_RPORT)) { 324 if (!(kret = k5_internalize_address(&auth_context->remote_port, 325 &bp, &remain))) 326 kret = krb5_ser_unpack_int32(&tag, &bp, &remain); 327 } 328 329 /* This is the local_addr */ 330 if (!kret && (tag == TOKEN_LADDR)) { 331 if (!(kret = k5_internalize_address(&auth_context->local_addr, 332 &bp, &remain))) 333 kret = krb5_ser_unpack_int32(&tag, &bp, &remain); 334 } 335 336 /* This is the local_port */ 337 if (!kret && (tag == TOKEN_LPORT)) { 338 if (!(kret = k5_internalize_address(&auth_context->local_port, 339 &bp, &remain))) 340 kret = krb5_ser_unpack_int32(&tag, &bp, &remain); 341 } 342 343 /* This is the keyblock */ 344 if (!kret && (tag == TOKEN_KEYBLOCK)) { 345 if (!(kret = intern_key(&auth_context->key, &bp, &remain))) 346 kret = krb5_ser_unpack_int32(&tag, &bp, &remain); 347 } 348 349 /* This is the send_subkey */ 350 if (!kret && (tag == TOKEN_LSKBLOCK)) { 351 if (!(kret = intern_key(&auth_context->send_subkey, 352 &bp, &remain))) 353 kret = krb5_ser_unpack_int32(&tag, &bp, &remain); 354 } 355 356 /* This is the recv_subkey */ 357 if (!kret) { 358 if (tag == TOKEN_RSKBLOCK) { 359 kret = intern_key(&auth_context->recv_subkey, 360 &bp, &remain); 361 } 362 else { 363 /* 364 * We read the next tag, but it's not of any use here, so 365 * we effectively 'unget' it here. 366 */ 367 bp -= sizeof(krb5_int32); 368 remain += sizeof(krb5_int32); 369 } 370 } 371 372 /* Now find the authentp */ 373 if (!kret) { 374 kret = k5_internalize_authenticator(&auth_context->authentp, 375 &bp, &remain); 376 if (kret == EINVAL) 377 kret = 0; 378 } 379 380 /* Finally, find the trailer */ 381 if (!kret) { 382 kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain); 383 if (!kret && (ibuf != KV5M_AUTH_CONTEXT)) 384 kret = EINVAL; 385 } 386 if (!kret) { 387 *buffer = bp; 388 *lenremain = remain; 389 auth_context->magic = KV5M_AUTH_CONTEXT; 390 *argp = auth_context; 391 } 392 else 393 krb5_auth_con_free(NULL, auth_context); 394 } 395 } 396 return(kret); 397 } 398