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