Blame resolv/base64.c

Packit 6c4009
/*
Packit 6c4009
 * Copyright (c) 1996-1999 by Internet Software Consortium.
Packit 6c4009
 *
Packit 6c4009
 * Permission to use, copy, modify, and distribute this software for any
Packit 6c4009
 * purpose with or without fee is hereby granted, provided that the above
Packit 6c4009
 * copyright notice and this permission notice appear in all copies.
Packit 6c4009
 *
Packit 6c4009
 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
Packit 6c4009
 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
Packit 6c4009
 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
Packit 6c4009
 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
Packit 6c4009
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
Packit 6c4009
 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
Packit 6c4009
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
Packit 6c4009
 * SOFTWARE.
Packit 6c4009
 */
Packit 6c4009
Packit 6c4009
/*
Packit 6c4009
 * Portions Copyright (c) 1995 by International Business Machines, Inc.
Packit 6c4009
 *
Packit 6c4009
 * International Business Machines, Inc. (hereinafter called IBM) grants
Packit 6c4009
 * permission under its copyrights to use, copy, modify, and distribute this
Packit 6c4009
 * Software with or without fee, provided that the above copyright notice and
Packit 6c4009
 * all paragraphs of this notice appear in all copies, and that the name of IBM
Packit 6c4009
 * not be used in connection with the marketing of any product incorporating
Packit 6c4009
 * the Software or modifications thereof, without specific, written prior
Packit 6c4009
 * permission.
Packit 6c4009
 *
Packit 6c4009
 * To the extent it has a right to do so, IBM grants an immunity from suit
Packit 6c4009
 * under its patents, if any, for the use, sale or manufacture of products to
Packit 6c4009
 * the extent that such products are used for performing Domain Name System
Packit 6c4009
 * dynamic updates in TCP/IP networks by means of the Software.  No immunity is
Packit 6c4009
 * granted for any product per se or for any other function of any product.
Packit 6c4009
 *
Packit 6c4009
 * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
Packit 6c4009
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
Packit 6c4009
 * PARTICULAR PURPOSE.  IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
Packit 6c4009
 * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
Packit 6c4009
 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
Packit 6c4009
 * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
Packit 6c4009
 */
Packit 6c4009
Packit 6c4009
#include <sys/types.h>
Packit 6c4009
#include <sys/param.h>
Packit 6c4009
#include <sys/socket.h>
Packit 6c4009
Packit 6c4009
#include <netinet/in.h>
Packit 6c4009
#include <arpa/inet.h>
Packit 6c4009
#include <arpa/nameser.h>
Packit 6c4009
Packit 6c4009
#include <ctype.h>
Packit 6c4009
#include <resolv.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
Packit 6c4009
#define Assert(Cond) if (!(Cond)) abort()
Packit 6c4009
Packit 6c4009
static const char Base64[] =
Packit 6c4009
	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
Packit 6c4009
static const char Pad64 = '=';
Packit 6c4009
Packit 6c4009
/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
Packit 6c4009
   The following encoding technique is taken from RFC 1521 by Borenstein
Packit 6c4009
   and Freed.  It is reproduced here in a slightly edited form for
Packit 6c4009
   convenience.
Packit 6c4009
Packit 6c4009
   A 65-character subset of US-ASCII is used, enabling 6 bits to be
Packit 6c4009
   represented per printable character. (The extra 65th character, "=",
Packit 6c4009
   is used to signify a special processing function.)
Packit 6c4009
Packit 6c4009
   The encoding process represents 24-bit groups of input bits as output
Packit 6c4009
   strings of 4 encoded characters. Proceeding from left to right, a
Packit 6c4009
   24-bit input group is formed by concatenating 3 8-bit input groups.
Packit 6c4009
   These 24 bits are then treated as 4 concatenated 6-bit groups, each
Packit 6c4009
   of which is translated into a single digit in the base64 alphabet.
