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