aboutsummaryrefslogtreecommitdiff
path: root/lib/gssapi/krb5
diff options
context:
space:
mode:
Diffstat (limited to 'lib/gssapi/krb5')
-rw-r--r--lib/gssapi/krb5/accept_sec_context.c1
-rw-r--r--lib/gssapi/krb5/acquire_cred.c5
-rw-r--r--lib/gssapi/krb5/arcfour.c70
-rw-r--r--lib/gssapi/krb5/cfx.c52
-rw-r--r--lib/gssapi/krb5/decapsulate.c12
-rw-r--r--lib/gssapi/krb5/delete_sec_context.c2
-rw-r--r--lib/gssapi/krb5/display_status.c3
-rw-r--r--lib/gssapi/krb5/gsskrb5-private.h3
-rw-r--r--lib/gssapi/krb5/init_sec_context.c16
-rw-r--r--lib/gssapi/krb5/unwrap.c34
10 files changed, 137 insertions, 61 deletions
diff --git a/lib/gssapi/krb5/accept_sec_context.c b/lib/gssapi/krb5/accept_sec_context.c
index d4680e9e8fb6..e35cc10e560c 100644
--- a/lib/gssapi/krb5/accept_sec_context.c
+++ b/lib/gssapi/krb5/accept_sec_context.c
@@ -443,6 +443,7 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status,
* lets only send the error token on clock skew, that
* limit when send error token for non-MUTUAL.
*/
+ free_Authenticator(ctx->auth_context->authenticator);
return send_error_token(minor_status, context, kret,
server, &indata, output_token);
} else if (kret) {
diff --git a/lib/gssapi/krb5/acquire_cred.c b/lib/gssapi/krb5/acquire_cred.c
index 9c880b334fd6..431700070e53 100644
--- a/lib/gssapi/krb5/acquire_cred.c
+++ b/lib/gssapi/krb5/acquire_cred.c
@@ -100,6 +100,7 @@ acquire_cred_with_password(OM_uint32 *minor_status,
krb5_error_code kret;
time_t now;
OM_uint32 left;
+ const char *realm;
if (cred_usage == GSS_C_ACCEPT) {
/*
@@ -126,6 +127,10 @@ acquire_cred_with_password(OM_uint32 *minor_status,
if (kret)
goto end;
+ realm = krb5_principal_get_realm(context, handle->principal);
+
+ krb5_get_init_creds_opt_set_default_flags(context, "gss_krb5", realm, opt);
+
/*
* Get the current time before the AS exchange so we don't
* accidentally end up returning a value that puts advertised
diff --git a/lib/gssapi/krb5/arcfour.c b/lib/gssapi/krb5/arcfour.c
index d88ec4cddc53..aa03cbe41acb 100644
--- a/lib/gssapi/krb5/arcfour.c
+++ b/lib/gssapi/krb5/arcfour.c
@@ -177,7 +177,7 @@ arcfour_mic_cksum_iov(krb5_context context,
memcpy(ptr + ofs,
padding->buffer.value,
padding->buffer.length);
- ofs += padding->buffer.length;
+ /* ofs += padding->buffer.length; */
}
ret = krb5_crypto_init(context, key, 0, &crypto);
@@ -365,7 +365,7 @@ _gssapi_verify_mic_arcfour(OM_uint32 * minor_status,
return GSS_S_FAILURE;
}
- cmp = ct_memcmp(cksum_data, p + 8, 8);
+ cmp = (ct_memcmp(cksum_data, p + 8, 8) == 0);
if (cmp) {
*minor_status = 0;
return GSS_S_BAD_MIC;
@@ -385,9 +385,9 @@ _gssapi_verify_mic_arcfour(OM_uint32 * minor_status,
_gsskrb5_decode_be_om_uint32(SND_SEQ, &seq_number);
if (context_handle->more_flags & LOCAL)
- cmp = memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4);
+ cmp = (ct_memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4) != 0);
else
- cmp = memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4);
+ cmp = (ct_memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4) != 0);
memset_s(SND_SEQ, sizeof(SND_SEQ), 0, sizeof(SND_SEQ));
if (cmp != 0) {
@@ -656,9 +656,9 @@ OM_uint32 _gssapi_unwrap_arcfour(OM_uint32 *minor_status,
_gsskrb5_decode_be_om_uint32(SND_SEQ, &seq_number);
if (context_handle->more_flags & LOCAL)
- cmp = memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4);
+ cmp = (ct_memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4) != 0);
else
- cmp = memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4);
+ cmp = (ct_memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4) != 0);
if (cmp != 0) {
*minor_status = 0;
@@ -730,7 +730,7 @@ OM_uint32 _gssapi_unwrap_arcfour(OM_uint32 *minor_status,
return GSS_S_FAILURE;
}
- cmp = ct_memcmp(cksum_data, p0 + 16, 8); /* SGN_CKSUM */
+ cmp = (ct_memcmp(cksum_data, p0 + 16, 8) == 0); /* SGN_CKSUM */
if (cmp) {
_gsskrb5_release_buffer(minor_status, output_message_buffer);
*minor_status = 0;
@@ -880,7 +880,13 @@ _gssapi_wrap_iov_length_arcfour(OM_uint32 *minor_status,
}
}
- major_status = _gk_verify_buffers(minor_status, ctx, header, padding, trailer);
+ if (header == NULL) {
+ *minor_status = EINVAL;
+ return GSS_S_FAILURE;
+ }
+
+ major_status = _gk_verify_buffers(minor_status, ctx, header,
+ padding, trailer, FALSE);
if (major_status != GSS_S_COMPLETE) {
return major_status;
}
@@ -937,7 +943,8 @@ _gssapi_wrap_iov_arcfour(OM_uint32 *minor_status,
padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
- major_status = _gk_verify_buffers(minor_status, ctx, header, padding, trailer);
+ major_status = _gk_verify_buffers(minor_status, ctx, header,
+ padding, trailer, FALSE);
if (major_status != GSS_S_COMPLETE) {
return major_status;
}
@@ -974,7 +981,7 @@ _gssapi_wrap_iov_arcfour(OM_uint32 *minor_status,
header_len -= data_len;
}
- if (GSS_IOV_BUFFER_FLAGS(header->type) & GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE) {
+ if (GSS_IOV_BUFFER_FLAGS(header->type) & GSS_IOV_BUFFER_FLAG_ALLOCATE) {
major_status = _gk_allocate_buffer(minor_status, header,
header_len);
if (major_status != GSS_S_COMPLETE)
@@ -988,7 +995,7 @@ _gssapi_wrap_iov_arcfour(OM_uint32 *minor_status,
}
if (padding) {
- if (GSS_IOV_BUFFER_FLAGS(padding->type) & GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE) {
+ if (GSS_IOV_BUFFER_FLAGS(padding->type) & GSS_IOV_BUFFER_FLAG_ALLOCATE) {
major_status = _gk_allocate_buffer(minor_status, padding, 1);
if (major_status != GSS_S_COMPLETE)
goto failure;
@@ -1181,10 +1188,11 @@ _gssapi_unwrap_iov_arcfour(OM_uint32 *minor_status,
/* Check if the packet is correct */
major_status = _gk_verify_buffers(minor_status,
- ctx,
- header,
- padding,
- trailer);
+ ctx,
+ header,
+ padding,
+ trailer,
+ FALSE); /* behaves as stream cipher */
if (major_status != GSS_S_COMPLETE) {
return major_status;
}
@@ -1194,15 +1202,19 @@ _gssapi_unwrap_iov_arcfour(OM_uint32 *minor_status,
return GSS_S_FAILURE;
}
- if (IS_DCE_STYLE(context)) {
- verify_len = GSS_ARCFOUR_WRAP_TOKEN_SIZE +
- GSS_ARCFOUR_WRAP_TOKEN_DCE_DER_HEADER_SIZE;
- if (header->buffer.length > verify_len) {
- return GSS_S_BAD_MECH;
+ verify_len = header->buffer.length;
+
+ if (!IS_DCE_STYLE(context)) {
+ for (i = 0; i < iov_count; i++) {
+ /* length in header also includes data and padding */
+ if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA)
+ verify_len += iov[i].buffer.length;
}
- } else {
- verify_len = header->buffer.length;
+
+ if (padding)
+ verify_len += padding->buffer.length;
}
+
_p = header->buffer.value;
ret = _gssapi_verify_mech_header(&_p,
@@ -1267,19 +1279,9 @@ _gssapi_unwrap_iov_arcfour(OM_uint32 *minor_status,
_gsskrb5_decode_be_om_uint32(snd_seq, &seq_number);
if (ctx->more_flags & LOCAL) {
- cmp = memcmp(&snd_seq[4], "\xff\xff\xff\xff", 4);
- } else {
- cmp = memcmp(&snd_seq[4], "\x00\x00\x00\x00", 4);
- }
- if (cmp != 0) {
- *minor_status = 0;
- return GSS_S_BAD_MIC;
- }
-
- if (ctx->more_flags & LOCAL) {
- cmp = memcmp(&snd_seq[4], "\xff\xff\xff\xff", 4);
+ cmp = (ct_memcmp(&snd_seq[4], "\xff\xff\xff\xff", 4) != 0);
} else {
- cmp = memcmp(&snd_seq[4], "\x00\x00\x00\x00", 4);
+ cmp = (ct_memcmp(&snd_seq[4], "\x00\x00\x00\x00", 4) != 0);
}
if (cmp != 0) {
*minor_status = 0;
diff --git a/lib/gssapi/krb5/cfx.c b/lib/gssapi/krb5/cfx.c
index 29fecca861ce..8d806f9fbf1c 100644
--- a/lib/gssapi/krb5/cfx.c
+++ b/lib/gssapi/krb5/cfx.c
@@ -206,11 +206,36 @@ gss_iov_buffer_desc *
_gk_find_buffer(gss_iov_buffer_desc *iov, int iov_count, OM_uint32 type)
{
int i;
+ gss_iov_buffer_t iovp = GSS_C_NO_IOV_BUFFER;
- for (i = 0; i < iov_count; i++)
- if (type == GSS_IOV_BUFFER_TYPE(iov[i].type))
- return &iov[i];
- return NULL;
+ if (iov == GSS_C_NO_IOV_BUFFER)
+ return GSS_C_NO_IOV_BUFFER;
+
+ /*
+ * This function is used to find header, padding or trailer buffers
+ * which are singletons; return NULL if multiple instances are found.
+ */
+ for (i = 0; i < iov_count; i++) {
+ if (type == GSS_IOV_BUFFER_TYPE(iov[i].type)) {
+ if (iovp == GSS_C_NO_IOV_BUFFER)
+ iovp = &iov[i];
+ else
+ return GSS_C_NO_IOV_BUFFER;
+ }
+ }
+
+ /*
+ * For compatibility with SSPI, an empty padding buffer is treated
+ * equivalent to an absent padding buffer (unless the caller is
+ * requesting that a padding buffer be allocated).
+ */
+ if (iovp &&
+ iovp->buffer.length == 0 &&
+ type == GSS_IOV_BUFFER_TYPE_PADDING &&
+ (GSS_IOV_BUFFER_FLAGS(iovp->type) & GSS_IOV_BUFFER_FLAG_ALLOCATE) == 0)
+ iovp = NULL;
+
+ return iovp;
}
OM_uint32
@@ -239,7 +264,8 @@ _gk_verify_buffers(OM_uint32 *minor_status,
const gsskrb5_ctx ctx,
const gss_iov_buffer_desc *header,
const gss_iov_buffer_desc *padding,
- const gss_iov_buffer_desc *trailer)
+ const gss_iov_buffer_desc *trailer,
+ int block_cipher)
{
if (header == NULL) {
*minor_status = EINVAL;
@@ -260,9 +286,12 @@ _gk_verify_buffers(OM_uint32 *minor_status,
}
} else {
/*
- * In non-DCE style mode we require having a padding buffer
+ * In non-DCE style mode we require having a padding buffer for
+ * encryption types that do not behave as stream ciphers. This
+ * check is superfluous for now, as only RC4 and RFC4121 enctypes
+ * are presently implemented for the IOV APIs; be defensive.
*/
- if (padding == NULL) {
+ if (block_cipher && padding == NULL) {
*minor_status = EINVAL;
return GSS_S_FAILURE;
}
@@ -306,7 +335,8 @@ _gssapi_wrap_cfx_iov(OM_uint32 *minor_status,
trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
- major_status = _gk_verify_buffers(minor_status, ctx, header, padding, trailer);
+ major_status = _gk_verify_buffers(minor_status, ctx, header,
+ padding, trailer, FALSE);
if (major_status != GSS_S_COMPLETE) {
return major_status;
}
@@ -747,7 +777,8 @@ _gssapi_unwrap_cfx_iov(OM_uint32 *minor_status,
trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
- major_status = _gk_verify_buffers(minor_status, ctx, header, padding, trailer);
+ major_status = _gk_verify_buffers(minor_status, ctx, header,
+ padding, trailer, FALSE);
if (major_status != GSS_S_COMPLETE) {
return major_status;
}
@@ -1069,7 +1100,8 @@ _gssapi_wrap_iov_length_cfx(OM_uint32 *minor_status,
}
}
- major_status = _gk_verify_buffers(minor_status, ctx, header, padding, trailer);
+ major_status = _gk_verify_buffers(minor_status, ctx, header,
+ padding, trailer, FALSE);
if (major_status != GSS_S_COMPLETE) {
return major_status;
}
diff --git a/lib/gssapi/krb5/decapsulate.c b/lib/gssapi/krb5/decapsulate.c
index 86085f569501..d7b75a642224 100644
--- a/lib/gssapi/krb5/decapsulate.c
+++ b/lib/gssapi/krb5/decapsulate.c
@@ -54,6 +54,8 @@ _gsskrb5_get_mech (const u_char *ptr,
e = der_get_length (p, total_len - 1, &len, &len_len);
if (e || 1 + len_len + len != total_len)
return -1;
+ if (total_len < 1 + len_len + 1)
+ return -1;
p += len_len;
if (*p++ != 0x06)
return -1;
@@ -80,6 +82,10 @@ _gssapi_verify_mech_header(u_char **str,
if (mech_len != mech->length)
return GSS_S_BAD_MECH;
+ if (mech_len > total_len)
+ return GSS_S_BAD_MECH;
+ if (p - *str > total_len - mech_len)
+ return GSS_S_BAD_MECH;
if (ct_memcmp(p,
mech->elements,
mech->length) != 0)
@@ -193,13 +199,13 @@ _gssapi_verify_pad(gss_buffer_t wrapped_token,
if (wrapped_token->length < 1)
return GSS_S_BAD_MECH;
- pad = (u_char *)wrapped_token->value + wrapped_token->length - 1;
- padlength = *pad;
+ pad = (u_char *)wrapped_token->value + wrapped_token->length;
+ padlength = pad[-1];
if (padlength > datalen)
return GSS_S_BAD_MECH;
- for (i = padlength; i > 0 && *pad == padlength; i--, pad--)
+ for (i = padlength; i > 0 && *--pad == padlength; i--)
;
if (i != 0)
return GSS_S_BAD_MIC;
diff --git a/lib/gssapi/krb5/delete_sec_context.c b/lib/gssapi/krb5/delete_sec_context.c
index 83a66cc0ca01..a4800791ec4e 100644
--- a/lib/gssapi/krb5/delete_sec_context.c
+++ b/lib/gssapi/krb5/delete_sec_context.c
@@ -75,6 +75,8 @@ _gsskrb5_delete_sec_context(OM_uint32 * minor_status,
krb5_data_free(&ctx->fwd_data);
if (ctx->crypto)
krb5_crypto_destroy(context, ctx->crypto);
+ if (ctx->ccache && (ctx->more_flags & CLOSE_CCACHE))
+ krb5_cc_close(context, ctx->ccache);
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex);
diff --git a/lib/gssapi/krb5/display_status.c b/lib/gssapi/krb5/display_status.c
index c50200672aaf..2587b966cfb8 100644
--- a/lib/gssapi/krb5/display_status.c
+++ b/lib/gssapi/krb5/display_status.c
@@ -64,8 +64,7 @@ routine_error(OM_uint32 v)
"Incorrect channel bindings were supplied",
"An invalid status code was supplied",
"A token had an invalid MIC",
- "No credentials were supplied, "
- "or the credentials were unavailable or inaccessible.",
+ "No credentials were supplied, or the credentials were unavailable or inaccessible.",
"No context has been established",
"A token was invalid",
"A credential was invalid",
diff --git a/lib/gssapi/krb5/gsskrb5-private.h b/lib/gssapi/krb5/gsskrb5-private.h
index e05d4a6b6da6..29eea8adf0a8 100644
--- a/lib/gssapi/krb5/gsskrb5-private.h
+++ b/lib/gssapi/krb5/gsskrb5-private.h
@@ -42,7 +42,8 @@ _gk_verify_buffers (
const gsskrb5_ctx /*ctx*/,
const gss_iov_buffer_desc */*header*/,
const gss_iov_buffer_desc */*padding*/,
- const gss_iov_buffer_desc */*trailer*/);
+ const gss_iov_buffer_desc */*trailer*/,
+ int /*block_cipher*/);
OM_uint32 GSSAPI_CALLCONV
_gk_wrap_iov (
diff --git a/lib/gssapi/krb5/init_sec_context.c b/lib/gssapi/krb5/init_sec_context.c
index 4ef5c9c7123a..21ac554efd4f 100644
--- a/lib/gssapi/krb5/init_sec_context.c
+++ b/lib/gssapi/krb5/init_sec_context.c
@@ -600,7 +600,19 @@ init_auth_restart
if (ret == 0) {
if (timedata.length == 4) {
const u_char *p = timedata.data;
- offset = (p[0] <<24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0);
+ if (p[0] < 128) {
+ offset = (p[0] <<24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0);
+ } else {
+ /*
+ * (p[0] << 24), if p[0] > 127 -> offset is negative, but *p is
+ * positive, so this is overflow -- overflow we want, but UBSAN
+ * flags it.
+ *
+ * NOTE: We assume the platform is a twos-complement platform.
+ */
+ offset = INT32_MIN;
+ offset |= ((p[0] & 0x7f) <<24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0);
+ }
}
krb5_data_free(&timedata);
}
@@ -921,7 +933,7 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_init_sec_context
time_rec);
if (ret != GSS_S_COMPLETE)
break;
- /* FALL THOUGH */
+ /* FALLTHROUGH */
case INITIATOR_RESTART:
ret = init_auth_restart(minor_status,
cred,
diff --git a/lib/gssapi/krb5/unwrap.c b/lib/gssapi/krb5/unwrap.c
index da939c052930..bab30f45016b 100644
--- a/lib/gssapi/krb5/unwrap.c
+++ b/lib/gssapi/krb5/unwrap.c
@@ -64,6 +64,8 @@ unwrap_des
if (IS_DCE_STYLE(context_handle)) {
token_len = 22 + 8 + 15; /* 45 */
+ if (input_message_buffer->length < token_len)
+ return GSS_S_BAD_MECH;
} else {
token_len = input_message_buffer->length;
}
@@ -76,6 +78,11 @@ unwrap_des
if (ret)
return ret;
+ len = (p - (u_char *)input_message_buffer->value)
+ + 22 + 8;
+ if (input_message_buffer->length < len)
+ return GSS_S_BAD_MECH;
+
if (memcmp (p, "\x00\x00", 2) != 0)
return GSS_S_BAD_SIG;
p += 2;
@@ -117,7 +124,7 @@ unwrap_des
} else {
/* check pad */
ret = _gssapi_verify_pad(input_message_buffer,
- input_message_buffer->length - len,
+ input_message_buffer->length - len - 8,
&padlength);
if (ret)
return ret;
@@ -180,9 +187,10 @@ unwrap_des
output_message_buffer->value = malloc(output_message_buffer->length);
if(output_message_buffer->length != 0 && output_message_buffer->value == NULL)
return GSS_S_FAILURE;
- memcpy (output_message_buffer->value,
- p + 24,
- output_message_buffer->length);
+ if (output_message_buffer->value != NULL)
+ memcpy (output_message_buffer->value,
+ p + 24,
+ output_message_buffer->length);
return GSS_S_COMPLETE;
}
#endif
@@ -215,6 +223,8 @@ unwrap_des3
if (IS_DCE_STYLE(context_handle)) {
token_len = 34 + 8 + 15; /* 57 */
+ if (input_message_buffer->length < token_len)
+ return GSS_S_BAD_MECH;
} else {
token_len = input_message_buffer->length;
}
@@ -227,7 +237,12 @@ unwrap_des3
if (ret)
return ret;
- if (memcmp (p, "\x04\x00", 2) != 0) /* HMAC SHA1 DES3_KD */
+ len = (p - (u_char *)input_message_buffer->value)
+ + 34 + 8;
+ if (input_message_buffer->length < len)
+ return GSS_S_BAD_MECH;
+
+ if (ct_memcmp (p, "\x04\x00", 2) != 0) /* HMAC SHA1 DES3_KD */
return GSS_S_BAD_SIG;
p += 2;
if (ct_memcmp (p, "\x02\x00", 2) == 0) {
@@ -274,7 +289,7 @@ unwrap_des3
} else {
/* check pad */
ret = _gssapi_verify_pad(input_message_buffer,
- input_message_buffer->length - len,
+ input_message_buffer->length - len - 8,
&padlength);
if (ret)
return ret;
@@ -374,9 +389,10 @@ unwrap_des3
output_message_buffer->value = malloc(output_message_buffer->length);
if(output_message_buffer->length != 0 && output_message_buffer->value == NULL)
return GSS_S_FAILURE;
- memcpy (output_message_buffer->value,
- p + 36,
- output_message_buffer->length);
+ if (output_message_buffer->value != NULL)
+ memcpy (output_message_buffer->value,
+ p + 36,
+ output_message_buffer->length);
return GSS_S_COMPLETE;
}