• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PowerDNS / pdns / 12595591960

03 Jan 2025 09:27AM UTC coverage: 62.774% (+2.5%) from 60.245%
12595591960

Pull #15008

github

web-flow
Merge c2a2749d3 into 788f396a7
Pull Request #15008: Do not follow CNAME records for ANY or CNAME queries

30393 of 78644 branches covered (38.65%)

Branch coverage included in aggregate %.

105822 of 138350 relevant lines covered (76.49%)

4613078.44 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.69
/pdns/test-signers.cc
1
#ifndef BOOST_TEST_DYN_LINK
2
#define BOOST_TEST_DYN_LINK
3
#endif
4

5
#define BOOST_TEST_NO_MAIN
6

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

13
#include "base32.hh"
14
#include "base64.hh"
15
#include "dnsseckeeper.hh"
16
#include "dnssecinfra.hh"
17
#include "misc.hh"
18

19
#include <cstdio>
20
#include <unordered_map>
21

22
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables): Boost stuff.
23
BOOST_AUTO_TEST_SUITE(test_signers)
24

25
struct SignerParams
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;
36
  int bits;
37
  uint16_t flags;
38
  uint16_t rfcFlags;
39
  uint8_t algorithm;
40
  bool isDeterministic;
41
  std::string pem;
42
};
43

44
// clang-format off
45
static const SignerParams rsaSha256SignerParams = SignerParams
46
{
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",
66

67
  /* from https://github.com/CZ-NIC/knot/blob/master/src/dnssec/tests/sign.c */
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
  },
75

76
  .zoneRepresentation = "256 3 8 "
77
                        "AwEAAarbp0oh52KuF0SwXoSgMNRpcW/uPKCKQAu8NyYaY+"
78
                        "e9G29rh7eqK1hqp7skbSvKKlItgAaFdDxZvPiD4AzBHQk=",
79

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

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
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"
113
         "-----END RSA PRIVATE KEY-----\n"
114
#endif
115
};
116
// clang-format on
117

118
/* ECDSA-P256-SHA256 from
119
 * https://github.com/CZ-NIC/knot/blob/master/src/dnssec/tests/sample_keys.h
120
 */
121
// clang-format off
122
static const SignerParams ecdsaSha256 = SignerParams
123
{
124
  .iscMap = "Algorithm: 13\n"
125
            "PrivateKey: iyLIPdk3DOIxVmmSYlmTstbtUPiVlEyDX46psyCwNVQ=\n",
126

127
  .dsSHA1 = "5345 13 1 "
128
            "954103ac7c43810ce9f414e80f30ab1cbe49b236",
129

130
  .dsSHA256 = "5345 13 2 "
131
              "bac2107036e735b50f85006ce409a19a3438cab272e70769ebda032239a3d0ca",
132

133
  .dsSHA384 = "5345 13 4 "
134
              "a0ac6790483872be72a258314200a88ab75cdd70f66a18a0"
135
              "9f0f414c074df0989fdb1df0e67d82d4312cda67b93a76c1",
136

137
  /* from https://github.com/CZ-NIC/knot/blob/master/src/dnssec/tests/sign.c */
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
  },
145

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

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
170
  .pem = "-----BEGIN EC PRIVATE KEY-----\n"
171
         "MHcCAQEEIIsiyD3ZNwziMVZpkmJZk7LW7VD4lZRMg1+OqbMgsDVUoAoGCCqGSM49\n"
172
         "AwEHoUQDQgAE8uD7C4THTM/w7uhryRSToeE/jKT78/p853RX0L5EwrZrSLBubLPi\n"
173
         "Bw7gbvUP6SsIga5ZQ4CSAxNmYA/gZsuXzA==\n"
174
         "-----END EC PRIVATE KEY-----\n"
175
#endif
176
};
177
// clang-format on
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
 */
182
// clang-format off
183
static const SignerParams ed25519 = SignerParams{
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",
192

193
  .dsSHA384 = "3612 15 4 "
194
              "d11831153af4985efbd0ae792c967eb4aff3c35488db95f7"
195
              "e2f85dcec74ae8f59f9a72641798c91c67c675db1d710c18",
196

197
  /* from https://github.com/CZ-NIC/knot/blob/master/src/dnssec/tests/sign.c */
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
  },
