1226031Sstas/*
2226031Sstas * AEAD support
3226031Sstas */
4226031Sstas
5226031Sstas#include "mech_locl.h"
6226031Sstas
7226031Sstas/**
8226031Sstas * Encrypts or sign the data.
9226031Sstas *
10226031Sstas * This is a more complicated version of gss_wrap(), it allows the
11226031Sstas * caller to use AEAD data (signed header/trailer) and allow greater
12226031Sstas * controll over where the encrypted data is placed.
13226031Sstas *
14226031Sstas * The maximum packet size is gss_context_stream_sizes.max_msg_size.
15226031Sstas *
16226031Sstas * The caller needs provide the folloing buffers when using in conf_req_flag=1 mode:
17226031Sstas *
18226031Sstas * - HEADER (of size gss_context_stream_sizes.header)
19226031Sstas *   { DATA or SIGN_ONLY } (optional, zero or more)
20226031Sstas *   PADDING (of size gss_context_stream_sizes.blocksize, if zero padding is zero, can be omitted)
21226031Sstas *   TRAILER (of size gss_context_stream_sizes.trailer)
22226031Sstas *
23226031Sstas * - on DCE-RPC mode, the caller can skip PADDING and TRAILER if the
24226031Sstas *   DATA elements is padded to a block bountry and header is of at
25226031Sstas *   least size gss_context_stream_sizes.header + gss_context_stream_sizes.trailer.
26226031Sstas *
27226031Sstas * HEADER, PADDING, TRAILER will be shrunken to the size required to transmit any of them too large.
28226031Sstas *
29226031Sstas * To generate gss_wrap() compatible packets, use: HEADER | DATA | PADDING | TRAILER
30226031Sstas *
31226031Sstas * When used in conf_req_flag=0,
32226031Sstas *
33226031Sstas * - HEADER (of size gss_context_stream_sizes.header)
34226031Sstas *   { DATA or SIGN_ONLY } (optional, zero or more)
35226031Sstas *   PADDING (of size gss_context_stream_sizes.blocksize, if zero padding is zero, can be omitted)
36226031Sstas *   TRAILER (of size gss_context_stream_sizes.trailer)
37226031Sstas *
38226031Sstas *
39226031Sstas * The input sizes of HEADER, PADDING and TRAILER can be fetched using gss_wrap_iov_length() or
40226031Sstas * gss_context_query_attributes().
41226031Sstas *
42226031Sstas * @ingroup gssapi
43226031Sstas */
44226031Sstas
45226031Sstas
46226031SstasGSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
47226031Sstasgss_wrap_iov(OM_uint32 * minor_status,
48226031Sstas	     gss_ctx_id_t  context_handle,
49226031Sstas	     int conf_req_flag,
50226031Sstas	     gss_qop_t qop_req,
51226031Sstas	     int * conf_state,
52226031Sstas	     gss_iov_buffer_desc *iov,
53226031Sstas	     int iov_count)
54226031Sstas{
55226031Sstas	struct _gss_context *ctx = (struct _gss_context *) context_handle;
56226031Sstas	gssapi_mech_interface m;
57226031Sstas
58226031Sstas	if (minor_status)
59226031Sstas	    *minor_status = 0;
60226031Sstas	if (conf_state)
61226031Sstas	    *conf_state = 0;
62226031Sstas	if (ctx == NULL)
63226031Sstas	    return GSS_S_NO_CONTEXT;
64226031Sstas	if (iov == NULL && iov_count != 0)
65226031Sstas	    return GSS_S_CALL_INACCESSIBLE_READ;
66226031Sstas
67226031Sstas	m = ctx->gc_mech;
68226031Sstas
69226031Sstas	if (m->gm_wrap_iov == NULL)
70226031Sstas	    return GSS_S_UNAVAILABLE;
71226031Sstas
72226031Sstas	return (m->gm_wrap_iov)(minor_status, ctx->gc_ctx,
73226031Sstas				conf_req_flag, qop_req, conf_state,
74226031Sstas				iov, iov_count);
75226031Sstas}
76226031Sstas
77226031Sstas/**
78226031Sstas * Decrypt or verifies the signature on the data.
79226031Sstas *
80226031Sstas *
81226031Sstas * @ingroup gssapi
82226031Sstas */
83226031Sstas
84226031SstasGSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
85226031Sstasgss_unwrap_iov(OM_uint32 *minor_status,
86226031Sstas	       gss_ctx_id_t context_handle,
87226031Sstas	       int *conf_state,
88226031Sstas	       gss_qop_t *qop_state,
89226031Sstas	       gss_iov_buffer_desc *iov,
90226031Sstas	       int iov_count)
91226031Sstas{
92226031Sstas	struct _gss_context *ctx = (struct _gss_context *) context_handle;
93226031Sstas	gssapi_mech_interface m;
94226031Sstas
95226031Sstas	if (minor_status)
96226031Sstas	    *minor_status = 0;
97226031Sstas	if (conf_state)
98226031Sstas	    *conf_state = 0;
99226031Sstas	if (qop_state)
100226031Sstas	    *qop_state = 0;
101226031Sstas	if (ctx == NULL)
102226031Sstas	    return GSS_S_NO_CONTEXT;
103226031Sstas	if (iov == NULL && iov_count != 0)
104226031Sstas	    return GSS_S_CALL_INACCESSIBLE_READ;
105226031Sstas
106226031Sstas	m = ctx->gc_mech;
107226031Sstas
108226031Sstas	if (m->gm_unwrap_iov == NULL)
109226031Sstas	    return GSS_S_UNAVAILABLE;
110226031Sstas
111226031Sstas	return (m->gm_unwrap_iov)(minor_status, ctx->gc_ctx,
112226031Sstas				  conf_state, qop_state,
113226031Sstas				  iov, iov_count);
114226031Sstas}
115226031Sstas
116226031Sstas/**
117226031Sstas * Update the length fields in iov buffer for the types:
118226031Sstas * - GSS_IOV_BUFFER_TYPE_HEADER
119226031Sstas * - GSS_IOV_BUFFER_TYPE_PADDING
120226031Sstas * - GSS_IOV_BUFFER_TYPE_TRAILER
121226031Sstas *
122226031Sstas * Consider using gss_context_query_attributes() to fetch the data instead.
123226031Sstas *
124226031Sstas * @ingroup gssapi
125226031Sstas */
126226031Sstas
127226031SstasGSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
128226031Sstasgss_wrap_iov_length(OM_uint32 * minor_status,
129226031Sstas		    gss_ctx_id_t context_handle,
130226031Sstas		    int conf_req_flag,
131226031Sstas		    gss_qop_t qop_req,
132226031Sstas		    int *conf_state,
133226031Sstas		    gss_iov_buffer_desc *iov,
134226031Sstas		    int iov_count)
135226031Sstas{
136226031Sstas	struct _gss_context *ctx = (struct _gss_context *) context_handle;
137226031Sstas	gssapi_mech_interface m;
138226031Sstas
139226031Sstas	if (minor_status)
140226031Sstas	    *minor_status = 0;
141226031Sstas	if (conf_state)
142226031Sstas	    *conf_state = 0;
143226031Sstas	if (ctx == NULL)
144226031Sstas	    return GSS_S_NO_CONTEXT;
145226031Sstas	if (iov == NULL && iov_count != 0)
146226031Sstas	    return GSS_S_CALL_INACCESSIBLE_READ;
147226031Sstas
148226031Sstas	m = ctx->gc_mech;
149226031Sstas
150226031Sstas	if (m->gm_wrap_iov_length == NULL)
151226031Sstas	    return GSS_S_UNAVAILABLE;
152226031Sstas
153226031Sstas	return (m->gm_wrap_iov_length)(minor_status, ctx->gc_ctx,
154226031Sstas				       conf_req_flag, qop_req, conf_state,
155226031Sstas				       iov, iov_count);
156226031Sstas}
157226031Sstas
158226031Sstas/**
159226031Sstas * Free all buffer allocated by gss_wrap_iov() or gss_unwrap_iov() by
160226031Sstas * looking at the GSS_IOV_BUFFER_FLAG_ALLOCATED flag.
161226031Sstas *
162226031Sstas * @ingroup gssapi
163226031Sstas */
164226031Sstas
165226031SstasGSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
166226031Sstasgss_release_iov_buffer(OM_uint32 *minor_status,
167226031Sstas		       gss_iov_buffer_desc *iov,
168226031Sstas		       int iov_count)
169226031Sstas{
170226031Sstas    OM_uint32 junk;
171226031Sstas    int i;
172226031Sstas
173226031Sstas    if (minor_status)
174226031Sstas	*minor_status = 0;
175226031Sstas    if (iov == NULL && iov_count != 0)
176226031Sstas	return GSS_S_CALL_INACCESSIBLE_READ;
177226031Sstas
178226031Sstas    for (i = 0; i < iov_count; i++) {
179226031Sstas	if ((iov[i].type & GSS_IOV_BUFFER_FLAG_ALLOCATED) == 0)
180226031Sstas	    continue;
181226031Sstas	gss_release_buffer(&junk, &iov[i].buffer);
182226031Sstas	iov[i].type &= ~GSS_IOV_BUFFER_FLAG_ALLOCATED;
183226031Sstas    }
184226031Sstas    return GSS_S_COMPLETE;
185226031Sstas}
186226031Sstas
187226031Sstas/**
188226031Sstas * Query the context for parameters.
189226031Sstas *
190226031Sstas * SSPI equivalent if this function is QueryContextAttributes.
191226031Sstas *
192226031Sstas * - GSS_C_ATTR_STREAM_SIZES data is a gss_context_stream_sizes.
193226031Sstas *
194226031Sstas * @ingroup gssapi
195226031Sstas */
196226031Sstas
197226031Sstasgss_OID_desc GSSAPI_LIB_FUNCTION __gss_c_attr_stream_sizes_oid_desc =
198226031Sstas    {10, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x03")};
199226031Sstas
200226031SstasGSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
201226031Sstasgss_context_query_attributes(OM_uint32 *minor_status,
202226031Sstas			     const gss_ctx_id_t context_handle,
203226031Sstas			     const gss_OID attribute,
204226031Sstas			     void *data,
205226031Sstas			     size_t len)
206226031Sstas{
207226031Sstas    if (minor_status)
208226031Sstas	*minor_status = 0;
209226031Sstas
210226031Sstas    if (gss_oid_equal(GSS_C_ATTR_STREAM_SIZES, attribute)) {
211226031Sstas	memset(data, 0, len);
212226031Sstas	return GSS_S_COMPLETE;
213226031Sstas    }
214226031Sstas
215226031Sstas    return GSS_S_FAILURE;
216226031Sstas}
217