{
try{
boolean forward = false;
boolean crypto_completed = false;
ByteBuffer out_buffer = null;
synchronized( this ){
if ( crypto_complete.isReleasedForever()){
forward = true;
}else{
// basic sts flow:
// a -> puba -> b
// a <- pubb <- b
// a -> auta -> b
// a <- autb <- b
// a -> data -> b
// optimised
// a -> puba -> b
// a <- pubb + auta <- b
// a -> autb + data -> b
// therefore can be one or two messages in the payload
// 1 crypto
// 2 crypto (pub + auth)
// crypto + data
// initial a ->puba -> is done on first data send so data is ready for phase 3
ByteBuffer in_buffer = ByteBuffer.wrap( message.toByteArray());
message.returnToPool();
// piggyback pub key send
if ( !sent_keys ){
// we've received
// a -> puba -> b
// reply with
// a <- puba + auta <- b
out_buffer = ByteBuffer.allocate( 64*1024 );
// write our keys
sts_engine.getKeys( out_buffer );
sent_keys = true;
// read their keys
sts_engine.putKeys( in_buffer );
// write our auth
sts_engine.getAuth( out_buffer );
sent_auth = true;
}else if ( !sent_auth ){
out_buffer = ByteBuffer.allocate( 64*1024 );
// we've received
// a <- puba + auta <- b
// reply with
// a -> autb + data -> b
// read their keys
sts_engine.putKeys( in_buffer );
// write our auth
sts_engine.getAuth( out_buffer );
sent_auth = true;
// read their auth
sts_engine.putAuth( in_buffer );
// check we wanna talk to this person
byte[] rem_key = sts_engine.getRemotePublicKey();
if ( !key_locator.accept(
SESTSConnectionImpl.this,
new SEPublicKeyImpl( my_public_key.getType(), rem_key ))){
throw( new MessageException( "remote public key not accepted" ));
}
setupBlockCrypto();
if ( pending_message != null ){
byte[] pending_bytes = pending_message.toByteArray();
int pending_size = pending_bytes.length;
if ( outgoing_cipher != null ){
pending_size = (( pending_size + AES_KEY_SIZE_BYTES -1 )/AES_KEY_SIZE_BYTES)*AES_KEY_SIZE_BYTES;
if ( pending_size == 0 ){
pending_size = AES_KEY_SIZE_BYTES;
}
}
if ( out_buffer.remaining() >= pending_size ){
if ( outgoing_cipher != null ){
out_buffer.put( outgoing_cipher.doFinal( pending_bytes ));
}else{
out_buffer.put( pending_bytes );
}
// don't deallocate the pending message, the original caller does this
pending_message = null;
}
}
crypto_completed = true;
}else{
// we've received
// a -> autb + data -> b
// read their auth
sts_engine.putAuth( in_buffer );
// check we wanna talk to this person
byte[] rem_key = sts_engine.getRemotePublicKey();
if ( !key_locator.accept(
SESTSConnectionImpl.this,
new SEPublicKeyImpl( my_public_key.getType(), rem_key ))){
// this is just here to prevent unwanted spew during closedown process
connection.closing();
throw( new MessageException( "remote public key not accepted" ));
}
setupBlockCrypto();
crypto_completed = true;
// pick up any remaining data for delivery
if ( in_buffer.hasRemaining()){
message = new PooledByteBufferImpl( new DirectByteBuffer( in_buffer.slice()));
forward = true;
}
}
}