1 /*
2 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 * Copyright (c) 2016 by Delphix. All rights reserved.
5 */
6
7 /* DIGEST-MD5 SASL plugin
8 * Rob Siemborski
9 * Tim Martin
10 * Alexey Melnikov
11 * $Id: digestmd5.c,v 1.153 2003/03/30 22:17:06 leg Exp $
12 */
13 /*
14 * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved.
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 *
20 * 1. Redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer.
22 *
23 * 2. Redistributions in binary form must reproduce the above copyright
24 * notice, this list of conditions and the following disclaimer in
25 * the documentation and/or other materials provided with the
26 * distribution.
27 *
28 * 3. The name "Carnegie Mellon University" must not be used to
29 * endorse or promote products derived from this software without
30 * prior written permission. For permission or any other legal
31 * details, please contact
32 * Office of Technology Transfer
33 * Carnegie Mellon University
34 * 5000 Forbes Avenue
35 * Pittsburgh, PA 15213-3890
36 * (412) 268-4387, fax: (412) 268-7395
37 * tech-transfer@andrew.cmu.edu
38 *
39 * 4. Redistributions of any form whatsoever must retain the following
40 * acknowledgment:
41 * "This product includes software developed by Computing Services
42 * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
43 *
44 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
45 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
46 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
47 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
48 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
49 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
50 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
51 */
52
53 #include <config.h>
54
55 #include <stdlib.h>
56 #include <stdio.h>
57 #include <string.h>
58 #ifndef macintosh
59 #include <sys/types.h>
60 #include <sys/stat.h>
61 #endif
62 #include <fcntl.h>
63 #include <ctype.h>
64
65 /* DES support */
66 #ifdef WITH_DES
67 # ifdef WITH_SSL_DES
68 # include <openssl/des.h>
69 # else /* system DES library */
70 # include <des.h>
71 # endif
72 #endif /* WITH_DES */
73
74 #ifdef WIN32
75 # include <winsock.h>
76 #else /* Unix */
77 # include <netinet/in.h>
78 #endif /* WIN32 */
79
80 #ifdef _SUN_SDK_
81 #include <unistd.h>
82 #endif /* _SUN_SDK_ */
83
84 #include <sasl.h>
85 #include <saslplug.h>
86
87 #include "plugin_common.h"
88
89 #if defined _SUN_SDK_ && defined USE_UEF
90 #include <security/cryptoki.h>
91 static int uef_init(const sasl_utils_t *utils);
92 #endif /* _SUN_SDK_ && USE_UEF */
93
94 #ifndef WIN32
95 extern int strcasecmp(const char *s1, const char *s2);
96 #endif /* end WIN32 */
97
98 #ifdef macintosh
99 #include <sasl_md5_plugin_decl.h>
100 #endif
101
102 /* external definitions */
103
104 #ifndef _SUN_SDK_
105 #ifdef sun
106 /* gotta define gethostname ourselves on suns */
107 extern int gethostname(char *, int);
108 #endif
109 #endif /* !_SUN_SDK_ */
110
111 #define bool int
112
113 #ifndef TRUE
114 #define TRUE (1)
115 #define FALSE (0)
116 #endif
117
118 #define DEFAULT_BUFSIZE 0xFFFF
119
120 /***************************** Common Section *****************************/
121
122 #ifndef _SUN_SDK_
123 static const char plugin_id[] = "$Id: digestmd5.c,v 1.153 2003/03/30 22:17:06 leg Exp $";
124 #endif /* !_SUN_SDK_ */
125
126 /* Definitions */
127 #define NONCE_SIZE (32) /* arbitrary */
128
129 /* Layer Flags */
130 #define DIGEST_NOLAYER (1)
131 #define DIGEST_INTEGRITY (2)
132 #define DIGEST_PRIVACY (4)
133
134 /* defines */
135 #define HASHLEN 16
136 typedef unsigned char HASH[HASHLEN + 1];
137 #define HASHHEXLEN 32
138 typedef unsigned char HASHHEX[HASHHEXLEN + 1];
139
140 #define MAC_SIZE 10
141 #define MAC_OFFS 2
142
143 const char *SEALING_CLIENT_SERVER="Digest H(A1) to client-to-server sealing key magic constant";
144 const char *SEALING_SERVER_CLIENT="Digest H(A1) to server-to-client sealing key magic constant";
145
146 const char *SIGNING_CLIENT_SERVER="Digest session key to client-to-server signing key magic constant";
147 const char *SIGNING_SERVER_CLIENT="Digest session key to server-to-client signing key magic constant";
148
149 #define HT (9)
150 #define CR (13)
151 #define LF (10)
152 #define SP (32)
153 #define DEL (127)
154
155 struct context;
156
157 /* function definitions for cipher encode/decode */
158 typedef int cipher_function_t(struct context *,
159 const char *,
160 unsigned,
161 unsigned char[],
162 char *,
163 unsigned *);
164
165 #ifdef _SUN_SDK_
166 typedef int cipher_init_t(struct context *, char [16],
167 char [16]);
168 #else
169 typedef int cipher_init_t(struct context *, unsigned char [16],
170 unsigned char [16]);
171 #endif /* _SUN_SDK_ */
172
173 typedef void cipher_free_t(struct context *);
174
175 enum Context_type { SERVER = 0, CLIENT = 1 };
176
177 typedef struct cipher_context cipher_context_t;
178
179 /* cached auth info used for fast reauth */
180 typedef struct reauth_entry {
181 char *authid;
182 char *realm;
183 unsigned char *nonce;
184 unsigned int nonce_count;
185 unsigned char *cnonce;
186
187 union {
188 struct {
189 time_t timestamp;
190 } s; /* server stuff */
191
192 struct {
193 char *serverFQDN;
194 int protection;
195 struct digest_cipher *cipher;
196 unsigned int server_maxbuf;
197 } c; /* client stuff */
198 } u;
199 } reauth_entry_t;
200
201 typedef struct reauth_cache {
202 /* static stuff */
203 enum Context_type i_am; /* are we the client or server? */
204 time_t timeout;
205 void *mutex;
206 size_t size;
207
208 reauth_entry_t *e; /* fixed-size hash table of entries */
209 } reauth_cache_t;
210
211 /* context that stores info */
212 typedef struct context {
213 int state; /* state in the authentication we are in */
214 enum Context_type i_am; /* are we the client or server? */
215
216 reauth_cache_t *reauth;
217
218 char *authid;
219 char *realm;
220 unsigned char *nonce;
221 unsigned int nonce_count;
222 unsigned char *cnonce;
223
224 char *response_value;
225
226 unsigned int seqnum;
227 unsigned int rec_seqnum; /* for checking integrity */
228
229 HASH Ki_send;
230 HASH Ki_receive;
231
232 HASH HA1; /* Kcc or Kcs */
233
234 /* copy of utils from the params structures */
235 const sasl_utils_t *utils;
236
237 /* For general use */
238 char *out_buf;
239 unsigned out_buf_len;
240
241 /* for encoding/decoding */
242 buffer_info_t *enc_in_buf;
243 char *encode_buf, *decode_buf, *decode_once_buf;
244 unsigned encode_buf_len, decode_buf_len, decode_once_buf_len;
245 char *decode_tmp_buf;
246 unsigned decode_tmp_buf_len;
247 char *MAC_buf;
248 unsigned MAC_buf_len;
249
250 char *buffer;
251 char sizebuf[4];
252 int cursize;
253
254 /* Layer info */
255 unsigned int size; /* Absolute size of buffer */
256 unsigned int needsize; /* How much of the size of the buffer is left */
257
258 /* Server MaxBuf for Client or Client MaxBuf For Server */
259 /* INCOMING */
260 unsigned int in_maxbuf;
261
262 /* if privacy mode is used use these functions for encode and decode */
263 cipher_function_t *cipher_enc;
264 cipher_function_t *cipher_dec;
265 cipher_init_t *cipher_init;
266 cipher_free_t *cipher_free;
267 struct cipher_context *cipher_enc_context;
268 struct cipher_context *cipher_dec_context;
269 } context_t;
270
271 struct digest_cipher {
272 char *name;
273 sasl_ssf_t ssf;
274 int n; /* bits to make privacy key */
275 int flag; /* a bitmask to make things easier for us */
276
277 cipher_function_t *cipher_enc;
278 cipher_function_t *cipher_dec;
279 cipher_init_t *cipher_init;
280 cipher_free_t *cipher_free;
281 };
282
283 #ifdef _SUN_SDK_
284 static const unsigned char *COLON = (unsigned char *)":";
285 #else
286 static const unsigned char *COLON = ":";
287 #endif /* _SUN_SDK_ */
288
289 /* Hashes a string to produce an unsigned short */
hash(const char * str)290 static unsigned hash(const char *str)
291 {
292 unsigned val = 0;
293 int i;
294
295 while (str && *str) {
296 i = (int) *str;
297 val ^= i;
298 val <<= 1;
299 str++;
300 }
301
302 return val;
303 }
304
CvtHex(HASH Bin,HASHHEX Hex)305 static void CvtHex(HASH Bin, HASHHEX Hex)
306 {
307 unsigned short i;
308 unsigned char j;
309
310 for (i = 0; i < HASHLEN; i++) {
311 j = (Bin[i] >> 4) & 0xf;
312 if (j <= 9)
313 Hex[i * 2] = (j + '0');
314 else
315 Hex[i * 2] = (j + 'a' - 10);
316 j = Bin[i] & 0xf;
317 if (j <= 9)
318 Hex[i * 2 + 1] = (j + '0');
319 else
320 Hex[i * 2 + 1] = (j + 'a' - 10);
321 }
322 Hex[HASHHEXLEN] = '\0';
323 }
324
325 /*
326 * calculate request-digest/response-digest as per HTTP Digest spec
327 */
328 void
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)329 DigestCalcResponse(const sasl_utils_t * utils,
330 HASHHEX HA1, /* H(A1) */
331 unsigned char *pszNonce, /* nonce from server */
332 unsigned int pszNonceCount, /* 8 hex digits */
333 unsigned char *pszCNonce, /* client nonce */
334 unsigned char *pszQop, /* qop-value: "", "auth",
335 * "auth-int" */
336 unsigned char *pszDigestUri, /* requested URL */
337 unsigned char *pszMethod,
338 HASHHEX HEntity, /* H(entity body) if qop="auth-int" */
339 HASHHEX Response /* request-digest or response-digest */
340 )
341 {
342 MD5_CTX Md5Ctx;
343 HASH HA2;
344 HASH RespHash;
345 HASHHEX HA2Hex;
346 char ncvalue[10];
347
348 /* calculate H(A2) */
349 utils->MD5Init(&Md5Ctx);
350
351 if (pszMethod != NULL) {
352 utils->MD5Update(&Md5Ctx, pszMethod, strlen((char *) pszMethod));
353 }
354 utils->MD5Update(&Md5Ctx, (unsigned char *) COLON, 1);
355
356 /* utils->MD5Update(&Md5Ctx, (unsigned char *) "AUTHENTICATE:", 13); */
357 utils->MD5Update(&Md5Ctx, pszDigestUri, strlen((char *) pszDigestUri));
358 if (strcasecmp((char *) pszQop, "auth") != 0) {
359 /* append ":00000000000000000000000000000000" */
360 utils->MD5Update(&Md5Ctx, COLON, 1);
361 utils->MD5Update(&Md5Ctx, HEntity, HASHHEXLEN);
362 }
363 utils->MD5Final(HA2, &Md5Ctx);
364 CvtHex(HA2, HA2Hex);
365
366 /* calculate response */
367 utils->MD5Init(&Md5Ctx);
368 utils->MD5Update(&Md5Ctx, HA1, HASHHEXLEN);
369 utils->MD5Update(&Md5Ctx, COLON, 1);
370 utils->MD5Update(&Md5Ctx, pszNonce, strlen((char *) pszNonce));
371 utils->MD5Update(&Md5Ctx, COLON, 1);
372 if (*pszQop) {
373 sprintf(ncvalue, "%08x", pszNonceCount);
374 #ifdef _SUN_SDK_
375 utils->MD5Update(&Md5Ctx, (unsigned char *)ncvalue, strlen(ncvalue));
376 #else
377 utils->MD5Update(&Md5Ctx, ncvalue, strlen(ncvalue));
378 #endif /* _SUN_SDK_ */
379 utils->MD5Update(&Md5Ctx, COLON, 1);
380 utils->MD5Update(&Md5Ctx, pszCNonce, strlen((char *) pszCNonce));
381 utils->MD5Update(&Md5Ctx, COLON, 1);
382 utils->MD5Update(&Md5Ctx, pszQop, strlen((char *) pszQop));
383 utils->MD5Update(&Md5Ctx, COLON, 1);
384 }
385 utils->MD5Update(&Md5Ctx, HA2Hex, HASHHEXLEN);
386 utils->MD5Final(RespHash, &Md5Ctx);
387 CvtHex(RespHash, Response);
388 }
389
UTF8_In_8859_1(const unsigned char * base,int len)390 static bool UTF8_In_8859_1(const unsigned char *base, int len)
391 {
392 const unsigned char *scan, *end;
393
394 end = base + len;
395 for (scan = base; scan < end; ++scan) {
396 if (*scan > 0xC3)
397 break; /* abort if outside 8859-1 */
398 if (*scan >= 0xC0 && *scan <= 0xC3) {
399 if (++scan == end || *scan < 0x80 || *scan > 0xBF)
400 break;
401 }
402 }
403
404 /* if scan >= end, then this is a 8859-1 string. */
405 return (scan >= end);
406 }
407
408 /*
409 * if the string is entirely in the 8859-1 subset of UTF-8, then translate to
410 * 8859-1 prior to MD5
411 */
MD5_UTF8_8859_1(const sasl_utils_t * utils,MD5_CTX * ctx,bool In_ISO_8859_1,const unsigned char * base,int len)412 void MD5_UTF8_8859_1(const sasl_utils_t * utils,
413 MD5_CTX * ctx,
414 bool In_ISO_8859_1,
415 const unsigned char *base,
416 int len)
417 {
418 const unsigned char *scan, *end;
419 unsigned char cbuf;
420
421 end = base + len;
422
423 /* if we found a character outside 8859-1, don't alter string */
424 if (!In_ISO_8859_1) {
425 utils->MD5Update(ctx, base, len);
426 return;
427 }
428 /* convert to 8859-1 prior to applying hash */
429 do {
430 for (scan = base; scan < end && *scan < 0xC0; ++scan);
431 if (scan != base)
432 utils->MD5Update(ctx, base, scan - base);
433 if (scan + 1 >= end)
434 break;
435 cbuf = ((scan[0] & 0x3) << 6) | (scan[1] & 0x3f);
436 utils->MD5Update(ctx, &cbuf, 1);
437 base = scan + 2;
438 }
439 while (base < end);
440 }
441
DigestCalcSecret(const sasl_utils_t * utils,unsigned char * pszUserName,unsigned char * pszRealm,unsigned char * Password,int PasswordLen,HASH HA1)442 static void DigestCalcSecret(const sasl_utils_t * utils,
443 unsigned char *pszUserName,
444 unsigned char *pszRealm,
445 unsigned char *Password,
446 int PasswordLen,
447 HASH HA1)
448 {
449 bool In_8859_1;
450
451 MD5_CTX Md5Ctx;
452
453 /* Chris Newman clarified that the following text in DIGEST-MD5 spec
454 is bogus: "if name and password are both in ISO 8859-1 charset"
455 We shoud use code example instead */
456
457 utils->MD5Init(&Md5Ctx);
458
459 /* We have to convert UTF-8 to ISO-8859-1 if possible */
460 In_8859_1 = UTF8_In_8859_1(pszUserName, strlen((char *) pszUserName));
461 MD5_UTF8_8859_1(utils, &Md5Ctx, In_8859_1,
462 pszUserName, strlen((char *) pszUserName));
463
464 utils->MD5Update(&Md5Ctx, COLON, 1);
465
466 if (pszRealm != NULL && pszRealm[0] != '\0') {
467 /* a NULL realm is equivalent to the empty string */
468 utils->MD5Update(&Md5Ctx, pszRealm, strlen((char *) pszRealm));
469 }
470
471 utils->MD5Update(&Md5Ctx, COLON, 1);
472
473 /* We have to convert UTF-8 to ISO-8859-1 if possible */
474 In_8859_1 = UTF8_In_8859_1(Password, PasswordLen);
475 MD5_UTF8_8859_1(utils, &Md5Ctx, In_8859_1,
476 Password, PasswordLen);
477
478 utils->MD5Final(HA1, &Md5Ctx);
479 }
480
create_nonce(const sasl_utils_t * utils)481 static unsigned char *create_nonce(const sasl_utils_t * utils)
482 {
483 unsigned char *base64buf;
484 int base64len;
485
486 char *ret = (char *) utils->malloc(NONCE_SIZE);
487 if (ret == NULL)
488 return NULL;
489
490 #if defined _DEV_URANDOM && defined _SUN_SDK_
491 {
492 int fd = open(_DEV_URANDOM, O_RDONLY);
493 int nread = 0;
494
495 if (fd != -1) {
496 nread = read(fd, ret, NONCE_SIZE);
497 close(fd);
498 }
499 if (nread != NONCE_SIZE)
500 utils->rand(utils->rpool, (char *) ret, NONCE_SIZE);
501 }
502 #else
503 utils->rand(utils->rpool, (char *) ret, NONCE_SIZE);
504 #endif /* _DEV_URANDOM && _SUN_SDK_ */
505
506 /* base 64 encode it so it has valid chars */
507 base64len = (NONCE_SIZE * 4 / 3) + (NONCE_SIZE % 3 ? 4 : 0);
508
509 base64buf = (unsigned char *) utils->malloc(base64len + 1);
510 if (base64buf == NULL) {
511 #ifdef _SUN_SDK_
512 utils->log(utils->conn, SASL_LOG_ERR,
513 "Unable to allocate final buffer");
514 #else
515 utils->seterror(utils->conn, 0, "Unable to allocate final buffer");
516 #endif /* _SUN_SDK_ */
517 return NULL;
518 }
519
520 /*
521 * Returns SASL_OK on success, SASL_BUFOVER if result won't fit
522 */
523 if (utils->encode64(ret, NONCE_SIZE,
524 (char *) base64buf, base64len, NULL) != SASL_OK) {
525 utils->free(ret);
526 return NULL;
527 }
528 utils->free(ret);
529
530 return base64buf;
531 }
532
add_to_challenge(const sasl_utils_t * utils,char ** str,unsigned * buflen,unsigned * curlen,char * name,unsigned char * value,bool need_quotes)533 static int add_to_challenge(const sasl_utils_t *utils,
534 char **str, unsigned *buflen, unsigned *curlen,
535 char *name,
536 unsigned char *value,
537 bool need_quotes)
538 {
539 int namesize = strlen(name);
540 int valuesize = strlen((char *) value);
541 int ret;
542
543 ret = _plug_buf_alloc(utils, str, buflen,
544 *curlen + 1 + namesize + 2 + valuesize + 2);
545 if(ret != SASL_OK) return ret;
546
547 *curlen = *curlen + 1 + namesize + 2 + valuesize + 2;
548
549 strcat(*str, ",");
550 strcat(*str, name);
551
552 if (need_quotes) {
553 strcat(*str, "=\"");
554 strcat(*str, (char *) value); /* XXX. What about quoting??? */
555 strcat(*str, "\"");
556 } else {
557 strcat(*str, "=");
558 strcat(*str, (char *) value);
559 }
560
561 return SASL_OK;
562 }
563
skip_lws(char * s)564 static char *skip_lws (char *s)
565 {
566 if(!s) return NULL;
567
568 /* skipping spaces: */
569 while (s[0] == ' ' || s[0] == HT || s[0] == CR || s[0] == LF) {
570 if (s[0]=='\0') break;
571 s++;
572 }
573
574 return s;
575 }
576
577 #ifdef __SUN_SDK_
skip_token(char * s,int caseinsensitive)578 static char *skip_token (char *s, int caseinsensitive __attribute__((unused)))
579 #else
580 static char *skip_token (char *s, int caseinsensitive)
581 #endif /* _SUN_SDK_ */
582 {
583 if(!s) return NULL;
584
585 #ifdef __SUN_SDK_
586 while (((unsigned char *)s)[0]>SP) {
587 #else
588 while (s[0]>SP) {
589 #endif /* _SUN_SDK_ */
590 if (s[0]==DEL || s[0]=='(' || s[0]==')' || s[0]=='<' || s[0]=='>' ||
591 s[0]=='@' || s[0]==',' || s[0]==';' || s[0]==':' || s[0]=='\\' ||
592 s[0]=='\'' || s[0]=='/' || s[0]=='[' || s[0]==']' || s[0]== '?' ||
593 s[0]=='=' || s[0]== '{' || s[0]== '}') {
594 #ifdef __SUN_SDK_
595 /* the above chars are never uppercase */
596 break;
597 #else
598 if (caseinsensitive == 1) {
599 if (!isupper((unsigned char) s[0]))
600 break;
601 } else {
602 break;
603 }
604 #endif /* _SUN_SDK_ */
605 }
606 s++;
607 }
608 return s;
609 }
610
611 /* NULL - error (unbalanced quotes),
612 otherwise pointer to the first character after value */
613 static char *unquote (char *qstr)
614 {
615 char *endvalue;
616 int escaped = 0;
617 char *outptr;
618
619 if(!qstr) return NULL;
620
621 if (qstr[0] == '"') {
622 qstr++;
623 outptr = qstr;
624
625 for (endvalue = qstr; endvalue[0] != '\0'; endvalue++, outptr++) {
626 if (escaped) {
627 outptr[0] = endvalue[0];
628 escaped = 0;
629 }
630 else if (endvalue[0] == '\\') {
631 escaped = 1;
632 outptr--; /* Will be incremented at the end of the loop */
633 }
634 else if (endvalue[0] == '"') {
635 break;
636 }
637 else {
638 outptr[0] = endvalue[0];
639 }
640 }
641
642 if (endvalue[0] != '"') {
643 return NULL;
644 }
645
646 while (outptr <= endvalue) {
647 outptr[0] = '\0';
648 outptr++;
649 }
650 endvalue++;
651 }
652 else { /* not qouted value (token) */
653 endvalue = skip_token(qstr,0);
654 };
655
656 return endvalue;
657 }
658
659 static void get_pair(char **in, char **name, char **value)
660 {
661 char *endpair;
662 /* int inQuotes; */
663 char *curp = *in;
664 *name = NULL;
665 *value = NULL;
666
667 if (curp == NULL) return;
668 if (curp[0] == '\0') return;
669
670 /* skipping spaces: */
671 curp = skip_lws(curp);
672
673 *name = curp;
674
675 curp = skip_token(curp,1);
676
677 /* strip wierd chars */
678 if (curp[0] != '=' && curp[0] != '\0') {
679 *curp++ = '\0';
680 };
681
682 curp = skip_lws(curp);
683
684 if (curp[0] != '=') { /* No '=' sign */
685 *name = NULL;
686 return;
687 }
688
689 curp[0] = '\0';
690 curp++;
691
692 curp = skip_lws(curp);
693
694 *value = (curp[0] == '"') ? curp+1 : curp;
695
696 endpair = unquote (curp);
697 if (endpair == NULL) { /* Unbalanced quotes */
698 *name = NULL;
699 return;
700 }
701 if (endpair[0] != ',') {
702 if (endpair[0]!='\0') {
703 *endpair++ = '\0';
704 }
705 }
706
707 endpair = skip_lws(endpair);
708
709 /* syntax check: MUST be '\0' or ',' */
710 if (endpair[0] == ',') {
711 endpair[0] = '\0';
712 endpair++; /* skipping <,> */
713 } else if (endpair[0] != '\0') {
714 *name = NULL;
715 return;
716 }
717
718 *in = endpair;
719 }
720
721 #ifdef WITH_DES
722 struct des_context_s {
723 des_key_schedule keysched; /* key schedule for des initialization */
724 des_cblock ivec; /* initial vector for encoding */
725 des_key_schedule keysched2; /* key schedule for 3des initialization */
726 };
727
728 typedef struct des_context_s des_context_t;
729
730 /* slide the first 7 bytes of 'inbuf' into the high seven bits of the
731 first 8 bytes of 'keybuf'. 'keybuf' better be 8 bytes long or longer. */
732 static void slidebits(unsigned char *keybuf, unsigned char *inbuf)
733 {
734 keybuf[0] = inbuf[0];
735 keybuf[1] = (inbuf[0]<<7) | (inbuf[1]>>1);
736 keybuf[2] = (inbuf[1]<<6) | (inbuf[2]>>2);
737 keybuf[3] = (inbuf[2]<<5) | (inbuf[3]>>3);
738 keybuf[4] = (inbuf[3]<<4) | (inbuf[4]>>4);
739 keybuf[5] = (inbuf[4]<<3) | (inbuf[5]>>5);
740 keybuf[6] = (inbuf[5]<<2) | (inbuf[6]>>6);
741 keybuf[7] = (inbuf[6]<<1);
742 }
743
744 /******************************
745 *
746 * 3DES functions
747 *
748 *****************************/
749
750 static int dec_3des(context_t *text,
751 const char *input,
752 unsigned inputlen,
753 unsigned char digest[16],
754 char *output,
755 unsigned *outputlen)
756 {
757 des_context_t *c = (des_context_t *) text->cipher_dec_context;
758 int padding, p;
759
760 des_ede2_cbc_encrypt((void *) input,
761 (void *) output,
762 inputlen,
763 c->keysched,
764 c->keysched2,
765 &c->ivec,
766 DES_DECRYPT);
767
768 /* now chop off the padding */
769 padding = output[inputlen - 11];
770 if (padding < 1 || padding > 8) {
771 /* invalid padding length */
772 return SASL_FAIL;
773 }
774 /* verify all padding is correct */
775 for (p = 1; p <= padding; p++) {
776 if (output[inputlen - 10 - p] != padding) {
777 return SASL_FAIL;
778 }
779 }
780
781 /* chop off the padding */
782 *outputlen = inputlen - padding - 10;
783
784 /* copy in the HMAC to digest */
785 memcpy(digest, output + inputlen - 10, 10);
786
787 return SASL_OK;
788 }
789
790 static int enc_3des(context_t *text,
791 const char *input,
792 unsigned inputlen,
793 unsigned char digest[16],
794 char *output,
795 unsigned *outputlen)
796 {
797 des_context_t *c = (des_context_t *) text->cipher_enc_context;
798 int len;
799 int paddinglen;
800
801 /* determine padding length */
802 paddinglen = 8 - ((inputlen + 10) % 8);
803
804 /* now construct the full stuff to be ciphered */
805 memcpy(output, input, inputlen); /* text */
806 memset(output+inputlen, paddinglen, paddinglen);/* pad */
807 memcpy(output+inputlen+paddinglen, digest, 10); /* hmac */
808
809 len=inputlen+paddinglen+10;
810
811 des_ede2_cbc_encrypt((void *) output,
812 (void *) output,
813 len,
814 c->keysched,
815 c->keysched2,
816 &c->ivec,
817 DES_ENCRYPT);
818
819 *outputlen=len;
820
821 return SASL_OK;
822 }
823
824 static int init_3des(context_t *text,
825 unsigned char enckey[16],
826 unsigned char deckey[16])
827 {
828 des_context_t *c;
829 unsigned char keybuf[8];
830
831 /* allocate enc & dec context */
832 c = (des_context_t *) text->utils->malloc(2 * sizeof(des_context_t));
833 if (c == NULL) return SASL_NOMEM;
834
835 /* setup enc context */
836 slidebits(keybuf, enckey);
837 if (des_key_sched((des_cblock *) keybuf, c->keysched) < 0)
838 return SASL_FAIL;
839
840 slidebits(keybuf, enckey + 7);
841 if (des_key_sched((des_cblock *) keybuf, c->keysched2) < 0)
842 return SASL_FAIL;
843 memcpy(c->ivec, ((char *) enckey) + 8, 8);
844
845 text->cipher_enc_context = (cipher_context_t *) c;
846
847 /* setup dec context */
848 c++;
849 slidebits(keybuf, deckey);
850 if (des_key_sched((des_cblock *) keybuf, c->keysched) < 0)
851 return SASL_FAIL;
852
853 slidebits(keybuf, deckey + 7);
854 if (des_key_sched((des_cblock *) keybuf, c->keysched2) < 0)
855 return SASL_FAIL;
856
857 memcpy(c->ivec, ((char *) deckey) + 8, 8);
858
859 text->cipher_dec_context = (cipher_context_t *) c;
860
861 return SASL_OK;
862 }
863
864
865 /******************************
866 *
867 * DES functions
868 *
869 *****************************/
870
871 static int dec_des(context_t *text,
872 const char *input,
873 unsigned inputlen,
874 unsigned char digest[16],
875 char *output,
876 unsigned *outputlen)
877 {
878 des_context_t *c = (des_context_t *) text->cipher_dec_context;
879 int p, padding = 0;
880
881 des_cbc_encrypt((void *) input,
882 (void *) output,
883 inputlen,
884 c->keysched,
885 &c->ivec,
886 DES_DECRYPT);
887
888 /* Update the ivec (des_cbc_encrypt implementations tend to be broken in
889 this way) */
890 memcpy(c->ivec, input + (inputlen - 8), 8);
891
892 /* now chop off the padding */
893 padding = output[inputlen - 11];
894 if (padding < 1 || padding > 8) {
895 /* invalid padding length */
896 return SASL_FAIL;
897 }
898 /* verify all padding is correct */
899 for (p = 1; p <= padding; p++) {
900 if (output[inputlen - 10 - p] != padding) {
901 return SASL_FAIL;
902 }
903 }
904
905 /* chop off the padding */
906 *outputlen = inputlen - padding - 10;
907
908 /* copy in the HMAC to digest */
909 memcpy(digest, output + inputlen - 10, 10);
910
911 return SASL_OK;
912 }
913
914 static int enc_des(context_t *text,
915 const char *input,
916 unsigned inputlen,
917 unsigned char digest[16],
918 char *output,
919 unsigned *outputlen)
920 {
921 des_context_t *c = (des_context_t *) text->cipher_enc_context;
922 int len;
923 int paddinglen;
924
925 /* determine padding length */
926 paddinglen = 8 - ((inputlen+10) % 8);
927
928 /* now construct the full stuff to be ciphered */
929 memcpy(output, input, inputlen); /* text */
930 memset(output+inputlen, paddinglen, paddinglen);/* pad */
931 memcpy(output+inputlen+paddinglen, digest, 10); /* hmac */
932
933 len = inputlen + paddinglen + 10;
934
935 des_cbc_encrypt((void *) output,
936 (void *) output,
937 len,
938 c->keysched,
939 &c->ivec,
940 DES_ENCRYPT);
941
942 /* Update the ivec (des_cbc_encrypt implementations tend to be broken in
943 this way) */
944 memcpy(c->ivec, output + (len - 8), 8);
945
946 *outputlen = len;
947
948 return SASL_OK;
949 }
950
951 static int init_des(context_t *text,
952 unsigned char enckey[16],
953 unsigned char deckey[16])
954 {
955 des_context_t *c;
956 unsigned char keybuf[8];
957
958 /* allocate enc context */
959 c = (des_context_t *) text->utils->malloc(2 * sizeof(des_context_t));
960 if (c == NULL) return SASL_NOMEM;
961
962 /* setup enc context */
963 slidebits(keybuf, enckey);
964 des_key_sched((des_cblock *) keybuf, c->keysched);
965
966 memcpy(c->ivec, ((char *) enckey) + 8, 8);
967
968 text->cipher_enc_context = (cipher_context_t *) c;
969
970 /* setup dec context */
971 c++;
972 slidebits(keybuf, deckey);
973 des_key_sched((des_cblock *) keybuf, c->keysched);
974
975 memcpy(c->ivec, ((char *) deckey) + 8, 8);
976
977 text->cipher_dec_context = (cipher_context_t *) c;
978
979 return SASL_OK;
980 }
981
982 static void free_des(context_t *text)
983 {
984 /* free des contextss. only cipher_enc_context needs to be free'd,
985 since cipher_dec_context was allocated at the same time. */
986 if (text->cipher_enc_context) text->utils->free(text->cipher_enc_context);
987 }
988
989 #endif /* WITH_DES */
990
991 #ifdef WITH_RC4
992 /* quick generic implementation of RC4 */
993 struct rc4_context_s {
994 unsigned char sbox[256];
995 int i, j;
996 };
997
998 typedef struct rc4_context_s rc4_context_t;
999
1000 static void rc4_init(rc4_context_t *text,
1001 const unsigned char *key,
1002 unsigned keylen)
1003 {
1004 int i, j;
1005
1006 /* fill in linearly s0=0 s1=1... */
1007 for (i=0;i<256;i++)
1008 text->sbox[i]=i;
1009
1010 j=0;
1011 for (i = 0; i < 256; i++) {
1012 unsigned char tmp;
1013 /* j = (j + Si + Ki) mod 256 */
1014 j = (j + text->sbox[i] + key[i % keylen]) % 256;
1015
1016 /* swap Si and Sj */
1017 tmp = text->sbox[i];
1018 text->sbox[i] = text->sbox[j];
1019 text->sbox[j] = tmp;
1020 }
1021
1022 /* counters initialized to 0 */
1023 text->i = 0;
1024 text->j = 0;
1025 }
1026
1027 static void rc4_encrypt(rc4_context_t *text,
1028 const char *input,
1029 char *output,
1030 unsigned len)
1031 {
1032 int tmp;
1033 int i = text->i;
1034 int j = text->j;
1035 int t;
1036 int K;
1037 const char *input_end = input + len;
1038
1039 while (input < input_end) {
1040 i = (i + 1) % 256;
1041
1042 j = (j + text->sbox[i]) % 256;
1043
1044 /* swap Si and Sj */
1045 tmp = text->sbox[i];
1046 text->sbox[i] = text->sbox[j];
1047 text->sbox[j] = tmp;
1048
1049 t = (text->sbox[i] + text->sbox[j]) % 256;
1050
1051 K = text->sbox[t];
1052
1053 /* byte K is Xor'ed with plaintext */
1054 *output++ = *input++ ^ K;
1055 }
1056
1057 text->i = i;
1058 text->j = j;
1059 }
1060
1061 static void rc4_decrypt(rc4_context_t *text,
1062 const char *input,
1063 char *output,
1064 unsigned len)
1065 {
1066 int tmp;
1067 int i = text->i;
1068 int j = text->j;
1069 int t;
1070 int K;
1071 const char *input_end = input + len;
1072
1073 while (input < input_end) {
1074 i = (i + 1) % 256;
1075
1076 j = (j + text->sbox[i]) % 256;
1077
1078 /* swap Si and Sj */
1079 tmp = text->sbox[i];
1080 text->sbox[i] = text->sbox[j];
1081 text->sbox[j] = tmp;
1082
1083 t = (text->sbox[i] + text->sbox[j]) % 256;
1084
1085 K = text->sbox[t];
1086
1087 /* byte K is Xor'ed with plaintext */
1088 *output++ = *input++ ^ K;
1089 }
1090
1091 text->i = i;
1092 text->j = j;
1093 }
1094
1095 static void free_rc4(context_t *text)
1096 {
1097 /* free rc4 context structures */
1098
1099 if(text->cipher_enc_context) text->utils->free(text->cipher_enc_context);
1100 if(text->cipher_dec_context) text->utils->free(text->cipher_dec_context);
1101 #ifdef _SUN_SDK_
1102 text->cipher_enc_context = NULL;
1103 text->cipher_dec_context = NULL;
1104 #endif /* _SUN_SDK_ */
1105 }
1106
1107 static int init_rc4(context_t *text,
1108 #ifdef _SUN_SDK_
1109 char enckey[16],
1110 char deckey[16])
1111 #else
1112 unsigned char enckey[16],
1113 unsigned char deckey[16])
1114 #endif /* _SUN_SDK_ */
1115 {
1116 /* allocate rc4 context structures */
1117 text->cipher_enc_context=
1118 (cipher_context_t *) text->utils->malloc(sizeof(rc4_context_t));
1119 if (text->cipher_enc_context == NULL) return SASL_NOMEM;
1120
1121 text->cipher_dec_context=
1122 (cipher_context_t *) text->utils->malloc(sizeof(rc4_context_t));
1123 #ifdef _SUN_SDK_
1124 if (text->cipher_dec_context == NULL) {
1125 text->utils->free(text->cipher_enc_context);
1126 text->cipher_enc_context = NULL;
1127 return SASL_NOMEM;
1128 }
1129 #else
1130 if (text->cipher_dec_context == NULL) return SASL_NOMEM;
1131 #endif /* _SUN_SDK_ */
1132
1133 /* initialize them */
1134 rc4_init((rc4_context_t *) text->cipher_enc_context,
1135 (const unsigned char *) enckey, 16);
1136 rc4_init((rc4_context_t *) text->cipher_dec_context,
1137 (const unsigned char *) deckey, 16);
1138
1139 return SASL_OK;
1140 }
1141
1142 static int dec_rc4(context_t *text,
1143 const char *input,
1144 unsigned inputlen,
1145 unsigned char digest[16],
1146 char *output,
1147 unsigned *outputlen)
1148 {
1149 /* decrypt the text part */
1150 rc4_decrypt((rc4_context_t *) text->cipher_dec_context,
1151 input, output, inputlen-10);
1152
1153 /* decrypt the HMAC part */
1154 rc4_decrypt((rc4_context_t *) text->cipher_dec_context,
1155 input+(inputlen-10), (char *) digest, 10);
1156
1157 /* no padding so we just subtract the HMAC to get the text length */
1158 *outputlen = inputlen - 10;
1159
1160 return SASL_OK;
1161 }
1162
1163 static int enc_rc4(context_t *text,
1164 const char *input,
1165 unsigned inputlen,
1166 unsigned char digest[16],
1167 char *output,
1168 unsigned *outputlen)
1169 {
1170 /* pad is zero */
1171 *outputlen = inputlen+10;
1172
1173 /* encrypt the text part */
1174 rc4_encrypt((rc4_context_t *) text->cipher_enc_context,
1175 input,
1176 output,
1177 inputlen);
1178
1179 /* encrypt the HMAC part */
1180 rc4_encrypt((rc4_context_t *) text->cipher_enc_context,
1181 (const char *) digest,
1182 (output)+inputlen, 10);
1183
1184 return SASL_OK;
1185 }
1186
1187 #endif /* WITH_RC4 */
1188
1189 struct digest_cipher available_ciphers[] =
1190 {
1191 #ifdef WITH_RC4
1192 { "rc4-40", 40, 5, 0x01, &enc_rc4, &dec_rc4, &init_rc4, &free_rc4 },
1193 { "rc4-56", 56, 7, 0x02, &enc_rc4, &dec_rc4, &init_rc4, &free_rc4 },
1194 { "rc4", 128, 16, 0x04, &enc_rc4, &dec_rc4, &init_rc4, &free_rc4 },
1195 #endif
1196 #ifdef WITH_DES
1197 { "des", 55, 16, 0x08, &enc_des, &dec_des, &init_des, &free_des },
1198 { "3des", 112, 16, 0x10, &enc_3des, &dec_3des, &init_3des, &free_des },
1199 #endif
1200 { NULL, 0, 0, 0, NULL, NULL, NULL, NULL }
1201 };
1202
1203
1204 #ifdef USE_UEF
1205 DEFINE_STATIC_MUTEX(uef_init_mutex);
1206 #define DES_CIPHER_INDEX 3
1207 #define DES3_CIPHER_INDEX 4
1208
1209 static int got_uef_slot = FALSE;
1210 static sasl_ssf_t uef_max_ssf = 0;
1211 static CK_SLOT_ID rc4_slot_id;
1212 static CK_SLOT_ID des_slot_id;
1213 static CK_SLOT_ID des3_slot_id;
1214
1215 struct uef_context_s {
1216 CK_SESSION_HANDLE hSession;
1217 CK_OBJECT_HANDLE hKey;
1218 };
1219
1220 typedef struct uef_context_s uef_context_t;
1221
1222 /*
1223 * slide the first 7 bytes of 'inbuf' into the high seven bits of the
1224 * first 8 bytes of 'keybuf'. 'inbuf' better be 8 bytes long or longer.
1225 *
1226 * This is used to compute the IV for "des" and "3des" as described in
1227 * draft-ietf-sasl-rfc2831bis-00.txt - The IV for "des"
1228 * and "3des" is the last 8 bytes of Kcc or Kcs - the encryption keys.
1229 */
1230
1231 static void slidebits(unsigned char *keybuf, unsigned char *inbuf)
1232 {
1233 keybuf[0] = inbuf[0];
1234 keybuf[1] = (inbuf[0]<<7) | (inbuf[1]>>1);
1235 keybuf[2] = (inbuf[1]<<6) | (inbuf[2]>>2);
1236 keybuf[3] = (inbuf[2]<<5) | (inbuf[3]>>3);
1237 keybuf[4] = (inbuf[3]<<4) | (inbuf[4]>>4);
1238 keybuf[5] = (inbuf[4]<<3) | (inbuf[5]>>5);
1239 keybuf[6] = (inbuf[5]<<2) | (inbuf[6]>>6);
1240 keybuf[7] = (inbuf[6]<<1);
1241 }
1242
1243 /*
1244 * Create encryption and decryption session handle handles for later use.
1245 * Returns SASL_OK on success - any other return indicates failure.
1246 *
1247 * free_uef is called to release associated resources by
1248 * digestmd5_common_mech_dispose
1249 */
1250
1251 static int init_uef(context_t *text,
1252 CK_KEY_TYPE keyType,
1253 CK_MECHANISM_TYPE mech_type,
1254 CK_SLOT_ID slot_id,
1255 char enckey[16],
1256 char deckey[16])
1257 {
1258 CK_RV rv;
1259 uef_context_t *enc_context;
1260 uef_context_t *dec_context;
1261 CK_OBJECT_CLASS class = CKO_SECRET_KEY;
1262 CK_BBOOL true = TRUE;
1263 static CK_MECHANISM mechanism = {CKM_RC4, NULL, 0};
1264 unsigned char keybuf[24];
1265 CK_ATTRIBUTE template[] = {
1266 {CKA_CLASS, NULL, sizeof (class)},
1267 {CKA_KEY_TYPE, NULL, sizeof (keyType)},
1268 {CKA_ENCRYPT, NULL, sizeof (true)},
1269 {CKA_VALUE, NULL, 16}};
1270
1271 template[0].pValue = &class;
1272 template[1].pValue = &keyType;
1273 template[2].pValue = &true;
1274 if (keyType == CKK_DES || keyType == CKK_DES3) {
1275 slidebits(keybuf, (unsigned char *)enckey);
1276 if (keyType == CKK_DES3) {
1277 slidebits(keybuf + 8, (unsigned char *)enckey + 7);
1278 (void) memcpy(keybuf + 16, keybuf, 8);
1279 template[3].ulValueLen = 24;
1280 } else {
1281 template[3].ulValueLen = 8;
1282 }
1283 template[3].pValue = keybuf;
1284 mechanism.pParameter = enckey + 8;
1285 mechanism.ulParameterLen = 8;
1286 } else {
1287 template[3].pValue = enckey;
1288 }
1289 mechanism.mechanism = mech_type;
1290
1291 /* allocate rc4 context structures */
1292 enc_context = text->utils->malloc(sizeof (uef_context_t));
1293 if (enc_context == NULL)
1294 return SASL_NOMEM;
1295
1296 rv = C_OpenSession(slot_id, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR,
1297 &enc_context->hSession);
1298 if (rv != CKR_OK) {
1299 text->utils->free(enc_context);
1300 #ifdef DEBUG
1301 text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1302 "enc C_OpenSession Failed:0x%.8X\n", rv);
1303 #endif
1304 return SASL_FAIL;
1305 }
1306
1307 rv = C_CreateObject(enc_context->hSession, template,
1308 sizeof (template)/sizeof (template[0]), &enc_context->hKey);
1309 if (rv != CKR_OK) {
1310 text->utils->free(enc_context);
1311 (void) C_CloseSession(enc_context->hSession);
1312 #ifdef DEBUG
1313 text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1314 "enc C_CreateObject: rv = 0x%.8X\n", rv);
1315 #endif
1316 return SASL_FAIL;
1317 }
1318
1319 text->cipher_enc_context = (cipher_context_t *)enc_context;
1320
1321 /* Initialize the encryption operation in the session */
1322 rv = C_EncryptInit(enc_context->hSession, &mechanism, enc_context->hKey);
1323 if (rv != CKR_OK) {
1324 #ifdef DEBUG
1325 text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1326 "C_EncryptInit: rv = 0x%.8X\n", rv);
1327 #endif
1328 return SASL_FAIL;
1329 }
1330
1331 dec_context = text->utils->malloc(sizeof(uef_context_t));
1332 if (dec_context == NULL)
1333 return SASL_NOMEM;
1334
1335 rv = C_OpenSession(slot_id, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR,
1336 &dec_context->hSession);
1337 if (rv != CKR_OK) {
1338 #ifdef DEBUG
1339 text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1340 "dec C_OpenSession Failed:0x%.8X\n", rv);
1341 #endif
1342 text->utils->free(dec_context);
1343 return SASL_FAIL;
1344 }
1345
1346 template[2].type = CKA_DECRYPT;
1347 if (keyType == CKK_DES || keyType == CKK_DES3) {
1348 slidebits(keybuf, (unsigned char *)deckey);
1349 if (keyType == CKK_DES3) {
1350 slidebits(keybuf + 8, (unsigned char *)deckey + 7);
1351 (void) memcpy(keybuf + 16, keybuf, 8);
1352 }
1353 mechanism.pParameter = deckey + 8;
1354 } else {
1355 template[3].pValue = deckey;
1356 }
1357
1358 rv = C_CreateObject(dec_context->hSession, template,
1359 sizeof (template)/sizeof (template[0]), &dec_context->hKey);
1360 if (rv != CKR_OK) {
1361 #ifdef DEBUG
1362 text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1363 "dec C_CreateObject: rv = 0x%.8X\n", rv);
1364 #endif
1365 (void) C_CloseSession(dec_context->hSession);
1366 text->utils->free(dec_context);
1367 return SASL_FAIL;
1368 }
1369 text->cipher_dec_context = (cipher_context_t *)dec_context;
1370
1371 /* Initialize the decryption operation in the session */
1372 rv = C_DecryptInit(dec_context->hSession, &mechanism, dec_context->hKey);
1373 if (rv != CKR_OK) {
1374 #ifdef DEBUG
1375 text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1376 "C_DecryptInit: rv = 0x%.8X\n", rv);
1377 #endif
1378 return SASL_FAIL;
1379 }
1380
1381 return SASL_OK;
1382 }
1383
1384 static int init_rc4_uef(context_t *text,
1385 char enckey[16],
1386 char deckey[16])
1387 {
1388 return init_uef(text, CKK_RC4, CKM_RC4, rc4_slot_id, enckey, deckey);
1389 }
1390
1391 static int init_des_uef(context_t *text,
1392 char enckey[16],
1393 char deckey[16])
1394 {
1395 return init_uef(text, CKK_DES, CKM_DES_CBC, des_slot_id, enckey, deckey);
1396 }
1397
1398 static int init_3des_uef(context_t *text,
1399 char enckey[16],
1400 char deckey[16])
1401 {
1402 return init_uef(text, CKK_DES3, CKM_DES3_CBC, des3_slot_id, enckey, deckey);
1403 }
1404
1405 static void
1406 free_uef(context_t *text)
1407 {
1408 uef_context_t *enc_context =
1409 (uef_context_t *)text->cipher_enc_context;
1410 uef_context_t *dec_context =
1411 (uef_context_t *)text->cipher_dec_context;
1412 CK_RV rv;
1413 unsigned char buf[1];
1414 CK_ULONG ulLen = 0;
1415
1416
1417 if (enc_context != NULL) {
1418 rv = C_EncryptFinal(enc_context->hSession, buf, &ulLen);
1419 if (rv != CKR_OK) {
1420 #ifdef DEBUG
1421 text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1422 "C_EncryptFinal failed:0x%.8X\n", rv);
1423 #endif
1424 }
1425 rv = C_DestroyObject(enc_context->hSession, enc_context->hKey);
1426 if (rv != CKR_OK) {
1427 #ifdef DEBUG
1428 text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1429 "C_DestroyObject failed:0x%.8X\n", rv);
1430 #endif
1431 }
1432 rv = C_CloseSession(enc_context->hSession);
1433 if (rv != CKR_OK) {
1434 #ifdef DEBUG
1435 text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1436 "C_CloseSession failed:0x%.8X\n", rv);
1437 #endif
1438 }
1439 text->utils->free(enc_context);
1440 }
1441 if (dec_context != NULL) {
1442 rv = C_DecryptFinal(dec_context->hSession, buf, &ulLen);
1443 if (rv != CKR_OK) {
1444 #ifdef DEBUG
1445 text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1446 "C_DecryptFinal failed:0x%.8X\n", rv);
1447 #endif
1448 }
1449 rv = C_DestroyObject(dec_context->hSession, dec_context->hKey);
1450 if (rv != CKR_OK) {
1451 #ifdef DEBUG
1452 text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1453 "C_DestroyObject failed:0x%.8X\n", rv);
1454 #endif
1455 }
1456
1457 rv = C_CloseSession(dec_context->hSession);
1458 if (rv != CKR_OK) {
1459 #ifdef DEBUG
1460 text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1461 "C_CloseSession failed:0x%.8X\n", rv);
1462 #endif
1463 }
1464 text->utils->free(dec_context);
1465 }
1466 text->cipher_enc_context = NULL;
1467 text->cipher_dec_context = NULL;
1468 }
1469
1470 static int
1471 dec_rc4_uef(context_t *text,
1472 const char *input,
1473 unsigned inputlen,
1474 unsigned char digest[16],
1475 char *output,
1476 unsigned *outputlen)
1477 {
1478 CK_RV rv;
1479 uef_context_t *dec_context =
1480 (uef_context_t *)text->cipher_dec_context;
1481 CK_ULONG ulDataLen = *outputlen - MAC_SIZE;
1482 CK_ULONG ulDigestLen = MAC_SIZE;
1483
1484 rv = C_DecryptUpdate(dec_context->hSession, (CK_BYTE_PTR)input,
1485 inputlen - MAC_SIZE, (CK_BYTE_PTR)output, &ulDataLen);
1486 if (rv != CKR_OK) {
1487 #ifdef DEBUG
1488 text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1489 "C_DecryptUpdate failed:0x%.8X\n", rv);
1490 #endif
1491 return SASL_FAIL;
1492 }
1493 *outputlen = (unsigned)ulDataLen;
1494
1495 rv = C_DecryptUpdate(dec_context->hSession,
1496 (CK_BYTE_PTR)input+(inputlen-MAC_SIZE), MAC_SIZE, (CK_BYTE_PTR)digest,
1497 &ulDigestLen);
1498 if (rv != CKR_OK || ulDigestLen != MAC_SIZE) {
1499 #ifdef DEBUG
1500 text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1501 "C_DecryptUpdate:0x%.8X, digestLen:%d\n",
1502 rv, ulDigestLen);
1503 #endif
1504 return SASL_FAIL;
1505 }
1506
1507 return SASL_OK;
1508 }
1509
1510 static int
1511 enc_rc4_uef(context_t *text,
1512 const char *input,
1513 unsigned inputlen,
1514 unsigned char digest[16],
1515 char *output,
1516 unsigned *outputlen)
1517 {
1518 CK_RV rv;
1519 uef_context_t *enc_context =
1520 (uef_context_t *)text->cipher_enc_context;
1521 CK_ULONG ulDataLen = inputlen;
1522 CK_ULONG ulDigestLen = MAC_SIZE;
1523
1524 rv = C_EncryptUpdate(enc_context->hSession, (CK_BYTE_PTR)input, inputlen,
1525 (CK_BYTE_PTR)output, &ulDataLen);
1526 if (rv != CKR_OK) {
1527 #ifdef DEBUG
1528 text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1529 "C_EncryptUpdate failed: 0x%.8X "
1530 "inputlen:%d outputlen:%d\n",
1531 rv, inputlen, ulDataLen);
1532 #endif
1533 return SASL_FAIL;
1534 }
1535 rv = C_EncryptUpdate(enc_context->hSession, (CK_BYTE_PTR)digest, MAC_SIZE,
1536 (CK_BYTE_PTR)output + inputlen, &ulDigestLen);
1537 if (rv != CKR_OK) {
1538 #ifdef DEBUG
1539 text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1540 "C_EncryptUpdate failed: 0x%.8X ulDigestLen:%d\n",
1541 rv, ulDigestLen);
1542 #endif
1543 return SASL_FAIL;
1544 }
1545
1546 *outputlen = ulDataLen + ulDigestLen;
1547
1548 return SASL_OK;
1549 }
1550
1551 static int
1552 dec_des_uef(context_t *text,
1553 const char *input,
1554 unsigned inputlen,
1555 unsigned char digest[16],
1556 char *output,
1557 unsigned *outputlen)
1558 {
1559 CK_RV rv;
1560 uef_context_t *dec_context =
1561 (uef_context_t *)text->cipher_dec_context;
1562 CK_ULONG ulDataLen = inputlen;
1563 int padding, p;
1564
1565 rv = C_DecryptUpdate(dec_context->hSession, (CK_BYTE_PTR)input,
1566 inputlen, (CK_BYTE_PTR)output, &ulDataLen);
1567 if (rv != CKR_OK) {
1568 #ifdef DEBUG
1569 text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1570 "C_DecryptUpdate failed:0x%.8X\n", rv);
1571 #endif
1572 return SASL_FAIL;
1573 }
1574 if (ulDataLen != inputlen) {
1575 #ifdef DEBUG
1576 text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1577 "C_DecryptUpdate unexpected data len:%d !=%d\n",
1578 inputlen, ulDataLen);
1579 #endif
1580 return SASL_BUFOVER;
1581 }
1582
1583 /* now chop off the padding */
1584 padding = output[inputlen - 11];
1585 if (padding < 1 || padding > 8) {
1586 /* invalid padding length */
1587 return SASL_BADMAC;
1588 }
1589 /* verify all padding is correct */
1590 for (p = 1; p <= padding; p++) {
1591 if (output[inputlen - MAC_SIZE - p] != padding) {
1592 return SASL_BADMAC;
1593 }
1594 }
1595
1596 /* chop off the padding */
1597 *outputlen = inputlen - padding - MAC_SIZE;
1598
1599 /* copy in the HMAC to digest */
1600 memcpy(digest, output + inputlen - MAC_SIZE, MAC_SIZE);
1601
1602 return SASL_OK;
1603 }
1604
1605 static int
1606 enc_des_uef(context_t *text,
1607 const char *input,
1608 unsigned inputlen,
1609 unsigned char digest[16],
1610 char *output,
1611 unsigned *outputlen)
1612 {
1613 CK_RV rv;
1614 uef_context_t *enc_context =
1615 (uef_context_t *)text->cipher_enc_context;
1616 CK_ULONG ulDataLen;
1617 int paddinglen;
1618
1619 /* determine padding length */
1620 paddinglen = 8 - ((inputlen + MAC_SIZE) % 8);
1621
1622 /* now construct the full stuff to be ciphered */
1623 memcpy(output, input, inputlen); /* text */
1624 memset(output+inputlen, paddinglen, paddinglen);/* pad */
1625 memcpy(output+inputlen+paddinglen, digest, MAC_SIZE); /* hmac */
1626
1627 ulDataLen=inputlen+paddinglen+MAC_SIZE;
1628
1629 rv = C_EncryptUpdate(enc_context->hSession, (CK_BYTE_PTR)output, ulDataLen,
1630 (CK_BYTE_PTR)output, &ulDataLen);
1631 if (rv != CKR_OK) {
1632 #ifdef DEBUG
1633 text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1634 "C_EncryptUpdate failed: 0x%.8X "
1635 "inputlen:%d outputlen:%d\n",
1636 rv, ulDataLen, ulDataLen);
1637 #endif
1638 return SASL_FAIL;
1639 }
1640 *outputlen = (unsigned)ulDataLen;
1641
1642 return SASL_OK;
1643 }
1644
1645 struct digest_cipher uef_ciphers[] =
1646 {
1647 { "rc4-40", 40, 5, 0x01, &enc_rc4_uef, &dec_rc4_uef, &init_rc4_uef,
1648 &free_uef },
1649 { "rc4-56", 56, 7, 0x02, &enc_rc4_uef, &dec_rc4_uef, &init_rc4_uef,
1650 &free_uef },
1651 { "rc4", 128, 16, 0x04, &enc_rc4_uef, &dec_rc4_uef, &init_rc4_uef,
1652 &free_uef },
1653 { "des", 55, 16, 0x08, &enc_des_uef, &dec_des_uef, &init_des_uef,
1654 &free_uef },
1655 { "3des", 112, 16, 0x10, &enc_des_uef, &dec_des_uef, &init_3des_uef,
1656 &free_uef },
1657 { NULL, 0, 0, 0, NULL, NULL, NULL, NULL }
1658 };
1659
1660 struct digest_cipher *available_ciphers1 = uef_ciphers;
1661 #endif /* USE_UEF */
1662
1663 static int create_layer_keys(context_t *text,
1664 const sasl_utils_t *utils,
1665 HASH key, int keylen,
1666 char enckey[16], char deckey[16])
1667 {
1668 MD5_CTX Md5Ctx;
1669
1670 utils->MD5Init(&Md5Ctx);
1671 utils->MD5Update(&Md5Ctx, key, keylen);
1672 if (text->i_am == SERVER) {
1673 utils->MD5Update(&Md5Ctx, (const unsigned char *) SEALING_SERVER_CLIENT,
1674 strlen(SEALING_SERVER_CLIENT));
1675 } else {
1676 utils->MD5Update(&Md5Ctx, (const unsigned char *) SEALING_CLIENT_SERVER,
1677 strlen(SEALING_CLIENT_SERVER));
1678 }
1679 utils->MD5Final((unsigned char *) enckey, &Md5Ctx);
1680
1681 utils->MD5Init(&Md5Ctx);
1682 utils->MD5Update(&Md5Ctx, key, keylen);
1683 if (text->i_am != SERVER) {
1684 utils->MD5Update(&Md5Ctx, (const unsigned char *)SEALING_SERVER_CLIENT,
1685 strlen(SEALING_SERVER_CLIENT));
1686 } else {
1687 utils->MD5Update(&Md5Ctx, (const unsigned char *)SEALING_CLIENT_SERVER,
1688 strlen(SEALING_CLIENT_SERVER));
1689 }
1690 utils->MD5Final((unsigned char *) deckey, &Md5Ctx);
1691
1692 /* create integrity keys */
1693 /* sending */
1694 utils->MD5Init(&Md5Ctx);
1695 utils->MD5Update(&Md5Ctx, text->HA1, HASHLEN);
1696 if (text->i_am == SERVER) {
1697 utils->MD5Update(&Md5Ctx, (const unsigned char *)SIGNING_SERVER_CLIENT,
1698 strlen(SIGNING_SERVER_CLIENT));
1699 } else {
1700 utils->MD5Update(&Md5Ctx, (const unsigned char *)SIGNING_CLIENT_SERVER,
1701 strlen(SIGNING_CLIENT_SERVER));
1702 }
1703 utils->MD5Final(text->Ki_send, &Md5Ctx);
1704
1705 /* receiving */
1706 utils->MD5Init(&Md5Ctx);
1707 utils->MD5Update(&Md5Ctx, text->HA1, HASHLEN);
1708 if (text->i_am != SERVER) {
1709 utils->MD5Update(&Md5Ctx, (const unsigned char *)SIGNING_SERVER_CLIENT,
1710 strlen(SIGNING_SERVER_CLIENT));
1711 } else {
1712 utils->MD5Update(&Md5Ctx, (const unsigned char *)SIGNING_CLIENT_SERVER,
1713 strlen(SIGNING_CLIENT_SERVER));
1714 }
1715 utils->MD5Final(text->Ki_receive, &Md5Ctx);
1716
1717 return SASL_OK;
1718 }
1719
1720 static const unsigned short version = 1;
1721
1722 /* len, CIPHER(Kc, {msg, pag, HMAC(ki, {SeqNum, msg})[0..9]}), x0001, SeqNum */
1723
1724 static int
1725 digestmd5_privacy_encode(void *context,
1726 const struct iovec *invec,
1727 unsigned numiov,
1728 const char **output,
1729 unsigned *outputlen)
1730 {
1731 context_t *text = (context_t *) context;
1732 int tmp;
1733 unsigned int tmpnum;
1734 unsigned short int tmpshort;
1735 int ret;
1736 char *out;
1737 unsigned char digest[16];
1738 struct buffer_info *inblob, bufinfo;
1739
1740 if(!context || !invec || !numiov || !output || !outputlen) {
1741 PARAMERROR(text->utils);
1742 return SASL_BADPARAM;
1743 }
1744
1745 if (numiov > 1) {
1746 ret = _plug_iovec_to_buf(text->utils, invec, numiov, &text->enc_in_buf);
1747 if (ret != SASL_OK) return ret;
1748 inblob = text->enc_in_buf;
1749 } else {
1750 /* avoid the data copy */
1751 bufinfo.data = invec[0].iov_base;
1752 bufinfo.curlen = invec[0].iov_len;
1753 inblob = &bufinfo;
1754 }
1755
1756 /* make sure the output buffer is big enough for this blob */
1757 ret = _plug_buf_alloc(text->utils, &(text->encode_buf),
1758 &(text->encode_buf_len),
1759 (4 + /* for length */
1760 inblob->curlen + /* for content */
1761 10 + /* for MAC */
1762 8 + /* maximum pad */
1763 6 + /* for padding */
1764 1)); /* trailing null */
1765 if(ret != SASL_OK) return ret;
1766
1767 /* skip by the length for now */
1768 out = (text->encode_buf)+4;
1769
1770 /* construct (seqnum, msg) */
1771 /* We can just use the output buffer because it's big enough */
1772 tmpnum = htonl(text->seqnum);
1773 memcpy(text->encode_buf, &tmpnum, 4);
1774 memcpy(text->encode_buf + 4, inblob->data, inblob->curlen);
1775
1776 /* HMAC(ki, (seqnum, msg) ) */
1777 text->utils->hmac_md5((const unsigned char *) text->encode_buf,
1778 inblob->curlen + 4,
1779 text->Ki_send, HASHLEN, digest);
1780
1781 /* calculate the encrypted part */
1782 text->cipher_enc(text, inblob->data, inblob->curlen,
1783 digest, out, outputlen);
1784 out+=(*outputlen);
1785
1786 /* copy in version */
1787 tmpshort = htons(version);
1788 memcpy(out, &tmpshort, 2); /* 2 bytes = version */
1789
1790 out+=2;
1791 (*outputlen)+=2; /* for version */
1792
1793 /* put in seqnum */
1794 tmpnum = htonl(text->seqnum);
1795 memcpy(out, &tmpnum, 4); /* 4 bytes = seq # */
1796
1797 (*outputlen)+=4; /* for seqnum */
1798
1799 /* put the 1st 4 bytes in */
1800 tmp=htonl(*outputlen);
1801 memcpy(text->encode_buf, &tmp, 4);
1802
1803 (*outputlen)+=4;
1804
1805 *output = text->encode_buf;
1806 text->seqnum++;
1807
1808 return SASL_OK;
1809 }
1810
1811 static int
1812 digestmd5_privacy_decode_once(void *context,
1813 const char **input,
1814 unsigned *inputlen,
1815 char **output,
1816 unsigned *outputlen)
1817 {
1818 context_t *text = (context_t *) context;
1819 unsigned int tocopy;
1820 unsigned diff;
1821 int result;
1822 unsigned char digest[16];
1823 int tmpnum;
1824 int lup;
1825
1826 if (text->needsize>0) /* 4 bytes for how long message is */
1827 {
1828 /* if less than 4 bytes just copy those we have into text->size */
1829 if (*inputlen<4)
1830 tocopy=*inputlen;
1831 else
1832 tocopy=4;
1833
1834 if (tocopy>text->needsize)
1835 tocopy=text->needsize;
1836
1837 memcpy(text->sizebuf+4-text->needsize, *input, tocopy);
1838 text->needsize-=tocopy;
1839
1840 *input+=tocopy;
1841 *inputlen-=tocopy;
1842
1843 if (text->needsize==0) /* got all of size */
1844 {
1845 memcpy(&(text->size), text->sizebuf, 4);
1846 text->cursize=0;
1847 text->size=ntohl(text->size);
1848
1849 if (text->size > text->in_maxbuf) {
1850 return SASL_FAIL; /* too big probably error */
1851 }
1852
1853 if(!text->buffer)
1854 text->buffer=text->utils->malloc(text->size+5);
1855 else
1856 text->buffer=text->utils->realloc(text->buffer,
1857 text->size+5);
1858 if (text->buffer == NULL) return SASL_NOMEM;
1859 }
1860
1861 *outputlen=0;
1862 *output=NULL;
1863 if (*inputlen==0) /* have to wait until next time for data */
1864 return SASL_OK;
1865
1866 if (text->size==0) /* should never happen */
1867 return SASL_FAIL;
1868 }
1869
1870 diff=text->size - text->cursize; /* bytes need for full message */
1871
1872 if (! text->buffer)
1873 return SASL_FAIL;
1874
1875 if (*inputlen < diff) /* not enough for a decode */
1876 {
1877 memcpy(text->buffer+text->cursize, *input, *inputlen);
1878 text->cursize+=*inputlen;
1879 *inputlen=0;
1880 *outputlen=0;
1881 *output=NULL;
1882 return SASL_OK;
1883 } else {
1884 memcpy(text->buffer+text->cursize, *input, diff);
1885 *input+=diff;
1886 *inputlen-=diff;
1887 }
1888
1889 {
1890 unsigned short ver;
1891 unsigned int seqnum;
1892 unsigned char checkdigest[16];
1893
1894 result = _plug_buf_alloc(text->utils, &text->decode_once_buf,
1895 &text->decode_once_buf_len,
1896 text->size-6);
1897 if (result != SASL_OK)
1898 return result;
1899
1900 *output = text->decode_once_buf;
1901 *outputlen = *inputlen;
1902
1903 result=text->cipher_dec(text,text->buffer,text->size-6,digest,
1904 *output, outputlen);
1905
1906 if (result!=SASL_OK)
1907 return result;
1908
1909 {
1910 int i;
1911 for(i=10; i; i--) {
1912 memcpy(&ver, text->buffer+text->size-i,2);
1913 ver=ntohs(ver);
1914 }
1915 }
1916
1917 /* check the version number */
1918 memcpy(&ver, text->buffer+text->size-6, 2);
1919 ver=ntohs(ver);
1920 if (ver != version)
1921 {
1922 #ifdef _INTEGRATED_SOLARIS_
1923 text->utils->seterror(text->utils->conn, 0,
1924 gettext("Wrong Version"));
1925 #else
1926 text->utils->seterror(text->utils->conn, 0, "Wrong Version");
1927 #endif /* _INTEGRATED_SOLARIS_ */
1928 return SASL_FAIL;
1929 }
1930
1931 /* check the CMAC */
1932
1933 /* construct (seqnum, msg) */
1934 result = _plug_buf_alloc(text->utils, &text->decode_tmp_buf,
1935 &text->decode_tmp_buf_len, *outputlen + 4);
1936 if(result != SASL_OK) return result;
1937
1938 tmpnum = htonl(text->rec_seqnum);
1939 memcpy(text->decode_tmp_buf, &tmpnum, 4);
1940 memcpy(text->decode_tmp_buf + 4, *output, *outputlen);
1941
1942 /* HMAC(ki, (seqnum, msg) ) */
1943 text->utils->hmac_md5((const unsigned char *) text->decode_tmp_buf,
1944 (*outputlen) + 4,
1945 text->Ki_receive, HASHLEN, checkdigest);
1946
1947 /* now check it */
1948 for (lup=0;lup<10;lup++)
1949 if (checkdigest[lup]!=digest[lup])
1950 {
1951 #ifdef _SUN_SDK_
1952 text->utils->log(text->utils->conn, SASL_LOG_ERR,
1953 "CMAC doesn't match at byte %d!", lup);
1954 return SASL_BADMAC;
1955 #else
1956 text->utils->seterror(text->utils->conn, 0,
1957 "CMAC doesn't match at byte %d!", lup);
1958 return SASL_FAIL;
1959 #endif /* _SUN_SDK_ */
1960 }
1961
1962 /* check the sequence number */
1963 memcpy(&seqnum, text->buffer+text->size-4,4);
1964 seqnum=ntohl(seqnum);
1965
1966 if (seqnum!=text->rec_seqnum)
1967 {
1968 #ifdef _SUN_SDK_
1969 text->utils->log(text->utils->conn, SASL_LOG_ERR,
1970 "Incorrect Sequence Number");
1971 #else
1972 text->utils->seterror(text->utils->conn, 0,
1973 "Incorrect Sequence Number");
1974 #endif /* _SUN_SDK_ */
1975 return SASL_FAIL;
1976 }
1977
1978 text->rec_seqnum++; /* now increment it */
1979 }
1980
1981 text->needsize=4;
1982
1983 return SASL_OK;
1984 }
1985
1986 static int digestmd5_privacy_decode(void *context,
1987 const char *input, unsigned inputlen,
1988 const char **output, unsigned *outputlen)
1989 {
1990 context_t *text = (context_t *) context;
1991 int ret;
1992
1993 ret = _plug_decode(text->utils, context, input, inputlen,
1994 &text->decode_buf, &text->decode_buf_len, outputlen,
1995 digestmd5_privacy_decode_once);
1996
1997 *output = text->decode_buf;
1998
1999 return ret;
2000 }
2001
2002 static int
2003 digestmd5_integrity_encode(void *context,
2004 const struct iovec *invec,
2005 unsigned numiov,
2006 const char **output,
2007 unsigned *outputlen)
2008 {
2009 context_t *text = (context_t *) context;
2010 unsigned char MAC[16];
2011 unsigned int tmpnum;
2012 unsigned short int tmpshort;
2013 struct buffer_info *inblob, bufinfo;
2014 int ret;
2015
2016 if(!context || !invec || !numiov || !output || !outputlen) {
2017 PARAMERROR( text->utils );
2018 return SASL_BADPARAM;
2019 }
2020
2021 if (numiov > 1) {
2022 ret = _plug_iovec_to_buf(text->utils, invec, numiov,
2023 &text->enc_in_buf);
2024 if (ret != SASL_OK) return ret;
2025 inblob = text->enc_in_buf;
2026 } else {
2027 /* avoid the data copy */
2028 bufinfo.data = invec[0].iov_base;
2029 bufinfo.curlen = invec[0].iov_len;
2030 inblob = &bufinfo;
2031 }
2032
2033 /* construct output */
2034 *outputlen = 4 + inblob->curlen + 16;
2035
2036 ret = _plug_buf_alloc(text->utils, &(text->encode_buf),
2037 &(text->encode_buf_len), *outputlen);
2038 if(ret != SASL_OK) return ret;
2039
2040 /* construct (seqnum, msg) */
2041 /* we can just use the output buffer */
2042 tmpnum = htonl(text->seqnum);
2043 memcpy(text->encode_buf, &tmpnum, 4);
2044 memcpy(text->encode_buf + 4, inblob->data, inblob->curlen);
2045
2046 /* HMAC(ki, (seqnum, msg) ) */
2047 #ifdef _SUN_SDK_
2048 text->utils->hmac_md5((unsigned char *)text->encode_buf,
2049 inblob->curlen + 4,
2050 text->Ki_send, HASHLEN, MAC);
2051 #else
2052 text->utils->hmac_md5(text->encode_buf, inblob->curlen + 4,
2053 text->Ki_send, HASHLEN, MAC);
2054 #endif /* _SUN_SDK_ */
2055
2056 /* create MAC */
2057 tmpshort = htons(version);
2058 memcpy(MAC + 10, &tmpshort, MAC_OFFS); /* 2 bytes = version */
2059
2060 tmpnum = htonl(text->seqnum);
2061 memcpy(MAC + 12, &tmpnum, 4); /* 4 bytes = sequence number */
2062
2063 /* copy into output */
2064 tmpnum = htonl((*outputlen) - 4);
2065
2066 /* length of message in network byte order */
2067 memcpy(text->encode_buf, &tmpnum, 4);
2068 /* the message text */
2069 memcpy(text->encode_buf + 4, inblob->data, inblob->curlen);
2070 /* the MAC */
2071 memcpy(text->encode_buf + 4 + inblob->curlen, MAC, 16);
2072
2073 text->seqnum++; /* add one to sequence number */
2074
2075 *output = text->encode_buf;
2076
2077 return SASL_OK;
2078 }
2079
2080 static int
2081 create_MAC(context_t * text,
2082 char *input,
2083 int inputlen,
2084 int seqnum,
2085 unsigned char MAC[16])
2086 {
2087 unsigned int tmpnum;
2088 unsigned short int tmpshort;
2089 int ret;
2090
2091 if (inputlen < 0)
2092 return SASL_FAIL;
2093
2094 ret = _plug_buf_alloc(text->utils, &(text->MAC_buf),
2095 &(text->MAC_buf_len), inputlen + 4);
2096 if(ret != SASL_OK) return ret;
2097
2098 /* construct (seqnum, msg) */
2099 tmpnum = htonl(seqnum);
2100 memcpy(text->MAC_buf, &tmpnum, 4);
2101 memcpy(text->MAC_buf + 4, input, inputlen);
2102
2103 /* HMAC(ki, (seqnum, msg) ) */
2104 #ifdef _SUN_SDK_
2105 text->utils->hmac_md5((unsigned char *)text->MAC_buf, inputlen + 4,
2106 text->Ki_receive, HASHLEN,
2107 MAC);
2108 #else
2109 text->utils->hmac_md5(text->MAC_buf, inputlen + 4,
2110 text->Ki_receive, HASHLEN,
2111 MAC);
2112 #endif /* _SUN_SDK_ */
2113
2114 /* create MAC */
2115 tmpshort = htons(version);
2116 memcpy(MAC + 10, &tmpshort, 2); /* 2 bytes = version */
2117
2118 tmpnum = htonl(seqnum);
2119 memcpy(MAC + 12, &tmpnum, 4); /* 4 bytes = sequence number */
2120
2121 return SASL_OK;
2122 }
2123
2124 static int
2125 check_integrity(context_t * text,
2126 char *buf, int bufsize,
2127 char **output, unsigned *outputlen)
2128 {
2129 unsigned char MAC[16];
2130 int result;
2131
2132 result = create_MAC(text, buf, bufsize - 16, text->rec_seqnum, MAC);
2133 if (result != SASL_OK)
2134 return result;
2135
2136 /* make sure the MAC is right */
2137 if (strncmp((char *) MAC, buf + bufsize - 16, 16) != 0)
2138 {
2139 #ifdef _SUN_SDK_
2140 text->utils->log(text->utils->conn, SASL_LOG_ERR,
2141 "MAC doesn't match");
2142 return SASL_BADMAC;
2143 #else
2144 text->utils->seterror(text->utils->conn, 0, "MAC doesn't match");
2145 return SASL_FAIL;
2146 #endif /* _SUN_SDK_ */
2147 }
2148
2149 text->rec_seqnum++;
2150
2151 /* ok make output message */
2152 result = _plug_buf_alloc(text->utils, &text->decode_once_buf,
2153 &text->decode_once_buf_len,
2154 bufsize - 15);
2155 if (result != SASL_OK)
2156 return result;
2157
2158 *output = text->decode_once_buf;
2159 memcpy(*output, buf, bufsize - 16);
2160 *outputlen = bufsize - 16;
2161 (*output)[*outputlen] = 0;
2162
2163 return SASL_OK;
2164 }
2165
2166 static int
2167 digestmd5_integrity_decode_once(void *context,
2168 const char **input,
2169 unsigned *inputlen,
2170 char **output,
2171 unsigned *outputlen)
2172 {
2173 context_t *text = (context_t *) context;
2174 unsigned int tocopy;
2175 unsigned diff;
2176 int result;
2177
2178 if (text->needsize > 0) { /* 4 bytes for how long message is */
2179 /*
2180 * if less than 4 bytes just copy those we have into text->size
2181 */
2182 if (*inputlen < 4)
2183 tocopy = *inputlen;
2184 else
2185 tocopy = 4;
2186
2187 if (tocopy > text->needsize)
2188 tocopy = text->needsize;
2189
2190 memcpy(text->sizebuf + 4 - text->needsize, *input, tocopy);
2191 text->needsize -= tocopy;
2192
2193 *input += tocopy;
2194 *inputlen -= tocopy;
2195
2196 if (text->needsize == 0) { /* got all of size */
2197 memcpy(&(text->size), text->sizebuf, 4);
2198 text->cursize = 0;
2199 text->size = ntohl(text->size);
2200
2201 if (text->size > text->in_maxbuf)
2202 return SASL_FAIL; /* too big probably error */
2203
2204 if(!text->buffer)
2205 text->buffer=text->utils->malloc(text->size+5);
2206 else
2207 text->buffer=text->utils->realloc(text->buffer,text->size+5);
2208 if (text->buffer == NULL) return SASL_NOMEM;
2209 }
2210 *outputlen = 0;
2211 *output = NULL;
2212 if (*inputlen == 0) /* have to wait until next time for data */
2213 return SASL_OK;
2214
2215 if (text->size == 0) /* should never happen */
2216 return SASL_FAIL;
2217 }
2218 diff = text->size - text->cursize; /* bytes need for full message */
2219
2220 if(! text->buffer)
2221 return SASL_FAIL;
2222
2223 if (*inputlen < diff) { /* not enough for a decode */
2224 memcpy(text->buffer + text->cursize, *input, *inputlen);
2225 text->cursize += *inputlen;
2226 *inputlen = 0;
2227 *outputlen = 0;
2228 *output = NULL;
2229 return SASL_OK;
2230 } else {
2231 memcpy(text->buffer + text->cursize, *input, diff);
2232 *input += diff;
2233 *inputlen -= diff;
2234 }
2235
2236 result = check_integrity(text, text->buffer, text->size,
2237 output, outputlen);
2238 if (result != SASL_OK)
2239 return result;
2240
2241 /* Reset State */
2242 text->needsize = 4;
2243
2244 return SASL_OK;
2245 }
2246
2247 static int digestmd5_integrity_decode(void *context,
2248 const char *input, unsigned inputlen,
2249 const char **output, unsigned *outputlen)
2250 {
2251 context_t *text = (context_t *) context;
2252 int ret;
2253
2254 ret = _plug_decode(text->utils, context, input, inputlen,
2255 &text->decode_buf, &text->decode_buf_len, outputlen,
2256 digestmd5_integrity_decode_once);
2257
2258 *output = text->decode_buf;
2259
2260 return ret;
2261 }
2262
2263 static void
2264 digestmd5_common_mech_dispose(void *conn_context, const sasl_utils_t *utils)
2265 {
2266 context_t *text = (context_t *) conn_context;
2267
2268 if (!text || !utils) return;
2269
2270 if (text->authid) utils->free(text->authid);
2271 if (text->realm) utils->free(text->realm);
2272 if (text->nonce) utils->free(text->nonce);
2273 if (text->cnonce) utils->free(text->cnonce);
2274
2275 if (text->cipher_free) text->cipher_free(text);
2276
2277 /* free the stuff in the context */
2278 if (text->response_value) utils->free(text->response_value);
2279
2280 if (text->buffer) utils->free(text->buffer);
2281 if (text->encode_buf) utils->free(text->encode_buf);
2282 if (text->decode_buf) utils->free(text->decode_buf);
2283 if (text->decode_once_buf) utils->free(text->decode_once_buf);
2284 if (text->decode_tmp_buf) utils->free(text->decode_tmp_buf);
2285 if (text->out_buf) utils->free(text->out_buf);
2286 if (text->MAC_buf) utils->free(text->MAC_buf);
2287
2288 if (text->enc_in_buf) {
2289 if (text->enc_in_buf->data) utils->free(text->enc_in_buf->data);
2290 utils->free(text->enc_in_buf);
2291 }
2292
2293 utils->free(conn_context);
2294 }
2295
2296 static void
2297 clear_reauth_entry(reauth_entry_t *reauth, enum Context_type type,
2298 const sasl_utils_t *utils)
2299 {
2300 if (!reauth) return;
2301
2302 if (reauth->authid) utils->free(reauth->authid);
2303 if (reauth->realm) utils->free(reauth->realm);
2304 if (reauth->nonce) utils->free(reauth->nonce);
2305 if (reauth->cnonce) utils->free(reauth->cnonce);
2306
2307 if (type == CLIENT) {
2308 if (reauth->u.c.serverFQDN) utils->free(reauth->u.c.serverFQDN);
2309 }
2310
2311 memset(reauth, 0, sizeof(reauth_entry_t));
2312 }
2313
2314 static void
2315 digestmd5_common_mech_free(void *glob_context, const sasl_utils_t *utils)
2316 {
2317 reauth_cache_t *reauth_cache = (reauth_cache_t *) glob_context;
2318 size_t n;
2319
2320 if (!reauth_cache) return;
2321
2322 for (n = 0; n < reauth_cache->size; n++)
2323 clear_reauth_entry(&reauth_cache->e[n], reauth_cache->i_am, utils);
2324 if (reauth_cache->e) utils->free(reauth_cache->e);
2325
2326 if (reauth_cache->mutex) utils->mutex_free(reauth_cache->mutex);
2327
2328 utils->free(reauth_cache);
2329 }
2330
2331 /***************************** Server Section *****************************/
2332
2333 typedef struct server_context {
2334 context_t common;
2335
2336 time_t timestamp;
2337 int stale; /* last nonce is stale */
2338 sasl_ssf_t limitssf, requiressf; /* application defined bounds */
2339 } server_context_t;
2340
2341 static void
2342 DigestCalcHA1FromSecret(context_t * text,
2343 const sasl_utils_t * utils,
2344 HASH HA1,
2345 unsigned char *authorization_id,
2346 unsigned char *pszNonce,
2347 unsigned char *pszCNonce,
2348 HASHHEX SessionKey)
2349 {
2350 MD5_CTX Md5Ctx;
2351
2352 /* calculate session key */
2353 utils->MD5Init(&Md5Ctx);
2354 utils->MD5Update(&Md5Ctx, HA1, HASHLEN);
2355 utils->MD5Update(&Md5Ctx, COLON, 1);
2356 utils->MD5Update(&Md5Ctx, pszNonce, strlen((char *) pszNonce));
2357 utils->MD5Update(&Md5Ctx, COLON, 1);
2358 utils->MD5Update(&Md5Ctx, pszCNonce, strlen((char *) pszCNonce));
2359 if (authorization_id != NULL) {
2360 utils->MD5Update(&Md5Ctx, COLON, 1);
2361 utils->MD5Update(&Md5Ctx, authorization_id, strlen((char *) authorization_id));
2362 }
2363 utils->MD5Final(HA1, &Md5Ctx);
2364
2365 CvtHex(HA1, SessionKey);
2366
2367
2368 /* save HA1 because we need it to make the privacy and integrity keys */
2369 memcpy(text->HA1, HA1, sizeof(HASH));
2370 }
2371
2372 static char *create_response(context_t * text,
2373 const sasl_utils_t * utils,
2374 unsigned char *nonce,
2375 unsigned int ncvalue,
2376 unsigned char *cnonce,
2377 char *qop,
2378 char *digesturi,
2379 HASH Secret,
2380 char *authorization_id,
2381 char **response_value)
2382 {
2383 HASHHEX SessionKey;
2384 HASHHEX HEntity = "00000000000000000000000000000000";
2385 HASHHEX Response;
2386 char *result;
2387
2388 if (qop == NULL)
2389 qop = "auth";
2390
2391 DigestCalcHA1FromSecret(text,
2392 utils,
2393 Secret,
2394 (unsigned char *) authorization_id,
2395 nonce,
2396 cnonce,
2397 SessionKey);
2398
2399 DigestCalcResponse(utils,
2400 SessionKey,/* H(A1) */
2401 nonce, /* nonce from server */
2402 ncvalue, /* 8 hex digits */
2403 cnonce, /* client nonce */
2404 (unsigned char *) qop, /* qop-value: "", "auth",
2405 * "auth-int" */
2406 (unsigned char *) digesturi, /* requested URL */
2407 (unsigned char *) "AUTHENTICATE",
2408 HEntity, /* H(entity body) if qop="auth-int" */
2409 Response /* request-digest or response-digest */
2410 );
2411
2412 result = utils->malloc(HASHHEXLEN + 1);
2413 #ifdef _SUN_SDK_
2414 if (result == NULL)
2415 return NULL;
2416 #endif /* _SUN_SDK_ */
2417 /* TODO */
2418 memcpy(result, Response, HASHHEXLEN);
2419 result[HASHHEXLEN] = 0;
2420
2421 /* response_value (used for reauth i think */
2422 if (response_value != NULL) {
2423 DigestCalcResponse(utils,
2424 SessionKey, /* H(A1) */
2425 nonce, /* nonce from server */
2426 ncvalue, /* 8 hex digits */
2427 cnonce, /* client nonce */
2428 (unsigned char *) qop, /* qop-value: "", "auth",
2429 * "auth-int" */
2430 (unsigned char *) digesturi, /* requested URL */
2431 NULL,
2432 HEntity, /* H(entity body) if qop="auth-int" */
2433 Response /* request-digest or response-digest */
2434 );
2435
2436 *response_value = utils->malloc(HASHHEXLEN + 1);
2437 if (*response_value == NULL)
2438 return NULL;
2439 memcpy(*response_value, Response, HASHHEXLEN);
2440 (*response_value)[HASHHEXLEN] = 0;
2441 }
2442 return result;
2443 }
2444
2445 static int
2446 get_server_realm(sasl_server_params_t * params,
2447 char **realm)
2448 {
2449 /* look at user realm first */
2450 if (params->user_realm != NULL) {
2451 if(params->user_realm[0] != '\0') {
2452 *realm = (char *) params->user_realm;
2453 } else {
2454 /* Catch improperly converted apps */
2455 #ifdef _SUN_SDK_
2456 params->utils->log(params->utils->conn, SASL_LOG_ERR,
2457 "user_realm is an empty string!");
2458 #else
2459 params->utils->seterror(params->utils->conn, 0,
2460 "user_realm is an empty string!");
2461 #endif /* _SUN_SDK_ */
2462 return SASL_BADPARAM;
2463 }
2464 } else if (params->serverFQDN != NULL) {
2465 *realm = (char *) params->serverFQDN;
2466 } else {
2467 #ifdef _SUN_SDK_
2468 params->utils->log(params->utils->conn, SASL_LOG_ERR,
2469 "no way to obtain domain");
2470 #else
2471 params->utils->seterror(params->utils->conn, 0,
2472 "no way to obtain domain");
2473 #endif /* _SUN_SDK_ */
2474 return SASL_FAIL;
2475 }
2476
2477 return SASL_OK;
2478 }
2479
2480 /*
2481 * Convert hex string to int
2482 */
2483 static int htoi(unsigned char *hexin, unsigned int *res)
2484 {
2485 int lup, inlen;
2486 inlen = strlen((char *) hexin);
2487
2488 *res = 0;
2489 for (lup = 0; lup < inlen; lup++) {
2490 switch (hexin[lup]) {
2491 case '0':
2492 case '1':
2493 case '2':
2494 case '3':
2495 case '4':
2496 case '5':
2497 case '6':
2498 case '7':
2499 case '8':
2500 case '9':
2501 *res = (*res << 4) + (hexin[lup] - '0');
2502 break;
2503
2504 case 'a':
2505 case 'b':
2506 case 'c':
2507 case 'd':
2508 case 'e':
2509 case 'f':
2510 *res = (*res << 4) + (hexin[lup] - 'a' + 10);
2511 break;
2512
2513 case 'A':
2514 case 'B':
2515 case 'C':
2516 case 'D':
2517 case 'E':
2518 case 'F':
2519 *res = (*res << 4) + (hexin[lup] - 'A' + 10);
2520 break;
2521
2522 default:
2523 return SASL_BADPARAM;
2524 }
2525
2526 }
2527
2528 return SASL_OK;
2529 }
2530
2531 static int digestmd5_server_mech_new(void *glob_context,
2532 sasl_server_params_t * sparams,
2533 const char *challenge __attribute__((unused)),
2534 unsigned challen __attribute__((unused)),
2535 void **conn_context)
2536 {
2537 context_t *text;
2538
2539 /* holds state are in -- allocate server size */
2540 text = sparams->utils->malloc(sizeof(server_context_t));
2541 if (text == NULL)
2542 return SASL_NOMEM;
2543 memset(text, 0, sizeof(server_context_t));
2544
2545 text->state = 1;
2546 text->i_am = SERVER;
2547 text->reauth = glob_context;
2548
2549 *conn_context = text;
2550 return SASL_OK;
2551 }
2552
2553 static int
2554 digestmd5_server_mech_step1(server_context_t *stext,
2555 sasl_server_params_t *sparams,
2556 const char *clientin __attribute__((unused)),
2557 unsigned clientinlen __attribute__((unused)),
2558 const char **serverout,
2559 unsigned *serveroutlen,
2560 sasl_out_params_t * oparams __attribute__((unused)))
2561 {
2562 context_t *text = (context_t *) stext;
2563 int result;
2564 char *realm;
2565 unsigned char *nonce;
2566 char *charset = "utf-8";
2567 char qop[1024], cipheropts[1024];
2568 struct digest_cipher *cipher;
2569 unsigned resplen;
2570 int added_conf = 0;
2571 char maxbufstr[64];
2572
2573 sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
2574 "DIGEST-MD5 server step 1");
2575
2576 /* get realm */
2577 result = get_server_realm(sparams, &realm);
2578 if(result != SASL_OK) return result;
2579
2580 /* what options should we offer the client? */
2581 qop[0] = '\0';
2582 cipheropts[0] = '\0';
2583 if (stext->requiressf == 0) {
2584 if (*qop) strcat(qop, ",");
2585 strcat(qop, "auth");
2586 }
2587 if (stext->requiressf <= 1 && stext->limitssf >= 1) {
2588 if (*qop) strcat(qop, ",");
2589 strcat(qop, "auth-int");
2590 }
2591
2592 #ifdef USE_UEF_SERVER
2593 cipher = available_ciphers1;
2594 #else
2595 cipher = available_ciphers;
2596 #endif
2597 while (cipher->name) {
2598 /* do we allow this particular cipher? */
2599 if (stext->requiressf <= cipher->ssf &&
2600 stext->limitssf >= cipher->ssf) {
2601 if (!added_conf) {
2602 if (*qop) strcat(qop, ",");
2603 strcat(qop, "auth-conf");
2604 added_conf = 1;
2605 }
2606 #ifdef _SUN_SDK_
2607 if(strlen(cipheropts) + strlen(cipher->name) + 1 >=
2608 sizeof (cipheropts)) {
2609 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2610 "internal error: cipheropts too big");
2611 return SASL_FAIL;
2612 }
2613 #endif /* _SUN_SDK_ */
2614 if (*cipheropts) strcat(cipheropts, ",");
2615 strcat(cipheropts, cipher->name);
2616 }
2617 cipher++;
2618 }
2619
2620 if (*qop == '\0') {
2621 /* we didn't allow anything?!? we'll return SASL_TOOWEAK, since
2622 that's close enough */
2623 return SASL_TOOWEAK;
2624 }
2625
2626 /*
2627 * digest-challenge = 1#( realm | nonce | qop-options | stale | maxbuf |
2628 * charset | cipher-opts | auth-param )
2629 */
2630
2631 #ifndef _SUN_SDK_
2632 /* FIXME: get nonce XXX have to clean up after self if fail */
2633 #endif /* !_SUN_SDK_ */
2634 nonce = create_nonce(sparams->utils);
2635 if (nonce == NULL) {
2636 #ifdef _SUN_SDK_
2637 /* Note typo below */
2638 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2639 "internal error: failed creating a nonce");
2640 #else
2641 SETERROR(sparams->utils, "internal erorr: failed creating a nonce");
2642 #endif /* _SUN_SDK_ */
2643 return SASL_FAIL;
2644 }
2645
2646 #ifdef _SUN_SDK_
2647 resplen = strlen((char *)nonce) + strlen("nonce") + 5;
2648 #else
2649 resplen = strlen(nonce) + strlen("nonce") + 5;
2650 #endif /* _SUN_SDK_ */
2651 result = _plug_buf_alloc(sparams->utils, &(text->out_buf),
2652 &(text->out_buf_len), resplen);
2653 #ifdef _SUN_SDK_
2654 if(result != SASL_OK) {
2655 sparams->utils->free(nonce);
2656 return result;
2657 }
2658 #else
2659 if(result != SASL_OK) return result;
2660 #endif /* _SUN_SDK_ */
2661
2662 sprintf(text->out_buf, "nonce=\"%s\"", nonce);
2663
2664 /* add to challenge; if we chose not to specify a realm, we won't
2665 * send one to the client */
2666 if (realm && add_to_challenge(sparams->utils,
2667 &text->out_buf, &text->out_buf_len, &resplen,
2668 "realm", (unsigned char *) realm,
2669 TRUE) != SASL_OK) {
2670 #ifdef _SUN_SDK_
2671 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2672 "internal error: add_to_challenge failed");
2673 sparams->utils->free(nonce);
2674 #else
2675 SETERROR(sparams->utils, "internal error: add_to_challenge failed");
2676 #endif /* _SUN_SDK_ */
2677 return SASL_FAIL;
2678 }
2679 /*
2680 * qop-options A quoted string of one or more tokens indicating the
2681 * "quality of protection" values supported by the server. The value
2682 * "auth" indicates authentication; the value "auth-int" indicates
2683 * authentication with integrity protection; the value "auth-conf"
2684 * indicates authentication with integrity protection and encryption.
2685 */
2686
2687 /* add qop to challenge */
2688 if (add_to_challenge(sparams->utils,
2689 &text->out_buf, &text->out_buf_len, &resplen,
2690 "qop",
2691 (unsigned char *) qop, TRUE) != SASL_OK) {
2692 #ifdef _SUN_SDK_
2693 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2694 "internal error: add_to_challenge 3 failed");
2695 sparams->utils->free(nonce);
2696 #else
2697 SETERROR(sparams->utils, "internal error: add_to_challenge 3 failed");
2698 #endif /* _SUN_SDK_ */
2699 return SASL_FAIL;
2700 }
2701
2702 /*
2703 * Cipheropts - list of ciphers server supports
2704 */
2705 /* add cipher-opts to challenge; only add if there are some */
2706 if (strcmp(cipheropts,"")!=0)
2707 {
2708 if (add_to_challenge(sparams->utils,
2709 &text->out_buf, &text->out_buf_len, &resplen,
2710 "cipher", (unsigned char *) cipheropts,
2711 TRUE) != SASL_OK) {
2712 #ifdef _SUN_SDK_
2713 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2714 "internal error: add_to_challenge 4 failed");
2715 sparams->utils->free(nonce);
2716 #else
2717 SETERROR(sparams->utils,
2718 "internal error: add_to_challenge 4 failed");
2719 #endif /* _SUN_SDK_ */
2720 return SASL_FAIL;
2721 }
2722 }
2723
2724 /* "stale" is true if a reauth failed because of a nonce timeout */
2725 if (stext->stale &&
2726 add_to_challenge(sparams->utils,
2727 &text->out_buf, &text->out_buf_len, &resplen,
2728 #ifdef _SUN_SDK_
2729 "stale", (unsigned char *)"true", FALSE) != SASL_OK) {
2730 sparams->utils->free(nonce);
2731 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2732 "internal error: add_to_challenge failed");
2733 #else
2734 "stale", "true", FALSE) != SASL_OK) {
2735 SETERROR(sparams->utils, "internal error: add_to_challenge failed");
2736 #endif /* _SUN_SDK_ */
2737 return SASL_FAIL;
2738 }
2739
2740 /*
2741 * maxbuf A number indicating the size of the largest buffer the server
2742 * is able to receive when using "auth-int". If this directive is
2743 * missing, the default value is 65536. This directive may appear at most
2744 * once; if multiple instances are present, the client should abort the
2745 * authentication exchange.
2746 */
2747 if(sparams->props.maxbufsize) {
2748 snprintf(maxbufstr, sizeof(maxbufstr), "%d",
2749 sparams->props.maxbufsize);
2750 if (add_to_challenge(sparams->utils,
2751 &text->out_buf, &text->out_buf_len, &resplen,
2752 "maxbuf",
2753 (unsigned char *) maxbufstr, FALSE) != SASL_OK) {
2754 #ifdef _SUN_SDK_
2755 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2756 "internal error: add_to_challenge 5 failed");
2757 #else
2758 SETERROR(sparams->utils,
2759 "internal error: add_to_challenge 5 failed");
2760 #endif /* _SUN_SDK_ */
2761 return SASL_FAIL;
2762 }
2763 }
2764
2765
2766 if (add_to_challenge(sparams->utils,
2767 &text->out_buf, &text->out_buf_len, &resplen,
2768 "charset",
2769 (unsigned char *) charset, FALSE) != SASL_OK) {
2770 #ifdef _SUN_SDK_
2771 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2772 "internal error: add_to_challenge 6 failed");
2773 sparams->utils->free(nonce);
2774 #else
2775 SETERROR(sparams->utils, "internal error: add_to_challenge 6 failed");
2776 #endif /* _SUN_SDK_ */
2777 return SASL_FAIL;
2778 }
2779
2780
2781 /*
2782 * algorithm
2783 * This directive is required for backwards compatibility with HTTP
2784 * Digest., which supports other algorithms. . This directive is
2785 * required and MUST appear exactly once; if not present, or if multiple
2786 * instances are present, the client should abort the authentication
2787 * exchange.
2788 *
2789 * algorithm = "algorithm" "=" "md5-sess"
2790 */
2791
2792 if (add_to_challenge(sparams->utils,
2793 &text->out_buf, &text->out_buf_len, &resplen,
2794 "algorithm",
2795 (unsigned char *) "md5-sess", FALSE)!=SASL_OK) {
2796 #ifdef _SUN_SDK_
2797 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2798 "internal error: add_to_challenge 7 failed");
2799 sparams->utils->free(nonce);
2800 #else
2801 SETERROR(sparams->utils, "internal error: add_to_challenge 7 failed");
2802 #endif /* _SUN_SDK_ */
2803 return SASL_FAIL;
2804 }
2805
2806 /*
2807 * The size of a digest-challenge MUST be less than 2048 bytes!!!
2808 */
2809 if (*serveroutlen > 2048) {
2810 #ifdef _SUN_SDK_
2811 sparams->utils->free(nonce);
2812 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2813 "internal error: challenge larger than 2048 bytes");
2814 #else
2815 SETERROR(sparams->utils,
2816 "internal error: challenge larger than 2048 bytes");
2817 #endif /* _SUN_SDK_ */
2818 return SASL_FAIL;
2819 }
2820
2821 text->authid = NULL;
2822 _plug_strdup(sparams->utils, realm, &text->realm, NULL);
2823 text->nonce = nonce;
2824 text->nonce_count = 1;
2825 text->cnonce = NULL;
2826 stext->timestamp = time(0);
2827
2828 *serveroutlen = strlen(text->out_buf);
2829 *serverout = text->out_buf;
2830
2831 text->state = 2;
2832
2833 return SASL_CONTINUE;
2834 }
2835
2836 static int
2837 digestmd5_server_mech_step2(server_context_t *stext,
2838 sasl_server_params_t *sparams,
2839 const char *clientin,
2840 unsigned clientinlen,
2841 const char **serverout,
2842 unsigned *serveroutlen,
2843 sasl_out_params_t * oparams)
2844 {
2845 context_t *text = (context_t *) stext;
2846 /* verify digest */
2847 sasl_secret_t *sec = NULL;
2848 int result;
2849 char *serverresponse = NULL;
2850 char *username = NULL;
2851 char *authorization_id = NULL;
2852 char *realm = NULL;
2853 unsigned char *nonce = NULL, *cnonce = NULL;
2854 unsigned int noncecount = 0;
2855 char *qop = NULL;
2856 char *digesturi = NULL;
2857 char *response = NULL;
2858
2859 /* setting the default value (65536) */
2860 unsigned int client_maxbuf = 65536;
2861 int maxbuf_count = 0; /* How many maxbuf instaces was found */
2862
2863 char *charset = NULL;
2864 char *cipher = NULL;
2865 unsigned int n=0;
2866
2867 HASH A1;
2868
2869 /* password prop_request */
2870 const char *password_request[] = { SASL_AUX_PASSWORD,
2871 "*cmusaslsecretDIGEST-MD5",
2872 NULL };
2873 unsigned len;
2874 struct propval auxprop_values[2];
2875
2876 /* can we mess with clientin? copy it to be safe */
2877 char *in_start = NULL;
2878 char *in = NULL;
2879
2880 sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
2881 "DIGEST-MD5 server step 2");
2882
2883 in = sparams->utils->malloc(clientinlen + 1);
2884 #ifdef _SUN_SDK_
2885 if (!in) return SASL_NOMEM;
2886 #endif /* _SUN_SDK_ */
2887
2888 memcpy(in, clientin, clientinlen);
2889 in[clientinlen] = 0;
2890
2891 in_start = in;
2892
2893
2894 /* parse what we got */
2895 while (in[0] != '\0') {
2896 char *name = NULL, *value = NULL;
2897 get_pair(&in, &name, &value);
2898
2899 if (name == NULL)
2900 break;
2901
2902 /* Extracting parameters */
2903
2904 /*
2905 * digest-response = 1#( username | realm | nonce | cnonce |
2906 * nonce-count | qop | digest-uri | response | maxbuf | charset |
2907 * cipher | auth-param )
2908 */
2909
2910 if (strcasecmp(name, "username") == 0) {
2911 _plug_strdup(sparams->utils, value, &username, NULL);
2912 } else if (strcasecmp(name, "authzid") == 0) {
2913 _plug_strdup(sparams->utils, value, &authorization_id, NULL);
2914 } else if (strcasecmp(name, "cnonce") == 0) {
2915 _plug_strdup(sparams->utils, value, (char **) &cnonce, NULL);
2916 } else if (strcasecmp(name, "nc") == 0) {
2917 if (htoi((unsigned char *) value, &noncecount) != SASL_OK) {
2918 #ifdef _SUN_SDK_
2919 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2920 "error converting hex to int");
2921 #else
2922 SETERROR(sparams->utils,
2923 "error converting hex to int");
2924 #endif /* _SUN_SDK_ */
2925 result = SASL_BADAUTH;
2926 goto FreeAllMem;
2927 }
2928 } else if (strcasecmp(name, "realm") == 0) {
2929 if (realm) {
2930 #ifdef _SUN_SDK_
2931 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2932 "duplicate realm: authentication aborted");
2933 #else
2934 SETERROR(sparams->utils,
2935 "duplicate realm: authentication aborted");
2936 #endif /* _SUN_SDK_ */
2937 result = SASL_FAIL;
2938 goto FreeAllMem;
2939 }
2940 _plug_strdup(sparams->utils, value, &realm, NULL);
2941 } else if (strcasecmp(name, "nonce") == 0) {
2942 _plug_strdup(sparams->utils, value, (char **) &nonce, NULL);
2943 } else if (strcasecmp(name, "qop") == 0) {
2944 _plug_strdup(sparams->utils, value, &qop, NULL);
2945 } else if (strcasecmp(name, "digest-uri") == 0) {
2946 size_t service_len;
2947
2948 /*
2949 * digest-uri-value = serv-type "/" host [ "/" serv-name ]
2950 */
2951
2952 _plug_strdup(sparams->utils, value, &digesturi, NULL);
2953
2954 /* verify digest-uri format */
2955
2956 /* make sure it's the service that we're expecting */
2957 service_len = strlen(sparams->service);
2958 if (strncasecmp(digesturi, sparams->service, service_len) ||
2959 digesturi[service_len] != '/') {
2960 result = SASL_BADAUTH;
2961 #ifdef _SUN_SDK_
2962 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2963 "bad digest-uri: doesn't match service");
2964 #else
2965 SETERROR(sparams->utils,
2966 "bad digest-uri: doesn't match service");
2967 #endif /* _SUN_SDK_ */
2968 goto FreeAllMem;
2969 }
2970
2971 /* xxx we don't verify the hostname component */
2972
2973 } else if (strcasecmp(name, "response") == 0) {
2974 _plug_strdup(sparams->utils, value, &response, NULL);
2975 } else if (strcasecmp(name, "cipher") == 0) {
2976 _plug_strdup(sparams->utils, value, &cipher, NULL);
2977 } else if (strcasecmp(name, "maxbuf") == 0) {
2978 maxbuf_count++;
2979 if (maxbuf_count != 1) {
2980 result = SASL_BADAUTH;
2981 #ifdef _SUN_SDK_
2982 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2983 "duplicate maxbuf: authentication aborted");
2984 #else
2985 SETERROR(sparams->utils,
2986 "duplicate maxbuf: authentication aborted");
2987 #endif /* _SUN_SDK_ */
2988 goto FreeAllMem;
2989 } else if (sscanf(value, "%u", &client_maxbuf) != 1) {
2990 result = SASL_BADAUTH;
2991 #ifdef _SUN_SDK_
2992 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2993 "invalid maxbuf parameter");
2994 #else
2995 SETERROR(sparams->utils, "invalid maxbuf parameter");
2996 #endif /* _SUN_SDK_ */
2997 goto FreeAllMem;
2998 } else {
2999 if (client_maxbuf <= 16) {
3000 result = SASL_BADAUTH;
3001 #ifdef _SUN_SDK_
3002 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3003 "maxbuf parameter too small");
3004 #else
3005 SETERROR(sparams->utils,
3006 "maxbuf parameter too small");
3007 #endif /* _SUN_SDK_ */
3008 goto FreeAllMem;
3009 }
3010 }
3011 } else if (strcasecmp(name, "charset") == 0) {
3012 if (strcasecmp(value, "utf-8") != 0) {
3013 #ifdef _SUN_SDK_
3014 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3015 "client doesn't support UTF-8");
3016 #else
3017 SETERROR(sparams->utils, "client doesn't support UTF-8");
3018 #endif /* _SUN_SDK_ */
3019 result = SASL_FAIL;
3020 goto FreeAllMem;
3021 }
3022 _plug_strdup(sparams->utils, value, &charset, NULL);
3023 } else {
3024 sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
3025 "DIGEST-MD5 unrecognized pair %s/%s: ignoring",
3026 name, value);
3027 }
3028 }
3029
3030 /*
3031 * username = "username" "=" <"> username-value <">
3032 * username-value = qdstr-val cnonce = "cnonce" "=" <">
3033 * cnonce-value <"> cnonce-value = qdstr-val nonce-count = "nc"
3034 * "=" nc-value nc-value = 8LHEX qop = "qop" "="
3035 * qop-value digest-uri = "digest-uri" "=" digest-uri-value
3036 * digest-uri-value = serv-type "/" host [ "/" serv-name ] serv-type
3037 * = 1*ALPHA host = 1*( ALPHA | DIGIT | "-" | "." ) service
3038 * = host response = "response" "=" <"> response-value <">
3039 * response-value = 32LHEX LHEX = "0" | "1" | "2" | "3" | "4" | "5" |
3040 * "6" | "7" | "8" | "9" | "a" | "b" | "c" | "d" | "e" | "f" cipher =
3041 * "cipher" "=" cipher-value
3042 */
3043 /* Verifing that all parameters was defined */
3044 if ((username == NULL) ||
3045 (nonce == NULL) ||
3046 (noncecount == 0) ||
3047 (cnonce == NULL) ||
3048 (digesturi == NULL) ||
3049 (response == NULL)) {
3050 #ifdef _SUN_SDK_
3051 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3052 "required parameters missing");
3053 #else
3054 SETERROR(sparams->utils, "required parameters missing");
3055 #endif /* _SUN_SDK_ */
3056 result = SASL_BADAUTH;
3057 goto FreeAllMem;
3058 }
3059
3060 if (text->state == 1) {
3061 unsigned val = hash(username) % text->reauth->size;
3062
3063 /* reauth attempt, see if we have any info for this user */
3064 if (sparams->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
3065 if (text->reauth->e[val].authid &&
3066 !strcmp(username, text->reauth->e[val].authid)) {
3067
3068 _plug_strdup(sparams->utils, text->reauth->e[val].realm,
3069 &text->realm, NULL);
3070 #ifdef _SUN_SDK_
3071 _plug_strdup(sparams->utils, (char *)text->reauth->e[val].nonce,
3072 (char **) &text->nonce, NULL);
3073 #else
3074 _plug_strdup(sparams->utils, text->reauth->e[val].nonce,
3075 (char **) &text->nonce, NULL);
3076 #endif /* _SUN_SDK_ */
3077 text->nonce_count = ++text->reauth->e[val].nonce_count;
3078 #ifdef _SUN_SDK_
3079 _plug_strdup(sparams->utils, (char *)text->reauth->e[val].cnonce,
3080 (char **) &text->cnonce, NULL);
3081 #else
3082 _plug_strdup(sparams->utils, text->reauth->e[val].cnonce,
3083 (char **) &text->cnonce, NULL);
3084 #endif /* _SUN_SDK_ */
3085 stext->timestamp = text->reauth->e[val].u.s.timestamp;
3086 }
3087 sparams->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
3088 }
3089
3090 if (!text->nonce) {
3091 /* we don't have any reauth info, so bail */
3092 result = SASL_FAIL;
3093 goto FreeAllMem;
3094 }
3095 }
3096
3097 /* Sanity check the parameters */
3098 #ifdef _SUN_SDK_
3099 if ((realm != NULL && text->realm != NULL &&
3100 strcmp(realm, text->realm) != 0) ||
3101 (realm == NULL && text->realm != NULL) ||
3102 (realm != NULL && text->realm == NULL)) {
3103 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3104 "realm changed: authentication aborted");
3105 #else
3106 if (strcmp(realm, text->realm) != 0) {
3107 SETERROR(sparams->utils,
3108 "realm changed: authentication aborted");
3109 #endif /* _SUN_SDK_ */
3110 result = SASL_BADAUTH;
3111 goto FreeAllMem;
3112 }
3113 #ifdef _SUN_SDK_
3114 if (strcmp((char *)nonce, (char *) text->nonce) != 0) {
3115 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3116 "nonce changed: authentication aborted");
3117 #else
3118 if (strcmp(nonce, (char *) text->nonce) != 0) {
3119 SETERROR(sparams->utils,
3120 "nonce changed: authentication aborted");
3121 #endif /* _SUN_SKD_ */
3122 result = SASL_BADAUTH;
3123 goto FreeAllMem;
3124 }
3125 if (noncecount != text->nonce_count) {
3126 #ifdef _SUN_SDK_
3127 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3128 "incorrect nonce-count: authentication aborted");
3129 #else
3130 SETERROR(sparams->utils,
3131 "incorrect nonce-count: authentication aborted");
3132 #endif /* _SUN_SDK_ */
3133 result = SASL_BADAUTH;
3134 goto FreeAllMem;
3135 }
3136 #ifdef _SUN_SDK_
3137 if (text->cnonce && strcmp((char *)cnonce, (char *)text->cnonce) != 0) {
3138 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3139 "cnonce changed: authentication aborted");
3140 #else
3141 if (text->cnonce && strcmp(cnonce, text->cnonce) != 0) {
3142 SETERROR(sparams->utils,
3143 "cnonce changed: authentication aborted");
3144 #endif /* _SUN_SDK_ */
3145 result = SASL_BADAUTH;
3146 goto FreeAllMem;
3147 }
3148
3149 result = sparams->utils->prop_request(sparams->propctx, password_request);
3150 if(result != SASL_OK) {
3151 #ifdef _SUN_SDK_
3152 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3153 "unable to request user password");
3154 #else
3155 SETERROR(sparams->utils, "unable to resquest user password");
3156 #endif /* _SUN_SDK_ */
3157 goto FreeAllMem;
3158 }
3159
3160 /* this will trigger the getting of the aux properties */
3161 /* Note that if we don't have an authorization id, we don't use it... */
3162 result = sparams->canon_user(sparams->utils->conn,
3163 username, 0, SASL_CU_AUTHID, oparams);
3164 if (result != SASL_OK) {
3165 #ifdef _SUN_SDK_
3166 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3167 "unable canonify user and get auxprops");
3168 #else
3169 SETERROR(sparams->utils, "unable canonify user and get auxprops");
3170 #endif /* _SUN_SDK_ */
3171 goto FreeAllMem;
3172 }
3173
3174 if (!authorization_id || !*authorization_id) {
3175 result = sparams->canon_user(sparams->utils->conn,
3176 username, 0, SASL_CU_AUTHZID, oparams);
3177 } else {
3178 result = sparams->canon_user(sparams->utils->conn,
3179 authorization_id, 0, SASL_CU_AUTHZID,
3180 oparams);
3181 }
3182
3183 if (result != SASL_OK) {
3184 #ifdef _SUN_SDK_
3185 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3186 "unable to canonicalize authorization ID");
3187 #else
3188 SETERROR(sparams->utils, "unable authorization ID");
3189 #endif /* _SUN_SDK_ */
3190 goto FreeAllMem;
3191 }
3192
3193 result = sparams->utils->prop_getnames(sparams->propctx, password_request,
3194 auxprop_values);
3195 if (result < 0 ||
3196 ((!auxprop_values[0].name || !auxprop_values[0].values) &&
3197 (!auxprop_values[1].name || !auxprop_values[1].values))) {
3198 /* We didn't find this username */
3199 #ifdef _INTEGRATED_SOLARIS_
3200 sparams->utils->seterror(sparams->utils->conn, 0,
3201 gettext("no secret in database"));
3202 #else
3203 sparams->utils->seterror(sparams->utils->conn, 0,
3204 "no secret in database");
3205 #endif /* _INTEGRATED_SOLARIS_ */
3206 result = SASL_NOUSER;
3207 goto FreeAllMem;
3208 }
3209
3210 if (auxprop_values[0].name && auxprop_values[0].values) {
3211 len = strlen(auxprop_values[0].values[0]);
3212 if (len == 0) {
3213 #ifdef _INTEGRATED_SOLARIS_
3214 sparams->utils->seterror(sparams->utils->conn,0,
3215 gettext("empty secret"));
3216 #else
3217 sparams->utils->seterror(sparams->utils->conn,0,
3218 "empty secret");
3219 #endif /* _INTEGRATED_SOLARIS_ */
3220 result = SASL_FAIL;
3221 goto FreeAllMem;
3222 }
3223
3224 sec = sparams->utils->malloc(sizeof(sasl_secret_t) + len);
3225 if (!sec) {
3226 #ifdef _SUN_SDK_
3227 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3228 "unable to allocate secret");
3229 #else
3230 SETERROR(sparams->utils, "unable to allocate secret");
3231 #endif /* _SUN_SDK_ */
3232 result = SASL_FAIL;
3233 goto FreeAllMem;
3234 }
3235
3236 sec->len = len;
3237 #ifdef _SUN_SDK_
3238 strncpy((char *)sec->data, auxprop_values[0].values[0], len + 1);
3239 #else
3240 strncpy(sec->data, auxprop_values[0].values[0], len + 1);
3241 #endif /* _SUN_SDK_ */
3242
3243 /*
3244 * Verifying response obtained from client
3245 *
3246 * H_URP = H({ username-value,":",realm-value,":",passwd}) sec->data
3247 * contains H_URP
3248 */
3249
3250 /* Calculate the secret from the plaintext password */
3251 {
3252 HASH <