1135446Strhodes/* 2262706Serwin * Copyright (C) 2004, 2005, 2007, 2008, 2013, 2014 Internet Systems Consortium, Inc. ("ISC") 3135446Strhodes * Copyright (C) 2000-2003 Internet Software Consortium. 4135446Strhodes * 5193149Sdougb * Permission to use, copy, modify, and/or distribute this software for any 6135446Strhodes * purpose with or without fee is hereby granted, provided that the above 7135446Strhodes * copyright notice and this permission notice appear in all copies. 8135446Strhodes * 9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11135446Strhodes * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15135446Strhodes * PERFORMANCE OF THIS SOFTWARE. 16135446Strhodes */ 17135446Strhodes 18234010Sdougb/* $Id: hex.c,v 1.20 2008/09/25 04:02:39 tbox Exp $ */ 19135446Strhodes 20170222Sdougb/*! \file */ 21170222Sdougb 22135446Strhodes#include <config.h> 23135446Strhodes 24135446Strhodes#include <ctype.h> 25135446Strhodes 26135446Strhodes#include <isc/buffer.h> 27135446Strhodes#include <isc/hex.h> 28135446Strhodes#include <isc/lex.h> 29135446Strhodes#include <isc/string.h> 30135446Strhodes#include <isc/util.h> 31135446Strhodes 32135446Strhodes#define RETERR(x) do { \ 33135446Strhodes isc_result_t _r = (x); \ 34135446Strhodes if (_r != ISC_R_SUCCESS) \ 35135446Strhodes return (_r); \ 36135446Strhodes } while (0) 37135446Strhodes 38135446Strhodes 39135446Strhodes/* 40135446Strhodes * BEW: These static functions are copied from lib/dns/rdata.c. 41135446Strhodes */ 42135446Strhodesstatic isc_result_t 43135446Strhodesstr_totext(const char *source, isc_buffer_t *target); 44135446Strhodes 45135446Strhodesstatic isc_result_t 46135446Strhodesmem_tobuffer(isc_buffer_t *target, void *base, unsigned int length); 47135446Strhodes 48135446Strhodesstatic const char hex[] = "0123456789ABCDEF"; 49135446Strhodes 50135446Strhodesisc_result_t 51135446Strhodesisc_hex_totext(isc_region_t *source, int wordlength, 52135446Strhodes const char *wordbreak, isc_buffer_t *target) 53135446Strhodes{ 54135446Strhodes char buf[3]; 55135446Strhodes unsigned int loops = 0; 56135446Strhodes 57135446Strhodes if (wordlength < 2) 58135446Strhodes wordlength = 2; 59135446Strhodes 60135446Strhodes memset(buf, 0, sizeof(buf)); 61135446Strhodes while (source->length > 0) { 62135446Strhodes buf[0] = hex[(source->base[0] >> 4) & 0xf]; 63135446Strhodes buf[1] = hex[(source->base[0]) & 0xf]; 64135446Strhodes RETERR(str_totext(buf, target)); 65135446Strhodes isc_region_consume(source, 1); 66135446Strhodes 67135446Strhodes loops++; 68135446Strhodes if (source->length != 0 && 69135446Strhodes (int)((loops + 1) * 2) >= wordlength) 70135446Strhodes { 71135446Strhodes loops = 0; 72135446Strhodes RETERR(str_totext(wordbreak, target)); 73135446Strhodes } 74135446Strhodes } 75135446Strhodes return (ISC_R_SUCCESS); 76135446Strhodes} 77135446Strhodes 78170222Sdougb/*% 79135446Strhodes * State of a hex decoding process in progress. 80135446Strhodes */ 81135446Strhodestypedef struct { 82170222Sdougb int length; /*%< Desired length of binary data or -1 */ 83170222Sdougb isc_buffer_t *target; /*%< Buffer for resulting binary data */ 84170222Sdougb int digits; /*%< Number of buffered hex digits */ 85135446Strhodes int val[2]; 86135446Strhodes} hex_decode_ctx_t; 87135446Strhodes 88135446Strhodesstatic inline void 89135446Strhodeshex_decode_init(hex_decode_ctx_t *ctx, int length, isc_buffer_t *target) 90135446Strhodes{ 91135446Strhodes ctx->digits = 0; 92135446Strhodes ctx->length = length; 93135446Strhodes ctx->target = target; 94135446Strhodes} 95135446Strhodes 96135446Strhodesstatic inline isc_result_t 97135446Strhodeshex_decode_char(hex_decode_ctx_t *ctx, int c) { 98135446Strhodes char *s; 99135446Strhodes 100135446Strhodes if ((s = strchr(hex, toupper(c))) == NULL) 101135446Strhodes return (ISC_R_BADHEX); 102262706Serwin ctx->val[ctx->digits++] = (int)(s - hex); 103135446Strhodes if (ctx->digits == 2) { 104135446Strhodes unsigned char num; 105135446Strhodes 106135446Strhodes num = (ctx->val[0] << 4) + (ctx->val[1]); 107135446Strhodes RETERR(mem_tobuffer(ctx->target, &num, 1)); 108135446Strhodes if (ctx->length >= 0) { 109135446Strhodes if (ctx->length == 0) 110135446Strhodes return (ISC_R_BADHEX); 111135446Strhodes else 112135446Strhodes ctx->length -= 1; 113135446Strhodes } 114135446Strhodes ctx->digits = 0; 115135446Strhodes } 116135446Strhodes return (ISC_R_SUCCESS); 117135446Strhodes} 118135446Strhodes 119135446Strhodesstatic inline isc_result_t 120135446Strhodeshex_decode_finish(hex_decode_ctx_t *ctx) { 121135446Strhodes if (ctx->length > 0) 122135446Strhodes return (ISC_R_UNEXPECTEDEND); 123135446Strhodes if (ctx->digits != 0) 124135446Strhodes return (ISC_R_BADHEX); 125135446Strhodes return (ISC_R_SUCCESS); 126135446Strhodes} 127135446Strhodes 128135446Strhodesisc_result_t 129135446Strhodesisc_hex_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) { 130135446Strhodes hex_decode_ctx_t ctx; 131135446Strhodes isc_textregion_t *tr; 132135446Strhodes isc_token_t token; 133135446Strhodes isc_boolean_t eol; 134135446Strhodes 135135446Strhodes hex_decode_init(&ctx, length, target); 136135446Strhodes 137135446Strhodes while (ctx.length != 0) { 138135446Strhodes unsigned int i; 139135446Strhodes 140135446Strhodes if (length > 0) 141135446Strhodes eol = ISC_FALSE; 142135446Strhodes else 143135446Strhodes eol = ISC_TRUE; 144135446Strhodes RETERR(isc_lex_getmastertoken(lexer, &token, 145135446Strhodes isc_tokentype_string, eol)); 146135446Strhodes if (token.type != isc_tokentype_string) 147135446Strhodes break; 148135446Strhodes tr = &token.value.as_textregion; 149135446Strhodes for (i = 0; i < tr->length; i++) 150135446Strhodes RETERR(hex_decode_char(&ctx, tr->base[i])); 151135446Strhodes } 152135446Strhodes if (ctx.length < 0) 153135446Strhodes isc_lex_ungettoken(lexer, &token); 154135446Strhodes RETERR(hex_decode_finish(&ctx)); 155135446Strhodes return (ISC_R_SUCCESS); 156135446Strhodes} 157135446Strhodes 158135446Strhodesisc_result_t 159193149Sdougbisc_hex_decodestring(const char *cstr, isc_buffer_t *target) { 160135446Strhodes hex_decode_ctx_t ctx; 161135446Strhodes 162135446Strhodes hex_decode_init(&ctx, -1, target); 163135446Strhodes for (;;) { 164135446Strhodes int c = *cstr++; 165135446Strhodes if (c == '\0') 166135446Strhodes break; 167135446Strhodes if (c == ' ' || c == '\t' || c == '\n' || c== '\r') 168135446Strhodes continue; 169135446Strhodes RETERR(hex_decode_char(&ctx, c)); 170135446Strhodes } 171193149Sdougb RETERR(hex_decode_finish(&ctx)); 172135446Strhodes return (ISC_R_SUCCESS); 173135446Strhodes} 174135446Strhodes 175135446Strhodesstatic isc_result_t 176135446Strhodesstr_totext(const char *source, isc_buffer_t *target) { 177135446Strhodes unsigned int l; 178135446Strhodes isc_region_t region; 179135446Strhodes 180135446Strhodes isc_buffer_availableregion(target, ®ion); 181135446Strhodes l = strlen(source); 182135446Strhodes 183135446Strhodes if (l > region.length) 184135446Strhodes return (ISC_R_NOSPACE); 185135446Strhodes 186262706Serwin memmove(region.base, source, l); 187135446Strhodes isc_buffer_add(target, l); 188135446Strhodes return (ISC_R_SUCCESS); 189135446Strhodes} 190135446Strhodes 191135446Strhodesstatic isc_result_t 192135446Strhodesmem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) { 193135446Strhodes isc_region_t tr; 194135446Strhodes 195135446Strhodes isc_buffer_availableregion(target, &tr); 196135446Strhodes if (length > tr.length) 197135446Strhodes return (ISC_R_NOSPACE); 198262706Serwin memmove(tr.base, base, length); 199135446Strhodes isc_buffer_add(target, length); 200135446Strhodes return (ISC_R_SUCCESS); 201135446Strhodes} 202