Packit 6c4009
Packit 6c4009
   Each 6-bit group is used as an index into an array of 64 printable
Packit 6c4009
   characters. The character referenced by the index is placed in the
Packit 6c4009
   output string.
Packit 6c4009
Packit 6c4009
                         Table 1: The Base64 Alphabet
Packit 6c4009
Packit 6c4009
      Value Encoding  Value Encoding  Value Encoding  Value Encoding
Packit 6c4009
          0 A            17 R            34 i            51 z
Packit 6c4009
          1 B            18 S            35 j            52 0
Packit 6c4009
          2 C            19 T            36 k            53 1
Packit 6c4009
          3 D            20 U            37 l            54 2
Packit 6c4009
          4 E            21 V            38 m            55 3
Packit 6c4009
          5 F            22 W            39 n            56 4
Packit 6c4009
          6 G            23 X            40 o            57 5
Packit 6c4009
          7 H            24 Y            41 p            58 6
Packit 6c4009
          8 I            25 Z            42 q            59 7
Packit 6c4009
          9 J            26 a            43 r            60 8
Packit 6c4009
         10 K            27 b            44 s            61 9
Packit 6c4009
         11 L            28 c            45 t            62 +
Packit 6c4009
         12 M            29 d            46 u            63 /
Packit 6c4009
         13 N            30 e            47 v
Packit 6c4009
         14 O            31 f            48 w         (pad) =
Packit 6c4009
         15 P            32 g            49 x
Packit 6c4009
         16 Q            33 h            50 y
Packit 6c4009
Packit 6c4009
   Special processing is performed if fewer than 24 bits are available
Packit 6c4009
   at the end of the data being encoded.  A full encoding quantum is
Packit 6c4009
   always completed at the end of a quantity.  When fewer than 24 input
Packit 6c4009
   bits are available in an input group, zero bits are added (on the
Packit 6c4009
   right) to form an integral number of 6-bit groups.  Padding at the
Packit 6c4009
   end of the data is performed using the '=' character.
Packit 6c4009
Packit 6c4009
   Since all base64 input is an integral number of octets, only the
Packit 6c4009
         -------------------------------------------------
Packit 6c4009
   following cases can arise:
Packit 6c4009
Packit 6c4009
       (1) the final quantum of encoding input is an integral
Packit 6c4009
           multiple of 24 bits; here, the final unit of encoded
Packit 6c4009
	   output will be an integral multiple of 4 characters
Packit 6c4009
	   with no "=" padding,
Packit 6c4009
       (2) the final quantum of encoding input is exactly 8 bits;
Packit 6c4009
           here, the final unit of encoded output will be two
Packit 6c4009
	   characters followed by two "=" padding characters, or
Packit 6c4009
       (3) the final quantum of encoding input is exactly 16 bits;
Packit 6c4009
           here, the final unit of encoded output will be three
Packit 6c4009
	   characters followed by one "=" padding character.
