Skip to content

Commit

Permalink
zone: add zsk property and enable ad-hoc signing
Browse files Browse the repository at this point in the history
  • Loading branch information
pinheadmz committed Jul 8, 2020
1 parent 301fa7b commit cbc448c
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 7 deletions.
5 changes: 5 additions & 0 deletions lib/server/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ class AuthServer extends DNSServer {
this.initOptions(options);
}

setZSKFromString(str) {
this.zone.setZSKFromString(str);
return this;
}

setOrigin(name) {
this.zone.setOrigin(name);
return this;
Expand Down
31 changes: 28 additions & 3 deletions lib/zone.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ const fs = require('bfile');
const constants = require('./constants');
const util = require('./util');
const wire = require('./wire');
const dnssec = require('./dnssec');
const {keyFlags} = dnssec;
const {ZONE} = keyFlags;


const {
types,
Expand Down Expand Up @@ -46,8 +50,10 @@ class Zone {
this.origin = '.';
this.count = 0;
this.names = new Map();
this.wild = new RecordMap();
this.wild = new RecordMap(this);
this.nsec = new NameList();
this.zskpriv = null;
this.zskkey = null;
this.setOrigin(origin);
}

Expand All @@ -65,6 +71,12 @@ class Zone {
return this;
}

setZSKFromString(str) {
const [alg, zskpriv] = dnssec.decodePrivate(str);
this.zskpriv = zskpriv;
this.zskkey = dnssec.makeKey(this.origin, alg, zskpriv, ZONE);
}

setOrigin(origin) {
if (origin == null)
origin = '.';
Expand Down Expand Up @@ -95,7 +107,7 @@ class Zone {
this.wild.insert(rr);
} else {
if (!this.names.has(rr.name))
this.names.set(rr.name, new RecordMap());
this.names.set(rr.name, new RecordMap(this));

const map = this.names.get(rr.name);

Expand Down Expand Up @@ -356,11 +368,12 @@ class Zone {
*/

class RecordMap {
constructor() {
constructor(zone) {
// type -> rrs
this.rrs = new Map();
// type covered -> sigs
this.sigs = new Map();
this.zone = zone;
}

clear() {
Expand Down Expand Up @@ -454,6 +467,12 @@ class RecordMap {
an.push(convert(name, rr));
}

if (!sigs && this.zone.zskkey && this.zone.zskpriv) {
// Create dnssec sig on the fly (especially useful for wildcard)
const sig = dnssec.sign(this.zone.zskkey, this.zone.zskpriv, an);
an.push(sig);
}

return this;
}
}
Expand All @@ -472,6 +491,12 @@ class RecordMap {
for (const rr of sigs)
an.push(convert(name, rr));
}

if (!sigs && this.zone.zskkey && this.zone.zskpriv) {
// Create dnssec sig on the fly (especially useful for wildcard)
const sig = dnssec.sign(this.zone.zskkey, this.zone.zskpriv, an);
an.push(sig);
}
}

return this;
Expand Down
107 changes: 103 additions & 4 deletions test/zone-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ const fs = require('bfile');
const wire = require('../lib/wire');
const Zone = require('../lib/zone');
const {types, codes} = wire;
const dnssec = require('../lib/dnssec');
const {RSASHA256} = dnssec.algs;
const {ZONE, KSK} = dnssec.keyFlags;

const ROOT_ZONE = Path.resolve(__dirname, 'data', 'root.zone');
const COM_RESPONSE = Path.resolve(__dirname, 'data', 'com-response.zone');
Expand Down Expand Up @@ -153,7 +156,7 @@ describe('Zone', function() {

if (an.type === types.A) {
a = true;
assert (an.data.address = '10.20.30.40');
assert (an.data.address === '10.20.30.40');
}
}
assert(cname);
Expand All @@ -173,8 +176,8 @@ describe('Zone', function() {
assert(msg.authority.length === 0);
assert(msg.additional.length === 0);
assert(msg.answer.length === 1);
assert(msg.answer[0].type = types.CNAME);
assert(msg.answer[0].data.target = 'idontexist.');
assert(msg.answer[0].type === types.CNAME);
assert(msg.answer[0].data.target === 'idontexist.');
});
}
});
Expand Down Expand Up @@ -222,7 +225,7 @@ describe('Zone', function() {

if (an.type === types.A) {
a = true;
assert (an.data.address = '10.20.30.40');
assert (an.data.address === '10.20.30.40');
}
}
assert(cname);
Expand All @@ -231,4 +234,100 @@ describe('Zone', function() {
});
}
});

describe('DNSSEC for wildcard', function() {
const zone = new Zone();
const domain = 'thebnszone.';
const subdomain = 'subdomain.' + domain;

// TLD
zone.setOrigin(domain);
// Reset zone.
zone.clearRecords();
// A record for TLD (Common in Handshake, not in DNS)
zone.fromString(`${domain} 21600 IN A 10.20.30.40`);
// wildcard for subdomains
zone.fromString(`*.${domain} 21600 IN A 50.60.70.80`);
// SOA
zone.fromString(
`${domain} 21600 IN SOA ns1.${domain} admin.${domain} ` +
'2020070500 86400 7200 604800 300'
);

zone.zskpriv = dnssec.createPrivate(RSASHA256, 2048);
zone.zskkey = dnssec.makeKey(domain, RSASHA256, zone.zskpriv, ZONE);

let wrongsig = null;

it('should serve signed A record from defined name', () => {
const msg = zone.resolve(domain, types.A);
assert(msg.code === codes.NOERROR);
assert(msg.aa);
assert(msg.authority.length === 0);
assert(msg.additional.length === 0);
assert(msg.answer.length === 2);
let rrsig = null;
let a = null;
for (const an of msg.answer) {
if (an.type === types.RRSIG)
rrsig = an;

if (an.type === types.A) {
a = an;
assert (an.data.address === '10.20.30.40');
}
}
assert(rrsig);
assert(a);
assert(dnssec.verify(rrsig, zone.zskkey, [a]));
wrongsig = rrsig;
});

it('should serve signed A record from wildcard', () => {
const msg = zone.resolve(subdomain, types.A);
assert(msg.code === codes.NOERROR);
assert(msg.aa);
assert(msg.authority.length === 0);
assert(msg.additional.length === 0);
assert(msg.answer.length === 2);
let rrsig = null;
let a = null;
for (const an of msg.answer) {
if (an.type === types.RRSIG)
rrsig = an;

if (an.type === types.A) {
a = an;
assert (an.data.address === '50.60.70.80');
}
}
assert(rrsig);
assert(a);
assert(dnssec.verify(rrsig, zone.zskkey, [a]));
});

it('should not verify with the wrong signature', () => {
const msg = zone.resolve(subdomain, types.A);
assert(msg.code === codes.NOERROR);
assert(msg.aa);
assert(msg.authority.length === 0);
assert(msg.additional.length === 0);
assert(msg.answer.length === 2);
let rrsig = null;
let a = null;
for (const an of msg.answer) {
if (an.type === types.RRSIG)
rrsig = an;

if (an.type === types.A) {
a = an;
assert (an.data.address === '50.60.70.80');
}
}
assert(rrsig);
assert(a);
// sanity check
assert(!dnssec.verify(wrongsig, zone.zskkey, [a]));
});
});
});

0 comments on commit cbc448c

Please sign in to comment.