1 // Copyright (c) 1999-2010 Brian Wellington (bwelling@xbill.org)
2
3 package org.xbill.DNS;
4
5 import java.io.*;
6 import java.math.*;
7 import java.security.*;
8 import java.security.interfaces.*;
9 import java.security.spec.*;
10 import java.util.*;
11
12 /**
13 * Constants and methods relating to DNSSEC.
14 *
15 * DNSSEC provides authentication for DNS information.
16 * @see RRSIGRecord
17 * @see DNSKEYRecord
18 * @see RRset
19 *
20 * @author Brian Wellington
21 */
22
23 public class DNSSEC {
24
25 public static class Algorithm {
Algorithm()26 private Algorithm() {}
27
28 /** RSA/MD5 public key (deprecated) */
29 public static final int RSAMD5 = 1;
30
31 /** Diffie Hellman key */
32 public static final int DH = 2;
33
34 /** DSA public key */
35 public static final int DSA = 3;
36
37 /** RSA/SHA1 public key */
38 public static final int RSASHA1 = 5;
39
40 /** DSA/SHA1, NSEC3-aware public key */
41 public static final int DSA_NSEC3_SHA1 = 6;
42
43 /** RSA/SHA1, NSEC3-aware public key */
44 public static final int RSA_NSEC3_SHA1 = 7;
45
46 /** RSA/SHA256 public key */
47 public static final int RSASHA256 = 8;
48
49 /** RSA/SHA512 public key */
50 public static final int RSASHA512 = 10;
51
52 /** ECDSA Curve P-256 with SHA-256 public key **/
53 public static final int ECDSAP256SHA256 = 13;
54
55 /** ECDSA Curve P-384 with SHA-384 public key **/
56 public static final int ECDSAP384SHA384 = 14;
57
58 /** Indirect keys; the actual key is elsewhere. */
59 public static final int INDIRECT = 252;
60
61 /** Private algorithm, specified by domain name */
62 public static final int PRIVATEDNS = 253;
63
64 /** Private algorithm, specified by OID */
65 public static final int PRIVATEOID = 254;
66
67 private static Mnemonic algs = new Mnemonic("DNSSEC algorithm",
68 Mnemonic.CASE_UPPER);
69
70 static {
71 algs.setMaximum(0xFF);
72 algs.setNumericAllowed(true);
73
algs.add(RSAMD5, "RSAMD5")74 algs.add(RSAMD5, "RSAMD5");
algs.add(DH, "DH")75 algs.add(DH, "DH");
algs.add(DSA, "DSA")76 algs.add(DSA, "DSA");
algs.add(RSASHA1, "RSASHA1")77 algs.add(RSASHA1, "RSASHA1");
algs.add(DSA_NSEC3_SHA1, "DSA-NSEC3-SHA1")78 algs.add(DSA_NSEC3_SHA1, "DSA-NSEC3-SHA1");
algs.add(RSA_NSEC3_SHA1, "RSA-NSEC3-SHA1")79 algs.add(RSA_NSEC3_SHA1, "RSA-NSEC3-SHA1");
algs.add(RSASHA256, "RSASHA256")80 algs.add(RSASHA256, "RSASHA256");
algs.add(RSASHA512, "RSASHA512")81 algs.add(RSASHA512, "RSASHA512");
algs.add(ECDSAP256SHA256, "ECDSAP256SHA256")82 algs.add(ECDSAP256SHA256, "ECDSAP256SHA256");
algs.add(ECDSAP384SHA384, "ECDSAP384SHA384")83 algs.add(ECDSAP384SHA384, "ECDSAP384SHA384");
algs.add(INDIRECT, "INDIRECT")84 algs.add(INDIRECT, "INDIRECT");
algs.add(PRIVATEDNS, "PRIVATEDNS")85 algs.add(PRIVATEDNS, "PRIVATEDNS");
algs.add(PRIVATEOID, "PRIVATEOID")86 algs.add(PRIVATEOID, "PRIVATEOID");
87 }
88
89 /**
90 * Converts an algorithm into its textual representation
91 */
92 public static String
string(int alg)93 string(int alg) {
94 return algs.getText(alg);
95 }
96
97 /**
98 * Converts a textual representation of an algorithm into its numeric
99 * code. Integers in the range 0..255 are also accepted.
100 * @param s The textual representation of the algorithm
101 * @return The algorithm code, or -1 on error.
102 */
103 public static int
value(String s)104 value(String s) {
105 return algs.getValue(s);
106 }
107 }
108
109 private
DNSSEC()110 DNSSEC() { }
111
112 private static void
digestSIG(DNSOutput out, SIGBase sig)113 digestSIG(DNSOutput out, SIGBase sig) {
114 out.writeU16(sig.getTypeCovered());
115 out.writeU8(sig.getAlgorithm());
116 out.writeU8(sig.getLabels());
117 out.writeU32(sig.getOrigTTL());
118 out.writeU32(sig.getExpire().getTime() / 1000);
119 out.writeU32(sig.getTimeSigned().getTime() / 1000);
120 out.writeU16(sig.getFootprint());
121 sig.getSigner().toWireCanonical(out);
122 }
123
124 /**
125 * Creates a byte array containing the concatenation of the fields of the
126 * SIG record and the RRsets to be signed/verified. This does not perform
127 * a cryptographic digest.
128 * @param rrsig The RRSIG record used to sign/verify the rrset.
129 * @param rrset The data to be signed/verified.
130 * @return The data to be cryptographically signed or verified.
131 */
132 public static byte []
digestRRset(RRSIGRecord rrsig, RRset rrset)133 digestRRset(RRSIGRecord rrsig, RRset rrset) {
134 DNSOutput out = new DNSOutput();
135 digestSIG(out, rrsig);
136
137 int size = rrset.size();
138 Record [] records = new Record[size];
139
140 Iterator it = rrset.rrs();
141 Name name = rrset.getName();
142 Name wild = null;
143 int sigLabels = rrsig.getLabels() + 1; // Add the root label back.
144 if (name.labels() > sigLabels)
145 wild = name.wild(name.labels() - sigLabels);
146 while (it.hasNext())
147 records[--size] = (Record) it.next();
148 Arrays.sort(records);
149
150 DNSOutput header = new DNSOutput();
151 if (wild != null)
152 wild.toWireCanonical(header);
153 else
154 name.toWireCanonical(header);
155 header.writeU16(rrset.getType());
156 header.writeU16(rrset.getDClass());
157 header.writeU32(rrsig.getOrigTTL());
158 for (int i = 0; i < records.length; i++) {
159 out.writeByteArray(header.toByteArray());
160 int lengthPosition = out.current();
161 out.writeU16(0);
162 out.writeByteArray(records[i].rdataToWireCanonical());
163 int rrlength = out.current() - lengthPosition - 2;
164 out.save();
165 out.jump(lengthPosition);
166 out.writeU16(rrlength);
167 out.restore();
168 }
169 return out.toByteArray();
170 }
171
172 /**
173 * Creates a byte array containing the concatenation of the fields of the
174 * SIG(0) record and the message to be signed. This does not perform
175 * a cryptographic digest.
176 * @param sig The SIG record used to sign the rrset.
177 * @param msg The message to be signed.
178 * @param previous If this is a response, the signature from the query.
179 * @return The data to be cryptographically signed.
180 */
181 public static byte []
digestMessage(SIGRecord sig, Message msg, byte [] previous)182 digestMessage(SIGRecord sig, Message msg, byte [] previous) {
183 DNSOutput out = new DNSOutput();
184 digestSIG(out, sig);
185
186 if (previous != null)
187 out.writeByteArray(previous);
188
189 msg.toWire(out);
190 return out.toByteArray();
191 }
192
193 /**
194 * A DNSSEC exception.
195 */
196 public static class DNSSECException extends Exception {
DNSSECException(String s)197 DNSSECException(String s) {
198 super(s);
199 }
200 }
201
202 /**
203 * An algorithm is unsupported by this DNSSEC implementation.
204 */
205 public static class UnsupportedAlgorithmException extends DNSSECException {
UnsupportedAlgorithmException(int alg)206 UnsupportedAlgorithmException(int alg) {
207 super("Unsupported algorithm: " + alg);
208 }
209 }
210
211 /**
212 * The cryptographic data in a DNSSEC key is malformed.
213 */
214 public static class MalformedKeyException extends DNSSECException {
MalformedKeyException(KEYBase rec)215 MalformedKeyException(KEYBase rec) {
216 super("Invalid key data: " + rec.rdataToString());
217 }
218 }
219
220 /**
221 * A DNSSEC verification failed because fields in the DNSKEY and RRSIG records
222 * do not match.
223 */
224 public static class KeyMismatchException extends DNSSECException {
225 private KEYBase key;
226 private SIGBase sig;
227
KeyMismatchException(KEYBase key, SIGBase sig)228 KeyMismatchException(KEYBase key, SIGBase sig) {
229 super("key " +
230 key.getName() + "/" +
231 DNSSEC.Algorithm.string(key.getAlgorithm()) + "/" +
232 key.getFootprint() + " " +
233 "does not match signature " +
234 sig.getSigner() + "/" +
235 DNSSEC.Algorithm.string(sig.getAlgorithm()) + "/" +
236 sig.getFootprint());
237 }
238 }
239
240 /**
241 * A DNSSEC verification failed because the signature has expired.
242 */
243 public static class SignatureExpiredException extends DNSSECException {
244 private Date when, now;
245
SignatureExpiredException(Date when, Date now)246 SignatureExpiredException(Date when, Date now) {
247 super("signature expired");
248 this.when = when;
249 this.now = now;
250 }
251
252 /**
253 * @return When the signature expired
254 */
255 public Date
getExpiration()256 getExpiration() {
257 return when;
258 }
259
260 /**
261 * @return When the verification was attempted
262 */
263 public Date
getVerifyTime()264 getVerifyTime() {
265 return now;
266 }
267 }
268
269 /**
270 * A DNSSEC verification failed because the signature has not yet become valid.
271 */
272 public static class SignatureNotYetValidException extends DNSSECException {
273 private Date when, now;
274
SignatureNotYetValidException(Date when, Date now)275 SignatureNotYetValidException(Date when, Date now) {
276 super("signature is not yet valid");
277 this.when = when;
278 this.now = now;
279 }
280
281 /**
282 * @return When the signature will become valid
283 */
284 public Date
getExpiration()285 getExpiration() {
286 return when;
287 }
288
289 /**
290 * @return When the verification was attempted
291 */
292 public Date
getVerifyTime()293 getVerifyTime() {
294 return now;
295 }
296 }
297
298 /**
299 * A DNSSEC verification failed because the cryptographic signature
300 * verification failed.
301 */
302 public static class SignatureVerificationException extends DNSSECException {
SignatureVerificationException()303 SignatureVerificationException() {
304 super("signature verification failed");
305 }
306 }
307
308 /**
309 * The key data provided is inconsistent.
310 */
311 public static class IncompatibleKeyException extends IllegalArgumentException {
IncompatibleKeyException()312 IncompatibleKeyException() {
313 super("incompatible keys");
314 }
315 }
316
317 private static int
BigIntegerLength(BigInteger i)318 BigIntegerLength(BigInteger i) {
319 return (i.bitLength() + 7) / 8;
320 }
321
322 private static BigInteger
readBigInteger(DNSInput in, int len)323 readBigInteger(DNSInput in, int len) throws IOException {
324 byte [] b = in.readByteArray(len);
325 return new BigInteger(1, b);
326 }
327
328 private static BigInteger
readBigInteger(DNSInput in)329 readBigInteger(DNSInput in) {
330 byte [] b = in.readByteArray();
331 return new BigInteger(1, b);
332 }
333
334 private static void
writeBigInteger(DNSOutput out, BigInteger val)335 writeBigInteger(DNSOutput out, BigInteger val) {
336 byte [] b = val.toByteArray();
337 if (b[0] == 0)
338 out.writeByteArray(b, 1, b.length - 1);
339 else
340 out.writeByteArray(b);
341 }
342
343 private static PublicKey
toRSAPublicKey(KEYBase r)344 toRSAPublicKey(KEYBase r) throws IOException, GeneralSecurityException {
345 DNSInput in = new DNSInput(r.getKey());
346 int exponentLength = in.readU8();
347 if (exponentLength == 0)
348 exponentLength = in.readU16();
349 BigInteger exponent = readBigInteger(in, exponentLength);
350 BigInteger modulus = readBigInteger(in);
351
352 KeyFactory factory = KeyFactory.getInstance("RSA");
353 return factory.generatePublic(new RSAPublicKeySpec(modulus, exponent));
354 }
355
356 private static PublicKey
toDSAPublicKey(KEYBase r)357 toDSAPublicKey(KEYBase r) throws IOException, GeneralSecurityException,
358 MalformedKeyException
359 {
360 DNSInput in = new DNSInput(r.getKey());
361
362 int t = in.readU8();
363 if (t > 8)
364 throw new MalformedKeyException(r);
365
366 BigInteger q = readBigInteger(in, 20);
367 BigInteger p = readBigInteger(in, 64 + t*8);
368 BigInteger g = readBigInteger(in, 64 + t*8);
369 BigInteger y = readBigInteger(in, 64 + t*8);
370
371 KeyFactory factory = KeyFactory.getInstance("DSA");
372 return factory.generatePublic(new DSAPublicKeySpec(y, p, q, g));
373 }
374
375 private static class ECKeyInfo {
376 int length;
377 public BigInteger p, a, b, gx, gy, n;
378 EllipticCurve curve;
379 ECParameterSpec spec;
380
ECKeyInfo(int length, String p_str, String a_str, String b_str, String gx_str, String gy_str, String n_str)381 ECKeyInfo(int length, String p_str, String a_str, String b_str,
382 String gx_str, String gy_str, String n_str)
383 {
384 this.length = length;
385 p = new BigInteger(p_str, 16);
386 a = new BigInteger(a_str, 16);
387 b = new BigInteger(b_str, 16);
388 gx = new BigInteger(gx_str, 16);
389 gy = new BigInteger(gy_str, 16);
390 n = new BigInteger(n_str, 16);
391 curve = new EllipticCurve(new ECFieldFp(p), a, b);
392 spec = new ECParameterSpec(curve, new ECPoint(gx, gy), n, 1);
393 }
394 }
395
396 // RFC 5114 Section 2.6
397 private static final ECKeyInfo ECDSA_P256 = new ECKeyInfo(32,
398 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
399 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
400 "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
401 "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
402 "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
403 "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551");
404
405 // RFC 5114 Section 2.7
406 private static final ECKeyInfo ECDSA_P384 = new ECKeyInfo(48,
407 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF",
408 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC",
409 "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF",
410 "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7",
411 "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F",
412 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973");
413
414 private static PublicKey
toECDSAPublicKey(KEYBase r, ECKeyInfo keyinfo)415 toECDSAPublicKey(KEYBase r, ECKeyInfo keyinfo) throws IOException,
416 GeneralSecurityException, MalformedKeyException
417 {
418 DNSInput in = new DNSInput(r.getKey());
419
420 // RFC 6605 Section 4
421 BigInteger x = readBigInteger(in, keyinfo.length);
422 BigInteger y = readBigInteger(in, keyinfo.length);
423 ECPoint q = new ECPoint(x, y);
424
425 KeyFactory factory = KeyFactory.getInstance("EC");
426 return factory.generatePublic(new ECPublicKeySpec(q, keyinfo.spec));
427 }
428
429 /** Converts a KEY/DNSKEY record into a PublicKey */
430 static PublicKey
toPublicKey(KEYBase r)431 toPublicKey(KEYBase r) throws DNSSECException {
432 int alg = r.getAlgorithm();
433 try {
434 switch (alg) {
435 case Algorithm.RSAMD5:
436 case Algorithm.RSASHA1:
437 case Algorithm.RSA_NSEC3_SHA1:
438 case Algorithm.RSASHA256:
439 case Algorithm.RSASHA512:
440 return toRSAPublicKey(r);
441 case Algorithm.DSA:
442 case Algorithm.DSA_NSEC3_SHA1:
443 return toDSAPublicKey(r);
444 case Algorithm.ECDSAP256SHA256:
445 return toECDSAPublicKey(r, ECDSA_P256);
446 case Algorithm.ECDSAP384SHA384:
447 return toECDSAPublicKey(r, ECDSA_P384);
448 default:
449 throw new UnsupportedAlgorithmException(alg);
450 }
451 }
452 catch (IOException e) {
453 throw new MalformedKeyException(r);
454 }
455 catch (GeneralSecurityException e) {
456 throw new DNSSECException(e.toString());
457 }
458 }
459
460 private static byte []
fromRSAPublicKey(RSAPublicKey key)461 fromRSAPublicKey(RSAPublicKey key) {
462 DNSOutput out = new DNSOutput();
463 BigInteger exponent = key.getPublicExponent();
464 BigInteger modulus = key.getModulus();
465 int exponentLength = BigIntegerLength(exponent);
466
467 if (exponentLength < 256)
468 out.writeU8(exponentLength);
469 else {
470 out.writeU8(0);
471 out.writeU16(exponentLength);
472 }
473 writeBigInteger(out, exponent);
474 writeBigInteger(out, modulus);
475
476 return out.toByteArray();
477 }
478
479 private static byte []
fromDSAPublicKey(DSAPublicKey key)480 fromDSAPublicKey(DSAPublicKey key) {
481 DNSOutput out = new DNSOutput();
482 BigInteger q = key.getParams().getQ();
483 BigInteger p = key.getParams().getP();
484 BigInteger g = key.getParams().getG();
485 BigInteger y = key.getY();
486 int t = (p.toByteArray().length - 64) / 8;
487
488 out.writeU8(t);
489 writeBigInteger(out, q);
490 writeBigInteger(out, p);
491 writeBigInteger(out, g);
492 writeBigInteger(out, y);
493
494 return out.toByteArray();
495 }
496
497 private static byte []
fromECDSAPublicKey(ECPublicKey key)498 fromECDSAPublicKey(ECPublicKey key) {
499 DNSOutput out = new DNSOutput();
500
501 BigInteger x = key.getW().getAffineX();
502 BigInteger y = key.getW().getAffineY();
503
504 writeBigInteger(out, x);
505 writeBigInteger(out, y);
506
507 return out.toByteArray();
508 }
509
510 /** Builds a DNSKEY record from a PublicKey */
511 static byte []
fromPublicKey(PublicKey key, int alg)512 fromPublicKey(PublicKey key, int alg) throws DNSSECException
513 {
514
515 switch (alg) {
516 case Algorithm.RSAMD5:
517 case Algorithm.RSASHA1:
518 case Algorithm.RSA_NSEC3_SHA1:
519 case Algorithm.RSASHA256:
520 case Algorithm.RSASHA512:
521 if (! (key instanceof RSAPublicKey))
522 throw new IncompatibleKeyException();
523 return fromRSAPublicKey((RSAPublicKey) key);
524 case Algorithm.DSA:
525 case Algorithm.DSA_NSEC3_SHA1:
526 if (! (key instanceof DSAPublicKey))
527 throw new IncompatibleKeyException();
528 return fromDSAPublicKey((DSAPublicKey) key);
529 case Algorithm.ECDSAP256SHA256:
530 case Algorithm.ECDSAP384SHA384:
531 if (! (key instanceof ECPublicKey))
532 throw new IncompatibleKeyException();
533 return fromECDSAPublicKey((ECPublicKey) key);
534 default:
535 throw new UnsupportedAlgorithmException(alg);
536 }
537 }
538
539 /**
540 * Convert an algorithm number to the corresponding JCA string.
541 * @param alg The algorithm number.
542 * @throws UnsupportedAlgorithmException The algorithm is unknown.
543 */
544 public static String
algString(int alg)545 algString(int alg) throws UnsupportedAlgorithmException {
546 switch (alg) {
547 case Algorithm.RSAMD5:
548 return "MD5withRSA";
549 case Algorithm.DSA:
550 case Algorithm.DSA_NSEC3_SHA1:
551 return "SHA1withDSA";
552 case Algorithm.RSASHA1:
553 case Algorithm.RSA_NSEC3_SHA1:
554 return "SHA1withRSA";
555 case Algorithm.RSASHA256:
556 return "SHA256withRSA";
557 case Algorithm.RSASHA512:
558 return "SHA512withRSA";
559 case Algorithm.ECDSAP256SHA256:
560 return "SHA256withECDSA";
561 case Algorithm.ECDSAP384SHA384:
562 return "SHA384withECDSA";
563 default:
564 throw new UnsupportedAlgorithmException(alg);
565 }
566 }
567
568 private static final int ASN1_SEQ = 0x30;
569 private static final int ASN1_INT = 0x2;
570
571 private static final int DSA_LEN = 20;
572
573 private static byte []
DSASignaturefromDNS(byte [] dns)574 DSASignaturefromDNS(byte [] dns) throws DNSSECException, IOException {
575 if (dns.length != 1 + DSA_LEN * 2)
576 throw new SignatureVerificationException();
577
578 DNSInput in = new DNSInput(dns);
579 DNSOutput out = new DNSOutput();
580
581 int t = in.readU8();
582
583 byte [] r = in.readByteArray(DSA_LEN);
584 int rlen = DSA_LEN;
585 if (r[0] < 0)
586 rlen++;
587
588 byte [] s = in.readByteArray(DSA_LEN);
589 int slen = DSA_LEN;
590 if (s[0] < 0)
591 slen++;
592
593 out.writeU8(ASN1_SEQ);
594 out.writeU8(rlen + slen + 4);
595
596 out.writeU8(ASN1_INT);
597 out.writeU8(rlen);
598 if (rlen > DSA_LEN)
599 out.writeU8(0);
600 out.writeByteArray(r);
601
602 out.writeU8(ASN1_INT);
603 out.writeU8(slen);
604 if (slen > DSA_LEN)
605 out.writeU8(0);
606 out.writeByteArray(s);
607
608 return out.toByteArray();
609 }
610
611 private static byte []
DSASignaturetoDNS(byte [] signature, int t)612 DSASignaturetoDNS(byte [] signature, int t) throws IOException {
613 DNSInput in = new DNSInput(signature);
614 DNSOutput out = new DNSOutput();
615
616 out.writeU8(t);
617
618 int tmp = in.readU8();
619 if (tmp != ASN1_SEQ)
620 throw new IOException();
621 int seqlen = in.readU8();
622
623 tmp = in.readU8();
624 if (tmp != ASN1_INT)
625 throw new IOException();
626 int rlen = in.readU8();
627 if (rlen == DSA_LEN + 1) {
628 if (in.readU8() != 0)
629 throw new IOException();
630 } else if (rlen != DSA_LEN)
631 throw new IOException();
632 byte [] bytes = in.readByteArray(DSA_LEN);
633 out.writeByteArray(bytes);
634
635 tmp = in.readU8();
636 if (tmp != ASN1_INT)
637 throw new IOException();
638 int slen = in.readU8();
639 if (slen == DSA_LEN + 1) {
640 if (in.readU8() != 0)
641 throw new IOException();
642 } else if (slen != DSA_LEN)
643 throw new IOException();
644 bytes = in.readByteArray(DSA_LEN);
645 out.writeByteArray(bytes);
646
647 return out.toByteArray();
648 }
649
650 private static byte []
ECDSASignaturefromDNS(byte [] signature, ECKeyInfo keyinfo)651 ECDSASignaturefromDNS(byte [] signature, ECKeyInfo keyinfo)
652 throws DNSSECException, IOException
653 {
654 if (signature.length != keyinfo.length * 2)
655 throw new SignatureVerificationException();
656
657 DNSInput in = new DNSInput(signature);
658 DNSOutput out = new DNSOutput();
659
660 byte [] r = in.readByteArray(keyinfo.length);
661 int rlen = keyinfo.length;
662 if (r[0] < 0)
663 rlen++;
664
665 byte [] s = in.readByteArray(keyinfo.length);
666 int slen = keyinfo.length;
667 if (s[0] < 0)
668 slen++;
669
670 out.writeU8(ASN1_SEQ);
671 out.writeU8(rlen + slen + 4);
672
673 out.writeU8(ASN1_INT);
674 out.writeU8(rlen);
675 if (rlen > keyinfo.length)
676 out.writeU8(0);
677 out.writeByteArray(r);
678
679 out.writeU8(ASN1_INT);
680 out.writeU8(slen);
681 if (slen > keyinfo.length)
682 out.writeU8(0);
683 out.writeByteArray(s);
684
685 return out.toByteArray();
686 }
687
688 private static byte []
ECDSASignaturetoDNS(byte [] signature, ECKeyInfo keyinfo)689 ECDSASignaturetoDNS(byte [] signature, ECKeyInfo keyinfo) throws IOException {
690 DNSInput in = new DNSInput(signature);
691 DNSOutput out = new DNSOutput();
692
693 int tmp = in.readU8();
694 if (tmp != ASN1_SEQ)
695 throw new IOException();
696 int seqlen = in.readU8();
697
698 tmp = in.readU8();
699 if (tmp != ASN1_INT)
700 throw new IOException();
701 int rlen = in.readU8();
702 if (rlen == keyinfo.length + 1) {
703 if (in.readU8() != 0)
704 throw new IOException();
705 } else if (rlen != keyinfo.length)
706 throw new IOException();
707 byte[] bytes = in.readByteArray(keyinfo.length);
708 out.writeByteArray(bytes);
709
710 tmp = in.readU8();
711 if (tmp != ASN1_INT)
712 throw new IOException();
713 int slen = in.readU8();
714 if (slen == keyinfo.length + 1) {
715 if (in.readU8() != 0)
716 throw new IOException();
717 } else if (slen != keyinfo.length)
718 throw new IOException();
719 bytes = in.readByteArray(keyinfo.length);
720 out.writeByteArray(bytes);
721
722 return out.toByteArray();
723 }
724
725 private static void
verify(PublicKey key, int alg, byte [] data, byte [] signature)726 verify(PublicKey key, int alg, byte [] data, byte [] signature)
727 throws DNSSECException
728 {
729 if (key instanceof DSAPublicKey) {
730 try {
731 signature = DSASignaturefromDNS(signature);
732 }
733 catch (IOException e) {
734 throw new IllegalStateException();
735 }
736 } else if (key instanceof ECPublicKey) {
737 try {
738 switch (alg) {
739 case Algorithm.ECDSAP256SHA256:
740 signature = ECDSASignaturefromDNS(signature,
741 ECDSA_P256);
742 break;
743 case Algorithm.ECDSAP384SHA384:
744 signature = ECDSASignaturefromDNS(signature,
745 ECDSA_P384);
746 break;
747 default:
748 throw new UnsupportedAlgorithmException(alg);
749 }
750 }
751 catch (IOException e) {
752 throw new IllegalStateException();
753 }
754 }
755
756 try {
757 Signature s = Signature.getInstance(algString(alg));
758 s.initVerify(key);
759 s.update(data);
760 if (!s.verify(signature))
761 throw new SignatureVerificationException();
762 }
763 catch (GeneralSecurityException e) {
764 throw new DNSSECException(e.toString());
765 }
766 }
767
768 private static boolean
matches(SIGBase sig, KEYBase key)769 matches(SIGBase sig, KEYBase key)
770 {
771 return (key.getAlgorithm() == sig.getAlgorithm() &&
772 key.getFootprint() == sig.getFootprint() &&
773 key.getName().equals(sig.getSigner()));
774 }
775
776 /**
777 * Verify a DNSSEC signature.
778 * @param rrset The data to be verified.
779 * @param rrsig The RRSIG record containing the signature.
780 * @param key The DNSKEY record to verify the signature with.
781 * @throws UnsupportedAlgorithmException The algorithm is unknown
782 * @throws MalformedKeyException The key is malformed
783 * @throws KeyMismatchException The key and signature do not match
784 * @throws SignatureExpiredException The signature has expired
785 * @throws SignatureNotYetValidException The signature is not yet valid
786 * @throws SignatureVerificationException The signature does not verify.
787 * @throws DNSSECException Some other error occurred.
788 */
789 public static void
verify(RRset rrset, RRSIGRecord rrsig, DNSKEYRecord key)790 verify(RRset rrset, RRSIGRecord rrsig, DNSKEYRecord key) throws DNSSECException
791 {
792 if (!matches(rrsig, key))
793 throw new KeyMismatchException(key, rrsig);
794
795 Date now = new Date();
796 if (now.compareTo(rrsig.getExpire()) > 0)
797 throw new SignatureExpiredException(rrsig.getExpire(), now);
798 if (now.compareTo(rrsig.getTimeSigned()) < 0)
799 throw new SignatureNotYetValidException(rrsig.getTimeSigned(),
800 now);
801
802 verify(key.getPublicKey(), rrsig.getAlgorithm(),
803 digestRRset(rrsig, rrset), rrsig.getSignature());
804 }
805
806 private static byte []
sign(PrivateKey privkey, PublicKey pubkey, int alg, byte [] data, String provider)807 sign(PrivateKey privkey, PublicKey pubkey, int alg, byte [] data,
808 String provider) throws DNSSECException
809 {
810 byte [] signature;
811 try {
812 Signature s;
813 if (provider != null)
814 s = Signature.getInstance(algString(alg), provider);
815 else
816 s = Signature.getInstance(algString(alg));
817 s.initSign(privkey);
818 s.update(data);
819 signature = s.sign();
820 }
821 catch (GeneralSecurityException e) {
822 throw new DNSSECException(e.toString());
823 }
824
825 if (pubkey instanceof DSAPublicKey) {
826 try {
827 DSAPublicKey dsa = (DSAPublicKey) pubkey;
828 BigInteger P = dsa.getParams().getP();
829 int t = (BigIntegerLength(P) - 64) / 8;
830 signature = DSASignaturetoDNS(signature, t);
831 }
832 catch (IOException e) {
833 throw new IllegalStateException();
834 }
835 } else if (pubkey instanceof ECPublicKey) {
836 try {
837 switch (alg) {
838 case Algorithm.ECDSAP256SHA256:
839 signature = ECDSASignaturetoDNS(signature,
840 ECDSA_P256);
841 break;
842 case Algorithm.ECDSAP384SHA384:
843 signature = ECDSASignaturetoDNS(signature,
844 ECDSA_P384);
845 break;
846 default:
847 throw new UnsupportedAlgorithmException(alg);
848 }
849 }
850 catch (IOException e) {
851 throw new IllegalStateException();
852 }
853 }
854
855 return signature;
856 }
857 static void
checkAlgorithm(PrivateKey key, int alg)858 checkAlgorithm(PrivateKey key, int alg) throws UnsupportedAlgorithmException
859 {
860 switch (alg) {
861 case Algorithm.RSAMD5:
862 case Algorithm.RSASHA1:
863 case Algorithm.RSA_NSEC3_SHA1:
864 case Algorithm.RSASHA256:
865 case Algorithm.RSASHA512:
866 if (! (key instanceof RSAPrivateKey))
867 throw new IncompatibleKeyException();
868 break;
869 case Algorithm.DSA:
870 case Algorithm.DSA_NSEC3_SHA1:
871 if (! (key instanceof DSAPrivateKey))
872 throw new IncompatibleKeyException();
873 break;
874 case Algorithm.ECDSAP256SHA256:
875 case Algorithm.ECDSAP384SHA384:
876 if (! (key instanceof ECPrivateKey))
877 throw new IncompatibleKeyException();
878 break;
879 default:
880 throw new UnsupportedAlgorithmException(alg);
881 }
882 }
883
884 /**
885 * Generate a DNSSEC signature. key and privateKey must refer to the
886 * same underlying cryptographic key.
887 * @param rrset The data to be signed
888 * @param key The DNSKEY record to use as part of signing
889 * @param privkey The PrivateKey to use when signing
890 * @param inception The time at which the signatures should become valid
891 * @param expiration The time at which the signatures should expire
892 * @throws UnsupportedAlgorithmException The algorithm is unknown
893 * @throws MalformedKeyException The key is malformed
894 * @throws DNSSECException Some other error occurred.
895 * @return The generated signature
896 */
897 public static RRSIGRecord
sign(RRset rrset, DNSKEYRecord key, PrivateKey privkey, Date inception, Date expiration)898 sign(RRset rrset, DNSKEYRecord key, PrivateKey privkey,
899 Date inception, Date expiration) throws DNSSECException
900 {
901 return sign(rrset, key, privkey, inception, expiration, null);
902 }
903
904 /**
905 * Generate a DNSSEC signature. key and privateKey must refer to the
906 * same underlying cryptographic key.
907 * @param rrset The data to be signed
908 * @param key The DNSKEY record to use as part of signing
909 * @param privkey The PrivateKey to use when signing
910 * @param inception The time at which the signatures should become valid
911 * @param expiration The time at which the signatures should expire
912 * @param provider The name of the JCA provider. If non-null, it will be
913 * passed to JCA getInstance() methods.
914 * @throws UnsupportedAlgorithmException The algorithm is unknown
915 * @throws MalformedKeyException The key is malformed
916 * @throws DNSSECException Some other error occurred.
917 * @return The generated signature
918 */
919 public static RRSIGRecord
sign(RRset rrset, DNSKEYRecord key, PrivateKey privkey, Date inception, Date expiration, String provider)920 sign(RRset rrset, DNSKEYRecord key, PrivateKey privkey,
921 Date inception, Date expiration, String provider) throws DNSSECException
922 {
923 int alg = key.getAlgorithm();
924 checkAlgorithm(privkey, alg);
925
926 RRSIGRecord rrsig = new RRSIGRecord(rrset.getName(), rrset.getDClass(),
927 rrset.getTTL(), rrset.getType(),
928 alg, rrset.getTTL(),
929 expiration, inception,
930 key.getFootprint(),
931 key.getName(), null);
932
933 rrsig.setSignature(sign(privkey, key.getPublicKey(), alg,
934 digestRRset(rrsig, rrset), provider));
935 return rrsig;
936 }
937
938 static SIGRecord
signMessage(Message message, SIGRecord previous, KEYRecord key, PrivateKey privkey, Date inception, Date expiration)939 signMessage(Message message, SIGRecord previous, KEYRecord key,
940 PrivateKey privkey, Date inception, Date expiration)
941 throws DNSSECException
942 {
943 int alg = key.getAlgorithm();
944 checkAlgorithm(privkey, alg);
945
946 SIGRecord sig = new SIGRecord(Name.root, DClass.ANY, 0, 0,
947 alg, 0, expiration, inception,
948 key.getFootprint(),
949 key.getName(), null);
950 DNSOutput out = new DNSOutput();
951 digestSIG(out, sig);
952 if (previous != null)
953 out.writeByteArray(previous.getSignature());
954 message.toWire(out);
955
956 sig.setSignature(sign(privkey, key.getPublicKey(),
957 alg, out.toByteArray(), null));
958 return sig;
959 }
960
961 static void
verifyMessage(Message message, byte [] bytes, SIGRecord sig, SIGRecord previous, KEYRecord key)962 verifyMessage(Message message, byte [] bytes, SIGRecord sig, SIGRecord previous,
963 KEYRecord key) throws DNSSECException
964 {
965 if (!matches(sig, key))
966 throw new KeyMismatchException(key, sig);
967
968 Date now = new Date();
969
970 if (now.compareTo(sig.getExpire()) > 0)
971 throw new SignatureExpiredException(sig.getExpire(), now);
972 if (now.compareTo(sig.getTimeSigned()) < 0)
973 throw new SignatureNotYetValidException(sig.getTimeSigned(),
974 now);
975
976 DNSOutput out = new DNSOutput();
977 digestSIG(out, sig);
978 if (previous != null)
979 out.writeByteArray(previous.getSignature());
980
981 Header header = (Header) message.getHeader().clone();
982 header.decCount(Section.ADDITIONAL);
983 out.writeByteArray(header.toWire());
984
985 out.writeByteArray(bytes, Header.LENGTH,
986 message.sig0start - Header.LENGTH);
987
988 verify(key.getPublicKey(), sig.getAlgorithm(),
989 out.toByteArray(), sig.getSignature());
990 }
991
992 /**
993 * Generate the digest value for a DS key
994 * @param key Which is covered by the DS record
995 * @param digestid The type of digest
996 * @return The digest value as an array of bytes
997 */
998 static byte []
generateDSDigest(DNSKEYRecord key, int digestid)999 generateDSDigest(DNSKEYRecord key, int digestid)
1000 {
1001 MessageDigest digest;
1002 try {
1003 switch (digestid) {
1004 case DSRecord.Digest.SHA1:
1005 digest = MessageDigest.getInstance("sha-1");
1006 break;
1007 case DSRecord.Digest.SHA256:
1008 digest = MessageDigest.getInstance("sha-256");
1009 break;
1010 case DSRecord.Digest.SHA384:
1011 digest = MessageDigest.getInstance("sha-384");
1012 break;
1013 default:
1014 throw new IllegalArgumentException(
1015 "unknown DS digest type " + digestid);
1016 }
1017 }
1018 catch (NoSuchAlgorithmException e) {
1019 throw new IllegalStateException("no message digest support");
1020 }
1021 digest.update(key.getName().toWire());
1022 digest.update(key.rdataToWireCanonical());
1023 return digest.digest();
1024 }
1025
1026 }
1027