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