Source Code Cross Referenced for TSIG.java in  » Net » dnsjava » org » xbill » DNS » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Net » dnsjava » org.xbill.DNS 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        // Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
002:
003:        package org.xbill.DNS;
004:
005:        import java.util.*;
006:        import org.xbill.DNS.utils.*;
007:
008:        /**
009:         * Transaction signature handling.  This class generates and verifies
010:         * TSIG records on messages, which provide transaction security.
011:         * @see TSIGRecord
012:         *
013:         * @author Brian Wellington
014:         */
015:
016:        public class TSIG {
017:
018:            private static final String HMAC_MD5_STR = "HMAC-MD5.SIG-ALG.REG.INT.";
019:            private static final String HMAC_SHA1_STR = "hmac-sha1.";
020:            private static final String HMAC_SHA256_STR = "hmac-sha256.";
021:
022:            /** The domain name representing the HMAC-MD5 algorithm. */
023:            public static final Name HMAC_MD5 = Name
024:                    .fromConstantString(HMAC_MD5_STR);
025:
026:            /** The domain name representing the HMAC-MD5 algorithm (deprecated). */
027:            public static final Name HMAC = HMAC_MD5;
028:
029:            /** The domain name representing the HMAC-SHA1 algorithm. */
030:            public static final Name HMAC_SHA1 = Name
031:                    .fromConstantString(HMAC_SHA1_STR);
032:
033:            /** The domain name representing the HMAC-SHA256 algorithm. */
034:            public static final Name HMAC_SHA256 = Name
035:                    .fromConstantString(HMAC_SHA256_STR);
036:
037:            /**
038:             * The default fudge value for outgoing packets.  Can be overriden by the
039:             * tsigfudge option.
040:             */
041:            public static final short FUDGE = 300;
042:
043:            private Name name, alg;
044:            private String digest;
045:            private byte[] key;
046:
047:            private void getDigest() {
048:                if (alg.equals(HMAC_MD5))
049:                    digest = "md5";
050:                else if (alg.equals(HMAC_SHA1))
051:                    digest = "sha-1";
052:                else if (alg.equals(HMAC_SHA256))
053:                    digest = "sha-256";
054:                else
055:                    throw new IllegalArgumentException("Invalid algorithm");
056:            }
057:
058:            /**
059:             * Creates a new TSIG key, which can be used to sign or verify a message.
060:             * @param algorithm The algorithm of the shared key.
061:             * @param name The name of the shared key.
062:             * @param key The shared key's data.
063:             */
064:            public TSIG(Name algorithm, Name name, byte[] key) {
065:                this .name = name;
066:                this .alg = algorithm;
067:                this .key = key;
068:                getDigest();
069:            }
070:
071:            /**
072:             * Creates a new TSIG key with the hmac-md5 algorithm, which can be used to
073:             * sign or verify a message.
074:             * @param name The name of the shared key.
075:             * @param key The shared key's data.
076:             */
077:            public TSIG(Name name, byte[] key) {
078:                this (HMAC_MD5, name, key);
079:            }
080:
081:            /**
082:             * Creates a new TSIG object, which can be used to sign or verify a message.
083:             * @param name The name of the shared key.
084:             * @param key The shared key's data represented as a base64 encoded string.
085:             * @throws IllegalArgumentException The key name is an invalid name
086:             * @throws IllegalArgumentException The key data is improperly encoded
087:             */
088:            public TSIG(Name algorithm, String name, String key) {
089:                this .key = base64.fromString(key);
090:                if (this .key == null)
091:                    throw new IllegalArgumentException(
092:                            "Invalid TSIG key string");
093:                try {
094:                    this .name = Name.fromString(name, Name.root);
095:                } catch (TextParseException e) {
096:                    throw new IllegalArgumentException("Invalid TSIG key name");
097:                }
098:                this .alg = algorithm;
099:                getDigest();
100:            }
101:
102:            /**
103:             * Creates a new TSIG object, which can be used to sign or verify a message.
104:             * @param name The name of the shared key.  The legal values are "hmac-md5",
105:             * "hmac-sha1", and "hmac-sha256".
106:             * @param key The shared key's data represented as a base64 encoded string.
107:             * @throws IllegalArgumentException The key name is an invalid name
108:             * @throws IllegalArgumentException The key data is improperly encoded
109:             */
110:            public TSIG(String algorithm, String name, String key) {
111:                this (HMAC_MD5, name, key);
112:                if (algorithm.equalsIgnoreCase("hmac-md5"))
113:                    this .alg = HMAC_MD5;
114:                else if (algorithm.equalsIgnoreCase("hmac-sha1"))
115:                    this .alg = HMAC_SHA1;
116:                else if (algorithm.equalsIgnoreCase("hmac-sha256"))
117:                    this .alg = HMAC_SHA256;
118:                else
119:                    throw new IllegalArgumentException("Invalid TSIG algorithm");
120:                getDigest();
121:            }
122:
123:            /**
124:             * Creates a new TSIG object with the hmac-md5 algorithm, which can be used to
125:             * sign or verify a message.
126:             * @param name The name of the shared key
127:             * @param key The shared key's data, represented as a base64 encoded string.
128:             * @throws IllegalArgumentException The key name is an invalid name
129:             * @throws IllegalArgumentException The key data is improperly encoded
130:             */
131:            public TSIG(String name, String key) {
132:                this (HMAC_MD5, name, key);
133:            }
134:
135:            /**
136:             * Creates a new TSIG object with the hmac-md5 algorithm, which can be used to
137:             * sign or verify a message.
138:             * @param str The TSIG key, in the form name:secret, name/secret,
139:             * alg:name:secret, or alg/name/secret.  If an algorithm is specified, it must
140:             * be "hmac-md5", "hmac-sha1", or "hmac-sha256".
141:             * @throws IllegalArgumentException The string does not contain both a name
142:             * and secret.
143:             * @throws IllegalArgumentException The key name is an invalid name
144:             * @throws IllegalArgumentException The key data is improperly encoded
145:             */
146:            static public TSIG fromString(String str) {
147:                String[] parts = str.split("[:/]");
148:                if (parts.length < 2 || parts.length > 3)
149:                    throw new IllegalArgumentException("Invalid TSIG key "
150:                            + "specification");
151:                if (parts.length == 3)
152:                    return new TSIG(parts[0], parts[1], parts[2]);
153:                else
154:                    return new TSIG(HMAC_MD5, parts[0], parts[1]);
155:            }
156:
157:            /**
158:             * Generates a TSIG record with a specific error for a message that has
159:             * been rendered.
160:             * @param m The message
161:             * @param b The rendered message
162:             * @param error The error
163:             * @param old If this message is a response, the TSIG from the request
164:             * @return The TSIG record to be added to the message
165:             */
166:            public TSIGRecord generate(Message m, byte[] b, int error,
167:                    TSIGRecord old) {
168:                Date timeSigned;
169:                if (error != Rcode.BADTIME)
170:                    timeSigned = new Date();
171:                else
172:                    timeSigned = old.getTimeSigned();
173:                int fudge;
174:                HMAC hmac = null;
175:                if (error == Rcode.NOERROR || error == Rcode.BADTIME)
176:                    hmac = new HMAC(digest, key);
177:
178:                fudge = Options.intValue("tsigfudge");
179:                if (fudge < 0 || fudge > 0x7FFF)
180:                    fudge = FUDGE;
181:
182:                if (old != null) {
183:                    DNSOutput out = new DNSOutput();
184:                    out.writeU16(old.getSignature().length);
185:                    if (hmac != null) {
186:                        hmac.update(out.toByteArray());
187:                        hmac.update(old.getSignature());
188:                    }
189:                }
190:
191:                /* Digest the message */
192:                if (hmac != null)
193:                    hmac.update(b);
194:
195:                DNSOutput out = new DNSOutput();
196:                name.toWireCanonical(out);
197:                out.writeU16(DClass.ANY); /* class */
198:                out.writeU32(0); /* ttl */
199:                alg.toWireCanonical(out);
200:                long time = timeSigned.getTime() / 1000;
201:                int timeHigh = (int) (time >> 32);
202:                long timeLow = (time & 0xFFFFFFFFL);
203:                out.writeU16(timeHigh);
204:                out.writeU32(timeLow);
205:                out.writeU16(fudge);
206:
207:                out.writeU16(error);
208:                out.writeU16(0); /* No other data */
209:
210:                if (hmac != null)
211:                    hmac.update(out.toByteArray());
212:
213:                byte[] signature;
214:                if (hmac != null)
215:                    signature = hmac.sign();
216:                else
217:                    signature = new byte[0];
218:
219:                byte[] other = null;
220:                if (error == Rcode.BADTIME) {
221:                    out = new DNSOutput();
222:                    time = new Date().getTime() / 1000;
223:                    timeHigh = (int) (time >> 32);
224:                    timeLow = (time & 0xFFFFFFFFL);
225:                    out.writeU16(timeHigh);
226:                    out.writeU32(timeLow);
227:                    other = out.toByteArray();
228:                }
229:
230:                return (new TSIGRecord(name, DClass.ANY, 0, alg, timeSigned,
231:                        fudge, signature, m.getHeader().getID(), error, other));
232:            }
233:
234:            /**
235:             * Generates a TSIG record with a specific error for a message and adds it
236:             * to the message.
237:             * @param m The message
238:             * @param error The error
239:             * @param old If this message is a response, the TSIG from the request
240:             */
241:            public void apply(Message m, int error, TSIGRecord old) {
242:                Record r = generate(m, m.toWire(), error, old);
243:                m.addRecord(r, Section.ADDITIONAL);
244:                m.tsigState = Message.TSIG_SIGNED;
245:            }
246:
247:            /**
248:             * Generates a TSIG record for a message and adds it to the message
249:             * @param m The message
250:             * @param old If this message is a response, the TSIG from the request
251:             */
252:            public void apply(Message m, TSIGRecord old) {
253:                apply(m, Rcode.NOERROR, old);
254:            }
255:
256:            /**
257:             * Generates a TSIG record for a message and adds it to the message
258:             * @param m The message
259:             * @param old If this message is a response, the TSIG from the request
260:             */
261:            public void applyStream(Message m, TSIGRecord old, boolean first) {
262:                if (first) {
263:                    apply(m, old);
264:                    return;
265:                }
266:                Date timeSigned = new Date();
267:                int fudge;
268:                HMAC hmac = new HMAC(digest, key);
269:
270:                fudge = Options.intValue("tsigfudge");
271:                if (fudge < 0 || fudge > 0x7FFF)
272:                    fudge = FUDGE;
273:
274:                DNSOutput out = new DNSOutput();
275:                out.writeU16(old.getSignature().length);
276:                hmac.update(out.toByteArray());
277:                hmac.update(old.getSignature());
278:
279:                /* Digest the message */
280:                hmac.update(m.toWire());
281:
282:                out = new DNSOutput();
283:                long time = timeSigned.getTime() / 1000;
284:                int timeHigh = (int) (time >> 32);
285:                long timeLow = (time & 0xFFFFFFFFL);
286:                out.writeU16(timeHigh);
287:                out.writeU32(timeLow);
288:                out.writeU16(fudge);
289:
290:                hmac.update(out.toByteArray());
291:
292:                byte[] signature = hmac.sign();
293:                byte[] other = null;
294:
295:                Record r = new TSIGRecord(name, DClass.ANY, 0, alg, timeSigned,
296:                        fudge, signature, m.getHeader().getID(), Rcode.NOERROR,
297:                        other);
298:                m.addRecord(r, Section.ADDITIONAL);
299:                m.tsigState = Message.TSIG_SIGNED;
300:            }
301:
302:            /**
303:             * Verifies a TSIG record on an incoming message.  Since this is only called
304:             * in the context where a TSIG is expected to be present, it is an error
305:             * if one is not present.
306:             * @param m The message
307:             * @param b An array containing the message in unparsed form.  This is
308:             * necessary since TSIG signs the message in wire format, and we can't
309:             * recreate the exact wire format (with the same name compression).
310:             * @param length The length of the message in the array.
311:             * @param old If this message is a response, the TSIG from the request
312:             * @return The result of the verification (as an Rcode)
313:             * @see Rcode
314:             */
315:            public byte verify(Message m, byte[] b, int length, TSIGRecord old) {
316:                TSIGRecord tsig = m.getTSIG();
317:                HMAC hmac = new HMAC(digest, key);
318:                if (tsig == null)
319:                    return Rcode.FORMERR;
320:
321:                if (!tsig.getName().equals(name)
322:                        || !tsig.getAlgorithm().equals(alg)) {
323:                    if (Options.check("verbose"))
324:                        System.err.println("BADKEY failure");
325:                    return Rcode.BADKEY;
326:                }
327:                long now = System.currentTimeMillis();
328:                long then = tsig.getTimeSigned().getTime();
329:                long fudge = tsig.getFudge();
330:                if (Math.abs(now - then) > fudge * 1000) {
331:                    if (Options.check("verbose"))
332:                        System.err.println("BADTIME failure");
333:                    return Rcode.BADTIME;
334:                }
335:
336:                if (old != null && tsig.getError() != Rcode.BADKEY
337:                        && tsig.getError() != Rcode.BADSIG) {
338:                    DNSOutput out = new DNSOutput();
339:                    out.writeU16(old.getSignature().length);
340:                    hmac.update(out.toByteArray());
341:                    hmac.update(old.getSignature());
342:                }
343:                m.getHeader().decCount(Section.ADDITIONAL);
344:                byte[] header = m.getHeader().toWire();
345:                m.getHeader().incCount(Section.ADDITIONAL);
346:                hmac.update(header);
347:
348:                int len = m.tsigstart - header.length;
349:                hmac.update(b, header.length, len);
350:
351:                DNSOutput out = new DNSOutput();
352:                tsig.getName().toWireCanonical(out);
353:                out.writeU16(tsig.dclass);
354:                out.writeU32(tsig.ttl);
355:                tsig.getAlgorithm().toWireCanonical(out);
356:                long time = tsig.getTimeSigned().getTime() / 1000;
357:                int timeHigh = (int) (time >> 32);
358:                long timeLow = (time & 0xFFFFFFFFL);
359:                out.writeU16(timeHigh);
360:                out.writeU32(timeLow);
361:                out.writeU16(tsig.getFudge());
362:                out.writeU16(tsig.getError());
363:                if (tsig.getOther() != null) {
364:                    out.writeU16(tsig.getOther().length);
365:                    out.writeByteArray(tsig.getOther());
366:                } else {
367:                    out.writeU16(0);
368:                }
369:
370:                hmac.update(out.toByteArray());
371:
372:                if (hmac.verify(tsig.getSignature()))
373:                    return Rcode.NOERROR;
374:                else {
375:                    if (Options.check("verbose"))
376:                        System.err.println("BADSIG failure");
377:                    return Rcode.BADSIG;
378:                }
379:            }
380:
381:            /**
382:             * Verifies a TSIG record on an incoming message.  Since this is only called
383:             * in the context where a TSIG is expected to be present, it is an error
384:             * if one is not present.
385:             * @param m The message
386:             * @param b The message in unparsed form.  This is necessary since TSIG
387:             * signs the message in wire format, and we can't recreate the exact wire
388:             * format (with the same name compression).
389:             * @param old If this message is a response, the TSIG from the request
390:             * @return The result of the verification (as an Rcode)
391:             * @see Rcode
392:             */
393:            public int verify(Message m, byte[] b, TSIGRecord old) {
394:                return verify(m, b, b.length, old);
395:            }
396:
397:            /**
398:             * Returns the maximum length of a TSIG record generated by this key.
399:             * @see TSIGRecord
400:             */
401:            public int recordLength() {
402:                return (name.length() + 10 + alg.length() + 8 + // time signed, fudge
403:                        18 + // 2 byte MAC length, 16 byte MAC
404:                        4 + // original id, error
405:                8); // 2 byte error length, 6 byte max error field.
406:            }
407:
408:            public static class StreamVerifier {
409:                /**
410:                 * A helper class for verifying multiple message responses.
411:                 */
412:
413:                private TSIG key;
414:                private HMAC verifier;
415:                private int nresponses;
416:                private int lastsigned;
417:                private TSIGRecord lastTSIG;
418:
419:                /** Creates an object to verify a multiple message response */
420:                public StreamVerifier(TSIG tsig, TSIGRecord old) {
421:                    key = tsig;
422:                    verifier = new HMAC(key.digest, key.key);
423:                    nresponses = 0;
424:                    lastTSIG = old;
425:                }
426:
427:                /**
428:                 * Verifies a TSIG record on an incoming message that is part of a
429:                 * multiple message response.
430:                 * TSIG records must be present on the first and last messages, and
431:                 * at least every 100 records in between.
432:                 * @param m The message
433:                 * @param b The message in unparsed form
434:                 * @return The result of the verification (as an Rcode)
435:                 * @see Rcode
436:                 */
437:                public int verify(Message m, byte[] b) {
438:                    TSIGRecord tsig = m.getTSIG();
439:
440:                    nresponses++;
441:
442:                    if (nresponses == 1) {
443:                        int result = key.verify(m, b, lastTSIG);
444:                        if (result == Rcode.NOERROR) {
445:                            byte[] signature = tsig.getSignature();
446:                            DNSOutput out = new DNSOutput();
447:                            out.writeU16(signature.length);
448:                            verifier.update(out.toByteArray());
449:                            verifier.update(signature);
450:                        }
451:                        lastTSIG = tsig;
452:                        return result;
453:                    }
454:
455:                    if (tsig != null)
456:                        m.getHeader().decCount(Section.ADDITIONAL);
457:                    byte[] header = m.getHeader().toWire();
458:                    if (tsig != null)
459:                        m.getHeader().incCount(Section.ADDITIONAL);
460:                    verifier.update(header);
461:
462:                    int len;
463:                    if (tsig == null)
464:                        len = b.length - header.length;
465:                    else
466:                        len = m.tsigstart - header.length;
467:                    verifier.update(b, header.length, len);
468:
469:                    if (tsig != null) {
470:                        lastsigned = nresponses;
471:                        lastTSIG = tsig;
472:                    } else {
473:                        boolean required = (nresponses - lastsigned >= 100);
474:                        if (required)
475:                            return Rcode.FORMERR;
476:                        else
477:                            return Rcode.NOERROR;
478:                    }
479:
480:                    if (!tsig.getName().equals(key.name)
481:                            || !tsig.getAlgorithm().equals(key.alg)) {
482:                        if (Options.check("verbose"))
483:                            System.err.println("BADKEY failure");
484:                        return Rcode.BADKEY;
485:                    }
486:
487:                    DNSOutput out = new DNSOutput();
488:                    long time = tsig.getTimeSigned().getTime() / 1000;
489:                    int timeHigh = (int) (time >> 32);
490:                    long timeLow = (time & 0xFFFFFFFFL);
491:                    out.writeU16(timeHigh);
492:                    out.writeU32(timeLow);
493:                    out.writeU16(tsig.getFudge());
494:                    verifier.update(out.toByteArray());
495:
496:                    if (verifier.verify(tsig.getSignature()) == false) {
497:                        if (Options.check("verbose"))
498:                            System.err.println("BADSIG failure");
499:                        return Rcode.BADSIG;
500:                    }
501:
502:                    verifier.clear();
503:                    out = new DNSOutput();
504:                    out.writeU16(tsig.getSignature().length);
505:                    verifier.update(out.toByteArray());
506:                    verifier.update(tsig.getSignature());
507:
508:                    return Rcode.NOERROR;
509:                }
510:            }
511:
512:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.