Author: toad
Date: 2006-01-17 13:53:14 +0000 (Tue, 17 Jan 2006)
New Revision: 7868
Modified:
trunk/freenet/src/freenet/keys/ClientSSK.java
trunk/freenet/src/freenet/keys/FreenetURI.java
trunk/freenet/src/freenet/keys/NodeSSK.java
trunk/freenet/src/freenet/node/Node.java
trunk/freenet/src/freenet/node/RequestHandler.java
trunk/freenet/src/freenet/node/RequestSender.java
trunk/freenet/src/freenet/node/Version.java
Log:
358: (mandatory)
Fix KSKs.
Also fix issues related to corrupt pubkeys.
Modified: trunk/freenet/src/freenet/keys/ClientSSK.java
===================================================================
--- trunk/freenet/src/freenet/keys/ClientSSK.java 2006-01-16 18:58:14 UTC
(rev 7867)
+++ trunk/freenet/src/freenet/keys/ClientSSK.java 2006-01-17 13:53:14 UTC
(rev 7868)
@@ -15,7 +15,7 @@
/** Document name */
public final String docName;
/** Public key */
- public DSAPublicKey pubKey;
+ protected DSAPublicKey pubKey;
/** Public key hash */
public final byte[] pubKeyHash;
/** Encryption key */
@@ -96,7 +96,17 @@
}
public Key getNodeKey() {
- return new NodeSSK(pubKeyHash, ehDocname, pubKey);
+ try {
+ return new NodeSSK(pubKeyHash, ehDocname, pubKey);
+ } catch (SSKVerifyException e) {
+ IllegalStateException x = new
IllegalStateException("Have already verified and yet it fails!: "+e);
+ x.initCause(e);
+ throw x;
+ }
}
+ public DSAPublicKey getPubKey() {
+ return pubKey;
+ }
+
}
Modified: trunk/freenet/src/freenet/keys/FreenetURI.java
===================================================================
--- trunk/freenet/src/freenet/keys/FreenetURI.java 2006-01-16 18:58:14 UTC
(rev 7867)
+++ trunk/freenet/src/freenet/keys/FreenetURI.java 2006-01-17 13:53:14 UTC
(rev 7868)
@@ -155,7 +155,7 @@
sv.addElement(urlDecode(s));
URI = URI.substring(0, slash2);
}
- if(!"CHK".equals(keyType)) {
+ if("SSK".equals(keyType)) {
// docName not necessary, nor is it supported, for CHKs.
if(sv.isEmpty())
@@ -169,6 +169,11 @@
metaStr[i] = (String)
sv.elementAt(metaStr.length - 1 - i);
}
+ if(keyType.equalsIgnoreCase("KSK")) {
+ docName = URI;
+ return;
+ }
+
// URI now contains: routingKey[,cryptoKey][,metaInfo]
StringTokenizer st = new StringTokenizer(URI, ",");
try {
Modified: trunk/freenet/src/freenet/keys/NodeSSK.java
===================================================================
--- trunk/freenet/src/freenet/keys/NodeSSK.java 2006-01-16 18:58:14 UTC (rev
7867)
+++ trunk/freenet/src/freenet/keys/NodeSSK.java 2006-01-17 13:53:14 UTC (rev
7868)
@@ -9,6 +9,9 @@
import java.util.Arrays;
import freenet.crypt.DSAPublicKey;
+import freenet.support.Fields;
+import freenet.support.HexUtil;
+import freenet.support.Logger;
/**
* An SSK is a Signed Subspace Key.
@@ -27,21 +30,38 @@
final byte[] encryptedHashedDocname;
/** The signature key, if we know it */
DSAPublicKey pubKey;
+ final int hashCode;
static final int SSK_VERSION = 1;
static final int PUBKEY_HASH_SIZE = 32;
static final int E_H_DOCNAME_SIZE = 32;
- public NodeSSK(byte[] pkHash, byte[] ehDocname, DSAPublicKey pubKey) {
+ public String toString() {
+ return
super.toString()+":pkh="+HexUtil.bytesToHex(pubKeyHash)+":ehd="+HexUtil.bytesToHex(encryptedHashedDocname);
+ }
+
+ public NodeSSK(byte[] pkHash, byte[] ehDocname, DSAPublicKey pubKey)
throws SSKVerifyException {
super(makeRoutingKey(pkHash, ehDocname));
this.encryptedHashedDocname = ehDocname;
this.pubKeyHash = pkHash;
this.pubKey = pubKey;
+ if(pubKey != null) {
+ MessageDigest md256;
+ try {
+ md256 = MessageDigest.getInstance("SHA-256");
+ } catch (NoSuchAlgorithmException e) {
+ throw new Error(e);
+ }
+ byte[] hash = md256.digest(pubKey.asBytes());
+ if(!Arrays.equals(hash, pkHash))
+ throw new SSKVerifyException("Invalid pubKey:
wrong hash");
+ }
if(ehDocname.length != E_H_DOCNAME_SIZE)
throw new IllegalArgumentException("ehDocname must be
"+E_H_DOCNAME_SIZE+" bytes");
if(pkHash.length != PUBKEY_HASH_SIZE)
throw new IllegalArgumentException("pubKeyHash must be
"+PUBKEY_HASH_SIZE+" bytes");
+ hashCode = Fields.hashCode(pkHash) ^ Fields.hashCode(ehDocname);
}
// routingKey = H( E(H(docname)) + H(pubkey) )
@@ -71,7 +91,14 @@
raf.readFully(buf);
byte[] buf2 = new byte[PUBKEY_HASH_SIZE];
raf.readFully(buf2);
- return new NodeSSK(buf2, buf, null);
+ try {
+ return new NodeSSK(buf2, buf, null);
+ } catch (SSKVerifyException e) {
+ IllegalStateException impossible =
+ new IllegalStateException("Impossible: "+e);
+ impossible.initCause(e);
+ throw impossible;
+ }
}
public short getType() {
@@ -100,10 +127,27 @@
return pubKeyHash;
}
- public void setPubKey(DSAPublicKey pubKey2) {
+ public void setPubKey(DSAPublicKey pubKey2) throws SSKVerifyException {
if(pubKey == pubKey2) return;
- if(pubKey != null && !pubKey.equals(pubKey2)) throw new
IllegalStateException("Already assigned pubkey to different value!
Old="+pubKey.writeAsField()+", new="+pubKey2.writeAsField());
- this.pubKey = pubKey2;
+ if(pubKey2 == null) return;
+ if(pubKey == null || !pubKey2.equals(pubKey)) {
+ if(pubKey != null) {
+ MessageDigest md256;
+ try {
+ md256 =
MessageDigest.getInstance("SHA-256");
+ } catch (NoSuchAlgorithmException e) {
+ throw new Error(e);
+ }
+ byte[] newPubKeyHash =
md256.digest(pubKey2.asBytes());
+ if(Arrays.equals(pubKeyHash, newPubKeyHash)) {
+ Logger.error(this, "Found SHA-256
collision or something... WTF?");
+ } else {
+ throw new SSKVerifyException("New
pubkey has invalid hash");
+ }
+ throw new SSKVerifyException("Invalid new
pubkey: "+pubKey2+" old pubkey: "+pubKey);
+ }
+ pubKey = pubKey2;
+ }
}
public boolean equals(Object o) {
@@ -116,4 +160,8 @@
return true;
}
+ public int hashCode() {
+ return hashCode;
+ }
+
}
Modified: trunk/freenet/src/freenet/node/Node.java
===================================================================
--- trunk/freenet/src/freenet/node/Node.java 2006-01-16 18:58:14 UTC (rev
7867)
+++ trunk/freenet/src/freenet/node/Node.java 2006-01-17 13:53:14 UTC (rev
7868)
@@ -19,6 +19,7 @@
import java.net.SocketException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -466,6 +467,11 @@
}
public ClientKeyBlock getKey(ClientKey key, boolean localOnly,
RequestStarterClient client, boolean cache) throws LowLevelGetException {
+ if(key instanceof ClientSSK) {
+ ClientSSK k = (ClientSSK) key;
+ if(k.getPubKey() != null)
+ cacheKey(k.pubKeyHash, k.getPubKey());
+ }
if(localOnly)
return realGetKey(key, localOnly, cache);
else
@@ -560,6 +566,7 @@
case RequestSender.TIMED_OUT:
throw new
LowLevelGetException(LowLevelGetException.REJECTED_OVERLOAD);
case RequestSender.INTERNAL_ERROR:
+ throw new
LowLevelGetException(LowLevelGetException.INTERNAL_ERROR);
default:
Logger.error(this, "Unknown RequestSender code
in getCHK: "+rs.getStatus()+" on "+rs);
throw new
LowLevelGetException(LowLevelGetException.INTERNAL_ERROR);
@@ -986,9 +993,15 @@
DSAPublicKey pubKey = k.getPubKey();
if(pubKey == null) {
pubKey = getKey(k.getPubKeyHash());
- k.setPubKey(pubKey);
+ Logger.minor(this, "Got pubkey: "+pubKey+"
"+pubKey.writeAsField());
+ try {
+ k.setPubKey(pubKey);
+ } catch (SSKVerifyException e) {
+ Logger.error(this, "Error
setting pubkey: "+e, e);
+ }
}
if(pubKey != null) {
+ Logger.minor(this, "Got pubkey: "+pubKey+"
"+pubKey.writeAsField());
chk = sskDatastore.fetch((NodeSSK)key, !cache);
} else {
Logger.minor(this, "Not found because no
pubkey: "+uid);
@@ -1416,8 +1429,31 @@
ImmutableByteArrayWrapper w = new
ImmutableByteArrayWrapper(hash);
synchronized(cachedPubKeys) {
DSAPublicKey key2 = (DSAPublicKey) cachedPubKeys.get(w);
- if(key2 != null && !key2.equals(key))
+ if(key2 != null && !key2.equals(key)) {
+ MessageDigest md256;
+ // Check the hash.
+ try {
+ md256 =
MessageDigest.getInstance("SHA-256");
+ } catch (NoSuchAlgorithmException e) {
+ throw new Error(e);
+ }
+ byte[] hashCheck = md256.digest(key.asBytes());
+ if(Arrays.equals(hashCheck, hash)) {
+ Logger.error(this, "Hash is
correct!!!");
+ // Verify the old key
+ byte[] oldHash =
md256.digest(key2.asBytes());
+ if(Arrays.equals(oldHash, hash)) {
+ Logger.error(this, "Old hash is
correct too!! - Bug in DSAPublicKey.equals() or SHA-256 collision!");
+ } else {
+ Logger.error(this, "Old hash is
wrong!");
+ cachedPubKeys.removeKey(w);
+ cacheKey(hash, key);
+ }
+ } else {
+ Logger.error(this, "New hash is wrong");
+ }
throw new IllegalArgumentException("Wrong
hash?? Already have different key with same hash!");
+ }
cachedPubKeys.push(w, key);
while(cachedPubKeys.size() > MAX_CACHED_KEYS)
cachedPubKeys.popKey();
Modified: trunk/freenet/src/freenet/node/RequestHandler.java
===================================================================
--- trunk/freenet/src/freenet/node/RequestHandler.java 2006-01-16 18:58:14 UTC
(rev 7867)
+++ trunk/freenet/src/freenet/node/RequestHandler.java 2006-01-17 13:53:14 UTC
(rev 7868)
@@ -1,5 +1,6 @@
package freenet.node;
+import freenet.crypt.DSAPublicKey;
import freenet.io.comm.DMT;
import freenet.io.comm.Message;
import freenet.io.xfer.BlockTransmitter;
@@ -64,7 +65,9 @@
source.send(df);
if(key instanceof NodeSSK) {
if(needsPubKey) {
- Message pk = DMT.createFNPSSKPubKey(uid,
((NodeSSK)block.getKey()).getPubKey().asBytes());
+ DSAPublicKey key =
((NodeSSK)block.getKey()).getPubKey();
+ Message pk = DMT.createFNPSSKPubKey(uid, key.asBytes());
+ Logger.minor(this, "Sending PK: "+key+"
"+key.writeAsField());
source.send(pk);
}
}
Modified: trunk/freenet/src/freenet/node/RequestSender.java
===================================================================
--- trunk/freenet/src/freenet/node/RequestSender.java 2006-01-16 18:58:14 UTC
(rev 7867)
+++ trunk/freenet/src/freenet/node/RequestSender.java 2006-01-17 13:53:14 UTC
(rev 7868)
@@ -85,7 +85,9 @@
this.source = source;
this.nearestLoc = nearestLoc;
if(key instanceof NodeSSK && pubKey == null) {
- pubKey = node.getKey(((NodeSSK)key).getPubKeyHash());
+ pubKey = ((NodeSSK)key).getPubKey();
+ if(pubKey == null)
+ pubKey = node.getKey(((NodeSSK)key).getPubKeyHash());
}
target = key.toNormalizedDouble();
@@ -335,12 +337,16 @@
}
byte[] pubkeyAsBytes =
((ShortBuffer)msg.getObject(DMT.PUBKEY_AS_BYTES)).getData();
try {
- pubKey = new
DSAPublicKey(pubkeyAsBytes);
+ if(pubKey == null)
+ pubKey = new
DSAPublicKey(pubkeyAsBytes);
((NodeSSK)key).setPubKey(pubKey);
+ } catch (SSKVerifyException e) {
+ pubKey = null;
+ Logger.error(this, "Invalid pubkey from
"+source+" on "+uid+" (wrong hash)");
+ break; // try next node
} catch (IOException e) {
Logger.error(this, "Invalid pubkey from
"+source+" on "+uid);
- finish(VERIFY_FAILURE, next);
- return;
+ break; // try next node
}
if(sskData != null) {
finishSSK(next);
Modified: trunk/freenet/src/freenet/node/Version.java
===================================================================
--- trunk/freenet/src/freenet/node/Version.java 2006-01-16 18:58:14 UTC (rev
7867)
+++ trunk/freenet/src/freenet/node/Version.java 2006-01-17 13:53:14 UTC (rev
7868)
@@ -20,10 +20,10 @@
public static final String protocolVersion = "1.0";
/** The build number of the current revision */
- public static final int buildNumber = 357;
+ public static final int buildNumber = 358;
/** Oldest build of Fred we will talk to */
- public static final int lastGoodBuild = 357;
+ public static final int lastGoodBuild = 358;
/** The highest reported build of fred */
public static int highestSeenBuild = buildNumber;