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