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;


Reply via email to