205

206
  .zoneRepresentation = "256 3 15 l02Woi0iS8Aa25FQkUd9RMzZHJpBoRQwAQEX1SxZJA4=",
207

208
  .name = "ed25519.",
209

210
  // vector extracted from https://gitlab.labs.nic.cz/labs/ietf/blob/master/dnskey.py (rev
211
  // 476d6ded) by printing signature_data
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 ",
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
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"
231
         "-----END PRIVATE KEY-----\n"
232
};
233
// clang-format on
234

235
/* Ed448.
236
 */
237
// clang-format off
238
static 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

243
  .dsSHA1 = "9712 16 1 "
244
            "2873e800eb2d784cdd1802f884b3c540b573eaa0",
245

246
  .dsSHA256 = "9712 16 2 "
247
              "9aa27306f8a04a0a6fae8affd65d6f35875dcb134c05bd7c7b61bd0dc44009cd",
248

249
  .dsSHA384 = "9712 16 4 "
250
              "3876e5d892d3f31725f9964a332f9b9afd791171833480f2"
251
              "e71af78efb985cde9900ba95315287123a5908ca8f334369",
252

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
  },
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"
294
         "-----END PRIVATE KEY-----\n"
295
};
296
// clang-format on
297

298
struct Fixture
299
{
300
  Fixture()
301
  {
3✔
302
    BOOST_TEST_MESSAGE("All available/supported algorithms:");
3✔
303
    auto pairs = DNSCryptoKeyEngine::listAllAlgosWithBackend();
3✔
304
    for (auto const& pair : pairs) {
24✔
305
      BOOST_TEST_MESSAGE("  " + std::to_string(pair.first) + ": " + pair.second);
24✔
306
    }
24✔
307

308
    BOOST_TEST_MESSAGE("Setting up signer params:");
3✔
309

310
    addSignerParams(DNSSECKeeper::RSASHA256, "RSA SHA256", rsaSha256SignerParams);
3✔
311

312
#ifdef HAVE_LIBCRYPTO_ECDSA
3✔
313
    addSignerParams(DNSSECKeeper::ECDSA256, "ECDSA SHA256", ecdsaSha256);
3✔
314
#endif
3✔
315

316
// We need to have HAVE_LIBCRYPTO_ED25519 for the PEM reader/writer.
317
#if defined(HAVE_LIBCRYPTO_ED25519)
3✔
318
    addSignerParams(DNSSECKeeper::ED25519, "ED25519", ed25519);
3✔
319
#endif
3✔
320

321
#if defined(HAVE_LIBCRYPTO_ED448)
3✔
322
    addSignerParams(DNSSECKeeper::ED448, "ED448", ed448);
3✔
323
#endif
3✔
324
  }
3✔
325

326
  void addSignerParams(const uint8_t algorithm, const std::string& name, const SignerParams& params)
327
  {
12✔
328
    BOOST_TEST_MESSAGE("  " + std::to_string(algorithm) + ": " + name + " (" + params.name + ")");
12✔
329
    signerParams.insert_or_assign(algorithm, params);
12✔
330
  }
12✔
331

332
  const std::string message{"Very good, young padawan."};
333
  std::unordered_map<uint8_t, struct SignerParams> signerParams;
334
};
335

336
static void checkRR(const SignerParams& signer)
337
{
12✔
338
  DNSKEYRecordContent drc;
12✔
339
  auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::makeFromISCString(drc, signer.iscMap));
12✔
340
  DNSSECPrivateKey dpk;
12✔
341
  dpk.setKey(dcke, signer.rfcFlags);
12✔
342

343
  sortedRecords_t rrs;
12✔
344
  /* values taken from rfc8080 for ed25519 and ed448, rfc5933 for gost */
345
  DNSName qname(dpk.getAlgorithm() == DNSSECKeeper::ECCGOST ? "www.example.net." : "example.com.");
