Author: nextgens
Date: 2006-09-05 14:14:13 +0000 (Tue, 05 Sep 2006)
New Revision: 10395
Added:
trunk/freenet/src/freenet/io/comm/ReferenceSignatureVerificationException.java
Modified:
trunk/freenet/src/freenet/clients/http/DarknetConnectionsToadlet.java
trunk/freenet/src/freenet/node/Node.java
trunk/freenet/src/freenet/node/PeerManager.java
trunk/freenet/src/freenet/node/PeerNode.java
trunk/freenet/src/freenet/node/TextModeClientInterface.java
trunk/freenet/src/freenet/node/fcp/AddPeer.java
Log:
Implement most of #51: Reference signature
Maybe error messages ought to be polished ...
It's probably possible to improve the cache mechanism on Node.exportFieldSet()
...
So far it hasn't broken anything for me, but it has to be reviewed carefully!
Modified: trunk/freenet/src/freenet/clients/http/DarknetConnectionsToadlet.java
===================================================================
--- trunk/freenet/src/freenet/clients/http/DarknetConnectionsToadlet.java
2006-09-05 13:29:07 UTC (rev 10394)
+++ trunk/freenet/src/freenet/clients/http/DarknetConnectionsToadlet.java
2006-09-05 14:14:13 UTC (rev 10395)
@@ -20,6 +20,7 @@
import freenet.client.HighLevelSimpleClient;
import freenet.io.comm.IOStatisticCollector;
import freenet.io.comm.PeerParseException;
+import freenet.io.comm.ReferenceSignatureVerificationException;
import freenet.node.FSParseException;
import freenet.node.Node;
import freenet.node.NodeClientCore;
@@ -586,6 +587,9 @@
} catch (PeerParseException e1) {
this.sendErrorPage(ctx, 200, "Failed To Add
Node", "Unable to parse the given text as a node reference. Please try again.");
return;
+ } catch (ReferenceSignatureVerificationException e1){
+ this.sendErrorPage(ctx, 200, "Failed To Add
Node", "Unable to verify the signature of the given reference.");
+ return;
}
if(pn.getIdentityHash()==node.getIdentityHash()) {
this.sendErrorPage(ctx, 200, "Failed To Add
Node", "You can\u2019t add your own node to the list of remote peers.");
Added:
trunk/freenet/src/freenet/io/comm/ReferenceSignatureVerificationException.java
===================================================================
---
trunk/freenet/src/freenet/io/comm/ReferenceSignatureVerificationException.java
2006-09-05 13:29:07 UTC (rev 10394)
+++
trunk/freenet/src/freenet/io/comm/ReferenceSignatureVerificationException.java
2006-09-05 14:14:13 UTC (rev 10395)
@@ -0,0 +1,21 @@
+package freenet.io.comm;
+
+/**
+ * Thown when we can't parse a string to a Peer.
+ * @author amphibian
+ */
+public class ReferenceSignatureVerificationException extends Exception {
+ private static final long serialVersionUID = -1;
+ public ReferenceSignatureVerificationException(Exception e) {
+ super(e);
+ }
+
+ public ReferenceSignatureVerificationException() {
+ super();
+ }
+
+ public ReferenceSignatureVerificationException(String string) {
+ super(string);
+ }
+
+}
Modified: trunk/freenet/src/freenet/node/Node.java
===================================================================
--- trunk/freenet/src/freenet/node/Node.java 2006-09-05 13:29:07 UTC (rev
10394)
+++ trunk/freenet/src/freenet/node/Node.java 2006-09-05 14:14:13 UTC (rev
10395)
@@ -17,6 +17,7 @@
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
+import java.math.BigInteger;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.UnknownHostException;
@@ -39,9 +40,11 @@
import freenet.config.LongCallback;
import freenet.config.StringCallback;
import freenet.config.SubConfig;
+import freenet.crypt.DSA;
import freenet.crypt.DSAGroup;
import freenet.crypt.DSAPrivateKey;
import freenet.crypt.DSAPublicKey;
+import freenet.crypt.DSASignature;
import freenet.crypt.Global;
import freenet.crypt.RandomSource;
import freenet.io.comm.DMT;
@@ -332,8 +335,12 @@
/** Hash of identity. Used as setup key. */
byte[] identityHash;
/** Hash of hash of identity i.e. hash of setup key. */
- byte[] identityHashHash;
- String myName;
+ byte[] identityHashHash;
+ /** The signature of the above fieldset */
+ private DSASignature myReferenceSignature = null;
+ /** An ordered version of the FieldSet, without the signature */
+ private String mySignedReference = null;
+ private String myName;
final LocationManager lm;
final PeerManager peers; // my peers
/** Directory to put node, peers, etc into */
@@ -1649,6 +1656,14 @@
fs.put("dsaPubKey", myPubKey.asFieldSet());
fs.put("ark.number", Long.toString(this.myARKNumber));
fs.put("ark.pubURI", this.myARK.getURI().toString(false));
+
+ // TODO: maybe synchronize ?
+ if(myReferenceSignature == null || mySignedReference == null ||
!mySignedReference.equals(fs.toOrderedString())){
+ mySignedReference = fs.toOrderedString();
+ myReferenceSignature = DSA.sign(myCryptoGroup,
myPrivKey, new BigInteger(mySignedReference.getBytes()), random);
+ }
+ fs.put("sig", myReferenceSignature.toString());
+
if(logMINOR) Logger.minor(this, "My reference: "+fs);
return fs;
}
Modified: trunk/freenet/src/freenet/node/PeerManager.java
===================================================================
--- trunk/freenet/src/freenet/node/PeerManager.java 2006-09-05 13:29:07 UTC
(rev 10394)
+++ trunk/freenet/src/freenet/node/PeerManager.java 2006-09-05 14:14:13 UTC
(rev 10395)
@@ -18,6 +18,7 @@
import freenet.io.comm.NotConnectedException;
import freenet.io.comm.Peer;
import freenet.io.comm.PeerParseException;
+import freenet.io.comm.ReferenceSignatureVerificationException;
import freenet.node.useralerts.PeerManagerUserAlert;
import freenet.support.Logger;
import freenet.support.SimpleFieldSet;
@@ -111,7 +112,10 @@
} catch (PeerParseException e2) {
Logger.error(this, "Could not parse peer:
"+e2+"\n"+fs.toString(),e2);
continue;
- }
+ } catch (ReferenceSignatureVerificationException e2) {
+ Logger.error(this, "Could not parse peer:
"+e2+"\n"+fs.toString(),e2);
+ continue;
+ }
addPeer(pn);
gotSome = true;
}
@@ -276,7 +280,7 @@
/**
* Connect to a node provided the fieldset representing it.
*/
- public void connect(SimpleFieldSet noderef) throws FSParseException,
PeerParseException {
+ public void connect(SimpleFieldSet noderef) throws FSParseException,
PeerParseException, ReferenceSignatureVerificationException {
PeerNode pn = new PeerNode(noderef, node, false);
for(int i=0;i<myPeers.length;i++) {
if(Arrays.equals(myPeers[i].identity, pn.identity)) return;
Modified: trunk/freenet/src/freenet/node/PeerNode.java
===================================================================
--- trunk/freenet/src/freenet/node/PeerNode.java 2006-09-05 13:29:07 UTC
(rev 10394)
+++ trunk/freenet/src/freenet/node/PeerNode.java 2006-09-05 14:14:13 UTC
(rev 10395)
@@ -12,6 +12,7 @@
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
+import java.math.BigInteger;
import java.net.MalformedURLException;
import java.net.UnknownHostException;
import java.security.MessageDigest;
@@ -28,6 +29,10 @@
import freenet.client.async.USKRetriever;
import freenet.client.async.USKRetrieverCallback;
import freenet.crypt.BlockCipher;
+import freenet.crypt.DSA;
+import freenet.crypt.DSAGroup;
+import freenet.crypt.DSAPublicKey;
+import freenet.crypt.DSASignature;
import freenet.crypt.DiffieHellmanContext;
import freenet.crypt.UnsupportedCipherException;
import freenet.crypt.ciphers.Rijndael;
@@ -40,6 +45,7 @@
import freenet.io.comm.Peer;
import freenet.io.comm.PeerContext;
import freenet.io.comm.PeerParseException;
+import freenet.io.comm.ReferenceSignatureVerificationException;
import freenet.keys.ClientSSK;
import freenet.keys.FreenetURI;
import freenet.keys.USK;
@@ -206,6 +212,14 @@
/** Version of the node */
private String version;
+ /** Peer node crypto group */
+ private DSAGroup peerCryptoGroup;
+
+ /** Peer node public key */
+ private DSAPublicKey peerPubKey;
+
+ private boolean isSignatureVerificationSuccessfull;
+
/** Incoming setup key. Used to decrypt incoming auth packets.
* Specifically: K_node XOR H(setupKey).
*/
@@ -308,7 +322,7 @@
* @param fs The SimpleFieldSet to parse
* @param node2 The running Node we are part of.
*/
- public PeerNode(SimpleFieldSet fs, Node node2, boolean fromLocal) throws
FSParseException, PeerParseException {
+ public PeerNode(SimpleFieldSet fs, Node node2, boolean fromLocal) throws
FSParseException, PeerParseException, ReferenceSignatureVerificationException {
logMINOR = Logger.shouldLog(Logger.MINOR, this);
this.node = node2;
String identityString = fs.get("identity");
@@ -378,6 +392,28 @@
detectedPeer = (Peer) nominalPeer.firstElement();
}
+ /* Read the DSA key material for the peer */
+ try {
+ this.peerCryptoGroup = DSAGroup.create(fs.subset("dsaGroup"));
+ this.peerPubKey = DSAPublicKey.create(fs.subset("dsaPubKey"),
peerCryptoGroup);
+ String signature = fs.get("sig");
+ fs.removeValue("sig");
+ this.isSignatureVerificationSuccessfull =
DSA.verify(peerPubKey, new DSASignature(signature), new
BigInteger(fs.toOrderedString().getBytes()));
+ if(!isSignatureVerificationSuccessfull){
+ Logger.error(this, "The integrity of the reference has
been compromized!");
+ throw new ReferenceSignatureVerificationException("The
integrity of the reference has been compromized!");
+ }
+ } catch (IllegalBase64Exception e) {
+ Logger.error(this, "Caught "+e, e);
+ throw new FSParseException(e);
+ } catch (NullPointerException npe){
+ /* FIXME: REMOVE: backward compatibility hack */
+ Logger.normal(this, "Probably trying to add an old reference :
"+npe);
+ this.isSignatureVerificationSuccessfull=false;
+ }
+
+ /* FIXME: All the following is useless once we have definitely
switched to STS! */
+
// Setup incoming and outgoing setup ciphers
byte[] nodeKey = node.identityHash;
byte[] nodeKeyHash = node.identityHashHash;
@@ -1829,6 +1865,8 @@
fs.put("testnet", Boolean.toString(testnetEnabled));
fs.put("version", version);
fs.put("myName", getName());
+ fs.put("dsaGroup", peerCryptoGroup.asFieldSet());
+ fs.put("dsaPubKey", peerPubKey.asFieldSet());
if(myARK != null) {
// Decrement it because we keep the number we would
like to fetch, not the last one fetched.
fs.put("ark.number",
Long.toString(myARK.suggestedEdition - 1));
@@ -2852,4 +2890,8 @@
public synchronized long getTotalOutputBytes() {
return totalBytesOut;
}
+
+ public boolean isSignatureVerificationSuccessfull() {
+ return isSignatureVerificationSuccessfull;
+ }
}
Modified: trunk/freenet/src/freenet/node/TextModeClientInterface.java
===================================================================
--- trunk/freenet/src/freenet/node/TextModeClientInterface.java 2006-09-05
13:29:07 UTC (rev 10394)
+++ trunk/freenet/src/freenet/node/TextModeClientInterface.java 2006-09-05
14:14:13 UTC (rev 10395)
@@ -30,6 +30,7 @@
import freenet.crypt.RandomSource;
import freenet.io.comm.Peer;
import freenet.io.comm.PeerParseException;
+import freenet.io.comm.ReferenceSignatureVerificationException;
import freenet.keys.FreenetURI;
import freenet.keys.InsertableClientSSK;
import freenet.support.HexUtil;
@@ -608,7 +609,7 @@
addPeer(content);
} else if(uline.startsWith("NAME:")) {
- outsb.append("Node name currently: "+n.myName);
+ outsb.append("Node name currently:
"+n.config.get("node").getOption("name").getValueString());
String key = line.substring("NAME:".length());
while((key.length() > 0) && (key.charAt(0) == ' '))
key = key.substring(1);
@@ -905,7 +906,11 @@
System.err.println("Did not parse: "+e1);
Logger.error(this, "Did not parse: "+e1, e1);
return;
- }
+ } catch (ReferenceSignatureVerificationException e1) {
+ System.err.println("Did not parse: "+e1);
+ Logger.error(this, "Did not parse: "+e1, e1);
+ return;
+ }
if(n.peers.addPeer(pn))
System.out.println("Added peer: "+pn);
n.peers.writePeers();
Modified: trunk/freenet/src/freenet/node/fcp/AddPeer.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/AddPeer.java 2006-09-05 13:29:07 UTC
(rev 10394)
+++ trunk/freenet/src/freenet/node/fcp/AddPeer.java 2006-09-05 14:14:13 UTC
(rev 10395)
@@ -11,6 +11,7 @@
import java.net.URLConnection;
import freenet.io.comm.PeerParseException;
+import freenet.io.comm.ReferenceSignatureVerificationException;
import freenet.node.FSParseException;
import freenet.node.Node;
import freenet.node.PeerNode;
@@ -107,6 +108,9 @@
throw new
MessageInvalidException(ProtocolErrorMessage.REF_PARSE_ERROR, "Error parsing
retrieved ref: "+e.getMessage(), null);
} catch (PeerParseException e) {
throw new
MessageInvalidException(ProtocolErrorMessage.REF_PARSE_ERROR, "Error parsing
retrieved ref: "+e.getMessage(), null);
+ } catch (ReferenceSignatureVerificationException e) {
+ // TODO: maybe a special ProtocolErrorMessage ?
+ throw new
MessageInvalidException(ProtocolErrorMessage.REF_PARSE_ERROR, "Error parsing
retrieved ref: "+e.getMessage(), null);
}
// **FIXME** Handle duplicates somehow maybe? What about when
node.addDarknetConnection() fails for some reason?
if(node.addDarknetConnection(pn))