]>
Commit | Line | Data |
---|---|---|
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 |
23 | BOOST_AUTO_TEST_SUITE(test_signers) |
24 | ||
87066241 | 25 | struct 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 |
45 | static 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 |
122 | static 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 | 183 | static 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 |
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 | ||
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 | 298 | struct 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 | 336 | static 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 | 393 | static 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 | 456 | BOOST_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 |
481 | BOOST_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 | 555 | BOOST_AUTO_TEST_SUITE_END() |