using System; using System.Collections; using System.IO; using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Crypto.Tls { public abstract class SrpTlsClient : TlsClient { protected TlsCipherFactory cipherFactory; protected byte[] identity; protected byte[] password; protected TlsClientContext context; protected CompressionMethod selectedCompressionMethod; protected CipherSuite selectedCipherSuite; public SrpTlsClient(byte[] identity, byte[] password) : this(new DefaultTlsCipherFactory(), identity, password) { } public SrpTlsClient(TlsCipherFactory cipherFactory, byte[] identity, byte[] password) { this.cipherFactory = cipherFactory; this.identity = Arrays.Clone(identity); this.password = Arrays.Clone(password); } public virtual void Init(TlsClientContext context) { this.context = context; } public virtual CipherSuite[] GetCipherSuites() { return new CipherSuite[] { CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA, CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA, CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA, CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA, CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA, CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA, CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA, }; } public virtual IDictionary GetClientExtensions() { IDictionary clientExtensions = Platform.CreateHashtable(); MemoryStream srpData = new MemoryStream(); TlsUtilities.WriteOpaque8(this.identity, srpData); clientExtensions[ExtensionType.srp] = srpData.ToArray(); return clientExtensions; } public virtual CompressionMethod[] GetCompressionMethods() { return new CompressionMethod[] { CompressionMethod.NULL }; } public virtual void NotifySessionID(byte[] sessionID) { // Currently ignored } public virtual void NotifySelectedCipherSuite(CipherSuite selectedCipherSuite) { this.selectedCipherSuite = selectedCipherSuite; } public virtual void NotifySelectedCompressionMethod(CompressionMethod selectedCompressionMethod) { this.selectedCompressionMethod = selectedCompressionMethod; } public virtual void NotifySecureRenegotiation(bool secureRenegotiation) { if (!secureRenegotiation) { /* * RFC 5746 3.4. If the extension is not present, the server does not support * secure renegotiation; set secure_renegotiation flag to FALSE. In this case, * some clients may want to terminate the handshake instead of continuing; see * Section 4.1 for discussion. */ // throw new TlsFatalAlert(AlertDescription.handshake_failure); } } public virtual void ProcessServerExtensions(IDictionary serverExtensions) { // There is no server response for the SRP extension } public virtual TlsKeyExchange GetKeyExchange() { switch (selectedCipherSuite) { case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA: case CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA: case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA: return CreateSrpKeyExchange(KeyExchangeAlgorithm.SRP); case CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA: case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA: case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA: return CreateSrpKeyExchange(KeyExchangeAlgorithm.SRP_RSA); case CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA: case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA: case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA: return CreateSrpKeyExchange(KeyExchangeAlgorithm.SRP_DSS); default: /* * Note: internal error here; the TlsProtocolHandler verifies that the * server-selected cipher suite was in the list of client-offered cipher * suites, so if we now can't produce an implementation, we shouldn't have * offered it! */ throw new TlsFatalAlert(AlertDescription.internal_error); } } public abstract TlsAuthentication GetAuthentication(); public virtual TlsCompression GetCompression() { switch (selectedCompressionMethod) { case CompressionMethod.NULL: return new TlsNullCompression(); default: /* * Note: internal error here; the TlsProtocolHandler verifies that the * server-selected compression method was in the list of client-offered compression * methods, so if we now can't produce an implementation, we shouldn't have * offered it! */ throw new TlsFatalAlert(AlertDescription.internal_error); } } public virtual TlsCipher GetCipher() { switch (selectedCipherSuite) { case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA: case CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA: case CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA: return cipherFactory.CreateCipher(context, EncryptionAlgorithm.cls_3DES_EDE_CBC, DigestAlgorithm.SHA); case CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA: case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA: case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA: return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_128_CBC, DigestAlgorithm.SHA); case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA: case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA: case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA: return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_256_CBC, DigestAlgorithm.SHA); default: /* * Note: internal error here; the TlsProtocolHandler verifies that the * server-selected cipher suite was in the list of client-offered cipher * suites, so if we now can't produce an implementation, we shouldn't have * offered it! */ throw new TlsFatalAlert(AlertDescription.internal_error); } } protected virtual TlsKeyExchange CreateSrpKeyExchange(KeyExchangeAlgorithm keyExchange) { return new TlsSrpKeyExchange(context, keyExchange, identity, password); } } }