]>
Commit | Line | Data |
---|---|---|
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> | |
22de9dc8 PD |
10 | |
11 | #include "base64.hh" | |
12 | #include "dnsseckeeper.hh" | |
13 | #include "dnssecinfra.hh" | |
14 | #include "misc.hh" | |
22de9dc8 PD |
15 | BOOST_AUTO_TEST_SUITE(test_signers) |
16 | ||
620d4801 RG |
17 | static const std::string message = "Very good, young padawan."; |
18 | ||
19 | static const struct signerParams | |
20 | { | |
21 | std::string iscMap; | |
22 | std::string dsSHA1; | |
23 | std::string dsSHA256; | |
24 | std::string dsSHA384; | |
25 | std::vector<uint8_t> signature; | |
26 | std::string zoneRepresentation; | |
27 | std::string name; | |
28 | std::string rfcMsgDump; | |
29 | std::string rfcB64Signature; | |
690b86b7 | 30 | int bits; |
620d4801 RG |
31 | uint16_t flags; |
32 | uint16_t rfcFlags; | |
33 | uint8_t algorithm; | |
34 | bool isDeterministic; | |
35 | } signers[] = { | |
36 | /* RSA from https://github.com/CZ-NIC/knot/blob/master/src/dnssec/tests/sample_keys.h */ | |
37 | { "Algorithm: 8\n" | |
38 | "Modulus: qtunSiHnYq4XRLBehKAw1Glxb+48oIpAC7w3Jhpj570bb2uHt6orWGqnuyRtK8oqUi2ABoV0PFm8+IPgDMEdCQ==\n" | |
39 | "PublicExponent: AQAB\n" | |
40 | "PrivateExponent: MiItniUAngXzMeaGdWgDq/AcpvlCtOCcFlVt4TJRKkfp8DNRSxIxG53NNlOFkp1W00iLHqYC2GrH1qkKgT9l+Q==\n" | |
41 | "Prime1: 3sZmM+5FKFy5xaRt0n2ZQOZ2C+CoKzVil6/al9LmYVs=\n" | |
42 | "Prime2: xFcNWSIW6v8dDL2JQ1kxFDm/8RVeUSs1BNXXnvCjBGs=\n" | |
43 | "Exponent1: WuUwhjfN1+4djlrMxHmisixWNfpwI1Eg7Ss/UXsnrMk=\n" | |
44 | "Exponent2: vfMqas1cNsXRqP3Fym6D2Pl2BRuTQBv5E1B/ZrmQPTk=\n" | |
45 | "Coefficient: Q10z43cA3hkwOkKsj5T0W5jrX97LBwZoY5lIjDCa4+M=\n", | |
46 | "1506 8 1 172a500b374158d1a64ba3073cdbbc319b2fdf2c", | |
47 | "1506 8 2 253b099ff47b02c6ffa52695a30a94c6681c56befe0e71a5077d6f79514972f9", | |
48 | "1506 8 4 22ea940600dc2d9a98b1126c26ac0dc5c91b31eb50fe784b36ad675e9eecfe6573c1f85c53b6bc94580f3ac443d13c4c", | |
49 | /* from https://github.com/CZ-NIC/knot/blob/master/src/dnssec/tests/sign.c */ | |
50 | { 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 }, | |
51 | "256 3 8 AwEAAarbp0oh52KuF0SwXoSgMNRpcW/uPKCKQAu8NyYaY+e9G29rh7eqK1hqp7skbSvKKlItgAaFdDxZvPiD4AzBHQk=", | |
52 | "rsa.", | |
53 | "", | |
54 | "", | |
55 | 512, | |
56 | 256, | |
57 | 0, | |
58 | DNSSECKeeper::RSASHA256, | |
59 | true | |
60 | }, | |
620d4801 RG |
61 | #ifdef HAVE_LIBCRYPTO_ECDSA |
62 | /* ECDSA-P256-SHA256 from https://github.com/CZ-NIC/knot/blob/master/src/dnssec/tests/sample_keys.h */ | |
63 | { "Algorithm: 13\n" | |
64 | "PrivateKey: iyLIPdk3DOIxVmmSYlmTstbtUPiVlEyDX46psyCwNVQ=\n", | |
65 | "5345 13 1 954103ac7c43810ce9f414e80f30ab1cbe49b236", | |
66 | "5345 13 2 bac2107036e735b50f85006ce409a19a3438cab272e70769ebda032239a3d0ca", | |
67 | "5345 13 4 a0ac6790483872be72a258314200a88ab75cdd70f66a18a09f0f414c074df0989fdb1df0e67d82d4312cda67b93a76c1", | |
68 | /* from https://github.com/CZ-NIC/knot/blob/master/src/dnssec/tests/sign.c */ | |
69 | { 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, }, | |
70 | "256 3 13 8uD7C4THTM/w7uhryRSToeE/jKT78/p853RX0L5EwrZrSLBubLPiBw7gbvUP6SsIga5ZQ4CSAxNmYA/gZsuXzA==", | |
71 | "ecdsa.", | |
72 | "", | |
73 | "", | |
74 | 256, | |
75 | 256, | |
76 | 0, | |
77 | DNSSECKeeper::ECDSA256, | |
78 | false | |
79 | }, | |
80 | #endif /* HAVE_LIBCRYPTO_ECDSA */ | |
439974d7 | 81 | #if defined(HAVE_LIBSODIUM) || defined(HAVE_LIBDECAF) || defined(HAVE_LIBCRYPTO_ED25519) |
620d4801 RG |
82 | /* ed25519 from https://github.com/CZ-NIC/knot/blob/master/src/dnssec/tests/sample_keys.h, |
83 | also from rfc8080 section 6.1 */ | |
84 | { "Algorithm: 15\n" | |
85 | "PrivateKey: ODIyNjAzODQ2MjgwODAxMjI2NDUxOTAyMDQxNDIyNjI=\n", | |
86 | "3612 15 1 501249721e1f09a79d30d5c6c4dca1dc1da4ed5d", | |
87 | "3612 15 2 1b1c8766b2a96566ff196f77c0c4194af86aaa109c5346ff60231a27d2b07ac0", | |
88 | "3612 15 4 d11831153af4985efbd0ae792c967eb4aff3c35488db95f7e2f85dcec74ae8f59f9a72641798c91c67c675db1d710c18", | |
89 | /* from https://github.com/CZ-NIC/knot/blob/master/src/dnssec/tests/sign.c */ | |
90 | { 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 }, | |
91 | "256 3 15 l02Woi0iS8Aa25FQkUd9RMzZHJpBoRQwAQEX1SxZJA4=", | |
92 | "ed25519.", | |
93 | // vector extracted from https://gitlab.labs.nic.cz/labs/ietf/blob/master/dnskey.py (rev 476d6ded) by printing signature_data | |
94 | "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 ", | |
95 | // vector verified from dnskey.py as above, and confirmed with https://www.rfc-editor.org/errata_search.php?rfc=8080&eid=4935 | |
96 | "oL9krJun7xfBOIWcGHi7mag5/hdZrKWw15jPGrHpjQeRAvTdszaPD+QLs3fx8A4M3e23mRZ9VrbpMngwcrqNAg==", | |
97 | 256, | |
98 | 256, | |
99 | 257, | |
100 | DNSSECKeeper::ED25519, | |
101 | true | |
102 | }, | |
439974d7 | 103 | #endif /* defined(HAVE_LIBSODIUM) || defined(HAVE_LIBDECAF) || defined(HAVE_LIBCRYPTO_ED25519) */ |
620d4801 | 104 | }; |
22de9dc8 | 105 | |
620d4801 RG |
106 | static void checkRR(const signerParams& signer) |
107 | { | |
108 | DNSKEYRecordContent drc; | |
109 | auto dcke = DNSCryptoKeyEngine::makeFromISCString(drc, signer.iscMap); | |
110 | DNSSECPrivateKey dpk; | |
111 | dpk.setKey(dcke); | |
112 | dpk.d_flags = signer.rfcFlags; | |
22de9dc8 | 113 | |
c1e7b833 | 114 | sortedRecords_t rrs; |
620d4801 RG |
115 | /* values taken from rfc8080 for ed25519 and ed448, rfc5933 for gost */ |
116 | DNSName qname(dpk.d_algorithm == 12 ? "www.example.net." : "example.com."); | |
22de9dc8 | 117 | |
620d4801 | 118 | reportBasicTypes(); |
22de9dc8 | 119 | |
620d4801 RG |
120 | RRSIGRecordContent rrc; |
121 | uint32_t expire = 1440021600; | |
122 | uint32_t inception = 1438207200; | |
22de9dc8 | 123 | |
620d4801 RG |
124 | if (dpk.d_algorithm == 12) { |
125 | rrc.d_signer = DNSName("example.net."); | |
126 | inception = 946684800; | |
127 | expire = 1893456000; | |
c1e7b833 | 128 | rrs.insert(DNSRecordContent::mastermake(QType::A, QClass::IN, "192.0.2.1")); |
620d4801 RG |
129 | } |
130 | else { | |
22de9dc8 | 131 | rrc.d_signer = qname; |
c1e7b833 | 132 | rrs.insert(DNSRecordContent::mastermake(QType::MX, QClass::IN, "10 mail.example.com.")); |
620d4801 | 133 | } |
22de9dc8 | 134 | |
620d4801 RG |
135 | rrc.d_originalttl = 3600; |
136 | rrc.d_sigexpire = expire; | |
137 | rrc.d_siginception = inception; | |
c1e7b833 | 138 | rrc.d_type = (*rrs.cbegin())->getType(); |
620d4801 RG |
139 | rrc.d_labels = qname.countLabels(); |
140 | rrc.d_tag = dpk.getTag(); | |
141 | rrc.d_algorithm = dpk.d_algorithm; | |
22de9dc8 | 142 | |
620d4801 RG |
143 | string msg = getMessageForRRSET(qname, rrc, rrs, false); |
144 | ||
145 | BOOST_CHECK_EQUAL(makeHexDump(msg), signer.rfcMsgDump); | |
146 | ||
147 | string signature = dcke->sign(msg); | |
22de9dc8 | 148 | |
620d4801 RG |
149 | BOOST_CHECK(dcke->verify(msg, signature)); |
150 | ||
151 | if (signer.isDeterministic) { | |
22de9dc8 | 152 | string b64 = Base64Encode(signature); |
620d4801 RG |
153 | BOOST_CHECK_EQUAL(b64, signer.rfcB64Signature); |
154 | } | |
155 | else { | |
156 | std::string raw; | |
157 | B64Decode(signer.rfcB64Signature, raw); | |
158 | BOOST_CHECK(dcke->verify(msg, raw)); | |
159 | } | |
160 | } | |
22de9dc8 | 161 | |
620d4801 RG |
162 | BOOST_AUTO_TEST_CASE(test_generic_signers) |
163 | { | |
aa93edd5 | 164 | for (const auto& signer : signers) { |
620d4801 RG |
165 | DNSKEYRecordContent drc; |
166 | auto dcke = DNSCryptoKeyEngine::makeFromISCString(drc, signer.iscMap); | |
167 | ||
168 | BOOST_CHECK_EQUAL(dcke->getAlgorithm(), signer.algorithm); | |
169 | BOOST_CHECK_EQUAL(dcke->getBits(), signer.bits); | |
ac3f3893 | 170 | BOOST_CHECK_EQUAL(dcke->checkKey(nullptr), true); |
620d4801 RG |
171 | |
172 | BOOST_CHECK_EQUAL(drc.d_algorithm, signer.algorithm); | |
173 | ||
174 | DNSSECPrivateKey dpk; | |
175 | dpk.setKey(dcke); | |
176 | dpk.d_flags = signer.flags; | |
177 | drc = dpk.getDNSKEY(); | |
178 | ||
179 | BOOST_CHECK_EQUAL(drc.d_algorithm, signer.algorithm); | |
180 | BOOST_CHECK_EQUAL(drc.d_protocol, 3); | |
181 | BOOST_CHECK_EQUAL(drc.getZoneRepresentation(), signer.zoneRepresentation); | |
182 | ||
183 | DNSName name(signer.name); | |
690b86b7 | 184 | auto ds1 = makeDSFromDNSKey(name, drc, DNSSECKeeper::DIGEST_SHA1); |
620d4801 RG |
185 | if (!signer.dsSHA1.empty()) { |
186 | BOOST_CHECK_EQUAL(ds1.getZoneRepresentation(), signer.dsSHA1); | |
187 | } | |
188 | ||
690b86b7 | 189 | auto ds2 = makeDSFromDNSKey(name, drc, DNSSECKeeper::DIGEST_SHA256); |
620d4801 RG |
190 | if (!signer.dsSHA256.empty()) { |
191 | BOOST_CHECK_EQUAL(ds2.getZoneRepresentation(), signer.dsSHA256); | |
192 | } | |
193 | ||
690b86b7 | 194 | auto ds4 = makeDSFromDNSKey(name, drc, DNSSECKeeper::DIGEST_SHA384); |
620d4801 RG |
195 | if (!signer.dsSHA384.empty()) { |
196 | BOOST_CHECK_EQUAL(ds4.getZoneRepresentation(), signer.dsSHA384); | |
197 | } | |
198 | ||
199 | auto signature = dcke->sign(message); | |
200 | BOOST_CHECK(dcke->verify(message, signature)); | |
201 | ||
202 | if (signer.isDeterministic) { | |
203 | BOOST_CHECK_EQUAL(signature, std::string(signer.signature.begin(), signer.signature.end())); | |
204 | } else { | |
205 | /* since the signing process is not deterministic, we can't directly compare our signature | |
206 | with the one we have. Still the one we have should also validate correctly. */ | |
207 | BOOST_CHECK(dcke->verify(message, std::string(signer.signature.begin(), signer.signature.end()))); | |
208 | } | |
209 | ||
210 | if (!signer.rfcMsgDump.empty() && !signer.rfcB64Signature.empty()) { | |
211 | checkRR(signer); | |
212 | } | |
213 | } | |
22de9dc8 | 214 | } |
22de9dc8 | 215 | |
439974d7 | 216 | #if defined(HAVE_LIBDECAF) || defined(HAVE_LIBCRYPTO_ED448) |
2b7da695 | 217 | BOOST_AUTO_TEST_CASE(test_ed448_signer) { |
c1e7b833 | 218 | sortedRecords_t rrs; |
2b7da695 KM |
219 | DNSName qname("example.com."); |
220 | DNSKEYRecordContent drc; | |
221 | ||
222 | // TODO: make this a collection of inputs and resulting sigs for various algos | |
223 | shared_ptr<DNSCryptoKeyEngine> engine = DNSCryptoKeyEngine::makeFromISCString(drc, | |
224 | "Private-key-format: v1.2\n" | |
225 | "Algorithm: 16 (ED448)\n" | |
226 | "PrivateKey: xZ+5Cgm463xugtkY5B0Jx6erFTXp13rYegst0qRtNsOYnaVpMx0Z/c5EiA9x8wWbDDct/U3FhYWA\n"); | |
227 | ||
228 | DNSSECPrivateKey dpk; | |
229 | dpk.setKey(engine); | |
230 | ||
231 | reportBasicTypes(); | |
232 | ||
c1e7b833 | 233 | rrs.insert(DNSRecordContent::mastermake(QType::MX, 1, "10 mail.example.com.")); |
2b7da695 KM |
234 | |
235 | RRSIGRecordContent rrc; | |
236 | rrc.d_originalttl = 3600; | |
237 | rrc.d_sigexpire = 1440021600; | |
238 | rrc.d_siginception = 1438207200; | |
239 | rrc.d_signer = qname; | |
240 | rrc.d_type = QType::MX; | |
241 | rrc.d_labels = 2; | |
242 | // TODO: derive the next two from the key | |
243 | rrc.d_tag = 9713; | |
244 | rrc.d_algorithm = 16; | |
245 | ||
246 | string msg = getMessageForRRSET(qname, rrc, rrs, false); | |
247 | ||
248 | // vector extracted from https://gitlab.labs.nic.cz/labs/ietf/blob/master/dnskey.py (rev 476d6ded) by printing signature_data | |
249 | 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 "); | |
250 | ||
251 | string signature = engine->sign(msg); | |
252 | string b64 = Base64Encode(signature); | |
253 | ||
254 | // vector verified from dnskey.py as above, and confirmed with https://www.rfc-editor.org/errata_search.php?rfc=8080&eid=4935 | |
255 | BOOST_CHECK_EQUAL(b64, "3cPAHkmlnxcDHMyg7vFC34l0blBhuG1qpwLmjInI8w1CMB29FkEAIJUA0amxWndkmnBZ6SKiwZSAxGILn/NBtOXft0+Gj7FSvOKxE/07+4RQvE581N3Aj/JtIyaiYVdnYtyMWbSNyGEY2213WKsJlwEA"); | |
256 | } | |
439974d7 | 257 | #endif /* defined(HAVE_LIBDECAF) || defined(HAVE_LIBCRYPTO_ED448) */ |
2b7da695 | 258 | |
22de9dc8 | 259 | BOOST_AUTO_TEST_SUITE_END() |