1 /* 2 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 | #pragma ident "@(#)g_glue.c 1.26 04/09/08 SMI" 6 | #pragma ident "@(#)g_glue.c 1.25 04/02/23 SMI" 7 8 #include <mechglueP.h> 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <strings.h> 12 #include <errno.h> 13 14 #define MSO_BIT (8*(sizeof (int) - 1)) /* Most significant octet bit */ 15 16 /* 17 * This file contains the support routines for the glue layer. 18 */ 19 20 /* 21 + * get_der_length: Givin a pointer to a buffer that contains a DER encoded 22 + * length, decode the length updating the buffer to point to the character 23 + * after the DER encoding. The parameter bytes will point to the number of 24 + * bytes that made up the DER encoding of the length originally pointed to 25 + * by the buffer. Note we return -1 on error. 26 + */ 27 + int 28 + get_der_length(unsigned char **buf, unsigned int buf_len, unsigned int *bytes) 29 + { 30 + /* p points to the beginning of the buffer */ 31 + unsigned char *p = *buf; 32 + int length, new_length; 33 + int octets; 34 + 35 + if (buf_len < 1) 36 + return (-1); 37 + 38 + /* We should have at least one byte */ 39 + *bytes = 1; 40 + 41 + /* 42 + * If the High order bit is not set then the length is just the value 43 + * of *p. 44 + */ 45 + if (*p < 128) { 46 + *buf = p+1; /* Advance the buffer */ 47 + return (*p); /* return the length */ 48 + } 49 + 50 + /* 51 + * if the High order bit is set, then the low order bits represent 52 + * the number of bytes that contain the DER encoding of the length. 53 + */ 54 + 55 + octets = *p++ & 0x7f; 56 + *bytes += octets; 57 + 58 + /* See if the supplied buffer contains enough bytes for the length. */ 59 + if (octets > buf_len - 1) 60 + return (-1); 61 + 62 + /* 63 + * Calculate a multibyte length. The length is encoded as an 64 + * unsigned integer base 256. 65 + */ 66 + for (length = 0; octets; octets--) { 67 + new_length = (length << 8) + *p++; 68 + if (new_length < length) /* overflow */ 69 + return (-1); 70 + length = new_length; 71 + } 72 + 73 + *buf = p; /* Advance the buffer */ 74 + 75 + return (length); 76 + } 77 + 78 + /* 79 * der_length_size: Return the number of bytes to encode a given length. 80 */ 81 unsigned int 82 der_length_size(unsigned int len) 83 { 26 | if (length < (1<<7)) 84 | int i; 85 + 86 + if (len < 128) 87 return (1); 28 | else if (length < (1<<8)) 29 | return(2); 30 | #if (SIZEOF_INT == 2) 88 | 89 | for (i = 0; len; i++) { 90 | len >>= 8; 31 - else 32 - return(3); 33 - #else 34 - else if (length < (1<<16)) 35 - return(3); 36 - else if (length < (1<<24)) 37 - return(4); 38 - else 39 - return(5); 40 - #endif 91 } 92 93 + return (i+1); 94 + } 95 + 96 /* 97 + * put_der_length: Encode the supplied length into the buffer pointed to 98 + * by buf. max_length represents the maximum length of the buffer pointed 99 + * to by buff. We will advance buf to point to the character after the newly 100 + * DER encoded length. We return 0 on success or -l it the length cannot 101 + * be encoded in max_len characters. 102 + */ 103 + int 104 + put_der_length(unsigned length, unsigned char **buf, unsigned int max_len) 105 + { 106 + unsigned char *s = *buf, *p; 107 + unsigned int buf_len = 0; 108 + int i, first; 109 + 110 + /* Oops */ 111 + if (buf == 0 || max_len < 1) 112 + return (-1); 113 + 114 + /* Single byte is the length */ 115 + if (length < 128) { 116 + *s++ = length; 117 + *buf = s; 118 + return (0); 119 + } 120 + 121 + /* First byte contains the number of octets */ 122 + p = s + 1; 123 + 124 + /* Running total of the DER encoding length */ 125 + buf_len = 0; 126 + 127 + /* 128 + * Encode MSB first. We do the encoding by setting a shift 129 + * factor to MSO_BIT (24 for 32 bit words) and then shifting the length 130 + * by the factor. We then encode the resulting low order byte. 131 + * We subtract 8 from the shift factor and repeat to ecnode the next 132 + * byte. We stop when the shift factor is zero or we've run out of 133 + * buffer to encode into. 134 + */ 135 + first = 0; 136 + for (i = MSO_BIT; i >= 0 && buf_len <= max_len; i -= 8) { 137 + unsigned int v; 138 + v = (length >> i) & 0xff; 139 + if ((v) || first) { 140 + buf_len += 1; 141 + *p++ = v; 142 + first = 1; 143 + } 144 + } 145 + if (i >= 0) /* buffer overflow */ 146 + return (-1); 147 + 148 + /* 149 + * We go back now and set the first byte to be the length with 150 + * the high order bit set. 151 + */ 152 + *s = buf_len | 0x80; 153 + *buf = p; 154 + 155 + return (0); 156 + } 157 + 158 + 159 + /* 160 * glue routine for get_mech_type 161 * 162 */ 163 OM_uint32 164 __gss_get_mech_type(OID, token) 165 gss_OID OID; 166 const gss_buffer_t token; 167 { 168 unsigned char *buffer_ptr; 169 int length; 170 171 /* 172 * This routine reads the prefix of "token" in order to determine 173 * its mechanism type. It assumes the encoding suggested in 174 * Appendix B of RFC 1508. This format starts out as follows : 175 * 176 * tag for APPLICATION 0, Sequence[constructed, definite length] 177 * length of remainder of token 178 * tag of OBJECT IDENTIFIER 179 * length of mechanism OID 180 * encoding of mechanism OID 181 * <the rest of the token> 182 * 183 * Numerically, this looks like : 184 * 185 * 0x60 186 * <length> - could be multiple bytes 187 * 0x06 188 * <length> - assume only one byte, hence OID length < 127 189 * <mech OID bytes> 190 * 191 * The routine fills in the OID value and returns an error as necessary. 192 */ 193 78 | if (token == NULL) 194 | if (OID == NULL) 195 + return (GSS_S_CALL_INACCESSIBLE_WRITE); 196 + 197 + if ((token == NULL) || (token->value == NULL)) 198 return (GSS_S_DEFECTIVE_TOKEN); 199 200 /* Skip past the APP/Sequnce byte and the token length */ 201 202 buffer_ptr = (unsigned char *) token->value; 203 204 if (*(buffer_ptr++) != 0x60) 205 return (GSS_S_DEFECTIVE_TOKEN); 206 length = *buffer_ptr++; 207 + 208 + /* check if token length is null */ 209 + if (length == 0) 210 + return (GSS_S_DEFECTIVE_TOKEN); 211 + 212 if (length & 0x80) { 213 if ((length & 0x7f) > 4) 214 return (GSS_S_DEFECTIVE_TOKEN); 215 buffer_ptr += length & 0x7f; 216 } 217 218 if (*(buffer_ptr++) != 0x06) 219 return (GSS_S_DEFECTIVE_TOKEN); 220 221 OID->length = (OM_uint32) *(buffer_ptr++); 222 OID->elements = (void *) buffer_ptr; 223 return (GSS_S_COMPLETE); 224 } 225 226 227 /* 228 * Internal routines to get and release an internal mechanism name 229 */ 230 OM_uint32 __gss_import_internal_name(minor_status, mech_type, union_name, 231 internal_name) 232 OM_uint32 *minor_status; 233 const gss_OID mech_type; 234 gss_union_name_t union_name; 235 gss_name_t *internal_name; 236 { 237 OM_uint32 status; 238 gss_mechanism mech; 239 240 mech = __gss_get_mechanism(mech_type); 241 if (mech) { 242 if (mech->gss_import_name) 243 status = mech->gss_import_name( 244 mech->context, 245 minor_status, 246 union_name->external_name, 247 union_name->name_type, 248 internal_name); 249 else 126 | status = GSS_S_BAD_BINDINGS; 250 | status = GSS_S_UNAVAILABLE; 251 252 return (status); 253 } 254 255 return (GSS_S_BAD_MECH); 256 } 257 258 + 259 + OM_uint32 __gss_export_internal_name(minor_status, mech_type, 260 + internal_name, name_buf) 261 + OM_uint32 *minor_status; 262 + const gss_OID mech_type; 263 + const gss_name_t internal_name; 264 + gss_buffer_t name_buf; 265 + { 266 + OM_uint32 status; 267 + gss_mechanism mech; 268 + gss_buffer_desc dispName; 269 + gss_OID nameOid; 270 + unsigned char *buf = NULL; 271 + const unsigned char tokId[] = "\x04\x01"; 272 + const int tokIdLen = 2; 273 + const int mechOidLenLen = 2, mechOidTagLen = 1, nameLenLen = 4; 274 + int mechOidDERLen = 0; 275 + int mechOidLen = 0; 276 + 277 + mech = __gss_get_mechanism(mech_type); 278 + if (!mech) 279 + return (GSS_S_BAD_MECH); 280 + 281 + if (mech->gss_export_name) 282 + return (mech->gss_export_name(mech->context, 283 + minor_status, 284 + internal_name, 285 + name_buf)); 286 + 287 + /* 288 + * if we are here it is because the mechanism does not provide 289 + * a gss_export_name so we will use our implementation. We 290 + * do required that the mechanism define a gss_display_name. 291 + */ 292 + if (!mech->gss_display_name) 293 + return (GSS_S_UNAVAILABLE); 294 + 295 + /* 296 + * NOTE: RFC2743 (section 3.2) governs the format of the outer 297 + * wrapper of exported names; the mechanisms' specs govern 298 + * the format of the inner portion of the exported name 299 + * and, for some (e.g., RFC1964, the Kerberos V mech), a 300 + * generic default as implemented here will do. 301 + * 302 + * The outer wrapper of an exported MN is: 2-octet tok Id 303 + * (0x0401) + 2-octet network-byte order mech OID length + mech 304 + * oid (in DER format, including DER tag and DER length) + 305 + * 4-octet network-byte order length of inner portion + inner 306 + * portion. 307 + * 308 + * For the Kerberos V mechanism the inner portion of an exported 309 + * MN is the display name string and ignores the name type OID 310 + * altogether. And we hope this will be so for any future 311 + * mechanisms also, so that factoring name export/import out of 312 + * the mech and into libgss pays off. 313 + */ 314 + if ((status = mech->gss_display_name(mech->context, 315 + minor_status, 316 + internal_name, 317 + &dispName, 318 + &nameOid)) 319 + != GSS_S_COMPLETE) 320 + return (status); 321 + 322 + /* determine the size of the buffer needed */ 323 + mechOidDERLen = der_length_size(mech_type->length); 324 + name_buf->length = tokIdLen + mechOidLenLen + 325 + mechOidTagLen + mechOidDERLen + 326 + mech_type->length + 327 + nameLenLen + dispName.length; 328 + if ((name_buf->value = (void*)malloc(name_buf->length)) == 329 + (void*)NULL) { 330 + name_buf->length = 0; 331 + (void) gss_release_buffer(&status, &dispName); 332 + return (GSS_S_FAILURE); 333 + } 334 + 335 + /* now create the name ..... */ 336 + buf = (unsigned char *)name_buf->value; 337 + (void) memset(name_buf->value, 0, name_buf->length); 338 + (void) memcpy(buf, tokId, tokIdLen); 339 + buf += tokIdLen; 340 + 341 + /* spec allows only 2 bytes for the mech oid length */ 342 + mechOidLen = mechOidDERLen + mechOidTagLen + mech_type->length; 343 + *buf++ = (mechOidLen & 0xFF00) >> 8; 344 + *buf++ = (mechOidLen & 0x00FF); 345 + 346 + /* 347 + * DER Encoding of mech OID contains OID Tag (0x06), length and 348 + * mech OID value 349 + */ 350 + *buf++ = 0x06; 351 + if (put_der_length(mech_type->length, &buf, 352 + (name_buf->length - tokIdLen -2)) != 0) { 353 + name_buf->length = 0; 354 + free(name_buf->value); 355 + (void) gss_release_buffer(&status, &dispName); 356 + return (GSS_S_FAILURE); 357 + } 358 + 359 + (void) memcpy(buf, mech_type->elements, mech_type->length); 360 + buf += mech_type->length; 361 + 362 + /* spec designates the next 4 bytes for the name length */ 363 + *buf++ = (dispName.length & 0xFF000000) >> 24; 364 + *buf++ = (dispName.length & 0x00FF0000) >> 16; 365 + *buf++ = (dispName.length & 0x0000FF00) >> 8; 366 + *buf++ = (dispName.length & 0X000000FF); 367 + 368 + /* for the final ingredient - add the name from gss_display_name */ 369 + (void) memcpy(buf, dispName.value, dispName.length); 370 + 371 + /* release the buffer obtained from gss_display_name */ 372 + (void) gss_release_buffer(minor_status, &dispName); 373 + return (GSS_S_COMPLETE); 374 + } /* __gss_export_internal_name */ 375 + 376 + 377 OM_uint32 __gss_display_internal_name(minor_status, mech_type, internal_name, 378 external_name, name_type) 379 OM_uint32 *minor_status; 380 const gss_OID mech_type; 381 const gss_name_t internal_name; 382 gss_buffer_t external_name; 383 gss_OID *name_type; 384 { 385 OM_uint32 status; 386 gss_mechanism mech; 387 388 mech = __gss_get_mechanism(mech_type); 389 if (mech) { 390 if (mech->gss_display_name) 391 status = mech->gss_display_name( 392 mech->context, 393 minor_status, 394 internal_name, 395 external_name, 396 name_type); 397 else 155 | status = GSS_S_BAD_BINDINGS; 398 | status = GSS_S_UNAVAILABLE; 399 400 return (status); 401 } 402 403 return (GSS_S_BAD_MECH); 404 } 405 406 OM_uint32 407 __gss_release_internal_name(minor_status, mech_type, internal_name) 408 OM_uint32 *minor_status; 409 const gss_OID mech_type; 410 gss_name_t *internal_name; 411 { 412 OM_uint32 status; 413 gss_mechanism mech; 414 415 mech = __gss_get_mechanism(mech_type); 416 if (mech) { 417 if (mech->gss_release_name) 418 status = mech->gss_release_name( 419 mech->context, 420 minor_status, 421 internal_name); 422 else 180 | status = GSS_S_BAD_BINDINGS; 423 | status = GSS_S_UNAVAILABLE; 424 425 return (status); 426 } 427 428 return (GSS_S_BAD_MECH); 429 } 430 431 432 /* 433 * This function converts an internal gssapi name to a union gssapi 434 * name. Note that internal_name should be considered "consumed" by 435 * this call, whether or not we return an error. 436 */ 437 OM_uint32 __gss_convert_name_to_union_name(minor_status, mech, 438 internal_name, external_name) 439 OM_uint32 *minor_status; 440 gss_mechanism mech; 441 gss_name_t internal_name; 442 gss_name_t *external_name; 443 { 444 OM_uint32 major_status, tmp; 445 gss_union_name_t union_name; 446 447 union_name = (gss_union_name_t)malloc(sizeof (gss_union_name_desc)); 206 - *minor_status = ENOMEM; 448 if (!union_name) { 449 goto allocation_failure; 450 } 451 union_name->mech_type = 0; 452 union_name->mech_name = internal_name; 453 union_name->name_type = 0; 454 union_name->external_name = 0; 455 456 major_status = generic_gss_copy_oid(minor_status, &mech->mech_type, 457 &union_name->mech_type); 458 if (major_status != GSS_S_COMPLETE) 459 goto allocation_failure; 460 461 union_name->external_name = 462 (gss_buffer_t)malloc(sizeof (gss_buffer_desc)); 222 - *minor_status = ENOMEM; 463 if (!union_name->external_name) { 464 goto allocation_failure; 465 } 466 467 major_status = mech->gss_display_name(mech->context, minor_status, 468 internal_name, 469 union_name->external_name, 470 &union_name->name_type); 471 if (major_status != GSS_S_COMPLETE) 472 goto allocation_failure; 473 474 *external_name = (gss_name_t)union_name; 475 return (GSS_S_COMPLETE); 476 477 allocation_failure: 478 if (union_name) { 479 if (union_name->external_name) { 480 if (union_name->external_name->value) 481 free(union_name->external_name->value); 482 free(union_name->external_name); 483 } 484 if (union_name->name_type) 245 - if (union_name->mech_name) 246 - (void) __gss_release_internal_name(minor_status, 247 - union_name->mech_type, &union_name->mech_name); 485 (void) gss_release_oid(&tmp, &union_name->name_type); 486 if (union_name->mech_type) 487 (void) gss_release_oid(&tmp, &union_name->mech_type); 488 free(union_name); 489 } 490 + /* 491 + * do as the top comment says - since we are now owners of 492 + * internal_name, we must clean it up 493 + */ 494 + if (internal_name) 495 + (void) __gss_release_internal_name(&tmp, &mech->mech_type, 496 + &internal_name); 497 498 return (major_status); 499 } ----Unchanged portion omitted---- 521 522 + 523 + /* 524 + * Routine to create and copy the gss_buffer_desc structure. 525 + * Both space for the structure and the data is allocated. 526 + */ 527 + OM_uint32 528 + __gss_create_copy_buffer(srcBuf, destBuf, addNullChar) 529 + const gss_buffer_t srcBuf; 530 + gss_buffer_t *destBuf; 531 + int addNullChar; 532 + { 533 + gss_buffer_t aBuf; 534 + int len; 535 + 536 + if (destBuf == NULL) 537 + return (GSS_S_CALL_INACCESSIBLE_WRITE); 538 + 539 + *destBuf = 0; 540 + 541 + aBuf = (gss_buffer_t)malloc(sizeof (gss_buffer_desc)); 542 + if (!aBuf) 543 + return (GSS_S_FAILURE); 544 + 545 + if (addNullChar) 546 + len = srcBuf->length + 1; 547 + else 548 + len = srcBuf->length; 549 + 550 + if (!(aBuf->value = (void*)malloc(len))) { 551 + free(aBuf); 552 + return (GSS_S_FAILURE); 553 + } 554 + 555 + 556 + (void) memcpy(aBuf->value, srcBuf->value, srcBuf->length); 557 + aBuf->length = srcBuf->length; 558 + *destBuf = aBuf; 559 + 560 + /* optionally add a NULL character */ 561 + if (addNullChar) 562 + ((char *)aBuf->value)[aBuf->length] = '\0'; 563 + 564 + return (GSS_S_COMPLETE); 565 + } /* ****** __gss_create_copy_buffer ****** */