Branch data Line data Source code
1 : : /* krb5/msg.c --- Implementation of Kerberos 5 GSS-API Per-Message functions.
2 : : * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Simon Josefsson
3 : : *
4 : : * This file is part of the Generic Security Service (GSS).
5 : : *
6 : : * GSS is free software; you can redistribute it and/or modify it
7 : : * under the terms of the GNU General Public License as published by
8 : : * the Free Software Foundation; either version 3 of the License, or
9 : : * (at your option) any later version.
10 : : *
11 : : * GSS is distributed in the hope that it will be useful, but WITHOUT
12 : : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 : : * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
14 : : * License for more details.
15 : : *
16 : : * You should have received a copy of the GNU General Public License
17 : : * along with GSS; if not, see http://www.gnu.org/licenses or write to
18 : : * the Free Software Foundation, Inc., 51 Franklin Street, Fifth
19 : : * Floor, Boston, MA 02110-1301, USA.
20 : : *
21 : : */
22 : :
23 : : /* Get specification. */
24 : : #include "k5internal.h"
25 : :
26 : : #define TOK_LEN 2
27 : : #define TOK_WRAP "\x02\x01"
28 : :
29 : : #define C2I(buf) ((buf[0] & 0xFF) | \
30 : : ((buf[1] & 0xFF) << 8) | \
31 : : ((buf[2] & 0xFF) << 16) | \
32 : : ((buf[3] & 0xFF) << 24))
33 : :
34 : : OM_uint32
35 : 0 : gss_krb5_get_mic (OM_uint32 * minor_status,
36 : : const gss_ctx_id_t context_handle,
37 : : gss_qop_t qop_req,
38 : : const gss_buffer_t message_buffer,
39 : : gss_buffer_t message_token)
40 : : {
41 : 0 : return GSS_S_UNAVAILABLE;
42 : : }
43 : :
44 : : OM_uint32
45 : 0 : gss_krb5_verify_mic (OM_uint32 * minor_status,
46 : : const gss_ctx_id_t context_handle,
47 : : const gss_buffer_t message_buffer,
48 : : const gss_buffer_t token_buffer, gss_qop_t * qop_state)
49 : : {
50 : 0 : return GSS_S_UNAVAILABLE;
51 : : }
52 : :
53 : : OM_uint32
54 : 3 : gss_krb5_wrap (OM_uint32 * minor_status,
55 : : const gss_ctx_id_t context_handle,
56 : : int conf_req_flag,
57 : : gss_qop_t qop_req,
58 : : const gss_buffer_t input_message_buffer,
59 : : int *conf_state, gss_buffer_t output_message_buffer)
60 : : {
61 : 3 : _gss_krb5_ctx_t k5 = context_handle->krb5;
62 : : size_t padlength;
63 : : gss_buffer_desc data;
64 : : char *p;
65 : : size_t tmplen;
66 : : int rc;
67 : :
68 [ + - - ]: 3 : switch (shishi_key_type (k5->key))
69 : : {
70 : : /* XXX implement other checksums */
71 : :
72 : : case SHISHI_DES_CBC_MD5:
73 : : {
74 : : char header[8];
75 : : char seqno[8];
76 : : char *eseqno;
77 : : char *cksum;
78 : : char confounder[8];
79 : :
80 : : /* Typical data:
81 : : ;; 02 01 00 00 ff ff ff ff 0c 22 1f 79 59 3d 00 cb
82 : : ;; d5 78 2f fb 50 d2 b8 59 fb b4 e0 9b d0 a2 fa dc
83 : : ;; 01 00 20 00 04 04 04 04
84 : : Translates into:
85 : : ;; HEADER ENCRYPTED SEQ.NUMBER
86 : : ;; DES-MAC-MD5 CKSUM CONFOUNDER
87 : : ;; PADDED DATA
88 : : */
89 : 3 : padlength = 8 - input_message_buffer->length % 8;
90 : 3 : data.length = 4 * 8 + input_message_buffer->length + padlength;
91 : 3 : p = malloc (data.length);
92 [ - + ]: 3 : if (!p)
93 : : {
94 [ # # ]: 0 : if (minor_status)
95 : 0 : *minor_status = ENOMEM;
96 : 0 : return GSS_S_FAILURE;
97 : : }
98 : :
99 : : /* XXX encrypt data iff confidential option chosen */
100 : :
101 : : /* Setup header and confounder */
102 : 3 : memcpy (header, TOK_WRAP, 2); /* TOK_ID: Wrap 0201 */
103 : 3 : memcpy (header + 2, "\x00\x00", 2); /* SGN_ALG: DES-MAC-MD5 */
104 : 3 : memcpy (header + 4, "\xFF\xFF", 2); /* SEAL_ALG: none */
105 : 3 : memcpy (header + 6, "\xFF\xFF", 2); /* filler */
106 : 3 : rc = shishi_randomize (k5->sh, 0, confounder, 8);
107 [ - + ]: 3 : if (rc != SHISHI_OK)
108 : 0 : return GSS_S_FAILURE;
109 : :
110 : : /* Compute checksum over header, confounder, input string, and pad */
111 : 3 : memcpy (p, header, 8);
112 : 3 : memcpy (p + 8, confounder, 8);
113 : 3 : memcpy (p + 16, input_message_buffer->value,
114 : : input_message_buffer->length);
115 : 3 : memset (p + 16 + input_message_buffer->length,
116 : : (int) padlength, padlength);
117 : :
118 : 3 : rc = shishi_checksum (k5->sh,
119 : : k5->key,
120 : : 0, SHISHI_RSA_MD5_DES_GSS,
121 : : p,
122 : : 16 + input_message_buffer->length + padlength,
123 : : &cksum, &tmplen);
124 [ + - - + ]: 3 : if (rc != SHISHI_OK || tmplen != 8)
125 : 0 : return GSS_S_FAILURE;
126 : :
127 : : /* seq_nr */
128 [ - + ]: 3 : if (k5->acceptor)
129 : : {
130 : 0 : seqno[0] = k5->acceptseqnr & 0xFF;
131 : 0 : seqno[1] = k5->acceptseqnr >> 8 & 0xFF;
132 : 0 : seqno[2] = k5->acceptseqnr >> 16 & 0xFF;
133 : 0 : seqno[3] = k5->acceptseqnr >> 24 & 0xFF;
134 : 0 : memset (seqno + 4, 0xFF, 4);
135 : : }
136 : : else
137 : : {
138 : 3 : seqno[0] = k5->initseqnr & 0xFF;
139 : 3 : seqno[1] = k5->initseqnr >> 8 & 0xFF;
140 : 3 : seqno[2] = k5->initseqnr >> 16 & 0xFF;
141 : 3 : seqno[3] = k5->initseqnr >> 24 & 0xFF;
142 : 3 : memset (seqno + 4, 0, 4);
143 : : }
144 : :
145 : 3 : rc = shishi_encrypt_iv_etype (k5->sh, k5->key, 0,
146 : : SHISHI_DES_CBC_NONE, cksum, 8,
147 : : seqno, 8, &eseqno, &tmplen);
148 [ + - - + ]: 3 : if (rc != SHISHI_OK || tmplen != 8)
149 : 0 : return GSS_S_FAILURE;
150 : :
151 : : /* put things in place */
152 : 3 : memcpy (p, header, 8);
153 : 3 : memcpy (p + 8, eseqno, 8);
154 : 3 : free (eseqno);
155 : 3 : memcpy (p + 16, cksum, 8);
156 : 3 : free (cksum);
157 : 3 : memcpy (p + 24, confounder, 8);
158 : 3 : memcpy (p + 32, input_message_buffer->value,
159 : : input_message_buffer->length);
160 : 3 : memset (p + 32 + input_message_buffer->length,
161 : : (int) padlength, padlength);
162 : :
163 : 3 : data.value = p;
164 : :
165 : 3 : rc = gss_encapsulate_token (&data, GSS_KRB5, output_message_buffer);
166 [ - + ]: 3 : if (rc != GSS_S_COMPLETE)
167 : 0 : return GSS_S_FAILURE;
168 [ - + ]: 3 : if (k5->acceptor)
169 : 0 : k5->acceptseqnr++;
170 : : else
171 : 3 : k5->initseqnr++;
172 : : }
173 : 3 : break;
174 : :
175 : : case SHISHI_DES3_CBC_HMAC_SHA1_KD:
176 : : {
177 : : char *tmp;
178 : :
179 : 0 : padlength = 8 - input_message_buffer->length % 8;
180 : 0 : data.length = 8 + 8 + 20 + 8 + input_message_buffer->length
181 : : + padlength;
182 : 0 : p = malloc (data.length);
183 [ # # ]: 0 : if (!p)
184 : : {
185 [ # # ]: 0 : if (minor_status)
186 : 0 : *minor_status = ENOMEM;
187 : 0 : return GSS_S_FAILURE;
188 : : }
189 : :
190 : : /* XXX encrypt data iff confidential option chosen */
191 : :
192 : : /* Compute checksum over header, confounder, input string, and pad */
193 : :
194 : 0 : memcpy (p, TOK_WRAP, 2); /* TOK_ID: Wrap */
195 : 0 : memcpy (p + 2, "\x04\x00", 2); /* SGN_ALG: 3DES */
196 : 0 : memcpy (p + 4, "\xFF\xFF", 2); /* SEAL_ALG: none */
197 : 0 : memcpy (p + 6, "\xFF\xFF", 2); /* filler */
198 : 0 : rc = shishi_randomize (k5->sh, 0, p + 8, 8);
199 [ # # ]: 0 : if (rc != SHISHI_OK)
200 : 0 : return GSS_S_FAILURE;
201 : 0 : memcpy (p + 16, input_message_buffer->value,
202 : : input_message_buffer->length);
203 : 0 : memset (p + 16 + input_message_buffer->length,
204 : : (int) padlength, padlength);
205 : :
206 : 0 : rc = shishi_checksum (k5->sh,
207 : : k5->key,
208 : : SHISHI_KEYUSAGE_GSS_R2,
209 : : SHISHI_HMAC_SHA1_DES3_KD, p,
210 : : 16 + input_message_buffer->length + padlength,
211 : : &tmp, &tmplen);
212 [ # # # # ]: 0 : if (rc != SHISHI_OK || tmplen != 20)
213 : 0 : return GSS_S_FAILURE;
214 : :
215 : 0 : memcpy (p + 16, tmp, tmplen);
216 : 0 : memcpy (p + 36, p + 8, 8);
217 : :
218 : : /* seq_nr */
219 [ # # ]: 0 : if (k5->acceptor)
220 : : {
221 : 0 : (p + 8)[0] = k5->acceptseqnr & 0xFF;
222 : 0 : (p + 8)[1] = k5->acceptseqnr >> 8 & 0xFF;
223 : 0 : (p + 8)[2] = k5->acceptseqnr >> 16 & 0xFF;
224 : 0 : (p + 8)[3] = k5->acceptseqnr >> 24 & 0xFF;
225 : 0 : memset (p + 8 + 4, 0xFF, 4);
226 : : }
227 : : else
228 : : {
229 : 0 : (p + 8)[0] = k5->initseqnr & 0xFF;
230 : 0 : (p + 8)[1] = k5->initseqnr >> 8 & 0xFF;
231 : 0 : (p + 8)[2] = k5->initseqnr >> 16 & 0xFF;
232 : 0 : (p + 8)[3] = k5->initseqnr >> 24 & 0xFF;
233 : 0 : memset (p + 8 + 4, 0, 4);
234 : : }
235 : :
236 : 0 : rc = shishi_encrypt_iv_etype (k5->sh, k5->key, 0, SHISHI_DES3_CBC_NONE, p + 16, 8, /* cksum */
237 : : p + 8, 8, &tmp, &tmplen);
238 [ # # # # ]: 0 : if (rc != SHISHI_OK || tmplen != 8)
239 : 0 : return GSS_S_FAILURE;
240 : :
241 : 0 : memcpy (p + 8, tmp, tmplen);
242 : 0 : free (tmp);
243 : 0 : memcpy (p + 8 + 8 + 20 + 8, input_message_buffer->value,
244 : : input_message_buffer->length);
245 : 0 : memset (p + 8 + 8 + 20 + 8 + input_message_buffer->length,
246 : : (int) padlength, padlength);
247 : :
248 : 0 : data.value = p;
249 : :
250 : 0 : rc = gss_encapsulate_token (&data, GSS_KRB5, output_message_buffer);
251 [ # # ]: 0 : if (rc != GSS_S_COMPLETE)
252 : 0 : return GSS_S_FAILURE;
253 [ # # ]: 0 : if (k5->acceptor)
254 : 0 : k5->acceptseqnr++;
255 : : else
256 : 0 : k5->initseqnr++;
257 : 0 : break;
258 : : }
259 : :
260 : : default:
261 : 0 : return GSS_S_FAILURE;
262 : : }
263 : :
264 : 3 : return GSS_S_COMPLETE;
265 : : }
266 : :
267 : : OM_uint32
268 : 3 : gss_krb5_unwrap (OM_uint32 * minor_status,
269 : : const gss_ctx_id_t context_handle,
270 : : const gss_buffer_t input_message_buffer,
271 : : gss_buffer_t output_message_buffer,
272 : : int *conf_state, gss_qop_t * qop_state)
273 : : {
274 : 3 : _gss_krb5_ctx_t k5 = context_handle->krb5;
275 : : gss_buffer_desc tok;
276 : : char *data;
277 : : OM_uint32 sgn_alg, seal_alg;
278 : : size_t tmplen;
279 : : int rc;
280 : :
281 : 3 : rc = gss_decapsulate_token (input_message_buffer, GSS_KRB5, &tok);
282 [ - + ]: 3 : if (rc != GSS_S_COMPLETE)
283 : 0 : return GSS_S_BAD_MIC;
284 : :
285 [ - + ]: 3 : if (tok.length < 8)
286 : 0 : return GSS_S_BAD_MIC;
287 : :
288 [ - + ]: 3 : if (memcmp (tok.value, TOK_WRAP, TOK_LEN) != 0)
289 : 0 : return GSS_S_BAD_MIC;
290 : :
291 : 3 : data = tok.value;
292 : :
293 : 3 : sgn_alg = data[2] & 0xFF;
294 : 3 : sgn_alg |= data[3] << 8 & 0xFF00;
295 : :
296 : 3 : seal_alg = data[4] & 0xFF;
297 : 3 : seal_alg |= data[5] << 8 & 0xFF00;
298 : :
299 [ + - ]: 3 : if (conf_state != NULL)
300 : 3 : *conf_state = seal_alg == 0xFFFF;
301 : :
302 [ - + ]: 3 : if (memcmp (data + 6, "\xFF\xFF", 2) != 0)
303 : 0 : return GSS_S_BAD_MIC;
304 : :
305 [ + - - ]: 3 : switch (sgn_alg)
306 : : {
307 : : /* XXX implement other checksums */
308 : :
309 : : case 0: /* DES-MD5 */
310 : : {
311 : : size_t padlen;
312 : : char *pt;
313 : : char header[8];
314 : : char encseqno[8];
315 : : char seqno[8];
316 : : char cksum[8];
317 : : char confounder[8];
318 : : char *tmp;
319 : : uint32_t seqnr;
320 : : size_t outlen, i;
321 : :
322 : : /* Typical data:
323 : : ;; 02 01 00 00 ff ff ff ff 0c 22 1f 79 59 3d 00 cb
324 : : ;; d5 78 2f fb 50 d2 b8 59 fb b4 e0 9b d0 a2 fa dc
325 : : ;; 01 00 20 00 04 04 04 04
326 : : Translates into:
327 : : ;; HEADER ENCRYPTED SEQ.NUMBER
328 : : ;; DES-MAC-MD5 CKSUM CONFOUNDER
329 : : ;; PADDED DATA
330 : : */
331 : :
332 [ - + ]: 3 : if (tok.length < 5 * 8)
333 : 0 : return GSS_S_BAD_MIC;
334 : :
335 : 3 : memcpy (header, data, 8);
336 : 3 : memcpy (encseqno, data + 8, 8);
337 : 3 : memcpy (cksum, data + 16, 8);
338 : 3 : memcpy (confounder, data + 24, 8);
339 : 3 : pt = data + 32;
340 : :
341 : : /* XXX decrypt data iff confidential option chosen */
342 : :
343 : 3 : rc = shishi_decrypt_iv_etype (k5->sh,
344 : : k5->key,
345 : : 0, SHISHI_DES_CBC_NONE,
346 : : cksum, 8, encseqno, 8, &tmp, &outlen);
347 [ - + ]: 3 : if (rc != SHISHI_OK)
348 : 0 : return GSS_S_FAILURE;
349 [ - + ]: 3 : if (outlen != 8)
350 : 0 : return GSS_S_BAD_MIC;
351 : 3 : memcpy (seqno, tmp, 8);
352 : 3 : free (tmp);
353 : :
354 [ + - ][ - + ]: 3 : if (memcmp (seqno + 4, k5->acceptor ? "\x00\x00\x00\x00" :
355 : : "\xFF\xFF\xFF\xFF", 4) != 0)
356 : 0 : return GSS_S_BAD_MIC;
357 : :
358 : 3 : seqnr = C2I (seqno);
359 [ + - ][ - + ]: 3 : if (seqnr != (k5->acceptor ? k5->initseqnr : k5->acceptseqnr))
360 : 0 : return GSS_S_BAD_MIC;
361 : :
362 [ + - ]: 3 : if (k5->acceptor)
363 : 3 : k5->initseqnr++;
364 : : else
365 : 0 : k5->acceptseqnr++;
366 : :
367 : : /* Check pad */
368 : 3 : padlen = data[tok.length - 1];
369 [ - + ]: 3 : if (padlen > 8)
370 : 0 : return GSS_S_BAD_MIC;
371 [ + + ]: 15 : for (i = 1; i <= padlen; i++)
372 [ - + ]: 12 : if (data[tok.length - i] != (int) padlen)
373 : 0 : return GSS_S_BAD_MIC;
374 : :
375 : : /* Write header and confounder next to data */
376 : 3 : memcpy (data + 16, header, 8);
377 : 3 : memcpy (data + 24, confounder, 8);
378 : :
379 : : /* Checksum header + confounder + data + pad */
380 : 3 : rc = shishi_checksum (k5->sh,
381 : : k5->key,
382 : : 0, SHISHI_RSA_MD5_DES_GSS,
383 : : data + 16, tok.length - 16, &tmp, &tmplen);
384 [ + - - + ]: 3 : if (rc != SHISHI_OK || tmplen != 8)
385 : 0 : return GSS_S_FAILURE;
386 : :
387 : 3 : memcpy (data + 8, tmp, tmplen);
388 : :
389 : : /* Compare checksum */
390 [ + - ][ - + ]: 3 : if (tmplen != 8 || memcmp (cksum, data + 8, 8) != 0)
391 : 0 : return GSS_S_BAD_MIC;
392 : :
393 : : /* Copy output data */
394 : 3 : output_message_buffer->length = tok.length - 8 - 8 - 8 - 8 - padlen;
395 : 3 : output_message_buffer->value = malloc (output_message_buffer->length);
396 [ - + ]: 3 : if (!output_message_buffer->value)
397 : : {
398 [ # # ]: 0 : if (minor_status)
399 : 0 : *minor_status = ENOMEM;
400 : 0 : return GSS_S_FAILURE;
401 : : }
402 : :
403 : 3 : memcpy (output_message_buffer->value, pt,
404 : : tok.length - 4 * 8 - padlen);
405 : : }
406 : 3 : break;
407 : :
408 : : case 4: /* 3DES */
409 : : {
410 : : size_t padlen;
411 : : char *p;
412 : : char *t;
413 : : char cksum[20];
414 : : size_t outlen, i;
415 : : uint32_t seqnr;
416 : :
417 [ # # ]: 0 : if (tok.length < 8 + 8 + 20 + 8 + 8)
418 : 0 : return GSS_S_BAD_MIC;
419 : :
420 : 0 : memcpy (cksum, data + 8 + 8, 20);
421 : :
422 : : /* XXX decrypt data iff confidential option chosen */
423 : :
424 : 0 : p = data + 8;
425 : 0 : rc = shishi_decrypt_iv_etype (k5->sh,
426 : : k5->key,
427 : : 0, SHISHI_DES3_CBC_NONE,
428 : : cksum, 8, p, 8, &t, &outlen);
429 [ # # # # ]: 0 : if (rc != SHISHI_OK || outlen != 8)
430 : 0 : return GSS_S_FAILURE;
431 : :
432 : 0 : memcpy (p, t, 8);
433 : 0 : free (t);
434 : :
435 [ # # ][ # # ]: 0 : if (memcmp (p + 4, k5->acceptor ? "\x00\x00\x00\x00" :
436 : : "\xFF\xFF\xFF\xFF", 4) != 0)
437 : 0 : return GSS_S_BAD_MIC;
438 : 0 : seqnr = C2I (p);
439 [ # # ][ # # ]: 0 : if (seqnr != (k5->acceptor ? k5->initseqnr : k5->acceptseqnr))
440 : 0 : return GSS_S_BAD_MIC;
441 : :
442 [ # # ]: 0 : if (k5->acceptor)
443 : 0 : k5->initseqnr++;
444 : : else
445 : 0 : k5->acceptseqnr++;
446 : :
447 : : /* Check pad */
448 : 0 : padlen = data[tok.length - 1];
449 [ # # ]: 0 : if (padlen > 8)
450 : 0 : return GSS_S_BAD_MIC;
451 [ # # ]: 0 : for (i = 1; i <= padlen; i++)
452 [ # # ]: 0 : if (data[tok.length - i] != (int) padlen)
453 : 0 : return GSS_S_BAD_MIC;
454 : :
455 : : /* Write header next to confounder */
456 : 0 : memcpy (data + 8 + 20, data, 8);
457 : :
458 : : /* Checksum header + confounder + data + pad */
459 : 0 : rc = shishi_checksum (k5->sh,
460 : : k5->key,
461 : : SHISHI_KEYUSAGE_GSS_R2,
462 : : SHISHI_HMAC_SHA1_DES3_KD, data + 20 + 8,
463 : : tok.length - 20 - 8, &t, &tmplen);
464 [ # # # # ]: 0 : if (rc != SHISHI_OK || tmplen != 20)
465 : 0 : return GSS_S_FAILURE;
466 : :
467 : 0 : memcpy (data + 8 + 8, t, tmplen);
468 : 0 : free (t);
469 : :
470 : : /* Compare checksum */
471 [ # # ][ # # ]: 0 : if (tmplen != 20 || memcmp (cksum, data + 8 + 8, 20) != 0)
472 : 0 : return GSS_S_BAD_MIC;
473 : :
474 : : /* Copy output data */
475 : 0 : output_message_buffer->length = tok.length - 8 - 20 - 8 - 8 - padlen;
476 : 0 : output_message_buffer->value = malloc (output_message_buffer->length);
477 [ # # ]: 0 : if (!output_message_buffer->value)
478 : : {
479 [ # # ]: 0 : if (minor_status)
480 : 0 : *minor_status = ENOMEM;
481 : 0 : return GSS_S_FAILURE;
482 : : }
483 : 0 : memcpy (output_message_buffer->value, data + 20 + 8 + 8 + 8,
484 : : tok.length - 20 - 8 - 8 - 8 - padlen);
485 : : }
486 : 0 : break;
487 : :
488 : : default:
489 : 0 : return GSS_S_FAILURE;
490 : : }
491 : :
492 : 3 : return GSS_S_COMPLETE;
493 : : }
|