1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
7  *
8  * See the COPYRIGHT file distributed with this work for additional
9  * information regarding copyright ownership.
10  */
11 
12 
13 /*! \file */
14 
15 #include <config.h>
16 
17 #include <stdbool.h>
18 
19 #include <isc/base32.h>
20 #include <isc/buffer.h>
21 #include <isc/lex.h>
22 #include <isc/region.h>
23 #include <isc/string.h>
24 #include <isc/util.h>
25 
26 #define RETERR(x) do { \
27 	isc_result_t _r = (x); \
28 	if (_r != ISC_R_SUCCESS) \
29 		return (_r); \
30 	} while (0)
31 
32 
33 /*@{*/
34 /*!
35  * These static functions are also present in lib/dns/rdata.c.  I'm not
36  * sure where they should go. -- bwelling
37  */
38 static isc_result_t
39 str_totext(const char *source, isc_buffer_t *target);
40 
41 static isc_result_t
42 mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length);
43 
44 /*@}*/
45 
46 static const char base32[] =
47 	 "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=abcdefghijklmnopqrstuvwxyz234567";
48 static const char base32hex[] =
49 	"0123456789ABCDEFGHIJKLMNOPQRSTUV=0123456789abcdefghijklmnopqrstuv";
50 
51 static isc_result_t
base32_totext(isc_region_t * source,int wordlength,const char * wordbreak,isc_buffer_t * target,const char base[],char pad)52 base32_totext(isc_region_t *source, int wordlength, const char *wordbreak,
53 	      isc_buffer_t *target, const char base[], char pad)
54 {
55 	char buf[9];
56 	unsigned int loops = 0;
57 
58 	if (wordlength >= 0 && wordlength < 8)
59 		wordlength = 8;
60 
61 	memset(buf, 0, sizeof(buf));
62 	while (source->length > 0) {
63 		buf[0] = base[((source->base[0]>>3)&0x1f)];	/* 5 + */
64 		if (source->length == 1) {
65 			buf[1] = base[(source->base[0]<<2)&0x1c];
66 			buf[2] = buf[3] = buf[4] = pad;
67 			buf[5] = buf[6] = buf[7] = pad;
68 			RETERR(str_totext(buf, target));
69 			break;
70 		}
71 		buf[1] = base[((source->base[0]<<2)&0x1c)|	/* 3 = 8 */
72 			      ((source->base[1]>>6)&0x03)];	/* 2 + */
73 		buf[2] = base[((source->base[1]>>1)&0x1f)];	/* 5 + */
74 		if (source->length == 2) {
75 			buf[3] = base[(source->base[1]<<4)&0x10];
76 			buf[4] = buf[5] = buf[6] = buf[7] = pad;
77 			RETERR(str_totext(buf, target));
78 			break;
79 		}
80 		buf[3] = base[((source->base[1]<<4)&0x10)|	/* 1 = 8 */
81 			      ((source->base[2]>>4)&0x0f)];	/* 4 + */
82 		if (source->length == 3) {
83 			buf[4] = base[(source->base[2]<<1)&0x1e];
84 			buf[5] = buf[6] = buf[7] = pad;
85 			RETERR(str_totext(buf, target));
86 			break;
87 		}
88 		buf[4] = base[((source->base[2]<<1)&0x1e)|	/* 4 = 8 */
89 			      ((source->base[3]>>7)&0x01)];	/* 1 + */
90 		buf[5] = base[((source->base[3]>>2)&0x1f)];	/* 5 + */
91 		if (source->length == 4) {
92 			buf[6] = base[(source->base[3]<<3)&0x18];
93 			buf[7] = pad;
94 			RETERR(str_totext(buf, target));
95 			break;
96 		}
97 		buf[6] = base[((source->base[3]<<3)&0x18)|	/* 2 = 8 */
98 			      ((source->base[4]>>5)&0x07)];	/* 3 + */
99 		buf[7] = base[source->base[4]&0x1f];		/* 5 = 8 */
100 		RETERR(str_totext(buf, target));
101 		isc_region_consume(source, 5);
102 
103 		loops++;
104 		if (source->length != 0 && wordlength >= 0 &&
105 		    (int)((loops + 1) * 8) >= wordlength)
106 		{
107 			loops = 0;
108 			RETERR(str_totext(wordbreak, target));
109 		}
110 	}
111 	if (source->length > 0)
112 		isc_region_consume(source, source->length);
113 	return (ISC_R_SUCCESS);
114 }
115 
116 isc_result_t
isc_base32_totext(isc_region_t * source,int wordlength,const char * wordbreak,isc_buffer_t * target)117 isc_base32_totext(isc_region_t *source, int wordlength,
118 		  const char *wordbreak, isc_buffer_t *target)
119 {
120 	return (base32_totext(source, wordlength, wordbreak, target,
121 			      base32, '='));
122 }
123 
124 isc_result_t
isc_base32hex_totext(isc_region_t * source,int wordlength,const char * wordbreak,isc_buffer_t * target)125 isc_base32hex_totext(isc_region_t *source, int wordlength,
126 		     const char *wordbreak, isc_buffer_t *target)
127 {
128 	return (base32_totext(source, wordlength, wordbreak, target,
129 			      base32hex, '='));
130 }
131 
132 isc_result_t
isc_base32hexnp_totext(isc_region_t * source,int wordlength,const char * wordbreak,isc_buffer_t * target)133 isc_base32hexnp_totext(isc_region_t *source, int wordlength,
134 		     const char *wordbreak, isc_buffer_t *target)
135 {
136 	return (base32_totext(source, wordlength, wordbreak, target,
137 			      base32hex, 0));
138 }
139 
140 /*%
141  * State of a base32 decoding process in progress.
142  */
143 typedef struct {
144 	int length;		/*%< Desired length of binary data or -1 */
145 	isc_buffer_t *target;	/*%< Buffer for resulting binary data */
146 	int digits;		/*%< Number of buffered base32 digits */
147 	bool seen_end;	/*%< True if "=" end marker seen */
148 	int val[8];
149 	const char *base;	/*%< Which encoding we are using */
150 	int seen_32;		/*%< Number of significant bytes if non zero */
151 	bool pad;	/*%< Expect padding */
152 } base32_decode_ctx_t;
153 
154 static inline void
base32_decode_init(base32_decode_ctx_t * ctx,int length,const char base[],bool pad,isc_buffer_t * target)155 base32_decode_init(base32_decode_ctx_t *ctx, int length, const char base[],
156 		   bool pad, isc_buffer_t *target)
157 {
158 	ctx->digits = 0;
159 	ctx->seen_end = false;
160 	ctx->seen_32 = 0;
161 	ctx->length = length;
162 	ctx->target = target;
163 	ctx->base = base;
164 	ctx->pad = pad;
165 }
166 
167 static inline isc_result_t
base32_decode_char(base32_decode_ctx_t * ctx,int c)168 base32_decode_char(base32_decode_ctx_t *ctx, int c) {
169 	const char *s;
170 	unsigned int last;
171 
172 	if (ctx->seen_end) {
173 		return (ISC_R_BADBASE32);
174 	}
175 	if ((s = strchr(ctx->base, c)) == NULL) {
176 		return (ISC_R_BADBASE32);
177 	}
178 	last = (unsigned int)(s - ctx->base);
179 
180 	/*
181 	 * Handle lower case.
182 	 */
183 	if (last > 32) {
184 		last -= 33;
185 	}
186 
187 	/*
188 	 * Check that padding is contiguous.
189 	 */
190 	if (last != 32 && ctx->seen_32 != 0) {
191 		return (ISC_R_BADBASE32);
192 	}
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 	/*
202 	 * Check that padding starts at the right place and that
203 	 * bits that should be zero are.
204 	 * Record how many significant bytes in answer (seen_32).
205 	 */
206 	if (last == 32 && ctx->seen_32 == 0) {
207 		switch (ctx->digits) {
208 		case 0:
209 		case 1:
210 			return (ISC_R_BADBASE32);
211 		case 2:
212 			if ((ctx->val[1]&0x03) != 0) {
213 				return (ISC_R_BADBASE32);
214 			}
215 			ctx->seen_32 = 1;
216 			break;
217 		case 3:
218 			return (ISC_R_BADBASE32);
219 		case 4:
220 			if ((ctx->val[3]&0x0f) != 0) {
221 				return (ISC_R_BADBASE32);
222 			}
223 			ctx->seen_32 = 2;
224 			break;
225 		case 5:
226 			if ((ctx->val[4]&0x01) != 0) {
227 				return (ISC_R_BADBASE32);
228 			}
229 			ctx->seen_32 = 3;
230 			break;
231 		case 6:
232 			return (ISC_R_BADBASE32);
233 		case 7:
234 			if ((ctx->val[6]&0x07) != 0) {
235 				return (ISC_R_BADBASE32);
236 			}
237 			ctx->seen_32 = 4;
238 			break;
239 		}
240 	}
241 
242 	/*
243 	 * Zero fill pad values.
244 	 */
245 	ctx->val[ctx->digits++] = (last == 32) ? 0 : last;
246 
247 	if (ctx->digits == 8) {
248 		int n = 5;
249 		unsigned char buf[5];
250 
251 		if (ctx->seen_32 != 0) {
252 			ctx->seen_end = true;
253 			n = ctx->seen_32;
254 		}
255 		buf[0] = (ctx->val[0]<<3)|(ctx->val[1]>>2);
256 		buf[1] = (ctx->val[1]<<6)|(ctx->val[2]<<1)|(ctx->val[3]>>4);
257 		buf[2] = (ctx->val[3]<<4)|(ctx->val[4]>>1);
258 		buf[3] = (ctx->val[4]<<7)|(ctx->val[5]<<2)|(ctx->val[6]>>3);
259 		buf[4] = (ctx->val[6]<<5)|(ctx->val[7]);
260 		RETERR(mem_tobuffer(ctx->target, buf, n));
261 		if (ctx->length >= 0) {
262 			if (n > ctx->length) {
263 				return (ISC_R_BADBASE32);
264 			} else {
265 				ctx->length -= n;
266 			}
267 		}
268 		ctx->digits = 0;
269 	}
270 	return (ISC_R_SUCCESS);
271 }
272 
273 static inline isc_result_t
base32_decode_finish(base32_decode_ctx_t * ctx)274 base32_decode_finish(base32_decode_ctx_t *ctx) {
275 
276 	if (ctx->length > 0)
277 		return (ISC_R_UNEXPECTEDEND);
278 	/*
279 	 * Add missing padding if required.
280 	 */
281 	if (!ctx->pad && ctx->digits != 0) {
282 		ctx->pad = true;
283 		do {
284 			RETERR(base32_decode_char(ctx, '='));
285 		} while (ctx->digits != 0);
286 	}
287 	if (ctx->digits != 0)
288 		return (ISC_R_BADBASE32);
289 	return (ISC_R_SUCCESS);
290 }
291 
292 static isc_result_t
base32_tobuffer(isc_lex_t * lexer,const char base[],bool pad,isc_buffer_t * target,int length)293 base32_tobuffer(isc_lex_t *lexer, const char base[], bool pad,
294 		isc_buffer_t *target, int length)
295 {
296 	unsigned int before, after;
297 	base32_decode_ctx_t ctx;
298 	isc_textregion_t *tr;
299 	isc_token_t token;
300 	bool eol;
301 
302 	REQUIRE(length >= -2);
303 
304 	base32_decode_init(&ctx, length, base, pad, target);
305 
306 	before = isc_buffer_usedlength(target);
307 	while (!ctx.seen_end && (ctx.length != 0)) {
308 		unsigned int i;
309 
310 		if (length > 0) {
311 			eol = false;
312 		} else {
313 			eol = true;
314 		}
315 		RETERR(isc_lex_getmastertoken(lexer, &token,
316 					      isc_tokentype_string, eol));
317 		if (token.type != isc_tokentype_string) {
318 			break;
319 		}
320 		tr = &token.value.as_textregion;
321 		for (i = 0; i < tr->length; i++) {
322 			RETERR(base32_decode_char(&ctx, tr->base[i]));
323 		}
324 	}
325 	after = isc_buffer_usedlength(target);
326 	if (ctx.length < 0 && !ctx.seen_end) {
327 		isc_lex_ungettoken(lexer, &token);
328 	}
329 	RETERR(base32_decode_finish(&ctx));
330 	if (length == -2 && before == after) {
331 		return (ISC_R_UNEXPECTEDEND);
332 	}
333 	return (ISC_R_SUCCESS);
334 }
335 
336 isc_result_t
isc_base32_tobuffer(isc_lex_t * lexer,isc_buffer_t * target,int length)337 isc_base32_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) {
338 	return (base32_tobuffer(lexer, base32, true, target, length));
339 }
340 
341 isc_result_t
isc_base32hex_tobuffer(isc_lex_t * lexer,isc_buffer_t * target,int length)342 isc_base32hex_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) {
343 	return (base32_tobuffer(lexer, base32hex, true, target, length));
344 }
345 
346 isc_result_t
isc_base32hexnp_tobuffer(isc_lex_t * lexer,isc_buffer_t * target,int length)347 isc_base32hexnp_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) {
348 	return (base32_tobuffer(lexer, base32hex, false, target, length));
349 }
350 
351 static isc_result_t
base32_decodestring(const char * cstr,const char base[],bool pad,isc_buffer_t * target)352 base32_decodestring(const char *cstr, const char base[], bool pad,
353 		    isc_buffer_t *target)
354 {
355 	base32_decode_ctx_t ctx;
356 
357 	base32_decode_init(&ctx, -1, base, pad, target);
358 	for (;;) {
359 		int c = *cstr++;
360 		if (c == '\0')
361 			break;
362 		if (c == ' ' || c == '\t' || c == '\n' || c== '\r')
363 			continue;
364 		RETERR(base32_decode_char(&ctx, c));
365 	}
366 	RETERR(base32_decode_finish(&ctx));
367 	return (ISC_R_SUCCESS);
368 }
369 
370 isc_result_t
isc_base32_decodestring(const char * cstr,isc_buffer_t * target)371 isc_base32_decodestring(const char *cstr, isc_buffer_t *target) {
372 	return (base32_decodestring(cstr, base32, true, target));
373 }
374 
375 isc_result_t
isc_base32hex_decodestring(const char * cstr,isc_buffer_t * target)376 isc_base32hex_decodestring(const char *cstr, isc_buffer_t *target) {
377 	return (base32_decodestring(cstr, base32hex, true, target));
378 }
379 
380 isc_result_t
isc_base32hexnp_decodestring(const char * cstr,isc_buffer_t * target)381 isc_base32hexnp_decodestring(const char *cstr, isc_buffer_t *target) {
382 	return (base32_decodestring(cstr, base32hex, false, target));
383 }
384 
385 static isc_result_t
base32_decoderegion(isc_region_t * source,const char base[],bool pad,isc_buffer_t * target)386 base32_decoderegion(isc_region_t *source, const char base[],
387 		    bool pad, isc_buffer_t *target)
388 {
389 	base32_decode_ctx_t ctx;
390 
391 	base32_decode_init(&ctx, -1, base, pad, target);
392 	while (source->length != 0) {
393 		int c = *source->base;
394 		RETERR(base32_decode_char(&ctx, c));
395 		isc_region_consume(source, 1);
396 	}
397 	RETERR(base32_decode_finish(&ctx));
398 	return (ISC_R_SUCCESS);
399 }
400 
401 isc_result_t
isc_base32_decoderegion(isc_region_t * source,isc_buffer_t * target)402 isc_base32_decoderegion(isc_region_t *source, isc_buffer_t *target) {
403 	return (base32_decoderegion(source, base32, true, target));
404 }
405 
406 isc_result_t
isc_base32hex_decoderegion(isc_region_t * source,isc_buffer_t * target)407 isc_base32hex_decoderegion(isc_region_t *source, isc_buffer_t *target) {
408 	return (base32_decoderegion(source, base32hex, true, target));
409 }
410 
411 isc_result_t
isc_base32hexnp_decoderegion(isc_region_t * source,isc_buffer_t * target)412 isc_base32hexnp_decoderegion(isc_region_t *source, isc_buffer_t *target) {
413 	return (base32_decoderegion(source, base32hex, false, target));
414 }
415 
416 static isc_result_t
str_totext(const char * source,isc_buffer_t * target)417 str_totext(const char *source, isc_buffer_t *target) {
418 	unsigned int l;
419 	isc_region_t region;
420 
421 	isc_buffer_availableregion(target, &region);
422 	l = strlen(source);
423 
424 	if (l > region.length)
425 		return (ISC_R_NOSPACE);
426 
427 	memmove(region.base, source, l);
428 	isc_buffer_add(target, l);
429 	return (ISC_R_SUCCESS);
430 }
431 
432 static isc_result_t
mem_tobuffer(isc_buffer_t * target,void * base,unsigned int length)433 mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) {
434 	isc_region_t tr;
435 
436 	isc_buffer_availableregion(target, &tr);
437 	if (length > tr.length)
438 		return (ISC_R_NOSPACE);
439 	memmove(tr.base, base, length);
440 	isc_buffer_add(target, length);
441 	return (ISC_R_SUCCESS);
442 }
443