Commit 17c65253 authored by JINMEI Tatuya's avatar JINMEI Tatuya
Browse files

merged branches/trac256 for trac #256: various base32/hex bug fixes.


git-svn-id: svn://bind10.isc.org/svn/bind10/trunk@2549 e5f2f494-b856-4b98-b285-d166d9295462
parents 551e9a0b 327297de
......@@ -28,14 +28,14 @@
#include <datasrc/data_source.h>
#include <datasrc/query.h>
#include <dns/base32.h>
#include <dns/util/base32hex.h>
#include <dns/buffer.h>
#include <dns/message.h>
#include <dns/name.h>
#include <dns/rdataclass.h>
#include <dns/rrset.h>
#include <dns/rrsetlist.h>
#include <dns/sha1.h>
#include <dns/util/sha1.h>
#include <cc/data.h>
......@@ -1234,7 +1234,7 @@ Nsec3Param::getHash(const Name& name) const {
inlength = SHA1_HASHSIZE;
} while (n++ < iterations_);
return (encodeBase32(vector<uint8_t>(digest, digest + SHA1_HASHSIZE)));
return (encodeBase32Hex(vector<uint8_t>(digest, digest + SHA1_HASHSIZE)));
}
//
......
......@@ -57,12 +57,14 @@ BUILT_SOURCES = rrclass.h rrtype.h rrparamregistry.cc
lib_LTLIBRARIES = libdns++.la
libdns___la_SOURCES = base32.h base32.cc
libdns___la_SOURCES += base64.h base64.cc
libdns___la_SOURCES = util/base32hex.h util/base64.h util/base_n.cc
libdns___la_SOURCES += util/base32hex_from_binary.h
libdns___la_SOURCES += util/binary_from_base32hex.h
libdns___la_SOURCES += util/base16_from_binary.h util/binary_from_base16.h
libdns___la_SOURCES += buffer.h
libdns___la_SOURCES += dnssectime.h dnssectime.cc
libdns___la_SOURCES += exceptions.h exceptions.cc
libdns___la_SOURCES += hex.h hex.cc
libdns___la_SOURCES += util/hex.h
libdns___la_SOURCES += message.h message.cc
libdns___la_SOURCES += messagerenderer.h messagerenderer.cc
libdns___la_SOURCES += name.h name.cc
......@@ -74,7 +76,7 @@ libdns___la_SOURCES += rrsetlist.h rrsetlist.cc
libdns___la_SOURCES += rrttl.h rrttl.cc
libdns___la_SOURCES += rrtype.cc
libdns___la_SOURCES += question.h question.cc
libdns___la_SOURCES += sha1.h sha1.cc
libdns___la_SOURCES += util/sha1.h util/sha1.cc
libdns___la_SOURCES += tsig.h tsig.cc
nodist_libdns___la_SOURCES = rdataclass.cc rrclass.h rrtype.h
......@@ -105,9 +107,6 @@ libdns++_include_HEADERS = \
rrtype.h \
tsig.h
# Purposely not installing these headers:
# base32.h # used only internally, and not actually DNS specific
# base64.h # used only internally, and not actually DNS specific
# hex.h # used only internally, and not actually DNS specific
# sha1.h # used only internally, and not actually DNS specific
# util/*.h: used only internally, and not actually DNS specific
# rrclass-placeholder.h
# rrtype-placeholder.h
// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
// $Id$
#include <cassert>
#include <iterator>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <exceptions/exceptions.h>
#include <ctype.h>
#include <stdint.h>
#include <string.h>
#include <dns/base32.h>
using namespace std;
namespace isc {
namespace dns {
static const char base32hex[] = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
string
encodeBase32(const vector<uint8_t>& binary) {
ostringstream base32;
size_t len = binary.size();
size_t pos = 0;
while (len > 0) {
char buf[9];
memset(buf, '=', 8);
buf[8] = '\0';
uint8_t digit = (binary.at(pos) >> 3) & 0x1f;
buf[0] = base32hex[digit];
if (len == 1) {
digit = (binary.at(pos) << 2) & 0x1c;
buf[1] = base32hex[digit];
base32 << buf;
break;
}
digit = ((binary.at(pos) << 2) & 0x1c) |
((binary.at(pos + 1) >> 6) & 0x03);
buf[1] = base32hex[digit];
digit = (binary.at(pos + 1) >> 1) & 0x1f;
buf[2] = base32hex[digit];
if (len == 2) {
digit = (binary.at(pos + 1) << 4) & 0x10;
buf[3] = base32hex[digit];
base32 << buf;
break;
}
digit = ((binary.at(pos + 1) << 4) & 0x10) |
((binary.at(pos + 2) >> 4) & 0x0f);
buf[3] = base32hex[digit];
if (len == 3) {
digit = (binary.at(pos + 2) << 1) & 0x1e;
buf[4] = base32hex[digit];
base32 << buf;
break;
}
digit = ((binary.at(pos + 2) << 1) & 0x1e) |
((binary.at(pos + 3) >> 7) & 0x01);
buf[4] = base32hex[digit];
digit = (binary.at(pos + 3) >> 2) & 0x1f;
buf[5] = base32hex[digit];
if (len == 4) {
digit = (binary.at(pos + 3) << 3) & 0x18;
buf[6] = base32hex[digit];
base32 << buf;
break;
}
digit = ((binary.at(pos + 3) << 3) & 0x18) |
((binary.at(pos + 4) >> 5) & 0x07);
buf[6] = base32hex[digit];
digit = binary.at(pos + 4) & 0x1f;
buf[7] = base32hex[digit];
len -= 5;
pos += 5;
base32 << buf;
}
return (base32.str());
}
void
decodeBase32(const string& base32, vector<uint8_t>& result) {
ostringstream comp;
// compress input by removing whitespace
const size_t len = base32.length();
for (int i = 0; i < len; ++i) {
const char c = base32[i];
if (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
continue;
}
comp << c;
}
// base32 text should be a multiple of 8 bytes long
if (comp.str().length() % 8 != 0) {
isc_throw(BadBase32String, "Invalid length: " << comp.str().length());
}
istringstream iss(comp.str());
result.clear();
bool seenpad = false;
while (!iss.eof()) {
string group;
iss >> setw(8) >> group;
if (iss.bad() || iss.fail()) {
isc_throw(BadBase32String,
"Could not parse base32 input: " << base32);
}
uint8_t octet = 0;
for (int i = 0; i < 8; ++i) {
char c = toupper(group.at(i));
int value;
if (c != '=' && seenpad) {
isc_throw(BadBase32String, "Invalid base32 input: " << base32);
} else
if (c == '=' && !seenpad) {
value = 0;
seenpad = true;
} else {
const char* pos = strchr(base32hex, c);
if (!pos) {
isc_throw(BadBase32String,
"Invalid base32 input: " << base32);
}
value = pos - base32hex;
assert (value < 32);
}
switch (i) {
case 0: octet |= value << 3;
break;
case 1: octet |= value >> 2;
result.push_back(octet);
octet = (value & 0x03) << 6;
break;
case 2: octet |= value << 1;
break;
case 3: octet |= value >> 4;
result.push_back(octet);
octet = (value & 0x0f) << 4;
break;
case 4: octet |= value >> 1;
result.push_back(octet);
octet = (value & 0x01) << 7;
break;
case 5: octet |= value << 2;
break;
case 6: octet |= value >> 3;
result.push_back(octet);
octet = (value & 0x07) << 5;
break;
case 7: octet |= value;
result.push_back(octet);
}
}
}
}
}
}
// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
// $Id$
#include <stdint.h>
#include <cassert>
#include <iterator>
#include <string>
#include <vector>
#include <boost/archive/iterators/base64_from_binary.hpp>
#include <boost/archive/iterators/binary_from_base64.hpp>
#include <boost/archive/iterators/transform_width.hpp>
#include <exceptions/exceptions.h>
#include <dns/base64.h>
using namespace std;
using namespace boost::archive::iterators;
namespace isc {
namespace dns {
namespace {
const char BASE64_PADDING_CHAR = '=';
const uint8_t BINARY_ZERO_CODE = 0;
class BinaryNormalizer : public iterator<input_iterator_tag, uint8_t> {
public:
BinaryNormalizer(const vector<uint8_t>::const_iterator& base,
const vector<uint8_t>::const_iterator& base_end) :
base_(base), base_end_(base_end), in_pad_(false)
{}
BinaryNormalizer& operator++()
{
if (!in_pad_) {
++base_;
}
if (base_ == base_end_) {
in_pad_ = true;
}
return (*this);
}
const uint8_t& operator*() const {
if (in_pad_) {
return (BINARY_ZERO_CODE);
} else {
return (*base_);
}
}
bool operator==(const BinaryNormalizer& other) const
{
return (base_ == other.base_);
}
private:
vector<uint8_t>::const_iterator base_;
const vector<uint8_t>::const_iterator base_end_;
bool in_pad_;
};
typedef
base64_from_binary<transform_width<BinaryNormalizer, 6, 8> > base64_encoder;
} // end of anonymous namespace
string
encodeBase64(const vector<uint8_t>& binary)
{
// calculate the resulting length. it's the smallest multiple of 4
// equal to or larger than 4/3 * original data length.
size_t len = ((binary.size() * 4 / 3) + 3) & ~3;
string base64;
base64.reserve(len);
base64.assign(base64_encoder(BinaryNormalizer(binary.begin(),
binary.end())),
base64_encoder(BinaryNormalizer(binary.end(), binary.end())));
assert(len >= base64.length());
base64.append(len - base64.length(), BASE64_PADDING_CHAR);
return (base64);
}
namespace {
const size_t BASE64_MAX_PADDING_CHARS = 2;
const char BASE64_ZERO_CODE = 'A'; // correspond to 000000(2)
class Base64Normalizer : public iterator<input_iterator_tag, char> {
public:
Base64Normalizer(const string::const_iterator& base,
const string::const_iterator& base_beginpad,
const string::const_iterator& base_end) :
base_(base), base_beginpad_(base_beginpad), base_end_(base_end),
in_pad_(false)
{}
Base64Normalizer& operator++()
{
++base_;
while (base_ != base_end_ && isspace(*base_)) {
++base_;
}
if (base_ == base_beginpad_) {
in_pad_ = true;
}
return (*this);
}
const char& operator*() const {
if (in_pad_ && *base_ == BASE64_PADDING_CHAR) {
return (BASE64_ZERO_CODE);
} else {
return (*base_);
}
}
bool operator==(const Base64Normalizer& other) const
{
return (base_ == other.base_);
}
private:
string::const_iterator base_;
const string::const_iterator base_beginpad_;
const string::const_iterator base_end_;
bool in_pad_;
};
typedef
transform_width<binary_from_base64<Base64Normalizer, char>, 8, 6, char>
base64_decoder;
} // end of anonymous namespace
void
decodeBase64(const string& base64, vector<uint8_t>& result)
{
// enumerate the number of trailing padding characters (=), ignoring
// white spaces. since base64_from_binary doesn't accept padding,
// we handle it explicitly.
size_t padlen = 0;
string::const_reverse_iterator srit = base64.rbegin();
string::const_reverse_iterator srit_end = base64.rend();
while (srit != srit_end) {
char ch = *srit;
if (ch == BASE64_PADDING_CHAR) {
if (++padlen > BASE64_MAX_PADDING_CHARS) {
isc_throw(BadBase64String,
"Too many Base64 padding characters");
}
} else if (!isspace(ch)) {
break;
}
++srit;
}
try {
result.assign(base64_decoder(Base64Normalizer(base64.begin(),
srit.base(),
base64.end())),
base64_decoder(Base64Normalizer(base64.end(),
base64.end(),
base64.end())));
} catch (dataflow_exception& ex) {
isc_throw(BadBase64String, ex.what());
}
// Confirm the original base64 text is the canonical encoding of the
// data.
assert(result.size() >= padlen);
vector<uint8_t>::const_reverse_iterator rit = result.rbegin();
for (int i = 0; i < padlen; ++i, ++rit) {
if (*rit != 0) {
isc_throw(BadBase64String, "Non 0 bits included in padding");
}
}
// strip the padded zero-bit fields
result.resize(result.size() - padlen);
}
}
}
// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
// $Id$
#include <cassert>
#include <iterator>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <exceptions/exceptions.h>
#include <boost/foreach.hpp>
#include <ctype.h>
#include <stdint.h>
#include <dns/hex.h>
using namespace std;
namespace isc {
namespace dns {
namespace {
const char hexdigits[] = "0123456789ABCDEF";
}
std::string
encodeHex(const std::vector<uint8_t>& binary) {
// calculate the resulting length. it should be twice the
// original data length
const size_t len = (binary.size() * 2);
std::ostringstream hex;
BOOST_FOREACH(uint8_t octet, binary) {
hex << hexdigits[octet >> 4] << hexdigits[octet & 0xf];
}
assert(len >= hex.str().length());
return (hex.str());
}
void
decodeHex(const std::string& hex, std::vector<uint8_t>& result) {
ostringstream comp;
// compress input by removing whitespace
const size_t len = hex.length();
for (int i = 0; i < len; ++i) {
char c = hex.at(i);
if (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
continue;
}
comp << c;
}
istringstream iss(comp.str());
result.clear();
char c1, c2;
iss.width(1);
if ((comp.str().length() % 2) == 1) {
c2 = '0';
iss >> c2;
const char* pos = strchr(hexdigits, toupper(c2));
if (pos == NULL) {
isc_throw(BadHexString, "Invalid hex digit");
}
if (!iss.eof() && !iss.bad() && !iss.fail()) {
result.push_back(pos - hexdigits);
}
}
while (!iss.eof()) {
c1 = c2 = '0';
iss >> c1 >> c2;;
if (iss.eof() || iss.fail() || iss.bad()) {
break;
}
const char* pos1 = strchr(hexdigits, toupper(c1));
const char* pos2 = strchr(hexdigits, toupper(c2));
if (!pos1 || !pos2) {
isc_throw(BadHexString, "Invalid hex digit");
}
const uint8_t n = ((pos1 - hexdigits) << 4) | (pos2 - hexdigits);
result.push_back(n);
}
}
}
}
......@@ -22,7 +22,7 @@
#include <boost/lexical_cast.hpp>
#include <boost/foreach.hpp>
#include <dns/base64.h>
#include <dns/util/base64.h>
#include <dns/buffer.h>
#include <dns/messagerenderer.h>
#include <dns/name.h>
......
......@@ -22,7 +22,7 @@
#include <boost/lexical_cast.hpp>
#include <dns/buffer.h>
#include <dns/hex.h>
#include <dns/util/hex.h>
#include <dns/messagerenderer.h>
#include <dns/name.h>
#include <dns/rdata.h>
......
......@@ -22,10 +22,10 @@
#include <boost/lexical_cast.hpp>
#include <dns/base32.h>
#include <dns/util/base32hex.h>
#include <dns/buffer.h>
#include <dns/exceptions.h>
#include <dns/hex.h>
#include <dns/util/hex.h>
#include <dns/messagerenderer.h>
#include <dns/name.h>
#include <dns/rrtype.h>
......@@ -88,7 +88,7 @@ NSEC3::NSEC3(const string& nsec3_str) :
if (iss.bad() || iss.fail()) {
isc_throw(InvalidRdataText, "Invalid NSEC3 hash algorithm");
}
decodeBase32(nextstr, next);
decodeBase32Hex(nextstr, next);
uint8_t bitmap[8 * 1024]; // 64k bits
vector<uint8_t> typebits;
......@@ -237,7 +237,7 @@ NSEC3::toText() const
" " + lexical_cast<string>(static_cast<int>(impl_->flags_)) +
" " + lexical_cast<string>(static_cast<int>(impl_->iterations_)) +
" " + encodeHex(impl_->salt_) +
" " + encodeBase32(impl_->next_) + s.str());
" " + encodeBase32Hex(impl_->next_) + s.str());
}
void
......
......@@ -22,7 +22,7 @@
#include <boost/lexical_cast.hpp>
#include <dns/buffer.h>
#include <dns/hex.h>
#include <dns/util/hex.h>
#include <dns/messagerenderer.h>