public override int Read(byte[] buf, int off, int len) { int bytesToRead = System.Math.Min(buffer.Available, len); buffer.RemoveData(buf, off, bytesToRead, 0); return(bytesToRead); }
public override int Read(byte[] buf, int off, int len) { int num = Math.Min(buffer.Available, len); buffer.RemoveData(buf, off, num, 0); return(num); }
private int ReceiveRecord(byte[] buf, int off, int len, int waitMillis) { if (mRecordQueue.Available > 0) { int length = 0; if (mRecordQueue.Available >= RECORD_HEADER_LENGTH) { byte[] lengthBytes = new byte[2]; mRecordQueue.Read(lengthBytes, 0, 2, 11); length = TlsUtilities.ReadUint16(lengthBytes, 0); } int received = System.Math.Min(mRecordQueue.Available, RECORD_HEADER_LENGTH + length); mRecordQueue.RemoveData(buf, off, received, 0); return(received); } { int received = mTransport.Receive(buf, off, len, waitMillis); if (received >= RECORD_HEADER_LENGTH) { int fragmentLength = TlsUtilities.ReadUint16(buf, off + 11); int recordLength = RECORD_HEADER_LENGTH + fragmentLength; if (received > recordLength) { mRecordQueue.AddData(buf, off + recordLength, received - recordLength); received = recordLength; } } return(received); } }
/** * This method is called, when a change cipher spec message is received. * * @throws IOException If the message has an invalid content or the * handshake is not in the correct state. */ private void ProcessChangeCipherSpec() { while (changeCipherSpecQueue.Available > 0) { /* * A change cipher spec message is only one byte with the value 1. */ byte[] b = new byte[1]; changeCipherSpecQueue.Read(b, 0, 1, 0); changeCipherSpecQueue.RemoveData(1); if (b[0] != 1) { /* * This should never happen. */ this.FailWithError(AL_fatal, AP_unexpected_message); } /* * Check if we are in the correct connection state. */ if (this.connection_state != CS_CLIENT_FINISHED_SEND) { this.FailWithError(AL_fatal, AP_handshake_failure); } rs.ServerClientSpecReceived(); this.connection_state = CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED; } }
private void ProcessHandshake() { bool read; do { read = false; /* * We need the first 4 bytes, they contain type and length of * the message. */ if (handshakeQueue.Available >= 4) { byte[] beginning = new byte[4]; handshakeQueue.Read(beginning, 0, 4, 0); MemoryStream bis = new MemoryStream(beginning, false); short type = TlsUtilities.ReadUint8(bis); int len = TlsUtilities.ReadUint24(bis); /* * Check if we have enough bytes in the buffer to read * the full message. */ if (handshakeQueue.Available >= (len + 4)) { /* * Read the message. */ byte[] buf = new byte[len]; handshakeQueue.Read(buf, 0, len, 4); handshakeQueue.RemoveData(len + 4); /* * RFC 2246 7.4.9. "The value handshake_messages includes all * handshake messages starting at client hello up to, but not * including, this finished message. [..] Note: [Also,] Hello Request * messages are omitted from handshake hashes." */ switch (type) { case HP_HELLO_REQUEST: case HP_FINISHED: break; default: rs.UpdateHandshakeData(beginning, 0, 4); rs.UpdateHandshakeData(buf, 0, len); break; } /* * Now, parse the message. */ ProcessHandshakeMessage(type, buf); read = true; } } }while (read); }
/** * Read data from the network. The method will return immediately, if there is * still some data left in the buffer, or block until some application * data has been read from the network. * * @param buf The buffer where the data will be copied to. * @param offset The position where the data will be placed in the buffer. * @param len The maximum number of bytes to read. * @return The number of bytes read. * @throws IOException If something goes wrong during reading data. */ internal int ReadApplicationData(byte[] buf, int offset, int len) { while (applicationDataQueue.Available == 0) { if (this.closed) { /* * We need to read some data. */ if (this.failedWithError) { /* * Something went terribly wrong, we should throw an IOException */ throw new IOException(TLS_ERROR_MESSAGE); } /* * Connection has been closed, there is no more data to read. */ return(0); } SafeReadData(); } len = System.Math.Min(len, applicationDataQueue.Available); applicationDataQueue.Read(buf, offset, len, 0); applicationDataQueue.RemoveData(len); return(len); }
private int ReceiveRecord(byte[] buf, int off, int len, int waitMillis) { if (mRecordQueue.Available > 0) { int num = 0; if (mRecordQueue.Available >= 13) { byte[] buf2 = new byte[2]; mRecordQueue.Read(buf2, 0, 2, 11); num = TlsUtilities.ReadUint16(buf2, 0); } int num2 = Math.Min(mRecordQueue.Available, 13 + num); mRecordQueue.RemoveData(buf, off, num2, 0); return(num2); } int num3 = mTransport.Receive(buf, off, len, waitMillis); if (num3 >= 13) { int num4 = TlsUtilities.ReadUint16(buf, off + 11); int num5 = 13 + num4; if (num3 > num5) { mRecordQueue.AddData(buf, off + num5, num3 - num5); num3 = num5; } } return(num3); }
private void ProcessAlert() { while (true) { if (mAlertQueue.Available < 2) { return; } byte[] array = mAlertQueue.RemoveData(2, 0); byte b = array[0]; byte b2 = array[1]; Peer.NotifyAlertReceived(b, b2); if (b == 2) { break; } if (b2 == 0) { HandleClose(user_canceled: false); } HandleWarningMessage(b2); } InvalidateSession(); mFailedWithError = true; mClosed = true; mRecordStream.SafeClose(); throw new IOException(TLS_ERROR_MESSAGE); }
private void processAlert() { while (alertQueue.Available >= 2) { /* * An alert is always 2 bytes. Read the alert. */ byte[] tmp = new byte[2]; alertQueue.Read(tmp, 0, 2, 0); alertQueue.RemoveData(2); short level = tmp[0]; short description = tmp[1]; if (level == AL_fatal) { /* * This is a fatal error. */ this.failedWithError = true; this.closed = true; /* * Now try to Close the stream, ignore errors. */ try { rs.Close(); } catch (Exception) { } throw new IOException(TLS_ERROR_MESSAGE); } else { /* * This is just a warning. */ if (description == AP_close_notify) { /* * Close notify */ this.FailWithError(AL_warning, AP_close_notify); } /* * If it is just a warning, we continue. */ } } }
private void ProcessAlert() { while (alertQueue.Available >= 2) { /* * An alert is always 2 bytes. Read the alert. */ byte[] tmp = alertQueue.RemoveData(2, 0); byte level = tmp[0]; byte description = tmp[1]; if (level == (byte)AlertLevel.fatal) { this.failedWithError = true; this.closed = true; /* * Now try to Close the stream, ignore errors. */ try { rs.Close(); } catch (Exception) { } throw new IOException(TLS_ERROR_MESSAGE); } else { if (description == (byte)AlertDescription.close_notify) { HandleClose(false); } /* * If it is just a warning, we continue. */ } } }
private void ProcessHandshake() { bool flag; do { flag = false; if (mHandshakeQueue.Available >= 4) { byte[] array = new byte[4]; mHandshakeQueue.Read(array, 0, 4, 0); byte b = TlsUtilities.ReadUint8(array, 0); int num = TlsUtilities.ReadUint24(array, 1); if (mHandshakeQueue.Available >= num + 4) { byte[] array2 = mHandshakeQueue.RemoveData(num, 4); CheckReceivedChangeCipherSpec(mConnectionState == 16 || b == 20); switch (b) { default: { TlsContext context = Context; if (b == 20 && mExpectedVerifyData == null && context.SecurityParameters.MasterSecret != null) { mExpectedVerifyData = CreateVerifyData(!context.IsServer); } mRecordStream.UpdateHandshakeData(array, 0, 4); mRecordStream.UpdateHandshakeData(array2, 0, num); break; } case 0: break; } HandleHandshakeMessage(b, array2); flag = true; } } }while (flag); }
protected internal virtual int ReadApplicationData(byte[] buf, int offset, int len) { if (len < 1) { return(0); } while (mApplicationDataQueue.Available == 0) { if (mClosed) { if (mFailedWithError) { throw new IOException(TLS_ERROR_MESSAGE); } return(0); } SafeReadRecord(); } len = System.Math.Min(len, mApplicationDataQueue.Available); mApplicationDataQueue.RemoveData(buf, offset, len, 0); return(len); }
protected internal virtual int ReadApplicationData(byte[] buf, int offset, int len) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) if (len < 1) { return(0); } while (mApplicationDataQueue.Available == 0) { if (mClosed) { if (mFailedWithError) { throw new IOException(TLS_ERROR_MESSAGE); } return(0); } SafeReadRecord(); } len = Math.Min(len, mApplicationDataQueue.Available); mApplicationDataQueue.RemoveData(buf, offset, len, 0); return(len); }
private void ProcessAlert() { //IL_0051: Unknown result type (might be due to invalid IL or missing references) while (mAlertQueue.Available >= 2) { byte[] array = mAlertQueue.RemoveData(2, 0); byte b = array[0]; byte b2 = array[1]; Peer.NotifyAlertReceived(b, b2); if (b == 2) { InvalidateSession(); mFailedWithError = true; mClosed = true; mRecordStream.SafeClose(); throw new IOException(TLS_ERROR_MESSAGE); } if (b2 == 0) { HandleClose(user_canceled: false); } HandleWarningMessage(b2); } }
private void processHandshake() { bool read; do { read = false; /* * We need the first 4 bytes, they contain type and length of * the message. */ if (handshakeQueue.Available >= 4) { byte[] beginning = new byte[4]; handshakeQueue.Read(beginning, 0, 4, 0); MemoryStream bis = new MemoryStream(beginning, false); short type = TlsUtilities.ReadUint8(bis); int len = TlsUtilities.ReadUint24(bis); /* * Check if we have enough bytes in the buffer to read * the full message. */ if (handshakeQueue.Available >= (len + 4)) { /* * Read the message. */ byte[] buf = new byte[len]; handshakeQueue.Read(buf, 0, len, 4); handshakeQueue.RemoveData(len + 4); /* * If it is not a finished message, update our hashes * we prepare for the finish message. */ if (type != HP_FINISHED) { rs.hash1.BlockUpdate(beginning, 0, 4); rs.hash2.BlockUpdate(beginning, 0, 4); rs.hash1.BlockUpdate(buf, 0, len); rs.hash2.BlockUpdate(buf, 0, len); } /* * Now, parse the message. */ MemoryStream inStr = new MemoryStream(buf, false); /* * Check the type. */ switch (type) { case HP_CERTIFICATE: { switch (connection_state) { case CS_SERVER_HELLO_RECEIVED: { /* * Parse the certificates. */ Certificate cert = Certificate.Parse(inStr); AssertEmpty(inStr); X509CertificateStructure x509Cert = cert.certs[0]; SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo; try { this.serverPublicKey = PublicKeyFactory.CreateKey(keyInfo); } catch (Exception) { this.FailWithError(AL_fatal, AP_unsupported_certificate); } // Sanity check the PublicKeyFactory if (this.serverPublicKey.IsPrivate) { this.FailWithError(AL_fatal, AP_internal_error); } /* * Perform various checks per RFC2246 7.4.2 * TODO "Unless otherwise specified, the signing algorithm for the certificate * must be the same as the algorithm for the certificate key." */ switch (this.chosenCipherSuite.KeyExchangeAlgorithm) { case TlsCipherSuite.KE_RSA: if (!(this.serverPublicKey is RsaKeyParameters)) { this.FailWithError(AL_fatal, AP_certificate_unknown); } validateKeyUsage(x509Cert, KeyUsage.KeyEncipherment); break; case TlsCipherSuite.KE_DHE_RSA: if (!(this.serverPublicKey is RsaKeyParameters)) { this.FailWithError(AL_fatal, AP_certificate_unknown); } validateKeyUsage(x509Cert, KeyUsage.DigitalSignature); break; case TlsCipherSuite.KE_DHE_DSS: if (!(this.serverPublicKey is DsaPublicKeyParameters)) { this.FailWithError(AL_fatal, AP_certificate_unknown); } break; default: this.FailWithError(AL_fatal, AP_unsupported_certificate); break; } /* * Verify them. */ if (!this.verifyer.IsValid(cert.GetCerts())) { this.FailWithError(AL_fatal, AP_user_canceled); } break; } default: this.FailWithError(AL_fatal, AP_unexpected_message); break; } connection_state = CS_SERVER_CERTIFICATE_RECEIVED; read = true; break; } case HP_FINISHED: switch (connection_state) { case CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED: /* * Read the checksum from the finished message, * it has always 12 bytes. */ byte[] receivedChecksum = new byte[12]; TlsUtilities.ReadFully(receivedChecksum, inStr); AssertEmpty(inStr); /* * Calculate our own checksum. */ byte[] checksum = new byte[12]; byte[] md5andsha1 = new byte[16 + 20]; rs.hash2.DoFinal(md5andsha1, 0); TlsUtilities.PRF(this.ms, TlsUtilities.ToByteArray("server finished"), md5andsha1, checksum); /* * Compare both checksums. */ for (int i = 0; i < receivedChecksum.Length; i++) { if (receivedChecksum[i] != checksum[i]) { /* * Wrong checksum in the finished message. */ this.FailWithError(AL_fatal, AP_handshake_failure); } } connection_state = CS_DONE; /* * We are now ready to receive application data. */ this.appDataReady = true; read = true; break; default: this.FailWithError(AL_fatal, AP_unexpected_message); break; } break; case HP_SERVER_HELLO: switch (connection_state) { case CS_CLIENT_HELLO_SEND: /* * Read the server hello message */ TlsUtilities.CheckVersion(inStr, this); /* * Read the server random */ this.serverRandom = new byte[32]; TlsUtilities.ReadFully(this.serverRandom, inStr); /* * Currently, we don't support session ids */ short sessionIdLength = TlsUtilities.ReadUint8(inStr); byte[] sessionId = new byte[sessionIdLength]; TlsUtilities.ReadFully(sessionId, inStr); /* * Find out which ciphersuite the server has * chosen. If we don't support this ciphersuite, * the TlsCipherSuiteManager will throw an * exception. */ this.chosenCipherSuite = TlsCipherSuiteManager.GetCipherSuite( TlsUtilities.ReadUint16(inStr), this); /* * We support only the null compression which * means no compression. */ short compressionMethod = TlsUtilities.ReadUint8(inStr); if (compressionMethod != 0) { this.FailWithError(TlsProtocolHandler.AL_fatal, TlsProtocolHandler.AP_illegal_parameter); } AssertEmpty(inStr); connection_state = CS_SERVER_HELLO_RECEIVED; read = true; break; default: this.FailWithError(AL_fatal, AP_unexpected_message); break; } break; case HP_SERVER_HELLO_DONE: switch (connection_state) { case CS_SERVER_CERTIFICATE_RECEIVED: case CS_SERVER_KEY_EXCHANGE_RECEIVED: case CS_CERTIFICATE_REQUEST_RECEIVED: // NB: Original code used case label fall-through if (connection_state == CS_SERVER_CERTIFICATE_RECEIVED) { /* * There was no server key exchange message, check * that we are doing RSA key exchange. */ if (this.chosenCipherSuite.KeyExchangeAlgorithm != TlsCipherSuite.KE_RSA) { this.FailWithError(AL_fatal, AP_unexpected_message); } } AssertEmpty(inStr); bool isCertReq = (connection_state == CS_CERTIFICATE_REQUEST_RECEIVED); connection_state = CS_SERVER_HELLO_DONE_RECEIVED; if (isCertReq) { sendClientCertificate(); } /* * Send the client key exchange message, depending * on the key exchange we are using in our * ciphersuite. */ switch (this.chosenCipherSuite.KeyExchangeAlgorithm) { case TlsCipherSuite.KE_RSA: { /* * We are doing RSA key exchange. We will * choose a pre master secret and send it * rsa encrypted to the server. * * Prepare pre master secret. */ pms = new byte[48]; pms[0] = 3; pms[1] = 1; random.NextBytes(pms, 2, 46); /* * Encode the pms and send it to the server. * * Prepare an Pkcs1Encoding with good random * padding. */ RsaBlindedEngine rsa = new RsaBlindedEngine(); Pkcs1Encoding encoding = new Pkcs1Encoding(rsa); encoding.Init(true, new ParametersWithRandom(this.serverPublicKey, this.random)); byte[] encrypted = null; try { encrypted = encoding.ProcessBlock(pms, 0, pms.Length); } catch (InvalidCipherTextException) { /* * This should never happen, only during decryption. */ this.FailWithError(AL_fatal, AP_internal_error); } /* * Send the encrypted pms. */ sendClientKeyExchange(encrypted); break; } case TlsCipherSuite.KE_DHE_DSS: case TlsCipherSuite.KE_DHE_RSA: { /* * Send the Client Key Exchange message for * DHE key exchange. */ byte[] YcByte = BigIntegers.AsUnsignedByteArray(this.Yc); sendClientKeyExchange(YcByte); break; } default: /* * Problem during handshake, we don't know * how to handle this key exchange method. */ this.FailWithError(AL_fatal, AP_unexpected_message); break; } connection_state = CS_CLIENT_KEY_EXCHANGE_SEND; /* * Now, we send change cipher state */ byte[] cmessage = new byte[1]; cmessage[0] = 1; rs.WriteMessage((short)RL_CHANGE_CIPHER_SPEC, cmessage, 0, cmessage.Length); connection_state = CS_CLIENT_CHANGE_CIPHER_SPEC_SEND; /* * Calculate the ms */ this.ms = new byte[48]; byte[] randBytes = new byte[clientRandom.Length + serverRandom.Length]; Array.Copy(clientRandom, 0, randBytes, 0, clientRandom.Length); Array.Copy(serverRandom, 0, randBytes, clientRandom.Length, serverRandom.Length); TlsUtilities.PRF(pms, TlsUtilities.ToByteArray("master secret"), randBytes, this.ms); /* * Initialize our cipher suite */ rs.writeSuite = this.chosenCipherSuite; rs.writeSuite.Init(this.ms, clientRandom, serverRandom); /* * Send our finished message. */ byte[] checksum = new byte[12]; byte[] md5andsha1 = new byte[16 + 20]; rs.hash1.DoFinal(md5andsha1, 0); TlsUtilities.PRF(this.ms, TlsUtilities.ToByteArray("client finished"), md5andsha1, checksum); MemoryStream bos2 = new MemoryStream(); TlsUtilities.WriteUint8(HP_FINISHED, bos2); TlsUtilities.WriteUint24(12, bos2); bos2.Write(checksum, 0, checksum.Length); byte[] message2 = bos2.ToArray(); rs.WriteMessage((short)RL_HANDSHAKE, message2, 0, message2.Length); this.connection_state = CS_CLIENT_FINISHED_SEND; read = true; break; default: this.FailWithError(AL_fatal, AP_handshake_failure); break; } break; case HP_SERVER_KEY_EXCHANGE: { switch (connection_state) { case CS_SERVER_CERTIFICATE_RECEIVED: { /* * Check that we are doing DHE key exchange */ switch (this.chosenCipherSuite.KeyExchangeAlgorithm) { case TlsCipherSuite.KE_DHE_RSA: { processDHEKeyExchange(inStr, new TlsRsaSigner()); break; } case TlsCipherSuite.KE_DHE_DSS: { processDHEKeyExchange(inStr, new TlsDssSigner()); break; } default: this.FailWithError(AL_fatal, AP_unexpected_message); break; } break; } default: this.FailWithError(AL_fatal, AP_unexpected_message); break; } this.connection_state = CS_SERVER_KEY_EXCHANGE_RECEIVED; read = true; break; } case HP_CERTIFICATE_REQUEST: switch (connection_state) { case CS_SERVER_CERTIFICATE_RECEIVED: case CS_SERVER_KEY_EXCHANGE_RECEIVED: { // NB: Original code used case label fall-through if (connection_state == CS_SERVER_CERTIFICATE_RECEIVED) { /* * There was no server key exchange message, check * that we are doing RSA key exchange. */ if (this.chosenCipherSuite.KeyExchangeAlgorithm != TlsCipherSuite.KE_RSA) { this.FailWithError(AL_fatal, AP_unexpected_message); } } int typesLength = TlsUtilities.ReadUint8(inStr); byte[] types = new byte[typesLength]; TlsUtilities.ReadFully(types, inStr); int authsLength = TlsUtilities.ReadUint16(inStr); byte[] auths = new byte[authsLength]; TlsUtilities.ReadFully(auths, inStr); AssertEmpty(inStr); break; } default: this.FailWithError(AL_fatal, AP_unexpected_message); break; } this.connection_state = CS_CERTIFICATE_REQUEST_RECEIVED; read = true; break; case HP_HELLO_REQUEST: case HP_CLIENT_KEY_EXCHANGE: case HP_CERTIFICATE_VERIFY: case HP_CLIENT_HELLO: default: // We do not support this! this.FailWithError(AL_fatal, AP_unexpected_message); break; } } } }while (read); }
private void processHandshake() { bool read; do { read = false; /* * We need the first 4 bytes, they contain type and length of * the message. */ if (handshakeQueue.Available >= 4) { byte[] beginning = new byte[4]; handshakeQueue.Read(beginning, 0, 4, 0); MemoryStream bis = new MemoryStream(beginning, false); short type = TlsUtilities.ReadUint8(bis); int len = TlsUtilities.ReadUint24(bis); /* * Check if we have enough bytes in the buffer to read * the full message. */ if (handshakeQueue.Available >= (len + 4)) { /* * Read the message. */ byte[] buf = new byte[len]; handshakeQueue.Read(buf, 0, len, 4); handshakeQueue.RemoveData(len + 4); /* * If it is not a finished message, update our hashes * we prepare for the finish message. */ if (type != HP_FINISHED) { rs.hash1.BlockUpdate(beginning, 0, 4); rs.hash2.BlockUpdate(beginning, 0, 4); rs.hash1.BlockUpdate(buf, 0, len); rs.hash2.BlockUpdate(buf, 0, len); } /* * Now, parse the message. */ MemoryStream inStr = new MemoryStream(buf, false); /* * Check the type. */ switch (type) { case HP_CERTIFICATE: switch (connection_state) { case CS_SERVER_HELLO_RECEIVED: /* * Parse the certificates. */ Certificate cert = Certificate.Parse(inStr); AssertEmpty(inStr); /* * Verify them. */ if (!this.verifyer.IsValid(cert.GetCerts())) { this.FailWithError(AL_fatal, AP_user_canceled); } /* * We only support RSA certificates. Lets hope * this is one. */ RsaPublicKeyStructure rsaKey = null; try { rsaKey = RsaPublicKeyStructure.GetInstance( cert.certs[0].TbsCertificate.SubjectPublicKeyInfo.GetPublicKey()); } catch (Exception) { /* * Sorry, we have to fail ;-( */ this.FailWithError(AL_fatal, AP_unsupported_certificate); } /* * Parse the servers public RSA key. */ this.serverRsaKey = new RsaKeyParameters( false, rsaKey.Modulus, rsaKey.PublicExponent); connection_state = CS_SERVER_CERTIFICATE_RECEIVED; read = true; break; default: this.FailWithError(AL_fatal, AP_unexpected_message); break; } break; case HP_FINISHED: switch (connection_state) { case CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED: /* * Read the checksum from the finished message, * it has always 12 bytes. */ byte[] receivedChecksum = new byte[12]; TlsUtilities.ReadFully(receivedChecksum, inStr); AssertEmpty(inStr); /* * Calculate our owne checksum. */ byte[] checksum = new byte[12]; byte[] md5andsha1 = new byte[16 + 20]; rs.hash2.DoFinal(md5andsha1, 0); TlsUtilities.PRF(this.ms, TlsUtilities.ToByteArray("server finished"), md5andsha1, checksum); /* * Compare both checksums. */ for (int i = 0; i < receivedChecksum.Length; i++) { if (receivedChecksum[i] != checksum[i]) { /* * Wrong checksum in the finished message. */ this.FailWithError(AL_fatal, AP_handshake_failure); } } connection_state = CS_DONE; /* * We are now ready to receive application data. */ this.appDataReady = true; read = true; break; default: this.FailWithError(AL_fatal, AP_unexpected_message); break; } break; case HP_SERVER_HELLO: switch (connection_state) { case CS_CLIENT_HELLO_SEND: /* * Read the server hello message */ TlsUtilities.CheckVersion(inStr, this); /* * Read the server random */ this.serverRandom = new byte[32]; TlsUtilities.ReadFully(this.serverRandom, inStr); /* * Currenty, we don't support session ids */ short sessionIdLength = TlsUtilities.ReadUint8(inStr); byte[] sessionId = new byte[sessionIdLength]; TlsUtilities.ReadFully(sessionId, inStr); /* * Find out which ciphersuite the server has * choosen. If we don't support this ciphersuite, * the TlsCipherSuiteManager will throw an * exception. */ this.choosenCipherSuite = TlsCipherSuiteManager.GetCipherSuite( TlsUtilities.ReadUint16(inStr), this); /* * We support only the null compression which * means no compression. */ short compressionMethod = TlsUtilities.ReadUint8(inStr); if (compressionMethod != 0) { this.FailWithError(TlsProtocolHandler.AL_fatal, TlsProtocolHandler.AP_illegal_parameter); } AssertEmpty(inStr); connection_state = CS_SERVER_HELLO_RECEIVED; read = true; break; default: this.FailWithError(AL_fatal, AP_unexpected_message); break; } break; case HP_SERVER_HELLO_DONE: switch (connection_state) { case CS_SERVER_CERTIFICATE_RECEIVED: case CS_SERVER_KEY_EXCHANGE_RECEIVED: // NB: Original code used case label fall-through if (connection_state == CS_SERVER_CERTIFICATE_RECEIVED) { /* * There was no server key exchange message, check * that we are doing RSA key exchange. */ if (this.choosenCipherSuite.KeyExchangeAlgorithm != TlsCipherSuite.KE_RSA) { this.FailWithError(AL_fatal, AP_unexpected_message); } } AssertEmpty(inStr); connection_state = CS_SERVER_HELLO_DONE_RECEIVED; /* * Send the client key exchange message, depending * on the key exchange we are using in our * ciphersuite. */ short ke = this.choosenCipherSuite.KeyExchangeAlgorithm; switch (ke) { case TlsCipherSuite.KE_RSA: /* * We are doing RSA key exchange. We will * choose a pre master secret and send it * rsa encrypted to the server. * * Prepare pre master secret. */ pms = new byte[48]; pms[0] = 3; pms[1] = 1; random.NextBytes(pms, 2, 46); /* * Encode the pms and send it to the server. * * Prepare an Pkcs1Encoding with good random * padding. */ RsaBlindedEngine rsa = new RsaBlindedEngine(); Pkcs1Encoding encoding = new Pkcs1Encoding(rsa); encoding.Init(true, new ParametersWithRandom(this.serverRsaKey, this.random)); byte[] encrypted = null; try { encrypted = encoding.ProcessBlock(pms, 0, pms.Length); } catch (InvalidCipherTextException) { /* * This should never happen, only during decryption. */ this.FailWithError(AL_fatal, AP_internal_error); } /* * Send the encrypted pms. */ MemoryStream bos = new MemoryStream(); TlsUtilities.WriteUint8(HP_CLIENT_KEY_EXCHANGE, bos); TlsUtilities.WriteUint24(encrypted.Length + 2, bos); TlsUtilities.WriteUint16(encrypted.Length, bos); bos.Write(encrypted, 0, encrypted.Length); byte[] message = bos.ToArray(); rs.WriteMessage((short)RL_HANDSHAKE, message, 0, message.Length); break; case TlsCipherSuite.KE_DHE_RSA: /* * Send the Client Key Exchange message for * DHE key exchange. */ byte[] YcByte = this.Yc.ToByteArray(); MemoryStream DHbos = new MemoryStream(); TlsUtilities.WriteUint8(HP_CLIENT_KEY_EXCHANGE, DHbos); TlsUtilities.WriteUint24(YcByte.Length + 2, DHbos); TlsUtilities.WriteUint16(YcByte.Length, DHbos); DHbos.Write(YcByte, 0, YcByte.Length); byte[] DHmessage = DHbos.ToArray(); rs.WriteMessage((short)RL_HANDSHAKE, DHmessage, 0, DHmessage.Length); break; default: /* * Proble during handshake, we don't know * how to thandle this key exchange method. */ this.FailWithError(AL_fatal, AP_unexpected_message); break; } connection_state = CS_CLIENT_KEY_EXCHANGE_SEND; /* * Now, we send change cipher state */ byte[] cmessage = new byte[1]; cmessage[0] = 1; rs.WriteMessage((short)RL_CHANGE_CIPHER_SPEC, cmessage, 0, cmessage.Length); connection_state = CS_CLIENT_CHANGE_CIPHER_SPEC_SEND; /* * Calculate the ms */ this.ms = new byte[48]; byte[] randBytes = new byte[clientRandom.Length + serverRandom.Length]; Array.Copy(clientRandom, 0, randBytes, 0, clientRandom.Length); Array.Copy(serverRandom, 0, randBytes, clientRandom.Length, serverRandom.Length); TlsUtilities.PRF(pms, TlsUtilities.ToByteArray("master secret"), randBytes, this.ms); /* * Initialize our cipher suite */ rs.writeSuite = this.choosenCipherSuite; rs.writeSuite.Init(this.ms, clientRandom, serverRandom); /* * Send our finished message. */ byte[] checksum = new byte[12]; byte[] md5andsha1 = new byte[16 + 20]; rs.hash1.DoFinal(md5andsha1, 0); TlsUtilities.PRF(this.ms, TlsUtilities.ToByteArray("client finished"), md5andsha1, checksum); MemoryStream bos2 = new MemoryStream(); TlsUtilities.WriteUint8(HP_FINISHED, bos2); TlsUtilities.WriteUint24(12, bos2); bos2.Write(checksum, 0, checksum.Length); byte[] message2 = bos2.ToArray(); rs.WriteMessage((short)RL_HANDSHAKE, message2, 0, message2.Length); this.connection_state = CS_CLIENT_FINISHED_SEND; read = true; break; default: this.FailWithError(AL_fatal, AP_handshake_failure); break; } break; case HP_SERVER_KEY_EXCHANGE: switch (connection_state) { case CS_SERVER_CERTIFICATE_RECEIVED: /* * Check that we are doing DHE key exchange */ if (this.choosenCipherSuite.KeyExchangeAlgorithm != TlsCipherSuite.KE_DHE_RSA) { this.FailWithError(AL_fatal, AP_unexpected_message); } /* * Parse the Structure */ int pLength = TlsUtilities.ReadUint16(inStr); byte[] pByte = new byte[pLength]; TlsUtilities.ReadFully(pByte, inStr); int gLength = TlsUtilities.ReadUint16(inStr); byte[] gByte = new byte[gLength]; TlsUtilities.ReadFully(gByte, inStr); int YsLength = TlsUtilities.ReadUint16(inStr); byte[] YsByte = new byte[YsLength]; TlsUtilities.ReadFully(YsByte, inStr); int sigLength = TlsUtilities.ReadUint16(inStr); byte[] sigByte = new byte[sigLength]; TlsUtilities.ReadFully(sigByte, inStr); this.AssertEmpty(inStr); /* * Verify the Signature. * * First, calculate the hash. */ CombinedHash sigDigest = new CombinedHash(); MemoryStream signedData = new MemoryStream(); TlsUtilities.WriteUint16(pLength, signedData); signedData.Write(pByte, 0, pByte.Length); TlsUtilities.WriteUint16(gLength, signedData); signedData.Write(gByte, 0, gByte.Length); TlsUtilities.WriteUint16(YsLength, signedData); signedData.Write(YsByte, 0, YsByte.Length); byte[] signed = signedData.ToArray(); sigDigest.BlockUpdate(this.clientRandom, 0, this.clientRandom.Length); sigDigest.BlockUpdate(this.serverRandom, 0, this.serverRandom.Length); sigDigest.BlockUpdate(signed, 0, signed.Length); byte[] hash = new byte[sigDigest.GetDigestSize()]; sigDigest.DoFinal(hash, 0); /* * Now, do the RSA operation */ RsaBlindedEngine rsa = new RsaBlindedEngine(); Pkcs1Encoding encoding = new Pkcs1Encoding(rsa); encoding.Init(false, this.serverRsaKey); /* * The data which was signed */ byte[] sigHash = null; try { sigHash = encoding.ProcessBlock(sigByte, 0, sigByte.Length); } catch (InvalidCipherTextException) { this.FailWithError(AL_fatal, AP_bad_certificate); } /* * Check if the data which was signed is equal to * the hash we calculated. */ if (sigHash.Length != hash.Length) { this.FailWithError(AL_fatal, AP_bad_certificate); } for (int i = 0; i < sigHash.Length; i++) { if (sigHash[i] != hash[i]) { this.FailWithError(AL_fatal, AP_bad_certificate); } } /* * OK, Signature was correct. * * Do the DH calculation. */ BigInteger p = new BigInteger(1, pByte); BigInteger g = new BigInteger(1, gByte); BigInteger Ys = new BigInteger(1, YsByte); BigInteger x = new BigInteger(p.BitLength - 1, this.random); Yc = g.ModPow(x, p); this.pms = (Ys.ModPow(x, p)).ToByteArray(); /* * Remove leading zero byte, if present. */ if (this.pms[0] == 0) { byte[] tmp = new byte[this.pms.Length - 1]; Array.Copy(this.pms, 1, tmp, 0, tmp.Length); this.pms = tmp; } this.connection_state = CS_SERVER_KEY_EXCHANGE_RECEIVED; read = true; break; default: this.FailWithError(AL_fatal, AP_unexpected_message); break; } break; case HP_HELLO_REQUEST: case HP_CLIENT_KEY_EXCHANGE: case HP_CERTIFICATE_REQUEST: case HP_CERTIFICATE_VERIFY: case HP_CLIENT_HELLO: default: // We do not support this! this.FailWithError(AL_fatal, AP_unexpected_message); break; } } } }while (read); }