1 #define BOOST_TEST_DYN_LINK
2 #define BOOST_TEST_NO_MAIN
6 #include <boost/test/unit_test.hpp>
7 #include <boost/assign/list_of.hpp>
9 #include <boost/tuple/tuple.hpp>
10 #include <boost/scoped_ptr.hpp>
13 #include "dnsseckeeper.hh"
14 #include "dnssecinfra.hh"
16 BOOST_AUTO_TEST_SUITE(test_signers
)
18 static const std::string message
= "Very good, young padawan.";
20 static const struct signerParams
26 std::vector
<uint8_t> signature
;
27 std::string zoneRepresentation
;
29 std::string rfcMsgDump
;
30 std::string rfcB64Signature
;
37 /* RSA from https://github.com/CZ-NIC/knot/blob/master/src/dnssec/tests/sample_keys.h */
39 "Modulus: qtunSiHnYq4XRLBehKAw1Glxb+48oIpAC7w3Jhpj570bb2uHt6orWGqnuyRtK8oqUi2ABoV0PFm8+IPgDMEdCQ==\n"
40 "PublicExponent: AQAB\n"
41 "PrivateExponent: MiItniUAngXzMeaGdWgDq/AcpvlCtOCcFlVt4TJRKkfp8DNRSxIxG53NNlOFkp1W00iLHqYC2GrH1qkKgT9l+Q==\n"
42 "Prime1: 3sZmM+5FKFy5xaRt0n2ZQOZ2C+CoKzVil6/al9LmYVs=\n"
43 "Prime2: xFcNWSIW6v8dDL2JQ1kxFDm/8RVeUSs1BNXXnvCjBGs=\n"
44 "Exponent1: WuUwhjfN1+4djlrMxHmisixWNfpwI1Eg7Ss/UXsnrMk=\n"
45 "Exponent2: vfMqas1cNsXRqP3Fym6D2Pl2BRuTQBv5E1B/ZrmQPTk=\n"
46 "Coefficient: Q10z43cA3hkwOkKsj5T0W5jrX97LBwZoY5lIjDCa4+M=\n",
47 "1506 8 1 172a500b374158d1a64ba3073cdbbc319b2fdf2c",
48 "1506 8 2 253b099ff47b02c6ffa52695a30a94c6681c56befe0e71a5077d6f79514972f9",
49 "1506 8 4 22ea940600dc2d9a98b1126c26ac0dc5c91b31eb50fe784b36ad675e9eecfe6573c1f85c53b6bc94580f3ac443d13c4c",
50 /* from https://github.com/CZ-NIC/knot/blob/master/src/dnssec/tests/sign.c */
51 { 0x93, 0x93, 0x5f, 0xd8, 0xa1, 0x2b, 0x4c, 0x0b, 0xf3, 0x67, 0x42, 0x13, 0x52, 0x00, 0x35, 0xdc, 0x09, 0xe0, 0xdf, 0xe0, 0x3e, 0xc2, 0xcf, 0x64, 0xab, 0x9f, 0x9f, 0x51, 0x5f, 0x5c, 0x27, 0xbe, 0x13, 0xd6, 0x17, 0x07, 0xa6, 0xe4, 0x3b, 0x63, 0x44, 0x85, 0x06, 0x13, 0xaa, 0x01, 0x3c, 0x58, 0x52, 0xa3, 0x98, 0x20, 0x65, 0x03, 0xd0, 0x40, 0xc8, 0xa0, 0xe9, 0xd2, 0xc0, 0x03, 0x5a, 0xab },
52 "256 3 8 AwEAAarbp0oh52KuF0SwXoSgMNRpcW/uPKCKQAu8NyYaY+e9G29rh7eqK1hqp7skbSvKKlItgAaFdDxZvPiD4AzBHQk=",
59 DNSSECKeeper::RSASHA256
,
62 #ifdef HAVE_LIBCRYPTO_ECDSA
63 /* ECDSA-P256-SHA256 from https://github.com/CZ-NIC/knot/blob/master/src/dnssec/tests/sample_keys.h */
65 "PrivateKey: iyLIPdk3DOIxVmmSYlmTstbtUPiVlEyDX46psyCwNVQ=\n",
66 "5345 13 1 954103ac7c43810ce9f414e80f30ab1cbe49b236",
67 "5345 13 2 bac2107036e735b50f85006ce409a19a3438cab272e70769ebda032239a3d0ca",
68 "5345 13 4 a0ac6790483872be72a258314200a88ab75cdd70f66a18a09f0f414c074df0989fdb1df0e67d82d4312cda67b93a76c1",
69 /* from https://github.com/CZ-NIC/knot/blob/master/src/dnssec/tests/sign.c */
70 { 0xa2, 0x95, 0x76, 0xb5, 0xf5, 0x7e, 0xbd, 0xdd, 0xf5, 0x62, 0xa2, 0xc3, 0xa4, 0x8d, 0xd4, 0x53, 0x5c, 0xba, 0x29, 0x71, 0x8c, 0xcc, 0x28, 0x7b, 0x58, 0xf3, 0x1e, 0x4e, 0x58, 0xe2, 0x36, 0x7e, 0xa0, 0x1a, 0xb6, 0xe6, 0x29, 0x71, 0x1b, 0xd3, 0x8c, 0x88, 0xc3, 0xee, 0x12, 0x0e, 0x69, 0x70, 0x55, 0x99, 0xec, 0xd5, 0xf6, 0x4f, 0x4b, 0xe2, 0x41, 0xd9, 0x10, 0x7e, 0x67, 0xe5, 0xad, 0x2f, },
71 "256 3 13 8uD7C4THTM/w7uhryRSToeE/jKT78/p853RX0L5EwrZrSLBubLPiBw7gbvUP6SsIga5ZQ4CSAxNmYA/gZsuXzA==",
78 DNSSECKeeper::ECDSA256
,
81 #endif /* HAVE_LIBCRYPTO_ECDSA */
82 #if defined(HAVE_LIBSODIUM) || defined(HAVE_LIBDECAF) || defined(HAVE_LIBCRYPTO_ED25519)
83 /* ed25519 from https://github.com/CZ-NIC/knot/blob/master/src/dnssec/tests/sample_keys.h,
84 also from rfc8080 section 6.1 */
86 "PrivateKey: ODIyNjAzODQ2MjgwODAxMjI2NDUxOTAyMDQxNDIyNjI=\n",
87 "3612 15 1 501249721e1f09a79d30d5c6c4dca1dc1da4ed5d",
88 "3612 15 2 1b1c8766b2a96566ff196f77c0c4194af86aaa109c5346ff60231a27d2b07ac0",
89 "3612 15 4 d11831153af4985efbd0ae792c967eb4aff3c35488db95f7e2f85dcec74ae8f59f9a72641798c91c67c675db1d710c18",
90 /* from https://github.com/CZ-NIC/knot/blob/master/src/dnssec/tests/sign.c */
91 { 0x0a, 0x9e, 0x51, 0x5f, 0x16, 0x89, 0x49, 0x27, 0x0e, 0x98, 0x34, 0xd3, 0x48, 0xef, 0x5a, 0x6e, 0x85, 0x2f, 0x7c, 0xd6, 0xd7, 0xc8, 0xd0, 0xf4, 0x2c, 0x68, 0x8c, 0x1f, 0xf7, 0xdf, 0xeb, 0x7c, 0x25, 0xd6, 0x1a, 0x76, 0x3e, 0xaf, 0x28, 0x1f, 0x1d, 0x08, 0x10, 0x20, 0x1c, 0x01, 0x77, 0x1b, 0x5a, 0x48, 0xd6, 0xe5, 0x1c, 0xf9, 0xe3, 0xe0, 0x70, 0x34, 0x5e, 0x02, 0x49, 0xfb, 0x9e, 0x05 },
92 "256 3 15 l02Woi0iS8Aa25FQkUd9RMzZHJpBoRQwAQEX1SxZJA4=",
94 // vector extracted from https://gitlab.labs.nic.cz/labs/ietf/blob/master/dnskey.py (rev 476d6ded) by printing signature_data
95 "00 0f 0f 02 00 00 0e 10 55 d4 fc 60 55 b9 4c e0 0e 1d 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 00 0f 00 01 00 00 0e 10 00 14 00 0a 04 6d 61 69 6c 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 ",
96 // vector verified from dnskey.py as above, and confirmed with https://www.rfc-editor.org/errata_search.php?rfc=8080&eid=4935
97 "oL9krJun7xfBOIWcGHi7mag5/hdZrKWw15jPGrHpjQeRAvTdszaPD+QLs3fx8A4M3e23mRZ9VrbpMngwcrqNAg==",
101 DNSSECKeeper::ED25519
,
104 #endif /* defined(HAVE_LIBSODIUM) || defined(HAVE_LIBDECAF) || defined(HAVE_LIBCRYPTO_ED25519) */
107 static void checkRR(const signerParams
& signer
)
109 DNSKEYRecordContent drc
;
110 auto dcke
= DNSCryptoKeyEngine::makeFromISCString(drc
, signer
.iscMap
);
111 DNSSECPrivateKey dpk
;
113 dpk
.d_flags
= signer
.rfcFlags
;
115 vector
<std::shared_ptr
<DNSRecordContent
> > rrs
;
116 /* values taken from rfc8080 for ed25519 and ed448, rfc5933 for gost */
117 DNSName
qname(dpk
.d_algorithm
== 12 ? "www.example.net." : "example.com.");
121 RRSIGRecordContent rrc
;
122 uint32_t expire
= 1440021600;
123 uint32_t inception
= 1438207200;
125 if (dpk
.d_algorithm
== 12) {
126 rrc
.d_signer
= DNSName("example.net.");
127 inception
= 946684800;
129 rrs
.push_back(DNSRecordContent::mastermake(QType::A
, QClass::IN
, "192.0.2.1"));
132 rrc
.d_signer
= qname
;
133 rrs
.push_back(DNSRecordContent::mastermake(QType::MX
, QClass::IN
, "10 mail.example.com."));
136 rrc
.d_originalttl
= 3600;
137 rrc
.d_sigexpire
= expire
;
138 rrc
.d_siginception
= inception
;
139 rrc
.d_type
= rrs
.at(0)->getType();
140 rrc
.d_labels
= qname
.countLabels();
141 rrc
.d_tag
= dpk
.getTag();
142 rrc
.d_algorithm
= dpk
.d_algorithm
;
144 string msg
= getMessageForRRSET(qname
, rrc
, rrs
, false);
146 BOOST_CHECK_EQUAL(makeHexDump(msg
), signer
.rfcMsgDump
);
148 string signature
= dcke
->sign(msg
);
150 BOOST_CHECK(dcke
->verify(msg
, signature
));
152 if (signer
.isDeterministic
) {
153 string b64
= Base64Encode(signature
);
154 BOOST_CHECK_EQUAL(b64
, signer
.rfcB64Signature
);
158 B64Decode(signer
.rfcB64Signature
, raw
);
159 BOOST_CHECK(dcke
->verify(msg
, raw
));
163 BOOST_AUTO_TEST_CASE(test_generic_signers
)
165 for (const auto signer
: signers
) {
166 DNSKEYRecordContent drc
;
167 auto dcke
= DNSCryptoKeyEngine::makeFromISCString(drc
, signer
.iscMap
);
169 BOOST_CHECK_EQUAL(dcke
->getAlgorithm(), signer
.algorithm
);
170 BOOST_CHECK_EQUAL(dcke
->getBits(), signer
.bits
);
171 BOOST_CHECK_EQUAL(dcke
->checkKey(nullptr), true);
173 BOOST_CHECK_EQUAL(drc
.d_algorithm
, signer
.algorithm
);
175 DNSSECPrivateKey dpk
;
177 dpk
.d_flags
= signer
.flags
;
178 drc
= dpk
.getDNSKEY();
180 BOOST_CHECK_EQUAL(drc
.d_algorithm
, signer
.algorithm
);
181 BOOST_CHECK_EQUAL(drc
.d_protocol
, 3);
182 BOOST_CHECK_EQUAL(drc
.getZoneRepresentation(), signer
.zoneRepresentation
);
184 DNSName
name(signer
.name
);
185 auto ds1
= makeDSFromDNSKey(name
, drc
, DNSSECKeeper::SHA1
);
186 if (!signer
.dsSHA1
.empty()) {
187 BOOST_CHECK_EQUAL(ds1
.getZoneRepresentation(), signer
.dsSHA1
);
190 auto ds2
= makeDSFromDNSKey(name
, drc
, DNSSECKeeper::SHA256
);
191 if (!signer
.dsSHA256
.empty()) {
192 BOOST_CHECK_EQUAL(ds2
.getZoneRepresentation(), signer
.dsSHA256
);
195 auto ds4
= makeDSFromDNSKey(name
, drc
, DNSSECKeeper::SHA384
);
196 if (!signer
.dsSHA384
.empty()) {
197 BOOST_CHECK_EQUAL(ds4
.getZoneRepresentation(), signer
.dsSHA384
);
200 auto signature
= dcke
->sign(message
);
201 BOOST_CHECK(dcke
->verify(message
, signature
));
203 if (signer
.isDeterministic
) {
204 BOOST_CHECK_EQUAL(signature
, std::string(signer
.signature
.begin(), signer
.signature
.end()));
206 /* since the signing process is not deterministic, we can't directly compare our signature
207 with the one we have. Still the one we have should also validate correctly. */
208 BOOST_CHECK(dcke
->verify(message
, std::string(signer
.signature
.begin(), signer
.signature
.end())));
211 if (!signer
.rfcMsgDump
.empty() && !signer
.rfcB64Signature
.empty()) {
217 #if defined(HAVE_LIBDECAF) || defined(HAVE_LIBCRYPTO_ED448)
218 BOOST_AUTO_TEST_CASE(test_ed448_signer
) {
219 vector
<std::shared_ptr
<DNSRecordContent
> > rrs
;
220 DNSName
qname("example.com.");
221 DNSKEYRecordContent drc
;
223 // TODO: make this a collection of inputs and resulting sigs for various algos
224 shared_ptr
<DNSCryptoKeyEngine
> engine
= DNSCryptoKeyEngine::makeFromISCString(drc
,
225 "Private-key-format: v1.2\n"
226 "Algorithm: 16 (ED448)\n"
227 "PrivateKey: xZ+5Cgm463xugtkY5B0Jx6erFTXp13rYegst0qRtNsOYnaVpMx0Z/c5EiA9x8wWbDDct/U3FhYWA\n");
229 DNSSECPrivateKey dpk
;
234 rrs
.push_back(DNSRecordContent::mastermake(QType::MX
, 1, "10 mail.example.com."));
236 RRSIGRecordContent rrc
;
237 rrc
.d_originalttl
= 3600;
238 rrc
.d_sigexpire
= 1440021600;
239 rrc
.d_siginception
= 1438207200;
240 rrc
.d_signer
= qname
;
241 rrc
.d_type
= QType::MX
;
243 // TODO: derive the next two from the key
245 rrc
.d_algorithm
= 16;
247 string msg
= getMessageForRRSET(qname
, rrc
, rrs
, false);
249 // vector extracted from https://gitlab.labs.nic.cz/labs/ietf/blob/master/dnskey.py (rev 476d6ded) by printing signature_data
250 BOOST_CHECK_EQUAL(makeHexDump(msg
), "00 0f 10 02 00 00 0e 10 55 d4 fc 60 55 b9 4c e0 25 f1 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 00 0f 00 01 00 00 0e 10 00 14 00 0a 04 6d 61 69 6c 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 ");
252 string signature
= engine
->sign(msg
);
253 string b64
= Base64Encode(signature
);
255 // vector verified from dnskey.py as above, and confirmed with https://www.rfc-editor.org/errata_search.php?rfc=8080&eid=4935
256 BOOST_CHECK_EQUAL(b64
, "3cPAHkmlnxcDHMyg7vFC34l0blBhuG1qpwLmjInI8w1CMB29FkEAIJUA0amxWndkmnBZ6SKiwZSAxGILn/NBtOXft0+Gj7FSvOKxE/07+4RQvE581N3Aj/JtIyaiYVdnYtyMWbSNyGEY2213WKsJlwEA");
258 #endif /* defined(HAVE_LIBDECAF) || defined(HAVE_LIBCRYPTO_ED448) */
260 BOOST_AUTO_TEST_SUITE_END()