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