Skip to content

Commit

Permalink
Refactor to use external contracts for digest and algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
Arachnid committed Oct 16, 2017
1 parent 70f55fc commit f8bc52f
Show file tree
Hide file tree
Showing 13 changed files with 140 additions and 49 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
build/
5 changes: 5 additions & 0 deletions contracts/algorithm.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pragma solidity ^0.4.17;

contract Algorithm {
function verify(bytes key, bytes data, bytes signature) public view returns(bool);
}
2 changes: 1 addition & 1 deletion contracts/bytesutils.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pragma solidity ^0.4.13;
pragma solidity ^0.4.17;

library BytesUtils {
struct slice {
Expand Down
5 changes: 5 additions & 0 deletions contracts/digest.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pragma solidity ^0.4.17;

contract Digest {
function verify(bytes data, bytes hash) public view returns (bool);
}
71 changes: 27 additions & 44 deletions contracts/dnssec.sol
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
pragma solidity ^0.4.13;
pragma solidity ^0.4.17;

import "./rsaverify.sol";
import "./owned.sol";
import "./bytesutils.sol";
import "./rrutils.sol";
import "./algorithm.sol";
import "./digest.sol";

/*
* TODO: Support for wildcards
* TODO: Support for NSEC records
* NOTE: Doesn't enforce expiration for records, to allow 'playing forward'
* TODO: Enforce expiration for non-DNSKEY records
*/
contract DNSSEC {
contract DNSSEC is Owned {
using BytesUtils for *;
using RRUtils for *;

Expand Down Expand Up @@ -55,6 +57,11 @@ contract DNSSEC {
// (name, type, class) => RRSet
mapping(bytes32=>mapping(uint16=>mapping(uint16=>RRSet))) rrsets;

mapping(uint8=>Algorithm) public algorithms;
mapping(uint8=>Digest) public digests;

event AlgorithmUpdated(uint8 id, address addr);
event DigestUpdated(uint8 id, address addr);
event RRSetUpdated(bytes name);

function DNSSEC() public {
Expand All @@ -71,6 +78,16 @@ contract DNSSEC {
);
}

function setAlgorithm(uint8 id, Algorithm algo) public owner_only {
algorithms[id] = algo;
AlgorithmUpdated(id, algo);
}

function setDigest(uint8 id, Digest digest) public owner_only {
digests[id] = digest;
DigestUpdated(id, digest);
}

function rrset(uint16 class, uint16 dnstype, bytes name) public constant returns(uint32 inception, uint32 expiration, uint64 inserted, bytes rrs) {
var result = rrsets[keccak256(name)][dnstype][class];
return (result.inception, result.expiration, result.inserted, result.rrs);
Expand Down Expand Up @@ -170,6 +187,7 @@ contract DNSSEC {
}

function verifySignatureWithKey(BytesUtils.slice memory keyrdata, uint8 algorithm, uint16 keytag, bytes data, bytes sig) internal view returns(bool) {
require(algorithms[algorithm] != address(0));
// TODO: Check key isn't expired, unless updating key itself

// o The RRSIG RR's Signer's Name, Algorithm, and Key Tag fields MUST
Expand All @@ -184,10 +202,7 @@ contract DNSSEC {
// set.
if(keyrdata.uint16At(DNSKEY_FLAGS) & DNSKEY_FLAG_ZONEKEY == 0) return false;

if(algorithm == ALGORITHM_RSASHA256) {
if(verifyRSASHA256(keyrdata, data, sig)) return true;
}
return false;
return algorithms[algorithm].verify(keyrdata.toBytes(), data, sig);
}

function computeKeytag(BytesUtils.slice memory data) internal pure returns(uint16) {
Expand All @@ -199,37 +214,6 @@ contract DNSSEC {
return uint16(ac & 0xFFFF);
}

function verifyRSASHA256(BytesUtils.slice memory dnskey, bytes data, bytes sig) internal view returns (bool) {
bytes memory exponent;
bytes memory modulus;

var exponentLen = uint16(dnskey.uint8At(4));
if(exponentLen != 0) {
exponent = dnskey.toBytes(5, exponentLen + 5);
modulus = dnskey.toBytes(exponentLen + 5, dnskey.len);
} else {
exponentLen = dnskey.uint16At(5);
exponent = dnskey.toBytes(7, exponentLen + 7);
modulus = dnskey.toBytes(exponentLen + 7, dnskey.len);
}

bytes memory sigdata = new bytes(modulus.length);
BytesUtils.slice memory sigdataslice;
sigdataslice.fromBytes(sigdata);
// Write 0x0001
sigdataslice.writeBytes32(0, 0x0001 << 240);
// Repeat 0xFF as many times as needed (2 byte 0x0001 + 20 byte prefix + 32 byte hash = 54)
var padsize = modulus.length - 54;
sigdataslice.fill(2, padsize, 0xff);
// Write the prefix
sigdataslice.writeBytes32(padsize + 2, 0x00003031300d060960864801650304020105000420 << 96);
// Write the hash
sigdataslice.writeBytes32(padsize + 22, sha256(data));

// Verify the signature
return RSAVerify.rsaverify(sigdata, modulus, exponent, sig);
}

function verifyKeyWithDS(uint16 class, BytesUtils.slice memory keyname, BytesUtils.slice memory keyrdata, uint16 keytag, uint8 algorithm) internal constant returns (bool) {
var dss = rrsets[keyname.keccak()][DNSTYPE_DS][class];

Expand All @@ -243,20 +227,19 @@ contract DNSSEC {
if(dsrdata.uint8At(DS_ALGORITHM) != algorithm) continue;

var digesttype = dsrdata.uint8At(DS_DIGEST_TYPE);
if(digesttype == DIGEST_ALGORITHM_SHA256) {
if(verifySHA256(keyname, keyrdata, dsrdata)) return true;
}
if(verifyDSHash(digesttype, keyname, keyrdata, dsrdata)) return true;
}
return false;
}

function verifySHA256(BytesUtils.slice memory keyname, BytesUtils.slice memory keyrdata, BytesUtils.slice memory digest) internal pure returns (bool) {
function verifyDSHash(uint8 digesttype, BytesUtils.slice memory keyname, BytesUtils.slice memory keyrdata, BytesUtils.slice memory digest) internal view returns (bool) {
require(digests[digesttype] != address(0));

bytes memory data = new bytes(keyname.len + keyrdata.len);
BytesUtils.slice memory dataslice;
dataslice.fromBytes(data);
dataslice.memcpy(0, keyname, 0, keyname.len);
dataslice.memcpy(keyname.len, keyrdata, 0, keyrdata.len);
var hash = sha256(data);
return hash == digest.bytes32At(4);
return digests[digesttype].verify(dataslice.toBytes(), digest.toBytes(4, 36));
}
}
2 changes: 1 addition & 1 deletion contracts/modexp.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pragma solidity ^0.4.13;
pragma solidity ^0.4.17;

library BytesTool {
function memcopy(bytes src, uint srcoffset, bytes dst, uint dstoffset, uint len) pure internal {
Expand Down
18 changes: 18 additions & 0 deletions contracts/owned.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
pragma solidity ^0.4.17;

contract Owned {
address public owner;

function Owned() {
owner = msg.sender;
}

modifier owner_only() {
require(msg.sender == owner);
_;
}

function setOwner(address newOwner) public owner_only {
owner = newOwner;
}
}
2 changes: 1 addition & 1 deletion contracts/rrutils.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pragma solidity ^0.4.13;
pragma solidity ^0.4.17;

import "./bytesutils.sol";

Expand Down
43 changes: 43 additions & 0 deletions contracts/rsasha256algorithm.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
pragma solidity ^0.4.17;

import "./algorithm.sol";
import "./bytesutils.sol";
import "./rsaverify.sol";

contract RSASHA256Algorithm is Algorithm {
using BytesUtils for *;

function verify(bytes key, bytes data, bytes sig) public view returns (bool) {
BytesUtils.slice memory dnskey;
dnskey.fromBytes(key);

bytes memory exponent;
bytes memory modulus;

var exponentLen = uint16(dnskey.uint8At(4));
if(exponentLen != 0) {
exponent = dnskey.toBytes(5, exponentLen + 5);
modulus = dnskey.toBytes(exponentLen + 5, dnskey.len);
} else {
exponentLen = dnskey.uint16At(5);
exponent = dnskey.toBytes(7, exponentLen + 7);
modulus = dnskey.toBytes(exponentLen + 7, dnskey.len);
}

bytes memory sigdata = new bytes(modulus.length);
BytesUtils.slice memory sigdataslice;
sigdataslice.fromBytes(sigdata);
// Write 0x0001
sigdataslice.writeBytes32(0, 0x0001 << 240);
// Repeat 0xFF as many times as needed (2 byte 0x0001 + 20 byte prefix + 32 byte hash = 54)
var padsize = modulus.length - 54;
sigdataslice.fill(2, padsize, 0xff);
// Write the prefix
sigdataslice.writeBytes32(padsize + 2, 0x00003031300d060960864801650304020105000420 << 96);
// Write the hash
sigdataslice.writeBytes32(padsize + 22, sha256(data));

// Verify the signature
return RSAVerify.rsaverify(sigdata, modulus, exponent, sig);
}
}
2 changes: 1 addition & 1 deletion contracts/rsaverify.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pragma solidity ^0.4.16;
pragma solidity ^0.4.17;

import "./modexp.sol";

Expand Down
14 changes: 14 additions & 0 deletions contracts/sha256digest.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
pragma solidity ^0.4.17;

import "./digest.sol";
import "./bytesutils.sol";

contract SHA256Digest is Digest {
using BytesUtils for *;

function verify(bytes data, bytes hash) public view returns (bool) {
BytesUtils.slice memory hashslice;
hashslice.fromBytes(hash);
return sha256(data) == hashslice.bytes32At(0);
}
}
18 changes: 17 additions & 1 deletion migrations/2_deploy_contracts.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
var rsasha256 = artifacts.require("./rsasha256algorithm.sol");
var sha256 = artifacts.require("./sha256digest.sol");
var dnssec = artifacts.require("./dnssec.sol");

module.exports = function(deployer) {
deployer.deploy(dnssec);
deployer.deploy(dnssec).then(function() {
return deployer.deploy(rsasha256);
}).then(function() {
return deployer.deploy(sha256);
}).then(function() {
return dnssec.deployed().then(function(instance) {
return rsasha256.deployed().then(function(algorithm) {
return instance.setAlgorithm(8, algorithm.address);
}).then(function() {
return sha256.deployed();
}).then(function(digest) {
return instance.setDigest(2, digest.address);
});
});
});
};
6 changes: 6 additions & 0 deletions test/enssec.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit f8bc52f

Please sign in to comment.