1 /*
2  * Copyright (C) 2008, 2009, 2013-2015  Internet Systems Consortium, Inc. ("ISC")
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14  * PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /* $Id: base32.c,v 1.6.698.1 2012/02/15 05:00:16 marka Exp $ */
18 
19 /*! \file */
20 
21 #include <config.h>
22 
23 #include <isc/base32.h>
24 #include <isc/buffer.h>
25 #include <isc/lex.h>
26 #include <isc/region.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  */
42 static isc_result_t
43 str_totext(const char *source, isc_buffer_t *target);
44 
45 static isc_result_t
46 mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length);
47 
48 /*@}*/
49 
50 static const char base32[] =
51 	 "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=abcdefghijklmnopqrstuvwxyz234567";
52 static const char base32hex[] =
53 	"0123456789ABCDEFGHIJKLMNOPQRSTUV=0123456789abcdefghijklmnopqrstuv";
54 
55 static isc_result_t
base32_totext(isc_region_t * source,int wordlength,const char * wordbreak,isc_buffer_t * target,const char base[],char pad)56 base32_totext(isc_region_t *source, int wordlength, const char *wordbreak,
57 	      isc_buffer_t *target, const char base[], char pad)
58 {
59 	char buf[9];
60 	unsigned int loops = 0;
61 
62 	if (wordlength >= 0 && wordlength < 8)
63 		wordlength = 8;
64 
65 	memset(buf, 0, sizeof(buf));
66 	while (source->length > 0) {
67 		buf[0] = base[((source->base[0]>>3)&0x1f)];	/* 5 + */
68 		if (source->length == 1) {
69 			buf[1] = base[(source->base[0]<<2)&0x1c];
70 			buf[2] = buf[3] = buf[4] = pad;
71 			buf[5] = buf[6] = buf[7] = pad;
72 			RETERR(str_totext(buf, target));
73 			break;
74 		}
75 		buf[1] = base[((source->base[0]<<2)&0x1c)|	/* 3 = 8 */
76 			      ((source->base[1]>>6)&0x03)];	/* 2 + */
77 		buf[2] = base[((source->base[1]>>1)&0x1f)];	/* 5 + */
78 		if (source->length == 2) {
79 			buf[3] = base[(source->base[1]<<4)&0x10];
80 			buf[4] = buf[5] = buf[6] = buf[7] = pad;
81 			RETERR(str_totext(buf, target));
82 			break;
83 		}
84 		buf[3] = base[((source->base[1]<<4)&0x10)|	/* 1 = 8 */
85 			      ((source->base[2]>>4)&0x0f)];	/* 4 + */
86 		if (source->length == 3) {
87 			buf[4] = base[(source->base[2]<<1)&0x1e];
88 			buf[5] = buf[6] = buf[7] = pad;
89 			RETERR(str_totext(buf, target));
90 			break;
91 		}
92 		buf[4] = base[((source->base[2]<<1)&0x1e)|	/* 4 = 8 */
93 			      ((source->base[3]>>7)&0x01)];	/* 1 + */
94 		buf[5] = base[((source->base[3]>>2)&0x1f)];	/* 5 + */
95 		if (source->length == 4) {
96 			buf[6] = base[(source->base[3]<<3)&0x18];
97 			buf[7] = pad;
98 			RETERR(str_totext(buf, target));
99 			break;
100 		}
101 		buf[6] = base[((source->base[3]<<3)&0x18)|	/* 2 = 8 */
102 			      ((source->base[4]>>5)&0x07)];	/* 3 + */
103 		buf[7] = base[source->base[4]&0x1f];		/* 5 = 8 */
104 		RETERR(str_totext(buf, target));
105 		isc_region_consume(source, 5);
106 
107 		loops++;
108 		if (source->length != 0 && wordlength >= 0 &&
109 		    (int)((loops + 1) * 8) >= wordlength)
110 		{
111 			loops = 0;
112 			RETERR(str_totext(wordbreak, target));
113 		}
114 	}
115 	if (source->length > 0)
116 		isc_region_consume(source, source->length);
117 	return (ISC_R_SUCCESS);
118 }
119 
120 isc_result_t
isc_base32_totext(isc_region_t * source,int wordlength,const char * wordbreak,isc_buffer_t * target)121 isc_base32_totext(isc_region_t *source, int wordlength,
122 		  const char *wordbreak, isc_buffer_t *target)
123 {
124 	return (base32_totext(source, wordlength, wordbreak, target,
125 			      base32, '='));
126 }
127 
128 isc_result_t
isc_base32hex_totext(isc_region_t * source,int wordlength,const char * wordbreak,isc_buffer_t * target)129 isc_base32hex_totext(isc_region_t *source, int wordlength,
130 		     const char *wordbreak, isc_buffer_t *target)
131 {
132 	return (base32_totext(source, wordlength, wordbreak, target,
133 			      base32hex, '='));
134 }
135 
136 isc_result_t
isc_base32hexnp_totext(isc_region_t * source,int wordlength,const char * wordbreak,isc_buffer_t * target)137 isc_base32hexnp_totext(isc_region_t *source, int wordlength,
138 		     const char *wordbreak, isc_buffer_t *target)
139 {
140 	return (base32_totext(source, wordlength, wordbreak, target,
141 			      base32hex, 0));
142 }
143 
144 /*%
145  * State of a base32 decoding process in progress.
146  */
147 typedef struct {
148 	int length;		/*%< Desired length of binary data or -1 */
149 	isc_buffer_t *target;	/*%< Buffer for resulting binary data */
150 	int digits;		/*%< Number of buffered base32 digits */
151 	isc_boolean_t seen_end;	/*%< True if "=" end marker seen */
152 	int val[8];
153 	const char *base;	/*%< Which encoding we are using */
154 	int seen_32;		/*%< Number of significant bytes if non zero */
155 	isc_boolean_t pad;	/*%< Expect padding */
156 } base32_decode_ctx_t;
157 
158 static inline void
base32_decode_init(base32_decode_ctx_t * ctx,int length,const char base[],isc_boolean_t pad,isc_buffer_t * target)159 base32_decode_init(base32_decode_ctx_t *ctx, int length, const char base[],
160 		   isc_boolean_t pad, isc_buffer_t *target)
161 {
162 	ctx->digits = 0;
163 	ctx->seen_end = ISC_FALSE;
164 	ctx->seen_32 = 0;
165 	ctx->length = length;
166 	ctx->target = target;
167 	ctx->base = base;
168 	ctx->pad = pad;
169 }
170 
171 static inline isc_result_t
base32_decode_char(base32_decode_ctx_t * ctx,int c)172 base32_decode_char(base32_decode_ctx_t *ctx, int c) {
173 	const char *s;
174 	unsigned int last;
175 
176 	if (ctx->seen_end)
177 		return (ISC_R_BADBASE32);
178 	if ((s = strchr(ctx->base, c)) == NULL)
179 		return (ISC_R_BADBASE32);
180 	last = (unsigned int)(s - ctx->base);
181 
182 	/*
183 	 * Handle lower case.
184 	 */
185 	if (last > 32)
186 		last -= 33;
187 
188 	/*
189 	 * Check that padding is contiguous.
190 	 */
191 	if (last != 32 && ctx->seen_32 != 0)
192 		return (ISC_R_BADBASE32);
193 
194 	/*
195 	 * If padding is not permitted flag padding as a error.
196 	 */
197 	if (last == 32 && !ctx->pad)
198 		return (ISC_R_BADBASE32);
199 
200 	/*
201 	 * Check that padding starts at the right place and that
202 	 * bits that should be zero are.
203 	 * Record how many significant bytes in answer (seen_32).
204 	 */
205 	if (last == 32 && ctx->seen_32 == 0)
206 		switch (ctx->digits) {
207 		case 0:
208 		case 1:
209 			return (ISC_R_BADBASE32);
210 		case 2:
211 			if ((ctx->val[1]&0x03) != 0)
212 				return (ISC_R_BADBASE32);
213 			ctx->seen_32 = 1;
214 			break;
215 		case 3:
216 			return (ISC_R_BADBASE32);
217 		case 4:
218 			if ((ctx->val[3]&0x0f) != 0)
219 				return (ISC_R_BADBASE32);
220 			ctx->seen_32 = 3;
221 			break;
222 		case 5:
223 			if ((ctx->val[4]&0x01) != 0)
224 				return (ISC_R_BADBASE32);
225 			ctx->seen_32 = 3;
226 			break;
227 		case 6:
228 			return (ISC_R_BADBASE32);
229 		case 7:
230 			if ((ctx->val[6]&0x07) != 0)
231 				return (ISC_R_BADBASE32);
232 			ctx->seen_32 = 4;
233 			break;
234 		}
235 
236 	/*
237 	 * Zero fill pad values.
238 	 */
239 	ctx->val[ctx->digits++] = (last == 32) ? 0 : last;
240 
241 	if (ctx->digits == 8) {
242 		int n = 5;
243 		unsigned char buf[5];
244 
245 		if (ctx->seen_32 != 0) {
246 			ctx->seen_end = ISC_TRUE;
247 			n = ctx->seen_32;
248 		}
249 		buf[0] = (ctx->val[0]<<3)|(ctx->val[1]>>2);
250 		buf[1] = (ctx->val[1]<<6)|(ctx->val[2]<<1)|(ctx->val[3]>>4);
251 		buf[2] = (ctx->val[3]<<4)|(ctx->val[4]>>1);
252 		buf[3] = (ctx->val[4]<<7)|(ctx->val[5]<<2)|(ctx->val[6]>>3);
253 		buf[4] = (ctx->val[6]<<5)|(ctx->val[7]);
254 		RETERR(mem_tobuffer(ctx->target, buf, n));
255 		if (ctx->length >= 0) {
256 			if (n > ctx->length)
257 				return (ISC_R_BADBASE32);
258 			else
259 				ctx->length -= n;
260 		}
261 		ctx->digits = 0;
262 	}
263 	return (ISC_R_SUCCESS);
264 }
265 
266 static inline isc_result_t
base32_decode_finish(base32_decode_ctx_t * ctx)267 base32_decode_finish(base32_decode_ctx_t *ctx) {
268 
269 	if (ctx->length > 0)
270 		return (ISC_R_UNEXPECTEDEND);
271 	/*
272 	 * Add missing padding if required.
273 	 */
274 	if (!ctx->pad && ctx->digits != 0) {
275 		ctx->pad = ISC_TRUE;
276 		do {
277 			RETERR(base32_decode_char(ctx, '='));
278 		} while (ctx->digits != 0);
279 	}
280 	if (ctx->digits != 0)
281 		return (ISC_R_BADBASE32);
282 	return (ISC_R_SUCCESS);
283 }
284 
285 static isc_result_t
base32_tobuffer(isc_lex_t * lexer,const char base[],isc_boolean_t pad,isc_buffer_t * target,int length)286 base32_tobuffer(isc_lex_t *lexer, const char base[], isc_boolean_t pad,
287 		isc_buffer_t *target, int length)
288 {
289 	base32_decode_ctx_t ctx;
290 	isc_textregion_t *tr;
291 	isc_token_t token;
292 	isc_boolean_t eol;
293 
294 	base32_decode_init(&ctx, length, base, pad, target);
295 
296 	while (!ctx.seen_end && (ctx.length != 0)) {
297 		unsigned int i;
298 
299 		if (length > 0)
300 			eol = ISC_FALSE;
301 		else
302 			eol = ISC_TRUE;
303 		RETERR(isc_lex_getmastertoken(lexer, &token,
304 					      isc_tokentype_string, eol));
305 		if (token.type != isc_tokentype_string)
306 			break;
307 		tr = &token.value.as_textregion;
308 		for (i = 0; i < tr->length; i++)
309 			RETERR(base32_decode_char(&ctx, tr->base[i]));
310 	}
311 	if (ctx.length < 0 && !ctx.seen_end)
312 		isc_lex_ungettoken(lexer, &token);
313 	RETERR(base32_decode_finish(&ctx));
314 	return (ISC_R_SUCCESS);
315 }
316 
317 isc_result_t
isc_base32_tobuffer(isc_lex_t * lexer,isc_buffer_t * target,int length)318 isc_base32_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) {
319 	return (base32_tobuffer(lexer, base32, ISC_TRUE, target, length));
320 }
321 
322 isc_result_t
isc_base32hex_tobuffer(isc_lex_t * lexer,isc_buffer_t * target,int length)323 isc_base32hex_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) {
324 	return (base32_tobuffer(lexer, base32hex, ISC_TRUE, target, length));
325 }
326 
327 isc_result_t
isc_base32hexnp_tobuffer(isc_lex_t * lexer,isc_buffer_t * target,int length)328 isc_base32hexnp_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) {
329 	return (base32_tobuffer(lexer, base32hex, ISC_FALSE, target, length));
330 }
331 
332 static isc_result_t
base32_decodestring(const char * cstr,const char base[],isc_boolean_t pad,isc_buffer_t * target)333 base32_decodestring(const char *cstr, const char base[], isc_boolean_t pad,
334 		    isc_buffer_t *target)
335 {
336 	base32_decode_ctx_t ctx;
337 
338 	base32_decode_init(&ctx, -1, base, pad, target);
339 	for (;;) {
340 		int c = *cstr++;
341 		if (c == '\0')
342 			break;
343 		if (c == ' ' || c == '\t' || c == '\n' || c== '\r')
344 			continue;
345 		RETERR(base32_decode_char(&ctx, c));
346 	}
347 	RETERR(base32_decode_finish(&ctx));
348 	return (ISC_R_SUCCESS);
349 }
350 
351 isc_result_t
isc_base32_decodestring(const char * cstr,isc_buffer_t * target)352 isc_base32_decodestring(const char *cstr, isc_buffer_t *target) {
353 	return (base32_decodestring(cstr, base32, ISC_TRUE, target));
354 }
355 
356 isc_result_t
isc_base32hex_decodestring(const char * cstr,isc_buffer_t * target)357 isc_base32hex_decodestring(const char *cstr, isc_buffer_t *target) {
358 	return (base32_decodestring(cstr, base32hex, ISC_TRUE, target));
359 }
360 
361 isc_result_t
isc_base32hexnp_decodestring(const char * cstr,isc_buffer_t * target)362 isc_base32hexnp_decodestring(const char *cstr, isc_buffer_t *target) {
363 	return (base32_decodestring(cstr, base32hex, ISC_FALSE, target));
364 }
365 
366 static isc_result_t
base32_decoderegion(isc_region_t * source,const char base[],isc_boolean_t pad,isc_buffer_t * target)367 base32_decoderegion(isc_region_t *source, const char base[],
368 		    isc_boolean_t pad, isc_buffer_t *target)
369 {
370 	base32_decode_ctx_t ctx;
371 
372 	base32_decode_init(&ctx, -1, base, pad, target);
373 	while (source->length != 0) {
374 		int c = *source->base;
375 		RETERR(base32_decode_char(&ctx, c));
376 		isc_region_consume(source, 1);
377 	}
378 	RETERR(base32_decode_finish(&ctx));
379 	return (ISC_R_SUCCESS);
380 }
381 
382 isc_result_t
isc_base32_decoderegion(isc_region_t * source,isc_buffer_t * target)383 isc_base32_decoderegion(isc_region_t *source, isc_buffer_t *target) {
384 	return (base32_decoderegion(source, base32, ISC_TRUE, target));
385 }
386 
387 isc_result_t
isc_base32hex_decoderegion(isc_region_t * source,isc_buffer_t * target)388 isc_base32hex_decoderegion(isc_region_t *source, isc_buffer_t *target) {
389 	return (base32_decoderegion(source, base32hex, ISC_TRUE, target));
390 }
391 
392 isc_result_t
isc_base32hexnp_decoderegion(isc_region_t * source,isc_buffer_t * target)393 isc_base32hexnp_decoderegion(isc_region_t *source, isc_buffer_t *target) {
394 	return (base32_decoderegion(source, base32hex, ISC_FALSE, target));
395 }
396 
397 static isc_result_t
str_totext(const char * source,isc_buffer_t * target)398 str_totext(const char *source, isc_buffer_t *target) {
399 	unsigned int l;
400 	isc_region_t region;
401 
402 	isc_buffer_availableregion(target, &region);
403 	l = strlen(source);
404 
405 	if (l > region.length)
406 		return (ISC_R_NOSPACE);
407 
408 	memmove(region.base, source, l);
409 	isc_buffer_add(target, l);
410 	return (ISC_R_SUCCESS);
411 }
412 
413 static isc_result_t
mem_tobuffer(isc_buffer_t * target,void * base,unsigned int length)414 mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) {
415 	isc_region_t tr;
416 
417 	isc_buffer_availableregion(target, &tr);
418 	if (length > tr.length)
419 		return (ISC_R_NOSPACE);
420 	memmove(tr.base, base, length);
421 	isc_buffer_add(target, length);
422 	return (ISC_R_SUCCESS);
423 }
424