diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2015-03-09 01:44:59 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2015-03-09 01:44:59 +0700 |
commit | f7a9c0a501b6af92d3e729e08c73b5499a500c24 (patch) | |
tree | c2601bd90ae759a90a15ea41a7e82988dc11abd5 /crypto | |
parent | Port TLS-PSK tests from Java (diff) | |
download | BouncyCastle.NET-ed25519-f7a9c0a501b6af92d3e729e08c73b5499a500c24.tar.xz |
Porting from Java build
- SRP6 evidence messages and standard groups - TLS_SRP server-side support added - TLS_DHE server-side fixes - Improved support for DSA/ECDSA signing in TLS
Diffstat (limited to 'crypto')
41 files changed, 1693 insertions, 263 deletions
diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj index 84844e827..26af5666f 100644 --- a/crypto/crypto.csproj +++ b/crypto/crypto.csproj @@ -3154,6 +3154,11 @@ BuildAction = "Compile" /> <File + RelPath = "src\crypto\agreement\srp\SRP6StandardGroups.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File RelPath = "src\crypto\agreement\srp\SRP6Utilities.cs" SubType = "Code" BuildAction = "Compile" @@ -4174,6 +4179,11 @@ BuildAction = "Compile" /> <File + RelPath = "src\crypto\parameters\Srp6GroupParameters.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File RelPath = "src\crypto\parameters\TweakableBlockCipherParameters.cs" SubType = "Code" BuildAction = "Compile" @@ -4479,6 +4489,11 @@ BuildAction = "Compile" /> <File + RelPath = "src\crypto\tls\DefaultTlsSrpGroupVerifier.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File RelPath = "src\crypto\tls\DefaultTlsSignerCredentials.cs" SubType = "Code" BuildAction = "Compile" @@ -4684,6 +4699,11 @@ BuildAction = "Compile" /> <File + RelPath = "src\crypto\tls\ServerSrpParams.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File RelPath = "src\crypto\tls\ServerName.cs" SubType = "Code" BuildAction = "Compile" @@ -4719,11 +4739,21 @@ BuildAction = "Compile" /> <File + RelPath = "src\crypto\tls\SimulatedTlsSrpIdentityManager.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File RelPath = "src\crypto\tls\SrpTlsClient.cs" SubType = "Code" BuildAction = "Compile" /> <File + RelPath = "src\crypto\tls\SrpTlsServer.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File RelPath = "src\crypto\tls\SrtpProtectionProfile.cs" SubType = "Code" BuildAction = "Compile" @@ -4984,6 +5014,21 @@ BuildAction = "Compile" /> <File + RelPath = "src\crypto\tls\TlsSrpGroupVerifier.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File + RelPath = "src\crypto\tls\TlsSrpIdentityManager.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File + RelPath = "src\crypto\tls\TlsSrpLoginParameters.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File RelPath = "src\crypto\tls\TlsSrpKeyExchange.cs" SubType = "Code" BuildAction = "Compile" @@ -11043,6 +11088,16 @@ BuildAction = "Compile" /> <File + RelPath = "test\src\crypto\tls\test\MockSrpTlsClient.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File + RelPath = "test\src\crypto\tls\test\MockSrpTlsServer.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File RelPath = "test\src\crypto\tls\test\MockTlsClient.cs" SubType = "Code" BuildAction = "Compile" @@ -11073,6 +11128,11 @@ BuildAction = "Compile" /> <File + RelPath = "test\src\crypto\tls\test\TlsSrpProtocolTest.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File RelPath = "test\src\crypto\tls\test\TlsServerTest.cs" SubType = "Code" BuildAction = "Compile" diff --git a/crypto/src/crypto/agreement/srp/SRP6Client.cs b/crypto/src/crypto/agreement/srp/SRP6Client.cs index 309736564..f075d7ad1 100644 --- a/crypto/src/crypto/agreement/srp/SRP6Client.cs +++ b/crypto/src/crypto/agreement/srp/SRP6Client.cs @@ -1,5 +1,6 @@ using System; +using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Math; using Org.BouncyCastle.Security; @@ -24,7 +25,11 @@ namespace Org.BouncyCastle.Crypto.Agreement.Srp protected BigInteger u; protected BigInteger S; - protected IDigest digest; + protected BigInteger M1; + protected BigInteger M2; + protected BigInteger Key; + + protected IDigest digest; protected SecureRandom random; public Srp6Client() @@ -46,6 +51,11 @@ namespace Org.BouncyCastle.Crypto.Agreement.Srp this.random = random; } + public virtual void Init(Srp6GroupParameters group, IDigest digest, SecureRandom random) + { + Init(group.N, group.G, digest, random); + } + /** * Generates client's credentials given the client's salt, identity and password * @param salt The salt used in the client's verifier. @@ -89,5 +99,66 @@ namespace Org.BouncyCastle.Crypto.Agreement.Srp BigInteger tmp = g.ModPow(x, N).Multiply(k).Mod(N); return B.Subtract(tmp).Mod(N).ModPow(exp, N); } + + /** + * Computes the client evidence message M1 using the previously received values. + * To be called after calculating the secret S. + * @return M1: the client side generated evidence message + * @throws CryptoException + */ + public virtual BigInteger CalculateClientEvidenceMessage() + { + // Verify pre-requirements + if (this.pubA == null || this.B == null || this.S == null) + { + throw new CryptoException("Impossible to compute M1: " + + "some data are missing from the previous operations (A,B,S)"); + } + // compute the client evidence message 'M1' + this.M1 = Srp6Utilities.CalculateM1(digest, N, pubA, B, S); + return M1; + } + + /** Authenticates the server evidence message M2 received and saves it only if correct. + * @param M2: the server side generated evidence message + * @return A boolean indicating if the server message M2 was the expected one. + * @throws CryptoException + */ + public virtual bool VerifyServerEvidenceMessage(BigInteger serverM2) + { + // Verify pre-requirements + if (this.pubA == null || this.M1 == null || this.S == null) + { + throw new CryptoException("Impossible to compute and verify M2: " + + "some data are missing from the previous operations (A,M1,S)"); + } + + // Compute the own server evidence message 'M2' + BigInteger computedM2 = Srp6Utilities.CalculateM2(digest, N, pubA, M1, S); + if (computedM2.Equals(serverM2)) + { + this.M2 = serverM2; + return true; + } + return false; + } + + /** + * Computes the final session key as a result of the SRP successful mutual authentication + * To be called after verifying the server evidence message M2. + * @return Key: the mutually authenticated symmetric session key + * @throws CryptoException + */ + public virtual BigInteger CalculateSessionKey() + { + // Verify pre-requirements (here we enforce a previous calculation of M1 and M2) + if (this.S == null || this.M1 == null || this.M2 == null) + { + throw new CryptoException("Impossible to compute Key: " + + "some data are missing from the previous operations (S,M1,M2)"); + } + this.Key = Srp6Utilities.CalculateKey(digest, N, S); + return Key; + } } } diff --git a/crypto/src/crypto/agreement/srp/SRP6Server.cs b/crypto/src/crypto/agreement/srp/SRP6Server.cs index 35b96d488..fd0c9f1cb 100644 --- a/crypto/src/crypto/agreement/srp/SRP6Server.cs +++ b/crypto/src/crypto/agreement/srp/SRP6Server.cs @@ -1,5 +1,6 @@ using System; +using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Math; using Org.BouncyCastle.Security; @@ -26,6 +27,9 @@ namespace Org.BouncyCastle.Crypto.Agreement.Srp protected BigInteger u; protected BigInteger S; + protected BigInteger M1; + protected BigInteger M2; + protected BigInteger Key; public Srp6Server() { @@ -49,6 +53,11 @@ namespace Org.BouncyCastle.Crypto.Agreement.Srp this.digest = digest; } + public virtual void Init(Srp6GroupParameters group, BigInteger v, IDigest digest, SecureRandom random) + { + Init(group.N, group.G, v, digest, random); + } + /** * Generates the server's credentials that are to be sent to the client. * @return The server's public value to the client @@ -82,9 +91,73 @@ namespace Org.BouncyCastle.Crypto.Agreement.Srp return Srp6Utilities.GeneratePrivateValue(digest, N, g, random); } - private BigInteger CalculateS() + private BigInteger CalculateS() { return v.ModPow(u, N).Multiply(A).Mod(N).ModPow(privB, N); } + + /** + * Authenticates the received client evidence message M1 and saves it only if correct. + * To be called after calculating the secret S. + * @param M1: the client side generated evidence message + * @return A boolean indicating if the client message M1 was the expected one. + * @throws CryptoException + */ + public virtual bool VerifyClientEvidenceMessage(BigInteger clientM1) + { + // Verify pre-requirements + if (this.A == null || this.pubB == null || this.S == null) + { + throw new CryptoException("Impossible to compute and verify M1: " + + "some data are missing from the previous operations (A,B,S)"); + } + + // Compute the own client evidence message 'M1' + BigInteger computedM1 = Srp6Utilities.CalculateM1(digest, N, A, pubB, S); + if (computedM1.Equals(clientM1)) + { + this.M1 = clientM1; + return true; + } + return false; + } + + /** + * Computes the server evidence message M2 using the previously verified values. + * To be called after successfully verifying the client evidence message M1. + * @return M2: the server side generated evidence message + * @throws CryptoException + */ + public virtual BigInteger CalculateServerEvidenceMessage() + { + // Verify pre-requirements + if (this.A == null || this.M1 == null || this.S == null) + { + throw new CryptoException("Impossible to compute M2: " + + "some data are missing from the previous operations (A,M1,S)"); + } + + // Compute the server evidence message 'M2' + this.M2 = Srp6Utilities.CalculateM2(digest, N, A, M1, S); + return M2; + } + + /** + * Computes the final session key as a result of the SRP successful mutual authentication + * To be called after calculating the server evidence message M2. + * @return Key: the mutual authenticated symmetric session key + * @throws CryptoException + */ + public virtual BigInteger CalculateSessionKey() + { + // Verify pre-requirements + if (this.S == null || this.M1 == null || this.M2 == null) + { + throw new CryptoException("Impossible to compute Key: " + + "some data are missing from the previous operations (S,M1,M2)"); + } + this.Key = Srp6Utilities.CalculateKey(digest, N, S); + return Key; + } } } diff --git a/crypto/src/crypto/agreement/srp/SRP6StandardGroups.cs b/crypto/src/crypto/agreement/srp/SRP6StandardGroups.cs new file mode 100644 index 000000000..36f4aba11 --- /dev/null +++ b/crypto/src/crypto/agreement/srp/SRP6StandardGroups.cs @@ -0,0 +1,159 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Utilities.Encoders; + +namespace Org.BouncyCastle.Crypto.Agreement.Srp +{ + public class Srp6StandardGroups + { + private static BigInteger FromHex(string hex) + { + return new BigInteger(1, Hex.Decode(hex)); + } + + private static Srp6GroupParameters FromNG(string hexN, string hexG) + { + return new Srp6GroupParameters(FromHex(hexN), FromHex(hexG)); + } + + /* + * RFC 5054 + */ + private const string rfc5054_1024_N = "EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C" + + "9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE4" + + "8E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B29" + + "7BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9A" + "FD5138FE8376435B9FC61D2FC0EB06E3"; + private const string rfc5054_1024_g = "02"; + public static readonly Srp6GroupParameters rfc5054_1024 = FromNG(rfc5054_1024_N, rfc5054_1024_g); + + private const string rfc5054_1536_N = "9DEF3CAFB939277AB1F12A8617A47BBBDBA51DF499AC4C80BEEEA961" + + "4B19CC4D5F4F5F556E27CBDE51C6A94BE4607A291558903BA0D0F843" + + "80B655BB9A22E8DCDF028A7CEC67F0D08134B1C8B97989149B609E0B" + + "E3BAB63D47548381DBC5B1FC764E3F4B53DD9DA1158BFD3E2B9C8CF5" + + "6EDF019539349627DB2FD53D24B7C48665772E437D6C7F8CE442734A" + + "F7CCB7AE837C264AE3A9BEB87F8A2FE9B8B5292E5A021FFF5E91479E" + + "8CE7A28C2442C6F315180F93499A234DCF76E3FED135F9BB"; + private const string rfc5054_1536_g = "02"; + public static readonly Srp6GroupParameters rfc5054_1536 = FromNG(rfc5054_1536_N, rfc5054_1536_g); + + private const string rfc5054_2048_N = "AC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC319294" + + "3DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310D" + + "CD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FB" + + "D5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF74" + + "7359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A" + + "436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D" + + "5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E73" + + "03CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB6" + + "94B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F" + "9E4AFF73"; + private const string rfc5054_2048_g = "02"; + public static readonly Srp6GroupParameters rfc5054_2048 = FromNG(rfc5054_2048_N, rfc5054_2048_g); + + private const string rfc5054_3072_N = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" + + "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" + + "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9" + + "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6" + + "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8" + + "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C" + + "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718" + + "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D" + + "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D" + + "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226" + + "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC" + "E0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF"; + private const string rfc5054_3072_g = "05"; + public static readonly Srp6GroupParameters rfc5054_3072 = FromNG(rfc5054_3072_N, rfc5054_3072_g); + + private const string rfc5054_4096_N = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" + + "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" + + "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9" + + "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6" + + "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8" + + "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C" + + "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718" + + "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D" + + "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D" + + "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226" + + "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC" + + "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26" + + "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB" + + "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2" + + "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127" + + "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199" + "FFFFFFFFFFFFFFFF"; + private const string rfc5054_4096_g = "05"; + public static readonly Srp6GroupParameters rfc5054_4096 = FromNG(rfc5054_4096_N, rfc5054_4096_g); + + private const string rfc5054_6144_N = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" + + "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" + + "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9" + + "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6" + + "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8" + + "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C" + + "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718" + + "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D" + + "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D" + + "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226" + + "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC" + + "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26" + + "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB" + + "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2" + + "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127" + + "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" + + "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406" + + "AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918" + + "DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B33205151" + + "2BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03" + + "F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97F" + + "BEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" + + "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58B" + + "B7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632" + + "387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E" + "6DCC4024FFFFFFFFFFFFFFFF"; + private const string rfc5054_6144_g = "05"; + public static readonly Srp6GroupParameters rfc5054_6144 = FromNG(rfc5054_6144_N, rfc5054_6144_g); + + private const string rfc5054_8192_N = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" + + "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" + + "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9" + + "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6" + + "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8" + + "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C" + + "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718" + + "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D" + + "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D" + + "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226" + + "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC" + + "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26" + + "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB" + + "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2" + + "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127" + + "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" + + "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406" + + "AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918" + + "DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B33205151" + + "2BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03" + + "F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97F" + + "BEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" + + "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58B" + + "B7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632" + + "387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E" + + "6DBE115974A3926F12FEE5E438777CB6A932DF8CD8BEC4D073B931BA" + + "3BC832B68D9DD300741FA7BF8AFC47ED2576F6936BA424663AAB639C" + + "5AE4F5683423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9" + + "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B4BCBC886" + + "2F8385DDFA9D4B7FA2C087E879683303ED5BDD3A062B3CF5B3A278A6" + + "6D2A13F83F44F82DDF310EE074AB6A364597E899A0255DC164F31CC5" + + "0846851DF9AB48195DED7EA1B1D510BD7EE74D73FAF36BC31ECFA268" + + "359046F4EB879F924009438B481C6CD7889A002ED5EE382BC9190DA6" + + "FC026E479558E4475677E9AA9E3050E2765694DFC81F56E880B96E71" + "60C980DD98EDD3DFFFFFFFFFFFFFFFFF"; + private const string rfc5054_8192_g = "13"; + public static readonly Srp6GroupParameters rfc5054_8192 = FromNG(rfc5054_8192_N, rfc5054_8192_g); + } +} diff --git a/crypto/src/crypto/agreement/srp/SRP6Utilities.cs b/crypto/src/crypto/agreement/srp/SRP6Utilities.cs index 4e790f572..ef6d8f24c 100644 --- a/crypto/src/crypto/agreement/srp/SRP6Utilities.cs +++ b/crypto/src/crypto/agreement/srp/SRP6Utilities.cs @@ -54,7 +54,75 @@ namespace Org.BouncyCastle.Crypto.Agreement.Srp return val; } - private static BigInteger HashPaddedPair(IDigest digest, BigInteger N, BigInteger n1, BigInteger n2) + /** + * Computes the client evidence message (M1) according to the standard routine: + * M1 = H( A | B | S ) + * @param digest The Digest used as the hashing function H + * @param N Modulus used to get the pad length + * @param A The public client value + * @param B The public server value + * @param S The secret calculated by both sides + * @return M1 The calculated client evidence message + */ + public static BigInteger CalculateM1(IDigest digest, BigInteger N, BigInteger A, BigInteger B, BigInteger S) + { + BigInteger M1 = HashPaddedTriplet(digest, N, A, B, S); + return M1; + } + + /** + * Computes the server evidence message (M2) according to the standard routine: + * M2 = H( A | M1 | S ) + * @param digest The Digest used as the hashing function H + * @param N Modulus used to get the pad length + * @param A The public client value + * @param M1 The client evidence message + * @param S The secret calculated by both sides + * @return M2 The calculated server evidence message + */ + public static BigInteger CalculateM2(IDigest digest, BigInteger N, BigInteger A, BigInteger M1, BigInteger S) + { + BigInteger M2 = HashPaddedTriplet(digest, N, A, M1, S); + return M2; + } + + /** + * Computes the final Key according to the standard routine: Key = H(S) + * @param digest The Digest used as the hashing function H + * @param N Modulus used to get the pad length + * @param S The secret calculated by both sides + * @return + */ + public static BigInteger CalculateKey(IDigest digest, BigInteger N, BigInteger S) + { + int padLength = (N.BitLength + 7) / 8; + byte[] _S = GetPadded(S, padLength); + digest.BlockUpdate(_S, 0, _S.Length); + + byte[] output = new byte[digest.GetDigestSize()]; + digest.DoFinal(output, 0); + return new BigInteger(1, output); + } + + private static BigInteger HashPaddedTriplet(IDigest digest, BigInteger N, BigInteger n1, BigInteger n2, BigInteger n3) + { + int padLength = (N.BitLength + 7) / 8; + + byte[] n1_bytes = GetPadded(n1, padLength); + byte[] n2_bytes = GetPadded(n2, padLength); + byte[] n3_bytes = GetPadded(n3, padLength); + + digest.BlockUpdate(n1_bytes, 0, n1_bytes.Length); + digest.BlockUpdate(n2_bytes, 0, n2_bytes.Length); + digest.BlockUpdate(n3_bytes, 0, n3_bytes.Length); + + byte[] output = new byte[digest.GetDigestSize()]; + digest.DoFinal(output, 0); + + return new BigInteger(1, output); + } + + private static BigInteger HashPaddedPair(IDigest digest, BigInteger N, BigInteger n1, BigInteger n2) { int padLength = (N.BitLength + 7) / 8; diff --git a/crypto/src/crypto/agreement/srp/SRP6VerifierGenerator.cs b/crypto/src/crypto/agreement/srp/SRP6VerifierGenerator.cs index 264833b4d..956973598 100644 --- a/crypto/src/crypto/agreement/srp/SRP6VerifierGenerator.cs +++ b/crypto/src/crypto/agreement/srp/SRP6VerifierGenerator.cs @@ -1,5 +1,6 @@ using System; +using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Math; namespace Org.BouncyCastle.Crypto.Agreement.Srp @@ -31,7 +32,12 @@ namespace Org.BouncyCastle.Crypto.Agreement.Srp this.digest = digest; } - /** + public virtual void Init(Srp6GroupParameters group, IDigest digest) + { + Init(group.N, group.G, digest); + } + + /** * Creates a new SRP verifier * @param salt The salt to use, generally should be large and random * @param identity The user's identifying information (eg. username) diff --git a/crypto/src/crypto/parameters/Srp6GroupParameters.cs b/crypto/src/crypto/parameters/Srp6GroupParameters.cs new file mode 100644 index 000000000..6762dd31d --- /dev/null +++ b/crypto/src/crypto/parameters/Srp6GroupParameters.cs @@ -0,0 +1,27 @@ +using System; + +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public sealed class Srp6GroupParameters + { + private readonly BigInteger n, g; + + public Srp6GroupParameters(BigInteger N, BigInteger g) + { + this.n = N; + this.g = g; + } + + public BigInteger G + { + get { return g; } + } + + public BigInteger N + { + get { return n; } + } + } +} diff --git a/crypto/src/crypto/tls/AbstractTlsClient.cs b/crypto/src/crypto/tls/AbstractTlsClient.cs index 771bc004b..569979288 100644 --- a/crypto/src/crypto/tls/AbstractTlsClient.cs +++ b/crypto/src/crypto/tls/AbstractTlsClient.cs @@ -117,27 +117,7 @@ namespace Org.BouncyCastle.Crypto.Tls { // TODO Provide a way for the user to specify the acceptable hash/signature algorithms. - byte[] hashAlgorithms = new byte[]{ HashAlgorithm.sha512, HashAlgorithm.sha384, HashAlgorithm.sha256, - HashAlgorithm.sha224, HashAlgorithm.sha1 }; - - // TODO Sort out ECDSA signatures and add them as the preferred option here - byte[] signatureAlgorithms = new byte[]{ SignatureAlgorithm.rsa }; - - this.mSupportedSignatureAlgorithms = Platform.CreateArrayList(); - for (int i = 0; i < hashAlgorithms.Length; ++i) - { - for (int j = 0; j < signatureAlgorithms.Length; ++j) - { - this.mSupportedSignatureAlgorithms.Add(new SignatureAndHashAlgorithm(hashAlgorithms[i], - signatureAlgorithms[j])); - } - } - - /* - * RFC 5264 7.4.3. Currently, DSA [DSS] may only be used with SHA-1. - */ - this.mSupportedSignatureAlgorithms.Add(new SignatureAndHashAlgorithm(HashAlgorithm.sha1, - SignatureAlgorithm.dsa)); + this.mSupportedSignatureAlgorithms = TlsUtilities.GetDefaultSupportedSignatureAlgorithms(); clientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(clientExtensions); diff --git a/crypto/src/crypto/tls/AbstractTlsKeyExchange.cs b/crypto/src/crypto/tls/AbstractTlsKeyExchange.cs index 155ac94d8..c9ec06107 100644 --- a/crypto/src/crypto/tls/AbstractTlsKeyExchange.cs +++ b/crypto/src/crypto/tls/AbstractTlsKeyExchange.cs @@ -10,7 +10,7 @@ namespace Org.BouncyCastle.Crypto.Tls protected readonly int mKeyExchange; protected IList mSupportedSignatureAlgorithms; - protected TlsContext context; + protected TlsContext mContext; protected AbstractTlsKeyExchange(int keyExchange, IList supportedSignatureAlgorithms) { @@ -20,7 +20,7 @@ namespace Org.BouncyCastle.Crypto.Tls public virtual void Init(TlsContext context) { - this.context = context; + this.mContext = context; ProtocolVersion clientVersion = context.ClientVersion; diff --git a/crypto/src/crypto/tls/DefaultTlsClient.cs b/crypto/src/crypto/tls/DefaultTlsClient.cs index ec98413b7..f07080cbd 100644 --- a/crypto/src/crypto/tls/DefaultTlsClient.cs +++ b/crypto/src/crypto/tls/DefaultTlsClient.cs @@ -28,9 +28,18 @@ namespace Org.BouncyCastle.Crypto.Tls { return new int[] { + CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, + CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, + CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, + CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA, + CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, + CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, + CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256, CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256, CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA, diff --git a/crypto/src/crypto/tls/DefaultTlsServer.cs b/crypto/src/crypto/tls/DefaultTlsServer.cs index 75f6d8d88..156eff8af 100644 --- a/crypto/src/crypto/tls/DefaultTlsServer.cs +++ b/crypto/src/crypto/tls/DefaultTlsServer.cs @@ -20,6 +20,16 @@ namespace Org.BouncyCastle.Crypto.Tls { } + protected virtual TlsSignerCredentials GetDsaSignerCredentials() + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + protected virtual TlsSignerCredentials GetECDsaSignerCredentials() + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + protected virtual TlsEncryptionCredentials GetRsaEncryptionCredentials() { throw new TlsFatalAlert(AlertDescription.internal_error); @@ -45,6 +55,12 @@ namespace Org.BouncyCastle.Crypto.Tls CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, + CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, + CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, + CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, + CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA, + CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384, CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256, CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256, @@ -58,6 +74,76 @@ namespace Org.BouncyCastle.Crypto.Tls { switch (mSelectedCipherSuite) { + case CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_DH_DSS_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA256: + case CipherSuite.TLS_DH_DSS_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA: + case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA: + case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256: + case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_DH_DSS_WITH_DES_CBC_SHA: + case CipherSuite.TLS_DH_DSS_WITH_SEED_CBC_SHA: + 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_128_CBC_SHA256: + case CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256: + case CipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA: + case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA: + case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256: + case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_DHE_DSS_WITH_DES_CBC_SHA: + case CipherSuite.TLS_DHE_DSS_WITH_SEED_CBC_SHA: + 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 GetDsaSignerCredentials(); + + case CipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384: + case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_ECDH_ECDSA_WITH_NULL_SHA: + case CipherSuite.TLS_ECDH_ECDSA_WITH_RC4_128_SHA: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_ESTREAM_SALSA20_SHA1: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_NULL_SHA: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_SALSA20_SHA1: + return GetECDsaSignerCredentials(); + case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA: case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA: case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256: diff --git a/crypto/src/crypto/tls/DefaultTlsSrpGroupVerifier.cs b/crypto/src/crypto/tls/DefaultTlsSrpGroupVerifier.cs new file mode 100644 index 000000000..cc933bff9 --- /dev/null +++ b/crypto/src/crypto/tls/DefaultTlsSrpGroupVerifier.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Crypto.Agreement.Srp; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Tls +{ + public class DefaultTlsSrpGroupVerifier + : TlsSrpGroupVerifier + { + protected static readonly IList DefaultGroups = Platform.CreateArrayList(); + + static DefaultTlsSrpGroupVerifier() + { + DefaultGroups.Add(Srp6StandardGroups.rfc5054_1024); + DefaultGroups.Add(Srp6StandardGroups.rfc5054_1536); + DefaultGroups.Add(Srp6StandardGroups.rfc5054_2048); + DefaultGroups.Add(Srp6StandardGroups.rfc5054_3072); + DefaultGroups.Add(Srp6StandardGroups.rfc5054_4096); + DefaultGroups.Add(Srp6StandardGroups.rfc5054_6144); + DefaultGroups.Add(Srp6StandardGroups.rfc5054_8192); + } + + // Vector is (SRP6GroupParameters) + protected readonly IList mGroups; + + /** + * Accept only the group parameters specified in RFC 5054 Appendix A. + */ + public DefaultTlsSrpGroupVerifier() + : this(DefaultGroups) + { + } + + /** + * Specify a custom set of acceptable group parameters. + * + * @param groups a {@link Vector} of acceptable {@link SRP6GroupParameters} + */ + public DefaultTlsSrpGroupVerifier(IList groups) + { + this.mGroups = groups; + } + + public virtual bool Accept(Srp6GroupParameters group) + { + foreach (Srp6GroupParameters entry in mGroups) + { + if (AreGroupsEqual(group, entry)) + { + return true; + } + } + return false; + } + + protected virtual bool AreGroupsEqual(Srp6GroupParameters a, Srp6GroupParameters b) + { + return a == b || (AreParametersEqual(a.N, b.N) && AreParametersEqual(a.G, b.G)); + } + + protected virtual bool AreParametersEqual(BigInteger a, BigInteger b) + { + return a == b || a.Equals(b); + } + } +} diff --git a/crypto/src/crypto/tls/DtlsClientProtocol.cs b/crypto/src/crypto/tls/DtlsClientProtocol.cs index 2aa4df692..200bb1946 100644 --- a/crypto/src/crypto/tls/DtlsClientProtocol.cs +++ b/crypto/src/crypto/tls/DtlsClientProtocol.cs @@ -317,23 +317,17 @@ namespace Org.BouncyCastle.Crypto.Tls /* * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2 */ - SignatureAndHashAlgorithm signatureAndHashAlgorithm; - byte[] hash; + SignatureAndHashAlgorithm signatureAndHashAlgorithm = TlsUtilities.GetSignatureAndHashAlgorithm( + state.clientContext, signerCredentials); - if (TlsUtilities.IsTlsV12(state.clientContext)) + byte[] hash; + if (signatureAndHashAlgorithm == null) { - signatureAndHashAlgorithm = signerCredentials.SignatureAndHashAlgorithm; - if (signatureAndHashAlgorithm == null) - { - throw new TlsFatalAlert(AlertDescription.internal_error); - } - - hash = prepareFinishHash.GetFinalHash(signatureAndHashAlgorithm.Hash); + hash = securityParameters.SessionHash; } else { - signatureAndHashAlgorithm = null; - hash = securityParameters.SessionHash; + hash = prepareFinishHash.GetFinalHash(signatureAndHashAlgorithm.Hash); } byte[] signature = signerCredentials.GenerateCertificateSignature(hash); @@ -375,6 +369,7 @@ namespace Org.BouncyCastle.Crypto.Tls .SetMasterSecret(securityParameters.masterSecret) .SetPeerCertificate(serverCertificate) .SetPskIdentity(securityParameters.pskIdentity) + .SetSrpIdentity(securityParameters.srpIdentity) .Build(); state.tlsSession = TlsUtilities.ImportSession(state.tlsSession.SessionID, state.sessionParameters); diff --git a/crypto/src/crypto/tls/PskTlsServer.cs b/crypto/src/crypto/tls/PskTlsServer.cs index bdb8b74a5..335c9de86 100644 --- a/crypto/src/crypto/tls/PskTlsServer.cs +++ b/crypto/src/crypto/tls/PskTlsServer.cs @@ -338,7 +338,7 @@ namespace Org.BouncyCastle.Crypto.Tls } } - protected TlsKeyExchange CreatePskKeyExchange(int keyExchange) + protected virtual TlsKeyExchange CreatePskKeyExchange(int keyExchange) { return new TlsPskKeyExchange(keyExchange, mSupportedSignatureAlgorithms, null, mPskIdentityManager, GetDHParameters(), mNamedCurves, mClientECPointFormats, mServerECPointFormats); diff --git a/crypto/src/crypto/tls/SecurityParameters.cs b/crypto/src/crypto/tls/SecurityParameters.cs index 0f48ee23e..3b851587d 100644 --- a/crypto/src/crypto/tls/SecurityParameters.cs +++ b/crypto/src/crypto/tls/SecurityParameters.cs @@ -16,6 +16,7 @@ namespace Org.BouncyCastle.Crypto.Tls internal byte[] serverRandom = null; internal byte[] sessionHash = null; internal byte[] pskIdentity = null; + internal byte[] srpIdentity = null; // TODO Keep these internal, since it's maybe not the ideal place for them internal short maxFragmentLength = -1; @@ -93,5 +94,10 @@ namespace Org.BouncyCastle.Crypto.Tls { get { return pskIdentity; } } + + public virtual byte[] SrpIdentity + { + get { return srpIdentity; } + } } } diff --git a/crypto/src/crypto/tls/ServerSrpParams.cs b/crypto/src/crypto/tls/ServerSrpParams.cs new file mode 100644 index 000000000..556ac5310 --- /dev/null +++ b/crypto/src/crypto/tls/ServerSrpParams.cs @@ -0,0 +1,75 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Tls +{ + public class ServerSrpParams + { + protected BigInteger m_N, m_g, m_B; + protected byte[] m_s; + + public ServerSrpParams(BigInteger N, BigInteger g, byte[] s, BigInteger B) + { + this.m_N = N; + this.m_g = g; + this.m_s = Arrays.Clone(s); + this.m_B = B; + } + + public virtual BigInteger B + { + get { return m_B; } + } + + public virtual BigInteger G + { + get { return m_g; } + } + + public virtual BigInteger N + { + get { return m_N; } + } + + public virtual byte[] S + { + get { return m_s; } + } + + /** + * Encode this {@link ServerSRPParams} to an {@link OutputStream}. + * + * @param output + * the {@link OutputStream} to encode to. + * @throws IOException + */ + public virtual void Encode(Stream output) + { + TlsSrpUtilities.WriteSrpParameter(m_N, output); + TlsSrpUtilities.WriteSrpParameter(m_g, output); + TlsUtilities.WriteOpaque8(m_s, output); + TlsSrpUtilities.WriteSrpParameter(m_B, output); + } + + /** + * Parse a {@link ServerSRPParams} from an {@link InputStream}. + * + * @param input + * the {@link InputStream} to parse from. + * @return a {@link ServerSRPParams} object. + * @throws IOException + */ + public static ServerSrpParams Parse(Stream input) + { + BigInteger N = TlsSrpUtilities.ReadSrpParameter(input); + BigInteger g = TlsSrpUtilities.ReadSrpParameter(input); + byte[] s = TlsUtilities.ReadOpaque8(input); + BigInteger B = TlsSrpUtilities.ReadSrpParameter(input); + + return new ServerSrpParams(N, g, s, B); + } + } +} diff --git a/crypto/src/crypto/tls/SessionParameters.cs b/crypto/src/crypto/tls/SessionParameters.cs index b17e931d7..a1eb5f27c 100644 --- a/crypto/src/crypto/tls/SessionParameters.cs +++ b/crypto/src/crypto/tls/SessionParameters.cs @@ -15,6 +15,7 @@ namespace Org.BouncyCastle.Crypto.Tls private byte[] mMasterSecret = null; private Certificate mPeerCertificate = null; private byte[] mPskIdentity = null; + private byte[] mSrpIdentity = null; private byte[] mEncodedServerExtensions = null; public Builder() @@ -27,7 +28,7 @@ namespace Org.BouncyCastle.Crypto.Tls Validate(this.mCompressionAlgorithm >= 0, "compressionAlgorithm"); Validate(this.mMasterSecret != null, "masterSecret"); return new SessionParameters(mCipherSuite, (byte)mCompressionAlgorithm, mMasterSecret, mPeerCertificate, - mPskIdentity, mEncodedServerExtensions); + mPskIdentity, mSrpIdentity, mEncodedServerExtensions); } public Builder SetCipherSuite(int cipherSuite) @@ -60,6 +61,12 @@ namespace Org.BouncyCastle.Crypto.Tls return this; } + public Builder SetSrpIdentity(byte[] srpIdentity) + { + this.mSrpIdentity = srpIdentity; + return this; + } + public Builder SetServerExtensions(IDictionary serverExtensions) { if (serverExtensions == null) @@ -87,16 +94,18 @@ namespace Org.BouncyCastle.Crypto.Tls private byte[] mMasterSecret; private Certificate mPeerCertificate; private byte[] mPskIdentity; + private byte[] mSrpIdentity; private byte[] mEncodedServerExtensions; private SessionParameters(int cipherSuite, byte compressionAlgorithm, byte[] masterSecret, - Certificate peerCertificate, byte[] pskIdentity, byte[] encodedServerExtensions) + Certificate peerCertificate, byte[] pskIdentity, byte[] srpIdentity, byte[] encodedServerExtensions) { this.mCipherSuite = cipherSuite; this.mCompressionAlgorithm = compressionAlgorithm; this.mMasterSecret = Arrays.Clone(masterSecret); this.mPeerCertificate = peerCertificate; this.mPskIdentity = Arrays.Clone(pskIdentity); + this.mSrpIdentity = Arrays.Clone(srpIdentity); this.mEncodedServerExtensions = encodedServerExtensions; } @@ -111,7 +120,7 @@ namespace Org.BouncyCastle.Crypto.Tls public SessionParameters Copy() { return new SessionParameters(mCipherSuite, mCompressionAlgorithm, mMasterSecret, mPeerCertificate, - mPskIdentity, mEncodedServerExtensions); + mPskIdentity, mSrpIdentity, mEncodedServerExtensions); } public int CipherSuite @@ -139,6 +148,11 @@ namespace Org.BouncyCastle.Crypto.Tls get { return mPskIdentity; } } + public byte[] SrpIdentity + { + get { return mSrpIdentity; } + } + public IDictionary ReadServerExtensions() { if (mEncodedServerExtensions == null) diff --git a/crypto/src/crypto/tls/SimulatedTlsSrpIdentityManager.cs b/crypto/src/crypto/tls/SimulatedTlsSrpIdentityManager.cs new file mode 100644 index 000000000..3e9737cd7 --- /dev/null +++ b/crypto/src/crypto/tls/SimulatedTlsSrpIdentityManager.cs @@ -0,0 +1,69 @@ +using System; + +using Org.BouncyCastle.Crypto.Agreement.Srp; +using Org.BouncyCastle.Crypto.Macs; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Tls +{ + /** + * An implementation of {@link TlsSRPIdentityManager} that simulates the existence of "unknown" identities + * to obscure the fact that there is no verifier for them. + */ + public class SimulatedTlsSrpIdentityManager + : TlsSrpIdentityManager + { + private static readonly byte[] PREFIX_PASSWORD = Strings.ToByteArray("password"); + private static readonly byte[] PREFIX_SALT = Strings.ToByteArray("salt"); + + /** + * Create a {@link SimulatedTlsSRPIdentityManager} that implements the algorithm from RFC 5054 2.5.1.3 + * + * @param group the {@link SRP6GroupParameters} defining the group that SRP is operating in + * @param seedKey the secret "seed key" referred to in RFC 5054 2.5.1.3 + * @return an instance of {@link SimulatedTlsSRPIdentityManager} + */ + public static SimulatedTlsSrpIdentityManager GetRfc5054Default(Srp6GroupParameters group, byte[] seedKey) + { + Srp6VerifierGenerator verifierGenerator = new Srp6VerifierGenerator(); + verifierGenerator.Init(group, TlsUtilities.CreateHash(HashAlgorithm.sha1)); + + HMac mac = new HMac(TlsUtilities.CreateHash(HashAlgorithm.sha1)); + mac.Init(new KeyParameter(seedKey)); + + return new SimulatedTlsSrpIdentityManager(group, verifierGenerator, mac); + } + + protected readonly Srp6GroupParameters mGroup; + protected readonly Srp6VerifierGenerator mVerifierGenerator; + protected readonly IMac mMac; + + public SimulatedTlsSrpIdentityManager(Srp6GroupParameters group, Srp6VerifierGenerator verifierGenerator, IMac mac) + { + this.mGroup = group; + this.mVerifierGenerator = verifierGenerator; + this.mMac = mac; + } + + public virtual TlsSrpLoginParameters GetLoginParameters(byte[] identity) + { + mMac.BlockUpdate(PREFIX_SALT, 0, PREFIX_SALT.Length); + mMac.BlockUpdate(identity, 0, identity.Length); + + byte[] salt = new byte[mMac.GetMacSize()]; + mMac.DoFinal(salt, 0); + + mMac.BlockUpdate(PREFIX_PASSWORD, 0, PREFIX_PASSWORD.Length); + mMac.BlockUpdate(identity, 0, identity.Length); + + byte[] password = new byte[mMac.GetMacSize()]; + mMac.DoFinal(password, 0); + + BigInteger verifier = mVerifierGenerator.GenerateVerifier(salt, identity, password); + + return new TlsSrpLoginParameters(mGroup, verifier, salt); + } + } +} diff --git a/crypto/src/crypto/tls/SrpTlsClient.cs b/crypto/src/crypto/tls/SrpTlsClient.cs index 5d82ed470..bed6a8f0c 100644 --- a/crypto/src/crypto/tls/SrpTlsClient.cs +++ b/crypto/src/crypto/tls/SrpTlsClient.cs @@ -6,20 +6,29 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Crypto.Tls { - public abstract class SrpTlsClient + public class SrpTlsClient : AbstractTlsClient { + protected TlsSrpGroupVerifier mGroupVerifier; + protected byte[] mIdentity; protected byte[] mPassword; public SrpTlsClient(byte[] identity, byte[] password) - : this(new DefaultTlsCipherFactory(), identity, password) + : this(new DefaultTlsCipherFactory(), new DefaultTlsSrpGroupVerifier(), identity, password) { } public SrpTlsClient(TlsCipherFactory cipherFactory, byte[] identity, byte[] password) + : this(cipherFactory, new DefaultTlsSrpGroupVerifier(), identity, password) + { + } + + public SrpTlsClient(TlsCipherFactory cipherFactory, TlsSrpGroupVerifier groupVerifier, + byte[] identity, byte[] password) : base(cipherFactory) { + this.mGroupVerifier = groupVerifier; this.mIdentity = Arrays.Clone(identity); this.mPassword = Arrays.Clone(password); } @@ -86,6 +95,15 @@ namespace Org.BouncyCastle.Crypto.Tls } } + public override TlsAuthentication GetAuthentication() + { + /* + * Note: This method is not called unless a server certificate is sent, which may be the + * case e.g. for SRP_DSS or SRP_RSA key exchange. + */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + public override TlsCipher GetCipher() { switch (mSelectedCipherSuite) @@ -117,7 +135,7 @@ namespace Org.BouncyCastle.Crypto.Tls protected virtual TlsKeyExchange CreateSrpKeyExchange(int keyExchange) { - return new TlsSrpKeyExchange(keyExchange, mSupportedSignatureAlgorithms, mIdentity, mPassword); + return new TlsSrpKeyExchange(keyExchange, mSupportedSignatureAlgorithms, mGroupVerifier, mIdentity, mPassword); } } } diff --git a/crypto/src/crypto/tls/SrpTlsServer.cs b/crypto/src/crypto/tls/SrpTlsServer.cs new file mode 100644 index 000000000..1bd6b3af4 --- /dev/null +++ b/crypto/src/crypto/tls/SrpTlsServer.cs @@ -0,0 +1,162 @@ +using System; +using System.Collections; +using System.IO; + +namespace Org.BouncyCastle.Crypto.Tls +{ + public class SrpTlsServer + : AbstractTlsServer + { + protected TlsSrpIdentityManager mSrpIdentityManager; + + protected byte[] mSrpIdentity = null; + protected TlsSrpLoginParameters mLoginParameters = null; + + public SrpTlsServer(TlsSrpIdentityManager srpIdentityManager) + : this(new DefaultTlsCipherFactory(), srpIdentityManager) + { + } + + public SrpTlsServer(TlsCipherFactory cipherFactory, TlsSrpIdentityManager srpIdentityManager) + : base(cipherFactory) + { + this.mSrpIdentityManager = srpIdentityManager; + } + + protected virtual TlsSignerCredentials GetDsaSignerCredentials() + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + protected virtual TlsSignerCredentials GetRsaSignerCredentials() + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + protected override 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_RSA_WITH_AES_256_CBC_SHA, + CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA, + CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA, + CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA + }; + } + + public override void ProcessClientExtensions(IDictionary clientExtensions) + { + base.ProcessClientExtensions(clientExtensions); + + this.mSrpIdentity = TlsSrpUtilities.GetSrpExtension(clientExtensions); + } + + public override int GetSelectedCipherSuite() + { + int cipherSuite = base.GetSelectedCipherSuite(); + + if (TlsSrpUtilities.IsSrpCipherSuite(cipherSuite)) + { + if (mSrpIdentity != null) + { + this.mLoginParameters = mSrpIdentityManager.GetLoginParameters(mSrpIdentity); + } + + if (mLoginParameters == null) + throw new TlsFatalAlert(AlertDescription.unknown_psk_identity); + } + + return cipherSuite; + } + + public override TlsCredentials GetCredentials() + { + switch (mSelectedCipherSuite) + { + 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 null; + + 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 GetDsaSignerCredentials(); + + 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 GetRsaSignerCredentials(); + + default: + /* Note: internal error here; selected a key exchange we don't implement! */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public override TlsKeyExchange GetKeyExchange() + { + switch (mSelectedCipherSuite) + { + 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 TlsProtocol implementation 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 override TlsCipher GetCipher() + { + switch (mSelectedCipherSuite) + { + 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 mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.cls_3DES_EDE_CBC, MacAlgorithm.hmac_sha1); + + 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 mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_128_CBC, MacAlgorithm.hmac_sha1); + + 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 mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_256_CBC, MacAlgorithm.hmac_sha1); + + default: + /* + * Note: internal error here; the TlsProtocol implementation 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(keyExchange, mSupportedSignatureAlgorithms, mSrpIdentity, mLoginParameters); + } + } +} diff --git a/crypto/src/crypto/tls/TlsClientProtocol.cs b/crypto/src/crypto/tls/TlsClientProtocol.cs index 0c35e62af..1bd0653a6 100644 --- a/crypto/src/crypto/tls/TlsClientProtocol.cs +++ b/crypto/src/crypto/tls/TlsClientProtocol.cs @@ -373,21 +373,17 @@ namespace Org.BouncyCastle.Crypto.Tls /* * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2 */ - SignatureAndHashAlgorithm signatureAndHashAlgorithm; - byte[] hash; + SignatureAndHashAlgorithm signatureAndHashAlgorithm = TlsUtilities.GetSignatureAndHashAlgorithm( + Context, signerCredentials); - if (TlsUtilities.IsTlsV12(Context)) + byte[] hash; + if (signatureAndHashAlgorithm == null) { - signatureAndHashAlgorithm = signerCredentials.SignatureAndHashAlgorithm; - if (signatureAndHashAlgorithm == null) - throw new TlsFatalAlert(AlertDescription.internal_error); - - hash = prepareFinishHash.GetFinalHash(signatureAndHashAlgorithm.Hash); + hash = mSecurityParameters.SessionHash; } else { - signatureAndHashAlgorithm = null; - hash = mSecurityParameters.SessionHash; + hash = prepareFinishHash.GetFinalHash(signatureAndHashAlgorithm.Hash); } byte[] signature = signerCredentials.GenerateCertificateSignature(hash); diff --git a/crypto/src/crypto/tls/TlsDHKeyExchange.cs b/crypto/src/crypto/tls/TlsDHKeyExchange.cs index b831249a6..211249fcc 100644 --- a/crypto/src/crypto/tls/TlsDHKeyExchange.cs +++ b/crypto/src/crypto/tls/TlsDHKeyExchange.cs @@ -4,6 +4,7 @@ using System.IO; using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; using Org.BouncyCastle.Security; namespace Org.BouncyCastle.Crypto.Tls @@ -16,12 +17,10 @@ namespace Org.BouncyCastle.Crypto.Tls protected DHParameters mDHParameters; protected AsymmetricKeyParameter mServerPublicKey; - protected DHPublicKeyParameters mDHAgreeServerPublicKey; protected TlsAgreementCredentials mAgreementCredentials; - protected DHPrivateKeyParameters mDHAgreeClientPrivateKey; - protected DHPrivateKeyParameters mDHAgreeServerPrivateKey; - protected DHPublicKeyParameters mDHAgreeClientPublicKey; + protected DHPrivateKeyParameters mDHAgreePrivateKey; + protected DHPublicKeyParameters mDHAgreePublicKey; public TlsDHKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, DHParameters dhParameters) : base(keyExchange, supportedSignatureAlgorithms) @@ -81,7 +80,7 @@ namespace Org.BouncyCastle.Crypto.Tls { try { - this.mDHAgreeServerPublicKey = TlsDHUtilities.ValidateDHPublicKey((DHPublicKeyParameters)this.mServerPublicKey); + this.mDHAgreePublicKey = TlsDHUtilities.ValidateDHPublicKey((DHPublicKeyParameters)this.mServerPublicKey); } catch (InvalidCastException e) { @@ -165,26 +164,40 @@ namespace Org.BouncyCastle.Crypto.Tls */ if (mAgreementCredentials == null) { - this.mDHAgreeClientPrivateKey = TlsDHUtilities.GenerateEphemeralClientKeyExchange(context.SecureRandom, - mDHAgreeServerPublicKey.Parameters, output); + this.mDHAgreePrivateKey = TlsDHUtilities.GenerateEphemeralClientKeyExchange(mContext.SecureRandom, + mDHParameters, output); } } - public override byte[] GeneratePremasterSecret() + public override void ProcessClientCertificate(Certificate clientCertificate) { - if (mAgreementCredentials != null) + // TODO Extract the public key + // TODO If the certificate is 'fixed', take the public key as dhAgreeClientPublicKey + } + + public override void ProcessClientKeyExchange(Stream input) + { + if (mDHAgreePublicKey != null) { - return mAgreementCredentials.GenerateAgreement(mDHAgreeServerPublicKey); + // For dss_fixed_dh and rsa_fixed_dh, the key arrived in the client certificate + return; } - if (mDHAgreeServerPrivateKey != null) + BigInteger Yc = TlsDHUtilities.ReadDHParameter(input); + + this.mDHAgreePublicKey = TlsDHUtilities.ValidateDHPublicKey(new DHPublicKeyParameters(Yc, mDHParameters)); + } + + public override byte[] GeneratePremasterSecret() + { + if (mAgreementCredentials != null) { - return TlsDHUtilities.CalculateDHBasicAgreement(mDHAgreeClientPublicKey, mDHAgreeServerPrivateKey); + return mAgreementCredentials.GenerateAgreement(mDHAgreePublicKey); } - if (mDHAgreeClientPrivateKey != null) + if (mDHAgreePrivateKey != null) { - return TlsDHUtilities.CalculateDHBasicAgreement(mDHAgreeServerPublicKey, mDHAgreeClientPrivateKey); + return TlsDHUtilities.CalculateDHBasicAgreement(mDHAgreePublicKey, mDHAgreePrivateKey); } throw new TlsFatalAlert(AlertDescription.internal_error); diff --git a/crypto/src/crypto/tls/TlsDheKeyExchange.cs b/crypto/src/crypto/tls/TlsDheKeyExchange.cs index 3c05bb6f0..419d4e442 100644 --- a/crypto/src/crypto/tls/TlsDheKeyExchange.cs +++ b/crypto/src/crypto/tls/TlsDheKeyExchange.cs @@ -36,30 +36,18 @@ namespace Org.BouncyCastle.Crypto.Tls DigestInputBuffer buf = new DigestInputBuffer(); - this.mDHAgreeServerPrivateKey = TlsDHUtilities.GenerateEphemeralServerKeyExchange(context.SecureRandom, + this.mDHAgreePrivateKey = TlsDHUtilities.GenerateEphemeralServerKeyExchange(mContext.SecureRandom, this.mDHParameters, buf); /* * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2 */ - SignatureAndHashAlgorithm signatureAndHashAlgorithm; - IDigest d; - - if (TlsUtilities.IsTlsV12(context)) - { - signatureAndHashAlgorithm = mServerCredentials.SignatureAndHashAlgorithm; - if (signatureAndHashAlgorithm == null) - throw new TlsFatalAlert(AlertDescription.internal_error); - - d = TlsUtilities.CreateHash(signatureAndHashAlgorithm.Hash); - } - else - { - signatureAndHashAlgorithm = null; - d = new CombinedHash(); - } - - SecurityParameters securityParameters = context.SecurityParameters; + SignatureAndHashAlgorithm signatureAndHashAlgorithm = TlsUtilities.GetSignatureAndHashAlgorithm( + mContext, mServerCredentials); + + IDigest d = TlsUtilities.CreateHash(signatureAndHashAlgorithm); + + SecurityParameters securityParameters = mContext.SecurityParameters; d.BlockUpdate(securityParameters.clientRandom, 0, securityParameters.clientRandom.Length); d.BlockUpdate(securityParameters.serverRandom, 0, securityParameters.serverRandom.Length); buf.UpdateDigest(d); @@ -76,21 +64,22 @@ namespace Org.BouncyCastle.Crypto.Tls public override void ProcessServerKeyExchange(Stream input) { - SecurityParameters securityParameters = context.SecurityParameters; + SecurityParameters securityParameters = mContext.SecurityParameters; SignerInputBuffer buf = new SignerInputBuffer(); Stream teeIn = new TeeInputStream(input, buf); ServerDHParams dhParams = ServerDHParams.Parse(teeIn); - DigitallySigned signed_params = DigitallySigned.Parse(context, input); + DigitallySigned signed_params = DigitallySigned.Parse(mContext, input); ISigner signer = InitVerifyer(mTlsSigner, signed_params.Algorithm, securityParameters); buf.UpdateSigner(signer); if (!signer.VerifySignature(signed_params.Signature)) throw new TlsFatalAlert(AlertDescription.decrypt_error); - this.mDHAgreeServerPublicKey = TlsDHUtilities.ValidateDHPublicKey(dhParams.PublicKey); + this.mDHAgreePublicKey = TlsDHUtilities.ValidateDHPublicKey(dhParams.PublicKey); + this.mDHParameters = mDHAgreePublicKey.Parameters; } protected virtual ISigner InitVerifyer(TlsSigner tlsSigner, SignatureAndHashAlgorithm algorithm, diff --git a/crypto/src/crypto/tls/TlsDsaSigner.cs b/crypto/src/crypto/tls/TlsDsaSigner.cs index a5ac55974..f0c1e9451 100644 --- a/crypto/src/crypto/tls/TlsDsaSigner.cs +++ b/crypto/src/crypto/tls/TlsDsaSigner.cs @@ -64,8 +64,7 @@ namespace Org.BouncyCastle.Crypto.Tls if ((algorithm != null) != TlsUtilities.IsTlsV12(mContext)) throw new InvalidOperationException(); - // TODO For TLS 1.2+, lift the SHA-1 restriction here - if (algorithm != null && (algorithm.Hash != HashAlgorithm.sha1 || algorithm.Signature != SignatureAlgorithm)) + if (algorithm != null && algorithm.Signature != SignatureAlgorithm) throw new InvalidOperationException(); byte hashAlgorithm = algorithm == null ? HashAlgorithm.sha1 : algorithm.Hash; diff --git a/crypto/src/crypto/tls/TlsECDHKeyExchange.cs b/crypto/src/crypto/tls/TlsECDHKeyExchange.cs index 42dc2f2ef..992be4aca 100644 --- a/crypto/src/crypto/tls/TlsECDHKeyExchange.cs +++ b/crypto/src/crypto/tls/TlsECDHKeyExchange.cs @@ -166,7 +166,7 @@ namespace Org.BouncyCastle.Crypto.Tls { if (mAgreementCredentials == null) { - this.mECAgreePrivateKey = TlsEccUtilities.GenerateEphemeralClientKeyExchange(context.SecureRandom, + this.mECAgreePrivateKey = TlsEccUtilities.GenerateEphemeralClientKeyExchange(mContext.SecureRandom, mServerECPointFormats, mECAgreePublicKey.Parameters, output); } } diff --git a/crypto/src/crypto/tls/TlsECDheKeyExchange.cs b/crypto/src/crypto/tls/TlsECDheKeyExchange.cs index b99db0c18..b681aada3 100644 --- a/crypto/src/crypto/tls/TlsECDheKeyExchange.cs +++ b/crypto/src/crypto/tls/TlsECDheKeyExchange.cs @@ -36,30 +36,18 @@ namespace Org.BouncyCastle.Crypto.Tls { DigestInputBuffer buf = new DigestInputBuffer(); - this.mECAgreePrivateKey = TlsEccUtilities.GenerateEphemeralServerKeyExchange(context.SecureRandom, mNamedCurves, + this.mECAgreePrivateKey = TlsEccUtilities.GenerateEphemeralServerKeyExchange(mContext.SecureRandom, mNamedCurves, mClientECPointFormats, buf); /* * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2 */ - SignatureAndHashAlgorithm signatureAndHashAlgorithm; - IDigest d; + SignatureAndHashAlgorithm signatureAndHashAlgorithm = TlsUtilities.GetSignatureAndHashAlgorithm( + mContext, mServerCredentials); - if (TlsUtilities.IsTlsV12(context)) - { - signatureAndHashAlgorithm = mServerCredentials.SignatureAndHashAlgorithm; - if (signatureAndHashAlgorithm == null) - throw new TlsFatalAlert(AlertDescription.internal_error); - - d = TlsUtilities.CreateHash(signatureAndHashAlgorithm.Hash); - } - else - { - signatureAndHashAlgorithm = null; - d = new CombinedHash(); - } + IDigest d = TlsUtilities.CreateHash(signatureAndHashAlgorithm); - SecurityParameters securityParameters = context.SecurityParameters; + SecurityParameters securityParameters = mContext.SecurityParameters; d.BlockUpdate(securityParameters.clientRandom, 0, securityParameters.clientRandom.Length); d.BlockUpdate(securityParameters.serverRandom, 0, securityParameters.serverRandom.Length); buf.UpdateDigest(d); @@ -76,7 +64,7 @@ namespace Org.BouncyCastle.Crypto.Tls public override void ProcessServerKeyExchange(Stream input) { - SecurityParameters securityParameters = context.SecurityParameters; + SecurityParameters securityParameters = mContext.SecurityParameters; SignerInputBuffer buf = new SignerInputBuffer(); Stream teeIn = new TeeInputStream(input, buf); @@ -85,7 +73,7 @@ namespace Org.BouncyCastle.Crypto.Tls byte[] point = TlsUtilities.ReadOpaque8(teeIn); - DigitallySigned signed_params = DigitallySigned.Parse(context, input); + DigitallySigned signed_params = DigitallySigned.Parse(mContext, input); ISigner signer = InitVerifyer(mTlsSigner, signed_params.Algorithm, securityParameters); buf.UpdateSigner(signer); diff --git a/crypto/src/crypto/tls/TlsProtocol.cs b/crypto/src/crypto/tls/TlsProtocol.cs index 1a6e7a3bc..4ea72cd57 100644 --- a/crypto/src/crypto/tls/TlsProtocol.cs +++ b/crypto/src/crypto/tls/TlsProtocol.cs @@ -168,6 +168,8 @@ namespace Org.BouncyCastle.Crypto.Tls .SetCompressionAlgorithm(this.mSecurityParameters.compressionAlgorithm) .SetMasterSecret(this.mSecurityParameters.masterSecret) .SetPeerCertificate(this.mPeerCertificate) + .SetPskIdentity(this.mSecurityParameters.pskIdentity) + .SetSrpIdentity(this.mSecurityParameters.srpIdentity) // TODO Consider filtering extensions that aren't relevant to resumed sessions .SetServerExtensions(this.mServerExtensions) .Build(); diff --git a/crypto/src/crypto/tls/TlsPskKeyExchange.cs b/crypto/src/crypto/tls/TlsPskKeyExchange.cs index a8d0867ef..0af7f7a69 100644 --- a/crypto/src/crypto/tls/TlsPskKeyExchange.cs +++ b/crypto/src/crypto/tls/TlsPskKeyExchange.cs @@ -99,12 +99,12 @@ namespace Org.BouncyCastle.Crypto.Tls if (this.mDHParameters == null) throw new TlsFatalAlert(AlertDescription.internal_error); - this.mDHAgreePrivateKey = TlsDHUtilities.GenerateEphemeralServerKeyExchange(context.SecureRandom, + this.mDHAgreePrivateKey = TlsDHUtilities.GenerateEphemeralServerKeyExchange(mContext.SecureRandom, this.mDHParameters, buf); } else if (this.mKeyExchange == KeyExchangeAlgorithm.ECDHE_PSK) { - this.mECAgreePrivateKey = TlsEccUtilities.GenerateEphemeralServerKeyExchange(context.SecureRandom, + this.mECAgreePrivateKey = TlsEccUtilities.GenerateEphemeralServerKeyExchange(mContext.SecureRandom, mNamedCurves, mClientECPointFormats, buf); } @@ -165,6 +165,7 @@ namespace Org.BouncyCastle.Crypto.Tls ServerDHParams serverDHParams = ServerDHParams.Parse(input); this.mDHAgreePublicKey = TlsDHUtilities.ValidateDHPublicKey(serverDHParams.PublicKey); + this.mDHParameters = mDHAgreePublicKey.Parameters; } else if (this.mKeyExchange == KeyExchangeAlgorithm.ECDHE_PSK) { @@ -208,21 +209,21 @@ namespace Org.BouncyCastle.Crypto.Tls TlsUtilities.WriteOpaque16(psk_identity, output); - context.SecurityParameters.pskIdentity = psk_identity; + mContext.SecurityParameters.pskIdentity = psk_identity; if (this.mKeyExchange == KeyExchangeAlgorithm.DHE_PSK) { - this.mDHAgreePrivateKey = TlsDHUtilities.GenerateEphemeralClientKeyExchange(context.SecureRandom, - mDHAgreePublicKey.Parameters, output); + this.mDHAgreePrivateKey = TlsDHUtilities.GenerateEphemeralClientKeyExchange(mContext.SecureRandom, + mDHParameters, output); } else if (this.mKeyExchange == KeyExchangeAlgorithm.ECDHE_PSK) { - this.mECAgreePrivateKey = TlsEccUtilities.GenerateEphemeralClientKeyExchange(context.SecureRandom, + this.mECAgreePrivateKey = TlsEccUtilities.GenerateEphemeralClientKeyExchange(mContext.SecureRandom, mServerECPointFormats, mECAgreePublicKey.Parameters, output); } else if (this.mKeyExchange == KeyExchangeAlgorithm.RSA_PSK) { - this.mPremasterSecret = TlsRsaUtilities.GenerateEncryptedPreMasterSecret(context, + this.mPremasterSecret = TlsRsaUtilities.GenerateEncryptedPreMasterSecret(mContext, this.mRsaServerPublicKey, output); } } @@ -235,7 +236,7 @@ namespace Org.BouncyCastle.Crypto.Tls if (mPsk == null) throw new TlsFatalAlert(AlertDescription.unknown_psk_identity); - context.SecurityParameters.pskIdentity = psk_identity; + mContext.SecurityParameters.pskIdentity = psk_identity; if (this.mKeyExchange == KeyExchangeAlgorithm.DHE_PSK) { @@ -255,7 +256,7 @@ namespace Org.BouncyCastle.Crypto.Tls else if (this.mKeyExchange == KeyExchangeAlgorithm.RSA_PSK) { byte[] encryptedPreMasterSecret; - if (TlsUtilities.IsSsl(context)) + if (TlsUtilities.IsSsl(mContext)) { // TODO Do any SSLv3 clients actually include the length? encryptedPreMasterSecret = Streams.ReadAll(input); diff --git a/crypto/src/crypto/tls/TlsRsaKeyExchange.cs b/crypto/src/crypto/tls/TlsRsaKeyExchange.cs index 3a0a49154..b02d56486 100644 --- a/crypto/src/crypto/tls/TlsRsaKeyExchange.cs +++ b/crypto/src/crypto/tls/TlsRsaKeyExchange.cs @@ -16,13 +16,13 @@ namespace Org.BouncyCastle.Crypto.Tls public class TlsRsaKeyExchange : AbstractTlsKeyExchange { - protected AsymmetricKeyParameter serverPublicKey = null; + protected AsymmetricKeyParameter mServerPublicKey = null; - protected RsaKeyParameters rsaServerPublicKey = null; + protected RsaKeyParameters mRsaServerPublicKey = null; - protected TlsEncryptionCredentials serverCredentials = null; + protected TlsEncryptionCredentials mServerCredentials = null; - protected byte[] premasterSecret; + protected byte[] mPremasterSecret; public TlsRsaKeyExchange(IList supportedSignatureAlgorithms) : base(KeyExchangeAlgorithm.RSA, supportedSignatureAlgorithms) @@ -41,7 +41,7 @@ namespace Org.BouncyCastle.Crypto.Tls ProcessServerCertificate(serverCredentials.Certificate); - this.serverCredentials = (TlsEncryptionCredentials)serverCredentials; + this.mServerCredentials = (TlsEncryptionCredentials)serverCredentials; } public override void ProcessServerCertificate(Certificate serverCertificate) @@ -54,7 +54,7 @@ namespace Org.BouncyCastle.Crypto.Tls SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo; try { - this.serverPublicKey = PublicKeyFactory.CreateKey(keyInfo); + this.mServerPublicKey = PublicKeyFactory.CreateKey(keyInfo); } catch (Exception e) { @@ -62,10 +62,10 @@ namespace Org.BouncyCastle.Crypto.Tls } // Sanity check the PublicKeyFactory - if (this.serverPublicKey.IsPrivate) + if (this.mServerPublicKey.IsPrivate) throw new TlsFatalAlert(AlertDescription.internal_error); - this.rsaServerPublicKey = ValidateRsaPublicKey((RsaKeyParameters)this.serverPublicKey); + this.mRsaServerPublicKey = ValidateRsaPublicKey((RsaKeyParameters)this.mServerPublicKey); TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.KeyEncipherment); @@ -97,13 +97,13 @@ namespace Org.BouncyCastle.Crypto.Tls public override void GenerateClientKeyExchange(Stream output) { - this.premasterSecret = TlsRsaUtilities.GenerateEncryptedPreMasterSecret(context, rsaServerPublicKey, output); + this.mPremasterSecret = TlsRsaUtilities.GenerateEncryptedPreMasterSecret(mContext, mRsaServerPublicKey, output); } public override void ProcessClientKeyExchange(Stream input) { byte[] encryptedPreMasterSecret; - if (TlsUtilities.IsSsl(context)) + if (TlsUtilities.IsSsl(mContext)) { // TODO Do any SSLv3 clients actually include the length? encryptedPreMasterSecret = Streams.ReadAll(input); @@ -113,16 +113,16 @@ namespace Org.BouncyCastle.Crypto.Tls encryptedPreMasterSecret = TlsUtilities.ReadOpaque16(input); } - this.premasterSecret = serverCredentials.DecryptPreMasterSecret(encryptedPreMasterSecret); + this.mPremasterSecret = mServerCredentials.DecryptPreMasterSecret(encryptedPreMasterSecret); } public override byte[] GeneratePremasterSecret() { - if (this.premasterSecret == null) + if (this.mPremasterSecret == null) throw new TlsFatalAlert(AlertDescription.internal_error); - byte[] tmp = this.premasterSecret; - this.premasterSecret = null; + byte[] tmp = this.mPremasterSecret; + this.mPremasterSecret = null; return tmp; } diff --git a/crypto/src/crypto/tls/TlsSrpGroupVerifier.cs b/crypto/src/crypto/tls/TlsSrpGroupVerifier.cs new file mode 100644 index 000000000..185f2f50a --- /dev/null +++ b/crypto/src/crypto/tls/TlsSrpGroupVerifier.cs @@ -0,0 +1,17 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Tls +{ + public interface TlsSrpGroupVerifier + { + /** + * Check whether the given SRP group parameters are acceptable for use. + * + * @param group the {@link SRP6GroupParameters} to check + * @return true if (and only if) the specified group parameters are acceptable + */ + bool Accept(Srp6GroupParameters group); + } +} diff --git a/crypto/src/crypto/tls/TlsSrpIdentityManager.cs b/crypto/src/crypto/tls/TlsSrpIdentityManager.cs new file mode 100644 index 000000000..080a0dc16 --- /dev/null +++ b/crypto/src/crypto/tls/TlsSrpIdentityManager.cs @@ -0,0 +1,21 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Tls +{ + public interface TlsSrpIdentityManager + { + /** + * Lookup the {@link TlsSRPLoginParameters} corresponding to the specified identity. + * + * NOTE: To avoid "identity probing", unknown identities SHOULD be handled as recommended in RFC + * 5054 2.5.1.3. {@link SimulatedTlsSRPIdentityManager} is provided for this purpose. + * + * @param identity + * the SRP identity sent by the connecting client + * @return the {@link TlsSRPLoginParameters} for the specified identity, or else 'simulated' + * parameters if the identity is not recognized. A null value is also allowed, but not + * recommended. + */ + TlsSrpLoginParameters GetLoginParameters(byte[] identity); + } +} diff --git a/crypto/src/crypto/tls/TlsSrpKeyExchange.cs b/crypto/src/crypto/tls/TlsSrpKeyExchange.cs index f42f7456d..ce8e4834a 100644 --- a/crypto/src/crypto/tls/TlsSrpKeyExchange.cs +++ b/crypto/src/crypto/tls/TlsSrpKeyExchange.cs @@ -16,36 +16,64 @@ namespace Org.BouncyCastle.Crypto.Tls public class TlsSrpKeyExchange : AbstractTlsKeyExchange { + protected static TlsSigner CreateSigner(int keyExchange) + { + switch (keyExchange) + { + case KeyExchangeAlgorithm.SRP: + return null; + case KeyExchangeAlgorithm.SRP_RSA: + return new TlsRsaSigner(); + case KeyExchangeAlgorithm.SRP_DSS: + return new TlsDssSigner(); + default: + throw new ArgumentException("unsupported key exchange algorithm"); + } + } + protected TlsSigner mTlsSigner; + protected TlsSrpGroupVerifier mGroupVerifier; protected byte[] mIdentity; protected byte[] mPassword; protected AsymmetricKeyParameter mServerPublicKey = null; - protected byte[] mS = null; - protected BigInteger mB = null; - protected Srp6Client mSrpClient = new Srp6Client(); + protected Srp6GroupParameters mSrpGroup = null; + protected Srp6Client mSrpClient = null; + protected Srp6Server mSrpServer = null; + protected BigInteger mSrpPeerCredentials = null; + protected BigInteger mSrpVerifier = null; + protected byte[] mSrpSalt = null; + + protected TlsSignerCredentials mServerCredentials = null; + [Obsolete("Use constructor taking an explicit 'groupVerifier' argument")] public TlsSrpKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, byte[] identity, byte[] password) - : base(keyExchange, supportedSignatureAlgorithms) + : this(keyExchange, supportedSignatureAlgorithms, new DefaultTlsSrpGroupVerifier(), identity, password) { - switch (keyExchange) - { - case KeyExchangeAlgorithm.SRP: - this.mTlsSigner = null; - break; - case KeyExchangeAlgorithm.SRP_RSA: - this.mTlsSigner = new TlsRsaSigner(); - break; - case KeyExchangeAlgorithm.SRP_DSS: - this.mTlsSigner = new TlsDssSigner(); - break; - default: - throw new InvalidOperationException("unsupported key exchange algorithm"); - } + } + public TlsSrpKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, TlsSrpGroupVerifier groupVerifier, + byte[] identity, byte[] password) + : base(keyExchange, supportedSignatureAlgorithms) + { + this.mTlsSigner = CreateSigner(keyExchange); + this.mGroupVerifier = groupVerifier; this.mIdentity = identity; this.mPassword = password; + this.mSrpClient = new Srp6Client(); + } + + public TlsSrpKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, byte[] identity, + TlsSrpLoginParameters loginParameters) + : base(keyExchange, supportedSignatureAlgorithms) + { + this.mTlsSigner = CreateSigner(keyExchange); + this.mIdentity = identity; + this.mSrpServer = new Srp6Server(); + this.mSrpGroup = loginParameters.Group; + this.mSrpVerifier = loginParameters.Verifier; + this.mSrpSalt = loginParameters.Salt; } public override void Init(TlsContext context) @@ -91,14 +119,62 @@ namespace Org.BouncyCastle.Crypto.Tls base.ProcessServerCertificate(serverCertificate); } + public override void ProcessServerCredentials(TlsCredentials serverCredentials) + { + if ((mKeyExchange == KeyExchangeAlgorithm.SRP) || !(serverCredentials is TlsSignerCredentials)) + throw new TlsFatalAlert(AlertDescription.internal_error); + + ProcessServerCertificate(serverCredentials.Certificate); + + this.mServerCredentials = (TlsSignerCredentials)serverCredentials; + } + public override bool RequiresServerKeyExchange { get { return true; } } + public override byte[] GenerateServerKeyExchange() + { + mSrpServer.Init(mSrpGroup, mSrpVerifier, TlsUtilities.CreateHash(HashAlgorithm.sha1), mContext.SecureRandom); + BigInteger B = mSrpServer.GenerateServerCredentials(); + + ServerSrpParams srpParams = new ServerSrpParams(mSrpGroup.N, mSrpGroup.G, mSrpSalt, B); + + DigestInputBuffer buf = new DigestInputBuffer(); + + srpParams.Encode(buf); + + if (mServerCredentials != null) + { + /* + * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2 + */ + SignatureAndHashAlgorithm signatureAndHashAlgorithm = TlsUtilities.GetSignatureAndHashAlgorithm( + mContext, mServerCredentials); + + IDigest d = TlsUtilities.CreateHash(signatureAndHashAlgorithm); + + SecurityParameters securityParameters = mContext.SecurityParameters; + d.BlockUpdate(securityParameters.clientRandom, 0, securityParameters.clientRandom.Length); + d.BlockUpdate(securityParameters.serverRandom, 0, securityParameters.serverRandom.Length); + buf.UpdateDigest(d); + + byte[] hash = new byte[d.GetDigestSize()]; + d.DoFinal(hash, 0); + + byte[] signature = mServerCredentials.GenerateCertificateSignature(hash); + + DigitallySigned signed_params = new DigitallySigned(signatureAndHashAlgorithm, signature); + signed_params.Encode(buf); + } + + return buf.ToArray(); + } + public override void ProcessServerKeyExchange(Stream input) { - SecurityParameters securityParameters = context.SecurityParameters; + SecurityParameters securityParameters = mContext.SecurityParameters; SignerInputBuffer buf = null; Stream teeIn = input; @@ -109,14 +185,11 @@ namespace Org.BouncyCastle.Crypto.Tls teeIn = new TeeInputStream(input, buf); } - byte[] NBytes = TlsUtilities.ReadOpaque16(teeIn); - byte[] gBytes = TlsUtilities.ReadOpaque16(teeIn); - byte[] sBytes = TlsUtilities.ReadOpaque8(teeIn); - byte[] BBytes = TlsUtilities.ReadOpaque16(teeIn); + ServerSrpParams srpParams = ServerSrpParams.Parse(teeIn); if (buf != null) { - DigitallySigned signed_params = DigitallySigned.Parse(context, input); + DigitallySigned signed_params = DigitallySigned.Parse(mContext, input); ISigner signer = InitVerifyer(mTlsSigner, signed_params.Algorithm, securityParameters); buf.UpdateSigner(signer); @@ -124,13 +197,12 @@ namespace Org.BouncyCastle.Crypto.Tls throw new TlsFatalAlert(AlertDescription.decrypt_error); } - BigInteger N = new BigInteger(1, NBytes); - BigInteger g = new BigInteger(1, gBytes); + this.mSrpGroup = new Srp6GroupParameters(srpParams.N, srpParams.G); - // TODO Validate group parameters (see RFC 5054) - // throw new TlsFatalAlert(AlertDescription.insufficient_security); + if (!mGroupVerifier.Accept(mSrpGroup)) + throw new TlsFatalAlert(AlertDescription.insufficient_security); - this.mS = sBytes; + this.mSrpSalt = srpParams.S; /* * RFC 5054 2.5.3: The client MUST abort the handshake with an "illegal_parameter" alert if @@ -138,14 +210,14 @@ namespace Org.BouncyCastle.Crypto.Tls */ try { - this.mB = Srp6Utilities.ValidatePublicValue(N, new BigInteger(1, BBytes)); + this.mSrpPeerCredentials = Srp6Utilities.ValidatePublicValue(mSrpGroup.N, srpParams.B); } catch (CryptoException e) { throw new TlsFatalAlert(AlertDescription.illegal_parameter, e); } - this.mSrpClient.Init(N, g, TlsUtilities.CreateHash(HashAlgorithm.sha1), context.SecureRandom); + this.mSrpClient.Init(mSrpGroup, TlsUtilities.CreateHash(HashAlgorithm.sha1), mContext.SecureRandom); } public override void ValidateCertificateRequest(CertificateRequest certificateRequest) @@ -160,16 +232,40 @@ namespace Org.BouncyCastle.Crypto.Tls public override void GenerateClientKeyExchange(Stream output) { - BigInteger A = mSrpClient.GenerateClientCredentials(mS, this.mIdentity, this.mPassword); - TlsUtilities.WriteOpaque16(BigIntegers.AsUnsignedByteArray(A), output); + BigInteger A = mSrpClient.GenerateClientCredentials(mSrpSalt, mIdentity, mPassword); + TlsSrpUtilities.WriteSrpParameter(A, output); + + mContext.SecurityParameters.srpIdentity = Arrays.Clone(mIdentity); + } + + public override void ProcessClientKeyExchange(Stream input) + { + /* + * RFC 5054 2.5.4: The server MUST abort the handshake with an "illegal_parameter" alert if + * A % N = 0. + */ + try + { + this.mSrpPeerCredentials = Srp6Utilities.ValidatePublicValue(mSrpGroup.N, TlsSrpUtilities.ReadSrpParameter(input)); + } + catch (CryptoException e) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter, e); + } + + mContext.SecurityParameters.srpIdentity = Arrays.Clone(mIdentity); } public override byte[] GeneratePremasterSecret() { try { + BigInteger S = mSrpServer != null + ? mSrpServer.CalculateSecret(mSrpPeerCredentials) + : mSrpClient.CalculateSecret(mSrpPeerCredentials); + // TODO Check if this needs to be a fixed size - return BigIntegers.AsUnsignedByteArray(mSrpClient.CalculateSecret(mB)); + return BigIntegers.AsUnsignedByteArray(S); } catch (CryptoException e) { diff --git a/crypto/src/crypto/tls/TlsSrpLoginParameters.cs b/crypto/src/crypto/tls/TlsSrpLoginParameters.cs new file mode 100644 index 000000000..5ae4641f6 --- /dev/null +++ b/crypto/src/crypto/tls/TlsSrpLoginParameters.cs @@ -0,0 +1,36 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Crypto.Tls +{ + public class TlsSrpLoginParameters + { + protected readonly Srp6GroupParameters mGroup; + protected readonly BigInteger mVerifier; + protected readonly byte[] mSalt; + + public TlsSrpLoginParameters(Srp6GroupParameters group, BigInteger verifier, byte[] salt) + { + this.mGroup = group; + this.mVerifier = verifier; + this.mSalt = salt; + } + + public virtual Srp6GroupParameters Group + { + get { return mGroup; } + } + + public virtual byte[] Salt + { + get { return mSalt; } + } + + public virtual BigInteger Verifier + { + get { return mVerifier; } + } + } +} diff --git a/crypto/src/crypto/tls/TlsSrpUtilities.cs b/crypto/src/crypto/tls/TlsSrpUtilities.cs index bbb6ac280..873189dc6 100644 --- a/crypto/src/crypto/tls/TlsSrpUtilities.cs +++ b/crypto/src/crypto/tls/TlsSrpUtilities.cs @@ -2,6 +2,9 @@ using System.Collections; using System.IO; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Utilities; + namespace Org.BouncyCastle.Crypto.Tls { public abstract class TlsSrpUtilities @@ -37,5 +40,35 @@ namespace Org.BouncyCastle.Crypto.Tls return identity; } + + public static BigInteger ReadSrpParameter(Stream input) + { + return new BigInteger(1, TlsUtilities.ReadOpaque16(input)); + } + + public static void WriteSrpParameter(BigInteger x, Stream output) + { + TlsUtilities.WriteOpaque16(BigIntegers.AsUnsignedByteArray(x), output); + } + + public static bool IsSrpCipherSuite(int cipherSuite) + { + switch (cipherSuite) + { + 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: + 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: + 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 true; + + default: + return false; + } + } } } diff --git a/crypto/src/crypto/tls/TlsUtilities.cs b/crypto/src/crypto/tls/TlsUtilities.cs index 485ecb760..be91e6c4b 100644 --- a/crypto/src/crypto/tls/TlsUtilities.cs +++ b/crypto/src/crypto/tls/TlsUtilities.cs @@ -21,6 +21,9 @@ namespace Org.BouncyCastle.Crypto.Tls public abstract class TlsUtilities { public static readonly byte[] EmptyBytes = new byte[0]; + public static readonly short[] EmptyShorts = new short[0]; + public static readonly int[] EmptyInts = new int[0]; + public static readonly long[] EmptyLongs = new long[0]; public static void CheckUint8(int i) { @@ -589,6 +592,37 @@ namespace Org.BouncyCastle.Crypto.Tls return extensions == null ? null : (byte[])extensions[extensionType]; } + public static IList GetDefaultSupportedSignatureAlgorithms() + { + byte[] hashAlgorithms = new byte[]{ HashAlgorithm.sha1, HashAlgorithm.sha224, HashAlgorithm.sha256, + HashAlgorithm.sha384, HashAlgorithm.sha512 }; + byte[] signatureAlgorithms = new byte[]{ SignatureAlgorithm.rsa, SignatureAlgorithm.dsa, + SignatureAlgorithm.ecdsa }; + + IList result = Platform.CreateArrayList(); + for (int i = 0; i < signatureAlgorithms.Length; ++i) + { + for (int j = 0; j < hashAlgorithms.Length; ++j) + { + result.Add(new SignatureAndHashAlgorithm(hashAlgorithms[j], signatureAlgorithms[i])); + } + } + return result; + } + + public static SignatureAndHashAlgorithm GetSignatureAndHashAlgorithm(TlsContext context, + TlsSignerCredentials signerCredentials) + { + SignatureAndHashAlgorithm signatureAndHashAlgorithm = null; + if (IsTlsV12(context)) + { + signatureAndHashAlgorithm = signerCredentials.SignatureAndHashAlgorithm; + if (signatureAndHashAlgorithm == null) + throw new TlsFatalAlert(AlertDescription.internal_error); + } + return signatureAndHashAlgorithm; + } + public static bool HasExpectedEmptyExtensionData(IDictionary extensions, int extensionType, byte alertDescription) { @@ -941,6 +975,13 @@ namespace Org.BouncyCastle.Crypto.Tls } } + public static IDigest CreateHash(SignatureAndHashAlgorithm signatureAndHashAlgorithm) + { + return signatureAndHashAlgorithm == null + ? new CombinedHash() + : CreateHash(signatureAndHashAlgorithm.Hash); + } + public static IDigest CloneHash(byte hashAlgorithm, IDigest hash) { switch (hashAlgorithm) diff --git a/crypto/test/src/crypto/test/SRP6Test.cs b/crypto/test/src/crypto/test/SRP6Test.cs index 3b80e2c16..6b64df924 100644 --- a/crypto/test/src/crypto/test/SRP6Test.cs +++ b/crypto/test/src/crypto/test/SRP6Test.cs @@ -23,15 +23,7 @@ namespace Org.BouncyCastle.Crypto.Tests return new BigInteger(1, Hex.Decode(hex)); } - // 1024 bit example prime from RFC5054 and corresponding generator - private static readonly BigInteger N_1024 = FromHex("EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C" - + "9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE4" - + "8E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B29" - + "7BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9A" - + "FD5138FE8376435B9FC61D2FC0EB06E3"); - private static readonly BigInteger g_1024 = BigInteger.Two; - - private readonly SecureRandom random = new SecureRandom(); + private readonly SecureRandom random = new SecureRandom(); public override string Name { @@ -42,9 +34,9 @@ namespace Org.BouncyCastle.Crypto.Tests { rfc5054AppendixBTestVectors(); - testMutualVerification(N_1024, g_1024); - testClientCatchesBadB(N_1024, g_1024); - testServerCatchesBadA(N_1024, g_1024); + testMutualVerification(Srp6StandardGroups.rfc5054_1024); + testClientCatchesBadB(Srp6StandardGroups.rfc5054_1024); + testServerCatchesBadA(Srp6StandardGroups.rfc5054_1024); testWithRandomParams(256); testWithRandomParams(384); @@ -56,8 +48,8 @@ namespace Org.BouncyCastle.Crypto.Tests byte[] I = Encoding.UTF8.GetBytes("alice"); byte[] P = Encoding.UTF8.GetBytes("password123"); byte[] s = Hex.Decode("BEB25379D1A8581EB5A727673A2441EE"); - BigInteger N = N_1024; - BigInteger g = g_1024; + BigInteger N = Srp6StandardGroups.rfc5054_1024.N; + BigInteger g = Srp6StandardGroups.rfc5054_1024.G; BigInteger a = FromHex("60975527035CF2AD1989806F0407210BC81EDC04E2762A56AFD529DDDA2D4393"); BigInteger b = FromHex("E487CB59D31AC550471E81F00F6928E01DDA08E974A004F49E61F5D105284D20"); @@ -148,13 +140,10 @@ namespace Org.BouncyCastle.Crypto.Tests paramGen.Init(bits, 25, random); DHParameters parameters = paramGen.GenerateParameters(); - BigInteger g = parameters.G; - BigInteger p = parameters.P; - - testMutualVerification(p, g); + testMutualVerification(new Srp6GroupParameters(parameters.P, parameters.G)); } - private void testMutualVerification(BigInteger N, BigInteger g) + private void testMutualVerification(Srp6GroupParameters group) { byte[] I = Encoding.UTF8.GetBytes("username"); byte[] P = Encoding.UTF8.GetBytes("password"); @@ -162,16 +151,16 @@ namespace Org.BouncyCastle.Crypto.Tests random.NextBytes(s); Srp6VerifierGenerator gen = new Srp6VerifierGenerator(); - gen.Init(N, g, new Sha256Digest()); + gen.Init(group, new Sha256Digest()); BigInteger v = gen.GenerateVerifier(s, I, P); Srp6Client client = new Srp6Client(); - client.Init(N, g, new Sha256Digest(), random); + client.Init(group, new Sha256Digest(), random); Srp6Server server = new Srp6Server(); - server.Init(N, g, v, new Sha256Digest(), random); + server.Init(group, v, new Sha256Digest(), random); - BigInteger A = client.GenerateClientCredentials(s, I, P); + BigInteger A = client.GenerateClientCredentials(s, I, P); BigInteger B = server.GenerateServerCredentials(); BigInteger clientS = client.CalculateSecret(B); @@ -183,7 +172,7 @@ namespace Org.BouncyCastle.Crypto.Tests } } - private void testClientCatchesBadB(BigInteger N, BigInteger g) + private void testClientCatchesBadB(Srp6GroupParameters group) { byte[] I = Encoding.UTF8.GetBytes("username"); byte[] P = Encoding.UTF8.GetBytes("password"); @@ -191,7 +180,7 @@ namespace Org.BouncyCastle.Crypto.Tests random.NextBytes(s); Srp6Client client = new Srp6Client(); - client.Init(N, g, new Sha256Digest(), random); + client.Init(group, new Sha256Digest(), random); client.GenerateClientCredentials(s, I, P); @@ -207,7 +196,7 @@ namespace Org.BouncyCastle.Crypto.Tests try { - client.CalculateSecret(N); + client.CalculateSecret(group.N); Fail("Client failed to detect invalid value for 'B'"); } catch (CryptoException) @@ -216,7 +205,7 @@ namespace Org.BouncyCastle.Crypto.Tests } } - private void testServerCatchesBadA(BigInteger N, BigInteger g) + private void testServerCatchesBadA(Srp6GroupParameters group) { byte[] I = Encoding.UTF8.GetBytes("username"); byte[] P = Encoding.UTF8.GetBytes("password"); @@ -224,11 +213,11 @@ namespace Org.BouncyCastle.Crypto.Tests random.NextBytes(s); Srp6VerifierGenerator gen = new Srp6VerifierGenerator(); - gen.Init(N, g, new Sha256Digest()); + gen.Init(group, new Sha256Digest()); BigInteger v = gen.GenerateVerifier(s, I, P); Srp6Server server = new Srp6Server(); - server.Init(N, g, v, new Sha256Digest(), random); + server.Init(group, v, new Sha256Digest(), random); server.GenerateServerCredentials(); @@ -244,7 +233,7 @@ namespace Org.BouncyCastle.Crypto.Tests try { - server.CalculateSecret(N); + server.CalculateSecret(group.N); Fail("Client failed to detect invalid value for 'A'"); } catch (CryptoException) diff --git a/crypto/test/src/crypto/tls/test/MockSrpTlsClient.cs b/crypto/test/src/crypto/tls/test/MockSrpTlsClient.cs new file mode 100644 index 000000000..7225d84ce --- /dev/null +++ b/crypto/test/src/crypto/tls/test/MockSrpTlsClient.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Encoders; + +namespace Org.BouncyCastle.Crypto.Tls.Tests +{ + internal class MockSrpTlsClient + : SrpTlsClient + { + internal TlsSession mSession; + + internal MockSrpTlsClient(TlsSession session, byte[] identity, byte[] password) + : base(identity, password) + { + this.mSession = session; + } + + public override TlsSession GetSessionToResume() + { + return this.mSession; + } + + public override void NotifyAlertRaised(byte alertLevel, byte alertDescription, string message, Exception cause) + { + TextWriter output = (alertLevel == AlertLevel.fatal) ? Console.Error : Console.Out; + output.WriteLine("TLS-SRP client raised alert: " + AlertLevel.GetText(alertLevel) + + ", " + AlertDescription.GetText(alertDescription)); + if (message != null) + { + output.WriteLine("> " + message); + } + if (cause != null) + { + output.WriteLine(cause); + } + } + + public override void NotifyAlertReceived(byte alertLevel, byte alertDescription) + { + TextWriter output = (alertLevel == AlertLevel.fatal) ? Console.Error : Console.Out; + output.WriteLine("TLS-SRP client received alert: " + AlertLevel.GetText(alertLevel) + + ", " + AlertDescription.GetText(alertDescription)); + } + + public override void NotifyHandshakeComplete() + { + base.NotifyHandshakeComplete(); + + TlsSession newSession = mContext.ResumableSession; + if (newSession != null) + { + byte[] newSessionID = newSession.SessionID; + string hex = Hex.ToHexString(newSessionID); + + if (this.mSession != null && Arrays.AreEqual(this.mSession.SessionID, newSessionID)) + { + Console.WriteLine("Resumed session: " + hex); + } + else + { + Console.WriteLine("Established session: " + hex); + } + + this.mSession = newSession; + } + } + + public override ProtocolVersion MinimumVersion + { + get { return ProtocolVersion.TLSv12; } + } + + public override IDictionary GetClientExtensions() + { + IDictionary clientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(base.GetClientExtensions()); + TlsExtensionsUtilities.AddEncryptThenMacExtension(clientExtensions); + return clientExtensions; + } + + public override void NotifyServerVersion(ProtocolVersion serverVersion) + { + base.NotifyServerVersion(serverVersion); + + Console.WriteLine("TLS-SRP client negotiated " + serverVersion); + } + + public override TlsAuthentication GetAuthentication() + { + return new MyTlsAuthentication(mContext); + } + + internal class MyTlsAuthentication + : ServerOnlyTlsAuthentication + { + private readonly TlsContext mContext; + + internal MyTlsAuthentication(TlsContext context) + { + this.mContext = context; + } + + public override void NotifyServerCertificate(Certificate serverCertificate) + { + X509CertificateStructure[] chain = serverCertificate.GetCertificateList(); + Console.WriteLine("TLS-SRP client received server certificate chain of length " + chain.Length); + for (int i = 0; i != chain.Length; i++) + { + X509CertificateStructure entry = chain[i]; + // TODO Create Fingerprint based on certificate signature algorithm digest + Console.WriteLine(" Fingerprint:SHA-256 " + TlsTestUtilities.Fingerprint(entry) + " (" + + entry.Subject + ")"); + } + } + }; + } +} diff --git a/crypto/test/src/crypto/tls/test/MockSrpTlsServer.cs b/crypto/test/src/crypto/tls/test/MockSrpTlsServer.cs new file mode 100644 index 000000000..c15f63e0b --- /dev/null +++ b/crypto/test/src/crypto/tls/test/MockSrpTlsServer.cs @@ -0,0 +1,113 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Crypto.Agreement.Srp; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Tls.Tests +{ + internal class MockSrpTlsServer + : SrpTlsServer + { + internal static readonly Srp6GroupParameters TEST_GROUP = Srp6StandardGroups.rfc5054_1024; + internal static readonly byte[] TEST_IDENTITY = Strings.ToUtf8ByteArray("client"); + internal static readonly byte[] TEST_PASSWORD = Strings.ToUtf8ByteArray("password"); + internal static readonly byte[] TEST_SALT = Strings.ToUtf8ByteArray("salt"); + internal static readonly byte[] TEST_SEED_KEY = Strings.ToUtf8ByteArray("seed_key"); + + internal MockSrpTlsServer() + : base(new MyIdentityManager()) + { + } + + public override void NotifyAlertRaised(byte alertLevel, byte alertDescription, string message, Exception cause) + { + TextWriter output = (alertLevel == AlertLevel.fatal) ? Console.Error : Console.Out; + output.WriteLine("TLS-SRP server raised alert: " + AlertLevel.GetText(alertLevel) + + ", " + AlertDescription.GetText(alertDescription)); + if (message != null) + { + output.WriteLine("> " + message); + } + if (cause != null) + { + output.WriteLine(cause); + } + } + + public override void NotifyAlertReceived(byte alertLevel, byte alertDescription) + { + TextWriter output = (alertLevel == AlertLevel.fatal) ? Console.Error : Console.Out; + output.WriteLine("TLS-SRP server received alert: " + AlertLevel.GetText(alertLevel) + + ", " + AlertDescription.GetText(alertDescription)); + } + + public override void NotifyHandshakeComplete() + { + base.NotifyHandshakeComplete(); + + byte[] srpIdentity = mContext.SecurityParameters.SrpIdentity; + if (srpIdentity != null) + { + string name = Strings.FromUtf8ByteArray(srpIdentity); + Console.WriteLine("TLS-SRP server completed handshake for SRP identity: " + name); + } + } + + protected override ProtocolVersion MaximumVersion + { + get { return ProtocolVersion.TLSv12; } + } + + protected override ProtocolVersion MinimumVersion + { + get { return ProtocolVersion.TLSv12; } + } + + public override ProtocolVersion GetServerVersion() + { + ProtocolVersion serverVersion = base.GetServerVersion(); + + Console.WriteLine("TLS-SRP server negotiated " + serverVersion); + + return serverVersion; + } + + protected override TlsSignerCredentials GetDsaSignerCredentials() + { + return TlsTestUtilities.LoadSignerCredentials(mContext, mSupportedSignatureAlgorithms, SignatureAlgorithm.dsa, + "x509-server-dsa.pem", "x509-server-key-dsa.pem"); + } + + protected override TlsSignerCredentials GetRsaSignerCredentials() + { + return TlsTestUtilities.LoadSignerCredentials(mContext, mSupportedSignatureAlgorithms, SignatureAlgorithm.rsa, + "x509-server.pem", "x509-server-key.pem"); + } + + internal class MyIdentityManager + : TlsSrpIdentityManager + { + protected SimulatedTlsSrpIdentityManager unknownIdentityManager = SimulatedTlsSrpIdentityManager.GetRfc5054Default( + TEST_GROUP, TEST_SEED_KEY); + + public virtual TlsSrpLoginParameters GetLoginParameters(byte[] identity) + { + if (Arrays.AreEqual(TEST_IDENTITY, identity)) + { + Srp6VerifierGenerator verifierGenerator = new Srp6VerifierGenerator(); + verifierGenerator.Init(TEST_GROUP, TlsUtilities.CreateHash(HashAlgorithm.sha1)); + + BigInteger verifier = verifierGenerator.GenerateVerifier(TEST_SALT, identity, TEST_PASSWORD); + + return new TlsSrpLoginParameters(TEST_GROUP, verifier, TEST_SALT); + } + + return unknownIdentityManager.GetLoginParameters(identity); + } + } + } +} diff --git a/crypto/test/src/crypto/tls/test/MockTlsClient.cs b/crypto/test/src/crypto/tls/test/MockTlsClient.cs index 803989f59..fd673c3b9 100644 --- a/crypto/test/src/crypto/tls/test/MockTlsClient.cs +++ b/crypto/test/src/crypto/tls/test/MockTlsClient.cs @@ -133,27 +133,8 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests if (certificateTypes == null || !Arrays.Contains(certificateTypes, ClientCertificateType.rsa_sign)) return null; - SignatureAndHashAlgorithm signatureAndHashAlgorithm = null; - IList sigAlgs = certificateRequest.SupportedSignatureAlgorithms; - if (sigAlgs != null) - { - foreach (SignatureAndHashAlgorithm sigAlg in sigAlgs) - { - if (sigAlg.Signature == SignatureAlgorithm.rsa) - { - signatureAndHashAlgorithm = sigAlg; - break; - } - } - - if (signatureAndHashAlgorithm == null) - { - return null; - } - } - - return TlsTestUtilities.LoadSignerCredentials(mContext, new string[] { "x509-client.pem", "x509-ca.pem" }, - "x509-client-key.pem", signatureAndHashAlgorithm); + return TlsTestUtilities.LoadSignerCredentials(mContext, certificateRequest.SupportedSignatureAlgorithms, + SignatureAlgorithm.rsa, "x509-client.pem", "x509-client-key.pem"); } }; } diff --git a/crypto/test/src/crypto/tls/test/MockTlsServer.cs b/crypto/test/src/crypto/tls/test/MockTlsServer.cs index 14d6b9839..8fce95d63 100644 --- a/crypto/test/src/crypto/tls/test/MockTlsServer.cs +++ b/crypto/test/src/crypto/tls/test/MockTlsServer.cs @@ -61,29 +61,19 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests public override CertificateRequest GetCertificateRequest() { - IList serverSigAlgs = null; + byte[] certificateTypes = new byte[]{ ClientCertificateType.rsa_sign, + ClientCertificateType.dss_sign, ClientCertificateType.ecdsa_sign }; + IList serverSigAlgs = null; if (TlsUtilities.IsSignatureAlgorithmsExtensionAllowed(mServerVersion)) { - byte[] hashAlgorithms = new byte[]{ HashAlgorithm.sha512, HashAlgorithm.sha384, HashAlgorithm.sha256, - HashAlgorithm.sha224, HashAlgorithm.sha1 }; - byte[] signatureAlgorithms = new byte[]{ SignatureAlgorithm.rsa }; - - serverSigAlgs = new ArrayList(); - for (int i = 0; i < hashAlgorithms.Length; ++i) - { - for (int j = 0; j < signatureAlgorithms.Length; ++j) - { - serverSigAlgs.Add(new SignatureAndHashAlgorithm(hashAlgorithms[i], - signatureAlgorithms[j])); - } - } + serverSigAlgs = TlsUtilities.GetDefaultSupportedSignatureAlgorithms(); } IList certificateAuthorities = new ArrayList(); certificateAuthorities.Add(TlsTestUtilities.LoadCertificateResource("x509-ca.pem").Subject); - return new CertificateRequest(new byte[]{ ClientCertificateType.rsa_sign }, serverSigAlgs, certificateAuthorities); + return new CertificateRequest(certificateTypes, serverSigAlgs, certificateAuthorities); } public override void NotifyClientCertificate(Certificate clientCertificate) @@ -101,37 +91,14 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests protected override TlsEncryptionCredentials GetRsaEncryptionCredentials() { - return TlsTestUtilities.LoadEncryptionCredentials(mContext, new string[]{"x509-server.pem", "x509-ca.pem"}, + return TlsTestUtilities.LoadEncryptionCredentials(mContext, new string[]{ "x509-server.pem", "x509-ca.pem" }, "x509-server-key.pem"); } protected override TlsSignerCredentials GetRsaSignerCredentials() { - /* - * TODO Note that this code fails to provide default value for the client supported - * algorithms if it wasn't sent. - */ - SignatureAndHashAlgorithm signatureAndHashAlgorithm = null; - IList sigAlgs = mSupportedSignatureAlgorithms; - if (sigAlgs != null) - { - foreach (SignatureAndHashAlgorithm sigAlg in sigAlgs) - { - if (sigAlg.Signature == SignatureAlgorithm.rsa) - { - signatureAndHashAlgorithm = sigAlg; - break; - } - } - - if (signatureAndHashAlgorithm == null) - { - return null; - } - } - - return TlsTestUtilities.LoadSignerCredentials(mContext, new string[]{"x509-server.pem", "x509-ca.pem"}, - "x509-server-key.pem", signatureAndHashAlgorithm); + return TlsTestUtilities.LoadSignerCredentials(mContext, mSupportedSignatureAlgorithms, SignatureAlgorithm.rsa, + "x509-server.pem", "x509-server-key.pem"); } } } diff --git a/crypto/test/src/crypto/tls/test/TlsSrpProtocolTest.cs b/crypto/test/src/crypto/tls/test/TlsSrpProtocolTest.cs new file mode 100644 index 000000000..32e126ff2 --- /dev/null +++ b/crypto/test/src/crypto/tls/test/TlsSrpProtocolTest.cs @@ -0,0 +1,80 @@ +using System; +using System.IO; +using System.Threading; + +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.IO; + +using NUnit.Framework; + +namespace Org.BouncyCastle.Crypto.Tls.Tests +{ + [TestFixture] + public class TlsSrpProtocolTest + { + [Test] + public void TestClientServer() + { + SecureRandom secureRandom = new SecureRandom(); + + PipedStream clientPipe = new PipedStream(); + PipedStream serverPipe = new PipedStream(clientPipe); + + TlsClientProtocol clientProtocol = new TlsClientProtocol(clientPipe, secureRandom); + TlsServerProtocol serverProtocol = new TlsServerProtocol(serverPipe, secureRandom); + + Server server = new Server(serverProtocol); + + Thread serverThread = new Thread(new ThreadStart(server.Run)); + serverThread.Start(); + + MockSrpTlsClient client = new MockSrpTlsClient(null, MockSrpTlsServer.TEST_IDENTITY, MockSrpTlsServer.TEST_PASSWORD); + clientProtocol.Connect(client); + + // NOTE: Because we write-all before we read-any, this length can't be more than the pipe capacity + int length = 1000; + + byte[] data = new byte[length]; + secureRandom.NextBytes(data); + + Stream output = clientProtocol.Stream; + output.Write(data, 0, data.Length); + + byte[] echo = new byte[data.Length]; + int count = Streams.ReadFully(clientProtocol.Stream, echo); + + Assert.AreEqual(count, data.Length); + Assert.IsTrue(Arrays.AreEqual(data, echo)); + + output.Close(); + + serverThread.Join(); + } + + internal class Server + { + private readonly TlsServerProtocol mServerProtocol; + + internal Server(TlsServerProtocol serverProtocol) + { + this.mServerProtocol = serverProtocol; + } + + public void Run() + { + try + { + MockSrpTlsServer server = new MockSrpTlsServer(); + mServerProtocol.Accept(server); + Streams.PipeAll(mServerProtocol.Stream, mServerProtocol.Stream); + mServerProtocol.Close(); + } + catch (Exception) + { + //throw new RuntimeException(e); + } + } + } + } +} |