1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/util/nssb64e.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,731 @@ 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 encoding (binary to ascii). 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 See the big comment at the top of nssb64d.c about moving the 1.19 + * bulk of this code over into NSPR (the PL part). It all applies 1.20 + * here but I didn't want to duplicate it, to avoid divergence problems. 1.21 + */ 1.22 + 1.23 +/* 1.24 + ************************************************************** 1.25 + * XXX Beginning of base64 encoding code to be moved into NSPR. 1.26 + */ 1.27 + 1.28 + 1.29 +struct PLBase64EncodeStateStr { 1.30 + unsigned chunks; 1.31 + unsigned saved; 1.32 + unsigned char buf[3]; 1.33 +}; 1.34 + 1.35 +/* 1.36 + * This typedef would belong in the NSPR header file (i.e. plbase64.h). 1.37 + */ 1.38 +typedef struct PLBase64EncoderStr PLBase64Encoder; 1.39 + 1.40 +/* 1.41 + * The following implementation of base64 encoding was based on code 1.42 + * found in libmime (specifically, in mimeenc.c). It has been adapted to 1.43 + * use PR types and naming as well as to provide other necessary semantics 1.44 + * (like buffer-in/buffer-out in addition to "streaming" without undue 1.45 + * performance hit of extra copying if you made the buffer versions 1.46 + * use the output_fn). It also incorporates some aspects of the current 1.47 + * NSPR base64 encoding code. As such, you may find similarities to 1.48 + * both of those implementations. I tried to use names that reflected 1.49 + * the original code when possible. For this reason you may find some 1.50 + * inconsistencies -- libmime used lots of "in" and "out" whereas the 1.51 + * NSPR version uses "src" and "dest"; sometimes I changed one to the other 1.52 + * and sometimes I left them when I thought the subroutines were at least 1.53 + * self-consistent. 1.54 + */ 1.55 + 1.56 +PR_BEGIN_EXTERN_C 1.57 + 1.58 +/* 1.59 + * Opaque object used by the encoder to store state. 1.60 + */ 1.61 +struct PLBase64EncoderStr { 1.62 + /* 1.63 + * The one or two bytes pending. (We need 3 to create a "token", 1.64 + * and hold the leftovers here. in_buffer_count is *only* ever 1.65 + * 0, 1, or 2. 1.66 + */ 1.67 + unsigned char in_buffer[2]; 1.68 + int in_buffer_count; 1.69 + 1.70 + /* 1.71 + * If the caller wants linebreaks added, line_length specifies 1.72 + * where they come out. It must be a multiple of 4; if the caller 1.73 + * provides one that isn't, we round it down to the nearest 1.74 + * multiple of 4. 1.75 + * 1.76 + * The value of current_column counts how many characters have been 1.77 + * added since the last linebreaks (or since the beginning, on the 1.78 + * first line). It is also always a multiple of 4; it is unused when 1.79 + * line_length is 0. 1.80 + */ 1.81 + PRUint32 line_length; 1.82 + PRUint32 current_column; 1.83 + 1.84 + /* 1.85 + * Where to write the encoded data (used when streaming, not when 1.86 + * doing all in-memory (buffer) operations). 1.87 + * 1.88 + * Note that this definition is chosen to be compatible with PR_Write. 1.89 + */ 1.90 + PRInt32 (*output_fn) (void *output_arg, const char *buf, PRInt32 size); 1.91 + void *output_arg; 1.92 + 1.93 + /* 1.94 + * Where the encoded output goes -- either temporarily (in the streaming 1.95 + * case, staged here before it goes to the output function) or what will 1.96 + * be the entire buffered result for users of the buffer version. 1.97 + */ 1.98 + char *output_buffer; 1.99 + PRUint32 output_buflen; /* the total length of allocated buffer */ 1.100 + PRUint32 output_length; /* the length that is currently populated */ 1.101 +}; 1.102 + 1.103 +PR_END_EXTERN_C 1.104 + 1.105 + 1.106 +/* 1.107 + * Table to convert a binary value to its corresponding ascii "code". 1.108 + */ 1.109 +static unsigned char base64_valuetocode[64] = 1.110 + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 1.111 + 1.112 +#define B64_PAD '=' 1.113 +#define B64_CR '\r' 1.114 +#define B64_LF '\n' 1.115 + 1.116 +static PRStatus 1.117 +pl_base64_encode_buffer (PLBase64Encoder *data, const unsigned char *in, 1.118 + PRUint32 size) 1.119 +{ 1.120 + const unsigned char *end = in + size; 1.121 + char *out = data->output_buffer + data->output_length; 1.122 + unsigned int i = data->in_buffer_count; 1.123 + PRUint32 n = 0; 1.124 + int off; 1.125 + PRUint32 output_threshold; 1.126 + 1.127 + /* If this input buffer is too small, wait until next time. */ 1.128 + if (size < (3 - i)) { 1.129 + data->in_buffer[i++] = in[0]; 1.130 + if (size > 1) 1.131 + data->in_buffer[i++] = in[1]; 1.132 + PR_ASSERT(i < 3); 1.133 + data->in_buffer_count = i; 1.134 + return PR_SUCCESS; 1.135 + } 1.136 + 1.137 + /* If there are bytes that were put back last time, take them now. */ 1.138 + if (i > 0) { 1.139 + n = data->in_buffer[0]; 1.140 + if (i > 1) 1.141 + n = (n << 8) | data->in_buffer[1]; 1.142 + data->in_buffer_count = 0; 1.143 + } 1.144 + 1.145 + /* If our total is not a multiple of three, put one or two bytes back. */ 1.146 + off = (size + i) % 3; 1.147 + if (off > 0) { 1.148 + size -= off; 1.149 + data->in_buffer[0] = in[size]; 1.150 + if (off > 1) 1.151 + data->in_buffer[1] = in[size + 1]; 1.152 + data->in_buffer_count = off; 1.153 + end -= off; 1.154 + } 1.155 + 1.156 + output_threshold = data->output_buflen - 3; 1.157 + 1.158 + /* 1.159 + * Populate the output buffer with base64 data, one line (or buffer) 1.160 + * at a time. 1.161 + */ 1.162 + while (in < end) { 1.163 + int j, k; 1.164 + 1.165 + while (i < 3) { 1.166 + n = (n << 8) | *in++; 1.167 + i++; 1.168 + } 1.169 + i = 0; 1.170 + 1.171 + if (data->line_length > 0) { 1.172 + if (data->current_column >= data->line_length) { 1.173 + data->current_column = 0; 1.174 + *out++ = B64_CR; 1.175 + *out++ = B64_LF; 1.176 + data->output_length += 2; 1.177 + } 1.178 + data->current_column += 4; /* the bytes we are about to add */ 1.179 + } 1.180 + 1.181 + for (j = 18; j >= 0; j -= 6) { 1.182 + k = (n >> j) & 0x3F; 1.183 + *out++ = base64_valuetocode[k]; 1.184 + } 1.185 + n = 0; 1.186 + data->output_length += 4; 1.187 + 1.188 + if (data->output_length >= output_threshold) { 1.189 + PR_ASSERT(data->output_length <= data->output_buflen); 1.190 + if (data->output_fn != NULL) { 1.191 + PRInt32 output_result; 1.192 + 1.193 + output_result = data->output_fn (data->output_arg, 1.194 + data->output_buffer, 1.195 + (PRInt32) data->output_length); 1.196 + if (output_result < 0) 1.197 + return PR_FAILURE; 1.198 + 1.199 + out = data->output_buffer; 1.200 + data->output_length = 0; 1.201 + } else { 1.202 + /* 1.203 + * Check that we are about to exit the loop. (Since we 1.204 + * are over the threshold, there isn't enough room in the 1.205 + * output buffer for another trip around.) 1.206 + */ 1.207 + PR_ASSERT(in == end); 1.208 + if (in < end) { 1.209 + PR_SetError (PR_BUFFER_OVERFLOW_ERROR, 0); 1.210 + return PR_FAILURE; 1.211 + } 1.212 + } 1.213 + } 1.214 + } 1.215 + 1.216 + return PR_SUCCESS; 1.217 +} 1.218 + 1.219 +static PRStatus 1.220 +pl_base64_encode_flush (PLBase64Encoder *data) 1.221 +{ 1.222 + int i = data->in_buffer_count; 1.223 + 1.224 + if (i == 0 && data->output_length == 0) 1.225 + return PR_SUCCESS; 1.226 + 1.227 + if (i > 0) { 1.228 + char *out = data->output_buffer + data->output_length; 1.229 + PRUint32 n; 1.230 + int j, k; 1.231 + 1.232 + n = ((PRUint32) data->in_buffer[0]) << 16; 1.233 + if (i > 1) 1.234 + n |= ((PRUint32) data->in_buffer[1] << 8); 1.235 + 1.236 + data->in_buffer_count = 0; 1.237 + 1.238 + if (data->line_length > 0) { 1.239 + if (data->current_column >= data->line_length) { 1.240 + data->current_column = 0; 1.241 + *out++ = B64_CR; 1.242 + *out++ = B64_LF; 1.243 + data->output_length += 2; 1.244 + } 1.245 + } 1.246 + 1.247 + /* 1.248 + * This will fill in more than we really have data for, but the 1.249 + * valid parts will end up in the correct position and the extras 1.250 + * will be over-written with pad characters below. 1.251 + */ 1.252 + for (j = 18; j >= 0; j -= 6) { 1.253 + k = (n >> j) & 0x3F; 1.254 + *out++ = base64_valuetocode[k]; 1.255 + } 1.256 + 1.257 + /* Pad with equal-signs. */ 1.258 + if (i == 1) 1.259 + out[-2] = B64_PAD; 1.260 + out[-1] = B64_PAD; 1.261 + 1.262 + data->output_length += 4; 1.263 + } 1.264 + 1.265 + if (data->output_fn != NULL) { 1.266 + PRInt32 output_result; 1.267 + 1.268 + output_result = data->output_fn (data->output_arg, data->output_buffer, 1.269 + (PRInt32) data->output_length); 1.270 + data->output_length = 0; 1.271 + 1.272 + if (output_result < 0) 1.273 + return PR_FAILURE; 1.274 + } 1.275 + 1.276 + return PR_SUCCESS; 1.277 +} 1.278 + 1.279 + 1.280 +/* 1.281 + * The maximum space needed to hold the output of the encoder given input 1.282 + * data of length "size", and allowing for CRLF added at least every 1.283 + * line_length bytes (we will add it at nearest lower multiple of 4). 1.284 + * There is no trailing CRLF. 1.285 + */ 1.286 +static PRUint32 1.287 +PL_Base64MaxEncodedLength (PRUint32 size, PRUint32 line_length) 1.288 +{ 1.289 + PRUint32 tokens, tokens_per_line, full_lines, line_break_chars, remainder; 1.290 + 1.291 + tokens = (size + 2) / 3; 1.292 + 1.293 + if (line_length == 0) 1.294 + return tokens * 4; 1.295 + 1.296 + if (line_length < 4) /* too small! */ 1.297 + line_length = 4; 1.298 + 1.299 + tokens_per_line = line_length / 4; 1.300 + full_lines = tokens / tokens_per_line; 1.301 + remainder = (tokens - (full_lines * tokens_per_line)) * 4; 1.302 + line_break_chars = full_lines * 2; 1.303 + if (remainder == 0) 1.304 + line_break_chars -= 2; 1.305 + 1.306 + return (full_lines * tokens_per_line * 4) + line_break_chars + remainder; 1.307 +} 1.308 + 1.309 + 1.310 +/* 1.311 + * A distinct internal creation function for the buffer version to use. 1.312 + * (It does not want to specify an output_fn, and we want the normal 1.313 + * Create function to require that.) All common initialization of the 1.314 + * encoding context should be done *here*. 1.315 + * 1.316 + * Save "line_length", rounded down to nearest multiple of 4 (if not 1.317 + * already even multiple). Allocate output_buffer, if not provided -- 1.318 + * based on given size if specified, otherwise based on line_length. 1.319 + */ 1.320 +static PLBase64Encoder * 1.321 +pl_base64_create_encoder (PRUint32 line_length, char *output_buffer, 1.322 + PRUint32 output_buflen) 1.323 +{ 1.324 + PLBase64Encoder *data; 1.325 + PRUint32 line_tokens; 1.326 + 1.327 + data = PR_NEWZAP(PLBase64Encoder); 1.328 + if (data == NULL) 1.329 + return NULL; 1.330 + 1.331 + if (line_length > 0 && line_length < 4) /* too small! */ 1.332 + line_length = 4; 1.333 + 1.334 + line_tokens = line_length / 4; 1.335 + data->line_length = line_tokens * 4; 1.336 + 1.337 + if (output_buffer == NULL) { 1.338 + if (output_buflen == 0) { 1.339 + if (data->line_length > 0) /* need to include room for CRLF */ 1.340 + output_buflen = data->line_length + 2; 1.341 + else 1.342 + output_buflen = 64; /* XXX what is a good size? */ 1.343 + } 1.344 + 1.345 + output_buffer = (char *) PR_Malloc(output_buflen); 1.346 + if (output_buffer == NULL) { 1.347 + PR_Free(data); 1.348 + return NULL; 1.349 + } 1.350 + } 1.351 + 1.352 + data->output_buffer = output_buffer; 1.353 + data->output_buflen = output_buflen; 1.354 + return data; 1.355 +} 1.356 + 1.357 +/* 1.358 + * Function to start a base64 encoding context. 1.359 + * An "output_fn" is required; the "output_arg" parameter to that is optional. 1.360 + * If linebreaks in the encoded output are desired, "line_length" specifies 1.361 + * where to place them -- it will be rounded down to the nearest multiple of 4 1.362 + * (if it is not already an even multiple of 4). If it is zero, no linebreaks 1.363 + * will be added. (FYI, a linebreak is CRLF -- two characters.) 1.364 + */ 1.365 +static PLBase64Encoder * 1.366 +PL_CreateBase64Encoder (PRInt32 (*output_fn) (void *, const char *, PRInt32), 1.367 + void *output_arg, PRUint32 line_length) 1.368 +{ 1.369 + PLBase64Encoder *data; 1.370 + 1.371 + if (output_fn == NULL) { 1.372 + PR_SetError (PR_INVALID_ARGUMENT_ERROR, 0); 1.373 + return NULL; 1.374 + } 1.375 + 1.376 + data = pl_base64_create_encoder (line_length, NULL, 0); 1.377 + if (data == NULL) 1.378 + return NULL; 1.379 + 1.380 + data->output_fn = output_fn; 1.381 + data->output_arg = output_arg; 1.382 + 1.383 + return data; 1.384 +} 1.385 + 1.386 + 1.387 +/* 1.388 + * Push data through the encoder, causing the output_fn (provided to Create) 1.389 + * to be called with the encoded data. 1.390 + */ 1.391 +static PRStatus 1.392 +PL_UpdateBase64Encoder (PLBase64Encoder *data, const unsigned char *buffer, 1.393 + PRUint32 size) 1.394 +{ 1.395 + /* XXX Should we do argument checking only in debug build? */ 1.396 + if (data == NULL || buffer == NULL || size == 0) { 1.397 + PR_SetError (PR_INVALID_ARGUMENT_ERROR, 0); 1.398 + return PR_FAILURE; 1.399 + } 1.400 + 1.401 + return pl_base64_encode_buffer (data, buffer, size); 1.402 +} 1.403 + 1.404 + 1.405 +/* 1.406 + * When you're done encoding, call this to free the data. If "abort_p" 1.407 + * is false, then calling this may cause the output_fn to be called 1.408 + * one last time (as the last buffered data is flushed out). 1.409 + */ 1.410 +static PRStatus 1.411 +PL_DestroyBase64Encoder (PLBase64Encoder *data, PRBool abort_p) 1.412 +{ 1.413 + PRStatus status = PR_SUCCESS; 1.414 + 1.415 + /* XXX Should we do argument checking only in debug build? */ 1.416 + if (data == NULL) { 1.417 + PR_SetError (PR_INVALID_ARGUMENT_ERROR, 0); 1.418 + return PR_FAILURE; 1.419 + } 1.420 + 1.421 + /* Flush out the last few buffered characters. */ 1.422 + if (!abort_p) 1.423 + status = pl_base64_encode_flush (data); 1.424 + 1.425 + if (data->output_buffer != NULL) 1.426 + PR_Free(data->output_buffer); 1.427 + PR_Free(data); 1.428 + 1.429 + return status; 1.430 +} 1.431 + 1.432 + 1.433 +/* 1.434 + * Perform base64 encoding from an input buffer to an output buffer. 1.435 + * The output buffer can be provided (as "dest"); you can also pass in 1.436 + * a NULL and this function will allocate a buffer large enough for you, 1.437 + * and return it. If you do provide the output buffer, you must also 1.438 + * provide the maximum length of that buffer (as "maxdestlen"). 1.439 + * The actual encoded length of output will be returned to you in 1.440 + * "output_destlen". 1.441 + * 1.442 + * If linebreaks in the encoded output are desired, "line_length" specifies 1.443 + * where to place them -- it will be rounded down to the nearest multiple of 4 1.444 + * (if it is not already an even multiple of 4). If it is zero, no linebreaks 1.445 + * will be added. (FYI, a linebreak is CRLF -- two characters.) 1.446 + * 1.447 + * Return value is NULL on error, the output buffer (allocated or provided) 1.448 + * otherwise. 1.449 + */ 1.450 +static char * 1.451 +PL_Base64EncodeBuffer (const unsigned char *src, PRUint32 srclen, 1.452 + PRUint32 line_length, char *dest, PRUint32 maxdestlen, 1.453 + PRUint32 *output_destlen) 1.454 +{ 1.455 + PRUint32 need_length; 1.456 + PLBase64Encoder *data = NULL; 1.457 + PRStatus status; 1.458 + 1.459 + PR_ASSERT(srclen > 0); 1.460 + if (srclen == 0) 1.461 + return dest; 1.462 + 1.463 + /* 1.464 + * How much space could we possibly need for encoding this input? 1.465 + */ 1.466 + need_length = PL_Base64MaxEncodedLength (srclen, line_length); 1.467 + 1.468 + /* 1.469 + * Make sure we have at least that much, if output buffer provided. 1.470 + */ 1.471 + if (dest != NULL) { 1.472 + PR_ASSERT(maxdestlen >= need_length); 1.473 + if (maxdestlen < need_length) { 1.474 + PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0); 1.475 + return NULL; 1.476 + } 1.477 + } else { 1.478 + maxdestlen = need_length; 1.479 + } 1.480 + 1.481 + data = pl_base64_create_encoder(line_length, dest, maxdestlen); 1.482 + if (data == NULL) 1.483 + return NULL; 1.484 + 1.485 + status = pl_base64_encode_buffer (data, src, srclen); 1.486 + 1.487 + /* 1.488 + * We do not wait for Destroy to flush, because Destroy will also 1.489 + * get rid of our encoder context, which we need to look at first! 1.490 + */ 1.491 + if (status == PR_SUCCESS) 1.492 + status = pl_base64_encode_flush (data); 1.493 + 1.494 + if (status != PR_SUCCESS) { 1.495 + (void) PL_DestroyBase64Encoder (data, PR_TRUE); 1.496 + return NULL; 1.497 + } 1.498 + 1.499 + dest = data->output_buffer; 1.500 + 1.501 + /* Must clear this or Destroy will free it. */ 1.502 + data->output_buffer = NULL; 1.503 + 1.504 + *output_destlen = data->output_length; 1.505 + status = PL_DestroyBase64Encoder (data, PR_FALSE); 1.506 + if (status == PR_FAILURE) { 1.507 + PR_Free(dest); 1.508 + return NULL; 1.509 + } 1.510 + 1.511 + return dest; 1.512 +} 1.513 + 1.514 +/* 1.515 + * XXX End of base64 encoding code to be moved into NSPR. 1.516 + ******************************************************** 1.517 + */ 1.518 + 1.519 +/* 1.520 + * This is the beginning of the NSS cover functions. These will 1.521 + * provide the interface we want to expose as NSS-ish. For example, 1.522 + * they will operate on our Items, do any special handling or checking 1.523 + * we want to do, etc. 1.524 + */ 1.525 + 1.526 + 1.527 +PR_BEGIN_EXTERN_C 1.528 + 1.529 +/* 1.530 + * A boring cover structure for now. Perhaps someday it will include 1.531 + * some more interesting fields. 1.532 + */ 1.533 +struct NSSBase64EncoderStr { 1.534 + PLBase64Encoder *pl_data; 1.535 +}; 1.536 + 1.537 +PR_END_EXTERN_C 1.538 + 1.539 + 1.540 +/* 1.541 + * Function to start a base64 encoding context. 1.542 + */ 1.543 +NSSBase64Encoder * 1.544 +NSSBase64Encoder_Create (PRInt32 (*output_fn) (void *, const char *, PRInt32), 1.545 + void *output_arg) 1.546 +{ 1.547 + PLBase64Encoder *pl_data; 1.548 + NSSBase64Encoder *nss_data; 1.549 + 1.550 + nss_data = PORT_ZNew(NSSBase64Encoder); 1.551 + if (nss_data == NULL) 1.552 + return NULL; 1.553 + 1.554 + pl_data = PL_CreateBase64Encoder (output_fn, output_arg, 64); 1.555 + if (pl_data == NULL) { 1.556 + PORT_Free(nss_data); 1.557 + return NULL; 1.558 + } 1.559 + 1.560 + nss_data->pl_data = pl_data; 1.561 + return nss_data; 1.562 +} 1.563 + 1.564 + 1.565 +/* 1.566 + * Push data through the encoder, causing the output_fn (provided to Create) 1.567 + * to be called with the encoded data. 1.568 + */ 1.569 +SECStatus 1.570 +NSSBase64Encoder_Update (NSSBase64Encoder *data, const unsigned char *buffer, 1.571 + PRUint32 size) 1.572 +{ 1.573 + PRStatus pr_status; 1.574 + 1.575 + /* XXX Should we do argument checking only in debug build? */ 1.576 + if (data == NULL) { 1.577 + PORT_SetError (SEC_ERROR_INVALID_ARGS); 1.578 + return SECFailure; 1.579 + } 1.580 + 1.581 + pr_status = PL_UpdateBase64Encoder (data->pl_data, buffer, size); 1.582 + if (pr_status == PR_FAILURE) 1.583 + return SECFailure; 1.584 + 1.585 + return SECSuccess; 1.586 +} 1.587 + 1.588 + 1.589 +/* 1.590 + * When you're done encoding, call this to free the data. If "abort_p" 1.591 + * is false, then calling this may cause the output_fn to be called 1.592 + * one last time (as the last buffered data is flushed out). 1.593 + */ 1.594 +SECStatus 1.595 +NSSBase64Encoder_Destroy (NSSBase64Encoder *data, PRBool abort_p) 1.596 +{ 1.597 + PRStatus pr_status; 1.598 + 1.599 + /* XXX Should we do argument checking only in debug build? */ 1.600 + if (data == NULL) { 1.601 + PORT_SetError (SEC_ERROR_INVALID_ARGS); 1.602 + return SECFailure; 1.603 + } 1.604 + 1.605 + pr_status = PL_DestroyBase64Encoder (data->pl_data, abort_p); 1.606 + 1.607 + PORT_Free(data); 1.608 + 1.609 + if (pr_status == PR_FAILURE) 1.610 + return SECFailure; 1.611 + 1.612 + return SECSuccess; 1.613 +} 1.614 + 1.615 + 1.616 +/* 1.617 + * Perform base64 encoding of binary data "inItem" to an ascii string. 1.618 + * The output buffer may be provided (as "outStrOpt"); you can also pass 1.619 + * in a NULL and the buffer will be allocated for you. The result will 1.620 + * be null-terminated, and if the buffer is provided, "maxOutLen" must 1.621 + * specify the maximum length of the buffer and will be checked to 1.622 + * supply sufficient space space for the encoded result. (If "outStrOpt" 1.623 + * is NULL, "maxOutLen" is ignored.) 1.624 + * 1.625 + * If "outStrOpt" is NULL, allocation will happen out of the passed-in 1.626 + * "arenaOpt", if *it* is non-NULL, otherwise standard allocation (heap) 1.627 + * will be used. 1.628 + * 1.629 + * Return value is NULL on error, the output buffer (allocated or provided) 1.630 + * otherwise. 1.631 + */ 1.632 +char * 1.633 +NSSBase64_EncodeItem (PLArenaPool *arenaOpt, char *outStrOpt, 1.634 + unsigned int maxOutLen, SECItem *inItem) 1.635 +{ 1.636 + char *out_string = outStrOpt; 1.637 + PRUint32 max_out_len; 1.638 + PRUint32 out_len; 1.639 + void *mark = NULL; 1.640 + char *dummy; 1.641 + 1.642 + PORT_Assert(inItem != NULL && inItem->data != NULL && inItem->len != 0); 1.643 + if (inItem == NULL || inItem->data == NULL || inItem->len == 0) { 1.644 + PORT_SetError (SEC_ERROR_INVALID_ARGS); 1.645 + return NULL; 1.646 + } 1.647 + 1.648 + max_out_len = PL_Base64MaxEncodedLength (inItem->len, 64); 1.649 + 1.650 + if (arenaOpt != NULL) 1.651 + mark = PORT_ArenaMark (arenaOpt); 1.652 + 1.653 + if (out_string == NULL) { 1.654 + if (arenaOpt != NULL) 1.655 + out_string = PORT_ArenaAlloc (arenaOpt, max_out_len + 1); 1.656 + else 1.657 + out_string = PORT_Alloc (max_out_len + 1); 1.658 + 1.659 + if (out_string == NULL) { 1.660 + if (arenaOpt != NULL) 1.661 + PORT_ArenaRelease (arenaOpt, mark); 1.662 + return NULL; 1.663 + } 1.664 + } else { 1.665 + if ((max_out_len + 1) > maxOutLen) { 1.666 + PORT_SetError (SEC_ERROR_OUTPUT_LEN); 1.667 + return NULL; 1.668 + } 1.669 + max_out_len = maxOutLen; 1.670 + } 1.671 + 1.672 + 1.673 + dummy = PL_Base64EncodeBuffer (inItem->data, inItem->len, 64, 1.674 + out_string, max_out_len, &out_len); 1.675 + if (dummy == NULL) { 1.676 + if (arenaOpt != NULL) { 1.677 + PORT_ArenaRelease (arenaOpt, mark); 1.678 + } else { 1.679 + PORT_Free (out_string); 1.680 + } 1.681 + return NULL; 1.682 + } 1.683 + 1.684 + if (arenaOpt != NULL) 1.685 + PORT_ArenaUnmark (arenaOpt, mark); 1.686 + 1.687 + out_string[out_len] = '\0'; 1.688 + return out_string; 1.689 +} 1.690 + 1.691 + 1.692 +/* 1.693 + * XXX Everything below is deprecated. If you add new stuff, put it 1.694 + * *above*, not below. 1.695 + */ 1.696 + 1.697 +/* 1.698 + * XXX The following "BTOA" functions are provided for backward compatibility 1.699 + * with current code. They should be considered strongly deprecated. 1.700 + * When we can convert all our code over to using the new NSSBase64Encoder_ 1.701 + * functions defined above, we should get rid of these altogether. (Remove 1.702 + * protoypes from base64.h as well -- actually, remove that file completely). 1.703 + * If someone thinks either of these functions provides such a very useful 1.704 + * interface (though, as shown, the same functionality can already be 1.705 + * obtained by calling NSSBase64_EncodeItem directly), fine -- but then 1.706 + * that API should be provided with a nice new NSSFoo name and using 1.707 + * appropriate types, etc. 1.708 + */ 1.709 + 1.710 +#include "base64.h" 1.711 + 1.712 +/* 1.713 +** Return an PORT_Alloc'd ascii string which is the base64 encoded 1.714 +** version of the input string. 1.715 +*/ 1.716 +char * 1.717 +BTOA_DataToAscii(const unsigned char *data, unsigned int len) 1.718 +{ 1.719 + SECItem binary_item; 1.720 + 1.721 + binary_item.data = (unsigned char *)data; 1.722 + binary_item.len = len; 1.723 + 1.724 + return NSSBase64_EncodeItem (NULL, NULL, 0, &binary_item); 1.725 +} 1.726 + 1.727 +/* 1.728 +** Convert from binary encoding of an item to ascii. 1.729 +*/ 1.730 +char * 1.731 +BTOA_ConvertItemToAscii (SECItem *binary_item) 1.732 +{ 1.733 + return NSSBase64_EncodeItem (NULL, NULL, 0, binary_item); 1.734 +}