12!
346

347
  RRSIGRecordContent rrc;
12✔
348
  uint32_t expire = 1440021600;
12✔
349
  uint32_t inception = 1438207200;
12✔
350

351
  if (dpk.getAlgorithm() == DNSSECKeeper::ECCGOST) {
12!
352
    rrc.d_signer = DNSName("example.net.");
×
353
    inception = 946684800;
×
354
    expire = 1893456000;
×
355
    rrs.insert(DNSRecordContent::make(QType::A, QClass::IN, "192.0.2.1"));
×
356
  }
×
357
  else {
12✔
358
    rrc.d_signer = qname;
12✔
359
    rrs.insert(DNSRecordContent::make(QType::MX, QClass::IN, "10 mail.example.com."));
12✔
360
  }
12✔
361

362
  rrc.d_originalttl = 3600;
12✔
363
  rrc.d_sigexpire = expire;
12✔
364
  rrc.d_siginception = inception;
12✔
365
  rrc.d_type = (*rrs.cbegin())->getType();
12✔
366
  rrc.d_labels = qname.countLabels();
12✔
367
  rrc.d_tag = dpk.getTag();
12✔
368
  rrc.d_algorithm = dpk.getAlgorithm();
12✔
369

370
  string msg = getMessageForRRSET(qname, rrc, rrs, false);
12✔
371

372
  BOOST_CHECK_EQUAL(makeHexDump(msg), signer.rfcMsgDump);
12✔
373

374
  string signature = dcke->sign(msg);
12✔
375

376
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg): Boost stuff.
377
  BOOST_CHECK(dcke->verify(msg, signature));
12✔
378

379
  if (signer.isDeterministic) {
12!
380
    string b64 = Base64Encode(signature);
12✔
381
    BOOST_CHECK_EQUAL(b64, signer.rfcB64Signature);
12✔
382
  }
12✔
383
  else {
×
384
    std::string raw;
×
385
    B64Decode(signer.rfcB64Signature, raw);
×
386
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg): Boost stuff.
387
    BOOST_CHECK(dcke->verify(msg, raw));
×
388
  }
×
389
}
12✔
390

391
static void test_generic_signer(std::shared_ptr<DNSCryptoKeyEngine> dcke, DNSKEYRecordContent& drc, const SignerParams& signer, const std::string& message)
392
{
24✔
393
  BOOST_CHECK_EQUAL(dcke->getAlgorithm(), signer.algorithm);
24✔
394
  BOOST_CHECK_EQUAL(dcke->getBits(), signer.bits);
24✔
395

396
  vector<string> errorMessages{};
24✔
397
  BOOST_CHECK_EQUAL(dcke->checkKey(errorMessages), true);
24✔
398
  if (!errorMessages.empty()) {
24!
399
    BOOST_TEST_MESSAGE("Errors from " + dcke->getName() + " checkKey()");
×
400
    for (auto& errorMessage : errorMessages) {
×
401
      BOOST_TEST_MESSAGE("  " + errorMessage);
×
402
    }
×
403
  }
×
404

405
  BOOST_CHECK_EQUAL(drc.d_algorithm, signer.algorithm);
24✔
406

407
  DNSSECPrivateKey dpk;
24✔
408
  dpk.setKey(dcke, signer.flags);
24✔
409
  drc = dpk.getDNSKEY();
24✔
410

411
  BOOST_CHECK_EQUAL(drc.d_algorithm, signer.algorithm);
24✔
412
  BOOST_CHECK_EQUAL(drc.d_protocol, 3);
24✔
413
  BOOST_CHECK_EQUAL(drc.getZoneRepresentation(), signer.zoneRepresentation);
24✔
414

415
  DNSName name(signer.name);
24✔
416
  auto ds1 = makeDSFromDNSKey(name, drc, DNSSECKeeper::DIGEST_SHA1);
24✔
417
  if (!signer.dsSHA1.empty()) {
24!
418
    BOOST_CHECK_EQUAL(ds1.getZoneRepresentation(), signer.dsSHA1);
24✔
419
  }
24✔
420

421
  auto ds2 = makeDSFromDNSKey(name, drc, DNSSECKeeper::DIGEST_SHA256);
24✔
422
  if (!signer.dsSHA256.empty()) {
24!
423
    BOOST_CHECK_EQUAL(ds2.getZoneRepresentation(), signer.dsSHA256);
24✔
424
  }
24✔
425

426
  auto ds4 = makeDSFromDNSKey(name, drc, DNSSECKeeper::DIGEST_SHA384);
24✔
427
  if (!signer.dsSHA384.empty()) {
24!
428
    BOOST_CHECK_EQUAL(ds4.getZoneRepresentation(), signer.dsSHA384);
24✔
429
  }
24✔
430

431
  auto signature = dcke->sign(message);
24✔
432
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg): Boost stuff.
433
  BOOST_CHECK(dcke->verify(message, signature));
