1 |
|
2 |
https://bugzilla.redhat.com/show_bug.cgi?id=715025 |
3 |
|
4 |
http://svn.php.net/viewvc?view=revision&revision=313406 |
5 |
http://svn.php.net/viewvc?view=revision&revision=313999 |
6 |
|
7 |
--- php-5.3.3/ext/standard/crypt_blowfish.c.cve2483 |
8 |
+++ php-5.3.3/ext/standard/crypt_blowfish.c |
9 |
@@ -1,28 +1,39 @@ |
10 |
+/* $Id$ */ |
11 |
/* |
12 |
- $Id: crypt_blowfish.c 295339 2010-02-21 23:47:14Z pajoye $ |
13 |
-*/ |
14 |
-/* |
15 |
+ * The crypt_blowfish homepage is: |
16 |
+ * |
17 |
+ * http://www.openwall.com/crypt/ |
18 |
+ * |
19 |
* This code comes from John the Ripper password cracker, with reentrant |
20 |
* and crypt(3) interfaces added, but optimizations specific to password |
21 |
* cracking removed. |
22 |
* |
23 |
- * Written by Solar Designer <solar at openwall.com> in 1998-2002 and |
24 |
- * placed in the public domain. |
25 |
+ * Written by Solar Designer <solar at openwall.com> in 1998-2011. |
26 |
+ * No copyright is claimed, and the software is hereby placed in the public |
27 |
+ * domain. In case this attempt to disclaim copyright and place the software |
28 |
+ * in the public domain is deemed null and void, then the software is |
29 |
+ * Copyright (c) 1998-2011 Solar Designer and it is hereby released to the |
30 |
+ * general public under the following terms: |
31 |
* |
32 |
- * There's absolutely no warranty. |
33 |
+ * Redistribution and use in source and binary forms, with or without |
34 |
+ * modification, are permitted. |
35 |
+ * |
36 |
+ * There's ABSOLUTELY NO WARRANTY, express or implied. |
37 |
* |
38 |
* It is my intent that you should be able to use this on your system, |
39 |
- * as a part of a software package, or anywhere else to improve security, |
40 |
+ * as part of a software package, or anywhere else to improve security, |
41 |
* ensure compatibility, or for any other purpose. I would appreciate |
42 |
* it if you give credit where it is due and keep your modifications in |
43 |
* the public domain as well, but I don't require that in order to let |
44 |
* you place this code and any modifications you make under a license |
45 |
* of your choice. |
46 |
* |
47 |
- * This implementation is compatible with OpenBSD bcrypt.c (version 2a) |
48 |
- * by Niels Provos <provos at citi.umich.edu>, and uses some of his |
49 |
+ * This implementation is mostly compatible with OpenBSD's bcrypt.c (prefix |
50 |
+ * "$2a$") by Niels Provos <provos at citi.umich.edu>, and uses some of his |
51 |
* ideas. The password hashing algorithm was designed by David Mazieres |
52 |
- * <dm at lcs.mit.edu>. |
53 |
+ * <dm at lcs.mit.edu>. For more information on the level of compatibility, |
54 |
+ * please refer to the comments in BF_set_key() below and to the crypt(3) |
55 |
+ * man page included in the crypt_blowfish tarball. |
56 |
* |
57 |
* There's a paper on the algorithm that explains its design decisions: |
58 |
* |
59 |
@@ -40,16 +51,8 @@ |
60 |
#define __set_errno(val) errno = (val) |
61 |
#endif |
62 |
|
63 |
- |
64 |
-#ifndef __const |
65 |
-#ifdef __GNUC__ |
66 |
-#define __CONST __const |
67 |
-#else |
68 |
-#define __CONST |
69 |
-#endif |
70 |
-#else |
71 |
-#define __CONST __const |
72 |
-#endif |
73 |
+/* Just to make sure the prototypes match the actual definitions */ |
74 |
+#include "crypt_blowfish.h" |
75 |
|
76 |
#ifdef __i386__ |
77 |
#define BF_ASM 0 |
78 |
@@ -63,6 +66,7 @@ |
79 |
#endif |
80 |
|
81 |
typedef unsigned int BF_word; |
82 |
+typedef signed int BF_word_signed; |
83 |
|
84 |
/* Number of Blowfish rounds, this is also hardcoded into a few places */ |
85 |
#define BF_N 16 |
86 |
@@ -370,35 +374,21 @@ static unsigned char BF_atoi64[0x60] = { |
87 |
43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 64, 64, 64, 64, 64 |
88 |
}; |
89 |
|
90 |
-/* |
91 |
- * This may be optimized out if built with function inlining and no BF_ASM. |
92 |
- */ |
93 |
-static void clean(void *data, int size) |
94 |
-{ |
95 |
-#if BF_ASM |
96 |
- extern void _BF_clean(void *data); |
97 |
-#endif |
98 |
- memset(data, 0, size); |
99 |
-#if BF_ASM |
100 |
- _BF_clean(data); |
101 |
-#endif |
102 |
-} |
103 |
- |
104 |
#define BF_safe_atoi64(dst, src) \ |
105 |
{ \ |
106 |
tmp = (unsigned char)(src); \ |
107 |
- if (tmp == '$') break; \ |
108 |
+ if (tmp == '$') break; /* PHP hack */ \ |
109 |
if ((unsigned int)(tmp -= 0x20) >= 0x60) return -1; \ |
110 |
tmp = BF_atoi64[tmp]; \ |
111 |
if (tmp > 63) return -1; \ |
112 |
(dst) = tmp; \ |
113 |
} |
114 |
|
115 |
-static int BF_decode(BF_word *dst, __CONST char *src, int size) |
116 |
+static int BF_decode(BF_word *dst, const char *src, int size) |
117 |
{ |
118 |
unsigned char *dptr = (unsigned char *)dst; |
119 |
unsigned char *end = dptr + size; |
120 |
- unsigned char *sptr = (unsigned char *)src; |
121 |
+ const unsigned char *sptr = (const unsigned char *)src; |
122 |
unsigned int tmp, c1, c2, c3, c4; |
123 |
|
124 |
do { |
125 |
@@ -415,16 +405,16 @@ static int BF_decode(BF_word *dst, __CON |
126 |
*dptr++ = ((c3 & 0x03) << 6) | c4; |
127 |
} while (dptr < end); |
128 |
|
129 |
- while (dptr < end) |
130 |
+ while (dptr < end) /* PHP hack */ |
131 |
*dptr++ = 0; |
132 |
|
133 |
return 0; |
134 |
} |
135 |
|
136 |
-static void BF_encode(char *dst, __CONST BF_word *src, int size) |
137 |
+static void BF_encode(char *dst, const BF_word *src, int size) |
138 |
{ |
139 |
- unsigned char *sptr = (unsigned char *)src; |
140 |
- unsigned char *end = sptr + size; |
141 |
+ const unsigned char *sptr = (const unsigned char *)src; |
142 |
+ const unsigned char *end = sptr + size; |
143 |
unsigned char *dptr = (unsigned char *)dst; |
144 |
unsigned int c1, c2; |
145 |
|
146 |
@@ -555,32 +545,117 @@ static void BF_swap(BF_word *x, int coun |
147 |
} while (ptr < &data.ctx.S[3][0xFF]); |
148 |
#endif |
149 |
|
150 |
-static void BF_set_key(__CONST char *key, BF_key expanded, BF_key initial) |
151 |
+static void BF_set_key(const char *key, BF_key expanded, BF_key initial, |
152 |
+ unsigned char flags) |
153 |
{ |
154 |
- __CONST char *ptr = key; |
155 |
- int i, j; |
156 |
- BF_word tmp; |
157 |
+ const char *ptr = key; |
158 |
+ unsigned int bug, i, j; |
159 |
+ BF_word safety, sign, diff, tmp[2]; |
160 |
+ |
161 |
+/* |
162 |
+ * There was a sign extension bug in older revisions of this function. While |
163 |
+ * we would have liked to simply fix the bug and move on, we have to provide |
164 |
+ * a backwards compatibility feature (essentially the bug) for some systems and |
165 |
+ * a safety measure for some others. The latter is needed because for certain |
166 |
+ * multiple inputs to the buggy algorithm there exist easily found inputs to |
167 |
+ * the correct algorithm that produce the same hash. Thus, we optionally |
168 |
+ * deviate from the correct algorithm just enough to avoid such collisions. |
169 |
+ * While the bug itself affected the majority of passwords containing |
170 |
+ * characters with the 8th bit set (although only a percentage of those in a |
171 |
+ * collision-producing way), the anti-collision safety measure affects |
172 |
+ * only a subset of passwords containing the '\xff' character (not even all of |
173 |
+ * those passwords, just some of them). This character is not found in valid |
174 |
+ * UTF-8 sequences and is rarely used in popular 8-bit character encodings. |
175 |
+ * Thus, the safety measure is unlikely to cause much annoyance, and is a |
176 |
+ * reasonable tradeoff to use when authenticating against existing hashes that |
177 |
+ * are not reliably known to have been computed with the correct algorithm. |
178 |
+ * |
179 |
+ * We use an approach that tries to minimize side-channel leaks of password |
180 |
+ * information - that is, we mostly use fixed-cost bitwise operations instead |
181 |
+ * of branches or table lookups. (One conditional branch based on password |
182 |
+ * length remains. It is not part of the bug aftermath, though, and is |
183 |
+ * difficult and possibly unreasonable to avoid given the use of C strings by |
184 |
+ * the caller, which results in similar timing leaks anyway.) |
185 |
+ * |
186 |
+ * For actual implementation, we set an array index in the variable "bug" |
187 |
+ * (0 means no bug, 1 means sign extension bug emulation) and a flag in the |
188 |
+ * variable "safety" (bit 16 is set when the safety measure is requested). |
189 |
+ * Valid combinations of settings are: |
190 |
+ * |
191 |
+ * Prefix "$2a$": bug = 0, safety = 0x10000 |
192 |
+ * Prefix "$2x$": bug = 1, safety = 0 |
193 |
+ * Prefix "$2y$": bug = 0, safety = 0 |
194 |
+ */ |
195 |
+ bug = (unsigned int)flags & 1; |
196 |
+ safety = ((BF_word)flags & 2) << 15; |
197 |
+ |
198 |
+ sign = diff = 0; |
199 |
|
200 |
for (i = 0; i < BF_N + 2; i++) { |
201 |
- tmp = 0; |
202 |
+ tmp[0] = tmp[1] = 0; |
203 |
for (j = 0; j < 4; j++) { |
204 |
- tmp <<= 8; |
205 |
- tmp |= *ptr; |
206 |
- |
207 |
- if (!*ptr) ptr = key; else ptr++; |
208 |
+ tmp[0] <<= 8; |
209 |
+ tmp[0] |= (unsigned char)*ptr; /* correct */ |
210 |
+ tmp[1] <<= 8; |
211 |
+ tmp[1] |= (BF_word_signed)(signed char)*ptr; /* bug */ |
212 |
+/* |
213 |
+ * Sign extension in the first char has no effect - nothing to overwrite yet, |
214 |
+ * and those extra 24 bits will be fully shifted out of the 32-bit word. For |
215 |
+ * chars 2, 3, 4 in each four-char block, we set bit 7 of "sign" if sign |
216 |
+ * extension in tmp[1] occurs. Once this flag is set, it remains set. |
217 |
+ */ |
218 |
+ if (j) |
219 |
+ sign |= tmp[1] & 0x80; |
220 |
+ if (!*ptr) |
221 |
+ ptr = key; |
222 |
+ else |
223 |
+ ptr++; |
224 |
} |
225 |
+ diff |= tmp[0] ^ tmp[1]; /* Non-zero on any differences */ |
226 |
|
227 |
- expanded[i] = tmp; |
228 |
- initial[i] = BF_init_state.P[i] ^ tmp; |
229 |
+ expanded[i] = tmp[bug]; |
230 |
+ initial[i] = BF_init_state.P[i] ^ tmp[bug]; |
231 |
} |
232 |
+ |
233 |
+/* |
234 |
+ * At this point, "diff" is zero iff the correct and buggy algorithms produced |
235 |
+ * exactly the same result. If so and if "sign" is non-zero, which indicates |
236 |
+ * that there was a non-benign sign extension, this means that we have a |
237 |
+ * collision between the correctly computed hash for this password and a set of |
238 |
+ * passwords that could be supplied to the buggy algorithm. Our safety measure |
239 |
+ * is meant to protect from such many-buggy to one-correct collisions, by |
240 |
+ * deviating from the correct algorithm in such cases. Let's check for this. |
241 |
+ */ |
242 |
+ diff |= diff >> 16; /* still zero iff exact match */ |
243 |
+ diff &= 0xffff; /* ditto */ |
244 |
+ diff += 0xffff; /* bit 16 set iff "diff" was non-zero (on non-match) */ |
245 |
+ sign <<= 9; /* move the non-benign sign extension flag to bit 16 */ |
246 |
+ sign &= ~diff & safety; /* action needed? */ |
247 |
+ |
248 |
+/* |
249 |
+ * If we have determined that we need to deviate from the correct algorithm, |
250 |
+ * flip bit 16 in initial expanded key. (The choice of 16 is arbitrary, but |
251 |
+ * let's stick to it now. It came out of the approach we used above, and it's |
252 |
+ * not any worse than any other choice we could make.) |
253 |
+ * |
254 |
+ * It is crucial that we don't do the same to the expanded key used in the main |
255 |
+ * Eksblowfish loop. By doing it to only one of these two, we deviate from a |
256 |
+ * state that could be directly specified by a password to the buggy algorithm |
257 |
+ * (and to the fully correct one as well, but that's a side-effect). |
258 |
+ */ |
259 |
+ initial[0] ^= sign; |
260 |
} |
261 |
|
262 |
-char *php_crypt_blowfish_rn(__CONST char *key, __CONST char *setting, |
263 |
- char *output, int size) |
264 |
+static char *BF_crypt(const char *key, const char *setting, |
265 |
+ char *output, int size, |
266 |
+ BF_word min) |
267 |
{ |
268 |
#if BF_ASM |
269 |
extern void _BF_body_r(BF_ctx *ctx); |
270 |
#endif |
271 |
+ static const unsigned char flags_by_subtype[26] = |
272 |
+ {2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
273 |
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 0}; |
274 |
struct { |
275 |
BF_ctx ctx; |
276 |
BF_key expanded_key; |
277 |
@@ -602,7 +677,8 @@ char *php_crypt_blowfish_rn(__CONST char |
278 |
|
279 |
if (setting[0] != '$' || |
280 |
setting[1] != '2' || |
281 |
- setting[2] != 'a' || |
282 |
+ setting[2] < 'a' || setting[2] > 'z' || |
283 |
+ !flags_by_subtype[(unsigned int)(unsigned char)setting[2] - 'a'] || |
284 |
setting[3] != '$' || |
285 |
setting[4] < '0' || setting[4] > '3' || |
286 |
setting[5] < '0' || setting[5] > '9' || |
287 |
@@ -613,15 +689,14 @@ char *php_crypt_blowfish_rn(__CONST char |
288 |
} |
289 |
|
290 |
count = (BF_word)1 << ((setting[4] - '0') * 10 + (setting[5] - '0')); |
291 |
- if (count < 16 || BF_decode(data.binary.salt, &setting[7], 16)) { |
292 |
- clean(data.binary.salt, sizeof(data.binary.salt)); |
293 |
+ if (count < min || BF_decode(data.binary.salt, &setting[7], 16)) { |
294 |
__set_errno(EINVAL); |
295 |
return NULL; |
296 |
} |
297 |
- |
298 |
BF_swap(data.binary.salt, 4); |
299 |
|
300 |
- BF_set_key(key, data.expanded_key, data.ctx.P); |
301 |
+ BF_set_key(key, data.expanded_key, data.ctx.P, |
302 |
+ flags_by_subtype[(unsigned int)(unsigned char)setting[2] - 'a']); |
303 |
|
304 |
memcpy(data.ctx.S, BF_init_state.S, sizeof(data.ctx.S)); |
305 |
|
306 |
@@ -651,51 +726,33 @@ char *php_crypt_blowfish_rn(__CONST char |
307 |
} while (ptr < &data.ctx.S[3][0xFF]); |
308 |
|
309 |
do { |
310 |
- data.ctx.P[0] ^= data.expanded_key[0]; |
311 |
- data.ctx.P[1] ^= data.expanded_key[1]; |
312 |
- data.ctx.P[2] ^= data.expanded_key[2]; |
313 |
- data.ctx.P[3] ^= data.expanded_key[3]; |
314 |
- data.ctx.P[4] ^= data.expanded_key[4]; |
315 |
- data.ctx.P[5] ^= data.expanded_key[5]; |
316 |
- data.ctx.P[6] ^= data.expanded_key[6]; |
317 |
- data.ctx.P[7] ^= data.expanded_key[7]; |
318 |
- data.ctx.P[8] ^= data.expanded_key[8]; |
319 |
- data.ctx.P[9] ^= data.expanded_key[9]; |
320 |
- data.ctx.P[10] ^= data.expanded_key[10]; |
321 |
- data.ctx.P[11] ^= data.expanded_key[11]; |
322 |
- data.ctx.P[12] ^= data.expanded_key[12]; |
323 |
- data.ctx.P[13] ^= data.expanded_key[13]; |
324 |
- data.ctx.P[14] ^= data.expanded_key[14]; |
325 |
- data.ctx.P[15] ^= data.expanded_key[15]; |
326 |
- data.ctx.P[16] ^= data.expanded_key[16]; |
327 |
- data.ctx.P[17] ^= data.expanded_key[17]; |
328 |
- |
329 |
- BF_body(); |
330 |
- |
331 |
- tmp1 = data.binary.salt[0]; |
332 |
- tmp2 = data.binary.salt[1]; |
333 |
- tmp3 = data.binary.salt[2]; |
334 |
- tmp4 = data.binary.salt[3]; |
335 |
- data.ctx.P[0] ^= tmp1; |
336 |
- data.ctx.P[1] ^= tmp2; |
337 |
- data.ctx.P[2] ^= tmp3; |
338 |
- data.ctx.P[3] ^= tmp4; |
339 |
- data.ctx.P[4] ^= tmp1; |
340 |
- data.ctx.P[5] ^= tmp2; |
341 |
- data.ctx.P[6] ^= tmp3; |
342 |
- data.ctx.P[7] ^= tmp4; |
343 |
- data.ctx.P[8] ^= tmp1; |
344 |
- data.ctx.P[9] ^= tmp2; |
345 |
- data.ctx.P[10] ^= tmp3; |
346 |
- data.ctx.P[11] ^= tmp4; |
347 |
- data.ctx.P[12] ^= tmp1; |
348 |
- data.ctx.P[13] ^= tmp2; |
349 |
- data.ctx.P[14] ^= tmp3; |
350 |
- data.ctx.P[15] ^= tmp4; |
351 |
- data.ctx.P[16] ^= tmp1; |
352 |
- data.ctx.P[17] ^= tmp2; |
353 |
+ int done; |
354 |
|
355 |
- BF_body(); |
356 |
+ for (i = 0; i < BF_N + 2; i += 2) { |
357 |
+ data.ctx.P[i] ^= data.expanded_key[i]; |
358 |
+ data.ctx.P[i + 1] ^= data.expanded_key[i + 1]; |
359 |
+ } |
360 |
+ |
361 |
+ done = 0; |
362 |
+ do { |
363 |
+ BF_body(); |
364 |
+ if (done) |
365 |
+ break; |
366 |
+ done = 1; |
367 |
+ |
368 |
+ tmp1 = data.binary.salt[0]; |
369 |
+ tmp2 = data.binary.salt[1]; |
370 |
+ tmp3 = data.binary.salt[2]; |
371 |
+ tmp4 = data.binary.salt[3]; |
372 |
+ for (i = 0; i < BF_N; i += 4) { |
373 |
+ data.ctx.P[i] ^= tmp1; |
374 |
+ data.ctx.P[i + 1] ^= tmp2; |
375 |
+ data.ctx.P[i + 2] ^= tmp3; |
376 |
+ data.ctx.P[i + 3] ^= tmp4; |
377 |
+ } |
378 |
+ data.ctx.P[16] ^= tmp1; |
379 |
+ data.ctx.P[17] ^= tmp2; |
380 |
+ } while (1); |
381 |
} while (--count); |
382 |
|
383 |
for (i = 0; i < 6; i += 2) { |
384 |
@@ -721,19 +778,114 @@ char *php_crypt_blowfish_rn(__CONST char |
385 |
BF_encode(&output[7 + 22], data.binary.output, 23); |
386 |
output[7 + 22 + 31] = '\0'; |
387 |
|
388 |
-/* Overwrite the most obvious sensitive data we have on the stack. Note |
389 |
- * that this does not guarantee there's no sensitive data left on the |
390 |
- * stack and/or in registers; I'm not aware of portable code that does. */ |
391 |
- clean(&data, sizeof(data)); |
392 |
- |
393 |
return output; |
394 |
} |
395 |
|
396 |
-char *php_crypt_gensalt_blowfish_rn(unsigned long count, |
397 |
- __CONST char *input, int size, char *output, int output_size) |
398 |
+static int _crypt_output_magic(const char *setting, char *output, int size) |
399 |
+{ |
400 |
+ if (size < 3) |
401 |
+ return -1; |
402 |
+ |
403 |
+ output[0] = '*'; |
404 |
+ output[1] = '0'; |
405 |
+ output[2] = '\0'; |
406 |
+ |
407 |
+ if (setting[0] == '*' && setting[1] == '0') |
408 |
+ output[1] = '1'; |
409 |
+ |
410 |
+ return 0; |
411 |
+} |
412 |
+ |
413 |
+/* |
414 |
+ * Please preserve the runtime self-test. It serves two purposes at once: |
415 |
+ * |
416 |
+ * 1. We really can't afford the risk of producing incompatible hashes e.g. |
417 |
+ * when there's something like gcc bug 26587 again, whereas an application or |
418 |
+ * library integrating this code might not also integrate our external tests or |
419 |
+ * it might not run them after every build. Even if it does, the miscompile |
420 |
+ * might only occur on the production build, but not on a testing build (such |
421 |
+ * as because of different optimization settings). It is painful to recover |
422 |
+ * from incorrectly-computed hashes - merely fixing whatever broke is not |
423 |
+ * enough. Thus, a proactive measure like this self-test is needed. |
424 |
+ * |
425 |
+ * 2. We don't want to leave sensitive data from our actual password hash |
426 |
+ * computation on the stack or in registers. Previous revisions of the code |
427 |
+ * would do explicit cleanups, but simply running the self-test after hash |
428 |
+ * computation is more reliable. |
429 |
+ * |
430 |
+ * The performance cost of this quick self-test is around 0.6% at the "$2a$08" |
431 |
+ * setting. |
432 |
+ */ |
433 |
+char *php_crypt_blowfish_rn(const char *key, const char *setting, |
434 |
+ char *output, int size) |
435 |
+{ |
436 |
+ const char *test_key = "8b \xd0\xc1\xd2\xcf\xcc\xd8"; |
437 |
+ const char *test_setting = "$2a$00$abcdefghijklmnopqrstuu"; |
438 |
+ static const char * const test_hash[2] = |
439 |
+ {"VUrPmXD6q/nVSSp7pNDhCR9071IfIRe\0\x55", /* $2x$ */ |
440 |
+ "i1D709vfamulimlGcq0qq3UvuUasvEa\0\x55"}; /* $2a$, $2y$ */ |
441 |
+ char *retval; |
442 |
+ const char *p; |
443 |
+ int save_errno, ok; |
444 |
+ struct { |
445 |
+ char s[7 + 22 + 1]; |
446 |
+ char o[7 + 22 + 31 + 1 + 1 + 1]; |
447 |
+ } buf; |
448 |
+ |
449 |
+/* Hash the supplied password */ |
450 |
+ _crypt_output_magic(setting, output, size); |
451 |
+ retval = BF_crypt(key, setting, output, size, 16); |
452 |
+ save_errno = errno; |
453 |
+ |
454 |
+/* |
455 |
+ * Do a quick self-test. It is important that we make both calls to BF_crypt() |
456 |
+ * from the same scope such that they likely use the same stack locations, |
457 |
+ * which makes the second call overwrite the first call's sensitive data on the |
458 |
+ * stack and makes it more likely that any alignment related issues would be |
459 |
+ * detected by the self-test. |
460 |
+ */ |
461 |
+ memcpy(buf.s, test_setting, sizeof(buf.s)); |
462 |
+ if (retval) |
463 |
+ buf.s[2] = setting[2]; |
464 |
+ memset(buf.o, 0x55, sizeof(buf.o)); |
465 |
+ buf.o[sizeof(buf.o) - 1] = 0; |
466 |
+ p = BF_crypt(test_key, buf.s, buf.o, sizeof(buf.o) - (1 + 1), 1); |
467 |
+ |
468 |
+ ok = (p == buf.o && |
469 |
+ !memcmp(p, buf.s, 7 + 22) && |
470 |
+ !memcmp(p + (7 + 22), |
471 |
+ test_hash[(unsigned int)(unsigned char)buf.s[2] & 1], |
472 |
+ 31 + 1 + 1 + 1)); |
473 |
+ |
474 |
+ { |
475 |
+ const char *k = "\xff\xa3" "34" "\xff\xff\xff\xa3" "345"; |
476 |
+ BF_key ae, ai, ye, yi; |
477 |
+ BF_set_key(k, ae, ai, 2); /* $2a$ */ |
478 |
+ BF_set_key(k, ye, yi, 4); /* $2y$ */ |
479 |
+ ai[0] ^= 0x10000; /* undo the safety (for comparison) */ |
480 |
+ ok = ok && ai[0] == 0xdb9c59bc && ye[17] == 0x33343500 && |
481 |
+ !memcmp(ae, ye, sizeof(ae)) && |
482 |
+ !memcmp(ai, yi, sizeof(ai)); |
483 |
+ } |
484 |
+ |
485 |
+ __set_errno(save_errno); |
486 |
+ if (ok) |
487 |
+ return retval; |
488 |
+ |
489 |
+/* Should not happen */ |
490 |
+ _crypt_output_magic(setting, output, size); |
491 |
+ __set_errno(EINVAL); /* pretend we don't support this hash type */ |
492 |
+ return NULL; |
493 |
+} |
494 |
+ |
495 |
+#if 0 |
496 |
+char *_crypt_gensalt_blowfish_rn(const char *prefix, unsigned long count, |
497 |
+ const char *input, int size, char *output, int output_size) |
498 |
{ |
499 |
if (size < 16 || output_size < 7 + 22 + 1 || |
500 |
- (count && (count < 4 || count > 31))) { |
501 |
+ (count && (count < 4 || count > 31)) || |
502 |
+ prefix[0] != '$' || prefix[1] != '2' || |
503 |
+ (prefix[2] != 'a' && prefix[2] != 'y')) { |
504 |
if (output_size > 0) output[0] = '\0'; |
505 |
__set_errno((output_size < 7 + 22 + 1) ? ERANGE : EINVAL); |
506 |
return NULL; |
507 |
@@ -743,14 +895,15 @@ char *php_crypt_gensalt_blowfish_rn(unsi |
508 |
|
509 |
output[0] = '$'; |
510 |
output[1] = '2'; |
511 |
- output[2] = 'a'; |
512 |
+ output[2] = prefix[2]; |
513 |
output[3] = '$'; |
514 |
output[4] = '0' + count / 10; |
515 |
output[5] = '0' + count % 10; |
516 |
output[6] = '$'; |
517 |
|
518 |
- BF_encode(&output[7], (BF_word *)input, 16); |
519 |
+ BF_encode(&output[7], (const BF_word *)input, 16); |
520 |
output[7 + 22] = '\0'; |
521 |
|
522 |
return output; |
523 |
} |
524 |
+#endif |
525 |
--- php-5.3.3/ext/standard/crypt_blowfish.h.cve2483 |
526 |
+++ php-5.3.3/ext/standard/crypt_blowfish.h |
527 |
@@ -0,0 +1,32 @@ |
528 |
+/* $Id$ */ |
529 |
+/* |
530 |
+ * Written by Solar Designer <solar at openwall.com> in 2000-2011. |
531 |
+ * No copyright is claimed, and the software is hereby placed in the public |
532 |
+ * domain. In case this attempt to disclaim copyright and place the software |
533 |
+ * in the public domain is deemed null and void, then the software is |
534 |
+ * Copyright (c) 2000-2011 Solar Designer and it is hereby released to the |
535 |
+ * general public under the following terms: |
536 |
+ * |
537 |
+ * Redistribution and use in source and binary forms, with or without |
538 |
+ * modification, are permitted. |
539 |
+ * |
540 |
+ * There's ABSOLUTELY NO WARRANTY, express or implied. |
541 |
+ * |
542 |
+ * See crypt_blowfish.c for more information. |
543 |
+ */ |
544 |
+ |
545 |
+#ifndef _CRYPT_BLOWFISH_H |
546 |
+#define _CRYPT_BLOWFISH_H |
547 |
+ |
548 |
+#if 0 |
549 |
+extern int _crypt_output_magic(const char *setting, char *output, int size); |
550 |
+#endif |
551 |
+extern char *php_crypt_blowfish_rn(const char *key, const char *setting, |
552 |
+ char *output, int size); |
553 |
+#if 0 |
554 |
+extern char *_crypt_gensalt_blowfish_rn(const char *prefix, |
555 |
+ unsigned long count, |
556 |
+ const char *input, int size, char *output, int output_size); |
557 |
+#endif |
558 |
+ |
559 |
+#endif |
560 |
--- php-5.3.3/ext/standard/crypt.c.cve2483 |
561 |
+++ php-5.3.3/ext/standard/crypt.c |
562 |
@@ -240,7 +240,7 @@ PHP_FUNCTION(crypt) |
563 |
} else if ( |
564 |
salt[0] == '$' && |
565 |
salt[1] == '2' && |
566 |
- salt[2] == 'a' && |
567 |
+ salt[2] >= 'a' && salt[2] <= 'z' && |
568 |
salt[3] == '$' && |
569 |
salt[4] >= '0' && salt[4] <= '3' && |
570 |
salt[5] >= '0' && salt[5] <= '9' && |
571 |
--- php-5.3.3/ext/standard/php_crypt_r.h.cve2483 |
572 |
+++ php-5.3.3/ext/standard/php_crypt_r.h |
573 |
@@ -46,9 +46,9 @@ PHPAPI char *php_crypt_r (const char *__ |
574 |
|
575 |
#define MD5_HASH_MAX_LEN 120 |
576 |
|
577 |
+#include "crypt_blowfish.h" |
578 |
+ |
579 |
extern char * php_md5_crypt_r(const char *pw, const char *salt, char *out); |
580 |
-extern char * php_crypt_blowfish_rn(__CONST char *key, __CONST char *setting, |
581 |
- char *output, int size); |
582 |
extern char * php_sha512_crypt_r (const char *key, const char *salt, char *buffer, int buflen); |
583 |
extern char * php_sha256_crypt_r (const char *key, const char *salt, char *buffer, int buflen); |
584 |
|