1 // Copyright (c) 1999-2010 Brian Wellington (bwelling (at) 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 { 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 74 algs.add(RSAMD5, "RSAMD5"); 75 algs.add(DH, "DH"); 76 algs.add(DSA, "DSA"); 77 algs.add(RSASHA1, "RSASHA1"); 78 algs.add(DSA_NSEC3_SHA1, "DSA-NSEC3-SHA1"); 79 algs.add(RSA_NSEC3_SHA1, "RSA-NSEC3-SHA1"); 80 algs.add(RSASHA256, "RSASHA256"); 81 algs.add(RSASHA512, "RSASHA512"); 82 algs.add(ECDSAP256SHA256, "ECDSAP256SHA256"); 83 algs.add(ECDSAP384SHA384, "ECDSAP384SHA384"); 84 algs.add(INDIRECT, "INDIRECT"); 85 algs.add(PRIVATEDNS, "PRIVATEDNS"); 86 algs.add(PRIVATEOID, "PRIVATEOID"); 87 } 88 89 /** 90 * Converts an algorithm into its textual representation 91 */ 92 public static String 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 104 value(String s) { 105 return algs.getValue(s); 106 } 107 } 108 109 private 110 DNSSEC() { } 111 112 private static void 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 [] 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 [] 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 { 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 { 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 { 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 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 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 256 getExpiration() { 257 return when; 258 } 259 260 /** 261 * @return When the verification was attempted 262 */ 263 public Date 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 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 285 getExpiration() { 286 return when; 287 } 288 289 /** 290 * @return When the verification was attempted 291 */ 292 public Date 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 { 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 { 312 IncompatibleKeyException() { 313 super("incompatible keys"); 314 } 315 } 316 317 private static int 318 BigIntegerLength(BigInteger i) { 319 return (i.bitLength() + 7) / 8; 320 } 321 322 private static BigInteger 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 329 readBigInteger(DNSInput in) { 330 byte [] b = in.readByteArray(); 331 return new BigInteger(1, b); 332 } 333 334 private static void 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 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 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 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 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 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 [] 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 [] 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 [] 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 [] 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 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 [] 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 [] 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 [] 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 [] 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 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 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 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 [] 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 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 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 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 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 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 [] 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