Changeset 0e710f87 for apps


Ignore:
Timestamp:
Feb 3, 2019 1:41:42 PM (16 months ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
e20a6a9
Parents:
7d11fb26
Message:

Streaming: Support offline signatures (proposal 123)
Don't send FROM in RESET, not required since 0.9.20
Send RESET when SYN signature verification fails
Use cached buffers for signature verification
Move setOptionalFrom() from Packet to PacketLocal?
Always verify packets with signatures, even if not required
AIOOBE checks
cleanups, log tweaks

Location:
apps/streaming/java/src/net/i2p/client/streaming/impl
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • apps/streaming/java/src/net/i2p/client/streaming/impl/Connection.java

    r7d11fb26 r0e710f87  
    1616import net.i2p.data.DataHelper;
    1717import net.i2p.data.Destination;
     18import net.i2p.data.SigningPublicKey;
    1819import net.i2p.util.Log;
    1920import net.i2p.util.SimpleTimer;
     
    3132    private final I2PSession _session;
    3233    private Destination _remotePeer;
     34    private SigningPublicKey _transientSPK;
    3335    private final AtomicLong _sendStreamId = new AtomicLong();
    3436    private final AtomicLong _receiveStreamId = new AtomicLong();
     
    328330        reply.setSendStreamId(_sendStreamId.get());
    329331        reply.setReceiveStreamId(_receiveStreamId.get());
    330         // TODO remove this someday, as of 0.9.20 we do not require it
    331         reply.setOptionalFrom();
     332        // As of 0.9.20 we do not require FROM
     333        // Removed in 0.9.39
     334        //reply.setOptionalFrom();
    332335        reply.setLocalPort(_localPort);
    333336        reply.setRemotePort(_remotePort);
     
    873876        _connectionManager.updateOptsFromShare(this);
    874877    }
     878
     879    /**
     880     *  The key to verify signatures with.
     881     *  The transient SPK if previously received,
     882     *  else getRemotePeer().getSigningPublicKey() if previously received,
     883     *  else null.
     884     *
     885     *  @return peer Destination or null if unset
     886     *  @since 0.9.39
     887     */
     888    public synchronized SigningPublicKey getRemoteSPK() {
     889        if (_transientSPK != null)
     890            return _transientSPK;
     891        if (_remotePeer != null)
     892            return _remotePeer.getSigningPublicKey();
     893        return null;
     894    }
     895
     896    /**
     897     *  @param transientSPK null ok
     898     *  @since 0.9.39
     899     */
     900    public void setRemoteTransientSPK(SigningPublicKey transientSPK) {
     901        synchronized(this) {
     902            if (_transientSPK != null)
     903                throw new RuntimeException("Remote SPK already set");
     904            _transientSPK = transientSPK;
     905        }
     906    }
    875907   
    876908    /**
  • apps/streaming/java/src/net/i2p/client/streaming/impl/ConnectionHandler.java

    r7d11fb26 r0e710f87  
    88import net.i2p.I2PAppContext;
    99import net.i2p.client.streaming.RouterRestartException;
     10import net.i2p.data.ByteArray;
    1011import net.i2p.data.Destination;
     12import net.i2p.util.ByteCache;
    1113import net.i2p.util.Log;
    1214import net.i2p.util.SimpleTimer;
     
    2426    private final I2PAppContext _context;
    2527    private final Log _log;
     28    private final ByteCache _cache = ByteCache.getInstance(32, 4*1024);
    2629    private final ConnectionManager _manager;
    2730    private final LinkedBlockingQueue<Packet> _synQueue;
     
    260263    }
    261264
     265    /**
     266     *  Send a reset in response to this packet, but only if it
     267     *  contains a FROM field and Signature that can be verified.
     268     *
     269     *  @param packet the incoming packet we're responding to
     270     */
    262271    private void sendReset(Packet packet) {
    263         boolean ok = packet.verifySignature(_context, packet.getOptionalFrom(), null);
     272        ByteArray ba = _cache.acquire();
     273        boolean ok = packet.verifySignature(_context, ba.getData());
     274        _cache.release(ba);
    264275        if (!ok) {
    265             if (_log.shouldLog(Log.WARN))
    266                 _log.warn("Received a spoofed SYN packet: they said they were " + packet.getOptionalFrom());
     276            if (_log.shouldWarn())
     277                _log.warn("Can't send reset in response to packet: " + packet);
    267278            return;
    268279        }
    269280        PacketLocal reply = new PacketLocal(_context, packet.getOptionalFrom(), packet.getSession());
    270         reply.setFlag(Packet.FLAG_RESET);
    271         reply.setFlag(Packet.FLAG_SIGNATURE_INCLUDED);
     281        reply.setFlag(Packet.FLAG_RESET | Packet.FLAG_SIGNATURE_INCLUDED);
    272282        reply.setAckThrough(packet.getSequenceNum());
    273283        reply.setSendStreamId(packet.getReceiveStreamId());
    274284        reply.setReceiveStreamId(0);
    275         // TODO remove this someday, as of 0.9.20 we do not require it
    276         reply.setOptionalFrom();
     285        // As of 0.9.20 we do not require FROM
     286        // Removed in 0.9.39
     287        //reply.setOptionalFrom();
    277288        if (_log.shouldLog(Log.DEBUG))
    278289            _log.debug("Sending RST: " + reply + " because of " + packet);
  • apps/streaming/java/src/net/i2p/client/streaming/impl/ConnectionPacketHandler.java

    r7d11fb26 r0e710f87  
    55import net.i2p.I2PAppContext;
    66import net.i2p.I2PException;
     7import net.i2p.data.ByteArray;
    78import net.i2p.data.DataHelper;
    89import net.i2p.data.Destination;
     10import net.i2p.data.SigningPublicKey;
     11import net.i2p.util.ByteCache;
    912import net.i2p.util.Log;
    1013import net.i2p.util.SimpleTimer;
     
    2427    private final I2PAppContext _context;
    2528    private final Log _log;
     29    private final ByteCache _cache = ByteCache.getInstance(32, 4*1024);
    2630
    2731    public static final int MAX_SLOW_START_WINDOW = 24;
     
    515519            if (con.getSendStreamId() <= 0) {
    516520                if (packet.isFlagSet(Packet.FLAG_SYNCHRONIZE)) {
     521                    // this is an incoming connection.
    517522                    con.setSendStreamId(packet.getReceiveStreamId());
    518523                    Destination dest = packet.getOptionalFrom();
     
    523528                    }
    524529                    con.setRemotePeer(dest);
     530                    SigningPublicKey spk = packet.getTransientSPK();
     531                    if (spk != null)
     532                        con.setRemoteTransientSPK(spk);
    525533                    return true;
    526534                } else {
     
    536544                }
    537545            } else {
     546                // getting a lot of these - why? mostly/all for acks...
    538547                if (con.getSendStreamId() != packet.getReceiveStreamId()) {
    539548                    if (_log.shouldLog(Log.WARN))
     
    554563     * and we used that for verification.
    555564     * As of 0.9.20, we correctly use the connection's remote peer.
     565     *
     566     * @param con non-null
    556567     */
    557568    private void verifyReset(Packet packet, Connection con) {
    558569        if (con.getReceiveStreamId() == packet.getSendStreamId()) {
    559             Destination from = con.getRemotePeer();
    560             if (from == null)
    561                 from = packet.getOptionalFrom();
    562             boolean ok = packet.verifySignature(_context, from, null);
     570            SigningPublicKey spk = con.getRemoteSPK();
     571            ByteArray ba = _cache.acquire();
     572            boolean ok = packet.verifySignature(_context, spk, ba.getData());
     573            _cache.release(ba);
    563574            if (!ok) {
    564575                if (_log.shouldLog(Log.ERROR))
     
    566577                return;
    567578            } else {
    568                 if (_log.shouldLog(Log.DEBUG))
    569                     _log.debug("Reset received");
     579                if (_log.shouldWarn())
     580                    _log.warn("Reset received on " + con);;
    570581                // ok, valid RST
    571582                con.resetReceived();
     
    588599     * Verify the signature if necessary. 
    589600     *
     601     * @param con non-null
    590602     * @throws I2PException if the signature was necessary and it was invalid
    591603     */
     
    593605        // verify the signature if necessary
    594606        if (con.getOptions().getRequireFullySigned() ||
    595             packet.isFlagSet(Packet.FLAG_SYNCHRONIZE | Packet.FLAG_CLOSE)) {
     607            packet.isFlagSet(Packet.FLAG_SYNCHRONIZE | Packet.FLAG_CLOSE | Packet.FLAG_SIGNATURE_INCLUDED)) {
    596608            // we need a valid signature
    597             Destination from = con.getRemotePeer();
    598             if (from == null)
    599                 from = packet.getOptionalFrom();
    600             boolean sigOk = packet.verifySignature(_context, from, null);
     609            SigningPublicKey spk = con.getRemoteSPK();
     610            ByteArray ba = _cache.acquire();
     611            boolean sigOk = packet.verifySignature(_context, spk, null);
     612            _cache.release(ba);
    601613            if (!sigOk) {
    602614                throw new I2PException("Received unsigned / forged packet: " + packet);
  • apps/streaming/java/src/net/i2p/client/streaming/impl/MessageHandler.java

    r7d11fb26 r0e710f87  
    7878            packet.setLocalPort(toPort);
    7979            _manager.getPacketHandler().receivePacket(packet);
     80        } catch (IndexOutOfBoundsException ioobe) {
     81            _context.statManager().addRateData("stream.packetReceiveFailure", 1);
     82            if (_log.shouldWarn())
     83                _log.warn("Received an invalid packet", ioobe);
    8084        } catch (IllegalArgumentException iae) {
    8185            _context.statManager().addRateData("stream.packetReceiveFailure", 1);
  • apps/streaming/java/src/net/i2p/client/streaming/impl/Packet.java

    r7d11fb26 r0e710f87  
    22
    33import java.io.ByteArrayInputStream;
     4import java.io.ByteArrayOutputStream;
    45import java.io.IOException;
    56import java.util.Arrays;
     7import java.util.Date;
    68
    79import net.i2p.I2PAppContext;
     
    8385    private int _optionDelay;
    8486    private int _optionMaxSize;
     87    // following 3 for ofline sigs
     88    protected long _transientExpires;
     89    protected Signature _offlineSignature;
     90    protected SigningPublicKey _transientSigningPublicKey;
     91    // ports
    8592    private int _localPort;
    8693    private int _remotePort;
     
    162169     */
    163170    public static final int FLAG_NO_ACK = (1 << 10);
     171   
     172    /**
     173     * If set, an offline signing block is in the options.
     174     * @since 0.9.39
     175     */
     176    public static final int FLAG_SIGNATURE_OFFLINE = (1 << 11);
    164177
    165178    public static final int DEFAULT_MAX_SIZE = 32*1024;
     
    349362    public Destination getOptionalFrom() { return _optionFrom; }
    350363
    351     /**
    352      * This sets the from field in the packet to the Destination for the session
    353      * provided in the constructor.
    354      * This also sets flag FLAG_FROM_INCLUDED
    355      */
    356     public void setOptionalFrom() {
    357         setFlag(FLAG_FROM_INCLUDED, true);
    358         _optionFrom = _session.getMyDestination();
    359     }
     364    /**
     365     *  Only if an offline signing block was included, else null
     366     *
     367     *  @since 0.9.39
     368     */
     369    public SigningPublicKey getTransientSPK() { return _transientSigningPublicKey; }
    360370   
    361371    /**
     
    479489        if (isFlagSet(FLAG_MAX_PACKET_SIZE_INCLUDED))
    480490            optionSize += 2;
     491        if (isFlagSet(FLAG_SIGNATURE_OFFLINE)) {
     492            optionSize += 6;
     493            optionSize += _transientSigningPublicKey.length();
     494            optionSize += _offlineSignature.length();
     495        }
    481496        if (isFlagSet(FLAG_SIGNATURE_INCLUDED)) {
    482497            if (fakeSigLen > 0)
     
    502517            cur += 2;
    503518        }
     519        if (isFlagSet(FLAG_SIGNATURE_OFFLINE)) {
     520                DataHelper.toLong(buffer, cur, 4, _transientExpires / 1000);
     521                cur += 4;
     522                DataHelper.toLong(buffer, cur, 2, _transientSigningPublicKey.getType().getCode());
     523                cur += 2;
     524                int len = _transientSigningPublicKey.length();
     525                System.arraycopy(_transientSigningPublicKey.getData(), 0, buffer, cur, len);
     526                cur += len;
     527                len = _offlineSignature.length();
     528                System.arraycopy(_offlineSignature.getData(), 0, buffer, cur, len);
     529                cur += len;
     530            }
    504531        if (isFlagSet(FLAG_SIGNATURE_INCLUDED)) {
    505532            if (fakeSigLen == 0) {
     
    536563    /**
    537564     * how large would this packet be if we wrote it
     565     *
    538566     * @return How large the current packet would be
    539      *
    540      * @throws IllegalStateException
    541567     */
    542568    private int writtenSize() {
     
    565591        if (isFlagSet(FLAG_SIGNATURE_INCLUDED))
    566592            size += _optionSignature.length();
     593        if (isFlagSet(FLAG_SIGNATURE_OFFLINE)) {
     594            size += 6;
     595            size += _transientSigningPublicKey.length();
     596            size += _offlineSignature.length();
     597        }
    567598       
    568599        if (_payload != null) {
     
    584615     *
    585616     * @throws IllegalArgumentException if the data is b0rked
     617     * @throws IndexOutOfBoundsException if the data is b0rked
    586618     */
    587619    public void readPacket(byte buffer[], int offset, int length) throws IllegalArgumentException {
     
    658690            cur += 2;
    659691        }
     692        if (isFlagSet(FLAG_SIGNATURE_OFFLINE)) {
     693            _transientExpires = DataHelper.fromLong(buffer, cur, 4) * 1000;
     694            cur += 4;
     695            int itype = (int) DataHelper.fromLong(buffer, cur, 2);
     696            cur += 2;
     697            SigType type = SigType.getByCode(itype);
     698            if (type == null || !type.isAvailable())
     699                throw new IllegalArgumentException("Unsupported transient sig type: " + itype);
     700            _transientSigningPublicKey = new SigningPublicKey(type);
     701            byte[] buf = new byte[_transientSigningPublicKey.length()];
     702            System.arraycopy(buffer, cur, buf, 0, buf.length);
     703            _transientSigningPublicKey.setData(buf);
     704            cur += buf.length;
     705            if (_optionFrom != null) {
     706                type = _optionFrom.getSigningPublicKey().getType();
     707            } else {
     708                throw new IllegalArgumentException("TODO offline w/o FROM");
     709            }
     710            _offlineSignature = new Signature(type);
     711            buf = new byte[_offlineSignature.length()];
     712            System.arraycopy(buffer, cur, buf, 0, buf.length);
     713            _offlineSignature.setData(buf);
     714            cur += buf.length;
     715        }
    660716        if (isFlagSet(FLAG_SIGNATURE_INCLUDED)) {
    661717            Signature optionSignature;
    662             Destination from = getOptionalFrom();
    663             if (from != null) {
    664                 optionSignature = new Signature(from.getSigningPublicKey().getType());
     718            if (_optionFrom != null) {
     719                SigType type;
     720                if (isFlagSet(FLAG_SIGNATURE_OFFLINE))
     721                    type = _transientSigningPublicKey.getType();
     722                else
     723                    type = _optionFrom.getSigningPublicKey().getType();
     724                optionSignature = new Signature(type);
    665725            } else {
    666726                // super cheat for now, look for correct type,
     
    695755        }
    696756    }
    697    
     757
    698758    /**
    699759     * Determine whether the signature on the data is valid. 
     760     * Packet MUST have a FROM option or will return false.
    700761     *
    701762     * @param ctx Application context
    702      * @param from the Destination the data came from
    703      * @param buffer data to validate with signature
     763     * @param buffer data to validate with signature, or null to use our own buffer.
    704764     * @return true if the signature exists and validates against the data,
    705765     *         false otherwise.
    706      */
    707     public boolean verifySignature(I2PAppContext ctx, Destination from, byte buffer[]) {
     766     * @since 0.9.39
     767     */
     768    public boolean verifySignature(I2PAppContext ctx, byte buffer[]) {
     769        return verifySignature(ctx, null, buffer);   
     770    }
     771
     772    /**
     773     * Determine whether the signature on the data is valid. 
     774     *
     775     * @param ctx Application context
     776     * @param spk Signing key to verify with, ONLY if there is no FROM field in this packet.
     777     *        May be the SPK from a FROM field or offline sig field from a previous packet on this connection.
     778     *        Ignored if this packet contains a FROM option block.
     779     *        Null ok if none available.
     780     * @param buffer data to validate with signature, or null to use our own buffer.
     781     * @return true if the signature exists and validates against the data,
     782     *         false otherwise.
     783     */
     784    public boolean verifySignature(I2PAppContext ctx, SigningPublicKey altSPK, byte buffer[]) {
    708785        if (!isFlagSet(FLAG_SIGNATURE_INCLUDED)) return false;
    709786        if (_optionSignature == null) return false;
     787        SigningPublicKey spk = _optionFrom != null ? _optionFrom.getSigningPublicKey() : altSPK;
    710788        // prevent receiveNewSyn() ... !active ... sendReset() ... verifySignature ... NPE
    711         if (from == null) return false;
     789        if (spk == null) return false;
    712790       
    713791        int size = writtenSize();
     
    715793        if (buffer == null)
    716794            buffer = new byte[size];
    717         SigningPublicKey spk = from.getSigningPublicKey();
     795        if (isFlagSet(FLAG_SIGNATURE_OFFLINE)) {
     796            if (_transientExpires < ctx.clock().now()) {
     797                Log l = ctx.logManager().getLog(Packet.class);
     798                if (l.shouldLog(Log.WARN))
     799                    l.warn("Offline signature expired " + toString());
     800                return false;
     801            }
     802            ByteArrayOutputStream baos = new ByteArrayOutputStream(6 + _transientSigningPublicKey.length());
     803            try {
     804                DataHelper.writeLong(baos, 4, _transientExpires / 1000);
     805                DataHelper.writeLong(baos, 2, _transientSigningPublicKey.getType().getCode());
     806                _transientSigningPublicKey.writeBytes(baos);
     807            } catch (IOException ioe) {
     808                return false;
     809            } catch (DataFormatException dfe) {
     810                return false;
     811            }
     812            byte[] data = baos.toByteArray();
     813            boolean ok = ctx.dsa().verifySignature(_offlineSignature, data, 0, data.length, spk);
     814            if (!ok) {
     815                Log l = ctx.logManager().getLog(Packet.class);
     816                if (l.shouldLog(Log.WARN))
     817                    l.warn("Offline signature failed on " + toString());
     818                return false;
     819            }
     820            // use transient key to verify
     821            spk = _transientSigningPublicKey;
     822        }
    718823        SigType type = spk.getType();
    719         if (type == null) {
     824        if (type == null || !type.isAvailable()) {
    720825            Log l = ctx.logManager().getLog(Packet.class);
    721826            if (l.shouldLog(Log.WARN))
    722                 l.warn("Unknown sig type in " + from + " cannot verify " + toString());
     827                l.warn("Unknown sig type in " + spk + " cannot verify " + toString());
    723828            return false;
    724829        }
     
    732837        // on a close or reset packet where we have a signature without a FROM
    733838        if (type != _optionSignature.getType() &&
    734             type.getSigLen() == _optionSignature.length())
     839            type.getSigLen() == _optionSignature.length()) {
     840            //Log l = ctx.logManager().getLog(Packet.class);
     841            //if (l.shouldDebug())
     842            //    l.debug("Fixing up sig type from " + _optionSignature.getType() + " to " + type);
    735843            _optionSignature = new Signature(type, _optionSignature.getData());
    736 
    737         boolean ok = ctx.dsa().verifySignature(_optionSignature, buffer, 0, size, spk);
     844        }
     845
     846        boolean ok;
     847        try {
     848            ok = ctx.dsa().verifySignature(_optionSignature, buffer, 0, size, spk);
     849        } catch (IllegalArgumentException iae) {
     850            // sigtype mismatch
     851            Log l = ctx.logManager().getLog(Packet.class);
     852            if (l.shouldLog(Log.WARN))
     853                l.warn("Signature failed on " + toString(), iae);
     854            ok = false;
     855        }
    738856        if (!ok) {
    739857            Log l = ctx.logManager().getLog(Packet.class);
    740858            if (l.shouldLog(Log.WARN))
    741                 l.warn("Signature failed on " + toString(), new Exception("moo"));
    742             //if (false) {
    743             //    l.error(Base64.encode(buffer, 0, size));
    744             //    l.error("Signature: " + Base64.encode(_optionSignature.getData()));
    745             //}
     859                l.warn("Signature failed on " + toString() + " using SPK " + spk);
    746860        }
    747861        return ok;
     
    777891   
    778892    private final void toFlagString(StringBuilder buf) {
     893        if (isFlagSet(FLAG_SYNCHRONIZE)) buf.append(" SYN");
     894        if (isFlagSet(FLAG_CLOSE)) buf.append(" CLOSE");
     895        if (isFlagSet(FLAG_RESET)) buf.append(" RESET");
     896        if (isFlagSet(FLAG_ECHO)) buf.append(" ECHO");
     897        if (isFlagSet(FLAG_FROM_INCLUDED)) buf.append(" FROM ").append(_optionFrom.size());
    779898        if (isFlagSet(FLAG_NO_ACK))
    780899            buf.append(" NO_ACK");
     
    787906            }
    788907        }
    789         if (isFlagSet(FLAG_CLOSE)) buf.append(" CLOSE");
    790908        if (isFlagSet(FLAG_DELAY_REQUESTED)) buf.append(" DELAY ").append(_optionDelay);
    791         if (isFlagSet(FLAG_ECHO)) buf.append(" ECHO");
    792         if (isFlagSet(FLAG_FROM_INCLUDED)) buf.append(" FROM ").append(_optionFrom.size());
    793909        if (isFlagSet(FLAG_MAX_PACKET_SIZE_INCLUDED)) buf.append(" MS ").append(_optionMaxSize);
    794910        if (isFlagSet(FLAG_PROFILE_INTERACTIVE)) buf.append(" INTERACTIVE");
    795         if (isFlagSet(FLAG_RESET)) buf.append(" RESET");
     911        if (isFlagSet(FLAG_SIGNATURE_REQUESTED)) buf.append(" SIGREQ");
     912        if (isFlagSet(FLAG_SIGNATURE_OFFLINE)) {
     913            if (_transientExpires != 0)
     914                buf.append(" TRANSEXP ").append(new Date(_transientExpires));
     915            else
     916                buf.append(" (no expiration)");
     917            if (_transientSigningPublicKey != null)
     918                buf.append(" TRANSKEY ").append(_transientSigningPublicKey.getType());
     919            else
     920                buf.append(" (no key data)");
     921            if (_offlineSignature != null)
     922                buf.append(" OFFSIG ").append(_offlineSignature.getType());
     923            else
     924                buf.append(" (no offline sig data)");
     925        }
    796926        if (isFlagSet(FLAG_SIGNATURE_INCLUDED)) {
    797927            if (_optionSignature != null)
    798                 buf.append(" SIG ").append(_optionSignature.length());
     928                buf.append(" SIG ").append(_optionSignature.getType());
    799929            else
    800930                buf.append(" (to be signed)");
    801931        }
    802         if (isFlagSet(FLAG_SIGNATURE_REQUESTED)) buf.append(" SIGREQ");
    803         if (isFlagSet(FLAG_SYNCHRONIZE)) buf.append(" SYN");
    804932    }
    805933
  • apps/streaming/java/src/net/i2p/client/streaming/impl/PacketHandler.java

    r7d11fb26 r0e710f87  
    66import net.i2p.I2PAppContext;
    77import net.i2p.I2PException;
     8import net.i2p.data.ByteArray;
    89import net.i2p.data.Destination;
     10import net.i2p.data.SigningPublicKey;
     11import net.i2p.util.ByteCache;
    912import net.i2p.util.Log;
    1013
     
    1922    private final I2PAppContext _context;
    2023    private final Log _log;
     24    private final ByteCache _cache = ByteCache.getInstance(32, 4*1024);
    2125    //private int _lastDelay;
    2226    //private int _dropped;
     
    180184                    if (packet.isFlagSet(Packet.FLAG_SYNCHRONIZE)) {
    181185                        if (oldId <= 0) {
    182                             // con fully established, w00t
     186                            // outgoing con now fully established
    183187                            con.setSendStreamId(packet.getReceiveStreamId());
     188                            SigningPublicKey spk = packet.getTransientSPK();
     189                            if (spk != null)
     190                                con.setRemoteTransientSPK(spk);
    184191                        } else if (oldId == packet.getReceiveStreamId()) {
    185192                            // ok, as expected...
     
    196203                        con.getPacketHandler().receivePacket(packet, con);
    197204                    } catch (I2PException ie) {
    198                         if (_log.shouldLog(Log.ERROR))
    199                             _log.error("Received forged packet for " + con + "/" + oldId + ": " + packet, ie);
     205                        if (_log.shouldWarn())
     206                            _log.warn("Sig verify fail for " + con + "/" + oldId + ": " + packet, ie);
    200207                        con.setSendStreamId(oldId);
     208                        if (packet.isFlagSet(Packet.FLAG_SYNCHRONIZE)) {
     209                            // send a reset, it's a known con, so it's unlikely to be spoofed
     210                            // don't bother to send reset if it's just a CLOSE
     211                            sendResetUnverified(packet);
     212                        }
    201213                    }
    202214                } else if (packet.isFlagSet(Packet.FLAG_SYNCHRONIZE)) {
     
    239251        if (from == null)
    240252            return;
    241         boolean ok = packet.verifySignature(_context, from, null);
     253        ByteArray ba = _cache.acquire();
     254        boolean ok = packet.verifySignature(_context, ba.getData());
     255        _cache.release(ba);
    242256        if (!ok) {
    243257            if (_log.shouldLog(Log.WARN))
    244                 _log.warn("Can't send reset after recv spoofed packet: " + packet);
     258                _log.warn("Can't send reset in response to packet: " + packet);
    245259            return;
    246260        }
    247         PacketLocal reply = new PacketLocal(_context, from, packet.getSession());
     261        sendResetUnverified(packet);
     262    }
     263   
     264    /**
     265     *  This sends a reset back to the place this packet came from.
     266     *  Packet MUST have a FROM option.
     267     *  This is not associated with a connection, so no con stats are updated.
     268     *
     269     *  @param packet incoming packet to be replied to, MUST have a FROM option
     270     *  @since 0.9.39
     271     */
     272    private void sendResetUnverified(Packet packet) {
     273        PacketLocal reply = new PacketLocal(_context, packet.getOptionalFrom(), packet.getSession());
    248274        reply.setFlag(Packet.FLAG_RESET);
    249275        reply.setFlag(Packet.FLAG_SIGNATURE_INCLUDED);
    250276        reply.setSendStreamId(packet.getReceiveStreamId());
    251277        reply.setReceiveStreamId(packet.getSendStreamId());
    252         // TODO remove this someday, as of 0.9.20 we do not require it
    253         reply.setOptionalFrom();
     278        // As of 0.9.20 we do not require FROM
     279        // Removed in 0.9.39
     280        //reply.setOptionalFrom();
    254281        reply.setLocalPort(packet.getLocalPort());
    255282        reply.setRemotePort(packet.getRemotePort());
     
    349376     */
    350377    private void receivePing(Connection con, Packet packet) {
    351         boolean ok = packet.verifySignature(_context, packet.getOptionalFrom(), null);
     378        SigningPublicKey spk = con != null ? con.getRemoteSPK() : null;
     379        ByteArray ba = _cache.acquire();
     380        boolean ok = packet.verifySignature(_context, spk, ba.getData());
     381        _cache.release(ba);
    352382        if (!ok) {
    353             if (_log.shouldLog(Log.WARN)) {
    354                 if (packet.getOptionalFrom() == null)
    355                     _log.warn("Ping with no from (flagged? " + packet.isFlagSet(Packet.FLAG_FROM_INCLUDED) + ")");
    356                 else if (packet.getOptionalSignature() == null)
    357                     _log.warn("Ping with no signature (flagged? " + packet.isFlagSet(Packet.FLAG_SIGNATURE_INCLUDED) + ")");
    358                 else
    359                     _log.warn("Forged ping, discard (from=" + packet.getOptionalFrom().calculateHash().toBase64()
    360                               + " sig=" + packet.getOptionalSignature().toBase64() + ")");
    361             }
     383            if (_log.shouldLog(Log.WARN))
     384                _log.warn("Bad ping, dropping: " + packet);
    362385        } else {
    363386            _manager.receivePing(con, packet);
  • apps/streaming/java/src/net/i2p/client/streaming/impl/PacketLocal.java

    r7d11fb26 r0e710f87  
    6161        _lastSend = -1;
    6262        _cancelledOn = -1;
     63    }
     64
     65    /**
     66     * This sets the from field in the packet to the Destination for the session
     67     * provided in the constructor.
     68     * This also sets flag FLAG_FROM_INCLUDED.
     69     * Also, as of 0.9.39, sets the offline signing data if supported by the session.
     70     *
     71     * @since 0.9.39 moved from super
     72     */
     73    public void setOptionalFrom() {
     74        setFlag(FLAG_FROM_INCLUDED, true);
     75        _optionFrom = _session.getMyDestination();
     76        if (_session.isOffline()) {
     77            setFlag(FLAG_SIGNATURE_OFFLINE, true);
     78            _transientExpires = _session.getOfflineExpiration();
     79            _transientSigningPublicKey = _session.getTransientSigningPublicKey();
     80            _offlineSignature = _session.getOfflineSignature();
     81        }
    6382    }
    6483   
     
    228247                              //+ 2 // flags
    229248                              //+ 2 // optionSize
    230                               + 21
    231                               + (_nacks != null ? 4*_nacks.length + 1 : 1)
    232                               + (isFlagSet(FLAG_DELAY_REQUESTED) ? 2 : 0)
    233                               + (isFlagSet(FLAG_FROM_INCLUDED) ? _optionFrom.size() : 0)
    234                               + (isFlagSet(FLAG_MAX_PACKET_SIZE_INCLUDED) ? 2 : 0);
     249                              //+ 1 // nacksSize
     250                              + 22;
     251        if (_nacks != null)
     252            signatureOffset += 4 *_nacks.length;
     253        if (isFlagSet(FLAG_DELAY_REQUESTED))
     254            signatureOffset += 2;
     255        if (isFlagSet(FLAG_FROM_INCLUDED))
     256            signatureOffset += _optionFrom.size();
     257        if (isFlagSet(FLAG_MAX_PACKET_SIZE_INCLUDED))
     258            signatureOffset += 2;
     259        if (isFlagSet(FLAG_SIGNATURE_OFFLINE)) {
     260            signatureOffset += 6;
     261            signatureOffset += _transientSigningPublicKey.length();
     262            signatureOffset += _offlineSignature.length();
     263        }
    235264        System.arraycopy(_optionSignature.getData(), 0, buffer, signatureOffset, _optionSignature.length());
    236265        return size;
Note: See TracChangeset for help on using the changeset viewer.