Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Kea
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
Operations
Operations
Incidents
Packages & Registries
Packages & Registries
Container Registry
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Sebastian Schrader
Kea
Commits
eef87432
Commit
eef87432
authored
May 05, 2011
by
JINMEI Tatuya
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[trac893] implemented major logic of TSIG verify
parent
df8ef3ff
Changes
14
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
954 additions
and
161 deletions
+954
-161
src/lib/dns/tests/testdata/Makefile.am
src/lib/dns/tests/testdata/Makefile.am
+6
-0
src/lib/dns/tests/testdata/gen-wiredata.py.in
src/lib/dns/tests/testdata/gen-wiredata.py.in
+5
-8
src/lib/dns/tests/testdata/tsig_verify1.spec
src/lib/dns/tests/testdata/tsig_verify1.spec
+19
-0
src/lib/dns/tests/testdata/tsig_verify2.spec
src/lib/dns/tests/testdata/tsig_verify2.spec
+32
-0
src/lib/dns/tests/testdata/tsig_verify3.spec
src/lib/dns/tests/testdata/tsig_verify3.spec
+26
-0
src/lib/dns/tests/testdata/tsig_verify4.spec
src/lib/dns/tests/testdata/tsig_verify4.spec
+27
-0
src/lib/dns/tests/testdata/tsig_verify5.spec
src/lib/dns/tests/testdata/tsig_verify5.spec
+26
-0
src/lib/dns/tests/testdata/tsig_verify6.spec
src/lib/dns/tests/testdata/tsig_verify6.spec
+21
-0
src/lib/dns/tests/testdata/tsig_verify7.spec
src/lib/dns/tests/testdata/tsig_verify7.spec
+21
-0
src/lib/dns/tests/testdata/tsig_verify8.spec
src/lib/dns/tests/testdata/tsig_verify8.spec
+23
-0
src/lib/dns/tests/testdata/tsig_verify9.spec
src/lib/dns/tests/testdata/tsig_verify9.spec
+21
-0
src/lib/dns/tests/tsig_unittest.cc
src/lib/dns/tests/tsig_unittest.cc
+425
-66
src/lib/dns/tsig.cc
src/lib/dns/tsig.cc
+269
-73
src/lib/dns/tsig.h
src/lib/dns/tsig.h
+33
-14
No files found.
src/lib/dns/tests/testdata/Makefile.am
View file @
eef87432
...
...
@@ -40,6 +40,9 @@ BUILT_SOURCES += rdata_tsig_toWire1.wire rdata_tsig_toWire2.wire
BUILT_SOURCES
+=
rdata_tsig_toWire3.wire rdata_tsig_toWire4.wire
BUILT_SOURCES
+=
rdata_tsig_toWire5.wire
BUILT_SOURCES
+=
tsigrecord_toWire1.wire tsigrecord_toWire2.wire
BUILT_SOURCES
+=
tsig_verify1.wire tsig_verify2.wire tsig_verify3.wire
BUILT_SOURCES
+=
tsig_verify4.wire tsig_verify5.wire tsig_verify6.wire
BUILT_SOURCES
+=
tsig_verify7.wire tsig_verify8.wire tsig_verify9.wire
# NOTE: keep this in sync with real file listing
# so is included in tarball
...
...
@@ -108,6 +111,9 @@ EXTRA_DIST += rdata_tsig_toWire1.spec rdata_tsig_toWire2.spec
EXTRA_DIST
+=
rdata_tsig_toWire3.spec rdata_tsig_toWire4.spec
EXTRA_DIST
+=
rdata_tsig_toWire5.spec
EXTRA_DIST
+=
tsigrecord_toWire1.spec tsigrecord_toWire2.spec
EXTRA_DIST
+=
tsig_verify1.spec tsig_verify2.spec tsig_verify3.spec
EXTRA_DIST
+=
tsig_verify4.spec tsig_verify5.spec tsig_verify6.spec
EXTRA_DIST
+=
tsig_verify7.spec tsig_verify8.spec tsig_verify9.spec
.spec.wire
:
./gen-wiredata.py
-o
$@
$<
src/lib/dns/tests/testdata/gen-wiredata.py.in
View file @
eef87432
...
...
@@ -283,9 +283,8 @@ class NS(RR):
f.write('# NS name=%s\n' % (self.nsname))
f.write('%s\n' % nsname_wire)
class SOA:
# this currently doesn't support name compression within the RDATA.
rdlen = -1 # auto-calculate
class SOA(RR):
rdlen = None # auto-calculate
mname = 'ns.example.com'
rname = 'root.example.com'
serial = 2010012601
...
...
@@ -296,11 +295,9 @@ class SOA:
def dump(self, f):
mname_wire = encode_name(self.mname)
rname_wire = encode_name(self.rname)
rdlen = self.rdlen
if rdlen < 0:
rdlen = int(20 + len(mname_wire) / 2 + len(str(rname_wire)) / 2)
f.write('\n# SOA RDATA (RDLEN=%d)\n' % rdlen)
f.write('%04x\n' % rdlen);
if self.rdlen is None:
self.rdlen = int(20 + len(mname_wire) / 2 + len(str(rname_wire)) / 2)
self.dump_header(f, self.rdlen)
f.write('# NNAME=%s RNAME=%s\n' % (self.mname, self.rname))
f.write('%s %s\n' % (mname_wire, rname_wire))
f.write('# SERIAL(%d) REFRESH(%d) RETRY(%d) EXPIRE(%d) MINIMUM(%d)\n' %
...
...
src/lib/dns/tests/testdata/tsig_verify1.spec
0 → 100644
View file @
eef87432
#
# An example of signed AXFR request
#
[custom]
sections: header:question:tsig
[header]
id: 0x3410
arcount: 1
[question]
rrtype: AXFR
[tsig]
as_rr: True
rr_name: www.example.com
algorithm: hmac-md5
time_signed: 0x4da8e951
mac_size: 16
mac: 0x35b2fd08268781634400c7c8a5533b13
original_id: 0x3410
src/lib/dns/tests/testdata/tsig_verify2.spec
0 → 100644
View file @
eef87432
#
# An example of signed AXFR response
#
[custom]
sections: header:question:soa:tsig
[header]
id: 0x3410
aa: 1
qr: 1
ancount: 1
arcount: 1
[question]
rrtype: AXFR
[soa]
# note that names are compressed in this RR
as_rr: True
rr_name: ptr=12
mname: ns.ptr=12
rname: root.ptr=12
serial: 2011041503
refresh: 7200
retry: 3600
expire: 2592000
[tsig]
as_rr: True
rr_name: www.example.com
algorithm: hmac-md5
time_signed: 0x4da8e951
mac_size: 16
mac: 0xbdd612cd2c7f9e0648bd6dc23713e83c
original_id: 0x3410
src/lib/dns/tests/testdata/tsig_verify3.spec
0 → 100644
View file @
eef87432
#
# An example of signed AXFR response (continued)
#
[custom]
sections: header:ns:tsig
[header]
id: 0x3410
aa: 1
qr: 1
qdcount: 0
ancount: 1
arcount: 1
[ns]
# note that names are compressed in this RR
as_rr: True
rr_name: example.com.
nsname: ns.ptr=12
[tsig]
as_rr: True
rr_name: www.example.com
algorithm: hmac-md5
time_signed: 0x4da8e951
mac_size: 16
mac: 0x102458f7f62ddd7d638d746034130968
original_id: 0x3410
src/lib/dns/tests/testdata/tsig_verify4.spec
0 → 100644
View file @
eef87432
#
# An example of signed DNS response with bogus MAC
#
[custom]
sections: header:question:a:tsig
[header]
id: 0x2d65
aa: 1
qr: 1
rd: 1
ancount: 1
arcount: 1
[question]
name: www.example.com
[a]
as_rr: True
rr_name: ptr=12
[tsig]
as_rr: True
rr_name: www.example.com
algorithm: hmac-md5
time_signed: 0x4da8877a
mac_size: 16
# bogus MAC
mac: 0xdeadbeefdeadbeefdeadbeefdeadbeef
original_id: 0x2d65
src/lib/dns/tests/testdata/tsig_verify5.spec
0 → 100644
View file @
eef87432
#
# An example of signed DNS response
#
[custom]
sections: header:question:a:tsig
[header]
id: 0x2d65
aa: 1
qr: 1
rd: 1
ancount: 1
arcount: 1
[question]
name: www.example.com
[a]
as_rr: True
rr_name: ptr=12
[tsig]
as_rr: True
rr_name: www.example.com
algorithm: hmac-md5
time_signed: 0x4da8877a
mac_size: 16
mac: 0x8fcda66a7cd1a3b9948eb1869d384a9f
original_id: 0x2d65
src/lib/dns/tests/testdata/tsig_verify6.spec
0 → 100644
View file @
eef87432
#
# Forwarded DNS query message with TSIG signed (header ID != orig ID)
#
[custom]
sections: header:question:tsig
[header]
id: 0x1035
rd: 1
arcount: 1
[question]
name: www.example.com
[tsig]
as_rr: True
# TSIG QNAME won't be compressed
rr_name: www.example.com
algorithm: hmac-md5
time_signed: 0x4da8877a
mac_size: 16
mac: 0x227026ad297beee721ce6c6fff1e9ef3
original_id: 0x2d65
src/lib/dns/tests/testdata/tsig_verify7.spec
0 → 100644
View file @
eef87432
#
# DNS query message with TSIG that has empty MAC (invalidly)
#
[custom]
sections: header:question:tsig
[header]
id: 0x2d65
rd: 1
arcount: 1
[question]
name: www.example.com
[tsig]
as_rr: True
# TSIG QNAME won't be compressed
rr_name: www.example.com
algorithm: hmac-md5
time_signed: 0x4da8877a
mac_size: 0
mac: ''
original_id: 0x2d65
src/lib/dns/tests/testdata/tsig_verify8.spec
0 → 100644
View file @
eef87432
#
# DNS query message with TSIG that has empty MAC + BADKEY error
#
[custom]
sections: header:question:tsig
[header]
id: 0x2d65
rd: 1
arcount: 1
[question]
name: www.example.com
[tsig]
as_rr: True
# TSIG QNAME won't be compressed
rr_name: www.example.com
algorithm: hmac-md5
time_signed: 0x4da8877a
mac_size: 0
mac: ''
# 17: BADKEY
error: 17
original_id: 0x2d65
src/lib/dns/tests/testdata/tsig_verify9.spec
0 → 100644
View file @
eef87432
#
# A simple DNS query message with TSIG signed, but TSIG key and algorithm
# names have upper case characters (unusual)
#
[custom]
sections: header:question:tsig
[header]
id: 0x2d65
rd: 1
arcount: 1
[question]
name: www.example.com
[tsig]
as_rr: True
rr_name: WWW.EXAMPLE.COM
algorithm: HMAC-MD5.SIG-ALG.REG.INT
time_signed: 0x4da8877a
mac_size: 16
mac: 0x227026ad297beee721ce6c6fff1e9ef3
original_id: 0x2d65
src/lib/dns/tests/tsig_unittest.cc
View file @
eef87432
This diff is collapsed.
Click to expand it.
src/lib/dns/tsig.cc
View file @
eef87432
...
...
@@ -45,14 +45,15 @@ namespace dns {
namespace
{
typedef
boost
::
shared_ptr
<
HMAC
>
HMACPtr
;
// This singleton key is used when the TSIG context is constructed with no
// matching key. The key name and algorithm won't be used in subsequent
// sign/verify, so the their values don't matter.
const
TSIGKey
&
getDummyTSIGKey
()
{
static
TSIGKey
dummy_key
(
Name
::
ROOT_NAME
(),
TSIGKey
::
HMACMD5_NAME
(),
NULL
,
0
);
return
(
dummy_key
);
// TSIG uses 48-bit unsigned integer to represent time signed.
// Since gettimeWrapper() returns a 64-bit *signed* integer, we
// make sure it's stored in an unsigned 64-bit integer variable and
// represents a value in the expected range. (In reality, however,
// gettimeWrapper() will return a positive integer that will fit
// in 48 bits)
uint64_t
getTSIGTime
()
{
return
(
detail
::
gettimeWrapper
()
&
0x0000ffffffffffffULL
);
}
}
...
...
@@ -61,6 +62,32 @@ struct TSIGContext::TSIGContextImpl {
state_
(
INIT
),
key_
(
key
),
error_
(
Rcode
::
NOERROR
()),
previous_timesigned_
(
0
)
{}
TSIGError
postVerifyUpdate
(
TSIGError
error
,
const
void
*
digest
,
size_t
digest_len
)
{
if
(
state_
==
INIT
)
{
state_
=
RECEIVED_REQUEST
;
}
else
if
(
state_
==
WAIT_RESPONSE
&&
error
==
TSIGError
::
NOERROR
())
{
state_
=
VERIFIED_RESPONSE
;
}
if
(
digest
!=
NULL
)
{
previous_digest_
.
assign
(
static_cast
<
const
uint8_t
*>
(
digest
),
static_cast
<
const
uint8_t
*>
(
digest
)
+
digest_len
);
}
error_
=
error
;
return
(
error
);
}
void
digestPreviousMAC
(
OutputBuffer
&
buffer
,
HMACPtr
hmac
)
const
;
void
digestTSIGVariables
(
OutputBuffer
&
buffer
,
HMACPtr
hmac
,
uint16_t
rrclass
,
uint32_t
rrttl
,
uint64_t
time_signed
,
uint16_t
fudge
,
uint16_t
error
,
uint16_t
otherlen
,
const
void
*
otherdata
,
bool
time_variables_only
)
const
;
void
digestDNSMessage
(
OutputBuffer
&
buffer
,
HMACPtr
hmac
,
uint16_t
qid
,
const
void
*
data
,
size_t
data_len
)
const
;
State
state_
;
const
TSIGKey
key_
;
vector
<
uint8_t
>
previous_digest_
;
...
...
@@ -68,6 +95,89 @@ struct TSIGContext::TSIGContextImpl {
uint64_t
previous_timesigned_
;
// only meaningful for response with BADTIME
};
void
TSIGContext
::
TSIGContextImpl
::
digestPreviousMAC
(
OutputBuffer
&
buffer
,
HMACPtr
hmac
)
const
{
buffer
.
clear
();
const
uint16_t
previous_digest_len
(
previous_digest_
.
size
());
buffer
.
writeUint16
(
previous_digest_len
);
if
(
previous_digest_len
!=
0
)
{
buffer
.
writeData
(
&
previous_digest_
[
0
],
previous_digest_len
);
}
hmac
->
update
(
buffer
.
getData
(),
buffer
.
getLength
());
}
void
TSIGContext
::
TSIGContextImpl
::
digestTSIGVariables
(
OutputBuffer
&
buffer
,
HMACPtr
hmac
,
uint16_t
rrclass
,
uint32_t
rrttl
,
uint64_t
time_signed
,
uint16_t
fudge
,
uint16_t
error
,
uint16_t
otherlen
,
const
void
*
otherdata
,
bool
time_variables_only
)
const
{
buffer
.
clear
();
if
(
!
time_variables_only
)
{
key_
.
getKeyName
().
toWire
(
buffer
);
buffer
.
writeUint16
(
rrclass
);
buffer
.
writeUint32
(
rrttl
);
key_
.
getAlgorithmName
().
toWire
(
buffer
);
}
buffer
.
writeUint16
(
time_signed
>>
32
);
buffer
.
writeUint32
(
time_signed
&
0xffffffff
);
buffer
.
writeUint16
(
fudge
);
hmac
->
update
(
buffer
.
getData
(),
buffer
.
getLength
());
if
(
!
time_variables_only
)
{
buffer
.
clear
();
buffer
.
writeUint16
(
error
);
buffer
.
writeUint16
(
otherlen
);
hmac
->
update
(
buffer
.
getData
(),
buffer
.
getLength
());
if
(
otherlen
>
0
)
{
hmac
->
update
(
otherdata
,
otherlen
);
}
}
}
namespace
{
// We exploit some minimum knowledge of DNS message format:
// the header section has a fixed length of 12 octets
// the offset in the header section to the ID field is 0 (and the field length
// is 2 octets)
// the offset in the header section to the ARCOUNT field is 10 (and the field
// length is 2 octets)
const
size_t
MESSAGE_HEADER_LEN
=
12
;
}
void
TSIGContext
::
TSIGContextImpl
::
digestDNSMessage
(
OutputBuffer
&
buffer
,
HMACPtr
hmac
,
uint16_t
qid
,
const
void
*
data
,
size_t
data_len
)
const
{
buffer
.
clear
();
const
uint8_t
*
msgptr
=
static_cast
<
const
uint8_t
*>
(
data
);
// Install the original ID
buffer
.
writeUint16
(
qid
);
msgptr
+=
sizeof
(
uint16_t
);
// Copy the rest of the header except the ARCOUNT field.
buffer
.
writeData
(
msgptr
,
8
);
msgptr
+=
8
;
// Install the adjusted ARCOUNT (we don't care even if the value is bogus
// and it underflows; it would simply result in verification failure)
InputBuffer
b
(
msgptr
,
sizeof
(
uint16_t
));
const
uint16_t
arcount
=
b
.
readUint16
();
buffer
.
writeUint16
(
arcount
-
1
);
msgptr
+=
2
;
// Digest the header and the rest of the DNS message
hmac
->
update
(
buffer
.
getData
(),
buffer
.
getLength
());
hmac
->
update
(
msgptr
,
data_len
-
MESSAGE_HEADER_LEN
);
}
TSIGContext
::
TSIGContext
(
const
TSIGKey
&
key
)
:
impl_
(
new
TSIGContextImpl
(
key
))
{
}
...
...
@@ -78,7 +188,12 @@ TSIGContext::TSIGContext(const Name& key_name, const Name& algorithm_name,
const
TSIGKeyRing
::
FindResult
result
(
keyring
.
find
(
key_name
,
algorithm_name
));
if
(
result
.
code
==
TSIGKeyRing
::
NOTFOUND
)
{
impl_
=
new
TSIGContextImpl
(
getDummyTSIGKey
());
// If not key is found, create a dummy key with the specified key
// parameters and empty secret. In the common scenario this will
// be used in subsequent response with a TSIG indicating a BADKEY
// error.
impl_
=
new
TSIGContextImpl
(
TSIGKey
(
key_name
,
algorithm_name
,
NULL
,
0
));
impl_
->
error_
=
TSIGError
::
BAD_KEY
();
}
else
{
impl_
=
new
TSIGContextImpl
(
*
result
.
key
);
...
...
@@ -103,21 +218,20 @@ ConstTSIGRecordPtr
TSIGContext
::
sign
(
const
uint16_t
qid
,
const
void
*
const
data
,
const
size_t
data_len
)
{
if
(
impl_
->
state_
==
VERIFIED_RESPONSE
)
{
isc_throw
(
TSIGContextError
,
"TSIG sign attempt after verifying a response"
);
}
if
(
data
==
NULL
||
data_len
==
0
)
{
isc_throw
(
InvalidParameter
,
"TSIG sign error: empty data is given"
);
}
TSIGError
error
(
TSIGError
::
NOERROR
());
// TSIG uses 48-bit unsigned integer to represent time signed.
// Since gettimeofdayWrapper() returns a 64-bit *signed* integer, we
// make sure it's stored in an unsigned 64-bit integer variable and
// represents a value in the expected range. (In reality, however,
// gettimeofdayWrapper() will return a positive integer that will fit
// in 48 bits)
const
uint64_t
now
=
(
detail
::
gettimeWrapper
()
&
0x0000ffffffffffffULL
);
const
uint64_t
now
=
getTSIGTime
();
// For responses adjust the error code.
if
(
impl_
->
state_
==
CHECKED
)
{
if
(
impl_
->
state_
==
RECEIVED_REQUEST
)
{
error
=
impl_
->
error_
;
}
...
...
@@ -130,7 +244,7 @@ TSIGContext::sign(const uint16_t qid, const void* const data,
now
,
DEFAULT_FUDGE
,
0
,
NULL
,
qid
,
error
.
getCode
(),
0
,
NULL
)));
impl_
->
previous_digest_
.
clear
();
impl_
->
state_
=
S
IGNED
;
impl_
->
state_
=
S
ENT_RESPONSE
;
return
(
tsig
);
}
...
...
@@ -144,53 +258,35 @@ TSIGContext::sign(const uint16_t qid, const void* const data,
// If the context has previous MAC (either the Request MAC or its own
// previous MAC), digest it.
if
(
impl_
->
state_
!=
INIT
)
{
const
uint16_t
previous_digest_len
(
impl_
->
previous_digest_
.
size
());
variables
.
writeUint16
(
previous_digest_len
);
if
(
previous_digest_len
!=
0
)
{
variables
.
writeData
(
&
impl_
->
previous_digest_
[
0
],
previous_digest_len
);
}
hmac
->
update
(
variables
.
getData
(),
variables
.
getLength
());
impl_
->
digestPreviousMAC
(
variables
,
hmac
);
}
// Digest the message (without TSIG)
hmac
->
update
(
data
,
data_len
);
//
// Digest TSIG variables. If state_ is SIGNED we skip digesting them
// except for time related variables (RFC2845 4.4).
//
variables
.
clear
();
if
(
impl_
->
state_
!=
SIGNED
)
{
impl_
->
key_
.
getKeyName
().
toWire
(
variables
);
TSIGRecord
::
getClass
().
toWire
(
variables
);
variables
.
writeUint32
(
TSIGRecord
::
TSIG_TTL
);
impl_
->
key_
.
getAlgorithmName
().
toWire
(
variables
);
}
// Digest TSIG variables.
// First, prepare some non constant variables.
const
uint64_t
time_signed
=
(
error
==
TSIGError
::
BAD_TIME
())
?
impl_
->
previous_timesigned_
:
now
;
variables
.
writeUint16
(
time_signed
>>
32
);
variables
.
writeUint32
(
time_signed
&
0xffffffff
);
variables
.
writeUint16
(
DEFAULT_FUDGE
);
hmac
->
update
(
variables
.
getData
(),
variables
.
getLength
());
variables
.
clear
();
if
(
impl_
->
state_
!=
SIGNED
)
{
variables
.
writeUint16
(
error
.
getCode
());
// For BADTIME error, digest 6 bytes of other data.
// (6 bytes = size of time signed value)
variables
.
writeUint16
((
error
==
TSIGError
::
BAD_TIME
())
?
6
:
0
);
hmac
->
update
(
variables
.
getData
(),
variables
.
getLength
());
variables
.
clear
();
if
(
error
==
TSIGError
::
BAD_TIME
())
{
variables
.
writeUint16
(
now
>>
32
);
variables
.
writeUint32
(
now
&
0xffffffff
);
hmac
->
update
(
variables
.
getData
(),
variables
.
getLength
());
}
// For BADTIME error, we include 6 bytes of other data.
// (6 bytes = size of time signed value)
const
uint16_t
otherlen
=
(
error
==
TSIGError
::
BAD_TIME
())
?
6
:
0
;
OutputBuffer
otherdatabuf
(
otherlen
);
if
(
error
==
TSIGError
::
BAD_TIME
())
{
otherdatabuf
.
writeUint16
(
now
>>
32
);
otherdatabuf
.
writeUint32
(
now
&
0xffffffff
);
}
const
uint16_t
otherlen
=
variables
.
getLength
();
const
void
*
const
otherdata
=
(
otherlen
==
0
)
?
NULL
:
otherdatabuf
.
getData
();
// Then calculate the digest. If state_ is SENT_RESPONSE we are sending
// a continued message in the same TCP stream so skip digesting
// variables except for time related variables (RFC2845 4.4).
impl_
->
digestTSIGVariables
(
variables
,
hmac
,
TSIGRecord
::
getClass
().
getCode
(),
TSIGRecord
::
TSIG_TTL
,
time_signed
,
DEFAULT_FUDGE
,
error
.
getCode
(),
otherlen
,
otherdata
,
impl_
->
state_
==
SENT_RESPONSE
);
// Get the final digest, update internal state, then finish.
vector
<
uint8_t
>
digest
=
hmac
->
sign
();
...
...
@@ -200,31 +296,131 @@ TSIGContext::sign(const uint16_t qid, const void* const data,
time_signed
,
DEFAULT_FUDGE
,
digest
.
size
(),
&
digest
[
0
],
qid
,
error
.
getCode
(),
otherlen
,
otherlen
==
0
?
NULL
:
variables
.
getData
())));
otherdata
)));
// Exception free from now on.
impl_
->
previous_digest_
.
swap
(
digest
);
impl_
->
state_
=
SIGNED
;
impl_
->
state_
=
(
impl_
->
state_
==
INIT
)
?
WAIT_RESPONSE
:
SENT_RESPONSE
;
return
(
tsig
);
}
void
TSIGContext
::
verifyTentative
(
ConstTSIGRecordPtr
tsig
,
TSIGError
error
)
{
const
any
::
TSIG
tsig_rdata
=
tsig
->
getRdata
();
TSIGError
TSIGContext
::
verify
(
const
TSIGRecord
*
const
record
,
const
void
*
const
data
,
const
size_t
data_len
)
{
if
(
impl_
->
state_
==
SENT_RESPONSE
)
{
isc_throw
(
TSIGContextError
,
"TSIG verify attempt after sending a response"
);
}
impl_
->
error_
=
error
;
if
(
error
==
TSIGError
::
BAD_TIME
())
{
impl_
->
previous_timesigned_
=
tsig_rdata
.
getTimeSigned
();
// This case happens when we sent a signed request and have received an
// unsigned response. According to RFC2845 Section 4.6 this case should be
// considered a "format error" (although the specific error code
// wouldn't matter much for the caller).
if
(
record
==
NULL
)
{
return
(
impl_
->
postVerifyUpdate
(
TSIGError
::
FORMERR
(),
NULL
,
0
));
}
// For simplicity we assume non empty digests.
assert
(
tsig_rdata
.
getMACSize
()
!=
0
);
impl_
->
previous_digest_
.
assign
(
static_cast
<
const
uint8_t
*>
(
tsig_rdata
.
getMAC
()),
static_cast
<
const
uint8_t
*>
(
tsig_rdata
.
getMAC
())
+
tsig_rdata
.
getMACSize
());
const
any
::
TSIG
&
tsig_rdata
=
record
->
getRdata
();
impl_
->
state_
=
CHECKED
;
// Reject some obviously invalid data
if
(
data_len
<
MESSAGE_HEADER_LEN
+
record
->
getLength
())
{
isc_throw
(
InvalidParameter
,
"TSIG verify: data length is invalid: "
<<
data_len
);
}
if
(
data
==
NULL
)
{
isc_throw
(
InvalidParameter
,
"TSIG verify: empty data is invalid"
);
}
// Check key: whether we first verify it with a known key or we verify
// it using the consistent key in the context. If the check fails we are
// done with BADKEY.
if
(
impl_
->
state_
==
INIT
&&
impl_
->
error_
==
TSIGError
::
BAD_KEY
())
{
return
(
impl_
->
postVerifyUpdate
(
TSIGError
::
BAD_KEY
(),
NULL
,
0
));
}
if
(
impl_
->
key_
.
getKeyName
()
!=
record
->
getName
()
||
impl_
->
key_
.
getAlgorithmName
()
!=
tsig_rdata
.
getAlgorithm
())
{
return
(
impl_
->
postVerifyUpdate
(
TSIGError
::
BAD_KEY
(),
NULL
,
0
));
}
// Check time: the current time must be in the range of
// [time signed - fudge, time signed + fudge]. Otherwise verification
// fails with BADTIME. (RFC2845 Section 4.6.2)
const
uint64_t
now
=
getTSIGTime
();
if
(
tsig_rdata
.
getTimeSigned
()
+
DEFAULT_FUDGE
<
now
||
tsig_rdata
.
getTimeSigned
()
-
DEFAULT_FUDGE
>
now
)
{
const
void
*
digest
=
NULL
;
size_t
digest_len
=
0
;
if
(
impl_
->
state_
==
INIT
)
{
digest
=
tsig_rdata
.
getMAC
();
digest_len
=
tsig_rdata
.
getMACSize
();