2 * Copyright (c) 2010, JANET(UK)
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of JANET(UK) nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * Copyright 2001, 2008 by the Massachusetts Institute of Technology.
34 * Copyright 1993 by OpenVision Technologies, Inc.
36 * Permission to use, copy, modify, distribute, and sell this software
37 * and its documentation for any purpose is hereby granted without fee,
38 * provided that the above copyright notice appears in all copies and
39 * that both that copyright notice and this permission notice appear in
40 * supporting documentation, and that the name of OpenVision not be used
41 * in advertising or publicity pertaining to distribution of the software
42 * without specific, written prior permission. OpenVision makes no
43 * representations about the suitability of this software for any
44 * purpose. It is provided "as is" without express or implied warranty.
46 * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
47 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
48 * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
49 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
50 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
51 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
52 * PERFORMANCE OF THIS SOFTWARE.
55 * Copyright (C) 1998 by the FundsXpress, INC.
57 * All rights reserved.
59 * Export of this software from the United States of America may require
60 * a specific license from the United States Government. It is the
61 * responsibility of any person or organization contemplating export to
62 * obtain such a license before exporting.
64 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
65 * distribute this software and its documentation for any purpose and
66 * without fee is hereby granted, provided that the above copyright
67 * notice appear in all copies and that both that copyright notice and
68 * this permission notice appear in supporting documentation, and that
69 * the name of FundsXpress. not be used in advertising or publicity pertaining
70 * to distribution of the software without specific, written prior
71 * permission. FundsXpress makes no representations about the suitability of
72 * this software for any purpose. It is provided "as is" without express
73 * or implied warranty.
75 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
76 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
77 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
81 * Message protection services: cryptography helpers.
84 #include "gssapiP_eap.h"
87 * DCE_STYLE indicates actual RRC is EC + RRC
88 * EC is extra rotate count for DCE_STYLE, pad length otherwise
89 * RRC is rotate count.
91 static krb5_error_code
92 mapIov(krb5_context context, int dce_style, size_t ec, size_t rrc,
93 krb5_enctype enctype, gss_iov_buffer_desc *iov,
94 int iov_count, krb5_crypto_iov **pkiov,
97 gss_iov_buffer_t header;
98 gss_iov_buffer_t trailer;
101 krb5_crypto_iov *kiov;
102 unsigned int k5_headerlen = 0, k5_trailerlen = 0;
103 size_t gss_headerlen, gss_trailerlen;
104 krb5_error_code code;
109 header = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
110 assert(header != NULL);
112 trailer = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
113 assert(trailer == NULL || rrc == 0);
115 code = krb5_c_crypto_length(context, enctype, KRB5_CRYPTO_TYPE_HEADER,
120 code = krb5_c_crypto_length(context, enctype, KRB5_CRYPTO_TYPE_TRAILER,
125 /* Check header and trailer sizes */
126 gss_headerlen = 16 /* GSS-Header */ + k5_headerlen; /* Kerb-Header */
127 gss_trailerlen = ec + 16 /* E(GSS-Header) */ + k5_trailerlen; /* Kerb-Trailer */
129 /* If we're caller without a trailer, we must rotate by trailer length */
130 if (trailer == NULL) {
131 size_t actual_rrc = rrc;
134 actual_rrc += ec; /* compensate for Windows bug */
136 if (actual_rrc != gss_trailerlen)
137 return KRB5_BAD_MSIZE;
139 gss_headerlen += gss_trailerlen;
142 if (trailer->buffer.length != gss_trailerlen)
143 return KRB5_BAD_MSIZE;
146 if (header->buffer.length != gss_headerlen)
147 return KRB5_BAD_MSIZE;
149 kiov_count = 3 + iov_count;
150 kiov = (krb5_crypto_iov *)GSSEAP_MALLOC(kiov_count * sizeof(krb5_crypto_iov));
155 * The krb5 header is located at the end of the GSS header.
157 kiov[i].flags = KRB5_CRYPTO_TYPE_HEADER;
158 kiov[i].data.length = k5_headerlen;
159 kiov[i].data.data = (char *)header->buffer.value + header->buffer.length - k5_headerlen;
162 for (j = 0; j < iov_count; j++) {
163 kiov[i].flags = gssEapMapCryptoFlag(iov[j].type);
164 if (kiov[i].flags == KRB5_CRYPTO_TYPE_EMPTY)
167 kiov[i].data.length = iov[j].buffer.length;
168 kiov[i].data.data = (char *)iov[j].buffer.value;
173 * The EC and encrypted GSS header are placed in the trailer, which may
174 * be rotated directly after the plaintext header if no trailer buffer
177 kiov[i].flags = KRB5_CRYPTO_TYPE_DATA;
178 kiov[i].data.length = ec + 16; /* E(Header) */
180 kiov[i].data.data = (char *)header->buffer.value + 16;
182 kiov[i].data.data = (char *)trailer->buffer.value;
186 * The krb5 trailer is placed after the encrypted copy of the
187 * krb5 header (which may be in the GSS header or trailer).
189 kiov[i].flags = KRB5_CRYPTO_TYPE_TRAILER;
190 kiov[i].data.length = k5_trailerlen;
191 kiov[i].data.data = kiov[i - 1].data.data + ec + 16; /* E(Header) */
201 gssEapEncrypt(krb5_context context, int dce_style, size_t ec,
202 size_t rrc, krb5_keyblock *key, int usage, krb5_pointer iv,
203 gss_iov_buffer_desc *iov, int iov_count)
205 krb5_error_code code;
207 krb5_data ivd, *pivd;
209 krb5_crypto_iov *kiov;
212 code = krb5_c_block_size(context, KRB_KEY_TYPE(key), &blocksize);
216 ivd.length = blocksize;
217 ivd.data = GSSEAP_MALLOC(ivd.length);
218 if (ivd.data == NULL)
220 memcpy(ivd.data, iv, ivd.length);
226 code = mapIov(context, dce_style, ec, rrc,
227 KRB_KEY_TYPE(key), iov, iov_count,
230 code = krb5_c_encrypt_iov(context, key, usage, pivd, kiov, kiov_count);
235 GSSEAP_FREE(pivd->data);
241 gssEapDecrypt(krb5_context context, int dce_style, size_t ec,
242 size_t rrc, krb5_keyblock *key, int usage, krb5_pointer iv,
243 gss_iov_buffer_desc *iov, int iov_count)
245 krb5_error_code code;
247 krb5_data ivd, *pivd;
249 krb5_crypto_iov *kiov;
252 code = krb5_c_block_size(context, KRB_KEY_TYPE(key), &blocksize);
256 ivd.length = blocksize;
257 ivd.data = GSSEAP_MALLOC(ivd.length);
258 if (ivd.data == NULL)
260 memcpy(ivd.data, iv, ivd.length);
266 code = mapIov(context, dce_style, ec, rrc,
267 KRB_KEY_TYPE(key), iov, iov_count,
270 code = krb5_c_decrypt_iov(context, key, usage, pivd, kiov, kiov_count);
275 GSSEAP_FREE(pivd->data);
281 gssEapMapCryptoFlag(OM_uint32 type)
283 krb5_cryptotype ktype;
285 switch (GSS_IOV_BUFFER_TYPE(type)) {
286 case GSS_IOV_BUFFER_TYPE_DATA:
287 case GSS_IOV_BUFFER_TYPE_PADDING:
288 ktype = KRB5_CRYPTO_TYPE_DATA;
290 case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
291 ktype = KRB5_CRYPTO_TYPE_SIGN_ONLY;
294 ktype = KRB5_CRYPTO_TYPE_EMPTY;
302 gssEapLocateIov(gss_iov_buffer_desc *iov, int iov_count, OM_uint32 type)
305 gss_iov_buffer_t p = GSS_C_NO_IOV_BUFFER;
307 if (iov == GSS_C_NO_IOV_BUFFER)
308 return GSS_C_NO_IOV_BUFFER;
310 for (i = iov_count - 1; i >= 0; i--) {
311 if (GSS_IOV_BUFFER_TYPE(iov[i].type) == type) {
312 if (p == GSS_C_NO_IOV_BUFFER)
315 return GSS_C_NO_IOV_BUFFER;
323 gssEapIovMessageLength(gss_iov_buffer_desc *iov,
325 size_t *data_length_p,
326 size_t *assoc_data_length_p)
329 size_t data_length = 0, assoc_data_length = 0;
331 assert(iov != GSS_C_NO_IOV_BUFFER);
333 *data_length_p = *assoc_data_length_p = 0;
335 for (i = 0; i < iov_count; i++) {
336 OM_uint32 type = GSS_IOV_BUFFER_TYPE(iov[i].type);
338 if (type == GSS_IOV_BUFFER_TYPE_SIGN_ONLY)
339 assoc_data_length += iov[i].buffer.length;
341 if (type == GSS_IOV_BUFFER_TYPE_DATA ||
342 type == GSS_IOV_BUFFER_TYPE_SIGN_ONLY)
343 data_length += iov[i].buffer.length;
346 *data_length_p = data_length;
347 *assoc_data_length_p = assoc_data_length;
351 gssEapReleaseIov(gss_iov_buffer_desc *iov, int iov_count)
356 assert(iov != GSS_C_NO_IOV_BUFFER);
358 for (i = 0; i < iov_count; i++) {
359 if (iov[i].type & GSS_IOV_BUFFER_FLAG_ALLOCATED) {
360 gss_release_buffer(&min_stat, &iov[i].buffer);
361 iov[i].type &= ~(GSS_IOV_BUFFER_FLAG_ALLOCATED);
367 gssEapIsIntegrityOnly(gss_iov_buffer_desc *iov, int iov_count)
370 krb5_boolean has_conf_data = FALSE;
372 assert(iov != GSS_C_NO_IOV_BUFFER);
374 for (i = 0; i < iov_count; i++) {
375 if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA) {
376 has_conf_data = TRUE;
381 return (has_conf_data == FALSE);
385 gssEapAllocIov(gss_iov_buffer_t iov, size_t size)
387 assert(iov != GSS_C_NO_IOV_BUFFER);
388 assert(iov->type & GSS_IOV_BUFFER_FLAG_ALLOCATE);
390 iov->buffer.length = size;
391 iov->buffer.value = GSSEAP_MALLOC(size);
392 if (iov->buffer.value == NULL) {
393 iov->buffer.length = 0;
397 iov->type |= GSS_IOV_BUFFER_FLAG_ALLOCATED;