1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/util/nssb64d.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,836 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +/* 1.9 + * Base64 decoding (ascii to binary). 1.10 + */ 1.11 + 1.12 +#include "nssb64.h" 1.13 +#include "nspr.h" 1.14 +#include "secitem.h" 1.15 +#include "secerr.h" 1.16 + 1.17 +/* 1.18 + * XXX We want this basic support to go into NSPR (the PL part). 1.19 + * Until that can happen, the PL interface is going to be kept entirely 1.20 + * internal here -- all static functions and opaque data structures. 1.21 + * When someone can get it moved over into NSPR, that should be done: 1.22 + * - giving everything names that are accepted by the NSPR module owners 1.23 + * (though I tried to choose ones that would work without modification) 1.24 + * - exporting the functions (remove static declarations and add 1.25 + * to nssutil.def as necessary) 1.26 + * - put prototypes into appropriate header file (probably replacing 1.27 + * the entire current lib/libc/include/plbase64.h in NSPR) 1.28 + * along with a typedef for the context structure (which should be 1.29 + * kept opaque -- definition in the source file only, but typedef 1.30 + * ala "typedef struct PLBase64FooStr PLBase64Foo;" in header file) 1.31 + * - modify anything else as necessary to conform to NSPR required style 1.32 + * (I looked but found no formatting guide to follow) 1.33 + * 1.34 + * You will want to move over everything from here down to the comment 1.35 + * which says "XXX End of base64 decoding code to be moved into NSPR", 1.36 + * into a new file in NSPR. 1.37 + */ 1.38 + 1.39 +/* 1.40 + ************************************************************** 1.41 + * XXX Beginning of base64 decoding code to be moved into NSPR. 1.42 + */ 1.43 + 1.44 +/* 1.45 + * This typedef would belong in the NSPR header file (i.e. plbase64.h). 1.46 + */ 1.47 +typedef struct PLBase64DecoderStr PLBase64Decoder; 1.48 + 1.49 +/* 1.50 + * The following implementation of base64 decoding was based on code 1.51 + * found in libmime (specifically, in mimeenc.c). It has been adapted to 1.52 + * use PR types and naming as well as to provide other necessary semantics 1.53 + * (like buffer-in/buffer-out in addition to "streaming" without undue 1.54 + * performance hit of extra copying if you made the buffer versions 1.55 + * use the output_fn). It also incorporates some aspects of the current 1.56 + * NSPR base64 decoding code. As such, you may find similarities to 1.57 + * both of those implementations. I tried to use names that reflected 1.58 + * the original code when possible. For this reason you may find some 1.59 + * inconsistencies -- libmime used lots of "in" and "out" whereas the 1.60 + * NSPR version uses "src" and "dest"; sometimes I changed one to the other 1.61 + * and sometimes I left them when I thought the subroutines were at least 1.62 + * self-consistent. 1.63 + */ 1.64 + 1.65 +PR_BEGIN_EXTERN_C 1.66 + 1.67 +/* 1.68 + * Opaque object used by the decoder to store state. 1.69 + */ 1.70 +struct PLBase64DecoderStr { 1.71 + /* Current token (or portion, if token_size < 4) being decoded. */ 1.72 + unsigned char token[4]; 1.73 + int token_size; 1.74 + 1.75 + /* 1.76 + * Where to write the decoded data (used when streaming, not when 1.77 + * doing all in-memory (buffer) operations). 1.78 + * 1.79 + * Note that this definition is chosen to be compatible with PR_Write. 1.80 + */ 1.81 + PRInt32 (*output_fn) (void *output_arg, const unsigned char *buf, 1.82 + PRInt32 size); 1.83 + void *output_arg; 1.84 + 1.85 + /* 1.86 + * Where the decoded output goes -- either temporarily (in the streaming 1.87 + * case, staged here before it goes to the output function) or what will 1.88 + * be the entire buffered result for users of the buffer version. 1.89 + */ 1.90 + unsigned char *output_buffer; 1.91 + PRUint32 output_buflen; /* the total length of allocated buffer */ 1.92 + PRUint32 output_length; /* the length that is currently populated */ 1.93 +}; 1.94 + 1.95 +PR_END_EXTERN_C 1.96 + 1.97 + 1.98 +/* 1.99 + * Table to convert an ascii "code" to its corresponding binary value. 1.100 + * For ease of use, the binary values in the table are the actual values 1.101 + * PLUS ONE. This is so that the special value of zero can denote an 1.102 + * invalid mapping; that was much easier than trying to fill in the other 1.103 + * values with some value other than zero, and to check for it. 1.104 + * Just remember to SUBTRACT ONE when using the value retrieved. 1.105 + */ 1.106 +static unsigned char base64_codetovaluep1[256] = { 1.107 +/* 0: */ 0, 0, 0, 0, 0, 0, 0, 0, 1.108 +/* 8: */ 0, 0, 0, 0, 0, 0, 0, 0, 1.109 +/* 16: */ 0, 0, 0, 0, 0, 0, 0, 0, 1.110 +/* 24: */ 0, 0, 0, 0, 0, 0, 0, 0, 1.111 +/* 32: */ 0, 0, 0, 0, 0, 0, 0, 0, 1.112 +/* 40: */ 0, 0, 0, 63, 0, 0, 0, 64, 1.113 +/* 48: */ 53, 54, 55, 56, 57, 58, 59, 60, 1.114 +/* 56: */ 61, 62, 0, 0, 0, 0, 0, 0, 1.115 +/* 64: */ 0, 1, 2, 3, 4, 5, 6, 7, 1.116 +/* 72: */ 8, 9, 10, 11, 12, 13, 14, 15, 1.117 +/* 80: */ 16, 17, 18, 19, 20, 21, 22, 23, 1.118 +/* 88: */ 24, 25, 26, 0, 0, 0, 0, 0, 1.119 +/* 96: */ 0, 27, 28, 29, 30, 31, 32, 33, 1.120 +/* 104: */ 34, 35, 36, 37, 38, 39, 40, 41, 1.121 +/* 112: */ 42, 43, 44, 45, 46, 47, 48, 49, 1.122 +/* 120: */ 50, 51, 52, 0, 0, 0, 0, 0, 1.123 +/* 128: */ 0, 0, 0, 0, 0, 0, 0, 0 1.124 +/* and rest are all zero as well */ 1.125 +}; 1.126 + 1.127 +#define B64_PAD '=' 1.128 + 1.129 + 1.130 +/* 1.131 + * Reads 4; writes 3 (known, or expected, to have no trailing padding). 1.132 + * Returns bytes written; -1 on error (unexpected character). 1.133 + */ 1.134 +static int 1.135 +pl_base64_decode_4to3 (const unsigned char *in, unsigned char *out) 1.136 +{ 1.137 + int j; 1.138 + PRUint32 num = 0; 1.139 + unsigned char bits; 1.140 + 1.141 + for (j = 0; j < 4; j++) { 1.142 + bits = base64_codetovaluep1[in[j]]; 1.143 + if (bits == 0) 1.144 + return -1; 1.145 + num = (num << 6) | (bits - 1); 1.146 + } 1.147 + 1.148 + out[0] = (unsigned char) (num >> 16); 1.149 + out[1] = (unsigned char) ((num >> 8) & 0xFF); 1.150 + out[2] = (unsigned char) (num & 0xFF); 1.151 + 1.152 + return 3; 1.153 +} 1.154 + 1.155 +/* 1.156 + * Reads 3; writes 2 (caller already confirmed EOF or trailing padding). 1.157 + * Returns bytes written; -1 on error (unexpected character). 1.158 + */ 1.159 +static int 1.160 +pl_base64_decode_3to2 (const unsigned char *in, unsigned char *out) 1.161 +{ 1.162 + PRUint32 num = 0; 1.163 + unsigned char bits1, bits2, bits3; 1.164 + 1.165 + bits1 = base64_codetovaluep1[in[0]]; 1.166 + bits2 = base64_codetovaluep1[in[1]]; 1.167 + bits3 = base64_codetovaluep1[in[2]]; 1.168 + 1.169 + if ((bits1 == 0) || (bits2 == 0) || (bits3 == 0)) 1.170 + return -1; 1.171 + 1.172 + num = ((PRUint32)(bits1 - 1)) << 10; 1.173 + num |= ((PRUint32)(bits2 - 1)) << 4; 1.174 + num |= ((PRUint32)(bits3 - 1)) >> 2; 1.175 + 1.176 + out[0] = (unsigned char) (num >> 8); 1.177 + out[1] = (unsigned char) (num & 0xFF); 1.178 + 1.179 + return 2; 1.180 +} 1.181 + 1.182 +/* 1.183 + * Reads 2; writes 1 (caller already confirmed EOF or trailing padding). 1.184 + * Returns bytes written; -1 on error (unexpected character). 1.185 + */ 1.186 +static int 1.187 +pl_base64_decode_2to1 (const unsigned char *in, unsigned char *out) 1.188 +{ 1.189 + PRUint32 num = 0; 1.190 + unsigned char bits1, bits2; 1.191 + 1.192 + bits1 = base64_codetovaluep1[in[0]]; 1.193 + bits2 = base64_codetovaluep1[in[1]]; 1.194 + 1.195 + if ((bits1 == 0) || (bits2 == 0)) 1.196 + return -1; 1.197 + 1.198 + num = ((PRUint32)(bits1 - 1)) << 2; 1.199 + num |= ((PRUint32)(bits2 - 1)) >> 4; 1.200 + 1.201 + out[0] = (unsigned char) num; 1.202 + 1.203 + return 1; 1.204 +} 1.205 + 1.206 +/* 1.207 + * Reads 4; writes 0-3. Returns bytes written or -1 on error. 1.208 + * (Writes less than 3 only at (presumed) EOF.) 1.209 + */ 1.210 +static int 1.211 +pl_base64_decode_token (const unsigned char *in, unsigned char *out) 1.212 +{ 1.213 + if (in[3] != B64_PAD) 1.214 + return pl_base64_decode_4to3 (in, out); 1.215 + 1.216 + if (in[2] == B64_PAD) 1.217 + return pl_base64_decode_2to1 (in, out); 1.218 + 1.219 + return pl_base64_decode_3to2 (in, out); 1.220 +} 1.221 + 1.222 +static PRStatus 1.223 +pl_base64_decode_buffer (PLBase64Decoder *data, const unsigned char *in, 1.224 + PRUint32 length) 1.225 +{ 1.226 + unsigned char *out = data->output_buffer; 1.227 + unsigned char *token = data->token; 1.228 + int i, n = 0; 1.229 + 1.230 + i = data->token_size; 1.231 + data->token_size = 0; 1.232 + 1.233 + while (length > 0) { 1.234 + while (i < 4 && length > 0) { 1.235 + /* 1.236 + * XXX Note that the following simply ignores any unexpected 1.237 + * characters. This is exactly what the original code in 1.238 + * libmime did, and I am leaving it. We certainly want to skip 1.239 + * over whitespace (we must); this does much more than that. 1.240 + * I am not confident changing it, and I don't want to slow 1.241 + * the processing down doing more complicated checking, but 1.242 + * someone else might have different ideas in the future. 1.243 + */ 1.244 + if (base64_codetovaluep1[*in] > 0 || *in == B64_PAD) 1.245 + token[i++] = *in; 1.246 + in++; 1.247 + length--; 1.248 + } 1.249 + 1.250 + if (i < 4) { 1.251 + /* Didn't get enough for a complete token. */ 1.252 + data->token_size = i; 1.253 + break; 1.254 + } 1.255 + i = 0; 1.256 + 1.257 + PR_ASSERT((out - data->output_buffer + 3) <= data->output_buflen); 1.258 + 1.259 + /* 1.260 + * Assume we are not at the end; the following function only works 1.261 + * for an internal token (no trailing padding characters) but is 1.262 + * faster that way. If it hits an invalid character (padding) it 1.263 + * will return an error; we break out of the loop and try again 1.264 + * calling the routine that will handle a final token. 1.265 + * Note that we intentionally do it this way rather than explicitly 1.266 + * add a check for padding here (because that would just slow down 1.267 + * the normal case) nor do we rely on checking whether we have more 1.268 + * input to process (because that would also slow it down but also 1.269 + * because we want to allow trailing garbage, especially white space 1.270 + * and cannot tell that without read-ahead, also a slow proposition). 1.271 + * Whew. Understand? 1.272 + */ 1.273 + n = pl_base64_decode_4to3 (token, out); 1.274 + if (n < 0) 1.275 + break; 1.276 + 1.277 + /* Advance "out" by the number of bytes just written to it. */ 1.278 + out += n; 1.279 + n = 0; 1.280 + } 1.281 + 1.282 + /* 1.283 + * See big comment above, before call to pl_base64_decode_4to3. 1.284 + * Here we check if we error'd out of loop, and allow for the case 1.285 + * that we are processing the last interesting token. If the routine 1.286 + * which should handle padding characters also fails, then we just 1.287 + * have bad input and give up. 1.288 + */ 1.289 + if (n < 0) { 1.290 + n = pl_base64_decode_token (token, out); 1.291 + if (n < 0) 1.292 + return PR_FAILURE; 1.293 + 1.294 + out += n; 1.295 + } 1.296 + 1.297 + /* 1.298 + * As explained above, we can get here with more input remaining, but 1.299 + * it should be all characters we do not care about (i.e. would be 1.300 + * ignored when transferring from "in" to "token" in loop above, 1.301 + * except here we choose to ignore extraneous pad characters, too). 1.302 + * Swallow it, performing that check. If we find more characters that 1.303 + * we would expect to decode, something is wrong. 1.304 + */ 1.305 + while (length > 0) { 1.306 + if (base64_codetovaluep1[*in] > 0) 1.307 + return PR_FAILURE; 1.308 + in++; 1.309 + length--; 1.310 + } 1.311 + 1.312 + /* Record the length of decoded data we have left in output_buffer. */ 1.313 + data->output_length = (PRUint32) (out - data->output_buffer); 1.314 + return PR_SUCCESS; 1.315 +} 1.316 + 1.317 +/* 1.318 + * Flush any remaining buffered characters. Given well-formed input, 1.319 + * this will have nothing to do. If the input was missing the padding 1.320 + * characters at the end, though, there could be 1-3 characters left 1.321 + * behind -- we will tolerate that by adding the padding for them. 1.322 + */ 1.323 +static PRStatus 1.324 +pl_base64_decode_flush (PLBase64Decoder *data) 1.325 +{ 1.326 + int count; 1.327 + 1.328 + /* 1.329 + * If no remaining characters, or all are padding (also not well-formed 1.330 + * input, but again, be tolerant), then nothing more to do. (And, that 1.331 + * is considered successful.) 1.332 + */ 1.333 + if (data->token_size == 0 || data->token[0] == B64_PAD) 1.334 + return PR_SUCCESS; 1.335 + 1.336 + /* 1.337 + * Assume we have all the interesting input except for some expected 1.338 + * padding characters. Add them and decode the resulting token. 1.339 + */ 1.340 + while (data->token_size < 4) 1.341 + data->token[data->token_size++] = B64_PAD; 1.342 + 1.343 + data->token_size = 0; /* so a subsequent flush call is a no-op */ 1.344 + 1.345 + count = pl_base64_decode_token (data->token, 1.346 + data->output_buffer + data->output_length); 1.347 + if (count < 0) 1.348 + return PR_FAILURE; 1.349 + 1.350 + /* 1.351 + * If there is an output function, call it with this last bit of data. 1.352 + * Otherwise we are doing all buffered output, and the decoded bytes 1.353 + * are now there, we just need to reflect that in the length. 1.354 + */ 1.355 + if (data->output_fn != NULL) { 1.356 + PRInt32 output_result; 1.357 + 1.358 + PR_ASSERT(data->output_length == 0); 1.359 + output_result = data->output_fn (data->output_arg, 1.360 + data->output_buffer, 1.361 + (PRInt32) count); 1.362 + if (output_result < 0) 1.363 + return PR_FAILURE; 1.364 + } else { 1.365 + data->output_length += count; 1.366 + } 1.367 + 1.368 + return PR_SUCCESS; 1.369 +} 1.370 + 1.371 + 1.372 +/* 1.373 + * The maximum space needed to hold the output of the decoder given 1.374 + * input data of length "size". 1.375 + */ 1.376 +static PRUint32 1.377 +PL_Base64MaxDecodedLength (PRUint32 size) 1.378 +{ 1.379 + return ((size * 3) / 4); 1.380 +} 1.381 + 1.382 + 1.383 +/* 1.384 + * A distinct internal creation function for the buffer version to use. 1.385 + * (It does not want to specify an output_fn, and we want the normal 1.386 + * Create function to require that.) If more common initialization 1.387 + * of the decoding context needs to be done, it should be done *here*. 1.388 + */ 1.389 +static PLBase64Decoder * 1.390 +pl_base64_create_decoder (void) 1.391 +{ 1.392 + return PR_NEWZAP(PLBase64Decoder); 1.393 +} 1.394 + 1.395 +/* 1.396 + * Function to start a base64 decoding context. 1.397 + * An "output_fn" is required; the "output_arg" parameter to that is optional. 1.398 + */ 1.399 +static PLBase64Decoder * 1.400 +PL_CreateBase64Decoder (PRInt32 (*output_fn) (void *, const unsigned char *, 1.401 + PRInt32), 1.402 + void *output_arg) 1.403 +{ 1.404 + PLBase64Decoder *data; 1.405 + 1.406 + if (output_fn == NULL) { 1.407 + PR_SetError (PR_INVALID_ARGUMENT_ERROR, 0); 1.408 + return NULL; 1.409 + } 1.410 + 1.411 + data = pl_base64_create_decoder (); 1.412 + if (data != NULL) { 1.413 + data->output_fn = output_fn; 1.414 + data->output_arg = output_arg; 1.415 + } 1.416 + return data; 1.417 +} 1.418 + 1.419 + 1.420 +/* 1.421 + * Push data through the decoder, causing the output_fn (provided to Create) 1.422 + * to be called with the decoded data. 1.423 + */ 1.424 +static PRStatus 1.425 +PL_UpdateBase64Decoder (PLBase64Decoder *data, const char *buffer, 1.426 + PRUint32 size) 1.427 +{ 1.428 + PRUint32 need_length; 1.429 + PRStatus status; 1.430 + 1.431 + /* XXX Should we do argument checking only in debug build? */ 1.432 + if (data == NULL || buffer == NULL || size == 0) { 1.433 + PR_SetError (PR_INVALID_ARGUMENT_ERROR, 0); 1.434 + return PR_FAILURE; 1.435 + } 1.436 + 1.437 + /* 1.438 + * How much space could this update need for decoding? 1.439 + */ 1.440 + need_length = PL_Base64MaxDecodedLength (size + data->token_size); 1.441 + 1.442 + /* 1.443 + * Make sure we have at least that much. If not, (re-)allocate. 1.444 + */ 1.445 + if (need_length > data->output_buflen) { 1.446 + unsigned char *output_buffer = data->output_buffer; 1.447 + 1.448 + if (output_buffer != NULL) 1.449 + output_buffer = (unsigned char *) PR_Realloc(output_buffer, 1.450 + need_length); 1.451 + else 1.452 + output_buffer = (unsigned char *) PR_Malloc(need_length); 1.453 + 1.454 + if (output_buffer == NULL) 1.455 + return PR_FAILURE; 1.456 + 1.457 + data->output_buffer = output_buffer; 1.458 + data->output_buflen = need_length; 1.459 + } 1.460 + 1.461 + /* There should not have been any leftover output data in the buffer. */ 1.462 + PR_ASSERT(data->output_length == 0); 1.463 + data->output_length = 0; 1.464 + 1.465 + status = pl_base64_decode_buffer (data, (const unsigned char *) buffer, 1.466 + size); 1.467 + 1.468 + /* Now that we have some decoded data, write it. */ 1.469 + if (status == PR_SUCCESS && data->output_length > 0) { 1.470 + PRInt32 output_result; 1.471 + 1.472 + PR_ASSERT(data->output_fn != NULL); 1.473 + output_result = data->output_fn (data->output_arg, 1.474 + data->output_buffer, 1.475 + (PRInt32) data->output_length); 1.476 + if (output_result < 0) 1.477 + status = PR_FAILURE; 1.478 + } 1.479 + 1.480 + data->output_length = 0; 1.481 + return status; 1.482 +} 1.483 + 1.484 + 1.485 +/* 1.486 + * When you're done decoding, call this to free the data. If "abort_p" 1.487 + * is false, then calling this may cause the output_fn to be called 1.488 + * one last time (as the last buffered data is flushed out). 1.489 + */ 1.490 +static PRStatus 1.491 +PL_DestroyBase64Decoder (PLBase64Decoder *data, PRBool abort_p) 1.492 +{ 1.493 + PRStatus status = PR_SUCCESS; 1.494 + 1.495 + /* XXX Should we do argument checking only in debug build? */ 1.496 + if (data == NULL) { 1.497 + PR_SetError (PR_INVALID_ARGUMENT_ERROR, 0); 1.498 + return PR_FAILURE; 1.499 + } 1.500 + 1.501 + /* Flush out the last few buffered characters. */ 1.502 + if (!abort_p) 1.503 + status = pl_base64_decode_flush (data); 1.504 + 1.505 + if (data->output_buffer != NULL) 1.506 + PR_Free(data->output_buffer); 1.507 + PR_Free(data); 1.508 + 1.509 + return status; 1.510 +} 1.511 + 1.512 + 1.513 +/* 1.514 + * Perform base64 decoding from an input buffer to an output buffer. 1.515 + * The output buffer can be provided (as "dest"); you can also pass in 1.516 + * a NULL and this function will allocate a buffer large enough for you, 1.517 + * and return it. If you do provide the output buffer, you must also 1.518 + * provide the maximum length of that buffer (as "maxdestlen"). 1.519 + * The actual decoded length of output will be returned to you in 1.520 + * "output_destlen". 1.521 + * 1.522 + * Return value is NULL on error, the output buffer (allocated or provided) 1.523 + * otherwise. 1.524 + */ 1.525 +static unsigned char * 1.526 +PL_Base64DecodeBuffer (const char *src, PRUint32 srclen, unsigned char *dest, 1.527 + PRUint32 maxdestlen, PRUint32 *output_destlen) 1.528 +{ 1.529 + PRUint32 need_length; 1.530 + unsigned char *output_buffer = NULL; 1.531 + PLBase64Decoder *data = NULL; 1.532 + PRStatus status; 1.533 + 1.534 + PR_ASSERT(srclen > 0); 1.535 + if (srclen == 0) { 1.536 + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 1.537 + return NULL; 1.538 + } 1.539 + 1.540 + /* 1.541 + * How much space could we possibly need for decoding this input? 1.542 + */ 1.543 + need_length = PL_Base64MaxDecodedLength (srclen); 1.544 + 1.545 + /* 1.546 + * Make sure we have at least that much, if output buffer provided. 1.547 + * If no output buffer provided, then we allocate that much. 1.548 + */ 1.549 + if (dest != NULL) { 1.550 + PR_ASSERT(maxdestlen >= need_length); 1.551 + if (maxdestlen < need_length) { 1.552 + PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0); 1.553 + goto loser; 1.554 + } 1.555 + output_buffer = dest; 1.556 + } else { 1.557 + output_buffer = (unsigned char *) PR_Malloc(need_length); 1.558 + if (output_buffer == NULL) 1.559 + goto loser; 1.560 + maxdestlen = need_length; 1.561 + } 1.562 + 1.563 + data = pl_base64_create_decoder(); 1.564 + if (data == NULL) 1.565 + goto loser; 1.566 + 1.567 + data->output_buflen = maxdestlen; 1.568 + data->output_buffer = output_buffer; 1.569 + 1.570 + status = pl_base64_decode_buffer (data, (const unsigned char *) src, 1.571 + srclen); 1.572 + 1.573 + /* 1.574 + * We do not wait for Destroy to flush, because Destroy will also 1.575 + * get rid of our decoder context, which we need to look at first! 1.576 + */ 1.577 + if (status == PR_SUCCESS) 1.578 + status = pl_base64_decode_flush (data); 1.579 + 1.580 + /* Must clear this or Destroy will free it. */ 1.581 + data->output_buffer = NULL; 1.582 + 1.583 + if (status == PR_SUCCESS) { 1.584 + *output_destlen = data->output_length; 1.585 + status = PL_DestroyBase64Decoder (data, PR_FALSE); 1.586 + data = NULL; 1.587 + if (status == PR_FAILURE) 1.588 + goto loser; 1.589 + return output_buffer; 1.590 + } 1.591 + 1.592 +loser: 1.593 + if (dest == NULL && output_buffer != NULL) 1.594 + PR_Free(output_buffer); 1.595 + if (data != NULL) 1.596 + (void) PL_DestroyBase64Decoder (data, PR_TRUE); 1.597 + return NULL; 1.598 +} 1.599 + 1.600 + 1.601 +/* 1.602 + * XXX End of base64 decoding code to be moved into NSPR. 1.603 + ******************************************************** 1.604 + */ 1.605 + 1.606 +/* 1.607 + * This is the beginning of the NSS cover functions. These will 1.608 + * provide the interface we want to expose as NSS-ish. For example, 1.609 + * they will operate on our Items, do any special handling or checking 1.610 + * we want to do, etc. 1.611 + */ 1.612 + 1.613 + 1.614 +PR_BEGIN_EXTERN_C 1.615 + 1.616 +/* 1.617 + * A boring cover structure for now. Perhaps someday it will include 1.618 + * some more interesting fields. 1.619 + */ 1.620 +struct NSSBase64DecoderStr { 1.621 + PLBase64Decoder *pl_data; 1.622 +}; 1.623 + 1.624 +PR_END_EXTERN_C 1.625 + 1.626 + 1.627 +/* 1.628 + * Function to start a base64 decoding context. 1.629 + */ 1.630 +NSSBase64Decoder * 1.631 +NSSBase64Decoder_Create (PRInt32 (*output_fn) (void *, const unsigned char *, 1.632 + PRInt32), 1.633 + void *output_arg) 1.634 +{ 1.635 + PLBase64Decoder *pl_data; 1.636 + NSSBase64Decoder *nss_data; 1.637 + 1.638 + nss_data = PORT_ZNew(NSSBase64Decoder); 1.639 + if (nss_data == NULL) 1.640 + return NULL; 1.641 + 1.642 + pl_data = PL_CreateBase64Decoder (output_fn, output_arg); 1.643 + if (pl_data == NULL) { 1.644 + PORT_Free(nss_data); 1.645 + return NULL; 1.646 + } 1.647 + 1.648 + nss_data->pl_data = pl_data; 1.649 + return nss_data; 1.650 +} 1.651 + 1.652 + 1.653 +/* 1.654 + * Push data through the decoder, causing the output_fn (provided to Create) 1.655 + * to be called with the decoded data. 1.656 + */ 1.657 +SECStatus 1.658 +NSSBase64Decoder_Update (NSSBase64Decoder *data, const char *buffer, 1.659 + PRUint32 size) 1.660 +{ 1.661 + PRStatus pr_status; 1.662 + 1.663 + /* XXX Should we do argument checking only in debug build? */ 1.664 + if (data == NULL) { 1.665 + PORT_SetError (SEC_ERROR_INVALID_ARGS); 1.666 + return SECFailure; 1.667 + } 1.668 + 1.669 + pr_status = PL_UpdateBase64Decoder (data->pl_data, buffer, size); 1.670 + if (pr_status == PR_FAILURE) 1.671 + return SECFailure; 1.672 + 1.673 + return SECSuccess; 1.674 +} 1.675 + 1.676 + 1.677 +/* 1.678 + * When you're done decoding, call this to free the data. If "abort_p" 1.679 + * is false, then calling this may cause the output_fn to be called 1.680 + * one last time (as the last buffered data is flushed out). 1.681 + */ 1.682 +SECStatus 1.683 +NSSBase64Decoder_Destroy (NSSBase64Decoder *data, PRBool abort_p) 1.684 +{ 1.685 + PRStatus pr_status; 1.686 + 1.687 + /* XXX Should we do argument checking only in debug build? */ 1.688 + if (data == NULL) { 1.689 + PORT_SetError (SEC_ERROR_INVALID_ARGS); 1.690 + return SECFailure; 1.691 + } 1.692 + 1.693 + pr_status = PL_DestroyBase64Decoder (data->pl_data, abort_p); 1.694 + 1.695 + PORT_Free(data); 1.696 + 1.697 + if (pr_status == PR_FAILURE) 1.698 + return SECFailure; 1.699 + 1.700 + return SECSuccess; 1.701 +} 1.702 + 1.703 + 1.704 +/* 1.705 + * Perform base64 decoding from an ascii string "inStr" to an Item. 1.706 + * The length of the input must be provided as "inLen". The Item 1.707 + * may be provided (as "outItemOpt"); you can also pass in a NULL 1.708 + * and the Item will be allocated for you. 1.709 + * 1.710 + * In any case, the data within the Item will be allocated for you. 1.711 + * All allocation will happen out of the passed-in "arenaOpt", if non-NULL. 1.712 + * If "arenaOpt" is NULL, standard allocation (heap) will be used and 1.713 + * you will want to free the result via SECITEM_FreeItem. 1.714 + * 1.715 + * Return value is NULL on error, the Item (allocated or provided) otherwise. 1.716 + */ 1.717 +SECItem * 1.718 +NSSBase64_DecodeBuffer (PLArenaPool *arenaOpt, SECItem *outItemOpt, 1.719 + const char *inStr, unsigned int inLen) 1.720 +{ 1.721 + SECItem *out_item = NULL; 1.722 + PRUint32 max_out_len = 0; 1.723 + PRUint32 out_len; 1.724 + void *mark = NULL; 1.725 + unsigned char *dummy; 1.726 + 1.727 + if ((outItemOpt != NULL && outItemOpt->data != NULL) || inLen == 0) { 1.728 + PORT_SetError (SEC_ERROR_INVALID_ARGS); 1.729 + return NULL; 1.730 + } 1.731 + 1.732 + if (arenaOpt != NULL) 1.733 + mark = PORT_ArenaMark (arenaOpt); 1.734 + 1.735 + max_out_len = PL_Base64MaxDecodedLength (inLen); 1.736 + out_item = SECITEM_AllocItem (arenaOpt, outItemOpt, max_out_len); 1.737 + if (out_item == NULL) { 1.738 + if (arenaOpt != NULL) 1.739 + PORT_ArenaRelease (arenaOpt, mark); 1.740 + return NULL; 1.741 + } 1.742 + 1.743 + dummy = PL_Base64DecodeBuffer (inStr, inLen, out_item->data, 1.744 + max_out_len, &out_len); 1.745 + if (dummy == NULL) { 1.746 + if (arenaOpt != NULL) { 1.747 + PORT_ArenaRelease (arenaOpt, mark); 1.748 + if (outItemOpt != NULL) { 1.749 + outItemOpt->data = NULL; 1.750 + outItemOpt->len = 0; 1.751 + } 1.752 + } else { 1.753 + SECITEM_FreeItem (out_item, 1.754 + (outItemOpt == NULL) ? PR_TRUE : PR_FALSE); 1.755 + } 1.756 + return NULL; 1.757 + } 1.758 + 1.759 + if (arenaOpt != NULL) 1.760 + PORT_ArenaUnmark (arenaOpt, mark); 1.761 + out_item->len = out_len; 1.762 + return out_item; 1.763 +} 1.764 + 1.765 + 1.766 +/* 1.767 + * XXX Everything below is deprecated. If you add new stuff, put it 1.768 + * *above*, not below. 1.769 + */ 1.770 + 1.771 +/* 1.772 + * XXX The following "ATOB" functions are provided for backward compatibility 1.773 + * with current code. They should be considered strongly deprecated. 1.774 + * When we can convert all our code over to using the new NSSBase64Decoder_ 1.775 + * functions defined above, we should get rid of these altogether. (Remove 1.776 + * protoypes from base64.h as well -- actually, remove that file completely). 1.777 + * If someone thinks either of these functions provides such a very useful 1.778 + * interface (though, as shown, the same functionality can already be 1.779 + * obtained by calling NSSBase64_DecodeBuffer directly), fine -- but then 1.780 + * that API should be provided with a nice new NSSFoo name and using 1.781 + * appropriate types, etc. 1.782 + */ 1.783 + 1.784 +#include "base64.h" 1.785 + 1.786 +/* 1.787 +** Return an PORT_Alloc'd string which is the base64 decoded version 1.788 +** of the input string; set *lenp to the length of the returned data. 1.789 +*/ 1.790 +unsigned char * 1.791 +ATOB_AsciiToData(const char *string, unsigned int *lenp) 1.792 +{ 1.793 + SECItem binary_item, *dummy; 1.794 + 1.795 + binary_item.data = NULL; 1.796 + binary_item.len = 0; 1.797 + 1.798 + dummy = NSSBase64_DecodeBuffer (NULL, &binary_item, string, 1.799 + (PRUint32) PORT_Strlen(string)); 1.800 + if (dummy == NULL) 1.801 + return NULL; 1.802 + 1.803 + PORT_Assert(dummy == &binary_item); 1.804 + 1.805 + *lenp = dummy->len; 1.806 + return dummy->data; 1.807 +} 1.808 + 1.809 +/* 1.810 +** Convert from ascii to binary encoding of an item. 1.811 +*/ 1.812 +SECStatus 1.813 +ATOB_ConvertAsciiToItem(SECItem *binary_item, const char *ascii) 1.814 +{ 1.815 + SECItem *dummy; 1.816 + 1.817 + if (binary_item == NULL) { 1.818 + PORT_SetError (SEC_ERROR_INVALID_ARGS); 1.819 + return SECFailure; 1.820 + } 1.821 + 1.822 + /* 1.823 + * XXX Would prefer to assert here if data is non-null (actually, 1.824 + * don't need to, just let NSSBase64_DecodeBuffer do it), so as to 1.825 + * to catch unintended memory leaks, but callers are not clean in 1.826 + * this respect so we need to explicitly clear here to avoid the 1.827 + * assert in NSSBase64_DecodeBuffer. 1.828 + */ 1.829 + binary_item->data = NULL; 1.830 + binary_item->len = 0; 1.831 + 1.832 + dummy = NSSBase64_DecodeBuffer (NULL, binary_item, ascii, 1.833 + (PRUint32) PORT_Strlen(ascii)); 1.834 + 1.835 + if (dummy == NULL) 1.836 + return SECFailure; 1.837 + 1.838 + return SECSuccess; 1.839 +}