Print this page
3882 remove xmod & friends
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/sasl_plugins/digestmd5/digestmd5.c
+++ new/usr/src/lib/sasl_plugins/digestmd5/digestmd5.c
1 1 /*
2 2 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
3 3 * Use is subject to license terms.
4 4 */
5 5
6 6 #pragma ident "%Z%%M% %I% %E% SMI"
7 7
8 8 /* DIGEST-MD5 SASL plugin
9 9 * Rob Siemborski
10 10 * Tim Martin
11 11 * Alexey Melnikov
12 12 * $Id: digestmd5.c,v 1.153 2003/03/30 22:17:06 leg Exp $
13 13 */
14 14 /*
15 15 * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved.
16 16 *
17 17 * Redistribution and use in source and binary forms, with or without
18 18 * modification, are permitted provided that the following conditions
19 19 * are met:
20 20 *
21 21 * 1. Redistributions of source code must retain the above copyright
22 22 * notice, this list of conditions and the following disclaimer.
23 23 *
24 24 * 2. Redistributions in binary form must reproduce the above copyright
25 25 * notice, this list of conditions and the following disclaimer in
26 26 * the documentation and/or other materials provided with the
27 27 * distribution.
28 28 *
29 29 * 3. The name "Carnegie Mellon University" must not be used to
30 30 * endorse or promote products derived from this software without
31 31 * prior written permission. For permission or any other legal
32 32 * details, please contact
33 33 * Office of Technology Transfer
34 34 * Carnegie Mellon University
35 35 * 5000 Forbes Avenue
36 36 * Pittsburgh, PA 15213-3890
37 37 * (412) 268-4387, fax: (412) 268-7395
38 38 * tech-transfer@andrew.cmu.edu
39 39 *
40 40 * 4. Redistributions of any form whatsoever must retain the following
41 41 * acknowledgment:
42 42 * "This product includes software developed by Computing Services
43 43 * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
44 44 *
45 45 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
46 46 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
47 47 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
48 48 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
49 49 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
50 50 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
51 51 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
52 52 */
53 53
54 54 #include <config.h>
55 55
↓ open down ↓ |
55 lines elided |
↑ open up ↑ |
56 56 #include <stdlib.h>
57 57 #include <stdio.h>
58 58 #include <string.h>
59 59 #ifndef macintosh
60 60 #include <sys/types.h>
61 61 #include <sys/stat.h>
62 62 #endif
63 63 #include <fcntl.h>
64 64 #include <ctype.h>
65 65
66 -/* EXPORT DELETE START */
67 66 /* DES support */
68 67 #ifdef WITH_DES
69 68 # ifdef WITH_SSL_DES
70 69 # include <openssl/des.h>
71 70 # else /* system DES library */
72 71 # include <des.h>
73 72 # endif
74 73 #endif /* WITH_DES */
75 -/* EXPORT DELETE END */
76 74
77 75 #ifdef WIN32
78 76 # include <winsock.h>
79 77 #else /* Unix */
80 78 # include <netinet/in.h>
81 79 #endif /* WIN32 */
82 80
83 81 #ifdef _SUN_SDK_
84 82 #include <unistd.h>
85 83 #endif /* _SUN_SDK_ */
86 84
87 85 #include <sasl.h>
88 86 #include <saslplug.h>
89 87
90 88 #include "plugin_common.h"
91 89
92 90 #if defined _SUN_SDK_ && defined USE_UEF
93 91 #include <security/cryptoki.h>
94 92 static int uef_init(const sasl_utils_t *utils);
95 93 #endif /* _SUN_SDK_ && USE_UEF */
96 94
97 95 #ifndef WIN32
98 96 extern int strcasecmp(const char *s1, const char *s2);
99 97 #endif /* end WIN32 */
100 98
101 99 #ifdef macintosh
102 100 #include <sasl_md5_plugin_decl.h>
103 101 #endif
104 102
105 103 /* external definitions */
106 104
107 105 #ifndef _SUN_SDK_
108 106 #ifdef sun
109 107 /* gotta define gethostname ourselves on suns */
110 108 extern int gethostname(char *, int);
111 109 #endif
112 110 #endif /* !_SUN_SDK_ */
113 111
114 112 #define bool int
115 113
116 114 #ifndef TRUE
117 115 #define TRUE (1)
118 116 #define FALSE (0)
119 117 #endif
120 118
121 119 #define DEFAULT_BUFSIZE 0xFFFF
122 120
123 121 /***************************** Common Section *****************************/
124 122
125 123 #ifndef _SUN_SDK_
126 124 static const char plugin_id[] = "$Id: digestmd5.c,v 1.153 2003/03/30 22:17:06 leg Exp $";
127 125 #endif /* !_SUN_SDK_ */
128 126
129 127 /* Definitions */
130 128 #define NONCE_SIZE (32) /* arbitrary */
131 129
132 130 /* Layer Flags */
133 131 #define DIGEST_NOLAYER (1)
134 132 #define DIGEST_INTEGRITY (2)
135 133 #define DIGEST_PRIVACY (4)
136 134
137 135 /* defines */
138 136 #define HASHLEN 16
139 137 typedef unsigned char HASH[HASHLEN + 1];
140 138 #define HASHHEXLEN 32
141 139 typedef unsigned char HASHHEX[HASHHEXLEN + 1];
142 140
143 141 #define MAC_SIZE 10
144 142 #define MAC_OFFS 2
145 143
146 144 const char *SEALING_CLIENT_SERVER="Digest H(A1) to client-to-server sealing key magic constant";
147 145 const char *SEALING_SERVER_CLIENT="Digest H(A1) to server-to-client sealing key magic constant";
148 146
149 147 const char *SIGNING_CLIENT_SERVER="Digest session key to client-to-server signing key magic constant";
150 148 const char *SIGNING_SERVER_CLIENT="Digest session key to server-to-client signing key magic constant";
151 149
152 150 #define HT (9)
153 151 #define CR (13)
154 152 #define LF (10)
155 153 #define SP (32)
156 154 #define DEL (127)
157 155
158 156 struct context;
159 157
160 158 /* function definitions for cipher encode/decode */
161 159 typedef int cipher_function_t(struct context *,
162 160 const char *,
163 161 unsigned,
164 162 unsigned char[],
165 163 char *,
166 164 unsigned *);
167 165
168 166 #ifdef _SUN_SDK_
169 167 typedef int cipher_init_t(struct context *, char [16],
170 168 char [16]);
171 169 #else
172 170 typedef int cipher_init_t(struct context *, unsigned char [16],
173 171 unsigned char [16]);
174 172 #endif /* _SUN_SDK_ */
175 173
176 174 typedef void cipher_free_t(struct context *);
177 175
178 176 enum Context_type { SERVER = 0, CLIENT = 1 };
179 177
180 178 typedef struct cipher_context cipher_context_t;
181 179
182 180 /* cached auth info used for fast reauth */
183 181 typedef struct reauth_entry {
184 182 char *authid;
185 183 char *realm;
186 184 unsigned char *nonce;
187 185 unsigned int nonce_count;
188 186 unsigned char *cnonce;
189 187
190 188 union {
191 189 struct {
192 190 time_t timestamp;
193 191 } s; /* server stuff */
194 192
195 193 struct {
196 194 char *serverFQDN;
197 195 int protection;
198 196 struct digest_cipher *cipher;
199 197 unsigned int server_maxbuf;
200 198 } c; /* client stuff */
201 199 } u;
202 200 } reauth_entry_t;
203 201
204 202 typedef struct reauth_cache {
205 203 /* static stuff */
206 204 enum Context_type i_am; /* are we the client or server? */
207 205 time_t timeout;
208 206 void *mutex;
209 207 size_t size;
210 208
211 209 reauth_entry_t *e; /* fixed-size hash table of entries */
212 210 } reauth_cache_t;
213 211
214 212 /* context that stores info */
215 213 typedef struct context {
216 214 int state; /* state in the authentication we are in */
217 215 enum Context_type i_am; /* are we the client or server? */
218 216
219 217 reauth_cache_t *reauth;
220 218
221 219 char *authid;
222 220 char *realm;
223 221 unsigned char *nonce;
224 222 unsigned int nonce_count;
225 223 unsigned char *cnonce;
226 224
227 225 char *response_value;
228 226
229 227 unsigned int seqnum;
230 228 unsigned int rec_seqnum; /* for checking integrity */
231 229
232 230 HASH Ki_send;
233 231 HASH Ki_receive;
234 232
235 233 HASH HA1; /* Kcc or Kcs */
236 234
237 235 /* copy of utils from the params structures */
238 236 const sasl_utils_t *utils;
239 237
240 238 /* For general use */
241 239 char *out_buf;
242 240 unsigned out_buf_len;
243 241
244 242 /* for encoding/decoding */
245 243 buffer_info_t *enc_in_buf;
246 244 char *encode_buf, *decode_buf, *decode_once_buf;
247 245 unsigned encode_buf_len, decode_buf_len, decode_once_buf_len;
248 246 char *decode_tmp_buf;
249 247 unsigned decode_tmp_buf_len;
250 248 char *MAC_buf;
251 249 unsigned MAC_buf_len;
252 250
253 251 char *buffer;
254 252 char sizebuf[4];
255 253 int cursize;
256 254
257 255 /* Layer info */
258 256 unsigned int size; /* Absolute size of buffer */
259 257 unsigned int needsize; /* How much of the size of the buffer is left */
260 258
261 259 /* Server MaxBuf for Client or Client MaxBuf For Server */
262 260 /* INCOMING */
263 261 unsigned int in_maxbuf;
264 262
265 263 /* if privacy mode is used use these functions for encode and decode */
266 264 cipher_function_t *cipher_enc;
267 265 cipher_function_t *cipher_dec;
268 266 cipher_init_t *cipher_init;
269 267 cipher_free_t *cipher_free;
270 268 struct cipher_context *cipher_enc_context;
271 269 struct cipher_context *cipher_dec_context;
272 270 } context_t;
273 271
274 272 struct digest_cipher {
275 273 char *name;
276 274 sasl_ssf_t ssf;
277 275 int n; /* bits to make privacy key */
278 276 int flag; /* a bitmask to make things easier for us */
279 277
280 278 cipher_function_t *cipher_enc;
281 279 cipher_function_t *cipher_dec;
282 280 cipher_init_t *cipher_init;
283 281 cipher_free_t *cipher_free;
284 282 };
285 283
286 284 #ifdef _SUN_SDK_
287 285 static const unsigned char *COLON = (unsigned char *)":";
288 286 #else
289 287 static const unsigned char *COLON = ":";
290 288 #endif /* _SUN_SDK_ */
291 289
292 290 /* Hashes a string to produce an unsigned short */
293 291 static unsigned hash(const char *str)
294 292 {
295 293 unsigned val = 0;
296 294 int i;
297 295
298 296 while (str && *str) {
299 297 i = (int) *str;
300 298 val ^= i;
301 299 val <<= 1;
302 300 str++;
303 301 }
304 302
305 303 return val;
306 304 }
307 305
308 306 static void CvtHex(HASH Bin, HASHHEX Hex)
309 307 {
310 308 unsigned short i;
311 309 unsigned char j;
312 310
313 311 for (i = 0; i < HASHLEN; i++) {
314 312 j = (Bin[i] >> 4) & 0xf;
315 313 if (j <= 9)
316 314 Hex[i * 2] = (j + '0');
317 315 else
318 316 Hex[i * 2] = (j + 'a' - 10);
319 317 j = Bin[i] & 0xf;
320 318 if (j <= 9)
321 319 Hex[i * 2 + 1] = (j + '0');
322 320 else
323 321 Hex[i * 2 + 1] = (j + 'a' - 10);
324 322 }
325 323 Hex[HASHHEXLEN] = '\0';
326 324 }
327 325
328 326 /*
329 327 * calculate request-digest/response-digest as per HTTP Digest spec
330 328 */
331 329 void
332 330 DigestCalcResponse(const sasl_utils_t * utils,
333 331 HASHHEX HA1, /* H(A1) */
334 332 unsigned char *pszNonce, /* nonce from server */
335 333 unsigned int pszNonceCount, /* 8 hex digits */
336 334 unsigned char *pszCNonce, /* client nonce */
337 335 unsigned char *pszQop, /* qop-value: "", "auth",
338 336 * "auth-int" */
339 337 unsigned char *pszDigestUri, /* requested URL */
340 338 unsigned char *pszMethod,
341 339 HASHHEX HEntity, /* H(entity body) if qop="auth-int" */
342 340 HASHHEX Response /* request-digest or response-digest */
343 341 )
344 342 {
345 343 MD5_CTX Md5Ctx;
346 344 HASH HA2;
347 345 HASH RespHash;
348 346 HASHHEX HA2Hex;
349 347 char ncvalue[10];
350 348
351 349 /* calculate H(A2) */
352 350 utils->MD5Init(&Md5Ctx);
353 351
354 352 if (pszMethod != NULL) {
355 353 utils->MD5Update(&Md5Ctx, pszMethod, strlen((char *) pszMethod));
356 354 }
357 355 utils->MD5Update(&Md5Ctx, (unsigned char *) COLON, 1);
358 356
359 357 /* utils->MD5Update(&Md5Ctx, (unsigned char *) "AUTHENTICATE:", 13); */
360 358 utils->MD5Update(&Md5Ctx, pszDigestUri, strlen((char *) pszDigestUri));
361 359 if (strcasecmp((char *) pszQop, "auth") != 0) {
362 360 /* append ":00000000000000000000000000000000" */
363 361 utils->MD5Update(&Md5Ctx, COLON, 1);
364 362 utils->MD5Update(&Md5Ctx, HEntity, HASHHEXLEN);
365 363 }
366 364 utils->MD5Final(HA2, &Md5Ctx);
367 365 CvtHex(HA2, HA2Hex);
368 366
369 367 /* calculate response */
370 368 utils->MD5Init(&Md5Ctx);
371 369 utils->MD5Update(&Md5Ctx, HA1, HASHHEXLEN);
372 370 utils->MD5Update(&Md5Ctx, COLON, 1);
373 371 utils->MD5Update(&Md5Ctx, pszNonce, strlen((char *) pszNonce));
374 372 utils->MD5Update(&Md5Ctx, COLON, 1);
375 373 if (*pszQop) {
376 374 sprintf(ncvalue, "%08x", pszNonceCount);
377 375 #ifdef _SUN_SDK_
378 376 utils->MD5Update(&Md5Ctx, (unsigned char *)ncvalue, strlen(ncvalue));
379 377 #else
380 378 utils->MD5Update(&Md5Ctx, ncvalue, strlen(ncvalue));
381 379 #endif /* _SUN_SDK_ */
382 380 utils->MD5Update(&Md5Ctx, COLON, 1);
383 381 utils->MD5Update(&Md5Ctx, pszCNonce, strlen((char *) pszCNonce));
384 382 utils->MD5Update(&Md5Ctx, COLON, 1);
385 383 utils->MD5Update(&Md5Ctx, pszQop, strlen((char *) pszQop));
386 384 utils->MD5Update(&Md5Ctx, COLON, 1);
387 385 }
388 386 utils->MD5Update(&Md5Ctx, HA2Hex, HASHHEXLEN);
389 387 utils->MD5Final(RespHash, &Md5Ctx);
390 388 CvtHex(RespHash, Response);
391 389 }
392 390
393 391 static bool UTF8_In_8859_1(const unsigned char *base, int len)
394 392 {
395 393 const unsigned char *scan, *end;
396 394
397 395 end = base + len;
398 396 for (scan = base; scan < end; ++scan) {
399 397 if (*scan > 0xC3)
400 398 break; /* abort if outside 8859-1 */
401 399 if (*scan >= 0xC0 && *scan <= 0xC3) {
402 400 if (++scan == end || *scan < 0x80 || *scan > 0xBF)
403 401 break;
404 402 }
405 403 }
406 404
407 405 /* if scan >= end, then this is a 8859-1 string. */
408 406 return (scan >= end);
409 407 }
410 408
411 409 /*
412 410 * if the string is entirely in the 8859-1 subset of UTF-8, then translate to
413 411 * 8859-1 prior to MD5
414 412 */
415 413 void MD5_UTF8_8859_1(const sasl_utils_t * utils,
416 414 MD5_CTX * ctx,
417 415 bool In_ISO_8859_1,
418 416 const unsigned char *base,
419 417 int len)
420 418 {
421 419 const unsigned char *scan, *end;
422 420 unsigned char cbuf;
423 421
424 422 end = base + len;
425 423
426 424 /* if we found a character outside 8859-1, don't alter string */
427 425 if (!In_ISO_8859_1) {
428 426 utils->MD5Update(ctx, base, len);
429 427 return;
430 428 }
431 429 /* convert to 8859-1 prior to applying hash */
432 430 do {
433 431 for (scan = base; scan < end && *scan < 0xC0; ++scan);
434 432 if (scan != base)
435 433 utils->MD5Update(ctx, base, scan - base);
436 434 if (scan + 1 >= end)
437 435 break;
438 436 cbuf = ((scan[0] & 0x3) << 6) | (scan[1] & 0x3f);
439 437 utils->MD5Update(ctx, &cbuf, 1);
440 438 base = scan + 2;
441 439 }
442 440 while (base < end);
443 441 }
444 442
445 443 static void DigestCalcSecret(const sasl_utils_t * utils,
446 444 unsigned char *pszUserName,
447 445 unsigned char *pszRealm,
448 446 unsigned char *Password,
449 447 int PasswordLen,
450 448 HASH HA1)
451 449 {
452 450 bool In_8859_1;
453 451
454 452 MD5_CTX Md5Ctx;
455 453
456 454 /* Chris Newman clarified that the following text in DIGEST-MD5 spec
457 455 is bogus: "if name and password are both in ISO 8859-1 charset"
458 456 We shoud use code example instead */
459 457
460 458 utils->MD5Init(&Md5Ctx);
461 459
462 460 /* We have to convert UTF-8 to ISO-8859-1 if possible */
463 461 In_8859_1 = UTF8_In_8859_1(pszUserName, strlen((char *) pszUserName));
464 462 MD5_UTF8_8859_1(utils, &Md5Ctx, In_8859_1,
465 463 pszUserName, strlen((char *) pszUserName));
466 464
467 465 utils->MD5Update(&Md5Ctx, COLON, 1);
468 466
469 467 if (pszRealm != NULL && pszRealm[0] != '\0') {
470 468 /* a NULL realm is equivalent to the empty string */
471 469 utils->MD5Update(&Md5Ctx, pszRealm, strlen((char *) pszRealm));
472 470 }
473 471
474 472 utils->MD5Update(&Md5Ctx, COLON, 1);
475 473
476 474 /* We have to convert UTF-8 to ISO-8859-1 if possible */
477 475 In_8859_1 = UTF8_In_8859_1(Password, PasswordLen);
478 476 MD5_UTF8_8859_1(utils, &Md5Ctx, In_8859_1,
479 477 Password, PasswordLen);
480 478
481 479 utils->MD5Final(HA1, &Md5Ctx);
482 480 }
483 481
484 482 static unsigned char *create_nonce(const sasl_utils_t * utils)
485 483 {
486 484 unsigned char *base64buf;
487 485 int base64len;
488 486
489 487 char *ret = (char *) utils->malloc(NONCE_SIZE);
490 488 if (ret == NULL)
491 489 return NULL;
492 490
493 491 #if defined _DEV_URANDOM && defined _SUN_SDK_
494 492 {
495 493 int fd = open(_DEV_URANDOM, O_RDONLY);
496 494 int nread = 0;
497 495
498 496 if (fd != -1) {
499 497 nread = read(fd, ret, NONCE_SIZE);
500 498 close(fd);
501 499 }
502 500 if (nread != NONCE_SIZE)
503 501 utils->rand(utils->rpool, (char *) ret, NONCE_SIZE);
504 502 }
505 503 #else
506 504 utils->rand(utils->rpool, (char *) ret, NONCE_SIZE);
507 505 #endif /* _DEV_URANDOM && _SUN_SDK_ */
508 506
509 507 /* base 64 encode it so it has valid chars */
510 508 base64len = (NONCE_SIZE * 4 / 3) + (NONCE_SIZE % 3 ? 4 : 0);
511 509
512 510 base64buf = (unsigned char *) utils->malloc(base64len + 1);
513 511 if (base64buf == NULL) {
514 512 #ifdef _SUN_SDK_
515 513 utils->log(utils->conn, SASL_LOG_ERR,
516 514 "Unable to allocate final buffer");
517 515 #else
518 516 utils->seterror(utils->conn, 0, "Unable to allocate final buffer");
519 517 #endif /* _SUN_SDK_ */
520 518 return NULL;
521 519 }
522 520
523 521 /*
524 522 * Returns SASL_OK on success, SASL_BUFOVER if result won't fit
525 523 */
526 524 if (utils->encode64(ret, NONCE_SIZE,
527 525 (char *) base64buf, base64len, NULL) != SASL_OK) {
528 526 utils->free(ret);
529 527 return NULL;
530 528 }
531 529 utils->free(ret);
532 530
533 531 return base64buf;
534 532 }
535 533
536 534 static int add_to_challenge(const sasl_utils_t *utils,
537 535 char **str, unsigned *buflen, unsigned *curlen,
538 536 char *name,
539 537 unsigned char *value,
540 538 bool need_quotes)
541 539 {
542 540 int namesize = strlen(name);
543 541 int valuesize = strlen((char *) value);
544 542 int ret;
545 543
546 544 ret = _plug_buf_alloc(utils, str, buflen,
547 545 *curlen + 1 + namesize + 2 + valuesize + 2);
548 546 if(ret != SASL_OK) return ret;
549 547
550 548 *curlen = *curlen + 1 + namesize + 2 + valuesize + 2;
551 549
552 550 strcat(*str, ",");
553 551 strcat(*str, name);
554 552
555 553 if (need_quotes) {
556 554 strcat(*str, "=\"");
557 555 strcat(*str, (char *) value); /* XXX. What about quoting??? */
558 556 strcat(*str, "\"");
559 557 } else {
560 558 strcat(*str, "=");
561 559 strcat(*str, (char *) value);
562 560 }
563 561
564 562 return SASL_OK;
565 563 }
566 564
567 565 static char *skip_lws (char *s)
568 566 {
569 567 if(!s) return NULL;
570 568
571 569 /* skipping spaces: */
572 570 while (s[0] == ' ' || s[0] == HT || s[0] == CR || s[0] == LF) {
573 571 if (s[0]=='\0') break;
574 572 s++;
575 573 }
576 574
577 575 return s;
578 576 }
579 577
580 578 #ifdef __SUN_SDK_
581 579 static char *skip_token (char *s, int caseinsensitive __attribute__((unused)))
582 580 #else
583 581 static char *skip_token (char *s, int caseinsensitive)
584 582 #endif /* _SUN_SDK_ */
585 583 {
586 584 if(!s) return NULL;
587 585
588 586 #ifdef __SUN_SDK_
589 587 while (((unsigned char *)s)[0]>SP) {
590 588 #else
591 589 while (s[0]>SP) {
592 590 #endif /* _SUN_SDK_ */
593 591 if (s[0]==DEL || s[0]=='(' || s[0]==')' || s[0]=='<' || s[0]=='>' ||
594 592 s[0]=='@' || s[0]==',' || s[0]==';' || s[0]==':' || s[0]=='\\' ||
595 593 s[0]=='\'' || s[0]=='/' || s[0]=='[' || s[0]==']' || s[0]== '?' ||
596 594 s[0]=='=' || s[0]== '{' || s[0]== '}') {
597 595 #ifdef __SUN_SDK_
598 596 /* the above chars are never uppercase */
599 597 break;
600 598 #else
601 599 if (caseinsensitive == 1) {
602 600 if (!isupper((unsigned char) s[0]))
603 601 break;
604 602 } else {
605 603 break;
606 604 }
607 605 #endif /* _SUN_SDK_ */
608 606 }
609 607 s++;
610 608 }
611 609 return s;
612 610 }
613 611
614 612 /* NULL - error (unbalanced quotes),
615 613 otherwise pointer to the first character after value */
616 614 static char *unquote (char *qstr)
617 615 {
618 616 char *endvalue;
619 617 int escaped = 0;
620 618 char *outptr;
621 619
622 620 if(!qstr) return NULL;
623 621
624 622 if (qstr[0] == '"') {
625 623 qstr++;
626 624 outptr = qstr;
627 625
628 626 for (endvalue = qstr; endvalue[0] != '\0'; endvalue++, outptr++) {
629 627 if (escaped) {
630 628 outptr[0] = endvalue[0];
631 629 escaped = 0;
632 630 }
633 631 else if (endvalue[0] == '\\') {
634 632 escaped = 1;
635 633 outptr--; /* Will be incremented at the end of the loop */
636 634 }
637 635 else if (endvalue[0] == '"') {
638 636 break;
639 637 }
640 638 else {
641 639 outptr[0] = endvalue[0];
642 640 }
643 641 }
644 642
645 643 if (endvalue[0] != '"') {
646 644 return NULL;
647 645 }
648 646
649 647 while (outptr <= endvalue) {
650 648 outptr[0] = '\0';
651 649 outptr++;
652 650 }
653 651 endvalue++;
654 652 }
655 653 else { /* not qouted value (token) */
656 654 endvalue = skip_token(qstr,0);
657 655 };
658 656
659 657 return endvalue;
660 658 }
661 659
662 660 static void get_pair(char **in, char **name, char **value)
663 661 {
664 662 char *endpair;
665 663 /* int inQuotes; */
666 664 char *curp = *in;
667 665 *name = NULL;
668 666 *value = NULL;
669 667
670 668 if (curp == NULL) return;
671 669 if (curp[0] == '\0') return;
672 670
673 671 /* skipping spaces: */
674 672 curp = skip_lws(curp);
675 673
676 674 *name = curp;
677 675
678 676 curp = skip_token(curp,1);
679 677
680 678 /* strip wierd chars */
681 679 if (curp[0] != '=' && curp[0] != '\0') {
682 680 *curp++ = '\0';
683 681 };
684 682
685 683 curp = skip_lws(curp);
686 684
687 685 if (curp[0] != '=') { /* No '=' sign */
688 686 *name = NULL;
689 687 return;
690 688 }
691 689
692 690 curp[0] = '\0';
693 691 curp++;
694 692
695 693 curp = skip_lws(curp);
696 694
697 695 *value = (curp[0] == '"') ? curp+1 : curp;
698 696
699 697 endpair = unquote (curp);
700 698 if (endpair == NULL) { /* Unbalanced quotes */
701 699 *name = NULL;
702 700 return;
703 701 }
704 702 if (endpair[0] != ',') {
705 703 if (endpair[0]!='\0') {
706 704 *endpair++ = '\0';
707 705 }
708 706 }
709 707
710 708 endpair = skip_lws(endpair);
711 709
712 710 /* syntax check: MUST be '\0' or ',' */
713 711 if (endpair[0] == ',') {
↓ open down ↓ |
628 lines elided |
↑ open up ↑ |
714 712 endpair[0] = '\0';
715 713 endpair++; /* skipping <,> */
716 714 } else if (endpair[0] != '\0') {
717 715 *name = NULL;
718 716 return;
719 717 }
720 718
721 719 *in = endpair;
722 720 }
723 721
724 -/* EXPORT DELETE START */
725 722 #ifdef WITH_DES
726 723 struct des_context_s {
727 724 des_key_schedule keysched; /* key schedule for des initialization */
728 725 des_cblock ivec; /* initial vector for encoding */
729 726 des_key_schedule keysched2; /* key schedule for 3des initialization */
730 727 };
731 728
732 729 typedef struct des_context_s des_context_t;
733 730
734 731 /* slide the first 7 bytes of 'inbuf' into the high seven bits of the
735 732 first 8 bytes of 'keybuf'. 'keybuf' better be 8 bytes long or longer. */
736 733 static void slidebits(unsigned char *keybuf, unsigned char *inbuf)
737 734 {
738 735 keybuf[0] = inbuf[0];
739 736 keybuf[1] = (inbuf[0]<<7) | (inbuf[1]>>1);
740 737 keybuf[2] = (inbuf[1]<<6) | (inbuf[2]>>2);
741 738 keybuf[3] = (inbuf[2]<<5) | (inbuf[3]>>3);
742 739 keybuf[4] = (inbuf[3]<<4) | (inbuf[4]>>4);
743 740 keybuf[5] = (inbuf[4]<<3) | (inbuf[5]>>5);
744 741 keybuf[6] = (inbuf[5]<<2) | (inbuf[6]>>6);
745 742 keybuf[7] = (inbuf[6]<<1);
746 743 }
747 744
748 745 /******************************
749 746 *
750 747 * 3DES functions
751 748 *
752 749 *****************************/
753 750
754 751 static int dec_3des(context_t *text,
755 752 const char *input,
756 753 unsigned inputlen,
757 754 unsigned char digest[16],
758 755 char *output,
759 756 unsigned *outputlen)
760 757 {
761 758 des_context_t *c = (des_context_t *) text->cipher_dec_context;
762 759 int padding, p;
763 760
764 761 des_ede2_cbc_encrypt((void *) input,
765 762 (void *) output,
766 763 inputlen,
767 764 c->keysched,
768 765 c->keysched2,
769 766 &c->ivec,
770 767 DES_DECRYPT);
771 768
772 769 /* now chop off the padding */
773 770 padding = output[inputlen - 11];
774 771 if (padding < 1 || padding > 8) {
775 772 /* invalid padding length */
776 773 return SASL_FAIL;
777 774 }
778 775 /* verify all padding is correct */
779 776 for (p = 1; p <= padding; p++) {
780 777 if (output[inputlen - 10 - p] != padding) {
781 778 return SASL_FAIL;
782 779 }
783 780 }
784 781
785 782 /* chop off the padding */
786 783 *outputlen = inputlen - padding - 10;
787 784
788 785 /* copy in the HMAC to digest */
789 786 memcpy(digest, output + inputlen - 10, 10);
790 787
791 788 return SASL_OK;
792 789 }
793 790
794 791 static int enc_3des(context_t *text,
795 792 const char *input,
796 793 unsigned inputlen,
797 794 unsigned char digest[16],
798 795 char *output,
799 796 unsigned *outputlen)
800 797 {
801 798 des_context_t *c = (des_context_t *) text->cipher_enc_context;
802 799 int len;
803 800 int paddinglen;
804 801
805 802 /* determine padding length */
806 803 paddinglen = 8 - ((inputlen + 10) % 8);
807 804
808 805 /* now construct the full stuff to be ciphered */
809 806 memcpy(output, input, inputlen); /* text */
810 807 memset(output+inputlen, paddinglen, paddinglen);/* pad */
811 808 memcpy(output+inputlen+paddinglen, digest, 10); /* hmac */
812 809
813 810 len=inputlen+paddinglen+10;
814 811
815 812 des_ede2_cbc_encrypt((void *) output,
816 813 (void *) output,
817 814 len,
818 815 c->keysched,
819 816 c->keysched2,
820 817 &c->ivec,
821 818 DES_ENCRYPT);
822 819
823 820 *outputlen=len;
824 821
825 822 return SASL_OK;
826 823 }
827 824
828 825 static int init_3des(context_t *text,
829 826 unsigned char enckey[16],
830 827 unsigned char deckey[16])
831 828 {
832 829 des_context_t *c;
833 830 unsigned char keybuf[8];
834 831
835 832 /* allocate enc & dec context */
836 833 c = (des_context_t *) text->utils->malloc(2 * sizeof(des_context_t));
837 834 if (c == NULL) return SASL_NOMEM;
838 835
839 836 /* setup enc context */
840 837 slidebits(keybuf, enckey);
841 838 if (des_key_sched((des_cblock *) keybuf, c->keysched) < 0)
842 839 return SASL_FAIL;
843 840
844 841 slidebits(keybuf, enckey + 7);
845 842 if (des_key_sched((des_cblock *) keybuf, c->keysched2) < 0)
846 843 return SASL_FAIL;
847 844 memcpy(c->ivec, ((char *) enckey) + 8, 8);
848 845
849 846 text->cipher_enc_context = (cipher_context_t *) c;
850 847
851 848 /* setup dec context */
852 849 c++;
853 850 slidebits(keybuf, deckey);
854 851 if (des_key_sched((des_cblock *) keybuf, c->keysched) < 0)
855 852 return SASL_FAIL;
856 853
857 854 slidebits(keybuf, deckey + 7);
858 855 if (des_key_sched((des_cblock *) keybuf, c->keysched2) < 0)
859 856 return SASL_FAIL;
860 857
861 858 memcpy(c->ivec, ((char *) deckey) + 8, 8);
862 859
863 860 text->cipher_dec_context = (cipher_context_t *) c;
864 861
865 862 return SASL_OK;
866 863 }
867 864
868 865
869 866 /******************************
870 867 *
871 868 * DES functions
872 869 *
873 870 *****************************/
874 871
875 872 static int dec_des(context_t *text,
876 873 const char *input,
877 874 unsigned inputlen,
878 875 unsigned char digest[16],
879 876 char *output,
880 877 unsigned *outputlen)
881 878 {
882 879 des_context_t *c = (des_context_t *) text->cipher_dec_context;
883 880 int p, padding = 0;
884 881
885 882 des_cbc_encrypt((void *) input,
886 883 (void *) output,
887 884 inputlen,
888 885 c->keysched,
889 886 &c->ivec,
890 887 DES_DECRYPT);
891 888
892 889 /* Update the ivec (des_cbc_encrypt implementations tend to be broken in
893 890 this way) */
894 891 memcpy(c->ivec, input + (inputlen - 8), 8);
895 892
896 893 /* now chop off the padding */
897 894 padding = output[inputlen - 11];
898 895 if (padding < 1 || padding > 8) {
899 896 /* invalid padding length */
900 897 return SASL_FAIL;
901 898 }
902 899 /* verify all padding is correct */
903 900 for (p = 1; p <= padding; p++) {
904 901 if (output[inputlen - 10 - p] != padding) {
905 902 return SASL_FAIL;
906 903 }
907 904 }
908 905
909 906 /* chop off the padding */
910 907 *outputlen = inputlen - padding - 10;
911 908
912 909 /* copy in the HMAC to digest */
913 910 memcpy(digest, output + inputlen - 10, 10);
914 911
915 912 return SASL_OK;
916 913 }
917 914
918 915 static int enc_des(context_t *text,
919 916 const char *input,
920 917 unsigned inputlen,
921 918 unsigned char digest[16],
922 919 char *output,
923 920 unsigned *outputlen)
924 921 {
925 922 des_context_t *c = (des_context_t *) text->cipher_enc_context;
926 923 int len;
927 924 int paddinglen;
928 925
929 926 /* determine padding length */
930 927 paddinglen = 8 - ((inputlen+10) % 8);
931 928
932 929 /* now construct the full stuff to be ciphered */
933 930 memcpy(output, input, inputlen); /* text */
934 931 memset(output+inputlen, paddinglen, paddinglen);/* pad */
935 932 memcpy(output+inputlen+paddinglen, digest, 10); /* hmac */
936 933
937 934 len = inputlen + paddinglen + 10;
938 935
939 936 des_cbc_encrypt((void *) output,
940 937 (void *) output,
941 938 len,
942 939 c->keysched,
943 940 &c->ivec,
944 941 DES_ENCRYPT);
945 942
946 943 /* Update the ivec (des_cbc_encrypt implementations tend to be broken in
947 944 this way) */
948 945 memcpy(c->ivec, output + (len - 8), 8);
949 946
950 947 *outputlen = len;
951 948
952 949 return SASL_OK;
953 950 }
954 951
955 952 static int init_des(context_t *text,
956 953 unsigned char enckey[16],
957 954 unsigned char deckey[16])
958 955 {
959 956 des_context_t *c;
960 957 unsigned char keybuf[8];
961 958
962 959 /* allocate enc context */
963 960 c = (des_context_t *) text->utils->malloc(2 * sizeof(des_context_t));
964 961 if (c == NULL) return SASL_NOMEM;
965 962
966 963 /* setup enc context */
967 964 slidebits(keybuf, enckey);
968 965 des_key_sched((des_cblock *) keybuf, c->keysched);
969 966
970 967 memcpy(c->ivec, ((char *) enckey) + 8, 8);
971 968
972 969 text->cipher_enc_context = (cipher_context_t *) c;
973 970
974 971 /* setup dec context */
975 972 c++;
976 973 slidebits(keybuf, deckey);
977 974 des_key_sched((des_cblock *) keybuf, c->keysched);
978 975
979 976 memcpy(c->ivec, ((char *) deckey) + 8, 8);
980 977
981 978 text->cipher_dec_context = (cipher_context_t *) c;
982 979
983 980 return SASL_OK;
984 981 }
985 982
986 983 static void free_des(context_t *text)
987 984 {
988 985 /* free des contextss. only cipher_enc_context needs to be free'd,
989 986 since cipher_dec_context was allocated at the same time. */
990 987 if (text->cipher_enc_context) text->utils->free(text->cipher_enc_context);
991 988 }
992 989
993 990 #endif /* WITH_DES */
994 991
995 992 #ifdef WITH_RC4
996 993 /* quick generic implementation of RC4 */
997 994 struct rc4_context_s {
998 995 unsigned char sbox[256];
999 996 int i, j;
1000 997 };
1001 998
1002 999 typedef struct rc4_context_s rc4_context_t;
1003 1000
1004 1001 static void rc4_init(rc4_context_t *text,
1005 1002 const unsigned char *key,
1006 1003 unsigned keylen)
1007 1004 {
1008 1005 int i, j;
1009 1006
1010 1007 /* fill in linearly s0=0 s1=1... */
1011 1008 for (i=0;i<256;i++)
1012 1009 text->sbox[i]=i;
1013 1010
1014 1011 j=0;
1015 1012 for (i = 0; i < 256; i++) {
1016 1013 unsigned char tmp;
1017 1014 /* j = (j + Si + Ki) mod 256 */
1018 1015 j = (j + text->sbox[i] + key[i % keylen]) % 256;
1019 1016
1020 1017 /* swap Si and Sj */
1021 1018 tmp = text->sbox[i];
1022 1019 text->sbox[i] = text->sbox[j];
1023 1020 text->sbox[j] = tmp;
1024 1021 }
1025 1022
1026 1023 /* counters initialized to 0 */
1027 1024 text->i = 0;
1028 1025 text->j = 0;
1029 1026 }
1030 1027
1031 1028 static void rc4_encrypt(rc4_context_t *text,
1032 1029 const char *input,
1033 1030 char *output,
1034 1031 unsigned len)
1035 1032 {
1036 1033 int tmp;
1037 1034 int i = text->i;
1038 1035 int j = text->j;
1039 1036 int t;
1040 1037 int K;
1041 1038 const char *input_end = input + len;
1042 1039
1043 1040 while (input < input_end) {
1044 1041 i = (i + 1) % 256;
1045 1042
1046 1043 j = (j + text->sbox[i]) % 256;
1047 1044
1048 1045 /* swap Si and Sj */
1049 1046 tmp = text->sbox[i];
1050 1047 text->sbox[i] = text->sbox[j];
1051 1048 text->sbox[j] = tmp;
1052 1049
1053 1050 t = (text->sbox[i] + text->sbox[j]) % 256;
1054 1051
1055 1052 K = text->sbox[t];
1056 1053
1057 1054 /* byte K is Xor'ed with plaintext */
1058 1055 *output++ = *input++ ^ K;
1059 1056 }
1060 1057
1061 1058 text->i = i;
1062 1059 text->j = j;
1063 1060 }
1064 1061
1065 1062 static void rc4_decrypt(rc4_context_t *text,
1066 1063 const char *input,
1067 1064 char *output,
1068 1065 unsigned len)
1069 1066 {
1070 1067 int tmp;
1071 1068 int i = text->i;
1072 1069 int j = text->j;
1073 1070 int t;
1074 1071 int K;
1075 1072 const char *input_end = input + len;
1076 1073
1077 1074 while (input < input_end) {
1078 1075 i = (i + 1) % 256;
1079 1076
1080 1077 j = (j + text->sbox[i]) % 256;
1081 1078
1082 1079 /* swap Si and Sj */
1083 1080 tmp = text->sbox[i];
1084 1081 text->sbox[i] = text->sbox[j];
1085 1082 text->sbox[j] = tmp;
1086 1083
1087 1084 t = (text->sbox[i] + text->sbox[j]) % 256;
1088 1085
1089 1086 K = text->sbox[t];
1090 1087
1091 1088 /* byte K is Xor'ed with plaintext */
1092 1089 *output++ = *input++ ^ K;
1093 1090 }
1094 1091
1095 1092 text->i = i;
1096 1093 text->j = j;
1097 1094 }
1098 1095
1099 1096 static void free_rc4(context_t *text)
1100 1097 {
1101 1098 /* free rc4 context structures */
1102 1099
1103 1100 if(text->cipher_enc_context) text->utils->free(text->cipher_enc_context);
1104 1101 if(text->cipher_dec_context) text->utils->free(text->cipher_dec_context);
1105 1102 #ifdef _SUN_SDK_
1106 1103 text->cipher_enc_context = NULL;
1107 1104 text->cipher_dec_context = NULL;
1108 1105 #endif /* _SUN_SDK_ */
1109 1106 }
1110 1107
1111 1108 static int init_rc4(context_t *text,
1112 1109 #ifdef _SUN_SDK_
1113 1110 char enckey[16],
1114 1111 char deckey[16])
1115 1112 #else
1116 1113 unsigned char enckey[16],
1117 1114 unsigned char deckey[16])
1118 1115 #endif /* _SUN_SDK_ */
1119 1116 {
1120 1117 /* allocate rc4 context structures */
1121 1118 text->cipher_enc_context=
1122 1119 (cipher_context_t *) text->utils->malloc(sizeof(rc4_context_t));
1123 1120 if (text->cipher_enc_context == NULL) return SASL_NOMEM;
1124 1121
1125 1122 text->cipher_dec_context=
1126 1123 (cipher_context_t *) text->utils->malloc(sizeof(rc4_context_t));
1127 1124 #ifdef _SUN_SDK_
1128 1125 if (text->cipher_dec_context == NULL) {
1129 1126 text->utils->free(text->cipher_enc_context);
1130 1127 text->cipher_enc_context = NULL;
1131 1128 return SASL_NOMEM;
1132 1129 }
1133 1130 #else
1134 1131 if (text->cipher_dec_context == NULL) return SASL_NOMEM;
1135 1132 #endif /* _SUN_SDK_ */
1136 1133
1137 1134 /* initialize them */
1138 1135 rc4_init((rc4_context_t *) text->cipher_enc_context,
1139 1136 (const unsigned char *) enckey, 16);
1140 1137 rc4_init((rc4_context_t *) text->cipher_dec_context,
1141 1138 (const unsigned char *) deckey, 16);
1142 1139
1143 1140 return SASL_OK;
1144 1141 }
1145 1142
1146 1143 static int dec_rc4(context_t *text,
1147 1144 const char *input,
1148 1145 unsigned inputlen,
1149 1146 unsigned char digest[16],
1150 1147 char *output,
1151 1148 unsigned *outputlen)
1152 1149 {
1153 1150 /* decrypt the text part */
1154 1151 rc4_decrypt((rc4_context_t *) text->cipher_dec_context,
1155 1152 input, output, inputlen-10);
1156 1153
1157 1154 /* decrypt the HMAC part */
1158 1155 rc4_decrypt((rc4_context_t *) text->cipher_dec_context,
1159 1156 input+(inputlen-10), (char *) digest, 10);
1160 1157
1161 1158 /* no padding so we just subtract the HMAC to get the text length */
1162 1159 *outputlen = inputlen - 10;
1163 1160
1164 1161 return SASL_OK;
1165 1162 }
1166 1163
1167 1164 static int enc_rc4(context_t *text,
1168 1165 const char *input,
1169 1166 unsigned inputlen,
1170 1167 unsigned char digest[16],
1171 1168 char *output,
1172 1169 unsigned *outputlen)
1173 1170 {
1174 1171 /* pad is zero */
1175 1172 *outputlen = inputlen+10;
1176 1173
1177 1174 /* encrypt the text part */
1178 1175 rc4_encrypt((rc4_context_t *) text->cipher_enc_context,
1179 1176 input,
1180 1177 output,
1181 1178 inputlen);
↓ open down ↓ |
447 lines elided |
↑ open up ↑ |
1182 1179
1183 1180 /* encrypt the HMAC part */
1184 1181 rc4_encrypt((rc4_context_t *) text->cipher_enc_context,
1185 1182 (const char *) digest,
1186 1183 (output)+inputlen, 10);
1187 1184
1188 1185 return SASL_OK;
1189 1186 }
1190 1187
1191 1188 #endif /* WITH_RC4 */
1192 -/* EXPORT DELETE END */
1193 1189
1194 1190 struct digest_cipher available_ciphers[] =
1195 1191 {
1196 - /* EXPORT DELETE START */
1197 1192 #ifdef WITH_RC4
1198 1193 { "rc4-40", 40, 5, 0x01, &enc_rc4, &dec_rc4, &init_rc4, &free_rc4 },
1199 1194 { "rc4-56", 56, 7, 0x02, &enc_rc4, &dec_rc4, &init_rc4, &free_rc4 },
1200 1195 { "rc4", 128, 16, 0x04, &enc_rc4, &dec_rc4, &init_rc4, &free_rc4 },
1201 1196 #endif
1202 1197 #ifdef WITH_DES
1203 1198 { "des", 55, 16, 0x08, &enc_des, &dec_des, &init_des, &free_des },
1204 1199 { "3des", 112, 16, 0x10, &enc_3des, &dec_3des, &init_3des, &free_des },
1205 1200 #endif
1206 - /* EXPORT DELETE END */
1207 1201 { NULL, 0, 0, 0, NULL, NULL, NULL, NULL }
1208 1202 };
1209 1203
1210 1204
1211 1205 #ifdef USE_UEF
1212 1206 DEFINE_STATIC_MUTEX(uef_init_mutex);
1213 1207 #define DES_CIPHER_INDEX 3
1214 1208 #define DES3_CIPHER_INDEX 4
1215 1209
1216 1210 static int got_uef_slot = FALSE;
1217 1211 static sasl_ssf_t uef_max_ssf = 0;
1218 1212 static CK_SLOT_ID rc4_slot_id;
1219 1213 static CK_SLOT_ID des_slot_id;
1220 1214 static CK_SLOT_ID des3_slot_id;
1221 1215
1222 1216 struct uef_context_s {
1223 1217 CK_SESSION_HANDLE hSession;
1224 1218 CK_OBJECT_HANDLE hKey;
1225 1219 };
1226 1220
1227 1221 typedef struct uef_context_s uef_context_t;
1228 1222
1229 1223 /*
1230 1224 * slide the first 7 bytes of 'inbuf' into the high seven bits of the
1231 1225 * first 8 bytes of 'keybuf'. 'inbuf' better be 8 bytes long or longer.
1232 1226 *
1233 1227 * This is used to compute the IV for "des" and "3des" as described in
1234 1228 * draft-ietf-sasl-rfc2831bis-00.txt - The IV for "des"
1235 1229 * and "3des" is the last 8 bytes of Kcc or Kcs - the encryption keys.
1236 1230 */
1237 1231
1238 1232 static void slidebits(unsigned char *keybuf, unsigned char *inbuf)
1239 1233 {
1240 1234 keybuf[0] = inbuf[0];
1241 1235 keybuf[1] = (inbuf[0]<<7) | (inbuf[1]>>1);
1242 1236 keybuf[2] = (inbuf[1]<<6) | (inbuf[2]>>2);
1243 1237 keybuf[3] = (inbuf[2]<<5) | (inbuf[3]>>3);
1244 1238 keybuf[4] = (inbuf[3]<<4) | (inbuf[4]>>4);
1245 1239 keybuf[5] = (inbuf[4]<<3) | (inbuf[5]>>5);
1246 1240 keybuf[6] = (inbuf[5]<<2) | (inbuf[6]>>6);
1247 1241 keybuf[7] = (inbuf[6]<<1);
1248 1242 }
1249 1243
1250 1244 /*
1251 1245 * Create encryption and decryption session handle handles for later use.
1252 1246 * Returns SASL_OK on success - any other return indicates failure.
1253 1247 *
1254 1248 * free_uef is called to release associated resources by
1255 1249 * digestmd5_common_mech_dispose
1256 1250 */
1257 1251
1258 1252 static int init_uef(context_t *text,
1259 1253 CK_KEY_TYPE keyType,
1260 1254 CK_MECHANISM_TYPE mech_type,
1261 1255 CK_SLOT_ID slot_id,
1262 1256 char enckey[16],
1263 1257 char deckey[16])
1264 1258 {
1265 1259 CK_RV rv;
1266 1260 uef_context_t *enc_context;
1267 1261 uef_context_t *dec_context;
1268 1262 CK_OBJECT_CLASS class = CKO_SECRET_KEY;
1269 1263 CK_BBOOL true = TRUE;
1270 1264 static CK_MECHANISM mechanism = {CKM_RC4, NULL, 0};
1271 1265 unsigned char keybuf[24];
1272 1266 CK_ATTRIBUTE template[] = {
1273 1267 {CKA_CLASS, NULL, sizeof (class)},
1274 1268 {CKA_KEY_TYPE, NULL, sizeof (keyType)},
1275 1269 {CKA_ENCRYPT, NULL, sizeof (true)},
1276 1270 {CKA_VALUE, NULL, 16}};
1277 1271
1278 1272 template[0].pValue = &class;
1279 1273 template[1].pValue = &keyType;
1280 1274 template[2].pValue = &true;
1281 1275 if (keyType == CKK_DES || keyType == CKK_DES3) {
1282 1276 slidebits(keybuf, (unsigned char *)enckey);
1283 1277 if (keyType == CKK_DES3) {
1284 1278 slidebits(keybuf + 8, (unsigned char *)enckey + 7);
1285 1279 (void) memcpy(keybuf + 16, keybuf, 8);
1286 1280 template[3].ulValueLen = 24;
1287 1281 } else {
1288 1282 template[3].ulValueLen = 8;
1289 1283 }
1290 1284 template[3].pValue = keybuf;
1291 1285 mechanism.pParameter = enckey + 8;
1292 1286 mechanism.ulParameterLen = 8;
1293 1287 } else {
1294 1288 template[3].pValue = enckey;
1295 1289 }
1296 1290 mechanism.mechanism = mech_type;
1297 1291
1298 1292 /* allocate rc4 context structures */
1299 1293 enc_context = text->utils->malloc(sizeof (uef_context_t));
1300 1294 if (enc_context == NULL)
1301 1295 return SASL_NOMEM;
1302 1296
1303 1297 rv = C_OpenSession(slot_id, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR,
1304 1298 &enc_context->hSession);
1305 1299 if (rv != CKR_OK) {
1306 1300 text->utils->free(enc_context);
1307 1301 #ifdef DEBUG
1308 1302 text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1309 1303 "enc C_OpenSession Failed:0x%.8X\n", rv);
1310 1304 #endif
1311 1305 return SASL_FAIL;
1312 1306 }
1313 1307
1314 1308 rv = C_CreateObject(enc_context->hSession, template,
1315 1309 sizeof (template)/sizeof (template[0]), &enc_context->hKey);
1316 1310 if (rv != CKR_OK) {
1317 1311 text->utils->free(enc_context);
1318 1312 (void) C_CloseSession(enc_context->hSession);
1319 1313 #ifdef DEBUG
1320 1314 text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1321 1315 "enc C_CreateObject: rv = 0x%.8X\n", rv);
1322 1316 #endif
1323 1317 return SASL_FAIL;
1324 1318 }
1325 1319
1326 1320 text->cipher_enc_context = (cipher_context_t *)enc_context;
1327 1321
1328 1322 /* Initialize the encryption operation in the session */
1329 1323 rv = C_EncryptInit(enc_context->hSession, &mechanism, enc_context->hKey);
1330 1324 if (rv != CKR_OK) {
1331 1325 #ifdef DEBUG
1332 1326 text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1333 1327 "C_EncryptInit: rv = 0x%.8X\n", rv);
1334 1328 #endif
1335 1329 return SASL_FAIL;
1336 1330 }
1337 1331
1338 1332 dec_context = text->utils->malloc(sizeof(uef_context_t));
1339 1333 if (dec_context == NULL)
1340 1334 return SASL_NOMEM;
1341 1335
1342 1336 rv = C_OpenSession(slot_id, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR,
1343 1337 &dec_context->hSession);
1344 1338 if (rv != CKR_OK) {
1345 1339 #ifdef DEBUG
1346 1340 text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1347 1341 "dec C_OpenSession Failed:0x%.8X\n", rv);
1348 1342 #endif
1349 1343 text->utils->free(dec_context);
1350 1344 return SASL_FAIL;
1351 1345 }
1352 1346
1353 1347 template[2].type = CKA_DECRYPT;
1354 1348 if (keyType == CKK_DES || keyType == CKK_DES3) {
1355 1349 slidebits(keybuf, (unsigned char *)deckey);
1356 1350 if (keyType == CKK_DES3) {
1357 1351 slidebits(keybuf + 8, (unsigned char *)deckey + 7);
1358 1352 (void) memcpy(keybuf + 16, keybuf, 8);
1359 1353 }
1360 1354 mechanism.pParameter = deckey + 8;
1361 1355 } else {
1362 1356 template[3].pValue = deckey;
1363 1357 }
1364 1358
1365 1359 rv = C_CreateObject(dec_context->hSession, template,
1366 1360 sizeof (template)/sizeof (template[0]), &dec_context->hKey);
1367 1361 if (rv != CKR_OK) {
1368 1362 #ifdef DEBUG
1369 1363 text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1370 1364 "dec C_CreateObject: rv = 0x%.8X\n", rv);
1371 1365 #endif
1372 1366 (void) C_CloseSession(dec_context->hSession);
1373 1367 text->utils->free(dec_context);
1374 1368 return SASL_FAIL;
1375 1369 }
1376 1370 text->cipher_dec_context = (cipher_context_t *)dec_context;
1377 1371
1378 1372 /* Initialize the decryption operation in the session */
1379 1373 rv = C_DecryptInit(dec_context->hSession, &mechanism, dec_context->hKey);
1380 1374 if (rv != CKR_OK) {
1381 1375 #ifdef DEBUG
1382 1376 text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1383 1377 "C_DecryptInit: rv = 0x%.8X\n", rv);
1384 1378 #endif
1385 1379 return SASL_FAIL;
1386 1380 }
1387 1381
1388 1382 return SASL_OK;
1389 1383 }
1390 1384
1391 1385 static int init_rc4_uef(context_t *text,
1392 1386 char enckey[16],
1393 1387 char deckey[16])
1394 1388 {
1395 1389 return init_uef(text, CKK_RC4, CKM_RC4, rc4_slot_id, enckey, deckey);
1396 1390 }
1397 1391
1398 1392 static int init_des_uef(context_t *text,
1399 1393 char enckey[16],
1400 1394 char deckey[16])
1401 1395 {
1402 1396 return init_uef(text, CKK_DES, CKM_DES_CBC, des_slot_id, enckey, deckey);
1403 1397 }
1404 1398
1405 1399 static int init_3des_uef(context_t *text,
1406 1400 char enckey[16],
1407 1401 char deckey[16])
1408 1402 {
1409 1403 return init_uef(text, CKK_DES3, CKM_DES3_CBC, des3_slot_id, enckey, deckey);
1410 1404 }
1411 1405
1412 1406 static void
1413 1407 free_uef(context_t *text)
1414 1408 {
1415 1409 uef_context_t *enc_context =
1416 1410 (uef_context_t *)text->cipher_enc_context;
1417 1411 uef_context_t *dec_context =
1418 1412 (uef_context_t *)text->cipher_dec_context;
1419 1413 CK_RV rv;
1420 1414 unsigned char buf[1];
1421 1415 CK_ULONG ulLen = 0;
1422 1416
1423 1417
1424 1418 if (enc_context != NULL) {
1425 1419 rv = C_EncryptFinal(enc_context->hSession, buf, &ulLen);
1426 1420 if (rv != CKR_OK) {
1427 1421 #ifdef DEBUG
1428 1422 text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1429 1423 "C_EncryptFinal failed:0x%.8X\n", rv);
1430 1424 #endif
1431 1425 }
1432 1426 rv = C_DestroyObject(enc_context->hSession, enc_context->hKey);
1433 1427 if (rv != CKR_OK) {
1434 1428 #ifdef DEBUG
1435 1429 text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1436 1430 "C_DestroyObject failed:0x%.8X\n", rv);
1437 1431 #endif
1438 1432 }
1439 1433 rv = C_CloseSession(enc_context->hSession);
1440 1434 if (rv != CKR_OK) {
1441 1435 #ifdef DEBUG
1442 1436 text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1443 1437 "C_CloseSession failed:0x%.8X\n", rv);
1444 1438 #endif
1445 1439 }
1446 1440 text->utils->free(enc_context);
1447 1441 }
1448 1442 if (dec_context != NULL) {
1449 1443 rv = C_DecryptFinal(dec_context->hSession, buf, &ulLen);
1450 1444 if (rv != CKR_OK) {
1451 1445 #ifdef DEBUG
1452 1446 text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1453 1447 "C_DecryptFinal failed:0x%.8X\n", rv);
1454 1448 #endif
1455 1449 }
1456 1450 rv = C_DestroyObject(dec_context->hSession, dec_context->hKey);
1457 1451 if (rv != CKR_OK) {
1458 1452 #ifdef DEBUG
1459 1453 text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1460 1454 "C_DestroyObject failed:0x%.8X\n", rv);
1461 1455 #endif
1462 1456 }
1463 1457
1464 1458 rv = C_CloseSession(dec_context->hSession);
1465 1459 if (rv != CKR_OK) {
1466 1460 #ifdef DEBUG
1467 1461 text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1468 1462 "C_CloseSession failed:0x%.8X\n", rv);
1469 1463 #endif
1470 1464 }
1471 1465 text->utils->free(dec_context);
1472 1466 }
1473 1467 text->cipher_enc_context = NULL;
1474 1468 text->cipher_dec_context = NULL;
1475 1469 }
1476 1470
1477 1471 static int
1478 1472 dec_rc4_uef(context_t *text,
1479 1473 const char *input,
1480 1474 unsigned inputlen,
1481 1475 unsigned char digest[16],
1482 1476 char *output,
1483 1477 unsigned *outputlen)
1484 1478 {
1485 1479 CK_RV rv;
1486 1480 uef_context_t *dec_context =
1487 1481 (uef_context_t *)text->cipher_dec_context;
1488 1482 CK_ULONG ulDataLen = *outputlen - MAC_SIZE;
1489 1483 CK_ULONG ulDigestLen = MAC_SIZE;
1490 1484
1491 1485 rv = C_DecryptUpdate(dec_context->hSession, (CK_BYTE_PTR)input,
1492 1486 inputlen - MAC_SIZE, (CK_BYTE_PTR)output, &ulDataLen);
1493 1487 if (rv != CKR_OK) {
1494 1488 #ifdef DEBUG
1495 1489 text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1496 1490 "C_DecryptUpdate failed:0x%.8X\n", rv);
1497 1491 #endif
1498 1492 return SASL_FAIL;
1499 1493 }
1500 1494 *outputlen = (unsigned)ulDataLen;
1501 1495
1502 1496 rv = C_DecryptUpdate(dec_context->hSession,
1503 1497 (CK_BYTE_PTR)input+(inputlen-MAC_SIZE), MAC_SIZE, (CK_BYTE_PTR)digest,
1504 1498 &ulDigestLen);
1505 1499 if (rv != CKR_OK || ulDigestLen != MAC_SIZE) {
1506 1500 #ifdef DEBUG
1507 1501 text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1508 1502 "C_DecryptUpdate:0x%.8X, digestLen:%d\n",
1509 1503 rv, ulDigestLen);
1510 1504 #endif
1511 1505 return SASL_FAIL;
1512 1506 }
1513 1507
1514 1508 return SASL_OK;
1515 1509 }
1516 1510
1517 1511 static int
1518 1512 enc_rc4_uef(context_t *text,
1519 1513 const char *input,
1520 1514 unsigned inputlen,
1521 1515 unsigned char digest[16],
1522 1516 char *output,
1523 1517 unsigned *outputlen)
1524 1518 {
1525 1519 CK_RV rv;
1526 1520 uef_context_t *enc_context =
1527 1521 (uef_context_t *)text->cipher_enc_context;
1528 1522 CK_ULONG ulDataLen = inputlen;
1529 1523 CK_ULONG ulDigestLen = MAC_SIZE;
1530 1524
1531 1525 rv = C_EncryptUpdate(enc_context->hSession, (CK_BYTE_PTR)input, inputlen,
1532 1526 (CK_BYTE_PTR)output, &ulDataLen);
1533 1527 if (rv != CKR_OK) {
1534 1528 #ifdef DEBUG
1535 1529 text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1536 1530 "C_EncryptUpdate failed: 0x%.8X "
1537 1531 "inputlen:%d outputlen:%d\n",
1538 1532 rv, inputlen, ulDataLen);
1539 1533 #endif
1540 1534 return SASL_FAIL;
1541 1535 }
1542 1536 rv = C_EncryptUpdate(enc_context->hSession, (CK_BYTE_PTR)digest, MAC_SIZE,
1543 1537 (CK_BYTE_PTR)output + inputlen, &ulDigestLen);
1544 1538 if (rv != CKR_OK) {
1545 1539 #ifdef DEBUG
1546 1540 text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1547 1541 "C_EncryptUpdate failed: 0x%.8X ulDigestLen:%d\n",
1548 1542 rv, ulDigestLen);
1549 1543 #endif
1550 1544 return SASL_FAIL;
1551 1545 }
1552 1546
1553 1547 *outputlen = ulDataLen + ulDigestLen;
1554 1548
1555 1549 return SASL_OK;
1556 1550 }
1557 1551
1558 1552 static int
1559 1553 dec_des_uef(context_t *text,
1560 1554 const char *input,
1561 1555 unsigned inputlen,
1562 1556 unsigned char digest[16],
1563 1557 char *output,
1564 1558 unsigned *outputlen)
1565 1559 {
1566 1560 CK_RV rv;
1567 1561 uef_context_t *dec_context =
1568 1562 (uef_context_t *)text->cipher_dec_context;
1569 1563 CK_ULONG ulDataLen = inputlen;
1570 1564 int padding, p;
1571 1565
1572 1566 rv = C_DecryptUpdate(dec_context->hSession, (CK_BYTE_PTR)input,
1573 1567 inputlen, (CK_BYTE_PTR)output, &ulDataLen);
1574 1568 if (rv != CKR_OK) {
1575 1569 #ifdef DEBUG
1576 1570 text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1577 1571 "C_DecryptUpdate failed:0x%.8X\n", rv);
1578 1572 #endif
1579 1573 return SASL_FAIL;
1580 1574 }
1581 1575 if (ulDataLen != inputlen) {
1582 1576 #ifdef DEBUG
1583 1577 text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1584 1578 "C_DecryptUpdate unexpected data len:%d !=%d\n",
1585 1579 inputlen, ulDataLen);
1586 1580 #endif
1587 1581 return SASL_BUFOVER;
1588 1582 }
1589 1583
1590 1584 /* now chop off the padding */
1591 1585 padding = output[inputlen - 11];
1592 1586 if (padding < 1 || padding > 8) {
1593 1587 /* invalid padding length */
1594 1588 return SASL_BADMAC;
1595 1589 }
1596 1590 /* verify all padding is correct */
1597 1591 for (p = 1; p <= padding; p++) {
1598 1592 if (output[inputlen - MAC_SIZE - p] != padding) {
1599 1593 return SASL_BADMAC;
1600 1594 }
1601 1595 }
1602 1596
1603 1597 /* chop off the padding */
1604 1598 *outputlen = inputlen - padding - MAC_SIZE;
1605 1599
1606 1600 /* copy in the HMAC to digest */
1607 1601 memcpy(digest, output + inputlen - MAC_SIZE, MAC_SIZE);
1608 1602
1609 1603 return SASL_OK;
1610 1604 }
1611 1605
1612 1606 static int
1613 1607 enc_des_uef(context_t *text,
1614 1608 const char *input,
1615 1609 unsigned inputlen,
1616 1610 unsigned char digest[16],
1617 1611 char *output,
1618 1612 unsigned *outputlen)
1619 1613 {
1620 1614 CK_RV rv;
1621 1615 uef_context_t *enc_context =
1622 1616 (uef_context_t *)text->cipher_enc_context;
1623 1617 CK_ULONG ulDataLen;
1624 1618 int paddinglen;
1625 1619
1626 1620 /* determine padding length */
1627 1621 paddinglen = 8 - ((inputlen + MAC_SIZE) % 8);
1628 1622
1629 1623 /* now construct the full stuff to be ciphered */
1630 1624 memcpy(output, input, inputlen); /* text */
1631 1625 memset(output+inputlen, paddinglen, paddinglen);/* pad */
1632 1626 memcpy(output+inputlen+paddinglen, digest, MAC_SIZE); /* hmac */
1633 1627
1634 1628 ulDataLen=inputlen+paddinglen+MAC_SIZE;
1635 1629
1636 1630 rv = C_EncryptUpdate(enc_context->hSession, (CK_BYTE_PTR)output, ulDataLen,
1637 1631 (CK_BYTE_PTR)output, &ulDataLen);
1638 1632 if (rv != CKR_OK) {
1639 1633 #ifdef DEBUG
1640 1634 text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1641 1635 "C_EncryptUpdate failed: 0x%.8X "
1642 1636 "inputlen:%d outputlen:%d\n",
1643 1637 rv, ulDataLen, ulDataLen);
1644 1638 #endif
1645 1639 return SASL_FAIL;
1646 1640 }
1647 1641 *outputlen = (unsigned)ulDataLen;
1648 1642
1649 1643 return SASL_OK;
1650 1644 }
1651 1645
1652 1646 struct digest_cipher uef_ciphers[] =
1653 1647 {
1654 1648 { "rc4-40", 40, 5, 0x01, &enc_rc4_uef, &dec_rc4_uef, &init_rc4_uef,
1655 1649 &free_uef },
1656 1650 { "rc4-56", 56, 7, 0x02, &enc_rc4_uef, &dec_rc4_uef, &init_rc4_uef,
1657 1651 &free_uef },
1658 1652 { "rc4", 128, 16, 0x04, &enc_rc4_uef, &dec_rc4_uef, &init_rc4_uef,
1659 1653 &free_uef },
1660 1654 { "des", 55, 16, 0x08, &enc_des_uef, &dec_des_uef, &init_des_uef,
1661 1655 &free_uef },
1662 1656 { "3des", 112, 16, 0x10, &enc_des_uef, &dec_des_uef, &init_3des_uef,
1663 1657 &free_uef },
1664 1658 { NULL, 0, 0, 0, NULL, NULL, NULL, NULL }
1665 1659 };
1666 1660
1667 1661 struct digest_cipher *available_ciphers1 = uef_ciphers;
1668 1662 #endif /* USE_UEF */
1669 1663
1670 1664 static int create_layer_keys(context_t *text,
1671 1665 const sasl_utils_t *utils,
1672 1666 HASH key, int keylen,
1673 1667 char enckey[16], char deckey[16])
1674 1668 {
1675 1669 MD5_CTX Md5Ctx;
1676 1670
1677 1671 utils->MD5Init(&Md5Ctx);
1678 1672 utils->MD5Update(&Md5Ctx, key, keylen);
1679 1673 if (text->i_am == SERVER) {
1680 1674 utils->MD5Update(&Md5Ctx, (const unsigned char *) SEALING_SERVER_CLIENT,
1681 1675 strlen(SEALING_SERVER_CLIENT));
1682 1676 } else {
1683 1677 utils->MD5Update(&Md5Ctx, (const unsigned char *) SEALING_CLIENT_SERVER,
1684 1678 strlen(SEALING_CLIENT_SERVER));
1685 1679 }
1686 1680 utils->MD5Final((unsigned char *) enckey, &Md5Ctx);
1687 1681
1688 1682 utils->MD5Init(&Md5Ctx);
1689 1683 utils->MD5Update(&Md5Ctx, key, keylen);
1690 1684 if (text->i_am != SERVER) {
1691 1685 utils->MD5Update(&Md5Ctx, (const unsigned char *)SEALING_SERVER_CLIENT,
1692 1686 strlen(SEALING_SERVER_CLIENT));
1693 1687 } else {
1694 1688 utils->MD5Update(&Md5Ctx, (const unsigned char *)SEALING_CLIENT_SERVER,
1695 1689 strlen(SEALING_CLIENT_SERVER));
1696 1690 }
1697 1691 utils->MD5Final((unsigned char *) deckey, &Md5Ctx);
1698 1692
1699 1693 /* create integrity keys */
1700 1694 /* sending */
1701 1695 utils->MD5Init(&Md5Ctx);
1702 1696 utils->MD5Update(&Md5Ctx, text->HA1, HASHLEN);
1703 1697 if (text->i_am == SERVER) {
1704 1698 utils->MD5Update(&Md5Ctx, (const unsigned char *)SIGNING_SERVER_CLIENT,
1705 1699 strlen(SIGNING_SERVER_CLIENT));
1706 1700 } else {
1707 1701 utils->MD5Update(&Md5Ctx, (const unsigned char *)SIGNING_CLIENT_SERVER,
1708 1702 strlen(SIGNING_CLIENT_SERVER));
1709 1703 }
1710 1704 utils->MD5Final(text->Ki_send, &Md5Ctx);
1711 1705
1712 1706 /* receiving */
1713 1707 utils->MD5Init(&Md5Ctx);
1714 1708 utils->MD5Update(&Md5Ctx, text->HA1, HASHLEN);
1715 1709 if (text->i_am != SERVER) {
1716 1710 utils->MD5Update(&Md5Ctx, (const unsigned char *)SIGNING_SERVER_CLIENT,
1717 1711 strlen(SIGNING_SERVER_CLIENT));
1718 1712 } else {
1719 1713 utils->MD5Update(&Md5Ctx, (const unsigned char *)SIGNING_CLIENT_SERVER,
1720 1714 strlen(SIGNING_CLIENT_SERVER));
1721 1715 }
1722 1716 utils->MD5Final(text->Ki_receive, &Md5Ctx);
1723 1717
1724 1718 return SASL_OK;
1725 1719 }
1726 1720
1727 1721 static const unsigned short version = 1;
1728 1722
1729 1723 /* len, CIPHER(Kc, {msg, pag, HMAC(ki, {SeqNum, msg})[0..9]}), x0001, SeqNum */
1730 1724
1731 1725 static int
1732 1726 digestmd5_privacy_encode(void *context,
1733 1727 const struct iovec *invec,
1734 1728 unsigned numiov,
1735 1729 const char **output,
1736 1730 unsigned *outputlen)
1737 1731 {
1738 1732 context_t *text = (context_t *) context;
1739 1733 int tmp;
1740 1734 unsigned int tmpnum;
1741 1735 unsigned short int tmpshort;
1742 1736 int ret;
1743 1737 char *out;
1744 1738 unsigned char digest[16];
1745 1739 struct buffer_info *inblob, bufinfo;
1746 1740
1747 1741 if(!context || !invec || !numiov || !output || !outputlen) {
1748 1742 PARAMERROR(text->utils);
1749 1743 return SASL_BADPARAM;
1750 1744 }
1751 1745
1752 1746 if (numiov > 1) {
1753 1747 ret = _plug_iovec_to_buf(text->utils, invec, numiov, &text->enc_in_buf);
1754 1748 if (ret != SASL_OK) return ret;
1755 1749 inblob = text->enc_in_buf;
1756 1750 } else {
1757 1751 /* avoid the data copy */
1758 1752 bufinfo.data = invec[0].iov_base;
1759 1753 bufinfo.curlen = invec[0].iov_len;
1760 1754 inblob = &bufinfo;
1761 1755 }
1762 1756
1763 1757 /* make sure the output buffer is big enough for this blob */
1764 1758 ret = _plug_buf_alloc(text->utils, &(text->encode_buf),
1765 1759 &(text->encode_buf_len),
1766 1760 (4 + /* for length */
1767 1761 inblob->curlen + /* for content */
1768 1762 10 + /* for MAC */
1769 1763 8 + /* maximum pad */
1770 1764 6 + /* for padding */
1771 1765 1)); /* trailing null */
1772 1766 if(ret != SASL_OK) return ret;
1773 1767
1774 1768 /* skip by the length for now */
1775 1769 out = (text->encode_buf)+4;
1776 1770
1777 1771 /* construct (seqnum, msg) */
1778 1772 /* We can just use the output buffer because it's big enough */
1779 1773 tmpnum = htonl(text->seqnum);
1780 1774 memcpy(text->encode_buf, &tmpnum, 4);
1781 1775 memcpy(text->encode_buf + 4, inblob->data, inblob->curlen);
1782 1776
1783 1777 /* HMAC(ki, (seqnum, msg) ) */
1784 1778 text->utils->hmac_md5((const unsigned char *) text->encode_buf,
1785 1779 inblob->curlen + 4,
1786 1780 text->Ki_send, HASHLEN, digest);
1787 1781
1788 1782 /* calculate the encrypted part */
1789 1783 text->cipher_enc(text, inblob->data, inblob->curlen,
1790 1784 digest, out, outputlen);
1791 1785 out+=(*outputlen);
1792 1786
1793 1787 /* copy in version */
1794 1788 tmpshort = htons(version);
1795 1789 memcpy(out, &tmpshort, 2); /* 2 bytes = version */
1796 1790
1797 1791 out+=2;
1798 1792 (*outputlen)+=2; /* for version */
1799 1793
1800 1794 /* put in seqnum */
1801 1795 tmpnum = htonl(text->seqnum);
1802 1796 memcpy(out, &tmpnum, 4); /* 4 bytes = seq # */
1803 1797
1804 1798 (*outputlen)+=4; /* for seqnum */
1805 1799
1806 1800 /* put the 1st 4 bytes in */
1807 1801 tmp=htonl(*outputlen);
1808 1802 memcpy(text->encode_buf, &tmp, 4);
1809 1803
1810 1804 (*outputlen)+=4;
1811 1805
1812 1806 *output = text->encode_buf;
1813 1807 text->seqnum++;
1814 1808
1815 1809 return SASL_OK;
1816 1810 }
1817 1811
1818 1812 static int
1819 1813 digestmd5_privacy_decode_once(void *context,
1820 1814 const char **input,
1821 1815 unsigned *inputlen,
1822 1816 char **output,
1823 1817 unsigned *outputlen)
1824 1818 {
1825 1819 context_t *text = (context_t *) context;
1826 1820 unsigned int tocopy;
1827 1821 unsigned diff;
1828 1822 int result;
1829 1823 unsigned char digest[16];
1830 1824 int tmpnum;
1831 1825 int lup;
1832 1826
1833 1827 if (text->needsize>0) /* 4 bytes for how long message is */
1834 1828 {
1835 1829 /* if less than 4 bytes just copy those we have into text->size */
1836 1830 if (*inputlen<4)
1837 1831 tocopy=*inputlen;
1838 1832 else
1839 1833 tocopy=4;
1840 1834
1841 1835 if (tocopy>text->needsize)
1842 1836 tocopy=text->needsize;
1843 1837
1844 1838 memcpy(text->sizebuf+4-text->needsize, *input, tocopy);
1845 1839 text->needsize-=tocopy;
1846 1840
1847 1841 *input+=tocopy;
1848 1842 *inputlen-=tocopy;
1849 1843
1850 1844 if (text->needsize==0) /* got all of size */
1851 1845 {
1852 1846 memcpy(&(text->size), text->sizebuf, 4);
1853 1847 text->cursize=0;
1854 1848 text->size=ntohl(text->size);
1855 1849
1856 1850 if (text->size > text->in_maxbuf) {
1857 1851 return SASL_FAIL; /* too big probably error */
1858 1852 }
1859 1853
1860 1854 if(!text->buffer)
1861 1855 text->buffer=text->utils->malloc(text->size+5);
1862 1856 else
1863 1857 text->buffer=text->utils->realloc(text->buffer,
1864 1858 text->size+5);
1865 1859 if (text->buffer == NULL) return SASL_NOMEM;
1866 1860 }
1867 1861
1868 1862 *outputlen=0;
1869 1863 *output=NULL;
1870 1864 if (*inputlen==0) /* have to wait until next time for data */
1871 1865 return SASL_OK;
1872 1866
1873 1867 if (text->size==0) /* should never happen */
1874 1868 return SASL_FAIL;
1875 1869 }
1876 1870
1877 1871 diff=text->size - text->cursize; /* bytes need for full message */
1878 1872
1879 1873 if (! text->buffer)
1880 1874 return SASL_FAIL;
1881 1875
1882 1876 if (*inputlen < diff) /* not enough for a decode */
1883 1877 {
1884 1878 memcpy(text->buffer+text->cursize, *input, *inputlen);
1885 1879 text->cursize+=*inputlen;
1886 1880 *inputlen=0;
1887 1881 *outputlen=0;
1888 1882 *output=NULL;
1889 1883 return SASL_OK;
1890 1884 } else {
1891 1885 memcpy(text->buffer+text->cursize, *input, diff);
1892 1886 *input+=diff;
1893 1887 *inputlen-=diff;
1894 1888 }
1895 1889
1896 1890 {
1897 1891 unsigned short ver;
1898 1892 unsigned int seqnum;
1899 1893 unsigned char checkdigest[16];
1900 1894
1901 1895 result = _plug_buf_alloc(text->utils, &text->decode_once_buf,
1902 1896 &text->decode_once_buf_len,
1903 1897 text->size-6);
1904 1898 if (result != SASL_OK)
1905 1899 return result;
1906 1900
1907 1901 *output = text->decode_once_buf;
1908 1902 *outputlen = *inputlen;
1909 1903
1910 1904 result=text->cipher_dec(text,text->buffer,text->size-6,digest,
1911 1905 *output, outputlen);
1912 1906
1913 1907 if (result!=SASL_OK)
1914 1908 return result;
1915 1909
1916 1910 {
1917 1911 int i;
1918 1912 for(i=10; i; i--) {
1919 1913 memcpy(&ver, text->buffer+text->size-i,2);
1920 1914 ver=ntohs(ver);
1921 1915 }
1922 1916 }
1923 1917
1924 1918 /* check the version number */
1925 1919 memcpy(&ver, text->buffer+text->size-6, 2);
1926 1920 ver=ntohs(ver);
1927 1921 if (ver != version)
1928 1922 {
1929 1923 #ifdef _INTEGRATED_SOLARIS_
1930 1924 text->utils->seterror(text->utils->conn, 0,
1931 1925 gettext("Wrong Version"));
1932 1926 #else
1933 1927 text->utils->seterror(text->utils->conn, 0, "Wrong Version");
1934 1928 #endif /* _INTEGRATED_SOLARIS_ */
1935 1929 return SASL_FAIL;
1936 1930 }
1937 1931
1938 1932 /* check the CMAC */
1939 1933
1940 1934 /* construct (seqnum, msg) */
1941 1935 result = _plug_buf_alloc(text->utils, &text->decode_tmp_buf,
1942 1936 &text->decode_tmp_buf_len, *outputlen + 4);
1943 1937 if(result != SASL_OK) return result;
1944 1938
1945 1939 tmpnum = htonl(text->rec_seqnum);
1946 1940 memcpy(text->decode_tmp_buf, &tmpnum, 4);
1947 1941 memcpy(text->decode_tmp_buf + 4, *output, *outputlen);
1948 1942
1949 1943 /* HMAC(ki, (seqnum, msg) ) */
1950 1944 text->utils->hmac_md5((const unsigned char *) text->decode_tmp_buf,
1951 1945 (*outputlen) + 4,
1952 1946 text->Ki_receive, HASHLEN, checkdigest);
1953 1947
1954 1948 /* now check it */
1955 1949 for (lup=0;lup<10;lup++)
1956 1950 if (checkdigest[lup]!=digest[lup])
1957 1951 {
1958 1952 #ifdef _SUN_SDK_
1959 1953 text->utils->log(text->utils->conn, SASL_LOG_ERR,
1960 1954 "CMAC doesn't match at byte %d!", lup);
1961 1955 return SASL_BADMAC;
1962 1956 #else
1963 1957 text->utils->seterror(text->utils->conn, 0,
1964 1958 "CMAC doesn't match at byte %d!", lup);
1965 1959 return SASL_FAIL;
1966 1960 #endif /* _SUN_SDK_ */
1967 1961 }
1968 1962
1969 1963 /* check the sequence number */
1970 1964 memcpy(&seqnum, text->buffer+text->size-4,4);
1971 1965 seqnum=ntohl(seqnum);
1972 1966
1973 1967 if (seqnum!=text->rec_seqnum)
1974 1968 {
1975 1969 #ifdef _SUN_SDK_
1976 1970 text->utils->log(text->utils->conn, SASL_LOG_ERR,
1977 1971 "Incorrect Sequence Number");
1978 1972 #else
1979 1973 text->utils->seterror(text->utils->conn, 0,
1980 1974 "Incorrect Sequence Number");
1981 1975 #endif /* _SUN_SDK_ */
1982 1976 return SASL_FAIL;
1983 1977 }
1984 1978
1985 1979 text->rec_seqnum++; /* now increment it */
1986 1980 }
1987 1981
1988 1982 text->needsize=4;
1989 1983
1990 1984 return SASL_OK;
1991 1985 }
1992 1986
1993 1987 static int digestmd5_privacy_decode(void *context,
1994 1988 const char *input, unsigned inputlen,
1995 1989 const char **output, unsigned *outputlen)
1996 1990 {
1997 1991 context_t *text = (context_t *) context;
1998 1992 int ret;
1999 1993
2000 1994 ret = _plug_decode(text->utils, context, input, inputlen,
2001 1995 &text->decode_buf, &text->decode_buf_len, outputlen,
2002 1996 digestmd5_privacy_decode_once);
2003 1997
2004 1998 *output = text->decode_buf;
2005 1999
2006 2000 return ret;
2007 2001 }
2008 2002
2009 2003 static int
2010 2004 digestmd5_integrity_encode(void *context,
2011 2005 const struct iovec *invec,
2012 2006 unsigned numiov,
2013 2007 const char **output,
2014 2008 unsigned *outputlen)
2015 2009 {
2016 2010 context_t *text = (context_t *) context;
2017 2011 unsigned char MAC[16];
2018 2012 unsigned int tmpnum;
2019 2013 unsigned short int tmpshort;
2020 2014 struct buffer_info *inblob, bufinfo;
2021 2015 int ret;
2022 2016
2023 2017 if(!context || !invec || !numiov || !output || !outputlen) {
2024 2018 PARAMERROR( text->utils );
2025 2019 return SASL_BADPARAM;
2026 2020 }
2027 2021
2028 2022 if (numiov > 1) {
2029 2023 ret = _plug_iovec_to_buf(text->utils, invec, numiov,
2030 2024 &text->enc_in_buf);
2031 2025 if (ret != SASL_OK) return ret;
2032 2026 inblob = text->enc_in_buf;
2033 2027 } else {
2034 2028 /* avoid the data copy */
2035 2029 bufinfo.data = invec[0].iov_base;
2036 2030 bufinfo.curlen = invec[0].iov_len;
2037 2031 inblob = &bufinfo;
2038 2032 }
2039 2033
2040 2034 /* construct output */
2041 2035 *outputlen = 4 + inblob->curlen + 16;
2042 2036
2043 2037 ret = _plug_buf_alloc(text->utils, &(text->encode_buf),
2044 2038 &(text->encode_buf_len), *outputlen);
2045 2039 if(ret != SASL_OK) return ret;
2046 2040
2047 2041 /* construct (seqnum, msg) */
2048 2042 /* we can just use the output buffer */
2049 2043 tmpnum = htonl(text->seqnum);
2050 2044 memcpy(text->encode_buf, &tmpnum, 4);
2051 2045 memcpy(text->encode_buf + 4, inblob->data, inblob->curlen);
2052 2046
2053 2047 /* HMAC(ki, (seqnum, msg) ) */
2054 2048 #ifdef _SUN_SDK_
2055 2049 text->utils->hmac_md5((unsigned char *)text->encode_buf,
2056 2050 inblob->curlen + 4,
2057 2051 text->Ki_send, HASHLEN, MAC);
2058 2052 #else
2059 2053 text->utils->hmac_md5(text->encode_buf, inblob->curlen + 4,
2060 2054 text->Ki_send, HASHLEN, MAC);
2061 2055 #endif /* _SUN_SDK_ */
2062 2056
2063 2057 /* create MAC */
2064 2058 tmpshort = htons(version);
2065 2059 memcpy(MAC + 10, &tmpshort, MAC_OFFS); /* 2 bytes = version */
2066 2060
2067 2061 tmpnum = htonl(text->seqnum);
2068 2062 memcpy(MAC + 12, &tmpnum, 4); /* 4 bytes = sequence number */
2069 2063
2070 2064 /* copy into output */
2071 2065 tmpnum = htonl((*outputlen) - 4);
2072 2066
2073 2067 /* length of message in network byte order */
2074 2068 memcpy(text->encode_buf, &tmpnum, 4);
2075 2069 /* the message text */
2076 2070 memcpy(text->encode_buf + 4, inblob->data, inblob->curlen);
2077 2071 /* the MAC */
2078 2072 memcpy(text->encode_buf + 4 + inblob->curlen, MAC, 16);
2079 2073
2080 2074 text->seqnum++; /* add one to sequence number */
2081 2075
2082 2076 *output = text->encode_buf;
2083 2077
2084 2078 return SASL_OK;
2085 2079 }
2086 2080
2087 2081 static int
2088 2082 create_MAC(context_t * text,
2089 2083 char *input,
2090 2084 int inputlen,
2091 2085 int seqnum,
2092 2086 unsigned char MAC[16])
2093 2087 {
2094 2088 unsigned int tmpnum;
2095 2089 unsigned short int tmpshort;
2096 2090 int ret;
2097 2091
2098 2092 if (inputlen < 0)
2099 2093 return SASL_FAIL;
2100 2094
2101 2095 ret = _plug_buf_alloc(text->utils, &(text->MAC_buf),
2102 2096 &(text->MAC_buf_len), inputlen + 4);
2103 2097 if(ret != SASL_OK) return ret;
2104 2098
2105 2099 /* construct (seqnum, msg) */
2106 2100 tmpnum = htonl(seqnum);
2107 2101 memcpy(text->MAC_buf, &tmpnum, 4);
2108 2102 memcpy(text->MAC_buf + 4, input, inputlen);
2109 2103
2110 2104 /* HMAC(ki, (seqnum, msg) ) */
2111 2105 #ifdef _SUN_SDK_
2112 2106 text->utils->hmac_md5((unsigned char *)text->MAC_buf, inputlen + 4,
2113 2107 text->Ki_receive, HASHLEN,
2114 2108 MAC);
2115 2109 #else
2116 2110 text->utils->hmac_md5(text->MAC_buf, inputlen + 4,
2117 2111 text->Ki_receive, HASHLEN,
2118 2112 MAC);
2119 2113 #endif /* _SUN_SDK_ */
2120 2114
2121 2115 /* create MAC */
2122 2116 tmpshort = htons(version);
2123 2117 memcpy(MAC + 10, &tmpshort, 2); /* 2 bytes = version */
2124 2118
2125 2119 tmpnum = htonl(seqnum);
2126 2120 memcpy(MAC + 12, &tmpnum, 4); /* 4 bytes = sequence number */
2127 2121
2128 2122 return SASL_OK;
2129 2123 }
2130 2124
2131 2125 static int
2132 2126 check_integrity(context_t * text,
2133 2127 char *buf, int bufsize,
2134 2128 char **output, unsigned *outputlen)
2135 2129 {
2136 2130 unsigned char MAC[16];
2137 2131 int result;
2138 2132
2139 2133 result = create_MAC(text, buf, bufsize - 16, text->rec_seqnum, MAC);
2140 2134 if (result != SASL_OK)
2141 2135 return result;
2142 2136
2143 2137 /* make sure the MAC is right */
2144 2138 if (strncmp((char *) MAC, buf + bufsize - 16, 16) != 0)
2145 2139 {
2146 2140 #ifdef _SUN_SDK_
2147 2141 text->utils->log(text->utils->conn, SASL_LOG_ERR,
2148 2142 "MAC doesn't match");
2149 2143 return SASL_BADMAC;
2150 2144 #else
2151 2145 text->utils->seterror(text->utils->conn, 0, "MAC doesn't match");
2152 2146 return SASL_FAIL;
2153 2147 #endif /* _SUN_SDK_ */
2154 2148 }
2155 2149
2156 2150 text->rec_seqnum++;
2157 2151
2158 2152 /* ok make output message */
2159 2153 result = _plug_buf_alloc(text->utils, &text->decode_once_buf,
2160 2154 &text->decode_once_buf_len,
2161 2155 bufsize - 15);
2162 2156 if (result != SASL_OK)
2163 2157 return result;
2164 2158
2165 2159 *output = text->decode_once_buf;
2166 2160 memcpy(*output, buf, bufsize - 16);
2167 2161 *outputlen = bufsize - 16;
2168 2162 (*output)[*outputlen] = 0;
2169 2163
2170 2164 return SASL_OK;
2171 2165 }
2172 2166
2173 2167 static int
2174 2168 digestmd5_integrity_decode_once(void *context,
2175 2169 const char **input,
2176 2170 unsigned *inputlen,
2177 2171 char **output,
2178 2172 unsigned *outputlen)
2179 2173 {
2180 2174 context_t *text = (context_t *) context;
2181 2175 unsigned int tocopy;
2182 2176 unsigned diff;
2183 2177 int result;
2184 2178
2185 2179 if (text->needsize > 0) { /* 4 bytes for how long message is */
2186 2180 /*
2187 2181 * if less than 4 bytes just copy those we have into text->size
2188 2182 */
2189 2183 if (*inputlen < 4)
2190 2184 tocopy = *inputlen;
2191 2185 else
2192 2186 tocopy = 4;
2193 2187
2194 2188 if (tocopy > text->needsize)
2195 2189 tocopy = text->needsize;
2196 2190
2197 2191 memcpy(text->sizebuf + 4 - text->needsize, *input, tocopy);
2198 2192 text->needsize -= tocopy;
2199 2193
2200 2194 *input += tocopy;
2201 2195 *inputlen -= tocopy;
2202 2196
2203 2197 if (text->needsize == 0) { /* got all of size */
2204 2198 memcpy(&(text->size), text->sizebuf, 4);
2205 2199 text->cursize = 0;
2206 2200 text->size = ntohl(text->size);
2207 2201
2208 2202 if (text->size > text->in_maxbuf)
2209 2203 return SASL_FAIL; /* too big probably error */
2210 2204
2211 2205 if(!text->buffer)
2212 2206 text->buffer=text->utils->malloc(text->size+5);
2213 2207 else
2214 2208 text->buffer=text->utils->realloc(text->buffer,text->size+5);
2215 2209 if (text->buffer == NULL) return SASL_NOMEM;
2216 2210 }
2217 2211 *outputlen = 0;
2218 2212 *output = NULL;
2219 2213 if (*inputlen == 0) /* have to wait until next time for data */
2220 2214 return SASL_OK;
2221 2215
2222 2216 if (text->size == 0) /* should never happen */
2223 2217 return SASL_FAIL;
2224 2218 }
2225 2219 diff = text->size - text->cursize; /* bytes need for full message */
2226 2220
2227 2221 if(! text->buffer)
2228 2222 return SASL_FAIL;
2229 2223
2230 2224 if (*inputlen < diff) { /* not enough for a decode */
2231 2225 memcpy(text->buffer + text->cursize, *input, *inputlen);
2232 2226 text->cursize += *inputlen;
2233 2227 *inputlen = 0;
2234 2228 *outputlen = 0;
2235 2229 *output = NULL;
2236 2230 return SASL_OK;
2237 2231 } else {
2238 2232 memcpy(text->buffer + text->cursize, *input, diff);
2239 2233 *input += diff;
2240 2234 *inputlen -= diff;
2241 2235 }
2242 2236
2243 2237 result = check_integrity(text, text->buffer, text->size,
2244 2238 output, outputlen);
2245 2239 if (result != SASL_OK)
2246 2240 return result;
2247 2241
2248 2242 /* Reset State */
2249 2243 text->needsize = 4;
2250 2244
2251 2245 return SASL_OK;
2252 2246 }
2253 2247
2254 2248 static int digestmd5_integrity_decode(void *context,
2255 2249 const char *input, unsigned inputlen,
2256 2250 const char **output, unsigned *outputlen)
2257 2251 {
2258 2252 context_t *text = (context_t *) context;
2259 2253 int ret;
2260 2254
2261 2255 ret = _plug_decode(text->utils, context, input, inputlen,
2262 2256 &text->decode_buf, &text->decode_buf_len, outputlen,
2263 2257 digestmd5_integrity_decode_once);
2264 2258
2265 2259 *output = text->decode_buf;
2266 2260
2267 2261 return ret;
2268 2262 }
2269 2263
2270 2264 static void
2271 2265 digestmd5_common_mech_dispose(void *conn_context, const sasl_utils_t *utils)
2272 2266 {
2273 2267 context_t *text = (context_t *) conn_context;
2274 2268
2275 2269 if (!text || !utils) return;
2276 2270
2277 2271 if (text->authid) utils->free(text->authid);
2278 2272 if (text->realm) utils->free(text->realm);
2279 2273 if (text->nonce) utils->free(text->nonce);
2280 2274 if (text->cnonce) utils->free(text->cnonce);
2281 2275
2282 2276 if (text->cipher_free) text->cipher_free(text);
2283 2277
2284 2278 /* free the stuff in the context */
2285 2279 if (text->response_value) utils->free(text->response_value);
2286 2280
2287 2281 if (text->buffer) utils->free(text->buffer);
2288 2282 if (text->encode_buf) utils->free(text->encode_buf);
2289 2283 if (text->decode_buf) utils->free(text->decode_buf);
2290 2284 if (text->decode_once_buf) utils->free(text->decode_once_buf);
2291 2285 if (text->decode_tmp_buf) utils->free(text->decode_tmp_buf);
2292 2286 if (text->out_buf) utils->free(text->out_buf);
2293 2287 if (text->MAC_buf) utils->free(text->MAC_buf);
2294 2288
2295 2289 if (text->enc_in_buf) {
2296 2290 if (text->enc_in_buf->data) utils->free(text->enc_in_buf->data);
2297 2291 utils->free(text->enc_in_buf);
2298 2292 }
2299 2293
2300 2294 utils->free(conn_context);
2301 2295 }
2302 2296
2303 2297 static void
2304 2298 clear_reauth_entry(reauth_entry_t *reauth, enum Context_type type,
2305 2299 const sasl_utils_t *utils)
2306 2300 {
2307 2301 if (!reauth) return;
2308 2302
2309 2303 if (reauth->authid) utils->free(reauth->authid);
2310 2304 if (reauth->realm) utils->free(reauth->realm);
2311 2305 if (reauth->nonce) utils->free(reauth->nonce);
2312 2306 if (reauth->cnonce) utils->free(reauth->cnonce);
2313 2307
2314 2308 if (type == CLIENT) {
2315 2309 if (reauth->u.c.serverFQDN) utils->free(reauth->u.c.serverFQDN);
2316 2310 }
2317 2311
2318 2312 memset(reauth, 0, sizeof(reauth_entry_t));
2319 2313 }
2320 2314
2321 2315 static void
2322 2316 digestmd5_common_mech_free(void *glob_context, const sasl_utils_t *utils)
2323 2317 {
2324 2318 reauth_cache_t *reauth_cache = (reauth_cache_t *) glob_context;
2325 2319 size_t n;
2326 2320
2327 2321 if (!reauth_cache) return;
2328 2322
2329 2323 for (n = 0; n < reauth_cache->size; n++)
2330 2324 clear_reauth_entry(&reauth_cache->e[n], reauth_cache->i_am, utils);
2331 2325 if (reauth_cache->e) utils->free(reauth_cache->e);
2332 2326
2333 2327 if (reauth_cache->mutex) utils->mutex_free(reauth_cache->mutex);
2334 2328
2335 2329 utils->free(reauth_cache);
2336 2330 }
2337 2331
2338 2332 /***************************** Server Section *****************************/
2339 2333
2340 2334 typedef struct server_context {
2341 2335 context_t common;
2342 2336
2343 2337 time_t timestamp;
2344 2338 int stale; /* last nonce is stale */
2345 2339 sasl_ssf_t limitssf, requiressf; /* application defined bounds */
2346 2340 } server_context_t;
2347 2341
2348 2342 static void
2349 2343 DigestCalcHA1FromSecret(context_t * text,
2350 2344 const sasl_utils_t * utils,
2351 2345 HASH HA1,
2352 2346 unsigned char *authorization_id,
2353 2347 unsigned char *pszNonce,
2354 2348 unsigned char *pszCNonce,
2355 2349 HASHHEX SessionKey)
2356 2350 {
2357 2351 MD5_CTX Md5Ctx;
2358 2352
2359 2353 /* calculate session key */
2360 2354 utils->MD5Init(&Md5Ctx);
2361 2355 utils->MD5Update(&Md5Ctx, HA1, HASHLEN);
2362 2356 utils->MD5Update(&Md5Ctx, COLON, 1);
2363 2357 utils->MD5Update(&Md5Ctx, pszNonce, strlen((char *) pszNonce));
2364 2358 utils->MD5Update(&Md5Ctx, COLON, 1);
2365 2359 utils->MD5Update(&Md5Ctx, pszCNonce, strlen((char *) pszCNonce));
2366 2360 if (authorization_id != NULL) {
2367 2361 utils->MD5Update(&Md5Ctx, COLON, 1);
2368 2362 utils->MD5Update(&Md5Ctx, authorization_id, strlen((char *) authorization_id));
2369 2363 }
2370 2364 utils->MD5Final(HA1, &Md5Ctx);
2371 2365
2372 2366 CvtHex(HA1, SessionKey);
2373 2367
2374 2368
2375 2369 /* save HA1 because we need it to make the privacy and integrity keys */
2376 2370 memcpy(text->HA1, HA1, sizeof(HASH));
2377 2371 }
2378 2372
2379 2373 static char *create_response(context_t * text,
2380 2374 const sasl_utils_t * utils,
2381 2375 unsigned char *nonce,
2382 2376 unsigned int ncvalue,
2383 2377 unsigned char *cnonce,
2384 2378 char *qop,
2385 2379 char *digesturi,
2386 2380 HASH Secret,
2387 2381 char *authorization_id,
2388 2382 char **response_value)
2389 2383 {
2390 2384 HASHHEX SessionKey;
2391 2385 HASHHEX HEntity = "00000000000000000000000000000000";
2392 2386 HASHHEX Response;
2393 2387 char *result;
2394 2388
2395 2389 if (qop == NULL)
2396 2390 qop = "auth";
2397 2391
2398 2392 DigestCalcHA1FromSecret(text,
2399 2393 utils,
2400 2394 Secret,
2401 2395 (unsigned char *) authorization_id,
2402 2396 nonce,
2403 2397 cnonce,
2404 2398 SessionKey);
2405 2399
2406 2400 DigestCalcResponse(utils,
2407 2401 SessionKey,/* H(A1) */
2408 2402 nonce, /* nonce from server */
2409 2403 ncvalue, /* 8 hex digits */
2410 2404 cnonce, /* client nonce */
2411 2405 (unsigned char *) qop, /* qop-value: "", "auth",
2412 2406 * "auth-int" */
2413 2407 (unsigned char *) digesturi, /* requested URL */
2414 2408 (unsigned char *) "AUTHENTICATE",
2415 2409 HEntity, /* H(entity body) if qop="auth-int" */
2416 2410 Response /* request-digest or response-digest */
2417 2411 );
2418 2412
2419 2413 result = utils->malloc(HASHHEXLEN + 1);
2420 2414 #ifdef _SUN_SDK_
2421 2415 if (result == NULL)
2422 2416 return NULL;
2423 2417 #endif /* _SUN_SDK_ */
2424 2418 /* TODO */
2425 2419 memcpy(result, Response, HASHHEXLEN);
2426 2420 result[HASHHEXLEN] = 0;
2427 2421
2428 2422 /* response_value (used for reauth i think */
2429 2423 if (response_value != NULL) {
2430 2424 DigestCalcResponse(utils,
2431 2425 SessionKey, /* H(A1) */
2432 2426 nonce, /* nonce from server */
2433 2427 ncvalue, /* 8 hex digits */
2434 2428 cnonce, /* client nonce */
2435 2429 (unsigned char *) qop, /* qop-value: "", "auth",
2436 2430 * "auth-int" */
2437 2431 (unsigned char *) digesturi, /* requested URL */
2438 2432 NULL,
2439 2433 HEntity, /* H(entity body) if qop="auth-int" */
2440 2434 Response /* request-digest or response-digest */
2441 2435 );
2442 2436
2443 2437 *response_value = utils->malloc(HASHHEXLEN + 1);
2444 2438 if (*response_value == NULL)
2445 2439 return NULL;
2446 2440 memcpy(*response_value, Response, HASHHEXLEN);
2447 2441 (*response_value)[HASHHEXLEN] = 0;
2448 2442 }
2449 2443 return result;
2450 2444 }
2451 2445
2452 2446 static int
2453 2447 get_server_realm(sasl_server_params_t * params,
2454 2448 char **realm)
2455 2449 {
2456 2450 /* look at user realm first */
2457 2451 if (params->user_realm != NULL) {
2458 2452 if(params->user_realm[0] != '\0') {
2459 2453 *realm = (char *) params->user_realm;
2460 2454 } else {
2461 2455 /* Catch improperly converted apps */
2462 2456 #ifdef _SUN_SDK_
2463 2457 params->utils->log(params->utils->conn, SASL_LOG_ERR,
2464 2458 "user_realm is an empty string!");
2465 2459 #else
2466 2460 params->utils->seterror(params->utils->conn, 0,
2467 2461 "user_realm is an empty string!");
2468 2462 #endif /* _SUN_SDK_ */
2469 2463 return SASL_BADPARAM;
2470 2464 }
2471 2465 } else if (params->serverFQDN != NULL) {
2472 2466 *realm = (char *) params->serverFQDN;
2473 2467 } else {
2474 2468 #ifdef _SUN_SDK_
2475 2469 params->utils->log(params->utils->conn, SASL_LOG_ERR,
2476 2470 "no way to obtain domain");
2477 2471 #else
2478 2472 params->utils->seterror(params->utils->conn, 0,
2479 2473 "no way to obtain domain");
2480 2474 #endif /* _SUN_SDK_ */
2481 2475 return SASL_FAIL;
2482 2476 }
2483 2477
2484 2478 return SASL_OK;
2485 2479 }
2486 2480
2487 2481 /*
2488 2482 * Convert hex string to int
2489 2483 */
2490 2484 static int htoi(unsigned char *hexin, unsigned int *res)
2491 2485 {
2492 2486 int lup, inlen;
2493 2487 inlen = strlen((char *) hexin);
2494 2488
2495 2489 *res = 0;
2496 2490 for (lup = 0; lup < inlen; lup++) {
2497 2491 switch (hexin[lup]) {
2498 2492 case '0':
2499 2493 case '1':
2500 2494 case '2':
2501 2495 case '3':
2502 2496 case '4':
2503 2497 case '5':
2504 2498 case '6':
2505 2499 case '7':
2506 2500 case '8':
2507 2501 case '9':
2508 2502 *res = (*res << 4) + (hexin[lup] - '0');
2509 2503 break;
2510 2504
2511 2505 case 'a':
2512 2506 case 'b':
2513 2507 case 'c':
2514 2508 case 'd':
2515 2509 case 'e':
2516 2510 case 'f':
2517 2511 *res = (*res << 4) + (hexin[lup] - 'a' + 10);
2518 2512 break;
2519 2513
2520 2514 case 'A':
2521 2515 case 'B':
2522 2516 case 'C':
2523 2517 case 'D':
2524 2518 case 'E':
2525 2519 case 'F':
2526 2520 *res = (*res << 4) + (hexin[lup] - 'A' + 10);
2527 2521 break;
2528 2522
2529 2523 default:
2530 2524 return SASL_BADPARAM;
2531 2525 }
2532 2526
2533 2527 }
2534 2528
2535 2529 return SASL_OK;
2536 2530 }
2537 2531
2538 2532 static int digestmd5_server_mech_new(void *glob_context,
2539 2533 sasl_server_params_t * sparams,
2540 2534 const char *challenge __attribute__((unused)),
2541 2535 unsigned challen __attribute__((unused)),
2542 2536 void **conn_context)
2543 2537 {
2544 2538 context_t *text;
2545 2539
2546 2540 /* holds state are in -- allocate server size */
2547 2541 text = sparams->utils->malloc(sizeof(server_context_t));
2548 2542 if (text == NULL)
2549 2543 return SASL_NOMEM;
2550 2544 memset(text, 0, sizeof(server_context_t));
2551 2545
2552 2546 text->state = 1;
2553 2547 text->i_am = SERVER;
2554 2548 text->reauth = glob_context;
2555 2549
2556 2550 *conn_context = text;
2557 2551 return SASL_OK;
2558 2552 }
2559 2553
2560 2554 static int
2561 2555 digestmd5_server_mech_step1(server_context_t *stext,
2562 2556 sasl_server_params_t *sparams,
2563 2557 const char *clientin __attribute__((unused)),
2564 2558 unsigned clientinlen __attribute__((unused)),
2565 2559 const char **serverout,
2566 2560 unsigned *serveroutlen,
2567 2561 sasl_out_params_t * oparams __attribute__((unused)))
2568 2562 {
2569 2563 context_t *text = (context_t *) stext;
2570 2564 int result;
2571 2565 char *realm;
2572 2566 unsigned char *nonce;
2573 2567 char *charset = "utf-8";
2574 2568 char qop[1024], cipheropts[1024];
2575 2569 struct digest_cipher *cipher;
2576 2570 unsigned resplen;
2577 2571 int added_conf = 0;
2578 2572 char maxbufstr[64];
2579 2573
2580 2574 sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
2581 2575 "DIGEST-MD5 server step 1");
2582 2576
2583 2577 /* get realm */
2584 2578 result = get_server_realm(sparams, &realm);
2585 2579 if(result != SASL_OK) return result;
2586 2580
2587 2581 /* what options should we offer the client? */
2588 2582 qop[0] = '\0';
2589 2583 cipheropts[0] = '\0';
2590 2584 if (stext->requiressf == 0) {
2591 2585 if (*qop) strcat(qop, ",");
2592 2586 strcat(qop, "auth");
2593 2587 }
2594 2588 if (stext->requiressf <= 1 && stext->limitssf >= 1) {
2595 2589 if (*qop) strcat(qop, ",");
2596 2590 strcat(qop, "auth-int");
2597 2591 }
2598 2592
2599 2593 #ifdef USE_UEF_SERVER
2600 2594 cipher = available_ciphers1;
2601 2595 #else
2602 2596 cipher = available_ciphers;
2603 2597 #endif
2604 2598 while (cipher->name) {
2605 2599 /* do we allow this particular cipher? */
2606 2600 if (stext->requiressf <= cipher->ssf &&
2607 2601 stext->limitssf >= cipher->ssf) {
2608 2602 if (!added_conf) {
2609 2603 if (*qop) strcat(qop, ",");
2610 2604 strcat(qop, "auth-conf");
2611 2605 added_conf = 1;
2612 2606 }
2613 2607 #ifdef _SUN_SDK_
2614 2608 if(strlen(cipheropts) + strlen(cipher->name) + 1 >=
2615 2609 sizeof (cipheropts)) {
2616 2610 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2617 2611 "internal error: cipheropts too big");
2618 2612 return SASL_FAIL;
2619 2613 }
2620 2614 #endif /* _SUN_SDK_ */
2621 2615 if (*cipheropts) strcat(cipheropts, ",");
2622 2616 strcat(cipheropts, cipher->name);
2623 2617 }
2624 2618 cipher++;
2625 2619 }
2626 2620
2627 2621 if (*qop == '\0') {
2628 2622 /* we didn't allow anything?!? we'll return SASL_TOOWEAK, since
2629 2623 that's close enough */
2630 2624 return SASL_TOOWEAK;
2631 2625 }
2632 2626
2633 2627 /*
2634 2628 * digest-challenge = 1#( realm | nonce | qop-options | stale | maxbuf |
2635 2629 * charset | cipher-opts | auth-param )
2636 2630 */
2637 2631
2638 2632 #ifndef _SUN_SDK_
2639 2633 /* FIXME: get nonce XXX have to clean up after self if fail */
2640 2634 #endif /* !_SUN_SDK_ */
2641 2635 nonce = create_nonce(sparams->utils);
2642 2636 if (nonce == NULL) {
2643 2637 #ifdef _SUN_SDK_
2644 2638 /* Note typo below */
2645 2639 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2646 2640 "internal error: failed creating a nonce");
2647 2641 #else
2648 2642 SETERROR(sparams->utils, "internal erorr: failed creating a nonce");
2649 2643 #endif /* _SUN_SDK_ */
2650 2644 return SASL_FAIL;
2651 2645 }
2652 2646
2653 2647 #ifdef _SUN_SDK_
2654 2648 resplen = strlen((char *)nonce) + strlen("nonce") + 5;
2655 2649 #else
2656 2650 resplen = strlen(nonce) + strlen("nonce") + 5;
2657 2651 #endif /* _SUN_SDK_ */
2658 2652 result = _plug_buf_alloc(sparams->utils, &(text->out_buf),
2659 2653 &(text->out_buf_len), resplen);
2660 2654 #ifdef _SUN_SDK_
2661 2655 if(result != SASL_OK) {
2662 2656 sparams->utils->free(nonce);
2663 2657 return result;
2664 2658 }
2665 2659 #else
2666 2660 if(result != SASL_OK) return result;
2667 2661 #endif /* _SUN_SDK_ */
2668 2662
2669 2663 sprintf(text->out_buf, "nonce=\"%s\"", nonce);
2670 2664
2671 2665 /* add to challenge; if we chose not to specify a realm, we won't
2672 2666 * send one to the client */
2673 2667 if (realm && add_to_challenge(sparams->utils,
2674 2668 &text->out_buf, &text->out_buf_len, &resplen,
2675 2669 "realm", (unsigned char *) realm,
2676 2670 TRUE) != SASL_OK) {
2677 2671 #ifdef _SUN_SDK_
2678 2672 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2679 2673 "internal error: add_to_challenge failed");
2680 2674 sparams->utils->free(nonce);
2681 2675 #else
2682 2676 SETERROR(sparams->utils, "internal error: add_to_challenge failed");
2683 2677 #endif /* _SUN_SDK_ */
2684 2678 return SASL_FAIL;
2685 2679 }
2686 2680 /*
2687 2681 * qop-options A quoted string of one or more tokens indicating the
2688 2682 * "quality of protection" values supported by the server. The value
2689 2683 * "auth" indicates authentication; the value "auth-int" indicates
2690 2684 * authentication with integrity protection; the value "auth-conf"
2691 2685 * indicates authentication with integrity protection and encryption.
2692 2686 */
2693 2687
2694 2688 /* add qop to challenge */
2695 2689 if (add_to_challenge(sparams->utils,
2696 2690 &text->out_buf, &text->out_buf_len, &resplen,
2697 2691 "qop",
2698 2692 (unsigned char *) qop, TRUE) != SASL_OK) {
2699 2693 #ifdef _SUN_SDK_
2700 2694 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2701 2695 "internal error: add_to_challenge 3 failed");
2702 2696 sparams->utils->free(nonce);
2703 2697 #else
2704 2698 SETERROR(sparams->utils, "internal error: add_to_challenge 3 failed");
2705 2699 #endif /* _SUN_SDK_ */
2706 2700 return SASL_FAIL;
2707 2701 }
2708 2702
2709 2703 /*
2710 2704 * Cipheropts - list of ciphers server supports
2711 2705 */
2712 2706 /* add cipher-opts to challenge; only add if there are some */
2713 2707 if (strcmp(cipheropts,"")!=0)
2714 2708 {
2715 2709 if (add_to_challenge(sparams->utils,
2716 2710 &text->out_buf, &text->out_buf_len, &resplen,
2717 2711 "cipher", (unsigned char *) cipheropts,
2718 2712 TRUE) != SASL_OK) {
2719 2713 #ifdef _SUN_SDK_
2720 2714 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2721 2715 "internal error: add_to_challenge 4 failed");
2722 2716 sparams->utils->free(nonce);
2723 2717 #else
2724 2718 SETERROR(sparams->utils,
2725 2719 "internal error: add_to_challenge 4 failed");
2726 2720 #endif /* _SUN_SDK_ */
2727 2721 return SASL_FAIL;
2728 2722 }
2729 2723 }
2730 2724
2731 2725 /* "stale" is true if a reauth failed because of a nonce timeout */
2732 2726 if (stext->stale &&
2733 2727 add_to_challenge(sparams->utils,
2734 2728 &text->out_buf, &text->out_buf_len, &resplen,
2735 2729 #ifdef _SUN_SDK_
2736 2730 "stale", (unsigned char *)"true", FALSE) != SASL_OK) {
2737 2731 sparams->utils->free(nonce);
2738 2732 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2739 2733 "internal error: add_to_challenge failed");
2740 2734 #else
2741 2735 "stale", "true", FALSE) != SASL_OK) {
2742 2736 SETERROR(sparams->utils, "internal error: add_to_challenge failed");
2743 2737 #endif /* _SUN_SDK_ */
2744 2738 return SASL_FAIL;
2745 2739 }
2746 2740
2747 2741 /*
2748 2742 * maxbuf A number indicating the size of the largest buffer the server
2749 2743 * is able to receive when using "auth-int". If this directive is
2750 2744 * missing, the default value is 65536. This directive may appear at most
2751 2745 * once; if multiple instances are present, the client should abort the
2752 2746 * authentication exchange.
2753 2747 */
2754 2748 if(sparams->props.maxbufsize) {
2755 2749 snprintf(maxbufstr, sizeof(maxbufstr), "%d",
2756 2750 sparams->props.maxbufsize);
2757 2751 if (add_to_challenge(sparams->utils,
2758 2752 &text->out_buf, &text->out_buf_len, &resplen,
2759 2753 "maxbuf",
2760 2754 (unsigned char *) maxbufstr, FALSE) != SASL_OK) {
2761 2755 #ifdef _SUN_SDK_
2762 2756 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2763 2757 "internal error: add_to_challenge 5 failed");
2764 2758 #else
2765 2759 SETERROR(sparams->utils,
2766 2760 "internal error: add_to_challenge 5 failed");
2767 2761 #endif /* _SUN_SDK_ */
2768 2762 return SASL_FAIL;
2769 2763 }
2770 2764 }
2771 2765
2772 2766
2773 2767 if (add_to_challenge(sparams->utils,
2774 2768 &text->out_buf, &text->out_buf_len, &resplen,
2775 2769 "charset",
2776 2770 (unsigned char *) charset, FALSE) != SASL_OK) {
2777 2771 #ifdef _SUN_SDK_
2778 2772 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2779 2773 "internal error: add_to_challenge 6 failed");
2780 2774 sparams->utils->free(nonce);
2781 2775 #else
2782 2776 SETERROR(sparams->utils, "internal error: add_to_challenge 6 failed");
2783 2777 #endif /* _SUN_SDK_ */
2784 2778 return SASL_FAIL;
2785 2779 }
2786 2780
2787 2781
2788 2782 /*
2789 2783 * algorithm
2790 2784 * This directive is required for backwards compatibility with HTTP
2791 2785 * Digest., which supports other algorithms. . This directive is
2792 2786 * required and MUST appear exactly once; if not present, or if multiple
2793 2787 * instances are present, the client should abort the authentication
2794 2788 * exchange.
2795 2789 *
2796 2790 * algorithm = "algorithm" "=" "md5-sess"
2797 2791 */
2798 2792
2799 2793 if (add_to_challenge(sparams->utils,
2800 2794 &text->out_buf, &text->out_buf_len, &resplen,
2801 2795 "algorithm",
2802 2796 (unsigned char *) "md5-sess", FALSE)!=SASL_OK) {
2803 2797 #ifdef _SUN_SDK_
2804 2798 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2805 2799 "internal error: add_to_challenge 7 failed");
2806 2800 sparams->utils->free(nonce);
2807 2801 #else
2808 2802 SETERROR(sparams->utils, "internal error: add_to_challenge 7 failed");
2809 2803 #endif /* _SUN_SDK_ */
2810 2804 return SASL_FAIL;
2811 2805 }
2812 2806
2813 2807 /*
2814 2808 * The size of a digest-challenge MUST be less than 2048 bytes!!!
2815 2809 */
2816 2810 if (*serveroutlen > 2048) {
2817 2811 #ifdef _SUN_SDK_
2818 2812 sparams->utils->free(nonce);
2819 2813 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2820 2814 "internal error: challenge larger than 2048 bytes");
2821 2815 #else
2822 2816 SETERROR(sparams->utils,
2823 2817 "internal error: challenge larger than 2048 bytes");
2824 2818 #endif /* _SUN_SDK_ */
2825 2819 return SASL_FAIL;
2826 2820 }
2827 2821
2828 2822 text->authid = NULL;
2829 2823 _plug_strdup(sparams->utils, realm, &text->realm, NULL);
2830 2824 text->nonce = nonce;
2831 2825 text->nonce_count = 1;
2832 2826 text->cnonce = NULL;
2833 2827 stext->timestamp = time(0);
2834 2828
2835 2829 *serveroutlen = strlen(text->out_buf);
2836 2830 *serverout = text->out_buf;
2837 2831
2838 2832 text->state = 2;
2839 2833
2840 2834 return SASL_CONTINUE;
2841 2835 }
2842 2836
2843 2837 static int
2844 2838 digestmd5_server_mech_step2(server_context_t *stext,
2845 2839 sasl_server_params_t *sparams,
2846 2840 const char *clientin,
2847 2841 unsigned clientinlen,
2848 2842 const char **serverout,
2849 2843 unsigned *serveroutlen,
2850 2844 sasl_out_params_t * oparams)
2851 2845 {
2852 2846 context_t *text = (context_t *) stext;
2853 2847 /* verify digest */
2854 2848 sasl_secret_t *sec = NULL;
2855 2849 int result;
2856 2850 char *serverresponse = NULL;
2857 2851 char *username = NULL;
2858 2852 char *authorization_id = NULL;
2859 2853 char *realm = NULL;
2860 2854 unsigned char *nonce = NULL, *cnonce = NULL;
2861 2855 unsigned int noncecount = 0;
2862 2856 char *qop = NULL;
2863 2857 char *digesturi = NULL;
2864 2858 char *response = NULL;
2865 2859
2866 2860 /* setting the default value (65536) */
2867 2861 unsigned int client_maxbuf = 65536;
2868 2862 int maxbuf_count = 0; /* How many maxbuf instaces was found */
2869 2863
2870 2864 char *charset = NULL;
2871 2865 char *cipher = NULL;
2872 2866 unsigned int n=0;
2873 2867
2874 2868 HASH A1;
2875 2869
2876 2870 /* password prop_request */
2877 2871 const char *password_request[] = { SASL_AUX_PASSWORD,
2878 2872 "*cmusaslsecretDIGEST-MD5",
2879 2873 NULL };
2880 2874 unsigned len;
2881 2875 struct propval auxprop_values[2];
2882 2876
2883 2877 /* can we mess with clientin? copy it to be safe */
2884 2878 char *in_start = NULL;
2885 2879 char *in = NULL;
2886 2880
2887 2881 sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
2888 2882 "DIGEST-MD5 server step 2");
2889 2883
2890 2884 in = sparams->utils->malloc(clientinlen + 1);
2891 2885 #ifdef _SUN_SDK_
2892 2886 if (!in) return SASL_NOMEM;
2893 2887 #endif /* _SUN_SDK_ */
2894 2888
2895 2889 memcpy(in, clientin, clientinlen);
2896 2890 in[clientinlen] = 0;
2897 2891
2898 2892 in_start = in;
2899 2893
2900 2894
2901 2895 /* parse what we got */
2902 2896 while (in[0] != '\0') {
2903 2897 char *name = NULL, *value = NULL;
2904 2898 get_pair(&in, &name, &value);
2905 2899
2906 2900 if (name == NULL)
2907 2901 break;
2908 2902
2909 2903 /* Extracting parameters */
2910 2904
2911 2905 /*
2912 2906 * digest-response = 1#( username | realm | nonce | cnonce |
2913 2907 * nonce-count | qop | digest-uri | response | maxbuf | charset |
2914 2908 * cipher | auth-param )
2915 2909 */
2916 2910
2917 2911 if (strcasecmp(name, "username") == 0) {
2918 2912 _plug_strdup(sparams->utils, value, &username, NULL);
2919 2913 } else if (strcasecmp(name, "authzid") == 0) {
2920 2914 _plug_strdup(sparams->utils, value, &authorization_id, NULL);
2921 2915 } else if (strcasecmp(name, "cnonce") == 0) {
2922 2916 _plug_strdup(sparams->utils, value, (char **) &cnonce, NULL);
2923 2917 } else if (strcasecmp(name, "nc") == 0) {
2924 2918 if (htoi((unsigned char *) value, &noncecount) != SASL_OK) {
2925 2919 #ifdef _SUN_SDK_
2926 2920 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2927 2921 "error converting hex to int");
2928 2922 #else
2929 2923 SETERROR(sparams->utils,
2930 2924 "error converting hex to int");
2931 2925 #endif /* _SUN_SDK_ */
2932 2926 result = SASL_BADAUTH;
2933 2927 goto FreeAllMem;
2934 2928 }
2935 2929 } else if (strcasecmp(name, "realm") == 0) {
2936 2930 if (realm) {
2937 2931 #ifdef _SUN_SDK_
2938 2932 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2939 2933 "duplicate realm: authentication aborted");
2940 2934 #else
2941 2935 SETERROR(sparams->utils,
2942 2936 "duplicate realm: authentication aborted");
2943 2937 #endif /* _SUN_SDK_ */
2944 2938 result = SASL_FAIL;
2945 2939 goto FreeAllMem;
2946 2940 }
2947 2941 _plug_strdup(sparams->utils, value, &realm, NULL);
2948 2942 } else if (strcasecmp(name, "nonce") == 0) {
2949 2943 _plug_strdup(sparams->utils, value, (char **) &nonce, NULL);
2950 2944 } else if (strcasecmp(name, "qop") == 0) {
2951 2945 _plug_strdup(sparams->utils, value, &qop, NULL);
2952 2946 } else if (strcasecmp(name, "digest-uri") == 0) {
2953 2947 size_t service_len;
2954 2948
2955 2949 /*
2956 2950 * digest-uri-value = serv-type "/" host [ "/" serv-name ]
2957 2951 */
2958 2952
2959 2953 _plug_strdup(sparams->utils, value, &digesturi, NULL);
2960 2954
2961 2955 /* verify digest-uri format */
2962 2956
2963 2957 /* make sure it's the service that we're expecting */
2964 2958 service_len = strlen(sparams->service);
2965 2959 if (strncasecmp(digesturi, sparams->service, service_len) ||
2966 2960 digesturi[service_len] != '/') {
2967 2961 result = SASL_BADAUTH;
2968 2962 #ifdef _SUN_SDK_
2969 2963 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2970 2964 "bad digest-uri: doesn't match service");
2971 2965 #else
2972 2966 SETERROR(sparams->utils,
2973 2967 "bad digest-uri: doesn't match service");
2974 2968 #endif /* _SUN_SDK_ */
2975 2969 goto FreeAllMem;
2976 2970 }
2977 2971
2978 2972 /* xxx we don't verify the hostname component */
2979 2973
2980 2974 } else if (strcasecmp(name, "response") == 0) {
2981 2975 _plug_strdup(sparams->utils, value, &response, NULL);
2982 2976 } else if (strcasecmp(name, "cipher") == 0) {
2983 2977 _plug_strdup(sparams->utils, value, &cipher, NULL);
2984 2978 } else if (strcasecmp(name, "maxbuf") == 0) {
2985 2979 maxbuf_count++;
2986 2980 if (maxbuf_count != 1) {
2987 2981 result = SASL_BADAUTH;
2988 2982 #ifdef _SUN_SDK_
2989 2983 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2990 2984 "duplicate maxbuf: authentication aborted");
2991 2985 #else
2992 2986 SETERROR(sparams->utils,
2993 2987 "duplicate maxbuf: authentication aborted");
2994 2988 #endif /* _SUN_SDK_ */
2995 2989 goto FreeAllMem;
2996 2990 } else if (sscanf(value, "%u", &client_maxbuf) != 1) {
2997 2991 result = SASL_BADAUTH;
2998 2992 #ifdef _SUN_SDK_
2999 2993 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3000 2994 "invalid maxbuf parameter");
3001 2995 #else
3002 2996 SETERROR(sparams->utils, "invalid maxbuf parameter");
3003 2997 #endif /* _SUN_SDK_ */
3004 2998 goto FreeAllMem;
3005 2999 } else {
3006 3000 if (client_maxbuf <= 16) {
3007 3001 result = SASL_BADAUTH;
3008 3002 #ifdef _SUN_SDK_
3009 3003 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3010 3004 "maxbuf parameter too small");
3011 3005 #else
3012 3006 SETERROR(sparams->utils,
3013 3007 "maxbuf parameter too small");
3014 3008 #endif /* _SUN_SDK_ */
3015 3009 goto FreeAllMem;
3016 3010 }
3017 3011 }
3018 3012 } else if (strcasecmp(name, "charset") == 0) {
3019 3013 if (strcasecmp(value, "utf-8") != 0) {
3020 3014 #ifdef _SUN_SDK_
3021 3015 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3022 3016 "client doesn't support UTF-8");
3023 3017 #else
3024 3018 SETERROR(sparams->utils, "client doesn't support UTF-8");
3025 3019 #endif /* _SUN_SDK_ */
3026 3020 result = SASL_FAIL;
3027 3021 goto FreeAllMem;
3028 3022 }
3029 3023 _plug_strdup(sparams->utils, value, &charset, NULL);
3030 3024 } else {
3031 3025 sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
3032 3026 "DIGEST-MD5 unrecognized pair %s/%s: ignoring",
3033 3027 name, value);
3034 3028 }
3035 3029 }
3036 3030
3037 3031 /*
3038 3032 * username = "username" "=" <"> username-value <">
3039 3033 * username-value = qdstr-val cnonce = "cnonce" "=" <">
3040 3034 * cnonce-value <"> cnonce-value = qdstr-val nonce-count = "nc"
3041 3035 * "=" nc-value nc-value = 8LHEX qop = "qop" "="
3042 3036 * qop-value digest-uri = "digest-uri" "=" digest-uri-value
3043 3037 * digest-uri-value = serv-type "/" host [ "/" serv-name ] serv-type
3044 3038 * = 1*ALPHA host = 1*( ALPHA | DIGIT | "-" | "." ) service
3045 3039 * = host response = "response" "=" <"> response-value <">
3046 3040 * response-value = 32LHEX LHEX = "0" | "1" | "2" | "3" | "4" | "5" |
3047 3041 * "6" | "7" | "8" | "9" | "a" | "b" | "c" | "d" | "e" | "f" cipher =
3048 3042 * "cipher" "=" cipher-value
3049 3043 */
3050 3044 /* Verifing that all parameters was defined */
3051 3045 if ((username == NULL) ||
3052 3046 (nonce == NULL) ||
3053 3047 (noncecount == 0) ||
3054 3048 (cnonce == NULL) ||
3055 3049 (digesturi == NULL) ||
3056 3050 (response == NULL)) {
3057 3051 #ifdef _SUN_SDK_
3058 3052 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3059 3053 "required parameters missing");
3060 3054 #else
3061 3055 SETERROR(sparams->utils, "required parameters missing");
3062 3056 #endif /* _SUN_SDK_ */
3063 3057 result = SASL_BADAUTH;
3064 3058 goto FreeAllMem;
3065 3059 }
3066 3060
3067 3061 if (text->state == 1) {
3068 3062 unsigned val = hash(username) % text->reauth->size;
3069 3063
3070 3064 /* reauth attempt, see if we have any info for this user */
3071 3065 if (sparams->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
3072 3066 if (text->reauth->e[val].authid &&
3073 3067 !strcmp(username, text->reauth->e[val].authid)) {
3074 3068
3075 3069 _plug_strdup(sparams->utils, text->reauth->e[val].realm,
3076 3070 &text->realm, NULL);
3077 3071 #ifdef _SUN_SDK_
3078 3072 _plug_strdup(sparams->utils, (char *)text->reauth->e[val].nonce,
3079 3073 (char **) &text->nonce, NULL);
3080 3074 #else
3081 3075 _plug_strdup(sparams->utils, text->reauth->e[val].nonce,
3082 3076 (char **) &text->nonce, NULL);
3083 3077 #endif /* _SUN_SDK_ */
3084 3078 text->nonce_count = ++text->reauth->e[val].nonce_count;
3085 3079 #ifdef _SUN_SDK_
3086 3080 _plug_strdup(sparams->utils, (char *)text->reauth->e[val].cnonce,
3087 3081 (char **) &text->cnonce, NULL);
3088 3082 #else
3089 3083 _plug_strdup(sparams->utils, text->reauth->e[val].cnonce,
3090 3084 (char **) &text->cnonce, NULL);
3091 3085 #endif /* _SUN_SDK_ */
3092 3086 stext->timestamp = text->reauth->e[val].u.s.timestamp;
3093 3087 }
3094 3088 sparams->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
3095 3089 }
3096 3090
3097 3091 if (!text->nonce) {
3098 3092 /* we don't have any reauth info, so bail */
3099 3093 result = SASL_FAIL;
3100 3094 goto FreeAllMem;
3101 3095 }
3102 3096 }
3103 3097
3104 3098 /* Sanity check the parameters */
3105 3099 #ifdef _SUN_SDK_
3106 3100 if ((realm != NULL && text->realm != NULL &&
3107 3101 strcmp(realm, text->realm) != 0) ||
3108 3102 (realm == NULL && text->realm != NULL) ||
3109 3103 (realm != NULL && text->realm == NULL)) {
3110 3104 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3111 3105 "realm changed: authentication aborted");
3112 3106 #else
3113 3107 if (strcmp(realm, text->realm) != 0) {
3114 3108 SETERROR(sparams->utils,
3115 3109 "realm changed: authentication aborted");
3116 3110 #endif /* _SUN_SDK_ */
3117 3111 result = SASL_BADAUTH;
3118 3112 goto FreeAllMem;
3119 3113 }
3120 3114 #ifdef _SUN_SDK_
3121 3115 if (strcmp((char *)nonce, (char *) text->nonce) != 0) {
3122 3116 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3123 3117 "nonce changed: authentication aborted");
3124 3118 #else
3125 3119 if (strcmp(nonce, (char *) text->nonce) != 0) {
3126 3120 SETERROR(sparams->utils,
3127 3121 "nonce changed: authentication aborted");
3128 3122 #endif /* _SUN_SKD_ */
3129 3123 result = SASL_BADAUTH;
3130 3124 goto FreeAllMem;
3131 3125 }
3132 3126 if (noncecount != text->nonce_count) {
3133 3127 #ifdef _SUN_SDK_
3134 3128 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3135 3129 "incorrect nonce-count: authentication aborted");
3136 3130 #else
3137 3131 SETERROR(sparams->utils,
3138 3132 "incorrect nonce-count: authentication aborted");
3139 3133 #endif /* _SUN_SDK_ */
3140 3134 result = SASL_BADAUTH;
3141 3135 goto FreeAllMem;
3142 3136 }
3143 3137 #ifdef _SUN_SDK_
3144 3138 if (text->cnonce && strcmp((char *)cnonce, (char *)text->cnonce) != 0) {
3145 3139 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3146 3140 "cnonce changed: authentication aborted");
3147 3141 #else
3148 3142 if (text->cnonce && strcmp(cnonce, text->cnonce) != 0) {
3149 3143 SETERROR(sparams->utils,
3150 3144 "cnonce changed: authentication aborted");
3151 3145 #endif /* _SUN_SDK_ */
3152 3146 result = SASL_BADAUTH;
3153 3147 goto FreeAllMem;
3154 3148 }
3155 3149
3156 3150 result = sparams->utils->prop_request(sparams->propctx, password_request);
3157 3151 if(result != SASL_OK) {
3158 3152 #ifdef _SUN_SDK_
3159 3153 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3160 3154 "unable to request user password");
3161 3155 #else
3162 3156 SETERROR(sparams->utils, "unable to resquest user password");
3163 3157 #endif /* _SUN_SDK_ */
3164 3158 goto FreeAllMem;
3165 3159 }
3166 3160
3167 3161 /* this will trigger the getting of the aux properties */
3168 3162 /* Note that if we don't have an authorization id, we don't use it... */
3169 3163 result = sparams->canon_user(sparams->utils->conn,
3170 3164 username, 0, SASL_CU_AUTHID, oparams);
3171 3165 if (result != SASL_OK) {
3172 3166 #ifdef _SUN_SDK_
3173 3167 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3174 3168 "unable canonify user and get auxprops");
3175 3169 #else
3176 3170 SETERROR(sparams->utils, "unable canonify user and get auxprops");
3177 3171 #endif /* _SUN_SDK_ */
3178 3172 goto FreeAllMem;
3179 3173 }
3180 3174
3181 3175 if (!authorization_id || !*authorization_id) {
3182 3176 result = sparams->canon_user(sparams->utils->conn,
3183 3177 username, 0, SASL_CU_AUTHZID, oparams);
3184 3178 } else {
3185 3179 result = sparams->canon_user(sparams->utils->conn,
3186 3180 authorization_id, 0, SASL_CU_AUTHZID,
3187 3181 oparams);
3188 3182 }
3189 3183
3190 3184 if (result != SASL_OK) {
3191 3185 #ifdef _SUN_SDK_
3192 3186 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3193 3187 "unable to canonicalize authorization ID");
3194 3188 #else
3195 3189 SETERROR(sparams->utils, "unable authorization ID");
3196 3190 #endif /* _SUN_SDK_ */
3197 3191 goto FreeAllMem;
3198 3192 }
3199 3193
3200 3194 result = sparams->utils->prop_getnames(sparams->propctx, password_request,
3201 3195 auxprop_values);
3202 3196 if (result < 0 ||
3203 3197 ((!auxprop_values[0].name || !auxprop_values[0].values) &&
3204 3198 (!auxprop_values[1].name || !auxprop_values[1].values))) {
3205 3199 /* We didn't find this username */
3206 3200 #ifdef _INTEGRATED_SOLARIS_
3207 3201 sparams->utils->seterror(sparams->utils->conn, 0,
3208 3202 gettext("no secret in database"));
3209 3203 #else
3210 3204 sparams->utils->seterror(sparams->utils->conn, 0,
3211 3205 "no secret in database");
3212 3206 #endif /* _INTEGRATED_SOLARIS_ */
3213 3207 result = SASL_NOUSER;
3214 3208 goto FreeAllMem;
3215 3209 }
3216 3210
3217 3211 if (auxprop_values[0].name && auxprop_values[0].values) {
3218 3212 len = strlen(auxprop_values[0].values[0]);
3219 3213 if (len == 0) {
3220 3214 #ifdef _INTEGRATED_SOLARIS_
3221 3215 sparams->utils->seterror(sparams->utils->conn,0,
3222 3216 gettext("empty secret"));
3223 3217 #else
3224 3218 sparams->utils->seterror(sparams->utils->conn,0,
3225 3219 "empty secret");
3226 3220 #endif /* _INTEGRATED_SOLARIS_ */
3227 3221 result = SASL_FAIL;
3228 3222 goto FreeAllMem;
3229 3223 }
3230 3224
3231 3225 sec = sparams->utils->malloc(sizeof(sasl_secret_t) + len);
3232 3226 if (!sec) {
3233 3227 #ifdef _SUN_SDK_
3234 3228 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3235 3229 "unable to allocate secret");
3236 3230 #else
3237 3231 SETERROR(sparams->utils, "unable to allocate secret");
3238 3232 #endif /* _SUN_SDK_ */
3239 3233 result = SASL_FAIL;
3240 3234 goto FreeAllMem;
3241 3235 }
3242 3236
3243 3237 sec->len = len;
3244 3238 #ifdef _SUN_SDK_
3245 3239 strncpy((char *)sec->data, auxprop_values[0].values[0], len + 1);
3246 3240 #else
3247 3241 strncpy(sec->data, auxprop_values[0].values[0], len + 1);
3248 3242 #endif /* _SUN_SDK_ */
3249 3243
3250 3244 /*
3251 3245 * Verifying response obtained from client
3252 3246 *
3253 3247 * H_URP = H({ username-value,":",realm-value,":",passwd}) sec->data
3254 3248 * contains H_URP
3255 3249 */
3256 3250
3257 3251 /* Calculate the secret from the plaintext password */
3258 3252 {
3259 3253 HASH HA1;
3260 3254
3261 3255 #ifdef _SUN_SDK_
3262 3256 DigestCalcSecret(sparams->utils, (unsigned char *)username,
3263 3257 (unsigned char *)text->realm, sec->data,
3264 3258 sec->len, HA1);
3265 3259 #else
3266 3260 DigestCalcSecret(sparams->utils, username,
3267 3261 text->realm, sec->data, sec->len, HA1);
3268 3262 #endif /* _SUN_SDK_ */
3269 3263
3270 3264 /*
3271 3265 * A1 = { H( { username-value, ":", realm-value, ":", passwd } ),
3272 3266 * ":", nonce-value, ":", cnonce-value }
3273 3267 */
3274 3268
3275 3269 memcpy(A1, HA1, HASHLEN);
3276 3270 A1[HASHLEN] = '\0';
3277 3271 }
3278 3272
3279 3273 /* We're done with sec now. Let's get rid of it */
3280 3274 _plug_free_secret(sparams->utils, &sec);
3281 3275 } else if (auxprop_values[1].name && auxprop_values[1].values) {
3282 3276 memcpy(A1, auxprop_values[1].values[0], HASHLEN);
3283 3277 A1[HASHLEN] = '\0';
3284 3278 } else {
3285 3279 #ifdef _SUN_SDK_
3286 3280 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3287 3281 "Have neither type of secret");
3288 3282 #else
3289 3283 sparams->utils->seterror(sparams->utils->conn, 0,
3290 3284 "Have neither type of secret");
3291 3285 #endif /* _SUN_SDK_ */
3292 3286 #ifdef _SUN_SDK_
3293 3287 result = SASL_FAIL;
3294 3288 goto FreeAllMem;
3295 3289 #else
3296 3290 return SASL_FAIL;
3297 3291 #endif /* _SUN_SDK_ */
3298 3292 }
3299 3293
3300 3294 /* defaulting qop to "auth" if not specified */
3301 3295 if (qop == NULL) {
3302 3296 _plug_strdup(sparams->utils, "auth", &qop, NULL);
3303 3297 }
3304 3298
3305 3299 /* check which layer/cipher to use */
3306 3300 if ((!strcasecmp(qop, "auth-conf")) && (cipher != NULL)) {
3307 3301 /* see what cipher was requested */
3308 3302 struct digest_cipher *cptr;
3309 3303
3310 3304 #ifdef USE_UEF_SERVER
3311 3305 cptr = available_ciphers1;
3312 3306 #else
3313 3307 cptr = available_ciphers;
3314 3308 #endif
3315 3309 while (cptr->name) {
3316 3310 /* find the cipher requested & make sure it's one we're happy
3317 3311 with by policy */
3318 3312 if (!strcasecmp(cipher, cptr->name) &&
3319 3313 stext->requiressf <= cptr->ssf &&
3320 3314 stext->limitssf >= cptr->ssf) {
3321 3315 /* found it! */
3322 3316 break;
3323 3317 }
3324 3318 cptr++;
3325 3319 }
3326 3320
3327 3321 if (cptr->name) {
3328 3322 text->cipher_enc = cptr->cipher_enc;
3329 3323 text->cipher_dec = cptr->cipher_dec;
3330 3324 text->cipher_init = cptr->cipher_init;
3331 3325 text->cipher_free = cptr->cipher_free;
3332 3326 oparams->mech_ssf = cptr->ssf;
3333 3327 n = cptr->n;
3334 3328 } else {
3335 3329 /* erg? client requested something we didn't advertise! */
3336 3330 sparams->utils->log(sparams->utils->conn, SASL_LOG_WARN,
3337 3331 "protocol violation: client requested invalid cipher");
3338 3332 #ifndef _SUN_SDK_
3339 3333 SETERROR(sparams->utils, "client requested invalid cipher");
3340 3334 #endif /* !_SUN_SDK_ */
3341 3335 /* Mark that we attempted security layer negotiation */
3342 3336 oparams->mech_ssf = 2;
3343 3337 result = SASL_FAIL;
3344 3338 goto FreeAllMem;
3345 3339 }
3346 3340
3347 3341 oparams->encode=&digestmd5_privacy_encode;
3348 3342 oparams->decode=&digestmd5_privacy_decode;
3349 3343 } else if (!strcasecmp(qop, "auth-int") &&
3350 3344 stext->requiressf <= 1 && stext->limitssf >= 1) {
3351 3345 oparams->encode = &digestmd5_integrity_encode;
3352 3346 oparams->decode = &digestmd5_integrity_decode;
3353 3347 oparams->mech_ssf = 1;
3354 3348 } else if (!strcasecmp(qop, "auth") && stext->requiressf == 0) {
3355 3349 oparams->encode = NULL;
3356 3350 oparams->decode = NULL;
3357 3351 oparams->mech_ssf = 0;
3358 3352 } else {
3359 3353 #ifdef _SUN_SDK_
3360 3354 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3361 3355 "protocol violation: client requested invalid qop");
3362 3356 #else
3363 3357 SETERROR(sparams->utils,
3364 3358 "protocol violation: client requested invalid qop");
3365 3359 #endif /* _SUN_SDK_ */
3366 3360 result = SASL_FAIL;
3367 3361 goto FreeAllMem;
3368 3362 }
3369 3363
3370 3364 serverresponse = create_response(text,
3371 3365 sparams->utils,
3372 3366 text->nonce,
3373 3367 text->nonce_count,
3374 3368 cnonce,
3375 3369 qop,
3376 3370 digesturi,
3377 3371 A1,
3378 3372 authorization_id,
3379 3373 &text->response_value);
3380 3374
3381 3375 if (serverresponse == NULL) {
3382 3376 #ifndef _SUN_SDK_
3383 3377 SETERROR(sparams->utils, "internal error: unable to create response");
3384 3378 #endif /* !_SUN_SDK_ */
3385 3379 result = SASL_NOMEM;
3386 3380 goto FreeAllMem;
3387 3381 }
3388 3382
3389 3383 /* if ok verified */
3390 3384 if (strcmp(serverresponse, response) != 0) {
3391 3385 #ifdef _INTEGRATED_SOLARIS_
3392 3386 SETERROR(sparams->utils,
3393 3387 gettext("client response doesn't match what we generated"));
3394 3388 #else
3395 3389 SETERROR(sparams->utils,
3396 3390 "client response doesn't match what we generated");
3397 3391 #endif /* _INTEGRATED_SOLARIS_ */
3398 3392 result = SASL_BADAUTH;
3399 3393
3400 3394 goto FreeAllMem;
3401 3395 }
3402 3396
3403 3397 /* see if our nonce expired */
3404 3398 if (text->reauth->timeout &&
3405 3399 time(0) - stext->timestamp > text->reauth->timeout) {
3406 3400 #ifdef _INTEGRATED_SOLARIS_
3407 3401 SETERROR(sparams->utils, gettext("server nonce expired"));
3408 3402 #else
3409 3403 SETERROR(sparams->utils, "server nonce expired");
3410 3404 #endif /* _INTEGRATED_SOLARIS_ */
3411 3405 stext->stale = 1;
3412 3406 result = SASL_BADAUTH;
3413 3407
3414 3408 goto FreeAllMem;
3415 3409 }
3416 3410
3417 3411 /*
3418 3412 * nothing more to do; authenticated set oparams information
3419 3413 */
3420 3414 oparams->doneflag = 1;
3421 3415 oparams->maxoutbuf = client_maxbuf - 4;
3422 3416 if (oparams->mech_ssf > 1) {
3423 3417 #ifdef _SUN_SDK_
3424 3418 if (oparams->maxoutbuf <= 25) {
3425 3419 result = SASL_BADPARAM;
3426 3420 goto FreeAllMem;
3427 3421 }
3428 3422 #endif
3429 3423 /* MAC block (privacy) */
3430 3424 oparams->maxoutbuf -= 25;
3431 3425 } else if(oparams->mech_ssf == 1) {
3432 3426 #ifdef _SUN_SDK_
3433 3427 if (oparams->maxoutbuf <= 16) {
3434 3428 result = SASL_BADPARAM;
3435 3429 goto FreeAllMem;
3436 3430 }
3437 3431 #endif
3438 3432 /* MAC block (integrity) */
3439 3433 oparams->maxoutbuf -= 16;
3440 3434 }
3441 3435
3442 3436 oparams->param_version = 0;
3443 3437
3444 3438 text->seqnum = 0; /* for integrity/privacy */
3445 3439 text->rec_seqnum = 0; /* for integrity/privacy */
3446 3440 text->in_maxbuf =
3447 3441 sparams->props.maxbufsize ? sparams->props.maxbufsize : DEFAULT_BUFSIZE;
3448 3442 text->utils = sparams->utils;
3449 3443
3450 3444 /* used by layers */
3451 3445 text->needsize = 4;
3452 3446 text->buffer = NULL;
3453 3447
3454 3448 if (oparams->mech_ssf > 0) {
3455 3449 char enckey[16];
3456 3450 char deckey[16];
3457 3451
3458 3452 create_layer_keys(text, sparams->utils,text->HA1,n,enckey,deckey);
3459 3453
3460 3454 /* initialize cipher if need be */
3461 3455 #ifdef _SUN_SDK_
3462 3456 if (text->cipher_init) {
3463 3457 if (text->cipher_free)
3464 3458 text->cipher_free(text);
3465 3459 if ((result = text->cipher_init(text, enckey, deckey)) != SASL_OK) {
3466 3460 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3467 3461 "couldn't init cipher");
3468 3462 goto FreeAllMem;
3469 3463 }
3470 3464 }
3471 3465 #else
3472 3466 if (text->cipher_init)
3473 3467 if (text->cipher_init(text, enckey, deckey) != SASL_OK) {
3474 3468 sparams->utils->seterror(sparams->utils->conn, 0,
3475 3469 "couldn't init cipher");
3476 3470 }
3477 3471 #endif /* _SUN_SDK_ */
3478 3472 }
3479 3473
3480 3474 /*
3481 3475 * The server receives and validates the "digest-response". The server
3482 3476 * checks that the nonce-count is "00000001". If it supports subsequent
3483 3477 * authentication, it saves the value of the nonce and the nonce-count.
3484 3478 */
3485 3479
3486 3480 /*
3487 3481 * The "username-value", "realm-value" and "passwd" are encoded according
3488 3482 * to the value of the "charset" directive. If "charset=UTF-8" is
3489 3483 * present, and all the characters of either "username-value" or "passwd"
3490 3484 * are in the ISO 8859-1 character set, then it must be converted to
3491 3485 * UTF-8 before being hashed. A sample implementation of this conversion
3492 3486 * is in section 8.
3493 3487 */
3494 3488
3495 3489 /* add to challenge */
3496 3490 {
3497 3491 unsigned resplen =
3498 3492 strlen(text->response_value) + strlen("rspauth") + 3;
3499 3493
3500 3494 result = _plug_buf_alloc(sparams->utils, &(text->out_buf),
3501 3495 &(text->out_buf_len), resplen);
3502 3496 if(result != SASL_OK) {
3503 3497 goto FreeAllMem;
3504 3498 }
3505 3499
3506 3500 sprintf(text->out_buf, "rspauth=%s", text->response_value);
3507 3501
3508 3502 /* self check */
3509 3503 if (strlen(text->out_buf) > 2048) {
3510 3504 result = SASL_FAIL;
3511 3505 goto FreeAllMem;
3512 3506 }
3513 3507 }
3514 3508
3515 3509 *serveroutlen = strlen(text->out_buf);
3516 3510 *serverout = text->out_buf;
3517 3511
3518 3512 result = SASL_OK;
3519 3513
3520 3514 FreeAllMem:
3521 3515 if (text->reauth->timeout &&
3522 3516 sparams->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
3523 3517 unsigned val = hash(username) % text->reauth->size;
3524 3518
3525 3519 switch (result) {
3526 3520 case SASL_OK:
3527 3521 /* successful auth, setup for future reauth */
3528 3522 if (text->nonce_count == 1) {
3529 3523 /* successful initial auth, create new entry */
3530 3524 clear_reauth_entry(&text->reauth->e[val], SERVER, sparams->utils);
3531 3525 text->reauth->e[val].authid = username; username = NULL;
3532 3526 text->reauth->e[val].realm = text->realm; text->realm = NULL;
3533 3527 text->reauth->e[val].nonce = text->nonce; text->nonce = NULL;
3534 3528 text->reauth->e[val].cnonce = cnonce; cnonce = NULL;
3535 3529 }
3536 3530 if (text->nonce_count <= text->reauth->e[val].nonce_count) {
3537 3531 /* paranoia. prevent replay attacks */
3538 3532 clear_reauth_entry(&text->reauth->e[val], SERVER, sparams->utils);
3539 3533 }
3540 3534 else {
3541 3535 text->reauth->e[val].nonce_count = text->nonce_count;
3542 3536 text->reauth->e[val].u.s.timestamp = time(0);
3543 3537 }
3544 3538 break;
3545 3539 default:
3546 3540 if (text->nonce_count > 1) {
3547 3541 /* failed reauth, clear entry */
3548 3542 clear_reauth_entry(&text->reauth->e[val], SERVER, sparams->utils);
3549 3543 }
3550 3544 else {
3551 3545 /* failed initial auth, leave existing cache */
3552 3546 }
3553 3547 }
3554 3548 sparams->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
3555 3549 }
3556 3550
3557 3551 /* free everything */
3558 3552 if (in_start) sparams->utils->free (in_start);
3559 3553
3560 3554 if (username != NULL)
3561 3555 sparams->utils->free (username);
3562 3556 #ifdef _SUN_SDK_
3563 3557 if (authorization_id != NULL)
3564 3558 sparams->utils->free (authorization_id);
3565 3559 #endif /* _SUN_SDK_ */
3566 3560 if (realm != NULL)
3567 3561 sparams->utils->free (realm);
3568 3562 if (nonce != NULL)
3569 3563 sparams->utils->free (nonce);
3570 3564 if (cnonce != NULL)
3571 3565 sparams->utils->free (cnonce);
3572 3566 if (response != NULL)
3573 3567 sparams->utils->free (response);
3574 3568 if (cipher != NULL)
3575 3569 sparams->utils->free (cipher);
3576 3570 if (serverresponse != NULL)
3577 3571 sparams->utils->free(serverresponse);
3578 3572 if (charset != NULL)
3579 3573 sparams->utils->free (charset);
3580 3574 if (digesturi != NULL)
3581 3575 sparams->utils->free (digesturi);
3582 3576 if (qop!=NULL)
3583 3577 sparams->utils->free (qop);
3584 3578 if (sec)
3585 3579 _plug_free_secret(sparams->utils, &sec);
3586 3580
3587 3581 return result;
3588 3582 }
3589 3583
3590 3584 static int
3591 3585 digestmd5_server_mech_step(void *conn_context,
3592 3586 sasl_server_params_t *sparams,
3593 3587 const char *clientin,
3594 3588 unsigned clientinlen,
3595 3589 const char **serverout,
3596 3590 unsigned *serveroutlen,
3597 3591 sasl_out_params_t *oparams)
3598 3592 {
3599 3593 context_t *text = (context_t *) conn_context;
3600 3594 server_context_t *stext = (server_context_t *) conn_context;
3601 3595
3602 3596 if (clientinlen > 4096) return SASL_BADPROT;
3603 3597
3604 3598 *serverout = NULL;
3605 3599 *serveroutlen = 0;
3606 3600
3607 3601 switch (text->state) {
3608 3602
3609 3603 case 1:
3610 3604 /* setup SSF limits */
3611 3605 if (!sparams->props.maxbufsize) {
3612 3606 stext->limitssf = 0;
3613 3607 stext->requiressf = 0;
3614 3608 } else {
3615 3609 if (sparams->props.max_ssf < sparams->external_ssf) {
3616 3610 stext->limitssf = 0;
3617 3611 } else {
3618 3612 stext->limitssf =
3619 3613 sparams->props.max_ssf - sparams->external_ssf;
3620 3614 }
3621 3615 if (sparams->props.min_ssf < sparams->external_ssf) {
3622 3616 stext->requiressf = 0;
3623 3617 } else {
3624 3618 stext->requiressf =
3625 3619 sparams->props.min_ssf - sparams->external_ssf;
3626 3620 }
3627 3621 }
3628 3622
3629 3623 if (clientin && text->reauth->timeout) {
3630 3624 /* here's where we attempt fast reauth if possible */
3631 3625 if (digestmd5_server_mech_step2(stext, sparams,
3632 3626 clientin, clientinlen,
3633 3627 serverout, serveroutlen,
3634 3628 oparams) == SASL_OK) {
3635 3629 return SASL_OK;
3636 3630 }
3637 3631
3638 3632 #ifdef _SUN_SDK_
3639 3633 sparams->utils->log(sparams->utils->conn, SASL_LOG_WARN,
3640 3634 "DIGEST-MD5 reauth failed");
3641 3635 #else
3642 3636 sparams->utils->log(NULL, SASL_LOG_WARN,
3643 3637 "DIGEST-MD5 reauth failed\n");
3644 3638 #endif /* _SUN_SDK_ */
3645 3639
3646 3640 /* re-initialize everything for a fresh start */
3647 3641 memset(oparams, 0, sizeof(sasl_out_params_t));
3648 3642
3649 3643 /* fall through and issue challenge */
3650 3644 }
3651 3645
3652 3646 return digestmd5_server_mech_step1(stext, sparams,
3653 3647 clientin, clientinlen,
3654 3648 serverout, serveroutlen, oparams);
3655 3649
3656 3650 case 2:
3657 3651 return digestmd5_server_mech_step2(stext, sparams,
3658 3652 clientin, clientinlen,
3659 3653 serverout, serveroutlen, oparams);
3660 3654
3661 3655 default:
3662 3656 #ifdef _SUN_SDK_
3663 3657 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3664 3658 "Invalid DIGEST-MD5 server step %d", text->state);
3665 3659 #else
3666 3660 sparams->utils->log(NULL, SASL_LOG_ERR,
3667 3661 "Invalid DIGEST-MD5 server step %d\n", text->state);
3668 3662 #endif /* _SUN_SDK_ */
3669 3663 return SASL_FAIL;
3670 3664 }
3671 3665
3672 3666 #ifndef _SUN_SDK_
3673 3667 return SASL_FAIL; /* should never get here */
3674 3668 #endif /* !_SUN_SDK_ */
3675 3669 }
3676 3670
3677 3671 static void
3678 3672 digestmd5_server_mech_dispose(void *conn_context, const sasl_utils_t *utils)
3679 3673 {
3680 3674 server_context_t *stext = (server_context_t *) conn_context;
↓ open down ↓ |
2464 lines elided |
↑ open up ↑ |
3681 3675
3682 3676 if (!stext || !utils) return;
3683 3677
3684 3678 digestmd5_common_mech_dispose(conn_context, utils);
3685 3679 }
3686 3680
3687 3681 static sasl_server_plug_t digestmd5_server_plugins[] =
3688 3682 {
3689 3683 {
3690 3684 "DIGEST-MD5", /* mech_name */
3691 - /* EXPORT DELETE START */
3692 3685 #ifdef WITH_RC4
3693 3686 128, /* max_ssf */
3694 3687 #elif WITH_DES
3695 3688 112,
3696 3689 #else
3697 - /* EXPORT DELETE END */
3698 3690 0,
3699 - /* EXPORT DELETE START */
3700 3691 #endif
3701 - /* EXPORT DELETE END */
3702 3692 SASL_SEC_NOPLAINTEXT
3703 3693 | SASL_SEC_NOANONYMOUS
3704 3694 | SASL_SEC_MUTUAL_AUTH, /* security_flags */
3705 3695 SASL_FEAT_ALLOWS_PROXY, /* features */
3706 3696 NULL, /* glob_context */
3707 3697 &digestmd5_server_mech_new, /* mech_new */
3708 3698 &digestmd5_server_mech_step, /* mech_step */
3709 3699 &digestmd5_server_mech_dispose, /* mech_dispose */
3710 3700 &digestmd5_common_mech_free, /* mech_free */
3711 3701 NULL, /* setpass */
3712 3702 NULL, /* user_query */
3713 3703 NULL, /* idle */
3714 3704 NULL, /* mech avail */
3715 3705 NULL /* spare */
3716 3706 }
3717 3707 };
3718 3708
3719 3709 int digestmd5_server_plug_init(sasl_utils_t *utils,
3720 3710 int maxversion,
3721 3711 int *out_version,
3722 3712 sasl_server_plug_t **pluglist,
3723 3713 int *plugcount)
3724 3714 {
3725 3715 reauth_cache_t *reauth_cache;
3726 3716 const char *timeout = NULL;
3727 3717 unsigned int len;
3728 3718 #if defined _SUN_SDK_ && defined USE_UEF
3729 3719 int ret;
3730 3720 #endif /* _SUN_SDK_ && USE_UEF */
3731 3721
3732 3722 if (maxversion < SASL_SERVER_PLUG_VERSION)
3733 3723 return SASL_BADVERS;
3734 3724
3735 3725 #if defined _SUN_SDK_ && defined USE_UEF
3736 3726 if ((ret = uef_init(utils)) != SASL_OK)
3737 3727 return ret;
3738 3728 #endif /* _SUN_SDK_ && USE_UEF */
3739 3729
3740 3730 /* reauth cache */
3741 3731 reauth_cache = utils->malloc(sizeof(reauth_cache_t));
3742 3732 if (reauth_cache == NULL)
3743 3733 return SASL_NOMEM;
3744 3734 memset(reauth_cache, 0, sizeof(reauth_cache_t));
3745 3735 reauth_cache->i_am = SERVER;
3746 3736
3747 3737 /* fetch and canonify the reauth_timeout */
3748 3738 utils->getopt(utils->getopt_context, "DIGEST-MD5", "reauth_timeout",
3749 3739 &timeout, &len);
3750 3740 if (timeout)
3751 3741 reauth_cache->timeout = (time_t) 60 * strtol(timeout, NULL, 10);
3752 3742 #ifdef _SUN_SDK_
3753 3743 else
3754 3744 reauth_cache->timeout = 0;
3755 3745 #endif /* _SUN_SDK_ */
3756 3746 if (reauth_cache->timeout < 0)
3757 3747 reauth_cache->timeout = 0;
3758 3748
3759 3749 if (reauth_cache->timeout) {
3760 3750 /* mutex */
3761 3751 reauth_cache->mutex = utils->mutex_alloc();
3762 3752 if (!reauth_cache->mutex)
3763 3753 return SASL_FAIL;
3764 3754
3765 3755 /* entries */
3766 3756 reauth_cache->size = 100;
3767 3757 reauth_cache->e = utils->malloc(reauth_cache->size *
3768 3758 sizeof(reauth_entry_t));
3769 3759 if (reauth_cache->e == NULL)
3770 3760 return SASL_NOMEM;
3771 3761 memset(reauth_cache->e, 0, reauth_cache->size * sizeof(reauth_entry_t));
↓ open down ↓ |
60 lines elided |
↑ open up ↑ |
3772 3762 }
3773 3763
3774 3764 digestmd5_server_plugins[0].glob_context = reauth_cache;
3775 3765
3776 3766 #ifdef _SUN_SDK_
3777 3767 #ifdef USE_UEF_CLIENT
3778 3768 digestmd5_server_plugins[0].max_ssf = uef_max_ssf;
3779 3769 #endif /* USE_UEF_CLIENT */
3780 3770 #endif /* _SUN_SDK_ */
3781 3771
3782 - /* EXPORT DELETE START */
3783 - /* CRYPT DELETE START */
3784 3772 #ifdef _INTEGRATED_SOLARIS_
3785 3773 /*
3786 3774 * Let libsasl know that we are a "Sun" plugin so that privacy
3787 3775 * and integrity will be allowed.
3788 3776 */
3789 3777 REG_PLUG("DIGEST-MD5", digestmd5_server_plugins);
3790 3778 #endif /* _INTEGRATED_SOLARIS_ */
3791 - /* CRYPT DELETE END */
3792 - /* EXPORT DELETE END */
3793 3779
3794 3780 *out_version = SASL_SERVER_PLUG_VERSION;
3795 3781 *pluglist = digestmd5_server_plugins;
3796 3782 *plugcount = 1;
3797 3783
3798 3784 return SASL_OK;
3799 3785 }
3800 3786
3801 3787 /***************************** Client Section *****************************/
3802 3788
3803 3789 typedef struct client_context {
3804 3790 context_t common;
3805 3791
3806 3792 sasl_secret_t *password; /* user password */
3807 3793 unsigned int free_password; /* set if we need to free password */
3808 3794
3809 3795 int protection;
3810 3796 struct digest_cipher *cipher;
3811 3797 unsigned int server_maxbuf;
3812 3798 #ifdef _INTEGRATED_SOLARIS_
3813 3799 void *h;
3814 3800 #endif /* _INTEGRATED_SOLARIS_ */
3815 3801 } client_context_t;
3816 3802
3817 3803 /* calculate H(A1) as per spec */
3818 3804 static void
3819 3805 DigestCalcHA1(context_t * text,
3820 3806 const sasl_utils_t * utils,
3821 3807 unsigned char *pszUserName,
3822 3808 unsigned char *pszRealm,
3823 3809 sasl_secret_t * pszPassword,
3824 3810 unsigned char *pszAuthorization_id,
3825 3811 unsigned char *pszNonce,
3826 3812 unsigned char *pszCNonce,
3827 3813 HASHHEX SessionKey)
3828 3814 {
3829 3815 MD5_CTX Md5Ctx;
3830 3816 HASH HA1;
3831 3817
3832 3818 DigestCalcSecret(utils,
3833 3819 pszUserName,
3834 3820 pszRealm,
3835 3821 (unsigned char *) pszPassword->data,
3836 3822 pszPassword->len,
3837 3823 HA1);
3838 3824
3839 3825 /* calculate the session key */
3840 3826 utils->MD5Init(&Md5Ctx);
3841 3827 utils->MD5Update(&Md5Ctx, HA1, HASHLEN);
3842 3828 utils->MD5Update(&Md5Ctx, COLON, 1);
3843 3829 utils->MD5Update(&Md5Ctx, pszNonce, strlen((char *) pszNonce));
3844 3830 utils->MD5Update(&Md5Ctx, COLON, 1);
3845 3831 utils->MD5Update(&Md5Ctx, pszCNonce, strlen((char *) pszCNonce));
3846 3832 if (pszAuthorization_id != NULL) {
3847 3833 utils->MD5Update(&Md5Ctx, COLON, 1);
3848 3834 utils->MD5Update(&Md5Ctx, pszAuthorization_id,
3849 3835 strlen((char *) pszAuthorization_id));
3850 3836 }
3851 3837 utils->MD5Final(HA1, &Md5Ctx);
3852 3838
3853 3839 CvtHex(HA1, SessionKey);
3854 3840
3855 3841 /* xxx rc-* use different n */
3856 3842
3857 3843 /* save HA1 because we'll need it for the privacy and integrity keys */
3858 3844 memcpy(text->HA1, HA1, sizeof(HASH));
3859 3845
3860 3846 }
3861 3847
3862 3848 static char *calculate_response(context_t * text,
3863 3849 const sasl_utils_t * utils,
3864 3850 unsigned char *username,
3865 3851 unsigned char *realm,
3866 3852 unsigned char *nonce,
3867 3853 unsigned int ncvalue,
3868 3854 unsigned char *cnonce,
3869 3855 char *qop,
3870 3856 unsigned char *digesturi,
3871 3857 sasl_secret_t * passwd,
3872 3858 unsigned char *authorization_id,
3873 3859 char **response_value)
3874 3860 {
3875 3861 HASHHEX SessionKey;
3876 3862 HASHHEX HEntity = "00000000000000000000000000000000";
3877 3863 HASHHEX Response;
3878 3864 char *result;
3879 3865
3880 3866 /* Verifing that all parameters was defined */
3881 3867 if(!username || !cnonce || !nonce || !ncvalue || !digesturi || !passwd) {
3882 3868 PARAMERROR( utils );
3883 3869 return NULL;
3884 3870 }
3885 3871
3886 3872 if (realm == NULL) {
3887 3873 /* a NULL realm is equivalent to the empty string */
3888 3874 realm = (unsigned char *) "";
3889 3875 }
3890 3876
3891 3877 if (qop == NULL) {
3892 3878 /* default to a qop of just authentication */
3893 3879 qop = "auth";
3894 3880 }
3895 3881
3896 3882 DigestCalcHA1(text,
3897 3883 utils,
3898 3884 username,
3899 3885 realm,
3900 3886 passwd,
3901 3887 authorization_id,
3902 3888 nonce,
3903 3889 cnonce,
3904 3890 SessionKey);
3905 3891
3906 3892 DigestCalcResponse(utils,
3907 3893 SessionKey,/* H(A1) */
3908 3894 nonce, /* nonce from server */
3909 3895 ncvalue, /* 8 hex digits */
3910 3896 cnonce, /* client nonce */
3911 3897 (unsigned char *) qop, /* qop-value: "", "auth",
3912 3898 * "auth-int" */
3913 3899 digesturi, /* requested URL */
3914 3900 (unsigned char *) "AUTHENTICATE",
3915 3901 HEntity, /* H(entity body) if qop="auth-int" */
3916 3902 Response /* request-digest or response-digest */
3917 3903 );
3918 3904
3919 3905 result = utils->malloc(HASHHEXLEN + 1);
3920 3906 #ifdef _SUN_SDK_
3921 3907 if (result == NULL)
3922 3908 return NULL;
3923 3909 #endif /* _SUN_SDK_ */
3924 3910 memcpy(result, Response, HASHHEXLEN);
3925 3911 result[HASHHEXLEN] = 0;
3926 3912
3927 3913 if (response_value != NULL) {
3928 3914 DigestCalcResponse(utils,
3929 3915 SessionKey, /* H(A1) */
3930 3916 nonce, /* nonce from server */
3931 3917 ncvalue, /* 8 hex digits */
3932 3918 cnonce, /* client nonce */
3933 3919 (unsigned char *) qop, /* qop-value: "", "auth",
3934 3920 * "auth-int" */
3935 3921 (unsigned char *) digesturi, /* requested URL */
3936 3922 NULL,
3937 3923 HEntity, /* H(entity body) if qop="auth-int" */
3938 3924 Response /* request-digest or response-digest */
3939 3925 );
3940 3926
3941 3927 #ifdef _SUN_SDK_
3942 3928 if (*response_value != NULL)
3943 3929 utils->free(*response_value);
3944 3930 #endif /* _SUN_SDK_ */
3945 3931 *response_value = utils->malloc(HASHHEXLEN + 1);
3946 3932 if (*response_value == NULL)
3947 3933 return NULL;
3948 3934
3949 3935 memcpy(*response_value, Response, HASHHEXLEN);
3950 3936 (*response_value)[HASHHEXLEN] = 0;
3951 3937
3952 3938 }
3953 3939
3954 3940 return result;
3955 3941 }
3956 3942
3957 3943 static int
3958 3944 make_client_response(context_t *text,
3959 3945 sasl_client_params_t *params,
3960 3946 sasl_out_params_t *oparams)
3961 3947 {
3962 3948 client_context_t *ctext = (client_context_t *) text;
3963 3949 char *qop = NULL;
3964 3950 unsigned nbits = 0;
3965 3951 unsigned char *digesturi = NULL;
3966 3952 bool IsUTF8 = FALSE;
3967 3953 char ncvalue[10];
3968 3954 char maxbufstr[64];
3969 3955 char *response = NULL;
3970 3956 unsigned resplen = 0;
3971 3957 int result;
3972 3958
3973 3959 switch (ctext->protection) {
3974 3960 case DIGEST_PRIVACY:
3975 3961 qop = "auth-conf";
3976 3962 oparams->encode = &digestmd5_privacy_encode;
3977 3963 oparams->decode = &digestmd5_privacy_decode;
3978 3964 oparams->mech_ssf = ctext->cipher->ssf;
3979 3965
3980 3966 nbits = ctext->cipher->n;
3981 3967 text->cipher_enc = ctext->cipher->cipher_enc;
3982 3968 text->cipher_dec = ctext->cipher->cipher_dec;
3983 3969 text->cipher_free = ctext->cipher->cipher_free;
3984 3970 text->cipher_init = ctext->cipher->cipher_init;
3985 3971 break;
3986 3972 case DIGEST_INTEGRITY:
3987 3973 qop = "auth-int";
3988 3974 oparams->encode = &digestmd5_integrity_encode;
3989 3975 oparams->decode = &digestmd5_integrity_decode;
3990 3976 oparams->mech_ssf = 1;
3991 3977 break;
3992 3978 case DIGEST_NOLAYER:
3993 3979 default:
3994 3980 qop = "auth";
3995 3981 oparams->encode = NULL;
3996 3982 oparams->decode = NULL;
3997 3983 oparams->mech_ssf = 0;
3998 3984 }
3999 3985
4000 3986 digesturi = params->utils->malloc(strlen(params->service) + 1 +
4001 3987 strlen(params->serverFQDN) + 1 +
4002 3988 1);
4003 3989 if (digesturi == NULL) {
4004 3990 result = SASL_NOMEM;
4005 3991 goto FreeAllocatedMem;
4006 3992 };
4007 3993
4008 3994 /* allocated exactly this. safe */
4009 3995 strcpy((char *) digesturi, params->service);
4010 3996 strcat((char *) digesturi, "/");
4011 3997 strcat((char *) digesturi, params->serverFQDN);
4012 3998 /*
4013 3999 * strcat (digesturi, "/"); strcat (digesturi, params->serverFQDN);
4014 4000 */
4015 4001
4016 4002 /* response */
4017 4003 response =
4018 4004 calculate_response(text,
4019 4005 params->utils,
4020 4006 #ifdef _SUN_SDK_
4021 4007 (unsigned char *) oparams->authid,
4022 4008 #else
4023 4009 (char *) oparams->authid,
4024 4010 #endif /* _SUN_SDK_ */
4025 4011 (unsigned char *) text->realm,
4026 4012 text->nonce,
4027 4013 text->nonce_count,
4028 4014 text->cnonce,
4029 4015 qop,
4030 4016 digesturi,
4031 4017 ctext->password,
4032 4018 strcmp(oparams->user, oparams->authid) ?
4033 4019 #ifdef _SUN_SDK_
4034 4020 (unsigned char *) oparams->user : NULL,
4035 4021 #else
4036 4022 (char *) oparams->user : NULL,
4037 4023 #endif /* _SUN_SDK_ */
4038 4024 &text->response_value);
4039 4025
4040 4026 #ifdef _SUN_SDK_
4041 4027 if (response == NULL) {
4042 4028 result = SASL_NOMEM;
4043 4029 goto FreeAllocatedMem;
4044 4030 }
4045 4031 #endif /* _SUN_SDK_ */
4046 4032
4047 4033 resplen = strlen(oparams->authid) + strlen("username") + 5;
4048 4034 result =_plug_buf_alloc(params->utils, &(text->out_buf),
4049 4035 &(text->out_buf_len),
4050 4036 resplen);
4051 4037 if (result != SASL_OK) goto FreeAllocatedMem;
4052 4038
4053 4039 sprintf(text->out_buf, "username=\"%s\"", oparams->authid);
4054 4040
4055 4041 if (add_to_challenge(params->utils,
4056 4042 &text->out_buf, &text->out_buf_len, &resplen,
4057 4043 "realm", (unsigned char *) text->realm,
4058 4044 TRUE) != SASL_OK) {
4059 4045 result = SASL_FAIL;
4060 4046 goto FreeAllocatedMem;
4061 4047 }
4062 4048 if (strcmp(oparams->user, oparams->authid)) {
4063 4049 if (add_to_challenge(params->utils,
4064 4050 &text->out_buf, &text->out_buf_len, &resplen,
4065 4051 #ifdef _SUN_SDK_
4066 4052 "authzid", (unsigned char *) oparams->user,
4067 4053 TRUE) != SASL_OK) {
4068 4054 #else
4069 4055 "authzid", (char *) oparams->user, TRUE) != SASL_OK) {
4070 4056 #endif /* _SUN_SDK_ */
4071 4057 result = SASL_FAIL;
4072 4058 goto FreeAllocatedMem;
4073 4059 }
4074 4060 }
4075 4061 if (add_to_challenge(params->utils,
4076 4062 &text->out_buf, &text->out_buf_len, &resplen,
4077 4063 "nonce", text->nonce, TRUE) != SASL_OK) {
4078 4064 result = SASL_FAIL;
4079 4065 goto FreeAllocatedMem;
4080 4066 }
4081 4067 if (add_to_challenge(params->utils,
4082 4068 &text->out_buf, &text->out_buf_len, &resplen,
4083 4069 "cnonce", text->cnonce, TRUE) != SASL_OK) {
4084 4070 result = SASL_FAIL;
4085 4071 goto FreeAllocatedMem;
4086 4072 }
4087 4073 snprintf(ncvalue, sizeof(ncvalue), "%08x", text->nonce_count);
4088 4074 if (add_to_challenge(params->utils,
4089 4075 &text->out_buf, &text->out_buf_len, &resplen,
4090 4076 "nc", (unsigned char *) ncvalue, FALSE) != SASL_OK) {
4091 4077 result = SASL_FAIL;
4092 4078 goto FreeAllocatedMem;
4093 4079 }
4094 4080 if (add_to_challenge(params->utils,
4095 4081 &text->out_buf, &text->out_buf_len, &resplen,
4096 4082 "qop", (unsigned char *) qop, FALSE) != SASL_OK) {
4097 4083 result = SASL_FAIL;
4098 4084 goto FreeAllocatedMem;
4099 4085 }
4100 4086 if (ctext->cipher != NULL) {
4101 4087 if (add_to_challenge(params->utils,
4102 4088 &text->out_buf, &text->out_buf_len, &resplen,
4103 4089 "cipher",
4104 4090 (unsigned char *) ctext->cipher->name,
4105 4091 TRUE) != SASL_OK) {
4106 4092 result = SASL_FAIL;
4107 4093 goto FreeAllocatedMem;
4108 4094 }
4109 4095 }
4110 4096
4111 4097 if (params->props.maxbufsize) {
4112 4098 snprintf(maxbufstr, sizeof(maxbufstr), "%d", params->props.maxbufsize);
4113 4099 if (add_to_challenge(params->utils,
4114 4100 &text->out_buf, &text->out_buf_len, &resplen,
4115 4101 "maxbuf", (unsigned char *) maxbufstr,
4116 4102 FALSE) != SASL_OK) {
4117 4103 #ifdef _SUN_SDK_
4118 4104 params->utils->log(params->utils->conn, SASL_LOG_ERR,
4119 4105 "internal error: add_to_challenge maxbuf failed");
4120 4106 #else
4121 4107 SETERROR(params->utils,
4122 4108 "internal error: add_to_challenge maxbuf failed");
4123 4109 #endif /* _SUN_SDK_ */
4124 4110 goto FreeAllocatedMem;
4125 4111 }
4126 4112 }
4127 4113
4128 4114 if (IsUTF8) {
4129 4115 if (add_to_challenge(params->utils,
4130 4116 &text->out_buf, &text->out_buf_len, &resplen,
4131 4117 "charset", (unsigned char *) "utf-8",
4132 4118 FALSE) != SASL_OK) {
4133 4119 result = SASL_FAIL;
4134 4120 goto FreeAllocatedMem;
4135 4121 }
4136 4122 }
4137 4123 if (add_to_challenge(params->utils,
4138 4124 &text->out_buf, &text->out_buf_len, &resplen,
4139 4125 "digest-uri", digesturi, TRUE) != SASL_OK) {
4140 4126 result = SASL_FAIL;
4141 4127 goto FreeAllocatedMem;
4142 4128 }
4143 4129 if (add_to_challenge(params->utils,
4144 4130 &text->out_buf, &text->out_buf_len, &resplen,
4145 4131 "response", (unsigned char *) response,
4146 4132 FALSE) != SASL_OK) {
4147 4133
4148 4134 result = SASL_FAIL;
4149 4135 goto FreeAllocatedMem;
4150 4136 }
4151 4137
4152 4138 /* self check */
4153 4139 if (strlen(text->out_buf) > 2048) {
4154 4140 result = SASL_FAIL;
4155 4141 goto FreeAllocatedMem;
4156 4142 }
4157 4143
4158 4144 /* set oparams */
4159 4145 #ifdef _SUN_SDK_
4160 4146 oparams->maxoutbuf = ctext->server_maxbuf - 4;
4161 4147 #else
4162 4148 oparams->maxoutbuf = ctext->server_maxbuf;
4163 4149 #endif /* _SUN_SDK_ */
4164 4150 if(oparams->mech_ssf > 1) {
4165 4151 #ifdef _SUN_SDK_
4166 4152 if (oparams->maxoutbuf <= 25)
4167 4153 return (SASL_BADPARAM);
4168 4154 #endif
4169 4155 /* MAC block (privacy) */
4170 4156 oparams->maxoutbuf -= 25;
4171 4157 } else if(oparams->mech_ssf == 1) {
4172 4158 #ifdef _SUN_SDK_
4173 4159 if (oparams->maxoutbuf <= 16)
4174 4160 return (SASL_BADPARAM);
4175 4161 #endif
4176 4162 /* MAC block (integrity) */
4177 4163 oparams->maxoutbuf -= 16;
4178 4164 }
4179 4165
4180 4166 text->seqnum = 0; /* for integrity/privacy */
4181 4167 text->rec_seqnum = 0; /* for integrity/privacy */
4182 4168 text->utils = params->utils;
4183 4169
4184 4170 text->in_maxbuf =
4185 4171 params->props.maxbufsize ? params->props.maxbufsize : DEFAULT_BUFSIZE;
4186 4172
4187 4173 /* used by layers */
4188 4174 text->needsize = 4;
4189 4175 text->buffer = NULL;
4190 4176
4191 4177 if (oparams->mech_ssf > 0) {
4192 4178 char enckey[16];
4193 4179 char deckey[16];
4194 4180
4195 4181 create_layer_keys(text, params->utils, text->HA1, nbits,
4196 4182 enckey, deckey);
4197 4183
4198 4184 /* initialize cipher if need be */
4199 4185 #ifdef _SUN_SDK_
4200 4186 if (text->cipher_init) {
4201 4187 if (text->cipher_free)
4202 4188 text->cipher_free(text);
4203 4189 if((result = text->cipher_init(text, enckey, deckey)) != SASL_OK) {
4204 4190 params->utils->log(params->utils->conn, SASL_LOG_ERR,
4205 4191 "couldn't init cipher");
4206 4192 goto FreeAllocatedMem;
4207 4193 }
4208 4194 }
4209 4195 #else
4210 4196 if (text->cipher_init)
4211 4197 text->cipher_init(text, enckey, deckey);
4212 4198 #endif /* _SUN_SDK_ */
4213 4199 }
4214 4200
4215 4201 result = SASL_OK;
4216 4202
4217 4203 FreeAllocatedMem:
4218 4204 if (digesturi) params->utils->free(digesturi);
4219 4205 if (response) params->utils->free(response);
4220 4206
4221 4207 return result;
4222 4208 }
4223 4209
4224 4210 static int parse_server_challenge(client_context_t *ctext,
4225 4211 sasl_client_params_t *params,
4226 4212 const char *serverin, unsigned serverinlen,
4227 4213 char ***outrealms, int *noutrealm)
4228 4214 {
4229 4215 context_t *text = (context_t *) ctext;
4230 4216 int result = SASL_OK;
4231 4217 char *in_start = NULL;
4232 4218 char *in = NULL;
4233 4219 char **realms = NULL;
4234 4220 int nrealm = 0;
4235 4221 sasl_ssf_t limit, musthave = 0;
4236 4222 sasl_ssf_t external;
4237 4223 int protection = 0;
4238 4224 int ciphers = 0;
4239 4225 int maxbuf_count = 0;
4240 4226 #ifndef _SUN_SDK_
4241 4227 bool IsUTF8 = FALSE;
4242 4228 #endif /* !_SUN_SDK_ */
4243 4229 int algorithm_count = 0;
4244 4230
4245 4231 if (!serverin || !serverinlen) {
4246 4232 #ifndef _SUN_SDK_
4247 4233 params->utils->log(params->utils->conn, SASL_LOG_ERR,
4248 4234 "no server challenge");
4249 4235 #else
4250 4236 params->utils->seterror(params->utils->conn, 0,
4251 4237 "no server challenge");
4252 4238 #endif /* _SUN_SDK_ */
4253 4239 return SASL_FAIL;
4254 4240 }
4255 4241
4256 4242 in_start = in = params->utils->malloc(serverinlen + 1);
4257 4243 if (in == NULL) return SASL_NOMEM;
4258 4244
4259 4245 memcpy(in, serverin, serverinlen);
4260 4246 in[serverinlen] = 0;
4261 4247
4262 4248 ctext->server_maxbuf = 65536; /* Default value for maxbuf */
4263 4249
4264 4250 /* create a new cnonce */
4265 4251 text->cnonce = create_nonce(params->utils);
4266 4252 if (text->cnonce == NULL) {
4267 4253 #ifdef _SUN_SDK_
4268 4254 params->utils->log(params->utils->conn, SASL_LOG_ERR,
4269 4255 "failed to create cnonce");
4270 4256 #else
4271 4257 params->utils->seterror(params->utils->conn, 0,
4272 4258 "failed to create cnonce");
4273 4259 #endif /* _SUN_SDK_ */
4274 4260 result = SASL_FAIL;
4275 4261 goto FreeAllocatedMem;
4276 4262 }
4277 4263
4278 4264 /* parse the challenge */
4279 4265 while (in[0] != '\0') {
4280 4266 char *name, *value;
4281 4267
4282 4268 get_pair(&in, &name, &value);
4283 4269
4284 4270 /* if parse error */
4285 4271 if (name == NULL) {
4286 4272 #ifdef _SUN_SDK_
4287 4273 params->utils->log(params->utils->conn, SASL_LOG_ERR,
4288 4274 "Parse error");
4289 4275 #else
4290 4276 params->utils->seterror(params->utils->conn, 0, "Parse error");
4291 4277 #endif /* _SUN_SDK_ */
4292 4278 result = SASL_FAIL;
4293 4279 goto FreeAllocatedMem;
4294 4280 }
4295 4281
4296 4282 if (strcasecmp(name, "realm") == 0) {
4297 4283 nrealm++;
4298 4284
4299 4285 if(!realms)
4300 4286 realms = params->utils->malloc(sizeof(char *) * (nrealm + 1));
4301 4287 else
4302 4288 realms = params->utils->realloc(realms,
4303 4289 sizeof(char *) * (nrealm + 1));
4304 4290
4305 4291 if (realms == NULL) {
4306 4292 result = SASL_NOMEM;
4307 4293 goto FreeAllocatedMem;
4308 4294 }
4309 4295
4310 4296 _plug_strdup(params->utils, value, &realms[nrealm-1], NULL);
4311 4297 realms[nrealm] = NULL;
4312 4298 } else if (strcasecmp(name, "nonce") == 0) {
4313 4299 _plug_strdup(params->utils, value, (char **) &text->nonce,
4314 4300 NULL);
4315 4301 text->nonce_count = 1;
4316 4302 } else if (strcasecmp(name, "qop") == 0) {
4317 4303 while (value && *value) {
4318 4304 char *comma = strchr(value, ',');
4319 4305 if (comma != NULL) {
4320 4306 *comma++ = '\0';
4321 4307 }
4322 4308
4323 4309 if (strcasecmp(value, "auth-conf") == 0) {
4324 4310 protection |= DIGEST_PRIVACY;
4325 4311 } else if (strcasecmp(value, "auth-int") == 0) {
4326 4312 protection |= DIGEST_INTEGRITY;
4327 4313 } else if (strcasecmp(value, "auth") == 0) {
4328 4314 protection |= DIGEST_NOLAYER;
4329 4315 } else {
4330 4316 params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
4331 4317 "Server supports unknown layer: %s\n",
4332 4318 value);
4333 4319 }
4334 4320
4335 4321 value = comma;
4336 4322 }
4337 4323
4338 4324 if (protection == 0) {
4339 4325 result = SASL_BADAUTH;
4340 4326 #ifdef _INTEGRATED_SOLARIS_
4341 4327 params->utils->seterror(params->utils->conn, 0,
4342 4328 gettext("Server doesn't support known qop level"));
4343 4329 #else
4344 4330 params->utils->seterror(params->utils->conn, 0,
4345 4331 "Server doesn't support known qop level");
4346 4332 #endif /* _INTEGRATED_SOLARIS_ */
4347 4333 goto FreeAllocatedMem;
4348 4334 }
4349 4335 } else if (strcasecmp(name, "cipher") == 0) {
4350 4336 while (value && *value) {
4351 4337 char *comma = strchr(value, ',');
4352 4338 #ifdef USE_UEF_CLIENT
4353 4339 struct digest_cipher *cipher = available_ciphers1;
4354 4340 #else
4355 4341 struct digest_cipher *cipher = available_ciphers;
4356 4342 #endif
4357 4343
4358 4344 if (comma != NULL) {
4359 4345 *comma++ = '\0';
4360 4346 }
4361 4347
4362 4348 /* do we support this cipher? */
4363 4349 while (cipher->name) {
4364 4350 if (!strcasecmp(value, cipher->name)) break;
4365 4351 cipher++;
4366 4352 }
4367 4353 if (cipher->name) {
4368 4354 ciphers |= cipher->flag;
4369 4355 } else {
4370 4356 params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
4371 4357 "Server supports unknown cipher: %s\n",
4372 4358 value);
4373 4359 }
4374 4360
4375 4361 value = comma;
4376 4362 }
4377 4363 } else if (strcasecmp(name, "stale") == 0 && ctext->password) {
4378 4364 /* clear any cached password */
4379 4365 if (ctext->free_password)
4380 4366 _plug_free_secret(params->utils, &ctext->password);
4381 4367 ctext->password = NULL;
4382 4368 } else if (strcasecmp(name, "maxbuf") == 0) {
4383 4369 /* maxbuf A number indicating the size of the largest
4384 4370 * buffer the server is able to receive when using
4385 4371 * "auth-int". If this directive is missing, the default
4386 4372 * value is 65536. This directive may appear at most once;
4387 4373 * if multiple instances are present, the client should
4388 4374 * abort the authentication exchange.
4389 4375 */
4390 4376 maxbuf_count++;
4391 4377
4392 4378 if (maxbuf_count != 1) {
4393 4379 result = SASL_BADAUTH;
4394 4380 #ifdef _SUN_SDK_
4395 4381 params->utils->log(params->utils->conn, SASL_LOG_ERR,
4396 4382 "At least two maxbuf directives found."
4397 4383 " Authentication aborted");
4398 4384 #else
4399 4385 params->utils->seterror(params->utils->conn, 0,
4400 4386 "At least two maxbuf directives found. Authentication aborted");
4401 4387 #endif /* _SUN_SDK_ */
4402 4388 goto FreeAllocatedMem;
4403 4389 } else if (sscanf(value, "%u", &ctext->server_maxbuf) != 1) {
4404 4390 result = SASL_BADAUTH;
4405 4391 #ifdef _SUN_SDK_
4406 4392 params->utils->log(params->utils->conn, SASL_LOG_ERR,
4407 4393 "Invalid maxbuf parameter received from server");
4408 4394 #else
4409 4395 params->utils->seterror(params->utils->conn, 0,
4410 4396 "Invalid maxbuf parameter received from server");
4411 4397 #endif /* _SUN_SDK_ */
4412 4398 goto FreeAllocatedMem;
4413 4399 } else {
4414 4400 if (ctext->server_maxbuf<=16) {
4415 4401 result = SASL_BADAUTH;
4416 4402 #ifdef _SUN_SDK_
4417 4403 params->utils->log(params->utils->conn, SASL_LOG_ERR,
4418 4404 "Invalid maxbuf parameter received from server"
4419 4405 " (too small: %s)", value);
4420 4406 #else
4421 4407 params->utils->seterror(params->utils->conn, 0,
4422 4408 "Invalid maxbuf parameter received from server (too small: %s)", value);
4423 4409 #endif /* _SUN_SDK_ */
4424 4410 goto FreeAllocatedMem;
4425 4411 }
4426 4412 }
4427 4413 } else if (strcasecmp(name, "charset") == 0) {
4428 4414 if (strcasecmp(value, "utf-8") != 0) {
4429 4415 result = SASL_BADAUTH;
4430 4416 #ifdef _SUN_SDK_
4431 4417 params->utils->log(params->utils->conn, SASL_LOG_ERR,
4432 4418 "Charset must be UTF-8");
4433 4419 #else
4434 4420 params->utils->seterror(params->utils->conn, 0,
4435 4421 "Charset must be UTF-8");
4436 4422 #endif /* _SUN_SDK_ */
4437 4423 goto FreeAllocatedMem;
4438 4424 } else {
4439 4425 #ifndef _SUN_SDK_
4440 4426 IsUTF8 = TRUE;
4441 4427 #endif /* !_SUN_SDK_ */
4442 4428 }
4443 4429 } else if (strcasecmp(name,"algorithm")==0) {
4444 4430 if (strcasecmp(value, "md5-sess") != 0)
4445 4431 {
4446 4432 #ifdef _SUN_SDK_
4447 4433 params->utils->log(params->utils->conn, SASL_LOG_ERR,
4448 4434 "'algorithm' isn't 'md5-sess'");
4449 4435 #else
4450 4436 params->utils->seterror(params->utils->conn, 0,
4451 4437 "'algorithm' isn't 'md5-sess'");
4452 4438 #endif /* _SUN_SDK_ */
4453 4439 result = SASL_FAIL;
4454 4440 goto FreeAllocatedMem;
4455 4441 }
4456 4442
4457 4443 algorithm_count++;
4458 4444 if (algorithm_count > 1)
4459 4445 {
4460 4446 #ifdef _SUN_SDK_
4461 4447 params->utils->log(params->utils->conn, SASL_LOG_ERR,
4462 4448 "Must see 'algorithm' only once");
4463 4449 #else
4464 4450 params->utils->seterror(params->utils->conn, 0,
4465 4451 "Must see 'algorithm' only once");
4466 4452 #endif /* _SUN_SDK_ */
4467 4453 result = SASL_FAIL;
4468 4454 goto FreeAllocatedMem;
4469 4455 }
4470 4456 } else {
4471 4457 params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
4472 4458 "DIGEST-MD5 unrecognized pair %s/%s: ignoring",
4473 4459 name, value);
4474 4460 }
4475 4461 }
4476 4462
4477 4463 if (algorithm_count != 1) {
4478 4464 #ifdef _SUN_SDK_
4479 4465 params->utils->log(params->utils->conn, SASL_LOG_ERR,
4480 4466 "Must see 'algorithm' once. Didn't see at all");
4481 4467 #else
4482 4468 params->utils->seterror(params->utils->conn, 0,
4483 4469 "Must see 'algorithm' once. Didn't see at all");
4484 4470 #endif /* _SUN_SDK_ */
4485 4471 result = SASL_FAIL;
4486 4472 goto FreeAllocatedMem;
4487 4473 }
4488 4474
4489 4475 /* make sure we have everything we require */
4490 4476 if (text->nonce == NULL) {
4491 4477 #ifdef _SUN_SDK_
4492 4478 params->utils->log(params->utils->conn, SASL_LOG_ERR,
4493 4479 "Don't have nonce.");
4494 4480 #else
4495 4481 params->utils->seterror(params->utils->conn, 0,
4496 4482 "Don't have nonce.");
4497 4483 #endif /* _SUN_SDK_ */
4498 4484 result = SASL_FAIL;
4499 4485 goto FreeAllocatedMem;
4500 4486 }
4501 4487
4502 4488 /* get requested ssf */
4503 4489 external = params->external_ssf;
4504 4490
4505 4491 /* what do we _need_? how much is too much? */
4506 4492 if (params->props.maxbufsize == 0) {
4507 4493 musthave = 0;
4508 4494 limit = 0;
4509 4495 } else {
4510 4496 if (params->props.max_ssf > external) {
4511 4497 limit = params->props.max_ssf - external;
4512 4498 } else {
4513 4499 limit = 0;
4514 4500 }
4515 4501 if (params->props.min_ssf > external) {
4516 4502 musthave = params->props.min_ssf - external;
4517 4503 } else {
4518 4504 musthave = 0;
4519 4505 }
4520 4506 }
4521 4507
4522 4508 /* we now go searching for an option that gives us at least "musthave"
4523 4509 and at most "limit" bits of ssf. */
4524 4510 if ((limit > 1) && (protection & DIGEST_PRIVACY)) {
4525 4511 struct digest_cipher *cipher;
4526 4512
4527 4513 /* let's find an encryption scheme that we like */
4528 4514 #ifdef USE_UEF_CLIENT
4529 4515 cipher = available_ciphers1;
4530 4516 #else
4531 4517 cipher = available_ciphers;
4532 4518 #endif
4533 4519 while (cipher->name) {
4534 4520 /* examine each cipher we support, see if it meets our security
4535 4521 requirements, and see if the server supports it.
4536 4522 choose the best one of these */
4537 4523 if ((limit >= cipher->ssf) && (musthave <= cipher->ssf) &&
4538 4524 (ciphers & cipher->flag) &&
4539 4525 (!ctext->cipher || (cipher->ssf > ctext->cipher->ssf))) {
4540 4526 ctext->cipher = cipher;
4541 4527 }
4542 4528 cipher++;
4543 4529 }
4544 4530
4545 4531 if (ctext->cipher) {
4546 4532 /* we found a cipher we like */
4547 4533 ctext->protection = DIGEST_PRIVACY;
4548 4534 } else {
4549 4535 /* we didn't find any ciphers we like */
4550 4536 #ifdef _INTEGRATED_SOLARIS_
4551 4537 params->utils->seterror(params->utils->conn, 0,
4552 4538 gettext("No good privacy layers"));
4553 4539 #else
4554 4540 params->utils->seterror(params->utils->conn, 0,
4555 4541 "No good privacy layers");
4556 4542 #endif /* _INTEGRATED_SOLARIS_ */
4557 4543 }
4558 4544 }
4559 4545
4560 4546 if (ctext->cipher == NULL) {
4561 4547 /* we failed to find an encryption layer we liked;
4562 4548 can we use integrity or nothing? */
4563 4549
4564 4550 if ((limit >= 1) && (musthave <= 1)
4565 4551 && (protection & DIGEST_INTEGRITY)) {
4566 4552 /* integrity */
4567 4553 ctext->protection = DIGEST_INTEGRITY;
4568 4554 #ifdef _SUN_SDK_
4569 4555 } else if (musthave == 0) {
4570 4556 #else
4571 4557 } else if (musthave <= 0) {
4572 4558 #endif /* _SUN_SDK_ */
4573 4559 /* no layer */
4574 4560 ctext->protection = DIGEST_NOLAYER;
4575 4561
4576 4562 /* See if server supports not having a layer */
4577 4563 if ((protection & DIGEST_NOLAYER) != DIGEST_NOLAYER) {
4578 4564 #ifdef _INTEGRATED_SOLARIS_
4579 4565 params->utils->seterror(params->utils->conn, 0,
4580 4566 gettext("Server doesn't support \"no layer\""));
4581 4567 #else
4582 4568 params->utils->seterror(params->utils->conn, 0,
4583 4569 "Server doesn't support \"no layer\"");
4584 4570 #endif /* _INTEGRATED_SOLARIS_ */
4585 4571 result = SASL_FAIL;
4586 4572 goto FreeAllocatedMem;
4587 4573 }
4588 4574 } else {
4589 4575 #ifdef _INTEGRATED_SOLARIS_
4590 4576 params->utils->seterror(params->utils->conn, 0,
4591 4577 gettext("Can't find an acceptable layer"));
4592 4578 #else
4593 4579 params->utils->seterror(params->utils->conn, 0,
4594 4580 "Can't find an acceptable layer");
4595 4581 #endif /* _INTEGRATED_SOLARIS_ */
4596 4582 result = SASL_TOOWEAK;
4597 4583 goto FreeAllocatedMem;
4598 4584 }
4599 4585 }
4600 4586
4601 4587 *outrealms = realms;
4602 4588 *noutrealm = nrealm;
4603 4589
4604 4590 FreeAllocatedMem:
4605 4591 if (in_start) params->utils->free(in_start);
4606 4592
4607 4593 if (result != SASL_OK && realms) {
4608 4594 int lup;
4609 4595
4610 4596 /* need to free all the realms */
4611 4597 for (lup = 0;lup < nrealm; lup++)
4612 4598 params->utils->free(realms[lup]);
4613 4599
4614 4600 params->utils->free(realms);
4615 4601 }
4616 4602
4617 4603 return result;
4618 4604 }
4619 4605
4620 4606 static int ask_user_info(client_context_t *ctext,
4621 4607 sasl_client_params_t *params,
4622 4608 char **realms, int nrealm,
4623 4609 sasl_interact_t **prompt_need,
4624 4610 sasl_out_params_t *oparams)
4625 4611 {
4626 4612 context_t *text = (context_t *) ctext;
4627 4613 int result = SASL_OK;
4628 4614 const char *authid = NULL, *userid = NULL, *realm = NULL;
4629 4615 char *realm_chal = NULL;
4630 4616 int user_result = SASL_OK;
4631 4617 int auth_result = SASL_OK;
4632 4618 int pass_result = SASL_OK;
4633 4619 int realm_result = SASL_FAIL;
4634 4620
4635 4621 /* try to get the authid */
4636 4622 if (oparams->authid == NULL) {
4637 4623 auth_result = _plug_get_authid(params->utils, &authid, prompt_need);
4638 4624
4639 4625 if ((auth_result != SASL_OK) && (auth_result != SASL_INTERACT)) {
4640 4626 return auth_result;
4641 4627 }
4642 4628 }
4643 4629
4644 4630 /* try to get the userid */
4645 4631 if (oparams->user == NULL) {
4646 4632 user_result = _plug_get_userid(params->utils, &userid, prompt_need);
4647 4633
4648 4634 if ((user_result != SASL_OK) && (user_result != SASL_INTERACT)) {
4649 4635 return user_result;
4650 4636 }
4651 4637 }
4652 4638
4653 4639 /* try to get the password */
4654 4640 if (ctext->password == NULL) {
4655 4641 pass_result = _plug_get_password(params->utils, &ctext->password,
4656 4642 &ctext->free_password, prompt_need);
4657 4643 if ((pass_result != SASL_OK) && (pass_result != SASL_INTERACT)) {
4658 4644 return pass_result;
4659 4645 }
4660 4646 }
4661 4647
4662 4648 /* try to get the realm */
4663 4649 if (text->realm == NULL) {
4664 4650 if (realms) {
4665 4651 if(nrealm == 1) {
4666 4652 /* only one choice */
4667 4653 realm = realms[0];
4668 4654 realm_result = SASL_OK;
4669 4655 } else {
4670 4656 /* ask the user */
4671 4657 realm_result = _plug_get_realm(params->utils,
4672 4658 (const char **) realms,
4673 4659 (const char **) &realm,
4674 4660 prompt_need);
4675 4661 }
4676 4662 }
4677 4663
4678 4664 /* fake the realm if we must */
4679 4665 if ((realm_result != SASL_OK) && (realm_result != SASL_INTERACT)) {
4680 4666 if (params->serverFQDN) {
4681 4667 realm = params->serverFQDN;
4682 4668 } else {
4683 4669 return realm_result;
4684 4670 }
4685 4671 }
4686 4672 }
4687 4673
4688 4674 /* free prompts we got */
4689 4675 if (prompt_need && *prompt_need) {
4690 4676 params->utils->free(*prompt_need);
4691 4677 *prompt_need = NULL;
4692 4678 }
4693 4679
4694 4680 /* if there are prompts not filled in */
4695 4681 if ((user_result == SASL_INTERACT) || (auth_result == SASL_INTERACT) ||
4696 4682 (pass_result == SASL_INTERACT) || (realm_result == SASL_INTERACT)) {
4697 4683
4698 4684 /* make our default realm */
4699 4685 if ((realm_result == SASL_INTERACT) && params->serverFQDN) {
4700 4686 realm_chal = params->utils->malloc(3+strlen(params->serverFQDN));
4701 4687 if (realm_chal) {
4702 4688 sprintf(realm_chal, "{%s}", params->serverFQDN);
4703 4689 } else {
4704 4690 return SASL_NOMEM;
4705 4691 }
4706 4692 }
4707 4693
4708 4694 /* make the prompt list */
4709 4695 result =
4710 4696 #if defined _INTEGRATED_SOLARIS_
4711 4697 _plug_make_prompts(params->utils, &ctext->h, prompt_need,
4712 4698 user_result == SASL_INTERACT ?
4713 4699 convert_prompt(params->utils, &ctext->h,
4714 4700 gettext("Please enter your authorization name"))
4715 4701 : NULL,
4716 4702 NULL,
4717 4703 auth_result == SASL_INTERACT ?
4718 4704 convert_prompt(params->utils, &ctext->h,
4719 4705 gettext("Please enter your authentication name"))
4720 4706 : NULL,
4721 4707 NULL,
4722 4708 pass_result == SASL_INTERACT ?
4723 4709 convert_prompt(params->utils, &ctext->h,
4724 4710 gettext("Please enter your password"))
4725 4711 : NULL, NULL,
4726 4712 NULL, NULL, NULL,
4727 4713 realm_chal ? realm_chal : "{}",
4728 4714 realm_result == SASL_INTERACT ?
4729 4715 convert_prompt(params->utils, &ctext->h,
4730 4716 gettext("Please enter your realm")) : NULL,
4731 4717 params->serverFQDN ? params->serverFQDN : NULL);
4732 4718 #else
4733 4719 _plug_make_prompts(params->utils, prompt_need,
4734 4720 user_result == SASL_INTERACT ?
4735 4721 "Please enter your authorization name" : NULL,
4736 4722 NULL,
4737 4723 auth_result == SASL_INTERACT ?
4738 4724 "Please enter your authentication name" : NULL,
4739 4725 NULL,
4740 4726 pass_result == SASL_INTERACT ?
4741 4727 "Please enter your password" : NULL, NULL,
4742 4728 NULL, NULL, NULL,
4743 4729 realm_chal ? realm_chal : "{}",
4744 4730 realm_result == SASL_INTERACT ?
4745 4731 "Please enter your realm" : NULL,
4746 4732 params->serverFQDN ? params->serverFQDN : NULL);
4747 4733 #endif /* _INTEGRATED_SOLARIS_ */
4748 4734
4749 4735 if (result == SASL_OK) return SASL_INTERACT;
4750 4736
4751 4737 return result;
4752 4738 }
4753 4739
4754 4740 if (oparams->authid == NULL) {
4755 4741 if (!userid || !*userid) {
4756 4742 result = params->canon_user(params->utils->conn, authid, 0,
4757 4743 SASL_CU_AUTHID | SASL_CU_AUTHZID,
4758 4744 oparams);
4759 4745 }
4760 4746 else {
4761 4747 result = params->canon_user(params->utils->conn,
4762 4748 authid, 0, SASL_CU_AUTHID, oparams);
4763 4749 if (result != SASL_OK) return result;
4764 4750
4765 4751 result = params->canon_user(params->utils->conn,
4766 4752 userid, 0, SASL_CU_AUTHZID, oparams);
4767 4753 }
4768 4754 if (result != SASL_OK) return result;
4769 4755 }
4770 4756
4771 4757 /* Get an allocated version of the realm into the structure */
4772 4758 if (realm && text->realm == NULL) {
4773 4759 _plug_strdup(params->utils, realm, (char **) &text->realm, NULL);
4774 4760 }
4775 4761
4776 4762 return result;
4777 4763 }
4778 4764
4779 4765 static int
4780 4766 digestmd5_client_mech_new(void *glob_context,
4781 4767 sasl_client_params_t * params,
4782 4768 void **conn_context)
4783 4769 {
4784 4770 context_t *text;
4785 4771
4786 4772 /* holds state are in -- allocate client size */
4787 4773 text = params->utils->malloc(sizeof(client_context_t));
4788 4774 if (text == NULL)
4789 4775 return SASL_NOMEM;
4790 4776 memset(text, 0, sizeof(client_context_t));
4791 4777
4792 4778 text->state = 1;
4793 4779 text->i_am = CLIENT;
4794 4780 text->reauth = glob_context;
4795 4781
4796 4782 *conn_context = text;
4797 4783
4798 4784 return SASL_OK;
4799 4785 }
4800 4786
4801 4787 static int
4802 4788 digestmd5_client_mech_step1(client_context_t *ctext,
4803 4789 sasl_client_params_t *params,
4804 4790 const char *serverin __attribute__((unused)),
4805 4791 unsigned serverinlen __attribute__((unused)),
4806 4792 sasl_interact_t **prompt_need,
4807 4793 const char **clientout,
4808 4794 unsigned *clientoutlen,
4809 4795 sasl_out_params_t *oparams)
4810 4796 {
4811 4797 context_t *text = (context_t *) ctext;
4812 4798 int result = SASL_FAIL;
4813 4799 unsigned val;
4814 4800
4815 4801 params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
4816 4802 "DIGEST-MD5 client step 1");
4817 4803
4818 4804 result = ask_user_info(ctext, params, NULL, 0, prompt_need, oparams);
4819 4805 if (result != SASL_OK) return result;
4820 4806
4821 4807 /* check if we have cached info for this user on this server */
4822 4808 val = hash(params->serverFQDN) % text->reauth->size;
4823 4809 if (params->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
4824 4810 if (text->reauth->e[val].u.c.serverFQDN &&
4825 4811 !strcasecmp(text->reauth->e[val].u.c.serverFQDN,
4826 4812 params->serverFQDN) &&
4827 4813 !strcmp(text->reauth->e[val].authid, oparams->authid)) {
4828 4814
4829 4815 #ifdef _SUN_SDK_
4830 4816 if (text->realm) params->utils->free(text->realm);
4831 4817 if (text->nonce) params->utils->free(text->nonce);
4832 4818 if (text->cnonce) params->utils->free(text->cnonce);
4833 4819 #endif /* _SUN_SDK_ */
4834 4820 /* we have info, so use it */
4835 4821 _plug_strdup(params->utils, text->reauth->e[val].realm,
4836 4822 &text->realm, NULL);
4837 4823 #ifdef _SUN_SDK_
4838 4824 _plug_strdup(params->utils, (char *)text->reauth->e[val].nonce,
4839 4825 (char **) &text->nonce, NULL);
4840 4826 #else
4841 4827 _plug_strdup(params->utils, text->reauth->e[val].nonce,
4842 4828 (char **) &text->nonce, NULL);
4843 4829 #endif /* _SUN_SDK_ */
4844 4830 text->nonce_count = ++text->reauth->e[val].nonce_count;
4845 4831 #ifdef _SUN_SDK_
4846 4832 _plug_strdup(params->utils, (char *)text->reauth->e[val].cnonce,
4847 4833 (char **) &text->cnonce, NULL);
4848 4834 #else
4849 4835 _plug_strdup(params->utils, text->reauth->e[val].cnonce,
4850 4836 (char **) &text->cnonce, NULL);
4851 4837 #endif /* _SUN_SDK_ */
4852 4838 ctext->protection = text->reauth->e[val].u.c.protection;
4853 4839 ctext->cipher = text->reauth->e[val].u.c.cipher;
4854 4840 ctext->server_maxbuf = text->reauth->e[val].u.c.server_maxbuf;
4855 4841 }
4856 4842 params->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
4857 4843 }
4858 4844
4859 4845 if (!text->nonce) {
4860 4846 /* we don't have any reauth info, so just return
4861 4847 * that there is no initial client send */
4862 4848 text->state = 2;
4863 4849 return SASL_CONTINUE;
4864 4850 }
4865 4851
4866 4852 /*
4867 4853 * (username | realm | nonce | cnonce | nonce-count | qop digest-uri |
4868 4854 * response | maxbuf | charset | auth-param )
4869 4855 */
4870 4856
4871 4857 result = make_client_response(text, params, oparams);
4872 4858 if (result != SASL_OK) return result;
4873 4859
4874 4860 *clientoutlen = strlen(text->out_buf);
4875 4861 *clientout = text->out_buf;
4876 4862
4877 4863 text->state = 3;
4878 4864 return SASL_CONTINUE;
4879 4865 }
4880 4866
4881 4867 static int
4882 4868 digestmd5_client_mech_step2(client_context_t *ctext,
4883 4869 sasl_client_params_t *params,
4884 4870 const char *serverin,
4885 4871 unsigned serverinlen,
4886 4872 sasl_interact_t **prompt_need,
4887 4873 const char **clientout,
4888 4874 unsigned *clientoutlen,
4889 4875 sasl_out_params_t *oparams)
4890 4876 {
4891 4877 context_t *text = (context_t *) ctext;
4892 4878 int result = SASL_FAIL;
4893 4879 char **realms = NULL;
4894 4880 int nrealm = 0;
4895 4881
4896 4882 params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
4897 4883 "DIGEST-MD5 client step 2");
4898 4884
4899 4885 if (params->props.min_ssf > params->props.max_ssf) {
4900 4886 return SASL_BADPARAM;
4901 4887 }
4902 4888
4903 4889 /* don't bother parsing the challenge more than once */
4904 4890 if (text->nonce == NULL) {
4905 4891 result = parse_server_challenge(ctext, params, serverin, serverinlen,
4906 4892 &realms, &nrealm);
4907 4893 if (result != SASL_OK) goto FreeAllocatedMem;
4908 4894
4909 4895 if (nrealm == 1) {
4910 4896 /* only one choice! */
4911 4897 text->realm = realms[0];
4912 4898
4913 4899 /* free realms */
4914 4900 params->utils->free(realms);
4915 4901 realms = NULL;
4916 4902 }
4917 4903 }
4918 4904
4919 4905 result = ask_user_info(ctext, params, realms, nrealm,
4920 4906 prompt_need, oparams);
4921 4907 if (result != SASL_OK) goto FreeAllocatedMem;
4922 4908
4923 4909 /*
4924 4910 * (username | realm | nonce | cnonce | nonce-count | qop digest-uri |
4925 4911 * response | maxbuf | charset | auth-param )
4926 4912 */
4927 4913
4928 4914 result = make_client_response(text, params, oparams);
4929 4915 if (result != SASL_OK) goto FreeAllocatedMem;
4930 4916
4931 4917 *clientoutlen = strlen(text->out_buf);
4932 4918 *clientout = text->out_buf;
4933 4919
4934 4920 text->state = 3;
4935 4921
4936 4922 result = SASL_CONTINUE;
4937 4923
4938 4924 FreeAllocatedMem:
4939 4925 if (realms) {
4940 4926 int lup;
4941 4927
4942 4928 /* need to free all the realms */
4943 4929 for (lup = 0;lup < nrealm; lup++)
4944 4930 params->utils->free(realms[lup]);
4945 4931
4946 4932 params->utils->free(realms);
4947 4933 }
4948 4934
4949 4935 return result;
4950 4936 }
4951 4937
4952 4938 static int
4953 4939 digestmd5_client_mech_step3(client_context_t *ctext,
4954 4940 sasl_client_params_t *params,
4955 4941 const char *serverin,
4956 4942 unsigned serverinlen,
4957 4943 sasl_interact_t **prompt_need __attribute__((unused)),
4958 4944 const char **clientout __attribute__((unused)),
4959 4945 unsigned *clientoutlen __attribute__((unused)),
4960 4946 sasl_out_params_t *oparams)
4961 4947 {
4962 4948 context_t *text = (context_t *) ctext;
4963 4949 char *in = NULL;
4964 4950 char *in_start;
4965 4951 int result = SASL_FAIL;
4966 4952
4967 4953 params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
4968 4954 "DIGEST-MD5 client step 3");
4969 4955
4970 4956 /* Verify that server is really what he claims to be */
4971 4957 in_start = in = params->utils->malloc(serverinlen + 1);
4972 4958 if (in == NULL) return SASL_NOMEM;
4973 4959
4974 4960 memcpy(in, serverin, serverinlen);
4975 4961 in[serverinlen] = 0;
4976 4962
4977 4963 /* parse the response */
4978 4964 while (in[0] != '\0') {
4979 4965 char *name, *value;
4980 4966 get_pair(&in, &name, &value);
4981 4967
4982 4968 if (name == NULL) {
4983 4969 #ifdef _SUN_SDK_
4984 4970 params->utils->log(params->utils->conn, SASL_LOG_ERR,
4985 4971 "DIGEST-MD5 Received Garbage");
4986 4972 #else
4987 4973 params->utils->seterror(params->utils->conn, 0,
4988 4974 "DIGEST-MD5 Received Garbage");
4989 4975 #endif /* _SUN_SDK_ */
4990 4976 break;
4991 4977 }
4992 4978
4993 4979 if (strcasecmp(name, "rspauth") == 0) {
4994 4980
4995 4981 if (strcmp(text->response_value, value) != 0) {
4996 4982 #ifdef _INTEGRATED_SOLARIS_
4997 4983 params->utils->seterror(params->utils->conn, 0,
4998 4984 gettext("Server authentication failed"));
4999 4985 #else
5000 4986 params->utils->seterror(params->utils->conn, 0,
5001 4987 "DIGEST-MD5: This server wants us to believe that he knows shared secret");
5002 4988 #endif /* _INTEGRATED_SOLARIS_ */
5003 4989 result = SASL_FAIL;
5004 4990 } else {
5005 4991 oparams->doneflag = 1;
5006 4992 oparams->param_version = 0;
5007 4993
5008 4994 result = SASL_OK;
5009 4995 }
5010 4996 break;
5011 4997 } else {
5012 4998 params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
5013 4999 "DIGEST-MD5 unrecognized pair %s/%s: ignoring",
5014 5000 name, value);
5015 5001 }
5016 5002 }
5017 5003
5018 5004 params->utils->free(in_start);
5019 5005
5020 5006 if (params->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
5021 5007 unsigned val = hash(params->serverFQDN) % text->reauth->size;
5022 5008 switch (result) {
5023 5009 case SASL_OK:
5024 5010 if (text->nonce_count == 1) {
5025 5011 /* successful initial auth, setup for future reauth */
5026 5012 clear_reauth_entry(&text->reauth->e[val], CLIENT, params->utils);
5027 5013 _plug_strdup(params->utils, oparams->authid,
5028 5014 &text->reauth->e[val].authid, NULL);
5029 5015 text->reauth->e[val].realm = text->realm; text->realm = NULL;
5030 5016 text->reauth->e[val].nonce = text->nonce; text->nonce = NULL;
5031 5017 text->reauth->e[val].nonce_count = text->nonce_count;
5032 5018 text->reauth->e[val].cnonce = text->cnonce; text->cnonce = NULL;
5033 5019 _plug_strdup(params->utils, params->serverFQDN,
5034 5020 &text->reauth->e[val].u.c.serverFQDN, NULL);
5035 5021 text->reauth->e[val].u.c.protection = ctext->protection;
5036 5022 text->reauth->e[val].u.c.cipher = ctext->cipher;
5037 5023 text->reauth->e[val].u.c.server_maxbuf = ctext->server_maxbuf;
5038 5024 }
5039 5025 #ifndef _SUN_SDK_
5040 5026 else {
5041 5027 /* reauth, we already incremented nonce_count */
5042 5028 }
5043 5029 #endif /* !_SUN_SDK_ */
5044 5030 break;
5045 5031 default:
5046 5032 if (text->nonce_count > 1) {
5047 5033 /* failed reauth, clear cache */
5048 5034 clear_reauth_entry(&text->reauth->e[val], CLIENT, params->utils);
5049 5035 }
5050 5036 else {
5051 5037 /* failed initial auth, leave existing cache */
5052 5038 }
5053 5039 }
5054 5040 params->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
5055 5041 }
5056 5042
5057 5043 return result;
5058 5044 }
5059 5045
5060 5046 static int
5061 5047 digestmd5_client_mech_step(void *conn_context,
5062 5048 sasl_client_params_t *params,
5063 5049 const char *serverin,
5064 5050 unsigned serverinlen,
5065 5051 sasl_interact_t **prompt_need,
5066 5052 const char **clientout,
5067 5053 unsigned *clientoutlen,
5068 5054 sasl_out_params_t *oparams)
5069 5055 {
5070 5056 context_t *text = (context_t *) conn_context;
5071 5057 client_context_t *ctext = (client_context_t *) conn_context;
5072 5058 unsigned val = hash(params->serverFQDN) % text->reauth->size;
5073 5059
5074 5060 if (serverinlen > 2048) return SASL_BADPROT;
5075 5061
5076 5062 *clientout = NULL;
5077 5063 *clientoutlen = 0;
5078 5064
5079 5065 switch (text->state) {
5080 5066
5081 5067 case 1:
5082 5068 if (!serverin) {
5083 5069 /* here's where we attempt fast reauth if possible */
5084 5070 int reauth = 0;
5085 5071
5086 5072 /* check if we have saved info for this server */
5087 5073 if (params->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
5088 5074 reauth = text->reauth->e[val].u.c.serverFQDN &&
5089 5075 !strcasecmp(text->reauth->e[val].u.c.serverFQDN,
5090 5076 params->serverFQDN);
5091 5077 params->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
5092 5078 }
5093 5079 if (reauth) {
5094 5080 return digestmd5_client_mech_step1(ctext, params,
5095 5081 serverin, serverinlen,
5096 5082 prompt_need,
5097 5083 clientout, clientoutlen,
5098 5084 oparams);
5099 5085 }
5100 5086 else {
5101 5087 /* we don't have any reauth info, so just return
5102 5088 * that there is no initial client send */
5103 5089 text->state = 2;
5104 5090 return SASL_CONTINUE;
5105 5091 }
5106 5092 }
5107 5093
5108 5094 /* fall through and respond to challenge */
5109 5095
5110 5096 case 3:
5111 5097 if (serverin && !strncasecmp(serverin, "rspauth=", 8)) {
5112 5098 return digestmd5_client_mech_step3(ctext, params,
5113 5099 serverin, serverinlen,
5114 5100 prompt_need,
5115 5101 clientout, clientoutlen,
5116 5102 oparams);
5117 5103 }
5118 5104
5119 5105 /* fall through and respond to challenge */
5120 5106 text->state = 2;
5121 5107
5122 5108 /* cleanup after a failed reauth attempt */
5123 5109 if (params->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
5124 5110 clear_reauth_entry(&text->reauth->e[val], CLIENT, params->utils);
5125 5111
5126 5112 params->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
5127 5113 }
5128 5114
5129 5115 if (text->realm) params->utils->free(text->realm);
5130 5116 if (text->nonce) params->utils->free(text->nonce);
5131 5117 if (text->cnonce) params->utils->free(text->cnonce);
5132 5118 #ifdef _SUN_SDK_
5133 5119 text->realm = NULL;
5134 5120 text->nonce = text->cnonce = NULL;
5135 5121 #else
5136 5122 text->realm = text->nonce = text->cnonce = NULL;
5137 5123 #endif /* _SUN_SDK_ */
5138 5124 ctext->cipher = NULL;
5139 5125
5140 5126 case 2:
5141 5127 return digestmd5_client_mech_step2(ctext, params,
5142 5128 serverin, serverinlen,
5143 5129 prompt_need,
5144 5130 clientout, clientoutlen,
5145 5131 oparams);
5146 5132
5147 5133 default:
5148 5134 #ifdef _SUN_SDK_
5149 5135 params->utils->log(params->utils->conn, SASL_LOG_ERR,
5150 5136 "Invalid DIGEST-MD5 client step %d", text->state);
5151 5137 #else
5152 5138 params->utils->log(NULL, SASL_LOG_ERR,
5153 5139 "Invalid DIGEST-MD5 client step %d\n", text->state);
5154 5140 #endif /* _SUN_SDK_ */
5155 5141 return SASL_FAIL;
5156 5142 }
5157 5143
5158 5144 return SASL_FAIL; /* should never get here */
5159 5145 }
5160 5146
5161 5147 static void
5162 5148 digestmd5_client_mech_dispose(void *conn_context, const sasl_utils_t *utils)
5163 5149 {
5164 5150 client_context_t *ctext = (client_context_t *) conn_context;
5165 5151
5166 5152 if (!ctext || !utils) return;
5167 5153
5168 5154 #ifdef _INTEGRATED_SOLARIS_
5169 5155 convert_prompt(utils, &ctext->h, NULL);
5170 5156 #endif /* _INTEGRATED_SOLARIS_ */
↓ open down ↓ |
1368 lines elided |
↑ open up ↑ |
5171 5157
5172 5158 if (ctext->free_password) _plug_free_secret(utils, &ctext->password);
5173 5159
5174 5160 digestmd5_common_mech_dispose(conn_context, utils);
5175 5161 }
5176 5162
5177 5163 static sasl_client_plug_t digestmd5_client_plugins[] =
5178 5164 {
5179 5165 {
5180 5166 "DIGEST-MD5",
5181 - /* EXPORT DELETE START */
5182 5167 #ifdef WITH_RC4 /* mech_name */
5183 5168 128, /* max ssf */
5184 5169 #elif WITH_DES
5185 5170 112,
5186 5171 #else
5187 - /* EXPORT DELETE END */
5188 5172 0,
5189 - /* EXPORT DELETE START */
5190 5173 #endif
5191 - /* EXPORT DELETE END */
5192 5174 SASL_SEC_NOPLAINTEXT
5193 5175 | SASL_SEC_NOANONYMOUS
5194 5176 | SASL_SEC_MUTUAL_AUTH, /* security_flags */
5195 5177 SASL_FEAT_ALLOWS_PROXY, /* features */
5196 5178 NULL, /* required_prompts */
5197 5179 NULL, /* glob_context */
5198 5180 &digestmd5_client_mech_new, /* mech_new */
5199 5181 &digestmd5_client_mech_step, /* mech_step */
5200 5182 &digestmd5_client_mech_dispose, /* mech_dispose */
5201 5183 &digestmd5_common_mech_free, /* mech_free */
5202 5184 NULL, /* idle */
5203 5185 NULL, /* spare1 */
5204 5186 NULL /* spare2 */
5205 5187 }
5206 5188 };
5207 5189
5208 5190 int digestmd5_client_plug_init(sasl_utils_t *utils,
5209 5191 int maxversion,
5210 5192 int *out_version,
5211 5193 sasl_client_plug_t **pluglist,
5212 5194 int *plugcount)
5213 5195 {
5214 5196 reauth_cache_t *reauth_cache;
5215 5197 #if defined _SUN_SDK_ && defined USE_UEF
5216 5198 int ret;
5217 5199 #endif /* _SUN_SDK_ && USE_UEF */
5218 5200
5219 5201 if (maxversion < SASL_CLIENT_PLUG_VERSION)
5220 5202 return SASL_BADVERS;
5221 5203
5222 5204 #if defined _SUN_SDK_ && defined USE_UEF
5223 5205 if ((ret = uef_init(utils)) != SASL_OK)
5224 5206 return ret;
5225 5207 #endif /* _SUN_SDK_ && USE_UEF */
5226 5208
5227 5209 /* reauth cache */
5228 5210 reauth_cache = utils->malloc(sizeof(reauth_cache_t));
5229 5211 if (reauth_cache == NULL)
5230 5212 return SASL_NOMEM;
5231 5213 memset(reauth_cache, 0, sizeof(reauth_cache_t));
5232 5214 reauth_cache->i_am = CLIENT;
5233 5215
5234 5216 /* mutex */
5235 5217 reauth_cache->mutex = utils->mutex_alloc();
5236 5218 if (!reauth_cache->mutex)
5237 5219 return SASL_FAIL;
5238 5220
5239 5221 /* entries */
5240 5222 reauth_cache->size = 10;
5241 5223 reauth_cache->e = utils->malloc(reauth_cache->size *
5242 5224 sizeof(reauth_entry_t));
5243 5225 if (reauth_cache->e == NULL)
↓ open down ↓ |
42 lines elided |
↑ open up ↑ |
5244 5226 return SASL_NOMEM;
5245 5227 memset(reauth_cache->e, 0, reauth_cache->size * sizeof(reauth_entry_t));
5246 5228
5247 5229 digestmd5_client_plugins[0].glob_context = reauth_cache;
5248 5230 #ifdef _SUN_SDK_
5249 5231 #ifdef USE_UEF_CLIENT
5250 5232 digestmd5_client_plugins[0].max_ssf = uef_max_ssf;
5251 5233 #endif /* USE_UEF_CLIENT */
5252 5234 #endif /* _SUN_SDK_ */
5253 5235
5254 - /* EXPORT DELETE START */
5255 - /* CRYPT DELETE START */
5256 5236 #ifdef _INTEGRATED_SOLARIS_
5257 5237 /*
5258 5238 * Let libsasl know that we are a "Sun" plugin so that privacy
5259 5239 * and integrity will be allowed.
5260 5240 */
5261 5241 REG_PLUG("DIGEST-MD5", digestmd5_client_plugins);
5262 5242 #endif /* _INTEGRATED_SOLARIS_ */
5263 - /* CRYPT DELETE END */
5264 - /* EXPORT DELETE END */
5265 5243
5266 5244 *out_version = SASL_CLIENT_PLUG_VERSION;
5267 5245 *pluglist = digestmd5_client_plugins;
5268 5246 *plugcount = 1;
5269 5247
5270 5248 return SASL_OK;
5271 5249 }
5272 5250
5273 5251 #ifdef _SUN_SDK_
5274 5252 #ifdef USE_UEF
5275 5253 /* If we fail here - we should just not offer privacy or integrity */
5276 5254 static int
5277 5255 getSlotID(const sasl_utils_t *utils, CK_MECHANISM_TYPE mech_type,
5278 5256 CK_SLOT_ID *slot_id)
5279 5257 {
5280 5258 CK_RV rv;
5281 5259 CK_ULONG ulSlotCount;
5282 5260 CK_ULONG ulMechTypeCount;
5283 5261 CK_SLOT_ID *pSlotList = NULL;
5284 5262 CK_SLOT_ID slotID;
5285 5263 CK_MECHANISM_TYPE_PTR pMechTypeList = NULL;
5286 5264 int i, m;
5287 5265
5288 5266 rv = C_GetSlotList(CK_FALSE, NULL_PTR, &ulSlotCount);
5289 5267 if (rv != CKR_OK || ulSlotCount == 0) {
5290 5268 #ifdef DEBUG
5291 5269 utils->log(utils->conn, SASL_LOG_DEBUG,
5292 5270 "C_GetSlotList: 0x%.8X count:%d\n", rv, ulSlotCount);
5293 5271 #endif
5294 5272 return SASL_FAIL;
5295 5273 }
5296 5274
5297 5275 pSlotList = utils->calloc(sizeof (CK_SLOT_ID), ulSlotCount);
5298 5276 if (pSlotList == NULL)
5299 5277 return SASL_NOMEM;
5300 5278
5301 5279 rv = C_GetSlotList(CK_FALSE, pSlotList, &ulSlotCount);
5302 5280 if (rv != CKR_OK) {
5303 5281 #ifdef DEBUG
5304 5282 utils->log(utils->conn, SASL_LOG_DEBUG,
5305 5283 "C_GetSlotList: 0x%.8X count:%d\n", rv, ulSlotCount);
5306 5284 #endif
5307 5285 return SASL_FAIL;
5308 5286 }
5309 5287
5310 5288 for (i = 0; i < ulSlotCount; i++) {
5311 5289 slotID = pSlotList[i];
5312 5290 rv = C_GetMechanismList(slotID, NULL_PTR, &ulMechTypeCount);
5313 5291 if (rv != CKR_OK) {
5314 5292 #ifdef DEBUG
5315 5293 utils->log(utils->conn, SASL_LOG_DEBUG,
5316 5294 "C_GetMechanismList returned 0x%.8X count:%d\n", rv,
5317 5295 ulMechTypeCount);
5318 5296 #endif
5319 5297 utils->free(pSlotList);
5320 5298 return SASL_FAIL;
5321 5299 }
5322 5300 pMechTypeList =
5323 5301 utils->calloc(sizeof (CK_MECHANISM_TYPE), ulMechTypeCount);
5324 5302 if (pMechTypeList == NULL_PTR) {
5325 5303 utils->free(pSlotList);
5326 5304 return SASL_NOMEM;
5327 5305 }
5328 5306 rv = C_GetMechanismList(slotID, pMechTypeList, &ulMechTypeCount);
5329 5307 if (rv != CKR_OK) {
5330 5308 #ifdef DEBUG
5331 5309 utils->log(utils->conn, SASL_LOG_DEBUG,
5332 5310 "C_GetMechanismList returned 0x%.8X count:%d\n", rv,
5333 5311 ulMechTypeCount);
5334 5312 #endif
5335 5313 utils->free(pMechTypeList);
5336 5314 utils->free(pSlotList);
5337 5315 return SASL_FAIL;
5338 5316 }
5339 5317
5340 5318 for (m = 0; m < ulMechTypeCount; m++) {
5341 5319 if (pMechTypeList[m] == mech_type)
5342 5320 break;
5343 5321 }
5344 5322 utils->free(pMechTypeList);
5345 5323 pMechTypeList = NULL;
5346 5324 if (m < ulMechTypeCount)
5347 5325 break;
5348 5326 }
5349 5327 utils->free(pSlotList);
5350 5328 if (i < ulSlotCount) {
5351 5329 *slot_id = slotID;
5352 5330 return SASL_OK;
5353 5331 }
5354 5332 return SASL_FAIL;
5355 5333 }
5356 5334
5357 5335 static int
5358 5336 uef_init(const sasl_utils_t *utils)
5359 5337 {
5360 5338 int got_rc4;
5361 5339 int got_des;
5362 5340 int got_3des;
5363 5341 int next_c;
5364 5342 CK_RV rv;
5365 5343
5366 5344 if (got_uef_slot)
5367 5345 return (SASL_OK);
5368 5346
5369 5347 if (LOCK_MUTEX(&uef_init_mutex) < 0)
5370 5348 return (SASL_FAIL);
5371 5349
5372 5350 rv = C_Initialize(NULL_PTR);
5373 5351 if (rv != CKR_OK && rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
5374 5352 #ifdef DEBUG
5375 5353 utils->log(utils->conn, SASL_LOG_DEBUG,
5376 5354 "C_Initialize returned 0x%.8X\n", rv);
5377 5355 #endif
5378 5356 return SASL_FAIL;
5379 5357 }
5380 5358
5381 5359 got_rc4 = getSlotID(utils, CKM_RC4, &rc4_slot_id) == SASL_OK;
5382 5360 if (!got_rc4)
5383 5361 utils->log(utils->conn, SASL_LOG_WARN, "Could not get rc4");
5384 5362
5385 5363 got_des = getSlotID(utils, CKM_DES_CBC, &des_slot_id) == SASL_OK;
5386 5364 if (!got_des)
5387 5365 utils->log(utils->conn, SASL_LOG_WARN, "Could not get des");
5388 5366
5389 5367 got_3des = getSlotID(utils, CKM_DES3_CBC, &des3_slot_id) == SASL_OK;
5390 5368 if (!got_3des)
5391 5369 utils->log(utils->conn, SASL_LOG_WARN, "Could not get 3des");
5392 5370
5393 5371 uef_max_ssf = got_rc4 ? 128 : got_3des ? 112 : got_des ? 55 : 0;
5394 5372
5395 5373 /* adjust the available ciphers */
5396 5374 next_c = (got_rc4) ? 3 : 0;
5397 5375
5398 5376 if (got_des) {
5399 5377 uef_ciphers[next_c].name = uef_ciphers[DES_CIPHER_INDEX].name;
5400 5378 uef_ciphers[next_c].ssf = uef_ciphers[DES_CIPHER_INDEX].ssf;
5401 5379 uef_ciphers[next_c].n = uef_ciphers[DES_CIPHER_INDEX].n;
5402 5380 uef_ciphers[next_c].flag = uef_ciphers[DES_CIPHER_INDEX].flag;
5403 5381 uef_ciphers[next_c].cipher_enc =
5404 5382 uef_ciphers[DES_CIPHER_INDEX].cipher_enc;
5405 5383 uef_ciphers[next_c].cipher_dec =
5406 5384 uef_ciphers[DES_CIPHER_INDEX].cipher_dec;
5407 5385 uef_ciphers[next_c].cipher_init =
5408 5386 uef_ciphers[DES_CIPHER_INDEX].cipher_init;
5409 5387 next_c++;
5410 5388 }
5411 5389
5412 5390 if (got_3des) {
5413 5391 uef_ciphers[next_c].name = uef_ciphers[DES3_CIPHER_INDEX].name;
5414 5392 uef_ciphers[next_c].ssf = uef_ciphers[DES3_CIPHER_INDEX].ssf;
5415 5393 uef_ciphers[next_c].n = uef_ciphers[DES3_CIPHER_INDEX].n;
5416 5394 uef_ciphers[next_c].flag = uef_ciphers[DES3_CIPHER_INDEX].flag;
5417 5395 uef_ciphers[next_c].cipher_enc =
5418 5396 uef_ciphers[DES3_CIPHER_INDEX].cipher_enc;
5419 5397 uef_ciphers[next_c].cipher_dec =
5420 5398 uef_ciphers[DES3_CIPHER_INDEX].cipher_dec;
5421 5399 uef_ciphers[next_c].cipher_init =
5422 5400 uef_ciphers[DES3_CIPHER_INDEX].cipher_init;
5423 5401 next_c++;
5424 5402 }
5425 5403 uef_ciphers[next_c].name = NULL;
5426 5404
5427 5405 got_uef_slot = TRUE;
5428 5406 UNLOCK_MUTEX(&uef_init_mutex);
5429 5407
5430 5408 return (SASL_OK);
5431 5409 }
5432 5410 #endif /* USE_UEF */
5433 5411 #endif /* _SUN_SDK_ */
↓ open down ↓ |
159 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX