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