From d6a53cc3a61b198f9052e4a4708a13fff1b90c35 Mon Sep 17 00:00:00 2001
From: zzz <zzz@mail.i2p>
Date: Sat, 9 Mar 2019 11:47:03 +0000
Subject: [PATCH] Data: Consolidate offline key check i2ptunnel: Prevent
 registration auth if key offline

---
 apps/i2ptunnel/jsp/register.jsp                   |  2 ++
 apps/sam/java/src/net/i2p/sam/SAMUtils.java       | 15 +--------------
 .../src/net/i2p/client/impl/I2PSessionImpl.java   | 15 +--------------
 core/java/src/net/i2p/data/PrivateKeyFile.java    | 15 +--------------
 core/java/src/net/i2p/data/SigningPrivateKey.java | 15 +++++++++++++++
 5 files changed, 20 insertions(+), 42 deletions(-)

diff --git a/apps/i2ptunnel/jsp/register.jsp b/apps/i2ptunnel/jsp/register.jsp
index 313eea4b3e..5f4f229e98 100644
--- a/apps/i2ptunnel/jsp/register.jsp
+++ b/apps/i2ptunnel/jsp/register.jsp
@@ -127,6 +127,8 @@ input.default { width: 1px; height: 1px; visibility: hidden; }
            SigningPrivateKey spk = editBean.getSigningPrivateKey(curTunnel);
            if (spk == null) {
                %><tr><td class="infohelp"><%=intl._t("Destination signing key is not available. Start the tunnel.")%></td></tr><%
+           } else if (spk.isOffline()) {
+               %><tr><td class="infohelp"><%=intl._t("Destination signing key is offline. Use CLI tools on the offline machine.")%></td></tr><%
            } else {
                valid = true;
                OrderedProperties props = new OrderedProperties();
diff --git a/apps/sam/java/src/net/i2p/sam/SAMUtils.java b/apps/sam/java/src/net/i2p/sam/SAMUtils.java
index a17ec1f000..3ab98301bb 100644
--- a/apps/sam/java/src/net/i2p/sam/SAMUtils.java
+++ b/apps/sam/java/src/net/i2p/sam/SAMUtils.java
@@ -117,7 +117,7 @@ class SAMUtils {
             SigType dtype = d.getSigningPublicKey().getType();
             SigningPrivateKey spk = new SigningPrivateKey(dtype);
             spk.readBytes(destKeyStream);
-            if (isOffline(spk)) {
+            if (spk.isOffline()) {
                 // offlineExpiration
                 DataHelper.readLong(destKeyStream, 4);
                 int itype = (int) DataHelper.readLong(destKeyStream, 2);
@@ -140,19 +140,6 @@ class SAMUtils {
         return destKeyStream.available() == 0;
     }
 
-    /**
-     *  @since 0.9.39
-     */
-    private static boolean isOffline(SigningPrivateKey spk) {
-        byte[] data = spk.getData();
-        for (int i = 0; i < data.length; i++) {
-            if (data[i] != 0)
-                return false;
-        }
-        return true;
-    }
-
-
     /**
      * Resolved the specified hostname.
      *
diff --git a/core/java/src/net/i2p/client/impl/I2PSessionImpl.java b/core/java/src/net/i2p/client/impl/I2PSessionImpl.java
index 249f5b74bd..fad799a8e8 100644
--- a/core/java/src/net/i2p/client/impl/I2PSessionImpl.java
+++ b/core/java/src/net/i2p/client/impl/I2PSessionImpl.java
@@ -577,7 +577,7 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
         SigType dtype = _myDestination.getSigningPublicKey().getType();
         _signingPrivateKey = new SigningPrivateKey(dtype);
         _signingPrivateKey.readBytes(destKeyStream);
-        if (isOffline(_signingPrivateKey)) {
+        if (_signingPrivateKey.isOffline()) {
             _offlineExpiration = DataHelper.readLong(destKeyStream, 4) * 1000;;
             int itype = (int) DataHelper.readLong(destKeyStream, 2);
             SigType type = SigType.getByCode(itype);
@@ -593,19 +593,6 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
         }
     }
 
-    /**
-     *  Constant time
-     *  @since 0.9.38
-     */
-    private static boolean isOffline(SigningPrivateKey spk) {
-        byte b = 0;
-        byte[] data = spk.getData();
-        for (int i = 0; i < data.length; i++) {
-            b |= data[i];
-        }
-        return b == 0;
-    }
-
     /**
      *  Does this session have offline and transient keys?
      *  @since 0.9.38
diff --git a/core/java/src/net/i2p/data/PrivateKeyFile.java b/core/java/src/net/i2p/data/PrivateKeyFile.java
index 597ef1b161..db064bfc21 100644
--- a/core/java/src/net/i2p/data/PrivateKeyFile.java
+++ b/core/java/src/net/i2p/data/PrivateKeyFile.java
@@ -620,19 +620,6 @@ public class PrivateKeyFile {
     
     //// offline methods
 
-    /**
-     *  Constant time
-     *  @since 0.9.38
-     */
-    private static boolean isOffline(SigningPrivateKey spk) {
-        byte b = 0;
-        byte[] data = spk.getData();
-        for (int i = 0; i < data.length; i++) {
-            b |= data[i];
-        }
-        return b == 0;
-    }
-
     /**
      *  Does this session have offline and transient keys?
      *  @since 0.9.38
@@ -646,7 +633,7 @@ public class PrivateKeyFile {
      *  @since 0.9.38
      */
     public void setOfflineData(long expires, SigningPublicKey transientPub, Signature sig, SigningPrivateKey transientPriv) {
-        if (!isOffline(signingPrivKey)) {
+        if (!signingPrivKey.isOffline()) {
             SigType type = getSigningPrivKey().getType();
             byte[] dbytes = new byte[type.getPrivkeyLen()];
             signingPrivKey = new SigningPrivateKey(type, dbytes);
diff --git a/core/java/src/net/i2p/data/SigningPrivateKey.java b/core/java/src/net/i2p/data/SigningPrivateKey.java
index c9f0143d0a..757c9102a3 100644
--- a/core/java/src/net/i2p/data/SigningPrivateKey.java
+++ b/core/java/src/net/i2p/data/SigningPrivateKey.java
@@ -100,6 +100,21 @@ public class SigningPrivateKey extends SimpleDataStructure {
         return Blinding.blind(this, alpha);
     }
 
+    /**
+     *  Constant time
+     *  @return true if all zeros
+     *  @since 0.9.39 moved from PrivateKeyFile
+     */
+    public boolean isOffline() {
+        if (_data == null)
+            return true;
+        byte b = 0;
+        for (int i = 0; i < _data.length; i++) {
+            b |= _data[i];
+        }
+        return b == 0;
+    }
+
     /**
      *  @since 0.9.8
      */
-- 
GitLab