diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2013-12-17 17:34:32 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2013-12-17 17:34:32 +0700 |
commit | 33ef8acd210067b48eed37fbfb4b0c8da8921b8d (patch) | |
tree | e9b91cab27726821a4c90f923552440f039200b1 | |
parent | Add methods for converting from BC RSAPrivateKeyStructure (diff) | |
download | BouncyCastle.NET-ed25519-33ef8acd210067b48eed37fbfb4b0c8da8921b8d.tar.xz |
A round of porting from Java TLS
29 files changed, 1748 insertions, 1196 deletions
diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj index 0b81c9a6c..ac5aeb985 100644 --- a/crypto/crypto.csproj +++ b/crypto/crypto.csproj @@ -4324,6 +4324,11 @@ BuildAction = "Compile" /> <File + RelPath = "src\crypto\tls\HashAlgorithm.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File RelPath = "src\crypto\tls\ICertificateVerifyer.cs" SubType = "Code" BuildAction = "Compile" @@ -4364,6 +4369,16 @@ BuildAction = "Compile" /> <File + RelPath = "src\crypto\tls\SignatureAlgorithm.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File + RelPath = "src\crypto\tls\SignatureAndHashAlgorithm.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File RelPath = "src\crypto\tls\SrpTlsClient.cs" SubType = "Code" BuildAction = "Compile" @@ -4469,11 +4484,6 @@ BuildAction = "Compile" /> <File - RelPath = "src\crypto\tls\TlsException.cs" - SubType = "Code" - BuildAction = "Compile" - /> - <File RelPath = "src\crypto\tls\TlsFatalAlert.cs" SubType = "Code" BuildAction = "Compile" diff --git a/crypto/crypto.mdp b/crypto/crypto.mdp index 9a8988bb8..f655dd8d3 100644 --- a/crypto/crypto.mdp +++ b/crypto/crypto.mdp @@ -700,7 +700,6 @@ <File subtype="Code" buildaction="Compile" name="src/openssl/PEMUtilities.cs" /> <File subtype="Code" buildaction="Compile" name="src/openssl/PEMWriter.cs" /> <File subtype="Code" buildaction="Compile" name="src/crypto/generators/OpenSSLPBEParametersGenerator.cs" /> - <File subtype="Code" buildaction="Compile" name="src/crypto/tls/TlsException.cs" /> <File subtype="Code" buildaction="Compile" name="src/asn1/x509/X509ExtensionsGenerator.cs" /> <File subtype="Code" buildaction="Compile" name="src/security/GeneratorUtilities.cs" /> <File subtype="Code" buildaction="Compile" name="src/x509/extension/SubjectKeyIdentifierStructure.cs" /> @@ -2179,15 +2178,18 @@ <File subtype="Code" buildaction="Compile" name="src/util/collections/UnmodifiableListProxy.cs" /> <File subtype="Code" buildaction="Compile" name="src/crypto/tls/AlertDescription.cs" /> <File subtype="Code" buildaction="Compile" name="src/crypto/tls/AlertLevel.cs" /> + <File subtype="Code" buildaction="Compile" name="src/crypto/tls/CipherSuite.cs" /> + <File subtype="Code" buildaction="Compile" name="src/crypto/tls/ClientCertificateType.cs" /> <File subtype="Code" buildaction="Compile" name="src/crypto/tls/CompressionMethod.cs" /> <File subtype="Code" buildaction="Compile" name="src/crypto/tls/ContentType.cs" /> <File subtype="Code" buildaction="Compile" name="src/crypto/tls/ECCurveType.cs" /> <File subtype="Code" buildaction="Compile" name="src/crypto/tls/ECPointFormat.cs" /> <File subtype="Code" buildaction="Compile" name="src/crypto/tls/ExtensionType.cs" /> <File subtype="Code" buildaction="Compile" name="src/crypto/tls/HandshakeType.cs" /> - <File subtype="Code" buildaction="Compile" name="src/crypto/tls/ClientCertificateType.cs" /> + <File subtype="Code" buildaction="Compile" name="src/crypto/tls/HashAlgorithm.cs" /> <File subtype="Code" buildaction="Compile" name="src/crypto/tls/NamedCurve.cs" /> - <File subtype="Code" buildaction="Compile" name="src/crypto/tls/CipherSuite.cs" /> + <File subtype="Code" buildaction="Compile" name="src/crypto/tls/SignatureAlgorithm.cs" /> + <File subtype="Code" buildaction="Compile" name="src/crypto/tls/SignatureAndHashAlgorithm.cs" /> <File subtype="Code" buildaction="Compile" name="src/crypto/tls/TlsDheKeyExchange.cs" /> <File subtype="Code" buildaction="Compile" name="src/crypto/tls/TlsDsaSigner.cs" /> <File subtype="Code" buildaction="Compile" name="src/crypto/tls/TlsECDsaSigner.cs" /> diff --git a/crypto/src/crypto/tls/AlertDescription.cs b/crypto/src/crypto/tls/AlertDescription.cs index e1229a4a3..e09da6cab 100644 --- a/crypto/src/crypto/tls/AlertDescription.cs +++ b/crypto/src/crypto/tls/AlertDescription.cs @@ -1,47 +1,217 @@ namespace Org.BouncyCastle.Crypto.Tls { - /// <summary> - /// RFC 2246 7.2 - /// </summary> - public enum AlertDescription : byte - { - close_notify = 0, - unexpected_message = 10, - bad_record_mac = 20, - decryption_failed = 21, - record_overflow = 22, - decompression_failure = 30, - handshake_failure = 40, - /* 41 is not defined, for historical reasons */ - bad_certificate = 42, - unsupported_certificate = 43, - certificate_revoked = 44, - certificate_expired = 45, - certificate_unknown = 46, - illegal_parameter = 47, - unknown_ca = 48, - access_denied = 49, - decode_error = 50, - decrypt_error = 51, - export_restriction = 60, - protocol_version = 70, - insufficient_security = 71, - internal_error = 80, - user_canceled = 90, - no_renegotiation = 100, - - /* - * RFC 3546 - */ - unsupported_extension = 110, - certificate_unobtainable = 111, - unrecognized_name = 112, - bad_certificate_status_response = 113, - bad_certificate_hash_value = 114, - - /* - * RFC 4279 - */ - unknown_psk_identity = 115, - } + /// <summary> + /// RFC 5246 7.2 + /// </summary> + public abstract class AlertDescription + { + /** + * This message notifies the recipient that the sender will not send any more messages on this + * connection. Note that as of TLS 1.1, failure to properly close a connection no longer + * requires that a session not be resumed. This is a change from TLS 1.0 ("The session becomes + * unresumable if any connection is terminated without proper close_notify messages with level + * equal to warning.") to conform with widespread implementation practice. + */ + public const byte close_notify = 0; + + /** + * An inappropriate message was received. This alert is always fatal and should never be + * observed in communication between proper implementations. + */ + public const byte unexpected_message = 10; + + /** + * This alert is returned if a record is received with an incorrect MAC. This alert also MUST be + * returned if an alert is sent because a TLSCiphertext decrypted in an invalid way: either it + * wasn't an even multiple of the block length, or its padding values, when checked, weren't + * correct. This message is always fatal and should never be observed in communication between + * proper implementations (except when messages were corrupted in the network). + */ + public const byte bad_record_mac = 20; + + /** + * This alert was used in some earlier versions of TLS, and may have permitted certain attacks + * against the CBC mode [CBCATT]. It MUST NOT be sent by compliant implementations. + */ + public const byte decryption_failed = 21; + + /** + * A TLSCiphertext record was received that had a length more than 2^14+2048 bytes, or a record + * decrypted to a TLSCompressed record with more than 2^14+1024 bytes. This message is always + * fatal and should never be observed in communication between proper implementations (except + * when messages were corrupted in the network). + */ + public const byte record_overflow = 22; + + /** + * The decompression function received improper input (e.g., data that would expand to excessive + * length). This message is always fatal and should never be observed in communication between + * proper implementations. + */ + public const byte decompression_failure = 30; + + /** + * Reception of a handshake_failure alert message indicates that the sender was unable to + * negotiate an acceptable set of security parameters given the options available. This is a + * fatal error. + */ + public const byte handshake_failure = 40; + + /** + * This alert was used in SSLv3 but not any version of TLS. It MUST NOT be sent by compliant + * implementations. + */ + public const byte no_certificate = 41; + + /** + * A certificate was corrupt, contained signatures that did not verify correctly, etc. + */ + public const byte bad_certificate = 42; + + /** + * A certificate was of an unsupported type. + */ + public const byte unsupported_certificate = 43; + + /** + * A certificate was revoked by its signer. + */ + public const byte certificate_revoked = 44; + + /** + * A certificate has expired or is not currently valid. + */ + public const byte certificate_expired = 45; + + /** + * Some other (unspecified) issue arose in processing the certificate, rendering it + * unacceptable. + */ + public const byte certificate_unknown = 46; + + /** + * A field in the handshake was out of range or inconsistent with other fields. This message is + * always fatal. + */ + public const byte illegal_parameter = 47; + + /** + * A valid certificate chain or partial chain was received, but the certificate was not accepted + * because the CA certificate could not be located or couldn't be matched with a known, trusted + * CA. This message is always fatal. + */ + public const byte unknown_ca = 48; + + /** + * A valid certificate was received, but when access control was applied, the sender decided not + * to proceed with negotiation. This message is always fatal. + */ + public const byte access_denied = 49; + + /** + * A message could not be decoded because some field was out of the specified range or the + * length of the message was incorrect. This message is always fatal and should never be + * observed in communication between proper implementations (except when messages were corrupted + * in the network). + */ + public const byte decode_error = 50; + + /** + * A handshake cryptographic operation failed, including being unable to correctly verify a + * signature or validate a Finished message. This message is always fatal. + */ + public const byte decrypt_error = 51; + + /** + * This alert was used in some earlier versions of TLS. It MUST NOT be sent by compliant + * implementations. + */ + public const byte export_restriction = 60; + + /** + * The protocol version the client has attempted to negotiate is recognized but not supported. + * (For example, old protocol versions might be avoided for security reasons.) This message is + * always fatal. + */ + public const byte protocol_version = 70; + + /** + * Returned instead of handshake_failure when a negotiation has failed specifically because the + * server requires ciphers more secure than those supported by the client. This message is + * always fatal. + */ + public const byte insufficient_security = 71; + + /** + * An internal error unrelated to the peer or the correctness of the protocol (such as a memory + * allocation failure) makes it impossible to continue. This message is always fatal. + */ + public const byte internal_error = 80; + + /** + * This handshake is being canceled for some reason unrelated to a protocol failure. If the user + * cancels an operation after the handshake is complete, just closing the connection by sending + * a close_notify is more appropriate. This alert should be followed by a close_notify. This + * message is generally a warning. + */ + public const byte user_canceled = 90; + + /** + * Sent by the client in response to a hello request or by the server in response to a client + * hello after initial handshaking. Either of these would normally lead to renegotiation; when + * that is not appropriate, the recipient should respond with this alert. At that point, the + * original requester can decide whether to proceed with the connection. One case where this + * would be appropriate is where a server has spawned a process to satisfy a request; the + * process might receive security parameters (key length, authentication, etc.) at startup, and + * it might be difficult to communicate changes to these parameters after that point. This + * message is always a warning. + */ + public const byte no_renegotiation = 100; + + /** + * Sent by clients that receive an extended server hello containing an extension that they did + * not put in the corresponding client hello. This message is always fatal. + */ + public const byte unsupported_extension = 110; + + /* + * RFC 3546 + */ + + /** + * This alert is sent by servers who are unable to retrieve a certificate chain from the URL + * supplied by the client (see Section 3.3). This message MAY be fatal - for example if client + * authentication is required by the server for the handshake to continue and the server is + * unable to retrieve the certificate chain, it may send a fatal alert. + */ + public const byte certificate_unobtainable = 111; + + /** + * This alert is sent by servers that receive a server_name extension request, but do not + * recognize the server name. This message MAY be fatal. + */ + public const byte unrecognized_name = 112; + + /** + * This alert is sent by clients that receive an invalid certificate status response (see + * Section 3.6). This message is always fatal. + */ + public const byte bad_certificate_status_response = 113; + + /** + * This alert is sent by servers when a certificate hash does not match a client provided + * certificate_hash. This message is always fatal. + */ + public const byte bad_certificate_hash_value = 114; + + /* + * RFC 4279 + */ + + /** + * If the server does not recognize the PSK identity, it MAY respond with an + * "unknown_psk_identity" alert message. + */ + public const byte unknown_psk_identity = 115; + } } diff --git a/crypto/src/crypto/tls/AlertLevel.cs b/crypto/src/crypto/tls/AlertLevel.cs index afb04308b..d77251dfb 100644 --- a/crypto/src/crypto/tls/AlertLevel.cs +++ b/crypto/src/crypto/tls/AlertLevel.cs @@ -1,11 +1,11 @@ namespace Org.BouncyCastle.Crypto.Tls { - /// <summary> - /// RFC 2246 7.2 - /// </summary> - public enum AlertLevel : byte - { - warning = 1, - fatal = 2, - } + /// <summary> + /// RFC 5246 7.2 + /// </summary> + public abstract class AlertLevel + { + public const byte warning = 1; + public const byte fatal = 2; + } } diff --git a/crypto/src/crypto/tls/ByteQueue.cs b/crypto/src/crypto/tls/ByteQueue.cs index c3ce91402..f9398bbaf 100644 --- a/crypto/src/crypto/tls/ByteQueue.cs +++ b/crypto/src/crypto/tls/ByteQueue.cs @@ -68,13 +68,13 @@ namespace Org.BouncyCastle.Crypto.Tls int len, int skip) { - if ((available - skip) < len) + if ((buf.Length - offset) < len) { - throw new TlsException("Not enough data to read"); + throw new ArgumentException("Buffer size of " + buf.Length + " is too small for a read of " + len + " bytes"); } - if ((buf.Length - offset) < len) + if ((available - skip) < len) { - throw new TlsException("Buffer size of " + buf.Length + " is too small for a read of " + len + " bytes"); + throw new InvalidOperationException("Not enough data to read"); } Array.Copy(databuf, skipped + skip, buf, offset, len); } @@ -115,7 +115,7 @@ namespace Org.BouncyCastle.Crypto.Tls { if (i > available) { - throw new TlsException("Cannot remove " + i + " bytes, only got " + available); + throw new InvalidOperationException("Cannot remove " + i + " bytes, only got " + available); } /* diff --git a/crypto/src/crypto/tls/Certificate.cs b/crypto/src/crypto/tls/Certificate.cs index e4df041e2..95050abcd 100644 --- a/crypto/src/crypto/tls/Certificate.cs +++ b/crypto/src/crypto/tls/Certificate.cs @@ -8,104 +8,136 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Crypto.Tls { - /** - * A representation for a certificate chain. - */ - public class Certificate - { - public static readonly Certificate EmptyChain = new Certificate(new X509CertificateStructure[0]); - - /** - * The certificates. - */ - internal X509CertificateStructure[] certs; - - /** - * Parse the ServerCertificate message. - * - * @param inStr The stream where to parse from. - * @return A Certificate object with the certs, the server has sended. - * @throws IOException If something goes wrong during parsing. - */ - internal static Certificate Parse( - Stream inStr) - { - int left = TlsUtilities.ReadUint24(inStr); - if (left == 0) - { - return EmptyChain; - } - IList tmp = Platform.CreateArrayList(); - while (left > 0) - { - int size = TlsUtilities.ReadUint24(inStr); - left -= 3 + size; - byte[] buf = new byte[size]; - TlsUtilities.ReadFully(buf, inStr); - MemoryStream bis = new MemoryStream(buf, false); - Asn1Object o = Asn1Object.FromStream(bis); - tmp.Add(X509CertificateStructure.GetInstance(o)); - if (bis.Position < bis.Length) - { - throw new ArgumentException("Sorry, there is garbage data left after the certificate"); - } - } - X509CertificateStructure[] certs = new X509CertificateStructure[tmp.Count]; - for (int i = 0; i < tmp.Count; ++i) + /** + * Parsing and encoding of a <i>Certificate</i> struct from RFC 4346. + * <p/> + * <pre> + * opaque ASN.1Cert<2^24-1>; + * + * struct { + * ASN.1Cert certificate_list<0..2^24-1>; + * } Certificate; + * </pre> + * + * @see org.bouncycastle.asn1.x509.Certificate + */ + public class Certificate + { + public static readonly Certificate EmptyChain = new Certificate(new X509CertificateStructure[0]); + + /** + * The certificates. + */ + protected readonly X509CertificateStructure[] mCertificateList; + + public Certificate(X509CertificateStructure[] certificateList) + { + if (certificateList == null) + throw new ArgumentNullException("certificateList"); + + this.mCertificateList = certificateList; + } + + /// <returns>An array which contains the certs, this chain contains.</returns> + [Obsolete("Use 'GetCertificateList' instead")] + public virtual X509CertificateStructure[] GetCerts() + { + return GetCertificateList(); + } + + /** + * @return an array of {@link org.bouncycastle.asn1.x509.Certificate} representing a certificate + * chain. + */ + public virtual X509CertificateStructure[] GetCertificateList() + { + return CloneCertificateList(); + } + + public virtual X509CertificateStructure GetCertificateAt(int index) + { + return mCertificateList[index]; + } + + public virtual int Length + { + get { return mCertificateList.Length; } + } + + /** + * @return <code>true</code> if this certificate chain contains no certificates, or + * <code>false</code> otherwise. + */ + public virtual bool IsEmpty + { + get { return mCertificateList.Length == 0; } + } + + /** + * Encode this {@link Certificate} to a {@link Stream}. + * + * @param output the {@link Stream} to encode to. + * @throws IOException + */ + public virtual void Encode(Stream output) + { + IList derEncodings = Platform.CreateArrayList(mCertificateList.Length); + + int totalLength = 0; + foreach (Asn1Encodable asn1Cert in mCertificateList) + { + byte[] derEncoding = asn1Cert.GetEncoded(Asn1Encodable.Der); + derEncodings.Add(derEncoding); + totalLength += derEncoding.Length + 3; + } + + TlsUtilities.CheckUint24(totalLength); + TlsUtilities.WriteUint24(totalLength, output); + + foreach (byte[] derEncoding in derEncodings) + { + TlsUtilities.WriteOpaque24(derEncoding, output); + } + } + + /** + * Parse a {@link Certificate} from a {@link Stream}. + * + * @param input the {@link Stream} to parse from. + * @return a {@link Certificate} object. + * @throws IOException + */ + public static Certificate Parse(Stream input) + { + int totalLength = TlsUtilities.ReadUint24(input); + if (totalLength == 0) { - certs[i] = (X509CertificateStructure)tmp[i]; + return EmptyChain; } - return new Certificate(certs); - } - - /** - * Encodes version of the ClientCertificate message - * - * @param outStr stream to write the message to - * @throws IOException If something goes wrong - */ - internal void Encode( - Stream outStr) - { - IList encCerts = Platform.CreateArrayList(); - int totalSize = 0; - foreach (X509CertificateStructure cert in certs) - { - byte[] encCert = cert.GetEncoded(Asn1Encodable.Der); - encCerts.Add(encCert); - totalSize += encCert.Length + 3; - } - - TlsUtilities.WriteUint24(totalSize, outStr); - - foreach (byte[] encCert in encCerts) - { - TlsUtilities.WriteOpaque24(encCert, outStr); - } - } - - /** - * Private constructor from a cert array. - * - * @param certs The certs the chain should contain. - */ - public Certificate(X509CertificateStructure[] certs) - { - if (certs == null) - throw new ArgumentNullException("certs"); - - this.certs = certs; - } - - /// <returns>An array which contains the certs, this chain contains.</returns> - public X509CertificateStructure[] GetCerts() - { - return (X509CertificateStructure[]) certs.Clone(); - } - - public bool IsEmpty - { - get { return certs.Length == 0; } - } - } + + byte[] certListData = TlsUtilities.ReadFully(totalLength, input); + + MemoryStream buf = new MemoryStream(certListData, false); + + IList certificate_list = Platform.CreateArrayList(); + while (buf.Position < buf.Length) + { + byte[] derEncoding = TlsUtilities.ReadOpaque24(buf); + Asn1Object asn1Cert = TlsUtilities.ReadDerObject(derEncoding); + certificate_list.Add(X509CertificateStructure.GetInstance(asn1Cert)); + } + + X509CertificateStructure[] certificateList = new X509CertificateStructure[certificate_list.Count]; + for (int i = 0; i < certificate_list.Count; ++i) + { + certificateList[i] = (X509CertificateStructure)certificate_list[i]; + } + return new Certificate(certificateList); + } + + protected virtual X509CertificateStructure[] CloneCertificateList() + { + return (X509CertificateStructure[])mCertificateList.Clone(); + } + } } diff --git a/crypto/src/crypto/tls/CertificateRequest.cs b/crypto/src/crypto/tls/CertificateRequest.cs index 49d8ba6fb..db72a0fc1 100644 --- a/crypto/src/crypto/tls/CertificateRequest.cs +++ b/crypto/src/crypto/tls/CertificateRequest.cs @@ -1,28 +1,158 @@ using System; using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Crypto.Tls { - public class CertificateRequest - { - private ClientCertificateType[] certificateTypes; - private IList certificateAuthorities; - - public CertificateRequest(ClientCertificateType[] certificateTypes, IList certificateAuthorities) - { - this.certificateTypes = certificateTypes; - this.certificateAuthorities = certificateAuthorities; - } - - public ClientCertificateType[] CertificateTypes - { - get { return certificateTypes; } - } - - /// <returns>A <see cref="IList"/> of X509Name</returns> - public IList CertificateAuthorities - { - get { return certificateAuthorities; } - } - } -} \ No newline at end of file + /** + * Parsing and encoding of a <i>CertificateRequest</i> struct from RFC 4346. + * <p/> + * <pre> + * struct { + * ClientCertificateType certificate_types<1..2^8-1>; + * DistinguishedName certificate_authorities<3..2^16-1>; + * } CertificateRequest; + * </pre> + * + * @see ClientCertificateType + * @see X509Name + */ + public class CertificateRequest + { + protected readonly byte[] mCertificateTypes; + protected readonly IList mSupportedSignatureAlgorithms; + protected readonly IList mCertificateAuthorities; + + /** + * @param certificateTypes see {@link ClientCertificateType} for valid constants. + * @param certificateAuthorities an {@link IList} of {@link X509Name}. + */ + public CertificateRequest(byte[] certificateTypes, IList supportedSignatureAlgorithms, + IList certificateAuthorities) + { + this.mCertificateTypes = certificateTypes; + this.mSupportedSignatureAlgorithms = supportedSignatureAlgorithms; + this.mCertificateAuthorities = certificateAuthorities; + } + + /** + * @return an array of certificate types + * @see {@link ClientCertificateType} + */ + public virtual byte[] CertificateTypes + { + get { return mCertificateTypes; } + } + + /** + * @return an {@link IList} of {@link SignatureAndHashAlgorithm} (or null before TLS 1.2). + */ + public virtual IList SupportedSignatureAlgorithms + { + get { return mSupportedSignatureAlgorithms; } + } + + /** + * @return an {@link IList} of {@link X509Name} + */ + public virtual IList CertificateAuthorities + { + get { return mCertificateAuthorities; } + } + + /** + * Encode this {@link CertificateRequest} to a {@link Stream}. + * + * @param output the {@link Stream} to encode to. + * @throws IOException + */ + public virtual void Encode(Stream output) + { + if (mCertificateTypes == null || mCertificateTypes.Length == 0) + { + TlsUtilities.WriteUint8(0, output); + } + else + { + TlsUtilities.WriteUint8ArrayWithUint8Length(mCertificateTypes, output); + } + + if (mSupportedSignatureAlgorithms != null) + { + // TODO Check whether SignatureAlgorithm.anonymous is allowed here + TlsUtilities.EncodeSupportedSignatureAlgorithms(mSupportedSignatureAlgorithms, false, output); + } + + if (mCertificateAuthorities == null || mCertificateAuthorities.Count < 1) + { + TlsUtilities.WriteUint16(0, output); + } + else + { + IList derEncodings = Platform.CreateArrayList(mCertificateAuthorities.Count); + + int totalLength = 0; + foreach (Asn1Encodable certificateAuthority in mCertificateAuthorities) + { + byte[] derEncoding = certificateAuthority.GetEncoded(Asn1Encodable.Der); + derEncodings.Add(derEncoding); + totalLength += derEncoding.Length; + } + + TlsUtilities.CheckUint16(totalLength); + TlsUtilities.WriteUint16(totalLength, output); + + foreach (byte[] derEncoding in derEncodings) + { + output.Write(derEncoding, 0, derEncoding.Length); + } + } + } + + /** + * Parse a {@link CertificateRequest} from a {@link Stream}. + * + * @param context + * the {@link TlsContext} of the current connection. + * @param input + * the {@link Stream} to parse from. + * @return a {@link CertificateRequest} object. + * @throws IOException + */ + public static CertificateRequest Parse(//TlsContext context, + Stream input) + { + int numTypes = TlsUtilities.ReadUint8(input); + byte[] certificateTypes = new byte[numTypes]; + for (int i = 0; i < numTypes; ++i) + { + certificateTypes[i] = TlsUtilities.ReadUint8(input); + } + + // TODO Add TLS 1.2 support here + IList supportedSignatureAlgorithms = null; + //if (TlsUtilities.IsTLSv12(context)) + //{ + // // TODO Check whether SignatureAlgorithm.anonymous is allowed here + // supportedSignatureAlgorithms = TlsUtilities.ParseSupportedSignatureAlgorithms(false, input); + //} + + IList certificateAuthorities = Platform.CreateArrayList(); + byte[] certAuthData = TlsUtilities.ReadOpaque16(input); + MemoryStream bis = new MemoryStream(certAuthData, false); + while (bis.Position < bis.Length) + { + byte[] derEncoding = TlsUtilities.ReadOpaque16(bis); + Asn1Object asn1 = TlsUtilities.ReadDerObject(derEncoding); + // TODO Switch to X500Name when available + certificateAuthorities.Add(X509Name.GetInstance(asn1)); + } + + return new CertificateRequest(certificateTypes, supportedSignatureAlgorithms, certificateAuthorities); + } + } +} diff --git a/crypto/src/crypto/tls/ClientCertificateType.cs b/crypto/src/crypto/tls/ClientCertificateType.cs index 58f5d4276..a291a46e6 100644 --- a/crypto/src/crypto/tls/ClientCertificateType.cs +++ b/crypto/src/crypto/tls/ClientCertificateType.cs @@ -1,20 +1,23 @@ namespace Org.BouncyCastle.Crypto.Tls { - /// <summary> - /// RFC 2246 7.4.4 - /// </summary> - public enum ClientCertificateType : byte - { - rsa_sign = 1, - dss_sign = 2, - rsa_fixed_dh = 3, - dss_fixed_dh = 4, + public abstract class ClientCertificateType + { + /* + * RFC 4346 7.4.4 + */ + public const byte rsa_sign = 1; + public const byte dss_sign = 2; + public const byte rsa_fixed_dh = 3; + public const byte dss_fixed_dh = 4; + public const byte rsa_ephemeral_dh_RESERVED = 5; + public const byte dss_ephemeral_dh_RESERVED = 6; + public const byte fortezza_dms_RESERVED = 20; - /* - * RFC 4492 5.5 - */ - ecdsa_sign = 64, - rsa_fixed_ecdh = 65, - ecdsa_fixed_ecdh = 66, - } -} \ No newline at end of file + /* + * RFC 4492 5.5 + */ + public const byte ecdsa_sign = 64; + public const byte rsa_fixed_ecdh = 65; + public const byte ecdsa_fixed_ecdh = 66; + } +} diff --git a/crypto/src/crypto/tls/CompressionMethod.cs b/crypto/src/crypto/tls/CompressionMethod.cs index 4a127a63e..e4ee9666f 100644 --- a/crypto/src/crypto/tls/CompressionMethod.cs +++ b/crypto/src/crypto/tls/CompressionMethod.cs @@ -1,20 +1,22 @@ +using System; + namespace Org.BouncyCastle.Crypto.Tls { - /// <summary> - /// RFC 2246 6.1 - /// </summary> - public enum CompressionMethod : byte - { - NULL = 0, + /// <summary> + /// RFC 2246 6.1 + /// </summary> + public abstract class CompressionMethod + { + public const byte NULL = 0; - /* - * RFC 3749 2 - */ - DEFLATE = 1 + /* + * RFC 3749 2 + */ + public const byte DEFLATE = 1; - /* - * Values from 224 decimal (0xE0) through 255 decimal (0xFF) - * inclusive are reserved for private use. - */ - } + /* + * Values from 224 decimal (0xE0) through 255 decimal (0xFF) + * inclusive are reserved for private use. + */ + } } diff --git a/crypto/src/crypto/tls/DefaultTlsAgreementCredentials.cs b/crypto/src/crypto/tls/DefaultTlsAgreementCredentials.cs index 130f4c589..2bd2f40bf 100644 --- a/crypto/src/crypto/tls/DefaultTlsAgreementCredentials.cs +++ b/crypto/src/crypto/tls/DefaultTlsAgreementCredentials.cs @@ -22,7 +22,7 @@ namespace Org.BouncyCastle.Crypto.Tls { throw new ArgumentNullException("clientCertificate"); } - if (clientCertificate.certs.Length == 0) + if (clientCertificate.Length == 0) { throw new ArgumentException("cannot be empty", "clientCertificate"); } diff --git a/crypto/src/crypto/tls/DefaultTlsClient.cs b/crypto/src/crypto/tls/DefaultTlsClient.cs index 9f30a33f4..2e850e350 100644 --- a/crypto/src/crypto/tls/DefaultTlsClient.cs +++ b/crypto/src/crypto/tls/DefaultTlsClient.cs @@ -11,125 +11,125 @@ using Org.BouncyCastle.Crypto.Parameters; namespace Org.BouncyCastle.Crypto.Tls { - public abstract class DefaultTlsClient - : TlsClient - { - protected TlsCipherFactory cipherFactory; + public abstract class DefaultTlsClient + : TlsClient + { + protected TlsCipherFactory cipherFactory; - protected TlsClientContext context; + protected TlsClientContext context; - protected CompressionMethod selectedCompressionMethod; + protected byte selectedCompressionMethod; protected CipherSuite selectedCipherSuite; - public DefaultTlsClient() - : this(new DefaultTlsCipherFactory()) - { - } + public DefaultTlsClient() + : this(new DefaultTlsCipherFactory()) + { + } - public DefaultTlsClient(TlsCipherFactory cipherFactory) - { - this.cipherFactory = cipherFactory; - } + public DefaultTlsClient(TlsCipherFactory cipherFactory) + { + this.cipherFactory = cipherFactory; + } - public virtual void Init(TlsClientContext context) - { - this.context = context; - } + public virtual void Init(TlsClientContext context) + { + this.context = context; + } public virtual CipherSuite[] GetCipherSuites() - { - return new CipherSuite[] { - CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA, - CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA, - CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA, - CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA, - CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, - CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, - CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA, - CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA, - CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA, + { + return new CipherSuite[] { + CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA, + CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA, + CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA, + CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA, + CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, + CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, + CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA, + CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA, + CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA, CipherSuite.TLS_RSA_WITH_RC4_128_SHA, - }; - } + }; + } - public virtual CompressionMethod[] GetCompressionMethods() + public virtual byte[] GetCompressionMethods() { - /* - * To offer DEFLATE compression, override this method: - * return new CompressionMethod[] { CompressionMethod.DEFLATE, CompressionMethod.NULL }; - */ + /* + * To offer DEFLATE compression, override this method: + * return new byte[] { CompressionMethod.DEFLATE, CompressionMethod.NULL }; + */ - return new CompressionMethod[] { CompressionMethod.NULL }; + return new byte[] { CompressionMethod.NULL }; } public virtual IDictionary GetClientExtensions() - { - return null; - } + { + return null; + } public virtual void NotifySessionID(byte[] sessionID) - { - // Currently ignored - } + { + // Currently ignored + } public virtual void NotifySelectedCipherSuite(CipherSuite selectedCipherSuite) - { - this.selectedCipherSuite = selectedCipherSuite; - } + { + this.selectedCipherSuite = selectedCipherSuite; + } - public virtual void NotifySelectedCompressionMethod(CompressionMethod selectedCompressionMethod) + public virtual void NotifySelectedCompressionMethod(byte selectedCompressionMethod) { this.selectedCompressionMethod = selectedCompressionMethod; } public virtual void NotifySecureRenegotiation(bool secureRenegotiation) - { - if (!secureRenegotiation) - { - /* - * RFC 5746 3.4. - * If the extension is not present, the server does not support - * secure renegotiation; set secure_renegotiation flag to FALSE. - * In this case, some clients may want to terminate the handshake - * instead of continuing; see Section 4.1 for discussion. - */ + { + if (!secureRenegotiation) + { + /* + * RFC 5746 3.4. + * If the extension is not present, the server does not support + * secure renegotiation; set secure_renegotiation flag to FALSE. + * In this case, some clients may want to terminate the handshake + * instead of continuing; see Section 4.1 for discussion. + */ // throw new TlsFatalAlert(AlertDescription.handshake_failure); - } - } + } + } public virtual void ProcessServerExtensions(IDictionary serverExtensions) - { - } + { + } public virtual TlsKeyExchange GetKeyExchange() - { - switch (selectedCipherSuite) - { - case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA: - case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA: - case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA: + { + switch (selectedCipherSuite) + { + case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA: case CipherSuite.TLS_RSA_WITH_RC4_128_SHA: - return CreateRsaKeyExchange(); + return CreateRsaKeyExchange(); - case CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA: - case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA: - case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA: - return CreateDHKeyExchange(KeyExchangeAlgorithm.DH_DSS); + case CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA: + return CreateDHKeyExchange(KeyExchangeAlgorithm.DH_DSS); - case CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA: - case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA: - case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA: - return CreateDHKeyExchange(KeyExchangeAlgorithm.DH_RSA); + case CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA: + return CreateDHKeyExchange(KeyExchangeAlgorithm.DH_RSA); - case CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA: - case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA: - case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA: - return CreateDheKeyExchange(KeyExchangeAlgorithm.DHE_DSS); + case CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA: + return CreateDheKeyExchange(KeyExchangeAlgorithm.DHE_DSS); - case CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: - case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA: - case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA: - return CreateDheKeyExchange(KeyExchangeAlgorithm.DHE_RSA); + case CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA: + return CreateDheKeyExchange(KeyExchangeAlgorithm.DHE_RSA); case CipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA: case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA: @@ -155,54 +155,54 @@ namespace Org.BouncyCastle.Crypto.Tls case CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA: return CreateECDheKeyExchange(KeyExchangeAlgorithm.ECDHE_RSA); - default: - /* - * Note: internal error here; the TlsProtocolHandler verifies that the - * server-selected cipher suite was in the list of client-offered cipher - * suites, so if we now can't produce an implementation, we shouldn't have - * offered it! - */ - throw new TlsFatalAlert(AlertDescription.internal_error); - } - } - - public abstract TlsAuthentication GetAuthentication(); - - public virtual TlsCompression GetCompression() - { - switch (selectedCompressionMethod) - { - case CompressionMethod.NULL: - return new TlsNullCompression(); - - case CompressionMethod.DEFLATE: - return new TlsDeflateCompression(); - - default: - /* - * Note: internal error here; the TlsProtocolHandler verifies that the - * server-selected compression method was in the list of client-offered compression - * methods, so if we now can't produce an implementation, we shouldn't have - * offered it! - */ - throw new TlsFatalAlert(AlertDescription.internal_error); - } - } - - public virtual TlsCipher GetCipher() - { - switch (selectedCipherSuite) - { - case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA: - case CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA: - case CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA: - case CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA: - case CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: + default: + /* + * Note: internal error here; the TlsProtocolHandler verifies that the + * server-selected cipher suite was in the list of client-offered cipher + * suites, so if we now can't produce an implementation, we shouldn't have + * offered it! + */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public abstract TlsAuthentication GetAuthentication(); + + public virtual TlsCompression GetCompression() + { + switch (selectedCompressionMethod) + { + case CompressionMethod.NULL: + return new TlsNullCompression(); + + case CompressionMethod.DEFLATE: + return new TlsDeflateCompression(); + + default: + /* + * Note: internal error here; the TlsProtocolHandler verifies that the + * server-selected compression method was in the list of client-offered compression + * methods, so if we now can't produce an implementation, we shouldn't have + * offered it! + */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public virtual TlsCipher GetCipher() + { + switch (selectedCipherSuite) + { + case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: case CipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA: case CipherSuite.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA: case CipherSuite.TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA: case CipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: - return cipherFactory.CreateCipher(context, EncryptionAlgorithm.cls_3DES_EDE_CBC, DigestAlgorithm.SHA); + return cipherFactory.CreateCipher(context, EncryptionAlgorithm.cls_3DES_EDE_CBC, DigestAlgorithm.SHA); case CipherSuite.TLS_RSA_WITH_RC4_128_SHA: case CipherSuite.TLS_ECDH_ECDSA_WITH_RC4_128_SHA: @@ -212,47 +212,47 @@ namespace Org.BouncyCastle.Crypto.Tls return cipherFactory.CreateCipher(context, EncryptionAlgorithm.RC4_128, DigestAlgorithm.SHA); case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA: - case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA: - case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA: - case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA: - case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA: case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA: case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA: case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: - return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_128_CBC, DigestAlgorithm.SHA); + return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_128_CBC, DigestAlgorithm.SHA); - case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA: - case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA: - case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA: - case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA: - case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA: case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA: case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA: case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: - return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_256_CBC, DigestAlgorithm.SHA); - - default: - /* - * Note: internal error here; the TlsProtocolHandler verifies that the - * server-selected cipher suite was in the list of client-offered cipher - * suites, so if we now can't produce an implementation, we shouldn't have - * offered it! - */ - throw new TlsFatalAlert(AlertDescription.internal_error); - } - } - - protected virtual TlsKeyExchange CreateDHKeyExchange(KeyExchangeAlgorithm keyExchange) - { - return new TlsDHKeyExchange(context, keyExchange); - } + return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_256_CBC, DigestAlgorithm.SHA); + + default: + /* + * Note: internal error here; the TlsProtocolHandler verifies that the + * server-selected cipher suite was in the list of client-offered cipher + * suites, so if we now can't produce an implementation, we shouldn't have + * offered it! + */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + protected virtual TlsKeyExchange CreateDHKeyExchange(KeyExchangeAlgorithm keyExchange) + { + return new TlsDHKeyExchange(context, keyExchange); + } protected virtual TlsKeyExchange CreateDheKeyExchange(KeyExchangeAlgorithm keyExchange) - { - return new TlsDheKeyExchange(context, keyExchange); - } + { + return new TlsDheKeyExchange(context, keyExchange); + } protected virtual TlsKeyExchange CreateECDHKeyExchange(KeyExchangeAlgorithm keyExchange) { @@ -265,8 +265,8 @@ namespace Org.BouncyCastle.Crypto.Tls } protected virtual TlsKeyExchange CreateRsaKeyExchange() - { - return new TlsRsaKeyExchange(context); - } + { + return new TlsRsaKeyExchange(context); + } } } diff --git a/crypto/src/crypto/tls/DefaultTlsSignerCredentials.cs b/crypto/src/crypto/tls/DefaultTlsSignerCredentials.cs index 86c9d1a18..2c5aa3524 100644 --- a/crypto/src/crypto/tls/DefaultTlsSignerCredentials.cs +++ b/crypto/src/crypto/tls/DefaultTlsSignerCredentials.cs @@ -20,7 +20,7 @@ namespace Org.BouncyCastle.Crypto.Tls { throw new ArgumentNullException("clientCertificate"); } - if (clientCertificate.certs.Length == 0) + if (clientCertificate.Length == 0) { throw new ArgumentException("cannot be empty", "clientCertificate"); } diff --git a/crypto/src/crypto/tls/HashAlgorithm.cs b/crypto/src/crypto/tls/HashAlgorithm.cs new file mode 100644 index 000000000..41818ca2c --- /dev/null +++ b/crypto/src/crypto/tls/HashAlgorithm.cs @@ -0,0 +1,18 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Tls +{ + /** + * RFC 5246 7.4.1.4.1 + */ + public abstract class HashAlgorithm + { + public const byte none = 0; + public const byte md5 = 1; + public const byte sha1 = 2; + public const byte sha224 = 3; + public const byte sha256 = 4; + public const byte sha384 = 5; + public const byte sha512 = 6; + } +} diff --git a/crypto/src/crypto/tls/LegacyTlsAuthentication.cs b/crypto/src/crypto/tls/LegacyTlsAuthentication.cs index 395f94208..bce31c0b0 100644 --- a/crypto/src/crypto/tls/LegacyTlsAuthentication.cs +++ b/crypto/src/crypto/tls/LegacyTlsAuthentication.cs @@ -2,29 +2,29 @@ using System; namespace Org.BouncyCastle.Crypto.Tls { - /// <summary> - /// A temporary class to wrap old CertificateVerifyer stuff for new TlsAuthentication. - /// </summary> - [Obsolete] - public class LegacyTlsAuthentication - : TlsAuthentication - { - protected ICertificateVerifyer verifyer; + /// <summary> + /// A temporary class to wrap old CertificateVerifyer stuff for new TlsAuthentication. + /// </summary> + [Obsolete] + public class LegacyTlsAuthentication + : TlsAuthentication + { + protected ICertificateVerifyer verifyer; - public LegacyTlsAuthentication(ICertificateVerifyer verifyer) - { - this.verifyer = verifyer; - } + public LegacyTlsAuthentication(ICertificateVerifyer verifyer) + { + this.verifyer = verifyer; + } - public virtual void NotifyServerCertificate(Certificate serverCertificate) - { - if (!this.verifyer.IsValid(serverCertificate.GetCerts())) - throw new TlsFatalAlert(AlertDescription.user_canceled); - } + public virtual void NotifyServerCertificate(Certificate serverCertificate) + { + if (!this.verifyer.IsValid(serverCertificate.GetCertificateList())) + throw new TlsFatalAlert(AlertDescription.user_canceled); + } - public virtual TlsCredentials GetClientCredentials(CertificateRequest certificateRequest) - { - return null; - } - } + public virtual TlsCredentials GetClientCredentials(CertificateRequest certificateRequest) + { + return null; + } + } } diff --git a/crypto/src/crypto/tls/PskTlsClient.cs b/crypto/src/crypto/tls/PskTlsClient.cs index 9db7d7d90..cb42c31d8 100644 --- a/crypto/src/crypto/tls/PskTlsClient.cs +++ b/crypto/src/crypto/tls/PskTlsClient.cs @@ -3,168 +3,168 @@ using System.Collections; namespace Org.BouncyCastle.Crypto.Tls { - public abstract class PskTlsClient - :TlsClient - { - protected TlsCipherFactory cipherFactory; - protected TlsPskIdentity pskIdentity; + public abstract class PskTlsClient + :TlsClient + { + protected TlsCipherFactory cipherFactory; + protected TlsPskIdentity pskIdentity; protected TlsClientContext context; - protected CompressionMethod selectedCompressionMethod; - protected CipherSuite selectedCipherSuite; + protected byte selectedCompressionMethod; + protected CipherSuite selectedCipherSuite; public PskTlsClient(TlsPskIdentity pskIdentity) - : this(new DefaultTlsCipherFactory(), pskIdentity) - { - } + : this(new DefaultTlsCipherFactory(), pskIdentity) + { + } public PskTlsClient(TlsCipherFactory cipherFactory, TlsPskIdentity pskIdentity) - { - this.cipherFactory = cipherFactory; - this.pskIdentity = pskIdentity; - } + { + this.cipherFactory = cipherFactory; + this.pskIdentity = pskIdentity; + } public virtual void Init(TlsClientContext context) - { - this.context = context; - } + { + this.context = context; + } public virtual CipherSuite[] GetCipherSuites() - { - return new CipherSuite[] { - CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA, - CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA, - CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA, - CipherSuite.TLS_DHE_PSK_WITH_RC4_128_SHA, - CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA, - CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA, - CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA, - CipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA, - CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA, - CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA, - CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA, - CipherSuite.TLS_PSK_WITH_RC4_128_SHA, - }; - } + { + return new CipherSuite[] { + CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA, + CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA, + CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA, + CipherSuite.TLS_DHE_PSK_WITH_RC4_128_SHA, + CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA, + CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA, + CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA, + CipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA, + CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA, + CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA, + CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA, + CipherSuite.TLS_PSK_WITH_RC4_128_SHA, + }; + } public virtual IDictionary GetClientExtensions() - { - return null; - } + { + return null; + } - public virtual CompressionMethod[] GetCompressionMethods() - { - return new CompressionMethod[] { CompressionMethod.NULL }; - } + public virtual byte[] GetCompressionMethods() + { + return new byte[] { CompressionMethod.NULL }; + } public virtual void NotifySessionID(byte[] sessionID) - { - // Currently ignored - } + { + // Currently ignored + } public virtual void NotifySelectedCipherSuite(CipherSuite selectedCipherSuite) - { - this.selectedCipherSuite = selectedCipherSuite; - } + { + this.selectedCipherSuite = selectedCipherSuite; + } - public virtual void NotifySelectedCompressionMethod(CompressionMethod selectedCompressionMethod) - { - this.selectedCompressionMethod = selectedCompressionMethod; - } + public virtual void NotifySelectedCompressionMethod(byte selectedCompressionMethod) + { + this.selectedCompressionMethod = selectedCompressionMethod; + } public virtual void NotifySecureRenegotiation(bool secureRenegotiation) - { - if (!secureRenegotiation) - { - /* - * RFC 5746 3.4. If the extension is not present, the server does not support - * secure renegotiation; set secure_renegotiation flag to FALSE. In this case, - * some clients may want to terminate the handshake instead of continuing; see - * Section 4.1 for discussion. - */ + { + if (!secureRenegotiation) + { + /* + * RFC 5746 3.4. If the extension is not present, the server does not support + * secure renegotiation; set secure_renegotiation flag to FALSE. In this case, + * some clients may want to terminate the handshake instead of continuing; see + * Section 4.1 for discussion. + */ // throw new TlsFatalAlert(AlertDescription.handshake_failure); - } - } + } + } public virtual void ProcessServerExtensions(IDictionary serverExtensions) - { - } + { + } public virtual TlsKeyExchange GetKeyExchange() - { - switch (selectedCipherSuite) - { - case CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA: - case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA: - case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA: + { + switch (selectedCipherSuite) + { + case CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA: case CipherSuite.TLS_PSK_WITH_RC4_128_SHA: - return CreatePskKeyExchange(KeyExchangeAlgorithm.PSK); + return CreatePskKeyExchange(KeyExchangeAlgorithm.PSK); case CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA: - case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA: - case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA: case CipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA: return CreatePskKeyExchange(KeyExchangeAlgorithm.RSA_PSK); case CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA: - case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA: - case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA: case CipherSuite.TLS_DHE_PSK_WITH_RC4_128_SHA: return CreatePskKeyExchange(KeyExchangeAlgorithm.DHE_PSK); default: - /* - * Note: internal error here; the TlsProtocolHandler verifies that the - * server-selected cipher suite was in the list of client-offered cipher - * suites, so if we now can't produce an implementation, we shouldn't have - * offered it! - */ - throw new TlsFatalAlert(AlertDescription.internal_error); - } - } + /* + * Note: internal error here; the TlsProtocolHandler verifies that the + * server-selected cipher suite was in the list of client-offered cipher + * suites, so if we now can't produce an implementation, we shouldn't have + * offered it! + */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } public abstract TlsAuthentication GetAuthentication(); public virtual TlsCompression GetCompression() - { - switch (selectedCompressionMethod) - { - case CompressionMethod.NULL: - return new TlsNullCompression(); + { + switch (selectedCompressionMethod) + { + case CompressionMethod.NULL: + return new TlsNullCompression(); default: - /* - * Note: internal error here; the TlsProtocolHandler verifies that the - * server-selected compression method was in the list of client-offered compression - * methods, so if we now can't produce an implementation, we shouldn't have - * offered it! - */ - throw new TlsFatalAlert(AlertDescription.internal_error); - } - } + /* + * Note: internal error here; the TlsProtocolHandler verifies that the + * server-selected compression method was in the list of client-offered compression + * methods, so if we now can't produce an implementation, we shouldn't have + * offered it! + */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } public virtual TlsCipher GetCipher() - { - switch (selectedCipherSuite) - { - case CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA: - case CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA: - case CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA: - return cipherFactory.CreateCipher(context, EncryptionAlgorithm.cls_3DES_EDE_CBC, - DigestAlgorithm.SHA); + { + switch (selectedCipherSuite) + { + case CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA: + return cipherFactory.CreateCipher(context, EncryptionAlgorithm.cls_3DES_EDE_CBC, + DigestAlgorithm.SHA); case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA: - case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA: - case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA: - return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_128_CBC, - DigestAlgorithm.SHA); + case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA: + return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_128_CBC, + DigestAlgorithm.SHA); case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA: - case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA: - case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA: - return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_256_CBC, - DigestAlgorithm.SHA); + case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA: + return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_256_CBC, + DigestAlgorithm.SHA); case CipherSuite.TLS_PSK_WITH_RC4_128_SHA: case CipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA: @@ -173,19 +173,19 @@ namespace Org.BouncyCastle.Crypto.Tls DigestAlgorithm.SHA); default: - /* - * Note: internal error here; the TlsProtocolHandler verifies that the - * server-selected cipher suite was in the list of client-offered cipher - * suites, so if we now can't produce an implementation, we shouldn't have - * offered it! - */ - throw new TlsFatalAlert(AlertDescription.internal_error); - } - } + /* + * Note: internal error here; the TlsProtocolHandler verifies that the + * server-selected cipher suite was in the list of client-offered cipher + * suites, so if we now can't produce an implementation, we shouldn't have + * offered it! + */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } protected virtual TlsKeyExchange CreatePskKeyExchange(KeyExchangeAlgorithm keyExchange) - { - return new TlsPskKeyExchange(context, keyExchange, pskIdentity); - } - } + { + return new TlsPskKeyExchange(context, keyExchange, pskIdentity); + } + } } diff --git a/crypto/src/crypto/tls/SignatureAlgorithm.cs b/crypto/src/crypto/tls/SignatureAlgorithm.cs new file mode 100644 index 000000000..35b961762 --- /dev/null +++ b/crypto/src/crypto/tls/SignatureAlgorithm.cs @@ -0,0 +1,15 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Tls +{ + /** + * RFC 5246 7.4.1.4.1 (in RFC 2246, there were no specific values assigned) + */ + public abstract class SignatureAlgorithm + { + public const byte anonymous = 0; + public const byte rsa = 1; + public const byte dsa = 2; + public const byte ecdsa = 3; + } +} diff --git a/crypto/src/crypto/tls/SignatureAndHashAlgorithm.cs b/crypto/src/crypto/tls/SignatureAndHashAlgorithm.cs new file mode 100644 index 000000000..f74205b62 --- /dev/null +++ b/crypto/src/crypto/tls/SignatureAndHashAlgorithm.cs @@ -0,0 +1,94 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Crypto.Tls +{ + /** + * RFC 5246 7.4.1.4.1 + */ + public class SignatureAndHashAlgorithm + { + protected readonly byte mHash; + protected readonly byte mSignature; + + /** + * @param hash {@link HashAlgorithm} + * @param signature {@link SignatureAlgorithm} + */ + public SignatureAndHashAlgorithm(byte hash, byte signature) + { + if (!TlsUtilities.IsValidUint8(hash)) + { + throw new ArgumentException("should be a uint8", "hash"); + } + if (!TlsUtilities.IsValidUint8(signature)) + { + throw new ArgumentException("should be a uint8", "signature"); + } + if (signature == SignatureAlgorithm.anonymous) + { + throw new ArgumentException("MUST NOT be \"anonymous\"", "signature"); + } + + this.mHash = hash; + this.mSignature = signature; + } + + /** + * @return {@link HashAlgorithm} + */ + public virtual byte Hash + { + get { return mHash; } + } + + /** + * @return {@link SignatureAlgorithm} + */ + public virtual byte Signature + { + get { return mSignature; } + } + + public override bool Equals(object obj) + { + if (!(obj is SignatureAndHashAlgorithm)) + { + return false; + } + SignatureAndHashAlgorithm other = (SignatureAndHashAlgorithm)obj; + return other.Hash == Hash && other.Signature == Signature; + } + + public override int GetHashCode() + { + return ((int)Hash << 16) | (int)Signature; + } + + /** + * Encode this {@link SignatureAndHashAlgorithm} to a {@link Stream}. + * + * @param output the {@link Stream} to encode to. + * @throws IOException + */ + public virtual void Encode(Stream output) + { + TlsUtilities.WriteUint8(Hash, output); + TlsUtilities.WriteUint8(Signature, output); + } + + /** + * Parse a {@link SignatureAndHashAlgorithm} from a {@link Stream}. + * + * @param input the {@link Stream} to parse from. + * @return a {@link SignatureAndHashAlgorithm} object. + * @throws IOException + */ + public static SignatureAndHashAlgorithm Parse(Stream input) + { + byte hash = TlsUtilities.ReadUint8(input); + byte signature = TlsUtilities.ReadUint8(input); + return new SignatureAndHashAlgorithm(hash, signature); + } + } +} diff --git a/crypto/src/crypto/tls/SrpTlsClient.cs b/crypto/src/crypto/tls/SrpTlsClient.cs index 6c2638bb3..f487e9b21 100644 --- a/crypto/src/crypto/tls/SrpTlsClient.cs +++ b/crypto/src/crypto/tls/SrpTlsClient.cs @@ -6,183 +6,183 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Crypto.Tls { - public abstract class SrpTlsClient - : TlsClient - { - protected TlsCipherFactory cipherFactory; - protected byte[] identity; - protected byte[] password; + public abstract class SrpTlsClient + : TlsClient + { + protected TlsCipherFactory cipherFactory; + protected byte[] identity; + protected byte[] password; - protected TlsClientContext context; + protected TlsClientContext context; - protected CompressionMethod selectedCompressionMethod; + protected byte selectedCompressionMethod; protected CipherSuite selectedCipherSuite; - public SrpTlsClient(byte[] identity, byte[] password) - : this(new DefaultTlsCipherFactory(), identity, password) - { - } - - public SrpTlsClient(TlsCipherFactory cipherFactory, byte[] identity, byte[] password) - { - this.cipherFactory = cipherFactory; - this.identity = Arrays.Clone(identity); - this.password = Arrays.Clone(password); - } - - public virtual void Init(TlsClientContext context) - { - this.context = context; - } - - public virtual CipherSuite[] GetCipherSuites() - { - return new CipherSuite[] { - CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA, - CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA, - CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA, - CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA, - CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA, - CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA, - CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA, - CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA, - CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA, - }; - } - - public virtual IDictionary GetClientExtensions() - { - IDictionary clientExtensions = Platform.CreateHashtable(); - - MemoryStream srpData = new MemoryStream(); - TlsUtilities.WriteOpaque8(this.identity, srpData); - clientExtensions[ExtensionType.srp] = srpData.ToArray(); - - return clientExtensions; - } - - public virtual CompressionMethod[] GetCompressionMethods() - { - return new CompressionMethod[] { CompressionMethod.NULL }; - } - - public virtual void NotifySessionID(byte[] sessionID) - { - // Currently ignored - } - - public virtual void NotifySelectedCipherSuite(CipherSuite selectedCipherSuite) - { - this.selectedCipherSuite = selectedCipherSuite; - } - - public virtual void NotifySelectedCompressionMethod(CompressionMethod selectedCompressionMethod) - { + public 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 byte[] GetCompressionMethods() + { + return new byte[] { CompressionMethod.NULL }; + } + + public virtual void NotifySessionID(byte[] sessionID) + { + // Currently ignored + } + + public virtual void NotifySelectedCipherSuite(CipherSuite selectedCipherSuite) + { + this.selectedCipherSuite = selectedCipherSuite; + } + + public virtual void NotifySelectedCompressionMethod(byte selectedCompressionMethod) + { this.selectedCompressionMethod = selectedCompressionMethod; } - public virtual void NotifySecureRenegotiation(bool secureRenegotiation) - { - if (!secureRenegotiation) - { - /* - * RFC 5746 3.4. If the extension is not present, the server does not support - * secure renegotiation; set secure_renegotiation flag to FALSE. In this case, - * some clients may want to terminate the handshake instead of continuing; see - * Section 4.1 for discussion. - */ + public virtual void NotifySecureRenegotiation(bool secureRenegotiation) + { + if (!secureRenegotiation) + { + /* + * RFC 5746 3.4. If the extension is not present, the server does not support + * secure renegotiation; set secure_renegotiation flag to FALSE. In this case, + * some clients may want to terminate the handshake instead of continuing; see + * Section 4.1 for discussion. + */ // throw new TlsFatalAlert(AlertDescription.handshake_failure); - } - } - - public virtual void ProcessServerExtensions(IDictionary serverExtensions) - { - // There is no server response for the SRP extension - } - - public virtual TlsKeyExchange GetKeyExchange() - { - switch (selectedCipherSuite) - { - case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA: - case CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA: - case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA: - return CreateSrpKeyExchange(KeyExchangeAlgorithm.SRP); - - case CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA: - case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA: - case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA: - return CreateSrpKeyExchange(KeyExchangeAlgorithm.SRP_RSA); - - case CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA: - case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA: - case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA: - return CreateSrpKeyExchange(KeyExchangeAlgorithm.SRP_DSS); - - default: - /* - * Note: internal error here; the TlsProtocolHandler verifies that the - * server-selected cipher suite was in the list of client-offered cipher - * suites, so if we now can't produce an implementation, we shouldn't have - * offered it! - */ - throw new TlsFatalAlert(AlertDescription.internal_error); - } - } - - public abstract TlsAuthentication GetAuthentication(); - - public virtual TlsCompression GetCompression() - { - switch (selectedCompressionMethod) - { - case CompressionMethod.NULL: - return new TlsNullCompression(); - - default: - /* - * Note: internal error here; the TlsProtocolHandler verifies that the - * server-selected compression method was in the list of client-offered compression - * methods, so if we now can't produce an implementation, we shouldn't have - * offered it! - */ - throw new TlsFatalAlert(AlertDescription.internal_error); - } - } - - public virtual TlsCipher GetCipher() - { - switch (selectedCipherSuite) - { - case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA: - case CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA: - case CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA: - return cipherFactory.CreateCipher(context, EncryptionAlgorithm.cls_3DES_EDE_CBC, DigestAlgorithm.SHA); - - case CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA: - case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA: - case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA: - return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_128_CBC, DigestAlgorithm.SHA); - - case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA: - case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA: - case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA: - return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_256_CBC, DigestAlgorithm.SHA); - - default: - /* - * Note: internal error here; the TlsProtocolHandler verifies that the - * server-selected cipher suite was in the list of client-offered cipher - * suites, so if we now can't produce an implementation, we shouldn't have - * offered it! - */ - throw new TlsFatalAlert(AlertDescription.internal_error); - } - } - - protected virtual TlsKeyExchange CreateSrpKeyExchange(KeyExchangeAlgorithm keyExchange) - { - return new TlsSrpKeyExchange(context, keyExchange, identity, password); - } - } + } + } + + public virtual void ProcessServerExtensions(IDictionary serverExtensions) + { + // There is no server response for the SRP extension + } + + public virtual TlsKeyExchange GetKeyExchange() + { + switch (selectedCipherSuite) + { + case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA: + return CreateSrpKeyExchange(KeyExchangeAlgorithm.SRP); + + case CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA: + return CreateSrpKeyExchange(KeyExchangeAlgorithm.SRP_RSA); + + case CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA: + return CreateSrpKeyExchange(KeyExchangeAlgorithm.SRP_DSS); + + default: + /* + * Note: internal error here; the TlsProtocolHandler verifies that the + * server-selected cipher suite was in the list of client-offered cipher + * suites, so if we now can't produce an implementation, we shouldn't have + * offered it! + */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public abstract TlsAuthentication GetAuthentication(); + + public virtual TlsCompression GetCompression() + { + switch (selectedCompressionMethod) + { + case CompressionMethod.NULL: + return new TlsNullCompression(); + + default: + /* + * Note: internal error here; the TlsProtocolHandler verifies that the + * server-selected compression method was in the list of client-offered compression + * methods, so if we now can't produce an implementation, we shouldn't have + * offered it! + */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public virtual TlsCipher GetCipher() + { + switch (selectedCipherSuite) + { + case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA: + return cipherFactory.CreateCipher(context, EncryptionAlgorithm.cls_3DES_EDE_CBC, DigestAlgorithm.SHA); + + case CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA: + return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_128_CBC, DigestAlgorithm.SHA); + + case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA: + return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_256_CBC, DigestAlgorithm.SHA); + + default: + /* + * Note: internal error here; the TlsProtocolHandler verifies that the + * server-selected cipher suite was in the list of client-offered cipher + * suites, so if we now can't produce an implementation, we shouldn't have + * offered it! + */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + protected virtual TlsKeyExchange CreateSrpKeyExchange(KeyExchangeAlgorithm keyExchange) + { + return new TlsSrpKeyExchange(context, keyExchange, identity, password); + } + } } diff --git a/crypto/src/crypto/tls/TlsClient.cs b/crypto/src/crypto/tls/TlsClient.cs index eceaa3cd3..d32ac1547 100644 --- a/crypto/src/crypto/tls/TlsClient.cs +++ b/crypto/src/crypto/tls/TlsClient.cs @@ -28,9 +28,9 @@ namespace Org.BouncyCastle.Crypto.Tls /// <returns> /// An array of <see cref="CompressionMethod"/>, each specifying a supported compression method. /// </returns> - CompressionMethod[] GetCompressionMethods(); + byte[] GetCompressionMethods(); - /// <summary> + /// <summary> /// Get the (optional) table of client extensions to be included in (extended) client hello. /// </summary> /// <returns> @@ -69,7 +69,7 @@ namespace Org.BouncyCastle.Crypto.Tls /// <param name="selectedCompressionMethod"> /// A <see cref="CompressionMethod"/> /// </param> - void NotifySelectedCompressionMethod(CompressionMethod selectedCompressionMethod); + void NotifySelectedCompressionMethod(byte selectedCompressionMethod); /// <summary> /// Report whether the server supports secure renegotiation diff --git a/crypto/src/crypto/tls/TlsDHKeyExchange.cs b/crypto/src/crypto/tls/TlsDHKeyExchange.cs index 40ac416e0..465d8c0b2 100644 --- a/crypto/src/crypto/tls/TlsDHKeyExchange.cs +++ b/crypto/src/crypto/tls/TlsDHKeyExchange.cs @@ -9,193 +9,193 @@ using Org.BouncyCastle.Security; namespace Org.BouncyCastle.Crypto.Tls { - /// <summary> - /// TLS 1.0 DH key exchange. - /// </summary> - internal class TlsDHKeyExchange - : TlsKeyExchange - { - protected TlsClientContext context; - protected KeyExchangeAlgorithm keyExchange; - protected TlsSigner tlsSigner; - - protected AsymmetricKeyParameter serverPublicKey = null; - protected DHPublicKeyParameters dhAgreeServerPublicKey = null; - protected TlsAgreementCredentials agreementCredentials; - protected DHPrivateKeyParameters dhAgreeClientPrivateKey = null; - - internal TlsDHKeyExchange(TlsClientContext context, KeyExchangeAlgorithm keyExchange) - { - switch (keyExchange) - { - case KeyExchangeAlgorithm.DH_RSA: - case KeyExchangeAlgorithm.DH_DSS: - this.tlsSigner = null; - break; - case KeyExchangeAlgorithm.DHE_RSA: - this.tlsSigner = new TlsRsaSigner(); - break; - case KeyExchangeAlgorithm.DHE_DSS: - this.tlsSigner = new TlsDssSigner(); - break; - default: - throw new ArgumentException("unsupported key exchange algorithm", "keyExchange"); - } - - this.context = context; - this.keyExchange = keyExchange; - } - - public virtual void SkipServerCertificate() - { - throw new TlsFatalAlert(AlertDescription.unexpected_message); - } - - public virtual void ProcessServerCertificate(Certificate serverCertificate) - { - X509CertificateStructure x509Cert = serverCertificate.certs[0]; - SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo; - - try - { - this.serverPublicKey = PublicKeyFactory.CreateKey(keyInfo); - } - catch (Exception) - { - throw new TlsFatalAlert(AlertDescription.unsupported_certificate); - } - - if (tlsSigner == null) - { - try - { - this.dhAgreeServerPublicKey = ValidateDHPublicKey((DHPublicKeyParameters)this.serverPublicKey); - } - catch (InvalidCastException) - { - throw new TlsFatalAlert(AlertDescription.certificate_unknown); - } - - TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.KeyAgreement); - } - else - { - if (!tlsSigner.IsValidPublicKey(this.serverPublicKey)) - { - throw new TlsFatalAlert(AlertDescription.certificate_unknown); - } - - TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.DigitalSignature); - } - - // TODO - /* - * Perform various checks per RFC2246 7.4.2: "Unless otherwise specified, the - * signing algorithm for the certificate must be the same as the algorithm for the - * certificate key." - */ - } - - public virtual void SkipServerKeyExchange() - { - // OK - } - - public virtual void ProcessServerKeyExchange(Stream input) - { - throw new TlsFatalAlert(AlertDescription.unexpected_message); - } - - public virtual void ValidateCertificateRequest(CertificateRequest certificateRequest) - { - ClientCertificateType[] types = certificateRequest.CertificateTypes; - foreach (ClientCertificateType type in types) - { - switch (type) - { - case ClientCertificateType.rsa_sign: - case ClientCertificateType.dss_sign: - case ClientCertificateType.rsa_fixed_dh: - case ClientCertificateType.dss_fixed_dh: - case ClientCertificateType.ecdsa_sign: - break; - default: - throw new TlsFatalAlert(AlertDescription.illegal_parameter); - } - } - } - - public virtual void SkipClientCredentials() - { - this.agreementCredentials = null; - } - - public virtual void ProcessClientCredentials(TlsCredentials clientCredentials) - { - if (clientCredentials is TlsAgreementCredentials) - { - // TODO Validate client cert has matching parameters (see 'areCompatibleParameters')? - - this.agreementCredentials = (TlsAgreementCredentials)clientCredentials; - } - else if (clientCredentials is TlsSignerCredentials) - { - // OK - } - else - { - throw new TlsFatalAlert(AlertDescription.internal_error); - } - } - - public virtual void GenerateClientKeyExchange(Stream output) - { - /* - * RFC 2246 7.4.7.2 If the client certificate already contains a suitable - * Diffie-Hellman key, then Yc is implicit and does not need to be sent again. In - * this case, the Client Key Exchange message will be sent, but will be empty. - */ - if (agreementCredentials == null) - { - GenerateEphemeralClientKeyExchange(dhAgreeServerPublicKey.Parameters, output); - } - } + /// <summary> + /// TLS 1.0 DH key exchange. + /// </summary> + internal class TlsDHKeyExchange + : TlsKeyExchange + { + protected TlsClientContext context; + protected KeyExchangeAlgorithm keyExchange; + protected TlsSigner tlsSigner; + + protected AsymmetricKeyParameter serverPublicKey = null; + protected DHPublicKeyParameters dhAgreeServerPublicKey = null; + protected TlsAgreementCredentials agreementCredentials; + protected DHPrivateKeyParameters dhAgreeClientPrivateKey = null; + + internal TlsDHKeyExchange(TlsClientContext context, KeyExchangeAlgorithm keyExchange) + { + switch (keyExchange) + { + case KeyExchangeAlgorithm.DH_RSA: + case KeyExchangeAlgorithm.DH_DSS: + this.tlsSigner = null; + break; + case KeyExchangeAlgorithm.DHE_RSA: + this.tlsSigner = new TlsRsaSigner(); + break; + case KeyExchangeAlgorithm.DHE_DSS: + this.tlsSigner = new TlsDssSigner(); + break; + default: + throw new ArgumentException("unsupported key exchange algorithm", "keyExchange"); + } + + this.context = context; + this.keyExchange = keyExchange; + } + + public virtual void SkipServerCertificate() + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + public virtual void ProcessServerCertificate(Certificate serverCertificate) + { + X509CertificateStructure x509Cert = serverCertificate.GetCertificateAt(0); + SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo; + + try + { + this.serverPublicKey = PublicKeyFactory.CreateKey(keyInfo); + } + catch (Exception) + { + throw new TlsFatalAlert(AlertDescription.unsupported_certificate); + } + + if (tlsSigner == null) + { + try + { + this.dhAgreeServerPublicKey = ValidateDHPublicKey((DHPublicKeyParameters)this.serverPublicKey); + } + catch (InvalidCastException) + { + throw new TlsFatalAlert(AlertDescription.certificate_unknown); + } + + TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.KeyAgreement); + } + else + { + if (!tlsSigner.IsValidPublicKey(this.serverPublicKey)) + { + throw new TlsFatalAlert(AlertDescription.certificate_unknown); + } + + TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.DigitalSignature); + } + + // TODO + /* + * Perform various checks per RFC2246 7.4.2: "Unless otherwise specified, the + * signing algorithm for the certificate must be the same as the algorithm for the + * certificate key." + */ + } + + public virtual void SkipServerKeyExchange() + { + // OK + } + + public virtual void ProcessServerKeyExchange(Stream input) + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + public virtual void ValidateCertificateRequest(CertificateRequest certificateRequest) + { + byte[] types = certificateRequest.CertificateTypes; + foreach (byte type in types) + { + switch (type) + { + case ClientCertificateType.rsa_sign: + case ClientCertificateType.dss_sign: + case ClientCertificateType.rsa_fixed_dh: + case ClientCertificateType.dss_fixed_dh: + case ClientCertificateType.ecdsa_sign: + break; + default: + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + } + } + + public virtual void SkipClientCredentials() + { + this.agreementCredentials = null; + } + + public virtual void ProcessClientCredentials(TlsCredentials clientCredentials) + { + if (clientCredentials is TlsAgreementCredentials) + { + // TODO Validate client cert has matching parameters (see 'areCompatibleParameters')? + + this.agreementCredentials = (TlsAgreementCredentials)clientCredentials; + } + else if (clientCredentials is TlsSignerCredentials) + { + // OK + } + else + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public virtual void GenerateClientKeyExchange(Stream output) + { + /* + * RFC 2246 7.4.7.2 If the client certificate already contains a suitable + * Diffie-Hellman key, then Yc is implicit and does not need to be sent again. In + * this case, the Client Key Exchange message will be sent, but will be empty. + */ + if (agreementCredentials == null) + { + GenerateEphemeralClientKeyExchange(dhAgreeServerPublicKey.Parameters, output); + } + } public virtual byte[] GeneratePremasterSecret() - { - if (agreementCredentials != null) - { - return agreementCredentials.GenerateAgreement(dhAgreeServerPublicKey); - } - - return CalculateDHBasicAgreement(dhAgreeServerPublicKey, dhAgreeClientPrivateKey); - } - - protected virtual bool AreCompatibleParameters(DHParameters a, DHParameters b) - { - return a.P.Equals(b.P) && a.G.Equals(b.G); - } - - protected virtual byte[] CalculateDHBasicAgreement(DHPublicKeyParameters publicKey, - DHPrivateKeyParameters privateKey) - { - return TlsDHUtilities.CalculateDHBasicAgreement(publicKey, privateKey); - } - - protected virtual AsymmetricCipherKeyPair GenerateDHKeyPair(DHParameters dhParams) - { - return TlsDHUtilities.GenerateDHKeyPair(context.SecureRandom, dhParams); - } - - protected virtual void GenerateEphemeralClientKeyExchange(DHParameters dhParams, Stream output) - { - this.dhAgreeClientPrivateKey = TlsDHUtilities.GenerateEphemeralClientKeyExchange( - context.SecureRandom, dhParams, output); - } - - protected virtual DHPublicKeyParameters ValidateDHPublicKey(DHPublicKeyParameters key) - { - return TlsDHUtilities.ValidateDHPublicKey(key); - } - } + { + if (agreementCredentials != null) + { + return agreementCredentials.GenerateAgreement(dhAgreeServerPublicKey); + } + + return CalculateDHBasicAgreement(dhAgreeServerPublicKey, dhAgreeClientPrivateKey); + } + + protected virtual bool AreCompatibleParameters(DHParameters a, DHParameters b) + { + return a.P.Equals(b.P) && a.G.Equals(b.G); + } + + protected virtual byte[] CalculateDHBasicAgreement(DHPublicKeyParameters publicKey, + DHPrivateKeyParameters privateKey) + { + return TlsDHUtilities.CalculateDHBasicAgreement(publicKey, privateKey); + } + + protected virtual AsymmetricCipherKeyPair GenerateDHKeyPair(DHParameters dhParams) + { + return TlsDHUtilities.GenerateDHKeyPair(context.SecureRandom, dhParams); + } + + protected virtual void GenerateEphemeralClientKeyExchange(DHParameters dhParams, Stream output) + { + this.dhAgreeClientPrivateKey = TlsDHUtilities.GenerateEphemeralClientKeyExchange( + context.SecureRandom, dhParams, output); + } + + protected virtual DHPublicKeyParameters ValidateDHPublicKey(DHPublicKeyParameters key) + { + return TlsDHUtilities.ValidateDHPublicKey(key); + } + } } diff --git a/crypto/src/crypto/tls/TlsECDHKeyExchange.cs b/crypto/src/crypto/tls/TlsECDHKeyExchange.cs index 36155346a..4c5576fca 100644 --- a/crypto/src/crypto/tls/TlsECDHKeyExchange.cs +++ b/crypto/src/crypto/tls/TlsECDHKeyExchange.cs @@ -56,7 +56,7 @@ namespace Org.BouncyCastle.Crypto.Tls public virtual void ProcessServerCertificate(Certificate serverCertificate) { - X509CertificateStructure x509Cert = serverCertificate.certs[0]; + X509CertificateStructure x509Cert = serverCertificate.GetCertificateAt(0); SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo; try @@ -117,8 +117,8 @@ namespace Org.BouncyCastle.Crypto.Tls * prohibited because the use of a long-term ECDH client key would jeopardize the * forward secrecy property of these algorithms. */ - ClientCertificateType[] types = certificateRequest.CertificateTypes; - foreach (ClientCertificateType type in types) + byte[] types = certificateRequest.CertificateTypes; + foreach (byte type in types) { switch (type) { diff --git a/crypto/src/crypto/tls/TlsECDheKeyExchange.cs b/crypto/src/crypto/tls/TlsECDheKeyExchange.cs index 071d06b91..2dd284f12 100644 --- a/crypto/src/crypto/tls/TlsECDheKeyExchange.cs +++ b/crypto/src/crypto/tls/TlsECDheKeyExchange.cs @@ -72,8 +72,8 @@ namespace Org.BouncyCastle.Crypto.Tls * prohibited because the use of a long-term ECDH client key would jeopardize the * forward secrecy property of these algorithms. */ - ClientCertificateType[] types = certificateRequest.CertificateTypes; - foreach (ClientCertificateType type in types) + byte[] types = certificateRequest.CertificateTypes; + foreach (byte type in types) { switch (type) { diff --git a/crypto/src/crypto/tls/TlsException.cs b/crypto/src/crypto/tls/TlsException.cs deleted file mode 100644 index 59c129105..000000000 --- a/crypto/src/crypto/tls/TlsException.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; - -namespace Org.BouncyCastle.Crypto.Tls -{ -#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT) - [Serializable] -#endif - public class TlsException : Exception - { - public TlsException() : base() { } - public TlsException(string message) : base(message) { } - public TlsException(string message, Exception exception) : base(message, exception) { } - } -} diff --git a/crypto/src/crypto/tls/TlsFatalAlert.cs b/crypto/src/crypto/tls/TlsFatalAlert.cs index 0a9cc6f3a..4fb2a41bd 100644 --- a/crypto/src/crypto/tls/TlsFatalAlert.cs +++ b/crypto/src/crypto/tls/TlsFatalAlert.cs @@ -3,19 +3,19 @@ using System.IO; namespace Org.BouncyCastle.Crypto.Tls { - public class TlsFatalAlert - : IOException - { - private readonly AlertDescription alertDescription; + public class TlsFatalAlert + : IOException + { + private readonly byte alertDescription; - public TlsFatalAlert(AlertDescription alertDescription) - { - this.alertDescription = alertDescription; - } + public TlsFatalAlert(byte alertDescription) + { + this.alertDescription = alertDescription; + } - public AlertDescription AlertDescription - { - get { return alertDescription; } - } - } + public virtual byte AlertDescription + { + get { return alertDescription; } + } + } } diff --git a/crypto/src/crypto/tls/TlsProtocolHandler.cs b/crypto/src/crypto/tls/TlsProtocolHandler.cs index 1960d3ccd..5ba42ef66 100644 --- a/crypto/src/crypto/tls/TlsProtocolHandler.cs +++ b/crypto/src/crypto/tls/TlsProtocolHandler.cs @@ -40,8 +40,6 @@ namespace Org.BouncyCastle.Crypto.Tls private const short CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED = 11; private const short CS_DONE = 12; - private static readonly byte[] emptybuf = new byte[0]; - private static readonly string TLS_ERROR_MESSAGE = "Internal TLS error, this could be an attack"; /* @@ -70,7 +68,7 @@ namespace Org.BouncyCastle.Crypto.Tls private TlsClientContextImpl tlsClientContext = null; private TlsClient tlsClient = null; private CipherSuite[] offeredCipherSuites = null; - private CompressionMethod[] offeredCompressionMethods = null; + private byte[] offeredCompressionMethods = null; private TlsKeyExchange keyExchange = null; private TlsAuthentication authentication = null; private CertificateRequest certificateRequest = null; @@ -337,7 +335,7 @@ namespace Org.BouncyCastle.Crypto.Tls * Find out which CompressionMethod the server has chosen and check that * it was one of the offered ones. */ - CompressionMethod selectedCompressionMethod = (CompressionMethod)TlsUtilities.ReadUint8(inStr); + byte selectedCompressionMethod = TlsUtilities.ReadUint8(inStr); if (!ArrayContains(offeredCompressionMethods, selectedCompressionMethod)) { this.FailWithError(AlertLevel.fatal, AlertDescription.illegal_parameter); @@ -431,7 +429,7 @@ namespace Org.BouncyCastle.Crypto.Tls byte[] renegExtValue = (byte[])serverExtensions[ExtensionType.renegotiation_info]; if (!Arrays.ConstantTimeAreEqual(renegExtValue, - CreateRenegotiationInfo(emptybuf))) + CreateRenegotiationInfo(TlsUtilities.EmptyBytes))) { this.FailWithError(AlertLevel.fatal, AlertDescription.handshake_failure); } @@ -626,29 +624,11 @@ namespace Org.BouncyCastle.Crypto.Tls this.FailWithError(AlertLevel.fatal, AlertDescription.handshake_failure); } - int numTypes = TlsUtilities.ReadUint8(inStr); - ClientCertificateType[] certificateTypes = new ClientCertificateType[numTypes]; - for (int i = 0; i < numTypes; ++i) - { - certificateTypes[i] = (ClientCertificateType)TlsUtilities.ReadUint8(inStr); - } - - byte[] authorities = TlsUtilities.ReadOpaque16(inStr); + this.certificateRequest = CertificateRequest.Parse(//getContext(), + inStr); AssertEmpty(inStr); - IList authorityDNs = Platform.CreateArrayList(); - - MemoryStream bis = new MemoryStream(authorities, false); - while (bis.Position < bis.Length) - { - byte[] dnBytes = TlsUtilities.ReadOpaque16(bis); - // TODO Switch to X500Name when available - authorityDNs.Add(X509Name.GetInstance(Asn1Object.FromByteArray(dnBytes))); - } - - this.certificateRequest = new CertificateRequest(certificateTypes, - authorityDNs); this.keyExchange.ValidateCertificateRequest(this.certificateRequest); break; @@ -899,7 +879,7 @@ namespace Org.BouncyCastle.Crypto.Tls TlsUtilities.WriteUint8((byte)offeredCompressionMethods.Length, outStr); for (int i = 0; i < offeredCompressionMethods.Length; ++i) { - TlsUtilities.WriteUint8((byte)offeredCompressionMethods[i], outStr); + TlsUtilities.WriteUint8(offeredCompressionMethods[i], outStr); } } @@ -1123,7 +1103,7 @@ namespace Org.BouncyCastle.Crypto.Tls * @param alertDescription The exact alert message. * @throws IOException If alert was fatal. */ - private void FailWithError(AlertLevel alertLevel, AlertDescription alertDescription) + private void FailWithError(byte alertLevel, byte alertDescription) { /* * Check if the connection is still open. @@ -1155,11 +1135,9 @@ namespace Org.BouncyCastle.Crypto.Tls } } - internal void SendAlert(AlertLevel alertLevel, AlertDescription alertDescription) + internal void SendAlert(byte alertLevel, byte alertDescription) { - byte[] error = new byte[2]; - error[0] = (byte)alertLevel; - error[1] = (byte)alertDescription; + byte[] error = new byte[] { alertLevel, alertDescription }; rs.WriteMessage(ContentType.alert, error, 0, 2); } @@ -1218,7 +1196,7 @@ namespace Org.BouncyCastle.Crypto.Tls return false; } - private static bool ArrayContains(CompressionMethod[] a, CompressionMethod n) + private static bool ArrayContains(byte[] a, byte n) { for (int i = 0; i < a.Length; ++i) { diff --git a/crypto/src/crypto/tls/TlsPskKeyExchange.cs b/crypto/src/crypto/tls/TlsPskKeyExchange.cs index cadd643ca..b1f14e156 100644 --- a/crypto/src/crypto/tls/TlsPskKeyExchange.cs +++ b/crypto/src/crypto/tls/TlsPskKeyExchange.cs @@ -8,42 +8,42 @@ using Org.BouncyCastle.Security; namespace Org.BouncyCastle.Crypto.Tls { - internal class TlsPskKeyExchange - : TlsKeyExchange - { - protected TlsClientContext context; - protected KeyExchangeAlgorithm keyExchange; - protected TlsPskIdentity pskIdentity; + internal class TlsPskKeyExchange + : TlsKeyExchange + { + protected TlsClientContext context; + protected KeyExchangeAlgorithm keyExchange; + protected TlsPskIdentity pskIdentity; - protected byte[] psk_identity_hint = null; + protected byte[] psk_identity_hint = null; - protected DHPublicKeyParameters dhAgreeServerPublicKey = null; - protected DHPrivateKeyParameters dhAgreeClientPrivateKey = null; + protected DHPublicKeyParameters dhAgreeServerPublicKey = null; + protected DHPrivateKeyParameters dhAgreeClientPrivateKey = null; protected AsymmetricKeyParameter serverPublicKey = null; protected RsaKeyParameters rsaServerPublicKey = null; - protected byte[] premasterSecret; - - internal TlsPskKeyExchange(TlsClientContext context, KeyExchangeAlgorithm keyExchange, - TlsPskIdentity pskIdentity) - { - switch (keyExchange) - { - case KeyExchangeAlgorithm.PSK: - case KeyExchangeAlgorithm.RSA_PSK: - case KeyExchangeAlgorithm.DHE_PSK: - break; - default: - throw new ArgumentException("unsupported key exchange algorithm", "keyExchange"); - } - - this.context = context; - this.keyExchange = keyExchange; - this.pskIdentity = pskIdentity; - } - - public virtual void SkipServerCertificate() - { + protected byte[] premasterSecret; + + internal TlsPskKeyExchange(TlsClientContext context, KeyExchangeAlgorithm keyExchange, + TlsPskIdentity pskIdentity) + { + switch (keyExchange) + { + case KeyExchangeAlgorithm.PSK: + case KeyExchangeAlgorithm.RSA_PSK: + case KeyExchangeAlgorithm.DHE_PSK: + break; + default: + throw new ArgumentException("unsupported key exchange algorithm", "keyExchange"); + } + + this.context = context; + this.keyExchange = keyExchange; + this.pskIdentity = pskIdentity; + } + + public virtual void SkipServerCertificate() + { if (keyExchange == KeyExchangeAlgorithm.RSA_PSK) { throw new TlsFatalAlert(AlertDescription.unexpected_message); @@ -51,13 +51,13 @@ namespace Org.BouncyCastle.Crypto.Tls } public virtual void ProcessServerCertificate(Certificate serverCertificate) - { + { if (keyExchange != KeyExchangeAlgorithm.RSA_PSK) { throw new TlsFatalAlert(AlertDescription.unexpected_message); } - X509CertificateStructure x509Cert = serverCertificate.certs[0]; + X509CertificateStructure x509Cert = serverCertificate.GetCertificateAt(0); SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo; try @@ -88,107 +88,107 @@ namespace Org.BouncyCastle.Crypto.Tls */ } - public virtual void SkipServerKeyExchange() - { + public virtual void SkipServerKeyExchange() + { if (keyExchange == KeyExchangeAlgorithm.DHE_PSK) { throw new TlsFatalAlert(AlertDescription.unexpected_message); } - this.psk_identity_hint = new byte[0]; - } - - public virtual void ProcessServerKeyExchange(Stream input) - { - this.psk_identity_hint = TlsUtilities.ReadOpaque16(input); - - if (this.keyExchange == KeyExchangeAlgorithm.DHE_PSK) - { - byte[] pBytes = TlsUtilities.ReadOpaque16(input); - byte[] gBytes = TlsUtilities.ReadOpaque16(input); - byte[] YsBytes = TlsUtilities.ReadOpaque16(input); - - BigInteger p = new BigInteger(1, pBytes); - BigInteger g = new BigInteger(1, gBytes); - BigInteger Ys = new BigInteger(1, YsBytes); - - this.dhAgreeServerPublicKey = TlsDHUtilities.ValidateDHPublicKey( - new DHPublicKeyParameters(Ys, new DHParameters(p, g))); - } - else if (this.psk_identity_hint.Length == 0) - { - // TODO Should we enforce that this message should have been skipped if hint is empty? - //throw new TlsFatalAlert(AlertDescription.unexpected_message); - } - } - - public virtual void ValidateCertificateRequest(CertificateRequest certificateRequest) - { - throw new TlsFatalAlert(AlertDescription.unexpected_message); - } - - public virtual void SkipClientCredentials() - { - // OK - } - - public virtual void ProcessClientCredentials(TlsCredentials clientCredentials) - { - throw new TlsFatalAlert(AlertDescription.internal_error); - } - - public virtual void GenerateClientKeyExchange(Stream output) - { - if (psk_identity_hint == null || psk_identity_hint.Length == 0) - { - pskIdentity.SkipIdentityHint(); - } - else - { - pskIdentity.NotifyIdentityHint(psk_identity_hint); - } - - byte[] psk_identity = pskIdentity.GetPskIdentity(); - - TlsUtilities.WriteOpaque16(psk_identity, output); - - if (this.keyExchange == KeyExchangeAlgorithm.RSA_PSK) - { - this.premasterSecret = TlsRsaUtilities.GenerateEncryptedPreMasterSecret( - context.SecureRandom, this.rsaServerPublicKey, output); - } - else if (this.keyExchange == KeyExchangeAlgorithm.DHE_PSK) - { - this.dhAgreeClientPrivateKey = TlsDHUtilities.GenerateEphemeralClientKeyExchange( - context.SecureRandom, this.dhAgreeServerPublicKey.Parameters, output); - } - } - - public virtual byte[] GeneratePremasterSecret() - { - byte[] psk = pskIdentity.GetPsk(); - byte[] other_secret = GenerateOtherSecret(psk.Length); - - MemoryStream buf = new MemoryStream(4 + other_secret.Length + psk.Length); - TlsUtilities.WriteOpaque16(other_secret, buf); - TlsUtilities.WriteOpaque16(psk, buf); - return buf.ToArray(); - } - - protected virtual byte[] GenerateOtherSecret(int pskLength) - { - if (this.keyExchange == KeyExchangeAlgorithm.DHE_PSK) - { - return TlsDHUtilities.CalculateDHBasicAgreement(dhAgreeServerPublicKey, dhAgreeClientPrivateKey); - } - - if (this.keyExchange == KeyExchangeAlgorithm.RSA_PSK) - { - return this.premasterSecret; - } - - return new byte[pskLength]; - } + this.psk_identity_hint = TlsUtilities.EmptyBytes; + } + + public virtual void ProcessServerKeyExchange(Stream input) + { + this.psk_identity_hint = TlsUtilities.ReadOpaque16(input); + + if (this.keyExchange == KeyExchangeAlgorithm.DHE_PSK) + { + byte[] pBytes = TlsUtilities.ReadOpaque16(input); + byte[] gBytes = TlsUtilities.ReadOpaque16(input); + byte[] YsBytes = TlsUtilities.ReadOpaque16(input); + + BigInteger p = new BigInteger(1, pBytes); + BigInteger g = new BigInteger(1, gBytes); + BigInteger Ys = new BigInteger(1, YsBytes); + + this.dhAgreeServerPublicKey = TlsDHUtilities.ValidateDHPublicKey( + new DHPublicKeyParameters(Ys, new DHParameters(p, g))); + } + else if (this.psk_identity_hint.Length == 0) + { + // TODO Should we enforce that this message should have been skipped if hint is empty? + //throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + } + + public virtual void ValidateCertificateRequest(CertificateRequest certificateRequest) + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + public virtual void SkipClientCredentials() + { + // OK + } + + public virtual void ProcessClientCredentials(TlsCredentials clientCredentials) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + public virtual void GenerateClientKeyExchange(Stream output) + { + if (psk_identity_hint == null || psk_identity_hint.Length == 0) + { + pskIdentity.SkipIdentityHint(); + } + else + { + pskIdentity.NotifyIdentityHint(psk_identity_hint); + } + + byte[] psk_identity = pskIdentity.GetPskIdentity(); + + TlsUtilities.WriteOpaque16(psk_identity, output); + + if (this.keyExchange == KeyExchangeAlgorithm.RSA_PSK) + { + this.premasterSecret = TlsRsaUtilities.GenerateEncryptedPreMasterSecret( + context.SecureRandom, this.rsaServerPublicKey, output); + } + else if (this.keyExchange == KeyExchangeAlgorithm.DHE_PSK) + { + this.dhAgreeClientPrivateKey = TlsDHUtilities.GenerateEphemeralClientKeyExchange( + context.SecureRandom, this.dhAgreeServerPublicKey.Parameters, output); + } + } + + public virtual byte[] GeneratePremasterSecret() + { + byte[] psk = pskIdentity.GetPsk(); + byte[] other_secret = GenerateOtherSecret(psk.Length); + + MemoryStream buf = new MemoryStream(4 + other_secret.Length + psk.Length); + TlsUtilities.WriteOpaque16(other_secret, buf); + TlsUtilities.WriteOpaque16(psk, buf); + return buf.ToArray(); + } + + protected virtual byte[] GenerateOtherSecret(int pskLength) + { + if (this.keyExchange == KeyExchangeAlgorithm.DHE_PSK) + { + return TlsDHUtilities.CalculateDHBasicAgreement(dhAgreeServerPublicKey, dhAgreeClientPrivateKey); + } + + if (this.keyExchange == KeyExchangeAlgorithm.RSA_PSK) + { + return this.premasterSecret; + } + + return new byte[pskLength]; + } protected virtual RsaKeyParameters ValidateRsaPublicKey(RsaKeyParameters key) { diff --git a/crypto/src/crypto/tls/TlsRsaKeyExchange.cs b/crypto/src/crypto/tls/TlsRsaKeyExchange.cs index ad61f08de..aad482316 100644 --- a/crypto/src/crypto/tls/TlsRsaKeyExchange.cs +++ b/crypto/src/crypto/tls/TlsRsaKeyExchange.cs @@ -11,117 +11,117 @@ using Org.BouncyCastle.Security; namespace Org.BouncyCastle.Crypto.Tls { - /// <summary> - /// TLS 1.0 RSA key exchange. - /// </summary> - internal class TlsRsaKeyExchange - : TlsKeyExchange - { - protected TlsClientContext context; + /// <summary> + /// TLS 1.0 RSA key exchange. + /// </summary> + internal class TlsRsaKeyExchange + : TlsKeyExchange + { + protected TlsClientContext context; - protected AsymmetricKeyParameter serverPublicKey = null; + protected AsymmetricKeyParameter serverPublicKey = null; protected RsaKeyParameters rsaServerPublicKey = null; protected byte[] premasterSecret; - internal TlsRsaKeyExchange(TlsClientContext context) - { - this.context = context; - } - - public virtual void SkipServerCertificate() - { - throw new TlsFatalAlert(AlertDescription.unexpected_message); - } - - public virtual void ProcessServerCertificate(Certificate serverCertificate) - { - X509CertificateStructure x509Cert = serverCertificate.certs[0]; - SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo; - - try - { - this.serverPublicKey = PublicKeyFactory.CreateKey(keyInfo); - } + internal TlsRsaKeyExchange(TlsClientContext context) + { + this.context = context; + } + + public virtual void SkipServerCertificate() + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + public virtual void ProcessServerCertificate(Certificate serverCertificate) + { + X509CertificateStructure x509Cert = serverCertificate.GetCertificateAt(0); + SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo; + + try + { + this.serverPublicKey = PublicKeyFactory.CreateKey(keyInfo); + } // catch (RuntimeException) - catch (Exception) - { - throw new TlsFatalAlert(AlertDescription.unsupported_certificate); - } - - // Sanity check the PublicKeyFactory - if (this.serverPublicKey.IsPrivate) - { - throw new TlsFatalAlert(AlertDescription.internal_error); - } - - this.rsaServerPublicKey = ValidateRsaPublicKey((RsaKeyParameters)this.serverPublicKey); - - TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.KeyEncipherment); - - // TODO - /* - * Perform various checks per RFC2246 7.4.2: "Unless otherwise specified, the - * signing algorithm for the certificate must be the same as the algorithm for the - * certificate key." - */ - } - - public virtual void SkipServerKeyExchange() - { - // OK - } - - public virtual void ProcessServerKeyExchange(Stream input) - { - throw new TlsFatalAlert(AlertDescription.unexpected_message); - } - - public virtual void ValidateCertificateRequest(CertificateRequest certificateRequest) - { - ClientCertificateType[] types = certificateRequest.CertificateTypes; - foreach (ClientCertificateType type in types) - { - switch (type) - { - case ClientCertificateType.rsa_sign: - case ClientCertificateType.dss_sign: - case ClientCertificateType.ecdsa_sign: - break; - default: - throw new TlsFatalAlert(AlertDescription.illegal_parameter); - } - } - } - - public virtual void SkipClientCredentials() - { - // OK - } - - public virtual void ProcessClientCredentials(TlsCredentials clientCredentials) - { - if (!(clientCredentials is TlsSignerCredentials)) - { - throw new TlsFatalAlert(AlertDescription.internal_error); - } - } - + catch (Exception) + { + throw new TlsFatalAlert(AlertDescription.unsupported_certificate); + } + + // Sanity check the PublicKeyFactory + if (this.serverPublicKey.IsPrivate) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + this.rsaServerPublicKey = ValidateRsaPublicKey((RsaKeyParameters)this.serverPublicKey); + + TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.KeyEncipherment); + + // TODO + /* + * Perform various checks per RFC2246 7.4.2: "Unless otherwise specified, the + * signing algorithm for the certificate must be the same as the algorithm for the + * certificate key." + */ + } + + public virtual void SkipServerKeyExchange() + { + // OK + } + + public virtual void ProcessServerKeyExchange(Stream input) + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + public virtual void ValidateCertificateRequest(CertificateRequest certificateRequest) + { + byte[] types = certificateRequest.CertificateTypes; + foreach (byte type in types) + { + switch (type) + { + case ClientCertificateType.rsa_sign: + case ClientCertificateType.dss_sign: + case ClientCertificateType.ecdsa_sign: + break; + default: + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + } + } + + public virtual void SkipClientCredentials() + { + // OK + } + + public virtual void ProcessClientCredentials(TlsCredentials clientCredentials) + { + if (!(clientCredentials is TlsSignerCredentials)) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + public virtual void GenerateClientKeyExchange(Stream output) - { - this.premasterSecret = TlsRsaUtilities.GenerateEncryptedPreMasterSecret( - context.SecureRandom, this.rsaServerPublicKey, output); - } - - public virtual byte[] GeneratePremasterSecret() - { - byte[] tmp = this.premasterSecret; - this.premasterSecret = null; - return tmp; - } - - // Would be needed to process RSA_EXPORT server key exchange + { + this.premasterSecret = TlsRsaUtilities.GenerateEncryptedPreMasterSecret( + context.SecureRandom, this.rsaServerPublicKey, output); + } + + public virtual byte[] GeneratePremasterSecret() + { + byte[] tmp = this.premasterSecret; + this.premasterSecret = null; + return tmp; + } + + // Would be needed to process RSA_EXPORT server key exchange // protected virtual void ProcessRsaServerKeyExchange(Stream input, ISigner signer) // { // Stream sigIn = input; @@ -150,16 +150,16 @@ namespace Org.BouncyCastle.Crypto.Tls // } protected virtual RsaKeyParameters ValidateRsaPublicKey(RsaKeyParameters key) - { - // TODO What is the minimum bit length required? + { + // TODO What is the minimum bit length required? // key.Modulus.BitLength; - if (!key.Exponent.IsProbablePrime(2)) - { - throw new TlsFatalAlert(AlertDescription.illegal_parameter); - } + if (!key.Exponent.IsProbablePrime(2)) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } - return key; - } - } + return key; + } + } } diff --git a/crypto/src/crypto/tls/TlsSrpKeyExchange.cs b/crypto/src/crypto/tls/TlsSrpKeyExchange.cs index cb4e26e58..8040f8e6c 100644 --- a/crypto/src/crypto/tls/TlsSrpKeyExchange.cs +++ b/crypto/src/crypto/tls/TlsSrpKeyExchange.cs @@ -72,7 +72,7 @@ namespace Org.BouncyCastle.Crypto.Tls throw new TlsFatalAlert(AlertDescription.unexpected_message); } - X509CertificateStructure x509Cert = serverCertificate.certs[0]; + X509CertificateStructure x509Cert = serverCertificate.GetCertificateAt(0); SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo; try diff --git a/crypto/src/crypto/tls/TlsUtilities.cs b/crypto/src/crypto/tls/TlsUtilities.cs index dca842a80..5ed659ce7 100644 --- a/crypto/src/crypto/tls/TlsUtilities.cs +++ b/crypto/src/crypto/tls/TlsUtilities.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.IO; using System.Text; @@ -16,6 +17,41 @@ namespace Org.BouncyCastle.Crypto.Tls /// <remarks>Some helper functions for MicroTLS.</remarks> public class TlsUtilities { + public static readonly byte[] EmptyBytes = new byte[0]; + + public static void CheckUint8(int i) + { + if (!IsValidUint8(i)) + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + public static void CheckUint16(int i) + { + if (!IsValidUint16(i)) + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + public static void CheckUint24(int i) + { + if (!IsValidUint24(i)) + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + public static bool IsValidUint8(int i) + { + return (i & 0xFF) == i; + } + + public static bool IsValidUint16(int i) + { + return (i & 0xFFFF) == i; + } + + public static bool IsValidUint24(int i) + { + return (i & 0xFFFFFF) == i; + } + internal static void WriteUint8(byte i, Stream os) { os.WriteByte(i); @@ -99,6 +135,13 @@ namespace Org.BouncyCastle.Crypto.Tls os.Write(uints, 0, uints.Length); } + public static void WriteUint8ArrayWithUint8Length(byte[] uints, Stream output) + { + CheckUint8(uints.Length); + WriteUint8((byte)uints.Length, output); + WriteUint8Array(uints, output); + } + internal static void WriteUint16Array(int[] uints, Stream os) { for (int i = 0; i < uints.Length; ++i) @@ -140,6 +183,16 @@ namespace Org.BouncyCastle.Crypto.Tls return (i1 << 16) | (i2 << 8) | i3; } + public static byte[] ReadFully(int length, Stream input) + { + if (length < 1) + return EmptyBytes; + byte[] buf = new byte[length]; + if (length != Streams.ReadFully(input, buf)) + throw new EndOfStreamException(); + return buf; + } + internal static void ReadFully(byte[] buf, Stream inStr) { if (Streams.ReadFully(inStr, buf, 0, buf.Length) < buf.Length) @@ -162,6 +215,12 @@ namespace Org.BouncyCastle.Crypto.Tls return bytes; } + public static byte[] ReadOpaque24(Stream input) + { + int length = ReadUint24(input); + return ReadFully(length, input); + } + internal static void CheckVersion(byte[] readVersion) { if ((readVersion[0] != 3) || (readVersion[1] != 1)) @@ -180,6 +239,30 @@ namespace Org.BouncyCastle.Crypto.Tls } } + public static Asn1Object ReadAsn1Object(byte[] encoding) + { + Asn1InputStream asn1 = new Asn1InputStream(encoding); + Asn1Object result = asn1.ReadObject(); + if (null == result) + throw new TlsFatalAlert(AlertDescription.decode_error); + if (null != asn1.ReadObject()) + throw new TlsFatalAlert(AlertDescription.decode_error); + return result; + } + + public static Asn1Object ReadDerObject(byte[] encoding) + { + /* + * NOTE: The current ASN.1 parsing code can't enforce DER-only parsing, but since DER is + * canonical, we can check it by re-encoding the result and comparing to the original. + */ + Asn1Object result = ReadAsn1Object(encoding); + byte[] check = result.GetEncoded(Asn1Encodable.Der); + if (!Arrays.AreEqual(check, encoding)) + throw new TlsFatalAlert(AlertDescription.decode_error); + return result; + } + internal static void WriteGmtUnixTime(byte[] buf, int offset) { int t = (int)(DateTimeUtilities.CurrentUnixMs() / 1000L); @@ -201,6 +284,35 @@ namespace Org.BouncyCastle.Crypto.Tls buf[offset + 1] = 1; } + public static void EncodeSupportedSignatureAlgorithms(IList supportedSignatureAlgorithms, bool allowAnonymous, + Stream output) + { + if (supportedSignatureAlgorithms == null || supportedSignatureAlgorithms.Count < 1 + || supportedSignatureAlgorithms.Count >= (1 << 15)) + { + throw new ArgumentException("must have length from 1 to (2^15 - 1)", "supportedSignatureAlgorithms"); + } + + // supported_signature_algorithms + int length = 2 * supportedSignatureAlgorithms.Count; + TlsUtilities.CheckUint16(length); + TlsUtilities.WriteUint16(length, output); + + foreach (SignatureAndHashAlgorithm entry in supportedSignatureAlgorithms) + { + if (!allowAnonymous && entry.Signature == SignatureAlgorithm.anonymous) + { + /* + * RFC 5246 7.4.1.4.1 The "anonymous" value is meaningless in this context but used + * in Section 7.4.3. It MUST NOT appear in this extension. + */ + throw new ArgumentException( + "SignatureAlgorithm.anonymous MUST NOT appear in the signature_algorithms extension"); + } + entry.Encode(output); + } + } + private static void hmac_hash(IDigest digest, byte[] secret, byte[] seed, byte[] output) { HMac mac = new HMac(digest); |