1*ae771770SStanislav Sedov /*
2*ae771770SStanislav Sedov * AEAD support
3*ae771770SStanislav Sedov */
4*ae771770SStanislav Sedov
5*ae771770SStanislav Sedov #include "mech_locl.h"
6*ae771770SStanislav Sedov
7*ae771770SStanislav Sedov /**
8*ae771770SStanislav Sedov * Encrypts or sign the data.
9*ae771770SStanislav Sedov *
10*ae771770SStanislav Sedov * This is a more complicated version of gss_wrap(), it allows the
11*ae771770SStanislav Sedov * caller to use AEAD data (signed header/trailer) and allow greater
12*ae771770SStanislav Sedov * controll over where the encrypted data is placed.
13*ae771770SStanislav Sedov *
14*ae771770SStanislav Sedov * The maximum packet size is gss_context_stream_sizes.max_msg_size.
15*ae771770SStanislav Sedov *
16*ae771770SStanislav Sedov * The caller needs provide the folloing buffers when using in conf_req_flag=1 mode:
17*ae771770SStanislav Sedov *
18*ae771770SStanislav Sedov * - HEADER (of size gss_context_stream_sizes.header)
19*ae771770SStanislav Sedov * { DATA or SIGN_ONLY } (optional, zero or more)
20*ae771770SStanislav Sedov * PADDING (of size gss_context_stream_sizes.blocksize, if zero padding is zero, can be omitted)
21*ae771770SStanislav Sedov * TRAILER (of size gss_context_stream_sizes.trailer)
22*ae771770SStanislav Sedov *
23*ae771770SStanislav Sedov * - on DCE-RPC mode, the caller can skip PADDING and TRAILER if the
24*ae771770SStanislav Sedov * DATA elements is padded to a block bountry and header is of at
25*ae771770SStanislav Sedov * least size gss_context_stream_sizes.header + gss_context_stream_sizes.trailer.
26*ae771770SStanislav Sedov *
27*ae771770SStanislav Sedov * HEADER, PADDING, TRAILER will be shrunken to the size required to transmit any of them too large.
28*ae771770SStanislav Sedov *
29*ae771770SStanislav Sedov * To generate gss_wrap() compatible packets, use: HEADER | DATA | PADDING | TRAILER
30*ae771770SStanislav Sedov *
31*ae771770SStanislav Sedov * When used in conf_req_flag=0,
32*ae771770SStanislav Sedov *
33*ae771770SStanislav Sedov * - HEADER (of size gss_context_stream_sizes.header)
34*ae771770SStanislav Sedov * { DATA or SIGN_ONLY } (optional, zero or more)
35*ae771770SStanislav Sedov * PADDING (of size gss_context_stream_sizes.blocksize, if zero padding is zero, can be omitted)
36*ae771770SStanislav Sedov * TRAILER (of size gss_context_stream_sizes.trailer)
37*ae771770SStanislav Sedov *
38*ae771770SStanislav Sedov *
39*ae771770SStanislav Sedov * The input sizes of HEADER, PADDING and TRAILER can be fetched using gss_wrap_iov_length() or
40*ae771770SStanislav Sedov * gss_context_query_attributes().
41*ae771770SStanislav Sedov *
42*ae771770SStanislav Sedov * @ingroup gssapi
43*ae771770SStanislav Sedov */
44*ae771770SStanislav Sedov
45*ae771770SStanislav Sedov
46*ae771770SStanislav Sedov 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)47*ae771770SStanislav Sedov gss_wrap_iov(OM_uint32 * minor_status,
48*ae771770SStanislav Sedov gss_ctx_id_t context_handle,
49*ae771770SStanislav Sedov int conf_req_flag,
50*ae771770SStanislav Sedov gss_qop_t qop_req,
51*ae771770SStanislav Sedov int * conf_state,
52*ae771770SStanislav Sedov gss_iov_buffer_desc *iov,
53*ae771770SStanislav Sedov int iov_count)
54*ae771770SStanislav Sedov {
55*ae771770SStanislav Sedov struct _gss_context *ctx = (struct _gss_context *) context_handle;
56*ae771770SStanislav Sedov gssapi_mech_interface m;
57*ae771770SStanislav Sedov
58*ae771770SStanislav Sedov if (minor_status)
59*ae771770SStanislav Sedov *minor_status = 0;
60*ae771770SStanislav Sedov if (conf_state)
61*ae771770SStanislav Sedov *conf_state = 0;
62*ae771770SStanislav Sedov if (ctx == NULL)
63*ae771770SStanislav Sedov return GSS_S_NO_CONTEXT;
64*ae771770SStanislav Sedov if (iov == NULL && iov_count != 0)
65*ae771770SStanislav Sedov return GSS_S_CALL_INACCESSIBLE_READ;
66*ae771770SStanislav Sedov
67*ae771770SStanislav Sedov m = ctx->gc_mech;
68*ae771770SStanislav Sedov
69*ae771770SStanislav Sedov if (m->gm_wrap_iov == NULL)
70*ae771770SStanislav Sedov return GSS_S_UNAVAILABLE;
71*ae771770SStanislav Sedov
72*ae771770SStanislav Sedov return (m->gm_wrap_iov)(minor_status, ctx->gc_ctx,
73*ae771770SStanislav Sedov conf_req_flag, qop_req, conf_state,
74*ae771770SStanislav Sedov iov, iov_count);
75*ae771770SStanislav Sedov }
76*ae771770SStanislav Sedov
77*ae771770SStanislav Sedov /**
78*ae771770SStanislav Sedov * Decrypt or verifies the signature on the data.
79*ae771770SStanislav Sedov *
80*ae771770SStanislav Sedov *
81*ae771770SStanislav Sedov * @ingroup gssapi
82*ae771770SStanislav Sedov */
83*ae771770SStanislav Sedov
84*ae771770SStanislav Sedov 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)85*ae771770SStanislav Sedov gss_unwrap_iov(OM_uint32 *minor_status,
86*ae771770SStanislav Sedov gss_ctx_id_t context_handle,
87*ae771770SStanislav Sedov int *conf_state,
88*ae771770SStanislav Sedov gss_qop_t *qop_state,
89*ae771770SStanislav Sedov gss_iov_buffer_desc *iov,
90*ae771770SStanislav Sedov int iov_count)
91*ae771770SStanislav Sedov {
92*ae771770SStanislav Sedov struct _gss_context *ctx = (struct _gss_context *) context_handle;
93*ae771770SStanislav Sedov gssapi_mech_interface m;
94*ae771770SStanislav Sedov
95*ae771770SStanislav Sedov if (minor_status)
96*ae771770SStanislav Sedov *minor_status = 0;
97*ae771770SStanislav Sedov if (conf_state)
98*ae771770SStanislav Sedov *conf_state = 0;
99*ae771770SStanislav Sedov if (qop_state)
100*ae771770SStanislav Sedov *qop_state = 0;
101*ae771770SStanislav Sedov if (ctx == NULL)
102*ae771770SStanislav Sedov return GSS_S_NO_CONTEXT;
103*ae771770SStanislav Sedov if (iov == NULL && iov_count != 0)
104*ae771770SStanislav Sedov return GSS_S_CALL_INACCESSIBLE_READ;
105*ae771770SStanislav Sedov
106*ae771770SStanislav Sedov m = ctx->gc_mech;
107*ae771770SStanislav Sedov
108*ae771770SStanislav Sedov if (m->gm_unwrap_iov == NULL)
109*ae771770SStanislav Sedov return GSS_S_UNAVAILABLE;
110*ae771770SStanislav Sedov
111*ae771770SStanislav Sedov return (m->gm_unwrap_iov)(minor_status, ctx->gc_ctx,
112*ae771770SStanislav Sedov conf_state, qop_state,
113*ae771770SStanislav Sedov iov, iov_count);
114*ae771770SStanislav Sedov }
115*ae771770SStanislav Sedov
116*ae771770SStanislav Sedov /**
117*ae771770SStanislav Sedov * Update the length fields in iov buffer for the types:
118*ae771770SStanislav Sedov * - GSS_IOV_BUFFER_TYPE_HEADER
119*ae771770SStanislav Sedov * - GSS_IOV_BUFFER_TYPE_PADDING
120*ae771770SStanislav Sedov * - GSS_IOV_BUFFER_TYPE_TRAILER
121*ae771770SStanislav Sedov *
122*ae771770SStanislav Sedov * Consider using gss_context_query_attributes() to fetch the data instead.
123*ae771770SStanislav Sedov *
124*ae771770SStanislav Sedov * @ingroup gssapi
125*ae771770SStanislav Sedov */
126*ae771770SStanislav Sedov
127*ae771770SStanislav Sedov 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)128*ae771770SStanislav Sedov gss_wrap_iov_length(OM_uint32 * minor_status,
129*ae771770SStanislav Sedov gss_ctx_id_t context_handle,
130*ae771770SStanislav Sedov int conf_req_flag,
131*ae771770SStanislav Sedov gss_qop_t qop_req,
132*ae771770SStanislav Sedov int *conf_state,
133*ae771770SStanislav Sedov gss_iov_buffer_desc *iov,
134*ae771770SStanislav Sedov int iov_count)
135*ae771770SStanislav Sedov {
136*ae771770SStanislav Sedov struct _gss_context *ctx = (struct _gss_context *) context_handle;
137*ae771770SStanislav Sedov gssapi_mech_interface m;
138*ae771770SStanislav Sedov
139*ae771770SStanislav Sedov if (minor_status)
140*ae771770SStanislav Sedov *minor_status = 0;
141*ae771770SStanislav Sedov if (conf_state)
142*ae771770SStanislav Sedov *conf_state = 0;
143*ae771770SStanislav Sedov if (ctx == NULL)
144*ae771770SStanislav Sedov return GSS_S_NO_CONTEXT;
145*ae771770SStanislav Sedov if (iov == NULL && iov_count != 0)
146*ae771770SStanislav Sedov return GSS_S_CALL_INACCESSIBLE_READ;
147*ae771770SStanislav Sedov
148*ae771770SStanislav Sedov m = ctx->gc_mech;
149*ae771770SStanislav Sedov
150*ae771770SStanislav Sedov if (m->gm_wrap_iov_length == NULL)
151*ae771770SStanislav Sedov return GSS_S_UNAVAILABLE;
152*ae771770SStanislav Sedov
153*ae771770SStanislav Sedov return (m->gm_wrap_iov_length)(minor_status, ctx->gc_ctx,
154*ae771770SStanislav Sedov conf_req_flag, qop_req, conf_state,
155*ae771770SStanislav Sedov iov, iov_count);
156*ae771770SStanislav Sedov }
157*ae771770SStanislav Sedov
158*ae771770SStanislav Sedov /**
159*ae771770SStanislav Sedov * Free all buffer allocated by gss_wrap_iov() or gss_unwrap_iov() by
160*ae771770SStanislav Sedov * looking at the GSS_IOV_BUFFER_FLAG_ALLOCATED flag.
161*ae771770SStanislav Sedov *
162*ae771770SStanislav Sedov * @ingroup gssapi
163*ae771770SStanislav Sedov */
164*ae771770SStanislav Sedov
165*ae771770SStanislav Sedov GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
gss_release_iov_buffer(OM_uint32 * minor_status,gss_iov_buffer_desc * iov,int iov_count)166*ae771770SStanislav Sedov gss_release_iov_buffer(OM_uint32 *minor_status,
167*ae771770SStanislav Sedov gss_iov_buffer_desc *iov,
168*ae771770SStanislav Sedov int iov_count)
169*ae771770SStanislav Sedov {
170*ae771770SStanislav Sedov OM_uint32 junk;
171*ae771770SStanislav Sedov int i;
172*ae771770SStanislav Sedov
173*ae771770SStanislav Sedov if (minor_status)
174*ae771770SStanislav Sedov *minor_status = 0;
175*ae771770SStanislav Sedov if (iov == NULL && iov_count != 0)
176*ae771770SStanislav Sedov return GSS_S_CALL_INACCESSIBLE_READ;
177*ae771770SStanislav Sedov
178*ae771770SStanislav Sedov for (i = 0; i < iov_count; i++) {
179*ae771770SStanislav Sedov if ((iov[i].type & GSS_IOV_BUFFER_FLAG_ALLOCATED) == 0)
180*ae771770SStanislav Sedov continue;
181*ae771770SStanislav Sedov gss_release_buffer(&junk, &iov[i].buffer);
182*ae771770SStanislav Sedov iov[i].type &= ~GSS_IOV_BUFFER_FLAG_ALLOCATED;
183*ae771770SStanislav Sedov }
184*ae771770SStanislav Sedov return GSS_S_COMPLETE;
185*ae771770SStanislav Sedov }
186*ae771770SStanislav Sedov
187*ae771770SStanislav Sedov /**
188*ae771770SStanislav Sedov * Query the context for parameters.
189*ae771770SStanislav Sedov *
190*ae771770SStanislav Sedov * SSPI equivalent if this function is QueryContextAttributes.
191*ae771770SStanislav Sedov *
192*ae771770SStanislav Sedov * - GSS_C_ATTR_STREAM_SIZES data is a gss_context_stream_sizes.
193*ae771770SStanislav Sedov *
194*ae771770SStanislav Sedov * @ingroup gssapi
195*ae771770SStanislav Sedov */
196*ae771770SStanislav Sedov
197*ae771770SStanislav Sedov gss_OID_desc GSSAPI_LIB_FUNCTION __gss_c_attr_stream_sizes_oid_desc =
198*ae771770SStanislav Sedov {10, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x03")};
199*ae771770SStanislav Sedov
200*ae771770SStanislav Sedov GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
gss_context_query_attributes(OM_uint32 * minor_status,const gss_ctx_id_t context_handle,const gss_OID attribute,void * data,size_t len)201*ae771770SStanislav Sedov gss_context_query_attributes(OM_uint32 *minor_status,
202*ae771770SStanislav Sedov const gss_ctx_id_t context_handle,
203*ae771770SStanislav Sedov const gss_OID attribute,
204*ae771770SStanislav Sedov void *data,
205*ae771770SStanislav Sedov size_t len)
206*ae771770SStanislav Sedov {
207*ae771770SStanislav Sedov if (minor_status)
208*ae771770SStanislav Sedov *minor_status = 0;
209*ae771770SStanislav Sedov
210*ae771770SStanislav Sedov if (gss_oid_equal(GSS_C_ATTR_STREAM_SIZES, attribute)) {
211*ae771770SStanislav Sedov memset(data, 0, len);
212*ae771770SStanislav Sedov return GSS_S_COMPLETE;
213*ae771770SStanislav Sedov }
214*ae771770SStanislav Sedov
215*ae771770SStanislav Sedov return GSS_S_FAILURE;
216*ae771770SStanislav Sedov }
217