security/nss/lib/util/nssb64d.c

changeset 0
6474c204b198
     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 +}

mercurial