17b5038d7SDag-Erling Smørgrav /*
27b5038d7SDag-Erling Smørgrav * Copyright (c) 1996, 1998 by Internet Software Consortium.
37b5038d7SDag-Erling Smørgrav *
47b5038d7SDag-Erling Smørgrav * Permission to use, copy, modify, and distribute this software for any
57b5038d7SDag-Erling Smørgrav * purpose with or without fee is hereby granted, provided that the above
67b5038d7SDag-Erling Smørgrav * copyright notice and this permission notice appear in all copies.
77b5038d7SDag-Erling Smørgrav *
87b5038d7SDag-Erling Smørgrav * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
97b5038d7SDag-Erling Smørgrav * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
107b5038d7SDag-Erling Smørgrav * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
117b5038d7SDag-Erling Smørgrav * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
127b5038d7SDag-Erling Smørgrav * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
137b5038d7SDag-Erling Smørgrav * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
147b5038d7SDag-Erling Smørgrav * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
157b5038d7SDag-Erling Smørgrav * SOFTWARE.
167b5038d7SDag-Erling Smørgrav */
177b5038d7SDag-Erling Smørgrav
187b5038d7SDag-Erling Smørgrav /*
197b5038d7SDag-Erling Smørgrav * Portions Copyright (c) 1995 by International Business Machines, Inc.
207b5038d7SDag-Erling Smørgrav *
217b5038d7SDag-Erling Smørgrav * International Business Machines, Inc. (hereinafter called IBM) grants
227b5038d7SDag-Erling Smørgrav * permission under its copyrights to use, copy, modify, and distribute this
237b5038d7SDag-Erling Smørgrav * Software with or without fee, provided that the above copyright notice and
247b5038d7SDag-Erling Smørgrav * all paragraphs of this notice appear in all copies, and that the name of IBM
257b5038d7SDag-Erling Smørgrav * not be used in connection with the marketing of any product incorporating
267b5038d7SDag-Erling Smørgrav * the Software or modifications thereof, without specific, written prior
277b5038d7SDag-Erling Smørgrav * permission.
287b5038d7SDag-Erling Smørgrav *
297b5038d7SDag-Erling Smørgrav * To the extent it has a right to do so, IBM grants an immunity from suit
307b5038d7SDag-Erling Smørgrav * under its patents, if any, for the use, sale or manufacture of products to
317b5038d7SDag-Erling Smørgrav * the extent that such products are used for performing Domain Name System
327b5038d7SDag-Erling Smørgrav * dynamic updates in TCP/IP networks by means of the Software. No immunity is
337b5038d7SDag-Erling Smørgrav * granted for any product per se or for any other function of any product.
347b5038d7SDag-Erling Smørgrav *
357b5038d7SDag-Erling Smørgrav * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
367b5038d7SDag-Erling Smørgrav * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
377b5038d7SDag-Erling Smørgrav * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
387b5038d7SDag-Erling Smørgrav * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
397b5038d7SDag-Erling Smørgrav * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
407b5038d7SDag-Erling Smørgrav * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
417b5038d7SDag-Erling Smørgrav */
427b5038d7SDag-Erling Smørgrav #include <ldns/config.h>
437b5038d7SDag-Erling Smørgrav #include <ctype.h>
447b5038d7SDag-Erling Smørgrav #include <stdlib.h>
457b5038d7SDag-Erling Smørgrav #include <string.h>
467b5038d7SDag-Erling Smørgrav
477b5038d7SDag-Erling Smørgrav static const char Base64[] =
487b5038d7SDag-Erling Smørgrav "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
497b5038d7SDag-Erling Smørgrav static const char Pad64 = '=';
507b5038d7SDag-Erling Smørgrav
517b5038d7SDag-Erling Smørgrav /* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
527b5038d7SDag-Erling Smørgrav The following encoding technique is taken from RFC 1521 by Borenstein
537b5038d7SDag-Erling Smørgrav and Freed. It is reproduced here in a slightly edited form for
547b5038d7SDag-Erling Smørgrav convenience.
557b5038d7SDag-Erling Smørgrav
567b5038d7SDag-Erling Smørgrav A 65-character subset of US-ASCII is used, enabling 6 bits to be
577b5038d7SDag-Erling Smørgrav represented per printable character. (The extra 65th character, "=",
587b5038d7SDag-Erling Smørgrav is used to signify a special processing function.)
597b5038d7SDag-Erling Smørgrav
607b5038d7SDag-Erling Smørgrav The encoding process represents 24-bit groups of input bits as output
617b5038d7SDag-Erling Smørgrav strings of 4 encoded characters. Proceeding from left to right, a
627b5038d7SDag-Erling Smørgrav 24-bit input group is formed by concatenating 3 8-bit input groups.
637b5038d7SDag-Erling Smørgrav These 24 bits are then treated as 4 concatenated 6-bit groups, each
647b5038d7SDag-Erling Smørgrav of which is translated into a single digit in the base64 alphabet.
657b5038d7SDag-Erling Smørgrav
667b5038d7SDag-Erling Smørgrav Each 6-bit group is used as an index into an array of 64 printable
677b5038d7SDag-Erling Smørgrav characters. The character referenced by the index is placed in the
687b5038d7SDag-Erling Smørgrav output string.
697b5038d7SDag-Erling Smørgrav
707b5038d7SDag-Erling Smørgrav Table 1: The Base64 Alphabet
717b5038d7SDag-Erling Smørgrav
727b5038d7SDag-Erling Smørgrav Value Encoding Value Encoding Value Encoding Value Encoding
737b5038d7SDag-Erling Smørgrav 0 A 17 R 34 i 51 z
747b5038d7SDag-Erling Smørgrav 1 B 18 S 35 j 52 0
757b5038d7SDag-Erling Smørgrav 2 C 19 T 36 k 53 1
767b5038d7SDag-Erling Smørgrav 3 D 20 U 37 l 54 2
777b5038d7SDag-Erling Smørgrav 4 E 21 V 38 m 55 3
787b5038d7SDag-Erling Smørgrav 5 F 22 W 39 n 56 4
797b5038d7SDag-Erling Smørgrav 6 G 23 X 40 o 57 5
807b5038d7SDag-Erling Smørgrav 7 H 24 Y 41 p 58 6
817b5038d7SDag-Erling Smørgrav 8 I 25 Z 42 q 59 7
827b5038d7SDag-Erling Smørgrav 9 J 26 a 43 r 60 8
837b5038d7SDag-Erling Smørgrav 10 K 27 b 44 s 61 9
847b5038d7SDag-Erling Smørgrav 11 L 28 c 45 t 62 +
857b5038d7SDag-Erling Smørgrav 12 M 29 d 46 u 63 /
867b5038d7SDag-Erling Smørgrav 13 N 30 e 47 v
877b5038d7SDag-Erling Smørgrav 14 O 31 f 48 w (pad) =
887b5038d7SDag-Erling Smørgrav 15 P 32 g 49 x
897b5038d7SDag-Erling Smørgrav 16 Q 33 h 50 y
907b5038d7SDag-Erling Smørgrav
917b5038d7SDag-Erling Smørgrav Special processing is performed if fewer than 24 bits are available
927b5038d7SDag-Erling Smørgrav at the end of the data being encoded. A full encoding quantum is
937b5038d7SDag-Erling Smørgrav always completed at the end of a quantity. When fewer than 24 input
947b5038d7SDag-Erling Smørgrav bits are available in an input group, zero bits are added (on the
957b5038d7SDag-Erling Smørgrav right) to form an integral number of 6-bit groups. Padding at the
967b5038d7SDag-Erling Smørgrav end of the data is performed using the '=' character.
977b5038d7SDag-Erling Smørgrav
987b5038d7SDag-Erling Smørgrav Since all base64 input is an integral number of octets, only the
997b5038d7SDag-Erling Smørgrav -------------------------------------------------
1007b5038d7SDag-Erling Smørgrav following cases can arise:
1017b5038d7SDag-Erling Smørgrav
1027b5038d7SDag-Erling Smørgrav (1) the final quantum of encoding input is an integral
1037b5038d7SDag-Erling Smørgrav multiple of 24 bits; here, the final unit of encoded
1047b5038d7SDag-Erling Smørgrav output will be an integral multiple of 4 characters
1057b5038d7SDag-Erling Smørgrav with no "=" padding,
1067b5038d7SDag-Erling Smørgrav (2) the final quantum of encoding input is exactly 8 bits;
1077b5038d7SDag-Erling Smørgrav here, the final unit of encoded output will be two
1087b5038d7SDag-Erling Smørgrav characters followed by two "=" padding characters, or
1097b5038d7SDag-Erling Smørgrav (3) the final quantum of encoding input is exactly 16 bits;
1107b5038d7SDag-Erling Smørgrav here, the final unit of encoded output will be three
1117b5038d7SDag-Erling Smørgrav characters followed by one "=" padding character.
1127b5038d7SDag-Erling Smørgrav */
1137b5038d7SDag-Erling Smørgrav
1147b5038d7SDag-Erling Smørgrav /* skips all whitespace anywhere.
1157b5038d7SDag-Erling Smørgrav converts characters, four at a time, starting at (or after)
1167b5038d7SDag-Erling Smørgrav src from base - 64 numbers into three 8 bit bytes in the target area.
1177b5038d7SDag-Erling Smørgrav it returns the number of data bytes stored at the target, or -1 on error.
1187b5038d7SDag-Erling Smørgrav */
1197b5038d7SDag-Erling Smørgrav
1207b5038d7SDag-Erling Smørgrav int
ldns_b64_pton(char const * origsrc,uint8_t * target,size_t targsize)121*986ba33cSDag-Erling Smørgrav ldns_b64_pton(char const *origsrc, uint8_t *target, size_t targsize)
1227b5038d7SDag-Erling Smørgrav {
123*986ba33cSDag-Erling Smørgrav unsigned char const* src = (unsigned char*)origsrc;
1247b5038d7SDag-Erling Smørgrav int tarindex, state, ch;
1257b5038d7SDag-Erling Smørgrav char *pos;
1267b5038d7SDag-Erling Smørgrav
1277b5038d7SDag-Erling Smørgrav state = 0;
1287b5038d7SDag-Erling Smørgrav tarindex = 0;
1297b5038d7SDag-Erling Smørgrav
130*986ba33cSDag-Erling Smørgrav if (strlen(origsrc) == 0) {
1317b5038d7SDag-Erling Smørgrav return 0;
1327b5038d7SDag-Erling Smørgrav }
1337b5038d7SDag-Erling Smørgrav
1347b5038d7SDag-Erling Smørgrav while ((ch = *src++) != '\0') {
1357b5038d7SDag-Erling Smørgrav if (isspace((unsigned char)ch)) /* Skip whitespace anywhere. */
1367b5038d7SDag-Erling Smørgrav continue;
1377b5038d7SDag-Erling Smørgrav
1387b5038d7SDag-Erling Smørgrav if (ch == Pad64)
1397b5038d7SDag-Erling Smørgrav break;
1407b5038d7SDag-Erling Smørgrav
1417b5038d7SDag-Erling Smørgrav pos = strchr(Base64, ch);
1427b5038d7SDag-Erling Smørgrav if (pos == 0) {
1437b5038d7SDag-Erling Smørgrav /* A non-base64 character. */
1447b5038d7SDag-Erling Smørgrav return (-1);
1457b5038d7SDag-Erling Smørgrav }
1467b5038d7SDag-Erling Smørgrav
1477b5038d7SDag-Erling Smørgrav switch (state) {
1487b5038d7SDag-Erling Smørgrav case 0:
1497b5038d7SDag-Erling Smørgrav if (target) {
1507b5038d7SDag-Erling Smørgrav if ((size_t)tarindex >= targsize)
1517b5038d7SDag-Erling Smørgrav return (-1);
1527b5038d7SDag-Erling Smørgrav target[tarindex] = (pos - Base64) << 2;
1537b5038d7SDag-Erling Smørgrav }
1547b5038d7SDag-Erling Smørgrav state = 1;
1557b5038d7SDag-Erling Smørgrav break;
1567b5038d7SDag-Erling Smørgrav case 1:
1577b5038d7SDag-Erling Smørgrav if (target) {
1587b5038d7SDag-Erling Smørgrav if ((size_t)tarindex + 1 >= targsize)
1597b5038d7SDag-Erling Smørgrav return (-1);
1607b5038d7SDag-Erling Smørgrav target[tarindex] |= (pos - Base64) >> 4;
1617b5038d7SDag-Erling Smørgrav target[tarindex+1] = ((pos - Base64) & 0x0f)
1627b5038d7SDag-Erling Smørgrav << 4 ;
1637b5038d7SDag-Erling Smørgrav }
1647b5038d7SDag-Erling Smørgrav tarindex++;
1657b5038d7SDag-Erling Smørgrav state = 2;
1667b5038d7SDag-Erling Smørgrav break;
1677b5038d7SDag-Erling Smørgrav case 2:
1687b5038d7SDag-Erling Smørgrav if (target) {
1697b5038d7SDag-Erling Smørgrav if ((size_t)tarindex + 1 >= targsize)
1707b5038d7SDag-Erling Smørgrav return (-1);
1717b5038d7SDag-Erling Smørgrav target[tarindex] |= (pos - Base64) >> 2;
1727b5038d7SDag-Erling Smørgrav target[tarindex+1] = ((pos - Base64) & 0x03)
1737b5038d7SDag-Erling Smørgrav << 6;
1747b5038d7SDag-Erling Smørgrav }
1757b5038d7SDag-Erling Smørgrav tarindex++;
1767b5038d7SDag-Erling Smørgrav state = 3;
1777b5038d7SDag-Erling Smørgrav break;
1787b5038d7SDag-Erling Smørgrav case 3:
1797b5038d7SDag-Erling Smørgrav if (target) {
1807b5038d7SDag-Erling Smørgrav if ((size_t)tarindex >= targsize)
1817b5038d7SDag-Erling Smørgrav return (-1);
1827b5038d7SDag-Erling Smørgrav target[tarindex] |= (pos - Base64);
1837b5038d7SDag-Erling Smørgrav }
1847b5038d7SDag-Erling Smørgrav tarindex++;
1857b5038d7SDag-Erling Smørgrav state = 0;
1867b5038d7SDag-Erling Smørgrav break;
1877b5038d7SDag-Erling Smørgrav default:
1887b5038d7SDag-Erling Smørgrav abort();
1897b5038d7SDag-Erling Smørgrav }
1907b5038d7SDag-Erling Smørgrav }
1917b5038d7SDag-Erling Smørgrav
1927b5038d7SDag-Erling Smørgrav /*
1937b5038d7SDag-Erling Smørgrav * We are done decoding Base-64 chars. Let's see if we ended
1947b5038d7SDag-Erling Smørgrav * on a byte boundary, and/or with erroneous trailing characters.
1957b5038d7SDag-Erling Smørgrav */
1967b5038d7SDag-Erling Smørgrav
1977b5038d7SDag-Erling Smørgrav if (ch == Pad64) { /* We got a pad char. */
1987b5038d7SDag-Erling Smørgrav ch = *src++; /* Skip it, get next. */
1997b5038d7SDag-Erling Smørgrav switch (state) {
2007b5038d7SDag-Erling Smørgrav case 0: /* Invalid = in first position */
2017b5038d7SDag-Erling Smørgrav case 1: /* Invalid = in second position */
2027b5038d7SDag-Erling Smørgrav return (-1);
2037b5038d7SDag-Erling Smørgrav
2047b5038d7SDag-Erling Smørgrav case 2: /* Valid, means one byte of info */
2057b5038d7SDag-Erling Smørgrav /* Skip any number of spaces. */
2067b5038d7SDag-Erling Smørgrav for ((void)NULL; ch != '\0'; ch = *src++)
2077b5038d7SDag-Erling Smørgrav if (!isspace((unsigned char)ch))
2087b5038d7SDag-Erling Smørgrav break;
2097b5038d7SDag-Erling Smørgrav /* Make sure there is another trailing = sign. */
2107b5038d7SDag-Erling Smørgrav if (ch != Pad64)
2117b5038d7SDag-Erling Smørgrav return (-1);
2127b5038d7SDag-Erling Smørgrav ch = *src++; /* Skip the = */
2137b5038d7SDag-Erling Smørgrav /* Fall through to "single trailing =" case. */
2147b5038d7SDag-Erling Smørgrav /* FALLTHROUGH */
2157b5038d7SDag-Erling Smørgrav
2167b5038d7SDag-Erling Smørgrav case 3: /* Valid, means two bytes of info */
2177b5038d7SDag-Erling Smørgrav /*
2187b5038d7SDag-Erling Smørgrav * We know this char is an =. Is there anything but
2197b5038d7SDag-Erling Smørgrav * whitespace after it?
2207b5038d7SDag-Erling Smørgrav */
2217b5038d7SDag-Erling Smørgrav for ((void)NULL; ch != '\0'; ch = *src++)
2227b5038d7SDag-Erling Smørgrav if (!isspace((unsigned char)ch))
2237b5038d7SDag-Erling Smørgrav return (-1);
2247b5038d7SDag-Erling Smørgrav
2257b5038d7SDag-Erling Smørgrav /*
2267b5038d7SDag-Erling Smørgrav * Now make sure for cases 2 and 3 that the "extra"
2277b5038d7SDag-Erling Smørgrav * bits that slopped past the last full byte were
2287b5038d7SDag-Erling Smørgrav * zeros. If we don't check them, they become a
2297b5038d7SDag-Erling Smørgrav * subliminal channel.
2307b5038d7SDag-Erling Smørgrav */
2317b5038d7SDag-Erling Smørgrav if (target && target[tarindex] != 0)
2327b5038d7SDag-Erling Smørgrav return (-1);
2337b5038d7SDag-Erling Smørgrav }
2347b5038d7SDag-Erling Smørgrav } else {
2357b5038d7SDag-Erling Smørgrav /*
2367b5038d7SDag-Erling Smørgrav * We ended by seeing the end of the string. Make sure we
2377b5038d7SDag-Erling Smørgrav * have no partial bytes lying around.
2387b5038d7SDag-Erling Smørgrav */
2397b5038d7SDag-Erling Smørgrav if (state != 0)
2407b5038d7SDag-Erling Smørgrav return (-1);
2417b5038d7SDag-Erling Smørgrav }
2427b5038d7SDag-Erling Smørgrav
2437b5038d7SDag-Erling Smørgrav return (tarindex);
2447b5038d7SDag-Erling Smørgrav }
245