xref: /freebsd/crypto/krb5/src/tests/gssapi/t_iov.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* tests/gssapi/t_iov.c - Test program for IOV functions */
3 /*
4  * Copyright (C) 2013 by the Massachusetts Institute of Technology.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  *
14  * * Redistributions in binary form must reproduce the above copyright
15  *   notice, this list of conditions and the following disclaimer in
16  *   the documentation and/or other materials provided with the
17  *   distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30  * OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <stddef.h>
37 #include "common.h"
38 
39 /* Concatenate iov (except for sign-only buffers) into a contiguous token. */
40 static void
concat_iov(gss_iov_buffer_desc * iov,size_t iovlen,char ** buf_out,size_t * len_out)41 concat_iov(gss_iov_buffer_desc *iov, size_t iovlen, char **buf_out,
42            size_t *len_out)
43 {
44     size_t len, i;
45     char *buf;
46 
47     /* Concatenate the result into a contiguous buffer. */
48     len = 0;
49     for (i = 0; i < iovlen; i++) {
50         if (GSS_IOV_BUFFER_TYPE(iov[i].type) != GSS_IOV_BUFFER_TYPE_SIGN_ONLY)
51             len += iov[i].buffer.length;
52     }
53     buf = malloc(len);
54     if (buf == NULL)
55         errout("malloc failed");
56     len = 0;
57     for (i = 0; i < iovlen; i++) {
58         if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_SIGN_ONLY)
59             continue;
60         memcpy(buf + len, iov[i].buffer.value, iov[i].buffer.length);
61         len += iov[i].buffer.length;
62     }
63     *buf_out = buf;
64     *len_out = len;
65 }
66 
67 static void
check_encrypted(const char * msg,int conf,const char * buf,const char * plain)68 check_encrypted(const char *msg, int conf, const char *buf, const char *plain)
69 {
70     int same = memcmp(buf, plain, strlen(plain)) == 0;
71 
72     if ((conf && same) || (!conf && !same))
73         errout(msg);
74 }
75 
76 /*
77  * Wrap str in standard form (HEADER | DATA | PADDING | TRAILER) using the
78  * caller-provided array iov, which must have space for four elements.  Library
79  * allocation will be used for the header/padding/trailer buffers, so the
80  * caller must check and free them.
81  */
82 static void
wrap_std(gss_ctx_id_t ctx,char * str,gss_iov_buffer_desc * iov,int conf)83 wrap_std(gss_ctx_id_t ctx, char *str, gss_iov_buffer_desc *iov, int conf)
84 {
85     OM_uint32 minor, major;
86     int oconf;
87 
88     /* Lay out iov array. */
89     iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_FLAG_ALLOCATE;
90     iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
91     iov[1].buffer.value = str;
92     iov[1].buffer.length = strlen(str);
93     iov[2].type = GSS_IOV_BUFFER_TYPE_PADDING | GSS_IOV_BUFFER_FLAG_ALLOCATE;
94     iov[3].type = GSS_IOV_BUFFER_TYPE_TRAILER | GSS_IOV_BUFFER_FLAG_ALLOCATE;
95 
96     /* Wrap.  This will allocate header/padding/trailer buffers as necessary
97      * and encrypt str in place. */
98     major = gss_wrap_iov(&minor, ctx, conf, GSS_C_QOP_DEFAULT, &oconf, iov, 4);
99     check_gsserr("gss_wrap_iov(std)", major, minor);
100     if (oconf != conf)
101         errout("gss_wrap_iov(std) conf");
102 }
103 
104 /* Create standard tokens using gss_wrap_iov and ctx1, and make sure we can
105  * unwrap them using ctx2 in all of the supported ways. */
106 static void
test_standard_wrap(gss_ctx_id_t ctx1,gss_ctx_id_t ctx2,int conf)107 test_standard_wrap(gss_ctx_id_t ctx1, gss_ctx_id_t ctx2, int conf)
108 {
109     OM_uint32 major, minor;
110     gss_iov_buffer_desc iov[4], stiov[2];
111     gss_qop_t qop;
112     gss_buffer_desc input, output;
113     const char *string1 = "The swift brown fox jumped over the lazy dog.";
114     const char *string2 = "Now is the time!";
115     const char *string3 = "x";
116     const char *string4 = "!@#";
117     char data[1024], *fulltoken;
118     size_t len;
119     int oconf;
120     ptrdiff_t offset;
121 
122     /* Wrap a standard token and unwrap it using the iov array. */
123     memcpy(data, string1, strlen(string1) + 1);
124     wrap_std(ctx1, data, iov, conf);
125     check_encrypted("gss_wrap_iov(std1) encryption", conf, data, string1);
126     major = gss_unwrap_iov(&minor, ctx2, &oconf, &qop, iov, 4);
127     check_gsserr("gss_unwrap_iov(std1)", major, minor);
128     if (oconf != conf || qop != GSS_C_QOP_DEFAULT)
129         errout("gss_unwrap_iov(std1) conf/qop");
130     if (iov[1].buffer.value != data || iov[1].buffer.length != strlen(string1))
131         errout("gss_unwrap_iov(std1) data buffer");
132     if (memcmp(data, string1, iov[1].buffer.length) != 0)
133         errout("gss_unwrap_iov(std1) decryption");
134     (void)gss_release_iov_buffer(&minor, iov, 4);
135 
136     /* Wrap a standard token and unwrap it using gss_unwrap(). */
137     memcpy(data, string2, strlen(string2) + 1);
138     wrap_std(ctx1, data, iov, conf);
139     concat_iov(iov, 4, &fulltoken, &len);
140     input.value = fulltoken;
141     input.length = len;
142     major = gss_unwrap(&minor, ctx2, &input, &output, &oconf, &qop);
143     check_gsserr("gss_unwrap(std2)", major, minor);
144     if (oconf != conf || qop != GSS_C_QOP_DEFAULT)
145         errout("gss_unwrap(std2) conf/qop");
146     if (output.length != strlen(string2) ||
147         memcmp(output.value, string2, output.length) != 0)
148         errout("gss_unwrap(std2) decryption");
149     (void)gss_release_buffer(&minor, &output);
150     (void)gss_release_iov_buffer(&minor, iov, 4);
151     free(fulltoken);
152 
153     /* Wrap a standard token and unwrap it using a stream buffer. */
154     memcpy(data, string3, strlen(string3) + 1);
155     wrap_std(ctx1, data, iov, conf);
156     concat_iov(iov, 4, &fulltoken, &len);
157     stiov[0].type = GSS_IOV_BUFFER_TYPE_STREAM;
158     stiov[0].buffer.value = fulltoken;
159     stiov[0].buffer.length = len;
160     stiov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
161     major = gss_unwrap_iov(&minor, ctx2, &oconf, &qop, stiov, 2);
162     check_gsserr("gss_unwrap_iov(std3)", major, minor);
163     if (oconf != conf || qop != GSS_C_QOP_DEFAULT)
164         errout("gss_unwrap_iov(std3) conf/qop");
165     if (stiov[1].buffer.length != strlen(string3) ||
166         memcmp(stiov[1].buffer.value, string3, strlen(string3)) != 0)
167         errout("gss_unwrap_iov(std3) decryption");
168     offset = (char *)stiov[1].buffer.value - fulltoken;
169     if (offset < 0 || (size_t)offset > len)
170         errout("gss_unwrap_iov(std3) offset");
171     (void)gss_release_iov_buffer(&minor, iov, 4);
172     free(fulltoken);
173 
174     /* Wrap a token using gss_wrap and unwrap it using a stream buffer with
175      * allocation and copying. */
176     input.value = (char *)string4;
177     input.length = strlen(string4);
178     major = gss_wrap(&minor, ctx1, conf, GSS_C_QOP_DEFAULT, &input, &oconf,
179                      &output);
180     check_gsserr("gss_wrap(std4)", major, minor);
181     if (oconf != conf)
182         errout("gss_wrap(std4) conf");
183     stiov[0].type = GSS_IOV_BUFFER_TYPE_STREAM;
184     stiov[0].buffer = output;
185     stiov[1].type = GSS_IOV_BUFFER_TYPE_DATA | GSS_IOV_BUFFER_FLAG_ALLOCATE;
186     major = gss_unwrap_iov(&minor, ctx2, &oconf, &qop, stiov, 2);
187     check_gsserr("gss_unwrap_iov(std4)", major, minor);
188     if (!(GSS_IOV_BUFFER_FLAGS(stiov[1].type) & GSS_IOV_BUFFER_FLAG_ALLOCATED))
189         errout("gss_unwrap_iov(std4) allocated");
190     if (oconf != conf || qop != GSS_C_QOP_DEFAULT)
191         errout("gss_unwrap_iov(std4) conf/qop");
192     if (stiov[1].buffer.length != strlen(string4) ||
193         memcmp(stiov[1].buffer.value, string4, strlen(string4)) != 0)
194         errout("gss_unwrap_iov(std4) decryption");
195     (void)gss_release_buffer(&minor, &output);
196     (void)gss_release_iov_buffer(&minor, stiov, 2);
197 }
198 
199 /*
200  * Wrap an AEAD token (HEADER | SIGN_ONLY | DATA | PADDING | TRAILER) using the
201  * caller-provided array iov, which must have space for five elements, and the
202  * caller-provided buffer data, which must be big enough to handle the test
203  * inputs.  Library allocation will not be used.
204  */
205 static void
wrap_aead(gss_ctx_id_t ctx,const char * sign,const char * wrap,gss_iov_buffer_desc * iov,char * data,int conf)206 wrap_aead(gss_ctx_id_t ctx, const char *sign, const char *wrap,
207           gss_iov_buffer_desc *iov, char *data, int conf)
208 {
209     OM_uint32 major, minor;
210     int oconf;
211     char *ptr;
212 
213     /* Lay out iov array. */
214     iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
215     iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
216     iov[1].buffer.value = (char *)sign;
217     iov[1].buffer.length = strlen(sign);
218     iov[2].type = GSS_IOV_BUFFER_TYPE_DATA;
219     iov[2].buffer.value = (char *)wrap;
220     iov[2].buffer.length = strlen(wrap);
221     iov[3].type = GSS_IOV_BUFFER_TYPE_PADDING;
222     iov[4].type = GSS_IOV_BUFFER_TYPE_TRAILER;
223 
224     /* Get header/padding/trailer lengths. */
225     major = gss_wrap_iov_length(&minor, ctx, conf, GSS_C_QOP_DEFAULT, &oconf,
226                                 iov, 5);
227     check_gsserr("gss_wrap_iov_length(aead)", major, minor);
228     if (oconf != conf)
229         errout("gss_wrap_iov_length(aead) conf");
230     if (iov[1].buffer.value != sign || iov[1].buffer.length != strlen(sign))
231         errout("gss_wrap_iov_length(aead) sign-only buffer");
232     if (iov[2].buffer.value != wrap || iov[2].buffer.length != strlen(wrap))
233         errout("gss_wrap_iov_length(aead) data buffer");
234 
235     /* Set iov buffer pointers using returned lengths. */
236     iov[0].buffer.value = data;
237     ptr = data + iov[0].buffer.length;
238     memcpy(ptr, wrap, strlen(wrap));
239     iov[2].buffer.value = ptr;
240     ptr += iov[2].buffer.length;
241     iov[3].buffer.value = ptr;
242     ptr += iov[3].buffer.length;
243     iov[4].buffer.value = ptr;
244 
245     /* Wrap the AEAD token. */
246     major = gss_wrap_iov(&minor, ctx, conf, GSS_C_QOP_DEFAULT, &oconf, iov, 5);
247     check_gsserr("gss_wrap_iov(aead)", major, minor);
248     if (oconf != conf)
249         errout("gss_wrap_iov(aead) conf");
250     if (iov[1].buffer.value != sign || iov[1].buffer.length != strlen(sign))
251         errout("gss_wrap_iov(aead) sign-only buffer");
252     if (iov[2].buffer.length != strlen(wrap))
253         errout("gss_wrap_iov(aead) data buffer");
254     check_encrypted("gss_wrap_iov(aead) encryption", conf, iov[2].buffer.value,
255                     wrap);
256 }
257 
258 /* Create AEAD tokens using gss_wrap_iov and ctx1, and make sure we can unwrap
259  * them using ctx2 in all of the supported ways. */
260 static void
test_aead(gss_ctx_id_t ctx1,gss_ctx_id_t ctx2,int conf)261 test_aead(gss_ctx_id_t ctx1, gss_ctx_id_t ctx2, int conf)
262 {
263     OM_uint32 major, minor;
264     gss_iov_buffer_desc iov[5], stiov[3];
265     gss_qop_t qop;
266     gss_buffer_desc input, assoc, output;
267     const char *sign = "This data is only signed.";
268     const char *wrap = "This data is wrapped in-place.";
269     char data[1024], *fulltoken;
270     size_t len;
271     int oconf;
272     ptrdiff_t offset;
273 
274     /* Wrap an AEAD token and unwrap it using the IOV array. */
275     wrap_aead(ctx1, sign, wrap, iov, data, conf);
276     major = gss_unwrap_iov(&minor, ctx2, &oconf, &qop, iov, 5);
277     check_gsserr("gss_unwrap_iov(aead1)", major, minor);
278     if (oconf != conf || qop != GSS_C_QOP_DEFAULT)
279         errout("gss_unwrap_iov(aead1) conf/qop");
280     if (iov[1].buffer.value != sign || iov[1].buffer.length != strlen(sign))
281         errout("gss_unwrap_iov(aead1) sign-only buffer");
282     if (iov[2].buffer.length != strlen(wrap) ||
283         memcmp(iov[2].buffer.value, wrap, iov[2].buffer.length) != 0)
284         errout("gss_unwrap_iov(aead1) decryption");
285 
286     /* Wrap an AEAD token and unwrap it using gss_unwrap_aead. */
287     wrap_aead(ctx1, sign, wrap, iov, data, conf);
288     concat_iov(iov, 5, &fulltoken, &len);
289     input.value = fulltoken;
290     input.length = len;
291     assoc.value = (char *)sign;
292     assoc.length = strlen(sign);
293     major = gss_unwrap_aead(&minor, ctx2, &input, &assoc, &output, &oconf,
294                             &qop);
295     check_gsserr("gss_unwrap_aead(aead2)", major, minor);
296     if (output.length != strlen(wrap) ||
297         memcmp(output.value, wrap, output.length) != 0)
298         errout("gss_unwrap_aead(aead2) decryption");
299     free(fulltoken);
300     (void)gss_release_buffer(&minor, &output);
301 
302     /* Wrap an AEAD token and unwrap it using a stream buffer. */
303     wrap_aead(ctx1, sign, wrap, iov, data, conf);
304     concat_iov(iov, 5, &fulltoken, &len);
305     stiov[0].type = GSS_IOV_BUFFER_TYPE_STREAM;
306     stiov[0].buffer.value = fulltoken;
307     stiov[0].buffer.length = len;
308     stiov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
309     stiov[1].buffer.value = (char *)sign;
310     stiov[1].buffer.length = strlen(sign);
311     stiov[2].type = GSS_IOV_BUFFER_TYPE_DATA;
312     major = gss_unwrap_iov(&minor, ctx2, &oconf, &qop, stiov, 3);
313     check_gsserr("gss_unwrap_iov(aead3)", major, minor);
314     if (oconf != conf || qop != GSS_C_QOP_DEFAULT)
315         errout("gss_unwrap_iov(aead3) conf/qop");
316     if (stiov[2].buffer.length != strlen(wrap) ||
317         memcmp(stiov[2].buffer.value, wrap, strlen(wrap)) != 0)
318         errout("gss_unwrap_iov(aead3) decryption");
319     offset = (char *)stiov[2].buffer.value - fulltoken;
320     if (offset < 0 || (size_t)offset > len)
321         errout("gss_unwrap_iov(aead3) offset");
322     free(fulltoken);
323     (void)gss_release_iov_buffer(&minor, iov, 4);
324 
325     /* Wrap a token using gss_wrap_aead and unwrap it using a stream buffer
326      * with allocation and copying. */
327     input.value = (char *)wrap;
328     input.length = strlen(wrap);
329     assoc.value = (char *)sign;
330     assoc.length = strlen(sign);
331     major = gss_wrap_aead(&minor, ctx1, conf, GSS_C_QOP_DEFAULT, &assoc,
332                           &input, &oconf, &output);
333     check_gsserr("gss_wrap_aead(aead4)", major, minor);
334     if (oconf != conf)
335         errout("gss_wrap(aead4) conf");
336     stiov[0].type = GSS_IOV_BUFFER_TYPE_STREAM;
337     stiov[0].buffer = output;
338     stiov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
339     stiov[1].buffer = assoc;
340     stiov[2].type = GSS_IOV_BUFFER_TYPE_DATA | GSS_IOV_BUFFER_FLAG_ALLOCATE;
341     major = gss_unwrap_iov(&minor, ctx2, &oconf, &qop, stiov, 3);
342     check_gsserr("gss_unwrap_iov(aead4)", major, minor);
343     if (!(GSS_IOV_BUFFER_FLAGS(stiov[2].type) & GSS_IOV_BUFFER_FLAG_ALLOCATED))
344         errout("gss_unwrap_iov(aead4) allocated");
345     if (oconf != conf || qop != GSS_C_QOP_DEFAULT)
346         errout("gss_unwrap_iov(aead4) conf/qop");
347     if (stiov[2].buffer.length != strlen(wrap) ||
348         memcmp(stiov[2].buffer.value, wrap, strlen(wrap)) != 0)
349         errout("gss_unwrap_iov(aead4) decryption");
350     (void)gss_release_buffer(&minor, &output);
351     (void)gss_release_iov_buffer(&minor, stiov, 3);
352 }
353 
354 /*
355  * Get a MIC for sign1, sign2, and sign3 using the caller-provided array iov,
356  * which must have space for four elements, and the caller-provided buffer
357  * data, which must be big enough for the MIC.  If data is NULL, the library
358  * will be asked to allocate the MIC buffer.  The MIC will be located in
359  * iov[3].buffer.
360  */
361 static void
mic(gss_ctx_id_t ctx,const char * sign1,const char * sign2,const char * sign3,gss_iov_buffer_desc * iov,char * data)362 mic(gss_ctx_id_t ctx, const char *sign1, const char *sign2, const char *sign3,
363     gss_iov_buffer_desc *iov, char *data)
364 {
365     OM_uint32 minor, major;
366     krb5_boolean allocated;
367 
368     /* Lay out iov array. */
369     iov[0].type = GSS_IOV_BUFFER_TYPE_DATA;
370     iov[0].buffer.value = (char *)sign1;
371     iov[0].buffer.length = strlen(sign1);
372     iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
373     iov[1].buffer.value = (char *)sign2;
374     iov[1].buffer.length = strlen(sign2);
375     iov[2].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
376     iov[2].buffer.value = (char *)sign3;
377     iov[2].buffer.length = strlen(sign3);
378     iov[3].type = GSS_IOV_BUFFER_TYPE_MIC_TOKEN;
379     if (data == NULL) {
380         /* Ask the library to allocate the MIC buffer. */
381         iov[3].type |= GSS_IOV_BUFFER_FLAG_ALLOCATE;
382     } else {
383         /* Get the MIC length and use the caller-provided buffer. */
384         major = gss_get_mic_iov_length(&minor, ctx, GSS_C_QOP_DEFAULT, iov, 4);
385         check_gsserr("gss_get_mic_iov_length", major, minor);
386         iov[3].buffer.value = data;
387     }
388     major = gss_get_mic_iov(&minor, ctx, GSS_C_QOP_DEFAULT, iov, 4);
389     check_gsserr("gss_get_mic_iov", major, minor);
390     allocated = (GSS_IOV_BUFFER_FLAGS(iov[3].type) &
391                  GSS_IOV_BUFFER_FLAG_ALLOCATED) != 0;
392     if (allocated != (data == NULL))
393         errout("gss_get_mic_iov allocated");
394 }
395 
396 static void
test_mic(gss_ctx_id_t ctx1,gss_ctx_id_t ctx2)397 test_mic(gss_ctx_id_t ctx1, gss_ctx_id_t ctx2)
398 {
399     OM_uint32 major, minor;
400     gss_iov_buffer_desc iov[4];
401     gss_qop_t qop;
402     gss_buffer_desc concatbuf, micbuf;
403     const char *sign1 = "Data and sign-only ";
404     const char *sign2 = "buffers are treated ";
405     const char *sign3 = "equally by gss_get_mic_iov";
406     char concat[1024], data[1024];
407 
408     (void)snprintf(concat, sizeof(concat), "%s%s%s", sign1, sign2, sign3);
409     concatbuf.value = concat;
410     concatbuf.length = strlen(concat);
411 
412     /* MIC with a caller-provided buffer and verify with the IOV array. */
413     mic(ctx1, sign1, sign2, sign3, iov, data);
414     major = gss_verify_mic_iov(&minor, ctx2, &qop, iov, 4);
415     check_gsserr("gss_verify_mic_iov(mic1)", major, minor);
416     if (qop != GSS_C_QOP_DEFAULT)
417         errout("gss_verify_mic_iov(mic1) qop");
418 
419     /* MIC with an allocated buffer and verify with gss_verify_mic. */
420     mic(ctx1, sign1, sign2, sign3, iov, NULL);
421     major = gss_verify_mic(&minor, ctx2, &concatbuf, &iov[3].buffer, &qop);
422     check_gsserr("gss_verify_mic(mic2)", major, minor);
423     if (qop != GSS_C_QOP_DEFAULT)
424         errout("gss_verify_mic(mic2) qop");
425     (void)gss_release_iov_buffer(&minor, iov, 4);
426 
427     /* MIC with gss_c_get_mic and verify using the IOV array (which is still
428      * mostly set up from the last call to mic(). */
429     major = gss_get_mic(&minor, ctx1, GSS_C_QOP_DEFAULT, &concatbuf, &micbuf);
430     check_gsserr("gss_get_mic(mic3)", major, minor);
431     iov[3].buffer = micbuf;
432     major = gss_verify_mic_iov(&minor, ctx2, &qop, iov, 4);
433     check_gsserr("gss_verify_mic_iov(mic3)", major, minor);
434     if (qop != GSS_C_QOP_DEFAULT)
435         errout("gss_verify_mic_iov(mic3) qop");
436     (void)gss_release_buffer(&minor, &micbuf);
437 }
438 
439 /* Create a DCE-style token and make sure we can unwrap it. */
440 static void
test_dce(gss_ctx_id_t ctx1,gss_ctx_id_t ctx2,int conf)441 test_dce(gss_ctx_id_t ctx1, gss_ctx_id_t ctx2, int conf)
442 {
443     OM_uint32 major, minor;
444     gss_iov_buffer_desc iov[4];
445     gss_qop_t qop;
446     const char *sign1 = "First data to be signed";
447     const char *sign2 = "Second data to be signed";
448     const char *wrap = "This data must align to 16 bytes";
449     int oconf;
450     char data[1024];
451 
452     /* Wrap a SIGN_ONLY_1 | DATA | SIGN_ONLY_2 | HEADER token. */
453     memcpy(data, wrap, strlen(wrap) + 1);
454     iov[0].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
455     iov[0].buffer.value = (char *)sign1;
456     iov[0].buffer.length = strlen(sign1);
457     iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
458     iov[1].buffer.value = data;
459     iov[1].buffer.length = strlen(wrap);
460     iov[2].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
461     iov[2].buffer.value = (char *)sign2;
462     iov[2].buffer.length = strlen(sign2);
463     iov[3].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_FLAG_ALLOCATE;
464     major = gss_wrap_iov(&minor, ctx1, conf, GSS_C_QOP_DEFAULT, &oconf, iov,
465                          4);
466     check_gsserr("gss_wrap_iov(dce)", major, minor);
467     if (oconf != conf)
468         errout("gss_wrap_iov(dce) conf");
469     if (iov[0].buffer.value != sign1 || iov[0].buffer.length != strlen(sign1))
470         errout("gss_wrap_iov(dce) sign1 buffer");
471     if (iov[1].buffer.value != data || iov[1].buffer.length != strlen(wrap))
472         errout("gss_wrap_iov(dce) data buffer");
473     if (iov[2].buffer.value != sign2 || iov[2].buffer.length != strlen(sign2))
474         errout("gss_wrap_iov(dce) sign2 buffer");
475     check_encrypted("gss_wrap_iov(dce) encryption", conf, data, wrap);
476 
477     /* Make sure we can unwrap it. */
478     major = gss_unwrap_iov(&minor, ctx2, &oconf, &qop, iov, 4);
479     check_gsserr("gss_unwrap_iov(std1)", major, minor);
480     if (oconf != conf || qop != GSS_C_QOP_DEFAULT)
481         errout("gss_unwrap_iov(std1) conf/qop");
482     if (iov[0].buffer.value != sign1 || iov[0].buffer.length != strlen(sign1))
483         errout("gss_unwrap_iov(dce) sign1 buffer");
484     if (iov[1].buffer.value != data || iov[1].buffer.length != strlen(wrap))
485         errout("gss_unwrap_iov(dce) data buffer");
486     if (iov[2].buffer.value != sign2 || iov[2].buffer.length != strlen(sign2))
487         errout("gss_unwrap_iov(dce) sign2 buffer");
488     if (memcmp(data, wrap, iov[1].buffer.length) != 0)
489         errout("gss_unwrap_iov(dce) decryption");
490     (void)gss_release_iov_buffer(&minor, iov, 4);
491 }
492 
493 int
main(int argc,char * argv[])494 main(int argc, char *argv[])
495 {
496     OM_uint32 minor, flags;
497     gss_OID mech = &mech_krb5;
498     gss_name_t tname;
499     gss_ctx_id_t ictx, actx;
500 
501     /* Parse arguments. */
502     argv++;
503     if (*argv != NULL && strcmp(*argv, "-s") == 0) {
504         mech = &mech_spnego;
505         argv++;
506     }
507     if (*argv == NULL || *(argv + 1) != NULL)
508         errout("Usage: t_iov [-s] targetname");
509     tname = import_name(*argv);
510 
511     flags = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG | GSS_C_MUTUAL_FLAG;
512     establish_contexts(mech, GSS_C_NO_CREDENTIAL, GSS_C_NO_CREDENTIAL, tname,
513                        flags, &ictx, &actx, NULL, NULL, NULL);
514 
515     /* Test standard token wrapping and unwrapping in both directions, with and
516      * without confidentiality. */
517     test_standard_wrap(ictx, actx, 0);
518     test_standard_wrap(ictx, actx, 1);
519     test_standard_wrap(actx, ictx, 0);
520     test_standard_wrap(actx, ictx, 1);
521 
522     /* Test AEAD wrapping. */
523     test_aead(ictx, actx, 0);
524     test_aead(ictx, actx, 1);
525     test_aead(actx, ictx, 0);
526     test_aead(actx, ictx, 1);
527 
528     /* Test MIC tokens. */
529     test_mic(ictx, actx);
530     test_mic(actx, ictx);
531 
532     /* Test DCE wrapping with DCE-style contexts. */
533     (void)gss_delete_sec_context(&minor, &ictx, NULL);
534     (void)gss_delete_sec_context(&minor, &actx, NULL);
535     flags = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG | GSS_C_DCE_STYLE;
536     establish_contexts(mech, GSS_C_NO_CREDENTIAL, GSS_C_NO_CREDENTIAL, tname,
537                        flags, &ictx, &actx, NULL, NULL, NULL);
538     test_dce(ictx, actx, 0);
539     test_dce(ictx, actx, 1);
540     test_dce(actx, ictx, 0);
541     test_dce(actx, ictx, 1);
542 
543     (void)gss_release_name(&minor, &tname);
544     (void)gss_delete_sec_context(&minor, &ictx, NULL);
545     (void)gss_delete_sec_context(&minor, &actx, NULL);
546     return 0;
547 }
548