Author: nextgens
Date: 2007-09-30 08:40:45 +0000 (Sun, 30 Sep 2007)
New Revision: 15413
Modified:
trunk/freenet/src/freenet/node/FNPPacketMangler.java
Log:
* Fix r15411 (ensure that the nonce sent back by the responder is the one we
have chosen)
* Sign SA and SA' in message3 and message4
Modified: trunk/freenet/src/freenet/node/FNPPacketMangler.java
===================================================================
--- trunk/freenet/src/freenet/node/FNPPacketMangler.java 2007-09-30
07:01:20 UTC (rev 15412)
+++ trunk/freenet/src/freenet/node/FNPPacketMangler.java 2007-09-30
08:40:45 UTC (rev 15413)
@@ -514,12 +514,14 @@
DiffieHellmanLightContext dhContext =
getLightDiffieHellmanContext(pn);
int offset = 0;
byte[] myExponential =
stripBigIntegerToNetworkFormat(dhContext.myExponential);
- pn.jfkNonceInitiator = new byte[NONCE_SIZE];
- node.random.nextBytes(pn.jfkNonceInitiator);
+ byte[] nonce = new byte[NONCE_SIZE];
+ node.random.nextBytes(nonce);
+ pn.jfkNonceInitiator.put(replyTo, nonce);
+
byte[] message1 = new
byte[NONCE_SIZE+DiffieHellman.modulusLengthInBytes()];
- System.arraycopy(pn.jfkNonceInitiator, 0, message1, offset,
NONCE_SIZE);
+ System.arraycopy(nonce, 0, message1, offset, NONCE_SIZE);
offset += NONCE_SIZE;
System.arraycopy(myExponential, 0, message1, offset,
DiffieHellman.modulusLengthInBytes());
@@ -653,6 +655,16 @@
}
// sanity check
+ byte[] myNi = (byte[]) pn.jfkNonceInitiator.get(replyTo);
+ // We don't except such a message;
+ if(myNi == null) {
+ Logger.normal(this, "We received an unexpected JFK(3)
message from "+pn);
+ return;
+ } else if(!Arrays.equals(myNi, nonceInitiator)){
+ Logger.error(this, "The responder has tampered the
nonce in JFK(3)!! - "+pn);
+ return;
+ }
+
if(_hisExponential.compareTo(NativeBigInteger.ONE) < 1) {
Logger.error(this, "We can't accept the exponential
"+pn+" sent us; it's smaller than 1!!");
return;
@@ -684,6 +696,13 @@
* Compute the signature of the unVerifiedData and encrypt it using a
shared key
* which is derived from DHExponentials and the nonces; add a HMAC to
protect it
*
+ * Format:
+ * Ni, Nr, g^i, g^r
+ * Authenticator - HMAC{g^ir}(g^r, Nr, Ni, IP)
+ * HMAC{Ka}(cyphertext)
+ * IV + E{KE}[S{i}[Ni,Nr,g^i,g^r,idR, bootID, znoderefI], bootID,
znoderefI]
+ *
+ *
* @param Payload
* @param The peer to which we need to send the packet
* @param The peerNode we are talking to
@@ -694,11 +713,6 @@
final long t1 = System.currentTimeMillis();
if(logMINOR) Logger.minor(this, "Got a JFK(3) message,
processing it - "+pn);
- byte[] myNi = pn.jfkNonceInitiator;
- // We don't except such a message;
- if(myNi == null)
- return;
-
BlockCipher c = null;
try { c = new Rijndael(256, 256); } catch
(UnsupportedCipherException e) {}
int inputOffset=3;
@@ -758,12 +772,6 @@
}
return;
}
-
- // some sanity checks
- if(!Arrays.equals(myNi, nonceInitiator)) {
- Logger.error(this, "Huh? the responder sent us a
different nonce back! -"+pn);
- return;
- }
NativeBigInteger _hisExponential = new NativeBigInteger(1,
initiatorExponential);
if(_hisExponential.compareTo(NativeBigInteger.ONE) < 1) {
@@ -818,17 +826,18 @@
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);
// verify the signature
DSASignature remoteSignature = new DSASignature(new
NativeBigInteger(1,r), new NativeBigInteger(1,s));
- if(!DSA.verify(pn.peerPubKey, remoteSignature, new
NativeBigInteger(1, SHA256.digest(assembleDHParams(nonceInitiator,
nonceResponder, _hisExponential, _ourExponential, crypto.myIdentity))), false))
{
+ if(!DSA.verify(pn.peerPubKey, remoteSignature, new
NativeBigInteger(1, SHA256.digest(assembleDHParams(nonceInitiator,
nonceResponder, _hisExponential, _ourExponential, crypto.myIdentity, data))),
false)) {
Logger.error(this, "The signature verification has
failed!! JFK(3) - "+pn);
return;
}
// Send reply
- sendJFKMessage4(1, 2, 3, nonceInitiator,
nonceResponder,initiatorExponential, responderExponential, c, Ke, Ka,
authenticator, pn, replyTo);
+ sendJFKMessage4(1, 2, 3, nonceInitiator,
nonceResponder,initiatorExponential, responderExponential, c, Ke, Ka,
authenticator, hisRef, pn, replyTo);
c.initialize(Ks);
// Promote if necessary
@@ -846,7 +855,7 @@
// wantPeer will call node.peers.addPeer(), we don't
have to.
}
- if(pn.completedHandshake(bootID, data, 8, data.length-8, c, Ks,
replyTo, true)) {
+ if(pn.completedHandshake(bootID, hisRef, 0, hisRef.length, c,
Ks, replyTo, true)) {
if(dontWant)
node.peers.disconnect(pn, true, false);
else
@@ -864,6 +873,10 @@
* Responder Method:Message4
* Process Message4
*
+ * Format:
+ * HMAC{Ka}[cyphertext]
+ * IV + E{Ke}[S{R}[Ni, Nr, g^i, g^r, IDi, bootID, znoderefR,
znoderefI], bootID, znoderefR]
+ *
* @param Payload
* @param The peerNode we are talking to
* @param replyTo the Peer we are replying to
@@ -879,7 +892,7 @@
final int expectedLength = HASH_LENGTH + // HMAC of the
cyphertext
(c.getBlockSize() >> 3) + // IV
HASH_LENGTH + // the signature
- 8
// the bootid; there should be the noderef too
+
pn.jfkMyRef.length // the bootid + mynoderef
;
if(payload.length < expectedLength + 3) {
Logger.error(this, "Packet too short from "+pn+":
"+payload.length+" after decryption in JFK(4), should be "+(expectedLength +
3));
@@ -895,7 +908,6 @@
System.arraycopy(payload, inputOffset, hmac, 0, HASH_LENGTH);
inputOffset += HASH_LENGTH;
- //FIXME: do we need to "c.initialize(Ke);" ? I don't think so
but I'm not sure - nextgens
c.initialize(pn.jfkKe);
final PCFBMode pk = PCFBMode.create(c);
int ivLength = pk.lengthIV();
@@ -930,13 +942,20 @@
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 - pn.jfkMyRef.length - 8];
+ System.arraycopy(data, 8, 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];
+ byte[] locallyGeneratedText = new byte[NONCE_SIZE * 2 +
DiffieHellman.modulusLengthInBytes() * 2 + crypto.myIdentity.length + 8
/*bootID*/ + hisRef.length + pn.jfkMyRef.length];
int bufferOffset = NONCE_SIZE * 2 +
DiffieHellman.modulusLengthInBytes()*2;
System.arraycopy(jfkBuffer, 0, locallyGeneratedText, 0,
bufferOffset);
System.arraycopy(crypto.myIdentity, 0, locallyGeneratedText,
bufferOffset, crypto.myIdentity.length);
+ bufferOffset += crypto.myIdentity.length;
+ // bootID
+ System.arraycopy(data, 0, locallyGeneratedText, bufferOffset,
data.length - pn.jfkMyRef.length);
+ bufferOffset += data.length - pn.jfkMyRef.length;
+ System.arraycopy(pn.jfkMyRef, 0, locallyGeneratedText,
bufferOffset, pn.jfkMyRef.length);
if(!DSA.verify(pn.peerPubKey, remoteSignature, new
NativeBigInteger(1, SHA256.digest(locallyGeneratedText)), false)) {
Logger.error(this, "The signature verification has
failed!! JFK(4) -"+pn);
return;
@@ -973,7 +992,7 @@
pn.jfkKa = null;
pn.jfkKe = null;
pn.jfkKs = null;
- pn.jfkNonceInitiator = null;
+ pn.jfkNonceInitiator.clear();
final long t2=System.currentTimeMillis();
if((t2-t1)>500)
@@ -1000,9 +1019,8 @@
* Ni, Nr, g^i, g^r
* Authenticator - HMAC{g^ir}(g^r, Nr, Ni, IP)
* HMAC{Ka}(cyphertext)
- * IV + E{KE}[S{i}[Ni,Nr,g^i,g^r,idR], bootID, znoderef]
+ * IV + E{KE}[S{i}[Ni,Nr,g^i,g^r,idR, bootID, znoderefI], bootID,
znoderefI]
*
- * FIXME: neither the bootID nor the noderef are signed at that level;
should they be ?
*/
private void sendJFKMessage3(int version,int negType,int phase,byte[]
nonceInitiator,byte[] nonceResponder,byte[] hisExponential, byte[]
authenticator, PeerNode pn, Peer replyTo)
@@ -1012,10 +1030,10 @@
try { c = new Rijndael(256, 256); } catch
(UnsupportedCipherException e) {}
DiffieHellmanLightContext dhContext =
getLightDiffieHellmanContext(pn);
byte[] ourExponential =
stripBigIntegerToNetworkFormat(dhContext.myExponential);
- byte[] myRef = crypto.myCompressedSetupRef();
- byte[] data = new byte[8 + myRef.length];
+ pn.jfkMyRef = crypto.myCompressedSetupRef();
+ byte[] data = new byte[8 + pn.jfkMyRef.length];
System.arraycopy(Fields.longToBytes(node.bootID), 0, data, 0,
8);
- System.arraycopy(myRef, 0, data, 8, myRef.length);
+ System.arraycopy(pn.jfkMyRef, 0, data, 8, pn.jfkMyRef.length);
byte[] message3 = new byte[NONCE_SIZE*2 + // nI, nR
DiffieHellman.modulusLengthInBytes()*2 + // g^i, g^r
HASH_LENGTH + // authenticator
@@ -1047,7 +1065,7 @@
NativeBigInteger _ourExponential = new
NativeBigInteger(1,ourExponential);
NativeBigInteger _hisExponential = new
NativeBigInteger(1,hisExponential);
// save parameters so that we can verify message4
- byte[] toSign = assembleDHParams(nonceInitiator,
nonceResponder, _ourExponential, _hisExponential, pn.identity);
+ byte[] toSign = assembleDHParams(nonceInitiator,
nonceResponder, _ourExponential, _hisExponential, pn.identity, data);
pn.setJFKBuffer(toSign);
DSASignature localSignature =
crypto.sign(SHA256.digest(toSign));
byte[] r =
localSignature.getRBytes(Node.SIGNATURE_PARAMETER_LENGTH);
@@ -1107,26 +1125,26 @@
/*
* Format:
* HMAC{Ka}(cyphertext)
- * IV, E{Ke}[Sr[Ni,Nr,g^i,g^r,idI],bootID,znoderef]
+ * IV, E{Ke}[S{R}[Ni,Nr,g^i,g^r,idI, bootID, znoderefR,
znoderefI],bootID,znoderefR]
*
- * FIXME: neither bootID nor znoderef are signed; should they be?
*/
- 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, PeerNode pn, Peer replyTo)
+ 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)
{
if(logMINOR)
Logger.minor(this, "Sending a JFK(4) message to "+pn);
NativeBigInteger _responderExponential = new
NativeBigInteger(1,responderExponential);
NativeBigInteger _initiatorExponential = new
NativeBigInteger(1,initiatorExponential);
- DSASignature localSignature =
crypto.sign(SHA256.digest(assembleDHParams(nonceInitiator, nonceResponder,
_initiatorExponential, _responderExponential, pn.identity)));
- byte[] r =
localSignature.getRBytes(Node.SIGNATURE_PARAMETER_LENGTH);
- byte[] s =
localSignature.getSBytes(Node.SIGNATURE_PARAMETER_LENGTH);
-
byte[] myRef = crypto.myCompressedSetupRef();
- byte[] data = new byte[8 + myRef.length];
+ 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);
+ DSASignature localSignature =
crypto.sign(SHA256.digest(assembleDHParams(nonceInitiator, nonceResponder,
_initiatorExponential, _responderExponential, pn.identity, data)));
+ byte[] r =
localSignature.getRBytes(Node.SIGNATURE_PARAMETER_LENGTH);
+ byte[] s =
localSignature.getSBytes(Node.SIGNATURE_PARAMETER_LENGTH);
+
PCFBMode pk=PCFBMode.create(c);
int ivLength = pk.lengthIV();
byte[] iv=new byte[ivLength];
@@ -2414,7 +2432,7 @@
}
public int[] supportedNegTypes() {
- return new int[] { 2, 1 };
+ return new int[] { 2 };
}
public int fullHeadersLengthOneMessage() {
@@ -2464,10 +2482,10 @@
return toSign;
}
- private byte[] assembleDHParams(byte[] nonceInitiator,byte[]
nonceResponder,BigInteger initiatorExponential, BigInteger
responderExponential, byte[] id) {
+ private byte[] assembleDHParams(byte[] nonceInitiator,byte[]
nonceResponder,BigInteger initiatorExponential, BigInteger
responderExponential, byte[] id, byte[] sa) {
byte[] _initiatorExponential =
stripBigIntegerToNetworkFormat(initiatorExponential);
byte[] _responderExponential =
stripBigIntegerToNetworkFormat(responderExponential);
- byte[] result = new byte[nonceInitiator.length +
nonceResponder.length + _initiatorExponential.length +
_responderExponential.length + id.length];
+ byte[] result = new byte[nonceInitiator.length +
nonceResponder.length + _initiatorExponential.length +
_responderExponential.length + id.length + sa.length];
int offset = 0;
System.arraycopy(nonceInitiator,
0,result,offset,nonceInitiator.length);
@@ -2479,6 +2497,8 @@
System.arraycopy(_responderExponential, 0, result, offset,
_responderExponential.length);
offset += _responderExponential.length;
System.arraycopy(id, 0, result , offset,id.length);
+ offset += id.length;
+ System.arraycopy(sa, 0, result , offset,sa.length);
return result;
}