1*7b5038d7SDag-Erling Smørgrav /* 2*7b5038d7SDag-Erling Smørgrav * Copyright (c) 1996, 1998 by Internet Software Consortium. 3*7b5038d7SDag-Erling Smørgrav * 4*7b5038d7SDag-Erling Smørgrav * Permission to use, copy, modify, and distribute this software for any 5*7b5038d7SDag-Erling Smørgrav * purpose with or without fee is hereby granted, provided that the above 6*7b5038d7SDag-Erling Smørgrav * copyright notice and this permission notice appear in all copies. 7*7b5038d7SDag-Erling Smørgrav * 8*7b5038d7SDag-Erling Smørgrav * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS 9*7b5038d7SDag-Erling Smørgrav * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 10*7b5038d7SDag-Erling Smørgrav * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE 11*7b5038d7SDag-Erling Smørgrav * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 12*7b5038d7SDag-Erling Smørgrav * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 13*7b5038d7SDag-Erling Smørgrav * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 14*7b5038d7SDag-Erling Smørgrav * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 15*7b5038d7SDag-Erling Smørgrav * SOFTWARE. 16*7b5038d7SDag-Erling Smørgrav */ 17*7b5038d7SDag-Erling Smørgrav 18*7b5038d7SDag-Erling Smørgrav /* 19*7b5038d7SDag-Erling Smørgrav * Portions Copyright (c) 1995 by International Business Machines, Inc. 20*7b5038d7SDag-Erling Smørgrav * 21*7b5038d7SDag-Erling Smørgrav * International Business Machines, Inc. (hereinafter called IBM) grants 22*7b5038d7SDag-Erling Smørgrav * permission under its copyrights to use, copy, modify, and distribute this 23*7b5038d7SDag-Erling Smørgrav * Software with or without fee, provided that the above copyright notice and 24*7b5038d7SDag-Erling Smørgrav * all paragraphs of this notice appear in all copies, and that the name of IBM 25*7b5038d7SDag-Erling Smørgrav * not be used in connection with the marketing of any product incorporating 26*7b5038d7SDag-Erling Smørgrav * the Software or modifications thereof, without specific, written prior 27*7b5038d7SDag-Erling Smørgrav * permission. 28*7b5038d7SDag-Erling Smørgrav * 29*7b5038d7SDag-Erling Smørgrav * To the extent it has a right to do so, IBM grants an immunity from suit 30*7b5038d7SDag-Erling Smørgrav * under its patents, if any, for the use, sale or manufacture of products to 31*7b5038d7SDag-Erling Smørgrav * the extent that such products are used for performing Domain Name System 32*7b5038d7SDag-Erling Smørgrav * dynamic updates in TCP/IP networks by means of the Software. No immunity is 33*7b5038d7SDag-Erling Smørgrav * granted for any product per se or for any other function of any product. 34*7b5038d7SDag-Erling Smørgrav * 35*7b5038d7SDag-Erling Smørgrav * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, 36*7b5038d7SDag-Erling Smørgrav * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 37*7b5038d7SDag-Erling Smørgrav * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, 38*7b5038d7SDag-Erling Smørgrav * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING 39*7b5038d7SDag-Erling Smørgrav * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN 40*7b5038d7SDag-Erling Smørgrav * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. 41*7b5038d7SDag-Erling Smørgrav */ 42*7b5038d7SDag-Erling Smørgrav #include <ldns/config.h> 43*7b5038d7SDag-Erling Smørgrav 44*7b5038d7SDag-Erling Smørgrav #include <sys/types.h> 45*7b5038d7SDag-Erling Smørgrav #include <sys/param.h> 46*7b5038d7SDag-Erling Smørgrav #ifdef HAVE_SYS_SOCKET_H 47*7b5038d7SDag-Erling Smørgrav #include <sys/socket.h> 48*7b5038d7SDag-Erling Smørgrav #endif 49*7b5038d7SDag-Erling Smørgrav 50*7b5038d7SDag-Erling Smørgrav #ifdef HAVE_NETINET_IN_H 51*7b5038d7SDag-Erling Smørgrav #include <netinet/in.h> 52*7b5038d7SDag-Erling Smørgrav #endif 53*7b5038d7SDag-Erling Smørgrav #ifdef HAVE_ARPA_INET_H 54*7b5038d7SDag-Erling Smørgrav #include <arpa/inet.h> 55*7b5038d7SDag-Erling Smørgrav #endif 56*7b5038d7SDag-Erling Smørgrav 57*7b5038d7SDag-Erling Smørgrav #include <ctype.h> 58*7b5038d7SDag-Erling Smørgrav #include <stdio.h> 59*7b5038d7SDag-Erling Smørgrav #include <stdlib.h> 60*7b5038d7SDag-Erling Smørgrav #include <string.h> 61*7b5038d7SDag-Erling Smørgrav 62*7b5038d7SDag-Erling Smørgrav #define Assert(Cond) if (!(Cond)) abort() 63*7b5038d7SDag-Erling Smørgrav 64*7b5038d7SDag-Erling Smørgrav static const char Base64[] = 65*7b5038d7SDag-Erling Smørgrav "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 66*7b5038d7SDag-Erling Smørgrav static const char Pad64 = '='; 67*7b5038d7SDag-Erling Smørgrav 68*7b5038d7SDag-Erling Smørgrav /* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) 69*7b5038d7SDag-Erling Smørgrav The following encoding technique is taken from RFC 1521 by Borenstein 70*7b5038d7SDag-Erling Smørgrav and Freed. It is reproduced here in a slightly edited form for 71*7b5038d7SDag-Erling Smørgrav convenience. 72*7b5038d7SDag-Erling Smørgrav 73*7b5038d7SDag-Erling Smørgrav A 65-character subset of US-ASCII is used, enabling 6 bits to be 74*7b5038d7SDag-Erling Smørgrav represented per printable character. (The extra 65th character, "=", 75*7b5038d7SDag-Erling Smørgrav is used to signify a special processing function.) 76*7b5038d7SDag-Erling Smørgrav 77*7b5038d7SDag-Erling Smørgrav The encoding process represents 24-bit groups of input bits as output 78*7b5038d7SDag-Erling Smørgrav strings of 4 encoded characters. Proceeding from left to right, a 79*7b5038d7SDag-Erling Smørgrav 24-bit input group is formed by concatenating 3 8-bit input groups. 80*7b5038d7SDag-Erling Smørgrav These 24 bits are then treated as 4 concatenated 6-bit groups, each 81*7b5038d7SDag-Erling Smørgrav of which is translated into a single digit in the base64 alphabet. 82*7b5038d7SDag-Erling Smørgrav 83*7b5038d7SDag-Erling Smørgrav Each 6-bit group is used as an index into an array of 64 printable 84*7b5038d7SDag-Erling Smørgrav characters. The character referenced by the index is placed in the 85*7b5038d7SDag-Erling Smørgrav output string. 86*7b5038d7SDag-Erling Smørgrav 87*7b5038d7SDag-Erling Smørgrav Table 1: The Base64 Alphabet 88*7b5038d7SDag-Erling Smørgrav 89*7b5038d7SDag-Erling Smørgrav Value Encoding Value Encoding Value Encoding Value Encoding 90*7b5038d7SDag-Erling Smørgrav 0 A 17 R 34 i 51 z 91*7b5038d7SDag-Erling Smørgrav 1 B 18 S 35 j 52 0 92*7b5038d7SDag-Erling Smørgrav 2 C 19 T 36 k 53 1 93*7b5038d7SDag-Erling Smørgrav 3 D 20 U 37 l 54 2 94*7b5038d7SDag-Erling Smørgrav 4 E 21 V 38 m 55 3 95*7b5038d7SDag-Erling Smørgrav 5 F 22 W 39 n 56 4 96*7b5038d7SDag-Erling Smørgrav 6 G 23 X 40 o 57 5 97*7b5038d7SDag-Erling Smørgrav 7 H 24 Y 41 p 58 6 98*7b5038d7SDag-Erling Smørgrav 8 I 25 Z 42 q 59 7 99*7b5038d7SDag-Erling Smørgrav 9 J 26 a 43 r 60 8 100*7b5038d7SDag-Erling Smørgrav 10 K 27 b 44 s 61 9 101*7b5038d7SDag-Erling Smørgrav 11 L 28 c 45 t 62 + 102*7b5038d7SDag-Erling Smørgrav 12 M 29 d 46 u 63 / 103*7b5038d7SDag-Erling Smørgrav 13 N 30 e 47 v 104*7b5038d7SDag-Erling Smørgrav 14 O 31 f 48 w (pad) = 105*7b5038d7SDag-Erling Smørgrav 15 P 32 g 49 x 106*7b5038d7SDag-Erling Smørgrav 16 Q 33 h 50 y 107*7b5038d7SDag-Erling Smørgrav 108*7b5038d7SDag-Erling Smørgrav Special processing is performed if fewer than 24 bits are available 109*7b5038d7SDag-Erling Smørgrav at the end of the data being encoded. A full encoding quantum is 110*7b5038d7SDag-Erling Smørgrav always completed at the end of a quantity. When fewer than 24 input 111*7b5038d7SDag-Erling Smørgrav bits are available in an input group, zero bits are added (on the 112*7b5038d7SDag-Erling Smørgrav right) to form an integral number of 6-bit groups. Padding at the 113*7b5038d7SDag-Erling Smørgrav end of the data is performed using the '=' character. 114*7b5038d7SDag-Erling Smørgrav 115*7b5038d7SDag-Erling Smørgrav Since all base64 input is an integral number of octets, only the 116*7b5038d7SDag-Erling Smørgrav ------------------------------------------------- 117*7b5038d7SDag-Erling Smørgrav following cases can arise: 118*7b5038d7SDag-Erling Smørgrav 119*7b5038d7SDag-Erling Smørgrav (1) the final quantum of encoding input is an integral 120*7b5038d7SDag-Erling Smørgrav multiple of 24 bits; here, the final unit of encoded 121*7b5038d7SDag-Erling Smørgrav output will be an integral multiple of 4 characters 122*7b5038d7SDag-Erling Smørgrav with no "=" padding, 123*7b5038d7SDag-Erling Smørgrav (2) the final quantum of encoding input is exactly 8 bits; 124*7b5038d7SDag-Erling Smørgrav here, the final unit of encoded output will be two 125*7b5038d7SDag-Erling Smørgrav characters followed by two "=" padding characters, or 126*7b5038d7SDag-Erling Smørgrav (3) the final quantum of encoding input is exactly 16 bits; 127*7b5038d7SDag-Erling Smørgrav here, the final unit of encoded output will be three 128*7b5038d7SDag-Erling Smørgrav characters followed by one "=" padding character. 129*7b5038d7SDag-Erling Smørgrav */ 130*7b5038d7SDag-Erling Smørgrav 131*7b5038d7SDag-Erling Smørgrav /* skips all whitespace anywhere. 132*7b5038d7SDag-Erling Smørgrav converts characters, four at a time, starting at (or after) 133*7b5038d7SDag-Erling Smørgrav src from base - 64 numbers into three 8 bit bytes in the target area. 134*7b5038d7SDag-Erling Smørgrav it returns the number of data bytes stored at the target, or -1 on error. 135*7b5038d7SDag-Erling Smørgrav */ 136*7b5038d7SDag-Erling Smørgrav 137*7b5038d7SDag-Erling Smørgrav int 138*7b5038d7SDag-Erling Smørgrav ldns_b64_pton(char const *src, uint8_t *target, size_t targsize) 139*7b5038d7SDag-Erling Smørgrav { 140*7b5038d7SDag-Erling Smørgrav int tarindex, state, ch; 141*7b5038d7SDag-Erling Smørgrav char *pos; 142*7b5038d7SDag-Erling Smørgrav 143*7b5038d7SDag-Erling Smørgrav state = 0; 144*7b5038d7SDag-Erling Smørgrav tarindex = 0; 145*7b5038d7SDag-Erling Smørgrav 146*7b5038d7SDag-Erling Smørgrav if (strlen(src) == 0) { 147*7b5038d7SDag-Erling Smørgrav return 0; 148*7b5038d7SDag-Erling Smørgrav } 149*7b5038d7SDag-Erling Smørgrav 150*7b5038d7SDag-Erling Smørgrav while ((ch = *src++) != '\0') { 151*7b5038d7SDag-Erling Smørgrav if (isspace((unsigned char)ch)) /* Skip whitespace anywhere. */ 152*7b5038d7SDag-Erling Smørgrav continue; 153*7b5038d7SDag-Erling Smørgrav 154*7b5038d7SDag-Erling Smørgrav if (ch == Pad64) 155*7b5038d7SDag-Erling Smørgrav break; 156*7b5038d7SDag-Erling Smørgrav 157*7b5038d7SDag-Erling Smørgrav pos = strchr(Base64, ch); 158*7b5038d7SDag-Erling Smørgrav if (pos == 0) { 159*7b5038d7SDag-Erling Smørgrav /* A non-base64 character. */ 160*7b5038d7SDag-Erling Smørgrav return (-1); 161*7b5038d7SDag-Erling Smørgrav } 162*7b5038d7SDag-Erling Smørgrav 163*7b5038d7SDag-Erling Smørgrav switch (state) { 164*7b5038d7SDag-Erling Smørgrav case 0: 165*7b5038d7SDag-Erling Smørgrav if (target) { 166*7b5038d7SDag-Erling Smørgrav if ((size_t)tarindex >= targsize) 167*7b5038d7SDag-Erling Smørgrav return (-1); 168*7b5038d7SDag-Erling Smørgrav target[tarindex] = (pos - Base64) << 2; 169*7b5038d7SDag-Erling Smørgrav } 170*7b5038d7SDag-Erling Smørgrav state = 1; 171*7b5038d7SDag-Erling Smørgrav break; 172*7b5038d7SDag-Erling Smørgrav case 1: 173*7b5038d7SDag-Erling Smørgrav if (target) { 174*7b5038d7SDag-Erling Smørgrav if ((size_t)tarindex + 1 >= targsize) 175*7b5038d7SDag-Erling Smørgrav return (-1); 176*7b5038d7SDag-Erling Smørgrav target[tarindex] |= (pos - Base64) >> 4; 177*7b5038d7SDag-Erling Smørgrav target[tarindex+1] = ((pos - Base64) & 0x0f) 178*7b5038d7SDag-Erling Smørgrav << 4 ; 179*7b5038d7SDag-Erling Smørgrav } 180*7b5038d7SDag-Erling Smørgrav tarindex++; 181*7b5038d7SDag-Erling Smørgrav state = 2; 182*7b5038d7SDag-Erling Smørgrav break; 183*7b5038d7SDag-Erling Smørgrav case 2: 184*7b5038d7SDag-Erling Smørgrav if (target) { 185*7b5038d7SDag-Erling Smørgrav if ((size_t)tarindex + 1 >= targsize) 186*7b5038d7SDag-Erling Smørgrav return (-1); 187*7b5038d7SDag-Erling Smørgrav target[tarindex] |= (pos - Base64) >> 2; 188*7b5038d7SDag-Erling Smørgrav target[tarindex+1] = ((pos - Base64) & 0x03) 189*7b5038d7SDag-Erling Smørgrav << 6; 190*7b5038d7SDag-Erling Smørgrav } 191*7b5038d7SDag-Erling Smørgrav tarindex++; 192*7b5038d7SDag-Erling Smørgrav state = 3; 193*7b5038d7SDag-Erling Smørgrav break; 194*7b5038d7SDag-Erling Smørgrav case 3: 195*7b5038d7SDag-Erling Smørgrav if (target) { 196*7b5038d7SDag-Erling Smørgrav if ((size_t)tarindex >= targsize) 197*7b5038d7SDag-Erling Smørgrav return (-1); 198*7b5038d7SDag-Erling Smørgrav target[tarindex] |= (pos - Base64); 199*7b5038d7SDag-Erling Smørgrav } 200*7b5038d7SDag-Erling Smørgrav tarindex++; 201*7b5038d7SDag-Erling Smørgrav state = 0; 202*7b5038d7SDag-Erling Smørgrav break; 203*7b5038d7SDag-Erling Smørgrav default: 204*7b5038d7SDag-Erling Smørgrav abort(); 205*7b5038d7SDag-Erling Smørgrav } 206*7b5038d7SDag-Erling Smørgrav } 207*7b5038d7SDag-Erling Smørgrav 208*7b5038d7SDag-Erling Smørgrav /* 209*7b5038d7SDag-Erling Smørgrav * We are done decoding Base-64 chars. Let's see if we ended 210*7b5038d7SDag-Erling Smørgrav * on a byte boundary, and/or with erroneous trailing characters. 211*7b5038d7SDag-Erling Smørgrav */ 212*7b5038d7SDag-Erling Smørgrav 213*7b5038d7SDag-Erling Smørgrav if (ch == Pad64) { /* We got a pad char. */ 214*7b5038d7SDag-Erling Smørgrav ch = *src++; /* Skip it, get next. */ 215*7b5038d7SDag-Erling Smørgrav switch (state) { 216*7b5038d7SDag-Erling Smørgrav case 0: /* Invalid = in first position */ 217*7b5038d7SDag-Erling Smørgrav case 1: /* Invalid = in second position */ 218*7b5038d7SDag-Erling Smørgrav return (-1); 219*7b5038d7SDag-Erling Smørgrav 220*7b5038d7SDag-Erling Smørgrav case 2: /* Valid, means one byte of info */ 221*7b5038d7SDag-Erling Smørgrav /* Skip any number of spaces. */ 222*7b5038d7SDag-Erling Smørgrav for ((void)NULL; ch != '\0'; ch = *src++) 223*7b5038d7SDag-Erling Smørgrav if (!isspace((unsigned char)ch)) 224*7b5038d7SDag-Erling Smørgrav break; 225*7b5038d7SDag-Erling Smørgrav /* Make sure there is another trailing = sign. */ 226*7b5038d7SDag-Erling Smørgrav if (ch != Pad64) 227*7b5038d7SDag-Erling Smørgrav return (-1); 228*7b5038d7SDag-Erling Smørgrav ch = *src++; /* Skip the = */ 229*7b5038d7SDag-Erling Smørgrav /* Fall through to "single trailing =" case. */ 230*7b5038d7SDag-Erling Smørgrav /* FALLTHROUGH */ 231*7b5038d7SDag-Erling Smørgrav 232*7b5038d7SDag-Erling Smørgrav case 3: /* Valid, means two bytes of info */ 233*7b5038d7SDag-Erling Smørgrav /* 234*7b5038d7SDag-Erling Smørgrav * We know this char is an =. Is there anything but 235*7b5038d7SDag-Erling Smørgrav * whitespace after it? 236*7b5038d7SDag-Erling Smørgrav */ 237*7b5038d7SDag-Erling Smørgrav for ((void)NULL; ch != '\0'; ch = *src++) 238*7b5038d7SDag-Erling Smørgrav if (!isspace((unsigned char)ch)) 239*7b5038d7SDag-Erling Smørgrav return (-1); 240*7b5038d7SDag-Erling Smørgrav 241*7b5038d7SDag-Erling Smørgrav /* 242*7b5038d7SDag-Erling Smørgrav * Now make sure for cases 2 and 3 that the "extra" 243*7b5038d7SDag-Erling Smørgrav * bits that slopped past the last full byte were 244*7b5038d7SDag-Erling Smørgrav * zeros. If we don't check them, they become a 245*7b5038d7SDag-Erling Smørgrav * subliminal channel. 246*7b5038d7SDag-Erling Smørgrav */ 247*7b5038d7SDag-Erling Smørgrav if (target && target[tarindex] != 0) 248*7b5038d7SDag-Erling Smørgrav return (-1); 249*7b5038d7SDag-Erling Smørgrav } 250*7b5038d7SDag-Erling Smørgrav } else { 251*7b5038d7SDag-Erling Smørgrav /* 252*7b5038d7SDag-Erling Smørgrav * We ended by seeing the end of the string. Make sure we 253*7b5038d7SDag-Erling Smørgrav * have no partial bytes lying around. 254*7b5038d7SDag-Erling Smørgrav */ 255*7b5038d7SDag-Erling Smørgrav if (state != 0) 256*7b5038d7SDag-Erling Smørgrav return (-1); 257*7b5038d7SDag-Erling Smørgrav } 258*7b5038d7SDag-Erling Smørgrav 259*7b5038d7SDag-Erling Smørgrav return (tarindex); 260*7b5038d7SDag-Erling Smørgrav } 261