Changeset 51f9d6d


Ignore:
Timestamp:
Aug 25, 2014 8:33:56 PM (6 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
ed4fe56
Parents:
ddb32c6
Message:

NTCP RI sig types

File:
1 edited

Legend:

Unmodified
Added
Removed
  • router/java/src/net/i2p/router/transport/ntcp/EstablishState.java

    rddb32c6 r51f9d6d  
    11package net.i2p.router.transport.ntcp;
    22
     3import java.io.ByteArrayInputStream;
    34import java.io.ByteArrayOutputStream;
    45import java.io.IOException;
     
    89
    910import net.i2p.I2PAppContext;
     11import net.i2p.crypto.SigType;
    1012import net.i2p.data.Base64;
    1113import net.i2p.data.DataFormatException;
     
    7173    private final byte _hX_xor_bobIdentHash[];
    7274    private int _aliceIdentSize;
     75    private RouterIdentity _aliceIdent;
    7376    /** contains the decrypted aliceIndexSize + aliceIdent + tsA + padding + aliceSig */
    7477    private ByteArrayOutputStream _sz_aliceIdent_tsA_padding_aliceSig;
     
    113116    private boolean _failedBySkew;
    114117   
     118    private static final int MIN_RI_SIZE = 387;
     119    private static final int MAX_RI_SIZE = 2048;
     120
    115121    private EstablishState() {
    116122        _context = null;
     
    157163    public void receive(ByteBuffer src) {
    158164        if (_corrupt || _verified)
    159             throw new IllegalStateException(prefix() + "received after completion [corrupt?" + _corrupt + " verified? " + _verified + "] on " + _con);
     165            throw new IllegalStateException(prefix() + "received after completion [corrupt?" +
     166                                            _corrupt + " verified? " + _verified + "] on " + _con);
    160167        if (!src.hasRemaining())
    161168            return; // nothing to receive
     
    186193    private void receiveInbound(ByteBuffer src) {
    187194        if (_log.shouldLog(Log.DEBUG))
    188             _log.debug(prefix()+"Receiving inbound: prev received=" + _received + " src.remaining=" + src.remaining());
     195            _log.debug(prefix() + "Receiving inbound: prev received=" + _received +
     196                       " src.remaining=" + src.remaining());
    189197        while (_received < _X.length && src.hasRemaining()) {
    190198            byte c = src.get();
     
    270278                    SimpleByteCache.release(hxy);
    271279                    _e_hXY_tsB = new byte[toEncrypt.length];
    272                     _context.aes().encrypt(toEncrypt, 0, _e_hXY_tsB, 0, _dh.getSessionKey(), _Y, _Y.length-16, toEncrypt.length);
     280                    _context.aes().encrypt(toEncrypt, 0, _e_hXY_tsB, 0, _dh.getSessionKey(),
     281                                           _Y, _Y.length-16, toEncrypt.length);
    273282                    if (_log.shouldLog(Log.DEBUG))
    274283                        _log.debug(prefix()+"encrypted H(X+Y)+tsB+padding: " + Base64.encode(_e_hXY_tsB));
     
    287296            }
    288297
    289             // ok, we are onto the encrypted area
     298            // ok, we are onto the encrypted area, i.e. Message #3
    290299            while (src.hasRemaining() && !_corrupt) {
    291300                //if (_log.shouldLog(Log.DEBUG))
     
    296305                }
    297306                if (_curEncryptedOffset >= _curEncrypted.length) {
    298                     _context.aes().decrypt(_curEncrypted, 0, _curDecrypted, 0, _dh.getSessionKey(), _prevEncrypted, 0, _curEncrypted.length);
     307                    _context.aes().decrypt(_curEncrypted, 0, _curDecrypted, 0, _dh.getSessionKey(),
     308                                           _prevEncrypted, 0, _curEncrypted.length);
    299309                    //if (_log.shouldLog(Log.DEBUG))
    300310                    //    _log.debug(prefix()+"full block read and decrypted: " + Base64.encode(_curDecrypted));
     
    306316
    307317                    if (_aliceIdentSize <= 0) { // we are on the first decrypted block
    308                         _aliceIdentSize = (int)DataHelper.fromLong(_curDecrypted, 0, 2);
    309                         _sz_aliceIdent_tsA_padding_aliceSigSize = 2 + _aliceIdentSize + 4 + Signature.SIGNATURE_BYTES;
     318                        int sz = (int)DataHelper.fromLong(_curDecrypted, 0, 2);
     319                        if (sz < MIN_RI_SIZE || sz > MAX_RI_SIZE) {
     320                            _context.statManager().addRateData("ntcp.invalidInboundSize", sz);
     321                            fail("size is invalid", new Exception("size is " + sz));
     322                            return;
     323                        }
     324                        _aliceIdentSize  = sz;
     325
     326                        // We must defer the calculations for total size of the message until
     327                        //  we get the full alice ident so
     328                        // we can determine how long the signature is.
     329                        // See below
     330
     331                    }
     332                    try {
     333                        _sz_aliceIdent_tsA_padding_aliceSig.write(_curDecrypted);
     334                    } catch (IOException ioe) {
     335                        if (_log.shouldLog(Log.ERROR)) _log.error(prefix()+"Error writing to the baos?", ioe);
     336                    }
     337                    //if (_log.shouldLog(Log.DEBUG))
     338                    //    _log.debug(prefix()+"subsequent block decrypted (" + _sz_aliceIdent_tsA_padding_aliceSig.size() + ")");
     339
     340                    if (_aliceIdent == null &&
     341                        _sz_aliceIdent_tsA_padding_aliceSig.size() >= 2 + _aliceIdentSize) {
     342                        // we have enough to get Alice's RI and determine the sig+padding length
     343                        readAliceRouterIdentity();
     344                        if (_aliceIdent == null) {
     345                            // readAliceRouterIdentity already called fail
     346                            return;
     347                        }
     348                        SigType type = _aliceIdent.getSigningPublicKey().getType();
     349                        if (type == null) {
     350                            fail("Unsupported sig type");
     351                            return;
     352                        }
     353                        // handle variable signature size
     354                        _sz_aliceIdent_tsA_padding_aliceSigSize = 2 + _aliceIdentSize + 4 + type.getSigLen();
    310355                        int rem = (_sz_aliceIdent_tsA_padding_aliceSigSize % 16);
    311356                        int padding = 0;
     
    313358                            padding = 16-rem;
    314359                        _sz_aliceIdent_tsA_padding_aliceSigSize += padding;
    315                         try {
    316                             _sz_aliceIdent_tsA_padding_aliceSig.write(_curDecrypted);
    317                         } catch (IOException ioe) {
    318                             if (_log.shouldLog(Log.ERROR)) _log.error(prefix()+"Error writing to the baos?", ioe);
    319                         }
    320360                        if (_log.shouldLog(Log.DEBUG))
    321                             _log.debug(prefix()+"alice ident size decrypted as " + _aliceIdentSize + ", making the padding at " + padding + " and total size at " + _sz_aliceIdent_tsA_padding_aliceSigSize);
    322                     } else {
    323                         // subsequent block...
    324                         try {
    325                             _sz_aliceIdent_tsA_padding_aliceSig.write(_curDecrypted);
    326                         } catch (IOException ioe) {
    327                             if (_log.shouldLog(Log.ERROR)) _log.error(prefix()+"Error writing to the baos?", ioe);
    328                         }
    329                         //if (_log.shouldLog(Log.DEBUG))
    330                         //    _log.debug(prefix()+"subsequent block decrypted (" + _sz_aliceIdent_tsA_padding_aliceSig.size() + ")");
    331 
    332                         if (_sz_aliceIdent_tsA_padding_aliceSig.size() >= _sz_aliceIdent_tsA_padding_aliceSigSize) {
     361                            _log.debug(prefix() + "alice ident size decrypted as " + _aliceIdentSize +
     362                                       ", making the padding at " + padding + " and total size at " +
     363                                       _sz_aliceIdent_tsA_padding_aliceSigSize);
     364                    }
     365
     366                    if (_aliceIdent != null &&
     367                        _sz_aliceIdent_tsA_padding_aliceSig.size() >= _sz_aliceIdent_tsA_padding_aliceSigSize) {
     368                        // we have the remainder of Message #3, i.e. the padding+signature
     369                        // Time to verify.
     370
    333371                            verifyInbound();
    334372                            if (!_corrupt && _verified && src.hasRemaining())
     
    340378                                           + " verified=" + _verified + " extra=" + (_extra != null ? _extra.length : 0) + ")");
    341379                            return;
    342                         }
    343380                    }
    344381                } else {
     
    346383                    // block was read, so we can't decrypt it.
    347384                    if (_log.shouldLog(Log.DEBUG))
    348                         _log.debug(prefix()+"end of available data with only a partial block read (" + _curEncryptedOffset + ", " + _received + ")");
     385                        _log.debug(prefix() + "end of available data with only a partial block read (" +
     386                                   _curEncryptedOffset + ", " + _received + ")");
    349387                }
    350388            }
     
    459497
    460498                byte ident[] = _context.router().getRouterInfo().getIdentity().toByteArray();
    461                 int min = 2+ident.length+4+Signature.SIGNATURE_BYTES;
     499                // handle variable signature size
     500                int min = 2 + ident.length + 4 + sig.length();
    462501                int rem = min % 16;
    463502                int padding = 0;
     
    470509                if (padding > 0)
    471510                    _context.random().nextBytes(preEncrypt, 2 + ident.length + 4, padding);
    472                 System.arraycopy(sig.getData(), 0, preEncrypt, 2+ident.length+4+padding, Signature.SIGNATURE_BYTES);
     511                System.arraycopy(sig.getData(), 0, preEncrypt, 2+ident.length+4+padding, sig.length());
    473512
    474513                _prevEncrypted = new byte[preEncrypt.length];
    475                 _context.aes().encrypt(preEncrypt, 0, _prevEncrypted, 0, _dh.getSessionKey(), _hX_xor_bobIdentHash, _hX_xor_bobIdentHash.length-16, preEncrypt.length);
     514                _context.aes().encrypt(preEncrypt, 0, _prevEncrypted, 0, _dh.getSessionKey(),
     515                                       _hX_xor_bobIdentHash, _hX_xor_bobIdentHash.length-16, preEncrypt.length);
    476516
    477517                //if (_log.shouldLog(Log.DEBUG)) {
     
    489529            int off = 0;
    490530            if (_e_bobSig == null) {
    491                 _e_bobSig = new byte[48];
     531                // handle variable signature size
     532                int siglen = _con.getRemotePeer().getSigningPublicKey().getType().getSigLen();
     533                int rem = siglen % 16;
     534                int padding;
     535                if (rem > 0)
     536                    padding = 16 - rem;
     537                else
     538                    padding = 0;
     539                _e_bobSig = new byte[siglen + padding];
    492540                if (_log.shouldLog(Log.DEBUG))
    493                     _log.debug(prefix() + "receiving E(S(X+Y+Alice.identHash+tsA+tsB)+padding, sk, prev) (remaining? " + src.hasRemaining() + ")");
     541                    _log.debug(prefix() + "receiving E(S(X+Y+Alice.identHash+tsA+tsB)+padding, sk, prev) (remaining? " +
     542                               src.hasRemaining() + ")");
    494543            } else {
    495544                off = _received - _Y.length - _e_hXY_tsB.length;
    496545                if (_log.shouldLog(Log.DEBUG))
    497                     _log.debug(prefix() + "continuing to receive E(S(X+Y+Alice.identHash+tsA+tsB)+padding, sk, prev) (remaining? " + src.hasRemaining() + " off=" + off + " recv=" + _received + ")");
     546                    _log.debug(prefix() + "continuing to receive E(S(X+Y+Alice.identHash+tsA+tsB)+padding, sk, prev) (remaining? " +
     547                               src.hasRemaining() + " off=" + off + " recv=" + _received + ")");
    498548            }
    499549            while (src.hasRemaining() && off < _e_bobSig.length) {
     
    506556                    //    _log.debug(prefix() + "received E(S(X+Y+Alice.identHash+tsA+tsB)+padding, sk, prev): " + Base64.encode(_e_bobSig));
    507557                    byte bobSig[] = new byte[_e_bobSig.length];
    508                     _context.aes().decrypt(_e_bobSig, 0, bobSig, 0, _dh.getSessionKey(), _e_hXY_tsB, _e_hXY_tsB.length-16, _e_bobSig.length);
     558                    _context.aes().decrypt(_e_bobSig, 0, bobSig, 0, _dh.getSessionKey(),
     559                                           _e_hXY_tsB, _e_hXY_tsB.length-16, _e_bobSig.length);
    509560                    // ignore the padding
    510                     byte bobSigData[] = new byte[Signature.SIGNATURE_BYTES];
    511                     System.arraycopy(bobSig, 0, bobSigData, 0, Signature.SIGNATURE_BYTES);
    512                     Signature sig = new Signature(bobSigData);
     561                    // handle variable signature size
     562                    SigType type = _con.getRemotePeer().getSigningPublicKey().getType();
     563                    int siglen = type.getSigLen();
     564                    byte bobSigData[] = new byte[siglen];
     565                    System.arraycopy(bobSig, 0, bobSigData, 0, siglen);
     566                    Signature sig = new Signature(type, bobSigData);
    513567
    514568                    byte toVerify[] = new byte[_X.length+_Y.length+Hash.HASH_LENGTH+4+4];
     
    570624
    571625    /**
     626     * We are Bob. We have received enough of message #3 from Alice
     627     * to get Alice's RouterIdentity.
     628     *
     629     * _aliceIdentSize must be set.
     630     * _sz_aliceIdent_tsA_padding_aliceSig must contain at least 2 + _aliceIdentSize bytes.
     631     *
     632     * Sets _aliceIdent so that we
     633     * may determine the signature and padding sizes.
     634     *
     635     * After all of message #3 is received including the signature and
     636     * padding, verifyIdentity() must be called.
     637     *
     638     * @since 0.9.16 pulled out of verifyInbound()
     639     */
     640    private void readAliceRouterIdentity() {
     641        if (_corrupt) return;
     642        byte b[] = _sz_aliceIdent_tsA_padding_aliceSig.toByteArray();
     643        //if (_log.shouldLog(Log.DEBUG))
     644        //    _log.debug(prefix()+"decrypted sz(etc) data: " + Base64.encode(b));
     645
     646        try {
     647            int sz = _aliceIdentSize;
     648            if (sz < MIN_RI_SIZE || sz > MAX_RI_SIZE ||
     649                sz > b.length-2) {
     650                _context.statManager().addRateData("ntcp.invalidInboundSize", sz);
     651                fail("size is invalid", new Exception("size is " + sz));
     652                return;
     653            }
     654            RouterIdentity alice = new RouterIdentity();
     655            ByteArrayInputStream bais = new ByteArrayInputStream(b, 2, sz);
     656            alice.readBytes(bais);
     657            _aliceIdent = alice;
     658        } catch (IOException ioe) {
     659            _context.statManager().addRateData("ntcp.invalidInboundIOE", 1);
     660            fail("Error verifying peer", ioe);
     661        } catch (DataFormatException dfe) {
     662            _context.statManager().addRateData("ntcp.invalidInboundDFE", 1);
     663            fail("Error verifying peer", dfe);
     664        }
     665    }
     666
     667
     668    /**
    572669     * We are Bob. Verify message #3 from Alice, then send message #4 to Alice.
     670     *
     671     * _aliceIdentSize and _aliceIdent must be set.
     672     * _sz_aliceIdent_tsA_padding_aliceSig must contain at least
     673     *  (2 + _aliceIdentSize + 4 + padding + sig) bytes.
     674     *
     675     * Sets _aliceIdent so that we
     676     *
     677     * readAliceRouterIdentity() must have been called previously
    573678     *
    574679     * Make sure the signatures are correct, and if they are, update the
     
    580685        if (_corrupt) return;
    581686        byte b[] = _sz_aliceIdent_tsA_padding_aliceSig.toByteArray();
    582         //if (_log.shouldLog(Log.DEBUG))
    583         //    _log.debug(prefix()+"decrypted sz(etc) data: " + Base64.encode(b));
    584 
    585687        try {
    586             RouterIdentity alice = new RouterIdentity();
    587             int sz = (int)DataHelper.fromLong(b, 0, 2); // TO-DO: Hey zzz... Throws an NPE for me... see below, for my "quick fix", need to find out the real reason
    588             if ( (sz <= 0) || (sz > b.length-2-4-Signature.SIGNATURE_BYTES) ) {
    589                 _context.statManager().addRateData("ntcp.invalidInboundSize", sz);
    590                 fail("size is invalid", new Exception("size is " + sz));
    591                 return;
    592             }
    593             byte aliceData[] = new byte[sz];
    594             System.arraycopy(b, 2, aliceData, 0, sz);
    595             alice.fromByteArray(aliceData);
     688            int sz = _aliceIdentSize;
    596689            long tsA = DataHelper.fromLong(b, 2+sz, 4);
    597 
    598690            ByteArrayOutputStream baos = new ByteArrayOutputStream(768);
    599691            baos.write(_X);
     
    610702            }
    611703
    612             byte s[] = new byte[Signature.SIGNATURE_BYTES];
     704            // handle variable signature size
     705            SigType type = _aliceIdent.getSigningPublicKey().getType();
     706            if (type == null) {
     707                fail("unsupported sig type");
     708                return;
     709            }
     710            byte s[] = new byte[type.getSigLen()];
    613711            System.arraycopy(b, b.length-s.length, s, 0, s.length);
    614             Signature sig = new Signature(s);
    615             _verified = _context.dsa().verifySignature(sig, toVerify, alice.getSigningPublicKey());
     712            Signature sig = new Signature(type, s);
     713            _verified = _context.dsa().verifySignature(sig, toVerify, _aliceIdent.getSigningPublicKey());
    616714            if (_verified) {
    617715                // get inet-addr
    618716                InetAddress addr = this._con.getChannel().socket().getInetAddress();
    619717                byte[] ip = (addr == null) ? null : addr.getAddress();
    620                 if (_context.banlist().isBanlistedForever(alice.calculateHash())) {
     718                if (_context.banlist().isBanlistedForever(_aliceIdent.calculateHash())) {
    621719                    if (_log.shouldLog(Log.WARN))
    622                         _log.warn("Dropping inbound connection from permanently banlisted peer: " + alice.calculateHash().toBase64());
     720                        _log.warn("Dropping inbound connection from permanently banlisted peer: " + _aliceIdent.calculateHash());
    623721                    // So next time we will not accept the con from this IP,
    624722                    // rather than doing the whole handshake
    625723                    if(ip != null)
    626724                       _context.blocklist().add(ip);
    627                     fail("Peer is banlisted forever: " + alice.calculateHash().toBase64());
     725                    fail("Peer is banlisted forever: " + _aliceIdent.calculateHash());
    628726                    return;
    629727                }
    630728                if(ip != null)
    631                    _transport.setIP(alice.calculateHash(), ip);
     729                   _transport.setIP(_aliceIdent.calculateHash(), ip);
    632730                if (_log.shouldLog(Log.DEBUG))
    633731                    _log.debug(prefix() + "verification successful for " + _con);
     
    643741                } else if (diff >= Router.CLOCK_FUDGE_FACTOR) {
    644742                    _context.statManager().addRateData("ntcp.invalidInboundSkew", diff);
    645                     _transport.markReachable(alice.calculateHash(), true);
     743                    _transport.markReachable(_aliceIdent.calculateHash(), true);
    646744                    // Only banlist if we know what time it is
    647745                    _context.banlist().banlistRouter(DataHelper.formatDuration(diff),
    648                                                        alice.calculateHash(),
     746                                                       _aliceIdent.calculateHash(),
    649747                                                       _x("Excessive clock skew: {0}"));
    650748                    _transport.setLastBadSkew(tsA- _tsB);
     
    655753                }
    656754
    657                 sendInboundConfirm(alice, tsA);
    658                 _con.setRemotePeer(alice);
     755                sendInboundConfirm(_aliceIdent, tsA);
     756                _con.setRemotePeer(_aliceIdent);
    659757                if (_log.shouldLog(Log.DEBUG))
    660758                    _log.debug(prefix()+"e_bobSig is " + _e_bobSig.length + " bytes long");
     
    663761                _con.finishInboundEstablishment(_dh.getSessionKey(), (tsA-_tsB), iv, _prevEncrypted); // skew in seconds
    664762                if (_log.shouldLog(Log.INFO))
    665                     _log.info(prefix()+"Verified remote peer as " + alice.calculateHash().toBase64());
     763                    _log.info(prefix()+"Verified remote peer as " + _aliceIdent.calculateHash());
    666764            } else {
    667765                _context.statManager().addRateData("ntcp.invalidInboundSignature", 1);
    668                 fail("Peer verification failed - spoof of " + alice.calculateHash().toBase64() + "?");
     766                fail("Peer verification failed - spoof of " + _aliceIdent.calculateHash() + "?");
    669767            }
    670768        } catch (IOException ioe) {
    671769            _context.statManager().addRateData("ntcp.invalidInboundIOE", 1);
    672770            fail("Error verifying peer", ioe);
    673         } catch (DataFormatException dfe) {
    674             _context.statManager().addRateData("ntcp.invalidInboundDFE", 1);
    675             fail("Error verifying peer", dfe);
    676         } catch(NullPointerException npe) {
    677             fail("Error verifying peer", npe); // TO-DO: zzz This is that quick-fix. -- Sponge
    678771        }
    679772    }
     
    693786        DataHelper.toLong(toSign, off, 4, _tsB); off += 4;
    694787
     788        // handle variable signature size
    695789        Signature sig = _context.dsa().sign(toSign, _context.keyManager().getSigningPrivateKey());
    696         byte preSig[] = new byte[Signature.SIGNATURE_BYTES+8];
    697         System.arraycopy(sig.getData(), 0, preSig, 0, Signature.SIGNATURE_BYTES);
    698         _context.random().nextBytes(preSig, Signature.SIGNATURE_BYTES, 8);
     790        int siglen = sig.length();
     791        int rem = siglen % 16;
     792        int padding;
     793        if (rem > 0)
     794            padding = 16 - rem;
     795        else
     796            padding = 0;
     797        byte preSig[] = new byte[siglen + padding];
     798        System.arraycopy(sig.getData(), 0, preSig, 0, siglen);
     799        if (padding > 0)
     800            _context.random().nextBytes(preSig, siglen, padding);
    699801        _e_bobSig = new byte[preSig.length];
    700802        _context.aes().encrypt(preSig, 0, _e_bobSig, 0, _dh.getSessionKey(), _e_hXY_tsB, _e_hXY_tsB.length-16, _e_bobSig.length);
Note: See TracChangeset for help on using the changeset viewer.