| 112 | } |
| 113 | |
| 114 | static byte[] combine(RRSIG rrsig, List<Record<? extends Data>> records) { |
| 115 | ByteArrayOutputStream bos = new ByteArrayOutputStream(); |
| 116 | DataOutputStream dos = new DataOutputStream(bos); |
| 117 | |
| 118 | // Write RRSIG without signature |
| 119 | try { |
| 120 | rrsig.writePartialSignature(dos); |
| 121 | |
| 122 | DnsName sigName = records.get(0).name; |
| 123 | if (!sigName.isRootLabel()) { |
| 124 | if (sigName.getLabelCount() < rrsig.labels) { |
| 125 | // TODO: This is currently not covered by the unit tests. |
| 126 | throw new DnssecValidationFailedException("Invalid RRsig record"); |
| 127 | } |
| 128 | |
| 129 | if (sigName.getLabelCount() > rrsig.labels) { |
| 130 | // TODO: This is currently not covered by the unit tests. |
| 131 | // Expand wildcards |
| 132 | sigName = DnsName.from(DnsLabel.WILDCARD_LABEL, sigName.stripToLabels(rrsig.labels)); |
| 133 | } |
| 134 | } |
| 135 | |
| 136 | List<byte[]> recordBytes = new ArrayList<>(records.size()); |
| 137 | for (Record<? extends Data> record : records) { |
| 138 | Record<Data> ref = new Record<Data>(sigName, record.type, record.clazzValue, rrsig.originalTtl, record.payloadData); |
| 139 | recordBytes.add(ref.toByteArray()); |
| 140 | } |
| 141 | |
| 142 | // Sort correctly (cause they might be ordered randomly) as per RFC 4034 § 6.3. |
| 143 | final int offset = sigName.size() + 10; // Where the RDATA begins |
| 144 | Collections.sort(recordBytes, new Comparator<byte[]>() { |
| 145 | @Override |
| 146 | public int compare(byte[] b1, byte[] b2) { |
| 147 | for (int i = offset; i < b1.length && i < b2.length; i++) { |
| 148 | if (b1[i] != b2[i]) { |
| 149 | return (b1[i] & 0xFF) - (b2[i] & 0xFF); |
| 150 | } |
| 151 | } |
| 152 | return b1.length - b2.length; |
| 153 | } |
| 154 | }); |
| 155 | |
| 156 | for (byte[] recordByte : recordBytes) { |
| 157 | dos.write(recordByte); |
| 158 | } |
| 159 | dos.flush(); |
| 160 | } catch (IOException e) { |
| 161 | // Never happens |
| 162 | throw new RuntimeException(e); |
| 163 | } |
| 164 | return bos.toByteArray(); |
| 165 | } |
| 166 | |
| 167 | static boolean nsecMatches(String test, String lowerBound, String upperBound) { |
| 168 | return nsecMatches(DnsName.from(test), DnsName.from(lowerBound), DnsName.from(upperBound)); |