1/* $NetBSD: base64.c,v 1.3 2021/08/14 16:14:58 christos Exp $ */ 2 3/* base64.c -- routines to encode/decode base64 data */ 4/* $OpenLDAP$ */ 5/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 1998-2021 The OpenLDAP Foundation. 8 * Portions Copyright 1998-2003 Kurt D. Zeilenga. 9 * Portions Copyright 1995 IBM Corporation. 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted only as authorized by the OpenLDAP 14 * Public License. 15 * 16 * A copy of this license is available in the file LICENSE in the 17 * top-level directory of the distribution or, alternatively, at 18 * <http://www.OpenLDAP.org/license.html>. 19 */ 20/* Portions Copyright (c) 1996, 1998 by Internet Software Consortium. 21 * 22 * Permission to use, copy, modify, and distribute this software for any 23 * purpose with or without fee is hereby granted, provided that the above 24 * copyright notice and this permission notice appear in all copies. 25 * 26 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS 27 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 28 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE 29 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 30 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 31 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 32 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 33 * SOFTWARE. 34 */ 35/* This work is based upon Base64 routines (developed by IBM) found 36 * Berkeley Internet Name Daemon (BIND) as distributed by ISC. They 37 * were adapted for inclusion in OpenLDAP Software by Kurt D. Zeilenga. 38 */ 39 40#include <sys/cdefs.h> 41__RCSID("$NetBSD: base64.c,v 1.3 2021/08/14 16:14:58 christos Exp $"); 42 43#include "portable.h" 44 45#include <ac/assert.h> 46#include <ac/stdlib.h> 47#include <ac/ctype.h> 48#include <ac/string.h> 49 50/* include socket.h to get sys/types.h and/or winsock2.h */ 51#include <ac/socket.h> 52 53#include "lutil.h" 54 55static const char Base64[] = 56 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 57static const char Pad64 = '='; 58 59/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) 60 The following encoding technique is taken from RFC 1521 by Borenstein 61 and Freed. It is reproduced here in a slightly edited form for 62 convenience. 63 64 A 65-character subset of US-ASCII is used, enabling 6 bits to be 65 represented per printable character. (The extra 65th character, "=", 66 is used to signify a special processing function.) 67 68 The encoding process represents 24-bit groups of input bits as output 69 strings of 4 encoded characters. Proceeding from left to right, a 70 24-bit input group is formed by concatenating 3 8-bit input groups. 71 These 24 bits are then treated as 4 concatenated 6-bit groups, each 72 of which is translated into a single digit in the base64 alphabet. 73 74 Each 6-bit group is used as an index into an array of 64 printable 75 characters. The character referenced by the index is placed in the 76 output string. 77 78 Table 1: The Base64 Alphabet 79 80 Value Encoding Value Encoding Value Encoding Value Encoding 81 0 A 17 R 34 i 51 z 82 1 B 18 S 35 j 52 0 83 2 C 19 T 36 k 53 1 84 3 D 20 U 37 l 54 2 85 4 E 21 V 38 m 55 3 86 5 F 22 W 39 n 56 4 87 6 G 23 X 40 o 57 5 88 7 H 24 Y 41 p 58 6 89 8 I 25 Z 42 q 59 7 90 9 J 26 a 43 r 60 8 91 10 K 27 b 44 s 61 9 92 11 L 28 c 45 t 62 + 93 12 M 29 d 46 u 63 / 94 13 N 30 e 47 v 95 14 O 31 f 48 w (pad) = 96 15 P 32 g 49 x 97 16 Q 33 h 50 y 98 99 Special processing is performed if fewer than 24 bits are available 100 at the end of the data being encoded. A full encoding quantum is 101 always completed at the end of a quantity. When fewer than 24 input 102 bits are available in an input group, zero bits are added (on the 103 right) to form an integral number of 6-bit groups. Padding at the 104 end of the data is performed using the '=' character. 105 106 Since all base64 input is an integral number of octets, only the 107 ------------------------------------------------- 108 following cases can arise: 109 110 (1) the final quantum of encoding input is an integral 111 multiple of 24 bits; here, the final unit of encoded 112 output will be an integral multiple of 4 characters 113 with no "=" padding, 114 (2) the final quantum of encoding input is exactly 8 bits; 115 here, the final unit of encoded output will be two 116 characters followed by two "=" padding characters, or 117 (3) the final quantum of encoding input is exactly 16 bits; 118 here, the final unit of encoded output will be three 119 characters followed by one "=" padding character. 120 */ 121 122int 123lutil_b64_ntop( 124 u_char const *src, 125 size_t srclength, 126 char *target, 127 size_t targsize) 128{ 129 size_t datalength = 0; 130 u_char input[3]; 131 u_char output[4]; 132 size_t i; 133 134 while (2 < srclength) { 135 input[0] = *src++; 136 input[1] = *src++; 137 input[2] = *src++; 138 srclength -= 3; 139 140 output[0] = input[0] >> 2; 141 output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); 142 output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); 143 output[3] = input[2] & 0x3f; 144 assert(output[0] < 64); 145 assert(output[1] < 64); 146 assert(output[2] < 64); 147 assert(output[3] < 64); 148 149 if (datalength + 4 > targsize) 150 return (-1); 151 target[datalength++] = Base64[output[0]]; 152 target[datalength++] = Base64[output[1]]; 153 target[datalength++] = Base64[output[2]]; 154 target[datalength++] = Base64[output[3]]; 155 } 156 157 /* Now we worry about padding. */ 158 if (0 != srclength) { 159 /* Get what's left. */ 160 input[0] = input[1] = input[2] = '\0'; 161 for (i = 0; i < srclength; i++) 162 input[i] = *src++; 163 164 output[0] = input[0] >> 2; 165 output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); 166 output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); 167 assert(output[0] < 64); 168 assert(output[1] < 64); 169 assert(output[2] < 64); 170 171 if (datalength + 4 > targsize) 172 return (-1); 173 target[datalength++] = Base64[output[0]]; 174 target[datalength++] = Base64[output[1]]; 175 if (srclength == 1) 176 target[datalength++] = Pad64; 177 else 178 target[datalength++] = Base64[output[2]]; 179 target[datalength++] = Pad64; 180 } 181 if (datalength >= targsize) 182 return (-1); 183 target[datalength] = '\0'; /* Returned value doesn't count \0. */ 184 return (datalength); 185} 186 187/* skips all whitespace anywhere. 188 converts characters, four at a time, starting at (or after) 189 src from base - 64 numbers into three 8 bit bytes in the target area. 190 it returns the number of data bytes stored at the target, or -1 on error. 191 */ 192 193int 194lutil_b64_pton( 195 char const *src, 196 u_char *target, 197 size_t targsize) 198{ 199 int tarindex, state, ch; 200 char *pos; 201 202 state = 0; 203 tarindex = 0; 204 205 while ((ch = *src++) != '\0') { 206 if (isascii(ch) && isspace(ch)) /* Skip whitespace anywhere. */ 207 continue; 208 209 if (ch == Pad64) 210 break; 211 212 pos = strchr(Base64, ch); 213 if (pos == 0) /* A non-base64 character. */ 214 return (-1); 215 216 switch (state) { 217 case 0: 218 if (target) { 219 if ((size_t)tarindex >= targsize) 220 return (-1); 221 target[tarindex] = (pos - Base64) << 2; 222 } 223 state = 1; 224 break; 225 case 1: 226 if (target) { 227 if ((size_t)tarindex + 1 >= targsize) 228 return (-1); 229 target[tarindex] |= (pos - Base64) >> 4; 230 target[tarindex+1] = ((pos - Base64) & 0x0f) 231 << 4 ; 232 } 233 tarindex++; 234 state = 2; 235 break; 236 case 2: 237 if (target) { 238 if ((size_t)tarindex + 1 >= targsize) 239 return (-1); 240 target[tarindex] |= (pos - Base64) >> 2; 241 target[tarindex+1] = ((pos - Base64) & 0x03) 242 << 6; 243 } 244 tarindex++; 245 state = 3; 246 break; 247 case 3: 248 if (target) { 249 if ((size_t)tarindex >= targsize) 250 return (-1); 251 target[tarindex] |= (pos - Base64); 252 } 253 tarindex++; 254 state = 0; 255 break; 256 default: 257 abort(); 258 } 259 } 260 261 /* 262 * We are done decoding Base-64 chars. Let's see if we ended 263 * on a byte boundary, and/or with erroneous trailing characters. 264 */ 265 266 if (ch == Pad64) { /* We got a pad char. */ 267 ch = *src++; /* Skip it, get next. */ 268 switch (state) { 269 case 0: /* Invalid = in first position */ 270 case 1: /* Invalid = in second position */ 271 return (-1); 272 273 case 2: /* Valid, means one byte of info */ 274 /* Skip any number of spaces. */ 275 for ((void)NULL; ch != '\0'; ch = *src++) 276 if (! (isascii(ch) && isspace(ch))) 277 break; 278 /* Make sure there is another trailing = sign. */ 279 if (ch != Pad64) 280 return (-1); 281 ch = *src++; /* Skip the = */ 282 /* Fall through to "single trailing =" case. */ 283 /* FALLTHROUGH */ 284 285 case 3: /* Valid, means two bytes of info */ 286 /* 287 * We know this char is an =. Is there anything but 288 * whitespace after it? 289 */ 290 for ((void)NULL; ch != '\0'; ch = *src++) 291 if (! (isascii(ch) && isspace(ch))) 292 return (-1); 293 294 /* 295 * Now make sure for cases 2 and 3 that the "extra" 296 * bits that slopped past the last full byte were 297 * zeros. If we don't check them, they become a 298 * subliminal channel. 299 */ 300 if (target && target[tarindex] != 0) 301 return (-1); 302 } 303 } else { 304 /* 305 * We ended by seeing the end of the string. Make sure we 306 * have no partial bytes lying around. 307 */ 308 if (state != 0) 309 return (-1); 310 } 311 312 return (tarindex); 313} 314