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