Home | History | Annotate | Line # | Download | only in mech
      1 /*	$NetBSD: gss_aeap.c,v 1.2 2017/01/28 21:31:46 christos Exp $	*/
      2 
      3 /*
      4  * AEAD support
      5  */
      6 
      7 #include "mech_locl.h"
      8 
      9 /**
     10  * Encrypts or sign the data.
     11  *
     12  * This is a more complicated version of gss_wrap(), it allows the
     13  * caller to use AEAD data (signed header/trailer) and allow greater
     14  * controll over where the encrypted data is placed.
     15  *
     16  * The maximum packet size is gss_context_stream_sizes.max_msg_size.
     17  *
     18  * The caller needs provide the folloing buffers when using in conf_req_flag=1 mode:
     19  *
     20  * - HEADER (of size gss_context_stream_sizes.header)
     21  *   { DATA or SIGN_ONLY } (optional, zero or more)
     22  *   PADDING (of size gss_context_stream_sizes.blocksize, if zero padding is zero, can be omitted)
     23  *   TRAILER (of size gss_context_stream_sizes.trailer)
     24  *
     25  * - on DCE-RPC mode, the caller can skip PADDING and TRAILER if the
     26  *   DATA elements is padded to a block bountry and header is of at
     27  *   least size gss_context_stream_sizes.header + gss_context_stream_sizes.trailer.
     28  *
     29  * HEADER, PADDING, TRAILER will be shrunken to the size required to transmit any of them too large.
     30  *
     31  * To generate gss_wrap() compatible packets, use: HEADER | DATA | PADDING | TRAILER
     32  *
     33  * When used in conf_req_flag=0,
     34  *
     35  * - HEADER (of size gss_context_stream_sizes.header)
     36  *   { DATA or SIGN_ONLY } (optional, zero or more)
     37  *   PADDING (of size gss_context_stream_sizes.blocksize, if zero padding is zero, can be omitted)
     38  *   TRAILER (of size gss_context_stream_sizes.trailer)
     39  *
     40  *
     41  * The input sizes of HEADER, PADDING and TRAILER can be fetched using gss_wrap_iov_length() or
     42  * gss_context_query_attributes().
     43  *
     44  * @ingroup gssapi
     45  */
     46 
     47 
     48 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
     49 gss_wrap_iov(OM_uint32 * minor_status,
     50 	     gss_ctx_id_t  context_handle,
     51 	     int conf_req_flag,
     52 	     gss_qop_t qop_req,
     53 	     int * conf_state,
     54 	     gss_iov_buffer_desc *iov,
     55 	     int iov_count)
     56 {
     57 	struct _gss_context *ctx = (struct _gss_context *) context_handle;
     58 	gssapi_mech_interface m;
     59 
     60 	if (minor_status)
     61 	    *minor_status = 0;
     62 	if (conf_state)
     63 	    *conf_state = 0;
     64 	if (ctx == NULL)
     65 	    return GSS_S_NO_CONTEXT;
     66 	if (iov == NULL && iov_count != 0)
     67 	    return GSS_S_CALL_INACCESSIBLE_READ;
     68 
     69 	m = ctx->gc_mech;
     70 
     71 	if (m->gm_wrap_iov == NULL)
     72 	    return GSS_S_UNAVAILABLE;
     73 
     74 	return (m->gm_wrap_iov)(minor_status, ctx->gc_ctx,
     75 				conf_req_flag, qop_req, conf_state,
     76 				iov, iov_count);
     77 }
     78 
     79 /**
     80  * Decrypt or verifies the signature on the data.
     81  *
     82  *
     83  * @ingroup gssapi
     84  */
     85 
     86 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
     87 gss_unwrap_iov(OM_uint32 *minor_status,
     88 	       gss_ctx_id_t context_handle,
     89 	       int *conf_state,
     90 	       gss_qop_t *qop_state,
     91 	       gss_iov_buffer_desc *iov,
     92 	       int iov_count)
     93 {
     94 	struct _gss_context *ctx = (struct _gss_context *) context_handle;
     95 	gssapi_mech_interface m;
     96 
     97 	if (minor_status)
     98 	    *minor_status = 0;
     99 	if (conf_state)
    100 	    *conf_state = 0;
    101 	if (qop_state)
    102 	    *qop_state = 0;
    103 	if (ctx == NULL)
    104 	    return GSS_S_NO_CONTEXT;
    105 	if (iov == NULL && iov_count != 0)
    106 	    return GSS_S_CALL_INACCESSIBLE_READ;
    107 
    108 	m = ctx->gc_mech;
    109 
    110 	if (m->gm_unwrap_iov == NULL)
    111 	    return GSS_S_UNAVAILABLE;
    112 
    113 	return (m->gm_unwrap_iov)(minor_status, ctx->gc_ctx,
    114 				  conf_state, qop_state,
    115 				  iov, iov_count);
    116 }
    117 
    118 /**
    119  * Update the length fields in iov buffer for the types:
    120  * - GSS_IOV_BUFFER_TYPE_HEADER
    121  * - GSS_IOV_BUFFER_TYPE_PADDING
    122  * - GSS_IOV_BUFFER_TYPE_TRAILER
    123  *
    124  * Consider using gss_context_query_attributes() to fetch the data instead.
    125  *
    126  * @ingroup gssapi
    127  */
    128 
    129 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
    130 gss_wrap_iov_length(OM_uint32 * minor_status,
    131 		    gss_ctx_id_t context_handle,
    132 		    int conf_req_flag,
    133 		    gss_qop_t qop_req,
    134 		    int *conf_state,
    135 		    gss_iov_buffer_desc *iov,
    136 		    int iov_count)
    137 {
    138 	struct _gss_context *ctx = (struct _gss_context *) context_handle;
    139 	gssapi_mech_interface m;
    140 
    141 	if (minor_status)
    142 	    *minor_status = 0;
    143 	if (conf_state)
    144 	    *conf_state = 0;
    145 	if (ctx == NULL)
    146 	    return GSS_S_NO_CONTEXT;
    147 	if (iov == NULL && iov_count != 0)
    148 	    return GSS_S_CALL_INACCESSIBLE_READ;
    149 
    150 	m = ctx->gc_mech;
    151 
    152 	if (m->gm_wrap_iov_length == NULL)
    153 	    return GSS_S_UNAVAILABLE;
    154 
    155 	return (m->gm_wrap_iov_length)(minor_status, ctx->gc_ctx,
    156 				       conf_req_flag, qop_req, conf_state,
    157 				       iov, iov_count);
    158 }
    159 
    160 /**
    161  * Free all buffer allocated by gss_wrap_iov() or gss_unwrap_iov() by
    162  * looking at the GSS_IOV_BUFFER_FLAG_ALLOCATED flag.
    163  *
    164  * @ingroup gssapi
    165  */
    166 
    167 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
    168 gss_release_iov_buffer(OM_uint32 *minor_status,
    169 		       gss_iov_buffer_desc *iov,
    170 		       int iov_count)
    171 {
    172     OM_uint32 junk;
    173     int i;
    174 
    175     if (minor_status)
    176 	*minor_status = 0;
    177     if (iov == NULL && iov_count != 0)
    178 	return GSS_S_CALL_INACCESSIBLE_READ;
    179 
    180     for (i = 0; i < iov_count; i++) {
    181 	if ((iov[i].type & GSS_IOV_BUFFER_FLAG_ALLOCATED) == 0)
    182 	    continue;
    183 	gss_release_buffer(&junk, &iov[i].buffer);
    184 	iov[i].type &= ~GSS_IOV_BUFFER_FLAG_ALLOCATED;
    185     }
    186     return GSS_S_COMPLETE;
    187 }
    188 
    189 /**
    190  * Query the context for parameters.
    191  *
    192  * SSPI equivalent if this function is QueryContextAttributes.
    193  *
    194  * - GSS_C_ATTR_STREAM_SIZES data is a gss_context_stream_sizes.
    195  *
    196  * @ingroup gssapi
    197  */
    198 
    199 gss_OID_desc GSSAPI_LIB_FUNCTION __gss_c_attr_stream_sizes_oid_desc =
    200     {10, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x03")};
    201 
    202 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
    203 gss_context_query_attributes(OM_uint32 *minor_status,
    204 			     gss_const_ctx_id_t context_handle,
    205 			     const gss_OID attribute,
    206 			     void *data,
    207 			     size_t len)
    208 {
    209     if (minor_status)
    210 	*minor_status = 0;
    211 
    212     if (gss_oid_equal(GSS_C_ATTR_STREAM_SIZES, attribute)) {
    213 	memset(data, 0, len);
    214 	return GSS_S_COMPLETE;
    215     }
    216 
    217     return GSS_S_FAILURE;
    218 }
    219 
    220 /*
    221  * AEAD wrap API for a single piece of associated data, for compatibility
    222  * with MIT and as specified by draft-howard-gssapi-aead-00.txt.
    223  *
    224  * @ingroup gssapi
    225  */
    226 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
    227 gss_wrap_aead(OM_uint32 *minor_status,
    228 	      gss_ctx_id_t context_handle,
    229               int conf_req_flag,
    230               gss_qop_t qop_req,
    231               gss_buffer_t input_assoc_buffer,
    232               gss_buffer_t input_payload_buffer,
    233               int *conf_state,
    234               gss_buffer_t output_message_buffer)
    235 {
    236     OM_uint32 major_status, tmp, flags = 0;
    237     gss_iov_buffer_desc iov[5];
    238     size_t i;
    239     unsigned char *p;
    240 
    241     memset(iov, 0, sizeof(iov));
    242 
    243     iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
    244 
    245     iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
    246     if (input_assoc_buffer)
    247 	iov[1].buffer = *input_assoc_buffer;
    248 
    249     iov[2].type = GSS_IOV_BUFFER_TYPE_DATA;
    250     if (input_payload_buffer)
    251 	iov[2].buffer.length = input_payload_buffer->length;
    252 
    253     gss_inquire_context(minor_status, context_handle, NULL, NULL,
    254 			NULL, NULL, &flags, NULL, NULL);
    255 
    256     /* krb5 mech rejects padding/trailer if DCE-style is set */
    257     iov[3].type = (flags & GSS_C_DCE_STYLE) ? GSS_IOV_BUFFER_TYPE_EMPTY
    258 					    : GSS_IOV_BUFFER_TYPE_PADDING;
    259     iov[4].type = (flags & GSS_C_DCE_STYLE) ? GSS_IOV_BUFFER_TYPE_EMPTY
    260 					    : GSS_IOV_BUFFER_TYPE_TRAILER;
    261 
    262     major_status = gss_wrap_iov_length(minor_status, context_handle,
    263 				       conf_req_flag, qop_req, conf_state,
    264 				       iov, 5);
    265     if (GSS_ERROR(major_status))
    266 	return major_status;
    267 
    268     for (i = 0, output_message_buffer->length = 0; i < 5; i++) {
    269         if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_SIGN_ONLY)
    270 	    continue;
    271 
    272 	output_message_buffer->length += iov[i].buffer.length;
    273     }
    274 
    275     output_message_buffer->value = malloc(output_message_buffer->length);
    276     if (output_message_buffer->value == NULL) {
    277 	*minor_status = ENOMEM;
    278 	return GSS_S_FAILURE;
    279     }
    280 
    281     for (i = 0, p = output_message_buffer->value; i < 5; i++) {
    282 	if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_SIGN_ONLY)
    283 	    continue;
    284 	else if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA)
    285 	    memcpy(p, input_payload_buffer->value, input_payload_buffer->length);
    286 
    287 	iov[i].buffer.value = p;
    288 	p += iov[i].buffer.length;
    289     }
    290 
    291     major_status = gss_wrap_iov(minor_status, context_handle, conf_req_flag,
    292 				qop_req, conf_state, iov, 5);
    293     if (GSS_ERROR(major_status))
    294         gss_release_buffer(&tmp, output_message_buffer);
    295 
    296     return major_status;
    297 }
    298 
    299 /*
    300  * AEAD unwrap for a single piece of associated data, for compatibility
    301  * with MIT and as specified by draft-howard-gssapi-aead-00.txt.
    302  *
    303  * @ingroup gssapi
    304  */
    305 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
    306 gss_unwrap_aead(OM_uint32 *minor_status,
    307 		gss_ctx_id_t context_handle,
    308 		gss_buffer_t input_message_buffer,
    309 		gss_buffer_t input_assoc_buffer,
    310 		gss_buffer_t output_payload_buffer,
    311 		int *conf_state,
    312 		gss_qop_t *qop_state)
    313 {
    314     OM_uint32 major_status, tmp;
    315     gss_iov_buffer_desc iov[3];
    316 
    317     memset(iov, 0, sizeof(iov));
    318 
    319     iov[0].type = GSS_IOV_BUFFER_TYPE_STREAM;
    320     iov[0].buffer = *input_message_buffer;
    321 
    322     iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
    323     if (input_assoc_buffer)
    324 	iov[1].buffer = *input_assoc_buffer;
    325 
    326     iov[2].type = GSS_IOV_BUFFER_TYPE_DATA | GSS_IOV_BUFFER_FLAG_ALLOCATE;
    327 
    328     major_status = gss_unwrap_iov(minor_status, context_handle, conf_state,
    329 				  qop_state, iov, 3);
    330     if (GSS_ERROR(major_status))
    331 	gss_release_iov_buffer(&tmp, &iov[2], 1);
    332     else
    333 	*output_payload_buffer = iov[2].buffer;
    334 
    335     return major_status;
    336 }
    337