diff --git a/core/java/src/net/i2p/crypto/SigType.java b/core/java/src/net/i2p/crypto/SigType.java index 4c2e89fff..7b808a9e8 100644 --- a/core/java/src/net/i2p/crypto/SigType.java +++ b/core/java/src/net/i2p/crypto/SigType.java @@ -29,27 +29,30 @@ public enum SigType { * Pubkey 128 bytes; privkey 20 bytes; hash 20 bytes; sig 40 bytes * @since 0.9.8 */ - DSA_SHA1(0, 128, 20, 20, 40, SigAlgo.DSA, "SHA-1", "SHA1withDSA", CryptoConstants.DSA_SHA1_SPEC), + DSA_SHA1(0, 128, 20, 20, 40, SigAlgo.DSA, "SHA-1", "SHA1withDSA", CryptoConstants.DSA_SHA1_SPEC, "0"), /** Pubkey 64 bytes; privkey 32 bytes; hash 32 bytes; sig 64 bytes */ - ECDSA_SHA256_P256(1, 64, 32, 32, 64, SigAlgo.EC, "SHA-256", "SHA256withECDSA", ECConstants.P256_SPEC), + ECDSA_SHA256_P256(1, 64, 32, 32, 64, SigAlgo.EC, "SHA-256", "SHA256withECDSA", ECConstants.P256_SPEC, "0.9.12"), /** Pubkey 96 bytes; privkey 48 bytes; hash 48 bytes; sig 96 bytes */ - ECDSA_SHA384_P384(2, 96, 48, 48, 96, SigAlgo.EC, "SHA-384", "SHA384withECDSA", ECConstants.P384_SPEC), + ECDSA_SHA384_P384(2, 96, 48, 48, 96, SigAlgo.EC, "SHA-384", "SHA384withECDSA", ECConstants.P384_SPEC, "0.9.12"), /** Pubkey 132 bytes; privkey 66 bytes; hash 64 bytes; sig 132 bytes */ - ECDSA_SHA512_P521(3, 132, 66, 64, 132, SigAlgo.EC, "SHA-512", "SHA512withECDSA", ECConstants.P521_SPEC), + ECDSA_SHA512_P521(3, 132, 66, 64, 132, SigAlgo.EC, "SHA-512", "SHA512withECDSA", ECConstants.P521_SPEC, "0.9.12"), /** Pubkey 256 bytes; privkey 512 bytes; hash 32 bytes; sig 256 bytes */ - RSA_SHA256_2048(4, 256, 512, 32, 256, SigAlgo.RSA, "SHA-256", "SHA256withRSA", RSAConstants.F4_2048_SPEC), + RSA_SHA256_2048(4, 256, 512, 32, 256, SigAlgo.RSA, "SHA-256", "SHA256withRSA", RSAConstants.F4_2048_SPEC, "0.9.12"), /** Pubkey 384 bytes; privkey 768 bytes; hash 48 bytes; sig 384 bytes */ - RSA_SHA384_3072(5, 384, 768, 48, 384, SigAlgo.RSA, "SHA-384", "SHA384withRSA", RSAConstants.F4_3072_SPEC), + RSA_SHA384_3072(5, 384, 768, 48, 384, SigAlgo.RSA, "SHA-384", "SHA384withRSA", RSAConstants.F4_3072_SPEC, "0.9.12"), /** Pubkey 512 bytes; privkey 1024 bytes; hash 64 bytes; sig 512 bytes */ - RSA_SHA512_4096(6, 512, 1024, 64, 512, SigAlgo.RSA, "SHA-512", "SHA512withRSA", RSAConstants.F4_4096_SPEC), + RSA_SHA512_4096(6, 512, 1024, 64, 512, SigAlgo.RSA, "SHA-512", "SHA512withRSA", RSAConstants.F4_4096_SPEC, "0.9.12"), + /** + * Pubkey 32 bytes; privkey 32 bytes; hash 64 bytes; sig 64 bytes + * @since 0.9.15 + */ + EdDSA_SHA512_Ed25519(7, 32, 32, 64, 64, SigAlgo.EdDSA, "SHA-512", "SHA512withEdDSA", EdDSANamedCurveTable.getByName("ed25519-sha-512"), "0.9.15"); // TESTING.................... - /** Pubkey 32 bytes; privkey 32 bytes; hash 64 bytes; sig 64 bytes; */ - EdDSA_SHA512_Ed25519(4, 32, 32, 64, 64, SigAlgo.EdDSA, "SHA-512", "SHA512withEdDSA", EdDSANamedCurveTable.getByName("ed25519-sha-512")); // others.......... @@ -90,11 +93,11 @@ public enum SigType { private final int code, pubkeyLen, privkeyLen, hashLen, sigLen; private final SigAlgo base; - private final String digestName, algoName; + private final String digestName, algoName, since; private final AlgorithmParameterSpec params; SigType(int cod, int pubLen, int privLen, int hLen, int sLen, SigAlgo baseAlgo, - String mdName, String aName, AlgorithmParameterSpec pSpec) { + String mdName, String aName, AlgorithmParameterSpec pSpec, String supportedSince) { code = cod; pubkeyLen = pubLen; privkeyLen = privLen; @@ -104,6 +107,7 @@ public enum SigType { digestName = mdName; algoName = aName; params = pSpec; + since = supportedSince; } /** the unique identifier for this type */ @@ -162,6 +166,15 @@ public enum SigType { } } + /** + * The router version in which this type was first supported. + * + * @since 0.9.15 + */ + public String getSupportedSince() { + return since; + } + /** * @since 0.9.12 * @return true if supported in this JVM @@ -208,7 +221,8 @@ public enum SigType { static { for (SigType type : SigType.values()) { - BY_CODE.put(Integer.valueOf(type.getCode()), type); + if (BY_CODE.put(Integer.valueOf(type.getCode()), type) != null) + throw new IllegalStateException("Duplicate SigType code"); } } @@ -226,7 +240,11 @@ public enum SigType { */ public static SigType parseSigType(String stype) { try { - return valueOf(stype.toUpperCase(Locale.US)); + String uc = stype.toUpperCase(Locale.US); + // handle mixed-case enum + if (uc.equals("EDDSA_SHA512_ED25519")) + return EdDSA_SHA512_Ed25519; + return valueOf(uc); } catch (IllegalArgumentException iae) { try { int code = Integer.parseInt(stype); diff --git a/core/java/src/net/i2p/crypto/provider/I2PProvider.java b/core/java/src/net/i2p/crypto/provider/I2PProvider.java index ad001907e..d24b80d36 100644 --- a/core/java/src/net/i2p/crypto/provider/I2PProvider.java +++ b/core/java/src/net/i2p/crypto/provider/I2PProvider.java @@ -4,6 +4,9 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.security.Provider; +/** + * @since 0.9.15 + */ public final class I2PProvider extends Provider { public static final String PROVIDER_NAME = "I2P"; private static final String INFO = "I2P Security Provider v0.1, implementing" + diff --git a/history.txt b/history.txt index 3b9c6fdca..2b3caaf41 100644 --- a/history.txt +++ b/history.txt @@ -1,3 +1,13 @@ +2014-08-22 zzz + * SigTypes: + - Add isSupportedSince(), use in floodfill selection + - Handle mixed-case 25519 enum + - Fix 25519 type code + - Add dup type code check + +2014-08-21 str4d + * Add Ed25519 SigType + 2014-08-21 zzz * i2psnark: - Escape control chars in encodePath() diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index a6204817e..f2522cd4e 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -18,7 +18,7 @@ public class RouterVersion { /** deprecated */ public final static String ID = "Monotone"; public final static String VERSION = CoreVersion.VERSION; - public final static long BUILD = 8; + public final static long BUILD = 9; /** for example "-test" */ public final static String EXTRA = ""; diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillVerifyStoreJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillVerifyStoreJob.java index 645474357..f66b50020 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillVerifyStoreJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillVerifyStoreJob.java @@ -171,21 +171,23 @@ class FloodfillVerifyStoreJob extends JobImpl { private Hash pickTarget() { Hash rkey = getContext().routingKeyGenerator().getRoutingKey(_key); FloodfillPeerSelector sel = (FloodfillPeerSelector)_facade.getPeerSelector(); - boolean isKeyCert = false; + Certificate keyCert = null; if (!_isRouterInfo) { LeaseSet ls = _facade.lookupLeaseSetLocally(_key); - if (ls != null && - ls.getDestination().getCertificate().getCertificateType() == Certificate.CERTIFICATE_TYPE_KEY) - isKeyCert = true; + if (ls != null) { + Certificate cert = ls.getDestination().getCertificate(); + if (cert.getCertificateType() == Certificate.CERTIFICATE_TYPE_KEY) + keyCert = cert; + } } - if (isKeyCert) { + if (keyCert != null) { while (true) { List peers = sel.selectFloodfillParticipants(rkey, 1, _ignore, _facade.getKBuckets()); if (peers.isEmpty()) break; Hash peer = peers.get(0); RouterInfo ri = _facade.lookupRouterInfoLocally(peer); - if (ri != null && StoreJob.supportsKeyCerts(ri)) + if (ri != null && StoreJob.supportsCert(ri, keyCert)) return peer; if (_log.shouldLog(Log.INFO)) _log.info(getJobId() + ": Skipping verify w/ router that doesn't support key certs " + peer); diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java index a575a8f0c..311f2ba8f 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java @@ -12,8 +12,10 @@ import java.util.ArrayList; import java.util.List; import java.util.Set; +import net.i2p.crypto.SigType; import net.i2p.data.Certificate; import net.i2p.data.DatabaseEntry; +import net.i2p.data.DataFormatException; import net.i2p.data.Hash; import net.i2p.data.LeaseSet; import net.i2p.data.RouterInfo; @@ -170,8 +172,8 @@ class StoreJob extends JobImpl { _state.addSkipped(peer); skipped++; } else if (_state.getData().getType() == DatabaseEntry.KEY_TYPE_LEASESET && - ((LeaseSet)_state.getData()).getDestination().getCertificate().getCertificateType() == Certificate.CERTIFICATE_TYPE_KEY && - !supportsKeyCerts((RouterInfo)ds)) { + !supportsCert((RouterInfo)ds, + ((LeaseSet)_state.getData()).getDestination().getCertificate())) { if (_log.shouldLog(Log.INFO)) _log.info(getJobId() + ": Skipping router that doesn't support key certs " + peer); _state.addSkipped(peer); @@ -517,17 +519,27 @@ class StoreJob extends JobImpl { return VersionComparator.comp(v, MIN_ENCRYPTION_VERSION) >= 0; } - private static final String MIN_KEYCERT_VERSION = "0.9.12"; - /** - * Does he support key certs (assumed with a non-DSA key)? + * Does this router understand this cert? + * @return true if not a key cert * @since 0.9.12 */ - public static boolean supportsKeyCerts(RouterInfo ri) { + public static boolean supportsCert(RouterInfo ri, Certificate cert) { + if (cert.getCertificateType() != Certificate.CERTIFICATE_TYPE_KEY) + return true; + SigType type; + try { + type = cert.toKeyCertificate().getSigType(); + } catch (DataFormatException dfe) { + return false; + } + if (type == null) + return false; String v = ri.getOption("router.version"); if (v == null) return false; - return VersionComparator.comp(v, MIN_KEYCERT_VERSION) >= 0; + String since = type.getSupportedSince(); + return VersionComparator.comp(v, since) >= 0; } private static final String MIN_BIGLEASESET_VERSION = "0.9";