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

Side by Side Diff: mozilla/security/nss/lib/util/nssb64e.c

Issue 14249009: Change the NSS and NSPR source tree to the new directory structure to be (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/deps/third_party/nss/
Patch Set: Created 7 years, 8 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 | « mozilla/security/nss/lib/util/nssb64d.c ('k') | mozilla/security/nss/lib/util/nssb64t.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 /*
6 * Base64 encoding (binary to ascii).
7 *
8 * $Id: nssb64e.c,v 1.4 2012/04/25 14:50:16 gerv%gerv.net Exp $
9 */
10
11 #include "nssb64.h"
12 #include "nspr.h"
13 #include "secitem.h"
14 #include "secerr.h"
15
16 /*
17 * XXX See the big comment at the top of nssb64d.c about moving the
18 * bulk of this code over into NSPR (the PL part). It all applies
19 * here but I didn't want to duplicate it, to avoid divergence problems.
20 */
21
22 /*
23 **************************************************************
24 * XXX Beginning of base64 encoding code to be moved into NSPR.
25 */
26
27
28 struct PLBase64EncodeStateStr {
29 unsigned chunks;
30 unsigned saved;
31 unsigned char buf[3];
32 };
33
34 /*
35 * This typedef would belong in the NSPR header file (i.e. plbase64.h).
36 */
37 typedef struct PLBase64EncoderStr PLBase64Encoder;
38
39 /*
40 * The following implementation of base64 encoding was based on code
41 * found in libmime (specifically, in mimeenc.c). It has been adapted to
42 * use PR types and naming as well as to provide other necessary semantics
43 * (like buffer-in/buffer-out in addition to "streaming" without undue
44 * performance hit of extra copying if you made the buffer versions
45 * use the output_fn). It also incorporates some aspects of the current
46 * NSPR base64 encoding code. As such, you may find similarities to
47 * both of those implementations. I tried to use names that reflected
48 * the original code when possible. For this reason you may find some
49 * inconsistencies -- libmime used lots of "in" and "out" whereas the
50 * NSPR version uses "src" and "dest"; sometimes I changed one to the other
51 * and sometimes I left them when I thought the subroutines were at least
52 * self-consistent.
53 */
54
55 PR_BEGIN_EXTERN_C
56
57 /*
58 * Opaque object used by the encoder to store state.
59 */
60 struct PLBase64EncoderStr {
61 /*
62 * The one or two bytes pending. (We need 3 to create a "token",
63 * and hold the leftovers here. in_buffer_count is *only* ever
64 * 0, 1, or 2.
65 */
66 unsigned char in_buffer[2];
67 int in_buffer_count;
68
69 /*
70 * If the caller wants linebreaks added, line_length specifies
71 * where they come out. It must be a multiple of 4; if the caller
72 * provides one that isn't, we round it down to the nearest
73 * multiple of 4.
74 *
75 * The value of current_column counts how many characters have been
76 * added since the last linebreaks (or since the beginning, on the
77 * first line). It is also always a multiple of 4; it is unused when
78 * line_length is 0.
79 */
80 PRUint32 line_length;
81 PRUint32 current_column;
82
83 /*
84 * Where to write the encoded data (used when streaming, not when
85 * doing all in-memory (buffer) operations).
86 *
87 * Note that this definition is chosen to be compatible with PR_Write.
88 */
89 PRInt32 (*output_fn) (void *output_arg, const char *buf, PRInt32 size);
90 void *output_arg;
91
92 /*
93 * Where the encoded output goes -- either temporarily (in the streaming
94 * case, staged here before it goes to the output function) or what will
95 * be the entire buffered result for users of the buffer version.
96 */
97 char *output_buffer;
98 PRUint32 output_buflen; /* the total length of allocated buffer */
99 PRUint32 output_length; /* the length that is currently populated */
100 };
101
102 PR_END_EXTERN_C
103
104
105 /*
106 * Table to convert a binary value to its corresponding ascii "code".
107 */
108 static unsigned char base64_valuetocode[64] =
109 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
110
111 #define B64_PAD '='
112 #define B64_CR '\r'
113 #define B64_LF '\n'
114
115 static PRStatus
116 pl_base64_encode_buffer (PLBase64Encoder *data, const unsigned char *in,
117 PRUint32 size)
118 {
119 const unsigned char *end = in + size;
120 char *out = data->output_buffer + data->output_length;
121 unsigned int i = data->in_buffer_count;
122 PRUint32 n = 0;
123 int off;
124 PRUint32 output_threshold;
125
126 /* If this input buffer is too small, wait until next time. */
127 if (size < (3 - i)) {
128 data->in_buffer[i++] = in[0];
129 if (size > 1)
130 data->in_buffer[i++] = in[1];
131 PR_ASSERT(i < 3);
132 data->in_buffer_count = i;
133 return PR_SUCCESS;
134 }
135
136 /* If there are bytes that were put back last time, take them now. */
137 if (i > 0) {
138 n = data->in_buffer[0];
139 if (i > 1)
140 n = (n << 8) | data->in_buffer[1];
141 data->in_buffer_count = 0;
142 }
143
144 /* If our total is not a multiple of three, put one or two bytes back. */
145 off = (size + i) % 3;
146 if (off > 0) {
147 size -= off;
148 data->in_buffer[0] = in[size];
149 if (off > 1)
150 data->in_buffer[1] = in[size + 1];
151 data->in_buffer_count = off;
152 end -= off;
153 }
154
155 output_threshold = data->output_buflen - 3;
156
157 /*
158 * Populate the output buffer with base64 data, one line (or buffer)
159 * at a time.
160 */
161 while (in < end) {
162 int j, k;
163
164 while (i < 3) {
165 n = (n << 8) | *in++;
166 i++;
167 }
168 i = 0;
169
170 if (data->line_length > 0) {
171 if (data->current_column >= data->line_length) {
172 data->current_column = 0;
173 *out++ = B64_CR;
174 *out++ = B64_LF;
175 data->output_length += 2;
176 }
177 data->current_column += 4; /* the bytes we are about to add */
178 }
179
180 for (j = 18; j >= 0; j -= 6) {
181 k = (n >> j) & 0x3F;
182 *out++ = base64_valuetocode[k];
183 }
184 n = 0;
185 data->output_length += 4;
186
187 if (data->output_length >= output_threshold) {
188 PR_ASSERT(data->output_length <= data->output_buflen);
189 if (data->output_fn != NULL) {
190 PRInt32 output_result;
191
192 output_result = data->output_fn (data->output_arg,
193 data->output_buffer,
194 (PRInt32) data->output_length);
195 if (output_result < 0)
196 return PR_FAILURE;
197
198 out = data->output_buffer;
199 data->output_length = 0;
200 } else {
201 /*
202 * Check that we are about to exit the loop. (Since we
203 * are over the threshold, there isn't enough room in the
204 * output buffer for another trip around.)
205 */
206 PR_ASSERT(in == end);
207 if (in < end) {
208 PR_SetError (PR_BUFFER_OVERFLOW_ERROR, 0);
209 return PR_FAILURE;
210 }
211 }
212 }
213 }
214
215 return PR_SUCCESS;
216 }
217
218 static PRStatus
219 pl_base64_encode_flush (PLBase64Encoder *data)
220 {
221 int i = data->in_buffer_count;
222
223 if (i == 0 && data->output_length == 0)
224 return PR_SUCCESS;
225
226 if (i > 0) {
227 char *out = data->output_buffer + data->output_length;
228 PRUint32 n;
229 int j, k;
230
231 n = ((PRUint32) data->in_buffer[0]) << 16;
232 if (i > 1)
233 n |= ((PRUint32) data->in_buffer[1] << 8);
234
235 data->in_buffer_count = 0;
236
237 if (data->line_length > 0) {
238 if (data->current_column >= data->line_length) {
239 data->current_column = 0;
240 *out++ = B64_CR;
241 *out++ = B64_LF;
242 data->output_length += 2;
243 }
244 }
245
246 /*
247 * This will fill in more than we really have data for, but the
248 * valid parts will end up in the correct position and the extras
249 * will be over-written with pad characters below.
250 */
251 for (j = 18; j >= 0; j -= 6) {
252 k = (n >> j) & 0x3F;
253 *out++ = base64_valuetocode[k];
254 }
255
256 /* Pad with equal-signs. */
257 if (i == 1)
258 out[-2] = B64_PAD;
259 out[-1] = B64_PAD;
260
261 data->output_length += 4;
262 }
263
264 if (data->output_fn != NULL) {
265 PRInt32 output_result;
266
267 output_result = data->output_fn (data->output_arg, data->output_buffer,
268 (PRInt32) data->output_length);
269 data->output_length = 0;
270
271 if (output_result < 0)
272 return PR_FAILURE;
273 }
274
275 return PR_SUCCESS;
276 }
277
278
279 /*
280 * The maximum space needed to hold the output of the encoder given input
281 * data of length "size", and allowing for CRLF added at least every
282 * line_length bytes (we will add it at nearest lower multiple of 4).
283 * There is no trailing CRLF.
284 */
285 static PRUint32
286 PL_Base64MaxEncodedLength (PRUint32 size, PRUint32 line_length)
287 {
288 PRUint32 tokens, tokens_per_line, full_lines, line_break_chars, remainder;
289
290 tokens = (size + 2) / 3;
291
292 if (line_length == 0)
293 return tokens * 4;
294
295 if (line_length < 4) /* too small! */
296 line_length = 4;
297
298 tokens_per_line = line_length / 4;
299 full_lines = tokens / tokens_per_line;
300 remainder = (tokens - (full_lines * tokens_per_line)) * 4;
301 line_break_chars = full_lines * 2;
302 if (remainder == 0)
303 line_break_chars -= 2;
304
305 return (full_lines * tokens_per_line * 4) + line_break_chars + remainder;
306 }
307
308
309 /*
310 * A distinct internal creation function for the buffer version to use.
311 * (It does not want to specify an output_fn, and we want the normal
312 * Create function to require that.) All common initialization of the
313 * encoding context should be done *here*.
314 *
315 * Save "line_length", rounded down to nearest multiple of 4 (if not
316 * already even multiple). Allocate output_buffer, if not provided --
317 * based on given size if specified, otherwise based on line_length.
318 */
319 static PLBase64Encoder *
320 pl_base64_create_encoder (PRUint32 line_length, char *output_buffer,
321 PRUint32 output_buflen)
322 {
323 PLBase64Encoder *data;
324 PRUint32 line_tokens;
325
326 data = PR_NEWZAP(PLBase64Encoder);
327 if (data == NULL)
328 return NULL;
329
330 if (line_length > 0 && line_length < 4) /* too small! */
331 line_length = 4;
332
333 line_tokens = line_length / 4;
334 data->line_length = line_tokens * 4;
335
336 if (output_buffer == NULL) {
337 if (output_buflen == 0) {
338 if (data->line_length > 0) /* need to include room for CRLF */
339 output_buflen = data->line_length + 2;
340 else
341 output_buflen = 64; /* XXX what is a good size? */
342 }
343
344 output_buffer = (char *) PR_Malloc(output_buflen);
345 if (output_buffer == NULL) {
346 PR_Free(data);
347 return NULL;
348 }
349 }
350
351 data->output_buffer = output_buffer;
352 data->output_buflen = output_buflen;
353 return data;
354 }
355
356 /*
357 * Function to start a base64 encoding context.
358 * An "output_fn" is required; the "output_arg" parameter to that is optional.
359 * If linebreaks in the encoded output are desired, "line_length" specifies
360 * where to place them -- it will be rounded down to the nearest multiple of 4
361 * (if it is not already an even multiple of 4). If it is zero, no linebreaks
362 * will be added. (FYI, a linebreak is CRLF -- two characters.)
363 */
364 static PLBase64Encoder *
365 PL_CreateBase64Encoder (PRInt32 (*output_fn) (void *, const char *, PRInt32),
366 void *output_arg, PRUint32 line_length)
367 {
368 PLBase64Encoder *data;
369
370 if (output_fn == NULL) {
371 PR_SetError (PR_INVALID_ARGUMENT_ERROR, 0);
372 return NULL;
373 }
374
375 data = pl_base64_create_encoder (line_length, NULL, 0);
376 if (data == NULL)
377 return NULL;
378
379 data->output_fn = output_fn;
380 data->output_arg = output_arg;
381
382 return data;
383 }
384
385
386 /*
387 * Push data through the encoder, causing the output_fn (provided to Create)
388 * to be called with the encoded data.
389 */
390 static PRStatus
391 PL_UpdateBase64Encoder (PLBase64Encoder *data, const unsigned char *buffer,
392 PRUint32 size)
393 {
394 /* XXX Should we do argument checking only in debug build? */
395 if (data == NULL || buffer == NULL || size == 0) {
396 PR_SetError (PR_INVALID_ARGUMENT_ERROR, 0);
397 return PR_FAILURE;
398 }
399
400 return pl_base64_encode_buffer (data, buffer, size);
401 }
402
403
404 /*
405 * When you're done encoding, call this to free the data. If "abort_p"
406 * is false, then calling this may cause the output_fn to be called
407 * one last time (as the last buffered data is flushed out).
408 */
409 static PRStatus
410 PL_DestroyBase64Encoder (PLBase64Encoder *data, PRBool abort_p)
411 {
412 PRStatus status = PR_SUCCESS;
413
414 /* XXX Should we do argument checking only in debug build? */
415 if (data == NULL) {
416 PR_SetError (PR_INVALID_ARGUMENT_ERROR, 0);
417 return PR_FAILURE;
418 }
419
420 /* Flush out the last few buffered characters. */
421 if (!abort_p)
422 status = pl_base64_encode_flush (data);
423
424 if (data->output_buffer != NULL)
425 PR_Free(data->output_buffer);
426 PR_Free(data);
427
428 return status;
429 }
430
431
432 /*
433 * Perform base64 encoding from an input buffer to an output buffer.
434 * The output buffer can be provided (as "dest"); you can also pass in
435 * a NULL and this function will allocate a buffer large enough for you,
436 * and return it. If you do provide the output buffer, you must also
437 * provide the maximum length of that buffer (as "maxdestlen").
438 * The actual encoded length of output will be returned to you in
439 * "output_destlen".
440 *
441 * If linebreaks in the encoded output are desired, "line_length" specifies
442 * where to place them -- it will be rounded down to the nearest multiple of 4
443 * (if it is not already an even multiple of 4). If it is zero, no linebreaks
444 * will be added. (FYI, a linebreak is CRLF -- two characters.)
445 *
446 * Return value is NULL on error, the output buffer (allocated or provided)
447 * otherwise.
448 */
449 static char *
450 PL_Base64EncodeBuffer (const unsigned char *src, PRUint32 srclen,
451 PRUint32 line_length, char *dest, PRUint32 maxdestlen,
452 PRUint32 *output_destlen)
453 {
454 PRUint32 need_length;
455 PLBase64Encoder *data = NULL;
456 PRStatus status;
457
458 PR_ASSERT(srclen > 0);
459 if (srclen == 0)
460 return dest;
461
462 /*
463 * How much space could we possibly need for encoding this input?
464 */
465 need_length = PL_Base64MaxEncodedLength (srclen, line_length);
466
467 /*
468 * Make sure we have at least that much, if output buffer provided.
469 */
470 if (dest != NULL) {
471 PR_ASSERT(maxdestlen >= need_length);
472 if (maxdestlen < need_length) {
473 PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0);
474 return NULL;
475 }
476 } else {
477 maxdestlen = need_length;
478 }
479
480 data = pl_base64_create_encoder(line_length, dest, maxdestlen);
481 if (data == NULL)
482 return NULL;
483
484 status = pl_base64_encode_buffer (data, src, srclen);
485
486 /*
487 * We do not wait for Destroy to flush, because Destroy will also
488 * get rid of our encoder context, which we need to look at first!
489 */
490 if (status == PR_SUCCESS)
491 status = pl_base64_encode_flush (data);
492
493 if (status != PR_SUCCESS) {
494 (void) PL_DestroyBase64Encoder (data, PR_TRUE);
495 return NULL;
496 }
497
498 dest = data->output_buffer;
499
500 /* Must clear this or Destroy will free it. */
501 data->output_buffer = NULL;
502
503 *output_destlen = data->output_length;
504 status = PL_DestroyBase64Encoder (data, PR_FALSE);
505 if (status == PR_FAILURE) {
506 PR_Free(dest);
507 return NULL;
508 }
509
510 return dest;
511 }
512
513 /*
514 * XXX End of base64 encoding code to be moved into NSPR.
515 ********************************************************
516 */
517
518 /*
519 * This is the beginning of the NSS cover functions. These will
520 * provide the interface we want to expose as NSS-ish. For example,
521 * they will operate on our Items, do any special handling or checking
522 * we want to do, etc.
523 */
524
525
526 PR_BEGIN_EXTERN_C
527
528 /*
529 * A boring cover structure for now. Perhaps someday it will include
530 * some more interesting fields.
531 */
532 struct NSSBase64EncoderStr {
533 PLBase64Encoder *pl_data;
534 };
535
536 PR_END_EXTERN_C
537
538
539 /*
540 * Function to start a base64 encoding context.
541 */
542 NSSBase64Encoder *
543 NSSBase64Encoder_Create (PRInt32 (*output_fn) (void *, const char *, PRInt32),
544 void *output_arg)
545 {
546 PLBase64Encoder *pl_data;
547 NSSBase64Encoder *nss_data;
548
549 nss_data = PORT_ZNew(NSSBase64Encoder);
550 if (nss_data == NULL)
551 return NULL;
552
553 pl_data = PL_CreateBase64Encoder (output_fn, output_arg, 64);
554 if (pl_data == NULL) {
555 PORT_Free(nss_data);
556 return NULL;
557 }
558
559 nss_data->pl_data = pl_data;
560 return nss_data;
561 }
562
563
564 /*
565 * Push data through the encoder, causing the output_fn (provided to Create)
566 * to be called with the encoded data.
567 */
568 SECStatus
569 NSSBase64Encoder_Update (NSSBase64Encoder *data, const unsigned char *buffer,
570 PRUint32 size)
571 {
572 PRStatus pr_status;
573
574 /* XXX Should we do argument checking only in debug build? */
575 if (data == NULL) {
576 PORT_SetError (SEC_ERROR_INVALID_ARGS);
577 return SECFailure;
578 }
579
580 pr_status = PL_UpdateBase64Encoder (data->pl_data, buffer, size);
581 if (pr_status == PR_FAILURE)
582 return SECFailure;
583
584 return SECSuccess;
585 }
586
587
588 /*
589 * When you're done encoding, call this to free the data. If "abort_p"
590 * is false, then calling this may cause the output_fn to be called
591 * one last time (as the last buffered data is flushed out).
592 */
593 SECStatus
594 NSSBase64Encoder_Destroy (NSSBase64Encoder *data, PRBool abort_p)
595 {
596 PRStatus pr_status;
597
598 /* XXX Should we do argument checking only in debug build? */
599 if (data == NULL) {
600 PORT_SetError (SEC_ERROR_INVALID_ARGS);
601 return SECFailure;
602 }
603
604 pr_status = PL_DestroyBase64Encoder (data->pl_data, abort_p);
605
606 PORT_Free(data);
607
608 if (pr_status == PR_FAILURE)
609 return SECFailure;
610
611 return SECSuccess;
612 }
613
614
615 /*
616 * Perform base64 encoding of binary data "inItem" to an ascii string.
617 * The output buffer may be provided (as "outStrOpt"); you can also pass
618 * in a NULL and the buffer will be allocated for you. The result will
619 * be null-terminated, and if the buffer is provided, "maxOutLen" must
620 * specify the maximum length of the buffer and will be checked to
621 * supply sufficient space space for the encoded result. (If "outStrOpt"
622 * is NULL, "maxOutLen" is ignored.)
623 *
624 * If "outStrOpt" is NULL, allocation will happen out of the passed-in
625 * "arenaOpt", if *it* is non-NULL, otherwise standard allocation (heap)
626 * will be used.
627 *
628 * Return value is NULL on error, the output buffer (allocated or provided)
629 * otherwise.
630 */
631 char *
632 NSSBase64_EncodeItem (PRArenaPool *arenaOpt, char *outStrOpt,
633 unsigned int maxOutLen, SECItem *inItem)
634 {
635 char *out_string = outStrOpt;
636 PRUint32 max_out_len;
637 PRUint32 out_len;
638 void *mark = NULL;
639 char *dummy;
640
641 PORT_Assert(inItem != NULL && inItem->data != NULL && inItem->len != 0);
642 if (inItem == NULL || inItem->data == NULL || inItem->len == 0) {
643 PORT_SetError (SEC_ERROR_INVALID_ARGS);
644 return NULL;
645 }
646
647 max_out_len = PL_Base64MaxEncodedLength (inItem->len, 64);
648
649 if (arenaOpt != NULL)
650 mark = PORT_ArenaMark (arenaOpt);
651
652 if (out_string == NULL) {
653 if (arenaOpt != NULL)
654 out_string = PORT_ArenaAlloc (arenaOpt, max_out_len + 1);
655 else
656 out_string = PORT_Alloc (max_out_len + 1);
657
658 if (out_string == NULL) {
659 if (arenaOpt != NULL)
660 PORT_ArenaRelease (arenaOpt, mark);
661 return NULL;
662 }
663 } else {
664 if ((max_out_len + 1) > maxOutLen) {
665 PORT_SetError (SEC_ERROR_OUTPUT_LEN);
666 return NULL;
667 }
668 max_out_len = maxOutLen;
669 }
670
671
672 dummy = PL_Base64EncodeBuffer (inItem->data, inItem->len, 64,
673 out_string, max_out_len, &out_len);
674 if (dummy == NULL) {
675 if (arenaOpt != NULL) {
676 PORT_ArenaRelease (arenaOpt, mark);
677 } else {
678 PORT_Free (out_string);
679 }
680 return NULL;
681 }
682
683 if (arenaOpt != NULL)
684 PORT_ArenaUnmark (arenaOpt, mark);
685
686 out_string[out_len] = '\0';
687 return out_string;
688 }
689
690
691 /*
692 * XXX Everything below is deprecated. If you add new stuff, put it
693 * *above*, not below.
694 */
695
696 /*
697 * XXX The following "BTOA" functions are provided for backward compatibility
698 * with current code. They should be considered strongly deprecated.
699 * When we can convert all our code over to using the new NSSBase64Encoder_
700 * functions defined above, we should get rid of these altogether. (Remove
701 * protoypes from base64.h as well -- actually, remove that file completely).
702 * If someone thinks either of these functions provides such a very useful
703 * interface (though, as shown, the same functionality can already be
704 * obtained by calling NSSBase64_EncodeItem directly), fine -- but then
705 * that API should be provided with a nice new NSSFoo name and using
706 * appropriate types, etc.
707 */
708
709 #include "base64.h"
710
711 /*
712 ** Return an PORT_Alloc'd ascii string which is the base64 encoded
713 ** version of the input string.
714 */
715 char *
716 BTOA_DataToAscii(const unsigned char *data, unsigned int len)
717 {
718 SECItem binary_item;
719
720 binary_item.data = (unsigned char *)data;
721 binary_item.len = len;
722
723 return NSSBase64_EncodeItem (NULL, NULL, 0, &binary_item);
724 }
725
726 /*
727 ** Convert from binary encoding of an item to ascii.
728 */
729 char *
730 BTOA_ConvertItemToAscii (SECItem *binary_item)
731 {
732 return NSSBase64_EncodeItem (NULL, NULL, 0, binary_item);
733 }
OLDNEW
« no previous file with comments | « mozilla/security/nss/lib/util/nssb64d.c ('k') | mozilla/security/nss/lib/util/nssb64t.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698