forked from I2P_Developers/i2p.i2p
Router: Prep for RI sig types:
- New router.sigType config - Generate / regenerate router keys based on config - New router.keys2 file format for sig types and padding - Fix RouterInfo.readBytes() signature verification with sig types - Catch unset padding in KeysAndCert.writeBytes() - Catch key errors in ReadRouterJob - Show RI sig type on /netdb in console - Move some things from Router to startup classes - Startup classes package private - Buffer readin of key files - Remove configurability of router.info and router.keys file locations
This commit is contained in:
@ -415,7 +415,9 @@ public class NetDbRenderer {
|
|||||||
// shouldnt happen
|
// shouldnt happen
|
||||||
buf.append("<b>" + _("Published") + ":</b> in ").append(DataHelper.formatDuration2(0-age)).append("???<br>\n");
|
buf.append("<b>" + _("Published") + ":</b> in ").append(DataHelper.formatDuration2(0-age)).append("???<br>\n");
|
||||||
}
|
}
|
||||||
buf.append("<b>" + _("Address(es)") + ":</b> ");
|
buf.append("<b>").append(_("Signing Key")).append(":</b> ")
|
||||||
|
.append(info.getIdentity().getSigningPublicKey().getType().toString());
|
||||||
|
buf.append("<br>\n<b>" + _("Address(es)") + ":</b> ");
|
||||||
String country = _context.commSystem().getCountry(info.getIdentity().getHash());
|
String country = _context.commSystem().getCountry(info.getIdentity().getHash());
|
||||||
if(country != null) {
|
if(country != null) {
|
||||||
buf.append("<img height=\"11\" width=\"16\" alt=\"").append(country.toUpperCase(Locale.US)).append('\"');
|
buf.append("<img height=\"11\" width=\"16\" alt=\"").append(country.toUpperCase(Locale.US)).append('\"');
|
||||||
|
@ -114,6 +114,8 @@ public class KeysAndCert extends DataStructureImpl {
|
|||||||
_publicKey.writeBytes(out);
|
_publicKey.writeBytes(out);
|
||||||
if (_padding != null)
|
if (_padding != null)
|
||||||
out.write(_padding);
|
out.write(_padding);
|
||||||
|
else if (_signingKey.length() < SigningPublicKey.KEYSIZE_BYTES)
|
||||||
|
throw new DataFormatException("No padding set");
|
||||||
_signingKey.writeTruncatedBytes(out);
|
_signingKey.writeTruncatedBytes(out);
|
||||||
_certificate.writeBytes(out);
|
_certificate.writeBytes(out);
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,7 @@ import net.i2p.data.DataHelper;
|
|||||||
import net.i2p.data.Hash;
|
import net.i2p.data.Hash;
|
||||||
import net.i2p.data.KeysAndCert;
|
import net.i2p.data.KeysAndCert;
|
||||||
import net.i2p.data.Signature;
|
import net.i2p.data.Signature;
|
||||||
|
import net.i2p.data.SimpleDataStructure;
|
||||||
import net.i2p.util.Clock;
|
import net.i2p.util.Clock;
|
||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
import net.i2p.util.OrderedProperties;
|
import net.i2p.util.OrderedProperties;
|
||||||
@ -525,17 +526,20 @@ public class RouterInfo extends DatabaseEntry {
|
|||||||
public void readBytes(InputStream in, boolean verifySig) throws DataFormatException, IOException {
|
public void readBytes(InputStream in, boolean verifySig) throws DataFormatException, IOException {
|
||||||
if (_signature != null)
|
if (_signature != null)
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
|
_identity = new RouterIdentity();
|
||||||
|
_identity.readBytes(in);
|
||||||
|
// can't set the digest until we know the sig type
|
||||||
InputStream din;
|
InputStream din;
|
||||||
MessageDigest digest;
|
MessageDigest digest;
|
||||||
if (verifySig) {
|
if (verifySig) {
|
||||||
digest = SHA1.getInstance();
|
digest = _identity.getSigningPublicKey().getType().getDigestInstance();
|
||||||
|
// TODO any better way?
|
||||||
|
digest.update(_identity.toByteArray());
|
||||||
din = new DigestInputStream(in, digest);
|
din = new DigestInputStream(in, digest);
|
||||||
} else {
|
} else {
|
||||||
digest = null;
|
digest = null;
|
||||||
din = in;
|
din = in;
|
||||||
}
|
}
|
||||||
_identity = new RouterIdentity();
|
|
||||||
_identity.readBytes(din);
|
|
||||||
// avoid thrashing objects
|
// avoid thrashing objects
|
||||||
//Date when = DataHelper.readDate(in);
|
//Date when = DataHelper.readDate(in);
|
||||||
//if (when == null)
|
//if (when == null)
|
||||||
@ -565,7 +569,8 @@ public class RouterInfo extends DatabaseEntry {
|
|||||||
_signature.readBytes(in);
|
_signature.readBytes(in);
|
||||||
|
|
||||||
if (verifySig) {
|
if (verifySig) {
|
||||||
SHA1Hash hash = new SHA1Hash(digest.digest());
|
SimpleDataStructure hash = _identity.getSigningPublicKey().getType().getHashInstance();
|
||||||
|
hash.setData(digest.digest());
|
||||||
_isValid = DSAEngine.getInstance().verifySignature(_signature, hash, _identity.getSigningPublicKey());
|
_isValid = DSAEngine.getInstance().verifySignature(_signature, hash, _identity.getSigningPublicKey());
|
||||||
_validated = true;
|
_validated = true;
|
||||||
if (!_isValid) {
|
if (!_isValid) {
|
||||||
|
@ -18,6 +18,7 @@ import java.io.OutputStream;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import net.i2p.crypto.SigType;
|
||||||
import net.i2p.data.DataFormatException;
|
import net.i2p.data.DataFormatException;
|
||||||
import net.i2p.data.DataStructure;
|
import net.i2p.data.DataStructure;
|
||||||
import net.i2p.data.Destination;
|
import net.i2p.data.Destination;
|
||||||
@ -26,6 +27,7 @@ import net.i2p.data.PrivateKey;
|
|||||||
import net.i2p.data.PublicKey;
|
import net.i2p.data.PublicKey;
|
||||||
import net.i2p.data.SigningPrivateKey;
|
import net.i2p.data.SigningPrivateKey;
|
||||||
import net.i2p.data.SigningPublicKey;
|
import net.i2p.data.SigningPublicKey;
|
||||||
|
import net.i2p.router.startup.CreateRouterInfoJob;
|
||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
import net.i2p.util.SecureDirectory;
|
import net.i2p.util.SecureDirectory;
|
||||||
import net.i2p.util.SecureFileOutputStream;
|
import net.i2p.util.SecureFileOutputStream;
|
||||||
@ -151,8 +153,9 @@ public class KeyManager {
|
|||||||
private void syncKeys(File keyDir) {
|
private void syncKeys(File keyDir) {
|
||||||
syncPrivateKey(keyDir);
|
syncPrivateKey(keyDir);
|
||||||
syncPublicKey(keyDir);
|
syncPublicKey(keyDir);
|
||||||
syncSigningKey(keyDir);
|
SigType type = CreateRouterInfoJob.getSigTypeConfig(getContext());
|
||||||
syncVerificationKey(keyDir);
|
syncSigningKey(keyDir, type);
|
||||||
|
syncVerificationKey(keyDir, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void syncPrivateKey(File keyDir) {
|
private void syncPrivateKey(File keyDir) {
|
||||||
@ -181,27 +184,33 @@ public class KeyManager {
|
|||||||
_publicKey = (PublicKey) readin;
|
_publicKey = (PublicKey) readin;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void syncSigningKey(File keyDir) {
|
/**
|
||||||
|
* @param type the SigType to expect on read-in, ignored on write
|
||||||
|
*/
|
||||||
|
private void syncSigningKey(File keyDir, SigType type) {
|
||||||
DataStructure ds;
|
DataStructure ds;
|
||||||
File keyFile = new File(keyDir, KEYFILE_PRIVATE_SIGNING);
|
File keyFile = new File(keyDir, KEYFILE_PRIVATE_SIGNING);
|
||||||
boolean exists = (_signingPrivateKey != null);
|
boolean exists = (_signingPrivateKey != null);
|
||||||
if (exists)
|
if (exists)
|
||||||
ds = _signingPrivateKey;
|
ds = _signingPrivateKey;
|
||||||
else
|
else
|
||||||
ds = new SigningPrivateKey();
|
ds = new SigningPrivateKey(type);
|
||||||
DataStructure readin = syncKey(keyFile, ds, exists);
|
DataStructure readin = syncKey(keyFile, ds, exists);
|
||||||
if (readin != null && !exists)
|
if (readin != null && !exists)
|
||||||
_signingPrivateKey = (SigningPrivateKey) readin;
|
_signingPrivateKey = (SigningPrivateKey) readin;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void syncVerificationKey(File keyDir) {
|
/**
|
||||||
|
* @param type the SigType to expect on read-in, ignored on write
|
||||||
|
*/
|
||||||
|
private void syncVerificationKey(File keyDir, SigType type) {
|
||||||
DataStructure ds;
|
DataStructure ds;
|
||||||
File keyFile = new File(keyDir, KEYFILE_PUBLIC_SIGNING);
|
File keyFile = new File(keyDir, KEYFILE_PUBLIC_SIGNING);
|
||||||
boolean exists = (_signingPublicKey != null);
|
boolean exists = (_signingPublicKey != null);
|
||||||
if (exists)
|
if (exists)
|
||||||
ds = _signingPublicKey;
|
ds = _signingPublicKey;
|
||||||
else
|
else
|
||||||
ds = new SigningPublicKey();
|
ds = new SigningPublicKey(type);
|
||||||
DataStructure readin = syncKey(keyFile, ds, exists);
|
DataStructure readin = syncKey(keyFile, ds, exists);
|
||||||
if (readin != null && !exists)
|
if (readin != null && !exists)
|
||||||
_signingPublicKey = (SigningPublicKey) readin;
|
_signingPublicKey = (SigningPublicKey) readin;
|
||||||
|
@ -98,10 +98,6 @@ public class Router implements RouterClock.ClockShiftListener {
|
|||||||
/** this does not put an 'H' in your routerInfo **/
|
/** this does not put an 'H' in your routerInfo **/
|
||||||
public final static String PROP_HIDDEN_HIDDEN = "router.isHidden";
|
public final static String PROP_HIDDEN_HIDDEN = "router.isHidden";
|
||||||
public final static String PROP_DYNAMIC_KEYS = "router.dynamicKeys";
|
public final static String PROP_DYNAMIC_KEYS = "router.dynamicKeys";
|
||||||
public final static String PROP_INFO_FILENAME = "router.info.location";
|
|
||||||
public final static String PROP_INFO_FILENAME_DEFAULT = "router.info";
|
|
||||||
public final static String PROP_KEYS_FILENAME = "router.keys.location";
|
|
||||||
public final static String PROP_KEYS_FILENAME_DEFAULT = "router.keys";
|
|
||||||
public final static String PROP_SHUTDOWN_IN_PROGRESS = "__shutdownInProgress";
|
public final static String PROP_SHUTDOWN_IN_PROGRESS = "__shutdownInProgress";
|
||||||
public final static String DNS_CACHE_TIME = "" + (5*60);
|
public final static String DNS_CACHE_TIME = "" + (5*60);
|
||||||
private static final String EVENTLOG = "eventlog.txt";
|
private static final String EVENTLOG = "eventlog.txt";
|
||||||
@ -672,20 +668,6 @@ public class Router implements RouterClock.ClockShiftListener {
|
|||||||
return _context.commSystem().isInBadCountry();
|
return _context.commSystem().isInBadCountry();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Only called at startup via LoadRouterInfoJob and RebuildRouterInfoJob.
|
|
||||||
* Not called by periodic RepublishLocalRouterInfoJob.
|
|
||||||
* We don't want to change the cert on the fly as it changes the router hash.
|
|
||||||
* RouterInfo.isHidden() checks the capability, but RouterIdentity.isHidden() checks the cert.
|
|
||||||
* There's no reason to ever add a hidden cert?
|
|
||||||
* @return the certificate for a new RouterInfo - probably a null cert.
|
|
||||||
*/
|
|
||||||
public Certificate createCertificate() {
|
|
||||||
if (_context.getBooleanProperty(PROP_HIDDEN))
|
|
||||||
return new Certificate(Certificate.CERTIFICATE_TYPE_HIDDEN, null);
|
|
||||||
return Certificate.NULL_CERT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @since 0.9.3
|
* @since 0.9.3
|
||||||
*/
|
*/
|
||||||
|
@ -524,6 +524,11 @@ class PersistentDataStore extends TransientDataStore {
|
|||||||
if (_log.shouldLog(Log.INFO))
|
if (_log.shouldLog(Log.INFO))
|
||||||
_log.info("Unable to read the router reference in " + _routerFile.getName(), ioe);
|
_log.info("Unable to read the router reference in " + _routerFile.getName(), ioe);
|
||||||
corrupt = true;
|
corrupt = true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
// key certificate problems, etc., don't let one bad RI kill the whole thing
|
||||||
|
if (_log.shouldLog(Log.INFO))
|
||||||
|
_log.info("Unable to read the router reference in " + _routerFile.getName(), e);
|
||||||
|
corrupt = true;
|
||||||
} finally {
|
} finally {
|
||||||
if (fis != null) try { fis.close(); } catch (IOException ioe) {}
|
if (fis != null) try { fis.close(); } catch (IOException ioe) {}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ import net.i2p.router.tasks.ReadConfigJob;
|
|||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
|
|
||||||
/** This actually boots almost everything */
|
/** This actually boots almost everything */
|
||||||
public class BootCommSystemJob extends JobImpl {
|
class BootCommSystemJob extends JobImpl {
|
||||||
private Log _log;
|
private Log _log;
|
||||||
|
|
||||||
public static final String PROP_USE_TRUSTED_LINKS = "router.trustedLinks";
|
public static final String PROP_USE_TRUSTED_LINKS = "router.trustedLinks";
|
||||||
|
@ -12,7 +12,7 @@ import net.i2p.router.JobImpl;
|
|||||||
import net.i2p.router.RouterContext;
|
import net.i2p.router.RouterContext;
|
||||||
|
|
||||||
/** start up the network database */
|
/** start up the network database */
|
||||||
public class BootNetworkDbJob extends JobImpl {
|
class BootNetworkDbJob extends JobImpl {
|
||||||
|
|
||||||
public BootNetworkDbJob(RouterContext ctx) {
|
public BootNetworkDbJob(RouterContext ctx) {
|
||||||
super(ctx);
|
super(ctx);
|
||||||
|
@ -12,7 +12,7 @@ import net.i2p.router.JobImpl;
|
|||||||
import net.i2p.router.RouterContext;
|
import net.i2p.router.RouterContext;
|
||||||
|
|
||||||
/** start up the peer manager */
|
/** start up the peer manager */
|
||||||
public class BootPeerManagerJob extends JobImpl {
|
class BootPeerManagerJob extends JobImpl {
|
||||||
|
|
||||||
public BootPeerManagerJob(RouterContext ctx) {
|
public BootPeerManagerJob(RouterContext ctx) {
|
||||||
super(ctx);
|
super(ctx);
|
||||||
|
@ -15,7 +15,7 @@ import net.i2p.router.RouterContext;
|
|||||||
/**
|
/**
|
||||||
* For future restricted routes. Does nothing now.
|
* For future restricted routes. Does nothing now.
|
||||||
*/
|
*/
|
||||||
public class BuildTrustedLinksJob extends JobImpl {
|
class BuildTrustedLinksJob extends JobImpl {
|
||||||
private final Job _next;
|
private final Job _next;
|
||||||
|
|
||||||
public BuildTrustedLinksJob(RouterContext context, Job next) {
|
public BuildTrustedLinksJob(RouterContext context, Job next) {
|
||||||
|
@ -12,16 +12,21 @@ import java.io.BufferedOutputStream;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import net.i2p.crypto.SigType;
|
||||||
import net.i2p.data.Certificate;
|
import net.i2p.data.Certificate;
|
||||||
import net.i2p.data.DataFormatException;
|
import net.i2p.data.DataFormatException;
|
||||||
|
import net.i2p.data.DataHelper;
|
||||||
|
import net.i2p.data.KeyCertificate;
|
||||||
import net.i2p.data.PrivateKey;
|
import net.i2p.data.PrivateKey;
|
||||||
import net.i2p.data.PublicKey;
|
import net.i2p.data.PublicKey;
|
||||||
import net.i2p.data.router.RouterIdentity;
|
import net.i2p.data.router.RouterIdentity;
|
||||||
import net.i2p.data.router.RouterInfo;
|
import net.i2p.data.router.RouterInfo;
|
||||||
import net.i2p.data.SigningPrivateKey;
|
import net.i2p.data.SigningPrivateKey;
|
||||||
import net.i2p.data.SigningPublicKey;
|
import net.i2p.data.SigningPublicKey;
|
||||||
|
import net.i2p.data.SimpleDataStructure;
|
||||||
import net.i2p.router.Job;
|
import net.i2p.router.Job;
|
||||||
import net.i2p.router.JobImpl;
|
import net.i2p.router.JobImpl;
|
||||||
import net.i2p.router.Router;
|
import net.i2p.router.Router;
|
||||||
@ -40,7 +45,16 @@ public class CreateRouterInfoJob extends JobImpl {
|
|||||||
private final Log _log;
|
private final Log _log;
|
||||||
private final Job _next;
|
private final Job _next;
|
||||||
|
|
||||||
public CreateRouterInfoJob(RouterContext ctx, Job next) {
|
public static final String INFO_FILENAME = "router.info";
|
||||||
|
static final String KEYS_FILENAME = "router.keys";
|
||||||
|
static final String KEYS2_FILENAME = "router.keys2";
|
||||||
|
private static final String PROP_ROUTER_SIGTYPE = "router.sigType";
|
||||||
|
/** TODO when changing, check isAvailable() and fallback to DSA_SHA1 */
|
||||||
|
private static final SigType DEFAULT_SIGTYPE = SigType.DSA_SHA1;
|
||||||
|
static final byte[] KEYS2_MAGIC = DataHelper.getASCII("I2Pkeys2");
|
||||||
|
static final int KEYS2_UNUSED_BYTES = 28;
|
||||||
|
|
||||||
|
CreateRouterInfoJob(RouterContext ctx, Job next) {
|
||||||
super(ctx);
|
super(ctx);
|
||||||
_next = next;
|
_next = next;
|
||||||
_log = ctx.logManager().getLog(CreateRouterInfoJob.class);
|
_log = ctx.logManager().getLog(CreateRouterInfoJob.class);
|
||||||
@ -59,9 +73,24 @@ public class CreateRouterInfoJob extends JobImpl {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes 6 files: router.info (standard RI format),
|
* Writes 6 files: router.info (standard RI format),
|
||||||
* router,keys, and 4 individual key files under keyBackup/
|
* router.keys2, and 4 individual key files under keyBackup/
|
||||||
*
|
*
|
||||||
* router.keys file format: Note that this is NOT the
|
* router.keys2 file format: Note that this is NOT the
|
||||||
|
* same "eepPriv.dat" format used by the client code.
|
||||||
|
*<pre>
|
||||||
|
* - Magic "I2Pkeys2"
|
||||||
|
* - 2 byte crypto type, always 0000 for now
|
||||||
|
* - 2 byte sig type, see SigType
|
||||||
|
* - 28 bytes unused
|
||||||
|
* - Private key (256 bytes)
|
||||||
|
* - Signing Private key (20 bytes or see SigType)
|
||||||
|
* - Public key (256 bytes)
|
||||||
|
* - Random padding for Signing Public Key if less than 128 bytes
|
||||||
|
* - Signing Public key (128 bytes or see SigTpe)
|
||||||
|
* Total 660 bytes
|
||||||
|
*</pre>
|
||||||
|
*
|
||||||
|
* Old router.keys file format: Note that this is NOT the
|
||||||
* same "eepPriv.dat" format used by the client code.
|
* same "eepPriv.dat" format used by the client code.
|
||||||
*<pre>
|
*<pre>
|
||||||
* - Private key (256 bytes)
|
* - Private key (256 bytes)
|
||||||
@ -74,6 +103,7 @@ public class CreateRouterInfoJob extends JobImpl {
|
|||||||
* Caller must hold Router.routerInfoFileLock.
|
* Caller must hold Router.routerInfoFileLock.
|
||||||
*/
|
*/
|
||||||
RouterInfo createRouterInfo() {
|
RouterInfo createRouterInfo() {
|
||||||
|
SigType type = getSigTypeConfig(getContext());
|
||||||
RouterInfo info = new RouterInfo();
|
RouterInfo info = new RouterInfo();
|
||||||
OutputStream fos1 = null;
|
OutputStream fos1 = null;
|
||||||
OutputStream fos2 = null;
|
OutputStream fos2 = null;
|
||||||
@ -86,21 +116,26 @@ public class CreateRouterInfoJob extends JobImpl {
|
|||||||
// not necessary, in constructor
|
// not necessary, in constructor
|
||||||
//info.setPeers(new HashSet());
|
//info.setPeers(new HashSet());
|
||||||
info.setPublished(getCurrentPublishDate(getContext()));
|
info.setPublished(getCurrentPublishDate(getContext()));
|
||||||
RouterIdentity ident = new RouterIdentity();
|
|
||||||
Certificate cert = getContext().router().createCertificate();
|
|
||||||
ident.setCertificate(cert);
|
|
||||||
PublicKey pubkey = null;
|
|
||||||
PrivateKey privkey = null;
|
|
||||||
SigningPublicKey signingPubKey = null;
|
|
||||||
SigningPrivateKey signingPrivKey = null;
|
|
||||||
Object keypair[] = getContext().keyGenerator().generatePKIKeypair();
|
Object keypair[] = getContext().keyGenerator().generatePKIKeypair();
|
||||||
pubkey = (PublicKey)keypair[0];
|
PublicKey pubkey = (PublicKey)keypair[0];
|
||||||
privkey = (PrivateKey)keypair[1];
|
PrivateKey privkey = (PrivateKey)keypair[1];
|
||||||
Object signingKeypair[] = getContext().keyGenerator().generateSigningKeypair();
|
SimpleDataStructure signingKeypair[] = getContext().keyGenerator().generateSigningKeys(type);
|
||||||
signingPubKey = (SigningPublicKey)signingKeypair[0];
|
SigningPublicKey signingPubKey = (SigningPublicKey)signingKeypair[0];
|
||||||
signingPrivKey = (SigningPrivateKey)signingKeypair[1];
|
SigningPrivateKey signingPrivKey = (SigningPrivateKey)signingKeypair[1];
|
||||||
|
RouterIdentity ident = new RouterIdentity();
|
||||||
|
Certificate cert = createCertificate(getContext(), signingPubKey);
|
||||||
|
ident.setCertificate(cert);
|
||||||
ident.setPublicKey(pubkey);
|
ident.setPublicKey(pubkey);
|
||||||
ident.setSigningPublicKey(signingPubKey);
|
ident.setSigningPublicKey(signingPubKey);
|
||||||
|
byte[] padding;
|
||||||
|
int padLen = SigningPublicKey.KEYSIZE_BYTES - signingPubKey.length();
|
||||||
|
if (padLen > 0) {
|
||||||
|
padding = new byte[padLen];
|
||||||
|
getContext().random().nextBytes(padding);
|
||||||
|
ident.setPadding(padding);
|
||||||
|
} else {
|
||||||
|
padding = null;
|
||||||
|
}
|
||||||
info.setIdentity(ident);
|
info.setIdentity(ident);
|
||||||
|
|
||||||
info.sign(signingPrivKey);
|
info.sign(signingPrivKey);
|
||||||
@ -108,23 +143,35 @@ public class CreateRouterInfoJob extends JobImpl {
|
|||||||
if (!info.isValid())
|
if (!info.isValid())
|
||||||
throw new DataFormatException("RouterInfo we just built is invalid: " + info);
|
throw new DataFormatException("RouterInfo we just built is invalid: " + info);
|
||||||
|
|
||||||
String infoFilename = getContext().getProperty(Router.PROP_INFO_FILENAME, Router.PROP_INFO_FILENAME_DEFAULT);
|
// remove router.keys
|
||||||
File ifile = new File(getContext().getRouterDir(), infoFilename);
|
(new File(getContext().getRouterDir(), KEYS_FILENAME)).delete();
|
||||||
|
|
||||||
|
// write router.info
|
||||||
|
File ifile = new File(getContext().getRouterDir(), INFO_FILENAME);
|
||||||
fos1 = new BufferedOutputStream(new SecureFileOutputStream(ifile));
|
fos1 = new BufferedOutputStream(new SecureFileOutputStream(ifile));
|
||||||
info.writeBytes(fos1);
|
info.writeBytes(fos1);
|
||||||
|
|
||||||
String keyFilename = getContext().getProperty(Router.PROP_KEYS_FILENAME, Router.PROP_KEYS_FILENAME_DEFAULT);
|
// write router.keys2
|
||||||
File kfile = new File(getContext().getRouterDir(), keyFilename);
|
File kfile = new File(getContext().getRouterDir(), KEYS2_FILENAME);
|
||||||
fos2 = new BufferedOutputStream(new SecureFileOutputStream(kfile));
|
fos2 = new BufferedOutputStream(new SecureFileOutputStream(kfile));
|
||||||
|
fos2.write(KEYS2_MAGIC);
|
||||||
|
DataHelper.writeLong(fos2, 2, 0);
|
||||||
|
DataHelper.writeLong(fos2, 2, type.getCode());
|
||||||
|
fos2.write(new byte[KEYS2_UNUSED_BYTES]);
|
||||||
privkey.writeBytes(fos2);
|
privkey.writeBytes(fos2);
|
||||||
signingPrivKey.writeBytes(fos2);
|
signingPrivKey.writeBytes(fos2);
|
||||||
pubkey.writeBytes(fos2);
|
pubkey.writeBytes(fos2);
|
||||||
|
if (padding != null)
|
||||||
|
fos2.write(padding);
|
||||||
signingPubKey.writeBytes(fos2);
|
signingPubKey.writeBytes(fos2);
|
||||||
|
|
||||||
getContext().keyManager().setKeys(pubkey, privkey, signingPubKey, signingPrivKey);
|
getContext().keyManager().setKeys(pubkey, privkey, signingPubKey, signingPrivKey);
|
||||||
|
|
||||||
_log.info("Router info created and stored at " + ifile.getAbsolutePath() + " with private keys stored at " + kfile.getAbsolutePath() + " [" + info + "]");
|
if (_log.shouldLog(Log.INFO))
|
||||||
|
_log.info("Router info created and stored at " + ifile.getAbsolutePath() + " with private keys stored at " + kfile.getAbsolutePath() + " [" + info + "]");
|
||||||
getContext().router().eventLog().addEvent(EventLog.REKEYED, ident.calculateHash().toBase64());
|
getContext().router().eventLog().addEvent(EventLog.REKEYED, ident.calculateHash().toBase64());
|
||||||
|
} catch (GeneralSecurityException gse) {
|
||||||
|
_log.log(Log.CRIT, "Error building the new router information", gse);
|
||||||
} catch (DataFormatException dfe) {
|
} catch (DataFormatException dfe) {
|
||||||
_log.log(Log.CRIT, "Error building the new router information", dfe);
|
_log.log(Log.CRIT, "Error building the new router information", dfe);
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
@ -136,6 +183,20 @@ public class CreateRouterInfoJob extends JobImpl {
|
|||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The configured SigType to expect on read-in
|
||||||
|
* @since 0.9.16
|
||||||
|
*/
|
||||||
|
public static SigType getSigTypeConfig(RouterContext ctx) {
|
||||||
|
SigType cstype = CreateRouterInfoJob.DEFAULT_SIGTYPE;
|
||||||
|
String sstype = ctx.getProperty(PROP_ROUTER_SIGTYPE);
|
||||||
|
if (sstype != null) {
|
||||||
|
SigType ntype = SigType.parseSigType(sstype);
|
||||||
|
if (ntype != null && ntype.isAvailable())
|
||||||
|
cstype = ntype;
|
||||||
|
}
|
||||||
|
return cstype;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We probably don't want to expose the exact time at which a router published its info.
|
* We probably don't want to expose the exact time at which a router published its info.
|
||||||
@ -146,4 +207,22 @@ public class CreateRouterInfoJob extends JobImpl {
|
|||||||
//_log.info("Setting published date to /now/");
|
//_log.info("Setting published date to /now/");
|
||||||
return context.clock().now();
|
return context.clock().now();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only called at startup via LoadRouterInfoJob and RebuildRouterInfoJob.
|
||||||
|
* Not called by periodic RepublishLocalRouterInfoJob.
|
||||||
|
* We don't want to change the cert on the fly as it changes the router hash.
|
||||||
|
* RouterInfo.isHidden() checks the capability, but RouterIdentity.isHidden() checks the cert.
|
||||||
|
* There's no reason to ever add a hidden cert?
|
||||||
|
*
|
||||||
|
* @return the certificate for a new RouterInfo - probably a null cert.
|
||||||
|
* @since 0.9.16 moved from Router
|
||||||
|
*/
|
||||||
|
static Certificate createCertificate(RouterContext ctx, SigningPublicKey spk) {
|
||||||
|
if (spk.getType() != SigType.DSA_SHA1)
|
||||||
|
return new KeyCertificate(spk);
|
||||||
|
if (ctx.getBooleanProperty(Router.PROP_HIDDEN))
|
||||||
|
return new Certificate(Certificate.CERTIFICATE_TYPE_HIDDEN, null);
|
||||||
|
return Certificate.NULL_CERT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,9 @@ import java.io.InputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
import net.i2p.crypto.SigType;
|
||||||
import net.i2p.data.DataFormatException;
|
import net.i2p.data.DataFormatException;
|
||||||
|
import net.i2p.data.DataHelper;
|
||||||
import net.i2p.data.PrivateKey;
|
import net.i2p.data.PrivateKey;
|
||||||
import net.i2p.data.PublicKey;
|
import net.i2p.data.PublicKey;
|
||||||
import net.i2p.data.router.RouterInfo;
|
import net.i2p.data.router.RouterInfo;
|
||||||
@ -26,7 +28,11 @@ import net.i2p.router.Router;
|
|||||||
import net.i2p.router.RouterContext;
|
import net.i2p.router.RouterContext;
|
||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
|
|
||||||
public class LoadRouterInfoJob extends JobImpl {
|
/**
|
||||||
|
* Run once or twice at startup by StartupJob,
|
||||||
|
* and then runs BootCommSystemJob
|
||||||
|
*/
|
||||||
|
class LoadRouterInfoJob extends JobImpl {
|
||||||
private final Log _log;
|
private final Log _log;
|
||||||
private RouterInfo _us;
|
private RouterInfo _us;
|
||||||
private static final AtomicBoolean _keyLengthChecked = new AtomicBoolean();
|
private static final AtomicBoolean _keyLengthChecked = new AtomicBoolean();
|
||||||
@ -45,6 +51,7 @@ public class LoadRouterInfoJob extends JobImpl {
|
|||||||
if (_us == null) {
|
if (_us == null) {
|
||||||
RebuildRouterInfoJob r = new RebuildRouterInfoJob(getContext());
|
RebuildRouterInfoJob r = new RebuildRouterInfoJob(getContext());
|
||||||
r.rebuildRouterInfo(false);
|
r.rebuildRouterInfo(false);
|
||||||
|
// run a second time
|
||||||
getContext().jobQueue().addJob(this);
|
getContext().jobQueue().addJob(this);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
@ -54,15 +61,19 @@ public class LoadRouterInfoJob extends JobImpl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads router.info and router.keys2 or router.keys.
|
||||||
|
*
|
||||||
|
* See CreateRouterInfoJob for file formats
|
||||||
|
*/
|
||||||
private void loadRouterInfo() {
|
private void loadRouterInfo() {
|
||||||
String routerInfoFile = getContext().getProperty(Router.PROP_INFO_FILENAME, Router.PROP_INFO_FILENAME_DEFAULT);
|
|
||||||
RouterInfo info = null;
|
RouterInfo info = null;
|
||||||
String keyFilename = getContext().getProperty(Router.PROP_KEYS_FILENAME, Router.PROP_KEYS_FILENAME_DEFAULT);
|
File rif = new File(getContext().getRouterDir(), CreateRouterInfoJob.INFO_FILENAME);
|
||||||
|
|
||||||
File rif = new File(getContext().getRouterDir(), routerInfoFile);
|
|
||||||
boolean infoExists = rif.exists();
|
boolean infoExists = rif.exists();
|
||||||
File rkf = new File(getContext().getRouterDir(), keyFilename);
|
File rkf = new File(getContext().getRouterDir(), CreateRouterInfoJob.KEYS_FILENAME);
|
||||||
boolean keysExist = rkf.exists();
|
boolean keysExist = rkf.exists();
|
||||||
|
File rkf2 = new File(getContext().getRouterDir(), CreateRouterInfoJob.KEYS2_FILENAME);
|
||||||
|
boolean keys2Exist = rkf2.exists();
|
||||||
|
|
||||||
InputStream fis1 = null;
|
InputStream fis1 = null;
|
||||||
InputStream fis2 = null;
|
InputStream fis2 = null;
|
||||||
@ -73,7 +84,7 @@ public class LoadRouterInfoJob extends JobImpl {
|
|||||||
// CRIT ...sport.udp.EstablishmentManager: Error in the establisher java.lang.NullPointerException
|
// CRIT ...sport.udp.EstablishmentManager: Error in the establisher java.lang.NullPointerException
|
||||||
// at net.i2p.router.transport.udp.PacketBuilder.buildSessionConfirmedPacket(PacketBuilder.java:574)
|
// at net.i2p.router.transport.udp.PacketBuilder.buildSessionConfirmedPacket(PacketBuilder.java:574)
|
||||||
// so pretend the RI isn't there if there is no keyfile
|
// so pretend the RI isn't there if there is no keyfile
|
||||||
if (infoExists && keysExist) {
|
if (infoExists && (keys2Exist || keysExist)) {
|
||||||
fis1 = new BufferedInputStream(new FileInputStream(rif));
|
fis1 = new BufferedInputStream(new FileInputStream(rif));
|
||||||
info = new RouterInfo();
|
info = new RouterInfo();
|
||||||
info.readBytes(fis1);
|
info.readBytes(fis1);
|
||||||
@ -85,11 +96,37 @@ public class LoadRouterInfoJob extends JobImpl {
|
|||||||
_us = info;
|
_us = info;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keysExist) {
|
if (keys2Exist || keysExist) {
|
||||||
fis2 = new BufferedInputStream(new FileInputStream(rkf));
|
SigType stype;
|
||||||
|
if (keys2Exist) {
|
||||||
|
fis2 = new BufferedInputStream(new FileInputStream(rkf2));
|
||||||
|
// read keys2 headers
|
||||||
|
byte[] magic = new byte[CreateRouterInfoJob.KEYS2_MAGIC.length];
|
||||||
|
DataHelper.read(fis2, magic);
|
||||||
|
if (!DataHelper.eq(magic, CreateRouterInfoJob.KEYS2_MAGIC))
|
||||||
|
throw new IOException("Bad magic");
|
||||||
|
int ctype = (int) DataHelper.readLong(fis2, 2);
|
||||||
|
if (ctype != 0)
|
||||||
|
throw new IOException("Unsupported RI crypto type " + ctype);
|
||||||
|
int sstype = (int) DataHelper.readLong(fis2, 2);
|
||||||
|
stype = SigType.getByCode(sstype);
|
||||||
|
if (stype == null || !stype.isAvailable())
|
||||||
|
throw new IOException("Unsupported RI sig type " + stype);
|
||||||
|
DataHelper.skip(fis2, CreateRouterInfoJob.KEYS2_UNUSED_BYTES);
|
||||||
|
} else {
|
||||||
|
fis2 = new BufferedInputStream(new FileInputStream(rkf));
|
||||||
|
stype = SigType.DSA_SHA1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if the sigtype config changed
|
||||||
|
SigType cstype = CreateRouterInfoJob.getSigTypeConfig(getContext());
|
||||||
|
boolean sigTypeChanged = stype != cstype;
|
||||||
|
|
||||||
PrivateKey privkey = new PrivateKey();
|
PrivateKey privkey = new PrivateKey();
|
||||||
privkey.readBytes(fis2);
|
privkey.readBytes(fis2);
|
||||||
if (shouldRebuild(privkey)) {
|
if (sigTypeChanged || shouldRebuild(privkey)) {
|
||||||
|
if (sigTypeChanged)
|
||||||
|
_log.logAlways(Log.WARN, "Rebuilding RouterInfo with new signature type " + cstype);
|
||||||
_us = null;
|
_us = null;
|
||||||
// windows... close before deleting
|
// windows... close before deleting
|
||||||
if (fis1 != null) {
|
if (fis1 != null) {
|
||||||
@ -100,13 +137,19 @@ public class LoadRouterInfoJob extends JobImpl {
|
|||||||
fis2 = null;
|
fis2 = null;
|
||||||
rif.delete();
|
rif.delete();
|
||||||
rkf.delete();
|
rkf.delete();
|
||||||
|
rkf2.delete();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SigningPrivateKey signingPrivKey = new SigningPrivateKey();
|
SigningPrivateKey signingPrivKey = new SigningPrivateKey(stype);
|
||||||
signingPrivKey.readBytes(fis2);
|
signingPrivKey.readBytes(fis2);
|
||||||
PublicKey pubkey = new PublicKey();
|
PublicKey pubkey = new PublicKey();
|
||||||
pubkey.readBytes(fis2);
|
pubkey.readBytes(fis2);
|
||||||
SigningPublicKey signingPubKey = new SigningPublicKey();
|
SigningPublicKey signingPubKey = new SigningPublicKey(stype);
|
||||||
|
int padLen = SigningPublicKey.KEYSIZE_BYTES - signingPubKey.length();
|
||||||
|
if (padLen > 0) {
|
||||||
|
// we lose the padding as keymanager doesn't store it, what to do?
|
||||||
|
DataHelper.skip(fis2, padLen);
|
||||||
|
}
|
||||||
signingPubKey.readBytes(fis2);
|
signingPubKey.readBytes(fis2);
|
||||||
|
|
||||||
getContext().keyManager().setKeys(pubkey, privkey, signingPubKey, signingPrivKey);
|
getContext().keyManager().setKeys(pubkey, privkey, signingPubKey, signingPrivKey);
|
||||||
@ -125,6 +168,7 @@ public class LoadRouterInfoJob extends JobImpl {
|
|||||||
}
|
}
|
||||||
rif.delete();
|
rif.delete();
|
||||||
rkf.delete();
|
rkf.delete();
|
||||||
|
rkf2.delete();
|
||||||
} catch (DataFormatException dfe) {
|
} catch (DataFormatException dfe) {
|
||||||
_log.log(Log.CRIT, "Corrupt router info or keys at " + rif.getAbsolutePath() + " / " + rkf.getAbsolutePath(), dfe);
|
_log.log(Log.CRIT, "Corrupt router info or keys at " + rif.getAbsolutePath() + " / " + rkf.getAbsolutePath(), dfe);
|
||||||
_us = null;
|
_us = null;
|
||||||
@ -139,6 +183,7 @@ public class LoadRouterInfoJob extends JobImpl {
|
|||||||
}
|
}
|
||||||
rif.delete();
|
rif.delete();
|
||||||
rkf.delete();
|
rkf.delete();
|
||||||
|
rkf2.delete();
|
||||||
} finally {
|
} finally {
|
||||||
if (fis1 != null) try { fis1.close(); } catch (IOException ioe) {}
|
if (fis1 != null) try { fis1.close(); } catch (IOException ioe) {}
|
||||||
if (fis2 != null) try { fis2.close(); } catch (IOException ioe) {}
|
if (fis2 != null) try { fis2.close(); } catch (IOException ioe) {}
|
||||||
|
@ -8,14 +8,18 @@ package net.i2p.router.startup;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import net.i2p.crypto.SigType;
|
||||||
import net.i2p.data.Certificate;
|
import net.i2p.data.Certificate;
|
||||||
import net.i2p.data.DataFormatException;
|
import net.i2p.data.DataFormatException;
|
||||||
|
import net.i2p.data.DataHelper;
|
||||||
import net.i2p.data.PrivateKey;
|
import net.i2p.data.PrivateKey;
|
||||||
import net.i2p.data.PublicKey;
|
import net.i2p.data.PublicKey;
|
||||||
import net.i2p.data.router.RouterIdentity;
|
import net.i2p.data.router.RouterIdentity;
|
||||||
@ -44,7 +48,7 @@ import net.i2p.util.SecureFileOutputStream;
|
|||||||
* router.info.rebuild file is deleted
|
* router.info.rebuild file is deleted
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class RebuildRouterInfoJob extends JobImpl {
|
class RebuildRouterInfoJob extends JobImpl {
|
||||||
private final Log _log;
|
private final Log _log;
|
||||||
|
|
||||||
private final static long REBUILD_DELAY = 45*1000; // every 30 seconds
|
private final static long REBUILD_DELAY = 45*1000; // every 30 seconds
|
||||||
@ -57,11 +61,11 @@ public class RebuildRouterInfoJob extends JobImpl {
|
|||||||
public String getName() { return "Rebuild Router Info"; }
|
public String getName() { return "Rebuild Router Info"; }
|
||||||
|
|
||||||
public void runJob() {
|
public void runJob() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
/****
|
||||||
_log.debug("Testing to rebuild router info");
|
_log.debug("Testing to rebuild router info");
|
||||||
String infoFile = getContext().getProperty(Router.PROP_INFO_FILENAME, Router.PROP_INFO_FILENAME_DEFAULT);
|
File info = new File(getContext().getRouterDir(), CreateRouterInfoJob.INFO_FILENAME);
|
||||||
File info = new File(getContext().getRouterDir(), infoFile);
|
File keyFile = new File(getContext().getRouterDir(), CreateRouterInfoJob.KEYS2_FILENAME);
|
||||||
String keyFilename = getContext().getProperty(Router.PROP_KEYS_FILENAME, Router.PROP_KEYS_FILENAME_DEFAULT);
|
|
||||||
File keyFile = new File(getContext().getRouterDir(), keyFilename);
|
|
||||||
|
|
||||||
if (!info.exists() || !keyFile.exists()) {
|
if (!info.exists() || !keyFile.exists()) {
|
||||||
_log.info("Router info file [" + info.getAbsolutePath() + "] or private key file [" + keyFile.getAbsolutePath() + "] deleted, rebuilding");
|
_log.info("Router info file [" + info.getAbsolutePath() + "] or private key file [" + keyFile.getAbsolutePath() + "] deleted, rebuilding");
|
||||||
@ -71,41 +75,72 @@ public class RebuildRouterInfoJob extends JobImpl {
|
|||||||
}
|
}
|
||||||
getTiming().setStartAfter(getContext().clock().now() + REBUILD_DELAY);
|
getTiming().setStartAfter(getContext().clock().now() + REBUILD_DELAY);
|
||||||
getContext().jobQueue().addJob(this);
|
getContext().jobQueue().addJob(this);
|
||||||
|
****/
|
||||||
}
|
}
|
||||||
|
|
||||||
void rebuildRouterInfo() {
|
void rebuildRouterInfo() {
|
||||||
rebuildRouterInfo(true);
|
rebuildRouterInfo(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param alreadyRunning unused
|
||||||
|
*/
|
||||||
void rebuildRouterInfo(boolean alreadyRunning) {
|
void rebuildRouterInfo(boolean alreadyRunning) {
|
||||||
_log.debug("Rebuilding the new router info");
|
_log.debug("Rebuilding the new router info");
|
||||||
RouterInfo info = null;
|
RouterInfo info = null;
|
||||||
String infoFilename = getContext().getProperty(Router.PROP_INFO_FILENAME, Router.PROP_INFO_FILENAME_DEFAULT);
|
File infoFile = new File(getContext().getRouterDir(), CreateRouterInfoJob.INFO_FILENAME);
|
||||||
File infoFile = new File(getContext().getRouterDir(), infoFilename);
|
File keyFile = new File(getContext().getRouterDir(), CreateRouterInfoJob.KEYS_FILENAME);
|
||||||
String keyFilename = getContext().getProperty(Router.PROP_KEYS_FILENAME, Router.PROP_KEYS_FILENAME_DEFAULT);
|
File keyFile2 = new File(getContext().getRouterDir(), CreateRouterInfoJob.KEYS2_FILENAME);
|
||||||
File keyFile = new File(getContext().getRouterDir(), keyFilename);
|
|
||||||
|
|
||||||
if (keyFile.exists()) {
|
if (keyFile2.exists() || keyFile.exists()) {
|
||||||
// ok, no need to rebuild a brand new identity, just update what we can
|
// ok, no need to rebuild a brand new identity, just update what we can
|
||||||
RouterInfo oldinfo = getContext().router().getRouterInfo();
|
RouterInfo oldinfo = getContext().router().getRouterInfo();
|
||||||
if (oldinfo == null) {
|
if (oldinfo == null) {
|
||||||
info = new RouterInfo();
|
info = new RouterInfo();
|
||||||
FileInputStream fis = null;
|
InputStream fis = null;
|
||||||
try {
|
try {
|
||||||
fis = new FileInputStream(keyFile);
|
SigType stype;
|
||||||
|
if (keyFile2.exists()) {
|
||||||
|
fis = new BufferedInputStream(new FileInputStream(keyFile2));
|
||||||
|
byte[] magic = new byte[CreateRouterInfoJob.KEYS2_MAGIC.length];
|
||||||
|
DataHelper.read(fis, magic);
|
||||||
|
if (!DataHelper.eq(magic, CreateRouterInfoJob.KEYS2_MAGIC))
|
||||||
|
throw new IOException("Bad magic");
|
||||||
|
int ctype = (int) DataHelper.readLong(fis, 2);
|
||||||
|
if (ctype != 0)
|
||||||
|
throw new IOException("Unsupported RI crypto type " + ctype);
|
||||||
|
int sstype = (int) DataHelper.readLong(fis, 2);
|
||||||
|
stype = SigType.getByCode(sstype);
|
||||||
|
if (stype == null || !stype.isAvailable())
|
||||||
|
throw new IOException("Unsupported RI sig type " + stype);
|
||||||
|
DataHelper.skip(fis, CreateRouterInfoJob.KEYS2_UNUSED_BYTES);
|
||||||
|
} else {
|
||||||
|
fis = new BufferedInputStream(new FileInputStream(keyFile));
|
||||||
|
stype = SigType.DSA_SHA1;
|
||||||
|
}
|
||||||
PrivateKey privkey = new PrivateKey();
|
PrivateKey privkey = new PrivateKey();
|
||||||
privkey.readBytes(fis);
|
privkey.readBytes(fis);
|
||||||
SigningPrivateKey signingPrivKey = new SigningPrivateKey();
|
SigningPrivateKey signingPrivKey = new SigningPrivateKey(stype);
|
||||||
signingPrivKey.readBytes(fis);
|
signingPrivKey.readBytes(fis);
|
||||||
PublicKey pubkey = new PublicKey();
|
PublicKey pubkey = new PublicKey();
|
||||||
pubkey.readBytes(fis);
|
pubkey.readBytes(fis);
|
||||||
SigningPublicKey signingPubKey = new SigningPublicKey();
|
SigningPublicKey signingPubKey = new SigningPublicKey(stype);
|
||||||
|
byte[] padding;
|
||||||
|
int padLen = SigningPublicKey.KEYSIZE_BYTES - signingPubKey.length();
|
||||||
|
if (padLen > 0) {
|
||||||
|
padding = new byte[padLen];
|
||||||
|
DataHelper.read(fis, padding);
|
||||||
|
} else {
|
||||||
|
padding = null;
|
||||||
|
}
|
||||||
signingPubKey.readBytes(fis);
|
signingPubKey.readBytes(fis);
|
||||||
RouterIdentity ident = new RouterIdentity();
|
RouterIdentity ident = new RouterIdentity();
|
||||||
Certificate cert = getContext().router().createCertificate();
|
Certificate cert = CreateRouterInfoJob.createCertificate(getContext(), signingPubKey);
|
||||||
ident.setCertificate(cert);
|
ident.setCertificate(cert);
|
||||||
ident.setPublicKey(pubkey);
|
ident.setPublicKey(pubkey);
|
||||||
ident.setSigningPublicKey(signingPubKey);
|
ident.setSigningPublicKey(signingPubKey);
|
||||||
|
if (padding != null)
|
||||||
|
ident.setPadding(padding);
|
||||||
info.setIdentity(ident);
|
info.setIdentity(ident);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
_log.log(Log.CRIT, "Error reading in the key data from " + keyFile.getAbsolutePath(), e);
|
_log.log(Log.CRIT, "Error reading in the key data from " + keyFile.getAbsolutePath(), e);
|
||||||
@ -160,12 +195,14 @@ public class RebuildRouterInfoJob extends JobImpl {
|
|||||||
_log.warn("Private key file " + keyFile.getAbsolutePath() + " deleted! Rebuilding a brand new router identity!");
|
_log.warn("Private key file " + keyFile.getAbsolutePath() + " deleted! Rebuilding a brand new router identity!");
|
||||||
// this proc writes the keys and info to the file as well as builds the latest and greatest info
|
// this proc writes the keys and info to the file as well as builds the latest and greatest info
|
||||||
CreateRouterInfoJob j = new CreateRouterInfoJob(getContext(), null);
|
CreateRouterInfoJob j = new CreateRouterInfoJob(getContext(), null);
|
||||||
info = j.createRouterInfo();
|
synchronized (getContext().router().routerInfoFileLock) {
|
||||||
|
info = j.createRouterInfo();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//MessageHistory.initialize();
|
//MessageHistory.initialize();
|
||||||
getContext().router().setRouterInfo(info);
|
getContext().router().setRouterInfo(info);
|
||||||
_log.info("Router info rebuilt and stored at " + infoFilename + " [" + info + "]");
|
_log.info("Router info rebuilt and stored at " + infoFile + " [" + info + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ import net.i2p.router.JobImpl;
|
|||||||
import net.i2p.router.RouterContext;
|
import net.i2p.router.RouterContext;
|
||||||
|
|
||||||
/** start I2CP interface */
|
/** start I2CP interface */
|
||||||
public class StartAcceptingClientsJob extends JobImpl {
|
class StartAcceptingClientsJob extends JobImpl {
|
||||||
|
|
||||||
public StartAcceptingClientsJob(RouterContext context) {
|
public StartAcceptingClientsJob(RouterContext context) {
|
||||||
super(context);
|
super(context);
|
||||||
|
@ -147,7 +147,7 @@ public class WorkingDir {
|
|||||||
// Check for a router.keys file or logs dir, if either exists it's an old install,
|
// Check for a router.keys file or logs dir, if either exists it's an old install,
|
||||||
// and only migrate the data files if told to do so
|
// and only migrate the data files if told to do so
|
||||||
// (router.keys could be deleted later by a killkeys())
|
// (router.keys could be deleted later by a killkeys())
|
||||||
test = new File(oldDirf, "router.keys");
|
test = new File(oldDirf, CreateRouterInfoJob.KEYS_FILENAME);
|
||||||
boolean oldInstall = test.exists();
|
boolean oldInstall = test.exists();
|
||||||
if (!oldInstall) {
|
if (!oldInstall) {
|
||||||
test = new File(oldDirf, "logs");
|
test = new File(oldDirf, "logs");
|
||||||
|
@ -15,8 +15,8 @@ import java.io.IOException;
|
|||||||
import net.i2p.data.DataFormatException;
|
import net.i2p.data.DataFormatException;
|
||||||
import net.i2p.data.router.RouterInfo;
|
import net.i2p.data.router.RouterInfo;
|
||||||
import net.i2p.router.JobImpl;
|
import net.i2p.router.JobImpl;
|
||||||
import net.i2p.router.Router;
|
|
||||||
import net.i2p.router.RouterContext;
|
import net.i2p.router.RouterContext;
|
||||||
|
import net.i2p.router.startup.CreateRouterInfoJob;
|
||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
import net.i2p.util.SecureFileOutputStream;
|
import net.i2p.util.SecureFileOutputStream;
|
||||||
|
|
||||||
@ -37,8 +37,7 @@ public class PersistRouterInfoJob extends JobImpl {
|
|||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.debug("Persisting updated router info");
|
_log.debug("Persisting updated router info");
|
||||||
|
|
||||||
String infoFilename = getContext().getProperty(Router.PROP_INFO_FILENAME, Router.PROP_INFO_FILENAME_DEFAULT);
|
File infoFile = new File(getContext().getRouterDir(), CreateRouterInfoJob.INFO_FILENAME);
|
||||||
File infoFile = new File(getContext().getRouterDir(), infoFilename);
|
|
||||||
|
|
||||||
RouterInfo info = getContext().router().getRouterInfo();
|
RouterInfo info = getContext().router().getRouterInfo();
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user