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