001: // Copyright (c) 2001-2004 Brian Wellington (bwelling@xbill.org)
002:
003: package org.xbill.DNS.security;
004:
005: import java.io.IOException;
006: import java.security.InvalidKeyException;
007: import java.security.NoSuchAlgorithmException;
008: import java.security.PrivateKey;
009: import java.security.PublicKey;
010: import java.security.Signature;
011: import java.security.SignatureException;
012: import java.security.interfaces.DSAKey;
013: import java.util.Date;
014: import org.xbill.DNS.*;
015:
016: /**
017: * Creates SIG(0) transaction signatures.
018: *
019: * @author Pasi Eronen
020: * @author Brian Wellington
021: */
022:
023: public class SIG0Signer {
024:
025: /**
026: * The default validity period for outgoing SIG(0) signed messages.
027: * Can be overriden by the sig0validity option.
028: */
029: private static final short VALIDITY = 300;
030:
031: private int algorithm;
032: private PrivateKey privateKey;
033: private Name name;
034: private int footprint;
035:
036: /**
037: * Creates a new SIG(0) signer object.
038: * @param algorithm usually DNSSEC.RSAMD5, DNSSEC.DSA, or DNSSEC.RSASHA1
039: * @param privateKey signing key (must match algorithm)
040: * @param name the name of the key
041: * @param keyFootprint the key tag
042: */
043: public SIG0Signer(int algorithm, PrivateKey privateKey, Name name,
044: int keyFootprint) {
045: this .algorithm = (byte) algorithm;
046: this .privateKey = privateKey;
047: this .name = name;
048: this .footprint = keyFootprint;
049: }
050:
051: /**
052: * Creates a new SIG(0) signer object. This is the same as the
053: * other constructor, except that the key tag is calculated automatically
054: * from the given public key.
055: */
056: public SIG0Signer(int algorithm, PrivateKey privateKey, Name name,
057: PublicKey publicKey) {
058: this .algorithm = (byte) algorithm;
059: this .privateKey = privateKey;
060: this .name = name;
061: Record rec = KEYConverter.buildRecord(name, Type.KEY,
062: DClass.IN, 0, KEYRecord.OWNER_USER,
063: KEYRecord.PROTOCOL_ANY, algorithm, publicKey);
064: KEYRecord keyRecord = (KEYRecord) rec;
065: this .footprint = keyRecord.getFootprint();
066: }
067:
068: /**
069: * Appends a SIG(0) signature to the message.
070: * @param m the message
071: * @param old if this message is a response, the original message
072: */
073: public void apply(Message m, byte[] old) throws IOException,
074: SignatureException, InvalidKeyException,
075: NoSuchAlgorithmException {
076:
077: int validity = Options.intValue("sig0validity");
078: if (validity < 0)
079: validity = VALIDITY;
080:
081: long now = System.currentTimeMillis();
082: Date timeSigned = new Date(now);
083: Date timeExpires = new Date(now + validity * 1000);
084:
085: String algorithmName;
086: if (algorithm == DNSSEC.DSA) {
087: algorithmName = "SHA1withDSA";
088: } else if (algorithm == DNSSEC.RSAMD5) {
089: algorithmName = "MD5withRSA";
090: } else if (algorithm == DNSSEC.RSASHA1) {
091: algorithmName = "SHA1withRSA";
092: } else {
093: throw new NoSuchAlgorithmException("Unknown algorithm");
094: }
095:
096: SIGRecord tmpsig = new SIGRecord(Name.root, DClass.ANY, 0, 0,
097: algorithm, 0, timeExpires, timeSigned, footprint, name,
098: null);
099:
100: byte[] outBytes = DNSSEC.digestMessage(tmpsig, m, old);
101:
102: Signature signer = Signature.getInstance(algorithmName);
103: signer.initSign(privateKey);
104: signer.update(outBytes);
105: byte[] signature = signer.sign();
106:
107: /*
108: * RSA signatures are already in correct format, but Java DSA
109: * routines use ASN.1; convert this to SIG format.
110: */
111: if (algorithm == DNSSEC.DSA) {
112: DSAKey dsakey = (DSAKey) privateKey;
113: signature = DSASignature.toDNS(dsakey.getParams(),
114: signature);
115: }
116:
117: SIGRecord sig = new SIGRecord(Name.root, DClass.ANY, 0, 0,
118: algorithm, 0, timeExpires, timeSigned, footprint, name,
119: signature);
120: m.addRecord(sig, Section.ADDITIONAL);
121: }
122:
123: }
|