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)
|