s4:heimdal: import lorikeet-heimdal-200906080040 (commit 904d0124b46eed7a8ad6e5b73e89...
[metze/samba/wip.git] / source4 / heimdal / lib / gssapi / krb5 / aeap.c
1 /*
2  * Copyright (c) 2008  Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden).
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the Institute nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #include "gsskrb5_locl.h"
35
36 #include <roken.h>
37
38 static OM_uint32
39 iov_allocate(OM_uint32 *minor_status, gss_iov_buffer_desc *iov, int iov_count)
40 {
41     unsigned int i;
42     
43     for (i = 0; i < iov_count; i++) {
44         if (GSS_IOV_BUFFER_FLAGS(iov[i].type) & GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE){
45             void *ptr = malloc(iov[i].buffer.length);
46             if (ptr == NULL)
47                 abort();
48             if (iov[i].buffer.value)
49                 memcpy(ptr, iov[i].buffer.value, iov[i].buffer.length);
50             iov[i].buffer.value = ptr;
51             iov[i].type |= GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATED;
52         }
53     }
54     return GSS_S_COMPLETE;
55 }
56
57 static OM_uint32
58 iov_map(OM_uint32 *minor_status,
59         const gss_iov_buffer_desc *iov,
60         int iov_count,
61         krb5_crypto_iov *data)
62 {
63     unsigned int i;
64
65     for (i = 0; i < iov_count; i++) {
66         switch(GSS_IOV_BUFFER_TYPE(iov[i].type)) {
67         case GSS_IOV_BUFFER_TYPE_EMPTY:
68             data[i].flags = KRB5_CRYPTO_TYPE_EMPTY;
69             break;
70         case GSS_IOV_BUFFER_TYPE_DATA:
71             data[i].flags = KRB5_CRYPTO_TYPE_DATA;
72             break;
73         case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
74             data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
75             break;
76         case GSS_IOV_BUFFER_TYPE_HEADER:
77             data[i].flags = KRB5_CRYPTO_TYPE_HEADER;
78             break;
79         case GSS_IOV_BUFFER_TYPE_TRAILER:
80             data[i].flags = KRB5_CRYPTO_TYPE_TRAILER;
81             break;
82         case GSS_IOV_BUFFER_TYPE_PADDING:
83             data[i].flags = KRB5_CRYPTO_TYPE_PADDING;
84             break;
85         case GSS_IOV_BUFFER_TYPE_STREAM:
86             abort();
87             break;
88         default:
89             *minor_status = EINVAL;
90             return GSS_S_FAILURE;
91         }
92         data[i].data.data = iov[i].buffer.value;
93         data[i].data.length = iov[i].buffer.length;
94     }
95     return GSS_S_COMPLETE;
96 }
97
98 OM_uint32 GSSAPI_LIB_FUNCTION
99 _gk_wrap_iov(OM_uint32 * minor_status,
100              gss_ctx_id_t  context_handle,
101              int conf_req_flag,
102              gss_qop_t qop_req,
103              int * conf_state,
104              gss_iov_buffer_desc *iov,
105              int iov_count)
106 {
107     gsskrb5_ctx ctx = (gsskrb5_ctx) context_handle;
108     krb5_context context;
109     OM_uint32 major_status, junk;
110     krb5_crypto_iov *data;
111     krb5_error_code ret;
112     unsigned usage;
113
114     GSSAPI_KRB5_INIT (&context);
115
116     major_status = iov_allocate(minor_status, iov, iov_count);
117     if (major_status != GSS_S_COMPLETE)
118         return major_status;
119
120     data = calloc(iov_count, sizeof(data[0]));
121     if (data == NULL) {
122         gss_release_iov_buffer(&junk, iov, iov_count);
123         *minor_status = ENOMEM;
124         return GSS_S_FAILURE;
125     }
126
127     major_status = iov_map(minor_status, iov, iov_count, data);
128     if (major_status != GSS_S_COMPLETE) {
129         gss_release_iov_buffer(&junk, iov, iov_count);
130         free(data);
131         return major_status;
132     }
133
134     if (ctx->more_flags & LOCAL) {
135         usage = KRB5_KU_USAGE_ACCEPTOR_SIGN;
136     } else {
137         usage = KRB5_KU_USAGE_INITIATOR_SIGN;
138     }
139
140     ret = krb5_encrypt_iov_ivec(context, ctx->crypto, usage,
141                                 data, iov_count, NULL);
142     free(data);
143     if (ret) {
144         gss_release_iov_buffer(&junk, iov, iov_count);
145         *minor_status = ret;
146         return GSS_S_FAILURE;
147     }
148
149     *minor_status = 0;
150     return GSS_S_COMPLETE;
151 }
152
153 OM_uint32 GSSAPI_LIB_FUNCTION
154 _gk_unwrap_iov(OM_uint32 *minor_status,
155                gss_ctx_id_t context_handle,
156                int *conf_state,
157                gss_qop_t *qop_state,
158                gss_iov_buffer_desc *iov,
159                int iov_count)
160 {
161     gsskrb5_ctx ctx = (gsskrb5_ctx) context_handle;
162     krb5_context context;
163     krb5_error_code ret;
164     OM_uint32 major_status, junk;
165     krb5_crypto_iov *data;
166     unsigned usage;
167
168     GSSAPI_KRB5_INIT (&context);
169
170     major_status = iov_allocate(minor_status, iov, iov_count);
171     if (major_status != GSS_S_COMPLETE)
172         return major_status;
173
174     data = calloc(iov_count, sizeof(data[0]));
175     if (data == NULL) {
176         gss_release_iov_buffer(&junk, iov, iov_count);
177         *minor_status = ENOMEM;
178         return GSS_S_FAILURE;
179     }
180
181     major_status = iov_map(minor_status, iov, iov_count, data);
182     if (major_status != GSS_S_COMPLETE) {
183         gss_release_iov_buffer(&junk, iov, iov_count);
184         free(data);
185         return major_status;
186     }
187
188     if (ctx->more_flags & LOCAL) {
189         usage = KRB5_KU_USAGE_INITIATOR_SIGN;
190     } else {
191         usage = KRB5_KU_USAGE_ACCEPTOR_SIGN;
192     }
193
194     ret = krb5_decrypt_iov_ivec(context, ctx->crypto, usage,
195                                 data, iov_count, NULL);
196     free(data);
197     if (ret) {
198         *minor_status = ret;
199         gss_release_iov_buffer(&junk, iov, iov_count);
200         return GSS_S_FAILURE;
201     }
202
203     *minor_status = 0;
204     return GSS_S_COMPLETE;
205 }
206
207 OM_uint32  GSSAPI_LIB_FUNCTION
208 _gk_wrap_iov_length(OM_uint32 * minor_status,
209                     gss_ctx_id_t context_handle,
210                     int conf_req_flag,
211                     gss_qop_t qop_req,
212                     int *conf_state,
213                     gss_iov_buffer_desc *iov,
214                     int iov_count)
215 {
216     gsskrb5_ctx ctx = (gsskrb5_ctx) context_handle;
217     krb5_context context;
218     unsigned int i;
219     size_t size;
220     size_t *padding = NULL;
221
222     GSSAPI_KRB5_INIT (&context);
223     *minor_status = 0;
224
225     for (size = 0, i = 0; i < iov_count; i++) {
226         switch(GSS_IOV_BUFFER_TYPE(iov[i].type)) {
227         case GSS_IOV_BUFFER_TYPE_EMPTY:
228             break;
229         case GSS_IOV_BUFFER_TYPE_DATA:
230             size += iov[i].buffer.length;
231             break;
232         case GSS_IOV_BUFFER_TYPE_HEADER:
233             iov[i].buffer.length =
234               krb5_crypto_length(context, ctx->crypto, KRB5_CRYPTO_TYPE_HEADER);
235             size += iov[i].buffer.length;
236             break;
237         case GSS_IOV_BUFFER_TYPE_TRAILER:
238             iov[i].buffer.length =
239               krb5_crypto_length(context, ctx->crypto, KRB5_CRYPTO_TYPE_TRAILER);
240             size += iov[i].buffer.length;
241             break;
242         case GSS_IOV_BUFFER_TYPE_PADDING:
243             if (padding != NULL) {
244                 *minor_status = 0;
245                 return GSS_S_FAILURE;
246             }
247             padding = &iov[i].buffer.length;
248             break;
249         case GSS_IOV_BUFFER_TYPE_STREAM:
250             size += iov[i].buffer.length;
251             break;
252         case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
253             break;
254         default:
255             *minor_status = EINVAL;
256             return GSS_S_FAILURE;
257         }
258     }
259     if (padding) {
260         size_t pad = krb5_crypto_length(context, ctx->crypto,
261                                         KRB5_CRYPTO_TYPE_PADDING);
262         if (pad > 1) {
263             *padding = pad - (size % pad);
264             if (*padding == pad)
265                 *padding = 0;
266         } else
267             *padding = 0;
268     }
269
270     return GSS_S_COMPLETE;
271 }