Author: toad
Date: 2008-12-05 20:14:58 +0000 (Fri, 05 Dec 2008)
New Revision: 24070
Modified:
trunk/freenet/src/freenet/node/FNPPacketMangler.java
trunk/freenet/src/freenet/node/PacketTracker.java
trunk/freenet/src/freenet/node/PeerNode.java
trunk/freenet/src/freenet/support/Fields.java
Log:
Neg type 4: negotiate during JFK(3) and JFK(4) whether to reuse the old
PacketTracker.
Modified: trunk/freenet/src/freenet/node/FNPPacketMangler.java
===================================================================
--- trunk/freenet/src/freenet/node/FNPPacketMangler.java 2008-12-05
16:50:17 UTC (rev 24069)
+++ trunk/freenet/src/freenet/node/FNPPacketMangler.java 2008-12-05
20:14:58 UTC (rev 24070)
@@ -598,7 +598,7 @@
Logger.error(this, "Decrypted auth packet but invalid
version: "+version);
return;
}
- if(!(negType == 2 || negType == 3)) {
+ if(!(negType == 2 || negType == 3 || negType == 4)) {
Logger.error(this, "Unknown neg type: "+negType);
return;
}
@@ -663,7 +663,9 @@
} else if (negType == 1) {
Logger.error(this, "Old StationToStation (negType 1)
not supported.");
return;
- } else if (negType==2 || negType == 3){ // negType == 3 => no
new PacketTracker when rekeying
+ } else if (negType==2 || negType == 3 || negType == 4){
+ // negType == 3 => no new PacketTracker when rekeying
+ // negType == 4 => negotiate whether to use a new
PacketTracker when rekeying
/*
* We implement Just Fast Keying key management
protocol with active identity protection
* for the initiator and no identity protection for the
responder
@@ -1045,6 +1047,7 @@
(c.getBlockSize() >> 3) + // IV
HASH_LENGTH + // it's at least a signature
8 + // a bootid
+ (negType >= 4 ? 8 : 0) + // packet tracker ID
1; // znoderefI* is at least 1 byte long
if(payload.length < expectedLength + 3) {
@@ -1148,9 +1151,20 @@
decypheredPayloadOffset += Node.SIGNATURE_PARAMETER_LENGTH;
byte[] data = new byte[decypheredPayload.length -
decypheredPayloadOffset];
System.arraycopy(decypheredPayload, decypheredPayloadOffset,
data, 0, decypheredPayload.length - decypheredPayloadOffset);
- long bootID = Fields.bytesToLong(data);
- byte[] hisRef = new byte[data.length - 8];
- System.arraycopy(data, 8, hisRef, 0, hisRef.length);
+ int ptr = 0;
+ long trackerID;
+ if(negType >= 4) {
+ trackerID = Fields.bytesToLong(data, ptr);
+ if(trackerID < 0) trackerID = -1;
+ ptr += 8;
+ } else {
+ if(negType == 3) trackerID = -2; // emulate negtype = 3
behaviour
+ else trackerID = -1;
+ }
+ long bootID = Fields.bytesToLong(data, ptr);
+ ptr += 8;
+ byte[] hisRef = new byte[data.length - ptr];
+ System.arraycopy(data, ptr, hisRef, 0, hisRef.length);
// construct the peernode
if(unknownInitiator) {
@@ -1175,12 +1189,10 @@
// At this point we know it's from the peer, so we can report a
packet received.
pn.receivedPacket(true, false);
- // Send reply
- sendJFKMessage4(1, negType, 3, nonceInitiator,
nonceResponder,initiatorExponential, responderExponential,
- c, Ke, Ka, authenticator, hisRef, pn, replyTo,
unknownInitiator, setupType);
+ BlockCipher cs = null;
+ try { cs = new Rijndael(256, 256); } catch
(UnsupportedCipherException e) {}
+ cs.initialize(Ks);
- c.initialize(Ks);
-
// Promote if necessary
boolean dontWant = false;
if(oldOpennetPeer) {
@@ -1196,13 +1208,21 @@
// wantPeer will call node.peers.addPeer(), we don't
have to.
}
- if(pn.completedHandshake(bootID, hisRef, 0, hisRef.length, c,
Ks, replyTo, true, negType)) {
+ long newTrackerID = pn.completedHandshake(bootID, hisRef, 0,
hisRef.length, cs, Ks, replyTo, true, negType, trackerID, false, false);
+
+ if(newTrackerID > 0) {
+
+ // Send reply
+ sendJFKMessage4(1, negType, 3, nonceInitiator,
nonceResponder,initiatorExponential, responderExponential,
+ c, Ke, Ka, authenticator, hisRef, pn,
replyTo, unknownInitiator, setupType, newTrackerID, newTrackerID == trackerID);
+
if(dontWant)
- node.peers.disconnect(pn, true, false);
+ node.peers.disconnect(pn, true, false); // Let
it connect then tell it to remove it.
else
pn.maybeSendInitialMessages();
} else {
Logger.error(this, "Handshake failure! with
"+pn.getPeer());
+ // Don't send the JFK(4). We have not successfully
connected.
}
final long t2=System.currentTimeMillis();
@@ -1279,6 +1299,7 @@
HASH_LENGTH + // HMAC of the cyphertext
(c.getBlockSize() >> 3) + // IV
Node.SIGNATURE_PARAMETER_LENGTH * 2 + // the signature
+ (negType >= 4 ? 9 : 0) + // ID of packet tracker, plus
boolean byte
8+ // bootID
1; // znoderefR
@@ -1344,25 +1365,39 @@
decypheredPayloadOffset += Node.SIGNATURE_PARAMETER_LENGTH;
byte[] data = new byte[decypheredPayload.length -
decypheredPayloadOffset];
System.arraycopy(decypheredPayload, decypheredPayloadOffset,
data, 0, decypheredPayload.length - decypheredPayloadOffset);
- long bootID = Fields.bytesToLong(data);
- if(data.length - 8 < 0) {
+ int ptr = 0;
+ long trackerID;
+ boolean reusedTracker;
+ if(negType >= 4) {
+ trackerID = Fields.bytesToLong(data, ptr);
+ ptr += 8;
+ reusedTracker = data[ptr++] != 0;
+ } else {
+ if(negType == 3) trackerID = -2;
+ else trackerID = -1;
+ reusedTracker = false;
+ }
+ long bootID = Fields.bytesToLong(data, ptr);
+ ptr += 8;
+ if(data.length - ptr < 0) {
Logger.error(this, "No space for hisRef:
data.length="+data.length+"
myRef.length="+(pn.jfkMyRef==null?0:pn.jfkMyRef.length)+" orig data length
"+(payload.length-inputOffset));
return true;
}
- byte[] hisRef = new byte[data.length - 8];
- System.arraycopy(data, 8, hisRef, 0, hisRef.length);
+ byte[] hisRef = new byte[data.length - ptr];
+ System.arraycopy(data, ptr, hisRef, 0, hisRef.length);
// verify the signature
DSASignature remoteSignature = new DSASignature(new
NativeBigInteger(1,r), new NativeBigInteger(1,s));
- byte[] locallyGeneratedText = new byte[NONCE_SIZE * 2 +
DiffieHellman.modulusLengthInBytes() * 2 + crypto.myIdentity.length + 8
/*bootID*/ + hisRef.length + pn.jfkMyRef.length];
+ int dataLen = hisRef.length + 8 + (negType >= 4 ? 9 : 0);
+ byte[] locallyGeneratedText = new byte[NONCE_SIZE * 2 +
DiffieHellman.modulusLengthInBytes() * 2 + crypto.myIdentity.length + dataLen +
pn.jfkMyRef.length];
int bufferOffset = NONCE_SIZE * 2 +
DiffieHellman.modulusLengthInBytes()*2;
System.arraycopy(jfkBuffer, 0, locallyGeneratedText, 0,
bufferOffset);
byte[] identity = crypto.getIdentity(unknownInitiator);
System.arraycopy(identity, 0, locallyGeneratedText,
bufferOffset, identity.length);
bufferOffset += identity.length;
// bootID
- System.arraycopy(data, 0, locallyGeneratedText, bufferOffset,
hisRef.length + 8);
- bufferOffset += hisRef.length + 8;
+ System.arraycopy(data, 0, locallyGeneratedText, bufferOffset,
dataLen);
+ bufferOffset += dataLen;
System.arraycopy(pn.jfkMyRef, 0, locallyGeneratedText,
bufferOffset, pn.jfkMyRef.length);
byte[] messageHash = SHA256.digest(locallyGeneratedText);
if(!DSA.verify(pn.peerPubKey, remoteSignature, new
NativeBigInteger(1, messageHash), false)) {
@@ -1391,7 +1426,7 @@
// We change the key
c.initialize(pn.jfkKs);
- if(pn.completedHandshake(bootID, data, 8, data.length - 8, c,
pn.jfkKs, replyTo, false, negType)) {
+ if(pn.completedHandshake(bootID, hisRef, 0, hisRef.length, c,
pn.jfkKs, replyTo, false, negType, trackerID, true, reusedTracker) >= 0) {
if(dontWant)
node.peers.disconnect(pn, true, false);
else
@@ -1442,9 +1477,19 @@
if(ctx == null) return;
byte[] ourExponential =
stripBigIntegerToNetworkFormat(ctx.myExponential);
pn.jfkMyRef = unknownInitiator ?
crypto.myCompressedHeavySetupRef() : crypto.myCompressedSetupRef();
- byte[] data = new byte[8 + pn.jfkMyRef.length];
- System.arraycopy(Fields.longToBytes(node.bootID), 0, data, 0,
8);
- System.arraycopy(pn.jfkMyRef, 0, data, 8, pn.jfkMyRef.length);
+ byte[] data = new byte[(negType >= 4 ? 8 : 0) + 8 +
pn.jfkMyRef.length];
+ int ptr = 0;
+ if(negType >= 4) {
+ long trackerID;
+ if(pn == null)
+ trackerID = -1;
+ else trackerID = pn.getReusableTrackerID();
+ System.arraycopy(Fields.longToBytes(trackerID), 0,
data, ptr, 8);
+ ptr += 8;
+ }
+ System.arraycopy(Fields.longToBytes(node.bootID), 0, data, ptr,
8);
+ ptr += 8;
+ System.arraycopy(pn.jfkMyRef, 0, data, ptr, pn.jfkMyRef.length);
final byte[] message3 = new byte[NONCE_SIZE*2 + // nI, nR
DiffieHellman.modulusLengthInBytes()*2 + // g^i, g^r
HASH_LENGTH + // authenticator
@@ -1554,7 +1599,7 @@
* @param pn The PeerNode to encrypt the auth packet to. Cannot be
null, because even in anonymous initiator,
* we will have created one before calling this method.
*/
- private void sendJFKMessage4(int version,int negType,int phase,byte[]
nonceInitiator,byte[] nonceResponder,byte[] initiatorExponential,byte[]
responderExponential, BlockCipher c, byte[] Ke, byte[] Ka, byte[]
authenticator, byte[] hisRef, PeerNode pn, Peer replyTo, boolean
unknownInitiator, int setupType)
+ private void sendJFKMessage4(int version,int negType,int phase,byte[]
nonceInitiator,byte[] nonceResponder,byte[] initiatorExponential,byte[]
responderExponential, BlockCipher c, byte[] Ke, byte[] Ka, byte[]
authenticator, byte[] hisRef, PeerNode pn, Peer replyTo, boolean
unknownInitiator, int setupType, long newTrackerID, boolean sameAsOldTrackerID)
{
if(logMINOR)
Logger.minor(this, "Sending a JFK(4) message to
"+pn.getPeer());
@@ -1563,11 +1608,20 @@
NativeBigInteger _initiatorExponential = new
NativeBigInteger(1,initiatorExponential);
byte[] myRef = crypto.myCompressedSetupRef();
- byte[] data = new byte[8 + myRef.length + hisRef.length];
- System.arraycopy(Fields.longToBytes(node.bootID), 0, data, 0,
8);
- System.arraycopy(myRef, 0, data, 8, myRef.length);
- System.arraycopy(hisRef, 0, data, 8 + myRef.length,
hisRef.length);
+ byte[] data = new byte[(negType >= 4 ? 9 : 0) + 8 +
myRef.length + hisRef.length];
+ int ptr = 0;
+ if(negType >= 4) {
+ System.arraycopy(Fields.longToBytes(newTrackerID), 0,
data, ptr, 8);
+ ptr += 8;
+ data[ptr++] = (byte) (sameAsOldTrackerID ? 1 : 0);
+ }
+ System.arraycopy(Fields.longToBytes(node.bootID), 0, data, ptr,
8);
+ ptr += 8;
+ System.arraycopy(myRef, 0, data, ptr, myRef.length);
+ ptr += myRef.length;
+ System.arraycopy(hisRef, 0, data, ptr, hisRef.length);
+
byte[] params = assembleDHParams(nonceInitiator,
nonceResponder, _initiatorExponential, _responderExponential, pn.identity,
data);
byte[] messageHash = SHA256.digest(params);
if(logMINOR)
@@ -2816,7 +2870,7 @@
}
public int[] supportedNegTypes() {
- return new int[] { 2, 3 };
+ return new int[] { 2, 3, 4 };
}
public int fullHeadersLengthOneMessage() {
Modified: trunk/freenet/src/freenet/node/PacketTracker.java
===================================================================
--- trunk/freenet/src/freenet/node/PacketTracker.java 2008-12-05 16:50:17 UTC
(rev 24069)
+++ trunk/freenet/src/freenet/node/PacketTracker.java 2008-12-05 20:14:58 UTC
(rev 24070)
@@ -78,9 +78,16 @@
final long createdTime;
/** The time at which we last successfully decoded a packet. */
private long timeLastDecodedPacket;
+ /** Tracker ID. Must be positive. */
+ final long trackerID;
/** Everything is clear to start with */
PacketTracker(PeerNode pn) {
+ this(pn, pn.node.random.nextLong() & Long.MAX_VALUE);
+ }
+
+ PacketTracker(PeerNode pn, long tid) {
+ trackerID = tid;
this.pn = pn;
ackQueue = new LinkedList<QueuedAck>();
forgottenQueue = new LinkedList<QueuedForgotten>();
Modified: trunk/freenet/src/freenet/node/PeerNode.java
===================================================================
--- trunk/freenet/src/freenet/node/PeerNode.java 2008-12-05 16:50:17 UTC
(rev 24069)
+++ trunk/freenet/src/freenet/node/PeerNode.java 2008-12-05 20:14:58 UTC
(rev 24070)
@@ -1812,11 +1812,21 @@
* @param length Number of bytes to read.
* @param encKey The new session key.
* @param replyTo The IP the handshake came in on.
- * @return True unless we rejected the handshake, or it failed to parse.
+ * @param trackerID The tracker ID proposed by the other side. If -1,
create a new tracker. If -2,
+ * reuse the old tracker if possible. If any other value, check whether
we have it, and if we do,
+ * return that, otherwise return the ID of the new tracker.
+ * @param isJFK4 If true, we are processing a JFK(4) and must respect
the tracker ID chosen by the
+ * responder. If false, we are processing a JFK(3) and we can either
reuse the suggested tracker ID,
+ * which the other side is able to reuse, or we can create a new tracker
ID.
+ * @param jfk4SameAsOld If true, the responder chose to use the tracker
ID that we provided. If
+ * we don't have it now the connection fails.
+ * @return The ID of the new PacketTracker. If this is different to the
passed-in trackerID, then
+ * it's a new tracker. -1 to indicate failure.
*/
- public boolean completedHandshake(long thisBootID, byte[] data, int
offset, int length, BlockCipher encCipher, byte[] encKey, Peer replyTo, boolean
unverified, int negType) {
+ public long completedHandshake(long thisBootID, byte[] data, int
offset, int length, BlockCipher encCipher, byte[] encKey, Peer replyTo, boolean
unverified, int negType, long trackerID, boolean isJFK4, boolean jfk4SameAsOld)
{
logMINOR = Logger.shouldLog(Logger.MINOR, PeerNode.class);
long now = System.currentTimeMillis();
+ if(logMINOR) Logger.minor(this, "Tracker ID "+trackerID+"
isJFK4="+isJFK4+" jfk4SameAsOld="+jfk4SameAsOld);
// Update sendHandshakeTime; don't send another handshake for a
while.
// If unverified, "a while" determines the timeout; if not,
it's just good practice to avoid a race below.
@@ -1833,7 +1843,7 @@
}
Logger.error(this, "Failed to parse new noderef for " +
this + ": " + e1, e1);
node.peers.disconnected(this);
- return false;
+ return -1;
}
boolean routable = true;
boolean newer = false;
@@ -1869,6 +1879,7 @@
KeyTracker prev = null;
KeyTracker newTracker;
MessageItem[] messagesTellDisconnected = null;
+ PacketTracker packets = null;
synchronized(this) {
handshakeCount = 0;
bogusNoderef = false;
@@ -1894,11 +1905,52 @@
} else if(bootIDChanged && logMINOR)
Logger.minor(this, "Changed boot ID from " +
bootID + " to " + thisBootID + " for " + getPeer());
this.bootID = thisBootID;
- PacketTracker packets;
boolean newPacketTracker = false;
- if(bootIDChanged) {
+ if(currentTracker != null &&
currentTracker.packets.trackerID == trackerID &&
!currentTracker.packets.isDeprecated()) {
+ if(isJFK4 && !jfk4SameAsOld)
+ Logger.error(this, "In JFK(4), found
tracker ID "+trackerID+" but other side says is new! for "+this);
+ packets = currentTracker.packets;
+ if(logMINOR) Logger.minor(this, "Re-using
packet tracker ID "+trackerID+" on "+this+" from current "+currentTracker);
+ } else if(previousTracker != null &&
previousTracker.packets.trackerID == trackerID &&
!previousTracker.packets.isDeprecated()) {
+ if(isJFK4 && !jfk4SameAsOld)
+ Logger.error(this, "In JFK(4), found
tracker ID "+trackerID+" but other side says is new! for "+this);
+ packets = previousTracker.packets;
+ if(logMINOR) Logger.minor(this, "Re-using
packet tracker ID "+trackerID+" on "+this+" from prev "+previousTracker);
+ } else if(isJFK4 && jfk4SameAsOld) {
+ isConnected = false;
+ Logger.error(this, "Can't reuse old tracker ID
"+trackerID+" as instructed - disconnecting");
+ return -1;
+ } else if(trackerID == -1) {
+ // Create a new tracker unconditionally
packets = new PacketTracker(this);
newPacketTracker = true;
+ if(logMINOR) Logger.minor(this, "Creating new
PacketTracker as instructed for "+this);
+ } else if(trackerID == -2 && !bootIDChanged) {
+ // Reuse if not deprecated and not boot ID
changed
+ if(currentTracker != null &&
!currentTracker.packets.isDeprecated() && negType >= 3) {
+ packets = currentTracker.packets;
+ if(logMINOR) Logger.minor(this,
"Re-using packet tracker (not given an ID): "+packets.trackerID+" on "+this+"
from current "+currentTracker);
+ } else if(previousTracker != null &&
!previousTracker.packets.isDeprecated() && negType >= 3) {
+ packets = previousTracker.packets;
+ if(logMINOR) Logger.minor(this,
"Re-using packet tracker (not given an ID): "+packets.trackerID+" on "+this+"
from prev "+previousTracker);
+ } else {
+ packets = new PacketTracker(this);
+ newPacketTracker = true;
+ if(logMINOR) Logger.minor(this, "Cannot
reuse trackers (not given an ID) on "+this);
+ }
+ } else {
+ if(isJFK4 && negType >= 4 && trackerID < 0)
+ Logger.error(this, "JFK(4) packet with
neg type "+negType+" has negative tracker ID: "+trackerID);
+
+ if(isJFK4/* && !jfk4SameAsOld implied */ &&
trackerID >= 0) {
+ packets = new PacketTracker(this,
trackerID);
+ } else
+ packets = new PacketTracker(this);
+ newPacketTracker = true;
+ if(logMINOR) Logger.minor(this, "Creating new
tracker (last resort) on "+this);
+ }
+ if(bootIDChanged) {
+ newPacketTracker = true;
oldPrev = previousTracker;
oldCur = currentTracker;
previousTracker = null;
@@ -1910,14 +1962,6 @@
this.offeredMainJarVersion = 0;
} else {
// else it's a rekey
- if(currentTracker != null &&
!currentTracker.packets.isDeprecated() && negType >= 3)
- packets = currentTracker.packets;
- else if(previousTracker != null &&
!previousTracker.packets.isDeprecated() && negType >= 3)
- packets = previousTracker.packets;
- else {
- packets = new PacketTracker(this);
- newPacketTracker = true;
- }
}
newTracker = new KeyTracker(this, packets, encCipher,
encKey);
if(logMINOR) Logger.minor(this, "New key tracker in
completedHandshake: "+newTracker+" for "+shortToString()+" neg type "+negType+"
new packet tracker: "+newPacketTracker);
@@ -1990,7 +2034,7 @@
onConnect();
}
- return true;
+ return packets.trackerID;
}
/**
@@ -4201,4 +4245,17 @@
return false;
}
+
+ /**
+ * @return The ID of a reusable PacketTracker if there is one,
otherwise -1.
+ */
+ public long getReusableTrackerID() {
+ KeyTracker cur;
+ synchronized(this) {
+ cur = currentTracker;
+ }
+ if(cur == null) return -1;
+ if(cur.packets.isDeprecated()) return -1;
+ return cur.packets.trackerID;
+ }
}
Modified: trunk/freenet/src/freenet/support/Fields.java
===================================================================
--- trunk/freenet/src/freenet/support/Fields.java 2008-12-05 16:50:17 UTC
(rev 24069)
+++ trunk/freenet/src/freenet/support/Fields.java 2008-12-05 20:14:58 UTC
(rev 24070)
@@ -502,11 +502,18 @@
* Convert an array of bytes to a single long.
*/
public static long bytesToLong(byte[] buf) {
- if(buf.length < 8)
+ return bytesToLong(buf, 0);
+ }
+
+ /**
+ * Convert an array of bytes to a single long.
+ */
+ public static long bytesToLong(byte[] buf, int offset) {
+ if(buf.length < 8 + offset)
throw new IllegalArgumentException();
long x = 0;
for(int j = 7; j >= 0; j--) {
- long y = (buf[j] & 0xff);
+ long y = (buf[j + offset] & 0xff);
x = (x << 8) | y;
}
return x;
_______________________________________________
cvs mailing list
[email protected]
http://emu.freenetproject.org/cgi-bin/mailman/listinfo/cvs