security/nss/lib/util/nssb64d.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 /*
michael@0 6 * Base64 decoding (ascii to binary).
michael@0 7 */
michael@0 8
michael@0 9 #include "nssb64.h"
michael@0 10 #include "nspr.h"
michael@0 11 #include "secitem.h"
michael@0 12 #include "secerr.h"
michael@0 13
michael@0 14 /*
michael@0 15 * XXX We want this basic support to go into NSPR (the PL part).
michael@0 16 * Until that can happen, the PL interface is going to be kept entirely
michael@0 17 * internal here -- all static functions and opaque data structures.
michael@0 18 * When someone can get it moved over into NSPR, that should be done:
michael@0 19 * - giving everything names that are accepted by the NSPR module owners
michael@0 20 * (though I tried to choose ones that would work without modification)
michael@0 21 * - exporting the functions (remove static declarations and add
michael@0 22 * to nssutil.def as necessary)
michael@0 23 * - put prototypes into appropriate header file (probably replacing
michael@0 24 * the entire current lib/libc/include/plbase64.h in NSPR)
michael@0 25 * along with a typedef for the context structure (which should be
michael@0 26 * kept opaque -- definition in the source file only, but typedef
michael@0 27 * ala "typedef struct PLBase64FooStr PLBase64Foo;" in header file)
michael@0 28 * - modify anything else as necessary to conform to NSPR required style
michael@0 29 * (I looked but found no formatting guide to follow)
michael@0 30 *
michael@0 31 * You will want to move over everything from here down to the comment
michael@0 32 * which says "XXX End of base64 decoding code to be moved into NSPR",
michael@0 33 * into a new file in NSPR.
michael@0 34 */
michael@0 35
michael@0 36 /*
michael@0 37 **************************************************************
michael@0 38 * XXX Beginning of base64 decoding code to be moved into NSPR.
michael@0 39 */
michael@0 40
michael@0 41 /*
michael@0 42 * This typedef would belong in the NSPR header file (i.e. plbase64.h).
michael@0 43 */
michael@0 44 typedef struct PLBase64DecoderStr PLBase64Decoder;
michael@0 45
michael@0 46 /*
michael@0 47 * The following implementation of base64 decoding was based on code
michael@0 48 * found in libmime (specifically, in mimeenc.c). It has been adapted to
michael@0 49 * use PR types and naming as well as to provide other necessary semantics
michael@0 50 * (like buffer-in/buffer-out in addition to "streaming" without undue
michael@0 51 * performance hit of extra copying if you made the buffer versions
michael@0 52 * use the output_fn). It also incorporates some aspects of the current
michael@0 53 * NSPR base64 decoding code. As such, you may find similarities to
michael@0 54 * both of those implementations. I tried to use names that reflected
michael@0 55 * the original code when possible. For this reason you may find some
michael@0 56 * inconsistencies -- libmime used lots of "in" and "out" whereas the
michael@0 57 * NSPR version uses "src" and "dest"; sometimes I changed one to the other
michael@0 58 * and sometimes I left them when I thought the subroutines were at least
michael@0 59 * self-consistent.
michael@0 60 */
michael@0 61
michael@0 62 PR_BEGIN_EXTERN_C
michael@0 63
michael@0 64 /*
michael@0 65 * Opaque object used by the decoder to store state.
michael@0 66 */
michael@0 67 struct PLBase64DecoderStr {
michael@0 68 /* Current token (or portion, if token_size < 4) being decoded. */
michael@0 69 unsigned char token[4];
michael@0 70 int token_size;
michael@0 71
michael@0 72 /*
michael@0 73 * Where to write the decoded data (used when streaming, not when
michael@0 74 * doing all in-memory (buffer) operations).
michael@0 75 *
michael@0 76 * Note that this definition is chosen to be compatible with PR_Write.
michael@0 77 */
michael@0 78 PRInt32 (*output_fn) (void *output_arg, const unsigned char *buf,
michael@0 79 PRInt32 size);
michael@0 80 void *output_arg;
michael@0 81
michael@0 82 /*
michael@0 83 * Where the decoded output goes -- either temporarily (in the streaming
michael@0 84 * case, staged here before it goes to the output function) or what will
michael@0 85 * be the entire buffered result for users of the buffer version.
michael@0 86 */
michael@0 87 unsigned char *output_buffer;
michael@0 88 PRUint32 output_buflen; /* the total length of allocated buffer */
michael@0 89 PRUint32 output_length; /* the length that is currently populated */
michael@0 90 };
michael@0 91
michael@0 92 PR_END_EXTERN_C
michael@0 93
michael@0 94
michael@0 95 /*
michael@0 96 * Table to convert an ascii "code" to its corresponding binary value.
michael@0 97 * For ease of use, the binary values in the table are the actual values
michael@0 98 * PLUS ONE. This is so that the special value of zero can denote an
michael@0 99 * invalid mapping; that was much easier than trying to fill in the other
michael@0 100 * values with some value other than zero, and to check for it.
michael@0 101 * Just remember to SUBTRACT ONE when using the value retrieved.
michael@0 102 */
michael@0 103 static unsigned char base64_codetovaluep1[256] = {
michael@0 104 /* 0: */ 0, 0, 0, 0, 0, 0, 0, 0,
michael@0 105 /* 8: */ 0, 0, 0, 0, 0, 0, 0, 0,
michael@0 106 /* 16: */ 0, 0, 0, 0, 0, 0, 0, 0,
michael@0 107 /* 24: */ 0, 0, 0, 0, 0, 0, 0, 0,
michael@0 108 /* 32: */ 0, 0, 0, 0, 0, 0, 0, 0,
michael@0 109 /* 40: */ 0, 0, 0, 63, 0, 0, 0, 64,
michael@0 110 /* 48: */ 53, 54, 55, 56, 57, 58, 59, 60,
michael@0 111 /* 56: */ 61, 62, 0, 0, 0, 0, 0, 0,
michael@0 112 /* 64: */ 0, 1, 2, 3, 4, 5, 6, 7,
michael@0 113 /* 72: */ 8, 9, 10, 11, 12, 13, 14, 15,
michael@0 114 /* 80: */ 16, 17, 18, 19, 20, 21, 22, 23,
michael@0 115 /* 88: */ 24, 25, 26, 0, 0, 0, 0, 0,
michael@0 116 /* 96: */ 0, 27, 28, 29, 30, 31, 32, 33,
michael@0 117 /* 104: */ 34, 35, 36, 37, 38, 39, 40, 41,
michael@0 118 /* 112: */ 42, 43, 44, 45, 46, 47, 48, 49,
michael@0 119 /* 120: */ 50, 51, 52, 0, 0, 0, 0, 0,
michael@0 120 /* 128: */ 0, 0, 0, 0, 0, 0, 0, 0
michael@0 121 /* and rest are all zero as well */
michael@0 122 };
michael@0 123
michael@0 124 #define B64_PAD '='
michael@0 125
michael@0 126
michael@0 127 /*
michael@0 128 * Reads 4; writes 3 (known, or expected, to have no trailing padding).
michael@0 129 * Returns bytes written; -1 on error (unexpected character).
michael@0 130 */
michael@0 131 static int
michael@0 132 pl_base64_decode_4to3 (const unsigned char *in, unsigned char *out)
michael@0 133 {
michael@0 134 int j;
michael@0 135 PRUint32 num = 0;
michael@0 136 unsigned char bits;
michael@0 137
michael@0 138 for (j = 0; j < 4; j++) {
michael@0 139 bits = base64_codetovaluep1[in[j]];
michael@0 140 if (bits == 0)
michael@0 141 return -1;
michael@0 142 num = (num << 6) | (bits - 1);
michael@0 143 }
michael@0 144
michael@0 145 out[0] = (unsigned char) (num >> 16);
michael@0 146 out[1] = (unsigned char) ((num >> 8) & 0xFF);
michael@0 147 out[2] = (unsigned char) (num & 0xFF);
michael@0 148
michael@0 149 return 3;
michael@0 150 }
michael@0 151
michael@0 152 /*
michael@0 153 * Reads 3; writes 2 (caller already confirmed EOF or trailing padding).
michael@0 154 * Returns bytes written; -1 on error (unexpected character).
michael@0 155 */
michael@0 156 static int
michael@0 157 pl_base64_decode_3to2 (const unsigned char *in, unsigned char *out)
michael@0 158 {
michael@0 159 PRUint32 num = 0;
michael@0 160 unsigned char bits1, bits2, bits3;
michael@0 161
michael@0 162 bits1 = base64_codetovaluep1[in[0]];
michael@0 163 bits2 = base64_codetovaluep1[in[1]];
michael@0 164 bits3 = base64_codetovaluep1[in[2]];
michael@0 165
michael@0 166 if ((bits1 == 0) || (bits2 == 0) || (bits3 == 0))
michael@0 167 return -1;
michael@0 168
michael@0 169 num = ((PRUint32)(bits1 - 1)) << 10;
michael@0 170 num |= ((PRUint32)(bits2 - 1)) << 4;
michael@0 171 num |= ((PRUint32)(bits3 - 1)) >> 2;
michael@0 172
michael@0 173 out[0] = (unsigned char) (num >> 8);
michael@0 174 out[1] = (unsigned char) (num & 0xFF);
michael@0 175
michael@0 176 return 2;
michael@0 177 }
michael@0 178
michael@0 179 /*
michael@0 180 * Reads 2; writes 1 (caller already confirmed EOF or trailing padding).
michael@0 181 * Returns bytes written; -1 on error (unexpected character).
michael@0 182 */
michael@0 183 static int
michael@0 184 pl_base64_decode_2to1 (const unsigned char *in, unsigned char *out)
michael@0 185 {
michael@0 186 PRUint32 num = 0;
michael@0 187 unsigned char bits1, bits2;
michael@0 188
michael@0 189 bits1 = base64_codetovaluep1[in[0]];
michael@0 190 bits2 = base64_codetovaluep1[in[1]];
michael@0 191
michael@0 192 if ((bits1 == 0) || (bits2 == 0))
michael@0 193 return -1;
michael@0 194
michael@0 195 num = ((PRUint32)(bits1 - 1)) << 2;
michael@0 196 num |= ((PRUint32)(bits2 - 1)) >> 4;
michael@0 197
michael@0 198 out[0] = (unsigned char) num;
michael@0 199
michael@0 200 return 1;
michael@0 201 }
michael@0 202
michael@0 203 /*
michael@0 204 * Reads 4; writes 0-3. Returns bytes written or -1 on error.
michael@0 205 * (Writes less than 3 only at (presumed) EOF.)
michael@0 206 */
michael@0 207 static int
michael@0 208 pl_base64_decode_token (const unsigned char *in, unsigned char *out)
michael@0 209 {
michael@0 210 if (in[3] != B64_PAD)
michael@0 211 return pl_base64_decode_4to3 (in, out);
michael@0 212
michael@0 213 if (in[2] == B64_PAD)
michael@0 214 return pl_base64_decode_2to1 (in, out);
michael@0 215
michael@0 216 return pl_base64_decode_3to2 (in, out);
michael@0 217 }
michael@0 218
michael@0 219 static PRStatus
michael@0 220 pl_base64_decode_buffer (PLBase64Decoder *data, const unsigned char *in,
michael@0 221 PRUint32 length)
michael@0 222 {
michael@0 223 unsigned char *out = data->output_buffer;
michael@0 224 unsigned char *token = data->token;
michael@0 225 int i, n = 0;
michael@0 226
michael@0 227 i = data->token_size;
michael@0 228 data->token_size = 0;
michael@0 229
michael@0 230 while (length > 0) {
michael@0 231 while (i < 4 && length > 0) {
michael@0 232 /*
michael@0 233 * XXX Note that the following simply ignores any unexpected
michael@0 234 * characters. This is exactly what the original code in
michael@0 235 * libmime did, and I am leaving it. We certainly want to skip
michael@0 236 * over whitespace (we must); this does much more than that.
michael@0 237 * I am not confident changing it, and I don't want to slow
michael@0 238 * the processing down doing more complicated checking, but
michael@0 239 * someone else might have different ideas in the future.
michael@0 240 */
michael@0 241 if (base64_codetovaluep1[*in] > 0 || *in == B64_PAD)
michael@0 242 token[i++] = *in;
michael@0 243 in++;
michael@0 244 length--;
michael@0 245 }
michael@0 246
michael@0 247 if (i < 4) {
michael@0 248 /* Didn't get enough for a complete token. */
michael@0 249 data->token_size = i;
michael@0 250 break;
michael@0 251 }
michael@0 252 i = 0;
michael@0 253
michael@0 254 PR_ASSERT((out - data->output_buffer + 3) <= data->output_buflen);
michael@0 255
michael@0 256 /*
michael@0 257 * Assume we are not at the end; the following function only works
michael@0 258 * for an internal token (no trailing padding characters) but is
michael@0 259 * faster that way. If it hits an invalid character (padding) it
michael@0 260 * will return an error; we break out of the loop and try again
michael@0 261 * calling the routine that will handle a final token.
michael@0 262 * Note that we intentionally do it this way rather than explicitly
michael@0 263 * add a check for padding here (because that would just slow down
michael@0 264 * the normal case) nor do we rely on checking whether we have more
michael@0 265 * input to process (because that would also slow it down but also
michael@0 266 * because we want to allow trailing garbage, especially white space
michael@0 267 * and cannot tell that without read-ahead, also a slow proposition).
michael@0 268 * Whew. Understand?
michael@0 269 */
michael@0 270 n = pl_base64_decode_4to3 (token, out);
michael@0 271 if (n < 0)
michael@0 272 break;
michael@0 273
michael@0 274 /* Advance "out" by the number of bytes just written to it. */
michael@0 275 out += n;
michael@0 276 n = 0;
michael@0 277 }
michael@0 278
michael@0 279 /*
michael@0 280 * See big comment above, before call to pl_base64_decode_4to3.
michael@0 281 * Here we check if we error'd out of loop, and allow for the case
michael@0 282 * that we are processing the last interesting token. If the routine
michael@0 283 * which should handle padding characters also fails, then we just
michael@0 284 * have bad input and give up.
michael@0 285 */
michael@0 286 if (n < 0) {
michael@0 287 n = pl_base64_decode_token (token, out);
michael@0 288 if (n < 0)
michael@0 289 return PR_FAILURE;
michael@0 290
michael@0 291 out += n;
michael@0 292 }
michael@0 293
michael@0 294 /*
michael@0 295 * As explained above, we can get here with more input remaining, but
michael@0 296 * it should be all characters we do not care about (i.e. would be
michael@0 297 * ignored when transferring from "in" to "token" in loop above,
michael@0 298 * except here we choose to ignore extraneous pad characters, too).
michael@0 299 * Swallow it, performing that check. If we find more characters that
michael@0 300 * we would expect to decode, something is wrong.
michael@0 301 */
michael@0 302 while (length > 0) {
michael@0 303 if (base64_codetovaluep1[*in] > 0)
michael@0 304 return PR_FAILURE;
michael@0 305 in++;
michael@0 306 length--;
michael@0 307 }
michael@0 308
michael@0 309 /* Record the length of decoded data we have left in output_buffer. */
michael@0 310 data->output_length = (PRUint32) (out - data->output_buffer);
michael@0 311 return PR_SUCCESS;
michael@0 312 }
michael@0 313
michael@0 314 /*
michael@0 315 * Flush any remaining buffered characters. Given well-formed input,
michael@0 316 * this will have nothing to do. If the input was missing the padding
michael@0 317 * characters at the end, though, there could be 1-3 characters left
michael@0 318 * behind -- we will tolerate that by adding the padding for them.
michael@0 319 */
michael@0 320 static PRStatus
michael@0 321 pl_base64_decode_flush (PLBase64Decoder *data)
michael@0 322 {
michael@0 323 int count;
michael@0 324
michael@0 325 /*
michael@0 326 * If no remaining characters, or all are padding (also not well-formed
michael@0 327 * input, but again, be tolerant), then nothing more to do. (And, that
michael@0 328 * is considered successful.)
michael@0 329 */
michael@0 330 if (data->token_size == 0 || data->token[0] == B64_PAD)
michael@0 331 return PR_SUCCESS;
michael@0 332
michael@0 333 /*
michael@0 334 * Assume we have all the interesting input except for some expected
michael@0 335 * padding characters. Add them and decode the resulting token.
michael@0 336 */
michael@0 337 while (data->token_size < 4)
michael@0 338 data->token[data->token_size++] = B64_PAD;
michael@0 339
michael@0 340 data->token_size = 0; /* so a subsequent flush call is a no-op */
michael@0 341
michael@0 342 count = pl_base64_decode_token (data->token,
michael@0 343 data->output_buffer + data->output_length);
michael@0 344 if (count < 0)
michael@0 345 return PR_FAILURE;
michael@0 346
michael@0 347 /*
michael@0 348 * If there is an output function, call it with this last bit of data.
michael@0 349 * Otherwise we are doing all buffered output, and the decoded bytes
michael@0 350 * are now there, we just need to reflect that in the length.
michael@0 351 */
michael@0 352 if (data->output_fn != NULL) {
michael@0 353 PRInt32 output_result;
michael@0 354
michael@0 355 PR_ASSERT(data->output_length == 0);
michael@0 356 output_result = data->output_fn (data->output_arg,
michael@0 357 data->output_buffer,
michael@0 358 (PRInt32) count);
michael@0 359 if (output_result < 0)
michael@0 360 return PR_FAILURE;
michael@0 361 } else {
michael@0 362 data->output_length += count;
michael@0 363 }
michael@0 364
michael@0 365 return PR_SUCCESS;
michael@0 366 }
michael@0 367
michael@0 368
michael@0 369 /*
michael@0 370 * The maximum space needed to hold the output of the decoder given
michael@0 371 * input data of length "size".
michael@0 372 */
michael@0 373 static PRUint32
michael@0 374 PL_Base64MaxDecodedLength (PRUint32 size)
michael@0 375 {
michael@0 376 return ((size * 3) / 4);
michael@0 377 }
michael@0 378
michael@0 379
michael@0 380 /*
michael@0 381 * A distinct internal creation function for the buffer version to use.
michael@0 382 * (It does not want to specify an output_fn, and we want the normal
michael@0 383 * Create function to require that.) If more common initialization
michael@0 384 * of the decoding context needs to be done, it should be done *here*.
michael@0 385 */
michael@0 386 static PLBase64Decoder *
michael@0 387 pl_base64_create_decoder (void)
michael@0 388 {
michael@0 389 return PR_NEWZAP(PLBase64Decoder);
michael@0 390 }
michael@0 391
michael@0 392 /*
michael@0 393 * Function to start a base64 decoding context.
michael@0 394 * An "output_fn" is required; the "output_arg" parameter to that is optional.
michael@0 395 */
michael@0 396 static PLBase64Decoder *
michael@0 397 PL_CreateBase64Decoder (PRInt32 (*output_fn) (void *, const unsigned char *,
michael@0 398 PRInt32),
michael@0 399 void *output_arg)
michael@0 400 {
michael@0 401 PLBase64Decoder *data;
michael@0 402
michael@0 403 if (output_fn == NULL) {
michael@0 404 PR_SetError (PR_INVALID_ARGUMENT_ERROR, 0);
michael@0 405 return NULL;
michael@0 406 }
michael@0 407
michael@0 408 data = pl_base64_create_decoder ();
michael@0 409 if (data != NULL) {
michael@0 410 data->output_fn = output_fn;
michael@0 411 data->output_arg = output_arg;
michael@0 412 }
michael@0 413 return data;
michael@0 414 }
michael@0 415
michael@0 416
michael@0 417 /*
michael@0 418 * Push data through the decoder, causing the output_fn (provided to Create)
michael@0 419 * to be called with the decoded data.
michael@0 420 */
michael@0 421 static PRStatus
michael@0 422 PL_UpdateBase64Decoder (PLBase64Decoder *data, const char *buffer,
michael@0 423 PRUint32 size)
michael@0 424 {
michael@0 425 PRUint32 need_length;
michael@0 426 PRStatus status;
michael@0 427
michael@0 428 /* XXX Should we do argument checking only in debug build? */
michael@0 429 if (data == NULL || buffer == NULL || size == 0) {
michael@0 430 PR_SetError (PR_INVALID_ARGUMENT_ERROR, 0);
michael@0 431 return PR_FAILURE;
michael@0 432 }
michael@0 433
michael@0 434 /*
michael@0 435 * How much space could this update need for decoding?
michael@0 436 */
michael@0 437 need_length = PL_Base64MaxDecodedLength (size + data->token_size);
michael@0 438
michael@0 439 /*
michael@0 440 * Make sure we have at least that much. If not, (re-)allocate.
michael@0 441 */
michael@0 442 if (need_length > data->output_buflen) {
michael@0 443 unsigned char *output_buffer = data->output_buffer;
michael@0 444
michael@0 445 if (output_buffer != NULL)
michael@0 446 output_buffer = (unsigned char *) PR_Realloc(output_buffer,
michael@0 447 need_length);
michael@0 448 else
michael@0 449 output_buffer = (unsigned char *) PR_Malloc(need_length);
michael@0 450
michael@0 451 if (output_buffer == NULL)
michael@0 452 return PR_FAILURE;
michael@0 453
michael@0 454 data->output_buffer = output_buffer;
michael@0 455 data->output_buflen = need_length;
michael@0 456 }
michael@0 457
michael@0 458 /* There should not have been any leftover output data in the buffer. */
michael@0 459 PR_ASSERT(data->output_length == 0);
michael@0 460 data->output_length = 0;
michael@0 461
michael@0 462 status = pl_base64_decode_buffer (data, (const unsigned char *) buffer,
michael@0 463 size);
michael@0 464
michael@0 465 /* Now that we have some decoded data, write it. */
michael@0 466 if (status == PR_SUCCESS && data->output_length > 0) {
michael@0 467 PRInt32 output_result;
michael@0 468
michael@0 469 PR_ASSERT(data->output_fn != NULL);
michael@0 470 output_result = data->output_fn (data->output_arg,
michael@0 471 data->output_buffer,
michael@0 472 (PRInt32) data->output_length);
michael@0 473 if (output_result < 0)
michael@0 474 status = PR_FAILURE;
michael@0 475 }
michael@0 476
michael@0 477 data->output_length = 0;
michael@0 478 return status;
michael@0 479 }
michael@0 480
michael@0 481
michael@0 482 /*
michael@0 483 * When you're done decoding, call this to free the data. If "abort_p"
michael@0 484 * is false, then calling this may cause the output_fn to be called
michael@0 485 * one last time (as the last buffered data is flushed out).
michael@0 486 */
michael@0 487 static PRStatus
michael@0 488 PL_DestroyBase64Decoder (PLBase64Decoder *data, PRBool abort_p)
michael@0 489 {
michael@0 490 PRStatus status = PR_SUCCESS;
michael@0 491
michael@0 492 /* XXX Should we do argument checking only in debug build? */
michael@0 493 if (data == NULL) {
michael@0 494 PR_SetError (PR_INVALID_ARGUMENT_ERROR, 0);
michael@0 495 return PR_FAILURE;
michael@0 496 }
michael@0 497
michael@0 498 /* Flush out the last few buffered characters. */
michael@0 499 if (!abort_p)
michael@0 500 status = pl_base64_decode_flush (data);
michael@0 501
michael@0 502 if (data->output_buffer != NULL)
michael@0 503 PR_Free(data->output_buffer);
michael@0 504 PR_Free(data);
michael@0 505
michael@0 506 return status;
michael@0 507 }
michael@0 508
michael@0 509
michael@0 510 /*
michael@0 511 * Perform base64 decoding from an input buffer to an output buffer.
michael@0 512 * The output buffer can be provided (as "dest"); you can also pass in
michael@0 513 * a NULL and this function will allocate a buffer large enough for you,
michael@0 514 * and return it. If you do provide the output buffer, you must also
michael@0 515 * provide the maximum length of that buffer (as "maxdestlen").
michael@0 516 * The actual decoded length of output will be returned to you in
michael@0 517 * "output_destlen".
michael@0 518 *
michael@0 519 * Return value is NULL on error, the output buffer (allocated or provided)
michael@0 520 * otherwise.
michael@0 521 */
michael@0 522 static unsigned char *
michael@0 523 PL_Base64DecodeBuffer (const char *src, PRUint32 srclen, unsigned char *dest,
michael@0 524 PRUint32 maxdestlen, PRUint32 *output_destlen)
michael@0 525 {
michael@0 526 PRUint32 need_length;
michael@0 527 unsigned char *output_buffer = NULL;
michael@0 528 PLBase64Decoder *data = NULL;
michael@0 529 PRStatus status;
michael@0 530
michael@0 531 PR_ASSERT(srclen > 0);
michael@0 532 if (srclen == 0) {
michael@0 533 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
michael@0 534 return NULL;
michael@0 535 }
michael@0 536
michael@0 537 /*
michael@0 538 * How much space could we possibly need for decoding this input?
michael@0 539 */
michael@0 540 need_length = PL_Base64MaxDecodedLength (srclen);
michael@0 541
michael@0 542 /*
michael@0 543 * Make sure we have at least that much, if output buffer provided.
michael@0 544 * If no output buffer provided, then we allocate that much.
michael@0 545 */
michael@0 546 if (dest != NULL) {
michael@0 547 PR_ASSERT(maxdestlen >= need_length);
michael@0 548 if (maxdestlen < need_length) {
michael@0 549 PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0);
michael@0 550 goto loser;
michael@0 551 }
michael@0 552 output_buffer = dest;
michael@0 553 } else {
michael@0 554 output_buffer = (unsigned char *) PR_Malloc(need_length);
michael@0 555 if (output_buffer == NULL)
michael@0 556 goto loser;
michael@0 557 maxdestlen = need_length;
michael@0 558 }
michael@0 559
michael@0 560 data = pl_base64_create_decoder();
michael@0 561 if (data == NULL)
michael@0 562 goto loser;
michael@0 563
michael@0 564 data->output_buflen = maxdestlen;
michael@0 565 data->output_buffer = output_buffer;
michael@0 566
michael@0 567 status = pl_base64_decode_buffer (data, (const unsigned char *) src,
michael@0 568 srclen);
michael@0 569
michael@0 570 /*
michael@0 571 * We do not wait for Destroy to flush, because Destroy will also
michael@0 572 * get rid of our decoder context, which we need to look at first!
michael@0 573 */
michael@0 574 if (status == PR_SUCCESS)
michael@0 575 status = pl_base64_decode_flush (data);
michael@0 576
michael@0 577 /* Must clear this or Destroy will free it. */
michael@0 578 data->output_buffer = NULL;
michael@0 579
michael@0 580 if (status == PR_SUCCESS) {
michael@0 581 *output_destlen = data->output_length;
michael@0 582 status = PL_DestroyBase64Decoder (data, PR_FALSE);
michael@0 583 data = NULL;
michael@0 584 if (status == PR_FAILURE)
michael@0 585 goto loser;
michael@0 586 return output_buffer;
michael@0 587 }
michael@0 588
michael@0 589 loser:
michael@0 590 if (dest == NULL && output_buffer != NULL)
michael@0 591 PR_Free(output_buffer);
michael@0 592 if (data != NULL)
michael@0 593 (void) PL_DestroyBase64Decoder (data, PR_TRUE);
michael@0 594 return NULL;
michael@0 595 }
michael@0 596
michael@0 597
michael@0 598 /*
michael@0 599 * XXX End of base64 decoding code to be moved into NSPR.
michael@0 600 ********************************************************
michael@0 601 */
michael@0 602
michael@0 603 /*
michael@0 604 * This is the beginning of the NSS cover functions. These will
michael@0 605 * provide the interface we want to expose as NSS-ish. For example,
michael@0 606 * they will operate on our Items, do any special handling or checking
michael@0 607 * we want to do, etc.
michael@0 608 */
michael@0 609
michael@0 610
michael@0 611 PR_BEGIN_EXTERN_C
michael@0 612
michael@0 613 /*
michael@0 614 * A boring cover structure for now. Perhaps someday it will include
michael@0 615 * some more interesting fields.
michael@0 616 */
michael@0 617 struct NSSBase64DecoderStr {
michael@0 618 PLBase64Decoder *pl_data;
michael@0 619 };
michael@0 620
michael@0 621 PR_END_EXTERN_C
michael@0 622
michael@0 623
michael@0 624 /*
michael@0 625 * Function to start a base64 decoding context.
michael@0 626 */
michael@0 627 NSSBase64Decoder *
michael@0 628 NSSBase64Decoder_Create (PRInt32 (*output_fn) (void *, const unsigned char *,
michael@0 629 PRInt32),
michael@0 630 void *output_arg)
michael@0 631 {
michael@0 632 PLBase64Decoder *pl_data;
michael@0 633 NSSBase64Decoder *nss_data;
michael@0 634
michael@0 635 nss_data = PORT_ZNew(NSSBase64Decoder);
michael@0 636 if (nss_data == NULL)
michael@0 637 return NULL;
michael@0 638
michael@0 639 pl_data = PL_CreateBase64Decoder (output_fn, output_arg);
michael@0 640 if (pl_data == NULL) {
michael@0 641 PORT_Free(nss_data);
michael@0 642 return NULL;
michael@0 643 }
michael@0 644
michael@0 645 nss_data->pl_data = pl_data;
michael@0 646 return nss_data;
michael@0 647 }
michael@0 648
michael@0 649
michael@0 650 /*
michael@0 651 * Push data through the decoder, causing the output_fn (provided to Create)
michael@0 652 * to be called with the decoded data.
michael@0 653 */
michael@0 654 SECStatus
michael@0 655 NSSBase64Decoder_Update (NSSBase64Decoder *data, const char *buffer,
michael@0 656 PRUint32 size)
michael@0 657 {
michael@0 658 PRStatus pr_status;
michael@0 659
michael@0 660 /* XXX Should we do argument checking only in debug build? */
michael@0 661 if (data == NULL) {
michael@0 662 PORT_SetError (SEC_ERROR_INVALID_ARGS);
michael@0 663 return SECFailure;
michael@0 664 }
michael@0 665
michael@0 666 pr_status = PL_UpdateBase64Decoder (data->pl_data, buffer, size);
michael@0 667 if (pr_status == PR_FAILURE)
michael@0 668 return SECFailure;
michael@0 669
michael@0 670 return SECSuccess;
michael@0 671 }
michael@0 672
michael@0 673
michael@0 674 /*
michael@0 675 * When you're done decoding, call this to free the data. If "abort_p"
michael@0 676 * is false, then calling this may cause the output_fn to be called
michael@0 677 * one last time (as the last buffered data is flushed out).
michael@0 678 */
michael@0 679 SECStatus
michael@0 680 NSSBase64Decoder_Destroy (NSSBase64Decoder *data, PRBool abort_p)
michael@0 681 {
michael@0 682 PRStatus pr_status;
michael@0 683
michael@0 684 /* XXX Should we do argument checking only in debug build? */
michael@0 685 if (data == NULL) {
michael@0 686 PORT_SetError (SEC_ERROR_INVALID_ARGS);
michael@0 687 return SECFailure;
michael@0 688 }
michael@0 689
michael@0 690 pr_status = PL_DestroyBase64Decoder (data->pl_data, abort_p);
michael@0 691
michael@0 692 PORT_Free(data);
michael@0 693
michael@0 694 if (pr_status == PR_FAILURE)
michael@0 695 return SECFailure;
michael@0 696
michael@0 697 return SECSuccess;
michael@0 698 }
michael@0 699
michael@0 700
michael@0 701 /*
michael@0 702 * Perform base64 decoding from an ascii string "inStr" to an Item.
michael@0 703 * The length of the input must be provided as "inLen". The Item
michael@0 704 * may be provided (as "outItemOpt"); you can also pass in a NULL
michael@0 705 * and the Item will be allocated for you.
michael@0 706 *
michael@0 707 * In any case, the data within the Item will be allocated for you.
michael@0 708 * All allocation will happen out of the passed-in "arenaOpt", if non-NULL.
michael@0 709 * If "arenaOpt" is NULL, standard allocation (heap) will be used and
michael@0 710 * you will want to free the result via SECITEM_FreeItem.
michael@0 711 *
michael@0 712 * Return value is NULL on error, the Item (allocated or provided) otherwise.
michael@0 713 */
michael@0 714 SECItem *
michael@0 715 NSSBase64_DecodeBuffer (PLArenaPool *arenaOpt, SECItem *outItemOpt,
michael@0 716 const char *inStr, unsigned int inLen)
michael@0 717 {
michael@0 718 SECItem *out_item = NULL;
michael@0 719 PRUint32 max_out_len = 0;
michael@0 720 PRUint32 out_len;
michael@0 721 void *mark = NULL;
michael@0 722 unsigned char *dummy;
michael@0 723
michael@0 724 if ((outItemOpt != NULL && outItemOpt->data != NULL) || inLen == 0) {
michael@0 725 PORT_SetError (SEC_ERROR_INVALID_ARGS);
michael@0 726 return NULL;
michael@0 727 }
michael@0 728
michael@0 729 if (arenaOpt != NULL)
michael@0 730 mark = PORT_ArenaMark (arenaOpt);
michael@0 731
michael@0 732 max_out_len = PL_Base64MaxDecodedLength (inLen);
michael@0 733 out_item = SECITEM_AllocItem (arenaOpt, outItemOpt, max_out_len);
michael@0 734 if (out_item == NULL) {
michael@0 735 if (arenaOpt != NULL)
michael@0 736 PORT_ArenaRelease (arenaOpt, mark);
michael@0 737 return NULL;
michael@0 738 }
michael@0 739
michael@0 740 dummy = PL_Base64DecodeBuffer (inStr, inLen, out_item->data,
michael@0 741 max_out_len, &out_len);
michael@0 742 if (dummy == NULL) {
michael@0 743 if (arenaOpt != NULL) {
michael@0 744 PORT_ArenaRelease (arenaOpt, mark);
michael@0 745 if (outItemOpt != NULL) {
michael@0 746 outItemOpt->data = NULL;
michael@0 747 outItemOpt->len = 0;
michael@0 748 }
michael@0 749 } else {
michael@0 750 SECITEM_FreeItem (out_item,
michael@0 751 (outItemOpt == NULL) ? PR_TRUE : PR_FALSE);
michael@0 752 }
michael@0 753 return NULL;
michael@0 754 }
michael@0 755
michael@0 756 if (arenaOpt != NULL)
michael@0 757 PORT_ArenaUnmark (arenaOpt, mark);
michael@0 758 out_item->len = out_len;
michael@0 759 return out_item;
michael@0 760 }
michael@0 761
michael@0 762
michael@0 763 /*
michael@0 764 * XXX Everything below is deprecated. If you add new stuff, put it
michael@0 765 * *above*, not below.
michael@0 766 */
michael@0 767
michael@0 768 /*
michael@0 769 * XXX The following "ATOB" functions are provided for backward compatibility
michael@0 770 * with current code. They should be considered strongly deprecated.
michael@0 771 * When we can convert all our code over to using the new NSSBase64Decoder_
michael@0 772 * functions defined above, we should get rid of these altogether. (Remove
michael@0 773 * protoypes from base64.h as well -- actually, remove that file completely).
michael@0 774 * If someone thinks either of these functions provides such a very useful
michael@0 775 * interface (though, as shown, the same functionality can already be
michael@0 776 * obtained by calling NSSBase64_DecodeBuffer directly), fine -- but then
michael@0 777 * that API should be provided with a nice new NSSFoo name and using
michael@0 778 * appropriate types, etc.
michael@0 779 */
michael@0 780
michael@0 781 #include "base64.h"
michael@0 782
michael@0 783 /*
michael@0 784 ** Return an PORT_Alloc'd string which is the base64 decoded version
michael@0 785 ** of the input string; set *lenp to the length of the returned data.
michael@0 786 */
michael@0 787 unsigned char *
michael@0 788 ATOB_AsciiToData(const char *string, unsigned int *lenp)
michael@0 789 {
michael@0 790 SECItem binary_item, *dummy;
michael@0 791
michael@0 792 binary_item.data = NULL;
michael@0 793 binary_item.len = 0;
michael@0 794
michael@0 795 dummy = NSSBase64_DecodeBuffer (NULL, &binary_item, string,
michael@0 796 (PRUint32) PORT_Strlen(string));
michael@0 797 if (dummy == NULL)
michael@0 798 return NULL;
michael@0 799
michael@0 800 PORT_Assert(dummy == &binary_item);
michael@0 801
michael@0 802 *lenp = dummy->len;
michael@0 803 return dummy->data;
michael@0 804 }
michael@0 805
michael@0 806 /*
michael@0 807 ** Convert from ascii to binary encoding of an item.
michael@0 808 */
michael@0 809 SECStatus
michael@0 810 ATOB_ConvertAsciiToItem(SECItem *binary_item, const char *ascii)
michael@0 811 {
michael@0 812 SECItem *dummy;
michael@0 813
michael@0 814 if (binary_item == NULL) {
michael@0 815 PORT_SetError (SEC_ERROR_INVALID_ARGS);
michael@0 816 return SECFailure;
michael@0 817 }
michael@0 818
michael@0 819 /*
michael@0 820 * XXX Would prefer to assert here if data is non-null (actually,
michael@0 821 * don't need to, just let NSSBase64_DecodeBuffer do it), so as to
michael@0 822 * to catch unintended memory leaks, but callers are not clean in
michael@0 823 * this respect so we need to explicitly clear here to avoid the
michael@0 824 * assert in NSSBase64_DecodeBuffer.
michael@0 825 */
michael@0 826 binary_item->data = NULL;
michael@0 827 binary_item->len = 0;
michael@0 828
michael@0 829 dummy = NSSBase64_DecodeBuffer (NULL, binary_item, ascii,
michael@0 830 (PRUint32) PORT_Strlen(ascii));
michael@0 831
michael@0 832 if (dummy == NULL)
michael@0 833 return SECFailure;
michael@0 834
michael@0 835 return SECSuccess;
michael@0 836 }

mercurial