]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/test-signers.cc
rec: allow exception to proxy protocal usage for specific listen addresses
[thirdparty/pdns.git] / pdns / test-signers.cc
CommitLineData
1c2d079d 1#ifndef BOOST_TEST_DYN_LINK
22de9dc8 2#define BOOST_TEST_DYN_LINK
1c2d079d
FM
3#endif
4
22de9dc8 5#define BOOST_TEST_NO_MAIN
1c2d079d 6
22de9dc8
PD
7#ifdef HAVE_CONFIG_H
8#include "config.h"
9#endif
10#include <boost/test/unit_test.hpp>
11#include <boost/assign/list_of.hpp>
12
2dc20546 13#include "base32.hh"
22de9dc8
PD
14#include "base64.hh"
15#include "dnsseckeeper.hh"
16#include "dnssecinfra.hh"
17#include "misc.hh"
2dc20546 18
87066241 19#include <cstdio>
66bafd13 20#include <unordered_map>
87066241 21
7519a9f6 22// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables): Boost stuff.
22de9dc8
PD
23BOOST_AUTO_TEST_SUITE(test_signers)
24
87066241 25struct SignerParams
620d4801
RG
26{
27 std::string iscMap;
28 std::string dsSHA1;
29 std::string dsSHA256;
30 std::string dsSHA384;
31 std::vector<uint8_t> signature;
32 std::string zoneRepresentation;
33 std::string name;
34 std::string rfcMsgDump;
35 std::string rfcB64Signature;
690b86b7 36 int bits;
620d4801
RG
37 uint16_t flags;
38 uint16_t rfcFlags;
39 uint8_t algorithm;
40 bool isDeterministic;
70b793af 41 std::string pem;
87066241
FM
42};
43
62f0df97 44// clang-format off
23ffe528
FM
45static const SignerParams rsaSha256SignerParams = SignerParams
46{
68b0591d
FM
47 .iscMap = "Algorithm: 8\n"
48 "Modulus: qtunSiHnYq4XRLBehKAw1Glxb+48oIpAC7w3Jhpj570bb2uHt6orWGqnuyRtK8oqUi2ABoV0PFm8+IPgDMEdCQ==\n"
49 "PublicExponent: AQAB\n"
50 "PrivateExponent: MiItniUAngXzMeaGdWgDq/AcpvlCtOCcFlVt4TJRKkfp8DNRSxIxG53NNlOFkp1W00iLHqYC2GrH1qkKgT9l+Q==\n"
51 "Prime1: 3sZmM+5FKFy5xaRt0n2ZQOZ2C+CoKzVil6/al9LmYVs=\n"
52 "Prime2: xFcNWSIW6v8dDL2JQ1kxFDm/8RVeUSs1BNXXnvCjBGs=\n"
53 "Exponent1: WuUwhjfN1+4djlrMxHmisixWNfpwI1Eg7Ss/UXsnrMk=\n"
54 "Exponent2: vfMqas1cNsXRqP3Fym6D2Pl2BRuTQBv5E1B/ZrmQPTk=\n"
55 "Coefficient: Q10z43cA3hkwOkKsj5T0W5jrX97LBwZoY5lIjDCa4+M=\n",
56
57 .dsSHA1 = "1506 8 1 "
58 "172a500b374158d1a64ba3073cdbbc319b2fdf2c",
59
60 .dsSHA256 = "1506 8 2 "
61 "253b099ff47b02c6ffa52695a30a94c6681c56befe0e71a5077d6f79514972f9",
62
63 .dsSHA384 = "1506 8 4 "
64 "22ea940600dc2d9a98b1126c26ac0dc5c91b31eb50fe784b"
65 "36ad675e9eecfe6573c1f85c53b6bc94580f3ac443d13c4c",
291c3b6d 66
291c3b6d 67 /* from https://github.com/CZ-NIC/knot/blob/master/src/dnssec/tests/sign.c */
68b0591d
FM
68 .signature = {
69 0x93, 0x93, 0x5f, 0xd8, 0xa1, 0x2b, 0x4c, 0x0b, 0xf3, 0x67, 0x42, 0x13, 0x52,
70 0x00, 0x35, 0xdc, 0x09, 0xe0, 0xdf, 0xe0, 0x3e, 0xc2, 0xcf, 0x64, 0xab, 0x9f,
71 0x9f, 0x51, 0x5f, 0x5c, 0x27, 0xbe, 0x13, 0xd6, 0x17, 0x07, 0xa6, 0xe4, 0x3b,
72 0x63, 0x44, 0x85, 0x06, 0x13, 0xaa, 0x01, 0x3c, 0x58, 0x52, 0xa3, 0x98, 0x20,
73 0x65, 0x03, 0xd0, 0x40, 0xc8, 0xa0, 0xe9, 0xd2, 0xc0, 0x03, 0x5a, 0xab
74 },
291c3b6d 75
68b0591d
FM
76 .zoneRepresentation = "256 3 8 "
77 "AwEAAarbp0oh52KuF0SwXoSgMNRpcW/uPKCKQAu8NyYaY+"
78 "e9G29rh7eqK1hqp7skbSvKKlItgAaFdDxZvPiD4AzBHQk=",
291c3b6d 79
68b0591d
FM
80 .name = "rsa.",
81
82 .rfcMsgDump = "",
83 .rfcB64Signature = "",
84
85 .bits = 512,
86 .flags = 256,
87 .rfcFlags = 0,
88
89 .algorithm = DNSSECKeeper::RSASHA256,
90 .isDeterministic = true,
91
23ffe528
FM
92#if OPENSSL_VERSION_MAJOR >= 3
93 // OpenSSL 3.0.0 uses a generic key interface which stores the key PKCS#8-encoded.
94 .pem = "-----BEGIN PRIVATE KEY-----\n"
95 "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqtunSiHnYq4XRLBe\n"
96 "hKAw1Glxb+48oIpAC7w3Jhpj570bb2uHt6orWGqnuyRtK8oqUi2ABoV0PFm8+IPg\n"
97 "DMEdCQIDAQABAkAyIi2eJQCeBfMx5oZ1aAOr8Bym+UK04JwWVW3hMlEqR+nwM1FL\n"
98 "EjEbnc02U4WSnVbTSIsepgLYasfWqQqBP2X5AiEA3sZmM+5FKFy5xaRt0n2ZQOZ2\n"
99 "C+CoKzVil6/al9LmYVsCIQDEVw1ZIhbq/x0MvYlDWTEUOb/xFV5RKzUE1dee8KME\n"
100 "awIgWuUwhjfN1+4djlrMxHmisixWNfpwI1Eg7Ss/UXsnrMkCIQC98ypqzVw2xdGo\n"
101 "/cXKboPY+XYFG5NAG/kTUH9muZA9OQIgQ10z43cA3hkwOkKsj5T0W5jrX97LBwZo\n"
102 "Y5lIjDCa4+M=\n"
103 "-----END PRIVATE KEY-----\n"
104#else
66814fba
FM
105 .pem = "-----BEGIN RSA PRIVATE KEY-----\n"
106 "MIIBOgIBAAJBAKrbp0oh52KuF0SwXoSgMNRpcW/uPKCKQAu8NyYaY+e9G29rh7eq\n"
107 "K1hqp7skbSvKKlItgAaFdDxZvPiD4AzBHQkCAwEAAQJAMiItniUAngXzMeaGdWgD\n"
108 "q/AcpvlCtOCcFlVt4TJRKkfp8DNRSxIxG53NNlOFkp1W00iLHqYC2GrH1qkKgT9l\n"
109 "+QIhAN7GZjPuRShcucWkbdJ9mUDmdgvgqCs1Ypev2pfS5mFbAiEAxFcNWSIW6v8d\n"
110 "DL2JQ1kxFDm/8RVeUSs1BNXXnvCjBGsCIFrlMIY3zdfuHY5azMR5orIsVjX6cCNR\n"
111 "IO0rP1F7J6zJAiEAvfMqas1cNsXRqP3Fym6D2Pl2BRuTQBv5E1B/ZrmQPTkCIENd\n"
112 "M+N3AN4ZMDpCrI+U9FuY61/eywcGaGOZSIwwmuPj\n"
23ffe528
FM
113 "-----END RSA PRIVATE KEY-----\n"
114#endif
115};
62f0df97 116// clang-format on
291c3b6d
FM
117
118/* ECDSA-P256-SHA256 from
119 * https://github.com/CZ-NIC/knot/blob/master/src/dnssec/tests/sample_keys.h
120 */
62f0df97 121// clang-format off
3319f4c8
FM
122static const SignerParams ecdsaSha256 = SignerParams
123{
68b0591d
FM
124 .iscMap = "Algorithm: 13\n"
125 "PrivateKey: iyLIPdk3DOIxVmmSYlmTstbtUPiVlEyDX46psyCwNVQ=\n",
126
127 .dsSHA1 = "5345 13 1 "
128 "954103ac7c43810ce9f414e80f30ab1cbe49b236",
291c3b6d 129
68b0591d
FM
130 .dsSHA256 = "5345 13 2 "
131 "bac2107036e735b50f85006ce409a19a3438cab272e70769ebda032239a3d0ca",
132
133 .dsSHA384 = "5345 13 4 "
134 "a0ac6790483872be72a258314200a88ab75cdd70f66a18a0"
135 "9f0f414c074df0989fdb1df0e67d82d4312cda67b93a76c1",
291c3b6d 136
291c3b6d 137 /* from https://github.com/CZ-NIC/knot/blob/master/src/dnssec/tests/sign.c */
68b0591d
FM
138 .signature = {
139 0xa2, 0x95, 0x76, 0xb5, 0xf5, 0x7e, 0xbd, 0xdd, 0xf5, 0x62, 0xa2, 0xc3, 0xa4,
140 0x8d, 0xd4, 0x53, 0x5c, 0xba, 0x29, 0x71, 0x8c, 0xcc, 0x28, 0x7b, 0x58, 0xf3,
141 0x1e, 0x4e, 0x58, 0xe2, 0x36, 0x7e, 0xa0, 0x1a, 0xb6, 0xe6, 0x29, 0x71, 0x1b,
142 0xd3, 0x8c, 0x88, 0xc3, 0xee, 0x12, 0x0e, 0x69, 0x70, 0x55, 0x99, 0xec, 0xd5,
143 0xf6, 0x4f, 0x4b, 0xe2, 0x41, 0xd9, 0x10, 0x7e, 0x67, 0xe5, 0xad, 0x2f
144 },
291c3b6d 145
68b0591d
FM
146 .zoneRepresentation = "256 3 13 "
147 "8uD7C4THTM/w7uhryRSToeE/jKT78/p853RX0L5EwrZ"
148 "rSLBubLPiBw7gbvUP6SsIga5ZQ4CSAxNmYA/gZsuXzA==",
149
150 .name = "ecdsa.",
151
152 .rfcMsgDump = "",
153 .rfcB64Signature = "",
154
155 .bits = 256,
156 .flags = 256,
157 .rfcFlags = 0,
158
159 .algorithm = DNSSECKeeper::ECDSA256,
160 .isDeterministic = false,
161
3319f4c8
FM
162#if OPENSSL_VERSION_MAJOR >= 3
163 // OpenSSL 3.0.0 uses a generic key interface which stores the key PKCS#8-encoded.
164 .pem = "-----BEGIN PRIVATE KEY-----\n"
165 "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgiyLIPdk3DOIxVmmS\n"
166 "YlmTstbtUPiVlEyDX46psyCwNVShRANCAATy4PsLhMdMz/Du6GvJFJOh4T+MpPvz\n"
167 "+nzndFfQvkTCtmtIsG5ss+IHDuBu9Q/pKwiBrllDgJIDE2ZgD+Bmy5fM\n"
168 "-----END PRIVATE KEY-----\n"
169#else
68b0591d
FM
170 .pem = "-----BEGIN EC PRIVATE KEY-----\n"
171 "MHcCAQEEIIsiyD3ZNwziMVZpkmJZk7LW7VD4lZRMg1+OqbMgsDVUoAoGCCqGSM49\n"
172 "AwEHoUQDQgAE8uD7C4THTM/w7uhryRSToeE/jKT78/p853RX0L5EwrZrSLBubLPi\n"
173 "Bw7gbvUP6SsIga5ZQ4CSAxNmYA/gZsuXzA==\n"
3319f4c8
FM
174 "-----END EC PRIVATE KEY-----\n"
175#endif
176};
62f0df97 177// clang-format on
291c3b6d
FM
178
179/* Ed25519 from https://github.com/CZ-NIC/knot/blob/master/src/dnssec/tests/sample_keys.h,
180 * also from rfc8080 section 6.1
181 */
62f0df97 182// clang-format off
291c3b6d 183static const SignerParams ed25519 = SignerParams{
68b0591d
FM
184 .iscMap = "Algorithm: 15\n"
185 "PrivateKey: ODIyNjAzODQ2MjgwODAxMjI2NDUxOTAyMDQxNDIyNjI=\n",
186
187 .dsSHA1 = "3612 15 1 "
188 "501249721e1f09a79d30d5c6c4dca1dc1da4ed5d",
189
190 .dsSHA256 = "3612 15 2 "
191 "1b1c8766b2a96566ff196f77c0c4194af86aaa109c5346ff60231a27d2b07ac0",
291c3b6d 192
68b0591d
FM
193 .dsSHA384 = "3612 15 4 "
194 "d11831153af4985efbd0ae792c967eb4aff3c35488db95f7"
195 "e2f85dcec74ae8f59f9a72641798c91c67c675db1d710c18",
291c3b6d 196
291c3b6d 197 /* from https://github.com/CZ-NIC/knot/blob/master/src/dnssec/tests/sign.c */
68b0591d
FM
198 .signature = {
199 0x0a, 0x9e, 0x51, 0x5f, 0x16, 0x89, 0x49, 0x27, 0x0e, 0x98, 0x34, 0xd3, 0x48,
200 0xef, 0x5a, 0x6e, 0x85, 0x2f, 0x7c, 0xd6, 0xd7, 0xc8, 0xd0, 0xf4, 0x2c, 0x68,
201 0x8c, 0x1f, 0xf7, 0xdf, 0xeb, 0x7c, 0x25, 0xd6, 0x1a, 0x76, 0x3e, 0xaf, 0x28,
202 0x1f, 0x1d, 0x08, 0x10, 0x20, 0x1c, 0x01, 0x77, 0x1b, 0x5a, 0x48, 0xd6, 0xe5,
203 0x1c, 0xf9, 0xe3, 0xe0, 0x70, 0x34, 0x5e, 0x02, 0x49, 0xfb, 0x9e, 0x05
204 },
291c3b6d 205
68b0591d
FM
206 .zoneRepresentation = "256 3 15 l02Woi0iS8Aa25FQkUd9RMzZHJpBoRQwAQEX1SxZJA4=",
207
208 .name = "ed25519.",
291c3b6d 209
59f254ab
FM
210 // vector extracted from https://gitlab.labs.nic.cz/labs/ietf/blob/master/dnskey.py (rev
211 // 476d6ded) by printing signature_data
68b0591d
FM
212 .rfcMsgDump = "00 0f 0f 02 00 00 0e 10 55 d4 fc 60 55 b9 4c e0 0e 1d 07 65 78 "
213 "61 6d 70 6c 65 03 63 6f 6d 00 07 65 78 61 6d 70 6c 65 03 63 6f "
214 "6d 00 00 0f 00 01 00 00 0e 10 00 14 00 0a 04 6d 61 69 6c 07 65 "
215 "78 61 6d 70 6c 65 03 63 6f 6d 00 ",
291c3b6d
FM
216
217 // vector verified from dnskey.py as above, and confirmed with
218 // https://www.rfc-editor.org/errata_search.php?rfc=8080&eid=4935
68b0591d
FM
219 .rfcB64Signature = "oL9krJun7xfBOIWcGHi7mag5/hdZrKWw15jPGrHpjQeR"
220 "AvTdszaPD+QLs3fx8A4M3e23mRZ9VrbpMngwcrqNAg==",
221
222 .bits = 256,
223 .flags = 256,
224 .rfcFlags = 257,
225
226 .algorithm = DNSSECKeeper::ED25519,
227 .isDeterministic = true,
228
229 .pem = "-----BEGIN PRIVATE KEY-----\n"
230 "MC4CAQAwBQYDK2VwBCIEIDgyMjYwMzg0NjI4MDgwMTIyNjQ1MTkwMjA0MTQyMjYy\n"
62f0df97
FM
231 "-----END PRIVATE KEY-----\n"
232};
233// clang-format on
291c3b6d 234
59f254ab
FM
235/* Ed448.
236 */
62f0df97 237// clang-format off
59f254ab
FM
238static const SignerParams ed448 = SignerParams{
239 .iscMap = "Private-key-format: v1.2\n"
240 "Algorithm: 16 (ED448)\n"
241 "PrivateKey: xZ+5Cgm463xugtkY5B0Jx6erFTXp13rYegst0qRtNsOYnaVpMx0Z/c5EiA9x8wWbDDct/U3FhYWA\n",
242
ea16a2f9
FM
243 .dsSHA1 = "9712 16 1 "
244 "2873e800eb2d784cdd1802f884b3c540b573eaa0",
59f254ab 245
ea16a2f9
FM
246 .dsSHA256 = "9712 16 2 "
247 "9aa27306f8a04a0a6fae8affd65d6f35875dcb134c05bd7c7b61bd0dc44009cd",
59f254ab 248
ea16a2f9
FM
249 .dsSHA384 = "9712 16 4 "
250 "3876e5d892d3f31725f9964a332f9b9afd791171833480f2"
251 "e71af78efb985cde9900ba95315287123a5908ca8f334369",
59f254ab 252
59f254ab
FM
253 .signature = {
254 0xb5, 0xcc, 0x21, 0x5a, 0x52, 0x21, 0x60, 0xa3, 0xb8, 0xd9, 0x3a, 0xd7, 0x05,
255 0xdd, 0x4a, 0x32, 0x96, 0xce, 0x08, 0xde, 0x74, 0x5f, 0xdb, 0xde, 0x54, 0x95,
256 0x97, 0x93, 0x6f, 0x3a, 0x4a, 0x34, 0x41, 0x14, 0xba, 0x99, 0x86, 0x0d, 0xe2,
257 0x99, 0xf1, 0x14, 0x6a, 0x1b, 0x7a, 0xfa, 0xef, 0xab, 0x62, 0xd2, 0x71, 0x85,
258 0xae, 0xd1, 0x84, 0x80, 0x00, 0x50, 0x03, 0x9e, 0x73, 0x53, 0xe8, 0x9e, 0x19,
259 0xb8, 0xc0, 0xdb, 0xd4, 0xf0, 0x1e, 0x44, 0x4c, 0xb7, 0x32, 0x07, 0xda, 0x0b,
260 0x64, 0x22, 0xa8, 0x63, 0xaa, 0x7a, 0x12, 0x73, 0xc9, 0x29, 0xfd, 0x50, 0x85,
261 0x0f, 0x43, 0x72, 0x77, 0x86, 0xec, 0x88, 0x1a, 0x96, 0x95, 0x4a, 0x01, 0xfe,
262 0xf2, 0xe6, 0x77, 0x4a, 0x2e, 0x43, 0xdd, 0x60, 0x29, 0x00,
263 },
59f254ab
FM
264
265 .zoneRepresentation = "256 3 16 "
266 "3kgROaDjrh0H2iuixWBrc8g2EpBBLCdGzHmn+"
267 "G2MpTPhpj/OiBVHHSfPodx1FYYUcJKm1MDpJtIA",
268
269 .name = "ed448.",
270
271 // vector extracted from https://gitlab.labs.nic.cz/labs/ietf/blob/master/dnskey.py (rev
272 // 476d6ded) by printing signature_data
273 .rfcMsgDump = "00 0f 10 02 00 00 0e 10 55 d4 fc 60 55 b9 4c e0 25 f1 07 65 78 "
274 "61 6d 70 6c 65 03 63 6f 6d 00 07 65 78 61 6d 70 6c 65 03 63 6f "
275 "6d 00 00 0f 00 01 00 00 0e 10 00 14 00 0a 04 6d 61 69 6c 07 65 "
276 "78 61 6d 70 6c 65 03 63 6f 6d 00 ",
277
278 // vector verified from dnskey.py as above, and confirmed with
279 // https://www.rfc-editor.org/errata_search.php?rfc=8080&eid=4935
280 .rfcB64Signature = "3cPAHkmlnxcDHMyg7vFC34l0blBhuG1qpwLmjInI8w1CMB29FkEA"
281 "IJUA0amxWndkmnBZ6SKiwZSAxGILn/NBtOXft0+Gj7FSvOKxE/07"
282 "+4RQvE581N3Aj/JtIyaiYVdnYtyMWbSNyGEY2213WKsJlwEA",
283
284 .bits = 456,
285 .flags = 256,
286 .rfcFlags = 257,
287
288 .algorithm = DNSSECKeeper::ED448,
289 .isDeterministic = true,
290
291 .pem = "-----BEGIN PRIVATE KEY-----\n"
292 "MEcCAQAwBQYDK2VxBDsEOcWfuQoJuOt8boLZGOQdCcenqxU16dd62HoLLdKkbTbD\n"
293 "mJ2laTMdGf3ORIgPcfMFmww3Lf1NxYWFgA==\n"
62f0df97
FM
294 "-----END PRIVATE KEY-----\n"
295};
296// clang-format on
59f254ab 297
291c3b6d 298struct Fixture
87066241 299{
291c3b6d
FM
300 Fixture()
301 {
302 BOOST_TEST_MESSAGE("All available/supported algorithms:");
303 auto pairs = DNSCryptoKeyEngine::listAllAlgosWithBackend();
304 for (auto const& pair : pairs) {
305 BOOST_TEST_MESSAGE(" " + std::to_string(pair.first) + ": " + pair.second);
306 }
307
308 BOOST_TEST_MESSAGE("Setting up signer params:");
309
310 addSignerParams(DNSSECKeeper::RSASHA256, "RSA SHA256", rsaSha256SignerParams);
311
b4bc0f7c 312#ifdef HAVE_LIBCRYPTO_ECDSA
291c3b6d 313 addSignerParams(DNSSECKeeper::ECDSA256, "ECDSA SHA256", ecdsaSha256);
b4bc0f7c 314#endif
291c3b6d 315
b4bc0f7c
FM
316// We need to have HAVE_LIBCRYPTO_ED25519 for the PEM reader/writer.
317#if defined(HAVE_LIBCRYPTO_ED25519)
291c3b6d 318 addSignerParams(DNSSECKeeper::ED25519, "ED25519", ed25519);
b4bc0f7c 319#endif
59f254ab 320
b4bc0f7c 321#if defined(HAVE_LIBDECAF) || defined(HAVE_LIBCRYPTO_ED448)
59f254ab 322 addSignerParams(DNSSECKeeper::ED448, "ED448", ed448);
b4bc0f7c 323#endif
291c3b6d
FM
324 }
325
326 void addSignerParams(const uint8_t algorithm, const std::string& name, const SignerParams& params)
327 {
328 BOOST_TEST_MESSAGE(" " + std::to_string(algorithm) + ": " + name + " (" + params.name + ")");
329 signerParams.insert_or_assign(algorithm, params);
330 }
331
332 const std::string message{"Very good, young padawan."};
333 std::unordered_map<uint8_t, struct SignerParams> signerParams;
620d4801 334};
22de9dc8 335
87066241 336static void checkRR(const SignerParams& signer)
620d4801
RG
337{
338 DNSKEYRecordContent drc;
a2c6e554 339 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::makeFromISCString(drc, signer.iscMap));
620d4801 340 DNSSECPrivateKey dpk;
a456662f 341 dpk.setKey(dcke, signer.rfcFlags);
22de9dc8 342
c1e7b833 343 sortedRecords_t rrs;
620d4801 344 /* values taken from rfc8080 for ed25519 and ed448, rfc5933 for gost */
a456662f 345 DNSName qname(dpk.getAlgorithm() == DNSSECKeeper::ECCGOST ? "www.example.net." : "example.com.");
22de9dc8 346
620d4801 347 reportBasicTypes();
22de9dc8 348
620d4801
RG
349 RRSIGRecordContent rrc;
350 uint32_t expire = 1440021600;
351 uint32_t inception = 1438207200;
22de9dc8 352
a456662f 353 if (dpk.getAlgorithm() == DNSSECKeeper::ECCGOST) {
620d4801
RG
354 rrc.d_signer = DNSName("example.net.");
355 inception = 946684800;
356 expire = 1893456000;
d525b58b 357 rrs.insert(DNSRecordContent::make(QType::A, QClass::IN, "192.0.2.1"));
620d4801
RG
358 }
359 else {
22de9dc8 360 rrc.d_signer = qname;
d525b58b 361 rrs.insert(DNSRecordContent::make(QType::MX, QClass::IN, "10 mail.example.com."));
620d4801 362 }
22de9dc8 363
620d4801
RG
364 rrc.d_originalttl = 3600;
365 rrc.d_sigexpire = expire;
366 rrc.d_siginception = inception;
c1e7b833 367 rrc.d_type = (*rrs.cbegin())->getType();
620d4801
RG
368 rrc.d_labels = qname.countLabels();
369 rrc.d_tag = dpk.getTag();
a456662f 370 rrc.d_algorithm = dpk.getAlgorithm();
22de9dc8 371
620d4801
RG
372 string msg = getMessageForRRSET(qname, rrc, rrs, false);
373
374 BOOST_CHECK_EQUAL(makeHexDump(msg), signer.rfcMsgDump);
375
376 string signature = dcke->sign(msg);
22de9dc8 377
7519a9f6 378 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg): Boost stuff.
620d4801
RG
379 BOOST_CHECK(dcke->verify(msg, signature));
380
381 if (signer.isDeterministic) {
22de9dc8 382 string b64 = Base64Encode(signature);
620d4801
RG
383 BOOST_CHECK_EQUAL(b64, signer.rfcB64Signature);
384 }
385 else {
386 std::string raw;
387 B64Decode(signer.rfcB64Signature, raw);
7519a9f6 388 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg): Boost stuff.
620d4801
RG
389 BOOST_CHECK(dcke->verify(msg, raw));
390 }
391}
22de9dc8 392
291c3b6d 393static void test_generic_signer(std::shared_ptr<DNSCryptoKeyEngine> dcke, DNSKEYRecordContent& drc, const SignerParams& signer, const std::string& message)
620d4801 394{
87066241
FM
395 BOOST_CHECK_EQUAL(dcke->getAlgorithm(), signer.algorithm);
396 BOOST_CHECK_EQUAL(dcke->getBits(), signer.bits);
3916c60f
FM
397
398 vector<string> errorMessages{};
f7b9d3b7 399 BOOST_CHECK_EQUAL(dcke->checkKey(errorMessages), true);
3916c60f
FM
400 if (!errorMessages.empty()) {
401 BOOST_TEST_MESSAGE("Errors from " + dcke->getName() + " checkKey()");
402 for (auto& errorMessage : errorMessages) {
403 BOOST_TEST_MESSAGE(" " + errorMessage);
404 }
405 }
87066241
FM
406
407 BOOST_CHECK_EQUAL(drc.d_algorithm, signer.algorithm);
408
409 DNSSECPrivateKey dpk;
a456662f 410 dpk.setKey(dcke, signer.flags);
87066241 411 drc = dpk.getDNSKEY();
620d4801 412
87066241
FM
413 BOOST_CHECK_EQUAL(drc.d_algorithm, signer.algorithm);
414 BOOST_CHECK_EQUAL(drc.d_protocol, 3);
415 BOOST_CHECK_EQUAL(drc.getZoneRepresentation(), signer.zoneRepresentation);
620d4801 416
87066241
FM
417 DNSName name(signer.name);
418 auto ds1 = makeDSFromDNSKey(name, drc, DNSSECKeeper::DIGEST_SHA1);
419 if (!signer.dsSHA1.empty()) {
420 BOOST_CHECK_EQUAL(ds1.getZoneRepresentation(), signer.dsSHA1);
421 }
620d4801 422
87066241
FM
423 auto ds2 = makeDSFromDNSKey(name, drc, DNSSECKeeper::DIGEST_SHA256);
424 if (!signer.dsSHA256.empty()) {
425 BOOST_CHECK_EQUAL(ds2.getZoneRepresentation(), signer.dsSHA256);
426 }
620d4801 427
87066241
FM
428 auto ds4 = makeDSFromDNSKey(name, drc, DNSSECKeeper::DIGEST_SHA384);
429 if (!signer.dsSHA384.empty()) {
430 BOOST_CHECK_EQUAL(ds4.getZoneRepresentation(), signer.dsSHA384);
431 }
620d4801 432
87066241 433 auto signature = dcke->sign(message);
7519a9f6 434 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg): Boost stuff.
87066241 435 BOOST_CHECK(dcke->verify(message, signature));
620d4801 436
5ba4a5e4 437 auto signerSignature = std::string(signer.signature.begin(), signer.signature.end());
87066241 438 if (signer.isDeterministic) {
5ba4a5e4
FM
439 auto signatureBase64 = Base64Encode(signature);
440 auto signerSignatureBase64 = Base64Encode(signerSignature);
441 BOOST_CHECK_EQUAL(signatureBase64, signerSignatureBase64);
87066241
FM
442 }
443 else {
444 /* since the signing process is not deterministic, we can't directly compare our signature
445 with the one we have. Still the one we have should also validate correctly. */
7519a9f6 446 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg): Boost stuff.
5ba4a5e4 447 BOOST_CHECK(dcke->verify(message, signerSignature));
87066241 448 }
620d4801 449
87066241
FM
450 if (!signer.rfcMsgDump.empty() && !signer.rfcB64Signature.empty()) {
451 checkRR(signer);
452 }
453}
454
7519a9f6 455// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables,readability-identifier-length): Boost stuff.
291c3b6d 456BOOST_FIXTURE_TEST_CASE(test_generic_signers, Fixture)
87066241 457{
291c3b6d
FM
458 for (const auto& algoSignerPair : signerParams) {
459 auto signer = algoSignerPair.second;
460
87066241
FM
461 DNSKEYRecordContent drc;
462 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::makeFromISCString(drc, signer.iscMap));
291c3b6d 463 test_generic_signer(dcke, drc, signer, message);
87066241 464
70b793af 465 DNSKEYRecordContent pemDRC;
3de36d82 466 shared_ptr<DNSCryptoKeyEngine> pemKey{DNSCryptoKeyEngine::makeFromPEMString(pemDRC, signer.algorithm, signer.pem)};
87066241 467
70b793af 468 BOOST_CHECK_EQUAL(pemKey->convertToISC(), dcke->convertToISC());
620d4801 469
70b793af 470 test_generic_signer(pemKey, pemDRC, signer, message);
18567bc6 471
d0fa1838 472 auto dckePEMOutput = dcke->convertToPEMString();
70b793af 473 BOOST_CHECK_EQUAL(dckePEMOutput, signer.pem);
18567bc6 474
d0fa1838 475 auto pemKeyOutput = pemKey->convertToPEMString();
70b793af 476 BOOST_CHECK_EQUAL(pemKeyOutput, signer.pem);
620d4801 477 }
22de9dc8 478}
22de9dc8 479
7519a9f6 480// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables,readability-identifier-length): Boost stuff.
b4bc0f7c
FM
481BOOST_AUTO_TEST_CASE(test_hash_qname_with_salt)
482{
0503c8fa 483 {
2dc20546 484 // rfc5155 appendix A
b4bc0f7c 485 const unsigned char salt[] = {0xaa, 0xbb, 0xcc, 0xdd};
0503c8fa
RG
486 const unsigned int iterations{12};
487 const std::vector<std::pair<std::string, std::string>> namesToHashes = {
b4bc0f7c
FM
488 {"example", "0p9mhaveqvm6t7vbl5lop2u3t2rp3tom"},
489 {"a.example", "35mthgpgcu1qg68fab165klnsnk3dpvl"},
490 {"ai.example", "gjeqe526plbf1g8mklp59enfd789njgi"},
491 {"ns1.example", "2t7b4g4vsa5smi47k61mv5bv1a22bojr"},
492 {"ns2.example", "q04jkcevqvmu85r014c7dkba38o0ji5r"},
493 {"w.example", "k8udemvp1j2f7eg6jebps17vp3n8i58h"},
494 {"*.w.example", "r53bq7cc2uvmubfu5ocmm6pers9tk9en"},
495 {"x.w.example", "b4um86eghhds6nea196smvmlo4ors995"},
496 {"y.w.example", "ji6neoaepv8b5o6k4ev33abha8ht9fgc"},
497 {"x.y.w.example", "2vptu5timamqttgl4luu9kg21e0aor3s"},
498 {"xx.example", "t644ebqk9bibcna874givr6joj62mlhv"},
499 {"2t7b4g4vsa5smi47k61mv5bv1a22bojr.example", "kohar7mbb8dc2ce8a9qvl8hon4k53uhi"},
0503c8fa
RG
500 };
501
502 for (const auto& [name, expectedHash] : namesToHashes) {
503 auto hash = hashQNameWithSalt(std::string(reinterpret_cast<const char*>(salt), sizeof(salt)), iterations, DNSName(name));
504 BOOST_CHECK_EQUAL(toBase32Hex(hash), expectedHash);
505 }
506 }
507
508 {
509 /* no additional iterations, very short salt */
b4bc0f7c 510 const unsigned char salt[] = {0xFF};
0503c8fa
RG
511 const unsigned int iterations{0};
512 const std::vector<std::pair<std::string, std::string>> namesToHashes = {
b4bc0f7c 513 {"example", "s9dp8o2l6jgqgg26ecobtjooe7p019cs"},
0503c8fa
RG
514 };
515
516 for (const auto& [name, expectedHash] : namesToHashes) {
517 auto hash = hashQNameWithSalt(std::string(reinterpret_cast<const char*>(salt), sizeof(salt)), iterations, DNSName(name));
518 BOOST_CHECK_EQUAL(toBase32Hex(hash), expectedHash);
519 }
520 }
521
522 {
523 /* only one iteration */
b4bc0f7c 524 const unsigned char salt[] = {0xaa, 0xbb, 0xcc, 0xdd};
0503c8fa
RG
525 const unsigned int iterations{1};
526 const std::vector<std::pair<std::string, std::string>> namesToHashes = {
b4bc0f7c 527 {"example", "ulddquehrj5jpf50ga76vgqr1oq40133"},
0503c8fa
RG
528 };
529
530 for (const auto& [name, expectedHash] : namesToHashes) {
531 auto hash = hashQNameWithSalt(std::string(reinterpret_cast<const char*>(salt), sizeof(salt)), iterations, DNSName(name));
532 BOOST_CHECK_EQUAL(toBase32Hex(hash), expectedHash);
533 }
534 }
535
536 {
537 /* 65535 iterations, long salt */
538 unsigned char salt[255];
539 for (unsigned char idx = 0; idx < 255; idx++) {
540 salt[idx] = idx;
541 };
542 const unsigned int iterations{65535};
543 const std::vector<std::pair<std::string, std::string>> namesToHashes = {
b4bc0f7c 544 {"example", "no95j4cfile8avstr7bn4aj9he18trri"},
0503c8fa
RG
545 };
546
547 for (const auto& [name, expectedHash] : namesToHashes) {
548 auto hash = hashQNameWithSalt(std::string(reinterpret_cast<const char*>(salt), sizeof(salt)), iterations, DNSName(name));
549 BOOST_CHECK_EQUAL(toBase32Hex(hash), expectedHash);
550 }
2dc20546
RG
551 }
552}
553
7519a9f6 554// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables): Boost stuff.
22de9dc8 555BOOST_AUTO_TEST_SUITE_END()