xref: /freebsd/crypto/heimdal/lib/gssapi/mech/gss_aeap.c (revision 6a068746777241722b2b32c5d0bc443a2a64d80b)
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