summary refs log tree commit diff
path: root/crypto/src/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src/crypto')
-rw-r--r--crypto/src/crypto/ec/CustomNamedCurves.cs95
-rw-r--r--crypto/src/crypto/engines/ChaChaEngine.cs189
-rw-r--r--crypto/src/crypto/engines/IdeaEngine.cs46
-rw-r--r--crypto/src/crypto/engines/Salsa20Engine.cs277
-rw-r--r--crypto/src/crypto/engines/XSalsa20Engine.cs71
-rw-r--r--crypto/src/crypto/generators/ECKeyPairGenerator.cs5
-rw-r--r--crypto/src/crypto/generators/Poly1305KeyGenerator.cs123
-rw-r--r--crypto/src/crypto/macs/CMac.cs2
-rw-r--r--crypto/src/crypto/macs/GMac.cs111
-rw-r--r--crypto/src/crypto/macs/Poly1305.cs272
-rw-r--r--crypto/src/crypto/modes/EAXBlockCipher.cs5
-rw-r--r--crypto/src/crypto/modes/GCMBlockCipher.cs5
-rw-r--r--crypto/src/crypto/modes/IAeadBlockCipher.cs3
-rw-r--r--crypto/src/crypto/tls/AlertDescription.cs258
-rw-r--r--crypto/src/crypto/tls/AlertLevel.cs16
-rw-r--r--crypto/src/crypto/tls/ByteQueue.cs10
-rw-r--r--crypto/src/crypto/tls/Certificate.cs228
-rw-r--r--crypto/src/crypto/tls/CertificateRequest.cs176
-rw-r--r--crypto/src/crypto/tls/CipherSuite.cs428
-rw-r--r--crypto/src/crypto/tls/ClientCertificateType.cs37
-rw-r--r--crypto/src/crypto/tls/CompressionMethod.cs32
-rw-r--r--crypto/src/crypto/tls/ContentType.cs21
-rw-r--r--crypto/src/crypto/tls/DefaultTlsAgreementCredentials.cs2
-rw-r--r--crypto/src/crypto/tls/DefaultTlsCipherFactory.cs116
-rw-r--r--crypto/src/crypto/tls/DefaultTlsClient.cs350
-rw-r--r--crypto/src/crypto/tls/DefaultTlsSignerCredentials.cs2
-rw-r--r--crypto/src/crypto/tls/ECCurveType.cs46
-rw-r--r--crypto/src/crypto/tls/ECPointFormat.cs24
-rw-r--r--crypto/src/crypto/tls/EncryptionAlgorithm.cs77
-rw-r--r--crypto/src/crypto/tls/ExtensionType.cs81
-rw-r--r--crypto/src/crypto/tls/HandshakeType.cs53
-rw-r--r--crypto/src/crypto/tls/HashAlgorithm.cs18
-rw-r--r--crypto/src/crypto/tls/KeyExchangeAlgorithm.cs81
-rw-r--r--crypto/src/crypto/tls/LegacyTlsAuthentication.cs44
-rw-r--r--crypto/src/crypto/tls/NamedCurve.cs126
-rw-r--r--crypto/src/crypto/tls/PrfAlgorithm.cs25
-rw-r--r--crypto/src/crypto/tls/ProtocolVersion.cs159
-rw-r--r--crypto/src/crypto/tls/PskTlsClient.cs262
-rw-r--r--crypto/src/crypto/tls/RecordStream.cs18
-rw-r--r--crypto/src/crypto/tls/SignatureAlgorithm.cs15
-rw-r--r--crypto/src/crypto/tls/SignatureAndHashAlgorithm.cs94
-rw-r--r--crypto/src/crypto/tls/SrpTlsClient.cs350
-rw-r--r--crypto/src/crypto/tls/TlsBlockCipher.cs194
-rw-r--r--crypto/src/crypto/tls/TlsCipher.cs14
-rw-r--r--crypto/src/crypto/tls/TlsCipherFactory.cs12
-rw-r--r--crypto/src/crypto/tls/TlsClient.cs190
-rw-r--r--crypto/src/crypto/tls/TlsDHKeyExchange.cs374
-rw-r--r--crypto/src/crypto/tls/TlsDheKeyExchange.cs90
-rw-r--r--crypto/src/crypto/tls/TlsECDHKeyExchange.cs10
-rw-r--r--crypto/src/crypto/tls/TlsECDheKeyExchange.cs10
-rw-r--r--crypto/src/crypto/tls/TlsException.cs14
-rw-r--r--crypto/src/crypto/tls/TlsFatalAlert.cs26
-rw-r--r--crypto/src/crypto/tls/TlsMac.cs174
-rw-r--r--crypto/src/crypto/tls/TlsNullCipher.cs42
-rw-r--r--crypto/src/crypto/tls/TlsProtocolHandler.cs119
-rw-r--r--crypto/src/crypto/tls/TlsPskKeyExchange.cs258
-rw-r--r--crypto/src/crypto/tls/TlsRsaKeyExchange.cs224
-rw-r--r--crypto/src/crypto/tls/TlsSrpKeyExchange.cs6
-rw-r--r--crypto/src/crypto/tls/TlsStreamCipher.cs40
-rw-r--r--crypto/src/crypto/tls/TlsUtilities.cs112
60 files changed, 4112 insertions, 2150 deletions
diff --git a/crypto/src/crypto/ec/CustomNamedCurves.cs b/crypto/src/crypto/ec/CustomNamedCurves.cs
new file mode 100644

