1 | /* |
---|
2 | * websda.c -- Digest Access Authentication routines |
---|
3 | * |
---|
4 | * Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved. |
---|
5 | * |
---|
6 | * See the file "license.txt" for usage and redistribution license requirements |
---|
7 | * |
---|
8 | * $Id$ |
---|
9 | */ |
---|
10 | |
---|
11 | /******************************** Description *********************************/ |
---|
12 | |
---|
13 | /* |
---|
14 | * Routines for generating DAA data. The module uses the |
---|
15 | * "RSA Data Security, Inc. MD5 Message-Digest Algorithm" found in md5c.c |
---|
16 | */ |
---|
17 | |
---|
18 | /********************************* Includes ***********************************/ |
---|
19 | |
---|
20 | #ifndef CE |
---|
21 | #include <time.h> |
---|
22 | #endif |
---|
23 | #include "websda.h" |
---|
24 | #include "md5.h" |
---|
25 | |
---|
26 | /******************************** Local Data **********************************/ |
---|
27 | |
---|
28 | #define RANDOMKEY T("onceuponatimeinparadise") |
---|
29 | #define NONCE_SIZE 34 |
---|
30 | #define HASH_SIZE 16 |
---|
31 | |
---|
32 | /*********************************** Code *************************************/ |
---|
33 | /* |
---|
34 | * websMD5binary returns the MD5 hash |
---|
35 | */ |
---|
36 | |
---|
37 | char *websMD5binary(unsigned char *buf, int length) |
---|
38 | { |
---|
39 | const char *hex = "0123456789abcdef"; |
---|
40 | MD5_CONTEXT md5ctx; |
---|
41 | unsigned char hash[HASH_SIZE]; |
---|
42 | char *r, *strReturn; |
---|
43 | char result[(HASH_SIZE * 2) + 1]; |
---|
44 | int i; |
---|
45 | |
---|
46 | /* |
---|
47 | * Take the MD5 hash of the string argument. |
---|
48 | */ |
---|
49 | MD5Init(&md5ctx); |
---|
50 | MD5Update(&md5ctx, buf, (unsigned int)length); |
---|
51 | MD5Final(hash, &md5ctx); |
---|
52 | |
---|
53 | /* |
---|
54 | * Prepare the resulting hash string |
---|
55 | */ |
---|
56 | for (i = 0, r = result; i < 16; i++) { |
---|
57 | *r++ = hex[hash[i] >> 4]; |
---|
58 | *r++ = hex[hash[i] & 0xF]; |
---|
59 | } |
---|
60 | |
---|
61 | /* |
---|
62 | * Zero terminate the hash string |
---|
63 | */ |
---|
64 | *r = '\0'; |
---|
65 | |
---|
66 | /* |
---|
67 | * Allocate a new copy of the hash string |
---|
68 | */ |
---|
69 | strReturn = balloc(B_L, sizeof(result)); |
---|
70 | strcpy(strReturn, result); |
---|
71 | |
---|
72 | return strReturn; |
---|
73 | } |
---|
74 | |
---|
75 | /*****************************************************************************/ |
---|
76 | /* |
---|
77 | * Convenience call to websMD5binary |
---|
78 | * (Performs char_t to char conversion and back) |
---|
79 | */ |
---|
80 | |
---|
81 | char_t *websMD5(char_t *string) |
---|
82 | { |
---|
83 | char_t *strReturn; |
---|
84 | |
---|
85 | a_assert(string && *string); |
---|
86 | |
---|
87 | if (string && *string) { |
---|
88 | char *strTemp, *strHash; |
---|
89 | int nLen; |
---|
90 | /* |
---|
91 | * Convert input char_t string to char string |
---|
92 | */ |
---|
93 | nLen = gstrlen(string); |
---|
94 | strTemp = ballocUniToAsc(string, nLen + 1); |
---|
95 | /* |
---|
96 | * Execute the digest calculation |
---|
97 | */ |
---|
98 | strHash = websMD5binary((unsigned char *)strTemp, nLen); |
---|
99 | /* |
---|
100 | * Convert the returned char string digest to a char_t string |
---|
101 | */ |
---|
102 | nLen = strlen(strHash); |
---|
103 | strReturn = ballocAscToUni(strHash, nLen); |
---|
104 | /* |
---|
105 | * Free up the temporary allocated resources |
---|
106 | */ |
---|
107 | bfree(B_L, strTemp); |
---|
108 | bfree(B_L, strHash); |
---|
109 | } else { |
---|
110 | strReturn = NULL; |
---|
111 | } |
---|
112 | |
---|
113 | return strReturn; |
---|
114 | } |
---|
115 | |
---|
116 | /******************************************************************************/ |
---|
117 | /* |
---|
118 | * Get a Nonce value for passing along to the client. This function |
---|
119 | * composes the string "RANDOMKEY:timestamp:myrealm" and |
---|
120 | * calculates the MD5 digest placing it in output. |
---|
121 | */ |
---|
122 | |
---|
123 | char_t *websCalcNonce(webs_t wp) |
---|
124 | { |
---|
125 | char_t *nonce, *prenonce; |
---|
126 | struct tm *newtime; |
---|
127 | time_t longTime; |
---|
128 | |
---|
129 | a_assert(wp); |
---|
130 | /* |
---|
131 | * Get time as long integer. |
---|
132 | */ |
---|
133 | time(&longTime); |
---|
134 | /* |
---|
135 | * Convert to local time. |
---|
136 | */ |
---|
137 | newtime = localtime(&longTime); |
---|
138 | /* |
---|
139 | * Create prenonce string. |
---|
140 | */ |
---|
141 | prenonce = NULL; |
---|
142 | #ifdef DIGEST_ACCESS_SUPPORT |
---|
143 | fmtAlloc(&prenonce, 256, T("%s:%s:%s"), RANDOMKEY, gasctime(newtime), |
---|
144 | wp->realm); |
---|
145 | #else |
---|
146 | fmtAlloc(&prenonce, 256, T("%s:%s:%s"), RANDOMKEY, gasctime(newtime), |
---|
147 | RANDOMKEY); |
---|
148 | #endif |
---|
149 | a_assert(prenonce); |
---|
150 | /* |
---|
151 | * Create the nonce |
---|
152 | */ |
---|
153 | nonce = websMD5(prenonce); |
---|
154 | /* |
---|
155 | * Cleanup |
---|
156 | */ |
---|
157 | bfreeSafe(B_L, prenonce); |
---|
158 | |
---|
159 | return nonce; |
---|
160 | } |
---|
161 | |
---|
162 | /******************************************************************************/ |
---|
163 | /* |
---|
164 | * Get an Opaque value for passing along to the client |
---|
165 | */ |
---|
166 | |
---|
167 | char_t *websCalcOpaque(webs_t wp) |
---|
168 | { |
---|
169 | char_t *opaque; |
---|
170 | a_assert(wp); |
---|
171 | /* |
---|
172 | * Temporary stub! |
---|
173 | */ |
---|
174 | opaque = bstrdup(B_L, T("5ccc069c403ebaf9f0171e9517f40e41")); |
---|
175 | |
---|
176 | return opaque; |
---|
177 | } |
---|
178 | |
---|
179 | /******************************************************************************/ |
---|
180 | /* |
---|
181 | * Get a Digest value using the MD5 algorithm |
---|
182 | */ |
---|
183 | |
---|
184 | char_t *websCalcDigest(webs_t wp) |
---|
185 | { |
---|
186 | #ifdef DIGEST_ACCESS_SUPPORT |
---|
187 | char_t *digest, *a1, *a1prime, *a2, *a2prime, *preDigest, *method; |
---|
188 | |
---|
189 | a_assert(wp); |
---|
190 | digest = NULL; |
---|
191 | |
---|
192 | /* |
---|
193 | * Calculate first portion of digest H(A1) |
---|
194 | */ |
---|
195 | a1 = NULL; |
---|
196 | fmtAlloc(&a1, 255, T("%s:%s:%s"), wp->userName, wp->realm, wp->password); |
---|
197 | a_assert(a1); |
---|
198 | a1prime = websMD5(a1); |
---|
199 | bfreeSafe(B_L, a1); |
---|
200 | /* |
---|
201 | * Calculate second portion of digest H(A2) |
---|
202 | */ |
---|
203 | method = websGetVar(wp, T("REQUEST_METHOD"), NULL); |
---|
204 | a_assert(method); |
---|
205 | a2 = NULL; |
---|
206 | fmtAlloc(&a2, 255, T("%s:%s"), method, wp->uri); |
---|
207 | a_assert(a2); |
---|
208 | a2prime = websMD5(a2); |
---|
209 | bfreeSafe(B_L, a2); |
---|
210 | /* |
---|
211 | * Construct final digest KD(H(A1):nonce:H(A2)) |
---|
212 | */ |
---|
213 | a_assert(a1prime); |
---|
214 | a_assert(a2prime); |
---|
215 | a_assert(wp->nonce); |
---|
216 | |
---|
217 | preDigest = NULL; |
---|
218 | if (!wp->qop) { |
---|
219 | fmtAlloc(&preDigest, 255, T("%s:%s:%s"), a1prime, wp->nonce, a2prime); |
---|
220 | } else { |
---|
221 | fmtAlloc(&preDigest, 255, T("%s:%s:%s:%s:%s:%s"), |
---|
222 | a1prime, |
---|
223 | wp->nonce, |
---|
224 | wp->nc, |
---|
225 | wp->cnonce, |
---|
226 | wp->qop, |
---|
227 | a2prime); |
---|
228 | } |
---|
229 | |
---|
230 | a_assert(preDigest); |
---|
231 | digest = websMD5(preDigest); |
---|
232 | /* |
---|
233 | * Now clean up |
---|
234 | */ |
---|
235 | bfreeSafe(B_L, a1prime); |
---|
236 | bfreeSafe(B_L, a2prime); |
---|
237 | bfreeSafe(B_L, preDigest); |
---|
238 | return digest; |
---|
239 | #else |
---|
240 | return NULL; |
---|
241 | #endif /* DIGEST_ACCESS_SUPPORT */ |
---|
242 | } |
---|
243 | |
---|
244 | /******************************************************************************/ |
---|