24✔
434

435
  auto signerSignature = std::string(signer.signature.begin(), signer.signature.end());
24✔
436
  if (signer.isDeterministic) {
24✔
437
    auto signatureBase64 = Base64Encode(signature);
18✔
438
    auto signerSignatureBase64 = Base64Encode(signerSignature);
18✔
439
    BOOST_CHECK_EQUAL(signatureBase64, signerSignatureBase64);
18✔
440
  }
18✔
441
  else {
6✔
442
    /* since the signing process is not deterministic, we can't directly compare our signature
443
       with the one we have. Still the one we have should also validate correctly. */
444
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg): Boost stuff.
445
    BOOST_CHECK(dcke->verify(message, signerSignature));
6✔
446
  }
6✔
447

448
  if (!signer.rfcMsgDump.empty() && !signer.rfcB64Signature.empty()) {
24!
449
    checkRR(signer);
12✔
450
  }
12✔
451
}
24✔
452

453
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables,readability-identifier-length): Boost stuff.
454
BOOST_FIXTURE_TEST_CASE(test_generic_signers, Fixture)
455
{
3✔
456
  for (const auto& algoSignerPair : signerParams) {
12✔
457
    auto signer = algoSignerPair.second;
12✔
458

459
    DNSKEYRecordContent drc;
12✔
460
    auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::makeFromISCString(drc, signer.iscMap));
12✔
461
    test_generic_signer(dcke, drc, signer, message);
12✔
462

463
    DNSKEYRecordContent pemDRC;
12✔
464
    shared_ptr<DNSCryptoKeyEngine> pemKey{DNSCryptoKeyEngine::makeFromPEMString(pemDRC, signer.algorithm, signer.pem)};
12✔
465

466
    BOOST_CHECK_EQUAL(pemKey->convertToISC(), dcke->convertToISC());
12✔
467

468
    test_generic_signer(pemKey, pemDRC, signer, message);
12✔
469

470
    auto dckePEMOutput = dcke->convertToPEMString();
12✔
471
    BOOST_CHECK_EQUAL(dckePEMOutput, signer.pem);
12✔
472

473
    auto pemKeyOutput = pemKey->convertToPEMString();
12✔
474
    BOOST_CHECK_EQUAL(pemKeyOutput, signer.pem);
12✔
475
  }
12✔
476
}
3✔
477

