diff options
Diffstat (limited to 'crypto/src/tls/DtlsVerifier.cs')
-rw-r--r-- | crypto/src/tls/DtlsVerifier.cs | 108 |
1 files changed, 49 insertions, 59 deletions
diff --git a/crypto/src/tls/DtlsVerifier.cs b/crypto/src/tls/DtlsVerifier.cs index e691685e6..01437d648 100644 --- a/crypto/src/tls/DtlsVerifier.cs +++ b/crypto/src/tls/DtlsVerifier.cs @@ -1,89 +1,79 @@ -using System; -using System.IO; +using System.IO; +using Org.BouncyCastle.Security; using Org.BouncyCastle.Tls.Crypto; using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Tls { + /// <summary> + /// Implements cookie generation/verification for a DTLS server as described in RFC 4347, + /// 4.2.1. Denial of Service Countermeasures. + /// </summary> + /// <remarks> + /// RFC 4347 4.2.1 additionally recommends changing the secret frequently. This class does not handle that + /// internally, so the instance should be replaced instead. + /// </remarks> public class DtlsVerifier { - private static TlsMac CreateCookieMac(TlsCrypto crypto) - { - TlsMac mac = crypto.CreateHmac(MacAlgorithm.hmac_sha256); - - byte[] secret = new byte[mac.MacLength]; - crypto.SecureRandom.NextBytes(secret); - - mac.SetKey(secret, 0, secret.Length); - - return mac; - } - - private readonly TlsMac m_cookieMac; - private readonly TlsMacSink m_cookieMacSink; + private readonly TlsCrypto m_crypto; + private readonly byte[] m_macKey; public DtlsVerifier(TlsCrypto crypto) { - this.m_cookieMac = CreateCookieMac(crypto); - this.m_cookieMacSink = new TlsMacSink(m_cookieMac); + m_crypto = crypto; + m_macKey = SecureRandom.GetNextBytes(crypto.SecureRandom, 32); } public virtual DtlsRequest VerifyRequest(byte[] clientID, byte[] data, int dataOff, int dataLen, DatagramSender sender) { - lock (this) + try { - bool resetCookieMac = true; + int msgLen = DtlsRecordLayer.ReceiveClientHelloRecord(data, dataOff, dataLen); + if (msgLen < 0) + return null; - try - { - m_cookieMac.Update(clientID, 0, clientID.Length); + int bodyLength = msgLen - DtlsReliableHandshake.MessageHeaderLength; + if (bodyLength < 39) // Minimum (syntactically) valid DTLS ClientHello length + return null; - DtlsRequest request = DtlsReliableHandshake.ReadClientRequest(data, dataOff, dataLen, - m_cookieMacSink); - if (null != request) - { - byte[] expectedCookie = m_cookieMac.CalculateMac(); - resetCookieMac = false; + int msgOff = dataOff + DtlsRecordLayer.RecordHeaderLength; - // TODO Consider stricter HelloVerifyRequest protocol - //switch (request.MessageSeq) - //{ - //case 0: - //{ - // DtlsReliableHandshake.SendHelloVerifyRequest(sender, request.RecordSeq, expectedCookie); - // break; - //} - //case 1: - //{ - // if (Arrays.FixedTimeEquals(expectedCookie, request.ClientHello.Cookie)) - // return request; + var buf = DtlsReliableHandshake.ReceiveClientHelloMessage(msg: data, msgOff, msgLen); + if (buf == null) + return null; - // break; - //} - //} + var macInput = new MemoryStream(bodyLength); + ClientHello clientHello = ClientHello.Parse(buf, dtlsOutput: macInput); + if (clientHello == null) + return null; - if (Arrays.FixedTimeEquals(expectedCookie, request.ClientHello.Cookie)) - return request; + long recordSeq = TlsUtilities.ReadUint48(data, dataOff + 5); - DtlsReliableHandshake.SendHelloVerifyRequest(sender, request.RecordSeq, expectedCookie); - } - } - catch (IOException) - { - // Ignore - } - finally + byte[] cookie = clientHello.Cookie; + + TlsMac mac = m_crypto.CreateHmac(MacAlgorithm.hmac_sha256); + mac.SetKey(m_macKey, 0, m_macKey.Length); + mac.Update(clientID, 0, clientID.Length); + macInput.WriteTo(new TlsMacSink(mac)); + byte[] expectedCookie = mac.CalculateMac(); + + if (Arrays.FixedTimeEquals(expectedCookie, cookie)) { - if (resetCookieMac) - { - m_cookieMac.Reset(); - } + byte[] message = TlsUtilities.CopyOfRangeExact(data, msgOff, msgOff + msgLen); + + return new DtlsRequest(recordSeq, message, clientHello); } - return null; + DtlsReliableHandshake.SendHelloVerifyRequest(sender, recordSeq, expectedCookie); + } + catch (IOException) + { + // Ignore } + + return null; } } } |