• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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