478
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables,readability-identifier-length): Boost stuff.
479
BOOST_AUTO_TEST_CASE(test_hash_qname_with_salt)
480
{
3✔
481
  {
3✔
482
    // rfc5155 appendix A
483
    const unsigned char salt[] = {0xaa, 0xbb, 0xcc, 0xdd};
3✔
484
    const unsigned int iterations{12};
3✔
485
    const std::vector<std::pair<std::string, std::string>> namesToHashes = {
3✔
486
      {"example", "0p9mhaveqvm6t7vbl5lop2u3t2rp3tom"},
3✔
487
      {"a.example", "35mthgpgcu1qg68fab165klnsnk3dpvl"},
3✔
488
      {"ai.example", "gjeqe526plbf1g8mklp59enfd789njgi"},
3✔
489
      {"ns1.example", "2t7b4g4vsa5smi47k61mv5bv1a22bojr"},
3✔
490
      {"ns2.example", "q04jkcevqvmu85r014c7dkba38o0ji5r"},
3✔
491
      {"w.example", "k8udemvp1j2f7eg6jebps17vp3n8i58h"},
3✔
492
      {"*.w.example", "r53bq7cc2uvmubfu5ocmm6pers9tk9en"},
3✔
493
      {"x.w.example", "b4um86eghhds6nea196smvmlo4ors995"},
3✔
494
      {"y.w.example", "ji6neoaepv8b5o6k4ev33abha8ht9fgc"},
3✔
495
      {"x.y.w.example", "2vptu5timamqttgl4luu9kg21e0aor3s"},
3✔
496
      {"xx.example", "t644ebqk9bibcna874givr6joj62mlhv"},
3✔
497
      {"2t7b4g4vsa5smi47k61mv5bv1a22bojr.example", "kohar7mbb8dc2ce8a9qvl8hon4k53uhi"},
3✔
498
    };
3✔
499

500
    for (const auto& [name, expectedHash] : namesToHashes) {
36✔
501
      auto hash = hashQNameWithSalt(std::string(reinterpret_cast<const char*>(salt), sizeof(salt)), iterations, DNSName(name));
36✔
502
      BOOST_CHECK_EQUAL(toBase32Hex(hash), expectedHash);
36✔
503
    }
36✔
504
  }
3✔
505

506
  {
3✔
507
    /* no additional iterations, very short salt */
508
    const unsigned char salt[] = {0xFF};
3✔
509
    const unsigned int iterations{0};
3✔
510
    const std::vector<std::pair<std::string, std::string>> namesToHashes = {
3✔
511
      {"example", "s9dp8o2l6jgqgg26ecobtjooe7p019cs"},
3✔
512
    };
3✔
513

514
    for (const auto& [name, expectedHash] : namesToHashes) {
3✔
515
      auto hash = hashQNameWithSalt(std::string(reinterpret_cast<const char*>(salt), sizeof(salt)), iterations, DNSName(name));
3✔
516
      BOOST_CHECK_EQUAL(toBase32Hex(hash), expectedHash);
3✔
517
    }
3✔
518
  }
3✔
519

520
  {
3✔
521
    /* only one iteration */
522
    const unsigned char salt[] = {0xaa, 0xbb, 0xcc, 0xdd};
3✔
523
    const unsigned int iterations{1};
3✔
524
    const std::vector<std::pair<std::string, std::string>> namesToHashes = {
3✔
525
      {"example", "ulddquehrj5jpf50ga76vgqr1oq40133"},
3✔
526
    };
3✔
527

528
    for (const auto& [name, expectedHash] : namesToHashes) {
3✔
529
      auto hash = hashQNameWithSalt(std::string(reinterpret_cast<const char*>(salt), sizeof(salt)), iterations, DNSName(name));
3✔
530
      BOOST_CHECK_EQUAL(toBase32Hex(hash), expectedHash);
3✔
531
    }
3✔
532
  }
3✔
533

534
  {
3✔
535
    /* 65535 iterations, long salt */
536
    unsigned char salt[255];
3✔
537
    for (unsigned char idx = 0; idx < 255; idx++) {
768✔
538
      salt[idx] = idx;
765✔
539
    };
765✔
540
    const unsigned int iterations{65535};
3✔
541
    const std::vector<std::pair<std::string, std::string>> namesToHashes = {
3✔
542
      {"example", "no95j4cfile8avstr7bn4aj9he18trri"},
3✔
543
    };
3✔
544

545
    for (const auto& [name, expectedHash] : namesToHashes) {
3✔
546
      auto hash = hashQNameWithSalt(std::string(reinterpret_cast<const char*>(salt), sizeof(salt)), iterations, DNSName(name));
3✔
547
      BOOST_CHECK_EQUAL(toBase32Hex(hash), expectedHash);
3✔
548
    }
3✔
549
  }
3✔
550
}
3✔
551

552
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables): Boost stuff.
553
BOOST_AUTO_TEST_SUITE_END()
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc