Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1294)

Side by Side Diff: mozilla/security/nss/lib/freebl/arcfour.c

Issue 12226071: Fix RC4 reads/writes outside array bounds. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/deps/third_party/nss/
Patch Set: Enable the code for Windows, fix compilation errors Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* arcfour.c - the arc four algorithm. 1 /* arcfour.c - the arc four algorithm.
2 * 2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public 3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 6
7 /* See NOTES ON UMRs, Unititialized Memory Reads, below. */
8
9 #ifdef FREEBL_NO_DEPEND 7 #ifdef FREEBL_NO_DEPEND
10 #include "stubs.h" 8 #include "stubs.h"
11 #endif 9 #endif
12 10
13 #include "prerr.h" 11 #include "prerr.h"
14 #include "secerr.h" 12 #include "secerr.h"
15 13
16 #include "prtypes.h" 14 #include "prtypes.h"
17 #include "blapi.h" 15 #include "blapi.h"
18 16
19 /* Architecture-dependent defines */ 17 /* Architecture-dependent defines */
20 18
21 #if defined(SOLARIS) || defined(HPUX) || defined(i386) || defined(IRIX) || \ 19 #if defined(SOLARIS) || defined(HPUX) || defined(NSS_X86) || \
22 defined(_WIN64) 20 defined(_WIN64)
23 /* Convert the byte-stream to a word-stream */ 21 /* Convert the byte-stream to a word-stream */
24 #define CONVERT_TO_WORDS 22 #define CONVERT_TO_WORDS
25 #endif 23 #endif
26 24
27 #if defined(AIX) || defined(OSF1) || defined(NSS_BEVAND_ARCFOUR) 25 #if defined(AIX) || defined(OSF1) || defined(NSS_BEVAND_ARCFOUR)
28 /* Treat array variables as words, not bytes, on CPUs that take 26 /* Treat array variables as words, not bytes, on CPUs that take
29 * much longer to write bytes than to write words, or when using 27 * much longer to write bytes than to write words, or when using
30 * assembler code that required it. 28 * assembler code that required it.
31 */ 29 */
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
112 RC4_AllocateContext(void) 110 RC4_AllocateContext(void)
113 { 111 {
114 return PORT_ZNew(RC4Context); 112 return PORT_ZNew(RC4Context);
115 } 113 }
116 114
117 SECStatus 115 SECStatus
118 RC4_InitContext(RC4Context *cx, const unsigned char *key, unsigned int len, 116 RC4_InitContext(RC4Context *cx, const unsigned char *key, unsigned int len,
119 const unsigned char * unused1, int unused2, 117 const unsigned char * unused1, int unused2,
120 unsigned int unused3, unsigned int unused4) 118 unsigned int unused3, unsigned int unused4)
121 { 119 {
122 » int i; 120 » unsigned int i;
123 PRUint8 j, tmp; 121 PRUint8 j, tmp;
124 PRUint8 K[256]; 122 PRUint8 K[256];
125 PRUint8 *L; 123 PRUint8 *L;
126 124
127 /* verify the key length. */ 125 /* verify the key length. */
128 PORT_Assert(len > 0 && len < ARCFOUR_STATE_SIZE); 126 PORT_Assert(len > 0 && len < ARCFOUR_STATE_SIZE);
129 if (len == 0 || len >= ARCFOUR_STATE_SIZE) { 127 if (len == 0 || len >= ARCFOUR_STATE_SIZE) {
130 PORT_SetError(SEC_ERROR_INVALID_ARGS); 128 PORT_SetError(SEC_ERROR_INVALID_ARGS);
131 return SECFailure; 129 return SECFailure;
132 } 130 }
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after
343 341
344 #ifdef IS_LITTLE_ENDIAN 342 #ifdef IS_LITTLE_ENDIAN
345 #define RSH << 343 #define RSH <<
346 #define LSH >> 344 #define LSH >>
347 #else 345 #else
348 #define RSH >> 346 #define RSH >>
349 #define LSH << 347 #define LSH <<
350 #endif 348 #endif
351 349
352 #ifdef CONVERT_TO_WORDS 350 #ifdef CONVERT_TO_WORDS
353 /* NOTE about UMRs, Uninitialized Memory Reads.
354 *
355 * This code reads all input data a WORD at a time, rather than byte at
356 * a time, and writes all output data a WORD at a time. Shifting and
357 * masking is used to remove unwanted data and realign bytes when
358 * needed. The first and last words of output are read, modified, and
359 * written when needed to preserve any unchanged bytes. This is a huge
360 * win on machines with high memory latency.
361 *
362 * However, when the input and output buffers do not begin and end on WORD
363 * boundaries, and the WORDS in memory that contain the first and last
364 * bytes of those buffers contain uninitialized data, then this code will
365 * read those uninitialized bytes, causing a UMR error to be reported by
366 * some tools.
367 *
368 * These UMRs are NOT a problem, NOT errors, and do NOT need to be "fixed".
369 *
370 * All the words read and written contain at least one byte that is
371 * part of the input data or output data. No words are read or written
372 * that do not contain data that is part of the buffer. Therefore,
373 * these UMRs cannot cause page faults or other problems unless the
374 * buffers have been assigned to improper addresses that would cause
375 * page faults with or without UMRs.
376 */
377 static SECStatus 351 static SECStatus
378 rc4_wordconv(RC4Context *cx, unsigned char *output, 352 rc4_wordconv(RC4Context *cx, unsigned char *output,
379 unsigned int *outputLen, unsigned int maxOutputLen, 353 unsigned int *outputLen, unsigned int maxOutputLen,
380 const unsigned char *input, unsigned int inputLen) 354 const unsigned char *input, unsigned int inputLen)
381 { 355 {
382 ptrdiff_t inOffset = (ptrdiff_t)input % WORDSIZE; 356 ptrdiff_t inOffset = (ptrdiff_t)input % WORDSIZE;
383 ptrdiff_t outOffset = (ptrdiff_t)output % WORDSIZE; 357 ptrdiff_t outOffset = (ptrdiff_t)output % WORDSIZE;
384 » register WORD streamWord, mask; 358 » register WORD streamWord;
385 » register WORD *pInWord, *pOutWord; 359 » const register WORD *pInWord;
386 » register WORD inWord, nextInWord; 360 » register WORD *pOutWord;
361 » WORD inWord;
362 » register WORD nextInWord;
387 PRUint8 t; 363 PRUint8 t;
388 register Stype tmpSi, tmpSj; 364 register Stype tmpSi, tmpSj;
389 register PRUint8 tmpi = cx->i; 365 register PRUint8 tmpi = cx->i;
390 register PRUint8 tmpj = cx->j; 366 register PRUint8 tmpj = cx->j;
391 unsigned int byteCount; 367 unsigned int byteCount;
392 unsigned int bufShift, invBufShift; 368 unsigned int bufShift, invBufShift;
393 » int i; 369 » unsigned int i;
370 » const unsigned char *finalIn;
371 » unsigned char *finalOut;
394 372
395 PORT_Assert(maxOutputLen >= inputLen); 373 PORT_Assert(maxOutputLen >= inputLen);
396 if (maxOutputLen < inputLen) { 374 if (maxOutputLen < inputLen) {
397 PORT_SetError(SEC_ERROR_INVALID_ARGS); 375 PORT_SetError(SEC_ERROR_INVALID_ARGS);
Ryan Sleevi 2013/02/08 19:32:47 aside: Why not SEC_ERROR_OUTPUT_LEN?
wtc 2013/02/09 01:38:25 Good idea. I will make this change. In my debuggi
398 return SECFailure; 376 return SECFailure;
399 } 377 }
400 if (inputLen < 2*WORDSIZE) { 378 if (inputLen < 2*WORDSIZE) {
401 /* Ignore word conversion, do byte-at-a-time */ 379 /* Ignore word conversion, do byte-at-a-time */
402 return rc4_no_opt(cx, output, outputLen, maxOutputLen, input, in putLen); 380 return rc4_no_opt(cx, output, outputLen, maxOutputLen, input, in putLen);
403 } 381 }
404 *outputLen = inputLen; 382 *outputLen = inputLen;
405 » pInWord = (WORD *)(input - inOffset); 383 » pInWord = (const WORD *)(input - inOffset);
384 » pOutWord = (WORD *)(output - outOffset);
406 if (inOffset < outOffset) { 385 if (inOffset < outOffset) {
407 bufShift = 8*(outOffset - inOffset); 386 bufShift = 8*(outOffset - inOffset);
408 invBufShift = 8*WORDSIZE - bufShift; 387 invBufShift = 8*WORDSIZE - bufShift;
409 } else { 388 } else {
410 invBufShift = 8*(inOffset - outOffset); 389 invBufShift = 8*(inOffset - outOffset);
411 bufShift = 8*WORDSIZE - invBufShift; 390 bufShift = 8*WORDSIZE - invBufShift;
412 } 391 }
413 /*****************************************************************/ 392 /*****************************************************************/
414 /* Step 1: */ 393 /* Step 1: */
415 /* If the first output word is partial, consume the bytes in the */ 394 /* If the first output word is partial, consume the bytes in the */
416 /* first partial output word by loading one or two words of */ 395 /* first partial output word by loading one or two words of */
417 /* input and shifting them accordingly. Otherwise, just load */ 396 /* input and shifting them accordingly. Otherwise, just load */
418 /* in the first word of input. At the end of this block, at */ 397 /* in the first word of input. At the end of this block, at */
419 /* least one partial word of input should ALWAYS be loaded. */ 398 /* least one partial word of input should ALWAYS be loaded. */
420 /*****************************************************************/ 399 /*****************************************************************/
421 if (outOffset) { 400 if (outOffset) {
422 /* Generate input and stream words aligned relative to the
423 * partial output buffer.
424 */
425 byteCount = WORDSIZE - outOffset; 401 byteCount = WORDSIZE - outOffset;
426 » » pOutWord = (WORD *)(output - outOffset); 402 » » for (i = 0; i < byteCount; i++) {
427 » » mask = streamWord = 0;
428 #ifdef IS_LITTLE_ENDIAN
429 » » for (i = WORDSIZE - byteCount; i < WORDSIZE; i++) {
430 #else
431 » » for (i = byteCount - 1; i >= 0; --i) {
432 #endif
433 ARCFOUR_NEXT_BYTE(); 403 ARCFOUR_NEXT_BYTE();
434 » » » streamWord |= (WORD)(cx->S[t]) << 8*i; 404 » » » output[i] = cx->S[t] ^ input[i];
435 » » » mask |= MASK1BYTE << 8*i; 405 » » }
436 » » } /* } */ 406 » » /* Consumed byteCount bytes of input */
437 » » inWord = *pInWord++; /* UMR? see comments above. */ 407 » » inputLen -= byteCount;
408 » » pInWord++;
Ryan Sleevi 2013/02/08 19:32:47 aside: Why not pre-increment, since you're no long
wtc 2013/02/09 01:38:25 Post-increment is more common in C. (I guess this
409
410 » » /* move to next word of output */
411 » » pOutWord++;
412
438 /* If buffers are relatively misaligned, shift the bytes in inWo rd 413 /* If buffers are relatively misaligned, shift the bytes in inWo rd
439 * to be aligned to the output buffer. 414 * to be aligned to the output buffer.
440 */ 415 */
441 nextInWord = 0;
442 if (inOffset < outOffset) { 416 if (inOffset < outOffset) {
443 » » » /* Have more bytes than needed, shift remainder into nex tInWord */ 417 » » » /* The first input word (which may be partial) has more bytes
444 » » » nextInWord = inWord LSH 8*(inOffset + byteCount); 418 » » » * than needed. Copy the remainder to inWord.
445 » » » inWord = inWord RSH bufShift; 419 » » » */
420 » » » inWord = 0;
421 » » » memcpy(&inWord, &input[byteCount], outOffset - inOffset) ;
446 } else if (inOffset > outOffset) { 422 } else if (inOffset > outOffset) {
447 » » » /* Didn't get enough bytes from current input word, load another 423 » » » /* Consumed some bytes in the second input word. Copy t he
448 » » » * word and then shift remainder into nextInWord. 424 » » » * remainder to inWord.
449 */ 425 */
450 » » » nextInWord = *pInWord++; 426 » » » inWord = *pInWord++;
451 » » » inWord = (inWord LSH invBufShift) | 427 » » » inWord = inWord LSH invBufShift;
452 » » » (nextInWord RSH bufShift);
453 » » » nextInWord = nextInWord LSH invBufShift;
454 } 428 }
455 /* Store output of first partial word */
456 *pOutWord = (*pOutWord & ~mask) | ((inWord ^ streamWord) & mask) ;
457 /* UMR? See comments above. */
458
459 /* Consumed byteCount bytes of input */
460 inputLen -= byteCount;
461 /* move to next word of output */
462 pOutWord++;
463 /* inWord has been consumed, but there may be bytes in nextInWor d */
464 inWord = nextInWord;
465 } else { 429 } else {
466 /* output is word-aligned */ 430 /* output is word-aligned */
467 pOutWord = (WORD *)output;
468 if (inOffset) { 431 if (inOffset) {
469 /* Input is not word-aligned. The first word load of in put 432 /* Input is not word-aligned. The first word load of in put
470 * will not produce a full word of input bytes, so one w ord 433 * will not produce a full word of input bytes, so one w ord
471 * must be pre-loaded. The main loop below will load in the 434 * must be pre-loaded. The main loop below will load in the
472 * next input word and shift some of its bytes into inWo rd 435 * next input word and shift some of its bytes into inWo rd
473 * in order to create a full input word. Note that the main 436 * in order to create a full input word. Note that the main
474 * loop must execute at least once because the input mus t 437 * loop must execute at least once because the input mus t
475 * be at least two words. 438 * be at least two words.
476 */ 439 */
477 » » » inWord = *pInWord++; /* UMR? see comments above. */ 440 » » » inWord = 0;
478 » » » inWord = inWord LSH invBufShift; 441 » » » memcpy(&inWord, &input[0], WORDSIZE - inOffset);
442 » » » pInWord++;
479 } else { 443 } else {
480 /* Input is word-aligned. The first word load of input 444 /* Input is word-aligned. The first word load of input
481 * will produce a full word of input bytes, so nothing 445 * will produce a full word of input bytes, so nothing
482 * needs to be loaded here. 446 * needs to be loaded here.
483 */ 447 */
484 inWord = 0; 448 inWord = 0;
485 } 449 }
486 } 450 }
487 /* Output buffer is aligned, inOffset is now measured relative to 451 /* Output buffer is aligned, inOffset is now measured relative to
488 * outOffset (and not a word boundary). 452 * outOffset (and not a word boundary).
(...skipping 14 matching lines...) Expand all
503 ARCFOUR_NEXT_WORD(); 467 ARCFOUR_NEXT_WORD();
504 *pOutWord++ = inWord ^ streamWord; 468 *pOutWord++ = inWord ^ streamWord;
505 inWord = nextInWord; 469 inWord = nextInWord;
506 } 470 }
507 if (inputLen == 0) { 471 if (inputLen == 0) {
508 /* Nothing left to do. */ 472 /* Nothing left to do. */
509 cx->i = tmpi; 473 cx->i = tmpi;
510 cx->j = tmpj; 474 cx->j = tmpj;
511 return SECSuccess; 475 return SECSuccess;
512 } 476 }
513 » » /* If the amount of remaining input is greater than the amount 477 » » finalIn = (const unsigned char *)pInWord - WORDSIZE + inOffset;
514 » » * bytes pulled from the current input word, need to do another
515 » » * word load. What's left in inWord will be consumed in step 3.
516 » » */
517 » » if (inputLen > WORDSIZE - inOffset)
518 » » » inWord |= *pInWord RSH bufShift; /* UMR? See above. */
519 } else { 478 } else {
520 for (; inputLen >= WORDSIZE; inputLen -= WORDSIZE) { 479 for (; inputLen >= WORDSIZE; inputLen -= WORDSIZE) {
521 inWord = *pInWord++; 480 inWord = *pInWord++;
522 ARCFOUR_NEXT_WORD(); 481 ARCFOUR_NEXT_WORD();
523 *pOutWord++ = inWord ^ streamWord; 482 *pOutWord++ = inWord ^ streamWord;
524 } 483 }
525 if (inputLen == 0) { 484 if (inputLen == 0) {
526 /* Nothing left to do. */ 485 /* Nothing left to do. */
527 cx->i = tmpi; 486 cx->i = tmpi;
528 cx->j = tmpj; 487 cx->j = tmpj;
529 return SECSuccess; 488 return SECSuccess;
530 } else {
531 /* A partial input word remains at the tail. Load it.
532 * The relevant bytes will be consumed in step 3.
533 */
534 inWord = *pInWord; /* UMR? See comments above */
535 } 489 }
490 finalIn = (const unsigned char *)pInWord;
536 } 491 }
537 /*****************************************************************/ 492 /*****************************************************************/
538 /* Step 3: */ 493 /* Step 3: */
539 » /* A partial word of input remains, and it is already loaded */ 494 » /* Do the remaining partial word of input one byte at a time. */
540 » /* into nextInWord. Shift appropriately and consume the bytes */
541 » /* used in the partial word. */
542 /*****************************************************************/ 495 /*****************************************************************/
543 » mask = streamWord = 0; 496 » finalOut = (unsigned char *)pOutWord;
544 #ifdef IS_LITTLE_ENDIAN 497 » for (i = 0; i < inputLen; i++) {
545 » for (i = 0; i < inputLen; ++i) {
546 #else
547 » for (i = WORDSIZE - 1; i >= WORDSIZE - inputLen; --i) {
548 #endif
549 ARCFOUR_NEXT_BYTE(); 498 ARCFOUR_NEXT_BYTE();
550 » » streamWord |= (WORD)(cx->S[t]) << 8*i; 499 » » finalOut[i] = cx->S[t] ^ finalIn[i];
551 » » mask |= MASK1BYTE << 8*i; 500 » }
552 » } /* } */
553 » /* UMR? See comments above. */
554 » *pOutWord = (*pOutWord & ~mask) | ((inWord ^ streamWord) & mask);
555 cx->i = tmpi; 501 cx->i = tmpi;
556 cx->j = tmpj; 502 cx->j = tmpj;
557 return SECSuccess; 503 return SECSuccess;
558 } 504 }
559 #endif 505 #endif
560 #endif /* NSS_BEVAND_ARCFOUR */ 506 #endif /* NSS_BEVAND_ARCFOUR */
561 507
562 SECStatus 508 SECStatus
563 RC4_Encrypt(RC4Context *cx, unsigned char *output, 509 RC4_Encrypt(RC4Context *cx, unsigned char *output,
564 unsigned int *outputLen, unsigned int maxOutputLen, 510 unsigned int *outputLen, unsigned int maxOutputLen,
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
600 /* Convert the byte-stream to a word-stream */ 546 /* Convert the byte-stream to a word-stream */
601 return rc4_wordconv(cx, output, outputLen, maxOutputLen, input, inputLen ); 547 return rc4_wordconv(cx, output, outputLen, maxOutputLen, input, inputLen );
602 #else 548 #else
603 /* Operate on bytes, but unroll the main loop */ 549 /* Operate on bytes, but unroll the main loop */
604 return rc4_unrolled(cx, output, outputLen, maxOutputLen, input, inputLen ); 550 return rc4_unrolled(cx, output, outputLen, maxOutputLen, input, inputLen );
605 #endif 551 #endif
606 } 552 }
607 553
608 #undef CONVERT_TO_WORDS 554 #undef CONVERT_TO_WORDS
609 #undef USE_WORD 555 #undef USE_WORD
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698