]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/test-signers.cc
auth 4.1 build: Switch to devtoolset 7 for el6
[thirdparty/pdns.git] / pdns / test-signers.cc
CommitLineData
22de9dc8
PD
1#define BOOST_TEST_DYN_LINK
2#define BOOST_TEST_NO_MAIN
3#ifdef HAVE_CONFIG_H
4#include "config.h"
5#endif
6#include <boost/test/unit_test.hpp>
7#include <boost/assign/list_of.hpp>
8
9#include <boost/tuple/tuple.hpp>
10#include <boost/scoped_ptr.hpp>
11
12#include "base64.hh"
13#include "dnsseckeeper.hh"
14#include "dnssecinfra.hh"
15#include "misc.hh"
22de9dc8
PD
16BOOST_AUTO_TEST_SUITE(test_signers)
17
620d4801
RG
18static const std::string message = "Very good, young padawan.";
19
20static const struct signerParams
21{
22 std::string iscMap;
23 std::string dsSHA1;
24 std::string dsSHA256;
25 std::string dsSHA384;
26 std::vector<uint8_t> signature;
27 std::string zoneRepresentation;
28 std::string name;
29 std::string rfcMsgDump;
30 std::string rfcB64Signature;
31 unsigned int bits;
32 uint16_t flags;
33 uint16_t rfcFlags;
34 uint8_t algorithm;
35 bool isDeterministic;
36} signers[] = {
37 /* RSA from https://github.com/CZ-NIC/knot/blob/master/src/dnssec/tests/sample_keys.h */
38 { "Algorithm: 8\n"
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=",
53 "rsa.",
54 "",
55 "",
56 512,
57 256,
58 0,
59 DNSSECKeeper::RSASHA256,
60 true
61 },
13f34f2e 62#ifdef HAVE_BOTAN
620d4801
RG
63 /* ECC-GOST from rfc5933 */
64 { "Algorithm: 12\n"
65 "GostAsn1: MEUCAQAwHAYGKoUDAgITMBIGByqFAwICIwEGByqFAwICHgEEIgQg/9MiXtXKg9FDXDN/R9CmVhJDyuzRAIgh4tPwCu4NHIs=\n",
66 "59732 12 1 794287b8033625ae938c0341fd800fd5ce45a728",
67 "59732 12 2 a7c24528480884ef4f5c0aaf85b3a20323a96722ccda26045aa7d304c9942868",
68 "59732 12 4 6f43cc67087875a5f2115adbc29604f0b5a43be6f28be0deaf71e08168967f7a1a8218d063a6f9137133a721e60eed4f",
69 { 0x1f, 0x3f, 0x2a, 0x2d, 0xc6, 0x72, 0x1d, 0xc8, 0xc4, 0x1f, 0x8b, 0xa1, 0xe8, 0x07, 0x83, 0x25, 0x9a, 0xbd, 0xc3, 0x80, 0xc1, 0x67, 0x80, 0xb7, 0x07, 0xed, 0xcb, 0xb0, 0x45, 0x5e, 0x46, 0x00, 0xcb, 0xa2, 0x7c, 0xf4, 0x7a, 0xa1, 0x81, 0x0c, 0xb2, 0xd1, 0xa1, 0xba, 0xb4, 0x53, 0xed, 0x8c, 0x10, 0x79, 0x12, 0x84, 0x9f, 0x9a, 0x69, 0xf5, 0x6d, 0x00, 0x4f, 0x06, 0x30, 0xba, 0xaa, 0xe6 },
70 "256 3 12 aRS/DcPWGQj2wVJydT8EcAVoC0kXn5pDVm2IMvDDPXeD32dsSKcmq8KNVzigjL4OXZTV+t/6w4X1gpNrZiC01g==",
71 "gost.",
72 "00 01 0c 03 00 00 0e 10 70 db d8 80 38 6d 43 80 e9 54 07 65 78 61 6d 70 6c 65 03 6e 65 74 00 03 77 77 77 07 65 78 61 6d 70 6c 65 03 6e 65 74 00 00 01 00 01 00 00 0e 10 00 04 c0 00 02 01 ",
73 /* from rfc5933 */
74 "7vzzz6iLOmvtjs5FjVjSHT8XnRKFY15ki6KpkNPkUnS8iIns0Kv4APT+D9ibmHhGri6Sfbyyzi67+wBbbW/jrA==",
75 256,
76 256,
77 256,
78 DNSSECKeeper::ECCGOST,
79 false
80 },
13f34f2e 81#endif /* HAVE_BOTAN */
620d4801
RG
82#ifdef HAVE_LIBCRYPTO_ECDSA
83 /* ECDSA-P256-SHA256 from https://github.com/CZ-NIC/knot/blob/master/src/dnssec/tests/sample_keys.h */
84 { "Algorithm: 13\n"
85 "PrivateKey: iyLIPdk3DOIxVmmSYlmTstbtUPiVlEyDX46psyCwNVQ=\n",
86 "5345 13 1 954103ac7c43810ce9f414e80f30ab1cbe49b236",
87 "5345 13 2 bac2107036e735b50f85006ce409a19a3438cab272e70769ebda032239a3d0ca",
88 "5345 13 4 a0ac6790483872be72a258314200a88ab75cdd70f66a18a09f0f414c074df0989fdb1df0e67d82d4312cda67b93a76c1",
89 /* from https://github.com/CZ-NIC/knot/blob/master/src/dnssec/tests/sign.c */
90 { 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, },
91 "256 3 13 8uD7C4THTM/w7uhryRSToeE/jKT78/p853RX0L5EwrZrSLBubLPiBw7gbvUP6SsIga5ZQ4CSAxNmYA/gZsuXzA==",
92 "ecdsa.",
93 "",
94 "",
95 256,
96 256,
97 0,
98 DNSSECKeeper::ECDSA256,
99 false
100 },
101#endif /* HAVE_LIBCRYPTO_ECDSA */
2b7da695 102#if defined(HAVE_LIBSODIUM) || defined(HAVE_LIBDECAF)
620d4801
RG
103 /* ed25519 from https://github.com/CZ-NIC/knot/blob/master/src/dnssec/tests/sample_keys.h,
104 also from rfc8080 section 6.1 */
105 { "Algorithm: 15\n"
106 "PrivateKey: ODIyNjAzODQ2MjgwODAxMjI2NDUxOTAyMDQxNDIyNjI=\n",
107 "3612 15 1 501249721e1f09a79d30d5c6c4dca1dc1da4ed5d",
108 "3612 15 2 1b1c8766b2a96566ff196f77c0c4194af86aaa109c5346ff60231a27d2b07ac0",
109 "3612 15 4 d11831153af4985efbd0ae792c967eb4aff3c35488db95f7e2f85dcec74ae8f59f9a72641798c91c67c675db1d710c18",
110 /* from https://github.com/CZ-NIC/knot/blob/master/src/dnssec/tests/sign.c */
111 { 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 },
112 "256 3 15 l02Woi0iS8Aa25FQkUd9RMzZHJpBoRQwAQEX1SxZJA4=",
113 "ed25519.",
114 // vector extracted from https://gitlab.labs.nic.cz/labs/ietf/blob/master/dnskey.py (rev 476d6ded) by printing signature_data
115 "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 ",
116 // vector verified from dnskey.py as above, and confirmed with https://www.rfc-editor.org/errata_search.php?rfc=8080&eid=4935
117 "oL9krJun7xfBOIWcGHi7mag5/hdZrKWw15jPGrHpjQeRAvTdszaPD+QLs3fx8A4M3e23mRZ9VrbpMngwcrqNAg==",
118 256,
119 256,
120 257,
121 DNSSECKeeper::ED25519,
122 true
123 },
124#endif /* defined(HAVE_LIBSODIUM) || defined(HAVE_LIBDECAF) */
125};
22de9dc8 126
620d4801
RG
127static void checkRR(const signerParams& signer)
128{
129 DNSKEYRecordContent drc;
130 auto dcke = DNSCryptoKeyEngine::makeFromISCString(drc, signer.iscMap);
131 DNSSECPrivateKey dpk;
132 dpk.setKey(dcke);
133 dpk.d_flags = signer.rfcFlags;
22de9dc8 134
620d4801
RG
135 vector<std::shared_ptr<DNSRecordContent> > rrs;
136 /* values taken from rfc8080 for ed25519 and ed448, rfc5933 for gost */
137 DNSName qname(dpk.d_algorithm == 12 ? "www.example.net." : "example.com.");
22de9dc8 138
620d4801 139 reportBasicTypes();
22de9dc8 140
620d4801
RG
141 RRSIGRecordContent rrc;
142 uint32_t expire = 1440021600;
143 uint32_t inception = 1438207200;
22de9dc8 144
620d4801
RG
145 if (dpk.d_algorithm == 12) {
146 rrc.d_signer = DNSName("example.net.");
147 inception = 946684800;
148 expire = 1893456000;
149 rrs.push_back(DNSRecordContent::makeunique(QType::A, QClass::IN, "192.0.2.1"));
150 }
151 else {
22de9dc8 152 rrc.d_signer = qname;
620d4801
RG
153 rrs.push_back(DNSRecordContent::makeunique(QType::MX, QClass::IN, "10 mail.example.com."));
154 }
22de9dc8 155
620d4801
RG
156 rrc.d_originalttl = 3600;
157 rrc.d_sigexpire = expire;
158 rrc.d_siginception = inception;
159 rrc.d_type = rrs.at(0)->getType();
160 rrc.d_labels = qname.countLabels();
161 rrc.d_tag = dpk.getTag();
162 rrc.d_algorithm = dpk.d_algorithm;
22de9dc8 163
620d4801
RG
164 string msg = getMessageForRRSET(qname, rrc, rrs, false);
165
166 BOOST_CHECK_EQUAL(makeHexDump(msg), signer.rfcMsgDump);
167
168 string signature = dcke->sign(msg);
22de9dc8 169
620d4801
RG
170 BOOST_CHECK(dcke->verify(msg, signature));
171
172 if (signer.isDeterministic) {
22de9dc8 173 string b64 = Base64Encode(signature);
620d4801
RG
174 BOOST_CHECK_EQUAL(b64, signer.rfcB64Signature);
175 }
176 else {
177 std::string raw;
178 B64Decode(signer.rfcB64Signature, raw);
179 BOOST_CHECK(dcke->verify(msg, raw));
180 }
181}
22de9dc8 182
620d4801
RG
183BOOST_AUTO_TEST_CASE(test_generic_signers)
184{
185 for (const auto signer : signers) {
186 DNSKEYRecordContent drc;
187 auto dcke = DNSCryptoKeyEngine::makeFromISCString(drc, signer.iscMap);
188
189 BOOST_CHECK_EQUAL(dcke->getAlgorithm(), signer.algorithm);
190 BOOST_CHECK_EQUAL(dcke->getBits(), signer.bits);
191 BOOST_CHECK_EQUAL(dcke->checkKey(), true);
192
193 BOOST_CHECK_EQUAL(drc.d_algorithm, signer.algorithm);
194
195 DNSSECPrivateKey dpk;
196 dpk.setKey(dcke);
197 dpk.d_flags = signer.flags;
198 drc = dpk.getDNSKEY();
199
200 BOOST_CHECK_EQUAL(drc.d_algorithm, signer.algorithm);
201 BOOST_CHECK_EQUAL(drc.d_protocol, 3);
202 BOOST_CHECK_EQUAL(drc.getZoneRepresentation(), signer.zoneRepresentation);
203
204 DNSName name(signer.name);
205 auto ds1 = makeDSFromDNSKey(name, drc, DNSSECKeeper::SHA1);
206 if (!signer.dsSHA1.empty()) {
207 BOOST_CHECK_EQUAL(ds1.getZoneRepresentation(), signer.dsSHA1);
208 }
209
210 auto ds2 = makeDSFromDNSKey(name, drc, DNSSECKeeper::SHA256);
211 if (!signer.dsSHA256.empty()) {
212 BOOST_CHECK_EQUAL(ds2.getZoneRepresentation(), signer.dsSHA256);
213 }
214
215 auto ds4 = makeDSFromDNSKey(name, drc, DNSSECKeeper::SHA384);
216 if (!signer.dsSHA384.empty()) {
217 BOOST_CHECK_EQUAL(ds4.getZoneRepresentation(), signer.dsSHA384);
218 }
219
220 auto signature = dcke->sign(message);
221 BOOST_CHECK(dcke->verify(message, signature));
222
223 if (signer.isDeterministic) {
224 BOOST_CHECK_EQUAL(signature, std::string(signer.signature.begin(), signer.signature.end()));
225 } else {
226 /* since the signing process is not deterministic, we can't directly compare our signature
227 with the one we have. Still the one we have should also validate correctly. */
228 BOOST_CHECK(dcke->verify(message, std::string(signer.signature.begin(), signer.signature.end())));
229 }
230
231 if (!signer.rfcMsgDump.empty() && !signer.rfcB64Signature.empty()) {
232 checkRR(signer);
233 }
234 }
22de9dc8 235}
22de9dc8 236
2b7da695
KM
237#ifdef HAVE_LIBDECAF
238BOOST_AUTO_TEST_CASE(test_ed448_signer) {
239 vector<std::shared_ptr<DNSRecordContent> > rrs;
240 DNSName qname("example.com.");
241 DNSKEYRecordContent drc;
242
243 // TODO: make this a collection of inputs and resulting sigs for various algos
244 shared_ptr<DNSCryptoKeyEngine> engine = DNSCryptoKeyEngine::makeFromISCString(drc,
245"Private-key-format: v1.2\n"
246"Algorithm: 16 (ED448)\n"
247"PrivateKey: xZ+5Cgm463xugtkY5B0Jx6erFTXp13rYegst0qRtNsOYnaVpMx0Z/c5EiA9x8wWbDDct/U3FhYWA\n");
248
249 DNSSECPrivateKey dpk;
250 dpk.setKey(engine);
251
252 reportBasicTypes();
253
254 rrs.push_back(DNSRecordContent::makeunique(QType::MX, 1, "10 mail.example.com."));
255
256 RRSIGRecordContent rrc;
257 rrc.d_originalttl = 3600;
258 rrc.d_sigexpire = 1440021600;
259 rrc.d_siginception = 1438207200;
260 rrc.d_signer = qname;
261 rrc.d_type = QType::MX;
262 rrc.d_labels = 2;
263 // TODO: derive the next two from the key
264 rrc.d_tag = 9713;
265 rrc.d_algorithm = 16;
266
267 string msg = getMessageForRRSET(qname, rrc, rrs, false);
268
269 // vector extracted from https://gitlab.labs.nic.cz/labs/ietf/blob/master/dnskey.py (rev 476d6ded) by printing signature_data
270 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 ");
271
272 string signature = engine->sign(msg);
273 string b64 = Base64Encode(signature);
274
275 // vector verified from dnskey.py as above, and confirmed with https://www.rfc-editor.org/errata_search.php?rfc=8080&eid=4935
276 BOOST_CHECK_EQUAL(b64, "3cPAHkmlnxcDHMyg7vFC34l0blBhuG1qpwLmjInI8w1CMB29FkEAIJUA0amxWndkmnBZ6SKiwZSAxGILn/NBtOXft0+Gj7FSvOKxE/07+4RQvE581N3Aj/JtIyaiYVdnYtyMWbSNyGEY2213WKsJlwEA");
277}
278#endif
279
22de9dc8 280BOOST_AUTO_TEST_SUITE_END()