summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Hudson <ghudson@mit.edu>2023-03-15 13:56:21 -0400
committerGreg Hudson <ghudson@mit.edu>2023-03-24 14:45:58 -0400
commitfdceb225f881e2b1337eebcb9a9443fa4a9be3fd (patch)
treed99be44b7aceb75fa0b7118a924fdd587bfff434
parent548da160b52b25a106e9f6077d6a42c2c049586c (diff)
downloadkrb5-fdceb225f881e2b1337eebcb9a9443fa4a9be3fd.tar.gz
Use k5-der.h in GSS library
Remove the DER implementations in lib/gssapi and use k5-der.h instead.
-rw-r--r--src/lib/gssapi/generic/gssapiP_generic.h4
-rw-r--r--src/lib/gssapi/generic/util_token.c199
-rw-r--r--src/lib/gssapi/krb5/accept_sec_context.c26
-rw-r--r--src/lib/gssapi/krb5/iakerb.c60
-rw-r--r--src/lib/gssapi/krb5/init_sec_context.c18
-rw-r--r--src/lib/gssapi/krb5/k5seal.c59
-rw-r--r--src/lib/gssapi/krb5/k5sealiov.c47
-rw-r--r--src/lib/gssapi/mechglue/g_encapsulate_token.c10
-rw-r--r--src/lib/gssapi/mechglue/g_glue.c284
-rw-r--r--src/lib/gssapi/mechglue/g_imp_name.c112
-rw-r--r--src/lib/gssapi/mechglue/mglueP.h17
-rw-r--r--src/lib/gssapi/spnego/spnego_mech.c1168
12 files changed, 474 insertions, 1530 deletions
diff --git a/src/lib/gssapi/generic/gssapiP_generic.h b/src/lib/gssapi/generic/gssapiP_generic.h
index 686a21772..5d01fb492 100644
--- a/src/lib/gssapi/generic/gssapiP_generic.h
+++ b/src/lib/gssapi/generic/gssapiP_generic.h
@@ -153,8 +153,8 @@ int g_make_string_buffer (const char *str, gss_buffer_t buffer);
unsigned int g_token_size (const gss_OID_desc * mech, unsigned int body_size);
-void g_make_token_header (const gss_OID_desc * mech, unsigned int body_size,
- unsigned char **buf, int tok_type);
+void g_make_token_header (struct k5buf *buf, const gss_OID_desc *mech,
+ size_t body_size, int tok_type);
/* flags for g_verify_token_header() */
#define G_VFY_TOKEN_HDR_WRAPPER_REQUIRED 0x01
diff --git a/src/lib/gssapi/generic/util_token.c b/src/lib/gssapi/generic/util_token.c
index 6e339f4ac..2369cae22 100644
--- a/src/lib/gssapi/generic/util_token.c
+++ b/src/lib/gssapi/generic/util_token.c
@@ -22,6 +22,7 @@
*/
#include "gssapiP_generic.h"
+#include "k5-der.h"
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
@@ -31,131 +32,33 @@
* $Id$
*/
-/* XXXX this code currently makes the assumption that a mech oid will
- never be longer than 127 bytes. This assumption is not inherent in
- the interfaces, so the code can be fixed if the OSI namespace
- balloons unexpectedly. */
-
-/*
- * Each token looks like this:
- * 0x60 tag for APPLICATION 0, SEQUENCE
- * (constructed, definite-length)
- * <length> possible multiple bytes, need to parse/generate
- * 0x06 tag for OBJECT IDENTIFIER
- * <moid_length> compile-time constant string (assume 1 byte)
- * <moid_bytes> compile-time constant string
- * <inner_bytes> the ANY containing the application token
- * bytes 0,1 are the token type
- * bytes 2,n are the token data
- *
- * Note that the token type field is a feature of RFC 1964 mechanisms and
- * is not used by other GSSAPI mechanisms. As such, a token type of -1
- * is interpreted to mean that no token type should be expected or
- * generated.
- *
- * For the purposes of this abstraction, the token "header" consists of
- * the sequence tag and length octets, the mech OID DER encoding, and the
- * first two inner bytes, which indicate the token type. The token
- * "body" consists of everything else.
- */
-static unsigned int
-der_length_size(int length)
-{
- if (length < (1<<7))
- return(1);
- else if (length < (1<<8))
- return(2);
-#if INT_MAX == 0x7fff
- else
- return(3);
-#else
- else if (length < (1<<16))
- return(3);
- else if (length < (1<<24))
- return(4);
- else
- return(5);
-#endif
-}
-
-static void
-der_write_length(unsigned char **buf, int length)
-{
- if (length < (1<<7)) {
- *(*buf)++ = (unsigned char) length;
- } else {
- *(*buf)++ = (unsigned char) (der_length_size(length)+127);
-#if INT_MAX > 0x7fff
- if (length >= (1<<24))
- *(*buf)++ = (unsigned char) (length>>24);
- if (length >= (1<<16))
- *(*buf)++ = (unsigned char) ((length>>16)&0xff);
-#endif
- if (length >= (1<<8))
- *(*buf)++ = (unsigned char) ((length>>8)&0xff);
- *(*buf)++ = (unsigned char) (length&0xff);
- }
-}
-
-/* returns decoded length, or < 0 on failure. Advances buf and
- decrements bufsize */
-
-static int
-der_read_length(unsigned char **buf, int *bufsize)
-{
- unsigned char sf;
- int ret;
-
- if (*bufsize < 1)
- return(-1);
- sf = *(*buf)++;
- (*bufsize)--;
- if (sf & 0x80) {
- if ((sf &= 0x7f) > ((*bufsize)-1))
- return(-1);
- if (sf > sizeof(int))
- return (-1);
- ret = 0;
- for (; sf; sf--) {
- ret = (ret<<8) + (*(*buf)++);
- (*bufsize)--;
- }
- } else {
- ret = sf;
- }
-
- return(ret);
-}
-
-/* returns the length of a token, given the mech oid and the body size */
-
+/* Return the length of an RFC 4121 token with RFC 2743 token framing, given
+ * the mech oid and the body size (without the two-byte RFC 4121 token ID). */
unsigned int
g_token_size(const gss_OID_desc * mech, unsigned int body_size)
{
- /* set body_size to sequence contents size */
- body_size += 4 + (unsigned int)mech->length; /* NEED overflow check */
- return(1 + der_length_size(body_size) + body_size);
-}
+ size_t mech_der_len = k5_der_value_len(mech->length);
-/* fills in a buffer with the token header. The buffer is assumed to
- be the right size. buf is advanced past the token header */
+ return k5_der_value_len(mech_der_len + 2 + body_size);
+}
+/*
+ * Add RFC 2743 generic token framing to buf with room left for body_size bytes
+ * in the sequence to be added by the caller. If tok_type is not -1, add it as
+ * a two-byte RFC 4121 token identifier after the framing and include room for
+ * it in the sequence.
+ */
void
-g_make_token_header(
- const gss_OID_desc * mech,
- unsigned int body_size,
- unsigned char **buf,
- int tok_type)
+g_make_token_header(struct k5buf *buf, const gss_OID_desc *mech,
+ size_t body_size, int tok_type)
{
- *(*buf)++ = 0x60;
- der_write_length(buf, ((tok_type == -1) ? 2 : 4) + mech->length + body_size);
- *(*buf)++ = 0x06;
- *(*buf)++ = (unsigned char) mech->length;
- TWRITE_STR(*buf, mech->elements, mech->length);
- if (tok_type != -1) {
- *(*buf)++ = (unsigned char) ((tok_type>>8)&0xff);
- *(*buf)++ = (unsigned char) (tok_type&0xff);
- }
+ size_t tok_len = (tok_type == -1) ? 0 : 2;
+ size_t seq_len = k5_der_value_len(mech->length) + body_size + tok_len;
+
+ k5_der_add_taglen(buf, 0x60, seq_len);
+ k5_der_add_value(buf, 0x06, mech->elements, mech->length);
+ if (tok_type != -1)
+ k5_buf_add_uint16_be(buf, tok_type);
}
/*
@@ -176,54 +79,30 @@ g_verify_token_header(
unsigned int toksize_in,
int flags)
{
- unsigned char *buf = *buf_in;
- int seqsize;
+ struct k5input in, mech_der;
gss_OID_desc toid;
- int toksize = toksize_in;
- if ((toksize-=1) < 0)
- return(G_BAD_TOK_HEADER);
- if (*buf++ != 0x60) {
- if (flags & G_VFY_TOKEN_HDR_WRAPPER_REQUIRED)
- return(G_BAD_TOK_HEADER);
- buf--;
- toksize++;
- goto skip_wrapper;
+ k5_input_init(&in, *buf_in, toksize_in);
+
+ if (k5_der_get_value(&in, 0x60, &in)) {
+ if (in.ptr + in.len != *buf_in + toksize_in)
+ return G_BAD_TOK_HEADER;
+ if (!k5_der_get_value(&in, 0x06, &mech_der))
+ return G_BAD_TOK_HEADER;
+ toid.elements = (uint8_t *)mech_der.ptr;
+ toid.length = mech_der.len;
+ if (!g_OID_equal(&toid, mech))
+ return G_WRONG_MECH;
+ } else if (flags & G_VFY_TOKEN_HDR_WRAPPER_REQUIRED) {
+ return G_BAD_TOK_HEADER;
}
- if ((seqsize = der_read_length(&buf, &toksize)) < 0)
- return(G_BAD_TOK_HEADER);
-
- if (seqsize != toksize)
- return(G_BAD_TOK_HEADER);
-
- if ((toksize-=1) < 0)
- return(G_BAD_TOK_HEADER);
- if (*buf++ != 0x06)
- return(G_BAD_TOK_HEADER);
-
- if ((toksize-=1) < 0)
- return(G_BAD_TOK_HEADER);
- toid.length = *buf++;
-
- if ((toksize-=toid.length) < 0)
- return(G_BAD_TOK_HEADER);
- toid.elements = buf;
- buf+=toid.length;
-
- if (! g_OID_equal(&toid, mech))
- return G_WRONG_MECH;
-skip_wrapper:
if (tok_type != -1) {
- if ((toksize-=2) < 0)
- return(G_BAD_TOK_HEADER);
-
- if ((*buf++ != ((tok_type>>8)&0xff)) ||
- (*buf++ != (tok_type&0xff)))
- return(G_WRONG_TOKID);
+ if (k5_input_get_uint16_be(&in) != tok_type)
+ return in.status ? G_BAD_TOK_HEADER : G_WRONG_TOKID;
}
- *buf_in = buf;
- *body_size = toksize;
+ *buf_in = (uint8_t *)in.ptr;
+ *body_size = in.len;
return 0;
}
diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c
index 44c056afd..dd4caf380 100644
--- a/src/lib/gssapi/krb5/accept_sec_context.c
+++ b/src/lib/gssapi/krb5/accept_sec_context.c
@@ -684,6 +684,7 @@ kg_accept_krb5(minor_status, context_handle,
krb5_enctype negotiated_etype;
krb5_authdata_context ad_context = NULL;
krb5_ap_req *request = NULL;
+ struct k5buf buf;
code = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
if (code) {
@@ -1009,7 +1010,6 @@ kg_accept_krb5(minor_status, context_handle,
/* generate an AP_REP if necessary */
if (ctx->gss_flags & GSS_C_MUTUAL_FLAG) {
- unsigned char * ptr3;
krb5_int32 seq_temp;
int cfx_generate_subkey;
@@ -1114,18 +1114,16 @@ kg_accept_krb5(minor_status, context_handle,
ctx->established = 1;
token.length = g_token_size(mech_used, ap_rep.length);
-
- if ((token.value = (unsigned char *) gssalloc_malloc(token.length))
- == NULL) {
+ token.value = gssalloc_malloc(token.length);
+ if (token.value == NULL) {
major_status = GSS_S_FAILURE;
code = ENOMEM;
goto fail;
}
- ptr3 = token.value;
- g_make_token_header(mech_used, ap_rep.length,
- &ptr3, KG_TOK_CTX_AP_REP);
-
- TWRITE_STR(ptr3, ap_rep.data, ap_rep.length);
+ k5_buf_init_fixed(&buf, token.value, token.length);
+ g_make_token_header(&buf, mech_used, ap_rep.length, KG_TOK_CTX_AP_REP);
+ k5_buf_add_len(&buf, ap_rep.data, ap_rep.length);
+ assert(buf.len == token.length);
ctx->established = 1;
@@ -1220,7 +1218,6 @@ fail:
(request->ap_options & AP_OPTS_MUTUAL_REQUIRED) ||
major_status == GSS_S_CONTINUE_NEEDED)) {
unsigned int tmsglen;
- int toktype;
/*
* The client is expecting a response, so we can send an
@@ -1242,17 +1239,16 @@ fail:
goto done;
tmsglen = scratch.length;
- toktype = KG_TOK_CTX_ERROR;
token.length = g_token_size(mech_used, tmsglen);
token.value = gssalloc_malloc(token.length);
if (!token.value)
goto done;
+ k5_buf_init_fixed(&buf, token.value, token.length);
+ g_make_token_header(&buf, mech_used, tmsglen, KG_TOK_CTX_ERROR);
+ k5_buf_add_len(&buf, scratch.data, scratch.length);
+ assert(buf.len == token.length);
- ptr = token.value;
- g_make_token_header(mech_used, tmsglen, &ptr, toktype);
-
- TWRITE_STR(ptr, scratch.data, scratch.length);
krb5_free_data_contents(context, &scratch);
*output_token = token;
diff --git a/src/lib/gssapi/krb5/iakerb.c b/src/lib/gssapi/krb5/iakerb.c
index b0d0ede17..a0d298c49 100644
--- a/src/lib/gssapi/krb5/iakerb.c
+++ b/src/lib/gssapi/krb5/iakerb.c
@@ -23,14 +23,13 @@
* or implied warranty.
*/
#include "k5-int.h"
+#include "k5-der.h"
#include "gssapiP_krb5.h"
/*
* IAKERB implementation
*/
-extern int gssint_get_der_length(unsigned char **, OM_uint32, unsigned int*);
-
enum iakerb_state {
IAKERB_AS_REQ, /* acquiring ticket with initial creds */
IAKERB_TGS_REQ, /* acquiring ticket with TGT */
@@ -172,11 +171,11 @@ iakerb_parse_token(iakerb_ctx_id_t ctx,
{
krb5_error_code code;
krb5_iakerb_header *iah = NULL;
- unsigned int bodysize, lenlen;
- int length;
- unsigned char *ptr;
+ unsigned int bodysize;
+ uint8_t *body;
int flags = 0;
krb5_data data;
+ struct k5input in, seq;
if (token == GSS_C_NO_BUFFER || token->length == 0) {
code = KRB5_BAD_MSIZE;
@@ -186,32 +185,20 @@ iakerb_parse_token(iakerb_ctx_id_t ctx,
if (initialContextToken)
flags |= G_VFY_TOKEN_HDR_WRAPPER_REQUIRED;
- ptr = token->value;
-
- code = g_verify_token_header(gss_mech_iakerb,
- &bodysize, &ptr,
- IAKERB_TOK_PROXY,
- token->length, flags);
+ body = token->value;
+ code = g_verify_token_header(gss_mech_iakerb, &bodysize, &body,
+ IAKERB_TOK_PROXY, token->length, flags);
if (code != 0)
goto cleanup;
- data.data = (char *)ptr;
-
- if (bodysize-- == 0 || *ptr++ != 0x30 /* SEQUENCE */) {
+ /* Find the end of the DER sequence tag and decode it (with the tag) as the
+ * IAKERB jeader. */
+ k5_input_init(&in, body, bodysize);
+ if (!k5_der_get_value(&in, 0x30, &seq)) {
code = ASN1_BAD_ID;
goto cleanup;
}
-
- length = gssint_get_der_length(&ptr, bodysize, &lenlen);
- if (length < 0 || bodysize - lenlen < (unsigned int)length) {
- code = KRB5_BAD_MSIZE;
- goto cleanup;
- }
- data.length = 1 /* SEQUENCE */ + lenlen + length;
-
- ptr += length;
- bodysize -= (lenlen + length);
-
+ data = make_data(body, seq.ptr + seq.len - body);
code = decode_krb5_iakerb_header(&data, &iah);
if (code != 0)
goto cleanup;
@@ -226,9 +213,8 @@ iakerb_parse_token(iakerb_ctx_id_t ctx,
iah->cookie = NULL;
}
- request->data = (char *)ptr;
- request->length = bodysize;
-
+ /* The remainder of the token body is the request. */
+ *request = make_data((uint8_t *)in.ptr, in.len);
assert(request->data + request->length ==
(char *)token->value + token->length);
@@ -254,7 +240,7 @@ iakerb_make_token(iakerb_ctx_id_t ctx,
krb5_data *data = NULL;
char *p;
unsigned int tokenSize;
- unsigned char *q;
+ struct k5buf buf;
token->value = NULL;
token->length = 0;
@@ -288,24 +274,22 @@ iakerb_make_token(iakerb_ctx_id_t ctx,
else
tokenSize = 2 + data->length;
- token->value = q = gssalloc_malloc(tokenSize);
- if (q == NULL) {
+ token->value = gssalloc_malloc(tokenSize);
+ if (token->value == NULL) {
code = ENOMEM;
goto cleanup;
}
token->length = tokenSize;
+ k5_buf_init_fixed(&buf, token->value, token->length);
if (initialContextToken) {
- g_make_token_header(gss_mech_iakerb, data->length, &q,
+ g_make_token_header(&buf, gss_mech_iakerb, data->length,
IAKERB_TOK_PROXY);
} else {
- store_16_be(IAKERB_TOK_PROXY, q);
- q += 2;
+ k5_buf_add_uint16_be(&buf, IAKERB_TOK_PROXY);
}
- memcpy(q, data->data, data->length);
- q += data->length;
-
- assert(q == (unsigned char *)token->value + token->length);
+ k5_buf_add_len(&buf, data->data, data->length);
+ assert(buf.len == token->length);
cleanup:
krb5_free_data(ctx->k5c, data);
diff --git a/src/lib/gssapi/krb5/init_sec_context.c b/src/lib/gssapi/krb5/init_sec_context.c
index f0f094ccb..83fd514c1 100644
--- a/src/lib/gssapi/krb5/init_sec_context.c
+++ b/src/lib/gssapi/krb5/init_sec_context.c
@@ -393,9 +393,9 @@ make_ap_req_v1(context, ctx, cred, k_cred, ad_context,
struct gss_checksum_data cksum_struct;
krb5_checksum md5;
krb5_data ap_req;
- unsigned char *ptr;
unsigned char *t;
unsigned int tlen;
+ struct k5buf buf;
k5_mutex_assert_locked(&cred->lock);
ap_req.data = 0;
@@ -447,19 +447,15 @@ make_ap_req_v1(context, ctx, cred, k_cred, ad_context,
} else {
/* allocate space for the token */
tlen = g_token_size((gss_OID) mech_type, ap_req.length);
-
- if ((t = (unsigned char *) gssalloc_malloc(tlen)) == NULL) {
+ t = gssalloc_malloc(tlen);
+ if (t == NULL) {
code = ENOMEM;
goto cleanup;
}
-
- /* fill in the buffer */
- ptr = t;
-
- g_make_token_header(mech_type, ap_req.length,
- &ptr, KG_TOK_CTX_AP_REQ);
-
- TWRITE_STR(ptr, ap_req.data, ap_req.length);
+ k5_buf_init_fixed(&buf, t, tlen);
+ g_make_token_header(&buf, mech_type, ap_req.length, KG_TOK_CTX_AP_REQ);
+ k5_buf_add_len(&buf, ap_req.data, ap_req.length);
+ assert(buf.len == tlen);
/* pass it back */
diff --git a/src/lib/gssapi/krb5/k5seal.c b/src/lib/gssapi/krb5/k5seal.c
index d1cdce486..99275be53 100644
--- a/src/lib/gssapi/krb5/k5seal.c
+++ b/src/lib/gssapi/krb5/k5seal.c
@@ -78,11 +78,11 @@ make_seal_token_v1 (krb5_context context,
* tlen is the length of the token
* including header. */
unsigned int conflen=0, tmsglen, tlen, msglen;
- unsigned char *t, *ptr;
+ unsigned char *t, *metadata, *checksum, *payload;
unsigned char *plain;
unsigned char pad;
krb5_keyusage sign_usage = KG_USAGE_SIGN;
-
+ struct k5buf buf;
assert((!do_encrypt) || (toktype == KG_TOK_SEAL_MSG));
/* create the token buffer */
@@ -108,31 +108,37 @@ make_seal_token_v1 (krb5_context context,
msglen = text->length;
pad = 0;
}
- tlen = g_token_size((gss_OID) oid, 14+cksum_size+tmsglen);
- if ((t = (unsigned char *) gssalloc_malloc(tlen)) == NULL)
+ tlen = g_token_size(oid, 14 + cksum_size + tmsglen);
+ t = gssalloc_malloc(tlen);
+ if (t == NULL)
return(ENOMEM);
+ k5_buf_init_fixed(&buf, t, tlen);
/*** fill in the token */
- ptr = t;
- g_make_token_header(oid, 14+cksum_size+tmsglen, &ptr, toktype);
+ g_make_token_header(&buf, oid, 14 + cksum_size + tmsglen, toktype);
+ metadata = k5_buf_get_space(&buf, 14);
+ checksum = k5_buf_get_space(&buf, cksum_size);
+ payload = k5_buf_get_space(&buf, tmsglen);
+ assert(metadata != NULL && checksum != NULL && payload != NULL);
+ assert(buf.len == tlen);
/* 0..1 SIGN_ALG */
- store_16_le(signalg, &ptr[0]);
+ store_16_le(signalg, &metadata[0]);
/* 2..3 SEAL_ALG or Filler */
if ((toktype == KG_TOK_SEAL_MSG) && do_encrypt) {
- store_16_le(sealalg, &ptr[2]);
+ store_16_le(sealalg, &metadata[2]);
} else {
/* No seal */
- ptr[2] = 0xff;
- ptr[3] = 0xff;
+ metadata[2] = 0xFF;
+ metadata[3] = 0xFF;
}
/* 4..5 Filler */
- ptr[4] = 0xff;
- ptr[5] = 0xff;
+ metadata[4] = 0xFF;
+ metadata[5] = 0xFF;
/* pad the plaintext, encrypt if needed, and stick it in the token */
@@ -183,8 +189,9 @@ make_seal_token_v1 (krb5_context context,
gssalloc_free(t);
return(ENOMEM);
}
- (void) memcpy(data_ptr, ptr-2, 8);
- (void) memcpy(data_ptr+8, plain, msglen);
+ /* Checksum over the token ID, metadata bytes, and plaintext. */
+ memcpy(data_ptr, metadata - 2, 8);
+ memcpy(data_ptr + 8, plain, msglen);
plaind.length = 8 + msglen;
plaind.data = data_ptr;
code = krb5_k_make_checksum(context, md5cksum.checksum_type, seq,
@@ -204,10 +211,10 @@ make_seal_token_v1 (krb5_context context,
*/
if (md5cksum.length != cksum_size)
abort ();
- memcpy (ptr+14, md5cksum.contents, md5cksum.length);
+ memcpy(checksum, md5cksum.contents, md5cksum.length);
break;
case SGN_ALG_HMAC_MD5:
- memcpy (ptr+14, md5cksum.contents, cksum_size);
+ memcpy(checksum, md5cksum.contents, cksum_size);
break;
}
@@ -215,8 +222,9 @@ make_seal_token_v1 (krb5_context context,
/* create the seq_num */
- if ((code = kg_make_seq_num(context, seq, direction?0:0xff,
- (krb5_ui_4)*seqnum, ptr+14, ptr+6))) {
+ code = kg_make_seq_num(context, seq, direction?0:0xff,
+ (krb5_ui_4)*seqnum, checksum, metadata + 6);
+ if (code) {
xfree (plain);
gssalloc_free(t);
return(code);
@@ -240,10 +248,8 @@ make_seal_token_v1 (krb5_context context,
assert (enc_key->length == 16);
for (i = 0; i <= 15; i++)
((char *) enc_key->contents)[i] ^=0xf0;
- code = kg_arcfour_docrypt (enc_key, 0,
- bigend_seqnum, 4,
- plain, tmsglen,
- ptr+14+cksum_size);
+ code = kg_arcfour_docrypt(enc_key, 0, bigend_seqnum, 4, plain,
+ tmsglen, payload);
krb5_free_keyblock (context, enc_key);
if (code)
{
@@ -254,10 +260,9 @@ make_seal_token_v1 (krb5_context context,
}
break;
default:
- if ((code = kg_encrypt(context, enc, KG_USAGE_SEAL, NULL,
- (krb5_pointer) plain,
- (krb5_pointer) (ptr+cksum_size+14),
- tmsglen))) {
+ code = kg_encrypt(context, enc, KG_USAGE_SEAL, NULL, plain,
+ payload, tmsglen);
+ if (code) {
xfree(plain);
gssalloc_free(t);
return(code);
@@ -265,7 +270,7 @@ make_seal_token_v1 (krb5_context context,
}
}else {
if (tmsglen)
- memcpy(ptr+14+cksum_size, plain, tmsglen);
+ memcpy(payload, plain, tmsglen);
}
xfree(plain);
diff --git a/src/lib/gssapi/krb5/k5sealiov.c b/src/lib/gssapi/krb5/k5sealiov.c
index 9bb2ee109..7bf7609a4 100644
--- a/src/lib/gssapi/krb5/k5sealiov.c
+++ b/src/lib/gssapi/krb5/k5sealiov.c
@@ -44,9 +44,10 @@ make_seal_token_v1_iov(krb5_context context,
krb5_checksum cksum;
size_t k5_headerlen = 0, k5_trailerlen = 0;
size_t data_length = 0, assoc_data_length = 0;
- size_t tmsglen = 0, tlen;
- unsigned char *ptr;
+ size_t tmsglen = 0, cnflen = 0, tlen;
+ uint8_t *metadata, *checksum, *confounder;
krb5_keyusage sign_usage = KG_USAGE_SIGN;
+ struct k5buf buf;
md5cksum.length = cksum.length = 0;
md5cksum.contents = cksum.contents = NULL;
@@ -65,17 +66,15 @@ make_seal_token_v1_iov(krb5_context context,
trailer->buffer.length = 0;
/* Determine confounder length */
- if (toktype == KG_TOK_WRAP_MSG || conf_req_flag)
- k5_headerlen = kg_confounder_size(context, ctx->enc->keyblock.enctype);
-
- /* Check padding length */
if (toktype == KG_TOK_WRAP_MSG) {
size_t k5_padlen = (ctx->sealalg == SEAL_ALG_MICROSOFT_RC4) ? 1 : 8;
size_t gss_padlen;
size_t conf_data_length;
+ cnflen = kg_confounder_size(context, ctx->enc->keyblock.enctype);
+
kg_iov_msglen(iov, iov_count, &data_length, &assoc_data_length);
- conf_data_length = k5_headerlen + data_length - assoc_data_length;
+ conf_data_length = cnflen + data_length - assoc_data_length;
if (k5_padlen == 1)
gss_padlen = 1; /* one byte to indicate one byte of padding */
@@ -103,7 +102,7 @@ make_seal_token_v1_iov(krb5_context context,
}
if (ctx->gss_flags & GSS_C_DCE_STYLE)
- tmsglen = k5_headerlen; /* confounder length */
+ tmsglen = cnflen; /* confounder length */
else
tmsglen = conf_data_length + padding->buffer.length;
}
@@ -111,7 +110,7 @@ make_seal_token_v1_iov(krb5_context context,
/* Determine token size */
tlen = g_token_size(ctx->mech_used, 14 + ctx->cksum_size + tmsglen);
- k5_headerlen += tlen - tmsglen;
+ k5_headerlen = cnflen + tlen - tmsglen;
if (header->type & GSS_IOV_BUFFER_FLAG_ALLOCATE)
code = kg_allocate_iov(header, k5_headerlen);
@@ -122,24 +121,28 @@ make_seal_token_v1_iov(krb5_context context,
header->buffer.length = k5_headerlen;
- ptr = (unsigned char *)header->buffer.value;
- g_make_token_header(ctx->mech_used, 14 + ctx->cksum_size + tmsglen, &ptr, toktype);
+ k5_buf_init_fixed(&buf, header->buffer.value, k5_headerlen);
+ g_make_token_header(&buf, ctx->mech_used, 14 + ctx->cksum_size + tmsglen,
+ toktype);
+ metadata = k5_buf_get_space(&buf, 14);
+ checksum = k5_buf_get_space(&buf, ctx->cksum_size);
+ assert(metadata != NULL && checksum != NULL);
/* 0..1 SIGN_ALG */
- store_16_le(ctx->signalg, &ptr[0]);
+ store_16_le(ctx->signalg, &metadata[0]);
/* 2..3 SEAL_ALG or Filler */
if (toktype == KG_TOK_WRAP_MSG && conf_req_flag) {
- store_16_le(ctx->sealalg, &ptr[2]);
+ store_16_le(ctx->sealalg, &metadata[2]);
} else {
/* No seal */
- ptr[2] = 0xFF;
- ptr[3] = 0xFF;
+ metadata[2] = 0xFF;
+ metadata[3] = 0xFF;
}
/* 4..5 Filler */
- ptr[4] = 0xFF;
- ptr[5] = 0xFF;
+ metadata[4] = 0xFF;
+ metadata[5] = 0xFF;
/* pad the plaintext, encrypt if needed, and stick it in the token */
@@ -163,8 +166,10 @@ make_seal_token_v1_iov(krb5_context context,
md5cksum.length = k5_trailerlen;
if (k5_headerlen != 0 && toktype == KG_TOK_WRAP_MSG) {
+ confounder = k5_buf_get_space(&buf, cnflen);
+ assert(confounder != NULL);
code = kg_make_confounder(context, ctx->enc->keyblock.enctype,
- ptr + 14 + ctx->cksum_size);
+ confounder);
if (code != 0)
goto cleanup;
}
@@ -180,16 +185,16 @@ make_seal_token_v1_iov(krb5_context context,
switch (ctx->signalg) {
case SGN_ALG_HMAC_SHA1_DES3_KD:
assert(md5cksum.length == ctx->cksum_size);
- memcpy(ptr + 14, md5cksum.contents, md5cksum.length);
+ memcpy(checksum, md5cksum.contents, md5cksum.length);
break;
case SGN_ALG_HMAC_MD5:
- memcpy(ptr + 14, md5cksum.contents, ctx->cksum_size);
+ memcpy(checksum, md5cksum.contents, ctx->cksum_size);
break;
}
/* create the seq_num */
code = kg_make_seq_num(context, ctx->seq, ctx->initiate ? 0 : 0xFF,
- (OM_uint32)ctx->seq_send, ptr + 14, ptr + 6);
+ (OM_uint32)ctx->seq_send, checksum, metadata + 6);
if (code != 0)
goto cleanup;
diff --git a/src/lib/gssapi/mechglue/g_encapsulate_token.c b/src/lib/gssapi/mechglue/g_encapsulate_token.c
index 850e3ee65..1ccd3cd73 100644
--- a/src/lib/gssapi/mechglue/g_encapsulate_token.c
+++ b/src/lib/gssapi/mechglue/g_encapsulate_token.c
@@ -38,7 +38,7 @@ gss_encapsulate_token(gss_const_buffer_t input_token,
gss_buffer_t output_token)
{
unsigned int tokenSize;
- unsigned char *buf;
+ struct k5buf buf;
if (input_token == GSS_C_NO_BUFFER || token_oid == GSS_C_NO_OID)
return GSS_S_CALL_INACCESSIBLE_READ;
@@ -55,10 +55,10 @@ gss_encapsulate_token(gss_const_buffer_t input_token,
if (output_token->value == NULL)
return GSS_S_FAILURE;
- buf = output_token->value;
-
- g_make_token_header(token_oid, input_token->length, &buf, -1);
- memcpy(buf, input_token->value, input_token->length);
+ k5_buf_init_fixed(&buf, output_token->value, tokenSize);
+ g_make_token_header(&buf, token_oid, input_token->length, -1);
+ k5_buf_add_len(&buf, input_token->value, input_token->length);
+ assert(buf.len == tokenSize);
output_token->length = tokenSize;
return GSS_S_COMPLETE;
diff --git a/src/lib/gssapi/mechglue/g_glue.c b/src/lib/gssapi/mechglue/g_glue.c
index dfef49e0c..176fbe63e 100644
--- a/src/lib/gssapi/mechglue/g_glue.c
+++ b/src/lib/gssapi/mechglue/g_glue.c
@@ -23,6 +23,7 @@
*/
#include "mglueP.h"
+#include "k5-der.h"
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
@@ -38,219 +39,24 @@ extern gss_mechanism *gssint_mechs_array;
* This file contains the support routines for the glue layer.
*/
-/*
- * get_der_length: Givin a pointer to a buffer that contains a DER encoded
- * length, decode the length updating the buffer to point to the character
- * after the DER encoding. The parameter bytes will point to the number of
- * bytes that made up the DER encoding of the length originally pointed to
- * by the buffer. Note we return -1 on error.
- */
-int
-gssint_get_der_length(unsigned char **buf, unsigned int buf_len, unsigned int *bytes)
+/* Retrieve the mechanism OID from an RFC 2743 InitialContextToken. Place
+ * the result into *oid_out, aliasing memory from token. */
+OM_uint32 gssint_get_mech_type_oid(gss_OID oid_out, gss_buffer_t token)
{
- /* p points to the beginning of the buffer */
- unsigned char *p = *buf;
- int length, new_length;
- unsigned int octets;
-
- if (buf_len < 1)
- return (-1);
-
- /* We should have at least one byte */
- *bytes = 1;
-
- /*
- * If the High order bit is not set then the length is just the value
- * of *p.
- */
- if (*p < 128) {
- *buf = p+1; /* Advance the buffer */
- return (*p); /* return the length */
- }
-
- /*
- * if the High order bit is set, then the low order bits represent
- * the number of bytes that contain the DER encoding of the length.
- */
+ struct k5input in;
- octets = *p++ & 0x7f;
- *bytes += octets;
-
- /* See if the supplied buffer contains enough bytes for the length. */
- if (octets > buf_len - 1)
- return (-1);
-
- /*
- * Calculate a multibyte length. The length is encoded as an
- * unsigned integer base 256.
- */
- for (length = 0; octets; octets--) {
- new_length = (length << 8) + *p++;
- if (new_length < length) /* overflow */
- return (-1);
- length = new_length;
- }
-
- *buf = p; /* Advance the buffer */
-
- return (length);
-}
-
-/*
- * der_length_size: Return the number of bytes to encode a given length.
- */
-unsigned int
-gssint_der_length_size(unsigned int len)
-{
- int i;
-
- if (len < 128)
- return (1);
-
- for (i = 0; len; i++) {
- len >>= 8;
- }
-
- return (i+1);
-}
-
-/*
- * put_der_length: Encode the supplied length into the buffer pointed to
- * by buf. max_length represents the maximum length of the buffer pointed
- * to by buff. We will advance buf to point to the character after the newly
- * DER encoded length. We return 0 on success or -l it the length cannot
- * be encoded in max_len characters.
- */
-int
-gssint_put_der_length(unsigned int length, unsigned char **buf, unsigned int max_len)
-{
- unsigned char *s, *p;
- unsigned int buf_len = 0;
- int i, first;
-
- /* Oops */
- if (buf == 0 || max_len < 1)
- return (-1);
-
- s = *buf;
-
- /* Single byte is the length */
- if (length < 128) {
- *s++ = length;
- *buf = s;
- return (0);
- }
-
- /* First byte contains the number of octets */
- p = s + 1;
-
- /* Running total of the DER encoding length */
- buf_len = 0;
-
- /*
- * Encode MSB first. We do the encoding by setting a shift
- * factor to MSO_BIT (24 for 32 bit words) and then shifting the length
- * by the factor. We then encode the resulting low order byte.
- * We subtract 8 from the shift factor and repeat to ecnode the next
- * byte. We stop when the shift factor is zero or we've run out of
- * buffer to encode into.
- */
- first = 0;
- for (i = MSO_BIT; i >= 0 && buf_len <= max_len; i -= 8) {
- unsigned int v;
- v = (length >> i) & 0xff;
- if ((v) || first) {
- buf_len += 1;
- *p++ = v;
- first = 1;
- }
- }
- if (i >= 0) /* buffer overflow */
- return (-1);
-
- /*
- * We go back now and set the first byte to be the length with
- * the high order bit set.
- */
- *s = buf_len | 0x80;
- *buf = p;
-
- return (0);
-}
-
-
-/*
- * glue routine for get_mech_type
- *
- */
-
-OM_uint32 gssint_get_mech_type_oid(OID, token)
- gss_OID OID;
- gss_buffer_t token;
-{
- unsigned char * buffer_ptr;
- size_t buflen, lenbytes, length, oidlen;
-
- /*
- * This routine reads the prefix of "token" in order to determine
- * its mechanism type. It assumes the encoding suggested in
- * Appendix B of RFC 1508. This format starts out as follows :
- *
- * tag for APPLICATION 0, Sequence[constructed, definite length]
- * length of remainder of token
- * tag of OBJECT IDENTIFIER
- * length of mechanism OID
- * encoding of mechanism OID
- * <the rest of the token>
- *
- * Numerically, this looks like :
- *
- * 0x60
- * <length> - could be multiple bytes
- * 0x06
- * <length> - assume only one byte, hence OID length < 127
- * <mech OID bytes>
- *
- * The routine fills in the OID value and returns an error as necessary.
- */
-
- if (OID == NULL)
- return (GSS_S_CALL_INACCESSIBLE_WRITE);
-
- if ((token == NULL) || (token->value == NULL))
- return (GSS_S_DEFECTIVE_TOKEN);
-
- /* Skip past the APP/Sequnce byte and the token length */
-
- buffer_ptr = (unsigned char *) token->value;
- buflen = token->length;
-
- if (buflen < 2 || *buffer_ptr++ != 0x60)
+ if (oid_out == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+ if (token == NULL || token->value == NULL)
return (GSS_S_DEFECTIVE_TOKEN);
- length = *buffer_ptr++;
- buflen -= 2;
-
- /* check if token length is null */
- if (length == 0)
- return (GSS_S_DEFECTIVE_TOKEN);
-
- if (length & 0x80) {
- lenbytes = length & 0x7f;
- if (lenbytes > 4 || lenbytes > buflen)
- return (GSS_S_DEFECTIVE_TOKEN);
- buffer_ptr += lenbytes;
- buflen -= lenbytes;
- }
- if (buflen < 2 || *buffer_ptr++ != 0x06)
+ k5_input_init(&in, token->value, token->length);
+ if (!k5_der_get_value(&in, 0x60, &in))
return (GSS_S_DEFECTIVE_TOKEN);
- oidlen = *buffer_ptr++;
- buflen -= 2;
- if (oidlen > 0x7f || oidlen > buflen)
+ if (!k5_der_get_value(&in, 0x06, &in))
return (GSS_S_DEFECTIVE_TOKEN);
-
- OID->length = oidlen;
- OID->elements = (void *) buffer_ptr;
+ oid_out->length = in.len;
+ oid_out->elements = (uint8_t *)in.ptr;
return (GSS_S_COMPLETE);
}
@@ -425,12 +231,8 @@ OM_uint32 gssint_export_internal_name(minor_status, mech_type,
gss_mechanism mech;
gss_buffer_desc dispName;
gss_OID nameOid;
- unsigned char *buf = NULL;
- const unsigned char tokId[] = "\x04\x01";
- const unsigned int tokIdLen = 2;
- const int mechOidLenLen = 2, mechOidTagLen = 1, nameLenLen = 4;
- int mechOidDERLen = 0;
- int mechOidLen = 0;
+ int mech_der_len = 0;
+ struct k5buf buf;
mech = gssint_get_mechanism(mech_type);
if (!mech)
@@ -481,52 +283,24 @@ OM_uint32 gssint_export_internal_name(minor_status, mech_type,
return (status);
}
- /* determine the size of the buffer needed */
- mechOidDERLen = gssint_der_length_size(mech_type->length);
- name_buf->length = tokIdLen + mechOidLenLen +
- mechOidTagLen + mechOidDERLen +
- mech_type->length +
- nameLenLen + dispName.length;
- if ((name_buf->value = (void*)gssalloc_malloc(name_buf->length)) ==
- (void*)NULL) {
+ /* Allocate space and prepare a buffer. */
+ mech_der_len = k5_der_value_len(mech_type->length);
+ name_buf->length = 2 + 2 + mech_der_len + 4 + dispName.length;
+ name_buf->value = gssalloc_malloc(name_buf->length);
+ if (name_buf->value == NULL) {
name_buf->length = 0;
(void) gss_release_buffer(&status, &dispName);
return (GSS_S_FAILURE);
}
-
- /* now create the name ..... */
- buf = (unsigned char *)name_buf->value;
- (void) memset(name_buf->value, 0, name_buf->length);
- (void) memcpy(buf, tokId, tokIdLen);
- buf += tokIdLen;
-
- /* spec allows only 2 bytes for the mech oid length */
- mechOidLen = mechOidDERLen + mechOidTagLen + mech_type->length;
- store_16_be(mechOidLen, buf);
- buf += 2;
-
- /*
- * DER Encoding of mech OID contains OID Tag (0x06), length and
- * mech OID value
- */
- *buf++ = 0x06;
- if (gssint_put_der_length(mech_type->length, &buf,
- (name_buf->length - tokIdLen -2)) != 0) {
- name_buf->length = 0;
- free(name_buf->value);
- (void) gss_release_buffer(&status, &dispName);
- return (GSS_S_FAILURE);
- }
-
- (void) memcpy(buf, mech_type->elements, mech_type->length);
- buf += mech_type->length;
-
- /* spec designates the next 4 bytes for the name length */
- store_32_be(dispName.length, buf);
- buf += 4;
-
- /* for the final ingredient - add the name from gss_display_name */
- (void) memcpy(buf, dispName.value, dispName.length);
+ k5_buf_init_fixed(&buf, name_buf->value, name_buf->length);
+
+ /* Assemble the name. */
+ k5_buf_add_len(&buf, "\x04\x01", 2);
+ k5_buf_add_uint16_be(&buf, mech_der_len);
+ k5_der_add_value(&buf, 0x06, mech_type->elements, mech_type->length);
+ k5_buf_add_uint32_be(&buf, dispName.length);
+ k5_buf_add_len(&buf, dispName.value, dispName.length);
+ assert(buf.len == name_buf->length);
/* release the buffer obtained from gss_display_name */
(void) gss_release_buffer(minor_status, &dispName);
diff --git a/src/lib/gssapi/mechglue/g_imp_name.c b/src/lib/gssapi/mechglue/g_imp_name.c
index c3e809c87..a805078a8 100644
--- a/src/lib/gssapi/mechglue/g_imp_name.c
+++ b/src/lib/gssapi/mechglue/g_imp_name.c
@@ -28,6 +28,7 @@
*/
#include "mglueP.h"
+#include "k5-der.h"
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
@@ -181,13 +182,6 @@ allocation_failure:
return (major_status);
}
-/*
- * GSS export name constants
- */
-static const unsigned int expNameTokIdLen = 2;
-static const unsigned int mechOidLenLen = 2;
-static const unsigned int nameTypeLenLen = 2;
-
static OM_uint32
importExportName(minor, unionName, inputNameType)
OM_uint32 *minor;
@@ -196,59 +190,31 @@ importExportName(minor, unionName, inputNameType)
{
gss_OID_desc mechOid;
gss_buffer_desc expName;
- unsigned char *buf;
gss_mechanism mech;
- OM_uint32 major, mechOidLen, nameLen, curLength;
- unsigned int bytes;
+ OM_uint32 major, mechOidLen, nameLen;
+ uint8_t b2;
+ const uint8_t *name;
+ struct k5input in, oid, old_format;
expName.value = unionName->external_name->value;
expName.length = unionName->external_name->length;
+ k5_input_init(&in, expName.value, expName.length);
- curLength = expNameTokIdLen + mechOidLenLen;
- if (expName.length < curLength)
+ if (k5_input_get_byte(&in) != 0x04)
return (GSS_S_DEFECTIVE_TOKEN);
-
- buf = (unsigned char *)expName.value;
- if (buf[0] != 0x04)
- return (GSS_S_DEFECTIVE_TOKEN);
- if (buf[1] != 0x01 && buf[1] != 0x02) /* allow composite names */
+ b2 = k5_input_get_byte(&in);
+ if (b2 != 0x01 && b2 != 0x02) /* allow composite names */
return (GSS_S_DEFECTIVE_TOKEN);
- buf += expNameTokIdLen;
+ mechOidLen = k5_input_get_uint16_be(&in);
- /* extract the mechanism oid length */
- mechOidLen = (*buf++ << 8);
- mechOidLen |= (*buf++);
- curLength += mechOidLen;
- if (expName.length < curLength)
+ if (!k5_der_get_value(&in, 0x06, &oid))
return (GSS_S_DEFECTIVE_TOKEN);
- /*
- * The mechOid itself is encoded in DER format, OID Tag (0x06)
- * length and the value of mech_OID
- */
- if (*buf++ != 0x06)
- return (GSS_S_DEFECTIVE_TOKEN);
-
- /*
- * mechoid Length is encoded twice; once in 2 bytes as
- * explained in RFC2743 (under mechanism independent exported
- * name object format) and once using DER encoding
- *
- * We verify both lengths.
- */
-
- mechOid.length = gssint_get_der_length(&buf,
- (expName.length - curLength), &bytes);
- mechOid.elements = (void *)buf;
-
- /*
- * 'bytes' is the length of the DER length, '1' is for the DER
- * tag for OID
- */
- if ((bytes + mechOid.length + 1) != mechOidLen)
+ /* Verify that mechOidLen is consistent with the DER OID length. */
+ if (mechOidLen != k5_der_value_len(oid.len))
return (GSS_S_DEFECTIVE_TOKEN);
-
- buf += mechOid.length;
+ mechOid.length = oid.len;
+ mechOid.elements = (uint8_t *)oid.ptr;
if ((mech = gssint_get_mechanism(&mechOid)) == NULL)
return (GSS_S_BAD_MECH);
@@ -297,21 +263,11 @@ importExportName(minor, unionName, inputNameType)
* that included a null terminator which was counted in the
* display name gss_buffer_desc.
*/
- curLength += 4; /* 4 bytes for name len */
- if (expName.length < curLength)
- return (GSS_S_DEFECTIVE_TOKEN);
/* next 4 bytes in the name are the name length */
- nameLen = load_32_be(buf);
- buf += 4;
-
- /*
- * we use < here because bad code in rpcsec_gss rounds up exported
- * name token lengths and pads with nulls, otherwise != would be
- * appropriate
- */
- curLength += nameLen; /* this is the total length */
- if (expName.length < curLength)
+ nameLen = k5_input_get_uint32_be(&in);
+ name = k5_input_get_bytes(&in, nameLen);
+ if (name == NULL)
return (GSS_S_DEFECTIVE_TOKEN);
/*
@@ -324,29 +280,19 @@ importExportName(minor, unionName, inputNameType)
* and length) there's the name itself, though null-terminated;
* this null terminator should also not be there, but it is.
*/
- if (nameLen > 0 && *buf == '\0') {
+ if (nameLen > 0 && *name == '\0') {
OM_uint32 nameTypeLen;
- /* next two bytes are the name oid */
- if (nameLen < nameTypeLenLen)
- return (GSS_S_DEFECTIVE_TOKEN);
-
- nameLen -= nameTypeLenLen;
- nameTypeLen = (*buf++) << 8;
- nameTypeLen |= (*buf++);
-
- if (nameLen < nameTypeLen)
+ /* Skip the name type. */
+ k5_input_init(&old_format, name, nameLen);
+ nameTypeLen = k5_input_get_uint16_be(&old_format);
+ if (k5_input_get_bytes(&old_format, nameTypeLen) == NULL)
return (GSS_S_DEFECTIVE_TOKEN);
-
- buf += nameTypeLen;
- nameLen -= nameTypeLen;
-
- /*
- * adjust for expected null terminator that should
- * really not be there
- */
- if (nameLen > 0 && *(buf + nameLen - 1) == '\0')
- nameLen--;
+ /* Remove a null terminator if one is present. */
+ if (old_format.len > 0 && old_format.ptr[old_format.len - 1] == 0)
+ old_format.len--;
+ name = old_format.ptr;
+ nameLen = old_format.len;
}
/*
@@ -365,7 +311,7 @@ importExportName(minor, unionName, inputNameType)
* IDN is thrown in with Kerberos V extensions).
*/
expName.length = nameLen;
- expName.value = nameLen ? (void *)buf : NULL;
+ expName.value = nameLen ? (uint8_t *)name : NULL;
if (mech->gssspi_import_name_by_mech) {
major = mech->gssspi_import_name_by_mech(minor, &mechOid, &expName,
GSS_C_NULL_OID,
diff --git a/src/lib/gssapi/mechglue/mglueP.h b/src/lib/gssapi/mechglue/mglueP.h
index dbd244b72..7f836fbb0 100644
--- a/src/lib/gssapi/mechglue/mglueP.h
+++ b/src/lib/gssapi/mechglue/mglueP.h
@@ -819,23 +819,6 @@ OM_uint32 gss_add_mech_name_type
* Sun extensions to GSS-API v2
*/
-int
-gssint_get_der_length(
- unsigned char **, /* buf */
- unsigned int, /* buf_len */
- unsigned int * /* bytes */
-);
-
-unsigned int
-gssint_der_length_size(unsigned int /* len */);
-
-int
-gssint_put_der_length(
- unsigned int, /* length */
- unsigned char **, /* buf */
- unsigned int /* max_len */
-);
-
OM_uint32
gssint_wrap_aead (gss_mechanism, /* mech */
OM_uint32 *, /* minor_status */
diff --git a/src/lib/gssapi/spnego/spnego_mech.c b/src/lib/gssapi/spnego/spnego_mech.c
index 654964c62..bdd75868a 100644
--- a/src/lib/gssapi/spnego/spnego_mech.c
+++ b/src/lib/gssapi/spnego/spnego_mech.c
@@ -60,40 +60,24 @@
/* #pragma ident "@(#)spnego_mech.c 1.7 04/09/28 SMI" */
#include <k5-int.h>
+#include <k5-der.h>
#include <krb5.h>
#include <mglueP.h>
#include "gssapiP_spnego.h"
#include <gssapi_err_generic.h>
-#undef g_token_size
-#undef g_verify_token_header
-#undef g_make_token_header
-
#define HARD_ERROR(v) ((v) != GSS_S_COMPLETE && (v) != GSS_S_CONTINUE_NEEDED)
typedef const gss_OID_desc *gss_OID_const;
-/* der routines defined in libgss */
-extern unsigned int gssint_der_length_size(unsigned int);
-extern int gssint_get_der_length(unsigned char **, unsigned int,
- unsigned int*);
-extern int gssint_put_der_length(unsigned int, unsigned char **, unsigned int);
-
-
/* private routines for spnego_mechanism */
static spnego_token_t make_spnego_token(const char *);
static gss_buffer_desc make_err_msg(const char *);
-static int g_token_size(gss_OID_const, unsigned int);
-static int g_make_token_header(gss_OID_const, unsigned int,
- unsigned char **, unsigned int);
-static int g_verify_token_header(gss_OID_const, unsigned int *,
- unsigned char **,
- int, unsigned int);
-static int g_verify_neg_token_init(unsigned char **, unsigned int);
-static gss_OID get_mech_oid(OM_uint32 *, unsigned char **, size_t);
-static gss_buffer_t get_input_token(unsigned char **, unsigned int);
-static gss_OID_set get_mech_set(OM_uint32 *, unsigned char **, unsigned int);
-static OM_uint32 get_req_flags(unsigned char **, OM_uint32, OM_uint32 *);
+static int verify_token_header(struct k5input *, gss_OID_const);
+static gss_OID get_mech_oid(OM_uint32 *minor_status, struct k5input *);
+static gss_buffer_t get_octet_string(struct k5input *);
+static gss_OID_set get_mech_set(OM_uint32 *, struct k5input *);
+static OM_uint32 get_req_flags(struct k5input *, OM_uint32 *);
static OM_uint32 get_available_mechs(OM_uint32 *, gss_name_t, gss_cred_usage_t,
gss_const_key_value_set_t,
gss_cred_id_t *, gss_OID_set *,
@@ -103,9 +87,6 @@ static OM_uint32 get_negotiable_mechs(OM_uint32 *, spnego_gss_ctx_id_t,
static void release_spnego_ctx(spnego_gss_ctx_id_t *);
static spnego_gss_ctx_id_t create_spnego_ctx(int);
static int put_mech_set(gss_OID_set mechSet, gss_buffer_t buf);
-static int put_input_token(unsigned char **, gss_buffer_t, unsigned int);
-static int put_mech_oid(unsigned char **, gss_OID_const, unsigned int);
-static int put_negResult(unsigned char **, OM_uint32, unsigned int);
static OM_uint32
process_mic(OM_uint32 *, gss_buffer_t, spnego_gss_ctx_id_t,
@@ -150,8 +131,6 @@ acc_ctx_call_acc(OM_uint32 *, spnego_gss_ctx_id_t, spnego_gss_cred_id_t,
static gss_OID
negotiate_mech(spnego_gss_ctx_id_t, gss_OID_set, OM_uint32 *);
-static int
-g_get_tag_and_length(unsigned char **, int, unsigned int, unsigned int *);
static int
make_spnego_tokenInit_msg(spnego_gss_ctx_id_t,
@@ -159,8 +138,8 @@ make_spnego_tokenInit_msg(spnego_gss_ctx_id_t,
gss_buffer_t,
OM_uint32, gss_buffer_t, send_token_flag,
gss_buffer_t);
-static int
-make_spnego_tokenTarg_msg(OM_uint32, gss_OID, gss_buffer_t,
+static OM_uint32
+make_spnego_tokenTarg_msg(uint8_t, gss_OID, gss_buffer_t,
gss_buffer_t, send_token_flag,
gss_buffer_t);
@@ -169,8 +148,8 @@ get_negTokenInit(OM_uint32 *, gss_buffer_t, gss_buffer_t,
gss_OID_set *, OM_uint32 *, gss_buffer_t *,
gss_buffer_t *);
static OM_uint32
-get_negTokenResp(OM_uint32 *, unsigned char *, unsigned int,
- OM_uint32 *, gss_OID *, gss_buffer_t *, gss_buffer_t *);
+get_negTokenResp(OM_uint32 *, struct k5input *, OM_uint32 *, gss_OID *,
+ gss_buffer_t *, gss_buffer_t *);
static int
is_kerb_mech(gss_OID oid);
@@ -189,7 +168,6 @@ const gss_OID_set_desc * const gss_mech_set_spnego = spnego_oidsets+0;
static gss_OID_desc negoex_mech = { NEGOEX_OID_LENGTH, NEGOEX_OID };
static int make_NegHints(OM_uint32 *, gss_buffer_t *);
-static int put_neg_hints(unsigned char **, gss_buffer_t, unsigned int);
static OM_uint32
acc_ctx_hints(OM_uint32 *, spnego_gss_cred_id_t, gss_buffer_t *, OM_uint32 *,
send_token_flag *, spnego_gss_ctx_id_t *);
@@ -720,15 +698,15 @@ init_ctx_cont(OM_uint32 *minor_status, spnego_gss_ctx_id_t sc,
send_token_flag *tokflag)
{
OM_uint32 ret, tmpmin;
- unsigned char *ptr;
gss_OID supportedMech = GSS_C_NO_OID;
+ struct k5input in;
*acc_negState = UNSPECIFIED;
*tokflag = ERROR_TOKEN_SEND;
- ptr = buf->value;
- ret = get_negTokenResp(minor_status, ptr, buf->length, acc_negState,
- &supportedMech, responseToken, mechListMIC);
+ k5_input_init(&in, buf->value, buf->length);
+ ret = get_negTokenResp(minor_status, &in, acc_negState, &supportedMech,
+ responseToken, mechListMIC);
if (ret != GSS_S_COMPLETE)
goto cleanup;
@@ -1179,33 +1157,6 @@ static const gss_OID_desc gss_mech_krb5_wrong_oid =
{ 9, "\052\206\110\202\367\022\001\002\002" };
/*
- * verify that the input token length is not 0. If it is, just return.
- * If the token length is greater than 0, der encode as a sequence
- * and place in buf_out, advancing buf_out.
- */
-
-static int
-put_neg_hints(unsigned char **buf_out, gss_buffer_t input_token,
- unsigned int buflen)
-{
- int ret;
-
- /* if token length is 0, we do not want to send */
- if (input_token->length == 0)
- return (0);
-
- if (input_token->length > buflen)
- return (-1);
-
- *(*buf_out)++ = SEQUENCE;
- if ((ret = gssint_put_der_length(input_token->length, buf_out,
- input_token->length)))
- return (ret);
- TWRITE_STR(*buf_out, input_token->value, input_token->length);
- return (0);
-}
-
-/*
* NegHints ::= SEQUENCE {
* hintName [0] GeneralString OPTIONAL,
* hintAddress [1] OCTET STRING OPTIONAL
@@ -1221,42 +1172,28 @@ static int
make_NegHints(OM_uint32 *minor_status, gss_buffer_t *outbuf)
{
OM_uint32 major_status;
- unsigned int tlen = 0;
- unsigned int hintNameSize = 0;
- unsigned char *ptr;
- unsigned char *t;
+ size_t hint_len, tlen;
+ uint8_t *t;
const char *hintname = "not_defined_in_RFC4178@please_ignore";
const size_t hintname_len = strlen(hintname);
+ struct k5buf buf;
*outbuf = GSS_C_NO_BUFFER;
major_status = GSS_S_FAILURE;
- /* Length of DER encoded GeneralString */
- tlen = 1 + gssint_der_length_size(hintname_len) + hintname_len;
- hintNameSize = tlen;
-
- /* Length of DER encoded hintName */
- tlen += 1 + gssint_der_length_size(hintNameSize);
+ hint_len = k5_der_value_len(hintname_len);
+ tlen = k5_der_value_len(hint_len);
t = gssalloc_malloc(tlen);
if (t == NULL) {
*minor_status = ENOMEM;
goto errout;
}
+ k5_buf_init_fixed(&buf, t, tlen);
- ptr = t;
-
- *ptr++ = CONTEXT | 0x00; /* hintName identifier */
- if (gssint_put_der_length(hintNameSize,
- &ptr, tlen - (int)(ptr-t)))
- goto errout;
-
- *ptr++ = GENERAL_STRING;
- if (gssint_put_der_length(hintname_len, &ptr, tlen - (int)(ptr-t)))
- goto errout;
-
- memcpy(ptr, hintname, hintname_len);
- ptr += hintname_len;
+ k5_der_add_taglen(&buf, CONTEXT | 0x00, hint_len);
+ k5_der_add_value(&buf, GENERAL_STRING, hintname, hintname_len);
+ assert(buf.len == tlen);
*outbuf = (gss_buffer_t)malloc(sizeof(gss_buffer_desc));
if (*outbuf == NULL) {
@@ -1264,7 +1201,7 @@ make_NegHints(OM_uint32 *minor_status, gss_buffer_t *outbuf)
goto errout;
}
(*outbuf)->value = (void *)t;
- (*outbuf)->length = ptr - t;
+ (*outbuf)->length = tlen;
t = NULL; /* don't free */
@@ -1431,8 +1368,7 @@ acc_ctx_cont(OM_uint32 *minstat,
{
OM_uint32 ret, tmpmin;
gss_OID supportedMech;
- unsigned int len;
- unsigned char *ptr, *bufstart;
+ struct k5input in;
ret = GSS_S_DEFECTIVE_TOKEN;
*negState = REJECT;
@@ -1441,27 +1377,18 @@ acc_ctx_cont(OM_uint32 *minstat,
*return_token = ERROR_TOKEN_SEND;
*responseToken = *mechListMIC = GSS_C_NO_BUFFER;
- ptr = bufstart = buf->value;
-#define REMAIN (buf->length - (ptr - bufstart))
- if (REMAIN == 0 || REMAIN > INT_MAX)
- return GSS_S_DEFECTIVE_TOKEN;
+ k5_input_init(&in, buf->value, buf->length);
- /*
- * Attempt to work with old Sun SPNEGO.
- */
- if (*ptr == HEADER_ID) {
- ret = g_verify_token_header(gss_mech_spnego,
- &len, &ptr, 0, REMAIN);
+ /* Attempt to work with old Sun SPNEGO. */
+ if (in.len > 0 && *in.ptr == HEADER_ID) {
+ ret = verify_token_header(&in, gss_mech_spnego);
if (ret) {
*minstat = ret;
return GSS_S_DEFECTIVE_TOKEN;
}
}
- if (*ptr != (CONTEXT | 0x01)) {
- return GSS_S_DEFECTIVE_TOKEN;
- }
- ret = get_negTokenResp(minstat, ptr, REMAIN,
- negState, &supportedMech,
+
+ ret = get_negTokenResp(minstat, &in, negState, &supportedMech,
responseToken, mechListMIC);
if (ret != GSS_S_COMPLETE)
goto cleanup;
@@ -1484,7 +1411,6 @@ cleanup:
generic_gss_release_oid(&tmpmin, &supportedMech);
}
return ret;
-#undef REMAIN
}
/*
@@ -3329,34 +3255,24 @@ cleanup:
/* following are token creation and reading routines */
/*
- * If buff_in is not pointing to a MECH_OID, then return NULL and do not
- * advance the buffer, otherwise, decode the mech_oid from the buffer and
- * place in gss_OID.
+ * If in contains a tagged OID encoding, return a copy of the contents as a
+ * gss_OID and advance in past the encoding. Otherwise return NULL and do not
+ * advance in.
*/
static gss_OID
-get_mech_oid(OM_uint32 *minor_status, unsigned char **buff_in, size_t length)
+get_mech_oid(OM_uint32 *minor_status, struct k5input *in)
{
- OM_uint32 status;
- gss_OID_desc toid;
- gss_OID mech_out = NULL;
- unsigned int bytes;
- int oid_length;
-
- if (length < 1 || **buff_in != MECH_OID)
- return (NULL);
- (*buff_in)++;
- length--;
+ struct k5input oidrep;
+ OM_uint32 status;
+ gss_OID_desc oid;
+ gss_OID mech_out = NULL;
- oid_length = gssint_get_der_length(buff_in, length, &bytes);
- if (oid_length < 0 || length - bytes < (size_t)oid_length)
+ if (!k5_der_get_value(in, MECH_OID, &oidrep))
return (NULL);
- toid.length = oid_length;
- toid.elements = *buff_in;
- *buff_in += toid.length;
-
- status = generic_gss_copy_oid(minor_status, &toid, &mech_out);
-
+ oid.length = oidrep.len;
+ oid.elements = (uint8_t *)oidrep.ptr;
+ status = generic_gss_copy_oid(minor_status, &oid, &mech_out);
if (status != GSS_S_COMPLETE) {
map_errcode(minor_status);
mech_out = NULL;
@@ -3366,42 +3282,24 @@ get_mech_oid(OM_uint32 *minor_status, unsigned char **buff_in, size_t length)
}
/*
- * der encode the given mechanism oid into buf_out, advancing the
- * buffer pointer.
- */
-
-static int
-put_mech_oid(unsigned char **buf_out, gss_OID_const mech, unsigned int buflen)
-{
- if (buflen < mech->length + 2)
- return (-1);
- *(*buf_out)++ = MECH_OID;
- *(*buf_out)++ = (unsigned char) mech->length;
- memcpy(*buf_out, mech->elements, mech->length);
- *buf_out += mech->length;
- return (0);
-}
-
-/*
- * verify that buff_in points to an octet string, if it does not,
- * return NULL and don't advance the pointer. If it is an octet string
- * decode buff_in into a gss_buffer_t and return it, advancing the
- * buffer pointer.
+ * If in contains a tagged octet string encoding, return a copy of the contents
+ * as a gss_buffer_t and advance in past the encoding. Otherwise return NULL
+ * and do not advance in.
*/
static gss_buffer_t
-get_input_token(unsigned char **buff_in, unsigned int buff_length)
+get_octet_string(struct k5input *in)
{
gss_buffer_t input_token;
- unsigned int len;
+ struct k5input ostr;
- if (g_get_tag_and_length(buff_in, OCTET_STRING, buff_length, &len) < 0)
+ if (!k5_der_get_value(in, OCTET_STRING, &ostr))
return (NULL);
input_token = (gss_buffer_t)malloc(sizeof (gss_buffer_desc));
if (input_token == NULL)
return (NULL);
- input_token->length = len;
+ input_token->length = ostr.len;
if (input_token->length > 0) {
input_token->value = gssalloc_malloc(input_token->length);
if (input_token->value == NULL) {
@@ -3409,88 +3307,49 @@ get_input_token(unsigned char **buff_in, unsigned int buff_length)
return (NULL);
}
- memcpy(input_token->value, *buff_in, input_token->length);
+ memcpy(input_token->value, ostr.ptr, input_token->length);
} else {
input_token->value = NULL;
}
- *buff_in += input_token->length;
return (input_token);
}
/*
- * verify that the input token length is not 0. If it is, just return.
- * If the token length is greater than 0, der encode as an octet string
- * and place in buf_out, advancing buf_out.
- */
-
-static int
-put_input_token(unsigned char **buf_out, gss_buffer_t input_token,
- unsigned int buflen)
-{
- int ret;
-
- /* if token length is 0, we do not want to send */
- if (input_token->length == 0)
- return (0);
-
- if (input_token->length > buflen)
- return (-1);
-
- *(*buf_out)++ = OCTET_STRING;
- if ((ret = gssint_put_der_length(input_token->length, buf_out,
- input_token->length)))
- return (ret);
- TWRITE_STR(*buf_out, input_token->value, input_token->length);
- return (0);
-}
-
-/*
* verify that buff_in points to a sequence of der encoding. The mech
* set is the only sequence of encoded object in the token, so if it is
* a sequence of encoding, decode the mechset into a gss_OID_set and
* return it, advancing the buffer pointer.
*/
static gss_OID_set
-get_mech_set(OM_uint32 *minor_status, unsigned char **buff_in,
- unsigned int buff_length)
+get_mech_set(OM_uint32 *minor_status, struct k5input *in)
{
gss_OID_set returned_mechSet;
OM_uint32 major_status, tmpmin;
- int length;
- unsigned int bytes;
- OM_uint32 set_length;
- unsigned char *start;
- int i;
+ struct k5input seq;
- if (buff_length < 1 || **buff_in != SEQUENCE_OF)
+ if (!k5_der_get_value(in, SEQUENCE_OF, &seq))
return (NULL);
- start = *buff_in;
- (*buff_in)++;
-
- length = gssint_get_der_length(buff_in, buff_length - 1, &bytes);
- if (length < 0 || buff_length - 1 - bytes < (unsigned int)length)
- return NULL;
-
major_status = gss_create_empty_oid_set(minor_status,
&returned_mechSet);
if (major_status != GSS_S_COMPLETE)
return (NULL);
- for (set_length = 0, i = 0; set_length < (unsigned int)length; i++) {
- gss_OID_desc *temp = get_mech_oid(minor_status, buff_in,
- buff_length - (*buff_in - start));
- if (temp == NULL)
- break;
+ while (!seq.status && seq.len > 0) {
+ gss_OID_desc *oid = get_mech_oid(minor_status, &seq);
+
+ if (oid == NULL) {
+ gss_release_oid_set(&tmpmin, &returned_mechSet);
+ return (NULL);
+ }
major_status = gss_add_oid_set_member(minor_status,
- temp, &returned_mechSet);
- generic_gss_release_oid(minor_status, &temp);
+ oid, &returned_mechSet);
+ generic_gss_release_oid(minor_status, &oid);
if (major_status != GSS_S_COMPLETE) {
gss_release_oid_set(&tmpmin, &returned_mechSet);
return (NULL);
}
- set_length += returned_mechSet->elements[i].length + 2;
}
return (returned_mechSet);
@@ -3500,74 +3359,48 @@ get_mech_set(OM_uint32 *minor_status, unsigned char **buff_in,
* Encode mechSet into buf.
*/
static int
-put_mech_set(gss_OID_set mechSet, gss_buffer_t buf)
+put_mech_set(gss_OID_set mechSet, gss_buffer_t buffer_out)
{
- unsigned char *ptr;
- unsigned int i;
- unsigned int tlen, ilen;
+ uint8_t *ptr;
+ size_t ilen, tlen, i;
+ struct k5buf buf;
+
+ ilen = 0;
+ for (i = 0; i < mechSet->count; i++)
+ ilen += k5_der_value_len(mechSet->elements[i].length);
+ tlen = k5_der_value_len(ilen);
- tlen = ilen = 0;
- for (i = 0; i < mechSet->count; i++) {
- /*
- * 0x06 [DER LEN] [OID]
- */
- ilen += 1 +
- gssint_der_length_size(mechSet->elements[i].length) +
- mechSet->elements[i].length;
- }
- /*
- * 0x30 [DER LEN]
- */
- tlen = 1 + gssint_der_length_size(ilen) + ilen;
ptr = gssalloc_malloc(tlen);
if (ptr == NULL)
return -1;
+ k5_buf_init_fixed(&buf, ptr, tlen);
- buf->value = ptr;
- buf->length = tlen;
-#define REMAIN (buf->length - ((unsigned char *)buf->value - ptr))
-
- *ptr++ = SEQUENCE_OF;
- if (gssint_put_der_length(ilen, &ptr, REMAIN) < 0)
- return -1;
+ k5_der_add_taglen(&buf, SEQUENCE_OF, ilen);
for (i = 0; i < mechSet->count; i++) {
- if (put_mech_oid(&ptr, &mechSet->elements[i], REMAIN) < 0) {
- return -1;
- }
+ k5_der_add_value(&buf, MECH_OID,
+ mechSet->elements[i].elements,
+ mechSet->elements[i].length);
}
+ assert(buf.len == tlen);
+
+ buffer_out->value = ptr;
+ buffer_out->length = tlen;
return 0;
-#undef REMAIN
}
-/*
- * Verify that buff_in is pointing to a BIT_STRING with the correct
- * length and padding for the req_flags. If it is, decode req_flags
- * and return them, otherwise, return NULL.
- */
+/* Decode SPNEGO request flags from the DER encoding of a bit string and set
+ * them in *ret_flags. */
static OM_uint32
-get_req_flags(unsigned char **buff_in, OM_uint32 bodysize,
- OM_uint32 *req_flags)
+get_req_flags(struct k5input *in, OM_uint32 *req_flags)
{
- unsigned int len;
-
- if (bodysize < 1 || **buff_in != (CONTEXT | 0x01))
- return (0);
-
- if (g_get_tag_and_length(buff_in, (CONTEXT | 0x01),
- bodysize, &len) < 0 || len != 4)
+ if (in->status || in->len != 4 ||
+ k5_input_get_byte(in) != BIT_STRING ||
+ k5_input_get_byte(in) != BIT_STRING_LENGTH ||
+ k5_input_get_byte(in) != BIT_STRING_PADDING)
return GSS_S_DEFECTIVE_TOKEN;
- if (*(*buff_in)++ != BIT_STRING)
- return GSS_S_DEFECTIVE_TOKEN;
-
- if (*(*buff_in)++ != BIT_STRING_LENGTH)
- return GSS_S_DEFECTIVE_TOKEN;
-
- if (*(*buff_in)++ != BIT_STRING_PADDING)
- return GSS_S_DEFECTIVE_TOKEN;
-
- *req_flags = (OM_uint32) (*(*buff_in)++ >> 1);
- return (0);
+ *req_flags = k5_input_get_byte(in) >> 1;
+ return GSS_S_COMPLETE;
}
static OM_uint32
@@ -3580,9 +3413,7 @@ get_negTokenInit(OM_uint32 *minor_status,
gss_buffer_t *mechListMIC)
{
OM_uint32 err;
- unsigned char *ptr, *bufstart;
- unsigned int len;
- gss_buffer_desc tmpbuf;
+ struct k5input in, seq, field;
*minor_status = 0;
der_mechSet->length = 0;
@@ -3591,148 +3422,100 @@ get_negTokenInit(OM_uint32 *minor_status,
*req_flags = 0;
*mechtok = *mechListMIC = GSS_C_NO_BUFFER;
- ptr = bufstart = buf->value;
- if ((buf->length - (ptr - bufstart)) > INT_MAX)
- return GSS_S_FAILURE;
-#define REMAIN (buf->length - (ptr - bufstart))
+ k5_input_init(&in, buf->value, buf->length);
- err = g_verify_token_header(gss_mech_spnego,
- &len, &ptr, 0, REMAIN);
- if (err) {
- *minor_status = err;
- map_errcode(minor_status);
- return GSS_S_FAILURE;
- }
- *minor_status = g_verify_neg_token_init(&ptr, REMAIN);
- if (*minor_status) {
- map_errcode(minor_status);
- return GSS_S_FAILURE;
- }
+ /* Advance past the framing header. */
+ err = verify_token_header(&in, gss_mech_spnego);
+ if (err)
+ return GSS_S_DEFECTIVE_TOKEN;
- /* alias into input_token */
- tmpbuf.value = ptr;
- tmpbuf.length = REMAIN;
- *mechSet = get_mech_set(minor_status, &ptr, REMAIN);
- if (*mechSet == NULL)
- return GSS_S_FAILURE;
+ /* Advance past the [0] tag for the NegotiationToken choice. */
+ if (!k5_der_get_value(&in, CONTEXT, &seq))
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ /* Advance past the SEQUENCE tag. */
+ if (!k5_der_get_value(&seq, SEQUENCE, &seq))
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ /* Get the contents of the mechTypes field. */
+ if (!k5_der_get_value(&seq, CONTEXT, &field))
+ return GSS_S_DEFECTIVE_TOKEN;
- tmpbuf.length = ptr - (unsigned char *)tmpbuf.value;
- der_mechSet->value = gssalloc_malloc(tmpbuf.length);
+ /* Store a copy of the contents for MIC computation. */
+ der_mechSet->value = gssalloc_malloc(field.len);
if (der_mechSet->value == NULL)
return GSS_S_FAILURE;
- memcpy(der_mechSet->value, tmpbuf.value, tmpbuf.length);
- der_mechSet->length = tmpbuf.length;
+ memcpy(der_mechSet->value, field.ptr, field.len);
+ der_mechSet->length = field.len;
- err = get_req_flags(&ptr, REMAIN, req_flags);
- if (err != GSS_S_COMPLETE) {
- return err;
+ /* Decode the contents into an OID set. */
+ *mechSet = get_mech_set(minor_status, &field);
+ if (*mechSet == NULL)
+ return GSS_S_FAILURE;
+
+ if (k5_der_get_value(&seq, CONTEXT | 0x01, &field)) {
+ err = get_req_flags(&field, req_flags);
+ if (err != GSS_S_COMPLETE)
+ return err;
}
- if (g_get_tag_and_length(&ptr, (CONTEXT | 0x02),
- REMAIN, &len) >= 0) {
- *mechtok = get_input_token(&ptr, len);
- if (*mechtok == GSS_C_NO_BUFFER) {
+
+ if (k5_der_get_value(&seq, CONTEXT | 0x02, &field)) {
+ *mechtok = get_octet_string(&field);
+ if (*mechtok == GSS_C_NO_BUFFER)
return GSS_S_FAILURE;
- }
}
- if (g_get_tag_and_length(&ptr, (CONTEXT | 0x03),
- REMAIN, &len) >= 0) {
- *mechListMIC = get_input_token(&ptr, len);
- if (*mechListMIC == GSS_C_NO_BUFFER) {
+
+ if (k5_der_get_value(&seq, CONTEXT | 0x03, &field)) {
+ *mechListMIC = get_octet_string(&field);
+ if (*mechListMIC == GSS_C_NO_BUFFER)
return GSS_S_FAILURE;
- }
}
- return GSS_S_COMPLETE;
-#undef REMAIN
+
+ return seq.status ? GSS_S_DEFECTIVE_TOKEN : GSS_S_COMPLETE;
}
+/* Decode a NegotiationToken of type negTokenResp. */
static OM_uint32
-get_negTokenResp(OM_uint32 *minor_status,
- unsigned char *buf, unsigned int buflen,
- OM_uint32 *negState,
- gss_OID *supportedMech,
- gss_buffer_t *responseToken,
- gss_buffer_t *mechListMIC)
+get_negTokenResp(OM_uint32 *minor_status, struct k5input *in,
+ OM_uint32 *negState, gss_OID *supportedMech,
+ gss_buffer_t *responseToken, gss_buffer_t *mechListMIC)
{
- unsigned char *ptr, *bufstart;
- unsigned int len;
- int tmplen;
- unsigned int tag, bytes;
+ struct k5input seq, field, en;
*negState = UNSPECIFIED;
*supportedMech = GSS_C_NO_OID;
*responseToken = *mechListMIC = GSS_C_NO_BUFFER;
- ptr = bufstart = buf;
-#define REMAIN (buflen - (ptr - bufstart))
- if (g_get_tag_and_length(&ptr, (CONTEXT | 0x01), REMAIN, &len) < 0)
+ /* Advance past the [1] tag for the NegotiationToken choice. */
+ if (!k5_der_get_value(in, CONTEXT | 0x01, &seq))
return GSS_S_DEFECTIVE_TOKEN;
- if (*ptr++ == SEQUENCE) {
- tmplen = gssint_get_der_length(&ptr, REMAIN, &bytes);
- if (tmplen < 0 || REMAIN < (unsigned int)tmplen)
- return GSS_S_DEFECTIVE_TOKEN;
- }
- if (REMAIN < 1)
- tag = 0;
- else
- tag = *ptr++;
-
- if (tag == CONTEXT) {
- tmplen = gssint_get_der_length(&ptr, REMAIN, &bytes);
- if (tmplen < 0 || REMAIN < (unsigned int)tmplen)
- return GSS_S_DEFECTIVE_TOKEN;
- if (g_get_tag_and_length(&ptr, ENUMERATED,
- REMAIN, &len) < 0)
- return GSS_S_DEFECTIVE_TOKEN;
+ /* Advance seq past the SEQUENCE tag (historically this code allows the
+ * tag to be missing). */
+ (void)k5_der_get_value(&seq, SEQUENCE, &seq);
- if (len != ENUMERATION_LENGTH)
+ if (k5_der_get_value(&seq, CONTEXT, &field)) {
+ if (!k5_der_get_value(&field, ENUMERATED, &en))
return GSS_S_DEFECTIVE_TOKEN;
-
- if (REMAIN < 1)
+ if (en.len != ENUMERATION_LENGTH)
return GSS_S_DEFECTIVE_TOKEN;
- *negState = *ptr++;
-
- if (REMAIN < 1)
- tag = 0;
- else
- tag = *ptr++;
+ *negState = *en.ptr;
}
- if (tag == (CONTEXT | 0x01)) {
- tmplen = gssint_get_der_length(&ptr, REMAIN, &bytes);
- if (tmplen < 0 || REMAIN < (unsigned int)tmplen)
- return GSS_S_DEFECTIVE_TOKEN;
- *supportedMech = get_mech_oid(minor_status, &ptr, REMAIN);
+ if (k5_der_get_value(&seq, CONTEXT | 0x01, &field)) {
+ *supportedMech = get_mech_oid(minor_status, &field);
if (*supportedMech == GSS_C_NO_OID)
return GSS_S_DEFECTIVE_TOKEN;
-
- if (REMAIN < 1)
- tag = 0;
- else
- tag = *ptr++;
}
- if (tag == (CONTEXT | 0x02)) {
- tmplen = gssint_get_der_length(&ptr, REMAIN, &bytes);
- if (tmplen < 0 || REMAIN < (unsigned int)tmplen)
- return GSS_S_DEFECTIVE_TOKEN;
- *responseToken = get_input_token(&ptr, REMAIN);
+ if (k5_der_get_value(&seq, CONTEXT | 0x02, &field)) {
+ *responseToken = get_octet_string(&field);
if (*responseToken == GSS_C_NO_BUFFER)
return GSS_S_DEFECTIVE_TOKEN;
-
- if (REMAIN < 1)
- tag = 0;
- else
- tag = *ptr++;
}
- if (tag == (CONTEXT | 0x03)) {
- tmplen = gssint_get_der_length(&ptr, REMAIN, &bytes);
- if (tmplen < 0 || REMAIN < (unsigned int)tmplen)
- return GSS_S_DEFECTIVE_TOKEN;
- *mechListMIC = get_input_token(&ptr, REMAIN);
- if (*mechListMIC == GSS_C_NO_BUFFER)
- return GSS_S_DEFECTIVE_TOKEN;
+ if (k5_der_get_value(&seq, CONTEXT | 0x04, &field)) {
+ *mechListMIC = get_octet_string(&field);
/* Handle Windows 2000 duplicate response token */
if (*responseToken &&
@@ -3746,25 +3529,8 @@ get_negTokenResp(OM_uint32 *minor_status,
*mechListMIC = NULL;
}
}
- return GSS_S_COMPLETE;
-#undef REMAIN
-}
-/*
- * der encode the passed negResults as an ENUMERATED type and
- * place it in buf_out, advancing the buffer.
- */
-
-static int
-put_negResult(unsigned char **buf_out, OM_uint32 negResult,
- unsigned int buflen)
-{
- if (buflen < 3)
- return (-1);
- *(*buf_out)++ = ENUMERATED;
- *(*buf_out)++ = ENUMERATION_LENGTH;
- *(*buf_out)++ = (unsigned char) negResult;
- return (0);
+ return seq.status ? GSS_S_DEFECTIVE_TOKEN : GSS_S_COMPLETE;
}
/*
@@ -3848,22 +3614,15 @@ make_err_msg(const char *name)
* Use DER rules, definite length method per RFC 2478
*/
static int
-make_spnego_tokenInit_msg(spnego_gss_ctx_id_t spnego_ctx,
- int negHintsCompat,
- gss_buffer_t mechListMIC, OM_uint32 req_flags,
- gss_buffer_t data, send_token_flag sendtoken,
+make_spnego_tokenInit_msg(spnego_gss_ctx_id_t spnego_ctx, int negHintsCompat,
+ gss_buffer_t mic, OM_uint32 req_flags,
+ gss_buffer_t token, send_token_flag sendtoken,
gss_buffer_t outbuf)
{
- int ret = 0;
- unsigned int tlen, dataLen = 0;
- unsigned int negTokenInitSize = 0;
- unsigned int negTokenInitSeqSize = 0;
- unsigned int negTokenInitContSize = 0;
- unsigned int rspTokenSize = 0;
- unsigned int mechListTokenSize = 0;
- unsigned int micTokenSize = 0;
- unsigned char *t;
- unsigned char *ptr;
+ size_t f0len, f2len, f3len, fields_len, seq_len, choice_len;
+ size_t mech_len, framed_len;
+ uint8_t *t;
+ struct k5buf buf;
if (outbuf == GSS_C_NO_BUFFER)
return (-1);
@@ -3871,141 +3630,66 @@ make_spnego_tokenInit_msg(spnego_gss_ctx_id_t spnego_ctx,
outbuf->length = 0;
outbuf->value = NULL;
- /* calculate the data length */
-
- /*
- * 0xa0 [DER LEN] [mechTypes]
- */
- mechListTokenSize = 1 +
- gssint_der_length_size(spnego_ctx->DER_mechTypes.length) +
- spnego_ctx->DER_mechTypes.length;
- dataLen += mechListTokenSize;
-
- /*
- * If a token from gss_init_sec_context exists,
- * add the length of the token + the ASN.1 overhead
- */
- if (data != NULL) {
- /*
- * Encoded in final output as:
- * 0xa2 [DER LEN] 0x04 [DER LEN] [DATA]
- * -----s--------|--------s2----------
- */
- rspTokenSize = 1 +
- gssint_der_length_size(data->length) +
- data->length;
- dataLen += 1 + gssint_der_length_size(rspTokenSize) +
- rspTokenSize;
- }
-
- if (mechListMIC) {
- /*
- * Encoded in final output as:
- * 0xa3 [DER LEN] 0x04 [DER LEN] [DATA]
- * --s-- -----tlen------------
- */
- micTokenSize = 1 +
- gssint_der_length_size(mechListMIC->length) +
- mechListMIC->length;
- dataLen += 1 +
- gssint_der_length_size(micTokenSize) +
- micTokenSize;
- }
-
- /*
- * Add size of DER encoding
- * [ SEQUENCE { MechTypeList | ReqFLags | Token | mechListMIC } ]
- * 0x30 [DER_LEN] [data]
- *
- */
- negTokenInitContSize = dataLen;
- negTokenInitSeqSize = 1 + gssint_der_length_size(dataLen) + dataLen;
- dataLen = negTokenInitSeqSize;
-
- /*
- * negTokenInitSize indicates the bytes needed to
- * hold the ASN.1 encoding of the entire NegTokenInit
- * SEQUENCE.
- * 0xa0 [DER_LEN] + data
- *
- */
- negTokenInitSize = 1 +
- gssint_der_length_size(negTokenInitSeqSize) +
- negTokenInitSeqSize;
-
- tlen = g_token_size(gss_mech_spnego, negTokenInitSize);
-
- t = (unsigned char *) gssalloc_malloc(tlen);
-
- if (t == NULL) {
+ /* Calculate the length of each field and the total fields length. */
+ fields_len = 0;
+ /* mechTypes [0] MechTypeList, previously assembled in spnego_ctx */
+ f0len = spnego_ctx->DER_mechTypes.length;
+ fields_len += k5_der_value_len(f0len);
+ if (token != NULL) {
+ /* mechToken [2] OCTET STRING OPTIONAL */
+ f2len = k5_der_value_len(token->length);
+ fields_len += k5_der_value_len(f2len);
+ }
+ if (mic != GSS_C_NO_BUFFER) {
+ /* mechListMIC [3] OCTET STRING OPTIONAL */
+ f3len = k5_der_value_len(mic->length);
+ fields_len += k5_der_value_len(f3len);
+ }
+
+ /* Calculate the length of the sequence and choice. */
+ seq_len = k5_der_value_len(fields_len);
+ choice_len = k5_der_value_len(seq_len);
+
+ /* Calculate the framed token length. */
+ mech_len = k5_der_value_len(gss_mech_spnego->length);
+ framed_len = k5_der_value_len(mech_len + choice_len);
+
+ /* Allocate space and prepare a buffer. */
+ t = gssalloc_malloc(framed_len);
+ if (t == NULL)
return (-1);
- }
-
- ptr = t;
+ k5_buf_init_fixed(&buf, t, framed_len);
- /* create the message */
- if ((ret = g_make_token_header(gss_mech_spnego, negTokenInitSize,
- &ptr, tlen)))
- goto errout;
+ /* Add generic token framing. */
+ k5_der_add_taglen(&buf, HEADER_ID, mech_len + choice_len);
+ k5_der_add_value(&buf, MECH_OID, gss_mech_spnego->elements,
+ gss_mech_spnego->length);
- *ptr++ = CONTEXT; /* NegotiationToken identifier */
- if ((ret = gssint_put_der_length(negTokenInitSeqSize, &ptr, tlen)))
- goto errout;
+ /* Add NegotiationToken choice tag and NegTokenInit sequence tag. */
+ k5_der_add_taglen(&buf, CONTEXT | 0x00, seq_len);
+ k5_der_add_taglen(&buf, SEQUENCE, fields_len);
- *ptr++ = SEQUENCE;
- if ((ret = gssint_put_der_length(negTokenInitContSize, &ptr,
- tlen - (int)(ptr-t))))
- goto errout;
+ /* Add the already-encoded mechanism list as mechTypes. */
+ k5_der_add_value(&buf, CONTEXT | 0x00, spnego_ctx->DER_mechTypes.value,
+ spnego_ctx->DER_mechTypes.length);
- *ptr++ = CONTEXT | 0x00; /* MechTypeList identifier */
- if ((ret = gssint_put_der_length(spnego_ctx->DER_mechTypes.length,
- &ptr, tlen - (int)(ptr-t))))
- goto errout;
-
- /* We already encoded the MechSetList */
- (void) memcpy(ptr, spnego_ctx->DER_mechTypes.value,
- spnego_ctx->DER_mechTypes.length);
-
- ptr += spnego_ctx->DER_mechTypes.length;
-
- if (data != NULL) {
- *ptr++ = CONTEXT | 0x02;
- if ((ret = gssint_put_der_length(rspTokenSize,
- &ptr, tlen - (int)(ptr - t))))
- goto errout;
-
- if ((ret = put_input_token(&ptr, data,
- tlen - (int)(ptr - t))))
- goto errout;
+ if (token != NULL) {
+ k5_der_add_taglen(&buf, CONTEXT | 0x02, f2len);
+ k5_der_add_value(&buf, OCTET_STRING, token->value,
+ token->length);
}
- if (mechListMIC != GSS_C_NO_BUFFER) {
- *ptr++ = CONTEXT | 0x03;
- if ((ret = gssint_put_der_length(micTokenSize,
- &ptr, tlen - (int)(ptr - t))))
- goto errout;
-
- if (negHintsCompat) {
- ret = put_neg_hints(&ptr, mechListMIC,
- tlen - (int)(ptr - t));
- if (ret)
- goto errout;
- } else if ((ret = put_input_token(&ptr, mechListMIC,
- tlen - (int)(ptr - t))))
- goto errout;
+ if (mic != GSS_C_NO_BUFFER) {
+ uint8_t id = negHintsCompat ? SEQUENCE : OCTET_STRING;
+ k5_der_add_taglen(&buf, CONTEXT | 0x03, f3len);
+ k5_der_add_value(&buf, id, mic->value, mic->length);
}
-errout:
- if (ret != 0) {
- if (t)
- free(t);
- t = NULL;
- tlen = 0;
- }
- outbuf->length = tlen;
- outbuf->value = (void *) t;
+ assert(buf.len == framed_len);
+ outbuf->length = framed_len;
+ outbuf->value = t;
- return (ret);
+ return (0);
}
/*
@@ -4013,414 +3697,106 @@ errout:
* gss_accept_sec_context and eventually up to the application program
* and over to the client.
*/
-static int
-make_spnego_tokenTarg_msg(OM_uint32 status, gss_OID mech_wanted,
- gss_buffer_t data, gss_buffer_t mechListMIC,
+static OM_uint32
+make_spnego_tokenTarg_msg(uint8_t status, gss_OID mech_wanted,
+ gss_buffer_t token, gss_buffer_t mic,
send_token_flag sendtoken,
gss_buffer_t outbuf)
{
- unsigned int tlen = 0;
- unsigned int ret = 0;
- unsigned int NegTokenTargSize = 0;
- unsigned int NegTokenSize = 0;
- unsigned int rspTokenSize = 0;
- unsigned int micTokenSize = 0;
- unsigned int dataLen = 0;
- unsigned char *t;
- unsigned char *ptr;
+ size_t f0len, f1len, f2len, f3len, fields_len, seq_len, choice_len;
+ uint8_t *t;
+ struct k5buf buf;
if (outbuf == GSS_C_NO_BUFFER)
return (GSS_S_DEFECTIVE_TOKEN);
if (sendtoken == INIT_TOKEN_SEND && mech_wanted == GSS_C_NO_OID)
- return (GSS_S_DEFECTIVE_TOKEN);
+ return (GSS_S_DEFECTIVE_TOKEN);
outbuf->length = 0;
outbuf->value = NULL;
- /*
- * ASN.1 encoding of the negResult
- * ENUMERATED type is 3 bytes
- * ENUMERATED TAG, Length, Value,
- * Plus 2 bytes for the CONTEXT id and length.
- */
- dataLen = 5;
-
- /*
- * calculate data length
- *
- * If this is the initial token, include length of
- * mech_type and the negotiation result fields.
- */
+ /* Calculate the length of each field and the total fields length. */
+ fields_len = 0;
+ /* negState [0] ENUMERATED { ... } OPTIONAL */
+ f0len = k5_der_value_len(1);
+ fields_len += k5_der_value_len(f0len);
if (sendtoken == INIT_TOKEN_SEND) {
- int mechlistTokenSize;
- /*
- * 1 byte for the CONTEXT ID(0xa0),
- * 1 byte for the OID ID(0x06)
- * 1 byte for OID Length field
- * Plus the rest... (OID Length, OID value)
- */
- mechlistTokenSize = 3 + mech_wanted->length +
- gssint_der_length_size(mech_wanted->length);
-
- dataLen += mechlistTokenSize;
+ /* supportedMech [1] MechType OPTIONAL */
+ f1len = k5_der_value_len(mech_wanted->length);
+ fields_len += k5_der_value_len(f1len);
}
- if (data != NULL && data->length > 0) {
- /* Length of the inner token */
- rspTokenSize = 1 + gssint_der_length_size(data->length) +
- data->length;
-
- dataLen += rspTokenSize;
-
- /* Length of the outer token */
- dataLen += 1 + gssint_der_length_size(rspTokenSize);
+ if (token != NULL && token->length > 0) {
+ /* mechToken [2] OCTET STRING OPTIONAL */
+ f2len = k5_der_value_len(token->length);
+ fields_len += k5_der_value_len(f2len);
}
- if (mechListMIC != NULL) {
-
- /* Length of the inner token */
- micTokenSize = 1 + gssint_der_length_size(mechListMIC->length) +
- mechListMIC->length;
-
- dataLen += micTokenSize;
-
- /* Length of the outer token */
- dataLen += 1 + gssint_der_length_size(micTokenSize);
+ if (mic != NULL) {
+ /* mechListMIC [3] OCTET STRING OPTIONAL */
+ f3len = k5_der_value_len(mic->length);
+ fields_len += k5_der_value_len(f3len);
}
- /*
- * Add size of DER encoded:
- * NegTokenTarg [ SEQUENCE ] of
- * NegResult[0] ENUMERATED {
- * accept_completed(0),
- * accept_incomplete(1),
- * reject(2) }
- * supportedMech [1] MechType OPTIONAL,
- * responseToken [2] OCTET STRING OPTIONAL,
- * mechListMIC [3] OCTET STRING OPTIONAL
- *
- * size = data->length + MechListMic + SupportedMech len +
- * Result Length + ASN.1 overhead
- */
- NegTokenTargSize = dataLen;
- dataLen += 1 + gssint_der_length_size(NegTokenTargSize);
-
- /*
- * NegotiationToken [ CHOICE ]{
- * negTokenInit [0] NegTokenInit,
- * negTokenTarg [1] NegTokenTarg }
- */
- NegTokenSize = dataLen;
- dataLen += 1 + gssint_der_length_size(NegTokenSize);
- tlen = dataLen;
- t = (unsigned char *) gssalloc_malloc(tlen);
+ /* Calculate the length of the sequence and choice. */
+ seq_len = k5_der_value_len(fields_len);
+ choice_len = k5_der_value_len(seq_len);
- if (t == NULL) {
- ret = GSS_S_DEFECTIVE_TOKEN;
- goto errout;
- }
+ /* Allocate space and prepare a buffer. */
+ t = gssalloc_malloc(choice_len);
+ if (t == NULL)
+ return (GSS_S_DEFECTIVE_TOKEN);
+ k5_buf_init_fixed(&buf, t, choice_len);
- ptr = t;
+ /* Add the choice tag and begin the sequence. */
+ k5_der_add_taglen(&buf, CONTEXT | 0x01, seq_len);
+ k5_der_add_taglen(&buf, SEQUENCE, fields_len);
- /*
- * Indicate that we are sending CHOICE 1
- * (NegTokenTarg)
- */
- *ptr++ = CONTEXT | 0x01;
- if (gssint_put_der_length(NegTokenSize, &ptr, dataLen) < 0) {
- ret = GSS_S_DEFECTIVE_TOKEN;
- goto errout;
- }
- *ptr++ = SEQUENCE;
- if (gssint_put_der_length(NegTokenTargSize, &ptr,
- tlen - (int)(ptr-t)) < 0) {
- ret = GSS_S_DEFECTIVE_TOKEN;
- goto errout;
- }
+ /* Add the negState field. */
+ k5_der_add_taglen(&buf, CONTEXT | 0x00, f0len);
+ k5_der_add_value(&buf, ENUMERATED, &status, 1);
- /*
- * First field of the NegTokenTarg SEQUENCE
- * is the ENUMERATED NegResult.
- */
- *ptr++ = CONTEXT;
- if (gssint_put_der_length(3, &ptr,
- tlen - (int)(ptr-t)) < 0) {
- ret = GSS_S_DEFECTIVE_TOKEN;
- goto errout;
- }
- if (put_negResult(&ptr, status, tlen - (int)(ptr - t)) < 0) {
- ret = GSS_S_DEFECTIVE_TOKEN;
- goto errout;
- }
if (sendtoken == INIT_TOKEN_SEND) {
- /*
- * Next, is the Supported MechType
- */
- *ptr++ = CONTEXT | 0x01;
- if (gssint_put_der_length(mech_wanted->length + 2,
- &ptr,
- tlen - (int)(ptr - t)) < 0) {
- ret = GSS_S_DEFECTIVE_TOKEN;
- goto errout;
- }
- if (put_mech_oid(&ptr, mech_wanted,
- tlen - (int)(ptr - t)) < 0) {
- ret = GSS_S_DEFECTIVE_TOKEN;
- goto errout;
- }
- }
- if (data != NULL && data->length > 0) {
- *ptr++ = CONTEXT | 0x02;
- if (gssint_put_der_length(rspTokenSize, &ptr,
- tlen - (int)(ptr - t)) < 0) {
- ret = GSS_S_DEFECTIVE_TOKEN;
- goto errout;
- }
- if (put_input_token(&ptr, data,
- tlen - (int)(ptr - t)) < 0) {
- ret = GSS_S_DEFECTIVE_TOKEN;
- goto errout;
- }
- }
- if (mechListMIC != NULL) {
- *ptr++ = CONTEXT | 0x03;
- if (gssint_put_der_length(micTokenSize, &ptr,
- tlen - (int)(ptr - t)) < 0) {
- ret = GSS_S_DEFECTIVE_TOKEN;
- goto errout;
- }
- if (put_input_token(&ptr, mechListMIC,
- tlen - (int)(ptr - t)) < 0) {
- ret = GSS_S_DEFECTIVE_TOKEN;
- goto errout;
- }
- }
- ret = GSS_S_COMPLETE;
-errout:
- if (ret != GSS_S_COMPLETE) {
- if (t)
- free(t);
- } else {
- outbuf->length = ptr - t;
- outbuf->value = (void *) t;
- }
-
- return (ret);
-}
-
-/* determine size of token */
-static int
-g_token_size(gss_OID_const mech, unsigned int body_size)
-{
- int hdrsize;
-
- /*
- * Initialize the header size to the
- * MECH_OID byte + the bytes needed to indicate the
- * length of the OID + the OID itself.
- *
- * 0x06 [MECHLENFIELD] MECHDATA
- */
- hdrsize = 1 + gssint_der_length_size(mech->length) + mech->length;
-
- /*
- * Now add the bytes needed for the initial header
- * token bytes:
- * 0x60 + [DER_LEN] + HDRSIZE
- */
- hdrsize += 1 + gssint_der_length_size(body_size + hdrsize);
-
- return (hdrsize + body_size);
-}
-
-/*
- * generate token header.
- *
- * Use DER Definite Length method per RFC2478
- * Use of indefinite length encoding will not be compatible
- * with Microsoft or others that actually follow the spec.
- */
-static int
-g_make_token_header(gss_OID_const mech,
- unsigned int body_size,
- unsigned char **buf,
- unsigned int totallen)
-{
- int ret = 0;
- unsigned int hdrsize;
- unsigned char *p = *buf;
-
- hdrsize = 1 + gssint_der_length_size(mech->length) + mech->length;
-
- *(*buf)++ = HEADER_ID;
- if ((ret = gssint_put_der_length(hdrsize + body_size, buf, totallen)))
- return (ret);
-
- *(*buf)++ = MECH_OID;
- if ((ret = gssint_put_der_length(mech->length, buf,
- totallen - (int)(p - *buf))))
- return (ret);
- TWRITE_STR(*buf, mech->elements, mech->length);
- return (0);
-}
-
-/*
- * NOTE: This checks that the length returned by
- * gssint_get_der_length() is not greater than the number of octets
- * remaining, even though gssint_get_der_length() already checks, in
- * theory.
- */
-static int
-g_get_tag_and_length(unsigned char **buf, int tag,
- unsigned int buflen, unsigned int *outlen)
-{
- unsigned char *ptr = *buf;
- int ret = -1; /* pessimists, assume failure ! */
- unsigned int encoded_len;
- int tmplen = 0;
-
- *outlen = 0;
- if (buflen > 1 && *ptr == tag) {
- ptr++;
- tmplen = gssint_get_der_length(&ptr, buflen - 1,
- &encoded_len);
- if (tmplen < 0) {
- ret = -1;
- } else if ((unsigned int)tmplen > buflen - (ptr - *buf)) {
- ret = -1;
- } else
- ret = 0;
+ /* Add the supportedMech field. */
+ k5_der_add_taglen(&buf, CONTEXT | 0x01, f1len);
+ k5_der_add_value(&buf, MECH_OID, mech_wanted->elements,
+ mech_wanted->length);
}
- *outlen = tmplen;
- *buf = ptr;
- return (ret);
-}
-
-static int
-g_verify_neg_token_init(unsigned char **buf_in, unsigned int cur_size)
-{
- unsigned char *buf = *buf_in;
- unsigned char *endptr = buf + cur_size;
- int seqsize;
- int ret = 0;
- unsigned int bytes;
-
- /*
- * Verify this is a NegotiationToken type token
- * - check for a0(context specific identifier)
- * - get length and verify that enoughd ata exists
- */
- if (g_get_tag_and_length(&buf, CONTEXT, cur_size, &bytes) < 0 ||
- bytes == 0)
- return (G_BAD_TOK_HEADER);
- cur_size = bytes; /* should indicate bytes remaining */
-
- /*
- * Verify the next piece, it should identify this as
- * a strucure of type NegTokenInit.
- */
- if (*buf++ == SEQUENCE) {
- if ((seqsize = gssint_get_der_length(&buf, cur_size - 1, &bytes)) <= 0)
- return (G_BAD_TOK_HEADER);
- /*
- * Make sure we have the entire buffer as described
- */
- if (seqsize > endptr - buf)
- return (G_BAD_TOK_HEADER);
- } else {
- return (G_BAD_TOK_HEADER);
+ if (token != NULL && token->length > 0) {
+ /* Add the mechToken field. */
+ k5_der_add_taglen(&buf, CONTEXT | 0x02, f2len);
+ k5_der_add_value(&buf, OCTET_STRING, token->value,
+ token->length);
}
- cur_size = seqsize; /* should indicate bytes remaining */
-
- /*
- * Verify that the first blob is a sequence of mechTypes
- */
- if (*buf++ == CONTEXT) {
- if ((seqsize = gssint_get_der_length(&buf, cur_size - 1, &bytes)) < 0)
- return (G_BAD_TOK_HEADER);
- /*
- * Make sure we have the entire buffer as described
- */
- if (seqsize > endptr - buf)
- return (G_BAD_TOK_HEADER);
- } else {
- return (G_BAD_TOK_HEADER);
+ if (mic != NULL) {
+ /* Add the mechListMIC field. */
+ k5_der_add_taglen(&buf, CONTEXT | 0x03, f3len);
+ k5_der_add_value(&buf, OCTET_STRING, mic->value, mic->length);
}
- /*
- * At this point, *buf should be at the beginning of the
- * DER encoded list of mech types that are to be negotiated.
- */
- *buf_in = buf;
-
- return (ret);
+ assert(buf.len == choice_len);
+ outbuf->length = choice_len;
+ outbuf->value = t;
+ return (0);
}
-/* verify token header. */
+/* Advance in past the [APPLICATION 0] tag and thisMech field of an
+ * InitialContextToken encoding, checking that thisMech matches mech. */
static int
-g_verify_token_header(gss_OID_const mech,
- unsigned int *body_size,
- unsigned char **buf_in,
- int tok_type,
- unsigned int toksize)
+verify_token_header(struct k5input *in, gss_OID_const mech)
{
- unsigned char *buf = *buf_in;
- int seqsize;
- gss_OID_desc toid;
- int ret = 0;
- unsigned int bytes;
+ gss_OID_desc oid;
+ struct k5input field;
- if (toksize-- < 1)
+ if (!k5_der_get_value(in, HEADER_ID, in))
return (G_BAD_TOK_HEADER);
-
- if (*buf++ != HEADER_ID)
+ if (!k5_der_get_value(in, MECH_OID, &field))
return (G_BAD_TOK_HEADER);
- if ((seqsize = gssint_get_der_length(&buf, toksize, &bytes)) < 0)
- return (G_BAD_TOK_HEADER);
-
- if ((seqsize + bytes) != toksize)
- return (G_BAD_TOK_HEADER);
-
- if (toksize-- < 1)
- return (G_BAD_TOK_HEADER);
-
-
- if (*buf++ != MECH_OID)
- return (G_BAD_TOK_HEADER);
-
- if (toksize-- < 1)
- return (G_BAD_TOK_HEADER);
-
- toid.length = *buf++;
-
- if (toksize < toid.length)
- return (G_BAD_TOK_HEADER);
- else
- toksize -= toid.length;
-
- toid.elements = buf;
- buf += toid.length;
-
- if (!g_OID_equal(&toid, mech))
- ret = G_WRONG_MECH;
-
- /*
- * G_WRONG_MECH is not returned immediately because it's more important
- * to return G_BAD_TOK_HEADER if the token header is in fact bad
- */
- if (toksize < 2)
- return (G_BAD_TOK_HEADER);
- else
- toksize -= 2;
-
- if (!ret) {
- *buf_in = buf;
- *body_size = toksize;
- }
-
- return (ret);
+ oid.length = field.len;
+ oid.elements = (uint8_t *)field.ptr;
+ return g_OID_equal(&oid, mech) ? 0 : G_WRONG_MECH;
}
/*