/contrib/bind9/lib/isc/base64.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 252 lines · 188 code · 30 blank · 34 comment · 67 complexity · 79e0ae044c45293d8daeb6fea337ee94 MD5 · raw file

  1. /*
  2. * Copyright (C) 2004, 2005, 2007, 2009 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. /* $Id: base64.c,v 1.34 2009/10/21 23:48:05 tbox Exp $ */
  18. /*! \file */
  19. #include <config.h>
  20. #include <isc/base64.h>
  21. #include <isc/buffer.h>
  22. #include <isc/lex.h>
  23. #include <isc/string.h>
  24. #include <isc/util.h>
  25. #define RETERR(x) do { \
  26. isc_result_t _r = (x); \
  27. if (_r != ISC_R_SUCCESS) \
  28. return (_r); \
  29. } while (0)
  30. /*@{*/
  31. /*!
  32. * These static functions are also present in lib/dns/rdata.c. I'm not
  33. * sure where they should go. -- bwelling
  34. */
  35. static isc_result_t
  36. str_totext(const char *source, isc_buffer_t *target);
  37. static isc_result_t
  38. mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length);
  39. static const char base64[] =
  40. "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
  41. /*@}*/
  42. isc_result_t
  43. isc_base64_totext(isc_region_t *source, int wordlength,
  44. const char *wordbreak, isc_buffer_t *target)
  45. {
  46. char buf[5];
  47. unsigned int loops = 0;
  48. if (wordlength < 4)
  49. wordlength = 4;
  50. memset(buf, 0, sizeof(buf));
  51. while (source->length > 2) {
  52. buf[0] = base64[(source->base[0]>>2)&0x3f];
  53. buf[1] = base64[((source->base[0]<<4)&0x30)|
  54. ((source->base[1]>>4)&0x0f)];
  55. buf[2] = base64[((source->base[1]<<2)&0x3c)|
  56. ((source->base[2]>>6)&0x03)];
  57. buf[3] = base64[source->base[2]&0x3f];
  58. RETERR(str_totext(buf, target));
  59. isc_region_consume(source, 3);
  60. loops++;
  61. if (source->length != 0 &&
  62. (int)((loops + 1) * 4) >= wordlength)
  63. {
  64. loops = 0;
  65. RETERR(str_totext(wordbreak, target));
  66. }
  67. }
  68. if (source->length == 2) {
  69. buf[0] = base64[(source->base[0]>>2)&0x3f];
  70. buf[1] = base64[((source->base[0]<<4)&0x30)|
  71. ((source->base[1]>>4)&0x0f)];
  72. buf[2] = base64[((source->base[1]<<2)&0x3c)];
  73. buf[3] = '=';
  74. RETERR(str_totext(buf, target));
  75. isc_region_consume(source, 2);
  76. } else if (source->length == 1) {
  77. buf[0] = base64[(source->base[0]>>2)&0x3f];
  78. buf[1] = base64[((source->base[0]<<4)&0x30)];
  79. buf[2] = buf[3] = '=';
  80. RETERR(str_totext(buf, target));
  81. isc_region_consume(source, 1);
  82. }
  83. return (ISC_R_SUCCESS);
  84. }
  85. /*%
  86. * State of a base64 decoding process in progress.
  87. */
  88. typedef struct {
  89. int length; /*%< Desired length of binary data or -1 */
  90. isc_buffer_t *target; /*%< Buffer for resulting binary data */
  91. int digits; /*%< Number of buffered base64 digits */
  92. isc_boolean_t seen_end; /*%< True if "=" end marker seen */
  93. int val[4];
  94. } base64_decode_ctx_t;
  95. static inline void
  96. base64_decode_init(base64_decode_ctx_t *ctx, int length, isc_buffer_t *target)
  97. {
  98. ctx->digits = 0;
  99. ctx->seen_end = ISC_FALSE;
  100. ctx->length = length;
  101. ctx->target = target;
  102. }
  103. static inline isc_result_t
  104. base64_decode_char(base64_decode_ctx_t *ctx, int c) {
  105. char *s;
  106. if (ctx->seen_end)
  107. return (ISC_R_BADBASE64);
  108. if ((s = strchr(base64, c)) == NULL)
  109. return (ISC_R_BADBASE64);
  110. ctx->val[ctx->digits++] = s - base64;
  111. if (ctx->digits == 4) {
  112. int n;
  113. unsigned char buf[3];
  114. if (ctx->val[0] == 64 || ctx->val[1] == 64)
  115. return (ISC_R_BADBASE64);
  116. if (ctx->val[2] == 64 && ctx->val[3] != 64)
  117. return (ISC_R_BADBASE64);
  118. /*
  119. * Check that bits that should be zero are.
  120. */
  121. if (ctx->val[2] == 64 && (ctx->val[1] & 0xf) != 0)
  122. return (ISC_R_BADBASE64);
  123. /*
  124. * We don't need to test for ctx->val[2] != 64 as
  125. * the bottom two bits of 64 are zero.
  126. */
  127. if (ctx->val[3] == 64 && (ctx->val[2] & 0x3) != 0)
  128. return (ISC_R_BADBASE64);
  129. n = (ctx->val[2] == 64) ? 1 :
  130. (ctx->val[3] == 64) ? 2 : 3;
  131. if (n != 3) {
  132. ctx->seen_end = ISC_TRUE;
  133. if (ctx->val[2] == 64)
  134. ctx->val[2] = 0;
  135. if (ctx->val[3] == 64)
  136. ctx->val[3] = 0;
  137. }
  138. buf[0] = (ctx->val[0]<<2)|(ctx->val[1]>>4);
  139. buf[1] = (ctx->val[1]<<4)|(ctx->val[2]>>2);
  140. buf[2] = (ctx->val[2]<<6)|(ctx->val[3]);
  141. RETERR(mem_tobuffer(ctx->target, buf, n));
  142. if (ctx->length >= 0) {
  143. if (n > ctx->length)
  144. return (ISC_R_BADBASE64);
  145. else
  146. ctx->length -= n;
  147. }
  148. ctx->digits = 0;
  149. }
  150. return (ISC_R_SUCCESS);
  151. }
  152. static inline isc_result_t
  153. base64_decode_finish(base64_decode_ctx_t *ctx) {
  154. if (ctx->length > 0)
  155. return (ISC_R_UNEXPECTEDEND);
  156. if (ctx->digits != 0)
  157. return (ISC_R_BADBASE64);
  158. return (ISC_R_SUCCESS);
  159. }
  160. isc_result_t
  161. isc_base64_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) {
  162. base64_decode_ctx_t ctx;
  163. isc_textregion_t *tr;
  164. isc_token_t token;
  165. isc_boolean_t eol;
  166. base64_decode_init(&ctx, length, target);
  167. while (!ctx.seen_end && (ctx.length != 0)) {
  168. unsigned int i;
  169. if (length > 0)
  170. eol = ISC_FALSE;
  171. else
  172. eol = ISC_TRUE;
  173. RETERR(isc_lex_getmastertoken(lexer, &token,
  174. isc_tokentype_string, eol));
  175. if (token.type != isc_tokentype_string)
  176. break;
  177. tr = &token.value.as_textregion;
  178. for (i = 0; i < tr->length; i++)
  179. RETERR(base64_decode_char(&ctx, tr->base[i]));
  180. }
  181. if (ctx.length < 0 && !ctx.seen_end)
  182. isc_lex_ungettoken(lexer, &token);
  183. RETERR(base64_decode_finish(&ctx));
  184. return (ISC_R_SUCCESS);
  185. }
  186. isc_result_t
  187. isc_base64_decodestring(const char *cstr, isc_buffer_t *target) {
  188. base64_decode_ctx_t ctx;
  189. base64_decode_init(&ctx, -1, target);
  190. for (;;) {
  191. int c = *cstr++;
  192. if (c == '\0')
  193. break;
  194. if (c == ' ' || c == '\t' || c == '\n' || c== '\r')
  195. continue;
  196. RETERR(base64_decode_char(&ctx, c));
  197. }
  198. RETERR(base64_decode_finish(&ctx));
  199. return (ISC_R_SUCCESS);
  200. }
  201. static isc_result_t
  202. str_totext(const char *source, isc_buffer_t *target) {
  203. unsigned int l;
  204. isc_region_t region;
  205. isc_buffer_availableregion(target, &region);
  206. l = strlen(source);
  207. if (l > region.length)
  208. return (ISC_R_NOSPACE);
  209. memcpy(region.base, source, l);
  210. isc_buffer_add(target, l);
  211. return (ISC_R_SUCCESS);
  212. }
  213. static isc_result_t
  214. mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) {
  215. isc_region_t tr;
  216. isc_buffer_availableregion(target, &tr);
  217. if (length > tr.length)
  218. return (ISC_R_NOSPACE);
  219. memcpy(tr.base, base, length);
  220. isc_buffer_add(target, length);
  221. return (ISC_R_SUCCESS);
  222. }