Changeset 926bce7 for core


Ignore:
Timestamp:
Dec 5, 2018 3:27:36 PM (18 months ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
92c42db
Parents:
d054c6bc
Message:

I2CP: Set and validate offline sig in SessionConfig?

Location:
core/java/src/net/i2p
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • core/java/src/net/i2p/client/impl/I2CPMessageProducer.java

    rd054c6bc r926bce7  
    9696        SessionConfig cfg = new SessionConfig(session.getMyDestination());
    9797        cfg.setOptions(session.getOptions());
    98         if (_log.shouldLog(Log.DEBUG)) _log.debug("config created");
     98        if (session.isOffline()) {
     99            cfg.setOfflineSignature(session.getOfflineExpiration(),
     100                                    session.getTransientSigningPublicKey(),
     101                                    session.getOfflineSignature());
     102        }
    99103        try {
    100104            cfg.signSessionConfig(session.getPrivateKey());
     
    102106            throw new I2PSessionException("Unable to sign the session config", dfe);
    103107        }
    104         if (_log.shouldLog(Log.DEBUG)) _log.debug("config signed");
    105108        msg.setSessionConfig(cfg);
    106         if (_log.shouldLog(Log.DEBUG)) _log.debug("config loaded into message");
    107109        session.sendMessage_unchecked(msg);
    108         if (_log.shouldLog(Log.DEBUG)) _log.debug("config message sent");
    109110    }
    110111
  • core/java/src/net/i2p/data/i2cp/SessionConfig.java

    rd054c6bc r926bce7  
    2020import net.i2p.I2PAppContext;
    2121import net.i2p.crypto.DSAEngine;
     22import net.i2p.crypto.SigType;
    2223import net.i2p.data.DataFormatException;
    2324import net.i2p.data.DataHelper;
     
    2627import net.i2p.data.Signature;
    2728import net.i2p.data.SigningPrivateKey;
     29import net.i2p.data.SigningPublicKey;
    2830import net.i2p.util.Clock;
    2931import net.i2p.util.Log;
     
    4143    private Properties _options;
    4244
     45    /**
     46     *  Seconds since epoch, NOT ms
     47     *  @since 0.9.38
     48     */
     49    public static final String PROP_OFFLINE_EXPIRATION = "i2cp.leaseSetOfflineExpiration";
     50
     51    /**
     52     *  Base 64, optionally preceded by sig type and ':', default DSA-SHA1
     53     *  @since 0.9.38
     54     */
     55    public static final String PROP_TRANSIENT_KEY = "i2cp.leaseSetTransientPublicKey";
     56
     57    /**
     58     *  Base 64, optionally preceded by sig type and ':', default DSA-SHA1
     59     *  @since 0.9.38
     60     */
     61    public static final String PROP_OFFLINE_SIGNATURE = "i2cp.leaseSetOfflineSignature";
     62
    4363    /**
    4464     * If the client authorized this session more than the specified period ago,
     
    99119     * Client side must promote defaults to the primary map.
    100120     *
     121     * Does NOT make a copy.
     122     *
    101123     * @param options Properties for this session
    102124     */
     
    114136
    115137    /**
     138     *  Set the offline signing data.
     139     *  Does NOT validate the signature.
     140     *  Must be called AFTER setOptions(). Will throw ISE otherwise.
     141     *  Side effect - modifies options.
     142     *
     143     *  @throws IllegalStateException
     144     *  @since 0.9.38
     145     */
     146    public void setOfflineSignature(long expires, SigningPublicKey transientSPK, Signature offlineSig) {
     147        if (_options == null)
     148            throw new IllegalStateException();
     149        _options.setProperty(PROP_OFFLINE_EXPIRATION, Long.toString(expires / 1000));
     150        _options.setProperty(PROP_TRANSIENT_KEY,
     151                             transientSPK.getType().getCode() + ":" + transientSPK.toBase64());
     152        _options.setProperty(PROP_OFFLINE_SIGNATURE, offlineSig.toBase64());
     153    }
     154
     155    /**
     156     *  Get the offline expiration
     157     *  @return Java time (ms) or 0 if not initialized or does not have offline keys
     158     *  @since 0.9.38
     159     */
     160    public long getOfflineExpiration() {
     161        if (_options == null)
     162            return 0;
     163        String s = _options.getProperty(PROP_OFFLINE_EXPIRATION);
     164        if (s == null)
     165            return 0;
     166        try {
     167            return Long.parseLong(s) * 1000;
     168        } catch (NumberFormatException nfe) {
     169            return 0;
     170        }
     171    }
     172
     173    /**
     174     *  @return null on error or if not initialized or does not have offline keys
     175     *  @since 0.9.38
     176     */
     177    public SigningPublicKey getTransientSigningPublicKey() {
     178        if (_options == null || _destination == null)
     179            return null;
     180        String s = _options.getProperty(PROP_TRANSIENT_KEY);
     181        if (s == null)
     182            return null;
     183        int colon = s.indexOf(':');
     184        SigType type;
     185        if (colon > 0) {
     186            String stype = s.substring(0, colon);
     187            type = SigType.parseSigType(stype);
     188            if (type == null)
     189                return null;
     190            s = s.substring(colon + 1);
     191        } else {
     192            type = SigType.DSA_SHA1;
     193        }
     194        SigningPublicKey rv = new SigningPublicKey(type);
     195        try {
     196            rv.fromBase64(s);
     197            return rv;
     198        } catch (DataFormatException dfe) {
     199            return null;
     200        }
     201    }
     202
     203    /**
     204     *  @return null on error or if not initialized or does not have offline keys
     205     *  @since 0.9.38
     206     */
     207    public Signature getOfflineSignature() {
     208        if (_options == null || _destination == null)
     209            return null;
     210        String s = _options.getProperty(PROP_OFFLINE_SIGNATURE);
     211        if (s == null)
     212            return null;
     213        Signature rv = new Signature(_destination.getSigningPublicKey().getType());
     214        try {
     215            rv.fromBase64(s);
     216            return rv;
     217        } catch (DataFormatException dfe) {
     218            return null;
     219        }
     220    }
     221
     222    /**
    116223     * Sign the structure using the supplied private key
    117224     *
    118      * @param signingKey SigningPrivateKey to sign with
     225     * @param signingKey SigningPrivateKey to sign with.
     226     *                   If offline data is set, must be with the transient key.
    119227     * @throws DataFormatException
    120228     */
     
    135243     * past or future. See tooOld() and getCreationDate().
    136244     *
     245     * As of 0.9.38, validates the offline signature if included.
     246     *
    137247     * @return true only if the signature matches
    138248     */
     
    160270        }
    161271
    162         boolean ok = DSAEngine.getInstance().verifySignature(getSignature(), data,
    163                                                              getDestination().getSigningPublicKey());
     272        SigningPublicKey spk = getTransientSigningPublicKey();
     273        if (spk != null) {
     274            // validate offline sig
     275            long expires = getOfflineExpiration();
     276            if (expires < _creationDate.getTime())
     277                return false;
     278            Signature sig = getOfflineSignature();
     279            if (sig == null)
     280                return false;
     281            ByteArrayOutputStream baos = new ByteArrayOutputStream(128);
     282            try {
     283                DataHelper.writeLong(baos, 4, expires / 1000);
     284                DataHelper.writeLong(baos, 2, spk.getType().getCode());
     285                spk.writeBytes(baos);
     286            } catch (IOException ioe) {
     287                return false;
     288            } catch (DataFormatException dfe) {
     289                return false;
     290            }
     291            byte[] odata = baos.toByteArray();
     292            boolean ok = DSAEngine.getInstance().verifySignature(sig, odata, 0, odata.length,
     293                                                                 _destination.getSigningPublicKey());
     294            if (!ok)
     295                return false;
     296        } else {
     297            spk = getDestination().getSigningPublicKey();
     298        }
     299
     300        boolean ok = DSAEngine.getInstance().verifySignature(getSignature(), data, spk);
    164301        if (!ok) {
    165302            Log log = I2PAppContext.getGlobalContext().logManager().getLog(SessionConfig.class);
Note: See TracChangeset for help on using the changeset viewer.