1/* 2 Unix SMB/CIFS implementation. 3 simple SPNEGO routines 4 Copyright (C) Andrew Tridgell 2001 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19*/ 20 21#include "includes.h" 22 23/* free an asn1 structure */ 24void asn1_free(ASN1_DATA *data) 25{ 26 struct nesting *nesting = data->nesting; 27 28 while (nesting) { 29 struct nesting *nnext = nesting->next; 30 free(nesting); 31 nesting = nnext; 32 }; 33 data->nesting = NULL; 34 SAFE_FREE(data->data); 35} 36 37/* write to the ASN1 buffer, advancing the buffer pointer */ 38BOOL asn1_write(ASN1_DATA *data, const void *p, int len) 39{ 40 if (data->has_error) return False; 41 if (data->length < data->ofs+len) { 42 data->data = SMB_REALLOC_ARRAY(data->data, unsigned char, 43 data->ofs+len); 44 if (!data->data) { 45 data->has_error = True; 46 return False; 47 } 48 data->length = data->ofs+len; 49 } 50 memcpy(data->data + data->ofs, p, len); 51 data->ofs += len; 52 return True; 53} 54 55/* useful fn for writing a uint8 */ 56BOOL asn1_write_uint8(ASN1_DATA *data, uint8 v) 57{ 58 return asn1_write(data, &v, 1); 59} 60 61/* push a tag onto the asn1 data buffer. Used for nested structures */ 62BOOL asn1_push_tag(ASN1_DATA *data, uint8 tag) 63{ 64 struct nesting *nesting; 65 66 asn1_write_uint8(data, tag); 67 nesting = SMB_MALLOC_P(struct nesting); 68 if (!nesting) { 69 data->has_error = True; 70 return False; 71 } 72 73 nesting->start = data->ofs; 74 nesting->next = data->nesting; 75 data->nesting = nesting; 76 return asn1_write_uint8(data, 0xff); 77} 78 79/* pop a tag */ 80BOOL asn1_pop_tag(ASN1_DATA *data) 81{ 82 struct nesting *nesting; 83 size_t len; 84 85 if (data->has_error) { 86 return False; 87 } 88 89 nesting = data->nesting; 90 91 if (!nesting) { 92 data->has_error = True; 93 return False; 94 } 95 len = data->ofs - (nesting->start+1); 96 /* yes, this is ugly. We don't know in advance how many bytes the length 97 of a tag will take, so we assumed 1 byte. If we were wrong then we 98 need to correct our mistake */ 99 if (len > 0xFFFF) { 100 data->data[nesting->start] = 0x83; 101 if (!asn1_write_uint8(data, 0)) return False; 102 if (!asn1_write_uint8(data, 0)) return False; 103 if (!asn1_write_uint8(data, 0)) return False; 104 memmove(data->data+nesting->start+4, data->data+nesting->start+1, len); 105 data->data[nesting->start+1] = (len>>16) & 0xFF; 106 data->data[nesting->start+2] = (len>>8) & 0xFF; 107 data->data[nesting->start+3] = len&0xff; 108 } else if (len > 255) { 109 data->data[nesting->start] = 0x82; 110 if (!asn1_write_uint8(data, 0)) return False; 111 if (!asn1_write_uint8(data, 0)) return False; 112 memmove(data->data+nesting->start+3, data->data+nesting->start+1, len); 113 data->data[nesting->start+1] = len>>8; 114 data->data[nesting->start+2] = len&0xff; 115 } else if (len > 127) { 116 data->data[nesting->start] = 0x81; 117 if (!asn1_write_uint8(data, 0)) return False; 118 memmove(data->data+nesting->start+2, data->data+nesting->start+1, len); 119 data->data[nesting->start+1] = len; 120 } else { 121 data->data[nesting->start] = len; 122 } 123 124 data->nesting = nesting->next; 125 free(nesting); 126 return True; 127} 128 129 130/* write an integer */ 131BOOL asn1_write_Integer(ASN1_DATA *data, int i) 132{ 133 if (!asn1_push_tag(data, ASN1_INTEGER)) return False; 134 do { 135 asn1_write_uint8(data, i); 136 i = i >> 8; 137 } while (i); 138 return asn1_pop_tag(data); 139} 140 141/* write an object ID to a ASN1 buffer */ 142BOOL asn1_write_OID(ASN1_DATA *data, const char *OID) 143{ 144 unsigned v, v2; 145 const char *p = (const char *)OID; 146 char *newp; 147 148 if (!asn1_push_tag(data, ASN1_OID)) 149 return False; 150 v = strtol(p, &newp, 10); 151 p = newp; 152 v2 = strtol(p, &newp, 10); 153 p = newp; 154 if (!asn1_write_uint8(data, 40*v + v2)) 155 return False; 156 157 while (*p) { 158 v = strtol(p, &newp, 10); 159 p = newp; 160 if (v >= (1<<28)) asn1_write_uint8(data, 0x80 | ((v>>28)&0xff)); 161 if (v >= (1<<21)) asn1_write_uint8(data, 0x80 | ((v>>21)&0xff)); 162 if (v >= (1<<14)) asn1_write_uint8(data, 0x80 | ((v>>14)&0xff)); 163 if (v >= (1<<7)) asn1_write_uint8(data, 0x80 | ((v>>7)&0xff)); 164 if (!asn1_write_uint8(data, v&0x7f)) 165 return False; 166 } 167 return asn1_pop_tag(data); 168} 169 170/* write an octet string */ 171BOOL asn1_write_OctetString(ASN1_DATA *data, const void *p, size_t length) 172{ 173 asn1_push_tag(data, ASN1_OCTET_STRING); 174 asn1_write(data, p, length); 175 asn1_pop_tag(data); 176 return !data->has_error; 177} 178 179/* write a general string */ 180BOOL asn1_write_GeneralString(ASN1_DATA *data, const char *s) 181{ 182 asn1_push_tag(data, ASN1_GENERAL_STRING); 183 asn1_write(data, s, strlen(s)); 184 asn1_pop_tag(data); 185 return !data->has_error; 186} 187 188/* write a BOOLEAN */ 189BOOL asn1_write_BOOLEAN(ASN1_DATA *data, BOOL v) 190{ 191 asn1_write_uint8(data, ASN1_BOOLEAN); 192 asn1_write_uint8(data, v); 193 return !data->has_error; 194} 195 196/* write a BOOLEAN - hmm, I suspect this one is the correct one, and the 197 above boolean is bogus. Need to check */ 198BOOL asn1_write_BOOLEAN2(ASN1_DATA *data, BOOL v) 199{ 200 asn1_push_tag(data, ASN1_BOOLEAN); 201 asn1_write_uint8(data, v); 202 asn1_pop_tag(data); 203 return !data->has_error; 204} 205 206/* check a BOOLEAN */ 207BOOL asn1_check_BOOLEAN(ASN1_DATA *data, BOOL v) 208{ 209 uint8 b = 0; 210 211 asn1_read_uint8(data, &b); 212 if (b != ASN1_BOOLEAN) { 213 data->has_error = True; 214 return False; 215 } 216 asn1_read_uint8(data, &b); 217 if (b != v) { 218 data->has_error = True; 219 return False; 220 } 221 return !data->has_error; 222} 223 224 225/* load a ASN1_DATA structure with a lump of data, ready to be parsed */ 226BOOL asn1_load(ASN1_DATA *data, DATA_BLOB blob) 227{ 228 ZERO_STRUCTP(data); 229 data->data = (unsigned char *)memdup(blob.data, blob.length); 230 if (!data->data) { 231 data->has_error = True; 232 return False; 233 } 234 data->length = blob.length; 235 return True; 236} 237 238/* read from a ASN1 buffer, advancing the buffer pointer */ 239BOOL asn1_read(ASN1_DATA *data, void *p, int len) 240{ 241 if (data->has_error) 242 return False; 243 244 if (len < 0 || data->ofs + len < data->ofs || data->ofs + len < len) { 245 data->has_error = True; 246 return False; 247 } 248 249 if (data->ofs + len > data->length) { 250 data->has_error = True; 251 return False; 252 } 253 memcpy(p, data->data + data->ofs, len); 254 data->ofs += len; 255 return True; 256} 257 258/* read a uint8 from a ASN1 buffer */ 259BOOL asn1_read_uint8(ASN1_DATA *data, uint8 *v) 260{ 261 return asn1_read(data, v, 1); 262} 263 264/* start reading a nested asn1 structure */ 265BOOL asn1_start_tag(ASN1_DATA *data, uint8 tag) 266{ 267 uint8 b; 268 struct nesting *nesting; 269 270 if (!asn1_read_uint8(data, &b)) 271 return False; 272 273 if (b != tag) { 274 data->has_error = True; 275 return False; 276 } 277 nesting = SMB_MALLOC_P(struct nesting); 278 if (!nesting) { 279 data->has_error = True; 280 return False; 281 } 282 283 if (!asn1_read_uint8(data, &b)) { 284 SAFE_FREE(nesting); 285 return False; 286 } 287 288 if (b & 0x80) { 289 int n = b & 0x7f; 290 if (!asn1_read_uint8(data, &b)) { 291 SAFE_FREE(nesting); 292 return False; 293 } 294 nesting->taglen = b; 295 while (n > 1) { 296 if (!asn1_read_uint8(data, &b)) { 297 SAFE_FREE(nesting); 298 return False; 299 } 300 nesting->taglen = (nesting->taglen << 8) | b; 301 n--; 302 } 303 } else { 304 nesting->taglen = b; 305 } 306 nesting->start = data->ofs; 307 nesting->next = data->nesting; 308 data->nesting = nesting; 309 return !data->has_error; 310} 311 312 313/* stop reading a tag */ 314BOOL asn1_end_tag(ASN1_DATA *data) 315{ 316 struct nesting *nesting; 317 318 /* make sure we read it all */ 319 if (asn1_tag_remaining(data) != 0) { 320 data->has_error = True; 321 return False; 322 } 323 324 nesting = data->nesting; 325 326 if (!nesting) { 327 data->has_error = True; 328 return False; 329 } 330 331 data->nesting = nesting->next; 332 free(nesting); 333 return True; 334} 335 336/* work out how many bytes are left in this nested tag */ 337int asn1_tag_remaining(ASN1_DATA *data) 338{ 339 if (data->has_error) 340 return 0; 341 342 if (!data->nesting) { 343 data->has_error = True; 344 return -1; 345 } 346 return data->nesting->taglen - (data->ofs - data->nesting->start); 347} 348 349/* read an object ID from a ASN1 buffer */ 350BOOL asn1_read_OID(ASN1_DATA *data, char **OID) 351{ 352 uint8 b; 353 pstring oid_str; 354 fstring el; 355 356 *OID = NULL; 357 358 if (!asn1_start_tag(data, ASN1_OID)) { 359 return False; 360 } 361 asn1_read_uint8(data, &b); 362 363 oid_str[0] = 0; 364 fstr_sprintf(el, "%u", b/40); 365 pstrcat(oid_str, el); 366 fstr_sprintf(el, " %u", b%40); 367 pstrcat(oid_str, el); 368 369 while (asn1_tag_remaining(data) > 0) { 370 unsigned v = 0; 371 do { 372 asn1_read_uint8(data, &b); 373 v = (v<<7) | (b&0x7f); 374 } while (!data->has_error && b & 0x80); 375 fstr_sprintf(el, " %u", v); 376 pstrcat(oid_str, el); 377 } 378 379 asn1_end_tag(data); 380 381 if (!data->has_error) { 382 *OID = SMB_STRDUP(oid_str); 383 } 384 385 return !data->has_error; 386} 387 388/* check that the next object ID is correct */ 389BOOL asn1_check_OID(ASN1_DATA *data, const char *OID) 390{ 391 char *id; 392 393 if (!asn1_read_OID(data, &id)) { 394 return False; 395 } 396 397 if (strcmp(id, OID) != 0) { 398 data->has_error = True; 399 return False; 400 } 401 free(id); 402 return True; 403} 404 405/* read a GeneralString from a ASN1 buffer */ 406BOOL asn1_read_GeneralString(ASN1_DATA *data, char **s) 407{ 408 int len; 409 char *str; 410 411 *s = NULL; 412 413 if (!asn1_start_tag(data, ASN1_GENERAL_STRING)) { 414 return False; 415 } 416 len = asn1_tag_remaining(data); 417 if (len < 0) { 418 data->has_error = True; 419 return False; 420 } 421 str = SMB_MALLOC_ARRAY(char, len+1); 422 if (!str) { 423 data->has_error = True; 424 return False; 425 } 426 asn1_read(data, str, len); 427 str[len] = 0; 428 asn1_end_tag(data); 429 430 if (!data->has_error) { 431 *s = str; 432 } 433 return !data->has_error; 434} 435 436/* read a octet string blob */ 437BOOL asn1_read_OctetString(ASN1_DATA *data, DATA_BLOB *blob) 438{ 439 int len; 440 ZERO_STRUCTP(blob); 441 if (!asn1_start_tag(data, ASN1_OCTET_STRING)) return False; 442 len = asn1_tag_remaining(data); 443 if (len < 0) { 444 data->has_error = True; 445 return False; 446 } 447 *blob = data_blob(NULL, len); 448 asn1_read(data, blob->data, len); 449 asn1_end_tag(data); 450 return !data->has_error; 451} 452 453/* read an interger */ 454BOOL asn1_read_Integer(ASN1_DATA *data, int *i) 455{ 456 uint8 b; 457 *i = 0; 458 459 if (!asn1_start_tag(data, ASN1_INTEGER)) return False; 460 while (asn1_tag_remaining(data)>0) { 461 asn1_read_uint8(data, &b); 462 *i = (*i << 8) + b; 463 } 464 return asn1_end_tag(data); 465 466} 467 468/* check a enumarted value is correct */ 469BOOL asn1_check_enumerated(ASN1_DATA *data, int v) 470{ 471 uint8 b; 472 if (!asn1_start_tag(data, ASN1_ENUMERATED)) return False; 473 asn1_read_uint8(data, &b); 474 asn1_end_tag(data); 475 476 if (v != b) 477 data->has_error = False; 478 479 return !data->has_error; 480} 481 482/* write an enumarted value to the stream */ 483BOOL asn1_write_enumerated(ASN1_DATA *data, uint8 v) 484{ 485 if (!asn1_push_tag(data, ASN1_ENUMERATED)) return False; 486 asn1_write_uint8(data, v); 487 asn1_pop_tag(data); 488 return !data->has_error; 489} 490