/** Get the current message sequence number */ byte[] /*NilOK*/ getSequence() { if (null != myTransform) { return myTransform.getSuspendInfo(); } else { return mySequence; } }
/** * Change the authorization protocol being used to receive messages on the connection. This * routine must be called when the RecvThread is synchronized with the Vat thread. This assertion * is checked by setting myChangeProtocolIsOk just before calling into the Vat with a new incoming * message and resetting it when the call returns. This routine will throw an Assertion failure if * that boolean is not true. * * @param protocolParms is the parameter bundle for the protocol suite to use. This routine must, * of course, support the selected suite. */ void changeProtocol(AuthSecrets protocolParms) { if (Trace.comm.verbose && Trace.ON) { Trace.comm.verbosem("ProtocolChange, pp=" + protocolParms); } T.require( myChangeProtocolIsOk, "Must only be called while caller " + "is processing an input message"); // For calculating the header length int headerLengthIndex = HEADER_INVALID; if (StartUpProtocol.PROTO_NONE.equals(protocolParms.myProtocolSuite)) { myIsAggragating = false; myIsDoingMac = false; mySequence = null; headerLengthIndex = HEADER_INT_LENGTH; // begin daffE -> E } else if (StartUpProtocol.PROTO_3DES_SDH_M.equals(protocolParms.myProtocolSuite)) { myIsAggragating = true; MessageDigest md5 = setSHA1(protocolParms); headerLengthIndex = HEADER_VLEN_SHA1; mySequence = null; byte[] raw_3des_key = TripleDESKeyConstructor.make(protocolParms.myDHSecret); myTransform = new Decrypt3DES(raw_3des_key, protocolParms.myIncomingSequence); // end daffE -> E // begin improved E protocol } else if (StartUpProtocol.PROTO_3DES_SDH_M2.equals(protocolParms.myProtocolSuite)) { myIsAggragating = true; MessageDigest md5 = setSHA1(protocolParms); headerLengthIndex = HEADER_VLEN_HMAC; mySequence = new byte[4]; // Assume initialized to zero byte[] raw_3des_key = TripleDESKeyConstructor.make(protocolParms.myDHSecret); myTransform = new Decrypt3DES(raw_3des_key, protocolParms.myIncomingSequence); myTransform.init(); myIsStandardCBC = true; myIsDoingHMAC = true; // end improved E protocol } else { T.fail("Invalid protocol type " + protocolParms); } myIsCompressingMsgLengths = myIsAggragating; int len = theHeaderLengths[headerLengthIndex]; T.require(0 <= len, "Invalid header length code"); myHeader = new byte[len]; }
/** Process input data. */ private void readAndProcessMessage() throws IOException { long authTime = 0; long macTime = 0; long startTime = 0; // Read the header fillArray(myHeader, 0, myHeader.length); if (null != myTransform) { if (Trace.comm.timing && Trace.ON) { startTime = MicroTime.queryTimer(); } if (!myIsStandardCBC) { myTransform.init(); } myTransform.transform(myHeader); if (Trace.comm.timing && Trace.ON) { authTime += MicroTime.queryTimer() - startTime; } } if (Trace.comm.verbose && Trace.ON) { String hdr = HexStringUtils.bytesToReadableHexStr(myHeader); Trace.comm.verbosem("Header: " + hdr); } int length; int nextItemOffset; // Offset to the next item in the header if (myIsCompressingMsgLengths) { int l1 = myHeader[0]; // First byte of the length if (0 == (l1 & 0x80)) { // len < 128 length = l1; nextItemOffset = 1; } else { if (0x80 == (l1 & 0xc0)) { // len < 16,384 length = ((l1 & 0x3f) << 8) | ((myHeader[1] & 0xff)); nextItemOffset = 2; } else if (0xc0 == (l1 & 0xe0)) { // len < 2,097,152 length = ((l1 & 0x1f) << 16) | ((myHeader[1] & 0xff) << 8) | ((myHeader[2] & 0xff)); nextItemOffset = 3; } else if (0xe0 == (l1 & 0xf0)) { // len < 2**28 length = ((l1 & 0x0f) << 24) | ((myHeader[1] & 0xff) << 16) | ((myHeader[2] & 0xff) << 8) | ((myHeader[3] & 0xff)); nextItemOffset = 4; } else { throw new IOException( "Invalid compressed length code" + HexStringUtils.bytesToReadableHexStr(myHeader)); } } } else { // Not compressing length = ((myHeader[0] & 0xff) << 24) | ((myHeader[1] & 0xff) << 16) | ((myHeader[2] & 0xff) << 8) | (myHeader[3] & 0xff); nextItemOffset = 4; } if (Trace.comm.verbose && Trace.ON) { Trace.comm.verbosem("incoming packet len = " + length); } if (Msg.MAX_INBOUND_MSG_LENGTH < length || 0 > length) { throw new IOException("Packet too large: " + length + " > " + Msg.MAX_INBOUND_MSG_LENGTH); } if (myIsDoingMac) { System.arraycopy(myHeader, nextItemOffset, myMAC, 0, 20); // Save MAC nextItemOffset += 20; } if (null != mySequence) { int seqLen = mySequence.length; byte[] theirSequence = new byte[seqLen]; System.arraycopy(myHeader, nextItemOffset, theirSequence, 0, seqLen); if (!isEqual(mySequence, theirSequence)) { if (Trace.comm.error) { traceErrorMsg( theirSequence, 0, theirSequence.length, "sequence error, [remote sequence number]:"); traceErrorMsg( mySequence, 0, mySequence.length, "sequence error, [local sequence number]:"); } throw new IOException("incoming packet sequence error"); } nextItemOffset += seqLen; } // Calculate message length + padding and allocate a buffer // The length required is the length of the data portion plus the // padding length for the original message. // The padding length for the original message is calculated: // msglen = (length_of_length + length_of_headers + length_of_data // padlen = ((msglen + 7) & 0xfffffff8) - msglen // length_of_length + length_of_headers is equal to nextItemOffset // (the amount of data eaten by processing them above). // length_of_data is length. byte[] message; if (myIsCompressingMsgLengths || null != myTransform) { int msglen = nextItemOffset + length; int padlen = ((msglen + 7) & 0xfffffff8) - msglen; message = new byte[length + padlen]; } else { message = new byte[length]; } if (nextItemOffset < myHeader.length) { // Copy compressed data read with header System.arraycopy(myHeader, nextItemOffset, message, 0, myHeader.length - nextItemOffset); } if (Trace.comm.verbose && Trace.ON) { String msg = HexStringUtils.bytesToReadableHexStr(message); Trace.comm.verbosem("Initial message: " + msg); } // Read rest of message into the buffer allocated for it fillArray( message, myHeader.length - nextItemOffset, message.length - (myHeader.length - nextItemOffset)); if (null != myTransform) { if (Trace.comm.timing && Trace.ON) { startTime = MicroTime.queryTimer(); } myTransform.transform( message, (myHeader.length - nextItemOffset), message.length - (myHeader.length - nextItemOffset)); if (Trace.comm.timing && Trace.ON) { authTime += MicroTime.queryTimer() - startTime; } } if (Trace.comm.verbose && Trace.ON) { String msg = HexStringUtils.bytesToReadableHexStr(message); Trace.comm.verbosem("Full message: " + msg); } myMessagesToPass.removeAllElements(); if (myIsAggragating) { if (Trace.comm.timing && Trace.ON) { startTime = MicroTime.queryTimer(); } ByteArrayInputStream bais = new ByteArrayInputStream(message); while (true) { length = 0; int input = bais.read(); if (0 >= input) { break; // -1 for eof on bais, 0 if only msg shorter than 3 } int count; if (myIsCompressingMsgLengths) { if (0 == (input & 0x80)) { length = input; count = 0; } else if (0x80 == (input & 0xc0)) { // len < 16,384 length = input & 0x3f; count = 1; } else if (0xc0 == (input & 0xe0)) { // len < 2,097,152 length = input & 0x1f; count = 2; } else if (0xe0 == (input & 0xf0)) { // len < 2**28 length = input & 0x0f; count = 3; } else { String msg = HexStringUtils.bytesToReadableHexStr(message); throw new IOException("Invalid compressed length code" + msg); } } else { count = 3; } for (int i = 0; i < count; i++) { length <<= 8; input = bais.read(); length |= input & 0xff; } if (Msg.MAX_INBOUND_MSG_LENGTH < length || 0 > length) { throw new IOException( "Message too large: " + length + " > " + Msg.MAX_INBOUND_MSG_LENGTH); } byte[] emsg = new byte[length]; int offset = 0; while (offset < emsg.length) { int read = bais.read(emsg, offset, emsg.length - offset); if (-1 == read) { break; } offset += read; } if (offset != length) { throw new IOException( "incoming packet not aggragated properly," + " expectedLength=" + length + " foundLength=" + offset + HexStringUtils.bytesToReadableHexStr(message)); } myMessagesToPass.addElement(emsg); } } else if (message.length != length) { byte[] a = new byte[length]; System.arraycopy(message, 0, a, 0, length); myMessagesToPass.addElement(a); } else { myMessagesToPass.addElement(message); } if (myIsDoingMac) { if (Trace.comm.timing && Trace.ON) { startTime = MicroTime.queryTimer(); } byte[] digest = computeMAC(myMessagesToPass); if (!MessageDigest.isEqual(digest, myMAC)) { if (Trace.comm.error) { traceErrorMsg(myMAC, 0, myMAC.length, "checksum mismatch, [remote checksum]:"); traceErrorMsg(digest, 0, digest.length, "checksum mismatch, [local checksum]:"); Enumeration itr = myMessagesToPass.elements(); while (itr.hasMoreElements()) { byte[] msg = (byte[]) (itr.nextElement()); int len = msg.length; byte[] m = new byte[len + 4]; m[0] = (byte) ((len >> 24) & 0xff); // The message length m[1] = (byte) ((len >> 16) & 0xff); m[2] = (byte) ((len >> 8) & 0xff); m[3] = (byte) ((len) & 0xff); System.arraycopy(msg, 0, m, 4, len); traceErrorMsg(m, 0, m.length, "checksum mismatch, [data ]:"); } } throw new IOException("incoming packet checksum mismatch"); } if (Trace.comm.timing && Trace.ON) { macTime += MicroTime.queryTimer() - startTime; } } // The input data counts are maintained in the DataPath // myDataPath.updateReceivedCounts(msgLengths, compressedLength); Enumeration itr; if (Trace.comm.timing && Trace.ON) { // Generate event record message itr = myMessagesToPass.elements(); String logMsg = "Processed message length(s)"; while (itr.hasMoreElements()) { byte[] msg = (byte[]) (itr.nextElement()); logMsg += " " + msg.length; } if (0 != authTime) { logMsg += " AuthTime=" + authTime; } if (0 != macTime) { logMsg += " MACTime=" + macTime; } myTotalTime += authTime + macTime; if (0 != myTotalTime) { logMsg += " TotalTime=" + myTotalTime; } Trace.comm.timingm(logMsg); } itr = myMessagesToPass.elements(); while (itr.hasMoreElements()) { byte[] msg = (byte[]) (itr.nextElement()); if (Trace.comm.debug && Trace.ON) { traceDebugMsg(msg, 0, msg.length, "incoming packet data"); } myChangeProtocolIsOk = true; // XXX should make embargo work again if (Msg.E_MSG == msg[0]) { myDataPath.getEmbargoLock().waitTillOff(); } callDataPath(new DataCommThunk(myDataPath, msg)); myChangeProtocolIsOk = false; } myMessagesToPass.removeAllElements(); // Clean up for garbage collecter }