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