3cec4f09b02e7bbe2aa32f993a65c4c12855f31c
[mech_eap.orig] / unwrap_iov.c
1 /*
2  * Copyright (c) 2010, JANET(UK)
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
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.
15  *
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.
19  *
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
30  * SUCH DAMAGE.
31  */
32 /*
33  * lib/gssapi/krb5/k5sealv3iov.c
34  *
35  * Copyright 2008 by the Massachusetts Institute of Technology.
36  * All Rights Reserved.
37  *
38  * Export of this software from the United States of America may
39  *   require a specific license from the United States Government.
40  *   It is the responsibility of any person or organization contemplating
41  *   export to obtain such a license before exporting.
42  *
43  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
44  * distribute this software and its documentation for any purpose and
45  * without fee is hereby granted, provided that the above copyright
46  * notice appear in all copies and that both that copyright notice and
47  * this permission notice appear in supporting documentation, and that
48  * the name of M.I.T. not be used in advertising or publicity pertaining
49  * to distribution of the software without specific, written prior
50  * permission.  Furthermore if you modify this software you must label
51  * your software as modified software and not distribute it in such a
52  * fashion that it might be confused with the original M.I.T. software.
53  * M.I.T. makes no representations about the suitability of
54  * this software for any purpose.  It is provided "as is" without express
55  * or implied warranty.
56  *
57  *
58  */
59
60 #include "gssapiP_eap.h"
61
62 OM_uint32
63 gssEapUnwrapOrVerifyMIC(OM_uint32 *minor_status,
64                         gss_ctx_id_t ctx,
65                         int *conf_state,
66                         gss_qop_t *qop_state,
67                         gss_iov_buffer_desc *iov,
68                         int iov_count,
69                         enum gss_eap_token_type toktype)
70 {
71     OM_uint32 code;
72     gss_iov_buffer_t header;
73     gss_iov_buffer_t padding;
74     gss_iov_buffer_t trailer;
75     unsigned char acceptor_flag;
76     unsigned char *ptr = NULL;
77     int key_usage;
78     size_t rrc, ec;
79     size_t data_length, assoc_data_length;
80     uint64_t seqnum;
81     krb5_boolean valid;
82     krb5_cksumtype cksumtype;
83     int conf_flag = 0;
84
85     *minor_status = 0;
86
87     if (qop_state != NULL)
88         *qop_state = GSS_C_QOP_DEFAULT;
89
90     if (!CTX_IS_ESTABLISHED(ctx))
91         return GSS_S_NO_CONTEXT;
92
93     header = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
94     assert(header != NULL);
95
96     padding = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
97     if (padding != NULL && padding->buffer.length != 0)
98         return GSS_S_DEFECTIVE_TOKEN;
99
100     trailer = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
101
102     acceptor_flag = CTX_IS_INITIATOR(ctx) ? TOK_FLAG_SENDER_IS_ACCEPTOR : 0;
103     key_usage = (toktype == TOK_TYPE_WRAP
104                  ? (!CTX_IS_INITIATOR(ctx)
105                     ? KRB_USAGE_INITIATOR_SEAL
106                     : KRB_USAGE_ACCEPTOR_SEAL)
107                  : (!CTX_IS_INITIATOR(ctx)
108                     ? KRB_USAGE_INITIATOR_SIGN
109                     : KRB_USAGE_ACCEPTOR_SIGN));
110
111     gssEapIovMessageLength(iov, iov_count, &data_length, &assoc_data_length);
112
113     ptr = (unsigned char *)header->buffer.value;
114
115     if (header->buffer.length < 16) {
116         *minor_status = 0;
117         return GSS_S_DEFECTIVE_TOKEN;
118     }
119
120     if ((ptr[2] & TOK_FLAG_SENDER_IS_ACCEPTOR) != acceptor_flag) {
121         return GSS_S_BAD_SIG;
122     }
123
124     if (ptr[2] & TOK_FLAG_ACCEPTOR_SUBKEY) {
125         return GSS_S_BAD_SIG;
126     }
127
128     if (toktype == TOK_TYPE_WRAP) {
129         unsigned int k5_trailerlen;
130
131         if (load_16_be(ptr) != TOK_TYPE_WRAP)
132             goto defective;
133         conf_flag = ((ptr[2] & TOK_FLAG_WRAP_CONFIDENTIAL) != 0);
134         if (ptr[3] != 0xFF)
135             goto defective;
136         ec = load_16_be(ptr + 4);
137         rrc = load_16_be(ptr + 6);
138         seqnum = load_64_be(ptr + 8);
139
140         code = krb5_c_crypto_length(ctx->kerberosCtx,
141                                     KRB_KEYTYPE(ctx->encryptionKey),
142                                     conf_flag ? KRB5_CRYPTO_TYPE_TRAILER :
143                                     KRB5_CRYPTO_TYPE_CHECKSUM,
144                                     &k5_trailerlen);
145         if (code != 0) {
146             *minor_status = code;
147             return GSS_S_FAILURE;
148         }
149
150         /* Deal with RRC */
151         if (trailer == NULL) {
152             size_t desired_rrc = k5_trailerlen;
153
154             if (conf_flag) {
155                 desired_rrc += 16; /* E(Header) */
156
157                 if ((ctx->gssFlags & GSS_C_DCE_STYLE) == 0)
158                     desired_rrc += ec;
159             }
160
161             /* According to MS, we only need to deal with a fixed RRC for DCE */
162             if (rrc != desired_rrc)
163                 goto defective;
164         } else if (rrc != 0) {
165             goto defective;
166         }
167
168         if (conf_flag) {
169             unsigned char *althdr;
170
171             /* Decrypt */
172             code = gssEapDecrypt(ctx->kerberosCtx,
173                                  ((ctx->gssFlags & GSS_C_DCE_STYLE) != 0),
174                                  ec, rrc, ctx->encryptionKey,
175                                  key_usage, 0, iov, iov_count);
176             if (code != 0) {
177                 *minor_status = code;
178                 return GSS_S_BAD_SIG;
179             }
180
181             /* Validate header integrity */
182             if (trailer == NULL)
183                 althdr = (unsigned char *)header->buffer.value + 16 + ec;
184             else
185                 althdr = (unsigned char *)trailer->buffer.value + ec;
186
187             if (load_16_be(althdr) != TOK_TYPE_WRAP
188                 || althdr[2] != ptr[2]
189                 || althdr[3] != ptr[3]
190                 || memcmp(althdr + 8, ptr + 8, 8) != 0) {
191                 *minor_status = 0;
192                 return GSS_S_BAD_SIG;
193             }
194         } else {
195             /* Verify checksum: note EC is checksum size here, not padding */
196             if (ec != k5_trailerlen)
197                 goto defective;
198
199             /* Zero EC, RRC before computing checksum */
200             store_16_be(0, ptr + 4);
201             store_16_be(0, ptr + 6);
202
203             code = gssEapVerify(ctx->kerberosCtx, cksumtype, rrc,
204                                 ctx->encryptionKey, key_usage,
205                                 iov, iov_count, &valid);
206             if (code != 0 || valid == FALSE) {
207                 *minor_status = code;
208                 return GSS_S_BAD_SIG;
209             }
210         }
211
212         code = g_order_check(&ctx->seqState, seqnum);
213     } else if (toktype == TOK_TYPE_MIC) {
214         if (load_16_be(ptr) != TOK_TYPE_MIC)
215             goto defective;
216
217     verify_mic_1:
218         if (ptr[3] != 0xFF)
219             goto defective;
220         seqnum = load_64_be(ptr + 8);
221
222         code = gssEapVerify(ctx->kerberosCtx, cksumtype, 0,
223                             ctx->encryptionKey, key_usage,
224                             iov, iov_count, &valid);
225         if (code != 0 || valid == FALSE) {
226             *minor_status = code;
227             return GSS_S_BAD_SIG;
228         }
229         code = g_order_check(&ctx->seqState, seqnum);
230     } else if (toktype == TOK_TYPE_DELETE) {
231         if (load_16_be(ptr) != TOK_TYPE_DELETE)
232             goto defective;
233         goto verify_mic_1;
234     } else {
235         goto defective;
236     }
237
238     *minor_status = 0;
239
240     if (conf_state != NULL)
241         *conf_state = conf_flag;
242
243     return code;
244
245 defective:
246     *minor_status = 0;
247
248     return GSS_S_DEFECTIVE_TOKEN;
249 }
250
251 OM_uint32
252 gss_unwrap_iov(OM_uint32 *minor,
253                gss_ctx_id_t ctx,
254                int *conf_state,
255                gss_qop_t *qop_state,
256                gss_iov_buffer_desc *iov,
257                int iov_count)
258 {
259     return gssEapUnwrapOrVerifyMIC(minor, ctx,
260                                    iov, iov_count, conf_state,
261                                    qop_state, TOK_TYPE_WRAP);
262
263 }