12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388 |
- #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
- using System;
- using System.Collections;
- using System.IO;
- using Org.BouncyCastle.Crypto.Prng;
- using Org.BouncyCastle.Security;
- using Org.BouncyCastle.Utilities;
- namespace Org.BouncyCastle.Crypto.Tls
- {
- public abstract class TlsProtocol
- {
- private static readonly string TLS_ERROR_MESSAGE = "Internal TLS error, this could be an attack";
- /*
- * Our Connection states
- */
- protected const short CS_START = 0;
- protected const short CS_CLIENT_HELLO = 1;
- protected const short CS_SERVER_HELLO = 2;
- protected const short CS_SERVER_SUPPLEMENTAL_DATA = 3;
- protected const short CS_SERVER_CERTIFICATE = 4;
- protected const short CS_CERTIFICATE_STATUS = 5;
- protected const short CS_SERVER_KEY_EXCHANGE = 6;
- protected const short CS_CERTIFICATE_REQUEST = 7;
- protected const short CS_SERVER_HELLO_DONE = 8;
- protected const short CS_CLIENT_SUPPLEMENTAL_DATA = 9;
- protected const short CS_CLIENT_CERTIFICATE = 10;
- protected const short CS_CLIENT_KEY_EXCHANGE = 11;
- protected const short CS_CERTIFICATE_VERIFY = 12;
- protected const short CS_CLIENT_FINISHED = 13;
- protected const short CS_SERVER_SESSION_TICKET = 14;
- protected const short CS_SERVER_FINISHED = 15;
- protected const short CS_END = 16;
- /*
- * Different modes to handle the known IV weakness
- */
- protected const short ADS_MODE_1_Nsub1 = 0; // 1/n-1 record splitting
- protected const short ADS_MODE_0_N = 1; // 0/n record splitting
- protected const short ADS_MODE_0_N_FIRSTONLY = 2; // 0/n record splitting on first data fragment only
- /*
- * Queues for data from some protocols.
- */
- private ByteQueue mApplicationDataQueue = new ByteQueue();
- private ByteQueue mAlertQueue = new ByteQueue(2);
- private ByteQueue mHandshakeQueue = new ByteQueue();
- // private ByteQueue mHeartbeatQueue = new ByteQueue();
- /*
- * The Record Stream we use
- */
- internal RecordStream mRecordStream;
- protected SecureRandom mSecureRandom;
- private TlsStream mTlsStream = null;
- private volatile bool mClosed = false;
- private volatile bool mFailedWithError = false;
- private volatile bool mAppDataReady = false;
- private volatile bool mAppDataSplitEnabled = true;
- private volatile int mAppDataSplitMode = ADS_MODE_1_Nsub1;
- private byte[] mExpectedVerifyData = null;
- protected TlsSession mTlsSession = null;
- protected SessionParameters mSessionParameters = null;
- protected SecurityParameters mSecurityParameters = null;
- protected Certificate mPeerCertificate = null;
- protected int[] mOfferedCipherSuites = null;
- protected byte[] mOfferedCompressionMethods = null;
- protected IDictionary mClientExtensions = null;
- protected IDictionary mServerExtensions = null;
- protected short mConnectionState = CS_START;
- protected bool mResumedSession = false;
- protected bool mReceivedChangeCipherSpec = false;
- protected bool mSecureRenegotiation = false;
- protected bool mAllowCertificateStatus = false;
- protected bool mExpectSessionTicket = false;
- protected bool mBlocking = true;
- protected ByteQueueStream mInputBuffers = null;
- protected ByteQueueStream mOutputBuffer = null;
- public TlsProtocol(Stream stream, SecureRandom secureRandom)
- : this(stream, stream, secureRandom)
- {
- }
- public TlsProtocol(Stream input, Stream output, SecureRandom secureRandom)
- {
- this.mRecordStream = new RecordStream(this, input, output);
- this.mSecureRandom = secureRandom;
- }
- public TlsProtocol(SecureRandom secureRandom)
- {
- this.mBlocking = false;
- this.mInputBuffers = new ByteQueueStream();
- this.mOutputBuffer = new ByteQueueStream();
- this.mRecordStream = new RecordStream(this, mInputBuffers, mOutputBuffer);
- this.mSecureRandom = secureRandom;
- }
- protected abstract TlsContext Context { get; }
- internal abstract AbstractTlsContext ContextAdmin { get; }
- protected abstract TlsPeer Peer { get; }
- protected virtual void HandleChangeCipherSpecMessage()
- {
- }
- protected abstract void HandleHandshakeMessage(byte type, byte[] buf);
- protected virtual void HandleWarningMessage(byte description)
- {
- }
- protected virtual void ApplyMaxFragmentLengthExtension()
- {
- if (mSecurityParameters.maxFragmentLength >= 0)
- {
- if (!MaxFragmentLength.IsValid((byte)mSecurityParameters.maxFragmentLength))
- throw new TlsFatalAlert(AlertDescription.internal_error);
- int plainTextLimit = 1 << (8 + mSecurityParameters.maxFragmentLength);
- mRecordStream.SetPlaintextLimit(plainTextLimit);
- }
- }
- protected virtual void CheckReceivedChangeCipherSpec(bool expected)
- {
- if (expected != mReceivedChangeCipherSpec)
- throw new TlsFatalAlert(AlertDescription.unexpected_message);
- }
- protected virtual void CleanupHandshake()
- {
- if (this.mExpectedVerifyData != null)
- {
- Arrays.Fill(this.mExpectedVerifyData, (byte)0);
- this.mExpectedVerifyData = null;
- }
- this.mSecurityParameters.Clear();
- this.mPeerCertificate = null;
- this.mOfferedCipherSuites = null;
- this.mOfferedCompressionMethods = null;
- this.mClientExtensions = null;
- this.mServerExtensions = null;
- this.mResumedSession = false;
- this.mReceivedChangeCipherSpec = false;
- this.mSecureRenegotiation = false;
- this.mAllowCertificateStatus = false;
- this.mExpectSessionTicket = false;
- }
- protected virtual void BlockForHandshake()
- {
- if (mBlocking)
- {
- while (this.mConnectionState != CS_END)
- {
- if (this.mClosed)
- {
- // TODO What kind of exception/alert?
- }
- SafeReadRecord();
- }
- }
- }
- protected virtual void CompleteHandshake()
- {
- try
- {
- this.mRecordStream.FinaliseHandshake();
- this.mAppDataSplitEnabled = !TlsUtilities.IsTlsV11(Context);
- /*
- * If this was an initial handshake, we are now ready to send and receive application data.
- */
- if (!mAppDataReady)
- {
- this.mAppDataReady = true;
- if (mBlocking)
- {
- this.mTlsStream = new TlsStream(this);
- }
- }
- if (this.mTlsSession != null)
- {
- if (this.mSessionParameters == null)
- {
- this.mSessionParameters = new SessionParameters.Builder()
- .SetCipherSuite(this.mSecurityParameters.CipherSuite)
- .SetCompressionAlgorithm(this.mSecurityParameters.CompressionAlgorithm)
- .SetMasterSecret(this.mSecurityParameters.MasterSecret)
- .SetPeerCertificate(this.mPeerCertificate)
- .SetPskIdentity(this.mSecurityParameters.PskIdentity)
- .SetSrpIdentity(this.mSecurityParameters.SrpIdentity)
- // TODO Consider filtering extensions that aren't relevant to resumed sessions
- .SetServerExtensions(this.mServerExtensions)
- .Build();
- this.mTlsSession = new TlsSessionImpl(this.mTlsSession.SessionID, this.mSessionParameters);
- }
- ContextAdmin.SetResumableSession(this.mTlsSession);
- }
- Peer.NotifyHandshakeComplete();
- }
- finally
- {
- CleanupHandshake();
- }
- }
- protected internal void ProcessRecord(byte protocol, byte[] buf, int offset, int len)
- {
- /*
- * Have a look at the protocol type, and add it to the correct queue.
- */
- switch (protocol)
- {
- case ContentType.alert:
- {
- mAlertQueue.AddData(buf, offset, len);
- ProcessAlert();
- break;
- }
- case ContentType.application_data:
- {
- if (!mAppDataReady)
- throw new TlsFatalAlert(AlertDescription.unexpected_message);
- mApplicationDataQueue.AddData(buf, offset, len);
- ProcessApplicationData();
- break;
- }
- case ContentType.change_cipher_spec:
- {
- ProcessChangeCipherSpec(buf, offset, len);
- break;
- }
- case ContentType.handshake:
- {
- mHandshakeQueue.AddData(buf, offset, len);
- ProcessHandshake();
- break;
- }
- case ContentType.heartbeat:
- {
- if (!mAppDataReady)
- throw new TlsFatalAlert(AlertDescription.unexpected_message);
- // TODO[RFC 6520]
- // mHeartbeatQueue.AddData(buf, offset, len);
- // ProcessHeartbeat();
- break;
- }
- default:
- /*
- * Uh, we don't know this protocol.
- *
- * RFC2246 defines on page 13, that we should ignore this.
- */
- break;
- }
- }
- private void ProcessHandshake()
- {
- bool read;
- do
- {
- read = false;
- /*
- * We need the first 4 bytes, they contain type and length of the message.
- */
- if (mHandshakeQueue.Available >= 4)
- {
- byte[] beginning = new byte[4];
- mHandshakeQueue.Read(beginning, 0, 4, 0);
- byte type = TlsUtilities.ReadUint8(beginning, 0);
- int len = TlsUtilities.ReadUint24(beginning, 1);
- /*
- * Check if we have enough bytes in the buffer to read the full message.
- */
- if (mHandshakeQueue.Available >= (len + 4))
- {
- /*
- * Read the message.
- */
- byte[] buf = mHandshakeQueue.RemoveData(len, 4);
- CheckReceivedChangeCipherSpec(mConnectionState == CS_END || type == HandshakeType.finished);
- /*
- * 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 HandshakeType.hello_request:
- break;
- case HandshakeType.finished:
- default:
- {
- TlsContext ctx = Context;
- if (type == HandshakeType.finished
- && this.mExpectedVerifyData == null
- && ctx.SecurityParameters.MasterSecret != null)
- {
- this.mExpectedVerifyData = CreateVerifyData(!ctx.IsServer);
- }
- mRecordStream.UpdateHandshakeData(beginning, 0, 4);
- mRecordStream.UpdateHandshakeData(buf, 0, len);
- break;
- }
- }
- /*
- * Now, parse the message.
- */
- HandleHandshakeMessage(type, buf);
- read = true;
- }
- }
- }
- while (read);
- }
- private void ProcessApplicationData()
- {
- /*
- * There is nothing we need to do here.
- *
- * This function could be used for callbacks when application data arrives in the future.
- */
- }
- private void ProcessAlert()
- {
- while (mAlertQueue.Available >= 2)
- {
- /*
- * An alert is always 2 bytes. Read the alert.
- */
- byte[] tmp = mAlertQueue.RemoveData(2, 0);
- byte level = tmp[0];
- byte description = tmp[1];
- Peer.NotifyAlertReceived(level, description);
- if (level == AlertLevel.fatal)
- {
- /*
- * RFC 2246 7.2.1. The session becomes unresumable if any connection is terminated
- * without proper close_notify messages with level equal to warning.
- */
- InvalidateSession();
- this.mFailedWithError = true;
- this.mClosed = true;
- mRecordStream.SafeClose();
- throw new IOException(TLS_ERROR_MESSAGE);
- }
- else
- {
- /*
- * RFC 5246 7.2.1. The other party MUST respond with a close_notify alert of its own
- * and close down the connection immediately, discarding any pending writes.
- */
- // TODO Can close_notify be a fatal alert?
- if (description == AlertDescription.close_notify)
- {
- HandleClose(false);
- }
- /*
- * If it is just a warning, we continue.
- */
- HandleWarningMessage(description);
- }
- }
- }
- /**
- * 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(byte[] buf, int off, int len)
- {
- for (int i = 0; i < len; ++i)
- {
- byte message = TlsUtilities.ReadUint8(buf, off + i);
- if (message != ChangeCipherSpec.change_cipher_spec)
- throw new TlsFatalAlert(AlertDescription.decode_error);
- if (this.mReceivedChangeCipherSpec
- || mAlertQueue.Available > 0
- || mHandshakeQueue.Available > 0)
- {
- throw new TlsFatalAlert(AlertDescription.unexpected_message);
- }
- mRecordStream.ReceivedReadCipherSpec();
- this.mReceivedChangeCipherSpec = true;
- HandleChangeCipherSpecMessage();
- }
- }
- protected internal virtual int ApplicationDataAvailable()
- {
- return mApplicationDataQueue.Available;
- }
- /**
- * 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.
- */
- protected internal virtual int ReadApplicationData(byte[] buf, int offset, int len)
- {
- if (len < 1)
- return 0;
- while (mApplicationDataQueue.Available == 0)
- {
- /*
- * We need to read some data.
- */
- if (this.mClosed)
- {
- if (this.mFailedWithError)
- {
- /*
- * 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;
- }
- SafeReadRecord();
- }
- len = System.Math.Min(len, mApplicationDataQueue.Available);
- mApplicationDataQueue.RemoveData(buf, offset, len, 0);
- return len;
- }
- protected virtual void SafeReadRecord()
- {
- try
- {
- if (!mRecordStream.ReadRecord())
- {
- // TODO It would be nicer to allow graceful connection close if between records
- // this.FailWithError(AlertLevel.warning, AlertDescription.close_notify);
- throw new EndOfStreamException();
- }
- }
- catch (TlsFatalAlert e)
- {
- if (!mClosed)
- {
- this.FailWithError(AlertLevel.fatal, e.AlertDescription, "Failed to read record", e);
- }
- throw e;
- }
- catch (Exception e)
- {
- if (!mClosed)
- {
- this.FailWithError(AlertLevel.fatal, AlertDescription.internal_error, "Failed to read record", e);
- }
- throw e;
- }
- }
- protected virtual void SafeWriteRecord(byte type, byte[] buf, int offset, int len)
- {
- try
- {
- mRecordStream.WriteRecord(type, buf, offset, len);
- }
- catch (TlsFatalAlert e)
- {
- if (!mClosed)
- {
- this.FailWithError(AlertLevel.fatal, e.AlertDescription, "Failed to write record", e);
- }
- throw e;
- }
- catch (Exception e)
- {
- if (!mClosed)
- {
- this.FailWithError(AlertLevel.fatal, AlertDescription.internal_error, "Failed to write record", e);
- }
- throw e;
- }
- }
- /**
- * Send some application data to the remote system.
- * <p/>
- * The method will handle fragmentation internally.
- *
- * @param buf The buffer with the data.
- * @param offset The position in the buffer where the data is placed.
- * @param len The length of the data.
- * @throws IOException If something goes wrong during sending.
- */
- protected internal virtual void WriteData(byte[] buf, int offset, int len)
- {
- if (this.mClosed)
- {
- if (this.mFailedWithError)
- throw new IOException(TLS_ERROR_MESSAGE);
- throw new IOException("Sorry, connection has been closed, you cannot write more data");
- }
- while (len > 0)
- {
- /*
- * RFC 5246 6.2.1. Zero-length fragments of Application data MAY be sent as they are
- * potentially useful as a traffic analysis countermeasure.
- *
- * NOTE: Actually, implementations appear to have settled on 1/n-1 record splitting.
- */
- if (this.mAppDataSplitEnabled)
- {
- /*
- * Protect against known IV attack!
- *
- * DO NOT REMOVE THIS CODE, EXCEPT YOU KNOW EXACTLY WHAT YOU ARE DOING HERE.
- */
- switch (mAppDataSplitMode)
- {
- case ADS_MODE_0_N:
- SafeWriteRecord(ContentType.application_data, TlsUtilities.EmptyBytes, 0, 0);
- break;
- case ADS_MODE_0_N_FIRSTONLY:
- this.mAppDataSplitEnabled = false;
- SafeWriteRecord(ContentType.application_data, TlsUtilities.EmptyBytes, 0, 0);
- break;
- case ADS_MODE_1_Nsub1:
- default:
- SafeWriteRecord(ContentType.application_data, buf, offset, 1);
- ++offset;
- --len;
- break;
- }
- }
- if (len > 0)
- {
- // Fragment data according to the current fragment limit.
- int toWrite = System.Math.Min(len, mRecordStream.GetPlaintextLimit());
- SafeWriteRecord(ContentType.application_data, buf, offset, toWrite);
- offset += toWrite;
- len -= toWrite;
- }
- }
- }
- protected virtual void SetAppDataSplitMode(int appDataSplitMode)
- {
- if (appDataSplitMode < ADS_MODE_1_Nsub1 || appDataSplitMode > ADS_MODE_0_N_FIRSTONLY)
- throw new ArgumentException("Illegal appDataSplitMode mode: " + appDataSplitMode, "appDataSplitMode");
- this.mAppDataSplitMode = appDataSplitMode;
- }
- protected virtual void WriteHandshakeMessage(byte[] buf, int off, int len)
- {
- while (len > 0)
- {
- // Fragment data according to the current fragment limit.
- int toWrite = System.Math.Min(len, mRecordStream.GetPlaintextLimit());
- SafeWriteRecord(ContentType.handshake, buf, off, toWrite);
- off += toWrite;
- len -= toWrite;
- }
- }
- /// <summary>The secure bidirectional stream for this connection</summary>
- /// <remarks>Only allowed in blocking mode.</remarks>
- public virtual Stream Stream
- {
- get
- {
- if (!mBlocking)
- throw new InvalidOperationException("Cannot use Stream in non-blocking mode! Use OfferInput()/OfferOutput() instead.");
- return this.mTlsStream;
- }
- }
- /**
- * Offer input from an arbitrary source. Only allowed in non-blocking mode.<br/>
- * <br/>
- * After this method returns, the input buffer is "owned" by this object. Other code
- * must not attempt to do anything with it.<br/>
- * <br/>
- * This method will decrypt and process all records that are fully available.
- * If only part of a record is available, the buffer will be retained until the
- * remainder of the record is offered.<br/>
- * <br/>
- * If any records containing application data were processed, the decrypted data
- * can be obtained using {@link #readInput(byte[], int, int)}. If any records
- * containing protocol data were processed, a response may have been generated.
- * You should always check to see if there is any available output after calling
- * this method by calling {@link #getAvailableOutputBytes()}.
- * @param input The input buffer to offer
- * @throws IOException If an error occurs while decrypting or processing a record
- */
- public virtual void OfferInput(byte[] input)
- {
- if (mBlocking)
- throw new InvalidOperationException("Cannot use OfferInput() in blocking mode! Use Stream instead.");
- if (mClosed)
- throw new IOException("Connection is closed, cannot accept any more input");
- mInputBuffers.Write(input);
- // loop while there are enough bytes to read the length of the next record
- while (mInputBuffers.Available >= RecordStream.TLS_HEADER_SIZE)
- {
- byte[] header = new byte[RecordStream.TLS_HEADER_SIZE];
- mInputBuffers.Peek(header);
- int totalLength = TlsUtilities.ReadUint16(header, RecordStream.TLS_HEADER_LENGTH_OFFSET) + RecordStream.TLS_HEADER_SIZE;
- if (mInputBuffers.Available < totalLength)
- {
- // not enough bytes to read a whole record
- break;
- }
- SafeReadRecord();
- }
- }
- /**
- * Gets the amount of received application data. A call to {@link #readInput(byte[], int, int)}
- * is guaranteed to be able to return at least this much data.<br/>
- * <br/>
- * Only allowed in non-blocking mode.
- * @return The number of bytes of available application data
- */
- public virtual int GetAvailableInputBytes()
- {
- if (mBlocking)
- throw new InvalidOperationException("Cannot use GetAvailableInputBytes() in blocking mode! Use ApplicationDataAvailable() instead.");
- return ApplicationDataAvailable();
- }
- /**
- * Retrieves received application data. Use {@link #getAvailableInputBytes()} to check
- * how much application data is currently available. This method functions similarly to
- * {@link InputStream#read(byte[], int, int)}, except that it never blocks. If no data
- * is available, nothing will be copied and zero will be returned.<br/>
- * <br/>
- * Only allowed in non-blocking mode.
- * @param buffer The buffer to hold the application data
- * @param offset The start offset in the buffer at which the data is written
- * @param length The maximum number of bytes to read
- * @return The total number of bytes copied to the buffer. May be less than the
- * length specified if the length was greater than the amount of available data.
- */
- public virtual int ReadInput(byte[] buffer, int offset, int length)
- {
- if (mBlocking)
- throw new InvalidOperationException("Cannot use ReadInput() in blocking mode! Use Stream instead.");
- return ReadApplicationData(buffer, offset, System.Math.Min(length, ApplicationDataAvailable()));
- }
- /**
- * Offer output from an arbitrary source. Only allowed in non-blocking mode.<br/>
- * <br/>
- * After this method returns, the specified section of the buffer will have been
- * processed. Use {@link #readOutput(byte[], int, int)} to get the bytes to
- * transmit to the other peer.<br/>
- * <br/>
- * This method must not be called until after the handshake is complete! Attempting
- * to call it before the handshake is complete will result in an exception.
- * @param buffer The buffer containing application data to encrypt
- * @param offset The offset at which to begin reading data
- * @param length The number of bytes of data to read
- * @throws IOException If an error occurs encrypting the data, or the handshake is not complete
- */
- public virtual void OfferOutput(byte[] buffer, int offset, int length)
- {
- if (mBlocking)
- throw new InvalidOperationException("Cannot use OfferOutput() in blocking mode! Use Stream instead.");
- if (!mAppDataReady)
- throw new IOException("Application data cannot be sent until the handshake is complete!");
- WriteData(buffer, offset, length);
- }
- /**
- * Gets the amount of encrypted data available to be sent. A call to
- * {@link #readOutput(byte[], int, int)} is guaranteed to be able to return at
- * least this much data.<br/>
- * <br/>
- * Only allowed in non-blocking mode.
- * @return The number of bytes of available encrypted data
- */
- public virtual int GetAvailableOutputBytes()
- {
- if (mBlocking)
- throw new InvalidOperationException("Cannot use GetAvailableOutputBytes() in blocking mode! Use Stream instead.");
- return mOutputBuffer.Available;
- }
- /**
- * Retrieves encrypted data to be sent. Use {@link #getAvailableOutputBytes()} to check
- * how much encrypted data is currently available. This method functions similarly to
- * {@link InputStream#read(byte[], int, int)}, except that it never blocks. If no data
- * is available, nothing will be copied and zero will be returned.<br/>
- * <br/>
- * Only allowed in non-blocking mode.
- * @param buffer The buffer to hold the encrypted data
- * @param offset The start offset in the buffer at which the data is written
- * @param length The maximum number of bytes to read
- * @return The total number of bytes copied to the buffer. May be less than the
- * length specified if the length was greater than the amount of available data.
- */
- public virtual int ReadOutput(byte[] buffer, int offset, int length)
- {
- if (mBlocking)
- throw new InvalidOperationException("Cannot use ReadOutput() in blocking mode! Use Stream instead.");
- return mOutputBuffer.Read(buffer, offset, length);
- }
- /**
- * Terminate this connection with an alert. Can be used for normal closure too.
- *
- * @param alertLevel
- * See {@link AlertLevel} for values.
- * @param alertDescription
- * See {@link AlertDescription} for values.
- * @throws IOException
- * If alert was fatal.
- */
- protected virtual void FailWithError(byte alertLevel, byte alertDescription, string message, Exception cause)
- {
- /*
- * Check if the connection is still open.
- */
- if (!mClosed)
- {
- /*
- * Prepare the message
- */
- this.mClosed = true;
- if (alertLevel == AlertLevel.fatal)
- {
- /*
- * RFC 2246 7.2.1. The session becomes unresumable if any connection is terminated
- * without proper close_notify messages with level equal to warning.
- */
- // TODO This isn't quite in the right place. Also, as of TLS 1.1 the above is obsolete.
- InvalidateSession();
- this.mFailedWithError = true;
- }
- RaiseAlert(alertLevel, alertDescription, message, cause);
- mRecordStream.SafeClose();
- if (alertLevel != AlertLevel.fatal)
- {
- return;
- }
- }
- throw new IOException(TLS_ERROR_MESSAGE);
- }
- protected virtual void InvalidateSession()
- {
- if (this.mSessionParameters != null)
- {
- this.mSessionParameters.Clear();
- this.mSessionParameters = null;
- }
- if (this.mTlsSession != null)
- {
- this.mTlsSession.Invalidate();
- this.mTlsSession = null;
- }
- }
- protected virtual void ProcessFinishedMessage(MemoryStream buf)
- {
- if (mExpectedVerifyData == null)
- throw new TlsFatalAlert(AlertDescription.internal_error);
- byte[] verify_data = TlsUtilities.ReadFully(mExpectedVerifyData.Length, buf);
- AssertEmpty(buf);
- /*
- * Compare both checksums.
- */
- if (!Arrays.ConstantTimeAreEqual(mExpectedVerifyData, verify_data))
- {
- /*
- * Wrong checksum in the finished message.
- */
- throw new TlsFatalAlert(AlertDescription.decrypt_error);
- }
- }
- protected virtual void RaiseAlert(byte alertLevel, byte alertDescription, string message, Exception cause)
- {
- Peer.NotifyAlertRaised(alertLevel, alertDescription, message, cause);
- byte[] error = new byte[]{ alertLevel, alertDescription };
- SafeWriteRecord(ContentType.alert, error, 0, 2);
- }
- protected virtual void RaiseWarning(byte alertDescription, string message)
- {
- RaiseAlert(AlertLevel.warning, alertDescription, message, null);
- }
- protected virtual void SendCertificateMessage(Certificate certificate)
- {
- if (certificate == null)
- {
- certificate = Certificate.EmptyChain;
- }
- if (certificate.IsEmpty)
- {
- TlsContext context = Context;
- if (!context.IsServer)
- {
- ProtocolVersion serverVersion = Context.ServerVersion;
- if (serverVersion.IsSsl)
- {
- string errorMessage = serverVersion.ToString() + " client didn't provide credentials";
- RaiseWarning(AlertDescription.no_certificate, errorMessage);
- return;
- }
- }
- }
- HandshakeMessage message = new HandshakeMessage(HandshakeType.certificate);
- certificate.Encode(message);
- message.WriteToRecordStream(this);
- }
- protected virtual void SendChangeCipherSpecMessage()
- {
- byte[] message = new byte[]{ 1 };
- SafeWriteRecord(ContentType.change_cipher_spec, message, 0, message.Length);
- mRecordStream.SentWriteCipherSpec();
- }
- protected virtual void SendFinishedMessage()
- {
- byte[] verify_data = CreateVerifyData(Context.IsServer);
- HandshakeMessage message = new HandshakeMessage(HandshakeType.finished, verify_data.Length);
- message.Write(verify_data, 0, verify_data.Length);
- message.WriteToRecordStream(this);
- }
- protected virtual void SendSupplementalDataMessage(IList supplementalData)
- {
- HandshakeMessage message = new HandshakeMessage(HandshakeType.supplemental_data);
- WriteSupplementalData(message, supplementalData);
- message.WriteToRecordStream(this);
- }
- protected virtual byte[] CreateVerifyData(bool isServer)
- {
- TlsContext context = Context;
- string asciiLabel = isServer ? ExporterLabel.server_finished : ExporterLabel.client_finished;
- byte[] sslSender = isServer ? TlsUtilities.SSL_SERVER : TlsUtilities.SSL_CLIENT;
- byte[] hash = GetCurrentPrfHash(context, mRecordStream.HandshakeHash, sslSender);
- return TlsUtilities.CalculateVerifyData(context, asciiLabel, hash);
- }
- /**
- * Closes this connection.
- *
- * @throws IOException If something goes wrong during closing.
- */
- public virtual void Close()
- {
- HandleClose(true);
- }
- protected virtual void HandleClose(bool user_canceled)
- {
- if (!mClosed)
- {
- if (user_canceled && !mAppDataReady)
- {
- RaiseWarning(AlertDescription.user_canceled, "User canceled handshake");
- }
- this.FailWithError(AlertLevel.warning, AlertDescription.close_notify, "Connection closed", null);
- }
- }
- protected internal virtual void Flush()
- {
- mRecordStream.Flush();
- }
- public virtual bool IsClosed
- {
- get { return mClosed; }
- }
- protected virtual short ProcessMaxFragmentLengthExtension(IDictionary clientExtensions, IDictionary serverExtensions,
- byte alertDescription)
- {
- short maxFragmentLength = TlsExtensionsUtilities.GetMaxFragmentLengthExtension(serverExtensions);
- if (maxFragmentLength >= 0)
- {
- if (!MaxFragmentLength.IsValid((byte)maxFragmentLength)
- || (!this.mResumedSession && maxFragmentLength != TlsExtensionsUtilities
- .GetMaxFragmentLengthExtension(clientExtensions)))
- {
- throw new TlsFatalAlert(alertDescription);
- }
- }
- return maxFragmentLength;
- }
- protected virtual void RefuseRenegotiation()
- {
- /*
- * RFC 5746 4.5 SSLv3 clients that refuse renegotiation SHOULD use a fatal
- * handshake_failure alert.
- */
- if (TlsUtilities.IsSsl(Context))
- throw new TlsFatalAlert(AlertDescription.handshake_failure);
- RaiseWarning(AlertDescription.no_renegotiation, "Renegotiation not supported");
- }
- /**
- * Make sure the InputStream 'buf' now empty. Fail otherwise.
- *
- * @param buf The InputStream to check.
- * @throws IOException If 'buf' is not empty.
- */
- protected internal static void AssertEmpty(MemoryStream buf)
- {
- if (buf.Position < buf.Length)
- throw new TlsFatalAlert(AlertDescription.decode_error);
- }
- protected internal static byte[] CreateRandomBlock(bool useGmtUnixTime, IRandomGenerator randomGenerator)
- {
- byte[] result = new byte[32];
- randomGenerator.NextBytes(result);
- if (useGmtUnixTime)
- {
- TlsUtilities.WriteGmtUnixTime(result, 0);
- }
- return result;
- }
- protected internal static byte[] CreateRenegotiationInfo(byte[] renegotiated_connection)
- {
- return TlsUtilities.EncodeOpaque8(renegotiated_connection);
- }
- protected internal static void EstablishMasterSecret(TlsContext context, TlsKeyExchange keyExchange)
- {
- byte[] pre_master_secret = keyExchange.GeneratePremasterSecret();
- try
- {
- context.SecurityParameters.masterSecret = TlsUtilities.CalculateMasterSecret(context, pre_master_secret);
- }
- finally
- {
- // TODO Is there a way to ensure the data is really overwritten?
- /*
- * RFC 2246 8.1. The pre_master_secret should be deleted from memory once the
- * master_secret has been computed.
- */
- if (pre_master_secret != null)
- {
- Arrays.Fill(pre_master_secret, (byte)0);
- }
- }
- }
- /**
- * 'sender' only relevant to SSLv3
- */
- protected internal static byte[] GetCurrentPrfHash(TlsContext context, TlsHandshakeHash handshakeHash, byte[] sslSender)
- {
- IDigest d = handshakeHash.ForkPrfHash();
- if (sslSender != null && TlsUtilities.IsSsl(context))
- {
- d.BlockUpdate(sslSender, 0, sslSender.Length);
- }
- return DigestUtilities.DoFinal(d);
- }
- protected internal static IDictionary ReadExtensions(MemoryStream input)
- {
- if (input.Position >= input.Length)
- return null;
- byte[] extBytes = TlsUtilities.ReadOpaque16(input);
- AssertEmpty(input);
- MemoryStream buf = new MemoryStream(extBytes, false);
- // Integer -> byte[]
- IDictionary extensions = Org.BouncyCastle.Utilities.Platform.CreateHashtable();
- while (buf.Position < buf.Length)
- {
- int extension_type = TlsUtilities.ReadUint16(buf);
- byte[] extension_data = TlsUtilities.ReadOpaque16(buf);
- /*
- * RFC 3546 2.3 There MUST NOT be more than one extension of the same type.
- */
- if (extensions.Contains(extension_type))
- throw new TlsFatalAlert(AlertDescription.illegal_parameter);
- extensions.Add(extension_type, extension_data);
- }
- return extensions;
- }
- protected internal static IList ReadSupplementalDataMessage(MemoryStream input)
- {
- byte[] supp_data = TlsUtilities.ReadOpaque24(input);
- AssertEmpty(input);
- MemoryStream buf = new MemoryStream(supp_data, false);
- IList supplementalData = Org.BouncyCastle.Utilities.Platform.CreateArrayList();
- while (buf.Position < buf.Length)
- {
- int supp_data_type = TlsUtilities.ReadUint16(buf);
- byte[] data = TlsUtilities.ReadOpaque16(buf);
- supplementalData.Add(new SupplementalDataEntry(supp_data_type, data));
- }
- return supplementalData;
- }
- protected internal static void WriteExtensions(Stream output, IDictionary extensions)
- {
- MemoryStream buf = new MemoryStream();
- /*
- * NOTE: There are reports of servers that don't accept a zero-length extension as the last
- * one, so we write out any zero-length ones first as a best-effort workaround.
- */
- WriteSelectedExtensions(buf, extensions, true);
- WriteSelectedExtensions(buf, extensions, false);
- byte[] extBytes = buf.ToArray();
- TlsUtilities.WriteOpaque16(extBytes, output);
- }
- protected internal static void WriteSelectedExtensions(Stream output, IDictionary extensions, bool selectEmpty)
- {
- foreach (int extension_type in extensions.Keys)
- {
- byte[] extension_data = (byte[])extensions[extension_type];
- if (selectEmpty == (extension_data.Length == 0))
- {
- TlsUtilities.CheckUint16(extension_type);
- TlsUtilities.WriteUint16(extension_type, output);
- TlsUtilities.WriteOpaque16(extension_data, output);
- }
- }
- }
- protected internal static void WriteSupplementalData(Stream output, IList supplementalData)
- {
- MemoryStream buf = new MemoryStream();
- foreach (SupplementalDataEntry entry in supplementalData)
- {
- int supp_data_type = entry.DataType;
- TlsUtilities.CheckUint16(supp_data_type);
- TlsUtilities.WriteUint16(supp_data_type, buf);
- TlsUtilities.WriteOpaque16(entry.Data, buf);
- }
- byte[] supp_data = buf.ToArray();
- TlsUtilities.WriteOpaque24(supp_data, output);
- }
- protected internal static int GetPrfAlgorithm(TlsContext context, int ciphersuite)
- {
- bool isTLSv12 = TlsUtilities.IsTlsV12(context);
- switch (ciphersuite)
- {
- case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256:
- case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256:
- case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256:
- case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA256:
- case CipherSuite.TLS_DH_DSS_WITH_AES_128_GCM_SHA256:
- case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA256:
- case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256:
- case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256:
- case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256:
- case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA256:
- case CipherSuite.TLS_DH_RSA_WITH_AES_128_GCM_SHA256:
- case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA256:
- case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
- case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
- case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256:
- case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:
- case CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:
- case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:
- case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256:
- case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256:
- case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256:
- case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CCM:
- case CipherSuite.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256:
- case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_AES_128_OCB:
- case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CCM:
- case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_AES_256_OCB:
- case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256:
- case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256:
- case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
- case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM:
- case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8:
- case CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
- case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_128_OCB:
- case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
- case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM:
- case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8:
- case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_256_OCB:
- case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
- case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
- case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256:
- case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
- case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
- case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
- case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
- case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
- case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
- case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
- case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
- case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
- case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_128_OCB:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8:
- case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_256_OCB:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
- case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
- case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_128_OCB:
- case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_256_OCB:
- case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256:
- case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
- case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
- case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_128_OCB:
- case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_256_OCB:
- case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
- case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
- case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
- case CipherSuite.TLS_PSK_DHE_WITH_AES_128_CCM_8:
- case CipherSuite.TLS_PSK_DHE_WITH_AES_256_CCM_8:
- case CipherSuite.TLS_PSK_WITH_AES_128_CCM:
- case CipherSuite.TLS_PSK_WITH_AES_128_CCM_8:
- case CipherSuite.TLS_PSK_WITH_AES_128_GCM_SHA256:
- case CipherSuite.DRAFT_TLS_PSK_WITH_AES_128_OCB:
- case CipherSuite.TLS_PSK_WITH_AES_256_CCM:
- case CipherSuite.TLS_PSK_WITH_AES_256_CCM_8:
- case CipherSuite.DRAFT_TLS_PSK_WITH_AES_256_OCB:
- case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256:
- case CipherSuite.DRAFT_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256:
- case CipherSuite.TLS_RSA_PSK_WITH_AES_128_GCM_SHA256:
- case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256:
- case CipherSuite.DRAFT_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256:
- case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256:
- case CipherSuite.TLS_RSA_WITH_AES_128_CCM:
- case CipherSuite.TLS_RSA_WITH_AES_128_CCM_8:
- case CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256:
- case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256:
- case CipherSuite.TLS_RSA_WITH_AES_256_CCM:
- case CipherSuite.TLS_RSA_WITH_AES_256_CCM_8:
- case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256:
- case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256:
- case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256:
- case CipherSuite.TLS_RSA_WITH_NULL_SHA256:
- {
- if (isTLSv12)
- {
- return PrfAlgorithm.tls_prf_sha256;
- }
- throw new TlsFatalAlert(AlertDescription.illegal_parameter);
- }
- case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_DH_DSS_WITH_AES_256_GCM_SHA384:
- case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_DH_RSA_WITH_AES_256_GCM_SHA384:
- case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384:
- case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_DHE_PSK_WITH_AES_256_GCM_SHA384:
- case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
- case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
- case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
- case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
- case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
- case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
- case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384:
- case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
- case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
- case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384:
- case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_PSK_WITH_AES_256_GCM_SHA384:
- case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_RSA_PSK_WITH_AES_256_GCM_SHA384:
- case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384:
- case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384:
- {
- if (isTLSv12)
- {
- return PrfAlgorithm.tls_prf_sha384;
- }
- throw new TlsFatalAlert(AlertDescription.illegal_parameter);
- }
- case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA384:
- case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
- case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA384:
- case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384:
- case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
- case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA384:
- case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA384:
- case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384:
- case CipherSuite.TLS_PSK_WITH_NULL_SHA384:
- case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA384:
- case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384:
- case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA384:
- {
- if (isTLSv12)
- {
- return PrfAlgorithm.tls_prf_sha384;
- }
- return PrfAlgorithm.tls_prf_legacy;
- }
- default:
- {
- if (isTLSv12)
- {
- return PrfAlgorithm.tls_prf_sha256;
- }
- return PrfAlgorithm.tls_prf_legacy;
- }
- }
- }
- internal class HandshakeMessage
- : MemoryStream
- {
- internal HandshakeMessage(byte handshakeType)
- : this(handshakeType, 60)
- {
- }
- internal HandshakeMessage(byte handshakeType, int length)
- : base(length + 4)
- {
- TlsUtilities.WriteUint8(handshakeType, this);
- // Reserve space for length
- TlsUtilities.WriteUint24(0, this);
- }
- internal void Write(byte[] data)
- {
- Write(data, 0, data.Length);
- }
- internal void WriteToRecordStream(TlsProtocol protocol)
- {
- // Patch actual length back in
- long length = Length - 4;
- TlsUtilities.CheckUint24(length);
- this.Position = 1;
- TlsUtilities.WriteUint24((int)length, this);
- #if PORTABLE || NETFX_CORE
- byte[] buf = ToArray();
- int bufLen = buf.Length;
- #else
- byte[] buf = GetBuffer();
- int bufLen = (int)Length;
- #endif
- protocol.WriteHandshakeMessage(buf, 0, bufLen);
- Org.BouncyCastle.Utilities.Platform.Dispose(this);
- }
- }
- }
- }
- #endif
|