summaryrefslogtreecommitdiffstats
path: root/third_party/heimdal/lib/gssapi/mech/gss_aeap.c
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/heimdal/lib/gssapi/mech/gss_aeap.c')
-rw-r--r--third_party/heimdal/lib/gssapi/mech/gss_aeap.c334
1 files changed, 334 insertions, 0 deletions
diff --git a/third_party/heimdal/lib/gssapi/mech/gss_aeap.c b/third_party/heimdal/lib/gssapi/mech/gss_aeap.c
new file mode 100644
index 0000000..dbcd611
--- /dev/null
+++ b/third_party/heimdal/lib/gssapi/mech/gss_aeap.c
@@ -0,0 +1,334 @@
+/*
+ * AEAD support
+ */
+
+#include "mech_locl.h"
+
+/**
+ * Encrypts or sign the data.
+ *
+ * This is a more complicated version of gss_wrap(), it allows the
+ * caller to use AEAD data (signed header/trailer) and allow greater
+ * controll over where the encrypted data is placed.
+ *
+ * The maximum packet size is gss_context_stream_sizes.max_msg_size.
+ *
+ * The caller needs provide the folloing buffers when using in conf_req_flag=1 mode:
+ *
+ * - HEADER (of size gss_context_stream_sizes.header)
+ * { DATA or SIGN_ONLY } (optional, zero or more)
+ * PADDING (of size gss_context_stream_sizes.blocksize, if zero padding is zero, can be omitted)
+ * TRAILER (of size gss_context_stream_sizes.trailer)
+ *
+ * - on DCE-RPC mode, the caller can skip PADDING and TRAILER if the
+ * DATA elements is padded to a block bountry and header is of at
+ * least size gss_context_stream_sizes.header + gss_context_stream_sizes.trailer.
+ *
+ * HEADER, PADDING, TRAILER will be shrunken to the size required to transmit any of them too large.
+ *
+ * To generate gss_wrap() compatible packets, use: HEADER | DATA | PADDING | TRAILER
+ *
+ * When used in conf_req_flag=0,
+ *
+ * - HEADER (of size gss_context_stream_sizes.header)
+ * { DATA or SIGN_ONLY } (optional, zero or more)
+ * PADDING (of size gss_context_stream_sizes.blocksize, if zero padding is zero, can be omitted)
+ * TRAILER (of size gss_context_stream_sizes.trailer)
+ *
+ *
+ * The input sizes of HEADER, PADDING and TRAILER can be fetched using gss_wrap_iov_length() or
+ * gss_context_query_attributes().
+ *
+ * @ingroup gssapi
+ */
+
+
+GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
+gss_wrap_iov(OM_uint32 * minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ int * conf_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+ struct _gss_context *ctx = (struct _gss_context *) context_handle;
+ gssapi_mech_interface m;
+
+ if (minor_status)
+ *minor_status = 0;
+ if (conf_state)
+ *conf_state = 0;
+ if (ctx == NULL)
+ return GSS_S_NO_CONTEXT;
+ if (iov == NULL && iov_count != 0)
+ return GSS_S_CALL_INACCESSIBLE_READ;
+
+ m = ctx->gc_mech;
+
+ if (m->gm_wrap_iov == NULL)
+ return GSS_S_UNAVAILABLE;
+
+ return (m->gm_wrap_iov)(minor_status, ctx->gc_ctx,
+ conf_req_flag, qop_req, conf_state,
+ iov, iov_count);
+}
+
+/**
+ * Decrypt or verifies the signature on the data.
+ *
+ *
+ * @ingroup gssapi
+ */
+
+GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
+gss_unwrap_iov(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int *conf_state,
+ gss_qop_t *qop_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+ struct _gss_context *ctx = (struct _gss_context *) context_handle;
+ gssapi_mech_interface m;
+
+ if (minor_status)
+ *minor_status = 0;
+ if (conf_state)
+ *conf_state = 0;
+ if (qop_state)
+ *qop_state = 0;
+ if (ctx == NULL)
+ return GSS_S_NO_CONTEXT;
+ if (iov == NULL && iov_count != 0)
+ return GSS_S_CALL_INACCESSIBLE_READ;
+
+ m = ctx->gc_mech;
+
+ if (m->gm_unwrap_iov == NULL)
+ return GSS_S_UNAVAILABLE;
+
+ return (m->gm_unwrap_iov)(minor_status, ctx->gc_ctx,
+ conf_state, qop_state,
+ iov, iov_count);
+}
+
+/**
+ * Update the length fields in iov buffer for the types:
+ * - GSS_IOV_BUFFER_TYPE_HEADER
+ * - GSS_IOV_BUFFER_TYPE_PADDING
+ * - GSS_IOV_BUFFER_TYPE_TRAILER
+ *
+ * Consider using gss_context_query_attributes() to fetch the data instead.
+ *
+ * @ingroup gssapi
+ */
+
+GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
+gss_wrap_iov_length(OM_uint32 * minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ int *conf_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+ struct _gss_context *ctx = (struct _gss_context *) context_handle;
+ gssapi_mech_interface m;
+
+ if (minor_status)
+ *minor_status = 0;
+ if (conf_state)
+ *conf_state = 0;
+ if (ctx == NULL)
+ return GSS_S_NO_CONTEXT;
+ if (iov == NULL && iov_count != 0)
+ return GSS_S_CALL_INACCESSIBLE_READ;
+
+ m = ctx->gc_mech;
+
+ if (m->gm_wrap_iov_length == NULL)
+ return GSS_S_UNAVAILABLE;
+
+ return (m->gm_wrap_iov_length)(minor_status, ctx->gc_ctx,
+ conf_req_flag, qop_req, conf_state,
+ iov, iov_count);
+}
+
+/**
+ * Free all buffer allocated by gss_wrap_iov() or gss_unwrap_iov() by
+ * looking at the GSS_IOV_BUFFER_FLAG_ALLOCATED flag.
+ *
+ * @ingroup gssapi
+ */
+
+GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
+gss_release_iov_buffer(OM_uint32 *minor_status,
+ gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+ OM_uint32 junk;
+ int i;
+
+ if (minor_status)
+ *minor_status = 0;
+ if (iov == NULL && iov_count != 0)
+ return GSS_S_CALL_INACCESSIBLE_READ;
+
+ for (i = 0; i < iov_count; i++) {
+ if ((iov[i].type & GSS_IOV_BUFFER_FLAG_ALLOCATED) == 0)
+ continue;
+ gss_release_buffer(&junk, &iov[i].buffer);
+ iov[i].type &= ~GSS_IOV_BUFFER_FLAG_ALLOCATED;
+ }
+ return GSS_S_COMPLETE;
+}
+
+/**
+ * Query the context for parameters.
+ *
+ * SSPI equivalent if this function is QueryContextAttributes.
+ *
+ * - GSS_C_ATTR_STREAM_SIZES data is a gss_context_stream_sizes.
+ *
+ * @ingroup gssapi
+ */
+
+gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_attr_stream_sizes_oid_desc =
+ {10, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x03")};
+
+GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
+gss_context_query_attributes(OM_uint32 *minor_status,
+ gss_const_ctx_id_t context_handle,
+ const gss_OID attribute,
+ void *data,
+ size_t len)
+{
+ if (minor_status)
+ *minor_status = 0;
+
+ if (gss_oid_equal(GSS_C_ATTR_STREAM_SIZES, attribute)) {
+ memset(data, 0, len);
+ return GSS_S_COMPLETE;
+ }
+
+ return GSS_S_FAILURE;
+}
+
+/*
+ * AEAD wrap API for a single piece of associated data, for compatibility
+ * with MIT and as specified by draft-howard-gssapi-aead-00.txt.
+ *
+ * @ingroup gssapi
+ */
+GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
+gss_wrap_aead(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ gss_buffer_t input_assoc_buffer,
+ gss_buffer_t input_payload_buffer,
+ int *conf_state,
+ gss_buffer_t output_message_buffer)
+{
+ OM_uint32 major_status, tmp, flags = 0;
+ gss_iov_buffer_desc iov[5];
+ size_t i;
+ unsigned char *p;
+
+ memset(iov, 0, sizeof(iov));
+
+ iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
+
+ iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
+ if (input_assoc_buffer)
+ iov[1].buffer = *input_assoc_buffer;
+
+ iov[2].type = GSS_IOV_BUFFER_TYPE_DATA;
+ if (input_payload_buffer)
+ iov[2].buffer.length = input_payload_buffer->length;
+
+ gss_inquire_context(minor_status, context_handle, NULL, NULL,
+ NULL, NULL, &flags, NULL, NULL);
+
+ /* krb5 mech rejects padding/trailer if DCE-style is set */
+ iov[3].type = (flags & GSS_C_DCE_STYLE) ? GSS_IOV_BUFFER_TYPE_EMPTY
+ : GSS_IOV_BUFFER_TYPE_PADDING;
+ iov[4].type = (flags & GSS_C_DCE_STYLE) ? GSS_IOV_BUFFER_TYPE_EMPTY
+ : GSS_IOV_BUFFER_TYPE_TRAILER;
+
+ major_status = gss_wrap_iov_length(minor_status, context_handle,
+ conf_req_flag, qop_req, conf_state,
+ iov, 5);
+ if (GSS_ERROR(major_status))
+ return major_status;
+
+ for (i = 0, output_message_buffer->length = 0; i < 5; i++) {
+ if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_SIGN_ONLY)
+ continue;
+
+ output_message_buffer->length += iov[i].buffer.length;
+ }
+
+ output_message_buffer->value = malloc(output_message_buffer->length);
+ if (output_message_buffer->value == NULL) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ for (i = 0, p = output_message_buffer->value; i < 5; i++) {
+ if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_SIGN_ONLY)
+ continue;
+ else if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA)
+ memcpy(p, input_payload_buffer->value, input_payload_buffer->length);
+
+ iov[i].buffer.value = p;
+ p += iov[i].buffer.length;
+ }
+
+ major_status = gss_wrap_iov(minor_status, context_handle, conf_req_flag,
+ qop_req, conf_state, iov, 5);
+ if (GSS_ERROR(major_status))
+ gss_release_buffer(&tmp, output_message_buffer);
+
+ return major_status;
+}
+
+/*
+ * AEAD unwrap for a single piece of associated data, for compatibility
+ * with MIT and as specified by draft-howard-gssapi-aead-00.txt.
+ *
+ * @ingroup gssapi
+ */
+GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
+gss_unwrap_aead(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ gss_buffer_t input_message_buffer,
+ gss_buffer_t input_assoc_buffer,
+ gss_buffer_t output_payload_buffer,
+ int *conf_state,
+ gss_qop_t *qop_state)
+{
+ OM_uint32 major_status, tmp;
+ gss_iov_buffer_desc iov[3];
+
+ memset(iov, 0, sizeof(iov));
+
+ iov[0].type = GSS_IOV_BUFFER_TYPE_STREAM;
+ iov[0].buffer = *input_message_buffer;
+
+ iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
+ if (input_assoc_buffer)
+ iov[1].buffer = *input_assoc_buffer;
+
+ iov[2].type = GSS_IOV_BUFFER_TYPE_DATA | GSS_IOV_BUFFER_FLAG_ALLOCATE;
+
+ major_status = gss_unwrap_iov(minor_status, context_handle, conf_state,
+ qop_state, iov, 3);
+ if (GSS_ERROR(major_status))
+ gss_release_iov_buffer(&tmp, &iov[2], 1);
+ else
+ *output_payload_buffer = iov[2].buffer;
+
+ return major_status;
+}