1 /* $NetBSD: base64.c,v 1.6 2014/12/10 04:37:59 christos Exp $ */ 2 3 /* 4 * Copyright (C) 2004, 2005, 2007, 2009, 2013, 2014 Internet Systems Consortium, Inc. ("ISC") 5 * Copyright (C) 1998-2001, 2003 Internet Software Consortium. 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* Id: base64.c,v 1.34 2009/10/21 23:48:05 tbox Exp */ 21 22 /*! \file */ 23 24 #include <config.h> 25 26 #include <isc/base64.h> 27 #include <isc/buffer.h> 28 #include <isc/lex.h> 29 #include <isc/string.h> 30 #include <isc/util.h> 31 32 #define RETERR(x) do { \ 33 isc_result_t _r = (x); \ 34 if (_r != ISC_R_SUCCESS) \ 35 return (_r); \ 36 } while (/*CONSTCOND*/0) 37 38 39 /*@{*/ 40 /*! 41 * These static functions are also present in lib/dns/rdata.c. I'm not 42 * sure where they should go. -- bwelling 43 */ 44 static isc_result_t 45 str_totext(const char *source, isc_buffer_t *target); 46 47 static isc_result_t 48 mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length); 49 50 static const char base64[] = 51 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; 52 /*@}*/ 53 54 isc_result_t 55 isc_base64_totext(isc_region_t *source, int wordlength, 56 const char *wordbreak, isc_buffer_t *target) 57 { 58 char buf[5]; 59 unsigned int loops = 0; 60 61 if (wordlength < 4) 62 wordlength = 4; 63 64 memset(buf, 0, sizeof(buf)); 65 while (source->length > 2) { 66 buf[0] = base64[(source->base[0]>>2)&0x3f]; 67 buf[1] = base64[((source->base[0]<<4)&0x30)| 68 ((source->base[1]>>4)&0x0f)]; 69 buf[2] = base64[((source->base[1]<<2)&0x3c)| 70 ((source->base[2]>>6)&0x03)]; 71 buf[3] = base64[source->base[2]&0x3f]; 72 RETERR(str_totext(buf, target)); 73 isc_region_consume(source, 3); 74 75 loops++; 76 if (source->length != 0 && 77 (int)((loops + 1) * 4) >= wordlength) 78 { 79 loops = 0; 80 RETERR(str_totext(wordbreak, target)); 81 } 82 } 83 if (source->length == 2) { 84 buf[0] = base64[(source->base[0]>>2)&0x3f]; 85 buf[1] = base64[((source->base[0]<<4)&0x30)| 86 ((source->base[1]>>4)&0x0f)]; 87 buf[2] = base64[((source->base[1]<<2)&0x3c)]; 88 buf[3] = '='; 89 RETERR(str_totext(buf, target)); 90 isc_region_consume(source, 2); 91 } else if (source->length == 1) { 92 buf[0] = base64[(source->base[0]>>2)&0x3f]; 93 buf[1] = base64[((source->base[0]<<4)&0x30)]; 94 buf[2] = buf[3] = '='; 95 RETERR(str_totext(buf, target)); 96 isc_region_consume(source, 1); 97 } 98 return (ISC_R_SUCCESS); 99 } 100 101 /*% 102 * State of a base64 decoding process in progress. 103 */ 104 typedef struct { 105 int length; /*%< Desired length of binary data or -1 */ 106 isc_buffer_t *target; /*%< Buffer for resulting binary data */ 107 int digits; /*%< Number of buffered base64 digits */ 108 isc_boolean_t seen_end; /*%< True if "=" end marker seen */ 109 int val[4]; 110 } base64_decode_ctx_t; 111 112 static inline void 113 base64_decode_init(base64_decode_ctx_t *ctx, int length, isc_buffer_t *target) 114 { 115 ctx->digits = 0; 116 ctx->seen_end = ISC_FALSE; 117 ctx->length = length; 118 ctx->target = target; 119 } 120 121 static inline isc_result_t 122 base64_decode_char(base64_decode_ctx_t *ctx, int c) { 123 char *s; 124 125 if (ctx->seen_end) 126 return (ISC_R_BADBASE64); 127 if ((s = strchr(base64, c)) == NULL) 128 return (ISC_R_BADBASE64); 129 ctx->val[ctx->digits++] = (int)(s - base64); 130 if (ctx->digits == 4) { 131 int n; 132 unsigned char buf[3]; 133 if (ctx->val[0] == 64 || ctx->val[1] == 64) 134 return (ISC_R_BADBASE64); 135 if (ctx->val[2] == 64 && ctx->val[3] != 64) 136 return (ISC_R_BADBASE64); 137 /* 138 * Check that bits that should be zero are. 139 */ 140 if (ctx->val[2] == 64 && (ctx->val[1] & 0xf) != 0) 141 return (ISC_R_BADBASE64); 142 /* 143 * We don't need to test for ctx->val[2] != 64 as 144 * the bottom two bits of 64 are zero. 145 */ 146 if (ctx->val[3] == 64 && (ctx->val[2] & 0x3) != 0) 147 return (ISC_R_BADBASE64); 148 n = (ctx->val[2] == 64) ? 1 : 149 (ctx->val[3] == 64) ? 2 : 3; 150 if (n != 3) { 151 ctx->seen_end = ISC_TRUE; 152 if (ctx->val[2] == 64) 153 ctx->val[2] = 0; 154 if (ctx->val[3] == 64) 155 ctx->val[3] = 0; 156 } 157 buf[0] = (ctx->val[0]<<2)|(ctx->val[1]>>4); 158 buf[1] = (ctx->val[1]<<4)|(ctx->val[2]>>2); 159 buf[2] = (ctx->val[2]<<6)|(ctx->val[3]); 160 RETERR(mem_tobuffer(ctx->target, buf, n)); 161 if (ctx->length >= 0) { 162 if (n > ctx->length) 163 return (ISC_R_BADBASE64); 164 else 165 ctx->length -= n; 166 } 167 ctx->digits = 0; 168 } 169 return (ISC_R_SUCCESS); 170 } 171 172 static inline isc_result_t 173 base64_decode_finish(base64_decode_ctx_t *ctx) { 174 if (ctx->length > 0) 175 return (ISC_R_UNEXPECTEDEND); 176 if (ctx->digits != 0) 177 return (ISC_R_BADBASE64); 178 return (ISC_R_SUCCESS); 179 } 180 181 isc_result_t 182 isc_base64_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) { 183 base64_decode_ctx_t ctx; 184 isc_textregion_t *tr; 185 isc_token_t token; 186 isc_boolean_t eol; 187 188 base64_decode_init(&ctx, length, target); 189 190 while (!ctx.seen_end && (ctx.length != 0)) { 191 unsigned int i; 192 193 if (length > 0) 194 eol = ISC_FALSE; 195 else 196 eol = ISC_TRUE; 197 RETERR(isc_lex_getmastertoken(lexer, &token, 198 isc_tokentype_string, eol)); 199 if (token.type != isc_tokentype_string) 200 break; 201 tr = &token.value.as_textregion; 202 for (i = 0; i < tr->length; i++) 203 RETERR(base64_decode_char(&ctx, tr->base[i])); 204 } 205 if (ctx.length < 0 && !ctx.seen_end) 206 isc_lex_ungettoken(lexer, &token); 207 RETERR(base64_decode_finish(&ctx)); 208 return (ISC_R_SUCCESS); 209 } 210 211 isc_result_t 212 isc_base64_decodestring(const char *cstr, isc_buffer_t *target) { 213 base64_decode_ctx_t ctx; 214 215 base64_decode_init(&ctx, -1, target); 216 for (;;) { 217 int c = *cstr++; 218 if (c == '\0') 219 break; 220 if (c == ' ' || c == '\t' || c == '\n' || c== '\r') 221 continue; 222 RETERR(base64_decode_char(&ctx, c)); 223 } 224 RETERR(base64_decode_finish(&ctx)); 225 return (ISC_R_SUCCESS); 226 } 227 228 static isc_result_t 229 str_totext(const char *source, isc_buffer_t *target) { 230 unsigned int l; 231 isc_region_t region; 232 233 isc_buffer_availableregion(target, ®ion); 234 l = strlen(source); 235 236 if (l > region.length) 237 return (ISC_R_NOSPACE); 238 239 memmove(region.base, source, l); 240 isc_buffer_add(target, l); 241 return (ISC_R_SUCCESS); 242 } 243 244 static isc_result_t 245 mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) { 246 isc_region_t tr; 247 248 isc_buffer_availableregion(target, &tr); 249 if (length > tr.length) 250 return (ISC_R_NOSPACE); 251 memmove(tr.base, base, length); 252 isc_buffer_add(target, length); 253 return (ISC_R_SUCCESS); 254 } 255