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.
7 /* DIGEST-MD5 SASL plugin
11 * $Id: digestmd5.c,v 1.153 2003/03/30 22:17:06 leg Exp $
14 * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved.
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
20 * 1. Redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer.
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
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
35 * Pittsburgh, PA 15213-3890
36 * (412) 268-4387, fax: (412) 268-7395
37 * tech-transfer@andrew.cmu.edu
39 * 4. Redistributions of any form whatsoever must retain the following
41 * "This product includes software developed by Computing Services
42 * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
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.
59 #include <sys/types.h>
68 # include <openssl/des.h>
69 # else /* system DES library */
77 # include <netinet/in.h>
82 #endif /* _SUN_SDK_ */
87 #include "plugin_common.h"
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 */
95 extern int strcasecmp(const char *s1
, const char *s2
);
96 #endif /* end WIN32 */
99 #include <sasl_md5_plugin_decl.h>
102 /* external definitions */
106 /* gotta define gethostname ourselves on suns */
107 extern int gethostname(char *, int);
109 #endif /* !_SUN_SDK_ */
118 #define DEFAULT_BUFSIZE 0xFFFF
120 /***************************** Common Section *****************************/
123 static const char plugin_id
[] = "$Id: digestmd5.c,v 1.153 2003/03/30 22:17:06 leg Exp $";
124 #endif /* !_SUN_SDK_ */
127 #define NONCE_SIZE (32) /* arbitrary */
130 #define DIGEST_NOLAYER (1)
131 #define DIGEST_INTEGRITY (2)
132 #define DIGEST_PRIVACY (4)
136 typedef unsigned char HASH
[HASHLEN
+ 1];
137 #define HASHHEXLEN 32
138 typedef unsigned char HASHHEX
[HASHHEXLEN
+ 1];
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";
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";
157 /* function definitions for cipher encode/decode */
158 typedef int cipher_function_t(struct context
*,
166 typedef int cipher_init_t(struct context
*, char [16],
169 typedef int cipher_init_t(struct context
*, unsigned char [16],
171 #endif /* _SUN_SDK_ */
173 typedef void cipher_free_t(struct context
*);
175 enum Context_type
{ SERVER
= 0, CLIENT
= 1 };
177 typedef struct cipher_context cipher_context_t
;
179 /* cached auth info used for fast reauth */
180 typedef struct reauth_entry
{
183 unsigned char *nonce
;
184 unsigned int nonce_count
;
185 unsigned char *cnonce
;
190 } s
; /* server stuff */
195 struct digest_cipher
*cipher
;
196 unsigned int server_maxbuf
;
197 } c
; /* client stuff */
201 typedef struct reauth_cache
{
203 enum Context_type i_am
; /* are we the client or server? */
208 reauth_entry_t
*e
; /* fixed-size hash table of entries */
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? */
216 reauth_cache_t
*reauth
;
220 unsigned char *nonce
;
221 unsigned int nonce_count
;
222 unsigned char *cnonce
;
224 char *response_value
;
227 unsigned int rec_seqnum
; /* for checking integrity */
232 HASH HA1
; /* Kcc or Kcs */
234 /* copy of utils from the params structures */
235 const sasl_utils_t
*utils
;
237 /* For general use */
239 unsigned out_buf_len
;
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
;
248 unsigned MAC_buf_len
;
255 unsigned int size
; /* Absolute size of buffer */
256 unsigned int needsize
; /* How much of the size of the buffer is left */
258 /* Server MaxBuf for Client or Client MaxBuf For Server */
260 unsigned int in_maxbuf
;
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
;
271 struct digest_cipher
{
274 int n
; /* bits to make privacy key */
275 int flag
; /* a bitmask to make things easier for us */
277 cipher_function_t
*cipher_enc
;
278 cipher_function_t
*cipher_dec
;
279 cipher_init_t
*cipher_init
;
280 cipher_free_t
*cipher_free
;
284 static const unsigned char *COLON
= (unsigned char *)":";
286 static const unsigned char *COLON
= ":";
287 #endif /* _SUN_SDK_ */
289 /* Hashes a string to produce an unsigned short */
290 static unsigned hash(const char *str
)
295 while (str
&& *str
) {
305 static void CvtHex(HASH Bin
, HASHHEX Hex
)
310 for (i
= 0; i
< HASHLEN
; i
++) {
311 j
= (Bin
[i
] >> 4) & 0xf;
313 Hex
[i
* 2] = (j
+ '0');
315 Hex
[i
* 2] = (j
+ 'a' - 10);
318 Hex
[i
* 2 + 1] = (j
+ '0');
320 Hex
[i
* 2 + 1] = (j
+ 'a' - 10);
322 Hex
[HASHHEXLEN
] = '\0';
326 * calculate request-digest/response-digest as per HTTP Digest spec
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",
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 */
348 /* calculate H(A2) */
349 utils
->MD5Init(&Md5Ctx
);
351 if (pszMethod
!= NULL
) {
352 utils
->MD5Update(&Md5Ctx
, pszMethod
, strlen((char *) pszMethod
));
354 utils
->MD5Update(&Md5Ctx
, (unsigned char *) COLON
, 1);
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
);
363 utils
->MD5Final(HA2
, &Md5Ctx
);
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);
373 sprintf(ncvalue
, "%08x", pszNonceCount
);
375 utils
->MD5Update(&Md5Ctx
, (unsigned char *)ncvalue
, strlen(ncvalue
));
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);
385 utils
->MD5Update(&Md5Ctx
, HA2Hex
, HASHHEXLEN
);
386 utils
->MD5Final(RespHash
, &Md5Ctx
);
387 CvtHex(RespHash
, Response
);
390 static bool UTF8_In_8859_1(const unsigned char *base
, int len
)
392 const unsigned char *scan
, *end
;
395 for (scan
= base
; scan
< end
; ++scan
) {
397 break; /* abort if outside 8859-1 */
398 if (*scan
>= 0xC0 && *scan
<= 0xC3) {
399 if (++scan
== end
|| *scan
< 0x80 || *scan
> 0xBF)
404 /* if scan >= end, then this is a 8859-1 string. */
405 return (scan
>= end
);
409 * if the string is entirely in the 8859-1 subset of UTF-8, then translate to
410 * 8859-1 prior to MD5
412 void MD5_UTF8_8859_1(const sasl_utils_t
* utils
,
415 const unsigned char *base
,
418 const unsigned char *scan
, *end
;
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
);
428 /* convert to 8859-1 prior to applying hash */
430 for (scan
= base
; scan
< end
&& *scan
< 0xC0; ++scan
);
432 utils
->MD5Update(ctx
, base
, scan
- base
);
435 cbuf
= ((scan
[0] & 0x3) << 6) | (scan
[1] & 0x3f);
436 utils
->MD5Update(ctx
, &cbuf
, 1);
442 static void DigestCalcSecret(const sasl_utils_t
* utils
,
443 unsigned char *pszUserName
,
444 unsigned char *pszRealm
,
445 unsigned char *Password
,
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 */
457 utils
->MD5Init(&Md5Ctx
);
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
));
464 utils
->MD5Update(&Md5Ctx
, COLON
, 1);
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
));
471 utils
->MD5Update(&Md5Ctx
, COLON
, 1);
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
);
478 utils
->MD5Final(HA1
, &Md5Ctx
);
481 static unsigned char *create_nonce(const sasl_utils_t
* utils
)
483 unsigned char *base64buf
;
486 char *ret
= (char *) utils
->malloc(NONCE_SIZE
);
490 #if defined _DEV_URANDOM && defined _SUN_SDK_
492 int fd
= open(_DEV_URANDOM
, O_RDONLY
);
496 nread
= read(fd
, ret
, NONCE_SIZE
);
499 if (nread
!= NONCE_SIZE
)
500 utils
->rand(utils
->rpool
, (char *) ret
, NONCE_SIZE
);
503 utils
->rand(utils
->rpool
, (char *) ret
, NONCE_SIZE
);
504 #endif /* _DEV_URANDOM && _SUN_SDK_ */
506 /* base 64 encode it so it has valid chars */
507 base64len
= (NONCE_SIZE
* 4 / 3) + (NONCE_SIZE
% 3 ? 4 : 0);
509 base64buf
= (unsigned char *) utils
->malloc(base64len
+ 1);
510 if (base64buf
== NULL
) {
512 utils
->log(utils
->conn
, SASL_LOG_ERR
,
513 "Unable to allocate final buffer");
515 utils
->seterror(utils
->conn
, 0, "Unable to allocate final buffer");
516 #endif /* _SUN_SDK_ */
521 * Returns SASL_OK on success, SASL_BUFOVER if result won't fit
523 if (utils
->encode64(ret
, NONCE_SIZE
,
524 (char *) base64buf
, base64len
, NULL
) != SASL_OK
) {
533 static int add_to_challenge(const sasl_utils_t
*utils
,
534 char **str
, unsigned *buflen
, unsigned *curlen
,
536 unsigned char *value
,
539 int namesize
= strlen(name
);
540 int valuesize
= strlen((char *) value
);
543 ret
= _plug_buf_alloc(utils
, str
, buflen
,
544 *curlen
+ 1 + namesize
+ 2 + valuesize
+ 2);
545 if(ret
!= SASL_OK
) return ret
;
547 *curlen
= *curlen
+ 1 + namesize
+ 2 + valuesize
+ 2;
554 strcat(*str
, (char *) value
); /* XXX. What about quoting??? */
558 strcat(*str
, (char *) value
);
564 static char *skip_lws (char *s
)
568 /* skipping spaces: */
569 while (s
[0] == ' ' || s
[0] == HT
|| s
[0] == CR
|| s
[0] == LF
) {
570 if (s
[0]=='\0') break;
578 static char *skip_token (char *s
, int caseinsensitive
__attribute__((unused
)))
580 static char *skip_token (char *s
, int caseinsensitive
)
581 #endif /* _SUN_SDK_ */
586 while (((unsigned char *)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]== '}') {
595 /* the above chars are never uppercase */
598 if (caseinsensitive
== 1) {
599 if (!isupper((unsigned char) s
[0]))
604 #endif /* _SUN_SDK_ */
611 /* NULL - error (unbalanced quotes),
612 otherwise pointer to the first character after value */
613 static char *unquote (char *qstr
)
619 if(!qstr
) return NULL
;
621 if (qstr
[0] == '"') {
625 for (endvalue
= qstr
; endvalue
[0] != '\0'; endvalue
++, outptr
++) {
627 outptr
[0] = endvalue
[0];
630 else if (endvalue
[0] == '\\') {
632 outptr
--; /* Will be incremented at the end of the loop */
634 else if (endvalue
[0] == '"') {
638 outptr
[0] = endvalue
[0];
642 if (endvalue
[0] != '"') {
646 while (outptr
<= endvalue
) {
652 else { /* not qouted value (token) */
653 endvalue
= skip_token(qstr
,0);
659 static void get_pair(char **in
, char **name
, char **value
)
667 if (curp
== NULL
) return;
668 if (curp
[0] == '\0') return;
670 /* skipping spaces: */
671 curp
= skip_lws(curp
);
675 curp
= skip_token(curp
,1);
677 /* strip wierd chars */
678 if (curp
[0] != '=' && curp
[0] != '\0') {
682 curp
= skip_lws(curp
);
684 if (curp
[0] != '=') { /* No '=' sign */
692 curp
= skip_lws(curp
);
694 *value
= (curp
[0] == '"') ? curp
+1 : curp
;
696 endpair
= unquote (curp
);
697 if (endpair
== NULL
) { /* Unbalanced quotes */
701 if (endpair
[0] != ',') {
702 if (endpair
[0]!='\0') {
707 endpair
= skip_lws(endpair
);
709 /* syntax check: MUST be '\0' or ',' */
710 if (endpair
[0] == ',') {
712 endpair
++; /* skipping <,> */
713 } else if (endpair
[0] != '\0') {
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 */
728 typedef struct des_context_s des_context_t
;
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
)
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);
744 /******************************
748 *****************************/
750 static int dec_3des(context_t
*text
,
753 unsigned char digest
[16],
757 des_context_t
*c
= (des_context_t
*) text
->cipher_dec_context
;
760 des_ede2_cbc_encrypt((void *) input
,
768 /* now chop off the padding */
769 padding
= output
[inputlen
- 11];
770 if (padding
< 1 || padding
> 8) {
771 /* invalid padding length */
774 /* verify all padding is correct */
775 for (p
= 1; p
<= padding
; p
++) {
776 if (output
[inputlen
- 10 - p
] != padding
) {
781 /* chop off the padding */
782 *outputlen
= inputlen
- padding
- 10;
784 /* copy in the HMAC to digest */
785 memcpy(digest
, output
+ inputlen
- 10, 10);
790 static int enc_3des(context_t
*text
,
793 unsigned char digest
[16],
797 des_context_t
*c
= (des_context_t
*) text
->cipher_enc_context
;
801 /* determine padding length */
802 paddinglen
= 8 - ((inputlen
+ 10) % 8);
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 */
809 len
=inputlen
+paddinglen
+10;
811 des_ede2_cbc_encrypt((void *) output
,
824 static int init_3des(context_t
*text
,
825 unsigned char enckey
[16],
826 unsigned char deckey
[16])
829 unsigned char keybuf
[8];
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
;
835 /* setup enc context */
836 slidebits(keybuf
, enckey
);
837 if (des_key_sched((des_cblock
*) keybuf
, c
->keysched
) < 0)
840 slidebits(keybuf
, enckey
+ 7);
841 if (des_key_sched((des_cblock
*) keybuf
, c
->keysched2
) < 0)
843 memcpy(c
->ivec
, ((char *) enckey
) + 8, 8);
845 text
->cipher_enc_context
= (cipher_context_t
*) c
;
847 /* setup dec context */
849 slidebits(keybuf
, deckey
);
850 if (des_key_sched((des_cblock
*) keybuf
, c
->keysched
) < 0)
853 slidebits(keybuf
, deckey
+ 7);
854 if (des_key_sched((des_cblock
*) keybuf
, c
->keysched2
) < 0)
857 memcpy(c
->ivec
, ((char *) deckey
) + 8, 8);
859 text
->cipher_dec_context
= (cipher_context_t
*) c
;
865 /******************************
869 *****************************/
871 static int dec_des(context_t
*text
,
874 unsigned char digest
[16],
878 des_context_t
*c
= (des_context_t
*) text
->cipher_dec_context
;
881 des_cbc_encrypt((void *) input
,
888 /* Update the ivec (des_cbc_encrypt implementations tend to be broken in
890 memcpy(c
->ivec
, input
+ (inputlen
- 8), 8);
892 /* now chop off the padding */
893 padding
= output
[inputlen
- 11];
894 if (padding
< 1 || padding
> 8) {
895 /* invalid padding length */
898 /* verify all padding is correct */
899 for (p
= 1; p
<= padding
; p
++) {
900 if (output
[inputlen
- 10 - p
] != padding
) {
905 /* chop off the padding */
906 *outputlen
= inputlen
- padding
- 10;
908 /* copy in the HMAC to digest */
909 memcpy(digest
, output
+ inputlen
- 10, 10);
914 static int enc_des(context_t
*text
,
917 unsigned char digest
[16],
921 des_context_t
*c
= (des_context_t
*) text
->cipher_enc_context
;
925 /* determine padding length */
926 paddinglen
= 8 - ((inputlen
+10) % 8);
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 */
933 len
= inputlen
+ paddinglen
+ 10;
935 des_cbc_encrypt((void *) output
,
942 /* Update the ivec (des_cbc_encrypt implementations tend to be broken in
944 memcpy(c
->ivec
, output
+ (len
- 8), 8);
951 static int init_des(context_t
*text
,
952 unsigned char enckey
[16],
953 unsigned char deckey
[16])
956 unsigned char keybuf
[8];
958 /* allocate enc context */
959 c
= (des_context_t
*) text
->utils
->malloc(2 * sizeof(des_context_t
));
960 if (c
== NULL
) return SASL_NOMEM
;
962 /* setup enc context */
963 slidebits(keybuf
, enckey
);
964 des_key_sched((des_cblock
*) keybuf
, c
->keysched
);
966 memcpy(c
->ivec
, ((char *) enckey
) + 8, 8);
968 text
->cipher_enc_context
= (cipher_context_t
*) c
;
970 /* setup dec context */
972 slidebits(keybuf
, deckey
);
973 des_key_sched((des_cblock
*) keybuf
, c
->keysched
);
975 memcpy(c
->ivec
, ((char *) deckey
) + 8, 8);
977 text
->cipher_dec_context
= (cipher_context_t
*) c
;
982 static void free_des(context_t
*text
)
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
);
989 #endif /* WITH_DES */
992 /* quick generic implementation of RC4 */
993 struct rc4_context_s
{
994 unsigned char sbox
[256];
998 typedef struct rc4_context_s rc4_context_t
;
1000 static void rc4_init(rc4_context_t
*text
,
1001 const unsigned char *key
,
1006 /* fill in linearly s0=0 s1=1... */
1011 for (i
= 0; i
< 256; i
++) {
1013 /* j = (j + Si + Ki) mod 256 */
1014 j
= (j
+ text
->sbox
[i
] + key
[i
% keylen
]) % 256;
1016 /* swap Si and Sj */
1017 tmp
= text
->sbox
[i
];
1018 text
->sbox
[i
] = text
->sbox
[j
];
1019 text
->sbox
[j
] = tmp
;
1022 /* counters initialized to 0 */
1027 static void rc4_encrypt(rc4_context_t
*text
,
1037 const char *input_end
= input
+ len
;
1039 while (input
< input_end
) {
1042 j
= (j
+ text
->sbox
[i
]) % 256;
1044 /* swap Si and Sj */
1045 tmp
= text
->sbox
[i
];
1046 text
->sbox
[i
] = text
->sbox
[j
];
1047 text
->sbox
[j
] = tmp
;
1049 t
= (text
->sbox
[i
] + text
->sbox
[j
]) % 256;
1053 /* byte K is Xor'ed with plaintext */
1054 *output
++ = *input
++ ^ K
;
1061 static void rc4_decrypt(rc4_context_t
*text
,
1071 const char *input_end
= input
+ len
;
1073 while (input
< input_end
) {
1076 j
= (j
+ text
->sbox
[i
]) % 256;
1078 /* swap Si and Sj */
1079 tmp
= text
->sbox
[i
];
1080 text
->sbox
[i
] = text
->sbox
[j
];
1081 text
->sbox
[j
] = tmp
;
1083 t
= (text
->sbox
[i
] + text
->sbox
[j
]) % 256;
1087 /* byte K is Xor'ed with plaintext */
1088 *output
++ = *input
++ ^ K
;
1095 static void free_rc4(context_t
*text
)
1097 /* free rc4 context structures */
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
);
1102 text
->cipher_enc_context
= NULL
;
1103 text
->cipher_dec_context
= NULL
;
1104 #endif /* _SUN_SDK_ */
1107 static int init_rc4(context_t
*text
,
1112 unsigned char enckey
[16],
1113 unsigned char deckey
[16])
1114 #endif /* _SUN_SDK_ */
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
;
1121 text
->cipher_dec_context
=
1122 (cipher_context_t
*) text
->utils
->malloc(sizeof(rc4_context_t
));
1124 if (text
->cipher_dec_context
== NULL
) {
1125 text
->utils
->free(text
->cipher_enc_context
);
1126 text
->cipher_enc_context
= NULL
;
1130 if (text
->cipher_dec_context
== NULL
) return SASL_NOMEM
;
1131 #endif /* _SUN_SDK_ */
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);
1142 static int dec_rc4(context_t
*text
,
1145 unsigned char digest
[16],
1147 unsigned *outputlen
)
1149 /* decrypt the text part */
1150 rc4_decrypt((rc4_context_t
*) text
->cipher_dec_context
,
1151 input
, output
, inputlen
-10);
1153 /* decrypt the HMAC part */
1154 rc4_decrypt((rc4_context_t
*) text
->cipher_dec_context
,
1155 input
+(inputlen
-10), (char *) digest
, 10);
1157 /* no padding so we just subtract the HMAC to get the text length */
1158 *outputlen
= inputlen
- 10;
1163 static int enc_rc4(context_t
*text
,
1166 unsigned char digest
[16],
1168 unsigned *outputlen
)
1171 *outputlen
= inputlen
+10;
1173 /* encrypt the text part */
1174 rc4_encrypt((rc4_context_t
*) text
->cipher_enc_context
,
1179 /* encrypt the HMAC part */
1180 rc4_encrypt((rc4_context_t
*) text
->cipher_enc_context
,
1181 (const char *) digest
,
1182 (output
)+inputlen
, 10);
1187 #endif /* WITH_RC4 */
1189 struct digest_cipher available_ciphers
[] =
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
},
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
},
1200 { NULL
, 0, 0, 0, NULL
, NULL
, NULL
, NULL
}
1205 DEFINE_STATIC_MUTEX(uef_init_mutex
);
1206 #define DES_CIPHER_INDEX 3
1207 #define DES3_CIPHER_INDEX 4
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
;
1215 struct uef_context_s
{
1216 CK_SESSION_HANDLE hSession
;
1217 CK_OBJECT_HANDLE hKey
;
1220 typedef struct uef_context_s uef_context_t
;
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.
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.
1231 static void slidebits(unsigned char *keybuf
, unsigned char *inbuf
)
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);
1244 * Create encryption and decryption session handle handles for later use.
1245 * Returns SASL_OK on success - any other return indicates failure.
1247 * free_uef is called to release associated resources by
1248 * digestmd5_common_mech_dispose
1251 static int init_uef(context_t
*text
,
1252 CK_KEY_TYPE keyType
,
1253 CK_MECHANISM_TYPE mech_type
,
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}};
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;
1281 template[3].ulValueLen
= 8;
1283 template[3].pValue
= keybuf
;
1284 mechanism
.pParameter
= enckey
+ 8;
1285 mechanism
.ulParameterLen
= 8;
1287 template[3].pValue
= enckey
;
1289 mechanism
.mechanism
= mech_type
;
1291 /* allocate rc4 context structures */
1292 enc_context
= text
->utils
->malloc(sizeof (uef_context_t
));
1293 if (enc_context
== NULL
)
1296 rv
= C_OpenSession(slot_id
, CKF_SERIAL_SESSION
, NULL_PTR
, NULL_PTR
,
1297 &enc_context
->hSession
);
1299 text
->utils
->free(enc_context
);
1301 text
->utils
->log(text
->utils
->conn
, SASL_LOG_DEBUG
,
1302 "enc C_OpenSession Failed:0x%.8X\n", rv
);
1307 rv
= C_CreateObject(enc_context
->hSession
, template,
1308 sizeof (template)/sizeof (template[0]), &enc_context
->hKey
);
1310 text
->utils
->free(enc_context
);
1311 (void) C_CloseSession(enc_context
->hSession
);
1313 text
->utils
->log(text
->utils
->conn
, SASL_LOG_DEBUG
,
1314 "enc C_CreateObject: rv = 0x%.8X\n", rv
);
1319 text
->cipher_enc_context
= (cipher_context_t
*)enc_context
;
1321 /* Initialize the encryption operation in the session */
1322 rv
= C_EncryptInit(enc_context
->hSession
, &mechanism
, enc_context
->hKey
);
1325 text
->utils
->log(text
->utils
->conn
, SASL_LOG_DEBUG
,
1326 "C_EncryptInit: rv = 0x%.8X\n", rv
);
1331 dec_context
= text
->utils
->malloc(sizeof(uef_context_t
));
1332 if (dec_context
== NULL
)
1335 rv
= C_OpenSession(slot_id
, CKF_SERIAL_SESSION
, NULL_PTR
, NULL_PTR
,
1336 &dec_context
->hSession
);
1339 text
->utils
->log(text
->utils
->conn
, SASL_LOG_DEBUG
,
1340 "dec C_OpenSession Failed:0x%.8X\n", rv
);
1342 text
->utils
->free(dec_context
);
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);
1353 mechanism
.pParameter
= deckey
+ 8;
1355 template[3].pValue
= deckey
;
1358 rv
= C_CreateObject(dec_context
->hSession
, template,
1359 sizeof (template)/sizeof (template[0]), &dec_context
->hKey
);
1362 text
->utils
->log(text
->utils
->conn
, SASL_LOG_DEBUG
,
1363 "dec C_CreateObject: rv = 0x%.8X\n", rv
);
1365 (void) C_CloseSession(dec_context
->hSession
);
1366 text
->utils
->free(dec_context
);
1369 text
->cipher_dec_context
= (cipher_context_t
*)dec_context
;
1371 /* Initialize the decryption operation in the session */
1372 rv
= C_DecryptInit(dec_context
->hSession
, &mechanism
, dec_context
->hKey
);
1375 text
->utils
->log(text
->utils
->conn
, SASL_LOG_DEBUG
,
1376 "C_DecryptInit: rv = 0x%.8X\n", rv
);
1384 static int init_rc4_uef(context_t
*text
,
1388 return init_uef(text
, CKK_RC4
, CKM_RC4
, rc4_slot_id
, enckey
, deckey
);
1391 static int init_des_uef(context_t
*text
,
1395 return init_uef(text
, CKK_DES
, CKM_DES_CBC
, des_slot_id
, enckey
, deckey
);
1398 static int init_3des_uef(context_t
*text
,
1402 return init_uef(text
, CKK_DES3
, CKM_DES3_CBC
, des3_slot_id
, enckey
, deckey
);
1406 free_uef(context_t
*text
)
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
;
1413 unsigned char buf
[1];
1417 if (enc_context
!= NULL
) {
1418 rv
= C_EncryptFinal(enc_context
->hSession
, buf
, &ulLen
);
1421 text
->utils
->log(text
->utils
->conn
, SASL_LOG_DEBUG
,
1422 "C_EncryptFinal failed:0x%.8X\n", rv
);
1425 rv
= C_DestroyObject(enc_context
->hSession
, enc_context
->hKey
);
1428 text
->utils
->log(text
->utils
->conn
, SASL_LOG_DEBUG
,
1429 "C_DestroyObject failed:0x%.8X\n", rv
);
1432 rv
= C_CloseSession(enc_context
->hSession
);
1435 text
->utils
->log(text
->utils
->conn
, SASL_LOG_DEBUG
,
1436 "C_CloseSession failed:0x%.8X\n", rv
);
1439 text
->utils
->free(enc_context
);
1441 if (dec_context
!= NULL
) {
1442 rv
= C_DecryptFinal(dec_context
->hSession
, buf
, &ulLen
);
1445 text
->utils
->log(text
->utils
->conn
, SASL_LOG_DEBUG
,
1446 "C_DecryptFinal failed:0x%.8X\n", rv
);
1449 rv
= C_DestroyObject(dec_context
->hSession
, dec_context
->hKey
);
1452 text
->utils
->log(text
->utils
->conn
, SASL_LOG_DEBUG
,
1453 "C_DestroyObject failed:0x%.8X\n", rv
);
1457 rv
= C_CloseSession(dec_context
->hSession
);
1460 text
->utils
->log(text
->utils
->conn
, SASL_LOG_DEBUG
,
1461 "C_CloseSession failed:0x%.8X\n", rv
);
1464 text
->utils
->free(dec_context
);
1466 text
->cipher_enc_context
= NULL
;
1467 text
->cipher_dec_context
= NULL
;
1471 dec_rc4_uef(context_t
*text
,
1474 unsigned char digest
[16],
1476 unsigned *outputlen
)
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
;
1484 rv
= C_DecryptUpdate(dec_context
->hSession
, (CK_BYTE_PTR
)input
,
1485 inputlen
- MAC_SIZE
, (CK_BYTE_PTR
)output
, &ulDataLen
);
1488 text
->utils
->log(text
->utils
->conn
, SASL_LOG_DEBUG
,
1489 "C_DecryptUpdate failed:0x%.8X\n", rv
);
1493 *outputlen
= (unsigned)ulDataLen
;
1495 rv
= C_DecryptUpdate(dec_context
->hSession
,
1496 (CK_BYTE_PTR
)input
+(inputlen
-MAC_SIZE
), MAC_SIZE
, (CK_BYTE_PTR
)digest
,
1498 if (rv
!= CKR_OK
|| ulDigestLen
!= MAC_SIZE
) {
1500 text
->utils
->log(text
->utils
->conn
, SASL_LOG_DEBUG
,
1501 "C_DecryptUpdate:0x%.8X, digestLen:%d\n",
1511 enc_rc4_uef(context_t
*text
,
1514 unsigned char digest
[16],
1516 unsigned *outputlen
)
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
;
1524 rv
= C_EncryptUpdate(enc_context
->hSession
, (CK_BYTE_PTR
)input
, inputlen
,
1525 (CK_BYTE_PTR
)output
, &ulDataLen
);
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
);
1535 rv
= C_EncryptUpdate(enc_context
->hSession
, (CK_BYTE_PTR
)digest
, MAC_SIZE
,
1536 (CK_BYTE_PTR
)output
+ inputlen
, &ulDigestLen
);
1539 text
->utils
->log(text
->utils
->conn
, SASL_LOG_DEBUG
,
1540 "C_EncryptUpdate failed: 0x%.8X ulDigestLen:%d\n",
1546 *outputlen
= ulDataLen
+ ulDigestLen
;
1552 dec_des_uef(context_t
*text
,
1555 unsigned char digest
[16],
1557 unsigned *outputlen
)
1560 uef_context_t
*dec_context
=
1561 (uef_context_t
*)text
->cipher_dec_context
;
1562 CK_ULONG ulDataLen
= inputlen
;
1565 rv
= C_DecryptUpdate(dec_context
->hSession
, (CK_BYTE_PTR
)input
,
1566 inputlen
, (CK_BYTE_PTR
)output
, &ulDataLen
);
1569 text
->utils
->log(text
->utils
->conn
, SASL_LOG_DEBUG
,
1570 "C_DecryptUpdate failed:0x%.8X\n", rv
);
1574 if (ulDataLen
!= inputlen
) {
1576 text
->utils
->log(text
->utils
->conn
, SASL_LOG_DEBUG
,
1577 "C_DecryptUpdate unexpected data len:%d !=%d\n",
1578 inputlen
, ulDataLen
);
1580 return SASL_BUFOVER
;
1583 /* now chop off the padding */
1584 padding
= output
[inputlen
- 11];
1585 if (padding
< 1 || padding
> 8) {
1586 /* invalid padding length */
1589 /* verify all padding is correct */
1590 for (p
= 1; p
<= padding
; p
++) {
1591 if (output
[inputlen
- MAC_SIZE
- p
] != padding
) {
1596 /* chop off the padding */
1597 *outputlen
= inputlen
- padding
- MAC_SIZE
;
1599 /* copy in the HMAC to digest */
1600 memcpy(digest
, output
+ inputlen
- MAC_SIZE
, MAC_SIZE
);
1606 enc_des_uef(context_t
*text
,
1609 unsigned char digest
[16],
1611 unsigned *outputlen
)
1614 uef_context_t
*enc_context
=
1615 (uef_context_t
*)text
->cipher_enc_context
;
1619 /* determine padding length */
1620 paddinglen
= 8 - ((inputlen
+ MAC_SIZE
) % 8);
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 */
1627 ulDataLen
=inputlen
+paddinglen
+MAC_SIZE
;
1629 rv
= C_EncryptUpdate(enc_context
->hSession
, (CK_BYTE_PTR
)output
, ulDataLen
,
1630 (CK_BYTE_PTR
)output
, &ulDataLen
);
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
);
1640 *outputlen
= (unsigned)ulDataLen
;
1645 struct digest_cipher uef_ciphers
[] =
1647 { "rc4-40", 40, 5, 0x01, &enc_rc4_uef
, &dec_rc4_uef
, &init_rc4_uef
,
1649 { "rc4-56", 56, 7, 0x02, &enc_rc4_uef
, &dec_rc4_uef
, &init_rc4_uef
,
1651 { "rc4", 128, 16, 0x04, &enc_rc4_uef
, &dec_rc4_uef
, &init_rc4_uef
,
1653 { "des", 55, 16, 0x08, &enc_des_uef
, &dec_des_uef
, &init_des_uef
,
1655 { "3des", 112, 16, 0x10, &enc_des_uef
, &dec_des_uef
, &init_3des_uef
,
1657 { NULL
, 0, 0, 0, NULL
, NULL
, NULL
, NULL
}
1660 struct digest_cipher
*available_ciphers1
= uef_ciphers
;
1661 #endif /* USE_UEF */
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])
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
));
1676 utils
->MD5Update(&Md5Ctx
, (const unsigned char *) SEALING_CLIENT_SERVER
,
1677 strlen(SEALING_CLIENT_SERVER
));
1679 utils
->MD5Final((unsigned char *) enckey
, &Md5Ctx
);
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
));
1687 utils
->MD5Update(&Md5Ctx
, (const unsigned char *)SEALING_CLIENT_SERVER
,
1688 strlen(SEALING_CLIENT_SERVER
));
1690 utils
->MD5Final((unsigned char *) deckey
, &Md5Ctx
);
1692 /* create integrity keys */
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
));
1700 utils
->MD5Update(&Md5Ctx
, (const unsigned char *)SIGNING_CLIENT_SERVER
,
1701 strlen(SIGNING_CLIENT_SERVER
));
1703 utils
->MD5Final(text
->Ki_send
, &Md5Ctx
);
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
));
1712 utils
->MD5Update(&Md5Ctx
, (const unsigned char *)SIGNING_CLIENT_SERVER
,
1713 strlen(SIGNING_CLIENT_SERVER
));
1715 utils
->MD5Final(text
->Ki_receive
, &Md5Ctx
);
1720 static const unsigned short version
= 1;
1722 /* len, CIPHER(Kc, {msg, pag, HMAC(ki, {SeqNum, msg})[0..9]}), x0001, SeqNum */
1725 digestmd5_privacy_encode(void *context
,
1726 const struct iovec
*invec
,
1728 const char **output
,
1729 unsigned *outputlen
)
1731 context_t
*text
= (context_t
*) context
;
1733 unsigned int tmpnum
;
1734 unsigned short int tmpshort
;
1737 unsigned char digest
[16];
1738 struct buffer_info
*inblob
, bufinfo
;
1740 if(!context
|| !invec
|| !numiov
|| !output
|| !outputlen
) {
1741 PARAMERROR(text
->utils
);
1742 return SASL_BADPARAM
;
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
;
1750 /* avoid the data copy */
1751 bufinfo
.data
= invec
[0].iov_base
;
1752 bufinfo
.curlen
= invec
[0].iov_len
;
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 */
1762 8 + /* maximum pad */
1763 6 + /* for padding */
1764 1)); /* trailing null */
1765 if(ret
!= SASL_OK
) return ret
;
1767 /* skip by the length for now */
1768 out
= (text
->encode_buf
)+4;
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
);
1776 /* HMAC(ki, (seqnum, msg) ) */
1777 text
->utils
->hmac_md5((const unsigned char *) text
->encode_buf
,
1779 text
->Ki_send
, HASHLEN
, digest
);
1781 /* calculate the encrypted part */
1782 text
->cipher_enc(text
, inblob
->data
, inblob
->curlen
,
1783 digest
, out
, outputlen
);
1786 /* copy in version */
1787 tmpshort
= htons(version
);
1788 memcpy(out
, &tmpshort
, 2); /* 2 bytes = version */
1791 (*outputlen
)+=2; /* for version */
1794 tmpnum
= htonl(text
->seqnum
);
1795 memcpy(out
, &tmpnum
, 4); /* 4 bytes = seq # */
1797 (*outputlen
)+=4; /* for seqnum */
1799 /* put the 1st 4 bytes in */
1800 tmp
=htonl(*outputlen
);
1801 memcpy(text
->encode_buf
, &tmp
, 4);
1805 *output
= text
->encode_buf
;
1812 digestmd5_privacy_decode_once(void *context
,
1816 unsigned *outputlen
)
1818 context_t
*text
= (context_t
*) context
;
1819 unsigned int tocopy
;
1822 unsigned char digest
[16];
1826 if (text
->needsize
>0) /* 4 bytes for how long message is */
1828 /* if less than 4 bytes just copy those we have into text->size */
1834 if (tocopy
>text
->needsize
)
1835 tocopy
=text
->needsize
;
1837 memcpy(text
->sizebuf
+4-text
->needsize
, *input
, tocopy
);
1838 text
->needsize
-=tocopy
;
1843 if (text
->needsize
==0) /* got all of size */
1845 memcpy(&(text
->size
), text
->sizebuf
, 4);
1847 text
->size
=ntohl(text
->size
);
1849 if (text
->size
> text
->in_maxbuf
) {
1850 return SASL_FAIL
; /* too big probably error */
1854 text
->buffer
=text
->utils
->malloc(text
->size
+5);
1856 text
->buffer
=text
->utils
->realloc(text
->buffer
,
1858 if (text
->buffer
== NULL
) return SASL_NOMEM
;
1863 if (*inputlen
==0) /* have to wait until next time for data */
1866 if (text
->size
==0) /* should never happen */
1870 diff
=text
->size
- text
->cursize
; /* bytes need for full message */
1875 if (*inputlen
< diff
) /* not enough for a decode */
1877 memcpy(text
->buffer
+text
->cursize
, *input
, *inputlen
);
1878 text
->cursize
+=*inputlen
;
1884 memcpy(text
->buffer
+text
->cursize
, *input
, diff
);
1891 unsigned int seqnum
;
1892 unsigned char checkdigest
[16];
1894 result
= _plug_buf_alloc(text
->utils
, &text
->decode_once_buf
,
1895 &text
->decode_once_buf_len
,
1897 if (result
!= SASL_OK
)
1900 *output
= text
->decode_once_buf
;
1901 *outputlen
= *inputlen
;
1903 result
=text
->cipher_dec(text
,text
->buffer
,text
->size
-6,digest
,
1904 *output
, outputlen
);
1906 if (result
!=SASL_OK
)
1912 memcpy(&ver
, text
->buffer
+text
->size
-i
,2);
1917 /* check the version number */
1918 memcpy(&ver
, text
->buffer
+text
->size
-6, 2);
1922 #ifdef _INTEGRATED_SOLARIS_
1923 text
->utils
->seterror(text
->utils
->conn
, 0,
1924 gettext("Wrong Version"));
1926 text
->utils
->seterror(text
->utils
->conn
, 0, "Wrong Version");
1927 #endif /* _INTEGRATED_SOLARIS_ */
1931 /* check the CMAC */
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
;
1938 tmpnum
= htonl(text
->rec_seqnum
);
1939 memcpy(text
->decode_tmp_buf
, &tmpnum
, 4);
1940 memcpy(text
->decode_tmp_buf
+ 4, *output
, *outputlen
);
1942 /* HMAC(ki, (seqnum, msg) ) */
1943 text
->utils
->hmac_md5((const unsigned char *) text
->decode_tmp_buf
,
1945 text
->Ki_receive
, HASHLEN
, checkdigest
);
1948 for (lup
=0;lup
<10;lup
++)
1949 if (checkdigest
[lup
]!=digest
[lup
])
1952 text
->utils
->log(text
->utils
->conn
, SASL_LOG_ERR
,
1953 "CMAC doesn't match at byte %d!", lup
);
1956 text
->utils
->seterror(text
->utils
->conn
, 0,
1957 "CMAC doesn't match at byte %d!", lup
);
1959 #endif /* _SUN_SDK_ */
1962 /* check the sequence number */
1963 memcpy(&seqnum
, text
->buffer
+text
->size
-4,4);
1964 seqnum
=ntohl(seqnum
);
1966 if (seqnum
!=text
->rec_seqnum
)
1969 text
->utils
->log(text
->utils
->conn
, SASL_LOG_ERR
,
1970 "Incorrect Sequence Number");
1972 text
->utils
->seterror(text
->utils
->conn
, 0,
1973 "Incorrect Sequence Number");
1974 #endif /* _SUN_SDK_ */
1978 text
->rec_seqnum
++; /* now increment it */
1986 static int digestmd5_privacy_decode(void *context
,
1987 const char *input
, unsigned inputlen
,
1988 const char **output
, unsigned *outputlen
)
1990 context_t
*text
= (context_t
*) context
;
1993 ret
= _plug_decode(text
->utils
, context
, input
, inputlen
,
1994 &text
->decode_buf
, &text
->decode_buf_len
, outputlen
,
1995 digestmd5_privacy_decode_once
);
1997 *output
= text
->decode_buf
;
2003 digestmd5_integrity_encode(void *context
,
2004 const struct iovec
*invec
,
2006 const char **output
,
2007 unsigned *outputlen
)
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
;
2016 if(!context
|| !invec
|| !numiov
|| !output
|| !outputlen
) {
2017 PARAMERROR( text
->utils
);
2018 return SASL_BADPARAM
;
2022 ret
= _plug_iovec_to_buf(text
->utils
, invec
, numiov
,
2024 if (ret
!= SASL_OK
) return ret
;
2025 inblob
= text
->enc_in_buf
;
2027 /* avoid the data copy */
2028 bufinfo
.data
= invec
[0].iov_base
;
2029 bufinfo
.curlen
= invec
[0].iov_len
;
2033 /* construct output */
2034 *outputlen
= 4 + inblob
->curlen
+ 16;
2036 ret
= _plug_buf_alloc(text
->utils
, &(text
->encode_buf
),
2037 &(text
->encode_buf_len
), *outputlen
);
2038 if(ret
!= SASL_OK
) return ret
;
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
);
2046 /* HMAC(ki, (seqnum, msg) ) */
2048 text
->utils
->hmac_md5((unsigned char *)text
->encode_buf
,
2050 text
->Ki_send
, HASHLEN
, MAC
);
2052 text
->utils
->hmac_md5(text
->encode_buf
, inblob
->curlen
+ 4,
2053 text
->Ki_send
, HASHLEN
, MAC
);
2054 #endif /* _SUN_SDK_ */
2057 tmpshort
= htons(version
);
2058 memcpy(MAC
+ 10, &tmpshort
, MAC_OFFS
); /* 2 bytes = version */
2060 tmpnum
= htonl(text
->seqnum
);
2061 memcpy(MAC
+ 12, &tmpnum
, 4); /* 4 bytes = sequence number */
2063 /* copy into output */
2064 tmpnum
= htonl((*outputlen
) - 4);
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
);
2071 memcpy(text
->encode_buf
+ 4 + inblob
->curlen
, MAC
, 16);
2073 text
->seqnum
++; /* add one to sequence number */
2075 *output
= text
->encode_buf
;
2081 create_MAC(context_t
* text
,
2085 unsigned char MAC
[16])
2087 unsigned int tmpnum
;
2088 unsigned short int tmpshort
;
2094 ret
= _plug_buf_alloc(text
->utils
, &(text
->MAC_buf
),
2095 &(text
->MAC_buf_len
), inputlen
+ 4);
2096 if(ret
!= SASL_OK
) return ret
;
2098 /* construct (seqnum, msg) */
2099 tmpnum
= htonl(seqnum
);
2100 memcpy(text
->MAC_buf
, &tmpnum
, 4);
2101 memcpy(text
->MAC_buf
+ 4, input
, inputlen
);
2103 /* HMAC(ki, (seqnum, msg) ) */
2105 text
->utils
->hmac_md5((unsigned char *)text
->MAC_buf
, inputlen
+ 4,
2106 text
->Ki_receive
, HASHLEN
,
2109 text
->utils
->hmac_md5(text
->MAC_buf
, inputlen
+ 4,
2110 text
->Ki_receive
, HASHLEN
,
2112 #endif /* _SUN_SDK_ */
2115 tmpshort
= htons(version
);
2116 memcpy(MAC
+ 10, &tmpshort
, 2); /* 2 bytes = version */
2118 tmpnum
= htonl(seqnum
);
2119 memcpy(MAC
+ 12, &tmpnum
, 4); /* 4 bytes = sequence number */
2125 check_integrity(context_t
* text
,
2126 char *buf
, int bufsize
,
2127 char **output
, unsigned *outputlen
)
2129 unsigned char MAC
[16];
2132 result
= create_MAC(text
, buf
, bufsize
- 16, text
->rec_seqnum
, MAC
);
2133 if (result
!= SASL_OK
)
2136 /* make sure the MAC is right */
2137 if (strncmp((char *) MAC
, buf
+ bufsize
- 16, 16) != 0)
2140 text
->utils
->log(text
->utils
->conn
, SASL_LOG_ERR
,
2141 "MAC doesn't match");
2144 text
->utils
->seterror(text
->utils
->conn
, 0, "MAC doesn't match");
2146 #endif /* _SUN_SDK_ */
2151 /* ok make output message */
2152 result
= _plug_buf_alloc(text
->utils
, &text
->decode_once_buf
,
2153 &text
->decode_once_buf_len
,
2155 if (result
!= SASL_OK
)
2158 *output
= text
->decode_once_buf
;
2159 memcpy(*output
, buf
, bufsize
- 16);
2160 *outputlen
= bufsize
- 16;
2161 (*output
)[*outputlen
] = 0;
2167 digestmd5_integrity_decode_once(void *context
,
2171 unsigned *outputlen
)
2173 context_t
*text
= (context_t
*) context
;
2174 unsigned int tocopy
;
2178 if (text
->needsize
> 0) { /* 4 bytes for how long message is */
2180 * if less than 4 bytes just copy those we have into text->size
2187 if (tocopy
> text
->needsize
)
2188 tocopy
= text
->needsize
;
2190 memcpy(text
->sizebuf
+ 4 - text
->needsize
, *input
, tocopy
);
2191 text
->needsize
-= tocopy
;
2194 *inputlen
-= tocopy
;
2196 if (text
->needsize
== 0) { /* got all of size */
2197 memcpy(&(text
->size
), text
->sizebuf
, 4);
2199 text
->size
= ntohl(text
->size
);
2201 if (text
->size
> text
->in_maxbuf
)
2202 return SASL_FAIL
; /* too big probably error */
2205 text
->buffer
=text
->utils
->malloc(text
->size
+5);
2207 text
->buffer
=text
->utils
->realloc(text
->buffer
,text
->size
+5);
2208 if (text
->buffer
== NULL
) return SASL_NOMEM
;
2212 if (*inputlen
== 0) /* have to wait until next time for data */
2215 if (text
->size
== 0) /* should never happen */
2218 diff
= text
->size
- text
->cursize
; /* bytes need for full message */
2223 if (*inputlen
< diff
) { /* not enough for a decode */
2224 memcpy(text
->buffer
+ text
->cursize
, *input
, *inputlen
);
2225 text
->cursize
+= *inputlen
;
2231 memcpy(text
->buffer
+ text
->cursize
, *input
, diff
);
2236 result
= check_integrity(text
, text
->buffer
, text
->size
,
2238 if (result
!= SASL_OK
)
2247 static int digestmd5_integrity_decode(void *context
,
2248 const char *input
, unsigned inputlen
,
2249 const char **output
, unsigned *outputlen
)
2251 context_t
*text
= (context_t
*) context
;
2254 ret
= _plug_decode(text
->utils
, context
, input
, inputlen
,
2255 &text
->decode_buf
, &text
->decode_buf_len
, outputlen
,
2256 digestmd5_integrity_decode_once
);
2258 *output
= text
->decode_buf
;
2264 digestmd5_common_mech_dispose(void *conn_context
, const sasl_utils_t
*utils
)
2266 context_t
*text
= (context_t
*) conn_context
;
2268 if (!text
|| !utils
) return;
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
);
2275 if (text
->cipher_free
) text
->cipher_free(text
);
2277 /* free the stuff in the context */
2278 if (text
->response_value
) utils
->free(text
->response_value
);
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
);
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
);
2293 utils
->free(conn_context
);
2297 clear_reauth_entry(reauth_entry_t
*reauth
, enum Context_type type
,
2298 const sasl_utils_t
*utils
)
2300 if (!reauth
) return;
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
);
2307 if (type
== CLIENT
) {
2308 if (reauth
->u
.c
.serverFQDN
) utils
->free(reauth
->u
.c
.serverFQDN
);
2311 memset(reauth
, 0, sizeof(reauth_entry_t
));
2315 digestmd5_common_mech_free(void *glob_context
, const sasl_utils_t
*utils
)
2317 reauth_cache_t
*reauth_cache
= (reauth_cache_t
*) glob_context
;
2320 if (!reauth_cache
) return;
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
);
2326 if (reauth_cache
->mutex
) utils
->mutex_free(reauth_cache
->mutex
);
2328 utils
->free(reauth_cache
);
2331 /***************************** Server Section *****************************/
2333 typedef struct server_context
{
2337 int stale
; /* last nonce is stale */
2338 sasl_ssf_t limitssf
, requiressf
; /* application defined bounds */
2342 DigestCalcHA1FromSecret(context_t
* text
,
2343 const sasl_utils_t
* utils
,
2345 unsigned char *authorization_id
,
2346 unsigned char *pszNonce
,
2347 unsigned char *pszCNonce
,
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
));
2363 utils
->MD5Final(HA1
, &Md5Ctx
);
2365 CvtHex(HA1
, SessionKey
);
2368 /* save HA1 because we need it to make the privacy and integrity keys */
2369 memcpy(text
->HA1
, HA1
, sizeof(HASH
));
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
,
2380 char *authorization_id
,
2381 char **response_value
)
2384 HASHHEX HEntity
= "00000000000000000000000000000000";
2391 DigestCalcHA1FromSecret(text
,
2394 (unsigned char *) authorization_id
,
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",
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 */
2412 result
= utils
->malloc(HASHHEXLEN
+ 1);
2416 #endif /* _SUN_SDK_ */
2418 memcpy(result
, Response
, HASHHEXLEN
);
2419 result
[HASHHEXLEN
] = 0;
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",
2430 (unsigned char *) digesturi
, /* requested URL */
2432 HEntity
, /* H(entity body) if qop="auth-int" */
2433 Response
/* request-digest or response-digest */
2436 *response_value
= utils
->malloc(HASHHEXLEN
+ 1);
2437 if (*response_value
== NULL
)
2439 memcpy(*response_value
, Response
, HASHHEXLEN
);
2440 (*response_value
)[HASHHEXLEN
] = 0;
2446 get_server_realm(sasl_server_params_t
* params
,
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
;
2454 /* Catch improperly converted apps */
2456 params
->utils
->log(params
->utils
->conn
, SASL_LOG_ERR
,
2457 "user_realm is an empty string!");
2459 params
->utils
->seterror(params
->utils
->conn
, 0,
2460 "user_realm is an empty string!");
2461 #endif /* _SUN_SDK_ */
2462 return SASL_BADPARAM
;
2464 } else if (params
->serverFQDN
!= NULL
) {
2465 *realm
= (char *) params
->serverFQDN
;
2468 params
->utils
->log(params
->utils
->conn
, SASL_LOG_ERR
,
2469 "no way to obtain domain");
2471 params
->utils
->seterror(params
->utils
->conn
, 0,
2472 "no way to obtain domain");
2473 #endif /* _SUN_SDK_ */
2481 * Convert hex string to int
2483 static int htoi(unsigned char *hexin
, unsigned int *res
)
2486 inlen
= strlen((char *) hexin
);
2489 for (lup
= 0; lup
< inlen
; lup
++) {
2490 switch (hexin
[lup
]) {
2501 *res
= (*res
<< 4) + (hexin
[lup
] - '0');
2510 *res
= (*res
<< 4) + (hexin
[lup
] - 'a' + 10);
2519 *res
= (*res
<< 4) + (hexin
[lup
] - 'A' + 10);
2523 return SASL_BADPARAM
;
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
)
2539 /* holds state are in -- allocate server size */
2540 text
= sparams
->utils
->malloc(sizeof(server_context_t
));
2543 memset(text
, 0, sizeof(server_context_t
));
2546 text
->i_am
= SERVER
;
2547 text
->reauth
= glob_context
;
2549 *conn_context
= text
;
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
)))
2562 context_t
*text
= (context_t
*) stext
;
2565 unsigned char *nonce
;
2566 char *charset
= "utf-8";
2567 char qop
[1024], cipheropts
[1024];
2568 struct digest_cipher
*cipher
;
2573 sparams
->utils
->log(sparams
->utils
->conn
, SASL_LOG_DEBUG
,
2574 "DIGEST-MD5 server step 1");
2577 result
= get_server_realm(sparams
, &realm
);
2578 if(result
!= SASL_OK
) return result
;
2580 /* what options should we offer the client? */
2582 cipheropts
[0] = '\0';
2583 if (stext
->requiressf
== 0) {
2584 if (*qop
) strcat(qop
, ",");
2585 strcat(qop
, "auth");
2587 if (stext
->requiressf
<= 1 && stext
->limitssf
>= 1) {
2588 if (*qop
) strcat(qop
, ",");
2589 strcat(qop
, "auth-int");
2592 #ifdef USE_UEF_SERVER
2593 cipher
= available_ciphers1
;
2595 cipher
= available_ciphers
;
2597 while (cipher
->name
) {
2598 /* do we allow this particular cipher? */
2599 if (stext
->requiressf
<= cipher
->ssf
&&
2600 stext
->limitssf
>= cipher
->ssf
) {
2602 if (*qop
) strcat(qop
, ",");
2603 strcat(qop
, "auth-conf");
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");
2613 #endif /* _SUN_SDK_ */
2614 if (*cipheropts
) strcat(cipheropts
, ",");
2615 strcat(cipheropts
, cipher
->name
);
2621 /* we didn't allow anything?!? we'll return SASL_TOOWEAK, since
2622 that's close enough */
2623 return SASL_TOOWEAK
;
2627 * digest-challenge = 1#( realm | nonce | qop-options | stale | maxbuf |
2628 * charset | cipher-opts | auth-param )
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
) {
2637 /* Note typo below */
2638 sparams
->utils
->log(sparams
->utils
->conn
, SASL_LOG_ERR
,
2639 "internal error: failed creating a nonce");
2641 SETERROR(sparams
->utils
, "internal erorr: failed creating a nonce");
2642 #endif /* _SUN_SDK_ */
2647 resplen
= strlen((char *)nonce
) + strlen("nonce") + 5;
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
);
2654 if(result
!= SASL_OK
) {
2655 sparams
->utils
->free(nonce
);
2659 if(result
!= SASL_OK
) return result
;
2660 #endif /* _SUN_SDK_ */
2662 sprintf(text
->out_buf
, "nonce=\"%s\"", nonce
);
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
,
2671 sparams
->utils
->log(sparams
->utils
->conn
, SASL_LOG_ERR
,
2672 "internal error: add_to_challenge failed");
2673 sparams
->utils
->free(nonce
);
2675 SETERROR(sparams
->utils
, "internal error: add_to_challenge failed");
2676 #endif /* _SUN_SDK_ */
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.
2687 /* add qop to challenge */
2688 if (add_to_challenge(sparams
->utils
,
2689 &text
->out_buf
, &text
->out_buf_len
, &resplen
,
2691 (unsigned char *) qop
, TRUE
) != SASL_OK
) {
2693 sparams
->utils
->log(sparams
->utils
->conn
, SASL_LOG_ERR
,
2694 "internal error: add_to_challenge 3 failed");
2695 sparams
->utils
->free(nonce
);
2697 SETERROR(sparams
->utils
, "internal error: add_to_challenge 3 failed");
2698 #endif /* _SUN_SDK_ */
2703 * Cipheropts - list of ciphers server supports
2705 /* add cipher-opts to challenge; only add if there are some */
2706 if (strcmp(cipheropts
,"")!=0)
2708 if (add_to_challenge(sparams
->utils
,
2709 &text
->out_buf
, &text
->out_buf_len
, &resplen
,
2710 "cipher", (unsigned char *) cipheropts
,
2713 sparams
->utils
->log(sparams
->utils
->conn
, SASL_LOG_ERR
,
2714 "internal error: add_to_challenge 4 failed");
2715 sparams
->utils
->free(nonce
);
2717 SETERROR(sparams
->utils
,
2718 "internal error: add_to_challenge 4 failed");
2719 #endif /* _SUN_SDK_ */
2724 /* "stale" is true if a reauth failed because of a nonce timeout */
2726 add_to_challenge(sparams
->utils
,
2727 &text
->out_buf
, &text
->out_buf_len
, &resplen
,
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");
2734 "stale", "true", FALSE
) != SASL_OK
) {
2735 SETERROR(sparams
->utils
, "internal error: add_to_challenge failed");
2736 #endif /* _SUN_SDK_ */
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.
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
,
2753 (unsigned char *) maxbufstr
, FALSE
) != SASL_OK
) {
2755 sparams
->utils
->log(sparams
->utils
->conn
, SASL_LOG_ERR
,
2756 "internal error: add_to_challenge 5 failed");
2758 SETERROR(sparams
->utils
,
2759 "internal error: add_to_challenge 5 failed");
2760 #endif /* _SUN_SDK_ */
2766 if (add_to_challenge(sparams
->utils
,
2767 &text
->out_buf
, &text
->out_buf_len
, &resplen
,
2769 (unsigned char *) charset
, FALSE
) != SASL_OK
) {
2771 sparams
->utils
->log(sparams
->utils
->conn
, SASL_LOG_ERR
,
2772 "internal error: add_to_challenge 6 failed");
2773 sparams
->utils
->free(nonce
);
2775 SETERROR(sparams
->utils
, "internal error: add_to_challenge 6 failed");
2776 #endif /* _SUN_SDK_ */
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
2789 * algorithm = "algorithm" "=" "md5-sess"
2792 if (add_to_challenge(sparams
->utils
,
2793 &text
->out_buf
, &text
->out_buf_len
, &resplen
,
2795 (unsigned char *) "md5-sess", FALSE
)!=SASL_OK
) {
2797 sparams
->utils
->log(sparams
->utils
->conn
, SASL_LOG_ERR
,
2798 "internal error: add_to_challenge 7 failed");
2799 sparams
->utils
->free(nonce
);
2801 SETERROR(sparams
->utils
, "internal error: add_to_challenge 7 failed");
2802 #endif /* _SUN_SDK_ */
2807 * The size of a digest-challenge MUST be less than 2048 bytes!!!
2809 if (*serveroutlen
> 2048) {
2811 sparams
->utils
->free(nonce
);
2812 sparams
->utils
->log(sparams
->utils
->conn
, SASL_LOG_ERR
,
2813 "internal error: challenge larger than 2048 bytes");
2815 SETERROR(sparams
->utils
,
2816 "internal error: challenge larger than 2048 bytes");
2817 #endif /* _SUN_SDK_ */
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);
2828 *serveroutlen
= strlen(text
->out_buf
);
2829 *serverout
= text
->out_buf
;
2833 return SASL_CONTINUE
;
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
)
2845 context_t
*text
= (context_t
*) stext
;
2847 sasl_secret_t
*sec
= NULL
;
2849 char *serverresponse
= NULL
;
2850 char *username
= NULL
;
2851 char *authorization_id
= NULL
;
2853 unsigned char *nonce
= NULL
, *cnonce
= NULL
;
2854 unsigned int noncecount
= 0;
2856 char *digesturi
= NULL
;
2857 char *response
= NULL
;
2859 /* setting the default value (65536) */
2860 unsigned int client_maxbuf
= 65536;
2861 int maxbuf_count
= 0; /* How many maxbuf instaces was found */
2863 char *charset
= NULL
;
2864 char *cipher
= NULL
;
2869 /* password prop_request */
2870 const char *password_request
[] = { SASL_AUX_PASSWORD
,
2871 "*cmusaslsecretDIGEST-MD5",
2874 struct propval auxprop_values
[2];
2876 /* can we mess with clientin? copy it to be safe */
2877 char *in_start
= NULL
;
2880 sparams
->utils
->log(sparams
->utils
->conn
, SASL_LOG_DEBUG
,
2881 "DIGEST-MD5 server step 2");
2883 in
= sparams
->utils
->malloc(clientinlen
+ 1);
2885 if (!in
) return SASL_NOMEM
;
2886 #endif /* _SUN_SDK_ */
2888 memcpy(in
, clientin
, clientinlen
);
2889 in
[clientinlen
] = 0;
2894 /* parse what we got */
2895 while (in
[0] != '\0') {
2896 char *name
= NULL
, *value
= NULL
;
2897 get_pair(&in
, &name
, &value
);
2902 /* Extracting parameters */
2905 * digest-response = 1#( username | realm | nonce | cnonce |
2906 * nonce-count | qop | digest-uri | response | maxbuf | charset |
2907 * cipher | auth-param )
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
) {
2919 sparams
->utils
->log(sparams
->utils
->conn
, SASL_LOG_ERR
,
2920 "error converting hex to int");
2922 SETERROR(sparams
->utils
,
2923 "error converting hex to int");
2924 #endif /* _SUN_SDK_ */
2925 result
= SASL_BADAUTH
;
2928 } else if (strcasecmp(name
, "realm") == 0) {
2931 sparams
->utils
->log(sparams
->utils
->conn
, SASL_LOG_ERR
,
2932 "duplicate realm: authentication aborted");
2934 SETERROR(sparams
->utils
,
2935 "duplicate realm: authentication aborted");
2936 #endif /* _SUN_SDK_ */
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) {
2949 * digest-uri-value = serv-type "/" host [ "/" serv-name ]
2952 _plug_strdup(sparams
->utils
, value
, &digesturi
, NULL
);
2954 /* verify digest-uri format */
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
;
2962 sparams
->utils
->log(sparams
->utils
->conn
, SASL_LOG_ERR
,
2963 "bad digest-uri: doesn't match service");
2965 SETERROR(sparams
->utils
,
2966 "bad digest-uri: doesn't match service");
2967 #endif /* _SUN_SDK_ */
2971 /* xxx we don't verify the hostname component */
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) {
2979 if (maxbuf_count
!= 1) {
2980 result
= SASL_BADAUTH
;
2982 sparams
->utils
->log(sparams
->utils
->conn
, SASL_LOG_ERR
,
2983 "duplicate maxbuf: authentication aborted");
2985 SETERROR(sparams
->utils
,
2986 "duplicate maxbuf: authentication aborted");
2987 #endif /* _SUN_SDK_ */
2989 } else if (sscanf(value
, "%u", &client_maxbuf
) != 1) {
2990 result
= SASL_BADAUTH
;
2992 sparams
->utils
->log(sparams
->utils
->conn
, SASL_LOG_ERR
,
2993 "invalid maxbuf parameter");
2995 SETERROR(sparams
->utils
, "invalid maxbuf parameter");
2996 #endif /* _SUN_SDK_ */
2999 if (client_maxbuf
<= 16) {
3000 result
= SASL_BADAUTH
;
3002 sparams
->utils
->log(sparams
->utils
->conn
, SASL_LOG_ERR
,
3003 "maxbuf parameter too small");
3005 SETERROR(sparams
->utils
,
3006 "maxbuf parameter too small");
3007 #endif /* _SUN_SDK_ */
3011 } else if (strcasecmp(name
, "charset") == 0) {
3012 if (strcasecmp(value
, "utf-8") != 0) {
3014 sparams
->utils
->log(sparams
->utils
->conn
, SASL_LOG_ERR
,
3015 "client doesn't support UTF-8");
3017 SETERROR(sparams
->utils
, "client doesn't support UTF-8");
3018 #endif /* _SUN_SDK_ */
3022 _plug_strdup(sparams
->utils
, value
, &charset
, NULL
);
3024 sparams
->utils
->log(sparams
->utils
->conn
, SASL_LOG_DEBUG
,
3025 "DIGEST-MD5 unrecognized pair %s/%s: ignoring",
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
3043 /* Verifing that all parameters was defined */
3044 if ((username
== NULL
) ||
3046 (noncecount
== 0) ||
3048 (digesturi
== NULL
) ||
3049 (response
== NULL
)) {
3051 sparams
->utils
->log(sparams
->utils
->conn
, SASL_LOG_ERR
,
3052 "required parameters missing");
3054 SETERROR(sparams
->utils
, "required parameters missing");
3055 #endif /* _SUN_SDK_ */
3056 result
= SASL_BADAUTH
;
3060 if (text
->state
== 1) {
3061 unsigned val
= hash(username
) % text
->reauth
->size
;
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
)) {
3068 _plug_strdup(sparams
->utils
, text
->reauth
->e
[val
].realm
,
3069 &text
->realm
, NULL
);
3071 _plug_strdup(sparams
->utils
, (char *)text
->reauth
->e
[val
].nonce
,
3072 (char **) &text
->nonce
, NULL
);
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
;
3079 _plug_strdup(sparams
->utils
, (char *)text
->reauth
->e
[val
].cnonce
,
3080 (char **) &text
->cnonce
, NULL
);
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
;
3087 sparams
->utils
->mutex_unlock(text
->reauth
->mutex
); /* UNLOCK */
3091 /* we don't have any reauth info, so bail */
3097 /* Sanity check the parameters */
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");
3106 if (strcmp(realm
, text
->realm
) != 0) {
3107 SETERROR(sparams
->utils
,
3108 "realm changed: authentication aborted");
3109 #endif /* _SUN_SDK_ */
3110 result
= SASL_BADAUTH
;
3114 if (strcmp((char *)nonce
, (char *) text
->nonce
) != 0) {
3115 sparams
->utils
->log(sparams
->utils
->conn
, SASL_LOG_ERR
,
3116 "nonce changed: authentication aborted");
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
;
3125 if (noncecount
!= text
->nonce_count
) {
3127 sparams
->utils
->log(sparams
->utils
->conn
, SASL_LOG_ERR
,
3128 "incorrect nonce-count: authentication aborted");
3130 SETERROR(sparams
->utils
,
3131 "incorrect nonce-count: authentication aborted");
3132 #endif /* _SUN_SDK_ */
3133 result
= SASL_BADAUTH
;
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");
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
;
3149 result
= sparams
->utils
->prop_request(sparams
->propctx
, password_request
);
3150 if(result
!= SASL_OK
) {
3152 sparams
->utils
->log(sparams
->utils
->conn
, SASL_LOG_ERR
,
3153 "unable to request user password");
3155 SETERROR(sparams
->utils
, "unable to resquest user password");
3156 #endif /* _SUN_SDK_ */
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
) {
3166 sparams
->utils
->log(sparams
->utils
->conn
, SASL_LOG_ERR
,
3167 "unable canonify user and get auxprops");
3169 SETERROR(sparams
->utils
, "unable canonify user and get auxprops");
3170 #endif /* _SUN_SDK_ */
3174 if (!authorization_id
|| !*authorization_id
) {
3175 result
= sparams
->canon_user(sparams
->utils
->conn
,
3176 username
, 0, SASL_CU_AUTHZID
, oparams
);
3178 result
= sparams
->canon_user(sparams
->utils
->conn
,
3179 authorization_id
, 0, SASL_CU_AUTHZID
,
3183 if (result
!= SASL_OK
) {
3185 sparams
->utils
->log(sparams
->utils
->conn
, SASL_LOG_ERR
,
3186 "unable to canonicalize authorization ID");
3188 SETERROR(sparams
->utils
, "unable authorization ID");
3189 #endif /* _SUN_SDK_ */
3193 result
= sparams
->utils
->prop_getnames(sparams
->propctx
, password_request
,
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"));
3203 sparams
->utils
->seterror(sparams
->utils
->conn
, 0,
3204 "no secret in database");
3205 #endif /* _INTEGRATED_SOLARIS_ */
3206 result
= SASL_NOUSER
;
3210 if (auxprop_values
[0].name
&& auxprop_values
[0].values
) {
3211 len
= strlen(auxprop_values
[0].values
[0]);
3213 #ifdef _INTEGRATED_SOLARIS_
3214 sparams
->utils
->seterror(sparams
->utils
->conn
,0,
3215 gettext("empty secret"));
3217 sparams
->utils
->seterror(sparams
->utils
->conn
,0,
3219 #endif /* _INTEGRATED_SOLARIS_ */
3224 sec
= sparams
->utils
->malloc(sizeof(sasl_secret_t
) + len
);
3227 sparams
->utils
->log(sparams
->utils
->conn
, SASL_LOG_ERR
,
3228 "unable to allocate secret");
3230 SETERROR(sparams
->utils
, "unable to allocate secret");
3231 #endif /* _SUN_SDK_ */
3238 strncpy((char *)sec
->data
, auxprop_values
[0].values
[0], len
+ 1);
3240 strncpy(sec
->data
, auxprop_values
[0].values
[0], len
+ 1);
3241 #endif /* _SUN_SDK_ */
3244 * Verifying response obtained from client
3246 * H_URP = H({ username-value,":",realm-value,":",passwd}) sec->data
3250 /* Calculate the secret from the plaintext password */
3255 DigestCalcSecret(sparams
->utils
, (unsigned char *)username
,
3256 (unsigned char *)text
->realm
, sec
->data
,
3259 DigestCalcSecret(sparams
->utils
, username
,
3260 text
->realm
, sec
->data
, sec
->len
, HA1
);
3261 #endif /* _SUN_SDK_ */
3264 * A1 = { H( { username-value, ":", realm-value, ":", passwd } ),
3265 * ":", nonce-value, ":", cnonce-value }
3268 memcpy(A1
, HA1
, HASHLEN
);
3272 /* We're done with sec now. Let's get rid of it */
3273 _plug_free_secret(sparams
->utils
, &sec
);
3274 } else if (auxprop_values
[1].name
&& auxprop_values
[1].values
) {
3275 memcpy(A1
, auxprop_values
[1].values
[0], HASHLEN
);
3279 sparams
->utils
->log(sparams
->utils
->conn
, SASL_LOG_ERR
,
3280 "Have neither type of secret");
3282 sparams
->utils
->seterror(sparams
->utils
->conn
, 0,
3283 "Have neither type of secret");
3284 #endif /* _SUN_SDK_ */
3290 #endif /* _SUN_SDK_ */
3293 /* defaulting qop to "auth" if not specified */
3295 _plug_strdup(sparams
->utils
, "auth", &qop
, NULL
);
3298 /* check which layer/cipher to use */
3299 if ((!strcasecmp(qop
, "auth-conf")) && (cipher
!= NULL
)) {
3300 /* see what cipher was requested */
3301 struct digest_cipher
*cptr
;
3303 #ifdef USE_UEF_SERVER
3304 cptr
= available_ciphers1
;
3306 cptr
= available_ciphers
;
3308 while (cptr
->name
) {
3309 /* find the cipher requested & make sure it's one we're happy
3311 if (!strcasecmp(cipher
, cptr
->name
) &&
3312 stext
->requiressf
<= cptr
->ssf
&&
3313 stext
->limitssf
>= cptr
->ssf
) {
3321 text
->cipher_enc
= cptr
->cipher_enc
;
3322 text
->cipher_dec
= cptr
->cipher_dec
;
3323 text
->cipher_init
= cptr
->cipher_init
;
3324 text
->cipher_free
= cptr
->cipher_free
;
3325 oparams
->mech_ssf
= cptr
->ssf
;
3328 /* erg? client requested something we didn't advertise! */
3329 sparams
->utils
->log(sparams
->utils
->conn
, SASL_LOG_WARN
,
3330 "protocol violation: client requested invalid cipher");
3332 SETERROR(sparams
->utils
, "client requested invalid cipher");
3333 #endif /* !_SUN_SDK_ */
3334 /* Mark that we attempted security layer negotiation */
3335 oparams
->mech_ssf
= 2;
3340 oparams
->encode
=&digestmd5_privacy_encode
;
3341 oparams
->decode
=&digestmd5_privacy_decode
;
3342 } else if (!strcasecmp(qop
, "auth-int") &&
3343 stext
->requiressf
<= 1 && stext
->limitssf
>= 1) {
3344 oparams
->encode
= &digestmd5_integrity_encode
;
3345 oparams
->decode
= &digestmd5_integrity_decode
;
3346 oparams
->mech_ssf
= 1;
3347 } else if (!strcasecmp(qop
, "auth") && stext
->requiressf
== 0) {
3348 oparams
->encode
= NULL
;
3349 oparams
->decode
= NULL
;
3350 oparams
->mech_ssf
= 0;
3353 sparams
->utils
->log(sparams
->utils
->conn
, SASL_LOG_ERR
,
3354 "protocol violation: client requested invalid qop");
3356 SETERROR(sparams
->utils
,
3357 "protocol violation: client requested invalid qop");
3358 #endif /* _SUN_SDK_ */
3363 serverresponse
= create_response(text
,
3372 &text
->response_value
);
3374 if (serverresponse
== NULL
) {
3376 SETERROR(sparams
->utils
, "internal error: unable to create response");
3377 #endif /* !_SUN_SDK_ */
3378 result
= SASL_NOMEM
;
3382 /* if ok verified */
3383 if (strcmp(serverresponse
, response
) != 0) {
3384 #ifdef _INTEGRATED_SOLARIS_
3385 SETERROR(sparams
->utils
,
3386 gettext("client response doesn't match what we generated"));
3388 SETERROR(sparams
->utils
,
3389 "client response doesn't match what we generated");
3390 #endif /* _INTEGRATED_SOLARIS_ */
3391 result
= SASL_BADAUTH
;
3396 /* see if our nonce expired */
3397 if (text
->reauth
->timeout
&&
3398 time(0) - stext
->timestamp
> text
->reauth
->timeout
) {
3399 #ifdef _INTEGRATED_SOLARIS_
3400 SETERROR(sparams
->utils
, gettext("server nonce expired"));
3402 SETERROR(sparams
->utils
, "server nonce expired");
3403 #endif /* _INTEGRATED_SOLARIS_ */
3405 result
= SASL_BADAUTH
;
3411 * nothing more to do; authenticated set oparams information
3413 oparams
->doneflag
= 1;
3414 oparams
->maxoutbuf
= client_maxbuf
- 4;
3415 if (oparams
->mech_ssf
> 1) {
3417 if (oparams
->maxoutbuf
<= 25) {
3418 result
= SASL_BADPARAM
;
3422 /* MAC block (privacy) */
3423 oparams
->maxoutbuf
-= 25;
3424 } else if(oparams
->mech_ssf
== 1) {
3426 if (oparams
->maxoutbuf
<= 16) {
3427 result
= SASL_BADPARAM
;
3431 /* MAC block (integrity) */
3432 oparams
->maxoutbuf
-= 16;
3435 oparams
->param_version
= 0;
3437 text
->seqnum
= 0; /* for integrity/privacy */
3438 text
->rec_seqnum
= 0; /* for integrity/privacy */
3440 sparams
->props
.maxbufsize
? sparams
->props
.maxbufsize
: DEFAULT_BUFSIZE
;
3441 text
->utils
= sparams
->utils
;
3443 /* used by layers */
3445 text
->buffer
= NULL
;
3447 if (oparams
->mech_ssf
> 0) {
3451 create_layer_keys(text
, sparams
->utils
,text
->HA1
,n
,enckey
,deckey
);
3453 /* initialize cipher if need be */
3455 if (text
->cipher_init
) {
3456 if (text
->cipher_free
)
3457 text
->cipher_free(text
);
3458 if ((result
= text
->cipher_init(text
, enckey
, deckey
)) != SASL_OK
) {
3459 sparams
->utils
->log(sparams
->utils
->conn
, SASL_LOG_ERR
,
3460 "couldn't init cipher");
3465 if (text
->cipher_init
)
3466 if (text
->cipher_init(text
, enckey
, deckey
) != SASL_OK
) {
3467 sparams
->utils
->seterror(sparams
->utils
->conn
, 0,
3468 "couldn't init cipher");
3470 #endif /* _SUN_SDK_ */
3474 * The server receives and validates the "digest-response". The server
3475 * checks that the nonce-count is "00000001". If it supports subsequent
3476 * authentication, it saves the value of the nonce and the nonce-count.
3480 * The "username-value", "realm-value" and "passwd" are encoded according
3481 * to the value of the "charset" directive. If "charset=UTF-8" is
3482 * present, and all the characters of either "username-value" or "passwd"
3483 * are in the ISO 8859-1 character set, then it must be converted to
3484 * UTF-8 before being hashed. A sample implementation of this conversion
3488 /* add to challenge */
3491 strlen(text
->response_value
) + strlen("rspauth") + 3;
3493 result
= _plug_buf_alloc(sparams
->utils
, &(text
->out_buf
),
3494 &(text
->out_buf_len
), resplen
);
3495 if(result
!= SASL_OK
) {
3499 sprintf(text
->out_buf
, "rspauth=%s", text
->response_value
);
3502 if (strlen(text
->out_buf
) > 2048) {
3508 *serveroutlen
= strlen(text
->out_buf
);
3509 *serverout
= text
->out_buf
;
3514 if (text
->reauth
->timeout
&&
3515 sparams
->utils
->mutex_lock(text
->reauth
->mutex
) == SASL_OK
) { /* LOCK */
3516 unsigned val
= hash(username
) % text
->reauth
->size
;
3520 /* successful auth, setup for future reauth */
3521 if (text
->nonce_count
== 1) {
3522 /* successful initial auth, create new entry */
3523 clear_reauth_entry(&text
->reauth
->e
[val
], SERVER
, sparams
->utils
);
3524 text
->reauth
->e
[val
].authid
= username
; username
= NULL
;
3525 text
->reauth
->e
[val
].realm
= text
->realm
; text
->realm
= NULL
;
3526 text
->reauth
->e
[val
].nonce
= text
->nonce
; text
->nonce
= NULL
;
3527 text
->reauth
->e
[val
].cnonce
= cnonce
; cnonce
= NULL
;
3529 if (text
->nonce_count
<= text
->reauth
->e
[val
].nonce_count
) {
3530 /* paranoia. prevent replay attacks */
3531 clear_reauth_entry(&text
->reauth
->e
[val
], SERVER
, sparams
->utils
);
3534 text
->reauth
->e
[val
].nonce_count
= text
->nonce_count
;
3535 text
->reauth
->e
[val
].u
.s
.timestamp
= time(0);
3539 if (text
->nonce_count
> 1) {
3540 /* failed reauth, clear entry */
3541 clear_reauth_entry(&text
->reauth
->e
[val
], SERVER
, sparams
->utils
);
3544 /* failed initial auth, leave existing cache */
3547 sparams
->utils
->mutex_unlock(text
->reauth
->mutex
); /* UNLOCK */
3550 /* free everything */
3551 if (in_start
) sparams
->utils
->free (in_start
);
3553 if (username
!= NULL
)
3554 sparams
->utils
->free (username
);
3556 if (authorization_id
!= NULL
)
3557 sparams
->utils
->free (authorization_id
);
3558 #endif /* _SUN_SDK_ */
3560 sparams
->utils
->free (realm
);
3562 sparams
->utils
->free (nonce
);
3564 sparams
->utils
->free (cnonce
);
3565 if (response
!= NULL
)
3566 sparams
->utils
->free (response
);
3568 sparams
->utils
->free (cipher
);
3569 if (serverresponse
!= NULL
)
3570 sparams
->utils
->free(serverresponse
);
3571 if (charset
!= NULL
)
3572 sparams
->utils
->free (charset
);
3573 if (digesturi
!= NULL
)
3574 sparams
->utils
->free (digesturi
);
3576 sparams
->utils
->free (qop
);
3578 _plug_free_secret(sparams
->utils
, &sec
);
3584 digestmd5_server_mech_step(void *conn_context
,
3585 sasl_server_params_t
*sparams
,
3586 const char *clientin
,
3587 unsigned clientinlen
,
3588 const char **serverout
,
3589 unsigned *serveroutlen
,
3590 sasl_out_params_t
*oparams
)
3592 context_t
*text
= (context_t
*) conn_context
;
3593 server_context_t
*stext
= (server_context_t
*) conn_context
;
3595 if (clientinlen
> 4096) return SASL_BADPROT
;
3600 switch (text
->state
) {
3603 /* setup SSF limits */
3604 if (!sparams
->props
.maxbufsize
) {
3605 stext
->limitssf
= 0;
3606 stext
->requiressf
= 0;
3608 if (sparams
->props
.max_ssf
< sparams
->external_ssf
) {
3609 stext
->limitssf
= 0;
3612 sparams
->props
.max_ssf
- sparams
->external_ssf
;
3614 if (sparams
->props
.min_ssf
< sparams
->external_ssf
) {
3615 stext
->requiressf
= 0;
3618 sparams
->props
.min_ssf
- sparams
->external_ssf
;
3622 if (clientin
&& text
->reauth
->timeout
) {
3623 /* here's where we attempt fast reauth if possible */
3624 if (digestmd5_server_mech_step2(stext
, sparams
,
3625 clientin
, clientinlen
,
3626 serverout
, serveroutlen
,
3627 oparams
) == SASL_OK
) {
3632 sparams
->utils
->log(sparams
->utils
->conn
, SASL_LOG_WARN
,
3633 "DIGEST-MD5 reauth failed");
3635 sparams
->utils
->log(NULL
, SASL_LOG_WARN
,
3636 "DIGEST-MD5 reauth failed\n");
3637 #endif /* _SUN_SDK_ */
3639 /* re-initialize everything for a fresh start */
3640 memset(oparams
, 0, sizeof(sasl_out_params_t
));
3642 /* fall through and issue challenge */
3645 return digestmd5_server_mech_step1(stext
, sparams
,
3646 clientin
, clientinlen
,
3647 serverout
, serveroutlen
, oparams
);
3650 return digestmd5_server_mech_step2(stext
, sparams
,
3651 clientin
, clientinlen
,
3652 serverout
, serveroutlen
, oparams
);
3656 sparams
->utils
->log(sparams
->utils
->conn
, SASL_LOG_ERR
,
3657 "Invalid DIGEST-MD5 server step %d", text
->state
);
3659 sparams
->utils
->log(NULL
, SASL_LOG_ERR
,
3660 "Invalid DIGEST-MD5 server step %d\n", text
->state
);
3661 #endif /* _SUN_SDK_ */
3666 return SASL_FAIL
; /* should never get here */
3667 #endif /* !_SUN_SDK_ */
3671 digestmd5_server_mech_dispose(void *conn_context
, const sasl_utils_t
*utils
)
3673 server_context_t
*stext
= (server_context_t
*) conn_context
;
3675 if (!stext
|| !utils
) return;
3677 digestmd5_common_mech_dispose(conn_context
, utils
);
3680 static sasl_server_plug_t digestmd5_server_plugins
[] =
3683 "DIGEST-MD5", /* mech_name */
3691 SASL_SEC_NOPLAINTEXT
3692 | SASL_SEC_NOANONYMOUS
3693 | SASL_SEC_MUTUAL_AUTH
, /* security_flags */
3694 SASL_FEAT_ALLOWS_PROXY
, /* features */
3695 NULL
, /* glob_context */
3696 &digestmd5_server_mech_new
, /* mech_new */
3697 &digestmd5_server_mech_step
, /* mech_step */
3698 &digestmd5_server_mech_dispose
, /* mech_dispose */
3699 &digestmd5_common_mech_free
, /* mech_free */
3701 NULL
, /* user_query */
3703 NULL
, /* mech avail */
3708 int digestmd5_server_plug_init(sasl_utils_t
*utils
,
3711 sasl_server_plug_t
**pluglist
,
3714 reauth_cache_t
*reauth_cache
;
3715 const char *timeout
= NULL
;
3717 #if defined _SUN_SDK_ && defined USE_UEF
3719 #endif /* _SUN_SDK_ && USE_UEF */
3721 if (maxversion
< SASL_SERVER_PLUG_VERSION
)
3722 return SASL_BADVERS
;
3724 #if defined _SUN_SDK_ && defined USE_UEF
3725 if ((ret
= uef_init(utils
)) != SASL_OK
)
3727 #endif /* _SUN_SDK_ && USE_UEF */
3730 reauth_cache
= utils
->malloc(sizeof(reauth_cache_t
));
3731 if (reauth_cache
== NULL
)
3733 memset(reauth_cache
, 0, sizeof(reauth_cache_t
));
3734 reauth_cache
->i_am
= SERVER
;
3736 /* fetch and canonify the reauth_timeout */
3737 utils
->getopt(utils
->getopt_context
, "DIGEST-MD5", "reauth_timeout",
3740 reauth_cache
->timeout
= (time_t) 60 * strtol(timeout
, NULL
, 10);
3743 reauth_cache
->timeout
= 0;
3744 #endif /* _SUN_SDK_ */
3745 if (reauth_cache
->timeout
< 0)
3746 reauth_cache
->timeout
= 0;
3748 if (reauth_cache
->timeout
) {
3750 reauth_cache
->mutex
= utils
->mutex_alloc();
3751 if (!reauth_cache
->mutex
)
3755 reauth_cache
->size
= 100;
3756 reauth_cache
->e
= utils
->malloc(reauth_cache
->size
*
3757 sizeof(reauth_entry_t
));
3758 if (reauth_cache
->e
== NULL
)
3760 memset(reauth_cache
->e
, 0, reauth_cache
->size
* sizeof(reauth_entry_t
));
3763 digestmd5_server_plugins
[0].glob_context
= reauth_cache
;
3766 #ifdef USE_UEF_CLIENT
3767 digestmd5_server_plugins
[0].max_ssf
= uef_max_ssf
;
3768 #endif /* USE_UEF_CLIENT */
3769 #endif /* _SUN_SDK_ */
3771 #ifdef _INTEGRATED_SOLARIS_
3773 * Let libsasl know that we are a "Sun" plugin so that privacy
3774 * and integrity will be allowed.
3776 REG_PLUG("DIGEST-MD5", digestmd5_server_plugins
);
3777 #endif /* _INTEGRATED_SOLARIS_ */
3779 *out_version
= SASL_SERVER_PLUG_VERSION
;
3780 *pluglist
= digestmd5_server_plugins
;
3786 /***************************** Client Section *****************************/
3788 typedef struct client_context
{
3791 sasl_secret_t
*password
; /* user password */
3792 unsigned int free_password
; /* set if we need to free password */
3795 struct digest_cipher
*cipher
;
3796 unsigned int server_maxbuf
;
3797 #ifdef _INTEGRATED_SOLARIS_
3799 #endif /* _INTEGRATED_SOLARIS_ */
3802 /* calculate H(A1) as per spec */
3804 DigestCalcHA1(context_t
* text
,
3805 const sasl_utils_t
* utils
,
3806 unsigned char *pszUserName
,
3807 unsigned char *pszRealm
,
3808 sasl_secret_t
* pszPassword
,
3809 unsigned char *pszAuthorization_id
,
3810 unsigned char *pszNonce
,
3811 unsigned char *pszCNonce
,
3817 DigestCalcSecret(utils
,
3820 (unsigned char *) pszPassword
->data
,
3824 /* calculate the session key */
3825 utils
->MD5Init(&Md5Ctx
);
3826 utils
->MD5Update(&Md5Ctx
, HA1
, HASHLEN
);
3827 utils
->MD5Update(&Md5Ctx
, COLON
, 1);
3828 utils
->MD5Update(&Md5Ctx
, pszNonce
, strlen((char *) pszNonce
));
3829 utils
->MD5Update(&Md5Ctx
, COLON
, 1);
3830 utils
->MD5Update(&Md5Ctx
, pszCNonce
, strlen((char *) pszCNonce
));
3831 if (pszAuthorization_id
!= NULL
) {
3832 utils
->MD5Update(&Md5Ctx
, COLON
, 1);
3833 utils
->MD5Update(&Md5Ctx
, pszAuthorization_id
,
3834 strlen((char *) pszAuthorization_id
));
3836 utils
->MD5Final(HA1
, &Md5Ctx
);
3838 CvtHex(HA1
, SessionKey
);
3840 /* xxx rc-* use different n */
3842 /* save HA1 because we'll need it for the privacy and integrity keys */
3843 memcpy(text
->HA1
, HA1
, sizeof(HASH
));
3847 static char *calculate_response(context_t
* text
,
3848 const sasl_utils_t
* utils
,
3849 unsigned char *username
,
3850 unsigned char *realm
,
3851 unsigned char *nonce
,
3852 unsigned int ncvalue
,
3853 unsigned char *cnonce
,
3855 unsigned char *digesturi
,
3856 sasl_secret_t
* passwd
,
3857 unsigned char *authorization_id
,
3858 char **response_value
)
3861 HASHHEX HEntity
= "00000000000000000000000000000000";
3865 /* Verifing that all parameters was defined */
3866 if(!username
|| !cnonce
|| !nonce
|| !ncvalue
|| !digesturi
|| !passwd
) {
3867 PARAMERROR( utils
);
3871 if (realm
== NULL
) {
3872 /* a NULL realm is equivalent to the empty string */
3873 realm
= (unsigned char *) "";
3877 /* default to a qop of just authentication */
3891 DigestCalcResponse(utils
,
3892 SessionKey
,/* H(A1) */
3893 nonce
, /* nonce from server */
3894 ncvalue
, /* 8 hex digits */
3895 cnonce
, /* client nonce */
3896 (unsigned char *) qop
, /* qop-value: "", "auth",
3898 digesturi
, /* requested URL */
3899 (unsigned char *) "AUTHENTICATE",
3900 HEntity
, /* H(entity body) if qop="auth-int" */
3901 Response
/* request-digest or response-digest */
3904 result
= utils
->malloc(HASHHEXLEN
+ 1);
3908 #endif /* _SUN_SDK_ */
3909 memcpy(result
, Response
, HASHHEXLEN
);
3910 result
[HASHHEXLEN
] = 0;
3912 if (response_value
!= NULL
) {
3913 DigestCalcResponse(utils
,
3914 SessionKey
, /* H(A1) */
3915 nonce
, /* nonce from server */
3916 ncvalue
, /* 8 hex digits */
3917 cnonce
, /* client nonce */
3918 (unsigned char *) qop
, /* qop-value: "", "auth",
3920 (unsigned char *) digesturi
, /* requested URL */
3922 HEntity
, /* H(entity body) if qop="auth-int" */
3923 Response
/* request-digest or response-digest */
3927 if (*response_value
!= NULL
)
3928 utils
->free(*response_value
);
3929 #endif /* _SUN_SDK_ */
3930 *response_value
= utils
->malloc(HASHHEXLEN
+ 1);
3931 if (*response_value
== NULL
)
3934 memcpy(*response_value
, Response
, HASHHEXLEN
);
3935 (*response_value
)[HASHHEXLEN
] = 0;
3943 make_client_response(context_t
*text
,
3944 sasl_client_params_t
*params
,
3945 sasl_out_params_t
*oparams
)
3947 client_context_t
*ctext
= (client_context_t
*) text
;
3950 unsigned char *digesturi
= NULL
;
3951 bool IsUTF8
= FALSE
;
3954 char *response
= NULL
;
3955 unsigned resplen
= 0;
3958 switch (ctext
->protection
) {
3959 case DIGEST_PRIVACY
:
3961 oparams
->encode
= &digestmd5_privacy_encode
;
3962 oparams
->decode
= &digestmd5_privacy_decode
;
3963 oparams
->mech_ssf
= ctext
->cipher
->ssf
;
3965 nbits
= ctext
->cipher
->n
;
3966 text
->cipher_enc
= ctext
->cipher
->cipher_enc
;
3967 text
->cipher_dec
= ctext
->cipher
->cipher_dec
;
3968 text
->cipher_free
= ctext
->cipher
->cipher_free
;
3969 text
->cipher_init
= ctext
->cipher
->cipher_init
;
3971 case DIGEST_INTEGRITY
:
3973 oparams
->encode
= &digestmd5_integrity_encode
;
3974 oparams
->decode
= &digestmd5_integrity_decode
;
3975 oparams
->mech_ssf
= 1;
3977 case DIGEST_NOLAYER
:
3980 oparams
->encode
= NULL
;
3981 oparams
->decode
= NULL
;
3982 oparams
->mech_ssf
= 0;
3985 digesturi
= params
->utils
->malloc(strlen(params
->service
) + 1 +
3986 strlen(params
->serverFQDN
) + 1 +
3988 if (digesturi
== NULL
) {
3989 result
= SASL_NOMEM
;
3990 goto FreeAllocatedMem
;
3993 /* allocated exactly this. safe */
3994 strcpy((char *) digesturi
, params
->service
);
3995 strcat((char *) digesturi
, "/");
3996 strcat((char *) digesturi
, params
->serverFQDN
);
3998 * strcat (digesturi, "/"); strcat (digesturi, params->serverFQDN);
4003 calculate_response(text
,
4006 (unsigned char *) oparams
->authid
,
4008 (char *) oparams
->authid
,
4009 #endif /* _SUN_SDK_ */
4010 (unsigned char *) text
->realm
,
4017 strcmp(oparams
->user
, oparams
->authid
) ?
4019 (unsigned char *) oparams
->user
: NULL
,
4021 (char *) oparams
->user
: NULL
,
4022 #endif /* _SUN_SDK_ */
4023 &text
->response_value
);
4026 if (response
== NULL
) {
4027 result
= SASL_NOMEM
;
4028 goto FreeAllocatedMem
;
4030 #endif /* _SUN_SDK_ */
4032 resplen
= strlen(oparams
->authid
) + strlen("username") + 5;
4033 result
=_plug_buf_alloc(params
->utils
, &(text
->out_buf
),
4034 &(text
->out_buf_len
),
4036 if (result
!= SASL_OK
) goto FreeAllocatedMem
;
4038 sprintf(text
->out_buf
, "username=\"%s\"", oparams
->authid
);
4040 if (add_to_challenge(params
->utils
,
4041 &text
->out_buf
, &text
->out_buf_len
, &resplen
,
4042 "realm", (unsigned char *) text
->realm
,
4045 goto FreeAllocatedMem
;
4047 if (strcmp(oparams
->user
, oparams
->authid
)) {
4048 if (add_to_challenge(params
->utils
,
4049 &text
->out_buf
, &text
->out_buf_len
, &resplen
,
4051 "authzid", (unsigned char *) oparams
->user
,
4054 "authzid", (char *) oparams
->user
, TRUE
) != SASL_OK
) {
4055 #endif /* _SUN_SDK_ */
4057 goto FreeAllocatedMem
;
4060 if (add_to_challenge(params
->utils
,
4061 &text
->out_buf
, &text
->out_buf_len
, &resplen
,
4062 "nonce", text
->nonce
, TRUE
) != SASL_OK
) {
4064 goto FreeAllocatedMem
;
4066 if (add_to_challenge(params
->utils
,
4067 &text
->out_buf
, &text
->out_buf_len
, &resplen
,
4068 "cnonce", text
->cnonce
, TRUE
) != SASL_OK
) {
4070 goto FreeAllocatedMem
;
4072 snprintf(ncvalue
, sizeof(ncvalue
), "%08x", text
->nonce_count
);
4073 if (add_to_challenge(params
->utils
,
4074 &text
->out_buf
, &text
->out_buf_len
, &resplen
,
4075 "nc", (unsigned char *) ncvalue
, FALSE
) != SASL_OK
) {
4077 goto FreeAllocatedMem
;
4079 if (add_to_challenge(params
->utils
,
4080 &text
->out_buf
, &text
->out_buf_len
, &resplen
,
4081 "qop", (unsigned char *) qop
, FALSE
) != SASL_OK
) {
4083 goto FreeAllocatedMem
;
4085 if (ctext
->cipher
!= NULL
) {
4086 if (add_to_challenge(params
->utils
,
4087 &text
->out_buf
, &text
->out_buf_len
, &resplen
,
4089 (unsigned char *) ctext
->cipher
->name
,
4092 goto FreeAllocatedMem
;
4096 if (params
->props
.maxbufsize
) {
4097 snprintf(maxbufstr
, sizeof(maxbufstr
), "%d", params
->props
.maxbufsize
);
4098 if (add_to_challenge(params
->utils
,
4099 &text
->out_buf
, &text
->out_buf_len
, &resplen
,
4100 "maxbuf", (unsigned char *) maxbufstr
,
4101 FALSE
) != SASL_OK
) {
4103 params
->utils
->log(params
->utils
->conn
, SASL_LOG_ERR
,
4104 "internal error: add_to_challenge maxbuf failed");
4106 SETERROR(params
->utils
,
4107 "internal error: add_to_challenge maxbuf failed");
4108 #endif /* _SUN_SDK_ */
4109 goto FreeAllocatedMem
;
4114 if (add_to_challenge(params
->utils
,
4115 &text
->out_buf
, &text
->out_buf_len
, &resplen
,
4116 "charset", (unsigned char *) "utf-8",
4117 FALSE
) != SASL_OK
) {
4119 goto FreeAllocatedMem
;
4122 if (add_to_challenge(params
->utils
,
4123 &text
->out_buf
, &text
->out_buf_len
, &resplen
,
4124 "digest-uri", digesturi
, TRUE
) != SASL_OK
) {
4126 goto FreeAllocatedMem
;
4128 if (add_to_challenge(params
->utils
,
4129 &text
->out_buf
, &text
->out_buf_len
, &resplen
,
4130 "response", (unsigned char *) response
,
4131 FALSE
) != SASL_OK
) {
4134 goto FreeAllocatedMem
;
4138 if (strlen(text
->out_buf
) > 2048) {
4140 goto FreeAllocatedMem
;
4145 oparams
->maxoutbuf
= ctext
->server_maxbuf
- 4;
4147 oparams
->maxoutbuf
= ctext
->server_maxbuf
;
4148 #endif /* _SUN_SDK_ */
4149 if(oparams
->mech_ssf
> 1) {
4151 if (oparams
->maxoutbuf
<= 25)
4152 return (SASL_BADPARAM
);
4154 /* MAC block (privacy) */
4155 oparams
->maxoutbuf
-= 25;
4156 } else if(oparams
->mech_ssf
== 1) {
4158 if (oparams
->maxoutbuf
<= 16)
4159 return (SASL_BADPARAM
);
4161 /* MAC block (integrity) */
4162 oparams
->maxoutbuf
-= 16;
4165 text
->seqnum
= 0; /* for integrity/privacy */
4166 text
->rec_seqnum
= 0; /* for integrity/privacy */
4167 text
->utils
= params
->utils
;
4170 params
->props
.maxbufsize
? params
->props
.maxbufsize
: DEFAULT_BUFSIZE
;
4172 /* used by layers */
4174 text
->buffer
= NULL
;
4176 if (oparams
->mech_ssf
> 0) {
4180 create_layer_keys(text
, params
->utils
, text
->HA1
, nbits
,
4183 /* initialize cipher if need be */
4185 if (text
->cipher_init
) {
4186 if (text
->cipher_free
)
4187 text
->cipher_free(text
);
4188 if((result
= text
->cipher_init(text
, enckey
, deckey
)) != SASL_OK
) {
4189 params
->utils
->log(params
->utils
->conn
, SASL_LOG_ERR
,
4190 "couldn't init cipher");
4191 goto FreeAllocatedMem
;
4195 if (text
->cipher_init
)
4196 text
->cipher_init(text
, enckey
, deckey
);
4197 #endif /* _SUN_SDK_ */
4203 if (digesturi
) params
->utils
->free(digesturi
);
4204 if (response
) params
->utils
->free(response
);
4209 static int parse_server_challenge(client_context_t
*ctext
,
4210 sasl_client_params_t
*params
,
4211 const char *serverin
, unsigned serverinlen
,
4212 char ***outrealms
, int *noutrealm
)
4214 context_t
*text
= (context_t
*) ctext
;
4215 int result
= SASL_OK
;
4216 char *in_start
= NULL
;
4218 char **realms
= NULL
;
4220 sasl_ssf_t limit
, musthave
= 0;
4221 sasl_ssf_t external
;
4224 int maxbuf_count
= 0;
4226 bool IsUTF8
= FALSE
;
4227 #endif /* !_SUN_SDK_ */
4228 int algorithm_count
= 0;
4230 if (!serverin
|| !serverinlen
) {
4232 params
->utils
->log(params
->utils
->conn
, SASL_LOG_ERR
,
4233 "no server challenge");
4235 params
->utils
->seterror(params
->utils
->conn
, 0,
4236 "no server challenge");
4237 #endif /* _SUN_SDK_ */
4241 in_start
= in
= params
->utils
->malloc(serverinlen
+ 1);
4242 if (in
== NULL
) return SASL_NOMEM
;
4244 memcpy(in
, serverin
, serverinlen
);
4245 in
[serverinlen
] = 0;
4247 ctext
->server_maxbuf
= 65536; /* Default value for maxbuf */
4249 /* create a new cnonce */
4250 text
->cnonce
= create_nonce(params
->utils
);
4251 if (text
->cnonce
== NULL
) {
4253 params
->utils
->log(params
->utils
->conn
, SASL_LOG_ERR
,
4254 "failed to create cnonce");
4256 params
->utils
->seterror(params
->utils
->conn
, 0,
4257 "failed to create cnonce");
4258 #endif /* _SUN_SDK_ */
4260 goto FreeAllocatedMem
;
4263 /* parse the challenge */
4264 while (in
[0] != '\0') {
4267 get_pair(&in
, &name
, &value
);
4269 /* if parse error */
4272 params
->utils
->log(params
->utils
->conn
, SASL_LOG_ERR
,
4275 params
->utils
->seterror(params
->utils
->conn
, 0, "Parse error");
4276 #endif /* _SUN_SDK_ */
4278 goto FreeAllocatedMem
;
4281 if (strcasecmp(name
, "realm") == 0) {
4285 realms
= params
->utils
->malloc(sizeof(char *) * (nrealm
+ 1));
4287 realms
= params
->utils
->realloc(realms
,
4288 sizeof(char *) * (nrealm
+ 1));
4290 if (realms
== NULL
) {
4291 result
= SASL_NOMEM
;
4292 goto FreeAllocatedMem
;
4295 _plug_strdup(params
->utils
, value
, &realms
[nrealm
-1], NULL
);
4296 realms
[nrealm
] = NULL
;
4297 } else if (strcasecmp(name
, "nonce") == 0) {
4298 _plug_strdup(params
->utils
, value
, (char **) &text
->nonce
,
4300 text
->nonce_count
= 1;
4301 } else if (strcasecmp(name
, "qop") == 0) {
4302 while (value
&& *value
) {
4303 char *comma
= strchr(value
, ',');
4304 if (comma
!= NULL
) {
4308 if (strcasecmp(value
, "auth-conf") == 0) {
4309 protection
|= DIGEST_PRIVACY
;
4310 } else if (strcasecmp(value
, "auth-int") == 0) {
4311 protection
|= DIGEST_INTEGRITY
;
4312 } else if (strcasecmp(value
, "auth") == 0) {
4313 protection
|= DIGEST_NOLAYER
;
4315 params
->utils
->log(params
->utils
->conn
, SASL_LOG_DEBUG
,
4316 "Server supports unknown layer: %s\n",
4323 if (protection
== 0) {
4324 result
= SASL_BADAUTH
;
4325 #ifdef _INTEGRATED_SOLARIS_
4326 params
->utils
->seterror(params
->utils
->conn
, 0,
4327 gettext("Server doesn't support known qop level"));
4329 params
->utils
->seterror(params
->utils
->conn
, 0,
4330 "Server doesn't support known qop level");
4331 #endif /* _INTEGRATED_SOLARIS_ */
4332 goto FreeAllocatedMem
;
4334 } else if (strcasecmp(name
, "cipher") == 0) {
4335 while (value
&& *value
) {
4336 char *comma
= strchr(value
, ',');
4337 #ifdef USE_UEF_CLIENT
4338 struct digest_cipher
*cipher
= available_ciphers1
;
4340 struct digest_cipher
*cipher
= available_ciphers
;
4343 if (comma
!= NULL
) {
4347 /* do we support this cipher? */
4348 while (cipher
->name
) {
4349 if (!strcasecmp(value
, cipher
->name
)) break;
4353 ciphers
|= cipher
->flag
;
4355 params
->utils
->log(params
->utils
->conn
, SASL_LOG_DEBUG
,
4356 "Server supports unknown cipher: %s\n",
4362 } else if (strcasecmp(name
, "stale") == 0 && ctext
->password
) {
4363 /* clear any cached password */
4364 if (ctext
->free_password
)
4365 _plug_free_secret(params
->utils
, &ctext
->password
);
4366 ctext
->password
= NULL
;
4367 } else if (strcasecmp(name
, "maxbuf") == 0) {
4368 /* maxbuf A number indicating the size of the largest
4369 * buffer the server is able to receive when using
4370 * "auth-int". If this directive is missing, the default
4371 * value is 65536. This directive may appear at most once;
4372 * if multiple instances are present, the client should
4373 * abort the authentication exchange.
4377 if (maxbuf_count
!= 1) {
4378 result
= SASL_BADAUTH
;
4380 params
->utils
->log(params
->utils
->conn
, SASL_LOG_ERR
,
4381 "At least two maxbuf directives found."
4382 " Authentication aborted");
4384 params
->utils
->seterror(params
->utils
->conn
, 0,
4385 "At least two maxbuf directives found. Authentication aborted");
4386 #endif /* _SUN_SDK_ */
4387 goto FreeAllocatedMem
;
4388 } else if (sscanf(value
, "%u", &ctext
->server_maxbuf
) != 1) {
4389 result
= SASL_BADAUTH
;
4391 params
->utils
->log(params
->utils
->conn
, SASL_LOG_ERR
,
4392 "Invalid maxbuf parameter received from server");
4394 params
->utils
->seterror(params
->utils
->conn
, 0,
4395 "Invalid maxbuf parameter received from server");
4396 #endif /* _SUN_SDK_ */
4397 goto FreeAllocatedMem
;
4399 if (ctext
->server_maxbuf
<=16) {
4400 result
= SASL_BADAUTH
;
4402 params
->utils
->log(params
->utils
->conn
, SASL_LOG_ERR
,
4403 "Invalid maxbuf parameter received from server"
4404 " (too small: %s)", value
);
4406 params
->utils
->seterror(params
->utils
->conn
, 0,
4407 "Invalid maxbuf parameter received from server (too small: %s)", value
);
4408 #endif /* _SUN_SDK_ */
4409 goto FreeAllocatedMem
;
4412 } else if (strcasecmp(name
, "charset") == 0) {
4413 if (strcasecmp(value
, "utf-8") != 0) {
4414 result
= SASL_BADAUTH
;
4416 params
->utils
->log(params
->utils
->conn
, SASL_LOG_ERR
,
4417 "Charset must be UTF-8");
4419 params
->utils
->seterror(params
->utils
->conn
, 0,
4420 "Charset must be UTF-8");
4421 #endif /* _SUN_SDK_ */
4422 goto FreeAllocatedMem
;
4426 #endif /* !_SUN_SDK_ */
4428 } else if (strcasecmp(name
,"algorithm")==0) {
4429 if (strcasecmp(value
, "md5-sess") != 0)
4432 params
->utils
->log(params
->utils
->conn
, SASL_LOG_ERR
,
4433 "'algorithm' isn't 'md5-sess'");
4435 params
->utils
->seterror(params
->utils
->conn
, 0,
4436 "'algorithm' isn't 'md5-sess'");
4437 #endif /* _SUN_SDK_ */
4439 goto FreeAllocatedMem
;
4443 if (algorithm_count
> 1)
4446 params
->utils
->log(params
->utils
->conn
, SASL_LOG_ERR
,
4447 "Must see 'algorithm' only once");
4449 params
->utils
->seterror(params
->utils
->conn
, 0,
4450 "Must see 'algorithm' only once");
4451 #endif /* _SUN_SDK_ */
4453 goto FreeAllocatedMem
;
4456 params
->utils
->log(params
->utils
->conn
, SASL_LOG_DEBUG
,
4457 "DIGEST-MD5 unrecognized pair %s/%s: ignoring",
4462 if (algorithm_count
!= 1) {
4464 params
->utils
->log(params
->utils
->conn
, SASL_LOG_ERR
,
4465 "Must see 'algorithm' once. Didn't see at all");
4467 params
->utils
->seterror(params
->utils
->conn
, 0,
4468 "Must see 'algorithm' once. Didn't see at all");
4469 #endif /* _SUN_SDK_ */
4471 goto FreeAllocatedMem
;
4474 /* make sure we have everything we require */
4475 if (text
->nonce
== NULL
) {
4477 params
->utils
->log(params
->utils
->conn
, SASL_LOG_ERR
,
4478 "Don't have nonce.");
4480 params
->utils
->seterror(params
->utils
->conn
, 0,
4481 "Don't have nonce.");
4482 #endif /* _SUN_SDK_ */
4484 goto FreeAllocatedMem
;
4487 /* get requested ssf */
4488 external
= params
->external_ssf
;
4490 /* what do we _need_? how much is too much? */
4491 if (params
->props
.maxbufsize
== 0) {
4495 if (params
->props
.max_ssf
> external
) {
4496 limit
= params
->props
.max_ssf
- external
;
4500 if (params
->props
.min_ssf
> external
) {
4501 musthave
= params
->props
.min_ssf
- external
;
4507 /* we now go searching for an option that gives us at least "musthave"
4508 and at most "limit" bits of ssf. */
4509 if ((limit
> 1) && (protection
& DIGEST_PRIVACY
)) {
4510 struct digest_cipher
*cipher
;
4512 /* let's find an encryption scheme that we like */
4513 #ifdef USE_UEF_CLIENT
4514 cipher
= available_ciphers1
;
4516 cipher
= available_ciphers
;
4518 while (cipher
->name
) {
4519 /* examine each cipher we support, see if it meets our security
4520 requirements, and see if the server supports it.
4521 choose the best one of these */
4522 if ((limit
>= cipher
->ssf
) && (musthave
<= cipher
->ssf
) &&
4523 (ciphers
& cipher
->flag
) &&
4524 (!ctext
->cipher
|| (cipher
->ssf
> ctext
->cipher
->ssf
))) {
4525 ctext
->cipher
= cipher
;
4530 if (ctext
->cipher
) {
4531 /* we found a cipher we like */
4532 ctext
->protection
= DIGEST_PRIVACY
;
4534 /* we didn't find any ciphers we like */
4535 #ifdef _INTEGRATED_SOLARIS_
4536 params
->utils
->seterror(params
->utils
->conn
, 0,
4537 gettext("No good privacy layers"));
4539 params
->utils
->seterror(params
->utils
->conn
, 0,
4540 "No good privacy layers");
4541 #endif /* _INTEGRATED_SOLARIS_ */
4545 if (ctext
->cipher
== NULL
) {
4546 /* we failed to find an encryption layer we liked;
4547 can we use integrity or nothing? */
4549 if ((limit
>= 1) && (musthave
<= 1)
4550 && (protection
& DIGEST_INTEGRITY
)) {
4552 ctext
->protection
= DIGEST_INTEGRITY
;
4554 } else if (musthave
== 0) {
4556 } else if (musthave
<= 0) {
4557 #endif /* _SUN_SDK_ */
4559 ctext
->protection
= DIGEST_NOLAYER
;
4561 /* See if server supports not having a layer */
4562 if ((protection
& DIGEST_NOLAYER
) != DIGEST_NOLAYER
) {
4563 #ifdef _INTEGRATED_SOLARIS_
4564 params
->utils
->seterror(params
->utils
->conn
, 0,
4565 gettext("Server doesn't support \"no layer\""));
4567 params
->utils
->seterror(params
->utils
->conn
, 0,
4568 "Server doesn't support \"no layer\"");
4569 #endif /* _INTEGRATED_SOLARIS_ */
4571 goto FreeAllocatedMem
;
4574 #ifdef _INTEGRATED_SOLARIS_
4575 params
->utils
->seterror(params
->utils
->conn
, 0,
4576 gettext("Can't find an acceptable layer"));
4578 params
->utils
->seterror(params
->utils
->conn
, 0,
4579 "Can't find an acceptable layer");
4580 #endif /* _INTEGRATED_SOLARIS_ */
4581 result
= SASL_TOOWEAK
;
4582 goto FreeAllocatedMem
;
4586 *outrealms
= realms
;
4587 *noutrealm
= nrealm
;
4590 if (in_start
) params
->utils
->free(in_start
);
4592 if (result
!= SASL_OK
&& realms
) {
4595 /* need to free all the realms */
4596 for (lup
= 0;lup
< nrealm
; lup
++)
4597 params
->utils
->free(realms
[lup
]);
4599 params
->utils
->free(realms
);
4605 static int ask_user_info(client_context_t
*ctext
,
4606 sasl_client_params_t
*params
,
4607 char **realms
, int nrealm
,
4608 sasl_interact_t
**prompt_need
,
4609 sasl_out_params_t
*oparams
)
4611 context_t
*text
= (context_t
*) ctext
;
4612 int result
= SASL_OK
;
4613 const char *authid
= NULL
, *userid
= NULL
, *realm
= NULL
;
4614 char *realm_chal
= NULL
;
4615 int user_result
= SASL_OK
;
4616 int auth_result
= SASL_OK
;
4617 int pass_result
= SASL_OK
;
4618 int realm_result
= SASL_FAIL
;
4620 /* try to get the authid */
4621 if (oparams
->authid
== NULL
) {
4622 auth_result
= _plug_get_authid(params
->utils
, &authid
, prompt_need
);
4624 if ((auth_result
!= SASL_OK
) && (auth_result
!= SASL_INTERACT
)) {
4629 /* try to get the userid */
4630 if (oparams
->user
== NULL
) {
4631 user_result
= _plug_get_userid(params
->utils
, &userid
, prompt_need
);
4633 if ((user_result
!= SASL_OK
) && (user_result
!= SASL_INTERACT
)) {
4638 /* try to get the password */
4639 if (ctext
->password
== NULL
) {
4640 pass_result
= _plug_get_password(params
->utils
, &ctext
->password
,
4641 &ctext
->free_password
, prompt_need
);
4642 if ((pass_result
!= SASL_OK
) && (pass_result
!= SASL_INTERACT
)) {
4647 /* try to get the realm */
4648 if (text
->realm
== NULL
) {
4651 /* only one choice */
4653 realm_result
= SASL_OK
;
4656 realm_result
= _plug_get_realm(params
->utils
,
4657 (const char **) realms
,
4658 (const char **) &realm
,
4663 /* fake the realm if we must */
4664 if ((realm_result
!= SASL_OK
) && (realm_result
!= SASL_INTERACT
)) {
4665 if (params
->serverFQDN
) {
4666 realm
= params
->serverFQDN
;
4668 return realm_result
;
4673 /* free prompts we got */
4674 if (prompt_need
&& *prompt_need
) {
4675 params
->utils
->free(*prompt_need
);
4676 *prompt_need
= NULL
;
4679 /* if there are prompts not filled in */
4680 if ((user_result
== SASL_INTERACT
) || (auth_result
== SASL_INTERACT
) ||
4681 (pass_result
== SASL_INTERACT
) || (realm_result
== SASL_INTERACT
)) {
4683 /* make our default realm */
4684 if ((realm_result
== SASL_INTERACT
) && params
->serverFQDN
) {
4685 realm_chal
= params
->utils
->malloc(3+strlen(params
->serverFQDN
));
4687 sprintf(realm_chal
, "{%s}", params
->serverFQDN
);
4693 /* make the prompt list */
4695 #if defined _INTEGRATED_SOLARIS_
4696 _plug_make_prompts(params
->utils
, &ctext
->h
, prompt_need
,
4697 user_result
== SASL_INTERACT
?
4698 convert_prompt(params
->utils
, &ctext
->h
,
4699 gettext("Please enter your authorization name"))
4702 auth_result
== SASL_INTERACT
?
4703 convert_prompt(params
->utils
, &ctext
->h
,
4704 gettext("Please enter your authentication name"))
4707 pass_result
== SASL_INTERACT
?
4708 convert_prompt(params
->utils
, &ctext
->h
,
4709 gettext("Please enter your password"))
4712 realm_chal
? realm_chal
: "{}",
4713 realm_result
== SASL_INTERACT
?
4714 convert_prompt(params
->utils
, &ctext
->h
,
4715 gettext("Please enter your realm")) : NULL
,
4716 params
->serverFQDN
? params
->serverFQDN
: NULL
);
4718 _plug_make_prompts(params
->utils
, prompt_need
,
4719 user_result
== SASL_INTERACT
?
4720 "Please enter your authorization name" : NULL
,
4722 auth_result
== SASL_INTERACT
?
4723 "Please enter your authentication name" : NULL
,
4725 pass_result
== SASL_INTERACT
?
4726 "Please enter your password" : NULL
, NULL
,
4728 realm_chal
? realm_chal
: "{}",
4729 realm_result
== SASL_INTERACT
?
4730 "Please enter your realm" : NULL
,
4731 params
->serverFQDN
? params
->serverFQDN
: NULL
);
4732 #endif /* _INTEGRATED_SOLARIS_ */
4734 if (result
== SASL_OK
) return SASL_INTERACT
;
4739 if (oparams
->authid
== NULL
) {
4740 if (!userid
|| !*userid
) {
4741 result
= params
->canon_user(params
->utils
->conn
, authid
, 0,
4742 SASL_CU_AUTHID
| SASL_CU_AUTHZID
,
4746 result
= params
->canon_user(params
->utils
->conn
,
4747 authid
, 0, SASL_CU_AUTHID
, oparams
);
4748 if (result
!= SASL_OK
) return result
;
4750 result
= params
->canon_user(params
->utils
->conn
,
4751 userid
, 0, SASL_CU_AUTHZID
, oparams
);
4753 if (result
!= SASL_OK
) return result
;
4756 /* Get an allocated version of the realm into the structure */
4757 if (realm
&& text
->realm
== NULL
) {
4758 _plug_strdup(params
->utils
, realm
, (char **) &text
->realm
, NULL
);
4765 digestmd5_client_mech_new(void *glob_context
,
4766 sasl_client_params_t
* params
,
4767 void **conn_context
)
4771 /* holds state are in -- allocate client size */
4772 text
= params
->utils
->malloc(sizeof(client_context_t
));
4775 memset(text
, 0, sizeof(client_context_t
));
4778 text
->i_am
= CLIENT
;
4779 text
->reauth
= glob_context
;
4781 *conn_context
= text
;
4787 digestmd5_client_mech_step1(client_context_t
*ctext
,
4788 sasl_client_params_t
*params
,
4789 const char *serverin
__attribute__((unused
)),
4790 unsigned serverinlen
__attribute__((unused
)),
4791 sasl_interact_t
**prompt_need
,
4792 const char **clientout
,
4793 unsigned *clientoutlen
,
4794 sasl_out_params_t
*oparams
)
4796 context_t
*text
= (context_t
*) ctext
;
4797 int result
= SASL_FAIL
;
4800 params
->utils
->log(params
->utils
->conn
, SASL_LOG_DEBUG
,
4801 "DIGEST-MD5 client step 1");
4803 result
= ask_user_info(ctext
, params
, NULL
, 0, prompt_need
, oparams
);
4804 if (result
!= SASL_OK
) return result
;
4806 /* check if we have cached info for this user on this server */
4807 val
= hash(params
->serverFQDN
) % text
->reauth
->size
;
4808 if (params
->utils
->mutex_lock(text
->reauth
->mutex
) == SASL_OK
) { /* LOCK */
4809 if (text
->reauth
->e
[val
].u
.c
.serverFQDN
&&
4810 !strcasecmp(text
->reauth
->e
[val
].u
.c
.serverFQDN
,
4811 params
->serverFQDN
) &&
4812 !strcmp(text
->reauth
->e
[val
].authid
, oparams
->authid
)) {
4815 if (text
->realm
) params
->utils
->free(text
->realm
);
4816 if (text
->nonce
) params
->utils
->free(text
->nonce
);
4817 if (text
->cnonce
) params
->utils
->free(text
->cnonce
);
4818 #endif /* _SUN_SDK_ */
4819 /* we have info, so use it */
4820 _plug_strdup(params
->utils
, text
->reauth
->e
[val
].realm
,
4821 &text
->realm
, NULL
);
4823 _plug_strdup(params
->utils
, (char *)text
->reauth
->e
[val
].nonce
,
4824 (char **) &text
->nonce
, NULL
);
4826 _plug_strdup(params
->utils
, text
->reauth
->e
[val
].nonce
,
4827 (char **) &text
->nonce
, NULL
);
4828 #endif /* _SUN_SDK_ */
4829 text
->nonce_count
= ++text
->reauth
->e
[val
].nonce_count
;
4831 _plug_strdup(params
->utils
, (char *)text
->reauth
->e
[val
].cnonce
,
4832 (char **) &text
->cnonce
, NULL
);
4834 _plug_strdup(params
->utils
, text
->reauth
->e
[val
].cnonce
,
4835 (char **) &text
->cnonce
, NULL
);
4836 #endif /* _SUN_SDK_ */
4837 ctext
->protection
= text
->reauth
->e
[val
].u
.c
.protection
;
4838 ctext
->cipher
= text
->reauth
->e
[val
].u
.c
.cipher
;
4839 ctext
->server_maxbuf
= text
->reauth
->e
[val
].u
.c
.server_maxbuf
;
4841 params
->utils
->mutex_unlock(text
->reauth
->mutex
); /* UNLOCK */
4845 /* we don't have any reauth info, so just return
4846 * that there is no initial client send */
4848 return SASL_CONTINUE
;
4852 * (username | realm | nonce | cnonce | nonce-count | qop digest-uri |
4853 * response | maxbuf | charset | auth-param )
4856 result
= make_client_response(text
, params
, oparams
);
4857 if (result
!= SASL_OK
) return result
;
4859 *clientoutlen
= strlen(text
->out_buf
);
4860 *clientout
= text
->out_buf
;
4863 return SASL_CONTINUE
;
4867 digestmd5_client_mech_step2(client_context_t
*ctext
,
4868 sasl_client_params_t
*params
,
4869 const char *serverin
,
4870 unsigned serverinlen
,
4871 sasl_interact_t
**prompt_need
,
4872 const char **clientout
,
4873 unsigned *clientoutlen
,
4874 sasl_out_params_t
*oparams
)
4876 context_t
*text
= (context_t
*) ctext
;
4877 int result
= SASL_FAIL
;
4878 char **realms
= NULL
;
4881 params
->utils
->log(params
->utils
->conn
, SASL_LOG_DEBUG
,
4882 "DIGEST-MD5 client step 2");
4884 if (params
->props
.min_ssf
> params
->props
.max_ssf
) {
4885 return SASL_BADPARAM
;
4888 /* don't bother parsing the challenge more than once */
4889 if (text
->nonce
== NULL
) {
4890 result
= parse_server_challenge(ctext
, params
, serverin
, serverinlen
,
4892 if (result
!= SASL_OK
) goto FreeAllocatedMem
;
4895 /* only one choice! */
4896 text
->realm
= realms
[0];
4899 params
->utils
->free(realms
);
4904 result
= ask_user_info(ctext
, params
, realms
, nrealm
,
4905 prompt_need
, oparams
);
4906 if (result
!= SASL_OK
) goto FreeAllocatedMem
;
4909 * (username | realm | nonce | cnonce | nonce-count | qop digest-uri |
4910 * response | maxbuf | charset | auth-param )
4913 result
= make_client_response(text
, params
, oparams
);
4914 if (result
!= SASL_OK
) goto FreeAllocatedMem
;
4916 *clientoutlen
= strlen(text
->out_buf
);
4917 *clientout
= text
->out_buf
;
4921 result
= SASL_CONTINUE
;
4927 /* need to free all the realms */
4928 for (lup
= 0;lup
< nrealm
; lup
++)
4929 params
->utils
->free(realms
[lup
]);
4931 params
->utils
->free(realms
);
4938 digestmd5_client_mech_step3(client_context_t
*ctext
,
4939 sasl_client_params_t
*params
,
4940 const char *serverin
,
4941 unsigned serverinlen
,
4942 sasl_interact_t
**prompt_need
__attribute__((unused
)),
4943 const char **clientout
__attribute__((unused
)),
4944 unsigned *clientoutlen
__attribute__((unused
)),
4945 sasl_out_params_t
*oparams
)
4947 context_t
*text
= (context_t
*) ctext
;
4950 int result
= SASL_FAIL
;
4952 params
->utils
->log(params
->utils
->conn
, SASL_LOG_DEBUG
,
4953 "DIGEST-MD5 client step 3");
4955 /* Verify that server is really what they claim to be */
4956 in_start
= in
= params
->utils
->malloc(serverinlen
+ 1);
4957 if (in
== NULL
) return SASL_NOMEM
;
4959 memcpy(in
, serverin
, serverinlen
);
4960 in
[serverinlen
] = 0;
4962 /* parse the response */
4963 while (in
[0] != '\0') {
4965 get_pair(&in
, &name
, &value
);
4969 params
->utils
->log(params
->utils
->conn
, SASL_LOG_ERR
,
4970 "DIGEST-MD5 Received Garbage");
4972 params
->utils
->seterror(params
->utils
->conn
, 0,
4973 "DIGEST-MD5 Received Garbage");
4974 #endif /* _SUN_SDK_ */
4978 if (strcasecmp(name
, "rspauth") == 0) {
4980 if (strcmp(text
->response_value
, value
) != 0) {
4981 #ifdef _INTEGRATED_SOLARIS_
4982 params
->utils
->seterror(params
->utils
->conn
, 0,
4983 gettext("Server authentication failed"));
4985 params
->utils
->seterror(params
->utils
->conn
, 0,
4986 "DIGEST-MD5: This server wants us to believe that he knows shared secret");
4987 #endif /* _INTEGRATED_SOLARIS_ */
4990 oparams
->doneflag
= 1;
4991 oparams
->param_version
= 0;
4997 params
->utils
->log(params
->utils
->conn
, SASL_LOG_DEBUG
,
4998 "DIGEST-MD5 unrecognized pair %s/%s: ignoring",
5003 params
->utils
->free(in_start
);
5005 if (params
->utils
->mutex_lock(text
->reauth
->mutex
) == SASL_OK
) { /* LOCK */
5006 unsigned val
= hash(params
->serverFQDN
) % text
->reauth
->size
;
5009 if (text
->nonce_count
== 1) {
5010 /* successful initial auth, setup for future reauth */
5011 clear_reauth_entry(&text
->reauth
->e
[val
], CLIENT
, params
->utils
);
5012 _plug_strdup(params
->utils
, oparams
->authid
,
5013 &text
->reauth
->e
[val
].authid
, NULL
);
5014 text
->reauth
->e
[val
].realm
= text
->realm
; text
->realm
= NULL
;
5015 text
->reauth
->e
[val
].nonce
= text
->nonce
; text
->nonce
= NULL
;
5016 text
->reauth
->e
[val
].nonce_count
= text
->nonce_count
;
5017 text
->reauth
->e
[val
].cnonce
= text
->cnonce
; text
->cnonce
= NULL
;
5018 _plug_strdup(params
->utils
, params
->serverFQDN
,
5019 &text
->reauth
->e
[val
].u
.c
.serverFQDN
, NULL
);
5020 text
->reauth
->e
[val
].u
.c
.protection
= ctext
->protection
;
5021 text
->reauth
->e
[val
].u
.c
.cipher
= ctext
->cipher
;
5022 text
->reauth
->e
[val
].u
.c
.server_maxbuf
= ctext
->server_maxbuf
;
5026 /* reauth, we already incremented nonce_count */
5028 #endif /* !_SUN_SDK_ */
5031 if (text
->nonce_count
> 1) {
5032 /* failed reauth, clear cache */
5033 clear_reauth_entry(&text
->reauth
->e
[val
], CLIENT
, params
->utils
);
5036 /* failed initial auth, leave existing cache */
5039 params
->utils
->mutex_unlock(text
->reauth
->mutex
); /* UNLOCK */
5046 digestmd5_client_mech_step(void *conn_context
,
5047 sasl_client_params_t
*params
,
5048 const char *serverin
,
5049 unsigned serverinlen
,
5050 sasl_interact_t
**prompt_need
,
5051 const char **clientout
,
5052 unsigned *clientoutlen
,
5053 sasl_out_params_t
*oparams
)
5055 context_t
*text
= (context_t
*) conn_context
;
5056 client_context_t
*ctext
= (client_context_t
*) conn_context
;
5057 unsigned val
= hash(params
->serverFQDN
) % text
->reauth
->size
;
5059 if (serverinlen
> 2048) return SASL_BADPROT
;
5064 switch (text
->state
) {
5068 /* here's where we attempt fast reauth if possible */
5071 /* check if we have saved info for this server */
5072 if (params
->utils
->mutex_lock(text
->reauth
->mutex
) == SASL_OK
) { /* LOCK */
5073 reauth
= text
->reauth
->e
[val
].u
.c
.serverFQDN
&&
5074 !strcasecmp(text
->reauth
->e
[val
].u
.c
.serverFQDN
,
5075 params
->serverFQDN
);
5076 params
->utils
->mutex_unlock(text
->reauth
->mutex
); /* UNLOCK */
5079 return digestmd5_client_mech_step1(ctext
, params
,
5080 serverin
, serverinlen
,
5082 clientout
, clientoutlen
,
5086 /* we don't have any reauth info, so just return
5087 * that there is no initial client send */
5089 return SASL_CONTINUE
;
5093 /* fall through and respond to challenge */
5096 if (serverin
&& !strncasecmp(serverin
, "rspauth=", 8)) {
5097 return digestmd5_client_mech_step3(ctext
, params
,
5098 serverin
, serverinlen
,
5100 clientout
, clientoutlen
,
5104 /* fall through and respond to challenge */
5107 /* cleanup after a failed reauth attempt */
5108 if (params
->utils
->mutex_lock(text
->reauth
->mutex
) == SASL_OK
) { /* LOCK */
5109 clear_reauth_entry(&text
->reauth
->e
[val
], CLIENT
, params
->utils
);
5111 params
->utils
->mutex_unlock(text
->reauth
->mutex
); /* UNLOCK */
5114 if (text
->realm
) params
->utils
->free(text
->realm
);
5115 if (text
->nonce
) params
->utils
->free(text
->nonce
);
5116 if (text
->cnonce
) params
->utils
->free(text
->cnonce
);
5119 text
->nonce
= text
->cnonce
= NULL
;
5121 text
->realm
= text
->nonce
= text
->cnonce
= NULL
;
5122 #endif /* _SUN_SDK_ */
5123 ctext
->cipher
= NULL
;
5126 return digestmd5_client_mech_step2(ctext
, params
,
5127 serverin
, serverinlen
,
5129 clientout
, clientoutlen
,
5134 params
->utils
->log(params
->utils
->conn
, SASL_LOG_ERR
,
5135 "Invalid DIGEST-MD5 client step %d", text
->state
);
5137 params
->utils
->log(NULL
, SASL_LOG_ERR
,
5138 "Invalid DIGEST-MD5 client step %d\n", text
->state
);
5139 #endif /* _SUN_SDK_ */
5143 return SASL_FAIL
; /* should never get here */
5147 digestmd5_client_mech_dispose(void *conn_context
, const sasl_utils_t
*utils
)
5149 client_context_t
*ctext
= (client_context_t
*) conn_context
;
5151 if (!ctext
|| !utils
) return;
5153 #ifdef _INTEGRATED_SOLARIS_
5154 convert_prompt(utils
, &ctext
->h
, NULL
);
5155 #endif /* _INTEGRATED_SOLARIS_ */
5157 if (ctext
->free_password
) _plug_free_secret(utils
, &ctext
->password
);
5159 digestmd5_common_mech_dispose(conn_context
, utils
);
5162 static sasl_client_plug_t digestmd5_client_plugins
[] =
5166 #ifdef WITH_RC4 /* mech_name */
5173 SASL_SEC_NOPLAINTEXT
5174 | SASL_SEC_NOANONYMOUS
5175 | SASL_SEC_MUTUAL_AUTH
, /* security_flags */
5176 SASL_FEAT_ALLOWS_PROXY
, /* features */
5177 NULL
, /* required_prompts */
5178 NULL
, /* glob_context */
5179 &digestmd5_client_mech_new
, /* mech_new */
5180 &digestmd5_client_mech_step
, /* mech_step */
5181 &digestmd5_client_mech_dispose
, /* mech_dispose */
5182 &digestmd5_common_mech_free
, /* mech_free */
5189 int digestmd5_client_plug_init(sasl_utils_t
*utils
,
5192 sasl_client_plug_t
**pluglist
,
5195 reauth_cache_t
*reauth_cache
;
5196 #if defined _SUN_SDK_ && defined USE_UEF
5198 #endif /* _SUN_SDK_ && USE_UEF */
5200 if (maxversion
< SASL_CLIENT_PLUG_VERSION
)
5201 return SASL_BADVERS
;
5203 #if defined _SUN_SDK_ && defined USE_UEF
5204 if ((ret
= uef_init(utils
)) != SASL_OK
)
5206 #endif /* _SUN_SDK_ && USE_UEF */
5209 reauth_cache
= utils
->malloc(sizeof(reauth_cache_t
));
5210 if (reauth_cache
== NULL
)
5212 memset(reauth_cache
, 0, sizeof(reauth_cache_t
));
5213 reauth_cache
->i_am
= CLIENT
;
5216 reauth_cache
->mutex
= utils
->mutex_alloc();
5217 if (!reauth_cache
->mutex
)
5221 reauth_cache
->size
= 10;
5222 reauth_cache
->e
= utils
->malloc(reauth_cache
->size
*
5223 sizeof(reauth_entry_t
));
5224 if (reauth_cache
->e
== NULL
)
5226 memset(reauth_cache
->e
, 0, reauth_cache
->size
* sizeof(reauth_entry_t
));
5228 digestmd5_client_plugins
[0].glob_context
= reauth_cache
;
5230 #ifdef USE_UEF_CLIENT
5231 digestmd5_client_plugins
[0].max_ssf
= uef_max_ssf
;
5232 #endif /* USE_UEF_CLIENT */
5233 #endif /* _SUN_SDK_ */
5235 #ifdef _INTEGRATED_SOLARIS_
5237 * Let libsasl know that we are a "Sun" plugin so that privacy
5238 * and integrity will be allowed.
5240 REG_PLUG("DIGEST-MD5", digestmd5_client_plugins
);
5241 #endif /* _INTEGRATED_SOLARIS_ */
5243 *out_version
= SASL_CLIENT_PLUG_VERSION
;
5244 *pluglist
= digestmd5_client_plugins
;
5252 /* If we fail here - we should just not offer privacy or integrity */
5254 getSlotID(const sasl_utils_t
*utils
, CK_MECHANISM_TYPE mech_type
,
5255 CK_SLOT_ID
*slot_id
)
5258 CK_ULONG ulSlotCount
;
5259 CK_ULONG ulMechTypeCount
;
5260 CK_SLOT_ID
*pSlotList
= NULL
;
5262 CK_MECHANISM_TYPE_PTR pMechTypeList
= NULL
;
5265 rv
= C_GetSlotList(CK_FALSE
, NULL_PTR
, &ulSlotCount
);
5266 if (rv
!= CKR_OK
|| ulSlotCount
== 0) {
5268 utils
->log(utils
->conn
, SASL_LOG_DEBUG
,
5269 "C_GetSlotList: 0x%.8X count:%d\n", rv
, ulSlotCount
);
5274 pSlotList
= utils
->calloc(sizeof (CK_SLOT_ID
), ulSlotCount
);
5275 if (pSlotList
== NULL
)
5278 rv
= C_GetSlotList(CK_FALSE
, pSlotList
, &ulSlotCount
);
5281 utils
->log(utils
->conn
, SASL_LOG_DEBUG
,
5282 "C_GetSlotList: 0x%.8X count:%d\n", rv
, ulSlotCount
);
5287 for (i
= 0; i
< ulSlotCount
; i
++) {
5288 slotID
= pSlotList
[i
];
5289 rv
= C_GetMechanismList(slotID
, NULL_PTR
, &ulMechTypeCount
);
5292 utils
->log(utils
->conn
, SASL_LOG_DEBUG
,
5293 "C_GetMechanismList returned 0x%.8X count:%d\n", rv
,
5296 utils
->free(pSlotList
);
5300 utils
->calloc(sizeof (CK_MECHANISM_TYPE
), ulMechTypeCount
);
5301 if (pMechTypeList
== NULL_PTR
) {
5302 utils
->free(pSlotList
);
5305 rv
= C_GetMechanismList(slotID
, pMechTypeList
, &ulMechTypeCount
);
5308 utils
->log(utils
->conn
, SASL_LOG_DEBUG
,
5309 "C_GetMechanismList returned 0x%.8X count:%d\n", rv
,
5312 utils
->free(pMechTypeList
);
5313 utils
->free(pSlotList
);
5317 for (m
= 0; m
< ulMechTypeCount
; m
++) {
5318 if (pMechTypeList
[m
] == mech_type
)
5321 utils
->free(pMechTypeList
);
5322 pMechTypeList
= NULL
;
5323 if (m
< ulMechTypeCount
)
5326 utils
->free(pSlotList
);
5327 if (i
< ulSlotCount
) {
5335 uef_init(const sasl_utils_t
*utils
)
5346 if (LOCK_MUTEX(&uef_init_mutex
) < 0)
5349 rv
= C_Initialize(NULL_PTR
);
5350 if (rv
!= CKR_OK
&& rv
!= CKR_CRYPTOKI_ALREADY_INITIALIZED
) {
5352 utils
->log(utils
->conn
, SASL_LOG_DEBUG
,
5353 "C_Initialize returned 0x%.8X\n", rv
);
5358 got_rc4
= getSlotID(utils
, CKM_RC4
, &rc4_slot_id
) == SASL_OK
;
5360 utils
->log(utils
->conn
, SASL_LOG_WARN
, "Could not get rc4");
5362 got_des
= getSlotID(utils
, CKM_DES_CBC
, &des_slot_id
) == SASL_OK
;
5364 utils
->log(utils
->conn
, SASL_LOG_WARN
, "Could not get des");
5366 got_3des
= getSlotID(utils
, CKM_DES3_CBC
, &des3_slot_id
) == SASL_OK
;
5368 utils
->log(utils
->conn
, SASL_LOG_WARN
, "Could not get 3des");
5370 uef_max_ssf
= got_rc4
? 128 : got_3des
? 112 : got_des
? 55 : 0;
5372 /* adjust the available ciphers */
5373 next_c
= (got_rc4
) ? 3 : 0;
5376 uef_ciphers
[next_c
].name
= uef_ciphers
[DES_CIPHER_INDEX
].name
;
5377 uef_ciphers
[next_c
].ssf
= uef_ciphers
[DES_CIPHER_INDEX
].ssf
;
5378 uef_ciphers
[next_c
].n
= uef_ciphers
[DES_CIPHER_INDEX
].n
;
5379 uef_ciphers
[next_c
].flag
= uef_ciphers
[DES_CIPHER_INDEX
].flag
;
5380 uef_ciphers
[next_c
].cipher_enc
=
5381 uef_ciphers
[DES_CIPHER_INDEX
].cipher_enc
;
5382 uef_ciphers
[next_c
].cipher_dec
=
5383 uef_ciphers
[DES_CIPHER_INDEX
].cipher_dec
;
5384 uef_ciphers
[next_c
].cipher_init
=
5385 uef_ciphers
[DES_CIPHER_INDEX
].cipher_init
;
5390 uef_ciphers
[next_c
].name
= uef_ciphers
[DES3_CIPHER_INDEX
].name
;
5391 uef_ciphers
[next_c
].ssf
= uef_ciphers
[DES3_CIPHER_INDEX
].ssf
;
5392 uef_ciphers
[next_c
].n
= uef_ciphers
[DES3_CIPHER_INDEX
].n
;
5393 uef_ciphers
[next_c
].flag
= uef_ciphers
[DES3_CIPHER_INDEX
].flag
;
5394 uef_ciphers
[next_c
].cipher_enc
=
5395 uef_ciphers
[DES3_CIPHER_INDEX
].cipher_enc
;
5396 uef_ciphers
[next_c
].cipher_dec
=
5397 uef_ciphers
[DES3_CIPHER_INDEX
].cipher_dec
;
5398 uef_ciphers
[next_c
].cipher_init
=
5399 uef_ciphers
[DES3_CIPHER_INDEX
].cipher_init
;
5402 uef_ciphers
[next_c
].name
= NULL
;
5404 got_uef_slot
= TRUE
;
5405 UNLOCK_MUTEX(&uef_init_mutex
);
5409 #endif /* USE_UEF */
5410 #endif /* _SUN_SDK_ */