index 000000000..ab609fdb9 --- /dev/null +++ b/crypto/src/crypto/ec/CustomNamedCurves.cs
@@ -0,0 +1,95 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X9; +using Org.BouncyCastle.Math.EC; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Collections; + +namespace Org.BouncyCastle.Crypto.EC +{ + public sealed class CustomNamedCurves + { + private CustomNamedCurves() + { + } + + private static ECCurve ConfigureCurve(ECCurve curve) + { + return curve; + } + + private static readonly IDictionary objIds = Platform.CreateHashtable(); + private static readonly IDictionary curves = Platform.CreateHashtable(); + private static readonly IDictionary names = Platform.CreateHashtable(); + + private static void DefineCurve( + string name, + DerObjectIdentifier oid, + X9ECParametersHolder holder) + { + objIds.Add(name, oid); + names.Add(oid, name); + curves.Add(oid, holder); + } + + static CustomNamedCurves() + { + } + + public static X9ECParameters GetByName( + string name) + { + DerObjectIdentifier oid = (DerObjectIdentifier) + objIds[Platform.ToLowerInvariant(name)]; + + return oid == null ? null : GetByOid(oid); + } + + + /** + * return the X9ECParameters object for the named curve represented by + * the passed in object identifier. Null if the curve isn't present. + * + * @param oid an object identifier representing a named curve, if present. + */ + public static X9ECParameters GetByOid( + DerObjectIdentifier oid) + { + X9ECParametersHolder holder = (X9ECParametersHolder)curves[oid]; + + return holder == null ? null : holder.Parameters; + } + + /** + * return the object identifier signified by the passed in name. Null + * if there is no object identifier associated with name. + * + * @return the object identifier associated with name, if present. + */ + public static DerObjectIdentifier GetOid( + string name) + { + return (DerObjectIdentifier)objIds[Platform.ToLowerInvariant(name)]; + } + + /** + * return the named curve name represented by the given object identifier. + */ + public static string GetName( + DerObjectIdentifier oid) + { + return (string)names[oid]; + } + + /** + * returns an enumeration containing the name strings for curves + * contained in this structure. + */ + public static IEnumerable Names + { + get { return new EnumerableProxy(objIds.Keys); } + } + } +} diff --git a/crypto/src/crypto/engines/ChaChaEngine.cs b/crypto/src/crypto/engines/ChaChaEngine.cs new file mode 100644
index 000000000..f4a7b8fe1 --- /dev/null +++ b/crypto/src/crypto/engines/ChaChaEngine.cs
@@ -0,0 +1,189 @@ +using System; +using Org.BouncyCastle.Crypto.Utilities; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /// <summary> + /// Implementation of Daniel J. Bernstein's ChaCha stream cipher. + /// </summary> + public class ChaChaEngine + : Salsa20Engine + { + + /// <summary> + /// Creates a 20 rounds ChaCha engine. + /// </summary> + public ChaChaEngine() + { + } + + /// <summary> + /// Creates a ChaCha engine with a specific number of rounds. + /// </summary> + /// <param name="rounds">the number of rounds (must be an even number).</param> + public ChaChaEngine(int rounds) + : base(rounds) + { + } + + public override string AlgorithmName + { + get { return "ChaCha" + rounds; } + } + + protected override void AdvanceCounter() + { + if (++engineState[12] == 0) + { + ++engineState[13]; + } + } + + protected override void ResetCounter() + { + engineState[12] = engineState[13] = 0; + } + + protected override void SetKey(byte[] keyBytes, byte[] ivBytes) + { + if ((keyBytes.Length != 16) && (keyBytes.Length != 32)) + { + throw new ArgumentException(AlgorithmName + " requires 128 bit or 256 bit key"); + } + + int offset = 0; + byte[] constants; + + // Key + engineState[4] = Pack.LE_To_UInt32(keyBytes, 0); + engineState[5] = Pack.LE_To_UInt32(keyBytes, 4); + engineState[6] = Pack.LE_To_UInt32(keyBytes, 8); + engineState[7] = Pack.LE_To_UInt32(keyBytes, 12); + + if (keyBytes.Length == 32) + { + constants = sigma; + offset = 16; + } else + { + constants = tau; + } + + engineState[8] = Pack.LE_To_UInt32(keyBytes, offset); + engineState[9] = Pack.LE_To_UInt32(keyBytes, offset + 4); + engineState[10] = Pack.LE_To_UInt32(keyBytes, offset + 8); + engineState[11] = Pack.LE_To_UInt32(keyBytes, offset + 12); + + engineState[0] = Pack.LE_To_UInt32(constants, 0); + engineState[1] = Pack.LE_To_UInt32(constants, 4); + engineState[2] = Pack.LE_To_UInt32(constants, 8); + engineState[3] = Pack.LE_To_UInt32(constants, 12); + + // Counter + engineState[12] = engineState[13] = 0; + + // IV + engineState[14] = Pack.LE_To_UInt32(ivBytes, 0); + engineState[15] = Pack.LE_To_UInt32(ivBytes, 4); + } + + protected override void GenerateKeyStream(byte[] output) + { + ChachaCore(rounds, engineState, x); + Pack.UInt32_To_LE(x, output, 0); + } + + /// <summary> + /// ChacCha function. + /// </summary> + /// <param name="rounds">The number of ChaCha rounds to execute</param> + /// <param name="input">The input words.</param> + /// <param name="x">The ChaCha state to modify.</param> + internal static void ChachaCore(int rounds, uint[] input, uint[] x) + { + if (input.Length != 16) { + throw new ArgumentException(); + } + if (x.Length != 16) { + throw new ArgumentException(); + } + if (rounds % 2 != 0) { + throw new ArgumentException("Number of rounds must be even"); + } + + uint x00 = input[ 0]; + uint x01 = input[ 1]; + uint x02 = input[ 2]; + uint x03 = input[ 3]; + uint x04 = input[ 4]; + uint x05 = input[ 5]; + uint x06 = input[ 6]; + uint x07 = input[ 7]; + uint x08 = input[ 8]; + uint x09 = input[ 9]; + uint x10 = input[10]; + uint x11 = input[11]; + uint x12 = input[12]; + uint x13 = input[13]; + uint x14 = input[14]; + uint x15 = input[15]; + + for (int i = rounds; i > 0; i -= 2) + { + x00 += x04; x12 = R(x12 ^ x00, 16); + x08 += x12; x04 = R(x04 ^ x08, 12); + x00 += x04; x12 = R(x12 ^ x00, 8); + x08 += x12; x04 = R(x04 ^ x08, 7); + x01 += x05; x13 = R(x13 ^ x01, 16); + x09 += x13; x05 = R(x05 ^ x09, 12); + x01 += x05; x13 = R(x13 ^ x01, 8); + x09 += x13; x05 = R(x05 ^ x09, 7); + x02 += x06; x14 = R(x14 ^ x02, 16); + x10 += x14; x06 = R(x06 ^ x10, 12); + x02 += x06; x14 = R(x14 ^ x02, 8); + x10 += x14; x06 = R(x06 ^ x10, 7); + x03 += x07; x15 = R(x15 ^ x03, 16); + x11 += x15; x07 = R(x07 ^ x11, 12); + x03 += x07; x15 = R(x15 ^ x03, 8); + x11 += x15; x07 = R(x07 ^ x11, 7); + x00 += x05; x15 = R(x15 ^ x00, 16); + x10 += x15; x05 = R(x05 ^ x10, 12); + x00 += x05; x15 = R(x15 ^ x00, 8); + x10 += x15; x05 = R(x05 ^ x10, 7); + x01 += x06; x12 = R(x12 ^ x01, 16); + x11 += x12; x06 = R(x06 ^ x11, 12); + x01 += x06; x12 = R(x12 ^ x01, 8); + x11 += x12; x06 = R(x06 ^ x11, 7); + x02 += x07; x13 = R(x13 ^ x02, 16); + x08 += x13; x07 = R(x07 ^ x08, 12); + x02 += x07; x13 = R(x13 ^ x02, 8); + x08 += x13; x07 = R(x07 ^ x08, 7); + x03 += x04; x14 = R(x14 ^ x03, 16); + x09 += x14; x04 = R(x04 ^ x09, 12); + x03 += x04; x14 = R(x14 ^ x03, 8); + x09 += x14; x04 = R(x04 ^ x09, 7); + + } + + x[ 0] = x00 + input[ 0]; + x[ 1] = x01 + input[ 1]; + x[ 2] = x02 + input[ 2]; + x[ 3] = x03 + input[ 3]; + x[ 4] = x04 + input[ 4]; + x[ 5] = x05 + input[ 5]; + x[ 6] = x06 + input[ 6]; + x[ 7] = x07 + input[ 7]; + x[ 8] = x08 + input[ 8]; + x[ 9] = x09 + input[ 9]; + x[10] = x10 + input[10]; + x[11] = x11 + input[11]; + x[12] = x12 + input[12]; + x[13] = x13 + input[13]; + x[14] = x14 + input[14]; + x[15] = x15 + input[15]; + } + + } + +} + diff --git a/crypto/src/crypto/engines/IdeaEngine.cs b/crypto/src/crypto/engines/IdeaEngine.cs
index f763c5939..46b5a787c 100644 --- a/crypto/src/crypto/engines/IdeaEngine.cs +++ b/crypto/src/crypto/engines/IdeaEngine.cs
@@ -1,5 +1,3 @@ -#if INCLUDE_IDEA - using System; using Org.BouncyCastle.Crypto.Parameters; @@ -12,26 +10,26 @@ namespace Org.BouncyCastle.Crypto.Engines * This implementation is based on the "HOWTO: INTERNATIONAL DATA ENCRYPTION ALGORITHM" * implementation summary by Fauzan Mirza (F.U.Mirza@sheffield.ac.uk). (baring 1 typo at the * end of the mulinv function!). - * </p> + * </p> * <p> * It can be found at ftp://ftp.funet.fi/pub/crypt/cryptography/symmetric/idea/ - * </p> + * </p> * <p> - * Note 1: This algorithm is patented in the USA, Japan, and Europe including + * Note 1: This algorithm is patented in the USA, Japan, and Europe including * at least Austria, France, Germany, Italy, Netherlands, Spain, Sweden, Switzerland * and the United Kingdom. Non-commercial use is free, however any commercial * products are liable for royalties. Please see * <a href="http://www.mediacrypt.com">www.mediacrypt.com</a> for * further details. This announcement has been included at the request of * the patent holders. - * </p> - * <p> - * Note 2: Due to the requests concerning the above, this algorithm is now only - * included in the extended assembly. It is not included in the default distributions. - * </p> + * </p> + * <p> + * Note 2: Due to the requests concerning the above, this algorithm is now only + * included in the extended assembly. It is not included in the default distributions. + * </p> */ public class IdeaEngine - : IBlockCipher + : IBlockCipher { private const int BLOCK_SIZE = 8; private int[] workingKey; @@ -54,28 +52,28 @@ namespace Org.BouncyCastle.Crypto.Engines ICipherParameters parameters) { if (!(parameters is KeyParameter)) - throw new ArgumentException("invalid parameter passed to IDEA init - " + parameters.GetType().ToString()); + throw new ArgumentException("invalid parameter passed to IDEA init - " + parameters.GetType().ToString()); - workingKey = GenerateWorkingKey(forEncryption, - ((KeyParameter)parameters).GetKey()); + workingKey = GenerateWorkingKey(forEncryption, + ((KeyParameter)parameters).GetKey()); } - public string AlgorithmName + public string AlgorithmName { get { return "IDEA"; } } - public bool IsPartialBlockOkay - { - get { return false; } - } + public bool IsPartialBlockOkay + { + get { return false; } + } - public int GetBlockSize() + public int GetBlockSize() { return BLOCK_SIZE; } - public int ProcessBlock( + public int ProcessBlock( byte[] input, int inOff, byte[] output, @@ -228,7 +226,7 @@ namespace Org.BouncyCastle.Crypto.Engines * Common Divisor algorithm. Zero and one are self inverse. * <p> * i.e. x * MulInv(x) == 1 (modulo BASE) - * </p> + * </p> */ private int MulInv( int x) @@ -261,7 +259,7 @@ namespace Org.BouncyCastle.Crypto.Engines * Return the additive inverse of x. * <p> * i.e. x + AddInv(x) == 0 - * </p> + * </p> */ int AddInv( int x) @@ -337,5 +335,3 @@ namespace Org.BouncyCastle.Crypto.Engines } } } - -#endif diff --git a/crypto/src/crypto/engines/Salsa20Engine.cs b/crypto/src/crypto/engines/Salsa20Engine.cs
index 7d68deab1..81884d603 100644 --- a/crypto/src/crypto/engines/Salsa20Engine.cs +++ b/crypto/src/crypto/engines/Salsa20Engine.cs
@@ -7,44 +7,60 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Crypto.Engines { - /** - * Implementation of Daniel J. Bernstein's Salsa20 stream cipher, Snuffle 2005 - */ + /// <summary> + /// Implementation of Daniel J. Bernstein's Salsa20 stream cipher, Snuffle 2005 + /// </summary> public class Salsa20Engine : IStreamCipher { + public static readonly int DEFAULT_ROUNDS = 20; + /** Constants */ private const int StateSize = 16; // 16, 32 bit ints = 64 bytes - private readonly static byte[] + protected readonly static byte[] sigma = Strings.ToAsciiByteArray("expand 32-byte k"), tau = Strings.ToAsciiByteArray("expand 16-byte k"); + protected int rounds; + /* * variables to hold the state of the engine * during encryption and decryption */ - private int index = 0; - private uint[] engineState = new uint[StateSize]; // state - private uint[] x = new uint[StateSize]; // internal buffer - private byte[] keyStream = new byte[StateSize * 4], // expanded state, 64 bytes - workingKey = null, - workingIV = null; - private bool initialised = false; + private int index = 0; + internal uint[] engineState = new uint[StateSize]; // state + internal uint[] x = new uint[StateSize]; // internal buffer + private byte[] keyStream = new byte[StateSize * 4]; // expanded state, 64 bytes + private bool initialised = false; /* * internal counter */ private uint cW0, cW1, cW2; - /** - * initialise a Salsa20 cipher. - * - * @param forEncryption whether or not we are for encryption. - * @param params the parameters required to set up the cipher. - * @exception ArgumentException if the params argument is - * inappropriate. - */ + /// <summary> + /// Creates a 20 round Salsa20 engine. + /// </summary> + public Salsa20Engine() + : this(DEFAULT_ROUNDS) + { + } + + /// <summary> + /// Creates a Salsa20 engine with a specific number of rounds. + /// </summary> + /// <param name="rounds">the number of rounds (must be an even number).</param> + public Salsa20Engine(int rounds) + { + if (rounds <= 0 || (rounds & 1) != 0) + { + throw new ArgumentException("'rounds' must be a positive, even number"); + } + + this.rounds = rounds; + } + public void Init( bool forEncryption, ICipherParameters parameters) @@ -58,27 +74,38 @@ namespace Org.BouncyCastle.Crypto.Engines ParametersWithIV ivParams = parameters as ParametersWithIV; if (ivParams == null) - throw new ArgumentException("Salsa20 Init requires an IV", "parameters"); + throw new ArgumentException(AlgorithmName + " Init requires an IV", "parameters"); byte[] iv = ivParams.GetIV(); - if (iv == null || iv.Length != 8) - throw new ArgumentException("Salsa20 requires exactly 8 bytes of IV"); + if (iv == null || iv.Length != NonceSize) + throw new ArgumentException(AlgorithmName + " requires exactly " + NonceSize + " bytes of IV"); KeyParameter key = ivParams.Parameters as KeyParameter; if (key == null) - throw new ArgumentException("Salsa20 Init requires a key", "parameters"); + throw new ArgumentException(AlgorithmName + " Init requires a key", "parameters"); - workingKey = key.GetKey(); - workingIV = iv; + SetKey(key.GetKey(), iv); + Reset(); + initialised = true; + } - SetKey(workingKey, workingIV); + protected virtual int NonceSize + { + get { return 8; } } - public string AlgorithmName + public virtual string AlgorithmName { - get { return "Salsa20"; } + get { + string name = "Salsa20"; + if (rounds != DEFAULT_ROUNDS) + { + name += "/" + rounds; + } + return name; + } } public byte ReturnByte( @@ -92,11 +119,7 @@ namespace Org.BouncyCastle.Crypto.Engines if (index == 0) { GenerateKeyStream(keyStream); - - if (++engineState[8] == 0) - { - ++engineState[9]; - } + AdvanceCounter(); } byte output = (byte)(keyStream[index] ^ input); @@ -105,6 +128,14 @@ namespace Org.BouncyCastle.Crypto.Engines return output; } + protected virtual void AdvanceCounter() + { + if (++engineState[8] == 0) + { + ++engineState[9]; + } + } + public void ProcessBytes( byte[] inBytes, int inOff, @@ -137,11 +168,7 @@ namespace Org.BouncyCastle.Crypto.Engines if (index == 0) { GenerateKeyStream(keyStream); - - if (++engineState[8] == 0) - { - ++engineState[9]; - } + AdvanceCounter(); } outBytes[i+outOff] = (byte)(keyStream[index]^inBytes[i+inOff]); index = (index + 1) & 63; @@ -150,28 +177,32 @@ namespace Org.BouncyCastle.Crypto.Engines public void Reset() { - SetKey(workingKey, workingIV); + index = 0; + ResetLimitCounter(); + ResetCounter(); } - // Private implementation + protected virtual void ResetCounter() + { + engineState[8] = engineState[9] = 0; + } - private void SetKey(byte[] keyBytes, byte[] ivBytes) + protected virtual void SetKey(byte[] keyBytes, byte[] ivBytes) { - workingKey = keyBytes; - workingIV = ivBytes; + if ((keyBytes.Length != 16) && (keyBytes.Length != 32)) { + throw new ArgumentException(AlgorithmName + " requires 128 bit or 256 bit key"); + } - index = 0; - ResetCounter(); int offset = 0; byte[] constants; // Key - engineState[1] = Pack.LE_To_UInt32(workingKey, 0); - engineState[2] = Pack.LE_To_UInt32(workingKey, 4); - engineState[3] = Pack.LE_To_UInt32(workingKey, 8); - engineState[4] = Pack.LE_To_UInt32(workingKey, 12); + engineState[1] = Pack.LE_To_UInt32(keyBytes, 0); + engineState[2] = Pack.LE_To_UInt32(keyBytes, 4); + engineState[3] = Pack.LE_To_UInt32(keyBytes, 8); + engineState[4] = Pack.LE_To_UInt32(keyBytes, 12); - if (workingKey.Length == 32) + if (keyBytes.Length == 32) { constants = sigma; offset = 16; @@ -181,83 +212,125 @@ namespace Org.BouncyCastle.Crypto.Engines constants = tau; } - engineState[11] = Pack.LE_To_UInt32(workingKey, offset); - engineState[12] = Pack.LE_To_UInt32(workingKey, offset + 4); - engineState[13] = Pack.LE_To_UInt32(workingKey, offset + 8); - engineState[14] = Pack.LE_To_UInt32(workingKey, offset + 12); + engineState[11] = Pack.LE_To_UInt32(keyBytes, offset); + engineState[12] = Pack.LE_To_UInt32(keyBytes, offset + 4); + engineState[13] = Pack.LE_To_UInt32(keyBytes, offset + 8); + engineState[14] = Pack.LE_To_UInt32(keyBytes, offset + 12); engineState[0] = Pack.LE_To_UInt32(constants, 0); engineState[5] = Pack.LE_To_UInt32(constants, 4); engineState[10] = Pack.LE_To_UInt32(constants, 8); engineState[15] = Pack.LE_To_UInt32(constants, 12); // IV - engineState[6] = Pack.LE_To_UInt32(workingIV, 0); - engineState[7] = Pack.LE_To_UInt32(workingIV, 4); - engineState[8] = engineState[9] = 0; - - initialised = true; + engineState[6] = Pack.LE_To_UInt32(ivBytes, 0); + engineState[7] = Pack.LE_To_UInt32(ivBytes, 4); + ResetCounter(); } - private void GenerateKeyStream(byte[] output) + protected virtual void GenerateKeyStream(byte[] output) { - SalsaCore(20, engineState, x); + SalsaCore(rounds, engineState, x); Pack.UInt32_To_LE(x, output, 0); } - internal static void SalsaCore(int rounds, uint[] state, uint[] x) + internal static void SalsaCore(int rounds, uint[] input, uint[] x) { - // TODO Exception if rounds odd? + if (input.Length != 16) { + throw new ArgumentException(); + } + if (x.Length != 16) { + throw new ArgumentException(); + } + if (rounds % 2 != 0) { + throw new ArgumentException("Number of rounds must be even"); + } - Array.Copy(state, 0, x, 0, state.Length); + uint x00 = input[ 0]; + uint x01 = input[ 1]; + uint x02 = input[ 2]; + uint x03 = input[ 3]; + uint x04 = input[ 4]; + uint x05 = input[ 5]; + uint x06 = input[ 6]; + uint x07 = input[ 7]; + uint x08 = input[ 8]; + uint x09 = input[ 9]; + uint x10 = input[10]; + uint x11 = input[11]; + uint x12 = input[12]; + uint x13 = input[13]; + uint x14 = input[14]; + uint x15 = input[15]; for (int i = rounds; i > 0; i -= 2) { - x[ 4] ^= R((x[ 0]+x[12]), 7); - x[ 8] ^= R((x[ 4]+x[ 0]), 9); - x[12] ^= R((x[ 8]+x[ 4]),13); - x[ 0] ^= R((x[12]+x[ 8]),18); - x[ 9] ^= R((x[ 5]+x[ 1]), 7); - x[13] ^= R((x[ 9]+x[ 5]), 9); - x[ 1] ^= R((x[13]+x[ 9]),13); - x[ 5] ^= R((x[ 1]+x[13]),18); - x[14] ^= R((x[10]+x[ 6]), 7); - x[ 2] ^= R((x[14]+x[10]), 9); - x[ 6] ^= R((x[ 2]+x[14]),13); - x[10] ^= R((x[ 6]+x[ 2]),18); - x[ 3] ^= R((x[15]+x[11]), 7); - x[ 7] ^= R((x[ 3]+x[15]), 9); - x[11] ^= R((x[ 7]+x[ 3]),13); - x[15] ^= R((x[11]+x[ 7]),18); - x[ 1] ^= R((x[ 0]+x[ 3]), 7); - x[ 2] ^= R((x[ 1]+x[ 0]), 9); - x[ 3] ^= R((x[ 2]+x[ 1]),13); - x[ 0] ^= R((x[ 3]+x[ 2]),18); - x[ 6] ^= R((x[ 5]+x[ 4]), 7); - x[ 7] ^= R((x[ 6]+x[ 5]), 9); - x[ 4] ^= R((x[ 7]+x[ 6]),13); - x[ 5] ^= R((x[ 4]+x[ 7]),18); - x[11] ^= R((x[10]+x[ 9]), 7); - x[ 8] ^= R((x[11]+x[10]), 9); - x[ 9] ^= R((x[ 8]+x[11]),13); - x[10] ^= R((x[ 9]+x[ 8]),18); - x[12] ^= R((x[15]+x[14]), 7); - x[13] ^= R((x[12]+x[15]), 9); - x[14] ^= R((x[13]+x[12]),13); - x[15] ^= R((x[14]+x[13]),18); + x04 ^= R((x00+x12), 7); + x08 ^= R((x04+x00), 9); + x12 ^= R((x08+x04),13); + x00 ^= R((x12+x08),18); + x09 ^= R((x05+x01), 7); + x13 ^= R((x09+x05), 9); + x01 ^= R((x13+x09),13); + x05 ^= R((x01+x13),18); + x14 ^= R((x10+x06), 7); + x02 ^= R((x14+x10), 9); + x06 ^= R((x02+x14),13); + x10 ^= R((x06+x02),18); + x03 ^= R((x15+x11), 7); + x07 ^= R((x03+x15), 9); + x11 ^= R((x07+x03),13); + x15 ^= R((x11+x07),18); + + x01 ^= R((x00+x03), 7); + x02 ^= R((x01+x00), 9); + x03 ^= R((x02+x01),13); + x00 ^= R((x03+x02),18); + x06 ^= R((x05+x04), 7); + x07 ^= R((x06+x05), 9); + x04 ^= R((x07+x06),13); + x05 ^= R((x04+x07),18); + x11 ^= R((x10+x09), 7); + x08 ^= R((x11+x10), 9); + x09 ^= R((x08+x11),13); + x10 ^= R((x09+x08),18); + x12 ^= R((x15+x14), 7); + x13 ^= R((x12+x15), 9); + x14 ^= R((x13+x12),13); + x15 ^= R((x14+x13),18); } - for (int i = 0; i < StateSize; ++i) - { - x[i] += state[i]; - } + x[ 0] = x00 + input[ 0]; + x[ 1] = x01 + input[ 1]; + x[ 2] = x02 + input[ 2]; + x[ 3] = x03 + input[ 3]; + x[ 4] = x04 + input[ 4]; + x[ 5] = x05 + input[ 5]; + x[ 6] = x06 + input[ 6]; + x[ 7] = x07 + input[ 7]; + x[ 8] = x08 + input[ 8]; + x[ 9] = x09 + input[ 9]; + x[10] = x10 + input[10]; + x[11] = x11 + input[11]; + x[12] = x12 + input[12]; + x[13] = x13 + input[13]; + x[14] = x14 + input[14]; + x[15] = x15 + input[15]; } - private static uint R(uint x, int y) + /** + * Rotate left + * + * @param x value to rotate + * @param y amount to rotate x + * + * @return rotated x + */ + internal static uint R(uint x, int y) { return (x << y) | (x >> (32 - y)); } - private void ResetCounter() + private void ResetLimitCounter() { cW0 = 0; cW1 = 0; diff --git a/crypto/src/crypto/engines/XSalsa20Engine.cs b/crypto/src/crypto/engines/XSalsa20Engine.cs new file mode 100644
index 000000000..fc6630905 --- /dev/null +++ b/crypto/src/crypto/engines/XSalsa20Engine.cs
@@ -0,0 +1,71 @@ +using System; + +using Org.BouncyCastle.Crypto.Utilities; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /// <summary> + /// Implementation of Daniel J. Bernstein's XSalsa20 stream cipher - Salsa20 with an extended nonce. + /// </summary> + /// <remarks> + /// XSalsa20 requires a 256 bit key, and a 192 bit nonce. + /// </remarks> + public class XSalsa20Engine + : Salsa20Engine + { + + public override string AlgorithmName + { + get { return "XSalsa20"; } + } + + protected override int NonceSize + { + get { return 24; } + } + + /// <summary> + /// XSalsa20 key generation: process 256 bit input key and 128 bits of the input nonce + /// using a core Salsa20 function without input addition to produce 256 bit working key + /// and use that with the remaining 64 bits of nonce to initialize a standard Salsa20 engine state. + /// </summary> + protected override void SetKey(byte[] keyBytes, byte[] ivBytes) + { + if (keyBytes.Length != 32) + { + throw new ArgumentException(AlgorithmName + " requires a 256 bit key"); + } + + // Set key for HSalsa20 + base.SetKey(keyBytes, ivBytes); + + // Pack next 64 bits of IV into engine state instead of counter + engineState[8] = Pack.LE_To_UInt32(ivBytes, 8); + engineState[9] = Pack.LE_To_UInt32(ivBytes, 12); + + // Process engine state to generate Salsa20 key + uint[] hsalsa20Out = new uint[engineState.Length]; + SalsaCore(20, engineState, hsalsa20Out); + + // Set new key, removing addition in last round of salsaCore + engineState[1] = hsalsa20Out[0] - engineState[0]; + engineState[2] = hsalsa20Out[5] - engineState[5]; + engineState[3] = hsalsa20Out[10] - engineState[10]; + engineState[4] = hsalsa20Out[15] - engineState[15]; + + engineState[11] = hsalsa20Out[6] - engineState[6]; + engineState[12] = hsalsa20Out[7] - engineState[7]; + engineState[13] = hsalsa20Out[8] - engineState[8]; + engineState[14] = hsalsa20Out[9] - engineState[9]; + + // Last 64 bits of input IV + engineState[6] = Pack.LE_To_UInt32(ivBytes, 16); + engineState[7] = Pack.LE_To_UInt32(ivBytes, 20); + + // Counter reset + ResetCounter(); + } + + } +} + diff --git a/crypto/src/crypto/generators/ECKeyPairGenerator.cs b/crypto/src/crypto/generators/ECKeyPairGenerator.cs
index 8f2b1c2b5..a936755e2 100644 --- a/crypto/src/crypto/generators/ECKeyPairGenerator.cs +++ b/crypto/src/crypto/generators/ECKeyPairGenerator.cs
@@ -81,6 +81,11 @@ namespace Org.BouncyCastle.Crypto.Generators } this.random = parameters.Random; + + if (this.random == null) + { + this.random = new SecureRandom(); + } } /** diff --git a/crypto/src/crypto/generators/Poly1305KeyGenerator.cs b/crypto/src/crypto/generators/Poly1305KeyGenerator.cs new file mode 100644
index 000000000..5deb50f07 --- /dev/null +++ b/crypto/src/crypto/generators/Poly1305KeyGenerator.cs
@@ -0,0 +1,123 @@ +using System; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Macs; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Crypto.Generators +{ + /// <summary> + /// Generates keys for the Poly1305 MAC. + /// </summary> + /// <remarks> + /// Poly1305 keys are 256 bit keys consisting of a 128 bit secret key used for the underlying block + /// cipher followed by a 128 bit {@code r} value used for the polynomial portion of the Mac. <br/> + /// The {@code r} value has a specific format with some bits required to be cleared, resulting in an + /// effective 106 bit key. <br/> + /// A separately generated 256 bit key can be modified to fit the Poly1305 key format by using the + /// {@link #clamp(byte[])} method to clear the required bits. + /// </remarks> + /// <seealso cref="Poly1305"/> + public class Poly1305KeyGenerator + : CipherKeyGenerator + { + private const byte R_MASK_LOW_2 = (byte)0xFC; + private const byte R_MASK_HIGH_4 = (byte)0x0F; + + /// <summary> + /// Initialises the key generator. + /// </summary> + /// <remarks> + /// Poly1305 keys are always 256 bits, so the key length in the provided parameters is ignored. + /// </remarks> + protected override void engineInit(KeyGenerationParameters param) + { + // Poly1305 keys are always 256 bits + this.random = param.Random; + this.strength = 32; + } + + /// <summary> + /// Generates a 256 bit key in the format required for Poly1305 - e.g. + /// <code>k[0] ... k[15], r[0] ... r[15]</code> with the required bits in <code>r</code> cleared + /// as per <see cref="Clamp(byte[])"/>. + /// </summary> + protected override byte[] engineGenerateKey() + { + byte[] key = base.engineGenerateKey(); + Clamp(key); + return key; + } + + /// <summary> + /// Modifies an existing 32 byte key value to comply with the requirements of the Poly1305 key by + /// clearing required bits in the <code>r</code> (second 16 bytes) portion of the key.<br/> + /// Specifically: + /// <ul> + /// <li>r[3], r[7], r[11], r[15] have top four bits clear (i.e., are {0, 1, . . . , 15})</li> + /// <li>r[4], r[8], r[12] have bottom two bits clear (i.e., are in {0, 4, 8, . . . , 252})</li> + /// </ul> + /// </summary> + /// <param name="key">a 32 byte key value <code>k[0] ... k[15], r[0] ... r[15]</code></param> + public static void Clamp(byte[] key) + { + /* + * Key is k[0] ... k[15], r[0] ... r[15] as per poly1305_aes_clamp in ref impl. + */ + if (key.Length != 32) + { + throw new ArgumentException("Poly1305 key must be 256 bits."); + } + + /* + * r[3], r[7], r[11], r[15] have top four bits clear (i.e., are {0, 1, . . . , 15}) + */ + key[19] &= R_MASK_HIGH_4; + key[23] &= R_MASK_HIGH_4; + key[27] &= R_MASK_HIGH_4; + key[31] &= R_MASK_HIGH_4; + + /* + * r[4], r[8], r[12] have bottom two bits clear (i.e., are in {0, 4, 8, . . . , 252}). + */ + key[20] &= R_MASK_LOW_2; + key[24] &= R_MASK_LOW_2; + key[28] &= R_MASK_LOW_2; + } + + /// <summary> + /// Checks a 32 byte key for compliance with the Poly1305 key requirements, e.g. + /// <code>k[0] ... k[15], r[0] ... r[15]</code> with the required bits in <code>r</code> cleared + /// as per <see cref="Clamp(byte[])"/>. + /// </summary> + /// <param name="key">Key.</param> + /// <exception cref="System.ArgumentException">if the key is of the wrong length, or has invalid bits set + /// in the <code>r</code> portion of the key.</exception> + public static void CheckKey(byte[] key) + { + if (key.Length != 32) + { + throw new ArgumentException("Poly1305 key must be 256 bits."); + } + + checkMask(key[19], R_MASK_HIGH_4); + checkMask(key[23], R_MASK_HIGH_4); + checkMask(key[27], R_MASK_HIGH_4); + checkMask(key[31], R_MASK_HIGH_4); + + checkMask(key[20], R_MASK_LOW_2); + checkMask(key[24], R_MASK_LOW_2); + checkMask(key[28], R_MASK_LOW_2); + } + + private static void checkMask(byte b, byte mask) + { + if ((b & (~mask)) != 0) + { + throw new ArgumentException("Invalid format for r portion of Poly1305 key."); + } + } + + } +} \ No newline at end of file diff --git a/crypto/src/crypto/macs/CMac.cs b/crypto/src/crypto/macs/CMac.cs
index b55a05605..682c12bac 100644 --- a/crypto/src/crypto/macs/CMac.cs +++ b/crypto/src/crypto/macs/CMac.cs
@@ -107,7 +107,7 @@ namespace Org.BouncyCastle.Crypto.Macs private static int ShiftLeft(byte[] block, byte[] output) { - int i = 16; + int i = block.Length; uint bit = 0; while (--i >= 0) { diff --git a/crypto/src/crypto/macs/GMac.cs b/crypto/src/crypto/macs/GMac.cs new file mode 100644
index 000000000..eb340ddbc --- /dev/null +++ b/crypto/src/crypto/macs/GMac.cs
@@ -0,0 +1,111 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Modes; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Macs +{ + /// <summary> + /// The GMAC specialisation of Galois/Counter mode (GCM) detailed in NIST Special Publication + /// 800-38D. + /// </summary> + /// <remarks> + /// GMac is an invocation of the GCM mode where no data is encrypted (i.e. all input data to the Mac + /// is processed as additional authenticated data with the underlying GCM block cipher). + /// </remarks> + public class GMac + : IMac + { + private readonly GcmBlockCipher cipher; + private readonly int macSizeBits; + + /// <summary> + /// Creates a GMAC based on the operation of a block cipher in GCM mode. + /// </summary> + /// <remarks> + /// This will produce an authentication code the length of the block size of the cipher. + /// </remarks> + /// <param name="cipher">the cipher to be used in GCM mode to generate the MAC.</param> + public GMac(GcmBlockCipher cipher) + : this(cipher, 128) + { + } + + /// <summary> + /// Creates a GMAC based on the operation of a 128 bit block cipher in GCM mode. + /// </summary> + /// <remarks> + /// This will produce an authentication code the length of the block size of the cipher. + /// </remarks> + /// <param name="cipher">the cipher to be used in GCM mode to generate the MAC.</param> + /// <param name="macSizeBits">the mac size to generate, in bits. Must be a multiple of 8, between 96 and 128 (inclusive).</param> + public GMac(GcmBlockCipher cipher, int macSizeBits) + { + this.cipher = cipher; + this.macSizeBits = macSizeBits; + } + + /// <summary> + /// Initialises the GMAC - requires a <see cref="Org.BouncyCastle.Crypto.Parameters.ParametersWithIV"/> + /// providing a <see cref="Org.BouncyCastle.Crypto.Parameters.KeyParameter"/> and a nonce. + /// </summary> + public void Init(ICipherParameters parameters) + { + if (parameters is ParametersWithIV) + { + ParametersWithIV param = (ParametersWithIV)parameters; + + byte[] iv = param.GetIV(); + KeyParameter keyParam = (KeyParameter)param.Parameters; + + // GCM is always operated in encrypt mode to calculate MAC + cipher.Init(true, new AeadParameters(keyParam, macSizeBits, iv)); + } + else + { + throw new ArgumentException("GMAC requires ParametersWithIV"); + } + } + + public string AlgorithmName + { + get { return cipher.GetUnderlyingCipher().AlgorithmName + "-GMAC"; } + } + + public int GetMacSize() + { + return macSizeBits / 8; + } + + public void Update(byte input) + { + cipher.ProcessAadByte(input); + } + + public void BlockUpdate(byte[] input, int inOff, int len) + { + cipher.ProcessAadBytes(input, inOff, len); + } + + public int DoFinal(byte[] output, int outOff) + { + try + { + return cipher.DoFinal(output, outOff); + } + catch (InvalidCipherTextException e) + { + // Impossible in encrypt mode + throw new InvalidOperationException(e.ToString()); + } + } + + public void Reset() + { + cipher.Reset(); + } + } +} diff --git a/crypto/src/crypto/macs/Poly1305.cs b/crypto/src/crypto/macs/Poly1305.cs new file mode 100644
index 000000000..2d453b6ad --- /dev/null +++ b/crypto/src/crypto/macs/Poly1305.cs
@@ -0,0 +1,272 @@ +using System; + +using Org.BouncyCastle.Crypto.Generators; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Crypto.Utilities; + +namespace Org.BouncyCastle.Crypto.Macs +{ + + /// <summary> + /// Poly1305 message authentication code, designed by D. J. Bernstein. + /// </summary> + /// <remarks> + /// Poly1305 computes a 128-bit (16 bytes) authenticator, using a 128 bit nonce and a 256 bit key + /// consisting of a 128 bit key applied to an underlying cipher, and a 128 bit key (with 106 + /// effective key bits) used in the authenticator. + /// + /// The polynomial calculation in this implementation is adapted from the public domain <a + /// href="https://github.com/floodyberry/poly1305-donna">poly1305-donna-unrolled</a> C implementation + /// by Andrew M (@floodyberry). + /// </remarks> + /// <seealso cref="Org.BouncyCastle.Crypto.Generators.Poly1305KeyGenerator"/> + public class Poly1305 + : IMac + { + private const int BLOCK_SIZE = 16; + + private readonly IBlockCipher cipher; + + private readonly byte[] singleByte = new byte[1]; + + // Initialised state + + /** Polynomial key */ + private uint r0, r1, r2, r3, r4; + + /** Precomputed 5 * r[1..4] */ + private uint s1, s2, s3, s4; + + /** Encrypted nonce */ + private uint k0, k1, k2, k3; + + // Accumulating state + + /** Current block of buffered input */ + private byte[] currentBlock = new byte[BLOCK_SIZE]; + + /** Current offset in input buffer */ + private int currentBlockOffset = 0; + + /** Polynomial accumulator */ + private uint h0, h1, h2, h3, h4; + + /** + * Constructs a Poly1305 MAC, using a 128 bit block cipher. + */ + public Poly1305(IBlockCipher cipher) + { + if (cipher.GetBlockSize() != BLOCK_SIZE) + { + throw new ArgumentException("Poly1305 requires a 128 bit block cipher."); + } + this.cipher = cipher; + } + + /// <summary> + /// Initialises the Poly1305 MAC. + /// </summary> + /// <param name="parameters">a {@link ParametersWithIV} containing a 128 bit nonce and a {@link KeyParameter} with + /// a 256 bit key complying to the {@link Poly1305KeyGenerator Poly1305 key format}.</param> + public void Init(ICipherParameters parameters) + { + byte[] nonce; + byte[] key; + if ((parameters is ParametersWithIV) && ((ParametersWithIV)parameters).Parameters is KeyParameter) + { + nonce = ((ParametersWithIV)parameters).GetIV(); + key = ((KeyParameter)((ParametersWithIV)parameters).Parameters).GetKey(); + } + else + { + throw new ArgumentException("Poly1305 requires a key and and IV."); + } + + setKey(key, nonce); + Reset(); + } + + private void setKey(byte[] key, byte[] nonce) + { + if (nonce.Length != BLOCK_SIZE) + { + throw new ArgumentException("Poly1305 requires a 128 bit IV."); + } + Poly1305KeyGenerator.CheckKey(key); + + // Extract r portion of key + uint t0 = Pack.LE_To_UInt32(key, BLOCK_SIZE + 0); + uint t1 = Pack.LE_To_UInt32(key, BLOCK_SIZE + 4); + uint t2 = Pack.LE_To_UInt32(key, BLOCK_SIZE + 8); + uint t3 = Pack.LE_To_UInt32(key, BLOCK_SIZE + 12); + + r0 = t0 & 0x3ffffff; t0 >>= 26; t0 |= t1 << 6; + r1 = t0 & 0x3ffff03; t1 >>= 20; t1 |= t2 << 12; + r2 = t1 & 0x3ffc0ff; t2 >>= 14; t2 |= t3 << 18; + r3 = t2 & 0x3f03fff; t3 >>= 8; + r4 = t3 & 0x00fffff; + + // Precompute multipliers + s1 = r1 * 5; + s2 = r2 * 5; + s3 = r3 * 5; + s4 = r4 * 5; + + // Compute encrypted nonce + byte[] cipherKey = new byte[BLOCK_SIZE]; + Array.Copy(key, 0, cipherKey, 0, cipherKey.Length); + + cipher.Init(true, new KeyParameter(cipherKey)); + cipher.ProcessBlock(nonce, 0, cipherKey, 0); + + k0 = Pack.LE_To_UInt32(cipherKey, 0); + k1 = Pack.LE_To_UInt32(cipherKey, 4); + k2 = Pack.LE_To_UInt32(cipherKey, 8); + k3 = Pack.LE_To_UInt32(cipherKey, 12); + } + + public string AlgorithmName + { + get { return "Poly1305-" + cipher.AlgorithmName; } + } + + public int GetMacSize() + { + return BLOCK_SIZE; + } + + public void Update(byte input) + { + singleByte[0] = input; + BlockUpdate(singleByte, 0, 1); + } + + public void BlockUpdate(byte[] input, int inOff, int len) + { + int copied = 0; + while (len > copied) + { + if (currentBlockOffset == BLOCK_SIZE) + { + processBlock(); + currentBlockOffset = 0; + } + + int toCopy = System.Math.Min((len - copied), BLOCK_SIZE - currentBlockOffset); + Array.Copy(input, copied + inOff, currentBlock, currentBlockOffset, toCopy); + copied += toCopy; + currentBlockOffset += toCopy; + } + + } + + private void processBlock() + { + if (currentBlockOffset < BLOCK_SIZE) + { + currentBlock[currentBlockOffset] = 1; + for (int i = currentBlockOffset + 1; i < BLOCK_SIZE; i++) + { + currentBlock[i] = 0; + } + } + + ulong t0 = Pack.LE_To_UInt32(currentBlock, 0); + ulong t1 = Pack.LE_To_UInt32(currentBlock, 4); + ulong t2 = Pack.LE_To_UInt32(currentBlock, 8); + ulong t3 = Pack.LE_To_UInt32(currentBlock, 12); + + h0 += (uint)(t0 & 0x3ffffffU); + h1 += (uint)((((t1 << 32) | t0) >> 26) & 0x3ffffff); + h2 += (uint)((((t2 << 32) | t1) >> 20) & 0x3ffffff); + h3 += (uint)((((t3 << 32) | t2) >> 14) & 0x3ffffff); + h4 += (uint)(t3 >> 8); + + if (currentBlockOffset == BLOCK_SIZE) + { + h4 += (1 << 24); + } + + ulong tp0 = mul32x32_64(h0,r0) + mul32x32_64(h1,s4) + mul32x32_64(h2,s3) + mul32x32_64(h3,s2) + mul32x32_64(h4,s1); + ulong tp1 = mul32x32_64(h0,r1) + mul32x32_64(h1,r0) + mul32x32_64(h2,s4) + mul32x32_64(h3,s3) + mul32x32_64(h4,s2); + ulong tp2 = mul32x32_64(h0,r2) + mul32x32_64(h1,r1) + mul32x32_64(h2,r0) + mul32x32_64(h3,s4) + mul32x32_64(h4,s3); + 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); + } + + public int DoFinal(byte[] output, int outOff) + { + if (outOff + BLOCK_SIZE > output.Length) + { + throw new DataLengthException("Output buffer is too short."); + } + + if (currentBlockOffset > 0) + { + // Process padded block + 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; + + uint g0, g1, g2, g3, g4; + g0 = h0 + 5; b = g0 >> 26; g0 &= 0x3ffffff; + g1 = h1 + b; b = g1 >> 26; g1 &= 0x3ffffff; + g2 = h2 + b; b = g2 >> 26; g2 &= 0x3ffffff; + g3 = h3 + b; b = g3 >> 26; g3 &= 0x3ffffff; + g4 = h4 + b - (1 << 26); + + b = (g4 >> 31) - 1; + uint nb = ~b; + h0 = (h0 & nb) | (g0 & b); + h1 = (h1 & nb) | (g1 & b); + h2 = (h2 & nb) | (g2 & b); + h3 = (h3 & nb) | (g3 & b); + h4 = (h4 & nb) | (g4 & b); + + f0 = ((h0 ) | (h1 << 26)) + (ulong)k0; + f1 = ((h1 >> 6 ) | (h2 << 20)) + (ulong)k1; + f2 = ((h2 >> 12) | (h3 << 14)) + (ulong)k2; + f3 = ((h3 >> 18) | (h4 << 8 )) + (ulong)k3; + + Pack.UInt32_To_LE((uint)f0, output, outOff); + f1 += (f0 >> 32); + Pack.UInt32_To_LE((uint)f1, output, outOff + 4); + f2 += (f1 >> 32); + Pack.UInt32_To_LE((uint)f2, output, outOff + 8); + f3 += (f2 >> 32); + Pack.UInt32_To_LE((uint)f3, output, outOff + 12); + + Reset(); + return BLOCK_SIZE; + } + + public void Reset() + { + currentBlockOffset = 0; + + h0 = h1 = h2 = h3 = h4 = 0; + } + + private static ulong mul32x32_64(uint i1, uint i2) + { + return ((ulong)i1) * i2; + } + } +} diff --git a/crypto/src/crypto/modes/EAXBlockCipher.cs b/crypto/src/crypto/modes/EAXBlockCipher.cs
index bb027b597..5ccc69b66 100644 --- a/crypto/src/crypto/modes/EAXBlockCipher.cs +++ b/crypto/src/crypto/modes/EAXBlockCipher.cs
@@ -65,6 +65,11 @@ namespace Org.BouncyCastle.Crypto.Modes get { return cipher.GetUnderlyingCipher().AlgorithmName + "/EAX"; } } + public IBlockCipher GetUnderlyingCipher() + { + return cipher; + } + public virtual int GetBlockSize() { return cipher.GetBlockSize(); diff --git a/crypto/src/crypto/modes/GCMBlockCipher.cs b/crypto/src/crypto/modes/GCMBlockCipher.cs
index 95fe6f7ec..74b895e7b 100644 --- a/crypto/src/crypto/modes/GCMBlockCipher.cs +++ b/crypto/src/crypto/modes/GCMBlockCipher.cs
@@ -69,6 +69,11 @@ namespace Org.BouncyCastle.Crypto.Modes get { return cipher.AlgorithmName + "/GCM"; } } + public IBlockCipher GetUnderlyingCipher() + { + return cipher; + } + public virtual int GetBlockSize() { return BlockSize; diff --git a/crypto/src/crypto/modes/IAeadBlockCipher.cs b/crypto/src/crypto/modes/IAeadBlockCipher.cs
index 06bc50488..52c4ff428 100644 --- a/crypto/src/crypto/modes/IAeadBlockCipher.cs +++ b/crypto/src/crypto/modes/IAeadBlockCipher.cs
@@ -11,6 +11,9 @@ namespace Org.BouncyCastle.Crypto.Modes /// <summary>The name of the algorithm this cipher implements.</summary> string AlgorithmName { get; } + /// <summary>The block cipher underlying this algorithm.</summary> + IBlockCipher GetUnderlyingCipher(); + /// <summary>Initialise the cipher.</summary> /// <remarks>Parameter can either be an AeadParameters or a ParametersWithIV object.</remarks> /// <param name="forEncryption">Initialise for encryption if true, for decryption if false.</param> diff --git a/crypto/src/crypto/tls/AlertDescription.cs b/crypto/src/crypto/tls/AlertDescription.cs
index e1229a4a3..e09da6cab 100644 --- a/crypto/src/crypto/tls/AlertDescription.cs +++ b/crypto/src/crypto/tls/AlertDescription.cs
@@ -1,47 +1,217 @@ namespace Org.BouncyCastle.Crypto.Tls { - /// <summary> - /// RFC 2246 7.2 - /// </summary> - public enum AlertDescription : byte - { - close_notify = 0, - unexpected_message = 10, - bad_record_mac = 20, - decryption_failed = 21, - record_overflow = 22, - decompression_failure = 30, - handshake_failure = 40, - /* 41 is not defined, for historical reasons */ - bad_certificate = 42, - unsupported_certificate = 43, - certificate_revoked = 44, - certificate_expired = 45, - certificate_unknown = 46, - illegal_parameter = 47, - unknown_ca = 48, - access_denied = 49, - decode_error = 50, - decrypt_error = 51, - export_restriction = 60, - protocol_version = 70, - insufficient_security = 71, - internal_error = 80, - user_canceled = 90, - no_renegotiation = 100, - - /* - * RFC 3546 - */ - unsupported_extension = 110, - certificate_unobtainable = 111, - unrecognized_name = 112, - bad_certificate_status_response = 113, - bad_certificate_hash_value = 114, - - /* - * RFC 4279 - */ - unknown_psk_identity = 115, - } + /// <summary> + /// RFC 5246 7.2 + /// </summary> + public abstract class AlertDescription + { + /** + * This message notifies the recipient that the sender will not send any more messages on this + * connection. Note that as of TLS 1.1, failure to properly close a connection no longer + * requires that a session not be resumed. This is a change from TLS 1.0 ("The session becomes + * unresumable if any connection is terminated without proper close_notify messages with level + * equal to warning.") to conform with widespread implementation practice. + */ + public const byte close_notify = 0; + + /** + * An inappropriate message was received. This alert is always fatal and should never be + * observed in communication between proper implementations. + */ + public const byte unexpected_message = 10; + + /** + * This alert is returned if a record is received with an incorrect MAC. This alert also MUST be + * returned if an alert is sent because a TLSCiphertext decrypted in an invalid way: either it + * wasn't an even multiple of the block length, or its padding values, when checked, weren't + * correct. This message is always fatal and should never be observed in communication between + * proper implementations (except when messages were corrupted in the network). + */ + public const byte bad_record_mac = 20; + + /** + * This alert was used in some earlier versions of TLS, and may have permitted certain attacks + * against the CBC mode [CBCATT]. It MUST NOT be sent by compliant implementations. + */ + public const byte decryption_failed = 21; + + /** + * A TLSCiphertext record was received that had a length more than 2^14+2048 bytes, or a record + * decrypted to a TLSCompressed record with more than 2^14+1024 bytes. This message is always + * fatal and should never be observed in communication between proper implementations (except + * when messages were corrupted in the network). + */ + public const byte record_overflow = 22; + + /** + * The decompression function received improper input (e.g., data that would expand to excessive + * length). This message is always fatal and should never be observed in communication between + * proper implementations. + */ + public const byte decompression_failure = 30; + + /** + * Reception of a handshake_failure alert message indicates that the sender was unable to + * negotiate an acceptable set of security parameters given the options available. This is a + * fatal error. + */ + public const byte handshake_failure = 40; + + /** + * This alert was used in SSLv3 but not any version of TLS. It MUST NOT be sent by compliant + * implementations. + */ + public const byte no_certificate = 41; + + /** + * A certificate was corrupt, contained signatures that did not verify correctly, etc. + */ + public const byte bad_certificate = 42; + + /** + * A certificate was of an unsupported type. + */ + public const byte unsupported_certificate = 43; + + /** + * A certificate was revoked by its signer. + */ + public const byte certificate_revoked = 44; + + /** + * A certificate has expired or is not currently valid. + */ + public const byte certificate_expired = 45; + + /** + * Some other (unspecified) issue arose in processing the certificate, rendering it + * unacceptable. + */ + public const byte certificate_unknown = 46; + + /** + * A field in the handshake was out of range or inconsistent with other fields. This message is + * always fatal. + */ + public const byte illegal_parameter = 47; + + /** + * A valid certificate chain or partial chain was received, but the certificate was not accepted + * because the CA certificate could not be located or couldn't be matched with a known, trusted + * CA. This message is always fatal. + */ + public const byte unknown_ca = 48; + + /** + * A valid certificate was received, but when access control was applied, the sender decided not + * to proceed with negotiation. This message is always fatal. + */ + public const byte access_denied = 49; + + /** + * A message could not be decoded because some field was out of the specified range or the + * length of the message was incorrect. This message is always fatal and should never be + * observed in communication between proper implementations (except when messages were corrupted + * in the network). + */ + public const byte decode_error = 50; + + /** + * A handshake cryptographic operation failed, including being unable to correctly verify a + * signature or validate a Finished message. This message is always fatal. + */ + public const byte decrypt_error = 51; + + /** + * This alert was used in some earlier versions of TLS. It MUST NOT be sent by compliant + * implementations. + */ + public const byte export_restriction = 60; + + /** + * The protocol version the client has attempted to negotiate is recognized but not supported. + * (For example, old protocol versions might be avoided for security reasons.) This message is + * always fatal. + */ + public const byte protocol_version = 70; + + /** + * Returned instead of handshake_failure when a negotiation has failed specifically because the + * server requires ciphers more secure than those supported by the client. This message is + * always fatal. + */ + public const byte insufficient_security = 71; + + /** + * An internal error unrelated to the peer or the correctness of the protocol (such as a memory + * allocation failure) makes it impossible to continue. This message is always fatal. + */ + public const byte internal_error = 80; + + /** + * This handshake is being canceled for some reason unrelated to a protocol failure. If the user + * cancels an operation after the handshake is complete, just closing the connection by sending + * a close_notify is more appropriate. This alert should be followed by a close_notify. This + * message is generally a warning. + */ + public const byte user_canceled = 90; + + /** + * Sent by the client in response to a hello request or by the server in response to a client + * hello after initial handshaking. Either of these would normally lead to renegotiation; when + * that is not appropriate, the recipient should respond with this alert. At that point, the + * original requester can decide whether to proceed with the connection. One case where this + * would be appropriate is where a server has spawned a process to satisfy a request; the + * process might receive security parameters (key length, authentication, etc.) at startup, and + * it might be difficult to communicate changes to these parameters after that point. This + * message is always a warning. + */ + public const byte no_renegotiation = 100; + + /** + * Sent by clients that receive an extended server hello containing an extension that they did + * not put in the corresponding client hello. This message is always fatal. + */ + public const byte unsupported_extension = 110; + + /* + * RFC 3546 + */ + + /** + * This alert is sent by servers who are unable to retrieve a certificate chain from the URL + * supplied by the client (see Section 3.3). This message MAY be fatal - for example if client + * authentication is required by the server for the handshake to continue and the server is + * unable to retrieve the certificate chain, it may send a fatal alert. + */ + public const byte certificate_unobtainable = 111; + + /** + * This alert is sent by servers that receive a server_name extension request, but do not + * recognize the server name. This message MAY be fatal. + */ + public const byte unrecognized_name = 112; + + /** + * This alert is sent by clients that receive an invalid certificate status response (see + * Section 3.6). This message is always fatal. + */ + public const byte bad_certificate_status_response = 113; + + /** + * This alert is sent by servers when a certificate hash does not match a client provided + * certificate_hash. This message is always fatal. + */ + public const byte bad_certificate_hash_value = 114; + + /* + * RFC 4279 + */ + + /** + * If the server does not recognize the PSK identity, it MAY respond with an + * "unknown_psk_identity" alert message. + */ + public const byte unknown_psk_identity = 115; + } } diff --git a/crypto/src/crypto/tls/AlertLevel.cs b/crypto/src/crypto/tls/AlertLevel.cs
index afb04308b..d77251dfb 100644 --- a/crypto/src/crypto/tls/AlertLevel.cs +++ b/crypto/src/crypto/tls/AlertLevel.cs
@@ -1,11 +1,11 @@ namespace Org.BouncyCastle.Crypto.Tls { - /// <summary> - /// RFC 2246 7.2 - /// </summary> - public enum AlertLevel : byte - { - warning = 1, - fatal = 2, - } + /// <summary> + /// RFC 5246 7.2 + /// </summary> + public abstract class AlertLevel + { + public const byte warning = 1; + public const byte fatal = 2; + } } diff --git a/crypto/src/crypto/tls/ByteQueue.cs b/crypto/src/crypto/tls/ByteQueue.cs
index c3ce91402..f9398bbaf 100644 --- a/crypto/src/crypto/tls/ByteQueue.cs +++ b/crypto/src/crypto/tls/ByteQueue.cs
@@ -68,13 +68,13 @@ namespace Org.BouncyCastle.Crypto.Tls int len, int skip) { - if ((available - skip) < len) + if ((buf.Length - offset) < len) { - throw new TlsException("Not enough data to read"); + throw new ArgumentException("Buffer size of " + buf.Length + " is too small for a read of " + len + " bytes"); } - if ((buf.Length - offset) < len) + if ((available - skip) < len) { - throw new TlsException("Buffer size of " + buf.Length + " is too small for a read of " + len + " bytes"); + throw new InvalidOperationException("Not enough data to read"); } Array.Copy(databuf, skipped + skip, buf, offset, len); } @@ -115,7 +115,7 @@ namespace Org.BouncyCastle.Crypto.Tls { if (i > available) { - throw new TlsException("Cannot remove " + i + " bytes, only got " + available); + throw new InvalidOperationException("Cannot remove " + i + " bytes, only got " + available); } /* diff --git a/crypto/src/crypto/tls/Certificate.cs b/crypto/src/crypto/tls/Certificate.cs
index e4df041e2..12bfa9214 100644 --- a/crypto/src/crypto/tls/Certificate.cs +++ b/crypto/src/crypto/tls/Certificate.cs
@@ -8,104 +8,136 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Crypto.Tls { - /** - * A representation for a certificate chain. - */ - public class Certificate - { - public static readonly Certificate EmptyChain = new Certificate(new X509CertificateStructure[0]); - - /** - * The certificates. - */ - internal X509CertificateStructure[] certs; - - /** - * Parse the ServerCertificate message. - * - * @param inStr The stream where to parse from. - * @return A Certificate object with the certs, the server has sended. - * @throws IOException If something goes wrong during parsing. - */ - internal static Certificate Parse( - Stream inStr) - { - int left = TlsUtilities.ReadUint24(inStr); - if (left == 0) - { - return EmptyChain; - } - IList tmp = Platform.CreateArrayList(); - while (left > 0) - { - int size = TlsUtilities.ReadUint24(inStr); - left -= 3 + size; - byte[] buf = new byte[size]; - TlsUtilities.ReadFully(buf, inStr); - MemoryStream bis = new MemoryStream(buf, false); - Asn1Object o = Asn1Object.FromStream(bis); - tmp.Add(X509CertificateStructure.GetInstance(o)); - if (bis.Position < bis.Length) - { - throw new ArgumentException("Sorry, there is garbage data left after the certificate"); - } - } - X509CertificateStructure[] certs = new X509CertificateStructure[tmp.Count]; - for (int i = 0; i < tmp.Count; ++i) + /** + * Parsing and encoding of a <i>Certificate</i> struct from RFC 4346. + * <p/> + * <pre> + * opaque ASN.1Cert&lt;2^24-1&gt;; + * + * struct { + * ASN.1Cert certificate_list&lt;0..2^24-1&gt;; + * } Certificate; + * </pre> + * + * @see Org.BouncyCastle.Asn1.X509.X509CertificateStructure + */ + public class Certificate + { + public static readonly Certificate EmptyChain = new Certificate(new X509CertificateStructure[0]); + + /** + * The certificates. + */ + protected readonly X509CertificateStructure[] mCertificateList; + + public Certificate(X509CertificateStructure[] certificateList) + { + if (certificateList == null) + throw new ArgumentNullException("certificateList"); + + this.mCertificateList = certificateList; + } + + /// <returns>An array which contains the certs, this chain contains.</returns> + [Obsolete("Use 'GetCertificateList' instead")] + public virtual X509CertificateStructure[] GetCerts() + { + return GetCertificateList(); + } + + /** + * @return an array of {@link org.bouncycastle.asn1.x509.Certificate} representing a certificate + * chain. + */ + public virtual X509CertificateStructure[] GetCertificateList() + { + return CloneCertificateList(); + } + + public virtual X509CertificateStructure GetCertificateAt(int index) + { + return mCertificateList[index]; + } + + public virtual int Length + { + get { return mCertificateList.Length; } + } + + /** + * @return <code>true</code> if this certificate chain contains no certificates, or + * <code>false</code> otherwise. + */ + public virtual bool IsEmpty + { + get { return mCertificateList.Length == 0; } + } + + /** + * Encode this {@link Certificate} to a {@link Stream}. + * + * @param output the {@link Stream} to encode to. + * @throws IOException + */ + public virtual void Encode(Stream output) + { + IList derEncodings = Platform.CreateArrayList(mCertificateList.Length); + + int totalLength = 0; + foreach (Asn1Encodable asn1Cert in mCertificateList) + { + byte[] derEncoding = asn1Cert.GetEncoded(Asn1Encodable.Der); + derEncodings.Add(derEncoding); + totalLength += derEncoding.Length + 3; + } + + TlsUtilities.CheckUint24(totalLength); + TlsUtilities.WriteUint24(totalLength, output); + + foreach (byte[] derEncoding in derEncodings) + { + TlsUtilities.WriteOpaque24(derEncoding, output); + } + } + + /** + * Parse a {@link Certificate} from a {@link Stream}. + * + * @param input the {@link Stream} to parse from. + * @return a {@link Certificate} object. + * @throws IOException + */ + public static Certificate Parse(Stream input) + { + int totalLength = TlsUtilities.ReadUint24(input); + if (totalLength == 0) { - certs[i] = (X509CertificateStructure)tmp[i]; + return EmptyChain; } - return new Certificate(certs); - } - - /** - * Encodes version of the ClientCertificate message - * - * @param outStr stream to write the message to - * @throws IOException If something goes wrong - */ - internal void Encode( - Stream outStr) - { - IList encCerts = Platform.CreateArrayList(); - int totalSize = 0; - foreach (X509CertificateStructure cert in certs) - { - byte[] encCert = cert.GetEncoded(Asn1Encodable.Der); - encCerts.Add(encCert); - totalSize += encCert.Length + 3; - } - - TlsUtilities.WriteUint24(totalSize, outStr); - - foreach (byte[] encCert in encCerts) - { - TlsUtilities.WriteOpaque24(encCert, outStr); - } - } - - /** - * Private constructor from a cert array. - * - * @param certs The certs the chain should contain. - */ - public Certificate(X509CertificateStructure[] certs) - { - if (certs == null) - throw new ArgumentNullException("certs"); - - this.certs = certs; - } - - /// <returns>An array which contains the certs, this chain contains.</returns> - public X509CertificateStructure[] GetCerts() - { - return (X509CertificateStructure[]) certs.Clone(); - } - - public bool IsEmpty - { - get { return certs.Length == 0; } - } - } + + byte[] certListData = TlsUtilities.ReadFully(totalLength, input); + + MemoryStream buf = new MemoryStream(certListData, false); + + IList certificate_list = Platform.CreateArrayList(); + while (buf.Position < buf.Length) + { + byte[] derEncoding = TlsUtilities.ReadOpaque24(buf); + Asn1Object asn1Cert = TlsUtilities.ReadDerObject(derEncoding); + certificate_list.Add(X509CertificateStructure.GetInstance(asn1Cert)); + } + + X509CertificateStructure[] certificateList = new X509CertificateStructure[certificate_list.Count]; + for (int i = 0; i < certificate_list.Count; ++i) + { + certificateList[i] = (X509CertificateStructure)certificate_list[i]; + } + return new Certificate(certificateList); + } + + protected virtual X509CertificateStructure[] CloneCertificateList() + { + return (X509CertificateStructure[])mCertificateList.Clone(); + } + } } diff --git a/crypto/src/crypto/tls/CertificateRequest.cs b/crypto/src/crypto/tls/CertificateRequest.cs
index 49d8ba6fb..8ab265513 100644 --- a/crypto/src/crypto/tls/CertificateRequest.cs +++ b/crypto/src/crypto/tls/CertificateRequest.cs
@@ -1,28 +1,158 @@ using System; using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Crypto.Tls { - public class CertificateRequest - { - private ClientCertificateType[] certificateTypes; - private IList certificateAuthorities; - - public CertificateRequest(ClientCertificateType[] certificateTypes, IList certificateAuthorities) - { - this.certificateTypes = certificateTypes; - this.certificateAuthorities = certificateAuthorities; - } - - public ClientCertificateType[] CertificateTypes - { - get { return certificateTypes; } - } - - /// <returns>A <see cref="IList"/> of X509Name</returns> - public IList CertificateAuthorities - { - get { return certificateAuthorities; } - } - } -} \ No newline at end of file + /** + * Parsing and encoding of a <i>CertificateRequest</i> struct from RFC 4346. + * <p/> + * <pre> + * struct { + * ClientCertificateType certificate_types&lt;1..2^8-1&gt;; + * DistinguishedName certificate_authorities&lt;3..2^16-1&gt; + * } CertificateRequest; + * </pre> + * + * @see ClientCertificateType + * @see X509Name + */ + public class CertificateRequest + { + protected readonly byte[] mCertificateTypes; + protected readonly IList mSupportedSignatureAlgorithms; + protected readonly IList mCertificateAuthorities; + + /** + * @param certificateTypes see {@link ClientCertificateType} for valid constants. + * @param certificateAuthorities an {@link IList} of {@link X509Name}. + */ + public CertificateRequest(byte[] certificateTypes, IList supportedSignatureAlgorithms, + IList certificateAuthorities) + { + this.mCertificateTypes = certificateTypes; + this.mSupportedSignatureAlgorithms = supportedSignatureAlgorithms; + this.mCertificateAuthorities = certificateAuthorities; + } + + /** + * @return an array of certificate types + * @see {@link ClientCertificateType} + */ + public virtual byte[] CertificateTypes + { + get { return mCertificateTypes; } + } + + /** + * @return an {@link IList} of {@link SignatureAndHashAlgorithm} (or null before TLS 1.2). + */ + public virtual IList SupportedSignatureAlgorithms + { + get { return mSupportedSignatureAlgorithms; } + } + + /** + * @return an {@link IList} of {@link X509Name} + */ + public virtual IList CertificateAuthorities + { + get { return mCertificateAuthorities; } + } + + /** + * Encode this {@link CertificateRequest} to a {@link Stream}. + * + * @param output the {@link Stream} to encode to. + * @throws IOException + */ + public virtual void Encode(Stream output) + { + if (mCertificateTypes == null || mCertificateTypes.Length == 0) + { + TlsUtilities.WriteUint8(0, output); + } + else + { + TlsUtilities.WriteUint8ArrayWithUint8Length(mCertificateTypes, output); + } + + if (mSupportedSignatureAlgorithms != null) + { + // TODO Check whether SignatureAlgorithm.anonymous is allowed here + TlsUtilities.EncodeSupportedSignatureAlgorithms(mSupportedSignatureAlgorithms, false, output); + } + + if (mCertificateAuthorities == null || mCertificateAuthorities.Count < 1) + { + TlsUtilities.WriteUint16(0, output); + } + else + { + IList derEncodings = Platform.CreateArrayList(mCertificateAuthorities.Count); + + int totalLength = 0; + foreach (Asn1Encodable certificateAuthority in mCertificateAuthorities) + { + byte[] derEncoding = certificateAuthority.GetEncoded(Asn1Encodable.Der); + derEncodings.Add(derEncoding); + totalLength += derEncoding.Length; + } + + TlsUtilities.CheckUint16(totalLength); + TlsUtilities.WriteUint16(totalLength, output); + + foreach (byte[] derEncoding in derEncodings) + { + output.Write(derEncoding, 0, derEncoding.Length); + } + } + } + + /** + * Parse a {@link CertificateRequest} from a {@link Stream}. + * + * @param context + * the {@link TlsContext} of the current connection. + * @param input + * the {@link Stream} to parse from. + * @return a {@link CertificateRequest} object. + * @throws IOException + */ + public static CertificateRequest Parse(//TlsContext context, + Stream input) + { + int numTypes = TlsUtilities.ReadUint8(input); + byte[] certificateTypes = new byte[numTypes]; + for (int i = 0; i < numTypes; ++i) + { + certificateTypes[i] = TlsUtilities.ReadUint8(input); + } + + // TODO Add TLS 1.2 support here + IList supportedSignatureAlgorithms = null; + //if (TlsUtilities.IsTLSv12(context)) + //{ + // // TODO Check whether SignatureAlgorithm.anonymous is allowed here + // supportedSignatureAlgorithms = TlsUtilities.ParseSupportedSignatureAlgorithms(false, input); + //} + + IList certificateAuthorities = Platform.CreateArrayList(); + byte[] certAuthData = TlsUtilities.ReadOpaque16(input); + MemoryStream bis = new MemoryStream(certAuthData, false); + while (bis.Position < bis.Length) + { + byte[] derEncoding = TlsUtilities.ReadOpaque16(bis); + Asn1Object asn1 = TlsUtilities.ReadDerObject(derEncoding); + // TODO Switch to X500Name when available + certificateAuthorities.Add(X509Name.GetInstance(asn1)); + } + + return new CertificateRequest(certificateTypes, supportedSignatureAlgorithms, certificateAuthorities); + } + } +} diff --git a/crypto/src/crypto/tls/CipherSuite.cs b/crypto/src/crypto/tls/CipherSuite.cs
index 6e1f7a545..2c5077780 100644 --- a/crypto/src/crypto/tls/CipherSuite.cs +++ b/crypto/src/crypto/tls/CipherSuite.cs
@@ -1,136 +1,298 @@ namespace Org.BouncyCastle.Crypto.Tls { - /// <summary> - /// RFC 2246 A.5 - /// </summary> - public enum CipherSuite : int - { - TLS_NULL_WITH_NULL_NULL = 0x0000, - TLS_RSA_WITH_NULL_MD5 = 0x0001, - TLS_RSA_WITH_NULL_SHA = 0x0002, - TLS_RSA_EXPORT_WITH_RC4_40_MD5 = 0x0003, - TLS_RSA_WITH_RC4_128_MD5 = 0x0004, - TLS_RSA_WITH_RC4_128_SHA = 0x0005, - TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 = 0x0006, - TLS_RSA_WITH_IDEA_CBC_SHA = 0x0007, - TLS_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x0008, - TLS_RSA_WITH_DES_CBC_SHA = 0x0009, - TLS_RSA_WITH_3DES_EDE_CBC_SHA = 0x000A, - TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = 0x000B, - TLS_DH_DSS_WITH_DES_CBC_SHA = 0x000C, - TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = 0x000D, - TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x000E, - TLS_DH_RSA_WITH_DES_CBC_SHA = 0x000F, - TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = 0x0010, - TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = 0x0011, - TLS_DHE_DSS_WITH_DES_CBC_SHA = 0x0012, - TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = 0x0013, - TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x0014, - TLS_DHE_RSA_WITH_DES_CBC_SHA = 0x0015, - TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = 0x0016, - TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 = 0x0017, - TLS_DH_anon_WITH_RC4_128_MD5 = 0x0018, - TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA = 0x0019, - TLS_DH_anon_WITH_DES_CBC_SHA = 0x001A, - TLS_DH_anon_WITH_3DES_EDE_CBC_SHA = 0x001B, - - /* - * RFC 3268 - */ - TLS_RSA_WITH_AES_128_CBC_SHA = 0x002F, - TLS_DH_DSS_WITH_AES_128_CBC_SHA = 0x0030, - TLS_DH_RSA_WITH_AES_128_CBC_SHA = 0x0031, - TLS_DHE_DSS_WITH_AES_128_CBC_SHA = 0x0032, - TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x0033, - TLS_DH_anon_WITH_AES_128_CBC_SHA = 0x0034, - TLS_RSA_WITH_AES_256_CBC_SHA = 0x0035, - TLS_DH_DSS_WITH_AES_256_CBC_SHA = 0x0036, - TLS_DH_RSA_WITH_AES_256_CBC_SHA = 0x0037, - TLS_DHE_DSS_WITH_AES_256_CBC_SHA = 0x0038, - TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x0039, - TLS_DH_anon_WITH_AES_256_CBC_SHA = 0x003A, - - /* - * RFC 4279 - */ - TLS_PSK_WITH_RC4_128_SHA = 0x008A, - TLS_PSK_WITH_3DES_EDE_CBC_SHA = 0x008B, - TLS_PSK_WITH_AES_128_CBC_SHA = 0x008C, - TLS_PSK_WITH_AES_256_CBC_SHA = 0x008D, - TLS_DHE_PSK_WITH_RC4_128_SHA = 0x008E, - TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA = 0x008F, - TLS_DHE_PSK_WITH_AES_128_CBC_SHA = 0x0090, - TLS_DHE_PSK_WITH_AES_256_CBC_SHA = 0x0091, - TLS_RSA_PSK_WITH_RC4_128_SHA = 0x0092, - TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA = 0x0093, - TLS_RSA_PSK_WITH_AES_128_CBC_SHA = 0x0094, - TLS_RSA_PSK_WITH_AES_256_CBC_SHA = 0x0095, - - /* - * RFC 4492 - */ - TLS_ECDH_ECDSA_WITH_NULL_SHA = 0xC001, - TLS_ECDH_ECDSA_WITH_RC4_128_SHA = 0xC002, - TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA = 0xC003, - TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA = 0xC004, - TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA = 0xC005, - TLS_ECDHE_ECDSA_WITH_NULL_SHA = 0xC006, - TLS_ECDHE_ECDSA_WITH_RC4_128_SHA = 0xC007, - TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA = 0xC008, - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = 0xC009, - TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = 0xC00A, - TLS_ECDH_RSA_WITH_NULL_SHA = 0xC00B, - TLS_ECDH_RSA_WITH_RC4_128_SHA = 0xC00C, - TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA = 0xC00D, - TLS_ECDH_RSA_WITH_AES_128_CBC_SHA = 0xC00E, - TLS_ECDH_RSA_WITH_AES_256_CBC_SHA = 0xC00F, - TLS_ECDHE_RSA_WITH_NULL_SHA = 0xC010, - TLS_ECDHE_RSA_WITH_RC4_128_SHA = 0xC011, - TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA = 0xC012, - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = 0xC013, - TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = 0xC014, - TLS_ECDH_anon_WITH_NULL_SHA = 0xC015, - TLS_ECDH_anon_WITH_RC4_128_SHA = 0xC016, - TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA = 0xC017, - TLS_ECDH_anon_WITH_AES_128_CBC_SHA = 0xC018, - TLS_ECDH_anon_WITH_AES_256_CBC_SHA = 0xC019, - - /* - * RFC 5054 - */ - TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA = 0xC01A, - TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA = 0xC01B, - TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA = 0xC01C, - TLS_SRP_SHA_WITH_AES_128_CBC_SHA = 0xC01D, - TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA = 0xC01E, - TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA = 0xC01F, - TLS_SRP_SHA_WITH_AES_256_CBC_SHA = 0xC020, - TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA = 0xC021, - TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA = 0xC022, - - /* - * RFC 5289 - */ - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = 0xC023, - TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = 0xC024, - TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 = 0xC025, - TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 = 0xC026, - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = 0xC027, - TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = 0xC028, - TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 = 0xC029, - TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 = 0xC02A, - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = 0xC02B, - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = 0xC02C, - TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 = 0xC02D, - TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 = 0xC02E, - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = 0xC02F, - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = 0xC030, - TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 = 0xC031, - TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 = 0xC032, - - /* - * RFC 5746 - */ - TLS_EMPTY_RENEGOTIATION_INFO_SCSV = 0x00FF, - } + /// <summary> + /// RFC 2246 A.5 + /// </summary> + public abstract class CipherSuite + { + public const int TLS_NULL_WITH_NULL_NULL = 0x0000; + public const int TLS_RSA_WITH_NULL_MD5 = 0x0001; + public const int TLS_RSA_WITH_NULL_SHA = 0x0002; + public const int TLS_RSA_EXPORT_WITH_RC4_40_MD5 = 0x0003; + public const int TLS_RSA_WITH_RC4_128_MD5 = 0x0004; + public const int TLS_RSA_WITH_RC4_128_SHA = 0x0005; + public const int TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 = 0x0006; + public const int TLS_RSA_WITH_IDEA_CBC_SHA = 0x0007; + public const int TLS_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x0008; + public const int TLS_RSA_WITH_DES_CBC_SHA = 0x0009; + public const int TLS_RSA_WITH_3DES_EDE_CBC_SHA = 0x000A; + public const int TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = 0x000B; + public const int TLS_DH_DSS_WITH_DES_CBC_SHA = 0x000C; + public const int TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = 0x000D; + public const int TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x000E; + public const int TLS_DH_RSA_WITH_DES_CBC_SHA = 0x000F; + public const int TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = 0x0010; + public const int TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = 0x0011; + public const int TLS_DHE_DSS_WITH_DES_CBC_SHA = 0x0012; + public const int TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = 0x0013; + public const int TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x0014; + public const int TLS_DHE_RSA_WITH_DES_CBC_SHA = 0x0015; + public const int TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = 0x0016; + public const int TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 = 0x0017; + public const int TLS_DH_anon_WITH_RC4_128_MD5 = 0x0018; + public const int TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA = 0x0019; + public const int TLS_DH_anon_WITH_DES_CBC_SHA = 0x001A; + public const int TLS_DH_anon_WITH_3DES_EDE_CBC_SHA = 0x001B; + + /* + * Note: The cipher suite values { 0x00, 0x1C } and { 0x00, 0x1D } are reserved to avoid + * collision with Fortezza-based cipher suites in SSL 3. + */ + + /* + * RFC 3268 + */ + public const int TLS_RSA_WITH_AES_128_CBC_SHA = 0x002F; + public const int TLS_DH_DSS_WITH_AES_128_CBC_SHA = 0x0030; + public const int TLS_DH_RSA_WITH_AES_128_CBC_SHA = 0x0031; + public const int TLS_DHE_DSS_WITH_AES_128_CBC_SHA = 0x0032; + public const int TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x0033; + public const int TLS_DH_anon_WITH_AES_128_CBC_SHA = 0x0034; + public const int TLS_RSA_WITH_AES_256_CBC_SHA = 0x0035; + public const int TLS_DH_DSS_WITH_AES_256_CBC_SHA = 0x0036; + public const int TLS_DH_RSA_WITH_AES_256_CBC_SHA = 0x0037; + public const int TLS_DHE_DSS_WITH_AES_256_CBC_SHA = 0x0038; + public const int TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x0039; + public const int TLS_DH_anon_WITH_AES_256_CBC_SHA = 0x003A; + + /* + * RFC 4132 + */ + public const int TLS_RSA_WITH_CAMELLIA_128_CBC_SHA = 0x0041; + public const int TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA = 0x0042; + public const int TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA = 0x0043; + public const int TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA = 0x0044; + public const int TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA = 0x0045; + public const int TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA = 0x0046; + public const int TLS_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0084; + public const int TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA = 0x0085; + public const int TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0086; + public const int TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA = 0x0087; + public const int TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0088; + public const int TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA = 0x0089; + + /* + * RFC 4162 + */ + public const int TLS_RSA_WITH_SEED_CBC_SHA = 0x0096; + public const int TLS_DH_DSS_WITH_SEED_CBC_SHA = 0x0097; + public const int TLS_DH_RSA_WITH_SEED_CBC_SHA = 0x0098; + public const int TLS_DHE_DSS_WITH_SEED_CBC_SHA = 0x0099; + public const int TLS_DHE_RSA_WITH_SEED_CBC_SHA = 0x009A; + public const int TLS_DH_anon_WITH_SEED_CBC_SHA = 0x009B; + + /* + * RFC 4279 + */ + public const int TLS_PSK_WITH_RC4_128_SHA = 0x008A; + public const int TLS_PSK_WITH_3DES_EDE_CBC_SHA = 0x008B; + public const int TLS_PSK_WITH_AES_128_CBC_SHA = 0x008C; + public const int TLS_PSK_WITH_AES_256_CBC_SHA = 0x008D; + public const int TLS_DHE_PSK_WITH_RC4_128_SHA = 0x008E; + public const int TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA = 0x008F; + public const int TLS_DHE_PSK_WITH_AES_128_CBC_SHA = 0x0090; + public const int TLS_DHE_PSK_WITH_AES_256_CBC_SHA = 0x0091; + public const int TLS_RSA_PSK_WITH_RC4_128_SHA = 0x0092; + public const int TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA = 0x0093; + public const int TLS_RSA_PSK_WITH_AES_128_CBC_SHA = 0x0094; + public const int TLS_RSA_PSK_WITH_AES_256_CBC_SHA = 0x0095; + + /* + * RFC 4492 + */ + public const int TLS_ECDH_ECDSA_WITH_NULL_SHA = 0xC001; + public const int TLS_ECDH_ECDSA_WITH_RC4_128_SHA = 0xC002; + public const int TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA = 0xC003; + public const int TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA = 0xC004; + public const int TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA = 0xC005; + public const int TLS_ECDHE_ECDSA_WITH_NULL_SHA = 0xC006; + public const int TLS_ECDHE_ECDSA_WITH_RC4_128_SHA = 0xC007; + public const int TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA = 0xC008; + public const int TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = 0xC009; + public const int TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = 0xC00A; + public const int TLS_ECDH_RSA_WITH_NULL_SHA = 0xC00B; + public const int TLS_ECDH_RSA_WITH_RC4_128_SHA = 0xC00C; + public const int TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA = 0xC00D; + public const int TLS_ECDH_RSA_WITH_AES_128_CBC_SHA = 0xC00E; + public const int TLS_ECDH_RSA_WITH_AES_256_CBC_SHA = 0xC00F; + public const int TLS_ECDHE_RSA_WITH_NULL_SHA = 0xC010; + public const int TLS_ECDHE_RSA_WITH_RC4_128_SHA = 0xC011; + public const int TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA = 0xC012; + public const int TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = 0xC013; + public const int TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = 0xC014; + public const int TLS_ECDH_anon_WITH_NULL_SHA = 0xC015; + public const int TLS_ECDH_anon_WITH_RC4_128_SHA = 0xC016; + public const int TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA = 0xC017; + public const int TLS_ECDH_anon_WITH_AES_128_CBC_SHA = 0xC018; + public const int TLS_ECDH_anon_WITH_AES_256_CBC_SHA = 0xC019; + + /* + * RFC 4785 + */ + public const int TLS_PSK_WITH_NULL_SHA = 0x002C; + public const int TLS_DHE_PSK_WITH_NULL_SHA = 0x002D; + public const int TLS_RSA_PSK_WITH_NULL_SHA = 0x002E; + + /* + * RFC 5054 + */ + public const int TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA = 0xC01A; + public const int TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA = 0xC01B; + public const int TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA = 0xC01C; + public const int TLS_SRP_SHA_WITH_AES_128_CBC_SHA = 0xC01D; + public const int TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA = 0xC01E; + public const int TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA = 0xC01F; + public const int TLS_SRP_SHA_WITH_AES_256_CBC_SHA = 0xC020; + public const int TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA = 0xC021; + public const int TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA = 0xC022; + + /* + * RFC 5246 + */ + public const int TLS_RSA_WITH_NULL_SHA256 = 0x003B; + public const int TLS_RSA_WITH_AES_128_CBC_SHA256 = 0x003C; + public const int TLS_RSA_WITH_AES_256_CBC_SHA256 = 0x003D; + public const int TLS_DH_DSS_WITH_AES_128_CBC_SHA256 = 0x003E; + public const int TLS_DH_RSA_WITH_AES_128_CBC_SHA256 = 0x003F; + public const int TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 = 0x0040; + public const int TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = 0x0067; + public const int TLS_DH_DSS_WITH_AES_256_CBC_SHA256 = 0x0068; + public const int TLS_DH_RSA_WITH_AES_256_CBC_SHA256 = 0x0069; + public const int TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 = 0x006A; + public const int TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = 0x006B; + public const int TLS_DH_anon_WITH_AES_128_CBC_SHA256 = 0x006C; + public const int TLS_DH_anon_WITH_AES_256_CBC_SHA256 = 0x006D; + + /* + * RFC 5288 + */ + public const int TLS_RSA_WITH_AES_128_GCM_SHA256 = 0x009C; + public const int TLS_RSA_WITH_AES_256_GCM_SHA384 = 0x009D; + public const int TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 = 0x009E; + public const int TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 = 0x009F; + public const int TLS_DH_RSA_WITH_AES_128_GCM_SHA256 = 0x00A0; + public const int TLS_DH_RSA_WITH_AES_256_GCM_SHA384 = 0x00A1; + public const int TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 = 0x00A2; + public const int TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 = 0x00A3; + public const int TLS_DH_DSS_WITH_AES_128_GCM_SHA256 = 0x00A4; + public const int TLS_DH_DSS_WITH_AES_256_GCM_SHA384 = 0x00A5; + public const int TLS_DH_anon_WITH_AES_128_GCM_SHA256 = 0x00A6; + public const int TLS_DH_anon_WITH_AES_256_GCM_SHA384 = 0x00A7; + + /* + * RFC 5289 + */ + public const int TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = 0xC023; + public const int TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = 0xC024; + public const int TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 = 0xC025; + public const int TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 = 0xC026; + public const int TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = 0xC027; + public const int TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = 0xC028; + public const int TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 = 0xC029; + public const int TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 = 0xC02A; + public const int TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = 0xC02B; + public const int TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = 0xC02C; + public const int TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 = 0xC02D; + public const int TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 = 0xC02E; + public const int TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = 0xC02F; + public const int TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = 0xC030; + public const int TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 = 0xC031; + public const int TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 = 0xC032; + + /* + * RFC 5487 + */ + public const int TLS_PSK_WITH_AES_128_GCM_SHA256 = 0x00A8; + public const int TLS_PSK_WITH_AES_256_GCM_SHA384 = 0x00A9; + public const int TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 = 0x00AA; + public const int TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 = 0x00AB; + public const int TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 = 0x00AC; + public const int TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 = 0x00AD; + public const int TLS_PSK_WITH_AES_128_CBC_SHA256 = 0x00AE; + public const int TLS_PSK_WITH_AES_256_CBC_SHA384 = 0x00AF; + public const int TLS_PSK_WITH_NULL_SHA256 = 0x00B0; + public const int TLS_PSK_WITH_NULL_SHA384 = 0x00B1; + public const int TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 = 0x00B2; + public const int TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 = 0x00B3; + public const int TLS_DHE_PSK_WITH_NULL_SHA256 = 0x00B4; + public const int TLS_DHE_PSK_WITH_NULL_SHA384 = 0x00B5; + public const int TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 = 0x00B6; + public const int TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 = 0x00B7; + public const int TLS_RSA_PSK_WITH_NULL_SHA256 = 0x00B8; + public const int TLS_RSA_PSK_WITH_NULL_SHA384 = 0x00B9; + + /* + * RFC 5489 + */ + public const int TLS_ECDHE_PSK_WITH_RC4_128_SHA = 0xC033; + public const int TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA = 0xC034; + public const int TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA = 0xC035; + public const int TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA = 0xC036; + public const int TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 = 0xC037; + public const int TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 = 0xC038; + public const int TLS_ECDHE_PSK_WITH_NULL_SHA = 0xC039; + public const int TLS_ECDHE_PSK_WITH_NULL_SHA256 = 0xC03A; + public const int TLS_ECDHE_PSK_WITH_NULL_SHA384 = 0xC03B; + + /* + * RFC 5746 + */ + public const int TLS_EMPTY_RENEGOTIATION_INFO_SCSV = 0x00FF; + + /* + * RFC 6655 + */ + public const int TLS_RSA_WITH_AES_128_CCM = 0xC09C; + public const int TLS_RSA_WITH_AES_256_CCM = 0xC09D; + public const int TLS_DHE_RSA_WITH_AES_128_CCM = 0xC09E; + public const int TLS_DHE_RSA_WITH_AES_256_CCM = 0xC09F; + public const int TLS_RSA_WITH_AES_128_CCM_8 = 0xC0A0; + public const int TLS_RSA_WITH_AES_256_CCM_8 = 0xC0A1; + public const int TLS_DHE_RSA_WITH_AES_128_CCM_8 = 0xC0A2; + public const int TLS_DHE_RSA_WITH_AES_256_CCM_8 = 0xC0A3; + public const int TLS_PSK_WITH_AES_128_CCM = 0xC0A4; + public const int TLS_PSK_WITH_AES_256_CCM = 0xC0A5; + public const int TLS_DHE_PSK_WITH_AES_128_CCM = 0xC0A6; + public const int TLS_DHE_PSK_WITH_AES_256_CCM = 0xC0A7; + public const int TLS_PSK_WITH_AES_128_CCM_8 = 0xC0A8; + public const int TLS_PSK_WITH_AES_256_CCM_8 = 0xC0A9; + public const int TLS_PSK_DHE_WITH_AES_128_CCM_8 = 0xC0AA; + public const int TLS_PSK_DHE_WITH_AES_256_CCM_8 = 0xC0AB; + + /* + * TBD[draft-josefsson-salsa20-tls-02] + */ + const int TLS_RSA_WITH_ESTREAM_SALSA20_SHA1 = 0xFF00; + const int TLS_RSA_WITH_SALSA20_SHA1 = 0xFF01; + const int TLS_DHE_RSA_WITH_ESTREAM_SALSA20_SHA1 = 0xFF02; + const int TLS_DHE_RSA_WITH_SALSA20_SHA1 = 0xFF03; + const int TLS_ECDHE_RSA_WITH_ESTREAM_SALSA20_SHA1 = 0xFF04; + const int TLS_ECDHE_RSA_WITH_SALSA20_SHA1 = 0xFF05; + const int TLS_ECDHE_ECDSA_WITH_ESTREAM_SALSA20_SHA1 = 0xFF06; + const int TLS_ECDHE_ECDSA_WITH_SALSA20_SHA1 = 0xFF07; + const int TLS_PSK_WITH_ESTREAM_SALSA20_SHA1 = 0xFF08; + const int TLS_PSK_WITH_SALSA20_SHA1 = 0xFF09; + const int TLS_DHE_PSK_WITH_ESTREAM_SALSA20_SHA1 = 0xFF0A; + const int TLS_DHE_PSK_WITH_SALSA20_SHA1 = 0xFF0B; + const int TLS_RSA_PSK_WITH_ESTREAM_SALSA20_SHA1 = 0xFF0C; + const int TLS_RSA_PSK_WITH_SALSA20_SHA1 = 0xFF0D; + const int TLS_ECDHE_PSK_WITH_ESTREAM_SALSA20_SHA1 = 0xFF0E; + const int TLS_ECDHE_PSK_WITH_SALSA20_SHA1 = 0xFF0F; + const int TLS_RSA_WITH_ESTREAM_SALSA20_UMAC96 = 0xFF10; + const int TLS_RSA_WITH_SALSA20_UMAC96 = 0xFF11; + const int TLS_DHE_RSA_WITH_ESTREAM_SALSA20_UMAC96 = 0xFF12; + const int TLS_DHE_RSA_WITH_SALSA20_UMAC96 = 0xFF13; + const int TLS_ECDHE_RSA_WITH_ESTREAM_SALSA20_UMAC96 = 0xFF14; + const int TLS_ECDHE_RSA_WITH_SALSA20_UMAC96 = 0xFF15; + const int TLS_ECDHE_ECDSA_WITH_ESTREAM_SALSA20_UMAC96 = 0xFF16; + const int TLS_ECDHE_ECDSA_WITH_SALSA20_UMAC96 = 0xFF17; + const int TLS_PSK_WITH_ESTREAM_SALSA20_UMAC96 = 0xFF18; + const int TLS_PSK_WITH_SALSA20_UMAC96 = 0xFF19; + const int TLS_DHE_PSK_WITH_ESTREAM_SALSA20_UMAC96 = 0xFF1A; + const int TLS_DHE_PSK_WITH_SALSA20_UMAC96 = 0xFF1B; + const int TLS_RSA_PSK_WITH_ESTREAM_SALSA20_UMAC96 = 0xFF1C; + const int TLS_RSA_PSK_WITH_SALSA20_UMAC96 = 0xFF1D; + const int TLS_ECDHE_PSK_WITH_ESTREAM_SALSA20_UMAC96 = 0xFF1E; + const int TLS_ECDHE_PSK_WITH_SALSA20_UMAC96 = 0xFF1F; + } } diff --git a/crypto/src/crypto/tls/ClientCertificateType.cs b/crypto/src/crypto/tls/ClientCertificateType.cs
index 58f5d4276..a291a46e6 100644 --- a/crypto/src/crypto/tls/ClientCertificateType.cs +++ b/crypto/src/crypto/tls/ClientCertificateType.cs
@@ -1,20 +1,23 @@ namespace Org.BouncyCastle.Crypto.Tls { - /// <summary> - /// RFC 2246 7.4.4 - /// </summary> - public enum ClientCertificateType : byte - { - rsa_sign = 1, - dss_sign = 2, - rsa_fixed_dh = 3, - dss_fixed_dh = 4, + public abstract class ClientCertificateType + { + /* + * RFC 4346 7.4.4 + */ + public const byte rsa_sign = 1; + public const byte dss_sign = 2; + public const byte rsa_fixed_dh = 3; + public const byte dss_fixed_dh = 4; + public const byte rsa_ephemeral_dh_RESERVED = 5; + public const byte dss_ephemeral_dh_RESERVED = 6; + public const byte fortezza_dms_RESERVED = 20; - /* - * RFC 4492 5.5 - */ - ecdsa_sign = 64, - rsa_fixed_ecdh = 65, - ecdsa_fixed_ecdh = 66, - } -} \ No newline at end of file + /* + * RFC 4492 5.5 + */ + public const byte ecdsa_sign = 64; + public const byte rsa_fixed_ecdh = 65; + public const byte ecdsa_fixed_ecdh = 66; + } +} diff --git a/crypto/src/crypto/tls/CompressionMethod.cs b/crypto/src/crypto/tls/CompressionMethod.cs
index 4a127a63e..e4ee9666f 100644 --- a/crypto/src/crypto/tls/CompressionMethod.cs +++ b/crypto/src/crypto/tls/CompressionMethod.cs
@@ -1,20 +1,22 @@ +using System; + namespace Org.BouncyCastle.Crypto.Tls { - /// <summary> - /// RFC 2246 6.1 - /// </summary> - public enum CompressionMethod : byte - { - NULL = 0, + /// <summary> + /// RFC 2246 6.1 + /// </summary> + public abstract class CompressionMethod + { + public const byte NULL = 0; - /* - * RFC 3749 2 - */ - DEFLATE = 1 + /* + * RFC 3749 2 + */ + public const byte DEFLATE = 1; - /* - * Values from 224 decimal (0xE0) through 255 decimal (0xFF) - * inclusive are reserved for private use. - */ - } + /* + * Values from 224 decimal (0xE0) through 255 decimal (0xFF) + * inclusive are reserved for private use. + */ + } } diff --git a/crypto/src/crypto/tls/ContentType.cs b/crypto/src/crypto/tls/ContentType.cs
index a664e3a38..d6ab43857 100644 --- a/crypto/src/crypto/tls/ContentType.cs +++ b/crypto/src/crypto/tls/ContentType.cs
@@ -1,13 +1,14 @@ namespace Org.BouncyCastle.Crypto.Tls { - /// <summary> - /// RFC 2246 6.2.1 - /// </summary> - public enum ContentType : byte - { - change_cipher_spec = 20, - alert = 21, - handshake = 22, - application_data = 23, - } + /** + * RFC 2246 6.2.1 + */ + public abstract class ContentType + { + public const byte change_cipher_spec = 20; + public const byte alert = 21; + public const byte handshake = 22; + public const byte application_data = 23; + public const byte heartbeat = 24; + } } diff --git a/crypto/src/crypto/tls/DefaultTlsAgreementCredentials.cs b/crypto/src/crypto/tls/DefaultTlsAgreementCredentials.cs
index 130f4c589..2bd2f40bf 100644 --- a/crypto/src/crypto/tls/DefaultTlsAgreementCredentials.cs +++ b/crypto/src/crypto/tls/DefaultTlsAgreementCredentials.cs
@@ -22,7 +22,7 @@ namespace Org.BouncyCastle.Crypto.Tls { throw new ArgumentNullException("clientCertificate"); } - if (clientCertificate.certs.Length == 0) + if (clientCertificate.Length == 0) { throw new ArgumentException("cannot be empty", "clientCertificate"); } diff --git a/crypto/src/crypto/tls/DefaultTlsCipherFactory.cs b/crypto/src/crypto/tls/DefaultTlsCipherFactory.cs
index 75ae311e1..9b6e2c14c 100644 --- a/crypto/src/crypto/tls/DefaultTlsCipherFactory.cs +++ b/crypto/src/crypto/tls/DefaultTlsCipherFactory.cs
@@ -7,26 +7,26 @@ using Org.BouncyCastle.Crypto.Modes; namespace Org.BouncyCastle.Crypto.Tls { - public class DefaultTlsCipherFactory - : TlsCipherFactory - { - public virtual TlsCipher CreateCipher(TlsClientContext context, - EncryptionAlgorithm encryptionAlgorithm, DigestAlgorithm digestAlgorithm) - { - switch (encryptionAlgorithm) - { - case EncryptionAlgorithm.cls_3DES_EDE_CBC: - return CreateDesEdeCipher(context, 24, digestAlgorithm); - case EncryptionAlgorithm.AES_128_CBC: - return CreateAesCipher(context, 16, digestAlgorithm); - case EncryptionAlgorithm.AES_256_CBC: - return CreateAesCipher(context, 32, digestAlgorithm); + public class DefaultTlsCipherFactory + : TlsCipherFactory + { + public virtual TlsCipher CreateCipher(TlsClientContext context, + int encryptionAlgorithm, DigestAlgorithm digestAlgorithm) + { + switch (encryptionAlgorithm) + { + case EncryptionAlgorithm.cls_3DES_EDE_CBC: + return CreateDesEdeCipher(context, 24, digestAlgorithm); + case EncryptionAlgorithm.AES_128_CBC: + return CreateAesCipher(context, 16, digestAlgorithm); + case EncryptionAlgorithm.AES_256_CBC: + return CreateAesCipher(context, 32, digestAlgorithm); case EncryptionAlgorithm.RC4_128: return CreateRC4Cipher(context, 16, digestAlgorithm); - default: - throw new TlsFatalAlert(AlertDescription.internal_error); - } - } + default: + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } /// <exception cref="IOException"></exception> protected virtual TlsCipher CreateRC4Cipher(TlsClientContext context, int cipherKeySize, DigestAlgorithm digestAlgorithm) @@ -34,53 +34,53 @@ namespace Org.BouncyCastle.Crypto.Tls return new TlsStreamCipher(context, CreateRC4StreamCipher(), CreateRC4StreamCipher(), CreateDigest(digestAlgorithm), CreateDigest(digestAlgorithm), cipherKeySize); } - /// <exception cref="IOException"></exception> - protected virtual TlsCipher CreateAesCipher(TlsClientContext context, int cipherKeySize, - DigestAlgorithm digestAlgorithm) - { - return new TlsBlockCipher(context, CreateAesBlockCipher(), CreateAesBlockCipher(), - CreateDigest(digestAlgorithm), CreateDigest(digestAlgorithm), cipherKeySize); - } + /// <exception cref="IOException"></exception> + protected virtual TlsCipher CreateAesCipher(TlsClientContext context, int cipherKeySize, + DigestAlgorithm digestAlgorithm) + { + return new TlsBlockCipher(context, CreateAesBlockCipher(), CreateAesBlockCipher(), + CreateDigest(digestAlgorithm), CreateDigest(digestAlgorithm), cipherKeySize); + } - /// <exception cref="IOException"></exception> - protected virtual TlsCipher CreateDesEdeCipher(TlsClientContext context, int cipherKeySize, - DigestAlgorithm digestAlgorithm) - { - return new TlsBlockCipher(context, CreateDesEdeBlockCipher(), CreateDesEdeBlockCipher(), - CreateDigest(digestAlgorithm), CreateDigest(digestAlgorithm), cipherKeySize); - } + /// <exception cref="IOException"></exception> + protected virtual TlsCipher CreateDesEdeCipher(TlsClientContext context, int cipherKeySize, + DigestAlgorithm digestAlgorithm) + { + return new TlsBlockCipher(context, CreateDesEdeBlockCipher(), CreateDesEdeBlockCipher(), + CreateDigest(digestAlgorithm), CreateDigest(digestAlgorithm), cipherKeySize); + } protected virtual IStreamCipher CreateRC4StreamCipher() { return new RC4Engine(); } - protected virtual IBlockCipher CreateAesBlockCipher() - { - return new CbcBlockCipher(new AesFastEngine()); - } + protected virtual IBlockCipher CreateAesBlockCipher() + { + return new CbcBlockCipher(new AesFastEngine()); + } - protected virtual IBlockCipher CreateDesEdeBlockCipher() - { - return new CbcBlockCipher(new DesEdeEngine()); - } + protected virtual IBlockCipher CreateDesEdeBlockCipher() + { + return new CbcBlockCipher(new DesEdeEngine()); + } - /// <exception cref="IOException"></exception> - protected virtual IDigest CreateDigest(DigestAlgorithm digestAlgorithm) - { - switch (digestAlgorithm) - { - case DigestAlgorithm.MD5: - return new MD5Digest(); - case DigestAlgorithm.SHA: - return new Sha1Digest(); - case DigestAlgorithm.SHA256: - return new Sha256Digest(); - case DigestAlgorithm.SHA384: - return new Sha384Digest(); - default: - throw new TlsFatalAlert(AlertDescription.internal_error); - } - } - } + /// <exception cref="IOException"></exception> + protected virtual IDigest CreateDigest(DigestAlgorithm digestAlgorithm) + { + switch (digestAlgorithm) + { + case DigestAlgorithm.MD5: + return new MD5Digest(); + case DigestAlgorithm.SHA: + return new Sha1Digest(); + case DigestAlgorithm.SHA256: + return new Sha256Digest(); + case DigestAlgorithm.SHA384: + return new Sha384Digest(); + default: + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + } } diff --git a/crypto/src/crypto/tls/DefaultTlsClient.cs b/crypto/src/crypto/tls/DefaultTlsClient.cs
index 9f30a33f4..a5fbe8235 100644 --- a/crypto/src/crypto/tls/DefaultTlsClient.cs +++ b/crypto/src/crypto/tls/DefaultTlsClient.cs
@@ -11,125 +11,125 @@ using Org.BouncyCastle.Crypto.Parameters; namespace Org.BouncyCastle.Crypto.Tls { - public abstract class DefaultTlsClient - : TlsClient - { - protected TlsCipherFactory cipherFactory; - - protected TlsClientContext context; - - protected CompressionMethod selectedCompressionMethod; - protected CipherSuite selectedCipherSuite; - - public DefaultTlsClient() - : this(new DefaultTlsCipherFactory()) - { - } - - public DefaultTlsClient(TlsCipherFactory cipherFactory) - { - this.cipherFactory = cipherFactory; - } - - public virtual void Init(TlsClientContext context) - { - this.context = context; - } - - public virtual CipherSuite[] GetCipherSuites() - { - return new CipherSuite[] { - CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA, - CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA, - CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA, - CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA, - CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, - CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, - CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA, - CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA, - CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA, + public abstract class DefaultTlsClient + : TlsClient + { + protected TlsCipherFactory cipherFactory; + + protected TlsClientContext context; + + protected byte selectedCompressionMethod; + protected int selectedCipherSuite; + + public DefaultTlsClient() + : this(new DefaultTlsCipherFactory()) + { + } + + public DefaultTlsClient(TlsCipherFactory cipherFactory) + { + this.cipherFactory = cipherFactory; + } + + public virtual void Init(TlsClientContext context) + { + this.context = context; + } + + public virtual int[] GetCipherSuites() + { + return new int[] { + CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA, + CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA, + CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA, + CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA, + CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, + CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, + CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA, + CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA, + CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA, CipherSuite.TLS_RSA_WITH_RC4_128_SHA, - }; - } + }; + } - public virtual CompressionMethod[] GetCompressionMethods() + public virtual byte[] GetCompressionMethods() { - /* - * To offer DEFLATE compression, override this method: - * return new CompressionMethod[] { CompressionMethod.DEFLATE, CompressionMethod.NULL }; - */ + /* + * To offer DEFLATE compression, override this method: + * return new byte[] { CompressionMethod.DEFLATE, CompressionMethod.NULL }; + */ - return new CompressionMethod[] { CompressionMethod.NULL }; + return new byte[] { CompressionMethod.NULL }; } public virtual IDictionary GetClientExtensions() - { - return null; - } + { + return null; + } public virtual void NotifySessionID(byte[] sessionID) - { - // Currently ignored - } + { + // Currently ignored + } - public virtual void NotifySelectedCipherSuite(CipherSuite selectedCipherSuite) - { - this.selectedCipherSuite = selectedCipherSuite; - } + public virtual void NotifySelectedCipherSuite(int selectedCipherSuite) + { + this.selectedCipherSuite = selectedCipherSuite; + } - public virtual void NotifySelectedCompressionMethod(CompressionMethod selectedCompressionMethod) + public virtual void NotifySelectedCompressionMethod(byte selectedCompressionMethod) { this.selectedCompressionMethod = selectedCompressionMethod; } public virtual void NotifySecureRenegotiation(bool secureRenegotiation) - { - if (!secureRenegotiation) - { - /* - * RFC 5746 3.4. - * If the extension is not present, the server does not support - * secure renegotiation; set secure_renegotiation flag to FALSE. - * In this case, some clients may want to terminate the handshake - * instead of continuing; see Section 4.1 for discussion. - */ + { + if (!secureRenegotiation) + { + /* + * RFC 5746 3.4. + * If the extension is not present, the server does not support + * secure renegotiation; set secure_renegotiation flag to FALSE. + * In this case, some clients may want to terminate the handshake + * instead of continuing; see Section 4.1 for discussion. + */ // throw new TlsFatalAlert(AlertDescription.handshake_failure); - } - } + } + } public virtual void ProcessServerExtensions(IDictionary serverExtensions) - { - } + { + } public virtual TlsKeyExchange GetKeyExchange() - { - switch (selectedCipherSuite) - { - case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA: - case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA: - case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA: + { + switch (selectedCipherSuite) + { + case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA: case CipherSuite.TLS_RSA_WITH_RC4_128_SHA: - return CreateRsaKeyExchange(); + return CreateRsaKeyExchange(); - 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: - return CreateDHKeyExchange(KeyExchangeAlgorithm.DH_DSS); + 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: + return CreateDHKeyExchange(KeyExchangeAlgorithm.DH_DSS); - case CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA: - case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA: - case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA: - return CreateDHKeyExchange(KeyExchangeAlgorithm.DH_RSA); + case CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA: + return CreateDHKeyExchange(KeyExchangeAlgorithm.DH_RSA); - case CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA: - case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA: - case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA: - return CreateDheKeyExchange(KeyExchangeAlgorithm.DHE_DSS); + case CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA: + return CreateDheKeyExchange(KeyExchangeAlgorithm.DHE_DSS); - case CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: - case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA: - case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA: - return CreateDheKeyExchange(KeyExchangeAlgorithm.DHE_RSA); + case CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA: + return CreateDheKeyExchange(KeyExchangeAlgorithm.DHE_RSA); case CipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA: case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA: @@ -155,54 +155,54 @@ namespace Org.BouncyCastle.Crypto.Tls case CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA: return CreateECDheKeyExchange(KeyExchangeAlgorithm.ECDHE_RSA); - default: - /* - * Note: internal error here; the TlsProtocolHandler verifies that the - * server-selected cipher suite was in the list of client-offered cipher - * suites, so if we now can't produce an implementation, we shouldn't have - * offered it! - */ - throw new TlsFatalAlert(AlertDescription.internal_error); - } - } - - public abstract TlsAuthentication GetAuthentication(); - - public virtual TlsCompression GetCompression() - { - switch (selectedCompressionMethod) - { - case CompressionMethod.NULL: - return new TlsNullCompression(); - - case CompressionMethod.DEFLATE: - return new TlsDeflateCompression(); - - default: - /* - * Note: internal error here; the TlsProtocolHandler verifies that the - * server-selected compression method was in the list of client-offered compression - * methods, so if we now can't produce an implementation, we shouldn't have - * offered it! - */ - throw new TlsFatalAlert(AlertDescription.internal_error); - } - } - - public virtual TlsCipher GetCipher() - { - switch (selectedCipherSuite) - { - case CipherSuite.TLS_RSA_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: - case CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: + default: + /* + * Note: internal error here; the TlsProtocolHandler verifies that the + * server-selected cipher suite was in the list of client-offered cipher + * suites, so if we now can't produce an implementation, we shouldn't have + * offered it! + */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public abstract TlsAuthentication GetAuthentication(); + + public virtual TlsCompression GetCompression() + { + switch (selectedCompressionMethod) + { + case CompressionMethod.NULL: + return new TlsNullCompression(); + + case CompressionMethod.DEFLATE: + return new TlsDeflateCompression(); + + default: + /* + * Note: internal error here; the TlsProtocolHandler verifies that the + * server-selected compression method was in the list of client-offered compression + * methods, so if we now can't produce an implementation, we shouldn't have + * offered it! + */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public virtual TlsCipher GetCipher() + { + switch (selectedCipherSuite) + { + case CipherSuite.TLS_RSA_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: + case CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: case CipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA: case CipherSuite.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA: case CipherSuite.TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA: case CipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: - return cipherFactory.CreateCipher(context, EncryptionAlgorithm.cls_3DES_EDE_CBC, DigestAlgorithm.SHA); + return cipherFactory.CreateCipher(context, EncryptionAlgorithm.cls_3DES_EDE_CBC, DigestAlgorithm.SHA); case CipherSuite.TLS_RSA_WITH_RC4_128_SHA: case CipherSuite.TLS_ECDH_ECDSA_WITH_RC4_128_SHA: @@ -212,61 +212,61 @@ namespace Org.BouncyCastle.Crypto.Tls return cipherFactory.CreateCipher(context, EncryptionAlgorithm.RC4_128, DigestAlgorithm.SHA); case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA: - case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA: - case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA: - case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA: - case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA: case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA: case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA: case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: - return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_128_CBC, DigestAlgorithm.SHA); + return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_128_CBC, DigestAlgorithm.SHA); - case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA: - case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA: - case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA: - case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA: - case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA: case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA: case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA: case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: - return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_256_CBC, DigestAlgorithm.SHA); - - default: - /* - * Note: internal error here; the TlsProtocolHandler verifies that the - * server-selected cipher suite was in the list of client-offered cipher - * suites, so if we now can't produce an implementation, we shouldn't have - * offered it! - */ - throw new TlsFatalAlert(AlertDescription.internal_error); - } - } - - protected virtual TlsKeyExchange CreateDHKeyExchange(KeyExchangeAlgorithm keyExchange) - { - return new TlsDHKeyExchange(context, keyExchange); - } - - protected virtual TlsKeyExchange CreateDheKeyExchange(KeyExchangeAlgorithm keyExchange) - { - return new TlsDheKeyExchange(context, keyExchange); - } - - protected virtual TlsKeyExchange CreateECDHKeyExchange(KeyExchangeAlgorithm keyExchange) + return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_256_CBC, DigestAlgorithm.SHA); + + default: + /* + * Note: internal error here; the TlsProtocolHandler verifies that the + * server-selected cipher suite was in the list of client-offered cipher + * suites, so if we now can't produce an implementation, we shouldn't have + * offered it! + */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + protected virtual TlsKeyExchange CreateDHKeyExchange(int keyExchange) + { + return new TlsDHKeyExchange(context, keyExchange); + } + + protected virtual TlsKeyExchange CreateDheKeyExchange(int keyExchange) + { + return new TlsDheKeyExchange(context, keyExchange); + } + + protected virtual TlsKeyExchange CreateECDHKeyExchange(int keyExchange) { return new TlsECDHKeyExchange(context, keyExchange); } - protected virtual TlsKeyExchange CreateECDheKeyExchange(KeyExchangeAlgorithm keyExchange) + protected virtual TlsKeyExchange CreateECDheKeyExchange(int keyExchange) { return new TlsECDheKeyExchange(context, keyExchange); } protected virtual TlsKeyExchange CreateRsaKeyExchange() - { - return new TlsRsaKeyExchange(context); - } + { + return new TlsRsaKeyExchange(context); + } } } diff --git a/crypto/src/crypto/tls/DefaultTlsSignerCredentials.cs b/crypto/src/crypto/tls/DefaultTlsSignerCredentials.cs
index 86c9d1a18..2c5aa3524 100644 --- a/crypto/src/crypto/tls/DefaultTlsSignerCredentials.cs +++ b/crypto/src/crypto/tls/DefaultTlsSignerCredentials.cs
@@ -20,7 +20,7 @@ namespace Org.BouncyCastle.Crypto.Tls { throw new ArgumentNullException("clientCertificate"); } - if (clientCertificate.certs.Length == 0) + if (clientCertificate.Length == 0) { throw new ArgumentException("cannot be empty", "clientCertificate"); } diff --git a/crypto/src/crypto/tls/ECCurveType.cs b/crypto/src/crypto/tls/ECCurveType.cs
index 15d5d7b42..1b352e9c4 100644 --- a/crypto/src/crypto/tls/ECCurveType.cs +++ b/crypto/src/crypto/tls/ECCurveType.cs
@@ -1,29 +1,29 @@ namespace Org.BouncyCastle.Crypto.Tls { - /// <summary> - /// RFC 4492 5.4 - /// </summary> - public enum ECCurveType : byte - { - /** - * Indicates the elliptic curve domain parameters are conveyed verbosely, and the - * underlying finite field is a prime field. - */ - explicit_prime = 1, + /// <summary> + /// RFC 4492 5.4 + /// </summary> + public abstract class ECCurveType + { + /** + * Indicates the elliptic curve domain parameters are conveyed verbosely, and the + * underlying finite field is a prime field. + */ + public const byte explicit_prime = 1; - /** - * Indicates the elliptic curve domain parameters are conveyed verbosely, and the - * underlying finite field is a characteristic-2 field. - */ - explicit_char2 = 2, + /** + * Indicates the elliptic curve domain parameters are conveyed verbosely, and the + * underlying finite field is a characteristic-2 field. + */ + public const byte explicit_char2 = 2; - /** - * Indicates that a named curve is used. This option SHOULD be used when applicable. - */ - named_curve = 3, + /** + * Indicates that a named curve is used. This option SHOULD be used when applicable. + */ + public const byte named_curve = 3; - /* - * Values 248 through 255 are reserved for private use. - */ - } + /* + * Values 248 through 255 are reserved for private use. + */ + } } diff --git a/crypto/src/crypto/tls/ECPointFormat.cs b/crypto/src/crypto/tls/ECPointFormat.cs
index 4e0dd0067..21b0fdd97 100644 --- a/crypto/src/crypto/tls/ECPointFormat.cs +++ b/crypto/src/crypto/tls/ECPointFormat.cs
@@ -1,16 +1,16 @@ namespace Org.BouncyCastle.Crypto.Tls { - /// <summary> - /// RFC 4492 5.1.2 - /// </summary> - public enum ECPointFormat : byte - { - uncompressed = 0, - ansiX962_compressed_prime = 1, - ansiX962_compressed_char2 = 2, + /// <summary> + /// RFC 4492 5.1.2 + /// </summary> + public abstract class ECPointFormat + { + public const byte uncompressed = 0; + public const byte ansiX962_compressed_prime = 1; + public const byte ansiX962_compressed_char2 = 2; - /* - * reserved (248..255) - */ - } + /* + * reserved (248..255) + */ + } } diff --git a/crypto/src/crypto/tls/EncryptionAlgorithm.cs b/crypto/src/crypto/tls/EncryptionAlgorithm.cs
index 79d3b63b5..69aee8abc 100644 --- a/crypto/src/crypto/tls/EncryptionAlgorithm.cs +++ b/crypto/src/crypto/tls/EncryptionAlgorithm.cs
@@ -2,31 +2,58 @@ using System; namespace Org.BouncyCastle.Crypto.Tls { - public enum EncryptionAlgorithm - { - /* - * Note that the values here are implementation-specific and arbitrary. - * It is recommended not to depend on the particular values (e.g. serialization). - */ - NULL, - RC4_40, - RC4_128, - RC2_CBC_40, - IDEA_CBC, - DES40_CBC, - DES_CBC, - cls_3DES_EDE_CBC, + /** + * RFC 2246 + * <p/> + * Note that the values here are implementation-specific and arbitrary. It is recommended not to + * depend on the particular values (e.g. serialization). + */ + public abstract class EncryptionAlgorithm + { + public const int NULL = 0; + public const int RC4_40 = 1; + public const int RC4_128 = 2; + public const int RC2_CBC_40 = 3; + public const int IDEA_CBC = 4; + public const int DES40_CBC = 5; + public const int DES_CBC = 6; + public const int cls_3DES_EDE_CBC = 7; - /* - * RFC 3268 - */ - AES_128_CBC, - AES_256_CBC, + /* + * RFC 3268 + */ + public const int AES_128_CBC = 8; + public const int AES_256_CBC = 9; - /* - * RFC 5289 - */ - AES_128_GCM, - AES_256_GCM, - } + /* + * RFC 5289 + */ + public const int AES_128_GCM = 10; + public const int AES_256_GCM = 11; + + /* + * RFC 4132 + */ + public const int CAMELLIA_128_CBC = 12; + public const int CAMELLIA_256_CBC = 13; + + /* + * RFC 4162 + */ + public const int SEED_CBC = 14; + + /* + * RFC 6655 + */ + public const int AES_128_CCM = 15; + public const int AES_128_CCM_8 = 16; + public const int AES_256_CCM = 17; + public const int AES_256_CCM_8 = 18; + + /* + * TBD[draft-josefsson-salsa20-tls-02] + */ + const int ESTREAM_SALSA20 = 100; + const int SALSA20 = 101; + } } diff --git a/crypto/src/crypto/tls/ExtensionType.cs b/crypto/src/crypto/tls/ExtensionType.cs
index f00e34e3f..0e6a45b5e 100644 --- a/crypto/src/crypto/tls/ExtensionType.cs +++ b/crypto/src/crypto/tls/ExtensionType.cs
@@ -1,31 +1,56 @@ namespace Org.BouncyCastle.Crypto.Tls { - /// <summary> - /// RFC 4366 2.3 - /// </summary> - public enum ExtensionType : int - { - server_name = 0, - max_fragment_length = 1, - client_certificate_url = 2, - trusted_ca_keys = 3, - truncated_hmac = 4, - status_request = 5, - - /* - * RFC 4492 - */ - elliptic_curves = 10, - ec_point_formats = 11, - - /* - * RFC 5054 2.8.1 - */ - srp = 12, - - /* - * RFC 5746 6 - */ - renegotiation_info = 0xff01, - } + public abstract class ExtensionType + { + /* + * RFC 2546 2.3. + */ + public const int server_name = 0; + public const int max_fragment_length = 1; + public const int client_certificate_url = 2; + public const int trusted_ca_keys = 3; + public const int truncated_hmac = 4; + public const int status_request = 5; + + /* + * RFC 4681 + */ + public const int user_mapping = 6; + + /* + * RFC 4492 5.1. + */ + public const int elliptic_curves = 10; + public const int ec_point_formats = 11; + + /* + * RFC 5054 2.8.1. + */ + public const int srp = 12; + + /* + * RFC 5077 7. + */ + public const int session_ticket = 35; + + /* + * RFC 5246 7.4.1.4. + */ + public const int signature_algorithms = 13; + + /* + * RFC 5764 9. + */ + public const int use_srtp = 14; + + /* + * RFC 6520 6. + */ + public const int heartbeat = 15; + + /* + * RFC 5746 3.2. + */ + public const int renegotiation_info = 0xff01; + } } diff --git a/crypto/src/crypto/tls/HandshakeType.cs b/crypto/src/crypto/tls/HandshakeType.cs
index deedb1f84..e63042ac3 100644 --- a/crypto/src/crypto/tls/HandshakeType.cs +++ b/crypto/src/crypto/tls/HandshakeType.cs
@@ -1,19 +1,40 @@ namespace Org.BouncyCastle.Crypto.Tls { - /// <summary> - /// RFC 2246 7.4 - /// </summary> - public enum HandshakeType : byte - { - hello_request = 0, - client_hello = 1, - server_hello = 2, - certificate = 11, - server_key_exchange = 12, - certificate_request = 13, - server_hello_done = 14, - certificate_verify = 15, - client_key_exchange = 16, - finished = 20, - } + public abstract class HandshakeType + { + /* + * RFC 2246 7.4 + */ + public const byte hello_request = 0; + public const byte client_hello = 1; + public const byte server_hello = 2; + public const byte certificate = 11; + public const byte server_key_exchange = 12; + public const byte certificate_request = 13; + public const byte server_hello_done = 14; + public const byte certificate_verify = 15; + public const byte client_key_exchange = 16; + public const byte finished = 20; + + /* + * RFC 3546 2.4 + */ + public const byte certificate_url = 21; + public const byte certificate_status = 22; + + /* + * (DTLS) RFC 4347 4.3.2 + */ + public const byte hello_verify_request = 3; + + /* + * RFC 4680 + */ + public const byte supplemental_data = 23; + + /* + * RFC 5077 + */ + public const byte session_ticket = 4; + } } diff --git a/crypto/src/crypto/tls/HashAlgorithm.cs b/crypto/src/crypto/tls/HashAlgorithm.cs new file mode 100644
index 000000000..41818ca2c --- /dev/null +++ b/crypto/src/crypto/tls/HashAlgorithm.cs
@@ -0,0 +1,18 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Tls +{ + /** + * RFC 5246 7.4.1.4.1 + */ + public abstract class HashAlgorithm + { + public const byte none = 0; + public const byte md5 = 1; + public const byte sha1 = 2; + public const byte sha224 = 3; + public const byte sha256 = 4; + public const byte sha384 = 5; + public const byte sha512 = 6; + } +} diff --git a/crypto/src/crypto/tls/KeyExchangeAlgorithm.cs b/crypto/src/crypto/tls/KeyExchangeAlgorithm.cs
index 3fdbeb2a6..3f5088d9b 100644 --- a/crypto/src/crypto/tls/KeyExchangeAlgorithm.cs +++ b/crypto/src/crypto/tls/KeyExchangeAlgorithm.cs
@@ -2,35 +2,54 @@ using System; namespace Org.BouncyCastle.Crypto.Tls { - public enum KeyExchangeAlgorithm - { - /* - * Note that the values here are implementation-specific and arbitrary. - * It is recommended not to depend on the particular values (e.g. serialization). - */ - NULL, - RSA, - RSA_EXPORT, - DHE_DSS, - DHE_DSS_EXPORT, - DHE_RSA, - DHE_RSA_EXPORT, - DH_DSS, - DH_DSS_EXPORT, - DH_RSA, - DH_RSA_EXPORT, - DH_anon, - DH_anon_export, - PSK, - DHE_PSK, - RSA_PSK, - ECDH_ECDSA, - ECDHE_ECDSA, - ECDH_RSA, - ECDHE_RSA, - ECDH_anon, - SRP, - SRP_DSS, - SRP_RSA, - } + /** + * RFC 2246 + * <p/> + * Note that the values here are implementation-specific and arbitrary. It is recommended not to + * depend on the particular values (e.g. serialization). + */ + public abstract class KeyExchangeAlgorithm + { + public const int NULL = 0; + public const int RSA = 1; + public const int RSA_EXPORT = 2; + public const int DHE_DSS = 3; + public const int DHE_DSS_EXPORT = 4; + public const int DHE_RSA = 5; + public const int DHE_RSA_EXPORT = 6; + public const int DH_DSS = 7; + public const int DH_DSS_EXPORT = 8; + public const int DH_RSA = 9; + public const int DH_RSA_EXPORT = 10; + public const int DH_anon = 11; + public const int DH_anon_EXPORT = 12; + + /* + * RFC 4279 + */ + public const int PSK = 13; + public const int DHE_PSK = 14; + public const int RSA_PSK = 15; + + /* + * RFC 4429 + */ + public const int ECDH_ECDSA = 16; + public const int ECDHE_ECDSA = 17; + public const int ECDH_RSA = 18; + public const int ECDHE_RSA = 19; + public const int ECDH_anon = 20; + + /* + * RFC 5054 + */ + public const int SRP = 21; + public const int SRP_DSS = 22; + public const int SRP_RSA = 23; + + /* + * RFC 5489 + */ + public const int ECDHE_PSK = 24; + } } diff --git a/crypto/src/crypto/tls/LegacyTlsAuthentication.cs b/crypto/src/crypto/tls/LegacyTlsAuthentication.cs
index 395f94208..bce31c0b0 100644 --- a/crypto/src/crypto/tls/LegacyTlsAuthentication.cs +++ b/crypto/src/crypto/tls/LegacyTlsAuthentication.cs
@@ -2,29 +2,29 @@ using System; namespace Org.BouncyCastle.Crypto.Tls { - /// <summary> - /// A temporary class to wrap old CertificateVerifyer stuff for new TlsAuthentication. - /// </summary> - [Obsolete] - public class LegacyTlsAuthentication - : TlsAuthentication - { - protected ICertificateVerifyer verifyer; + /// <summary> + /// A temporary class to wrap old CertificateVerifyer stuff for new TlsAuthentication. + /// </summary> + [Obsolete] + public class LegacyTlsAuthentication + : TlsAuthentication + { + protected ICertificateVerifyer verifyer; - public LegacyTlsAuthentication(ICertificateVerifyer verifyer) - { - this.verifyer = verifyer; - } + public LegacyTlsAuthentication(ICertificateVerifyer verifyer) + { + this.verifyer = verifyer; + } - public virtual void NotifyServerCertificate(Certificate serverCertificate) - { - if (!this.verifyer.IsValid(serverCertificate.GetCerts())) - throw new TlsFatalAlert(AlertDescription.user_canceled); - } + public virtual void NotifyServerCertificate(Certificate serverCertificate) + { + if (!this.verifyer.IsValid(serverCertificate.GetCertificateList())) + throw new TlsFatalAlert(AlertDescription.user_canceled); + } - public virtual TlsCredentials GetClientCredentials(CertificateRequest certificateRequest) - { - return null; - } - } + public virtual TlsCredentials GetClientCredentials(CertificateRequest certificateRequest) + { + return null; + } + } } diff --git a/crypto/src/crypto/tls/NamedCurve.cs b/crypto/src/crypto/tls/NamedCurve.cs
index c8ee189aa..8ef395069 100644 --- a/crypto/src/crypto/tls/NamedCurve.cs +++ b/crypto/src/crypto/tls/NamedCurve.cs
@@ -6,67 +6,91 @@ using Org.BouncyCastle.Crypto.Parameters; namespace Org.BouncyCastle.Crypto.Tls { - /// <summary> - /// RFC 4492 5.1.1 - /// The named curves defined here are those specified in SEC 2 [13]. Note that many of - /// these curves are also recommended in ANSI X9.62 [7] and FIPS 186-2 [11]. Values 0xFE00 - /// through 0xFEFF are reserved for private use. Values 0xFF01 and 0xFF02 indicate that the - /// client supports arbitrary prime and characteristic-2 curves, respectively (the curve - /// parameters must be encoded explicitly in ECParameters). - /// </summary> - public enum NamedCurve : int - { - sect163k1 = 1, - sect163r1 = 2, - sect163r2 = 3, - sect193r1 = 4, - sect193r2 = 5, - sect233k1 = 6, - sect233r1 = 7, - sect239k1 = 8, - sect283k1 = 9, - sect283r1 = 10, - sect409k1 = 11, - sect409r1 = 12, - sect571k1 = 13, - sect571r1 = 14, - secp160k1 = 15, - secp160r1 = 16, - secp160r2 = 17, - secp192k1 = 18, - secp192r1 = 19, - secp224k1 = 20, - secp224r1 = 21, - secp256k1 = 22, - secp256r1 = 23, - secp384r1 = 24, - secp521r1 = 25, + /// <summary> + /// RFC 4492 5.1.1 + /// The named curves defined here are those specified in SEC 2 [13]. Note that many of + /// these curves are also recommended in ANSI X9.62 [7] and FIPS 186-2 [11]. Values 0xFE00 + /// through 0xFEFF are reserved for private use. Values 0xFF01 and 0xFF02 indicate that the + /// client supports arbitrary prime and characteristic-2 curves, respectively (the curve + /// parameters must be encoded explicitly in ECParameters). + /// </summary> + public abstract class NamedCurve + { + public const int sect163k1 = 1; + public const int sect163r1 = 2; + public const int sect163r2 = 3; + public const int sect193r1 = 4; + public const int sect193r2 = 5; + public const int sect233k1 = 6; + public const int sect233r1 = 7; + public const int sect239k1 = 8; + public const int sect283k1 = 9; + public const int sect283r1 = 10; + public const int sect409k1 = 11; + public const int sect409r1 = 12; + public const int sect571k1 = 13; + public const int sect571r1 = 14; + public const int secp160k1 = 15; + public const int secp160r1 = 16; + public const int secp160r2 = 17; + public const int secp192k1 = 18; + public const int secp192r1 = 19; + public const int secp224k1 = 20; + public const int secp224r1 = 21; + public const int secp256k1 = 22; + public const int secp256r1 = 23; + public const int secp384r1 = 24; + public const int secp521r1 = 25; + + /* + * RFC 7027 + */ + public const int brainpoolP256r1 = 26; + public const int brainpoolP384r1 = 27; + public const int brainpoolP512r1 = 28; - /* - * reserved (0xFE00..0xFEFF) - */ + /* + * reserved (0xFE00..0xFEFF) + */ - arbitrary_explicit_prime_curves = 0xFF01, - arbitrary_explicit_char2_curves = 0xFF02, - } + public const int arbitrary_explicit_prime_curves = 0xFF01; + public const int arbitrary_explicit_char2_curves = 0xFF02; - internal class NamedCurveHelper - { - internal static ECDomainParameters GetECParameters(NamedCurve namedCurve) - { - if (!Enum.IsDefined(typeof(NamedCurve), namedCurve)) + public static bool IsValid(int namedCurve) + { + return namedCurve >= sect163k1 && namedCurve <= brainpoolP512r1; + } + + public static bool RefersToASpecificNamedCurve(int namedCurve) + { + switch (namedCurve) + { + case arbitrary_explicit_prime_curves: + case arbitrary_explicit_char2_curves: + return false; + default: + return true; + } + } + } + + internal class NamedCurveHelper + { + internal static ECDomainParameters GetECParameters(int namedCurve) + { + if (!NamedCurve.IsValid(namedCurve)) return null; string curveName = namedCurve.ToString(); // Lazily created the first time a particular curve is accessed - X9ECParameters ecP = SecNamedCurves.GetByName(curveName); + X9ECParameters ecP = SecNamedCurves.GetByName(curveName); if (ecP == null) return null; - // It's a bit inefficient to do this conversion every time - return new ECDomainParameters(ecP.Curve, ecP.G, ecP.N, ecP.H, ecP.GetSeed()); - } - } + // It's a bit inefficient to do this conversion every time + return new ECDomainParameters(ecP.Curve, ecP.G, ecP.N, ecP.H, ecP.GetSeed()); + } + } } diff --git a/crypto/src/crypto/tls/PrfAlgorithm.cs b/crypto/src/crypto/tls/PrfAlgorithm.cs new file mode 100644
index 000000000..976113495 --- /dev/null +++ b/crypto/src/crypto/tls/PrfAlgorithm.cs
@@ -0,0 +1,25 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Tls +{ + /** + * RFC 5246 + * <p/> + * Note that the values here are implementation-specific and arbitrary. It is recommended not to + * depend on the particular values (e.g. serialization). + */ + public abstract class PrfAlgorithm + { + /* + * Placeholder to refer to the legacy TLS algorithm + */ + public const int tls_prf_legacy = 0; + + public const int tls_prf_sha256 = 1; + + /* + * Implied by RFC 5288 + */ + public const int tls_prf_sha384 = 2; + } +} diff --git a/crypto/src/crypto/tls/ProtocolVersion.cs b/crypto/src/crypto/tls/ProtocolVersion.cs new file mode 100644
index 000000000..b0d55183a --- /dev/null +++ b/crypto/src/crypto/tls/ProtocolVersion.cs
@@ -0,0 +1,159 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Tls +{ + public sealed class ProtocolVersion + { + public static readonly ProtocolVersion SSLv3 = new ProtocolVersion(0x0300, "SSL 3.0"); + public static readonly ProtocolVersion TLSv10 = new ProtocolVersion(0x0301, "TLS 1.0"); + public static readonly ProtocolVersion TLSv11 = new ProtocolVersion(0x0302, "TLS 1.1"); + public static readonly ProtocolVersion TLSv12 = new ProtocolVersion(0x0303, "TLS 1.2"); + public static readonly ProtocolVersion DTLSv10 = new ProtocolVersion(0xFEFF, "DTLS 1.0"); + public static readonly ProtocolVersion DTLSv12 = new ProtocolVersion(0xFEFD, "DTLS 1.2"); + + private readonly int version; + private readonly String name; + + private ProtocolVersion(int v, String name) + { + this.version = v & 0xffff; + this.name = name; + } + + public int FullVersion + { + get { return version; } + } + + public int MajorVersion + { + get { return version >> 8; } + } + + public int MinorVersion + { + get { return version & 0xff; } + } + + public bool IsDtls + { + get { return MajorVersion == 0xFE; } + } + + public bool IsSsl + { + get { return this == SSLv3; } + } + + public bool IsTls + { + get { return MajorVersion == 0x03; } + } + + public ProtocolVersion GetEquivalentTLSVersion() + { + if (!IsDtls) + { + return this; + } + if (this == DTLSv10) + { + return TLSv11; + } + return TLSv12; + } + + public bool IsEqualOrEarlierVersionOf(ProtocolVersion version) + { + if (MajorVersion != version.MajorVersion) + { + return false; + } + int diffMinorVersion = version.MinorVersion - MinorVersion; + return IsDtls ? diffMinorVersion <= 0 : diffMinorVersion >= 0; + } + + public bool IsLaterVersionOf(ProtocolVersion version) + { + if (MajorVersion != version.MajorVersion) + { + return false; + } + int diffMinorVersion = version.MinorVersion - MinorVersion; + return IsDtls ? diffMinorVersion > 0 : diffMinorVersion < 0; + } + + public override bool Equals(object other) + { + return this == other || (other is ProtocolVersion && Equals((ProtocolVersion)other)); + } + + public bool Equals(ProtocolVersion other) + { + return other != null && this.version == other.version; + } + + public override int GetHashCode() + { + return version; + } + + /// <exception cref="IOException"/> + public static ProtocolVersion Get(int major, int minor) + { + switch (major) + { + case 0x03: + { + switch (minor) + { + case 0x00: + return SSLv3; + case 0x01: + return TLSv10; + case 0x02: + return TLSv11; + case 0x03: + return TLSv12; + } + return GetUnknownVersion(major, minor, "TLS"); + } + case 0xFE: + { + switch (minor) + { + case 0xFF: + return DTLSv10; + case 0xFE: + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + case 0xFD: + return DTLSv12; + } + return GetUnknownVersion(major, minor, "DTLS"); + } + default: + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + } + } + + public override string ToString() + { + return name; + } + + private static ProtocolVersion GetUnknownVersion(int major, int minor, string prefix) + { + TlsUtilities.CheckUint8(major); + TlsUtilities.CheckUint8(minor); + + int v = (major << 8) | minor; + String hex = Platform.ToUpperInvariant(Convert.ToString(0x10000 | v, 16).Substring(1)); + return new ProtocolVersion(v, prefix + " 0x" + hex); + } + } +} diff --git a/crypto/src/crypto/tls/PskTlsClient.cs b/crypto/src/crypto/tls/PskTlsClient.cs
index 9db7d7d90..6011daada 100644 --- a/crypto/src/crypto/tls/PskTlsClient.cs +++ b/crypto/src/crypto/tls/PskTlsClient.cs
@@ -3,168 +3,168 @@ using System.Collections; namespace Org.BouncyCastle.Crypto.Tls { - public abstract class PskTlsClient - :TlsClient - { - protected TlsCipherFactory cipherFactory; - protected TlsPskIdentity pskIdentity; + public abstract class PskTlsClient + :TlsClient + { + protected TlsCipherFactory cipherFactory; + protected TlsPskIdentity pskIdentity; protected TlsClientContext context; - protected CompressionMethod selectedCompressionMethod; - protected CipherSuite selectedCipherSuite; + protected byte selectedCompressionMethod; + protected int selectedCipherSuite; public PskTlsClient(TlsPskIdentity pskIdentity) - : this(new DefaultTlsCipherFactory(), pskIdentity) - { - } + : this(new DefaultTlsCipherFactory(), pskIdentity) + { + } public PskTlsClient(TlsCipherFactory cipherFactory, TlsPskIdentity pskIdentity) - { - this.cipherFactory = cipherFactory; - this.pskIdentity = pskIdentity; - } + { + this.cipherFactory = cipherFactory; + this.pskIdentity = pskIdentity; + } public virtual void Init(TlsClientContext context) - { - this.context = context; - } - - public virtual CipherSuite[] GetCipherSuites() - { - return new CipherSuite[] { - CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA, - CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA, - CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA, - CipherSuite.TLS_DHE_PSK_WITH_RC4_128_SHA, - CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA, - CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA, - CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA, - CipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA, - CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA, - CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA, - CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA, - CipherSuite.TLS_PSK_WITH_RC4_128_SHA, - }; - } + { + this.context = context; + } + + public virtual int[] GetCipherSuites() + { + return new int[] { + CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA, + CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA, + CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA, + CipherSuite.TLS_DHE_PSK_WITH_RC4_128_SHA, + CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA, + CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA, + CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA, + CipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA, + CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA, + CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA, + CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA, + CipherSuite.TLS_PSK_WITH_RC4_128_SHA, + }; + } public virtual IDictionary GetClientExtensions() - { - return null; - } + { + return null; + } - public virtual CompressionMethod[] GetCompressionMethods() - { - return new CompressionMethod[] { CompressionMethod.NULL }; - } + public virtual byte[] GetCompressionMethods() + { + return new byte[] { CompressionMethod.NULL }; + } public virtual void NotifySessionID(byte[] sessionID) - { - // Currently ignored - } + { + // Currently ignored + } - public virtual void NotifySelectedCipherSuite(CipherSuite selectedCipherSuite) - { - this.selectedCipherSuite = selectedCipherSuite; - } + public virtual void NotifySelectedCipherSuite(int selectedCipherSuite) + { + this.selectedCipherSuite = selectedCipherSuite; + } - public virtual void NotifySelectedCompressionMethod(CompressionMethod selectedCompressionMethod) - { - this.selectedCompressionMethod = selectedCompressionMethod; - } + public virtual void NotifySelectedCompressionMethod(byte selectedCompressionMethod) + { + this.selectedCompressionMethod = selectedCompressionMethod; + } public virtual void NotifySecureRenegotiation(bool secureRenegotiation) - { - if (!secureRenegotiation) - { - /* - * RFC 5746 3.4. If the extension is not present, the server does not support - * secure renegotiation; set secure_renegotiation flag to FALSE. In this case, - * some clients may want to terminate the handshake instead of continuing; see - * Section 4.1 for discussion. - */ + { + if (!secureRenegotiation) + { + /* + * RFC 5746 3.4. If the extension is not present, the server does not support + * secure renegotiation; set secure_renegotiation flag to FALSE. In this case, + * some clients may want to terminate the handshake instead of continuing; see + * Section 4.1 for discussion. + */ // throw new TlsFatalAlert(AlertDescription.handshake_failure); - } - } + } + } public virtual void ProcessServerExtensions(IDictionary serverExtensions) - { - } + { + } public virtual TlsKeyExchange GetKeyExchange() - { - switch (selectedCipherSuite) - { - case CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA: - case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA: - case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA: + { + switch (selectedCipherSuite) + { + case CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA: case CipherSuite.TLS_PSK_WITH_RC4_128_SHA: - return CreatePskKeyExchange(KeyExchangeAlgorithm.PSK); + return CreatePskKeyExchange(KeyExchangeAlgorithm.PSK); case CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA: - case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA: - case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA: case CipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA: return CreatePskKeyExchange(KeyExchangeAlgorithm.RSA_PSK); case CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA: - case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA: - case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA: case CipherSuite.TLS_DHE_PSK_WITH_RC4_128_SHA: return CreatePskKeyExchange(KeyExchangeAlgorithm.DHE_PSK); default: - /* - * Note: internal error here; the TlsProtocolHandler verifies that the - * server-selected cipher suite was in the list of client-offered cipher - * suites, so if we now can't produce an implementation, we shouldn't have - * offered it! - */ - throw new TlsFatalAlert(AlertDescription.internal_error); - } - } + /* + * Note: internal error here; the TlsProtocolHandler verifies that the + * server-selected cipher suite was in the list of client-offered cipher + * suites, so if we now can't produce an implementation, we shouldn't have + * offered it! + */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } public abstract TlsAuthentication GetAuthentication(); public virtual TlsCompression GetCompression() - { - switch (selectedCompressionMethod) - { - case CompressionMethod.NULL: - return new TlsNullCompression(); + { + switch (selectedCompressionMethod) + { + case CompressionMethod.NULL: + return new TlsNullCompression(); default: - /* - * Note: internal error here; the TlsProtocolHandler verifies that the - * server-selected compression method was in the list of client-offered compression - * methods, so if we now can't produce an implementation, we shouldn't have - * offered it! - */ - throw new TlsFatalAlert(AlertDescription.internal_error); - } - } + /* + * Note: internal error here; the TlsProtocolHandler verifies that the + * server-selected compression method was in the list of client-offered compression + * methods, so if we now can't produce an implementation, we shouldn't have + * offered it! + */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } public virtual TlsCipher GetCipher() - { - switch (selectedCipherSuite) - { - case CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA: - case CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA: - case CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA: - return cipherFactory.CreateCipher(context, EncryptionAlgorithm.cls_3DES_EDE_CBC, - DigestAlgorithm.SHA); + { + switch (selectedCipherSuite) + { + case CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA: + return cipherFactory.CreateCipher(context, EncryptionAlgorithm.cls_3DES_EDE_CBC, + DigestAlgorithm.SHA); case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA: - case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA: - case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA: - return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_128_CBC, - DigestAlgorithm.SHA); + case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA: + return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_128_CBC, + DigestAlgorithm.SHA); case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA: - case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA: - case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA: - return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_256_CBC, - DigestAlgorithm.SHA); + case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA: + return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_256_CBC, + DigestAlgorithm.SHA); case CipherSuite.TLS_PSK_WITH_RC4_128_SHA: case CipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA: @@ -173,19 +173,19 @@ namespace Org.BouncyCastle.Crypto.Tls DigestAlgorithm.SHA); default: - /* - * Note: internal error here; the TlsProtocolHandler verifies that the - * server-selected cipher suite was in the list of client-offered cipher - * suites, so if we now can't produce an implementation, we shouldn't have - * offered it! - */ - throw new TlsFatalAlert(AlertDescription.internal_error); - } - } - - protected virtual TlsKeyExchange CreatePskKeyExchange(KeyExchangeAlgorithm keyExchange) - { - return new TlsPskKeyExchange(context, keyExchange, pskIdentity); - } - } + /* + * Note: internal error here; the TlsProtocolHandler verifies that the + * server-selected cipher suite was in the list of client-offered cipher + * suites, so if we now can't produce an implementation, we shouldn't have + * offered it! + */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + protected virtual TlsKeyExchange CreatePskKeyExchange(int keyExchange) + { + return new TlsPskKeyExchange(context, keyExchange, pskIdentity); + } + } } diff --git a/crypto/src/crypto/tls/RecordStream.cs b/crypto/src/crypto/tls/RecordStream.cs
index 4a5cdc1c9..ce8882cbe 100644 --- a/crypto/src/crypto/tls/RecordStream.cs +++ b/crypto/src/crypto/tls/RecordStream.cs
@@ -45,21 +45,21 @@ namespace Org.BouncyCastle.Crypto.Tls public void ReadData() { - ContentType type = (ContentType)TlsUtilities.ReadUint8(inStr); + byte contentType = TlsUtilities.ReadUint8(inStr); TlsUtilities.CheckVersion(inStr); int size = TlsUtilities.ReadUint16(inStr); - byte[] buf = DecodeAndVerify(type, inStr, size); - handler.ProcessData(type, buf, 0, buf.Length); + byte[] buf = DecodeAndVerify(contentType, inStr, size); + handler.ProcessData(contentType, buf, 0, buf.Length); } internal byte[] DecodeAndVerify( - ContentType type, + byte contentType, Stream inStr, int len) { byte[] buf = new byte[len]; TlsUtilities.ReadFully(buf, inStr); - byte[] decoded = readCipher.DecodeCiphertext(type, buf, 0, buf.Length); + byte[] decoded = readCipher.DecodeCiphertext(contentType, buf, 0, buf.Length); Stream cOut = readCompression.Decompress(buffer); @@ -76,10 +76,10 @@ namespace Org.BouncyCastle.Crypto.Tls } internal void WriteMessage( - ContentType type, - byte[] message, - int offset, - int len) + byte type, + byte[] message, + int offset, + int len) { if (type == ContentType.handshake) { diff --git a/crypto/src/crypto/tls/SignatureAlgorithm.cs b/crypto/src/crypto/tls/SignatureAlgorithm.cs new file mode 100644
index 000000000..35b961762 --- /dev/null +++ b/crypto/src/crypto/tls/SignatureAlgorithm.cs
@@ -0,0 +1,15 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Tls +{ + /** + * RFC 5246 7.4.1.4.1 (in RFC 2246, there were no specific values assigned) + */ + public abstract class SignatureAlgorithm + { + public const byte anonymous = 0; + public const byte rsa = 1; + public const byte dsa = 2; + public const byte ecdsa = 3; + } +} diff --git a/crypto/src/crypto/tls/SignatureAndHashAlgorithm.cs b/crypto/src/crypto/tls/SignatureAndHashAlgorithm.cs new file mode 100644
index 000000000..f74205b62 --- /dev/null +++ b/crypto/src/crypto/tls/SignatureAndHashAlgorithm.cs
@@ -0,0 +1,94 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Crypto.Tls +{ + /** + * RFC 5246 7.4.1.4.1 + */ + public class SignatureAndHashAlgorithm + { + protected readonly byte mHash; + protected readonly byte mSignature; + + /** + * @param hash {@link HashAlgorithm} + * @param signature {@link SignatureAlgorithm} + */ + public SignatureAndHashAlgorithm(byte hash, byte signature) + { + if (!TlsUtilities.IsValidUint8(hash)) + { + throw new ArgumentException("should be a uint8", "hash"); + } + if (!TlsUtilities.IsValidUint8(signature)) + { + throw new ArgumentException("should be a uint8", "signature"); + } + if (signature == SignatureAlgorithm.anonymous) + { + throw new ArgumentException("MUST NOT be \"anonymous\"", "signature"); + } + + this.mHash = hash; + this.mSignature = signature; + } + + /** + * @return {@link HashAlgorithm} + */ + public virtual byte Hash + { + get { return mHash; } + } + + /** + * @return {@link SignatureAlgorithm} + */ + public virtual byte Signature + { + get { return mSignature; } + } + + public override bool Equals(object obj) + { + if (!(obj is SignatureAndHashAlgorithm)) + { + return false; + } + SignatureAndHashAlgorithm other = (SignatureAndHashAlgorithm)obj; + return other.Hash == Hash && other.Signature == Signature; + } + + public override int GetHashCode() + { + return ((int)Hash << 16) | (int)Signature; + } + + /** + * Encode this {@link SignatureAndHashAlgorithm} to a {@link Stream}. + * + * @param output the {@link Stream} to encode to. + * @throws IOException + */ + public virtual void Encode(Stream output) + { + TlsUtilities.WriteUint8(Hash, output); + TlsUtilities.WriteUint8(Signature, output); + } + + /** + * Parse a {@link SignatureAndHashAlgorithm} from a {@link Stream}. + * + * @param input the {@link Stream} to parse from. + * @return a {@link SignatureAndHashAlgorithm} object. + * @throws IOException + */ + public static SignatureAndHashAlgorithm Parse(Stream input) + { + byte hash = TlsUtilities.ReadUint8(input); + byte signature = TlsUtilities.ReadUint8(input); + return new SignatureAndHashAlgorithm(hash, signature); + } + } +} diff --git a/crypto/src/crypto/tls/SrpTlsClient.cs b/crypto/src/crypto/tls/SrpTlsClient.cs
index 6c2638bb3..f9c8ccc74 100644 --- a/crypto/src/crypto/tls/SrpTlsClient.cs +++ b/crypto/src/crypto/tls/SrpTlsClient.cs
@@ -6,183 +6,183 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Crypto.Tls { - public abstract class SrpTlsClient - : TlsClient - { - protected TlsCipherFactory cipherFactory; - protected byte[] identity; - protected byte[] password; - - protected TlsClientContext context; - - protected CompressionMethod selectedCompressionMethod; - protected CipherSuite selectedCipherSuite; - - public SrpTlsClient(byte[] identity, byte[] password) - : this(new DefaultTlsCipherFactory(), identity, password) - { - } - - public SrpTlsClient(TlsCipherFactory cipherFactory, byte[] identity, byte[] password) - { - this.cipherFactory = cipherFactory; - this.identity = Arrays.Clone(identity); - this.password = Arrays.Clone(password); - } - - public virtual void Init(TlsClientContext context) - { - this.context = context; - } - - public virtual CipherSuite[] GetCipherSuites() - { - return new CipherSuite[] { - CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA, - CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA, - CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA, - CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA, - CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA, - CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA, - CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA, - CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA, - CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA, - }; - } - - public virtual IDictionary GetClientExtensions() - { - IDictionary clientExtensions = Platform.CreateHashtable(); - - MemoryStream srpData = new MemoryStream(); - TlsUtilities.WriteOpaque8(this.identity, srpData); - clientExtensions[ExtensionType.srp] = srpData.ToArray(); - - return clientExtensions; - } - - public virtual CompressionMethod[] GetCompressionMethods() - { - return new CompressionMethod[] { CompressionMethod.NULL }; - } - - public virtual void NotifySessionID(byte[] sessionID) - { - // Currently ignored - } - - public virtual void NotifySelectedCipherSuite(CipherSuite selectedCipherSuite) - { - this.selectedCipherSuite = selectedCipherSuite; - } - - public virtual void NotifySelectedCompressionMethod(CompressionMethod selectedCompressionMethod) - { + public abstract class SrpTlsClient + : TlsClient + { + protected TlsCipherFactory cipherFactory; + protected byte[] identity; + protected byte[] password; + + protected TlsClientContext context; + + protected byte selectedCompressionMethod; + protected int selectedCipherSuite; + + public SrpTlsClient(byte[] identity, byte[] password) + : this(new DefaultTlsCipherFactory(), identity, password) + { + } + + public SrpTlsClient(TlsCipherFactory cipherFactory, byte[] identity, byte[] password) + { + this.cipherFactory = cipherFactory; + this.identity = Arrays.Clone(identity); + this.password = Arrays.Clone(password); + } + + public virtual void Init(TlsClientContext context) + { + this.context = context; + } + + public virtual int[] GetCipherSuites() + { + return new int[] { + CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA, + CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA, + CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA, + CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA, + CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA, + CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA, + CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA, + CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA, + CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA, + }; + } + + public virtual IDictionary GetClientExtensions() + { + IDictionary clientExtensions = Platform.CreateHashtable(); + + MemoryStream srpData = new MemoryStream(); + TlsUtilities.WriteOpaque8(this.identity, srpData); + clientExtensions[ExtensionType.srp] = srpData.ToArray(); + + return clientExtensions; + } + + public virtual byte[] GetCompressionMethods() + { + return new byte[] { CompressionMethod.NULL }; + } + + public virtual void NotifySessionID(byte[] sessionID) + { + // Currently ignored + } + + public virtual void NotifySelectedCipherSuite(int selectedCipherSuite) + { + this.selectedCipherSuite = selectedCipherSuite; + } + + public virtual void NotifySelectedCompressionMethod(byte selectedCompressionMethod) + { this.selectedCompressionMethod = selectedCompressionMethod; } - public virtual void NotifySecureRenegotiation(bool secureRenegotiation) - { - if (!secureRenegotiation) - { - /* - * RFC 5746 3.4. If the extension is not present, the server does not support - * secure renegotiation; set secure_renegotiation flag to FALSE. In this case, - * some clients may want to terminate the handshake instead of continuing; see - * Section 4.1 for discussion. - */ + public virtual void NotifySecureRenegotiation(bool secureRenegotiation) + { + if (!secureRenegotiation) + { + /* + * RFC 5746 3.4. If the extension is not present, the server does not support + * secure renegotiation; set secure_renegotiation flag to FALSE. In this case, + * some clients may want to terminate the handshake instead of continuing; see + * Section 4.1 for discussion. + */ // throw new TlsFatalAlert(AlertDescription.handshake_failure); - } - } - - public virtual void ProcessServerExtensions(IDictionary serverExtensions) - { - // There is no server response for the SRP extension - } - - public virtual TlsKeyExchange GetKeyExchange() - { - switch (selectedCipherSuite) - { - case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA: - case CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA: - case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA: - return CreateSrpKeyExchange(KeyExchangeAlgorithm.SRP); - - case CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA: - case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA: - case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA: - return CreateSrpKeyExchange(KeyExchangeAlgorithm.SRP_RSA); - - case CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA: - case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA: - case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA: - return CreateSrpKeyExchange(KeyExchangeAlgorithm.SRP_DSS); - - default: - /* - * Note: internal error here; the TlsProtocolHandler verifies that the - * server-selected cipher suite was in the list of client-offered cipher - * suites, so if we now can't produce an implementation, we shouldn't have - * offered it! - */ - throw new TlsFatalAlert(AlertDescription.internal_error); - } - } - - public abstract TlsAuthentication GetAuthentication(); - - public virtual TlsCompression GetCompression() - { - switch (selectedCompressionMethod) - { - case CompressionMethod.NULL: - return new TlsNullCompression(); - - default: - /* - * Note: internal error here; the TlsProtocolHandler verifies that the - * server-selected compression method was in the list of client-offered compression - * methods, so if we now can't produce an implementation, we shouldn't have - * offered it! - */ - throw new TlsFatalAlert(AlertDescription.internal_error); - } - } - - public virtual TlsCipher GetCipher() - { - switch (selectedCipherSuite) - { - case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA: - case CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA: - case CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA: - return cipherFactory.CreateCipher(context, EncryptionAlgorithm.cls_3DES_EDE_CBC, DigestAlgorithm.SHA); - - case CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA: - case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA: - case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA: - return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_128_CBC, DigestAlgorithm.SHA); - - case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA: - case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA: - case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA: - return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_256_CBC, DigestAlgorithm.SHA); - - default: - /* - * Note: internal error here; the TlsProtocolHandler verifies that the - * server-selected cipher suite was in the list of client-offered cipher - * suites, so if we now can't produce an implementation, we shouldn't have - * offered it! - */ - throw new TlsFatalAlert(AlertDescription.internal_error); - } - } - - protected virtual TlsKeyExchange CreateSrpKeyExchange(KeyExchangeAlgorithm keyExchange) - { - return new TlsSrpKeyExchange(context, keyExchange, identity, password); - } - } + } + } + + public virtual void ProcessServerExtensions(IDictionary serverExtensions) + { + // There is no server response for the SRP extension + } + + public virtual TlsKeyExchange GetKeyExchange() + { + switch (selectedCipherSuite) + { + case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA: + return CreateSrpKeyExchange(KeyExchangeAlgorithm.SRP); + + case CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA: + return CreateSrpKeyExchange(KeyExchangeAlgorithm.SRP_RSA); + + case CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA: + return CreateSrpKeyExchange(KeyExchangeAlgorithm.SRP_DSS); + + default: + /* + * Note: internal error here; the TlsProtocolHandler verifies that the + * server-selected cipher suite was in the list of client-offered cipher + * suites, so if we now can't produce an implementation, we shouldn't have + * offered it! + */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public abstract TlsAuthentication GetAuthentication(); + + public virtual TlsCompression GetCompression() + { + switch (selectedCompressionMethod) + { + case CompressionMethod.NULL: + return new TlsNullCompression(); + + default: + /* + * Note: internal error here; the TlsProtocolHandler verifies that the + * server-selected compression method was in the list of client-offered compression + * methods, so if we now can't produce an implementation, we shouldn't have + * offered it! + */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public virtual TlsCipher GetCipher() + { + switch (selectedCipherSuite) + { + case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA: + return cipherFactory.CreateCipher(context, EncryptionAlgorithm.cls_3DES_EDE_CBC, DigestAlgorithm.SHA); + + case CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA: + return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_128_CBC, DigestAlgorithm.SHA); + + case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA: + return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_256_CBC, DigestAlgorithm.SHA); + + default: + /* + * Note: internal error here; the TlsProtocolHandler verifies that the + * server-selected cipher suite was in the list of client-offered cipher + * suites, so if we now can't produce an implementation, we shouldn't have + * offered it! + */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + protected virtual TlsKeyExchange CreateSrpKeyExchange(int keyExchange) + { + return new TlsSrpKeyExchange(context, keyExchange, identity, password); + } + } } diff --git a/crypto/src/crypto/tls/TlsBlockCipher.cs b/crypto/src/crypto/tls/TlsBlockCipher.cs
index d77f118f4..cfbceb25e 100644 --- a/crypto/src/crypto/tls/TlsBlockCipher.cs +++ b/crypto/src/crypto/tls/TlsBlockCipher.cs
@@ -9,13 +9,13 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Crypto.Tls { - /// <summary> - /// A generic TLS 1.0 block cipher. This can be used for AES or 3DES for example. - /// </summary> - public class TlsBlockCipher + /// <summary> + /// A generic TLS 1.0 block cipher. This can be used for AES or 3DES for example. + /// </summary> + public class TlsBlockCipher : TlsCipher - { - protected TlsClientContext context; + { + protected TlsClientContext context; protected byte[] randomData; protected IBlockCipher encryptCipher; @@ -25,86 +25,86 @@ namespace Org.BouncyCastle.Crypto.Tls protected TlsMac rMac; public virtual TlsMac WriteMac - { + { get { return wMac; } - } + } - public virtual TlsMac ReadMac - { + public virtual TlsMac ReadMac + { get { return rMac; } - } + } - public TlsBlockCipher(TlsClientContext context, IBlockCipher encryptCipher, - IBlockCipher decryptCipher, IDigest writeDigest, IDigest readDigest, int cipherKeySize) - { - this.context = context; + public TlsBlockCipher(TlsClientContext context, IBlockCipher encryptCipher, + IBlockCipher decryptCipher, IDigest writeDigest, IDigest readDigest, int cipherKeySize) + { + this.context = context; this.randomData = new byte[256]; context.SecureRandom.NextBytes(randomData); this.encryptCipher = encryptCipher; - this.decryptCipher = decryptCipher; + this.decryptCipher = decryptCipher; - int prfSize = (2 * cipherKeySize) + writeDigest.GetDigestSize() - + readDigest.GetDigestSize() + encryptCipher.GetBlockSize() - + decryptCipher.GetBlockSize(); + int prfSize = (2 * cipherKeySize) + writeDigest.GetDigestSize() + + readDigest.GetDigestSize() + encryptCipher.GetBlockSize() + + decryptCipher.GetBlockSize(); - SecurityParameters securityParameters = context.SecurityParameters; + SecurityParameters securityParameters = context.SecurityParameters; - byte[] keyBlock = TlsUtilities.PRF(securityParameters.masterSecret, "key expansion", - TlsUtilities.Concat(securityParameters.serverRandom, securityParameters.clientRandom), - prfSize); + byte[] keyBlock = TlsUtilities.PRF(securityParameters.masterSecret, "key expansion", + TlsUtilities.Concat(securityParameters.serverRandom, securityParameters.clientRandom), + prfSize); - int offset = 0; + int offset = 0; - // Init MACs - wMac = CreateTlsMac(writeDigest, keyBlock, ref offset); + // Init MACs + wMac = CreateTlsMac(writeDigest, keyBlock, ref offset); rMac = CreateTlsMac(readDigest, keyBlock, ref offset); - // Build keys - KeyParameter encryptKey = CreateKeyParameter(keyBlock, ref offset, cipherKeySize); - KeyParameter decryptKey = CreateKeyParameter(keyBlock, ref offset, cipherKeySize); + // Build keys + KeyParameter encryptKey = CreateKeyParameter(keyBlock, ref offset, cipherKeySize); + KeyParameter decryptKey = CreateKeyParameter(keyBlock, ref offset, cipherKeySize); - // Add IVs - ParametersWithIV encryptParams = CreateParametersWithIV(encryptKey, - keyBlock, ref offset, encryptCipher.GetBlockSize()); - ParametersWithIV decryptParams = CreateParametersWithIV(decryptKey, - keyBlock, ref offset, decryptCipher.GetBlockSize()); + // Add IVs + ParametersWithIV encryptParams = CreateParametersWithIV(encryptKey, + keyBlock, ref offset, encryptCipher.GetBlockSize()); + ParametersWithIV decryptParams = CreateParametersWithIV(decryptKey, + keyBlock, ref offset, decryptCipher.GetBlockSize()); - if (offset != prfSize) - throw new TlsFatalAlert(AlertDescription.internal_error); + if (offset != prfSize) + throw new TlsFatalAlert(AlertDescription.internal_error); - // Init Ciphers - encryptCipher.Init(true, encryptParams); - decryptCipher.Init(false, decryptParams); - } + // Init Ciphers + encryptCipher.Init(true, encryptParams); + decryptCipher.Init(false, decryptParams); + } protected virtual TlsMac CreateTlsMac(IDigest digest, byte[] buf, ref int off) - { - int len = digest.GetDigestSize(); - TlsMac mac = new TlsMac(digest, buf, off, len); - off += len; - return mac; - } + { + int len = digest.GetDigestSize(); + TlsMac mac = new TlsMac(digest, buf, off, len); + off += len; + return mac; + } protected virtual KeyParameter CreateKeyParameter(byte[] buf, ref int off, int len) - { - KeyParameter key = new KeyParameter(buf, off, len); - off += len; - return key; - } + { + KeyParameter key = new KeyParameter(buf, off, len); + off += len; + return key; + } protected virtual ParametersWithIV CreateParametersWithIV(KeyParameter key, - byte[] buf, ref int off, int len) - { - ParametersWithIV ivParams = new ParametersWithIV(key, buf, off, len); - off += len; - return ivParams; - } - - public virtual byte[] EncodePlaintext(ContentType type, byte[] plaintext, int offset, int len) - { - int blocksize = encryptCipher.GetBlockSize(); + byte[] buf, ref int off, int len) + { + ParametersWithIV ivParams = new ParametersWithIV(key, buf, off, len); + off += len; + return ivParams; + } + + public virtual byte[] EncodePlaintext(byte type, byte[] plaintext, int offset, int len) + { + int blocksize = encryptCipher.GetBlockSize(); int padding_length = blocksize - 1 - ((len + wMac.Size) % blocksize); //bool isTls = context.ServerVersion.FullVersion >= ProtocolVersion.TLSv10.FullVersion; @@ -119,24 +119,24 @@ namespace Org.BouncyCastle.Crypto.Tls } int totalsize = len + wMac.Size + padding_length + 1; - byte[] outbuf = new byte[totalsize]; - Array.Copy(plaintext, offset, outbuf, 0, len); + byte[] outbuf = new byte[totalsize]; + Array.Copy(plaintext, offset, outbuf, 0, len); byte[] mac = wMac.CalculateMac(type, plaintext, offset, len); - Array.Copy(mac, 0, outbuf, len, mac.Length); - int paddoffset = len + mac.Length; + Array.Copy(mac, 0, outbuf, len, mac.Length); + int paddoffset = len + mac.Length; for (int i = 0; i <= padding_length; i++) - { + { outbuf[i + paddoffset] = (byte)padding_length; - } - for (int i = 0; i < totalsize; i += blocksize) - { - encryptCipher.ProcessBlock(outbuf, i, outbuf, i); - } - return outbuf; - } - - public virtual byte[] DecodeCiphertext(ContentType type, byte[] ciphertext, int offset, int len) - { + } + for (int i = 0; i < totalsize; i += blocksize) + { + encryptCipher.ProcessBlock(outbuf, i, outbuf, i); + } + return outbuf; + } + + public virtual byte[] DecodeCiphertext(byte type, byte[] ciphertext, int offset, int len) + { int blockSize = decryptCipher.GetBlockSize(); int macSize = rMac.Size; @@ -173,7 +173,7 @@ namespace Org.BouncyCastle.Crypto.Tls throw new TlsFatalAlert(AlertDescription.bad_record_mac); return Arrays.Copy(ciphertext, offset, macInputLen); - } + } protected virtual int CheckPaddingConstantTime(byte[] buf, int off, int len, int blockSize, int macSize) { @@ -224,28 +224,28 @@ namespace Org.BouncyCastle.Crypto.Tls } protected virtual int ChooseExtraPadBlocks(SecureRandom r, int max) - { + { // return r.NextInt(max + 1); - uint x = (uint)r.NextInt(); - int n = LowestBitSet(x); - return System.Math.Min(n, max); - } + uint x = (uint)r.NextInt(); + int n = LowestBitSet(x); + return System.Math.Min(n, max); + } private int LowestBitSet(uint x) - { - if (x == 0) - { - return 32; - } - - int n = 0; - while ((x & 1) == 0) - { - ++n; - x >>= 1; - } - return n; - } - } + { + if (x == 0) + { + return 32; + } + + int n = 0; + while ((x & 1) == 0) + { + ++n; + x >>= 1; + } + return n; + } + } } diff --git a/crypto/src/crypto/tls/TlsCipher.cs b/crypto/src/crypto/tls/TlsCipher.cs
index 22c769d82..a58f4943f 100644 --- a/crypto/src/crypto/tls/TlsCipher.cs +++ b/crypto/src/crypto/tls/TlsCipher.cs
@@ -3,12 +3,12 @@ using System.IO; namespace Org.BouncyCastle.Crypto.Tls { - public interface TlsCipher - { - /// <exception cref="IOException"></exception> - byte[] EncodePlaintext(ContentType type, byte[] plaintext, int offset, int len); + public interface TlsCipher + { + /// <exception cref="IOException"></exception> + byte[] EncodePlaintext(byte type, byte[] plaintext, int offset, int len); - /// <exception cref="IOException"></exception> - byte[] DecodeCiphertext(ContentType type, byte[] ciphertext, int offset, int len); - } + /// <exception cref="IOException"></exception> + byte[] DecodeCiphertext(byte type, byte[] ciphertext, int offset, int len); + } } diff --git a/crypto/src/crypto/tls/TlsCipherFactory.cs b/crypto/src/crypto/tls/TlsCipherFactory.cs
index 0756603f4..bd65f8b4b 100644 --- a/crypto/src/crypto/tls/TlsCipherFactory.cs +++ b/crypto/src/crypto/tls/TlsCipherFactory.cs
@@ -3,10 +3,10 @@ using System.IO; namespace Org.BouncyCastle.Crypto.Tls { - public interface TlsCipherFactory - { - /// <exception cref="IOException"></exception> - TlsCipher CreateCipher(TlsClientContext context, EncryptionAlgorithm encryptionAlgorithm, - DigestAlgorithm digestAlgorithm); - } + public interface TlsCipherFactory + { + /// <exception cref="IOException"></exception> + TlsCipher CreateCipher(TlsClientContext context, int encryptionAlgorithm, + DigestAlgorithm digestAlgorithm); + } } diff --git a/crypto/src/crypto/tls/TlsClient.cs b/crypto/src/crypto/tls/TlsClient.cs
index eceaa3cd3..9e7937c94 100644 --- a/crypto/src/crypto/tls/TlsClient.cs +++ b/crypto/src/crypto/tls/TlsClient.cs
@@ -4,60 +4,60 @@ using System.IO; namespace Org.BouncyCastle.Crypto.Tls { - public interface TlsClient - { - /// <summary> - /// Called at the start of a new TLS session, before any other methods. - /// </summary> - /// <param name="context"> - /// A <see cref="TlsProtocolHandler"/> - /// </param> - void Init(TlsClientContext context); + public interface TlsClient + { + /// <summary> + /// Called at the start of a new TLS session, before any other methods. + /// </summary> + /// <param name="context"> + /// A <see cref="TlsProtocolHandler"/> + /// </param> + void Init(TlsClientContext context); - /// <summary> - /// Get the list of cipher suites that this client supports. - /// </summary> - /// <returns> - /// An array of <see cref="CipherSuite"/>, each specifying a supported cipher suite. - /// </returns> - CipherSuite[] GetCipherSuites(); + /// <summary> + /// Get the list of cipher suites that this client supports. + /// </summary> + /// <returns> + /// An array of <see cref="CipherSuite"/> values, each specifying a supported cipher suite. + /// </returns> + int[] GetCipherSuites(); /// <summary> /// Get the list of compression methods that this client supports. /// </summary> /// <returns> - /// An array of <see cref="CompressionMethod"/>, each specifying a supported compression method. + /// An array of <see cref="CompressionMethod"/> values, each specifying a supported compression method. /// </returns> - CompressionMethod[] GetCompressionMethods(); + byte[] GetCompressionMethods(); - /// <summary> - /// Get the (optional) table of client extensions to be included in (extended) client hello. - /// </summary> - /// <returns> - /// A <see cref="IDictionary"/> (<see cref="ExtensionType"/> -> byte[]). May be null. - /// </returns> - /// <exception cref="IOException"></exception> - IDictionary GetClientExtensions(); + /// <summary> + /// Get the (optional) table of client extensions to be included in (extended) client hello. + /// </summary> + /// <returns> + /// A <see cref="IDictionary"/> (Int32 -> byte[]). May be null. + /// </returns> + /// <exception cref="IOException"></exception> + IDictionary GetClientExtensions(); - /// <summary> - /// Reports the session ID once it has been determined. - /// </summary> - /// <param name="sessionID"> - /// A <see cref="System.Byte"/> - /// </param> - void NotifySessionID(byte[] sessionID); + /// <summary> + /// Reports the session ID once it has been determined. + /// </summary> + /// <param name="sessionID"> + /// A <see cref="System.Byte"/> + /// </param> + void NotifySessionID(byte[] sessionID); - /// <summary> - /// Report the cipher suite that was selected by the server. - /// </summary> - /// <remarks> - /// The protocol handler validates this value against the offered cipher suites - /// <seealso cref="GetCipherSuites"/> - /// </remarks> - /// <param name="selectedCipherSuite"> - /// A <see cref="CipherSuite"/> - /// </param> - void NotifySelectedCipherSuite(CipherSuite selectedCipherSuite); + /// <summary> + /// Report the cipher suite that was selected by the server. + /// </summary> + /// <remarks> + /// The protocol handler validates this value against the offered cipher suites + /// <seealso cref="GetCipherSuites"/> + /// </remarks> + /// <param name="selectedCipherSuite"> + /// A <see cref="CipherSuite"/> + /// </param> + void NotifySelectedCipherSuite(int selectedCipherSuite); /// <summary> /// Report the compression method that was selected by the server. @@ -69,61 +69,61 @@ namespace Org.BouncyCastle.Crypto.Tls /// <param name="selectedCompressionMethod"> /// A <see cref="CompressionMethod"/> /// </param> - void NotifySelectedCompressionMethod(CompressionMethod selectedCompressionMethod); + void NotifySelectedCompressionMethod(byte selectedCompressionMethod); - /// <summary> - /// Report whether the server supports secure renegotiation - /// </summary> - /// <remarks> - /// The protocol handler automatically processes the relevant extensions - /// </remarks> - /// <param name="secureRenegotiation"> - /// A <see cref="System.Boolean"/>, true if the server supports secure renegotiation - /// </param> - /// <exception cref="IOException"></exception> - void NotifySecureRenegotiation(bool secureRenegotiation); + /// <summary> + /// Report whether the server supports secure renegotiation + /// </summary> + /// <remarks> + /// The protocol handler automatically processes the relevant extensions + /// </remarks> + /// <param name="secureRenegotiation"> + /// A <see cref="System.Boolean"/>, true if the server supports secure renegotiation + /// </param> + /// <exception cref="IOException"></exception> + void NotifySecureRenegotiation(bool secureRenegotiation); - /// <summary> - /// Report the extensions from an extended server hello. - /// </summary> - /// <remarks> - /// Will only be called if we returned a non-null result from <see cref="GetClientExtensions"/>. - /// </remarks> - /// <param name="serverExtensions"> - /// A <see cref="IDictionary"/> (<see cref="ExtensionType"/> -> byte[]) - /// </param> - void ProcessServerExtensions(IDictionary serverExtensions); + /// <summary> + /// Report the extensions from an extended server hello. + /// </summary> + /// <remarks> + /// Will only be called if we returned a non-null result from <see cref="GetClientExtensions"/>. + /// </remarks> + /// <param name="serverExtensions"> + /// A <see cref="IDictionary"/> (Int32 -> byte[]) + /// </param> + void ProcessServerExtensions(IDictionary serverExtensions); - /// <summary> - /// Return an implementation of <see cref="TlsKeyExchange"/> to negotiate the key exchange - /// part of the protocol. - /// </summary> - /// <returns> - /// A <see cref="TlsKeyExchange"/> - /// </returns> - /// <exception cref="IOException"/> - TlsKeyExchange GetKeyExchange(); + /// <summary> + /// Return an implementation of <see cref="TlsKeyExchange"/> to negotiate the key exchange + /// part of the protocol. + /// </summary> + /// <returns> + /// A <see cref="TlsKeyExchange"/> + /// </returns> + /// <exception cref="IOException"/> + TlsKeyExchange GetKeyExchange(); - /// <summary> - /// Return an implementation of <see cref="TlsAuthentication"/> to handle authentication - /// part of the protocol. - /// </summary> - /// <exception cref="IOException"/> - TlsAuthentication GetAuthentication(); + /// <summary> + /// Return an implementation of <see cref="TlsAuthentication"/> to handle authentication + /// part of the protocol. + /// </summary> + /// <exception cref="IOException"/> + TlsAuthentication GetAuthentication(); - /// <summary> - /// Return an implementation of <see cref="TlsCompression"/> to handle record compression. - /// </summary> - /// <exception cref="IOException"/> - TlsCompression GetCompression(); + /// <summary> + /// Return an implementation of <see cref="TlsCompression"/> to handle record compression. + /// </summary> + /// <exception cref="IOException"/> + TlsCompression GetCompression(); - /// <summary> - /// Return an implementation of <see cref="TlsCipher"/> to use for encryption/decryption. - /// </summary> - /// <returns> - /// A <see cref="TlsCipher"/> - /// </returns> - /// <exception cref="IOException"/> - TlsCipher GetCipher(); - } + /// <summary> + /// Return an implementation of <see cref="TlsCipher"/> to use for encryption/decryption. + /// </summary> + /// <returns> + /// A <see cref="TlsCipher"/> + /// </returns> + /// <exception cref="IOException"/> + TlsCipher GetCipher(); + } } diff --git a/crypto/src/crypto/tls/TlsDHKeyExchange.cs b/crypto/src/crypto/tls/TlsDHKeyExchange.cs
index 40ac416e0..26d76fd3d 100644 --- a/crypto/src/crypto/tls/TlsDHKeyExchange.cs +++ b/crypto/src/crypto/tls/TlsDHKeyExchange.cs
@@ -9,193 +9,193 @@ using Org.BouncyCastle.Security; namespace Org.BouncyCastle.Crypto.Tls { - /// <summary> - /// TLS 1.0 DH key exchange. - /// </summary> - internal class TlsDHKeyExchange - : TlsKeyExchange - { - protected TlsClientContext context; - protected KeyExchangeAlgorithm keyExchange; - protected TlsSigner tlsSigner; - - protected AsymmetricKeyParameter serverPublicKey = null; - protected DHPublicKeyParameters dhAgreeServerPublicKey = null; - protected TlsAgreementCredentials agreementCredentials; - protected DHPrivateKeyParameters dhAgreeClientPrivateKey = null; - - internal TlsDHKeyExchange(TlsClientContext context, KeyExchangeAlgorithm keyExchange) - { - switch (keyExchange) - { - case KeyExchangeAlgorithm.DH_RSA: - case KeyExchangeAlgorithm.DH_DSS: - this.tlsSigner = null; - break; - case KeyExchangeAlgorithm.DHE_RSA: - this.tlsSigner = new TlsRsaSigner(); - break; - case KeyExchangeAlgorithm.DHE_DSS: - this.tlsSigner = new TlsDssSigner(); - break; - default: - throw new ArgumentException("unsupported key exchange algorithm", "keyExchange"); - } - - this.context = context; - this.keyExchange = keyExchange; - } - - public virtual void SkipServerCertificate() - { - throw new TlsFatalAlert(AlertDescription.unexpected_message); - } - - public virtual void ProcessServerCertificate(Certificate serverCertificate) - { - X509CertificateStructure x509Cert = serverCertificate.certs[0]; - SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo; - - try - { - this.serverPublicKey = PublicKeyFactory.CreateKey(keyInfo); - } - catch (Exception) - { - throw new TlsFatalAlert(AlertDescription.unsupported_certificate); - } - - if (tlsSigner == null) - { - try - { - this.dhAgreeServerPublicKey = ValidateDHPublicKey((DHPublicKeyParameters)this.serverPublicKey); - } - catch (InvalidCastException) - { - throw new TlsFatalAlert(AlertDescription.certificate_unknown); - } - - TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.KeyAgreement); - } - else - { - if (!tlsSigner.IsValidPublicKey(this.serverPublicKey)) - { - throw new TlsFatalAlert(AlertDescription.certificate_unknown); - } - - TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.DigitalSignature); - } - - // TODO - /* - * Perform various checks per RFC2246 7.4.2: "Unless otherwise specified, the - * signing algorithm for the certificate must be the same as the algorithm for the - * certificate key." - */ - } - - public virtual void SkipServerKeyExchange() - { - // OK - } - - public virtual void ProcessServerKeyExchange(Stream input) - { - throw new TlsFatalAlert(AlertDescription.unexpected_message); - } - - public virtual void ValidateCertificateRequest(CertificateRequest certificateRequest) - { - ClientCertificateType[] types = certificateRequest.CertificateTypes; - foreach (ClientCertificateType type in types) - { - switch (type) - { - case ClientCertificateType.rsa_sign: - case ClientCertificateType.dss_sign: - case ClientCertificateType.rsa_fixed_dh: - case ClientCertificateType.dss_fixed_dh: - case ClientCertificateType.ecdsa_sign: - break; - default: - throw new TlsFatalAlert(AlertDescription.illegal_parameter); - } - } - } - - public virtual void SkipClientCredentials() - { - this.agreementCredentials = null; - } - - public virtual void ProcessClientCredentials(TlsCredentials clientCredentials) - { - if (clientCredentials is TlsAgreementCredentials) - { - // TODO Validate client cert has matching parameters (see 'areCompatibleParameters')? - - this.agreementCredentials = (TlsAgreementCredentials)clientCredentials; - } - else if (clientCredentials is TlsSignerCredentials) - { - // OK - } - else - { - throw new TlsFatalAlert(AlertDescription.internal_error); - } - } - - public virtual void GenerateClientKeyExchange(Stream output) - { - /* - * RFC 2246 7.4.7.2 If the client certificate already contains a suitable - * Diffie-Hellman key, then Yc is implicit and does not need to be sent again. In - * this case, the Client Key Exchange message will be sent, but will be empty. - */ - if (agreementCredentials == null) - { - GenerateEphemeralClientKeyExchange(dhAgreeServerPublicKey.Parameters, output); - } - } + /// <summary> + /// TLS 1.0 DH key exchange. + /// </summary> + internal class TlsDHKeyExchange + : TlsKeyExchange + { + protected TlsClientContext context; + protected int keyExchange; + protected TlsSigner tlsSigner; + + protected AsymmetricKeyParameter serverPublicKey = null; + protected DHPublicKeyParameters dhAgreeServerPublicKey = null; + protected TlsAgreementCredentials agreementCredentials; + protected DHPrivateKeyParameters dhAgreeClientPrivateKey = null; + + internal TlsDHKeyExchange(TlsClientContext context, int keyExchange) + { + switch (keyExchange) + { + case KeyExchangeAlgorithm.DH_RSA: + case KeyExchangeAlgorithm.DH_DSS: + this.tlsSigner = null; + break; + case KeyExchangeAlgorithm.DHE_RSA: + this.tlsSigner = new TlsRsaSigner(); + break; + case KeyExchangeAlgorithm.DHE_DSS: + this.tlsSigner = new TlsDssSigner(); + break; + default: + throw new ArgumentException("unsupported key exchange algorithm", "keyExchange"); + } + + this.context = context; + this.keyExchange = keyExchange; + } + + public virtual void SkipServerCertificate() + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + public virtual void ProcessServerCertificate(Certificate serverCertificate) + { + X509CertificateStructure x509Cert = serverCertificate.GetCertificateAt(0); + SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo; + + try + { + this.serverPublicKey = PublicKeyFactory.CreateKey(keyInfo); + } + catch (Exception) + { + throw new TlsFatalAlert(AlertDescription.unsupported_certificate); + } + + if (tlsSigner == null) + { + try + { + this.dhAgreeServerPublicKey = ValidateDHPublicKey((DHPublicKeyParameters)this.serverPublicKey); + } + catch (InvalidCastException) + { + throw new TlsFatalAlert(AlertDescription.certificate_unknown); + } + + TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.KeyAgreement); + } + else + { + if (!tlsSigner.IsValidPublicKey(this.serverPublicKey)) + { + throw new TlsFatalAlert(AlertDescription.certificate_unknown); + } + + TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.DigitalSignature); + } + + // TODO + /* + * Perform various checks per RFC2246 7.4.2: "Unless otherwise specified, the + * signing algorithm for the certificate must be the same as the algorithm for the + * certificate key." + */ + } + + public virtual void SkipServerKeyExchange() + { + // OK + } + + public virtual void ProcessServerKeyExchange(Stream input) + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + public virtual void ValidateCertificateRequest(CertificateRequest certificateRequest) + { + byte[] types = certificateRequest.CertificateTypes; + foreach (byte type in types) + { + switch (type) + { + case ClientCertificateType.rsa_sign: + case ClientCertificateType.dss_sign: + case ClientCertificateType.rsa_fixed_dh: + case ClientCertificateType.dss_fixed_dh: + case ClientCertificateType.ecdsa_sign: + break; + default: + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + } + } + + public virtual void SkipClientCredentials() + { + this.agreementCredentials = null; + } + + public virtual void ProcessClientCredentials(TlsCredentials clientCredentials) + { + if (clientCredentials is TlsAgreementCredentials) + { + // TODO Validate client cert has matching parameters (see 'areCompatibleParameters')? + + this.agreementCredentials = (TlsAgreementCredentials)clientCredentials; + } + else if (clientCredentials is TlsSignerCredentials) + { + // OK + } + else + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public virtual void GenerateClientKeyExchange(Stream output) + { + /* + * RFC 2246 7.4.7.2 If the client certificate already contains a suitable + * Diffie-Hellman key, then Yc is implicit and does not need to be sent again. In + * this case, the Client Key Exchange message will be sent, but will be empty. + */ + if (agreementCredentials == null) + { + GenerateEphemeralClientKeyExchange(dhAgreeServerPublicKey.Parameters, output); + } + } public virtual byte[] GeneratePremasterSecret() - { - if (agreementCredentials != null) - { - return agreementCredentials.GenerateAgreement(dhAgreeServerPublicKey); - } - - return CalculateDHBasicAgreement(dhAgreeServerPublicKey, dhAgreeClientPrivateKey); - } - - protected virtual bool AreCompatibleParameters(DHParameters a, DHParameters b) - { - return a.P.Equals(b.P) && a.G.Equals(b.G); - } - - protected virtual byte[] CalculateDHBasicAgreement(DHPublicKeyParameters publicKey, - DHPrivateKeyParameters privateKey) - { - return TlsDHUtilities.CalculateDHBasicAgreement(publicKey, privateKey); - } - - protected virtual AsymmetricCipherKeyPair GenerateDHKeyPair(DHParameters dhParams) - { - return TlsDHUtilities.GenerateDHKeyPair(context.SecureRandom, dhParams); - } - - protected virtual void GenerateEphemeralClientKeyExchange(DHParameters dhParams, Stream output) - { - this.dhAgreeClientPrivateKey = TlsDHUtilities.GenerateEphemeralClientKeyExchange( - context.SecureRandom, dhParams, output); - } - - protected virtual DHPublicKeyParameters ValidateDHPublicKey(DHPublicKeyParameters key) - { - return TlsDHUtilities.ValidateDHPublicKey(key); - } - } + { + if (agreementCredentials != null) + { + return agreementCredentials.GenerateAgreement(dhAgreeServerPublicKey); + } + + return CalculateDHBasicAgreement(dhAgreeServerPublicKey, dhAgreeClientPrivateKey); + } + + protected virtual bool AreCompatibleParameters(DHParameters a, DHParameters b) + { + return a.P.Equals(b.P) && a.G.Equals(b.G); + } + + protected virtual byte[] CalculateDHBasicAgreement(DHPublicKeyParameters publicKey, + DHPrivateKeyParameters privateKey) + { + return TlsDHUtilities.CalculateDHBasicAgreement(publicKey, privateKey); + } + + protected virtual AsymmetricCipherKeyPair GenerateDHKeyPair(DHParameters dhParams) + { + return TlsDHUtilities.GenerateDHKeyPair(context.SecureRandom, dhParams); + } + + protected virtual void GenerateEphemeralClientKeyExchange(DHParameters dhParams, Stream output) + { + this.dhAgreeClientPrivateKey = TlsDHUtilities.GenerateEphemeralClientKeyExchange( + context.SecureRandom, dhParams, output); + } + + protected virtual DHPublicKeyParameters ValidateDHPublicKey(DHPublicKeyParameters key) + { + return TlsDHUtilities.ValidateDHPublicKey(key); + } + } } diff --git a/crypto/src/crypto/tls/TlsDheKeyExchange.cs b/crypto/src/crypto/tls/TlsDheKeyExchange.cs
index 725cc1bf3..ee6d6eb44 100644 --- a/crypto/src/crypto/tls/TlsDheKeyExchange.cs +++ b/crypto/src/crypto/tls/TlsDheKeyExchange.cs
@@ -7,50 +7,50 @@ using Org.BouncyCastle.Math; namespace Org.BouncyCastle.Crypto.Tls { - internal class TlsDheKeyExchange - : TlsDHKeyExchange - { - internal TlsDheKeyExchange(TlsClientContext context, KeyExchangeAlgorithm keyExchange) - : base(context, keyExchange) - { - } - - public override void SkipServerKeyExchange() - { - throw new TlsFatalAlert(AlertDescription.unexpected_message); - } - - public override void ProcessServerKeyExchange(Stream input) - { - SecurityParameters securityParameters = context.SecurityParameters; - - ISigner signer = InitSigner(tlsSigner, securityParameters); - Stream sigIn = new SignerStream(input, signer, null); - - byte[] pBytes = TlsUtilities.ReadOpaque16(sigIn); - byte[] gBytes = TlsUtilities.ReadOpaque16(sigIn); - byte[] YsBytes = TlsUtilities.ReadOpaque16(sigIn); - - byte[] sigByte = TlsUtilities.ReadOpaque16(input); - if (!signer.VerifySignature(sigByte)) - { + internal class TlsDheKeyExchange + : TlsDHKeyExchange + { + internal TlsDheKeyExchange(TlsClientContext context, int keyExchange) + : base(context, keyExchange) + { + } + + public override void SkipServerKeyExchange() + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + public override void ProcessServerKeyExchange(Stream input) + { + SecurityParameters securityParameters = context.SecurityParameters; + + ISigner signer = InitSigner(tlsSigner, securityParameters); + Stream sigIn = new SignerStream(input, signer, null); + + byte[] pBytes = TlsUtilities.ReadOpaque16(sigIn); + byte[] gBytes = TlsUtilities.ReadOpaque16(sigIn); + byte[] YsBytes = TlsUtilities.ReadOpaque16(sigIn); + + byte[] sigByte = TlsUtilities.ReadOpaque16(input); + if (!signer.VerifySignature(sigByte)) + { throw new TlsFatalAlert(AlertDescription.decrypt_error); - } - - BigInteger p = new BigInteger(1, pBytes); - BigInteger g = new BigInteger(1, gBytes); - BigInteger Ys = new BigInteger(1, YsBytes); - - this.dhAgreeServerPublicKey = ValidateDHPublicKey( - new DHPublicKeyParameters(Ys, new DHParameters(p, g))); - } - - protected virtual ISigner InitSigner(TlsSigner tlsSigner, SecurityParameters securityParameters) - { - ISigner signer = tlsSigner.CreateVerifyer(this.serverPublicKey); - signer.BlockUpdate(securityParameters.clientRandom, 0, securityParameters.clientRandom.Length); - signer.BlockUpdate(securityParameters.serverRandom, 0, securityParameters.serverRandom.Length); - return signer; - } - } + } + + BigInteger p = new BigInteger(1, pBytes); + BigInteger g = new BigInteger(1, gBytes); + BigInteger Ys = new BigInteger(1, YsBytes); + + this.dhAgreeServerPublicKey = ValidateDHPublicKey( + new DHPublicKeyParameters(Ys, new DHParameters(p, g))); + } + + protected virtual ISigner InitSigner(TlsSigner tlsSigner, SecurityParameters securityParameters) + { + ISigner signer = tlsSigner.CreateVerifyer(this.serverPublicKey); + signer.BlockUpdate(securityParameters.clientRandom, 0, securityParameters.clientRandom.Length); + signer.BlockUpdate(securityParameters.serverRandom, 0, securityParameters.serverRandom.Length); + return signer; + } + } } diff --git a/crypto/src/crypto/tls/TlsECDHKeyExchange.cs b/crypto/src/crypto/tls/TlsECDHKeyExchange.cs
index 36155346a..65d07a10c 100644 --- a/crypto/src/crypto/tls/TlsECDHKeyExchange.cs +++ b/crypto/src/crypto/tls/TlsECDHKeyExchange.cs
@@ -19,7 +19,7 @@ namespace Org.BouncyCastle.Crypto.Tls : TlsKeyExchange { protected TlsClientContext context; - protected KeyExchangeAlgorithm keyExchange; + protected int keyExchange; protected TlsSigner tlsSigner; protected AsymmetricKeyParameter serverPublicKey; @@ -27,7 +27,7 @@ namespace Org.BouncyCastle.Crypto.Tls protected TlsAgreementCredentials agreementCredentials; protected ECPrivateKeyParameters ecAgreeClientPrivateKey = null; - internal TlsECDHKeyExchange(TlsClientContext context, KeyExchangeAlgorithm keyExchange) + internal TlsECDHKeyExchange(TlsClientContext context, int keyExchange) { switch (keyExchange) { @@ -56,7 +56,7 @@ namespace Org.BouncyCastle.Crypto.Tls public virtual void ProcessServerCertificate(Certificate serverCertificate) { - X509CertificateStructure x509Cert = serverCertificate.certs[0]; + X509CertificateStructure x509Cert = serverCertificate.GetCertificateAt(0); SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo; try @@ -117,8 +117,8 @@ namespace Org.BouncyCastle.Crypto.Tls * prohibited because the use of a long-term ECDH client key would jeopardize the * forward secrecy property of these algorithms. */ - ClientCertificateType[] types = certificateRequest.CertificateTypes; - foreach (ClientCertificateType type in types) + byte[] types = certificateRequest.CertificateTypes; + foreach (byte type in types) { switch (type) { diff --git a/crypto/src/crypto/tls/TlsECDheKeyExchange.cs b/crypto/src/crypto/tls/TlsECDheKeyExchange.cs
index 071d06b91..a671ebfbe 100644 --- a/crypto/src/crypto/tls/TlsECDheKeyExchange.cs +++ b/crypto/src/crypto/tls/TlsECDheKeyExchange.cs
@@ -13,7 +13,7 @@ namespace Org.BouncyCastle.Crypto.Tls */ internal class TlsECDheKeyExchange : TlsECDHKeyExchange { - internal TlsECDheKeyExchange(TlsClientContext context, KeyExchangeAlgorithm keyExchange) + internal TlsECDheKeyExchange(TlsClientContext context, int keyExchange) : base(context, keyExchange) { } @@ -30,13 +30,13 @@ namespace Org.BouncyCastle.Crypto.Tls ISigner signer = InitSigner(tlsSigner, securityParameters); Stream sigIn = new SignerStream(input, signer, null); - ECCurveType curveType = (ECCurveType)TlsUtilities.ReadUint8(sigIn); + byte curveType = TlsUtilities.ReadUint8(sigIn); ECDomainParameters curve_params; // Currently, we only support named curves if (curveType == ECCurveType.named_curve) { - NamedCurve namedCurve = (NamedCurve)TlsUtilities.ReadUint16(sigIn); + int namedCurve = TlsUtilities.ReadUint16(sigIn); // TODO Check namedCurve is one we offered? @@ -72,8 +72,8 @@ namespace Org.BouncyCastle.Crypto.Tls * prohibited because the use of a long-term ECDH client key would jeopardize the * forward secrecy property of these algorithms. */ - ClientCertificateType[] types = certificateRequest.CertificateTypes; - foreach (ClientCertificateType type in types) + byte[] types = certificateRequest.CertificateTypes; + foreach (byte type in types) { switch (type) { diff --git a/crypto/src/crypto/tls/TlsException.cs b/crypto/src/crypto/tls/TlsException.cs deleted file mode 100644
index 59c129105..000000000 --- a/crypto/src/crypto/tls/TlsException.cs +++ /dev/null
@@ -1,14 +0,0 @@ -using System; - -namespace Org.BouncyCastle.Crypto.Tls -{ -#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT) - [Serializable] -#endif - public class TlsException : Exception - { - public TlsException() : base() { } - public TlsException(string message) : base(message) { } - public TlsException(string message, Exception exception) : base(message, exception) { } - } -} diff --git a/crypto/src/crypto/tls/TlsFatalAlert.cs b/crypto/src/crypto/tls/TlsFatalAlert.cs
index 0a9cc6f3a..4fb2a41bd 100644 --- a/crypto/src/crypto/tls/TlsFatalAlert.cs +++ b/crypto/src/crypto/tls/TlsFatalAlert.cs
@@ -3,19 +3,19 @@ using System.IO; namespace Org.BouncyCastle.Crypto.Tls { - public class TlsFatalAlert - : IOException - { - private readonly AlertDescription alertDescription; + public class TlsFatalAlert + : IOException + { + private readonly byte alertDescription; - public TlsFatalAlert(AlertDescription alertDescription) - { - this.alertDescription = alertDescription; - } + public TlsFatalAlert(byte alertDescription) + { + this.alertDescription = alertDescription; + } - public AlertDescription AlertDescription - { - get { return alertDescription; } - } - } + public virtual byte AlertDescription + { + get { return alertDescription; } + } + } } diff --git a/crypto/src/crypto/tls/TlsMac.cs b/crypto/src/crypto/tls/TlsMac.cs
index 862c887ad..e4313617e 100644 --- a/crypto/src/crypto/tls/TlsMac.cs +++ b/crypto/src/crypto/tls/TlsMac.cs
@@ -9,103 +9,103 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Crypto.Tls { - /// <remarks> - /// A generic TLS MAC implementation, which can be used with any kind of - /// IDigest to act as an HMAC. - /// </remarks> - public class TlsMac - { - protected long seqNo; - protected byte[] secret; - protected HMac mac; - - /** - * Generate a new instance of an TlsMac. - * - * @param digest The digest to use. - * @param key_block A byte-array where the key for this mac is located. - * @param offset The number of bytes to skip, before the key starts in the buffer. - * @param len The length of the key. - */ - public TlsMac( - IDigest digest, - byte[] key_block, - int offset, - int len) - { - this.seqNo = 0; - - KeyParameter param = new KeyParameter(key_block, offset, len); - - this.secret = Arrays.Clone(param.GetKey()); - - this.mac = new HMac(digest); - this.mac.Init(param); - } - - /** - * @return the MAC write secret - */ - public virtual byte[] GetMacSecret() - { - return this.secret; - } - - /** - * @return the current write sequence number - */ - public virtual long SequenceNumber - { - get { return this.seqNo; } - } - - /** - * Increment the current write sequence number - */ - public virtual void IncSequenceNumber() - { - this.seqNo++; - } - - /** - * @return The Keysize of the mac. - */ - public virtual int Size - { - get { return mac.GetMacSize(); } - } - - /** - * Calculate the mac for some given data. - * <p/> - * TlsMac will keep track of the sequence number internally. - * - * @param type The message type of the message. - * @param message A byte-buffer containing the message. - * @param offset The number of bytes to skip, before the message starts. - * @param len The length of the message. - * @return A new byte-buffer containing the mac value. - */ - public virtual byte[] CalculateMac(ContentType type, byte[] message, int offset, int len) - { + /// <remarks> + /// A generic TLS MAC implementation, which can be used with any kind of + /// IDigest to act as an HMAC. + /// </remarks> + public class TlsMac + { + protected long seqNo; + protected byte[] secret; + protected HMac mac; + + /** + * Generate a new instance of an TlsMac. + * + * @param digest The digest to use. + * @param key_block A byte-array where the key for this mac is located. + * @param offset The number of bytes to skip, before the key starts in the buffer. + * @param len The length of the key. + */ + public TlsMac( + IDigest digest, + byte[] key_block, + int offset, + int len) + { + this.seqNo = 0; + + KeyParameter param = new KeyParameter(key_block, offset, len); + + this.secret = Arrays.Clone(param.GetKey()); + + this.mac = new HMac(digest); + this.mac.Init(param); + } + + /** + * @return the MAC write secret + */ + public virtual byte[] GetMacSecret() + { + return this.secret; + } + + /** + * @return the current write sequence number + */ + public virtual long SequenceNumber + { + get { return this.seqNo; } + } + + /** + * Increment the current write sequence number + */ + public virtual void IncSequenceNumber() + { + this.seqNo++; + } + + /** + * @return The Keysize of the mac. + */ + public virtual int Size + { + get { return mac.GetMacSize(); } + } + + /** + * Calculate the mac for some given data. + * <p/> + * TlsMac will keep track of the sequence number internally. + * + * @param type The message type of the message. + * @param message A byte-buffer containing the message. + * @param offset The number of bytes to skip, before the message starts. + * @param len The length of the message. + * @return A new byte-buffer containing the mac value. + */ + public virtual byte[] CalculateMac(byte type, byte[] message, int offset, int len) + { //bool isTls = context.ServerVersion.FullVersion >= ProtocolVersion.TLSv10.FullVersion; bool isTls = true; byte[] macHeader = new byte[isTls ? 13 : 11]; - TlsUtilities.WriteUint64(seqNo++, macHeader, 0); - TlsUtilities.WriteUint8((byte)type, macHeader, 8); + TlsUtilities.WriteUint64(seqNo++, macHeader, 0); + TlsUtilities.WriteUint8(type, macHeader, 8); if (isTls) { TlsUtilities.WriteVersion(macHeader, 9); } - TlsUtilities.WriteUint16(len, macHeader, 11); + TlsUtilities.WriteUint16(len, macHeader, 11); mac.BlockUpdate(macHeader, 0, macHeader.Length); - mac.BlockUpdate(message, offset, len); - return MacUtilities.DoFinal(mac); - } + mac.BlockUpdate(message, offset, len); + return MacUtilities.DoFinal(mac); + } - public virtual byte[] CalculateMacConstantTime(ContentType type, byte[] message, int offset, int len, + public virtual byte[] CalculateMacConstantTime(byte type, byte[] message, int offset, int len, int fullLength, byte[] dummyData) { // Actual MAC only calculated on 'len' bytes @@ -138,5 +138,5 @@ namespace Org.BouncyCastle.Crypto.Tls return result; } - } + } } diff --git a/crypto/src/crypto/tls/TlsNullCipher.cs b/crypto/src/crypto/tls/TlsNullCipher.cs
index b76f76d9c..3e2bfa847 100644 --- a/crypto/src/crypto/tls/TlsNullCipher.cs +++ b/crypto/src/crypto/tls/TlsNullCipher.cs
@@ -2,27 +2,27 @@ using System; namespace Org.BouncyCastle.Crypto.Tls { - /// <summary> - /// A NULL cipher suite, for use during handshake. - /// </summary> - public class TlsNullCipher - : TlsCipher - { - public virtual byte[] EncodePlaintext(ContentType type, byte[] plaintext, int offset, int len) - { - return CopyData(plaintext, offset, len); - } + /// <summary> + /// A NULL cipher suite, for use during handshake. + /// </summary> + public class TlsNullCipher + : TlsCipher + { + public virtual byte[] EncodePlaintext(byte type, byte[] plaintext, int offset, int len) + { + return CopyData(plaintext, offset, len); + } - public virtual byte[] DecodeCiphertext(ContentType type, byte[] ciphertext, int offset, int len) - { - return CopyData(ciphertext, offset, len); - } + public virtual byte[] DecodeCiphertext(byte type, byte[] ciphertext, int offset, int len) + { + return CopyData(ciphertext, offset, len); + } - protected virtual byte[] CopyData(byte[] text, int offset, int len) - { - byte[] result = new byte[len]; - Array.Copy(text, offset, result, 0, len); - return result; - } - } + protected virtual byte[] CopyData(byte[] text, int offset, int len) + { + byte[] result = new byte[len]; + Array.Copy(text, offset, result, 0, len); + return result; + } + } } diff --git a/crypto/src/crypto/tls/TlsProtocolHandler.cs b/crypto/src/crypto/tls/TlsProtocolHandler.cs
index 0a970d251..c538229dc 100644 --- a/crypto/src/crypto/tls/TlsProtocolHandler.cs +++ b/crypto/src/crypto/tls/TlsProtocolHandler.cs
@@ -40,8 +40,6 @@ namespace Org.BouncyCastle.Crypto.Tls private const short CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED = 11; private const short CS_DONE = 12; - private static readonly byte[] emptybuf = new byte[0]; - private static readonly string TLS_ERROR_MESSAGE = "Internal TLS error, this could be an attack"; /* @@ -69,8 +67,8 @@ namespace Org.BouncyCastle.Crypto.Tls private TlsClientContextImpl tlsClientContext = null; private TlsClient tlsClient = null; - private CipherSuite[] offeredCipherSuites = null; - private CompressionMethod[] offeredCompressionMethods = null; + private int[] offeredCipherSuites = null; + private byte[] offeredCompressionMethods = null; private TlsKeyExchange keyExchange = null; private TlsAuthentication authentication = null; private CertificateRequest certificateRequest = null; @@ -122,15 +120,15 @@ namespace Org.BouncyCastle.Crypto.Tls } internal void ProcessData( - ContentType protocol, - byte[] buf, - int offset, - int len) + byte contentType, + byte[] buf, + int offset, + int len) { /* * Have a look at the protocol type, and add it to the correct queue. */ - switch (protocol) + switch (contentType) { case ContentType.change_cipher_spec: ProcessChangeCipherSpec(buf, offset, len); @@ -177,7 +175,7 @@ namespace Org.BouncyCastle.Crypto.Tls byte[] beginning = new byte[4]; handshakeQueue.Read(beginning, 0, 4, 0); MemoryStream bis = new MemoryStream(beginning, false); - HandshakeType type = (HandshakeType)TlsUtilities.ReadUint8(bis); + byte handshakeType = TlsUtilities.ReadUint8(bis); int len = TlsUtilities.ReadUint24(bis); /* @@ -197,7 +195,7 @@ namespace Org.BouncyCastle.Crypto.Tls * including, this finished message. [..] Note: [Also,] Hello Request * messages are omitted from handshake hashes. */ - switch (type) + switch (handshakeType) { case HandshakeType.hello_request: case HandshakeType.finished: @@ -211,7 +209,7 @@ namespace Org.BouncyCastle.Crypto.Tls /* * Now, parse the message. */ - ProcessHandshakeMessage(type, buf); + ProcessHandshakeMessage(handshakeType, buf); read = true; } } @@ -219,14 +217,14 @@ namespace Org.BouncyCastle.Crypto.Tls while (read); } - private void ProcessHandshakeMessage(HandshakeType type, byte[] buf) + private void ProcessHandshakeMessage(byte handshakeType, byte[] buf) { MemoryStream inStr = new MemoryStream(buf, false); /* * Check the type. */ - switch (type) + switch (handshakeType) { case HandshakeType.certificate: { @@ -324,7 +322,7 @@ namespace Org.BouncyCastle.Crypto.Tls * Find out which CipherSuite the server has chosen and check that * it was one of the offered ones. */ - CipherSuite selectedCipherSuite = (CipherSuite)TlsUtilities.ReadUint16(inStr); + int selectedCipherSuite = TlsUtilities.ReadUint16(inStr); if (!ArrayContains(offeredCipherSuites, selectedCipherSuite) || selectedCipherSuite == CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV) { @@ -337,7 +335,7 @@ namespace Org.BouncyCastle.Crypto.Tls * Find out which CompressionMethod the server has chosen and check that * it was one of the offered ones. */ - CompressionMethod selectedCompressionMethod = (CompressionMethod)TlsUtilities.ReadUint8(inStr); + byte selectedCompressionMethod = TlsUtilities.ReadUint8(inStr); if (!ArrayContains(offeredCompressionMethods, selectedCompressionMethod)) { this.FailWithError(AlertLevel.fatal, AlertDescription.illegal_parameter); @@ -364,7 +362,7 @@ namespace Org.BouncyCastle.Crypto.Tls * containing no extensions. */ - // ExtensionType -> byte[] + // Int32 -> byte[] IDictionary serverExtensions = Platform.CreateHashtable(); if (inStr.Position < inStr.Length) @@ -375,7 +373,7 @@ namespace Org.BouncyCastle.Crypto.Tls MemoryStream ext = new MemoryStream(extBytes, false); while (ext.Position < ext.Length) { - ExtensionType extType = (ExtensionType)TlsUtilities.ReadUint16(ext); + int extType = TlsUtilities.ReadUint16(ext); byte[] extValue = TlsUtilities.ReadOpaque16(ext); // Note: RFC 5746 makes a special case for EXT_RenegotiationInfo @@ -431,7 +429,7 @@ namespace Org.BouncyCastle.Crypto.Tls byte[] renegExtValue = (byte[])serverExtensions[ExtensionType.renegotiation_info]; if (!Arrays.ConstantTimeAreEqual(renegExtValue, - CreateRenegotiationInfo(emptybuf))) + CreateRenegotiationInfo(TlsUtilities.EmptyBytes))) { this.FailWithError(AlertLevel.fatal, AlertDescription.handshake_failure); } @@ -626,29 +624,11 @@ namespace Org.BouncyCastle.Crypto.Tls this.FailWithError(AlertLevel.fatal, AlertDescription.handshake_failure); } - int numTypes = TlsUtilities.ReadUint8(inStr); - ClientCertificateType[] certificateTypes = new ClientCertificateType[numTypes]; - for (int i = 0; i < numTypes; ++i) - { - certificateTypes[i] = (ClientCertificateType)TlsUtilities.ReadUint8(inStr); - } - - byte[] authorities = TlsUtilities.ReadOpaque16(inStr); + this.certificateRequest = CertificateRequest.Parse(//getContext(), + inStr); AssertEmpty(inStr); - IList authorityDNs = Platform.CreateArrayList(); - - MemoryStream bis = new MemoryStream(authorities, false); - while (bis.Position < bis.Length) - { - byte[] dnBytes = TlsUtilities.ReadOpaque16(bis); - // TODO Switch to X500Name when available - authorityDNs.Add(X509Name.GetInstance(Asn1Object.FromByteArray(dnBytes))); - } - - this.certificateRequest = new CertificateRequest(certificateTypes, - authorityDNs); this.keyExchange.ValidateCertificateRequest(this.certificateRequest); break; @@ -855,7 +835,7 @@ namespace Org.BouncyCastle.Crypto.Tls this.offeredCipherSuites = this.tlsClient.GetCipherSuites(); - // ExtensionType -> byte[] + // Int32 -> byte[] this.clientExtensions = this.tlsClient.GetClientExtensions(); // Cipher Suites (and SCSV) @@ -899,7 +879,7 @@ namespace Org.BouncyCastle.Crypto.Tls TlsUtilities.WriteUint8((byte)offeredCompressionMethods.Length, outStr); for (int i = 0; i < offeredCompressionMethods.Length; ++i) { - TlsUtilities.WriteUint8((byte)offeredCompressionMethods[i], outStr); + TlsUtilities.WriteUint8(offeredCompressionMethods[i], outStr); } } @@ -908,7 +888,7 @@ namespace Org.BouncyCastle.Crypto.Tls { MemoryStream ext = new MemoryStream(); - foreach (ExtensionType extType in clientExtensions.Keys) + foreach (int extType in clientExtensions.Keys) { WriteExtension(ext, extType, (byte[])clientExtensions[extType]); } @@ -1009,7 +989,7 @@ namespace Org.BouncyCastle.Crypto.Tls } } - private void SafeWriteMessage(ContentType type, byte[] buf, int offset, int len) + private void SafeWriteMessage(byte type, byte[] buf, int offset, int len) { try { @@ -1064,22 +1044,33 @@ namespace Org.BouncyCastle.Crypto.Tls while (len > 0) { /* - * Protect against known IV attack! - * - * DO NOT REMOVE THIS LINE, EXCEPT YOU KNOW EXACTLY WHAT - * YOU ARE DOING HERE. + * 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. */ - SafeWriteMessage(ContentType.application_data, emptybuf, 0, 0); - /* - * We are only allowed to write fragments up to 2^14 bytes. - */ - int toWrite = System.Math.Min(len, 1 << 14); - - SafeWriteMessage(ContentType.application_data, buf, offset, toWrite); + //if (this.splitApplicationDataRecords) + { + /* + * Protect against known IV attack! + * + * DO NOT REMOVE THIS CODE, EXCEPT YOU KNOW EXACTLY WHAT YOU ARE DOING HERE. + */ + SafeWriteMessage(ContentType.application_data, buf, offset, 1); + ++offset; + --len; + } - offset += toWrite; - len -= toWrite; + if (len > 0) + { + // Fragment data according to the current fragment limit. + //int toWrite = System.Math.Min(len, recordStream.GetPlaintextLimit()); + int toWrite = System.Math.Min(len, 1 << 14); + SafeWriteMessage(ContentType.application_data, buf, offset, toWrite); + offset += toWrite; + len -= toWrite; + } } } @@ -1112,7 +1103,7 @@ namespace Org.BouncyCastle.Crypto.Tls * @param alertDescription The exact alert message. * @throws IOException If alert was fatal. */ - private void FailWithError(AlertLevel alertLevel, AlertDescription alertDescription) + private void FailWithError(byte alertLevel, byte alertDescription) { /* * Check if the connection is still open. @@ -1144,11 +1135,9 @@ namespace Org.BouncyCastle.Crypto.Tls } } - internal void SendAlert(AlertLevel alertLevel, AlertDescription alertDescription) + internal void SendAlert(byte alertLevel, byte alertDescription) { - byte[] error = new byte[2]; - error[0] = (byte)alertLevel; - error[1] = (byte)alertDescription; + byte[] error = new byte[] { alertLevel, alertDescription }; rs.WriteMessage(ContentType.alert, error, 0, 2); } @@ -1197,7 +1186,7 @@ namespace Org.BouncyCastle.Crypto.Tls get { return closed; } } - private static bool ArrayContains(CipherSuite[] a, CipherSuite n) + private static bool ArrayContains(byte[] a, byte n) { for (int i = 0; i < a.Length; ++i) { @@ -1207,7 +1196,7 @@ namespace Org.BouncyCastle.Crypto.Tls return false; } - private static bool ArrayContains(CompressionMethod[] a, CompressionMethod n) + private static bool ArrayContains(int[] a, int n) { for (int i = 0; i < a.Length; ++i) { @@ -1224,9 +1213,9 @@ namespace Org.BouncyCastle.Crypto.Tls return buf.ToArray(); } - private static void WriteExtension(Stream output, ExtensionType extType, byte[] extValue) + private static void WriteExtension(Stream output, int extType, byte[] extValue) { - TlsUtilities.WriteUint16((int)extType, output); + TlsUtilities.WriteUint16(extType, output); TlsUtilities.WriteOpaque16(extValue, output); } } diff --git a/crypto/src/crypto/tls/TlsPskKeyExchange.cs b/crypto/src/crypto/tls/TlsPskKeyExchange.cs
index cadd643ca..9961fc9d1 100644 --- a/crypto/src/crypto/tls/TlsPskKeyExchange.cs +++ b/crypto/src/crypto/tls/TlsPskKeyExchange.cs
@@ -8,42 +8,42 @@ using Org.BouncyCastle.Security; namespace Org.BouncyCastle.Crypto.Tls { - internal class TlsPskKeyExchange - : TlsKeyExchange - { - protected TlsClientContext context; - protected KeyExchangeAlgorithm keyExchange; - protected TlsPskIdentity pskIdentity; + internal class TlsPskKeyExchange + : TlsKeyExchange + { + protected TlsClientContext context; + protected int keyExchange; + protected TlsPskIdentity pskIdentity; - protected byte[] psk_identity_hint = null; + protected byte[] psk_identity_hint = null; - protected DHPublicKeyParameters dhAgreeServerPublicKey = null; - protected DHPrivateKeyParameters dhAgreeClientPrivateKey = null; + protected DHPublicKeyParameters dhAgreeServerPublicKey = null; + protected DHPrivateKeyParameters dhAgreeClientPrivateKey = null; protected AsymmetricKeyParameter serverPublicKey = null; protected RsaKeyParameters rsaServerPublicKey = null; - protected byte[] premasterSecret; - - internal TlsPskKeyExchange(TlsClientContext context, KeyExchangeAlgorithm keyExchange, - TlsPskIdentity pskIdentity) - { - switch (keyExchange) - { - case KeyExchangeAlgorithm.PSK: - case KeyExchangeAlgorithm.RSA_PSK: - case KeyExchangeAlgorithm.DHE_PSK: - break; - default: - throw new ArgumentException("unsupported key exchange algorithm", "keyExchange"); - } - - this.context = context; - this.keyExchange = keyExchange; - this.pskIdentity = pskIdentity; - } - - public virtual void SkipServerCertificate() - { + protected byte[] premasterSecret; + + internal TlsPskKeyExchange(TlsClientContext context, int keyExchange, + TlsPskIdentity pskIdentity) + { + switch (keyExchange) + { + case KeyExchangeAlgorithm.PSK: + case KeyExchangeAlgorithm.RSA_PSK: + case KeyExchangeAlgorithm.DHE_PSK: + break; + default: + throw new ArgumentException("unsupported key exchange algorithm", "keyExchange"); + } + + this.context = context; + this.keyExchange = keyExchange; + this.pskIdentity = pskIdentity; + } + + public virtual void SkipServerCertificate() + { if (keyExchange == KeyExchangeAlgorithm.RSA_PSK) { throw new TlsFatalAlert(AlertDescription.unexpected_message); @@ -51,13 +51,13 @@ namespace Org.BouncyCastle.Crypto.Tls } public virtual void ProcessServerCertificate(Certificate serverCertificate) - { + { if (keyExchange != KeyExchangeAlgorithm.RSA_PSK) { throw new TlsFatalAlert(AlertDescription.unexpected_message); } - X509CertificateStructure x509Cert = serverCertificate.certs[0]; + X509CertificateStructure x509Cert = serverCertificate.GetCertificateAt(0); SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo; try @@ -88,107 +88,107 @@ namespace Org.BouncyCastle.Crypto.Tls */ } - public virtual void SkipServerKeyExchange() - { + public virtual void SkipServerKeyExchange() + { if (keyExchange == KeyExchangeAlgorithm.DHE_PSK) { throw new TlsFatalAlert(AlertDescription.unexpected_message); } - this.psk_identity_hint = new byte[0]; - } - - public virtual void ProcessServerKeyExchange(Stream input) - { - this.psk_identity_hint = TlsUtilities.ReadOpaque16(input); - - if (this.keyExchange == KeyExchangeAlgorithm.DHE_PSK) - { - byte[] pBytes = TlsUtilities.ReadOpaque16(input); - byte[] gBytes = TlsUtilities.ReadOpaque16(input); - byte[] YsBytes = TlsUtilities.ReadOpaque16(input); - - BigInteger p = new BigInteger(1, pBytes); - BigInteger g = new BigInteger(1, gBytes); - BigInteger Ys = new BigInteger(1, YsBytes); - - this.dhAgreeServerPublicKey = TlsDHUtilities.ValidateDHPublicKey( - new DHPublicKeyParameters(Ys, new DHParameters(p, g))); - } - else if (this.psk_identity_hint.Length == 0) - { - // TODO Should we enforce that this message should have been skipped if hint is empty? - //throw new TlsFatalAlert(AlertDescription.unexpected_message); - } - } - - public virtual void ValidateCertificateRequest(CertificateRequest certificateRequest) - { - throw new TlsFatalAlert(AlertDescription.unexpected_message); - } - - public virtual void SkipClientCredentials() - { - // OK - } - - public virtual void ProcessClientCredentials(TlsCredentials clientCredentials) - { - throw new TlsFatalAlert(AlertDescription.internal_error); - } - - public virtual void GenerateClientKeyExchange(Stream output) - { - if (psk_identity_hint == null || psk_identity_hint.Length == 0) - { - pskIdentity.SkipIdentityHint(); - } - else - { - pskIdentity.NotifyIdentityHint(psk_identity_hint); - } - - byte[] psk_identity = pskIdentity.GetPskIdentity(); - - TlsUtilities.WriteOpaque16(psk_identity, output); - - if (this.keyExchange == KeyExchangeAlgorithm.RSA_PSK) - { - this.premasterSecret = TlsRsaUtilities.GenerateEncryptedPreMasterSecret( - context.SecureRandom, this.rsaServerPublicKey, output); - } - else if (this.keyExchange == KeyExchangeAlgorithm.DHE_PSK) - { - this.dhAgreeClientPrivateKey = TlsDHUtilities.GenerateEphemeralClientKeyExchange( - context.SecureRandom, this.dhAgreeServerPublicKey.Parameters, output); - } - } - - public virtual byte[] GeneratePremasterSecret() - { - byte[] psk = pskIdentity.GetPsk(); - byte[] other_secret = GenerateOtherSecret(psk.Length); - - MemoryStream buf = new MemoryStream(4 + other_secret.Length + psk.Length); - TlsUtilities.WriteOpaque16(other_secret, buf); - TlsUtilities.WriteOpaque16(psk, buf); - return buf.ToArray(); - } - - protected virtual byte[] GenerateOtherSecret(int pskLength) - { - if (this.keyExchange == KeyExchangeAlgorithm.DHE_PSK) - { - return TlsDHUtilities.CalculateDHBasicAgreement(dhAgreeServerPublicKey, dhAgreeClientPrivateKey); - } - - if (this.keyExchange == KeyExchangeAlgorithm.RSA_PSK) - { - return this.premasterSecret; - } - - return new byte[pskLength]; - } + this.psk_identity_hint = TlsUtilities.EmptyBytes; + } + + public virtual void ProcessServerKeyExchange(Stream input) + { + this.psk_identity_hint = TlsUtilities.ReadOpaque16(input); + + if (this.keyExchange == KeyExchangeAlgorithm.DHE_PSK) + { + byte[] pBytes = TlsUtilities.ReadOpaque16(input); + byte[] gBytes = TlsUtilities.ReadOpaque16(input); + byte[] YsBytes = TlsUtilities.ReadOpaque16(input); + + BigInteger p = new BigInteger(1, pBytes); + BigInteger g = new BigInteger(1, gBytes); + BigInteger Ys = new BigInteger(1, YsBytes); + + this.dhAgreeServerPublicKey = TlsDHUtilities.ValidateDHPublicKey( + new DHPublicKeyParameters(Ys, new DHParameters(p, g))); + } + else if (this.psk_identity_hint.Length == 0) + { + // TODO Should we enforce that this message should have been skipped if hint is empty? + //throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + } + + public virtual void ValidateCertificateRequest(CertificateRequest certificateRequest) + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + public virtual void SkipClientCredentials() + { + // OK + } + + public virtual void ProcessClientCredentials(TlsCredentials clientCredentials) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + public virtual void GenerateClientKeyExchange(Stream output) + { + if (psk_identity_hint == null || psk_identity_hint.Length == 0) + { + pskIdentity.SkipIdentityHint(); + } + else + { + pskIdentity.NotifyIdentityHint(psk_identity_hint); + } + + byte[] psk_identity = pskIdentity.GetPskIdentity(); + + TlsUtilities.WriteOpaque16(psk_identity, output); + + if (this.keyExchange == KeyExchangeAlgorithm.RSA_PSK) + { + this.premasterSecret = TlsRsaUtilities.GenerateEncryptedPreMasterSecret( + context.SecureRandom, this.rsaServerPublicKey, output); + } + else if (this.keyExchange == KeyExchangeAlgorithm.DHE_PSK) + { + this.dhAgreeClientPrivateKey = TlsDHUtilities.GenerateEphemeralClientKeyExchange( + context.SecureRandom, this.dhAgreeServerPublicKey.Parameters, output); + } + } + + public virtual byte[] GeneratePremasterSecret() + { + byte[] psk = pskIdentity.GetPsk(); + byte[] other_secret = GenerateOtherSecret(psk.Length); + + MemoryStream buf = new MemoryStream(4 + other_secret.Length + psk.Length); + TlsUtilities.WriteOpaque16(other_secret, buf); + TlsUtilities.WriteOpaque16(psk, buf); + return buf.ToArray(); + } + + protected virtual byte[] GenerateOtherSecret(int pskLength) + { + if (this.keyExchange == KeyExchangeAlgorithm.DHE_PSK) + { + return TlsDHUtilities.CalculateDHBasicAgreement(dhAgreeServerPublicKey, dhAgreeClientPrivateKey); + } + + if (this.keyExchange == KeyExchangeAlgorithm.RSA_PSK) + { + return this.premasterSecret; + } + + return new byte[pskLength]; + } protected virtual RsaKeyParameters ValidateRsaPublicKey(RsaKeyParameters key) { diff --git a/crypto/src/crypto/tls/TlsRsaKeyExchange.cs b/crypto/src/crypto/tls/TlsRsaKeyExchange.cs
index ad61f08de..aad482316 100644 --- a/crypto/src/crypto/tls/TlsRsaKeyExchange.cs +++ b/crypto/src/crypto/tls/TlsRsaKeyExchange.cs
@@ -11,117 +11,117 @@ using Org.BouncyCastle.Security; namespace Org.BouncyCastle.Crypto.Tls { - /// <summary> - /// TLS 1.0 RSA key exchange. - /// </summary> - internal class TlsRsaKeyExchange - : TlsKeyExchange - { - protected TlsClientContext context; + /// <summary> + /// TLS 1.0 RSA key exchange. + /// </summary> + internal class TlsRsaKeyExchange + : TlsKeyExchange + { + protected TlsClientContext context; - protected AsymmetricKeyParameter serverPublicKey = null; + protected AsymmetricKeyParameter serverPublicKey = null; protected RsaKeyParameters rsaServerPublicKey = null; protected byte[] premasterSecret; - internal TlsRsaKeyExchange(TlsClientContext context) - { - this.context = context; - } - - public virtual void SkipServerCertificate() - { - throw new TlsFatalAlert(AlertDescription.unexpected_message); - } - - public virtual void ProcessServerCertificate(Certificate serverCertificate) - { - X509CertificateStructure x509Cert = serverCertificate.certs[0]; - SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo; - - try - { - this.serverPublicKey = PublicKeyFactory.CreateKey(keyInfo); - } + internal TlsRsaKeyExchange(TlsClientContext context) + { + this.context = context; + } + + public virtual void SkipServerCertificate() + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + public virtual void ProcessServerCertificate(Certificate serverCertificate) + { + X509CertificateStructure x509Cert = serverCertificate.GetCertificateAt(0); + SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo; + + try + { + this.serverPublicKey = PublicKeyFactory.CreateKey(keyInfo); + } // catch (RuntimeException) - catch (Exception) - { - throw new TlsFatalAlert(AlertDescription.unsupported_certificate); - } - - // Sanity check the PublicKeyFactory - if (this.serverPublicKey.IsPrivate) - { - throw new TlsFatalAlert(AlertDescription.internal_error); - } - - this.rsaServerPublicKey = ValidateRsaPublicKey((RsaKeyParameters)this.serverPublicKey); - - TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.KeyEncipherment); - - // TODO - /* - * Perform various checks per RFC2246 7.4.2: "Unless otherwise specified, the - * signing algorithm for the certificate must be the same as the algorithm for the - * certificate key." - */ - } - - public virtual void SkipServerKeyExchange() - { - // OK - } - - public virtual void ProcessServerKeyExchange(Stream input) - { - throw new TlsFatalAlert(AlertDescription.unexpected_message); - } - - public virtual void ValidateCertificateRequest(CertificateRequest certificateRequest) - { - ClientCertificateType[] types = certificateRequest.CertificateTypes; - foreach (ClientCertificateType type in types) - { - switch (type) - { - case ClientCertificateType.rsa_sign: - case ClientCertificateType.dss_sign: - case ClientCertificateType.ecdsa_sign: - break; - default: - throw new TlsFatalAlert(AlertDescription.illegal_parameter); - } - } - } - - public virtual void SkipClientCredentials() - { - // OK - } - - public virtual void ProcessClientCredentials(TlsCredentials clientCredentials) - { - if (!(clientCredentials is TlsSignerCredentials)) - { - throw new TlsFatalAlert(AlertDescription.internal_error); - } - } - + catch (Exception) + { + throw new TlsFatalAlert(AlertDescription.unsupported_certificate); + } + + // Sanity check the PublicKeyFactory + if (this.serverPublicKey.IsPrivate) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + this.rsaServerPublicKey = ValidateRsaPublicKey((RsaKeyParameters)this.serverPublicKey); + + TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.KeyEncipherment); + + // TODO + /* + * Perform various checks per RFC2246 7.4.2: "Unless otherwise specified, the + * signing algorithm for the certificate must be the same as the algorithm for the + * certificate key." + */ + } + + public virtual void SkipServerKeyExchange() + { + // OK + } + + public virtual void ProcessServerKeyExchange(Stream input) + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + public virtual void ValidateCertificateRequest(CertificateRequest certificateRequest) + { + byte[] types = certificateRequest.CertificateTypes; + foreach (byte type in types) + { + switch (type) + { + case ClientCertificateType.rsa_sign: + case ClientCertificateType.dss_sign: + case ClientCertificateType.ecdsa_sign: + break; + default: + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + } + } + + public virtual void SkipClientCredentials() + { + // OK + } + + public virtual void ProcessClientCredentials(TlsCredentials clientCredentials) + { + if (!(clientCredentials is TlsSignerCredentials)) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + public virtual void GenerateClientKeyExchange(Stream output) - { - this.premasterSecret = TlsRsaUtilities.GenerateEncryptedPreMasterSecret( - context.SecureRandom, this.rsaServerPublicKey, output); - } - - public virtual byte[] GeneratePremasterSecret() - { - byte[] tmp = this.premasterSecret; - this.premasterSecret = null; - return tmp; - } - - // Would be needed to process RSA_EXPORT server key exchange + { + this.premasterSecret = TlsRsaUtilities.GenerateEncryptedPreMasterSecret( + context.SecureRandom, this.rsaServerPublicKey, output); + } + + public virtual byte[] GeneratePremasterSecret() + { + byte[] tmp = this.premasterSecret; + this.premasterSecret = null; + return tmp; + } + + // Would be needed to process RSA_EXPORT server key exchange // protected virtual void ProcessRsaServerKeyExchange(Stream input, ISigner signer) // { // Stream sigIn = input; @@ -150,16 +150,16 @@ namespace Org.BouncyCastle.Crypto.Tls // } protected virtual RsaKeyParameters ValidateRsaPublicKey(RsaKeyParameters key) - { - // TODO What is the minimum bit length required? + { + // TODO What is the minimum bit length required? // key.Modulus.BitLength; - if (!key.Exponent.IsProbablePrime(2)) - { - throw new TlsFatalAlert(AlertDescription.illegal_parameter); - } + if (!key.Exponent.IsProbablePrime(2)) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } - return key; - } - } + return key; + } + } } diff --git a/crypto/src/crypto/tls/TlsSrpKeyExchange.cs b/crypto/src/crypto/tls/TlsSrpKeyExchange.cs
index cb4e26e58..950be87ba 100644 --- a/crypto/src/crypto/tls/TlsSrpKeyExchange.cs +++ b/crypto/src/crypto/tls/TlsSrpKeyExchange.cs
@@ -22,7 +22,7 @@ namespace Org.BouncyCastle.Crypto.Tls : TlsKeyExchange { protected TlsClientContext context; - protected KeyExchangeAlgorithm keyExchange; + protected int keyExchange; protected TlsSigner tlsSigner; protected byte[] identity; protected byte[] password; @@ -33,7 +33,7 @@ namespace Org.BouncyCastle.Crypto.Tls protected BigInteger B = null; protected Srp6Client srpClient = new Srp6Client(); - internal TlsSrpKeyExchange(TlsClientContext context, KeyExchangeAlgorithm keyExchange, + internal TlsSrpKeyExchange(TlsClientContext context, int keyExchange, byte[] identity, byte[] password) { switch (keyExchange) @@ -72,7 +72,7 @@ namespace Org.BouncyCastle.Crypto.Tls throw new TlsFatalAlert(AlertDescription.unexpected_message); } - X509CertificateStructure x509Cert = serverCertificate.certs[0]; + X509CertificateStructure x509Cert = serverCertificate.GetCertificateAt(0); SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo; try diff --git a/crypto/src/crypto/tls/TlsStreamCipher.cs b/crypto/src/crypto/tls/TlsStreamCipher.cs
index 65d6054ff..35f794d96 100644 --- a/crypto/src/crypto/tls/TlsStreamCipher.cs +++ b/crypto/src/crypto/tls/TlsStreamCipher.cs
@@ -18,40 +18,40 @@ namespace Org.BouncyCastle.Crypto.Tls protected TlsMac readMac; public TlsStreamCipher(TlsClientContext context, IStreamCipher encryptCipher, - IStreamCipher decryptCipher, IDigest writeDigest, IDigest readDigest, int cipherKeySize) - { - this.context = context; - this.encryptCipher = encryptCipher; - this.decryptCipher = decryptCipher; + IStreamCipher decryptCipher, IDigest writeDigest, IDigest readDigest, int cipherKeySize) + { + this.context = context; + this.encryptCipher = encryptCipher; + this.decryptCipher = decryptCipher; int prfSize = (2 * cipherKeySize) + writeDigest.GetDigestSize() + readDigest.GetDigestSize(); - SecurityParameters securityParameters = context.SecurityParameters; + SecurityParameters securityParameters = context.SecurityParameters; - byte[] keyBlock = TlsUtilities.PRF(securityParameters.masterSecret, "key expansion", - TlsUtilities.Concat(securityParameters.serverRandom, securityParameters.clientRandom), - prfSize); + byte[] keyBlock = TlsUtilities.PRF(securityParameters.masterSecret, "key expansion", + TlsUtilities.Concat(securityParameters.serverRandom, securityParameters.clientRandom), + prfSize); - int offset = 0; + int offset = 0; - // Init MACs - writeMac = CreateTlsMac(writeDigest, keyBlock, ref offset); - readMac = CreateTlsMac(readDigest, keyBlock, ref offset); + // Init MACs + writeMac = CreateTlsMac(writeDigest, keyBlock, ref offset); + readMac = CreateTlsMac(readDigest, keyBlock, ref offset); - // Build keys - KeyParameter encryptKey = CreateKeyParameter(keyBlock, ref offset, cipherKeySize); - KeyParameter decryptKey = CreateKeyParameter(keyBlock, ref offset, cipherKeySize); + // Build keys + KeyParameter encryptKey = CreateKeyParameter(keyBlock, ref offset, cipherKeySize); + KeyParameter decryptKey = CreateKeyParameter(keyBlock, ref offset, cipherKeySize); - if (offset != prfSize) + if (offset != prfSize) throw new TlsFatalAlert(AlertDescription.internal_error); // Init Ciphers encryptCipher.Init(true, encryptKey); decryptCipher.Init(false, decryptKey); - } + } - public byte[] EncodePlaintext(ContentType type, byte[] plaintext, int offset, int len) + public byte[] EncodePlaintext(byte type, byte[] plaintext, int offset, int len) { byte[] mac = writeMac.CalculateMac(type, plaintext, offset, len); int size = len + mac.Length; @@ -64,7 +64,7 @@ namespace Org.BouncyCastle.Crypto.Tls return outbuf; } - public byte[] DecodeCiphertext(ContentType type, byte[] ciphertext, int offset, int len) + public byte[] DecodeCiphertext(byte type, byte[] ciphertext, int offset, int len) { byte[] deciphered = new byte[len]; decryptCipher.ProcessBytes(ciphertext, offset, len, deciphered, 0); diff --git a/crypto/src/crypto/tls/TlsUtilities.cs b/crypto/src/crypto/tls/TlsUtilities.cs
index dca842a80..5ed659ce7 100644 --- a/crypto/src/crypto/tls/TlsUtilities.cs +++ b/crypto/src/crypto/tls/TlsUtilities.cs
@@ -1,4 +1,5 @@ using System; +using System.Collections; using System.IO; using System.Text; @@ -16,6 +17,41 @@ namespace Org.BouncyCastle.Crypto.Tls /// <remarks>Some helper functions for MicroTLS.</remarks> public class TlsUtilities { + public static readonly byte[] EmptyBytes = new byte[0]; + + public static void CheckUint8(int i) + { + if (!IsValidUint8(i)) + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + public static void CheckUint16(int i) + { + if (!IsValidUint16(i)) + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + public static void CheckUint24(int i) + { + if (!IsValidUint24(i)) + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + public static bool IsValidUint8(int i) + { + return (i & 0xFF) == i; + } + + public static bool IsValidUint16(int i) + { + return (i & 0xFFFF) == i; + } + + public static bool IsValidUint24(int i) + { + return (i & 0xFFFFFF) == i; + } + internal static void WriteUint8(byte i, Stream os) { os.WriteByte(i); @@ -99,6 +135,13 @@ namespace Org.BouncyCastle.Crypto.Tls os.Write(uints, 0, uints.Length); } + public static void WriteUint8ArrayWithUint8Length(byte[] uints, Stream output) + { + CheckUint8(uints.Length); + WriteUint8((byte)uints.Length, output); + WriteUint8Array(uints, output); + } + internal static void WriteUint16Array(int[] uints, Stream os) { for (int i = 0; i < uints.Length; ++i) @@ -140,6 +183,16 @@ namespace Org.BouncyCastle.Crypto.Tls return (i1 << 16) | (i2 << 8) | i3; } + public static byte[] ReadFully(int length, Stream input) + { + if (length < 1) + return EmptyBytes; + byte[] buf = new byte[length]; + if (length != Streams.ReadFully(input, buf)) + throw new EndOfStreamException(); + return buf; + } + internal static void ReadFully(byte[] buf, Stream inStr) { if (Streams.ReadFully(inStr, buf, 0, buf.Length) < buf.Length) @@ -162,6 +215,12 @@ namespace Org.BouncyCastle.Crypto.Tls return bytes; } + public static byte[] ReadOpaque24(Stream input) + { + int length = ReadUint24(input); + return ReadFully(length, input); + } + internal static void CheckVersion(byte[] readVersion) { if ((readVersion[0] != 3) || (readVersion[1] != 1)) @@ -180,6 +239,30 @@ namespace Org.BouncyCastle.Crypto.Tls } } + public static Asn1Object ReadAsn1Object(byte[] encoding) + { + Asn1InputStream asn1 = new Asn1InputStream(encoding); + Asn1Object result = asn1.ReadObject(); + if (null == result) + throw new TlsFatalAlert(AlertDescription.decode_error); + if (null != asn1.ReadObject()) + throw new TlsFatalAlert(AlertDescription.decode_error); + return result; + } + + public static Asn1Object ReadDerObject(byte[] encoding) + { + /* + * NOTE: The current ASN.1 parsing code can't enforce DER-only parsing, but since DER is + * canonical, we can check it by re-encoding the result and comparing to the original. + */ + Asn1Object result = ReadAsn1Object(encoding); + byte[] check = result.GetEncoded(Asn1Encodable.Der); + if (!Arrays.AreEqual(check, encoding)) + throw new TlsFatalAlert(AlertDescription.decode_error); + return result; + } + internal static void WriteGmtUnixTime(byte[] buf, int offset) { int t = (int)(DateTimeUtilities.CurrentUnixMs() / 1000L); @@ -201,6 +284,35 @@ namespace Org.BouncyCastle.Crypto.Tls buf[offset + 1] = 1; } + public static void EncodeSupportedSignatureAlgorithms(IList supportedSignatureAlgorithms, bool allowAnonymous, + Stream output) + { + if (supportedSignatureAlgorithms == null || supportedSignatureAlgorithms.Count < 1 + || supportedSignatureAlgorithms.Count >= (1 << 15)) + { + throw new ArgumentException("must have length from 1 to (2^15 - 1)", "supportedSignatureAlgorithms"); + } + + // supported_signature_algorithms + int length = 2 * supportedSignatureAlgorithms.Count; + TlsUtilities.CheckUint16(length); + TlsUtilities.WriteUint16(length, output); + + foreach (SignatureAndHashAlgorithm entry in supportedSignatureAlgorithms) + { + if (!allowAnonymous && entry.Signature == SignatureAlgorithm.anonymous) + { + /* + * RFC 5246 7.4.1.4.1 The "anonymous" value is meaningless in this context but used + * in Section 7.4.3. It MUST NOT appear in this extension. + */ + throw new ArgumentException( + "SignatureAlgorithm.anonymous MUST NOT appear in the signature_algorithms extension"); + } + entry.Encode(output); + } + } + private static void hmac_hash(IDigest digest, byte[] secret, byte[] seed, byte[] output) { HMac mac = new HMac(digest);