diff options
author | Oren Novotny <oren@novotny.org> | 2017-05-20 14:30:13 -0400 |
---|---|---|
committer | Oren Novotny <oren@novotny.org> | 2017-05-20 14:30:13 -0400 |
commit | 20e8223cb0b11bb07da677242cbde2745616eb90 (patch) | |
tree | 1a3cddcdb84d6a92e1de86560beb053c21d2e1b1 | |
parent | Merge pull request #2 from ctaggart/SourceLink.2.1.0 (diff) | |
parent | Added validation of integer/enumerated encoding. (diff) | |
download | BouncyCastle.NET-ed25519-20e8223cb0b11bb07da677242cbde2745616eb90.tar.xz |
merge from master
34 files changed, 660 insertions, 232 deletions
diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj index 6f1fdcf61..fe6b5fa1c 100644 --- a/crypto/crypto.csproj +++ b/crypto/crypto.csproj @@ -5194,6 +5194,11 @@ BuildAction = "Compile" /> <File + RelPath = "src\crypto\tls\TlsNoCloseNotifyException.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File RelPath = "src\crypto\tls\TlsNullCipher.cs" SubType = "Code" BuildAction = "Compile" diff --git a/crypto/src/asn1/DerEnumerated.cs b/crypto/src/asn1/DerEnumerated.cs index 476b7fa9a..db27065bb 100644 --- a/crypto/src/asn1/DerEnumerated.cs +++ b/crypto/src/asn1/DerEnumerated.cs @@ -64,7 +64,18 @@ namespace Org.BouncyCastle.Asn1 public DerEnumerated( byte[] bytes) { - this.bytes = bytes; + if (bytes.Length > 1) + { + if (bytes[0] == 0 && (bytes[1] & 0x80) == 0) + { + throw new ArgumentException("malformed enumerated"); + } + if (bytes[0] == (byte)0xff && (bytes[1] & 0x80) != 0) + { + throw new ArgumentException("malformed enumerated"); + } + } + this.bytes = Arrays.Clone(bytes); } public BigInteger Value diff --git a/crypto/src/asn1/DerInteger.cs b/crypto/src/asn1/DerInteger.cs index 3610de588..5b240d281 100644 --- a/crypto/src/asn1/DerInteger.cs +++ b/crypto/src/asn1/DerInteger.cs @@ -70,7 +70,18 @@ namespace Org.BouncyCastle.Asn1 public DerInteger( byte[] bytes) { - this.bytes = bytes; + if (bytes.Length > 1) + { + if (bytes[0] == 0 && (bytes[1] & 0x80) == 0) + { + throw new ArgumentException("malformed integer"); + } + if (bytes[0] == (byte)0xff && (bytes[1] & 0x80) != 0) + { + throw new ArgumentException("malformed integer"); + } + } + this.bytes = Arrays.Clone(bytes); } public BigInteger Value diff --git a/crypto/src/asn1/x509/UserNotice.cs b/crypto/src/asn1/x509/UserNotice.cs index 5938f7c49..f40916434 100644 --- a/crypto/src/asn1/x509/UserNotice.cs +++ b/crypto/src/asn1/x509/UserNotice.cs @@ -58,6 +58,7 @@ namespace Org.BouncyCastle.Asn1.X509 * calling @{link toASN1Object()} for a <code>UserNotice</code> * instance or from parsing it from a DER-encoded stream.</p> */ + [Obsolete("Use GetInstance() instead")] public UserNotice( Asn1Sequence seq) { @@ -71,12 +72,19 @@ namespace Org.BouncyCastle.Asn1.X509 if (seq[0].ToAsn1Object() is Asn1Sequence) { noticeRef = NoticeReference.GetInstance(seq[0]); + explicitText = null; } else { + noticeRef = null; explicitText = DisplayText.GetInstance(seq[0]); } } + else if (seq.Count == 0) + { + noticeRef = null; // neither field set! + explicitText = null; + } else { throw new ArgumentException("Bad sequence size: " + seq.Count); diff --git a/crypto/src/crypto/macs/Poly1305.cs b/crypto/src/crypto/macs/Poly1305.cs index 0f66ccccc..c0a660fac 100644 --- a/crypto/src/crypto/macs/Poly1305.cs +++ b/crypto/src/crypto/macs/Poly1305.cs @@ -219,13 +219,13 @@ namespace Org.BouncyCastle.Crypto.Macs ulong tp3 = mul32x32_64(h0,r3) + mul32x32_64(h1,r2) + mul32x32_64(h2,r1) + mul32x32_64(h3,r0) + mul32x32_64(h4,s4); ulong tp4 = mul32x32_64(h0,r4) + mul32x32_64(h1,r3) + mul32x32_64(h2,r2) + mul32x32_64(h3,r1) + mul32x32_64(h4,r0); - ulong b; - h0 = (uint)tp0 & 0x3ffffff; b = (tp0 >> 26); - tp1 += b; h1 = (uint)tp1 & 0x3ffffff; b = (tp1 >> 26); - tp2 += b; h2 = (uint)tp2 & 0x3ffffff; b = (tp2 >> 26); - tp3 += b; h3 = (uint)tp3 & 0x3ffffff; b = (tp3 >> 26); - tp4 += b; h4 = (uint)tp4 & 0x3ffffff; b = (tp4 >> 26); - h0 += (uint)(b * 5); + h0 = (uint)tp0 & 0x3ffffff; tp1 += (tp0 >> 26); + h1 = (uint)tp1 & 0x3ffffff; tp2 += (tp1 >> 26); + h2 = (uint)tp2 & 0x3ffffff; tp3 += (tp2 >> 26); + h3 = (uint)tp3 & 0x3ffffff; tp4 += (tp3 >> 26); + h4 = (uint)tp4 & 0x3ffffff; + h0 += (uint)(tp4 >> 26) * 5; + h1 += (h0 >> 26); h0 &= 0x3ffffff; } public int DoFinal(byte[] output, int outOff) @@ -238,17 +238,14 @@ namespace Org.BouncyCastle.Crypto.Macs ProcessBlock(); } - ulong f0, f1, f2, f3; - - uint b = h0 >> 26; - h0 = h0 & 0x3ffffff; - h1 += b; b = h1 >> 26; h1 = h1 & 0x3ffffff; - h2 += b; b = h2 >> 26; h2 = h2 & 0x3ffffff; - h3 += b; b = h3 >> 26; h3 = h3 & 0x3ffffff; - h4 += b; b = h4 >> 26; h4 = h4 & 0x3ffffff; - h0 += b * 5; + h1 += (h0 >> 26); h0 &= 0x3ffffff; + h2 += (h1 >> 26); h1 &= 0x3ffffff; + h3 += (h2 >> 26); h2 &= 0x3ffffff; + h4 += (h3 >> 26); h3 &= 0x3ffffff; + h0 += (h4 >> 26) * 5; h4 &= 0x3ffffff; + h1 += (h0 >> 26); h0 &= 0x3ffffff; - uint g0, g1, g2, g3, g4; + uint g0, g1, g2, g3, g4, b; g0 = h0 + 5; b = g0 >> 26; g0 &= 0x3ffffff; g1 = h1 + b; b = g1 >> 26; g1 &= 0x3ffffff; g2 = h2 + b; b = g2 >> 26; g2 &= 0x3ffffff; @@ -263,6 +260,7 @@ namespace Org.BouncyCastle.Crypto.Macs h3 = (h3 & nb) | (g3 & b); h4 = (h4 & nb) | (g4 & b); + ulong f0, f1, f2, f3; f0 = ((h0 ) | (h1 << 26)) + (ulong)k0; f1 = ((h1 >> 6 ) | (h2 << 20)) + (ulong)k1; f2 = ((h2 >> 12) | (h3 << 14)) + (ulong)k2; diff --git a/crypto/src/crypto/tls/AbstractTlsKeyExchange.cs b/crypto/src/crypto/tls/AbstractTlsKeyExchange.cs index 09fb8782d..294b24929 100644 --- a/crypto/src/crypto/tls/AbstractTlsKeyExchange.cs +++ b/crypto/src/crypto/tls/AbstractTlsKeyExchange.cs @@ -38,7 +38,7 @@ namespace Org.BouncyCastle.Crypto.Tls if (TlsUtilities.IsSignatureAlgorithmsExtensionAllowed(clientVersion)) { /* - * RFC 5264 7.4.1.4.1. If the client does not send the signature_algorithms extension, + * RFC 5246 7.4.1.4.1. If the client does not send the signature_algorithms extension, * the server MUST do the following: * * - If the negotiated key exchange algorithm is one of (RSA, DHE_RSA, DH_RSA, RSA_PSK, @@ -106,14 +106,14 @@ namespace Org.BouncyCastle.Crypto.Tls if (mSupportedSignatureAlgorithms == null) { /* - * TODO RFC 2264 7.4.2. Unless otherwise specified, the signing algorithm for the + * TODO RFC 2246 7.4.2. Unless otherwise specified, the signing algorithm for the * certificate must be the same as the algorithm for the certificate key. */ } else { /* - * TODO RFC 5264 7.4.2. If the client provided a "signature_algorithms" extension, then + * TODO RFC 5246 7.4.2. If the client provided a "signature_algorithms" extension, then * all certificates provided by the server MUST be signed by a hash/signature algorithm * pair that appears in that extension. */ diff --git a/crypto/src/crypto/tls/AbstractTlsServer.cs b/crypto/src/crypto/tls/AbstractTlsServer.cs index d87a294f0..52a79c9d8 100644 --- a/crypto/src/crypto/tls/AbstractTlsServer.cs +++ b/crypto/src/crypto/tls/AbstractTlsServer.cs @@ -194,11 +194,12 @@ namespace Org.BouncyCastle.Crypto.Tls public virtual int GetSelectedCipherSuite() { /* - * TODO RFC 5246 7.4.3. In order to negotiate correctly, the server MUST check any candidate + * RFC 5246 7.4.3. In order to negotiate correctly, the server MUST check any candidate * cipher suites against the "signature_algorithms" extension before selecting them. This is * somewhat inelegant but is a compromise designed to minimize changes to the original * cipher suite design. */ + IList sigAlgs = TlsUtilities.GetUsableSignatureAlgorithms(this.mSupportedSignatureAlgorithms); /* * RFC 4429 5.1. A server that receives a ClientHello containing one or both of these @@ -216,7 +217,8 @@ namespace Org.BouncyCastle.Crypto.Tls if (Arrays.Contains(this.mOfferedCipherSuites, cipherSuite) && (eccCipherSuitesEnabled || !TlsEccUtilities.IsEccCipherSuite(cipherSuite)) - && TlsUtilities.IsValidCipherSuiteForVersion(cipherSuite, mServerVersion)) + && TlsUtilities.IsValidCipherSuiteForVersion(cipherSuite, mServerVersion) + && TlsUtilities.IsValidCipherSuiteForSignatureAlgorithms(cipherSuite, sigAlgs)) { return this.mSelectedCipherSuite = cipherSuite; } diff --git a/crypto/src/crypto/tls/ByteQueue.cs b/crypto/src/crypto/tls/ByteQueue.cs index f9398bbaf..b4df6850e 100644 --- a/crypto/src/crypto/tls/ByteQueue.cs +++ b/crypto/src/crypto/tls/ByteQueue.cs @@ -1,4 +1,5 @@ using System; +using System.IO; namespace Org.BouncyCastle.Crypto.Tls { @@ -47,6 +48,8 @@ namespace Org.BouncyCastle.Crypto.Tls */ private int available = 0; + private bool readOnlyBuf = false; + public ByteQueue() : this(DefaultCapacity) { @@ -54,29 +57,15 @@ namespace Org.BouncyCastle.Crypto.Tls public ByteQueue(int capacity) { - this.databuf = new byte[capacity]; + this.databuf = capacity == 0 ? TlsUtilities.EmptyBytes : new byte[capacity]; } - /// <summary>Read data from the buffer.</summary> - /// <param name="buf">The buffer where the read data will be copied to.</param> - /// <param name="offset">How many bytes to skip at the beginning of buf.</param> - /// <param name="len">How many bytes to read at all.</param> - /// <param name="skip">How many bytes from our data to skip.</param> - public void Read( - byte[] buf, - int offset, - int len, - int skip) + public ByteQueue(byte[] buf, int off, int len) { - if ((buf.Length - offset) < len) - { - throw new ArgumentException("Buffer size of " + buf.Length + " is too small for a read of " + len + " bytes"); - } - if ((available - skip) < len) - { - throw new InvalidOperationException("Not enough data to read"); - } - Array.Copy(databuf, skipped + skip, buf, offset, len); + this.databuf = buf; + this.skipped = off; + this.available = len; + this.readOnlyBuf = true; } /// <summary>Add some data to our buffer.</summary> @@ -84,10 +73,13 @@ namespace Org.BouncyCastle.Crypto.Tls /// <param name="offset">How many bytes to skip at the beginning of the array.</param> /// <param name="len">How many bytes to read from the array.</param> public void AddData( - byte[] data, - int offset, - int len) + byte[] data, + int offset, + int len) { + if (readOnlyBuf) + throw new InvalidOperationException("Cannot add data to read-only buffer"); + if ((skipped + available + len) > databuf.Length) { int desiredSize = ByteQueue.NextTwoPow(available + len); @@ -108,6 +100,64 @@ namespace Org.BouncyCastle.Crypto.Tls available += len; } + /// <summary>The number of bytes which are available in this buffer.</summary> + public int Available + { + get { return available; } + } + + /// <summary>Copy some bytes from the beginning of the data to the provided <c cref="Stream">Stream</c>.</summary> + /// <param name="output">The <c cref="Stream">Stream</c> to copy the bytes to.</param> + /// <param name="length">How many bytes to copy.</param> + /// <exception cref="InvalidOperationException">If insufficient data is available.</exception> + /// <exception cref="IOException">If there is a problem copying the data.</exception> + public void CopyTo(Stream output, int length) + { + if (length > available) + throw new InvalidOperationException("Cannot copy " + length + " bytes, only got " + available); + + output.Write(databuf, skipped, length); + } + + /// <summary>Read data from the buffer.</summary> + /// <param name="buf">The buffer where the read data will be copied to.</param> + /// <param name="offset">How many bytes to skip at the beginning of buf.</param> + /// <param name="len">How many bytes to read at all.</param> + /// <param name="skip">How many bytes from our data to skip.</param> + public void Read( + byte[] buf, + int offset, + int len, + int skip) + { + if ((buf.Length - offset) < len) + { + throw new ArgumentException("Buffer size of " + buf.Length + " is too small for a read of " + len + " bytes"); + } + if ((available - skip) < len) + { + throw new InvalidOperationException("Not enough data to read"); + } + Array.Copy(databuf, skipped + skip, buf, offset, len); + } + + /// <summary>Return a <c cref="MemoryStream">MemoryStream</c> over some bytes at the beginning of the data.</summary> + /// <param name="length">How many bytes will be readable.</param> + /// <returns>A <c cref="MemoryStream">MemoryStream</c> over the data.</returns> + /// <exception cref="InvalidOperationException">If insufficient data is available.</exception> + public MemoryStream ReadFrom(int length) + { + if (length > available) + throw new InvalidOperationException("Cannot read " + length + " bytes, only got " + available); + + int position = skipped; + + available -= length; + skipped += length; + + return new MemoryStream(databuf, position, length, false); + } + /// <summary>Remove some bytes from our data from the beginning.</summary> /// <param name="i">How many bytes to remove.</param> public void RemoveData( @@ -138,10 +188,24 @@ namespace Org.BouncyCastle.Crypto.Tls return buf; } - /// <summary>The number of bytes which are available in this buffer.</summary> - public int Available + public void Shrink() { - get { return available; } + if (available == 0) + { + databuf = TlsUtilities.EmptyBytes; + skipped = 0; + } + else + { + int desiredSize = ByteQueue.NextTwoPow(available); + if (desiredSize < databuf.Length) + { + byte[] tmp = new byte[desiredSize]; + Array.Copy(databuf, skipped, tmp, 0, available); + databuf = tmp; + skipped = 0; + } + } } } } diff --git a/crypto/src/crypto/tls/CertificateUrl.cs b/crypto/src/crypto/tls/CertificateUrl.cs index d285fa0f6..aff999551 100644 --- a/crypto/src/crypto/tls/CertificateUrl.cs +++ b/crypto/src/crypto/tls/CertificateUrl.cs @@ -3,6 +3,7 @@ using System.Collections; using System.IO; using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.IO; namespace Org.BouncyCastle.Crypto.Tls { @@ -116,7 +117,7 @@ namespace Org.BouncyCastle.Crypto.Tls TlsUtilities.CheckUint16(length); this.Position = 0; TlsUtilities.WriteUint16((int)length, this); - this.WriteTo(output); + Streams.WriteBufTo(this, output); Platform.Dispose(this); } } diff --git a/crypto/src/crypto/tls/DefaultTlsClient.cs b/crypto/src/crypto/tls/DefaultTlsClient.cs index 7dadf8a1a..32a86e503 100644 --- a/crypto/src/crypto/tls/DefaultTlsClient.cs +++ b/crypto/src/crypto/tls/DefaultTlsClient.cs @@ -52,6 +52,7 @@ namespace Org.BouncyCastle.Crypto.Tls switch (keyExchangeAlgorithm) { + case KeyExchangeAlgorithm.DH_anon: case KeyExchangeAlgorithm.DH_DSS: case KeyExchangeAlgorithm.DH_RSA: return CreateDHKeyExchange(keyExchangeAlgorithm); diff --git a/crypto/src/crypto/tls/DefaultTlsServer.cs b/crypto/src/crypto/tls/DefaultTlsServer.cs index 44ceb30e3..8b9a7c9a0 100644 --- a/crypto/src/crypto/tls/DefaultTlsServer.cs +++ b/crypto/src/crypto/tls/DefaultTlsServer.cs @@ -42,7 +42,7 @@ namespace Org.BouncyCastle.Crypto.Tls protected virtual DHParameters GetDHParameters() { - return DHStandardGroups.rfc5114_2048_256; + return DHStandardGroups.rfc3526_2048; } protected override int[] GetCipherSuites() @@ -79,6 +79,7 @@ namespace Org.BouncyCastle.Crypto.Tls case KeyExchangeAlgorithm.DHE_DSS: return GetDsaSignerCredentials(); + case KeyExchangeAlgorithm.DH_anon: case KeyExchangeAlgorithm.ECDH_anon: return null; @@ -104,6 +105,7 @@ namespace Org.BouncyCastle.Crypto.Tls switch (keyExchangeAlgorithm) { + case KeyExchangeAlgorithm.DH_anon: case KeyExchangeAlgorithm.DH_DSS: case KeyExchangeAlgorithm.DH_RSA: return CreateDHKeyExchange(keyExchangeAlgorithm); diff --git a/crypto/src/crypto/tls/DigestInputBuffer.cs b/crypto/src/crypto/tls/DigestInputBuffer.cs index 547bcab54..4435b40a5 100644 --- a/crypto/src/crypto/tls/DigestInputBuffer.cs +++ b/crypto/src/crypto/tls/DigestInputBuffer.cs @@ -1,8 +1,6 @@ using System; using System.IO; -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Crypto.IO; using Org.BouncyCastle.Utilities.IO; namespace Org.BouncyCastle.Crypto.Tls @@ -12,7 +10,7 @@ namespace Org.BouncyCastle.Crypto.Tls { internal void UpdateDigest(IDigest d) { - WriteTo(new DigStream(d)); + Streams.WriteBufTo(this, new DigStream(d)); } private class DigStream diff --git a/crypto/src/crypto/tls/DtlsClientProtocol.cs b/crypto/src/crypto/tls/DtlsClientProtocol.cs index 90430d772..ae6e6a573 100644 --- a/crypto/src/crypto/tls/DtlsClientProtocol.cs +++ b/crypto/src/crypto/tls/DtlsClientProtocol.cs @@ -776,7 +776,7 @@ namespace Org.BouncyCastle.Crypto.Tls securityParameters.CipherSuite); /* - * RFC 5264 7.4.9. Any cipher suite which does not explicitly specify verify_data_length has + * RFC 5246 7.4.9. Any cipher suite which does not explicitly specify verify_data_length has * a verify_data_length equal to 12. This includes all existing cipher suites. */ securityParameters.verifyDataLength = 12; diff --git a/crypto/src/crypto/tls/DtlsRecordLayer.cs b/crypto/src/crypto/tls/DtlsRecordLayer.cs index 4a781b5b5..3c3e1821f 100644 --- a/crypto/src/crypto/tls/DtlsRecordLayer.cs +++ b/crypto/src/crypto/tls/DtlsRecordLayer.cs @@ -491,7 +491,7 @@ namespace Org.BouncyCastle.Crypto.Tls throw new TlsFatalAlert(AlertDescription.internal_error); /* - * RFC 5264 6.2.1 Implementations MUST NOT send zero-length fragments of Handshake, Alert, + * RFC 5246 6.2.1 Implementations MUST NOT send zero-length fragments of Handshake, Alert, * or ChangeCipherSpec content types. */ if (len < 1 && contentType != ContentType.application_data) diff --git a/crypto/src/crypto/tls/DtlsServerProtocol.cs b/crypto/src/crypto/tls/DtlsServerProtocol.cs index fbf33045b..3032269d1 100644 --- a/crypto/src/crypto/tls/DtlsServerProtocol.cs +++ b/crypto/src/crypto/tls/DtlsServerProtocol.cs @@ -425,7 +425,7 @@ namespace Org.BouncyCastle.Crypto.Tls securityParameters.CipherSuite); /* - * RFC 5264 7.4.9. Any cipher suite which does not explicitly specify verify_data_length + * RFC 5246 7.4.9. Any cipher suite which does not explicitly specify verify_data_length * has a verify_data_length equal to 12. This includes all existing cipher suites. */ securityParameters.verifyDataLength = 12; diff --git a/crypto/src/crypto/tls/OcspStatusRequest.cs b/crypto/src/crypto/tls/OcspStatusRequest.cs index 2dd8371e5..d9203a3c4 100644 --- a/crypto/src/crypto/tls/OcspStatusRequest.cs +++ b/crypto/src/crypto/tls/OcspStatusRequest.cs @@ -6,6 +6,7 @@ using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.Ocsp; using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.IO; namespace Org.BouncyCastle.Crypto.Tls { @@ -71,7 +72,7 @@ namespace Org.BouncyCastle.Crypto.Tls } TlsUtilities.CheckUint16(buf.Length); TlsUtilities.WriteUint16((int)buf.Length, output); - buf.WriteTo(output); + Streams.WriteBufTo(buf, output); } if (mRequestExtensions == null) diff --git a/crypto/src/crypto/tls/PskTlsServer.cs b/crypto/src/crypto/tls/PskTlsServer.cs index 85f3055fb..d6f54db1f 100644 --- a/crypto/src/crypto/tls/PskTlsServer.cs +++ b/crypto/src/crypto/tls/PskTlsServer.cs @@ -28,7 +28,7 @@ namespace Org.BouncyCastle.Crypto.Tls protected virtual DHParameters GetDHParameters() { - return DHStandardGroups.rfc5114_2048_256; + return DHStandardGroups.rfc3526_2048; } protected override int[] GetCipherSuites() diff --git a/crypto/src/crypto/tls/RecordStream.cs b/crypto/src/crypto/tls/RecordStream.cs index d510ed94e..46673cf7e 100644 --- a/crypto/src/crypto/tls/RecordStream.cs +++ b/crypto/src/crypto/tls/RecordStream.cs @@ -2,6 +2,7 @@ using System; using System.IO; using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.IO; namespace Org.BouncyCastle.Crypto.Tls { @@ -24,6 +25,7 @@ namespace Org.BouncyCastle.Crypto.Tls private MemoryStream mBuffer = new MemoryStream(); private TlsHandshakeHash mHandshakeHash = null; + private readonly BaseOutputStream mHandshakeHashUpdater; private ProtocolVersion mReadVersion = null, mWriteVersion = null; private bool mRestrictReadVersion = true; @@ -37,6 +39,7 @@ namespace Org.BouncyCastle.Crypto.Tls this.mOutput = output; this.mReadCompression = new TlsNullCompression(); this.mWriteCompression = this.mReadCompression; + this.mHandshakeHashUpdater = new HandshakeHashUpdateStream(this); } internal virtual void Init(TlsContext context) @@ -121,6 +124,40 @@ namespace Org.BouncyCastle.Crypto.Tls this.mPendingCipher = null; } + internal virtual void CheckRecordHeader(byte[] recordHeader) + { + byte type = TlsUtilities.ReadUint8(recordHeader, TLS_HEADER_TYPE_OFFSET); + + /* + * RFC 5246 6. If a TLS implementation receives an unexpected record type, it MUST send an + * unexpected_message alert. + */ + CheckType(type, AlertDescription.unexpected_message); + + if (!mRestrictReadVersion) + { + int version = TlsUtilities.ReadVersionRaw(recordHeader, TLS_HEADER_VERSION_OFFSET); + if ((version & 0xffffff00) != 0x0300) + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + else + { + ProtocolVersion version = TlsUtilities.ReadVersion(recordHeader, TLS_HEADER_VERSION_OFFSET); + if (mReadVersion == null) + { + // Will be set later in 'readRecord' + } + else if (!version.Equals(mReadVersion)) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + } + + int length = TlsUtilities.ReadUint16(recordHeader, TLS_HEADER_LENGTH_OFFSET); + + CheckLength(length, mCiphertextLimit, AlertDescription.record_overflow); + } + internal virtual bool ReadRecord() { byte[] recordHeader = TlsUtilities.ReadAllOrNothing(TLS_HEADER_SIZE, mInput); @@ -155,6 +192,9 @@ namespace Org.BouncyCastle.Crypto.Tls } int length = TlsUtilities.ReadUint16(recordHeader, TLS_HEADER_LENGTH_OFFSET); + + CheckLength(length, mCiphertextLimit, AlertDescription.record_overflow); + byte[] plaintext = DecodeAndVerify(type, mInput, length); mHandler.ProcessRecord(type, plaintext, 0, plaintext.Length); return true; @@ -162,15 +202,13 @@ namespace Org.BouncyCastle.Crypto.Tls internal virtual byte[] DecodeAndVerify(byte type, Stream input, int len) { - CheckLength(len, mCiphertextLimit, AlertDescription.record_overflow); - byte[] buf = TlsUtilities.ReadFully(len, input); byte[] decoded = mReadCipher.DecodeCiphertext(mReadSeqNo++, type, buf, 0, buf.Length); CheckLength(decoded.Length, mCompressedLimit, AlertDescription.record_overflow); /* - * TODO RFC5264 6.2.2. Implementation note: Decompression functions are responsible for + * TODO 5246 6.2.2. Implementation note: Decompression functions are responsible for * ensuring that messages cannot cause internal buffer overflows. */ Stream cOut = mReadCompression.Decompress(mBuffer); @@ -182,14 +220,14 @@ namespace Org.BouncyCastle.Crypto.Tls } /* - * RFC 5264 6.2.2. If the decompression function encounters a TLSCompressed.fragment that + * RFC 5246 6.2.2. If the decompression function encounters a TLSCompressed.fragment that * would decompress to a length in excess of 2^14 bytes, it should report a fatal * decompression failure error. */ CheckLength(decoded.Length, mPlaintextLimit, AlertDescription.decompression_failure); /* - * RFC 5264 6.2.1 Implementations MUST NOT send zero-length fragments of Handshake, Alert, + * RFC 5246 6.2.1 Implementations MUST NOT send zero-length fragments of Handshake, Alert, * or ChangeCipherSpec content types. */ if (decoded.Length < 1 && type != ContentType.application_data) @@ -205,28 +243,23 @@ namespace Org.BouncyCastle.Crypto.Tls return; /* - * RFC 5264 6. Implementations MUST NOT send record types not defined in this document + * RFC 5246 6. Implementations MUST NOT send record types not defined in this document * unless negotiated by some extension. */ CheckType(type, AlertDescription.internal_error); /* - * RFC 5264 6.2.1 The length should not exceed 2^14. + * RFC 5246 6.2.1 The length should not exceed 2^14. */ CheckLength(plaintextLength, mPlaintextLimit, AlertDescription.internal_error); /* - * RFC 5264 6.2.1 Implementations MUST NOT send zero-length fragments of Handshake, Alert, + * RFC 5246 6.2.1 Implementations MUST NOT send zero-length fragments of Handshake, Alert, * or ChangeCipherSpec content types. */ if (plaintextLength < 1 && type != ContentType.application_data) throw new TlsFatalAlert(AlertDescription.internal_error); - if (type == ContentType.handshake) - { - UpdateHandshakeData(plaintext, plaintextOffset, plaintextLength); - } - Stream cOut = mWriteCompression.Compress(mBuffer); byte[] ciphertext; @@ -241,7 +274,7 @@ namespace Org.BouncyCastle.Crypto.Tls byte[] compressed = GetBufferContents(); /* - * RFC5264 6.2.2. Compression must be lossless and may not increase the content length + * RFC 5246 6.2.2. Compression must be lossless and may not increase the content length * by more than 1024 bytes. */ CheckLength(compressed.Length, plaintextLength + 1024, AlertDescription.internal_error); @@ -250,7 +283,7 @@ namespace Org.BouncyCastle.Crypto.Tls } /* - * RFC 5264 6.2.3. The length may not exceed 2^14 + 2048. + * RFC 5246 6.2.3. The length may not exceed 2^14 + 2048. */ CheckLength(ciphertext.Length, mCiphertextLimit, AlertDescription.internal_error); @@ -273,6 +306,11 @@ namespace Org.BouncyCastle.Crypto.Tls get { return mHandshakeHash; } } + internal virtual Stream HandshakeHashUpdater + { + get { return mHandshakeHashUpdater; } + } + internal virtual TlsHandshakeHash PrepareToFinish() { TlsHandshakeHash result = mHandshakeHash; @@ -280,11 +318,6 @@ namespace Org.BouncyCastle.Crypto.Tls return result; } - internal virtual void UpdateHandshakeData(byte[] message, int offset, int len) - { - mHandshakeHash.BlockUpdate(message, offset, len); - } - internal virtual void SafeClose() { try @@ -324,7 +357,7 @@ namespace Org.BouncyCastle.Crypto.Tls case ContentType.alert: case ContentType.change_cipher_spec: case ContentType.handshake: - case ContentType.heartbeat: + //case ContentType.heartbeat: break; default: throw new TlsFatalAlert(alertDescription); @@ -336,5 +369,20 @@ namespace Org.BouncyCastle.Crypto.Tls if (length > limit) throw new TlsFatalAlert(alertDescription); } + + private class HandshakeHashUpdateStream + : BaseOutputStream + { + private readonly RecordStream mOuter; + public HandshakeHashUpdateStream(RecordStream mOuter) + { + this.mOuter = mOuter; + } + + public override void Write(byte[] buf, int off, int len) + { + mOuter.mHandshakeHash.BlockUpdate(buf, off, len); + } + } } } diff --git a/crypto/src/crypto/tls/ServerNameList.cs b/crypto/src/crypto/tls/ServerNameList.cs index 5b5b90e58..ed4e59359 100644 --- a/crypto/src/crypto/tls/ServerNameList.cs +++ b/crypto/src/crypto/tls/ServerNameList.cs @@ -3,6 +3,7 @@ using System.Collections; using System.IO; using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.IO; namespace Org.BouncyCastle.Crypto.Tls { @@ -52,7 +53,7 @@ namespace Org.BouncyCastle.Crypto.Tls TlsUtilities.CheckUint16(buf.Length); TlsUtilities.WriteUint16((int)buf.Length, output); - buf.WriteTo(output); + Streams.WriteBufTo(buf, output); } /** diff --git a/crypto/src/crypto/tls/SignerInputBuffer.cs b/crypto/src/crypto/tls/SignerInputBuffer.cs index ef2827c4d..7bc69624c 100644 --- a/crypto/src/crypto/tls/SignerInputBuffer.cs +++ b/crypto/src/crypto/tls/SignerInputBuffer.cs @@ -1,8 +1,6 @@ using System; using System.IO; -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Crypto.IO; using Org.BouncyCastle.Utilities.IO; namespace Org.BouncyCastle.Crypto.Tls @@ -12,7 +10,7 @@ namespace Org.BouncyCastle.Crypto.Tls { internal void UpdateSigner(ISigner s) { - WriteTo(new SigStream(s)); + Streams.WriteBufTo(this, new SigStream(s)); } private class SigStream diff --git a/crypto/src/crypto/tls/TlsClientProtocol.cs b/crypto/src/crypto/tls/TlsClientProtocol.cs index 4c2a0a545..0ea84c05c 100644 --- a/crypto/src/crypto/tls/TlsClientProtocol.cs +++ b/crypto/src/crypto/tls/TlsClientProtocol.cs @@ -135,10 +135,8 @@ namespace Org.BouncyCastle.Crypto.Tls get { return mTlsClient; } } - protected override void HandleHandshakeMessage(byte type, byte[] data) + protected override void HandleHandshakeMessage(byte type, MemoryStream buf) { - MemoryStream buf = new MemoryStream(data, false); - if (this.mResumedSession) { if (type != HandshakeType.finished || this.mConnectionState != CS_SERVER_HELLO) @@ -149,7 +147,6 @@ namespace Org.BouncyCastle.Crypto.Tls SendFinishedMessage(); this.mConnectionState = CS_CLIENT_FINISHED; - this.mConnectionState = CS_END; CompleteHandshake(); return; @@ -243,7 +240,6 @@ namespace Org.BouncyCastle.Crypto.Tls ProcessFinishedMessage(buf); this.mConnectionState = CS_SERVER_FINISHED; - this.mConnectionState = CS_END; CompleteHandshake(); break; @@ -384,10 +380,19 @@ namespace Org.BouncyCastle.Crypto.Tls SendClientKeyExchangeMessage(); this.mConnectionState = CS_CLIENT_KEY_EXCHANGE; + if (TlsUtilities.IsSsl(Context)) + { + EstablishMasterSecret(Context, mKeyExchange); + } + TlsHandshakeHash prepareFinishHash = mRecordStream.PrepareToFinish(); this.mSecurityParameters.sessionHash = GetCurrentPrfHash(Context, prepareFinishHash, null); - EstablishMasterSecret(Context, mKeyExchange); + if (!TlsUtilities.IsSsl(Context)) + { + EstablishMasterSecret(Context, mKeyExchange); + } + mRecordStream.SetPendingConnectionState(Peer.GetCompression(), Peer.GetCipher()); if (clientCreds != null && clientCreds is TlsSignerCredentials) @@ -422,7 +427,7 @@ namespace Org.BouncyCastle.Crypto.Tls break; } default: - throw new TlsFatalAlert(AlertDescription.handshake_failure); + throw new TlsFatalAlert(AlertDescription.unexpected_message); } this.mConnectionState = CS_CLIENT_FINISHED; @@ -785,7 +790,7 @@ namespace Org.BouncyCastle.Crypto.Tls this.mSecurityParameters.prfAlgorithm = GetPrfAlgorithm(Context, this.mSecurityParameters.CipherSuite); /* - * RFC 5264 7.4.9. Any cipher suite which does not explicitly specify + * RFC 5246 7.4.9. Any cipher suite which does not explicitly specify * verify_data_length has a verify_data_length equal to 12. This includes all * existing cipher suites. */ diff --git a/crypto/src/crypto/tls/TlsDHKeyExchange.cs b/crypto/src/crypto/tls/TlsDHKeyExchange.cs index 93ef1fa4a..eec9daaca 100644 --- a/crypto/src/crypto/tls/TlsDHKeyExchange.cs +++ b/crypto/src/crypto/tls/TlsDHKeyExchange.cs @@ -27,6 +27,7 @@ namespace Org.BouncyCastle.Crypto.Tls { switch (keyExchange) { + case KeyExchangeAlgorithm.DH_anon: case KeyExchangeAlgorithm.DH_RSA: case KeyExchangeAlgorithm.DH_DSS: this.mTlsSigner = null; @@ -56,11 +57,14 @@ namespace Org.BouncyCastle.Crypto.Tls public override void SkipServerCredentials() { - throw new TlsFatalAlert(AlertDescription.unexpected_message); + if (mKeyExchange != KeyExchangeAlgorithm.DH_anon) + throw new TlsFatalAlert(AlertDescription.unexpected_message); } public override void ProcessServerCertificate(Certificate serverCertificate) { + if (mKeyExchange == KeyExchangeAlgorithm.DH_anon) + throw new TlsFatalAlert(AlertDescription.unexpected_message); if (serverCertificate.IsEmpty) throw new TlsFatalAlert(AlertDescription.bad_certificate); @@ -109,9 +113,9 @@ namespace Org.BouncyCastle.Crypto.Tls { switch (mKeyExchange) { + case KeyExchangeAlgorithm.DH_anon: case KeyExchangeAlgorithm.DHE_DSS: case KeyExchangeAlgorithm.DHE_RSA: - case KeyExchangeAlgorithm.DH_anon: return true; default: return false; @@ -119,6 +123,32 @@ namespace Org.BouncyCastle.Crypto.Tls } } + public override byte[] GenerateServerKeyExchange() + { + if (!RequiresServerKeyExchange) + return null; + + // DH_anon is handled here, DHE_* in a subclass + + MemoryStream buf = new MemoryStream(); + this.mDHAgreePrivateKey = TlsDHUtilities.GenerateEphemeralServerKeyExchange(mContext.SecureRandom, + this.mDHParameters, buf); + return buf.ToArray(); + } + + public override void ProcessServerKeyExchange(Stream input) + { + if (!RequiresServerKeyExchange) + throw new TlsFatalAlert(AlertDescription.unexpected_message); + + // DH_anon is handled here, DHE_* in a subclass + + ServerDHParams dhParams = ServerDHParams.Parse(input); + + this.mDHAgreePublicKey = TlsDHUtilities.ValidateDHPublicKey(dhParams.PublicKey); + this.mDHParameters = ValidateDHParameters(mDHAgreePublicKey.Parameters); + } + public override void ValidateCertificateRequest(CertificateRequest certificateRequest) { byte[] types = certificateRequest.CertificateTypes; @@ -140,6 +170,9 @@ namespace Org.BouncyCastle.Crypto.Tls public override void ProcessClientCredentials(TlsCredentials clientCredentials) { + if (mKeyExchange == KeyExchangeAlgorithm.DH_anon) + throw new TlsFatalAlert(AlertDescription.internal_error); + if (clientCredentials is TlsAgreementCredentials) { // TODO Validate client cert has matching parameters (see 'areCompatibleParameters')? @@ -172,12 +205,11 @@ namespace Org.BouncyCastle.Crypto.Tls public override void ProcessClientCertificate(Certificate clientCertificate) { - // TODO Extract the public key and validate + if (mKeyExchange == KeyExchangeAlgorithm.DH_anon) + throw new TlsFatalAlert(AlertDescription.unexpected_message); - /* - * TODO If the certificate is 'fixed', take the public key as dhAgreePublicKey and check - * that the parameters match the server's (see 'areCompatibleParameters'). - */ + // TODO Extract the public key + // TODO If the certificate is 'fixed', take the public key as dhAgreePublicKey } public override void ProcessClientKeyExchange(Stream input) diff --git a/crypto/src/crypto/tls/TlsNoCloseNotifyException.cs b/crypto/src/crypto/tls/TlsNoCloseNotifyException.cs new file mode 100644 index 000000000..72159ba47 --- /dev/null +++ b/crypto/src/crypto/tls/TlsNoCloseNotifyException.cs @@ -0,0 +1,19 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Crypto.Tls +{ + /// <summary> + /// This exception will be thrown(only) when the connection is closed by the peer without sending a + /// <code cref="AlertDescription.close_notify">close_notify</code> warning alert. + /// </summary> + /// <remarks> + /// If this happens, the TLS protocol cannot rule out truncation of the connection data (potentially + /// malicious). It may be possible to check for truncation via some property of a higher level protocol + /// built upon TLS, e.g.the Content-Length header for HTTPS. + /// </remarks> + public class TlsNoCloseNotifyException + : EndOfStreamException + { + } +} diff --git a/crypto/src/crypto/tls/TlsProtocol.cs b/crypto/src/crypto/tls/TlsProtocol.cs index 6d5c93f40..490580fad 100644 --- a/crypto/src/crypto/tls/TlsProtocol.cs +++ b/crypto/src/crypto/tls/TlsProtocol.cs @@ -43,9 +43,9 @@ namespace Org.BouncyCastle.Crypto.Tls /* * Queues for data from some protocols. */ - private ByteQueue mApplicationDataQueue = new ByteQueue(); + private ByteQueue mApplicationDataQueue = new ByteQueue(0); private ByteQueue mAlertQueue = new ByteQueue(2); - private ByteQueue mHandshakeQueue = new ByteQueue(); + private ByteQueue mHandshakeQueue = new ByteQueue(0); // private ByteQueue mHeartbeatQueue = new ByteQueue(); /* @@ -114,7 +114,7 @@ namespace Org.BouncyCastle.Crypto.Tls { } - protected abstract void HandleHandshakeMessage(byte type, byte[] buf); + protected abstract void HandleHandshakeMessage(byte type, MemoryStream buf); protected virtual void HandleWarningMessage(byte description) { @@ -169,7 +169,8 @@ namespace Org.BouncyCastle.Crypto.Tls { if (this.mClosed) { - // TODO What kind of exception/alert? + // NOTE: Any close during the handshake should have raised an exception. + throw new TlsFatalAlert(AlertDescription.internal_error); } SafeReadRecord(); @@ -181,6 +182,11 @@ namespace Org.BouncyCastle.Crypto.Tls { try { + this.mConnectionState = CS_END; + + this.mAlertQueue.Shrink(); + this.mHandshakeQueue.Shrink(); + this.mRecordStream.FinaliseHandshake(); this.mAppDataSplitEnabled = !TlsUtilities.IsTlsV11(Context); @@ -227,7 +233,7 @@ namespace Org.BouncyCastle.Crypto.Tls } } - protected internal void ProcessRecord(byte protocol, byte[] buf, int offset, int len) + protected internal void ProcessRecord(byte protocol, byte[] buf, int off, int len) { /* * Have a look at the protocol type, and add it to the correct queue. @@ -236,8 +242,8 @@ namespace Org.BouncyCastle.Crypto.Tls { case ContentType.alert: { - mAlertQueue.AddData(buf, offset, len); - ProcessAlert(); + mAlertQueue.AddData(buf, off, len); + ProcessAlertQueue(); break; } case ContentType.application_data: @@ -245,107 +251,108 @@ namespace Org.BouncyCastle.Crypto.Tls if (!mAppDataReady) throw new TlsFatalAlert(AlertDescription.unexpected_message); - mApplicationDataQueue.AddData(buf, offset, len); - ProcessApplicationData(); + mApplicationDataQueue.AddData(buf, off, len); + ProcessApplicationDataQueue(); break; } case ContentType.change_cipher_spec: { - ProcessChangeCipherSpec(buf, offset, len); + ProcessChangeCipherSpec(buf, off, 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(); + if (mHandshakeQueue.Available > 0) + { + mHandshakeQueue.AddData(buf, off, len); + ProcessHandshakeQueue(mHandshakeQueue); + } + else + { + ByteQueue tmpQueue = new ByteQueue(buf, off, len); + ProcessHandshakeQueue(tmpQueue); + int remaining = tmpQueue.Available; + if (remaining > 0) + { + mHandshakeQueue.AddData(buf, off + len - remaining, remaining); + } + } 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; + // Record type should already have been checked + throw new TlsFatalAlert(AlertDescription.internal_error); } } - private void ProcessHandshake() + private void ProcessHandshakeQueue(ByteQueue queue) { - bool read; - do + while (queue.Available >= 4) { - 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); + byte[] beginning = new byte[4]; + queue.Read(beginning, 0, 4, 0); + byte type = TlsUtilities.ReadUint8(beginning, 0); + int length = TlsUtilities.ReadUint24(beginning, 1); + int totalLength = 4 + length; - /* - * 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); + /* + * Check if we have enough bytes in the buffer to read the full message. + */ + if (queue.Available < totalLength) + break; - /* - * 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; - } - } + CheckReceivedChangeCipherSpec(mConnectionState == CS_END || type == HandshakeType.finished); - /* - * Now, parse the message. - */ - HandleHandshakeMessage(type, buf); - read = true; + /* + * 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); } + + queue.CopyTo(mRecordStream.HandshakeHashUpdater, totalLength); + break; + } } + + queue.RemoveData(4); + + MemoryStream buf = queue.ReadFrom(length); + + /* + * Now, parse the message. + */ + HandleHandshakeMessage(type, buf); } - while (read); } - private void ProcessApplicationData() + private void ProcessApplicationDataQueue() { /* * There is nothing we need to do here. @@ -354,7 +361,7 @@ namespace Org.BouncyCastle.Crypto.Tls */ } - private void ProcessAlert() + private void ProcessAlertQueue() { while (mAlertQueue.Available >= 2) { @@ -384,14 +391,16 @@ namespace Org.BouncyCastle.Crypto.Tls } 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) { + if (!mAppDataReady) + { + throw new TlsFatalAlert(AlertDescription.handshake_failure); + } HandleClose(false); } @@ -482,15 +491,35 @@ namespace Org.BouncyCastle.Crypto.Tls return len; } + protected virtual void SafeCheckRecordHeader(byte[] recordHeader) + { + try + { + mRecordStream.CheckRecordHeader(recordHeader); + } + catch (TlsFatalAlert e) + { + this.FailWithError(AlertLevel.fatal, e.AlertDescription, "Failed to read record", e); + throw e; + } + catch (Exception e) + { + this.FailWithError(AlertLevel.fatal, AlertDescription.internal_error, "Failed to read record", e); + throw e; + } + } + 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(); + if (!mAppDataReady) + { + throw new TlsFatalAlert(AlertDescription.handshake_failure); + } + throw new TlsNoCloseNotifyException(); } } catch (TlsFatalAlert e) @@ -610,14 +639,24 @@ namespace Org.BouncyCastle.Crypto.Tls protected virtual void WriteHandshakeMessage(byte[] buf, int off, int len) { - while (len > 0) + if (len < 4) + throw new TlsFatalAlert(AlertDescription.internal_error); + + byte type = TlsUtilities.ReadUint8(buf, off); + if (type != HandshakeType.hello_request) + { + mRecordStream.HandshakeHashUpdater.Write(buf, off, len); + } + + int total = 0; + do { // 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; + int toWrite = System.Math.Min(len - total, mRecordStream.GetPlaintextLimit()); + SafeWriteRecord(ContentType.handshake, buf, off + total, toWrite); + total += toWrite; } + while (total < len); } /// <summary>The secure bidirectional stream for this connection</summary> @@ -633,6 +672,26 @@ namespace Org.BouncyCastle.Crypto.Tls } /** + * Should be called in non-blocking mode when the input data reaches EOF. + */ + public virtual void CloseInput() + { + if (mBlocking) + throw new InvalidOperationException("Cannot use CloseInput() in blocking mode!"); + + if (mClosed) + return; + + if (mInputBuffers.Available > 0) + throw new EndOfStreamException(); + + if (!mAppDataReady) + throw new TlsFatalAlert(AlertDescription.handshake_failure); + + throw new TlsNoCloseNotifyException(); + } + + /** * 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 @@ -662,17 +721,28 @@ namespace Org.BouncyCastle.Crypto.Tls // 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); + byte[] recordHeader = new byte[RecordStream.TLS_HEADER_SIZE]; + mInputBuffers.Peek(recordHeader); - int totalLength = TlsUtilities.ReadUint16(header, RecordStream.TLS_HEADER_LENGTH_OFFSET) + RecordStream.TLS_HEADER_SIZE; + int totalLength = TlsUtilities.ReadUint16(recordHeader, RecordStream.TLS_HEADER_LENGTH_OFFSET) + RecordStream.TLS_HEADER_SIZE; if (mInputBuffers.Available < totalLength) { // not enough bytes to read a whole record + SafeCheckRecordHeader(recordHeader); break; } SafeReadRecord(); + + if (mClosed) + { + if (mConnectionState != CS_END) + { + // NOTE: Any close during the handshake should have raised an exception. + throw new TlsFatalAlert(AlertDescription.internal_error); + } + break; + } } } @@ -1164,6 +1234,9 @@ namespace Org.BouncyCastle.Crypto.Tls switch (ciphersuite) { + case CipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_DH_anon_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_DH_anon_WITH_AES_256_CBC_SHA256: 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: @@ -1267,6 +1340,7 @@ namespace Org.BouncyCastle.Crypto.Tls throw new TlsFatalAlert(AlertDescription.illegal_parameter); } + case CipherSuite.TLS_DH_anon_WITH_AES_256_GCM_SHA384: 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: diff --git a/crypto/src/crypto/tls/TlsRsaSigner.cs b/crypto/src/crypto/tls/TlsRsaSigner.cs index 6da1c5e9b..1614f503b 100644 --- a/crypto/src/crypto/tls/TlsRsaSigner.cs +++ b/crypto/src/crypto/tls/TlsRsaSigner.cs @@ -91,7 +91,7 @@ namespace Org.BouncyCastle.Crypto.Tls protected virtual IAsymmetricBlockCipher CreateRsaImpl() { /* - * RFC 5264 7.4.7.1. Implementation note: It is now known that remote timing-based attacks + * RFC 5246 7.4.7.1. Implementation note: It is now known that remote timing-based attacks * on TLS are possible, at least when the client and server are on the same LAN. * Accordingly, implementations that use static RSA keys MUST use RSA blinding or some other * anti-timing technique, as described in [TIMING]. diff --git a/crypto/src/crypto/tls/TlsServerProtocol.cs b/crypto/src/crypto/tls/TlsServerProtocol.cs index 38f2befea..5f3ce18e2 100644 --- a/crypto/src/crypto/tls/TlsServerProtocol.cs +++ b/crypto/src/crypto/tls/TlsServerProtocol.cs @@ -124,10 +124,8 @@ namespace Org.BouncyCastle.Crypto.Tls get { return mTlsServer; } } - protected override void HandleHandshakeMessage(byte type, byte[] data) + protected override void HandleHandshakeMessage(byte type, MemoryStream buf) { - MemoryStream buf = new MemoryStream(data); - switch (type) { case HandshakeType.client_hello: @@ -367,7 +365,6 @@ namespace Org.BouncyCastle.Crypto.Tls SendFinishedMessage(); this.mConnectionState = CS_SERVER_FINISHED; - this.mConnectionState = CS_END; CompleteHandshake(); break; @@ -625,10 +622,19 @@ namespace Org.BouncyCastle.Crypto.Tls AssertEmpty(buf); + if (TlsUtilities.IsSsl(Context)) + { + EstablishMasterSecret(Context, mKeyExchange); + } + this.mPrepareFinishHash = mRecordStream.PrepareToFinish(); this.mSecurityParameters.sessionHash = GetCurrentPrfHash(Context, mPrepareFinishHash, null); - EstablishMasterSecret(Context, mKeyExchange); + if (!TlsUtilities.IsSsl(Context)) + { + EstablishMasterSecret(Context, mKeyExchange); + } + mRecordStream.SetPendingConnectionState(Peer.GetCompression(), Peer.GetCipher()); if (!mExpectSessionTicket) @@ -780,7 +786,7 @@ namespace Org.BouncyCastle.Crypto.Tls mSecurityParameters.prfAlgorithm = GetPrfAlgorithm(Context, mSecurityParameters.CipherSuite); /* - * RFC 5264 7.4.9. Any cipher suite which does not explicitly specify verify_data_length has + * RFC 5246 7.4.9. Any cipher suite which does not explicitly specify verify_data_length has * a verify_data_length equal to 12. This includes all existing cipher suites. */ mSecurityParameters.verifyDataLength = 12; diff --git a/crypto/src/crypto/tls/TlsUtilities.cs b/crypto/src/crypto/tls/TlsUtilities.cs index d51a8ff48..48e51a7b6 100644 --- a/crypto/src/crypto/tls/TlsUtilities.cs +++ b/crypto/src/crypto/tls/TlsUtilities.cs @@ -571,6 +571,16 @@ namespace Org.BouncyCastle.Crypto.Tls buf[offset + 1] = (byte)version.MinorVersion; } + public static IList GetAllSignatureAlgorithms() + { + IList v = Platform.CreateArrayList(4); + v.Add(SignatureAlgorithm.anonymous); + v.Add(SignatureAlgorithm.rsa); + v.Add(SignatureAlgorithm.dsa); + v.Add(SignatureAlgorithm.ecdsa); + return v; + } + public static IList GetDefaultDssSignatureAlgorithms() { return VectorOfOne(new SignatureAndHashAlgorithm(HashAlgorithm.sha1, SignatureAlgorithm.dsa)); @@ -1260,6 +1270,7 @@ namespace Org.BouncyCastle.Crypto.Tls { switch (ciphersuite) { + case CipherSuite.TLS_DH_anon_WITH_3DES_EDE_CBC_SHA: case CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA: case CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA: case CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA: @@ -1279,6 +1290,8 @@ namespace Org.BouncyCastle.Crypto.Tls case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA: return EncryptionAlgorithm.cls_3DES_EDE_CBC; + case CipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA256: case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA: case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA256: case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA: @@ -1325,6 +1338,7 @@ namespace Org.BouncyCastle.Crypto.Tls case CipherSuite.TLS_RSA_WITH_AES_128_CCM_8: return EncryptionAlgorithm.AES_128_CCM_8; + case CipherSuite.TLS_DH_anon_WITH_AES_128_GCM_SHA256: case CipherSuite.TLS_DH_DSS_WITH_AES_128_GCM_SHA256: case CipherSuite.TLS_DH_RSA_WITH_AES_128_GCM_SHA256: case CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256: @@ -1347,6 +1361,8 @@ namespace Org.BouncyCastle.Crypto.Tls case CipherSuite.DRAFT_TLS_PSK_WITH_AES_128_OCB: return EncryptionAlgorithm.AES_128_OCB_TAGLEN96; + case CipherSuite.TLS_DH_anon_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_DH_anon_WITH_AES_256_CBC_SHA256: case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA: case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA256: case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA: @@ -1393,6 +1409,7 @@ namespace Org.BouncyCastle.Crypto.Tls case CipherSuite.TLS_RSA_WITH_AES_256_CCM_8: return EncryptionAlgorithm.AES_256_CCM_8; + case CipherSuite.TLS_DH_anon_WITH_AES_256_GCM_SHA384: case CipherSuite.TLS_DH_DSS_WITH_AES_256_GCM_SHA384: case CipherSuite.TLS_DH_RSA_WITH_AES_256_GCM_SHA384: case CipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384: @@ -1415,17 +1432,16 @@ namespace Org.BouncyCastle.Crypto.Tls case CipherSuite.DRAFT_TLS_PSK_WITH_AES_256_OCB: return EncryptionAlgorithm.AES_256_OCB_TAGLEN96; + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA: + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256: case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA: - case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA: - case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA: - case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA: - case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA: - return EncryptionAlgorithm.CAMELLIA_128_CBC; - case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA: case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA: case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256: case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA: case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256: case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256: case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256: @@ -1433,10 +1449,12 @@ namespace Org.BouncyCastle.Crypto.Tls case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256: case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256: case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256: - case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA: case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256: return EncryptionAlgorithm.CAMELLIA_128_CBC; + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256: case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256: case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256: case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256: @@ -1451,30 +1469,29 @@ namespace Org.BouncyCastle.Crypto.Tls case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256: return EncryptionAlgorithm.CAMELLIA_128_GCM; + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA: + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256: case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA: - case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA: - case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA: - case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA: - case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA: - return EncryptionAlgorithm.CAMELLIA_256_CBC; - case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256: + case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA: case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256: + case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA: case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256: - case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256: - case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256: - return EncryptionAlgorithm.CAMELLIA_256_CBC; - case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA: + case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256: case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384: case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384: case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384: case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384: case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384: case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA: + case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256: case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384: return EncryptionAlgorithm.CAMELLIA_256_CBC; + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384: case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384: case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384: case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384: @@ -1542,6 +1559,7 @@ namespace Org.BouncyCastle.Crypto.Tls case CipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA: return EncryptionAlgorithm.RC4_128; + case CipherSuite.TLS_DH_anon_WITH_SEED_CBC_SHA: case CipherSuite.TLS_DH_DSS_WITH_SEED_CBC_SHA: case CipherSuite.TLS_DH_RSA_WITH_SEED_CBC_SHA: case CipherSuite.TLS_DHE_DSS_WITH_SEED_CBC_SHA: @@ -1558,6 +1576,23 @@ namespace Org.BouncyCastle.Crypto.Tls { switch (ciphersuite) { + case CipherSuite.TLS_DH_anon_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_DH_anon_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_DH_anon_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_DH_anon_WITH_AES_256_CBC_SHA256: + case CipherSuite.TLS_DH_anon_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA: + 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_SHA: + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256: + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_DH_anon_WITH_RC4_128_MD5: + case CipherSuite.TLS_DH_anon_WITH_SEED_CBC_SHA: + return KeyExchangeAlgorithm.DH_anon; + case CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA: case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA: case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA256: @@ -1837,6 +1872,10 @@ namespace Org.BouncyCastle.Crypto.Tls { switch (ciphersuite) { + case CipherSuite.TLS_DH_anon_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_DH_anon_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384: case CipherSuite.TLS_DH_DSS_WITH_AES_128_GCM_SHA256: case CipherSuite.TLS_DH_DSS_WITH_AES_256_GCM_SHA384: case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256: @@ -1926,10 +1965,17 @@ namespace Org.BouncyCastle.Crypto.Tls case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384: return MacAlgorithm.cls_null; + case CipherSuite.TLS_DH_anon_WITH_RC4_128_MD5: case CipherSuite.TLS_RSA_WITH_NULL_MD5: case CipherSuite.TLS_RSA_WITH_RC4_128_MD5: return MacAlgorithm.hmac_md5; + case CipherSuite.TLS_DH_anon_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DH_anon_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA: + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA: + case CipherSuite.TLS_DH_anon_WITH_SEED_CBC_SHA: case CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA: case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA: case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA: @@ -2018,6 +2064,10 @@ namespace Org.BouncyCastle.Crypto.Tls case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA: return MacAlgorithm.hmac_sha1; + case CipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_DH_anon_WITH_AES_256_CBC_SHA256: + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_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_256_CBC_SHA256: case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256: @@ -2092,6 +2142,10 @@ namespace Org.BouncyCastle.Crypto.Tls { switch (ciphersuite) { + case CipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_DH_anon_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_DH_anon_WITH_AES_256_CBC_SHA256: + case CipherSuite.TLS_DH_anon_WITH_AES_256_GCM_SHA384: 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: @@ -2242,9 +2296,68 @@ namespace Org.BouncyCastle.Crypto.Tls return CipherType.stream == GetCipherType(ciphersuite); } + public static bool IsValidCipherSuiteForSignatureAlgorithms(int cipherSuite, IList sigAlgs) + { + int keyExchangeAlgorithm; + try + { + keyExchangeAlgorithm = GetKeyExchangeAlgorithm(cipherSuite); + } + catch (IOException e) + { + return true; + } + + switch (keyExchangeAlgorithm) + { + case KeyExchangeAlgorithm.DH_anon: + case KeyExchangeAlgorithm.DH_anon_EXPORT: + case KeyExchangeAlgorithm.ECDH_anon: + return sigAlgs.Contains(SignatureAlgorithm.anonymous); + + case KeyExchangeAlgorithm.DHE_RSA: + case KeyExchangeAlgorithm.DHE_RSA_EXPORT: + case KeyExchangeAlgorithm.ECDHE_RSA: + case KeyExchangeAlgorithm.SRP_RSA: + return sigAlgs.Contains(SignatureAlgorithm.rsa); + + case KeyExchangeAlgorithm.DHE_DSS: + case KeyExchangeAlgorithm.DHE_DSS_EXPORT: + case KeyExchangeAlgorithm.SRP_DSS: + return sigAlgs.Contains(SignatureAlgorithm.dsa); + + case KeyExchangeAlgorithm.ECDHE_ECDSA: + return sigAlgs.Contains(SignatureAlgorithm.ecdsa); + + default: + return true; + } + } + public static bool IsValidCipherSuiteForVersion(int cipherSuite, ProtocolVersion serverVersion) { return GetMinimumVersion(cipherSuite).IsEqualOrEarlierVersionOf(serverVersion.GetEquivalentTLSVersion()); } + + public static IList GetUsableSignatureAlgorithms(IList sigHashAlgs) + { + if (sigHashAlgs == null) + return GetAllSignatureAlgorithms(); + + IList v = Platform.CreateArrayList(4); + v.Add(SignatureAlgorithm.anonymous); + foreach (SignatureAndHashAlgorithm sigHashAlg in sigHashAlgs) + { + //if (sigHashAlg.Hash >= MINIMUM_HASH_STRICT) + { + byte sigAlg = sigHashAlg.Signature; + if (!v.Contains(sigAlg)) + { + v.Add(sigAlg); + } + } + } + return v; + } } } diff --git a/crypto/src/util/io/BaseOutputStream.cs b/crypto/src/util/io/BaseOutputStream.cs index a0608d111..0dbe821de 100644 --- a/crypto/src/util/io/BaseOutputStream.cs +++ b/crypto/src/util/io/BaseOutputStream.cs @@ -60,5 +60,10 @@ namespace Org.BouncyCastle.Utilities.IO { Write(buffer, 0, buffer.Length); } - } + + public override void WriteByte(byte b) + { + Write(new byte[]{ b }, 0, 1); + } + } } diff --git a/crypto/src/util/io/Streams.cs b/crypto/src/util/io/Streams.cs index 70957acc7..cc7fa924c 100644 --- a/crypto/src/util/io/Streams.cs +++ b/crypto/src/util/io/Streams.cs @@ -90,5 +90,11 @@ namespace Org.BouncyCastle.Utilities.IO } return total; } - } + + /// <exception cref="IOException"></exception> + public static void WriteBufTo(MemoryStream buf, Stream output) + { + buf.WriteTo(output); + } + } } diff --git a/crypto/test/src/crypto/test/Poly1305Test.cs b/crypto/test/src/crypto/test/Poly1305Test.cs index eee9bcca5..7375b09be 100644 --- a/crypto/test/src/crypto/test/Poly1305Test.cs +++ b/crypto/test/src/crypto/test/Poly1305Test.cs @@ -86,7 +86,16 @@ namespace Org.BouncyCastle.Crypto.Tests null, "f05204a74f0f88a7fa1a95b84ec3d8ffb36fcdc7723ea65dfe7cd464e86e0abf6b9d51db3220cfd8496ad6e6d36ebee8d990f9ce0d3bb7f72b7ab5b3ab0a73240d11efe772c857021ae859db4933cdde4387b471d2ce700fef4b81087f8f47c307881fd83017afcd15b8d21edf9b704677f46df97b07e5b83f87c8abd90af9b1d0f9e2710e8ebd0d4d1c6a055abea861f42368bed94d9373e909c1d3715b221c16bc524c55c31ec3eab204850bb2474a84f9917038eff9d921130951391b5c54f09b5e1de833ea2cd7d3b306740abb7096d1e173da83427da2adddd3631eda30b54dbf487f2b082e8646f07d6e0a87e97522ca38d4ace4954bf3db6dd3a93b06fa18eb56856627ed6cffcd7ae26374554ca18ab8905f26331d323fe10e6e70624c7bc07a70f06ecd804b48f8f7e75e910165e1beb554f1f0ec7949c9c8d429a206b4d5c0653102249b6098e6b45fac2a07ff0220b0b8ae8f4c6bcc0c813a7cd141fa8b398b42575fc395747c5a0257ac41d6c1f434cfbf5dfe8349f5347ef6b60e611f5d6c3cbc20ca2555274d1934325824cef4809da293ea13f181929e2af025bbd1c9abdc3af93afd4c50a2854ade3887f4d2c8c225168052c16e74d76d2dd3e9467a2c5b8e15c06ffbffa42b8536384139f07e195a8c9f70f514f31dca4eb2cf262c0dcbde53654b6250a29efe21d54e83c80e005a1cad36d5934ff01c32e4bc5fe06d03064ff4a268517df4a94c759289f323734318cfa5d859d4ce9c16e63d02dff0896976f521607638535d2ee8dd3312e1ddc80a55d34fe829ab954c1ebd54d929954770f1be9d32b4c05003c5c9e97943b6431e2afe820b1e967b19843e5985a131b1100517cdc363799104af91e2cf3f53cb8fd003653a6dd8a31a3f9d566a7124b0ffe9695bcb87c482eb60106f88198f766a40bc0f4873c23653c5f9e7a8e446f770beb8034cf01d21028ba15ccee21a8db918c4829d61c88bfa927bc5def831501796c5b401a60a6b1b433c9fb905c8cd40412fffee81ab", "045be28cc52009f506bdbfabedacf0b4"), - }; + // Test case from JIRA issue BJA-620 + new TestCase( + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff", + null, + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffff", + "c80cb43844f387946e5aa6085bdf67da") + }; public override string Name { diff --git a/crypto/test/src/crypto/tls/test/TlsProtocolNonBlockingTest.cs b/crypto/test/src/crypto/tls/test/TlsProtocolNonBlockingTest.cs index 477e287f1..68f2341ee 100644 --- a/crypto/test/src/crypto/tls/test/TlsProtocolNonBlockingTest.cs +++ b/crypto/test/src/crypto/tls/test/TlsProtocolNonBlockingTest.cs @@ -52,6 +52,7 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests // close the connection clientProtocol.Close(); PumpData(clientProtocol, serverProtocol, fragment); + serverProtocol.CloseInput(); CheckClosed(serverProtocol); CheckClosed(clientProtocol); } diff --git a/crypto/test/src/crypto/tls/test/TlsServerTest.cs b/crypto/test/src/crypto/tls/test/TlsServerTest.cs index df31e1c0e..28272169b 100644 --- a/crypto/test/src/crypto/tls/test/TlsServerTest.cs +++ b/crypto/test/src/crypto/tls/test/TlsServerTest.cs @@ -27,14 +27,21 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests TcpListener ss = new TcpListener(IPAddress.Any, port); ss.Start(); Stream stdout = Console.OpenStandardOutput(); - while (true) + try { - TcpClient s = ss.AcceptTcpClient(); - Console.WriteLine("--------------------------------------------------------------------------------"); - Console.WriteLine("Accepted " + s); - ServerThread st = new ServerThread(s, stdout); - Thread t = new Thread(new ThreadStart(st.Run)); - t.Start(); + while (true) + { + TcpClient s = ss.AcceptTcpClient(); + Console.WriteLine("--------------------------------------------------------------------------------"); + Console.WriteLine("Accepted " + s); + ServerThread st = new ServerThread(s, stdout); + Thread t = new Thread(new ThreadStart(st.Run)); + t.Start(); + } + } + finally + { + ss.Stop(); } } diff --git a/crypto/test/src/crypto/tls/test/TlsTestSuite.cs b/crypto/test/src/crypto/tls/test/TlsTestSuite.cs index 77cebe0a6..5dd9cf0f5 100644 --- a/crypto/test/src/crypto/tls/test/TlsTestSuite.cs +++ b/crypto/test/src/crypto/tls/test/TlsTestSuite.cs @@ -19,6 +19,7 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests IList testSuite = new ArrayList(); AddFallbackTests(testSuite); + AddVersionTests(testSuite, ProtocolVersion.SSLv3); AddVersionTests(testSuite, ProtocolVersion.TLSv10); AddVersionTests(testSuite, ProtocolVersion.TLSv11); AddVersionTests(testSuite, ProtocolVersion.TLSv12); @@ -194,10 +195,10 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests private static TlsTestConfig CreateTlsTestConfig(ProtocolVersion version) { TlsTestConfig c = new TlsTestConfig(); - c.clientMinimumVersion = ProtocolVersion.TLSv10; + c.clientMinimumVersion = ProtocolVersion.SSLv3; c.clientOfferVersion = ProtocolVersion.TLSv12; c.serverMaximumVersion = version; - c.serverMinimumVersion = ProtocolVersion.TLSv10; + c.serverMinimumVersion = ProtocolVersion.SSLv3; return c; } } diff --git a/crypto/test/src/tsp/test/ParseTest.cs b/crypto/test/src/tsp/test/ParseTest.cs index ec9ba72f6..e9489a278 100644 --- a/crypto/test/src/tsp/test/ParseTest.cs +++ b/crypto/test/src/tsp/test/ParseTest.cs @@ -360,7 +360,8 @@ namespace Org.BouncyCastle.Tsp.Tests [Test] public void TestGeneralizedTime() { - generalizedTimeParse(generalizedTime); + // TODO: response is invalid - malformed integer + // generalizedTimeParse(generalizedTime); } [Test] |