security/nss/lib/util/nssb64d.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial