summary refs log tree commit diff
path: root/crypto/src
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src')
-rw-r--r--crypto/src/crypto/macs/HMac.cs14
-rw-r--r--crypto/src/crypto/signers/PssSigner.cs28
-rw-r--r--crypto/src/tls/AbstractTlsPeer.cs3
-rw-r--r--crypto/src/tls/CertificateVerify.cs57
-rw-r--r--crypto/src/tls/DefaultTlsClient.cs6
-rw-r--r--crypto/src/tls/DefaultTlsServer.cs12
-rw-r--r--crypto/src/tls/DigitallySigned.cs18
-rw-r--r--crypto/src/tls/DtlsClientProtocol.cs103
-rw-r--r--crypto/src/tls/DtlsServerProtocol.cs37
-rw-r--r--crypto/src/tls/KeyExchangeAlgorithm.cs13
-rw-r--r--crypto/src/tls/ProtocolVersion.cs72
-rw-r--r--crypto/src/tls/PskTlsClient.cs2
-rw-r--r--crypto/src/tls/PskTlsServer.cs2
-rw-r--r--crypto/src/tls/SignatureAlgorithm.cs43
-rw-r--r--crypto/src/tls/SignatureScheme.cs7
-rw-r--r--crypto/src/tls/SrpTlsClient.cs2
-rw-r--r--crypto/src/tls/SrpTlsServer.cs2
-rw-r--r--crypto/src/tls/TlsClientProtocol.cs117
-rw-r--r--crypto/src/tls/TlsServerProtocol.cs43
-rw-r--r--crypto/src/tls/TlsUtilities.cs269
-rw-r--r--crypto/src/tls/crypto/CryptoSignatureAlgorithm.cs3
-rw-r--r--crypto/src/tls/crypto/Tls13Verifier.cs14
-rw-r--r--crypto/src/tls/crypto/TlsCertificate.cs2
-rw-r--r--crypto/src/tls/crypto/TlsCrypto.cs22
-rw-r--r--crypto/src/tls/crypto/TlsCryptoUtilities.cs35
-rw-r--r--crypto/src/tls/crypto/TlsStreamSigner.cs2
-rw-r--r--crypto/src/tls/crypto/TlsStreamVerifier.cs2
-rw-r--r--crypto/src/tls/crypto/impl/AbstractTlsCrypto.cs6
-rw-r--r--crypto/src/tls/crypto/impl/LegacyTls13Verifier.cs60
-rw-r--r--crypto/src/tls/crypto/impl/TlsAeadCipher.cs5
-rw-r--r--crypto/src/tls/crypto/impl/bc/BcTls13Verifier.cs32
-rw-r--r--crypto/src/tls/crypto/impl/bc/BcTlsCertificate.cs106
-rw-r--r--crypto/src/tls/crypto/impl/bc/BcTlsCrypto.cs49
-rw-r--r--crypto/src/tls/crypto/impl/bc/BcTlsECDsa13Verifier.cs40
-rw-r--r--crypto/src/tls/crypto/impl/bc/BcTlsEd25519Verifier.cs28
-rw-r--r--crypto/src/tls/crypto/impl/bc/BcTlsEd448Verifier.cs28
-rw-r--r--crypto/src/tls/crypto/impl/bc/BcTlsRsaPssSigner.cs16
-rw-r--r--crypto/src/tls/crypto/impl/bc/BcTlsRsaPssVerifier.cs9
-rw-r--r--crypto/src/tls/crypto/impl/bc/BcTlsStreamSigner.cs4
-rw-r--r--crypto/src/tls/crypto/impl/bc/BcTlsStreamVerifier.cs4
-rw-r--r--crypto/src/tls/crypto/impl/bc/BcVerifyingStreamSigner.cs4
41 files changed, 819 insertions, 502 deletions
diff --git a/crypto/src/crypto/macs/HMac.cs b/crypto/src/crypto/macs/HMac.cs

index 460f3c5a0..3d42aec0f 100644 --- a/crypto/src/crypto/macs/HMac.cs +++ b/crypto/src/crypto/macs/HMac.cs
@@ -136,11 +136,15 @@ namespace Org.BouncyCastle.Crypto.Macs */ public virtual void Reset() { - // Reset underlying digest - digest.Reset(); - - // Initialise the digest - digest.BlockUpdate(inputPad, 0, inputPad.Length); + if (ipadState != null) + { + ((IMemoable)digest).Reset(ipadState); + } + else + { + digest.Reset(); + digest.BlockUpdate(inputPad, 0, inputPad.Length); + } } private static void XorPad(byte[] pad, int len, byte n) diff --git a/crypto/src/crypto/signers/PssSigner.cs b/crypto/src/crypto/signers/PssSigner.cs
index 66efa51b8..2a941df47 100644 --- a/crypto/src/crypto/signers/PssSigner.cs +++ b/crypto/src/crypto/signers/PssSigner.cs
@@ -15,7 +15,7 @@ namespace Org.BouncyCastle.Crypto.Signers public class PssSigner : ISigner { - public const byte TrailerImplicit = (byte)0xBC; + public const byte TrailerImplicit = 0xBC; private readonly IDigest contentDigest1, contentDigest2; private readonly IDigest mgfDigest; @@ -33,23 +33,23 @@ namespace Org.BouncyCastle.Crypto.Signers private byte[] block; private byte trailer; - public static PssSigner CreateRawSigner( - IAsymmetricBlockCipher cipher, - IDigest digest) + public static PssSigner CreateRawSigner(IAsymmetricBlockCipher cipher, IDigest digest) { return new PssSigner(cipher, new NullDigest(), digest, digest, digest.GetDigestSize(), null, TrailerImplicit); } - public static PssSigner CreateRawSigner( - IAsymmetricBlockCipher cipher, - IDigest contentDigest, - IDigest mgfDigest, - int saltLen, - byte trailer) + public static PssSigner CreateRawSigner(IAsymmetricBlockCipher cipher, IDigest contentDigest, IDigest mgfDigest, + int saltLen, byte trailer) { return new PssSigner(cipher, new NullDigest(), contentDigest, mgfDigest, saltLen, null, trailer); } + public static PssSigner CreateRawSigner(IAsymmetricBlockCipher cipher, IDigest contentDigest, IDigest mgfDigest, + byte[] salt, byte trailer) + { + return new PssSigner(cipher, new NullDigest(), contentDigest, mgfDigest, salt.Length, salt, trailer); + } + public PssSigner( IAsymmetricBlockCipher cipher, IDigest digest) @@ -225,6 +225,9 @@ namespace Org.BouncyCastle.Crypto.Signers /// </summary> public virtual byte[] GenerateSignature() { + if (contentDigest1.GetDigestSize() != hLen) + throw new InvalidOperationException(); + contentDigest1.DoFinal(mDash, mDash.Length - hLen - sLen); if (sLen != 0) @@ -271,7 +274,10 @@ namespace Org.BouncyCastle.Crypto.Signers public virtual bool VerifySignature( byte[] signature) { - contentDigest1.DoFinal(mDash, mDash.Length - hLen - sLen); + if (contentDigest1.GetDigestSize() != hLen) + throw new InvalidOperationException(); + + contentDigest1.DoFinal(mDash, mDash.Length - hLen - sLen); byte[] b = cipher.ProcessBlock(signature, 0, signature.Length); Arrays.Fill(block, 0, block.Length - b.Length, 0); diff --git a/crypto/src/tls/AbstractTlsPeer.cs b/crypto/src/tls/AbstractTlsPeer.cs
index 6d29953ee..4e1b28e58 100644 --- a/crypto/src/tls/AbstractTlsPeer.cs +++ b/crypto/src/tls/AbstractTlsPeer.cs
@@ -26,8 +26,7 @@ namespace Org.BouncyCastle.Tls /// <returns>an array of supported <see cref="ProtocolVersion"/> values.</returns> protected virtual ProtocolVersion[] GetSupportedVersions() { - // TODO[tls13] Enable TLSv13 by default in due course - return ProtocolVersion.TLSv12.DownTo(ProtocolVersion.TLSv10); + return ProtocolVersion.TLSv13.DownTo(ProtocolVersion.TLSv12); } protected abstract int[] GetSupportedCipherSuites(); diff --git a/crypto/src/tls/CertificateVerify.cs b/crypto/src/tls/CertificateVerify.cs new file mode 100644
index 000000000..7c9f02735 --- /dev/null +++ b/crypto/src/tls/CertificateVerify.cs
@@ -0,0 +1,57 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Tls +{ + public sealed class CertificateVerify + { + private readonly int m_algorithm; + private readonly byte[] m_signature; + + public CertificateVerify(int algorithm, byte[] signature) + { + if (!TlsUtilities.IsValidUint16(algorithm)) + throw new ArgumentException("algorithm"); + if (signature == null) + throw new ArgumentNullException("signature"); + + this.m_algorithm = algorithm; + this.m_signature = signature; + } + + /// <returns>a <see cref="SignatureScheme"/> value.</returns> + public int Algorithm + { + get { return m_algorithm; } + } + + public byte[] Signature + { + get { return m_signature; } + } + + /// <summary>Encode this <see cref="CertificateVerify"/> to a <see cref="Stream"/>.</summary> + /// <param name="output">the <see cref="Stream"/> to encode to.</param> + /// <exception cref="IOException"/> + public void Encode(Stream output) + { + TlsUtilities.WriteUint16(m_algorithm, output); + TlsUtilities.WriteOpaque16(m_signature, output); + } + + /// <summary>Parse a <see cref="CertificateVerify"/> from a <see cref="Stream"/>.</summary> + /// <param name="context">the <see cref="TlsContext"/> of the current connection.</param> + /// <param name="input">the <see cref="Stream"/> to parse from.</param> + /// <returns>a <see cref="CertificateVerify"/> object.</returns> + /// <exception cref="IOException"/> + public static CertificateVerify Parse(TlsContext context, Stream input) + { + if (!TlsUtilities.IsTlsV13(context)) + throw new InvalidOperationException(); + + int algorithm = TlsUtilities.ReadUint16(input); + byte[] signature = TlsUtilities.ReadOpaque16(input); + return new CertificateVerify(algorithm, signature); + } + } +} diff --git a/crypto/src/tls/DefaultTlsClient.cs b/crypto/src/tls/DefaultTlsClient.cs
index a2a742633..00827b5e7 100644 --- a/crypto/src/tls/DefaultTlsClient.cs +++ b/crypto/src/tls/DefaultTlsClient.cs
@@ -10,10 +10,10 @@ namespace Org.BouncyCastle.Tls private static readonly int[] DefaultCipherSuites = new int[] { /* - * TODO[tls13] TLS 1.3 + * TLS 1.3 */ - //CipherSuite.TLS_CHACHA20_POLY1305_SHA256, - //CipherSuite.TLS_AES_128_GCM_SHA256, + CipherSuite.TLS_CHACHA20_POLY1305_SHA256, + CipherSuite.TLS_AES_128_GCM_SHA256, /* * pre-TLS 1.3 diff --git a/crypto/src/tls/DefaultTlsServer.cs b/crypto/src/tls/DefaultTlsServer.cs
index de8a3f4a0..2df6c37eb 100644 --- a/crypto/src/tls/DefaultTlsServer.cs +++ b/crypto/src/tls/DefaultTlsServer.cs
@@ -11,11 +11,11 @@ namespace Org.BouncyCastle.Tls private static readonly int[] DefaultCipherSuites = new int[] { /* - * TODO[tls13] TLS 1.3 + * TLS 1.3 */ - //CipherSuite.TLS_CHACHA20_POLY1305_SHA256, - //CipherSuite.TLS_AES_256_GCM_SHA384, - //CipherSuite.TLS_AES_128_GCM_SHA256, + CipherSuite.TLS_CHACHA20_POLY1305_SHA256, + CipherSuite.TLS_AES_256_GCM_SHA384, + CipherSuite.TLS_AES_128_GCM_SHA256, /* * pre-TLS 1.3 @@ -85,10 +85,6 @@ namespace Org.BouncyCastle.Tls case KeyExchangeAlgorithm.DHE_DSS: return GetDsaSignerCredentials(); - case KeyExchangeAlgorithm.DH_anon: - case KeyExchangeAlgorithm.ECDH_anon: - return null; - case KeyExchangeAlgorithm.ECDHE_ECDSA: return GetECDsaSignerCredentials(); diff --git a/crypto/src/tls/DigitallySigned.cs b/crypto/src/tls/DigitallySigned.cs
index e977b350b..137847ada 100644 --- a/crypto/src/tls/DigitallySigned.cs +++ b/crypto/src/tls/DigitallySigned.cs
@@ -5,27 +5,27 @@ namespace Org.BouncyCastle.Tls { public sealed class DigitallySigned { - private readonly SignatureAndHashAlgorithm algorithm; - private readonly byte[] signature; + private readonly SignatureAndHashAlgorithm m_algorithm; + private readonly byte[] m_signature; public DigitallySigned(SignatureAndHashAlgorithm algorithm, byte[] signature) { if (signature == null) throw new ArgumentNullException("signature"); - this.algorithm = algorithm; - this.signature = signature; + this.m_algorithm = algorithm; + this.m_signature = signature; } /// <returns>a <see cref="SignatureAndHashAlgorithm"/> (or null before TLS 1.2).</returns> public SignatureAndHashAlgorithm Algorithm { - get { return algorithm; } + get { return m_algorithm; } } public byte[] Signature { - get { return signature; } + get { return m_signature; } } /// <summary>Encode this <see cref="DigitallySigned"/> to a <see cref="Stream"/>.</summary> @@ -33,11 +33,11 @@ namespace Org.BouncyCastle.Tls /// <exception cref="IOException"/> public void Encode(Stream output) { - if (algorithm != null) + if (m_algorithm != null) { - algorithm.Encode(output); + m_algorithm.Encode(output); } - TlsUtilities.WriteOpaque16(signature, output); + TlsUtilities.WriteOpaque16(m_signature, output); } /// <summary>Parse a <see cref="DigitallySigned"/> from a <see cref="Stream"/>.</summary> diff --git a/crypto/src/tls/DtlsClientProtocol.cs b/crypto/src/tls/DtlsClientProtocol.cs
index 44f574e3a..fd9985ab5 100644 --- a/crypto/src/tls/DtlsClientProtocol.cs +++ b/crypto/src/tls/DtlsClientProtocol.cs
@@ -237,12 +237,6 @@ namespace Org.BouncyCastle.Tls TlsUtilities.EstablishServerSigAlgs(securityParameters, state.certificateRequest); - /* - * TODO Give the client a chance to immediately select the CertificateVerify hash - * algorithm here to avoid tracking the other hash algorithms unnecessarily? - */ - TlsUtilities.TrackHashAlgorithms(handshake.HandshakeHash, securityParameters.ServerSigAlgs); - serverMessage = handshake.ReceiveMessage(); } else @@ -262,54 +256,68 @@ namespace Org.BouncyCastle.Tls throw new TlsFatalAlert(AlertDescription.unexpected_message); } - IList clientSupplementalData = state.client.GetClientSupplementalData(); - if (clientSupplementalData != null) - { - byte[] supplementalDataBody = GenerateSupplementalData(clientSupplementalData); - handshake.SendMessage(HandshakeType.supplemental_data, supplementalDataBody); - } + TlsCredentials clientAuthCredentials = null; + TlsCredentialedSigner clientAuthSigner = null; + Certificate clientAuthCertificate = null; + SignatureAndHashAlgorithm clientAuthAlgorithm = null; + TlsStreamSigner clientAuthStreamSigner = null; - if (null != state.certificateRequest) + if (state.certificateRequest != null) { - state.clientCredentials = TlsUtilities.EstablishClientCredentials(state.authentication, + clientAuthCredentials = TlsUtilities.EstablishClientCredentials(state.authentication, state.certificateRequest); + if (clientAuthCredentials != null) + { + clientAuthCertificate = clientAuthCredentials.Certificate; - /* - * RFC 5246 If no suitable certificate is available, the client MUST send a certificate - * message containing no certificates. - * - * NOTE: In previous RFCs, this was SHOULD instead of MUST. - */ + if (clientAuthCredentials is TlsCredentialedSigner) + { + clientAuthSigner = (TlsCredentialedSigner)clientAuthCredentials; + clientAuthAlgorithm = TlsUtilities.GetSignatureAndHashAlgorithm( + securityParameters.NegotiatedVersion, clientAuthSigner); + clientAuthStreamSigner = clientAuthSigner.GetStreamSigner(); - Certificate clientCertificate = null; - if (null != state.clientCredentials) - { - clientCertificate = state.clientCredentials.Certificate; - } + if (ProtocolVersion.DTLSv12.Equals(securityParameters.NegotiatedVersion)) + { + TlsUtilities.VerifySupportedSignatureAlgorithm(securityParameters.ServerSigAlgs, + clientAuthAlgorithm, AlertDescription.internal_error); + + if (clientAuthStreamSigner == null) + { + TlsUtilities.TrackHashAlgorithmClient(handshake.HandshakeHash, clientAuthAlgorithm); + } + } - SendCertificateMessage(state.clientContext, handshake, clientCertificate, null); + if (clientAuthStreamSigner != null) + { + handshake.HandshakeHash.ForceBuffering(); + } + } + } } - TlsCredentialedSigner credentialedSigner = null; - TlsStreamSigner streamSigner = null; + handshake.HandshakeHash.SealHashAlgorithms(); - if (null != state.clientCredentials) + if (clientAuthCredentials == null) { - state.keyExchange.ProcessClientCredentials(state.clientCredentials); - - if (state.clientCredentials is TlsCredentialedSigner) - { - credentialedSigner = (TlsCredentialedSigner)state.clientCredentials; - streamSigner = credentialedSigner.GetStreamSigner(); - } + state.keyExchange.SkipClientCredentials(); } else { - state.keyExchange.SkipClientCredentials(); + state.keyExchange.ProcessClientCredentials(clientAuthCredentials); } - bool forceBuffering = streamSigner != null; - TlsUtilities.SealHandshakeHash(state.clientContext, handshake.HandshakeHash, forceBuffering); + IList clientSupplementalData = state.client.GetClientSupplementalData(); + if (clientSupplementalData != null) + { + byte[] supplementalDataBody = GenerateSupplementalData(clientSupplementalData); + handshake.SendMessage(HandshakeType.supplemental_data, supplementalDataBody); + } + + if (null != state.certificateRequest) + { + SendCertificateMessage(state.clientContext, handshake, clientAuthCertificate, null); + } byte[] clientKeyExchangeBody = GenerateClientKeyExchange(state); handshake.SendMessage(HandshakeType.client_key_exchange, clientKeyExchangeBody); @@ -319,18 +327,16 @@ namespace Org.BouncyCastle.Tls TlsProtocol.EstablishMasterSecret(state.clientContext, state.keyExchange); recordLayer.InitPendingEpoch(TlsUtilities.InitCipher(state.clientContext)); + if (clientAuthSigner != null) { - if (credentialedSigner != null) - { - DigitallySigned certificateVerify = TlsUtilities.GenerateCertificateVerifyClient( - state.clientContext, credentialedSigner, streamSigner, handshake.HandshakeHash); - byte[] certificateVerifyBody = GenerateCertificateVerify(state, certificateVerify); - handshake.SendMessage(HandshakeType.certificate_verify, certificateVerifyBody); - } - - handshake.PrepareToFinish(); + DigitallySigned certificateVerify = TlsUtilities.GenerateCertificateVerifyClient(state.clientContext, + clientAuthSigner, clientAuthAlgorithm, clientAuthStreamSigner, handshake.HandshakeHash); + byte[] certificateVerifyBody = GenerateCertificateVerify(state, certificateVerify); + handshake.SendMessage(HandshakeType.certificate_verify, certificateVerifyBody); } + handshake.PrepareToFinish(); + securityParameters.m_localVerifyData = TlsUtilities.CalculateVerifyData(state.clientContext, handshake.HandshakeHash, false); handshake.SendMessage(HandshakeType.finished, securityParameters.LocalVerifyData); @@ -973,7 +979,6 @@ namespace Org.BouncyCastle.Tls internal TlsAuthentication authentication = null; internal CertificateStatus certificateStatus = null; internal CertificateRequest certificateRequest = null; - internal TlsCredentials clientCredentials = null; internal TlsHeartbeat heartbeat = null; internal short heartbeatPolicy = HeartbeatMode.peer_not_allowed_to_send; } diff --git a/crypto/src/tls/DtlsServerProtocol.cs b/crypto/src/tls/DtlsServerProtocol.cs
index b49122423..b01c6e34f 100644 --- a/crypto/src/tls/DtlsServerProtocol.cs +++ b/crypto/src/tls/DtlsServerProtocol.cs
@@ -155,7 +155,13 @@ namespace Org.BouncyCastle.Tls } state.keyExchange = TlsUtilities.InitKeyExchangeServer(state.serverContext, state.server); - state.serverCredentials = TlsUtilities.EstablishServerCredentials(state.server); + + state.serverCredentials = null; + + if (!KeyExchangeAlgorithm.IsAnonymous(securityParameters.KeyExchangeAlgorithm)) + { + state.serverCredentials = TlsUtilities.EstablishServerCredentials(state.server); + } // Server certificate { @@ -225,17 +231,34 @@ namespace Org.BouncyCastle.Tls TlsUtilities.EstablishServerSigAlgs(securityParameters, state.certificateRequest); - TlsUtilities.TrackHashAlgorithms(handshake.HandshakeHash, securityParameters.ServerSigAlgs); + if (ProtocolVersion.DTLSv12.Equals(securityParameters.NegotiatedVersion)) + { + TlsUtilities.TrackHashAlgorithms(handshake.HandshakeHash, securityParameters.ServerSigAlgs); - byte[] certificateRequestBody = GenerateCertificateRequest(state, state.certificateRequest); - handshake.SendMessage(HandshakeType.certificate_request, certificateRequestBody); + if (state.serverContext.Crypto.HasAnyStreamVerifiers(securityParameters.ServerSigAlgs)) + { + handshake.HandshakeHash.ForceBuffering(); + } + } + else + { + if (state.serverContext.Crypto.HasAnyStreamVerifiersLegacy(state.certificateRequest.CertificateTypes)) + { + handshake.HandshakeHash.ForceBuffering(); + } + } } } - handshake.SendMessage(HandshakeType.server_hello_done, TlsUtilities.EmptyBytes); + handshake.HandshakeHash.SealHashAlgorithms(); - bool forceBuffering = false; - TlsUtilities.SealHandshakeHash(state.serverContext, handshake.HandshakeHash, forceBuffering); + if (null != state.certificateRequest) + { + byte[] certificateRequestBody = GenerateCertificateRequest(state, state.certificateRequest); + handshake.SendMessage(HandshakeType.certificate_request, certificateRequestBody); + } + + handshake.SendMessage(HandshakeType.server_hello_done, TlsUtilities.EmptyBytes); clientMessage = handshake.ReceiveMessage(); diff --git a/crypto/src/tls/KeyExchangeAlgorithm.cs b/crypto/src/tls/KeyExchangeAlgorithm.cs
index 1dfa6db66..fdb2773f1 100644 --- a/crypto/src/tls/KeyExchangeAlgorithm.cs +++ b/crypto/src/tls/KeyExchangeAlgorithm.cs
@@ -59,5 +59,18 @@ namespace Org.BouncyCastle.Tls * GMT 0024-2014 */ public const int SM2 = 25; + + public static bool IsAnonymous(int keyExchangeAlgorithm) + { + switch (keyExchangeAlgorithm) + { + case DH_anon: + case DH_anon_EXPORT: + case ECDH_anon: + return true; + default: + return false; + } + } } } diff --git a/crypto/src/tls/ProtocolVersion.cs b/crypto/src/tls/ProtocolVersion.cs
index f37ce382d..f516aed2a 100644 --- a/crypto/src/tls/ProtocolVersion.cs +++ b/crypto/src/tls/ProtocolVersion.cs
@@ -14,6 +14,7 @@ namespace Org.BouncyCastle.Tls public static readonly ProtocolVersion TLSv13 = new ProtocolVersion(0x0304, "TLS 1.3"); public static readonly ProtocolVersion DTLSv10 = new ProtocolVersion(0xFEFF, "DTLS 1.0"); public static readonly ProtocolVersion DTLSv12 = new ProtocolVersion(0xFEFD, "DTLS 1.2"); + public static readonly ProtocolVersion DTLSv13 = new ProtocolVersion(0xFEFC, "DTLS 1.3"); internal static readonly ProtocolVersion CLIENT_EARLIEST_SUPPORTED_DTLS = DTLSv10; internal static readonly ProtocolVersion CLIENT_EARLIEST_SUPPORTED_TLS = SSLv3; @@ -225,17 +226,22 @@ namespace Org.BouncyCastle.Tls { switch (MajorVersion) { - case 0x03: - return this; - case 0xFE: - switch (MinorVersion) - { - case 0xFF: return TLSv11; - case 0xFD: return TLSv12; - default: return null; - } + case 0x03: + return this; + case 0xFE: + switch (MinorVersion) + { + case 0xFF: + return TLSv11; + case 0xFD: + return TLSv12; + case 0xFC: + return TLSv13; default: return null; + } + default: + return null; } } @@ -247,15 +253,20 @@ namespace Org.BouncyCastle.Tls case 0x03: switch (minor) { - case 0xFF: return null; - default: return Get(major, minor + 1); + case 0xFF: + return null; + default: + return Get(major, minor + 1); } case 0xFE: switch (minor) { - case 0x00: return null; - case 0xFF: return DTLSv12; - default: return Get(major, minor - 1); + case 0x00: + return null; + case 0xFF: + return DTLSv12; + default: + return Get(major, minor - 1); } default: return null; @@ -267,21 +278,26 @@ namespace Org.BouncyCastle.Tls int major = MajorVersion, minor = MinorVersion; switch (major) { - case 0x03: - switch (minor) - { - case 0x00: return null; - default: return Get(major, minor - 1); - } - case 0xFE: - switch (minor) - { - case 0xFF: return null; - case 0xFD: return DTLSv10; - default: return Get(major, minor + 1); - } + case 0x03: + switch (minor) + { + case 0x00: + return null; default: + return Get(major, minor - 1); + } + case 0xFE: + switch (minor) + { + case 0xFF: return null; + case 0xFD: + return DTLSv10; + default: + return Get(major, minor + 1); + } + default: + return null; } } @@ -367,6 +383,8 @@ namespace Org.BouncyCastle.Tls throw new ArgumentException("{0xFE, 0xFE} is a reserved protocol version"); case 0xFD: return DTLSv12; + case 0xFC: + return DTLSv13; } return GetUnknownVersion(major, minor, "DTLS"); } diff --git a/crypto/src/tls/PskTlsClient.cs b/crypto/src/tls/PskTlsClient.cs
index 3e9a00390..c475be63b 100644 --- a/crypto/src/tls/PskTlsClient.cs +++ b/crypto/src/tls/PskTlsClient.cs
@@ -34,7 +34,7 @@ namespace Org.BouncyCastle.Tls protected override ProtocolVersion[] GetSupportedVersions() { - return ProtocolVersion.TLSv12.DownTo(ProtocolVersion.TLSv10); + return ProtocolVersion.TLSv12.Only(); } protected override int[] GetSupportedCipherSuites() diff --git a/crypto/src/tls/PskTlsServer.cs b/crypto/src/tls/PskTlsServer.cs
index 7197b6ad8..968cd5ce3 100644 --- a/crypto/src/tls/PskTlsServer.cs +++ b/crypto/src/tls/PskTlsServer.cs
@@ -40,7 +40,7 @@ namespace Org.BouncyCastle.Tls protected override ProtocolVersion[] GetSupportedVersions() { - return ProtocolVersion.TLSv12.DownTo(ProtocolVersion.TLSv10); + return ProtocolVersion.TLSv12.Only(); } protected override int[] GetSupportedCipherSuites() diff --git a/crypto/src/tls/SignatureAlgorithm.cs b/crypto/src/tls/SignatureAlgorithm.cs
index 726504c52..baf5620e3 100644 --- a/crypto/src/tls/SignatureAlgorithm.cs +++ b/crypto/src/tls/SignatureAlgorithm.cs
@@ -86,20 +86,16 @@ namespace Org.BouncyCastle.Tls return "dsa"; case ecdsa: return "ecdsa"; - case ed25519: - return "ed25519"; - case ed448: - return "ed448"; - case gostr34102012_256: - return "gostr34102012_256"; - case gostr34102012_512: - return "gostr34102012_512"; case rsa_pss_rsae_sha256: return "rsa_pss_rsae_sha256"; case rsa_pss_rsae_sha384: return "rsa_pss_rsae_sha384"; case rsa_pss_rsae_sha512: return "rsa_pss_rsae_sha512"; + case ed25519: + return "ed25519"; + case ed448: + return "ed448"; case rsa_pss_pss_sha256: return "rsa_pss_pss_sha256"; case rsa_pss_pss_sha384: @@ -112,6 +108,10 @@ namespace Org.BouncyCastle.Tls return "ecdsa_brainpoolP384r1tls13_sha384"; case ecdsa_brainpoolP512r1tls13_sha512: return "ecdsa_brainpoolP512r1tls13_sha512"; + case gostr34102012_256: + return "gostr34102012_256"; + case gostr34102012_512: + return "gostr34102012_512"; default: return "UNKNOWN"; } @@ -121,5 +121,32 @@ namespace Org.BouncyCastle.Tls { return GetName(signatureAlgorithm) + "(" + signatureAlgorithm + ")"; } + + public static bool IsRecognized(short signatureAlgorithm) + { + switch (signatureAlgorithm) + { + case anonymous: + case rsa: + case dsa: + case ecdsa: + case rsa_pss_rsae_sha256: + case rsa_pss_rsae_sha384: + case rsa_pss_rsae_sha512: + case ed25519: + case ed448: + case rsa_pss_pss_sha256: + case rsa_pss_pss_sha384: + case rsa_pss_pss_sha512: + case ecdsa_brainpoolP256r1tls13_sha256: + case ecdsa_brainpoolP384r1tls13_sha384: + case ecdsa_brainpoolP512r1tls13_sha512: + case gostr34102012_256: + case gostr34102012_512: + return true; + default: + return false; + } + } } } diff --git a/crypto/src/tls/SignatureScheme.cs b/crypto/src/tls/SignatureScheme.cs
index 4b934133d..ed8e3c21b 100644 --- a/crypto/src/tls/SignatureScheme.cs +++ b/crypto/src/tls/SignatureScheme.cs
@@ -92,11 +92,16 @@ namespace Org.BouncyCastle.Tls if (HashAlgorithm.Intrinsic == hashAlgorithm || !HashAlgorithm.IsRecognized(hashAlgorithm)) return -1; - return TlsCryptoUtilities.GetHash(GetHashAlgorithm(signatureScheme)); + return TlsCryptoUtilities.GetHash(hashAlgorithm); } } } + public static int GetCryptoHashAlgorithm(SignatureAndHashAlgorithm signatureAndHashAlgorithm) + { + return GetCryptoHashAlgorithm(From(signatureAndHashAlgorithm)); + } + public static string GetName(int signatureScheme) { switch (signatureScheme) diff --git a/crypto/src/tls/SrpTlsClient.cs b/crypto/src/tls/SrpTlsClient.cs
index a2b0e9461..f6f6472bc 100644 --- a/crypto/src/tls/SrpTlsClient.cs +++ b/crypto/src/tls/SrpTlsClient.cs
@@ -34,7 +34,7 @@ namespace Org.BouncyCastle.Tls protected override ProtocolVersion[] GetSupportedVersions() { - return ProtocolVersion.TLSv12.DownTo(ProtocolVersion.TLSv10); + return ProtocolVersion.TLSv12.Only(); } protected virtual bool RequireSrpServerExtension diff --git a/crypto/src/tls/SrpTlsServer.cs b/crypto/src/tls/SrpTlsServer.cs
index 58f89ee22..1e2f09e03 100644 --- a/crypto/src/tls/SrpTlsServer.cs +++ b/crypto/src/tls/SrpTlsServer.cs
@@ -44,7 +44,7 @@ namespace Org.BouncyCastle.Tls protected override ProtocolVersion[] GetSupportedVersions() { - return ProtocolVersion.TLSv12.DownTo(ProtocolVersion.TLSv10); + return ProtocolVersion.TLSv12.Only(); } protected override int[] GetSupportedCipherSuites() diff --git a/crypto/src/tls/TlsClientProtocol.cs b/crypto/src/tls/TlsClientProtocol.cs
index cb59289ae..ba2b565ca 100644 --- a/crypto/src/tls/TlsClientProtocol.cs +++ b/crypto/src/tls/TlsClientProtocol.cs
@@ -450,24 +450,27 @@ namespace Org.BouncyCastle.Tls { Process13HelloRetryRequest(serverHello); m_handshakeHash.NotifyPrfDetermined(); + m_handshakeHash.SealHashAlgorithms(); TlsUtilities.AdjustTranscriptForRetry(m_handshakeHash); buf.UpdateHash(m_handshakeHash); this.m_connectionState = CS_SERVER_HELLO_RETRY_REQUEST; Send13ClientHelloRetry(); - m_handshakeHash.SealHashAlgorithms(); this.m_connectionState = CS_CLIENT_HELLO_RETRY; } else { ProcessServerHello(serverHello); m_handshakeHash.NotifyPrfDetermined(); + if (TlsUtilities.IsTlsV13(securityParameters.NegotiatedVersion)) + { + m_handshakeHash.SealHashAlgorithms(); + } buf.UpdateHash(m_handshakeHash); this.m_connectionState = CS_SERVER_HELLO; if (TlsUtilities.IsTlsV13(securityParameters.NegotiatedVersion)) { - m_handshakeHash.SealHashAlgorithms(); Process13ServerHelloCoda(serverHello, false); } } @@ -526,61 +529,70 @@ namespace Org.BouncyCastle.Tls this.m_connectionState = CS_SERVER_HELLO_DONE; - IList clientSupplementalData = m_tlsClient.GetClientSupplementalData(); - if (clientSupplementalData != null) + TlsCredentials clientAuthCredentials = null; + TlsCredentialedSigner clientAuthSigner = null; + Certificate clientAuthCertificate = null; + SignatureAndHashAlgorithm clientAuthAlgorithm = null; + TlsStreamSigner clientAuthStreamSigner = null; + + if (m_certificateRequest != null) { - SendSupplementalDataMessage(clientSupplementalData); - this.m_connectionState = CS_CLIENT_SUPPLEMENTAL_DATA; + clientAuthCredentials = TlsUtilities.EstablishClientCredentials(m_authentication, + m_certificateRequest); + if (clientAuthCredentials != null) + { + clientAuthCertificate = clientAuthCredentials.Certificate; + + if (clientAuthCredentials is TlsCredentialedSigner) + { + clientAuthSigner = (TlsCredentialedSigner)clientAuthCredentials; + clientAuthAlgorithm = TlsUtilities.GetSignatureAndHashAlgorithm( + securityParameters.NegotiatedVersion, clientAuthSigner); + clientAuthStreamSigner = clientAuthSigner.GetStreamSigner(); + + if (ProtocolVersion.TLSv12.Equals(securityParameters.NegotiatedVersion)) + { + TlsUtilities.VerifySupportedSignatureAlgorithm(securityParameters.ServerSigAlgs, + clientAuthAlgorithm, AlertDescription.internal_error); + + if (clientAuthStreamSigner == null) + { + TlsUtilities.TrackHashAlgorithmClient(m_handshakeHash, clientAuthAlgorithm); + } + } + + if (clientAuthStreamSigner != null) + { + m_handshakeHash.ForceBuffering(); + } + } + } } - TlsCredentialedSigner credentialedSigner = null; - TlsStreamSigner streamSigner = null; + m_handshakeHash.SealHashAlgorithms(); - if (m_certificateRequest == null) + if (clientAuthCredentials == null) { m_keyExchange.SkipClientCredentials(); } else { - Certificate clientCertificate = null; - - TlsCredentials clientCredentials = TlsUtilities.EstablishClientCredentials(m_authentication, - m_certificateRequest); - if (null == clientCredentials) - { - m_keyExchange.SkipClientCredentials(); - - /* - * RFC 5246 If no suitable certificate is available, the client MUST send a - * certificate message containing no certificates. - * - * NOTE: In previous RFCs, this was SHOULD instead of MUST. - */ - } - else - { - m_keyExchange.ProcessClientCredentials(clientCredentials); - - clientCertificate = clientCredentials.Certificate; - - if (clientCredentials is TlsCredentialedSigner) - { - credentialedSigner = (TlsCredentialedSigner)clientCredentials; - streamSigner = credentialedSigner.GetStreamSigner(); - } - } + m_keyExchange.ProcessClientCredentials(clientAuthCredentials); + } - SendCertificateMessage(clientCertificate, null); - this.m_connectionState = CS_CLIENT_CERTIFICATE; + IList clientSupplementalData = m_tlsClient.GetClientSupplementalData(); + if (clientSupplementalData != null) + { + SendSupplementalDataMessage(clientSupplementalData); + this.m_connectionState = CS_CLIENT_SUPPLEMENTAL_DATA; } - bool forceBuffering = streamSigner != null; - TlsUtilities.SealHandshakeHash(m_tlsClientContext, m_handshakeHash, forceBuffering); + if (m_certificateRequest != null) + { + SendCertificateMessage(clientAuthCertificate, null); + this.m_connectionState = CS_CLIENT_CERTIFICATE; + } - /* - * Send the client key exchange message, depending on the key exchange we are using - * in our CipherSuite. - */ SendClientKeyExchange(); this.m_connectionState = CS_CLIENT_KEY_EXCHANGE; @@ -601,10 +613,11 @@ namespace Org.BouncyCastle.Tls m_recordStream.SetPendingCipher(TlsUtilities.InitCipher(m_tlsClientContext)); - if (credentialedSigner != null) + if (clientAuthSigner != null) { DigitallySigned certificateVerify = TlsUtilities.GenerateCertificateVerifyClient( - m_tlsClientContext, credentialedSigner, streamSigner, m_handshakeHash); + m_tlsClientContext, clientAuthSigner, clientAuthAlgorithm, clientAuthStreamSigner, + m_handshakeHash); SendCertificateVerifyMessage(certificateVerify); this.m_connectionState = CS_CLIENT_CERTIFICATE_VERIFY; } @@ -674,13 +687,6 @@ namespace Org.BouncyCastle.Tls ReceiveCertificateRequest(buf); TlsUtilities.EstablishServerSigAlgs(securityParameters, m_certificateRequest); - - /* - * TODO Give the client a chance to immediately select the CertificateVerify hash - * algorithm here to avoid tracking the other hash algorithms unnecessarily? - */ - TlsUtilities.TrackHashAlgorithms(m_handshakeHash, securityParameters.ServerSigAlgs); - break; } default: @@ -1467,12 +1473,11 @@ namespace Org.BouncyCastle.Tls if (null == serverCertificate || serverCertificate.IsEmpty) throw new TlsFatalAlert(AlertDescription.internal_error); - // TODO[tls13] Actual structure is 'CertificateVerify' in RFC 8446, consider adding for clarity - DigitallySigned certificateVerify = DigitallySigned.Parse(m_tlsClientContext, buf); + CertificateVerify certificateVerify = CertificateVerify.Parse(m_tlsClientContext, buf); AssertEmpty(buf); - TlsUtilities.Verify13CertificateVerifyServer(m_tlsClientContext, certificateVerify, m_handshakeHash); + TlsUtilities.Verify13CertificateVerifyServer(m_tlsClientContext, m_handshakeHash, certificateVerify); } /// <exception cref="IOException"/> diff --git a/crypto/src/tls/TlsServerProtocol.cs b/crypto/src/tls/TlsServerProtocol.cs
index 0ab8a7a98..c90ef4109 100644 --- a/crypto/src/tls/TlsServerProtocol.cs +++ b/crypto/src/tls/TlsServerProtocol.cs
@@ -907,6 +907,7 @@ namespace Org.BouncyCastle.Tls if (serverHello.IsHelloRetryRequest()) { TlsUtilities.AdjustTranscriptForRetry(m_handshakeHash); + SendServerHelloMessage(serverHello); this.m_connectionState = CS_SERVER_HELLO_RETRY_REQUEST; @@ -952,7 +953,12 @@ namespace Org.BouncyCastle.Tls this.m_keyExchange = TlsUtilities.InitKeyExchangeServer(m_tlsServerContext, m_tlsServer); - TlsCredentials serverCredentials = TlsUtilities.EstablishServerCredentials(m_tlsServer); + TlsCredentials serverCredentials = null; + + if (!KeyExchangeAlgorithm.IsAnonymous(securityParameters.KeyExchangeAlgorithm)) + { + serverCredentials = TlsUtilities.EstablishServerCredentials(m_tlsServer); + } // Server certificate { @@ -1026,19 +1032,36 @@ namespace Org.BouncyCastle.Tls TlsUtilities.EstablishServerSigAlgs(securityParameters, m_certificateRequest); - TlsUtilities.TrackHashAlgorithms(m_handshakeHash, securityParameters.ServerSigAlgs); + if (ProtocolVersion.TLSv12.Equals(securityParameters.NegotiatedVersion)) + { + TlsUtilities.TrackHashAlgorithms(m_handshakeHash, securityParameters.ServerSigAlgs); - SendCertificateRequestMessage(m_certificateRequest); - this.m_connectionState = CS_SERVER_CERTIFICATE_REQUEST; + if (m_tlsServerContext.Crypto.HasAnyStreamVerifiers(securityParameters.ServerSigAlgs)) + { + m_handshakeHash.ForceBuffering(); + } + } + else + { + if (m_tlsServerContext.Crypto.HasAnyStreamVerifiersLegacy(m_certificateRequest.CertificateTypes)) + { + m_handshakeHash.ForceBuffering(); + } + } } } + m_handshakeHash.SealHashAlgorithms(); + + if (null != m_certificateRequest) + { + SendCertificateRequestMessage(m_certificateRequest); + this.m_connectionState = CS_SERVER_CERTIFICATE_REQUEST; + } + SendServerHelloDoneMessage(); this.m_connectionState = CS_SERVER_HELLO_DONE; - bool forceBuffering = false; - TlsUtilities.SealHandshakeHash(m_tlsServerContext, m_handshakeHash, forceBuffering); - break; } default: @@ -1281,13 +1304,11 @@ namespace Org.BouncyCastle.Tls if (null == clientCertificate || clientCertificate.IsEmpty) throw new TlsFatalAlert(AlertDescription.internal_error); - // TODO[tls13] Actual structure is 'CertificateVerify' in RFC 8446, consider adding for clarity - DigitallySigned certificateVerify = DigitallySigned.Parse(m_tlsServerContext, buf); + CertificateVerify certificateVerify = CertificateVerify.Parse(m_tlsServerContext, buf); AssertEmpty(buf); - TlsUtilities.Verify13CertificateVerifyClient(m_tlsServerContext, m_certificateRequest, certificateVerify, - m_handshakeHash); + TlsUtilities.Verify13CertificateVerifyClient(m_tlsServerContext, m_handshakeHash, certificateVerify); } /// <exception cref="IOException"/> diff --git a/crypto/src/tls/TlsUtilities.cs b/crypto/src/tls/TlsUtilities.cs
index 05d38c59c..72ff92271 100644 --- a/crypto/src/tls/TlsUtilities.cs +++ b/crypto/src/tls/TlsUtilities.cs
@@ -1068,16 +1068,22 @@ namespace Org.BouncyCastle.Tls public static IList GetDefaultSupportedSignatureAlgorithms(TlsContext context) { + return GetSupportedSignatureAlgorithms(context, DefaultSupportedSigAlgs); + } + + public static IList GetSupportedSignatureAlgorithms(TlsContext context, IList candidates) + { TlsCrypto crypto = context.Crypto; IList result = Platform.CreateArrayList(DefaultSupportedSigAlgs.Count); - foreach (SignatureAndHashAlgorithm sigAndHashAlg in DefaultSupportedSigAlgs) + foreach (SignatureAndHashAlgorithm sigAndHashAlg in candidates) { AddIfSupported(result, crypto, sigAndHashAlg); } return result; } + [Obsolete("Will be removed")] public static SignatureAndHashAlgorithm GetSignatureAndHashAlgorithm(TlsContext context, TlsCredentialedSigner signerCredentials) { @@ -1085,14 +1091,19 @@ namespace Org.BouncyCastle.Tls } internal static SignatureAndHashAlgorithm GetSignatureAndHashAlgorithm(ProtocolVersion negotiatedVersion, - TlsCredentialedSigner signerCredentials) + TlsCredentialedSigner credentialedSigner) { SignatureAndHashAlgorithm signatureAndHashAlgorithm = null; - if (IsTlsV12(negotiatedVersion)) + if (IsSignatureAlgorithmsExtensionAllowed(negotiatedVersion)) { - signatureAndHashAlgorithm = signerCredentials.SignatureAndHashAlgorithm; + signatureAndHashAlgorithm = credentialedSigner.SignatureAndHashAlgorithm; if (signatureAndHashAlgorithm == null) + { + /* + * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2 + */ throw new TlsFatalAlert(AlertDescription.internal_error); + } } return signatureAndHashAlgorithm; } @@ -1347,6 +1358,14 @@ namespace Org.BouncyCastle.Tls public static void VerifySupportedSignatureAlgorithm(IList supportedSignatureAlgorithms, SignatureAndHashAlgorithm signatureAlgorithm) { + VerifySupportedSignatureAlgorithm(supportedSignatureAlgorithms, signatureAlgorithm, + AlertDescription.illegal_parameter); + } + + /// <exception cref="IOException"/> + internal static void VerifySupportedSignatureAlgorithm(IList supportedSignatureAlgorithms, + SignatureAndHashAlgorithm signatureAlgorithm, short alertDescription) + { if (supportedSignatureAlgorithms == null || supportedSignatureAlgorithms.Count < 1 || supportedSignatureAlgorithms.Count >= (1 << 15)) { @@ -1358,7 +1377,7 @@ namespace Org.BouncyCastle.Tls if (signatureAlgorithm.Signature == SignatureAlgorithm.anonymous || !ContainsSignatureAlgorithm(supportedSignatureAlgorithms, signatureAlgorithm)) { - throw new TlsFatalAlert(AlertDescription.illegal_parameter); + throw new TlsFatalAlert(alertDescription); } } @@ -2088,7 +2107,7 @@ namespace Org.BouncyCastle.Tls TlsHash h = algorithm == null ? new CombinedHash(crypto) - : CreateHash(crypto, algorithm.Hash); + : CreateHash(crypto, algorithm); SecurityParameters sp = context.SecurityParameters; // NOTE: The implicit copy here is intended (and important) @@ -2124,48 +2143,38 @@ namespace Org.BouncyCastle.Tls } internal static DigitallySigned GenerateCertificateVerifyClient(TlsClientContext clientContext, - TlsCredentialedSigner credentialedSigner, TlsStreamSigner streamSigner, TlsHandshakeHash handshakeHash) + TlsCredentialedSigner clientAuthSigner, SignatureAndHashAlgorithm clientAuthAlgorithm, + TlsStreamSigner clientAuthStreamSigner, TlsHandshakeHash handshakeHash) { SecurityParameters securityParameters = clientContext.SecurityParameters; - ProtocolVersion negotiatedVersion = securityParameters.NegotiatedVersion; - - if (IsTlsV13(negotiatedVersion)) + if (IsTlsV13(securityParameters.NegotiatedVersion)) { - // Should be using GenerateCertificateVerify13 instead + // Should be using Generate13CertificateVerify instead throw new TlsFatalAlert(AlertDescription.internal_error); } - /* - * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2 - */ - SignatureAndHashAlgorithm signatureAndHashAlgorithm = GetSignatureAndHashAlgorithm(negotiatedVersion, - credentialedSigner); - byte[] signature; - if (streamSigner != null) + if (clientAuthStreamSigner != null) { - handshakeHash.CopyBufferTo(streamSigner.GetOutputStream()); - signature = streamSigner.GetSignature(); + handshakeHash.CopyBufferTo(clientAuthStreamSigner.Stream); + signature = clientAuthStreamSigner.GetSignature(); } else { byte[] hash; - if (signatureAndHashAlgorithm == null) + if (clientAuthAlgorithm == null) { hash = securityParameters.SessionHash; } else { - int signatureScheme = SignatureScheme.From(signatureAndHashAlgorithm); - int cryptoHashAlgorithm = SignatureScheme.GetCryptoHashAlgorithm(signatureScheme); - - hash = handshakeHash.GetFinalHash(cryptoHashAlgorithm); + hash = handshakeHash.GetFinalHash(SignatureScheme.GetCryptoHashAlgorithm(clientAuthAlgorithm)); } - signature = credentialedSigner.GenerateRawSignature(hash); + signature = clientAuthSigner.GenerateRawSignature(hash); } - return new DigitallySigned(signatureAndHashAlgorithm, signature); + return new DigitallySigned(clientAuthAlgorithm, signature); } internal static DigitallySigned Generate13CertificateVerify(TlsContext context, @@ -2195,16 +2204,13 @@ namespace Org.BouncyCastle.Tls if (null != streamSigner) { - Stream output = streamSigner.GetOutputStream(); + Stream output = streamSigner.Stream; output.Write(header, 0, header.Length); output.Write(prfHash, 0, prfHash.Length); return streamSigner.GetSignature(); } - int signatureScheme = SignatureScheme.From(signatureAndHashAlgorithm); - int cryptoHashAlgorithm = SignatureScheme.GetCryptoHashAlgorithm(signatureScheme); - - TlsHash tlsHash = crypto.CreateHash(cryptoHashAlgorithm); + TlsHash tlsHash = CreateHash(crypto, signatureAndHashAlgorithm); tlsHash.Update(header, 0, header.Length); tlsHash.Update(prfHash, 0, prfHash.Length); byte[] hash = tlsHash.CalculateHash(); @@ -2224,22 +2230,17 @@ namespace Org.BouncyCastle.Tls { signatureAlgorithm = verifyingCert.GetLegacySignatureAlgorithm(); - short clientCertType = GetLegacyClientCertType(signatureAlgorithm); - if (clientCertType < 0 || !Arrays.Contains(certificateRequest.CertificateTypes, clientCertType)) - throw new TlsFatalAlert(AlertDescription.unsupported_certificate); + CheckClientCertificateType(certificateRequest, GetLegacyClientCertType(signatureAlgorithm), + AlertDescription.unsupported_certificate); } else { - signatureAlgorithm = sigAndHashAlg.Signature; + VerifySupportedSignatureAlgorithm(securityParameters.ServerSigAlgs, sigAndHashAlg); - // TODO Is it possible (maybe only pre-1.2 to check this immediately when the Certificate arrives? - if (!IsValidSignatureAlgorithmForCertificateVerify(signatureAlgorithm, - certificateRequest.CertificateTypes)) - { - throw new TlsFatalAlert(AlertDescription.illegal_parameter); - } + signatureAlgorithm = sigAndHashAlg.Signature; - VerifySupportedSignatureAlgorithm(securityParameters.ServerSigAlgs, sigAndHashAlg); + CheckClientCertificateType(certificateRequest, + SignatureAlgorithm.GetClientCertificateType(signatureAlgorithm), AlertDescription.illegal_parameter); } // Verify the CertificateVerify message contains a correct signature. @@ -2251,7 +2252,7 @@ namespace Org.BouncyCastle.Tls if (streamVerifier != null) { - handshakeHash.CopyBufferTo(streamVerifier.GetOutputStream()); + handshakeHash.CopyBufferTo(streamVerifier.Stream); verified = streamVerifier.IsVerified(); } else @@ -2259,10 +2260,7 @@ namespace Org.BouncyCastle.Tls byte[] hash; if (IsTlsV12(serverContext)) { - int signatureScheme = SignatureScheme.From(sigAndHashAlg); - int cryptoHashAlgorithm = SignatureScheme.GetCryptoHashAlgorithm(signatureScheme); - - hash = handshakeHash.GetFinalHash(cryptoHashAlgorithm); + hash = handshakeHash.GetFinalHash(SignatureScheme.GetCryptoHashAlgorithm(sigAndHashAlg)); } else { @@ -2287,62 +2285,54 @@ namespace Org.BouncyCastle.Tls } } + /// <exception cref="IOException"/> internal static void Verify13CertificateVerifyClient(TlsServerContext serverContext, - CertificateRequest certificateRequest, DigitallySigned certificateVerify, TlsHandshakeHash handshakeHash) + TlsHandshakeHash handshakeHash, CertificateVerify certificateVerify) { SecurityParameters securityParameters = serverContext.SecurityParameters; - Certificate clientCertificate = securityParameters.PeerCertificate; - TlsCertificate verifyingCert = clientCertificate.GetCertificateAt(0); - - SignatureAndHashAlgorithm sigAndHashAlg = certificateVerify.Algorithm; - VerifySupportedSignatureAlgorithm(securityParameters.ServerSigAlgs, sigAndHashAlg); - - int signatureScheme = SignatureScheme.From(sigAndHashAlg); - - // Verify the CertificateVerify message contains a correct signature. - bool verified; - try - { - TlsVerifier verifier = verifyingCert.CreateVerifier(signatureScheme); - verified = Verify13CertificateVerify(serverContext.Crypto, certificateVerify, verifier, - "TLS 1.3, client CertificateVerify", handshakeHash); - } - catch (TlsFatalAlert e) - { - throw e; - } - catch (Exception e) - { - throw new TlsFatalAlert(AlertDescription.decrypt_error, e); - } + IList supportedAlgorithms = securityParameters.ServerSigAlgs; + TlsCertificate certificate = securityParameters.PeerCertificate.GetCertificateAt(0); - if (!verified) - { - throw new TlsFatalAlert(AlertDescription.decrypt_error); - } + Verify13CertificateVerify(supportedAlgorithms, "TLS 1.3, client CertificateVerify", handshakeHash, + certificate, certificateVerify); } + /// <exception cref="IOException"/> internal static void Verify13CertificateVerifyServer(TlsClientContext clientContext, - DigitallySigned certificateVerify, TlsHandshakeHash handshakeHash) + TlsHandshakeHash handshakeHash, CertificateVerify certificateVerify) { SecurityParameters securityParameters = clientContext.SecurityParameters; - Certificate serverCertificate = securityParameters.PeerCertificate; - TlsCertificate verifyingCert = serverCertificate.GetCertificateAt(0); - SignatureAndHashAlgorithm sigAndHashAlg = certificateVerify.Algorithm; - VerifySupportedSignatureAlgorithm(securityParameters.ClientSigAlgs, sigAndHashAlg); + IList supportedAlgorithms = securityParameters.ClientSigAlgs; + TlsCertificate certificate = securityParameters.PeerCertificate.GetCertificateAt(0); - int signatureScheme = SignatureScheme.From(sigAndHashAlg); + Verify13CertificateVerify(supportedAlgorithms, "TLS 1.3, server CertificateVerify", handshakeHash, + certificate, certificateVerify); + } + /// <exception cref="IOException"/> + private static void Verify13CertificateVerify(IList supportedAlgorithms, string contextString, + TlsHandshakeHash handshakeHash, TlsCertificate certificate, CertificateVerify certificateVerify) + { // Verify the CertificateVerify message contains a correct signature. bool verified; try { - TlsVerifier verifier = verifyingCert.CreateVerifier(signatureScheme); + int signatureScheme = certificateVerify.Algorithm; + + SignatureAndHashAlgorithm algorithm = SignatureScheme.GetSignatureAndHashAlgorithm(signatureScheme); + VerifySupportedSignatureAlgorithm(supportedAlgorithms, algorithm); + + Tls13Verifier verifier = certificate.CreateVerifier(signatureScheme); + + byte[] header = GetCertificateVerifyHeader(contextString); + byte[] prfHash = GetCurrentPrfHash(handshakeHash); - verified = Verify13CertificateVerify(clientContext.Crypto, certificateVerify, verifier, - "TLS 1.3, server CertificateVerify", handshakeHash); + Stream output = verifier.Stream; + output.Write(header, 0, header.Length); + output.Write(prfHash, 0, prfHash.Length); + verified = verifier.VerifySignature(certificateVerify.Signature); } catch (TlsFatalAlert e) { @@ -2359,32 +2349,6 @@ namespace Org.BouncyCastle.Tls } } - private static bool Verify13CertificateVerify(TlsCrypto crypto, DigitallySigned certificateVerify, - TlsVerifier verifier, string contextString, TlsHandshakeHash handshakeHash) - { - TlsStreamVerifier streamVerifier = verifier.GetStreamVerifier(certificateVerify); - - byte[] header = GetCertificateVerifyHeader(contextString); - byte[] prfHash = GetCurrentPrfHash(handshakeHash); - - if (null != streamVerifier) - { - Stream output = streamVerifier.GetOutputStream(); - output.Write(header, 0, header.Length); - output.Write(prfHash, 0, prfHash.Length); - return streamVerifier.IsVerified(); - } - - int signatureScheme = SignatureScheme.From(certificateVerify.Algorithm); - int cryptoHashAlgorithm = SignatureScheme.GetCryptoHashAlgorithm(signatureScheme); - - TlsHash tlsHash = crypto.CreateHash(cryptoHashAlgorithm); - tlsHash.Update(header, 0, header.Length); - tlsHash.Update(prfHash, 0, prfHash.Length); - byte[] hash = tlsHash.CalculateHash(); - return verifier.VerifyRawSignature(certificateVerify, hash); - } - private static byte[] GetCertificateVerifyHeader(string contextString) { int count = contextString.Length; @@ -2409,13 +2373,13 @@ namespace Org.BouncyCastle.Tls /* * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2 */ - SignatureAndHashAlgorithm algorithm = GetSignatureAndHashAlgorithm(context, credentials); + SignatureAndHashAlgorithm algorithm = GetSignatureAndHashAlgorithm(context.ServerVersion, credentials); TlsStreamSigner streamSigner = credentials.GetStreamSigner(); byte[] signature; if (streamSigner != null) { - SendSignatureInput(context, extraSignatureInput, digestBuffer, streamSigner.GetOutputStream()); + SendSignatureInput(context, extraSignatureInput, digestBuffer, streamSigner.Stream); signature = streamSigner.GetSignature(); } else @@ -2461,7 +2425,7 @@ namespace Org.BouncyCastle.Tls bool verified; if (streamVerifier != null) { - SendSignatureInput(context, null, digestBuffer, streamVerifier.GetOutputStream()); + SendSignatureInput(context, null, digestBuffer, streamVerifier.Stream); verified = streamVerifier.IsVerified(); } else @@ -2476,28 +2440,28 @@ namespace Org.BouncyCastle.Tls } } + internal static void TrackHashAlgorithmClient(TlsHandshakeHash handshakeHash, + SignatureAndHashAlgorithm signatureAndHashAlgorithm) + { + int cryptoHashAlgorithm = SignatureScheme.GetCryptoHashAlgorithm(signatureAndHashAlgorithm); + if (cryptoHashAlgorithm >= 0) + { + handshakeHash.TrackHashAlgorithm(cryptoHashAlgorithm); + } + } + internal static void TrackHashAlgorithms(TlsHandshakeHash handshakeHash, IList supportedSignatureAlgorithms) { - if (supportedSignatureAlgorithms != null) + foreach (SignatureAndHashAlgorithm signatureAndHashAlgorithm in supportedSignatureAlgorithms) { - foreach (SignatureAndHashAlgorithm signatureAndHashAlgorithm in supportedSignatureAlgorithms) + int cryptoHashAlgorithm = SignatureScheme.GetCryptoHashAlgorithm(signatureAndHashAlgorithm); + if (cryptoHashAlgorithm >= 0) { - /* - * TODO We could validate the signature algorithm part. Currently the impact is - * that we might be tracking extra hashes pointlessly (but there are only a - * limited number of recognized hash algorithms). - */ - int signatureScheme = SignatureScheme.From(signatureAndHashAlgorithm); - int cryptoHashAlgorithm = SignatureScheme.GetCryptoHashAlgorithm(signatureScheme); - - if (cryptoHashAlgorithm >= 0) - { - handshakeHash.TrackHashAlgorithm(cryptoHashAlgorithm); - } - else if (HashAlgorithm.Intrinsic == signatureAndHashAlgorithm.Hash) - { - handshakeHash.ForceBuffering(); - } + handshakeHash.TrackHashAlgorithm(cryptoHashAlgorithm); + } + else if (HashAlgorithm.Intrinsic == signatureAndHashAlgorithm.Hash) + { + handshakeHash.ForceBuffering(); } } } @@ -3896,14 +3860,6 @@ namespace Org.BouncyCastle.Tls && NamedGroup.CanBeNegotiated(keyShareGroup, negotiatedVersion); } - internal static bool IsValidSignatureAlgorithmForCertificateVerify(short signatureAlgorithm, - short[] clientCertificateTypes) - { - short clientCertificateType = SignatureAlgorithm.GetClientCertificateType(signatureAlgorithm); - - return clientCertificateType >= 0 && Arrays.Contains(clientCertificateTypes, clientCertificateType); - } - internal static bool IsValidSignatureAlgorithmForServerKeyExchange(short signatureAlgorithm, int keyExchangeAlgorithm) { @@ -4238,21 +4194,14 @@ namespace Org.BouncyCastle.Tls return handshakeHash.ForkPrfHash().CalculateHash(); } - internal static void SealHandshakeHash(TlsContext context, TlsHandshakeHash handshakeHash, bool forceBuffering) + private static TlsHash CreateHash(TlsCrypto crypto, short hashAlgorithm) { - if (forceBuffering || !context.Crypto.HasAllRawSignatureAlgorithms()) - { - handshakeHash.ForceBuffering(); - } - - handshakeHash.SealHashAlgorithms(); + return crypto.CreateHash(TlsCryptoUtilities.GetHash(hashAlgorithm)); } - private static TlsHash CreateHash(TlsCrypto crypto, short hashAlgorithm) + private static TlsHash CreateHash(TlsCrypto crypto, SignatureAndHashAlgorithm signatureAndHashAlgorithm) { - int cryptoHashAlgorithm = TlsCryptoUtilities.GetHash(hashAlgorithm); - - return crypto.CreateHash(cryptoHashAlgorithm); + return crypto.CreateHash(SignatureScheme.GetCryptoHashAlgorithm(signatureAndHashAlgorithm)); } /// <exception cref="IOException"/> @@ -4793,6 +4742,17 @@ namespace Org.BouncyCastle.Tls return (TlsCredentialedSigner)credentials; } + /// <exception cref="IOException"/> + private static void CheckClientCertificateType(CertificateRequest certificateRequest, + short clientCertificateType, short alertDescription) + { + if (clientCertificateType < 0 + || !Arrays.Contains(certificateRequest.CertificateTypes, clientCertificateType)) + { + throw new TlsFatalAlert(alertDescription); + } + } + private static void CheckDowngradeMarker(byte[] randomBlock, byte[] downgradeMarker) { int len = downgradeMarker.Length; @@ -4839,8 +4799,11 @@ namespace Org.BouncyCastle.Tls MemoryStream buf) { SecurityParameters securityParameters = clientContext.SecurityParameters; - if (null != securityParameters.PeerCertificate) + if (KeyExchangeAlgorithm.IsAnonymous(securityParameters.KeyExchangeAlgorithm) + || null != securityParameters.PeerCertificate) + { throw new TlsFatalAlert(AlertDescription.unexpected_message); + } MemoryStream endPointHash = new MemoryStream(); diff --git a/crypto/src/tls/crypto/CryptoSignatureAlgorithm.cs b/crypto/src/tls/crypto/CryptoSignatureAlgorithm.cs
index ed58820b8..15435cab5 100644 --- a/crypto/src/tls/crypto/CryptoSignatureAlgorithm.cs +++ b/crypto/src/tls/crypto/CryptoSignatureAlgorithm.cs
@@ -15,6 +15,9 @@ namespace Org.BouncyCastle.Tls.Crypto public const int rsa_pss_pss_sha256 = 9; public const int rsa_pss_pss_sha384 = 10; public const int rsa_pss_pss_sha512 = 11; + public const int ecdsa_brainpoolP256r1tls13_sha256 = 26; + public const int ecdsa_brainpoolP384r1tls13_sha384 = 27; + public const int ecdsa_brainpoolP512r1tls13_sha512 = 28; public const int gostr34102012_256 = 64; public const int gostr34102012_512 = 65; public const int sm2 = 200; diff --git a/crypto/src/tls/crypto/Tls13Verifier.cs b/crypto/src/tls/crypto/Tls13Verifier.cs new file mode 100644
index 000000000..143ea7394 --- /dev/null +++ b/crypto/src/tls/crypto/Tls13Verifier.cs
@@ -0,0 +1,14 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Tls.Crypto +{ + public interface Tls13Verifier + { + /// <exception cref="IOException"/> + Stream Stream { get; } + + /// <exception cref="IOException"/> + bool VerifySignature(byte[] signature); + } +} diff --git a/crypto/src/tls/crypto/TlsCertificate.cs b/crypto/src/tls/crypto/TlsCertificate.cs
index fe507a662..6b3e3220a 100644 --- a/crypto/src/tls/crypto/TlsCertificate.cs +++ b/crypto/src/tls/crypto/TlsCertificate.cs
@@ -21,7 +21,7 @@ namespace Org.BouncyCastle.Tls.Crypto /// <param name="signatureScheme"><see cref="SignatureScheme"/></param> /// <exception cref="IOException"/> - TlsVerifier CreateVerifier(int signatureScheme); + Tls13Verifier CreateVerifier(int signatureScheme); /// <exception cref="IOException"/> byte[] GetEncoded(); diff --git a/crypto/src/tls/crypto/TlsCrypto.cs b/crypto/src/tls/crypto/TlsCrypto.cs
index 4dab6bc57..27c5fb9e1 100644 --- a/crypto/src/tls/crypto/TlsCrypto.cs +++ b/crypto/src/tls/crypto/TlsCrypto.cs
@@ -1,4 +1,5 @@ using System; +using System.Collections; using System.IO; using Org.BouncyCastle.Math; @@ -10,11 +11,22 @@ namespace Org.BouncyCastle.Tls.Crypto /// cryptography in the API.</summary> public interface TlsCrypto { - /// <summary>Return true if this TlsCrypto can perform raw signatures and verifications for all supported - /// algorithms.</summary> - /// <returns>true if this instance can perform raw signatures and verifications for all supported algorithms, - /// false otherwise.</returns> - bool HasAllRawSignatureAlgorithms(); + /// <summary>Return true if this TlsCrypto would use a stream verifier for any of the passed in algorithms. + /// </summary> + /// <remarks>This method is only relevant to handshakes negotiating (D)TLS 1.2.</remarks> + /// <param name="signatureAndHashAlgorithms">A <see cref="IList">list</see> of + /// <see cref="SignatureAndHashAlgorithm"/> values.</param> + /// <returns>true if this instance would use a stream verifier for any of the passed in algorithms, otherwise + /// false.</returns> + bool HasAnyStreamVerifiers(IList signatureAndHashAlgorithms); + + /// <summary>Return true if this TlsCrypto would use a stream verifier for any of the passed in algorithms. + /// </summary> + /// <remarks>This method is only relevant to handshakes negotiating (D)TLS versions older than 1.2.</remarks> + /// <param name="clientCertificateTypes">An array of <see cref="ClientCertificateType"/> values.</param> + /// <returns>true if this instance would use a stream verifier for any of the passed in algorithms, otherwise + /// false.</returns> + bool HasAnyStreamVerifiersLegacy(short[] clientCertificateTypes); /// <summary>Return true if this TlsCrypto can support the passed in hash algorithm.</summary> /// <param name="cryptoHashAlgorithm">the algorithm of interest.</param> diff --git a/crypto/src/tls/crypto/TlsCryptoUtilities.cs b/crypto/src/tls/crypto/TlsCryptoUtilities.cs
index 757eda1be..98ac87a83 100644 --- a/crypto/src/tls/crypto/TlsCryptoUtilities.cs +++ b/crypto/src/tls/crypto/TlsCryptoUtilities.cs
@@ -1,6 +1,11 @@ using System; using System.IO; +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X509; + namespace Org.BouncyCastle.Tls.Crypto { public abstract class TlsCryptoUtilities @@ -108,6 +113,30 @@ namespace Org.BouncyCastle.Tls.Crypto } } + public static DerObjectIdentifier GetOidForHash(int cryptoHashAlgorithm) + { + switch (cryptoHashAlgorithm) + { + case CryptoHashAlgorithm.md5: + return PkcsObjectIdentifiers.MD5; + case CryptoHashAlgorithm.sha1: + return X509ObjectIdentifiers.IdSha1; + case CryptoHashAlgorithm.sha224: + return NistObjectIdentifiers.IdSha224; + case CryptoHashAlgorithm.sha256: + return NistObjectIdentifiers.IdSha256; + case CryptoHashAlgorithm.sha384: + return NistObjectIdentifiers.IdSha384; + case CryptoHashAlgorithm.sha512: + return NistObjectIdentifiers.IdSha512; + // TODO[RFC 8998] + //case CryptoHashAlgorithm.sm3: + // return GMObjectIdentifiers.sm3; + default: + throw new ArgumentException(); + } + } + public static int GetSignature(short signatureAlgorithm) { switch (signatureAlgorithm) @@ -134,6 +163,12 @@ namespace Org.BouncyCastle.Tls.Crypto return CryptoSignatureAlgorithm.rsa_pss_pss_sha384; case SignatureAlgorithm.rsa_pss_pss_sha512: return CryptoSignatureAlgorithm.rsa_pss_pss_sha512; + case SignatureAlgorithm.ecdsa_brainpoolP256r1tls13_sha256: + return CryptoSignatureAlgorithm.ecdsa_brainpoolP256r1tls13_sha256; + case SignatureAlgorithm.ecdsa_brainpoolP384r1tls13_sha384: + return CryptoSignatureAlgorithm.ecdsa_brainpoolP384r1tls13_sha384; + case SignatureAlgorithm.ecdsa_brainpoolP512r1tls13_sha512: + return CryptoSignatureAlgorithm.ecdsa_brainpoolP512r1tls13_sha512; case SignatureAlgorithm.gostr34102012_256: return CryptoSignatureAlgorithm.gostr34102012_256; case SignatureAlgorithm.gostr34102012_512: diff --git a/crypto/src/tls/crypto/TlsStreamSigner.cs b/crypto/src/tls/crypto/TlsStreamSigner.cs
index 8f79346bf..c3634fe27 100644 --- a/crypto/src/tls/crypto/TlsStreamSigner.cs +++ b/crypto/src/tls/crypto/TlsStreamSigner.cs
@@ -6,7 +6,7 @@ namespace Org.BouncyCastle.Tls.Crypto public interface TlsStreamSigner { /// <exception cref="IOException"/> - Stream GetOutputStream(); + Stream Stream { get; } /// <exception cref="IOException"/> byte[] GetSignature(); diff --git a/crypto/src/tls/crypto/TlsStreamVerifier.cs b/crypto/src/tls/crypto/TlsStreamVerifier.cs
index 9d18a9c9c..33b0e3879 100644 --- a/crypto/src/tls/crypto/TlsStreamVerifier.cs +++ b/crypto/src/tls/crypto/TlsStreamVerifier.cs
@@ -6,7 +6,7 @@ namespace Org.BouncyCastle.Tls.Crypto public interface TlsStreamVerifier { /// <exception cref="IOException"/> - Stream GetOutputStream(); + Stream Stream { get; } /// <exception cref="IOException"/> bool IsVerified(); diff --git a/crypto/src/tls/crypto/impl/AbstractTlsCrypto.cs b/crypto/src/tls/crypto/impl/AbstractTlsCrypto.cs
index 39d86c241..87fe66dff 100644 --- a/crypto/src/tls/crypto/impl/AbstractTlsCrypto.cs +++ b/crypto/src/tls/crypto/impl/AbstractTlsCrypto.cs
@@ -1,5 +1,5 @@ using System; -using System.IO; +using System.Collections; using Org.BouncyCastle.Math; using Org.BouncyCastle.Security; @@ -12,7 +12,9 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl public abstract class AbstractTlsCrypto : TlsCrypto { - public abstract bool HasAllRawSignatureAlgorithms(); + public abstract bool HasAnyStreamVerifiers(IList signatureAndHashAlgorithms); + + public abstract bool HasAnyStreamVerifiersLegacy(short[] clientCertificateTypes); public abstract bool HasCryptoHashAlgorithm(int cryptoHashAlgorithm); diff --git a/crypto/src/tls/crypto/impl/LegacyTls13Verifier.cs b/crypto/src/tls/crypto/impl/LegacyTls13Verifier.cs new file mode 100644
index 000000000..294a14da4 --- /dev/null +++ b/crypto/src/tls/crypto/impl/LegacyTls13Verifier.cs
@@ -0,0 +1,60 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Tls.Crypto.Impl +{ + public sealed class LegacyTls13Verifier + : TlsVerifier + { + private readonly int m_signatureScheme; + private readonly Tls13Verifier m_tls13Verifier; + + public LegacyTls13Verifier(int signatureScheme, Tls13Verifier tls13Verifier) + { + if (!TlsUtilities.IsValidUint16(signatureScheme)) + throw new ArgumentException("signatureScheme"); + if (tls13Verifier == null) + throw new ArgumentNullException("tls13Verifier"); + + this.m_signatureScheme = signatureScheme; + this.m_tls13Verifier = tls13Verifier; + } + + public TlsStreamVerifier GetStreamVerifier(DigitallySigned digitallySigned) + { + SignatureAndHashAlgorithm algorithm = digitallySigned.Algorithm; + if (algorithm == null || SignatureScheme.From(algorithm) != m_signatureScheme) + throw new InvalidOperationException("Invalid algorithm: " + algorithm); + + return new TlsStreamVerifierImpl(m_tls13Verifier, digitallySigned.Signature); + } + + public bool VerifyRawSignature(DigitallySigned digitallySigned, byte[] hash) + { + throw new NotSupportedException(); + } + + private class TlsStreamVerifierImpl + : TlsStreamVerifier + { + private readonly Tls13Verifier m_tls13Verifier; + private readonly byte[] m_signature; + + internal TlsStreamVerifierImpl(Tls13Verifier tls13Verifier, byte[] signature) + { + this.m_tls13Verifier = tls13Verifier; + this.m_signature = signature; + } + + public Stream Stream + { + get { return m_tls13Verifier.Stream; } + } + + public bool IsVerified() + { + return m_tls13Verifier.VerifySignature(m_signature); + } + } + } +} diff --git a/crypto/src/tls/crypto/impl/TlsAeadCipher.cs b/crypto/src/tls/crypto/impl/TlsAeadCipher.cs
index ec76e98c1..04f9ce80f 100644 --- a/crypto/src/tls/crypto/impl/TlsAeadCipher.cs +++ b/crypto/src/tls/crypto/impl/TlsAeadCipher.cs
@@ -175,14 +175,13 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl try { - m_encryptCipher.Init(nonce, m_macSize, additionalData); - Array.Copy(plaintext, plaintextOffset, output, outputPos, plaintextLength); if (m_isTlsV13) { output[outputPos + plaintextLength] = (byte)contentType; } + m_encryptCipher.Init(nonce, m_macSize, additionalData); outputPos += m_encryptCipher.DoFinal(output, outputPos, plaintextLength + extraLength, output, outputPos); } @@ -354,7 +353,7 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl Array.Copy(iv, 0, nonce, 0, m_fixed_iv_length); // NOTE: Ensure dummy nonce is not part of the generated sequence(s) - iv [0] ^= 0x80; + iv[0] ^= 0x80; cipher.Init(iv, m_macSize, null); } diff --git a/crypto/src/tls/crypto/impl/bc/BcTls13Verifier.cs b/crypto/src/tls/crypto/impl/bc/BcTls13Verifier.cs new file mode 100644
index 000000000..ba4d0ccf8 --- /dev/null +++ b/crypto/src/tls/crypto/impl/bc/BcTls13Verifier.cs
@@ -0,0 +1,32 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.IO; + +namespace Org.BouncyCastle.Tls.Crypto.Impl.BC +{ + internal sealed class BcTls13Verifier + : Tls13Verifier + { + private readonly SignerSink m_output; + + internal BcTls13Verifier(ISigner verifier) + { + if (verifier == null) + throw new ArgumentNullException("verifier"); + + this.m_output = new SignerSink(verifier); + } + + public Stream Stream + { + get { return m_output; } + } + + public bool VerifySignature(byte[] signature) + { + return m_output.Signer.VerifySignature(signature); + } + } +} diff --git a/crypto/src/tls/crypto/impl/bc/BcTlsCertificate.cs b/crypto/src/tls/crypto/impl/bc/BcTlsCertificate.cs
index 469785dc2..7e946ce23 100644 --- a/crypto/src/tls/crypto/impl/bc/BcTlsCertificate.cs +++ b/crypto/src/tls/crypto/impl/bc/BcTlsCertificate.cs
@@ -4,7 +4,9 @@ using System.IO; using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Engines; using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Crypto.Signers; using Org.BouncyCastle.Math; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities; @@ -87,38 +89,56 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC { switch (signatureAlgorithm) { - case SignatureAlgorithm.rsa_pss_rsae_sha256: - case SignatureAlgorithm.rsa_pss_rsae_sha384: - case SignatureAlgorithm.rsa_pss_rsae_sha512: case SignatureAlgorithm.ed25519: case SignatureAlgorithm.ed448: - case SignatureAlgorithm.rsa_pss_pss_sha256: - case SignatureAlgorithm.rsa_pss_pss_sha384: - case SignatureAlgorithm.rsa_pss_pss_sha512: - return CreateVerifier(SignatureScheme.From(HashAlgorithm.Intrinsic, signatureAlgorithm)); + { + int signatureScheme = SignatureScheme.From(HashAlgorithm.Intrinsic, signatureAlgorithm); + Tls13Verifier tls13Verifier = CreateVerifier(signatureScheme); + return new LegacyTls13Verifier(signatureScheme, tls13Verifier); + } } ValidateKeyUsage(KeyUsage.DigitalSignature); switch (signatureAlgorithm) { - case SignatureAlgorithm.rsa: - ValidateRsa_Pkcs1(); - return new BcTlsRsaVerifier(m_crypto, GetPubKeyRsa()); - case SignatureAlgorithm.dsa: return new BcTlsDsaVerifier(m_crypto, GetPubKeyDss()); case SignatureAlgorithm.ecdsa: return new BcTlsECDsaVerifier(m_crypto, GetPubKeyEC()); + case SignatureAlgorithm.rsa: + { + ValidateRsa_Pkcs1(); + return new BcTlsRsaVerifier(m_crypto, GetPubKeyRsa()); + } + + case SignatureAlgorithm.rsa_pss_pss_sha256: + case SignatureAlgorithm.rsa_pss_pss_sha384: + case SignatureAlgorithm.rsa_pss_pss_sha512: + { + ValidateRsa_Pss_Pss(signatureAlgorithm); + int signatureScheme = SignatureScheme.From(HashAlgorithm.Intrinsic, signatureAlgorithm); + return new BcTlsRsaPssVerifier(m_crypto, GetPubKeyRsa(), signatureScheme); + } + + case SignatureAlgorithm.rsa_pss_rsae_sha256: + case SignatureAlgorithm.rsa_pss_rsae_sha384: + case SignatureAlgorithm.rsa_pss_rsae_sha512: + { + ValidateRsa_Pss_Rsae(); + int signatureScheme = SignatureScheme.From(HashAlgorithm.Intrinsic, signatureAlgorithm); + return new BcTlsRsaPssVerifier(m_crypto, GetPubKeyRsa(), signatureScheme); + } + default: throw new TlsFatalAlert(AlertDescription.certificate_unknown); } } /// <exception cref="IOException"/> - public virtual TlsVerifier CreateVerifier(int signatureScheme) + public virtual Tls13Verifier CreateVerifier(int signatureScheme) { ValidateKeyUsage(KeyUsage.DigitalSignature); @@ -131,13 +151,31 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC case SignatureScheme.ecdsa_secp384r1_sha384: case SignatureScheme.ecdsa_secp521r1_sha512: case SignatureScheme.ecdsa_sha1: - return new BcTlsECDsa13Verifier(m_crypto, GetPubKeyEC(), signatureScheme); + { + int cryptoHashAlgorithm = SignatureScheme.GetCryptoHashAlgorithm(signatureScheme); + IDigest digest = m_crypto.CreateDigest(cryptoHashAlgorithm); + + ISigner verifier = new DsaDigestSigner(new ECDsaSigner(), digest); + verifier.Init(false, GetPubKeyEC()); + + return new BcTls13Verifier(verifier); + } case SignatureScheme.ed25519: - return new BcTlsEd25519Verifier(m_crypto, GetPubKeyEd25519()); + { + Ed25519Signer verifier = new Ed25519Signer(); + verifier.Init(false, GetPubKeyEd25519()); + + return new BcTls13Verifier(verifier); + } case SignatureScheme.ed448: - return new BcTlsEd448Verifier(m_crypto, GetPubKeyEd448()); + { + Ed448Signer verifier = new Ed448Signer(TlsUtilities.EmptyBytes); + verifier.Init(false, GetPubKeyEd448()); + + return new BcTls13Verifier(verifier); + } case SignatureScheme.rsa_pkcs1_sha1: case SignatureScheme.rsa_pkcs1_sha256: @@ -145,7 +183,15 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC case SignatureScheme.rsa_pkcs1_sha512: { ValidateRsa_Pkcs1(); - return new BcTlsRsaVerifier(m_crypto, GetPubKeyRsa()); + + int cryptoHashAlgorithm = SignatureScheme.GetCryptoHashAlgorithm(signatureScheme); + IDigest digest = m_crypto.CreateDigest(cryptoHashAlgorithm); + + RsaDigestSigner verifier = new RsaDigestSigner(digest, + TlsCryptoUtilities.GetOidForHash(cryptoHashAlgorithm)); + verifier.Init(false, GetPubKeyRsa()); + + return new BcTls13Verifier(verifier); } case SignatureScheme.rsa_pss_pss_sha256: @@ -153,7 +199,14 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC case SignatureScheme.rsa_pss_pss_sha512: { ValidateRsa_Pss_Pss(SignatureScheme.GetSignatureAlgorithm(signatureScheme)); - return new BcTlsRsaPssVerifier(m_crypto, GetPubKeyRsa(), signatureScheme); + + int cryptoHashAlgorithm = SignatureScheme.GetCryptoHashAlgorithm(signatureScheme); + IDigest digest = m_crypto.CreateDigest(cryptoHashAlgorithm); + + PssSigner verifier = new PssSigner(new RsaEngine(), digest, digest.GetDigestSize()); + verifier.Init(false, GetPubKeyRsa()); + + return new BcTls13Verifier(verifier); } case SignatureScheme.rsa_pss_rsae_sha256: @@ -161,12 +214,27 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC case SignatureScheme.rsa_pss_rsae_sha512: { ValidateRsa_Pss_Rsae(); - return new BcTlsRsaPssVerifier(m_crypto, GetPubKeyRsa(), signatureScheme); + + int cryptoHashAlgorithm = SignatureScheme.GetCryptoHashAlgorithm(signatureScheme); + IDigest digest = m_crypto.CreateDigest(cryptoHashAlgorithm); + + PssSigner verifier = new PssSigner(new RsaEngine(), digest, digest.GetDigestSize()); + verifier.Init(false, GetPubKeyRsa()); + + return new BcTls13Verifier(verifier); } // TODO[RFC 8998] //case SignatureScheme.sm2sig_sm3: - // return new BcTlsSM2Verifier(m_crypto, GetPubKeyEC(), Strings.ToByteArray("TLSv1.3+GM+Cipher+Suite")); + //{ + // ParametersWithID parametersWithID = new ParametersWithID(GetPubKeyEC(), + // Strings.ToByteArray("TLSv1.3+GM+Cipher+Suite")); + + // SM2Signer verifier = new SM2Signer(); + // verifier.Init(false, parametersWithID); + + // return new BcTls13Verifier(verifier); + //} default: throw new TlsFatalAlert(AlertDescription.certificate_unknown); diff --git a/crypto/src/tls/crypto/impl/bc/BcTlsCrypto.cs b/crypto/src/tls/crypto/impl/bc/BcTlsCrypto.cs
index a56835105..38062829e 100644 --- a/crypto/src/tls/crypto/impl/bc/BcTlsCrypto.cs +++ b/crypto/src/tls/crypto/impl/bc/BcTlsCrypto.cs
@@ -1,4 +1,5 @@ using System; +using System.Collections; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Agreement.Srp; @@ -152,9 +153,22 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC return new BcTlsNonceGenerator(randomGenerator); } - public override bool HasAllRawSignatureAlgorithms() + public override bool HasAnyStreamVerifiers(IList signatureAndHashAlgorithms) + { + foreach (SignatureAndHashAlgorithm algorithm in signatureAndHashAlgorithms) + { + switch (SignatureScheme.From(algorithm)) + { + case SignatureScheme.ed25519: + case SignatureScheme.ed448: + return true; + } + } + return false; + } + + public override bool HasAnyStreamVerifiersLegacy(short[] clientCertificateTypes) { - // TODO[RFC 8422] Revisit the need to buffer the handshake for "Intrinsic" hash signatures return false; } @@ -219,16 +233,39 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC { switch (encryptionAlgorithm) { - case EncryptionAlgorithm.DES40_CBC: + case EncryptionAlgorithm.AES_128_CBC: + case EncryptionAlgorithm.AES_128_CCM: + case EncryptionAlgorithm.AES_128_CCM_8: + case EncryptionAlgorithm.AES_128_GCM: + case EncryptionAlgorithm.AES_256_CBC: + case EncryptionAlgorithm.AES_256_CCM: + case EncryptionAlgorithm.AES_256_CCM_8: + case EncryptionAlgorithm.AES_256_GCM: + case EncryptionAlgorithm.ARIA_128_CBC: + case EncryptionAlgorithm.ARIA_128_GCM: + case EncryptionAlgorithm.ARIA_256_CBC: + case EncryptionAlgorithm.ARIA_256_GCM: + case EncryptionAlgorithm.CAMELLIA_128_CBC: + case EncryptionAlgorithm.CAMELLIA_128_GCM: + case EncryptionAlgorithm.CAMELLIA_256_CBC: + case EncryptionAlgorithm.CAMELLIA_256_GCM: + case EncryptionAlgorithm.CHACHA20_POLY1305: + case EncryptionAlgorithm.cls_3DES_EDE_CBC: + case EncryptionAlgorithm.NULL: + case EncryptionAlgorithm.SEED_CBC: + case EncryptionAlgorithm.SM4_CBC: + case EncryptionAlgorithm.SM4_CCM: + case EncryptionAlgorithm.SM4_GCM: + return true; + case EncryptionAlgorithm.DES_CBC: + case EncryptionAlgorithm.DES40_CBC: case EncryptionAlgorithm.IDEA_CBC: case EncryptionAlgorithm.RC2_CBC_40: case EncryptionAlgorithm.RC4_128: case EncryptionAlgorithm.RC4_40: - return false; - default: - return true; + return false; } } diff --git a/crypto/src/tls/crypto/impl/bc/BcTlsECDsa13Verifier.cs b/crypto/src/tls/crypto/impl/bc/BcTlsECDsa13Verifier.cs deleted file mode 100644
index 159b17c0b..000000000 --- a/crypto/src/tls/crypto/impl/bc/BcTlsECDsa13Verifier.cs +++ /dev/null
@@ -1,40 +0,0 @@ -using System; - -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Crypto.Digests; -using Org.BouncyCastle.Crypto.Parameters; -using Org.BouncyCastle.Crypto.Signers; - -namespace Org.BouncyCastle.Tls.Crypto.Impl.BC -{ - /// <summary>Implementation class for verification of ECDSA signatures in TLS 1.3+ using the BC light-weight API. - /// </summary> - public class BcTlsECDsa13Verifier - : BcTlsVerifier - { - private readonly int m_signatureScheme; - - public BcTlsECDsa13Verifier(BcTlsCrypto crypto, ECPublicKeyParameters publicKey, int signatureScheme) - : base(crypto, publicKey) - { - if (!SignatureScheme.IsECDsa(signatureScheme)) - throw new ArgumentException("signatureScheme"); - - this.m_signatureScheme = signatureScheme; - } - - public override bool VerifyRawSignature(DigitallySigned digitallySigned, byte[] hash) - { - SignatureAndHashAlgorithm algorithm = digitallySigned.Algorithm; - if (algorithm == null || SignatureScheme.From(algorithm) != m_signatureScheme) - throw new InvalidOperationException("Invalid algorithm: " + algorithm); - - IDsa dsa = new ECDsaSigner(); - - ISigner signer = new DsaDigestSigner(dsa, new NullDigest()); - signer.Init(false, m_publicKey); - signer.BlockUpdate(hash, 0, hash.Length); - return signer.VerifySignature(digitallySigned.Signature); - } - } -} diff --git a/crypto/src/tls/crypto/impl/bc/BcTlsEd25519Verifier.cs b/crypto/src/tls/crypto/impl/bc/BcTlsEd25519Verifier.cs deleted file mode 100644
index a787bb92a..000000000 --- a/crypto/src/tls/crypto/impl/bc/BcTlsEd25519Verifier.cs +++ /dev/null
@@ -1,28 +0,0 @@ -using System; - -using Org.BouncyCastle.Crypto.Parameters; -using Org.BouncyCastle.Crypto.Signers; - -namespace Org.BouncyCastle.Tls.Crypto.Impl.BC -{ - public class BcTlsEd25519Verifier - : BcTlsVerifier - { - public BcTlsEd25519Verifier(BcTlsCrypto crypto, Ed25519PublicKeyParameters publicKey) - : base(crypto, publicKey) - { - } - - public override TlsStreamVerifier GetStreamVerifier(DigitallySigned digitallySigned) - { - SignatureAndHashAlgorithm algorithm = digitallySigned.Algorithm; - if (algorithm == null || SignatureScheme.From(algorithm) != SignatureScheme.ed25519) - throw new InvalidOperationException("Invalid algorithm: " + algorithm); - - Ed25519Signer verifier = new Ed25519Signer(); - verifier.Init(false, m_publicKey); - - return new BcTlsStreamVerifier(verifier, digitallySigned.Signature); - } - } -} diff --git a/crypto/src/tls/crypto/impl/bc/BcTlsEd448Verifier.cs b/crypto/src/tls/crypto/impl/bc/BcTlsEd448Verifier.cs deleted file mode 100644
index 7940d0757..000000000 --- a/crypto/src/tls/crypto/impl/bc/BcTlsEd448Verifier.cs +++ /dev/null
@@ -1,28 +0,0 @@ -using System; - -using Org.BouncyCastle.Crypto.Parameters; -using Org.BouncyCastle.Crypto.Signers; - -namespace Org.BouncyCastle.Tls.Crypto.Impl.BC -{ - public class BcTlsEd448Verifier - : BcTlsVerifier - { - public BcTlsEd448Verifier(BcTlsCrypto crypto, Ed448PublicKeyParameters publicKey) - : base(crypto, publicKey) - { - } - - public override TlsStreamVerifier GetStreamVerifier(DigitallySigned digitallySigned) - { - SignatureAndHashAlgorithm algorithm = digitallySigned.Algorithm; - if (algorithm == null || SignatureScheme.From(algorithm) != SignatureScheme.ed448) - throw new InvalidOperationException("Invalid algorithm: " + algorithm); - - Ed448Signer verifier = new Ed448Signer(TlsUtilities.EmptyBytes); - verifier.Init(false, m_publicKey); - - return new BcTlsStreamVerifier(verifier, digitallySigned.Signature); - } - } -} diff --git a/crypto/src/tls/crypto/impl/bc/BcTlsRsaPssSigner.cs b/crypto/src/tls/crypto/impl/bc/BcTlsRsaPssSigner.cs
index 3e7d1ceef..1b33573f6 100644 --- a/crypto/src/tls/crypto/impl/bc/BcTlsRsaPssSigner.cs +++ b/crypto/src/tls/crypto/impl/bc/BcTlsRsaPssSigner.cs
@@ -22,7 +22,7 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC this.m_signatureScheme = signatureScheme; } - public override TlsStreamSigner GetStreamSigner(SignatureAndHashAlgorithm algorithm) + public override byte[] GenerateRawSignature(SignatureAndHashAlgorithm algorithm, byte[] hash) { if (algorithm == null || SignatureScheme.From(algorithm) != m_signatureScheme) throw new InvalidOperationException("Invalid algorithm: " + algorithm); @@ -30,10 +30,18 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC int cryptoHashAlgorithm = SignatureScheme.GetCryptoHashAlgorithm(m_signatureScheme); IDigest digest = m_crypto.CreateDigest(cryptoHashAlgorithm); - PssSigner signer = new PssSigner(new RsaBlindedEngine(), digest, digest.GetDigestSize()); + PssSigner signer = PssSigner.CreateRawSigner(new RsaBlindedEngine(), digest, digest, digest.GetDigestSize(), + PssSigner.TrailerImplicit); signer.Init(true, new ParametersWithRandom(m_privateKey, m_crypto.SecureRandom)); - - return new BcTlsStreamSigner(signer); + signer.BlockUpdate(hash, 0, hash.Length); + try + { + return signer.GenerateSignature(); + } + catch (CryptoException e) + { + throw new TlsFatalAlert(AlertDescription.internal_error, e); + } } } } diff --git a/crypto/src/tls/crypto/impl/bc/BcTlsRsaPssVerifier.cs b/crypto/src/tls/crypto/impl/bc/BcTlsRsaPssVerifier.cs
index dc8cebdd9..18c2082aa 100644 --- a/crypto/src/tls/crypto/impl/bc/BcTlsRsaPssVerifier.cs +++ b/crypto/src/tls/crypto/impl/bc/BcTlsRsaPssVerifier.cs
@@ -22,7 +22,7 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC this.m_signatureScheme = signatureScheme; } - public override TlsStreamVerifier GetStreamVerifier(DigitallySigned digitallySigned) + public override bool VerifyRawSignature(DigitallySigned digitallySigned, byte[] hash) { SignatureAndHashAlgorithm algorithm = digitallySigned.Algorithm; if (algorithm == null || SignatureScheme.From(algorithm) != m_signatureScheme) @@ -31,10 +31,11 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC int cryptoHashAlgorithm = SignatureScheme.GetCryptoHashAlgorithm(m_signatureScheme); IDigest digest = m_crypto.CreateDigest(cryptoHashAlgorithm); - PssSigner verifier = new PssSigner(new RsaEngine(), digest, digest.GetDigestSize()); + PssSigner verifier = PssSigner.CreateRawSigner(new RsaEngine(), digest, digest, digest.GetDigestSize(), + PssSigner.TrailerImplicit); verifier.Init(false, m_publicKey); - - return new BcTlsStreamVerifier(verifier, digitallySigned.Signature); + verifier.BlockUpdate(hash, 0, hash.Length); + return verifier.VerifySignature(digitallySigned.Signature); } } } diff --git a/crypto/src/tls/crypto/impl/bc/BcTlsStreamSigner.cs b/crypto/src/tls/crypto/impl/bc/BcTlsStreamSigner.cs
index 158fb053e..21db0af8e 100644 --- a/crypto/src/tls/crypto/impl/bc/BcTlsStreamSigner.cs +++ b/crypto/src/tls/crypto/impl/bc/BcTlsStreamSigner.cs
@@ -16,9 +16,9 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC this.m_output = new SignerSink(signer); } - public Stream GetOutputStream() + public Stream Stream { - return m_output; + get { return m_output; } } public byte[] GetSignature() diff --git a/crypto/src/tls/crypto/impl/bc/BcTlsStreamVerifier.cs b/crypto/src/tls/crypto/impl/bc/BcTlsStreamVerifier.cs
index 0848a30dd..edf13e6ec 100644 --- a/crypto/src/tls/crypto/impl/bc/BcTlsStreamVerifier.cs +++ b/crypto/src/tls/crypto/impl/bc/BcTlsStreamVerifier.cs
@@ -18,9 +18,9 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC this.m_signature = signature; } - public Stream GetOutputStream() + public Stream Stream { - return m_output; + get { return m_output; } } public bool IsVerified() diff --git a/crypto/src/tls/crypto/impl/bc/BcVerifyingStreamSigner.cs b/crypto/src/tls/crypto/impl/bc/BcVerifyingStreamSigner.cs
index 4d9506857..4093fc52f 100644 --- a/crypto/src/tls/crypto/impl/bc/BcVerifyingStreamSigner.cs +++ b/crypto/src/tls/crypto/impl/bc/BcVerifyingStreamSigner.cs
@@ -24,9 +24,9 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC this.m_output = new TeeOutputStream(outputSigner, outputVerifier); } - public Stream GetOutputStream() + public Stream Stream { - return m_output; + get { return m_output; } } public byte[] GetSignature()