]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/test-signers.cc
auth: switch circleci mssql image
[thirdparty/pdns.git] / pdns / test-signers.cc
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"
16 BOOST_AUTO_TEST_SUITE(test_signers)
17
18 static const std::string message = "Very good, young padawan.";
19
20 static 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 },
62 #ifdef HAVE_LIBCRYPTO_ECDSA
63 /* ECDSA-P256-SHA256 from https://github.com/CZ-NIC/knot/blob/master/src/dnssec/tests/sample_keys.h */
64 { "Algorithm: 13\n"
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==",
72 "ecdsa.",
73 "",
74 "",
75 256,
76 256,
77 0,
78 DNSSECKeeper::ECDSA256,
79 false
80 },
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 */
85 { "Algorithm: 15\n"
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=",
93 "ed25519.",
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==",
98 256,
99 256,
100 257,
101 DNSSECKeeper::ED25519,
102 true
103 },
104 #endif /* defined(HAVE_LIBSODIUM) || defined(HAVE_LIBDECAF) || defined(HAVE_LIBCRYPTO_ED25519) */
105 };
106
107 static void checkRR(const signerParams& signer)
108 {
109 DNSKEYRecordContent drc;
110 auto dcke = DNSCryptoKeyEngine::makeFromISCString(drc, signer.iscMap);
111 DNSSECPrivateKey dpk;
112 dpk.setKey(dcke);
113 dpk.d_flags = signer.rfcFlags;
114
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.");
118
119 reportBasicTypes();
120
121 RRSIGRecordContent rrc;
122 uint32_t expire = 1440021600;
123 uint32_t inception = 1438207200;
124
125 if (dpk.d_algorithm == 12) {
126 rrc.d_signer = DNSName("example.net.");
127 inception = 946684800;
128 expire = 1893456000;
129 rrs.push_back(DNSRecordContent::mastermake(QType::A, QClass::IN, "192.0.2.1"));
130 }
131 else {
132 rrc.d_signer = qname;
133 rrs.push_back(DNSRecordContent::mastermake(QType::MX, QClass::IN, "10 mail.example.com."));
134 }
135
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;
143
144 string msg = getMessageForRRSET(qname, rrc, rrs, false);
145
146 BOOST_CHECK_EQUAL(makeHexDump(msg), signer.rfcMsgDump);
147
148 string signature = dcke->sign(msg);
149
150 BOOST_CHECK(dcke->verify(msg, signature));
151
152 if (signer.isDeterministic) {
153 string b64 = Base64Encode(signature);
154 BOOST_CHECK_EQUAL(b64, signer.rfcB64Signature);
155 }
156 else {
157 std::string raw;
158 B64Decode(signer.rfcB64Signature, raw);
159 BOOST_CHECK(dcke->verify(msg, raw));
160 }
161 }
162
163 BOOST_AUTO_TEST_CASE(test_generic_signers)
164 {
165 for (const auto signer : signers) {
166 DNSKEYRecordContent drc;
167 auto dcke = DNSCryptoKeyEngine::makeFromISCString(drc, signer.iscMap);
168
169 BOOST_CHECK_EQUAL(dcke->getAlgorithm(), signer.algorithm);
170 BOOST_CHECK_EQUAL(dcke->getBits(), signer.bits);
171 BOOST_CHECK_EQUAL(dcke->checkKey(nullptr), true);
172
173 BOOST_CHECK_EQUAL(drc.d_algorithm, signer.algorithm);
174
175 DNSSECPrivateKey dpk;
176 dpk.setKey(dcke);
177 dpk.d_flags = signer.flags;
178 drc = dpk.getDNSKEY();
179
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);
183
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);
188 }
189
190 auto ds2 = makeDSFromDNSKey(name, drc, DNSSECKeeper::SHA256);
191 if (!signer.dsSHA256.empty()) {
192 BOOST_CHECK_EQUAL(ds2.getZoneRepresentation(), signer.dsSHA256);
193 }
194
195 auto ds4 = makeDSFromDNSKey(name, drc, DNSSECKeeper::SHA384);
196 if (!signer.dsSHA384.empty()) {
197 BOOST_CHECK_EQUAL(ds4.getZoneRepresentation(), signer.dsSHA384);
198 }
199
200 auto signature = dcke->sign(message);
201 BOOST_CHECK(dcke->verify(message, signature));
202
203 if (signer.isDeterministic) {
204 BOOST_CHECK_EQUAL(signature, std::string(signer.signature.begin(), signer.signature.end()));
205 } else {
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())));
209 }
210
211 if (!signer.rfcMsgDump.empty() && !signer.rfcB64Signature.empty()) {
212 checkRR(signer);
213 }
214 }
215 }
216
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;
222
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");
228
229 DNSSECPrivateKey dpk;
230 dpk.setKey(engine);
231
232 reportBasicTypes();
233
234 rrs.push_back(DNSRecordContent::mastermake(QType::MX, 1, "10 mail.example.com."));
235
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;
242 rrc.d_labels = 2;
243 // TODO: derive the next two from the key
244 rrc.d_tag = 9713;
245 rrc.d_algorithm = 16;
246
247 string msg = getMessageForRRSET(qname, rrc, rrs, false);
248
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 ");
251
252 string signature = engine->sign(msg);
253 string b64 = Base64Encode(signature);
254
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");
257 }
258 #endif /* defined(HAVE_LIBDECAF) || defined(HAVE_LIBCRYPTO_ED448) */
259
260 BOOST_AUTO_TEST_SUITE_END()