Packit 6c4009
   */
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize) {
Packit 6c4009
	size_t datalength = 0;
Packit 6c4009
	u_char input[3];
Packit 6c4009
	u_char output[4];
Packit 6c4009
	size_t i;
Packit 6c4009
Packit 6c4009
	while (2 < srclength) {
Packit 6c4009
		input[0] = *src++;
Packit 6c4009
		input[1] = *src++;
Packit 6c4009
		input[2] = *src++;
Packit 6c4009
		srclength -= 3;
Packit 6c4009
Packit 6c4009
		output[0] = input[0] >> 2;
Packit 6c4009
		output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
Packit 6c4009
		output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
Packit 6c4009
		output[3] = input[2] & 0x3f;
Packit 6c4009
		Assert(output[0] < 64);
Packit 6c4009
		Assert(output[1] < 64);
Packit 6c4009
		Assert(output[2] < 64);
Packit 6c4009
		Assert(output[3] < 64);
Packit 6c4009
Packit 6c4009
		if (datalength + 4 > targsize)
Packit 6c4009
			return (-1);
Packit 6c4009
		target[datalength++] = Base64[output[0]];
Packit 6c4009
		target[datalength++] = Base64[output[1]];
Packit 6c4009
		target[datalength++] = Base64[output[2]];
Packit 6c4009
		target[datalength++] = Base64[output[3]];
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
	/* Now we worry about padding. */
Packit 6c4009
	if (0 != srclength) {
Packit 6c4009
		/* Get what's left. */
Packit 6c4009
		input[0] = input[1] = input[2] = '\0';
Packit 6c4009
		for (i = 0; i < srclength; i++)
Packit 6c4009
			input[i] = *src++;
Packit 6c4009
Packit 6c4009
		output[0] = input[0] >> 2;
Packit 6c4009
		output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
Packit 6c4009
		output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
Packit 6c4009
		Assert(output[0] < 64);
Packit 6c4009
		Assert(output[1] < 64);
Packit 6c4009
		Assert(output[2] < 64);
Packit 6c4009
Packit 6c4009
		if (datalength + 4 > targsize)
Packit 6c4009
			return (-1);
Packit 6c4009
		target[datalength++] = Base64[output[0]];
Packit 6c4009
		target[datalength++] = Base64[output[1]];
Packit 6c4009
		if (srclength == 1)
Packit 6c4009
			target[datalength++] = Pad64;
Packit 6c4009
		else
Packit 6c4009
			target[datalength++] = Base64[output[2]];
Packit 6c4009
		target[datalength++] = Pad64;
Packit 6c4009
	}
Packit 6c4009
	if (datalength >= targsize)
Packit 6c4009
		return (-1);
Packit 6c4009
	target[datalength] = '\0';	/* Returned value doesn't count \0. */
Packit 6c4009
	return (datalength);
Packit 6c4009
}
Packit 6c4009
libresolv_hidden_def (b64_ntop)
Packit 6c4009
Packit 6c4009
/* skips all whitespace anywhere.
Packit 6c4009
   converts characters, four at a time, starting at (or after)
Packit 6c4009
   src from base - 64 numbers into three 8 bit bytes in the target area.
Packit 6c4009
   it returns the number of data bytes stored at the target, or -1 on error.
Packit 6c4009
 */
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
b64_pton (char const *src, u_char *target, size_t targsize)
Packit 6c4009
{
Packit 6c4009
	int tarindex, state, ch;
Packit 6c4009
	char *pos;
Packit 6c4009
Packit 6c4009
	state = 0;
Packit 6c4009
	tarindex = 0;
Packit 6c4009
Packit 6c4009
	while ((ch = *src++) != '\0') {
Packit 6c4009
		if (isspace(ch))	/* Skip whitespace anywhere. */
Packit 6c4009
			continue;
Packit 6c4009
Packit 6c4009
		if (ch == Pad64)
Packit 6c4009
			break;
Packit 6c4009
Packit 6c4009
		pos = strchr(Base64, ch);
Packit 6c4009
		if (pos == 0) 		/* A non-base64 character. */
Packit 6c4009
			return (-1);
Packit 6c4009
Packit 6c4009
		switch (state) {
Packit 6c4009
		case 0:
Packit 6c4009
			if (target) {
Packit 6c4009
				if ((size_t)tarindex >= targsize)
Packit 6c4009
					return (-1);
Packit 6c4009
				target[tarindex] = (pos - Base64) << 2;
Packit 6c4009
			}
Packit 6c4009
			state = 1;
Packit 6c4009
			break;
Packit 6c4009
		case 1:
Packit 6c4009
			if (target) {
Packit 6c4009
				if ((size_t)tarindex + 1 >= targsize)
Packit 6c4009
					return (-1);
Packit 6c4009
				target[tarindex]   |=  (pos - Base64) >> 4;
Packit 6c4009
				target[tarindex+1]  = ((pos - Base64) & 0x0f)
Packit 6c4009
							<< 4 ;
Packit 6c4009
			}
Packit 6c4009
			tarindex++;
Packit 6c4009
			state = 2;
Packit 6c4009
			break;
Packit 6c4009
		case 2:
Packit 6c4009
			if (target) {
Packit 6c4009
				if ((size_t)tarindex + 1 >= targsize)
Packit 6c4009
					return (-1);
Packit 6c4009
				target[tarindex]   |=  (pos - Base64) >> 2;
Packit 6c4009
				target[tarindex+1]  = ((pos - Base64) & 0x03)
Packit 6c4009
							<< 6;
Packit 6c4009
			}
Packit 6c4009
			tarindex++;
Packit 6c4009
			state = 3;
Packit 6c4009
			break;
Packit 6c4009
		case 3:
Packit 6c4009
			if (target) {
Packit 6c4009
				if ((size_t)tarindex >= targsize)
Packit 6c4009
					return (-1);
Packit 6c4009
				target[tarindex] |= (pos - Base64);
Packit 6c4009
			}
Packit 6c4009
			tarindex++;
Packit 6c4009
			state = 0;
Packit 6c4009
			break;
Packit 6c4009
		default:
Packit 6c4009
			abort();
Packit 6c4009
		}
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
	/*
Packit 6c4009
	 * We are done decoding Base-64 chars.  Let's see if we ended
Packit 6c4009
	 * on a byte boundary, and/or with erroneous trailing characters.
Packit 6c4009
	 */
Packit 6c4009
Packit 6c4009
	if (ch == Pad64) {		/* We got a pad char. */
Packit 6c4009
		ch = *src++;		/* Skip it, get next. */
Packit 6c4009
		switch (state) {
Packit 6c4009
		case 0:		/* Invalid = in first position */
Packit 6c4009
		case 1:		/* Invalid = in second position */
Packit 6c4009
			return (-1);
Packit 6c4009
Packit 6c4009
		case 2:		/* Valid, means one byte of info */
Packit 6c4009
			/* Skip any number of spaces. */
Packit 6c4009
			for ((void)NULL; ch != '\0'; ch = *src++)
Packit 6c4009
				if (!isspace(ch))
Packit 6c4009
					break;
Packit 6c4009
			/* Make sure there is another trailing = sign. */
Packit 6c4009
			if (ch != Pad64)
Packit 6c4009
				return (-1);
Packit 6c4009
			ch = *src++;		/* Skip the = */
Packit 6c4009
			/* Fall through to "single trailing =" case. */
Packit 6c4009
			/* FALLTHROUGH */
Packit 6c4009
Packit 6c4009
		case 3:		/* Valid, means two bytes of info */
Packit 6c4009
			/*
Packit 6c4009
			 * We know this char is an =.  Is there anything but
Packit 6c4009
			 * whitespace after it?
Packit 6c4009
			 */
Packit 6c4009
			for ((void)NULL; ch != '\0'; ch = *src++)
Packit 6c4009
				if (!isspace(ch))
Packit 6c4009
					return (-1);
Packit 6c4009
Packit 6c4009
			/*
Packit 6c4009
			 * Now make sure for cases 2 and 3 that the "extra"
Packit 6c4009
			 * bits that slopped past the last full byte were
Packit 6c4009
			 * zeros.  If we don't check them, they become a
Packit 6c4009
			 * subliminal channel.
Packit 6c4009
			 */
Packit 6c4009
			if (target && target[tarindex] != 0)
Packit 6c4009
				return (-1);
Packit 6c4009
		}
Packit 6c4009
	} else {
Packit 6c4009
		/*
Packit 6c4009
		 * We ended by seeing the end of the string.  Make sure we
Packit 6c4009
		 * have no partial bytes lying around.
Packit 6c4009
		 */
Packit 6c4009
		if (state != 0)
Packit 6c4009
			return (-1);
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
	return (tarindex);
Packit 6c4009
}