summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crypto/src/tls/AbstractTlsServer.cs5
-rw-r--r--crypto/src/tls/ClientHello.cs5
-rw-r--r--crypto/src/tls/HandshakeMessageInput.cs36
-rw-r--r--crypto/src/tls/OfferedPsks.cs29
-rw-r--r--crypto/src/tls/PskIdentity.cs17
-rw-r--r--crypto/src/tls/TlsServer.cs11
6 files changed, 96 insertions, 7 deletions
diff --git a/crypto/src/tls/AbstractTlsServer.cs b/crypto/src/tls/AbstractTlsServer.cs
index 7514e3618..f12233326 100644
--- a/crypto/src/tls/AbstractTlsServer.cs
+++ b/crypto/src/tls/AbstractTlsServer.cs
@@ -250,6 +250,11 @@ namespace Org.BouncyCastle.Tls
             return null;
         }
 
+        public virtual TlsPskExternal GetExternalPsk(IList identities)
+        {
+            return null;
+        }
+
         public virtual void NotifySession(TlsSession session)
         {
         }
diff --git a/crypto/src/tls/ClientHello.cs b/crypto/src/tls/ClientHello.cs
index 700d424cd..7f1018e89 100644
--- a/crypto/src/tls/ClientHello.cs
+++ b/crypto/src/tls/ClientHello.cs
@@ -70,6 +70,9 @@ namespace Org.BouncyCastle.Tls
         /// <exception cref="IOException"/>
         public void Encode(TlsContext context, Stream output)
         {
+            if (m_bindersSize < 0)
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+
             TlsUtilities.WriteVersion(m_version, output);
 
             output.Write(m_random, 0, m_random.Length);
@@ -168,7 +171,7 @@ namespace Org.BouncyCastle.Tls
                 extensions = TlsProtocol.ReadExtensionsDataClientHello(extBytes);
             }
 
-            return new ClientHello(clientVersion, random, sessionID, cookie, cipherSuites, extensions, 0);
+            return new ClientHello(clientVersion, random, sessionID, cookie, cipherSuites, extensions, -1);
         }
     }
 }
diff --git a/crypto/src/tls/HandshakeMessageInput.cs b/crypto/src/tls/HandshakeMessageInput.cs
index d7cd19994..c15112cc0 100644
--- a/crypto/src/tls/HandshakeMessageInput.cs
+++ b/crypto/src/tls/HandshakeMessageInput.cs
@@ -6,17 +6,51 @@ using Org.BouncyCastle.Utilities.IO;
 
 namespace Org.BouncyCastle.Tls
 {
+    // TODO Rewrite without MemoryStream
     public sealed class HandshakeMessageInput
         : MemoryStream
     {
+        private readonly int m_offset;
+
         internal HandshakeMessageInput(byte[] buf, int offset, int length)
-            : base(buf, offset, length, false)
+            : base(buf, offset, length, false, true)
         {
+#if PORTABLE
+            this.m_offset = 0;
+#else
+            this.m_offset = offset;
+#endif
         }
 
         public void UpdateHash(TlsHash hash)
         {
             Streams.WriteBufTo(this, new TlsHashSink(hash));
         }
+
+        internal void UpdateHashPrefix(TlsHash hash, int bindersSize)
+        {
+#if PORTABLE
+            byte[] buf = ToArray();
+            int count = buf.Length;
+#else
+            byte[] buf = GetBuffer();
+            int count = (int)Length;
+#endif
+
+            hash.Update(buf, m_offset, count - bindersSize);
+        }
+
+        internal void UpdateHashSuffix(TlsHash hash, int bindersSize)
+        {
+#if PORTABLE
+            byte[] buf = ToArray();
+            int count = buf.Length;
+#else
+            byte[] buf = GetBuffer();
+            int count = (int)Length;
+#endif
+
+            hash.Update(buf, m_offset + count - bindersSize, bindersSize);
+        }
     }
 }
diff --git a/crypto/src/tls/OfferedPsks.cs b/crypto/src/tls/OfferedPsks.cs
index 14b6448b4..9eddd2e23 100644
--- a/crypto/src/tls/OfferedPsks.cs
+++ b/crypto/src/tls/OfferedPsks.cs
@@ -28,21 +28,35 @@ namespace Org.BouncyCastle.Tls
 
         private readonly IList m_identities;
         private readonly IList m_binders;
+        private readonly int m_bindersSize;
 
         public OfferedPsks(IList identities)
-            : this(identities, null)
+            : this(identities, null, -1)
         {
         }
 
-        private OfferedPsks(IList identities, IList binders)
+        private OfferedPsks(IList identities, IList binders, int bindersSize)
         {
             if (null == identities || identities.Count < 1)
                 throw new ArgumentException("cannot be null or empty", "identities");
             if (null != binders && identities.Count != binders.Count)
                 throw new ArgumentException("must be the same length as 'identities' (or null)", "binders");
+            if ((null != binders) != (bindersSize >= 0))
+                throw new ArgumentException("must be >= 0 iff 'binders' are present", "bindersSize");
 
             this.m_identities = identities;
             this.m_binders = binders;
+            this.m_bindersSize = bindersSize;
+        }
+
+        internal byte[] GetBinderForIdentity(PskIdentity matchIdentity)
+        {
+            for (int i = 0, count = m_identities.Count; i < count; ++i)
+            {
+                if (matchIdentity.Equals(m_identities[i]))
+                    return (byte[])m_binders[i];
+            }
+            return null;
         }
 
         public IList Binders
@@ -50,6 +64,11 @@ namespace Org.BouncyCastle.Tls
             get { return m_binders; }
         }
 
+        public int BindersSize
+        {
+            get { return m_bindersSize; }
+        }
+
         public IList Identities
         {
             get { return m_identities; }
@@ -168,8 +187,8 @@ namespace Org.BouncyCastle.Tls
             }
 
             IList binders = Platform.CreateArrayList();
+            int totalLengthBinders = TlsUtilities.ReadUint16(input);
             {
-                int totalLengthBinders = TlsUtilities.ReadUint16(input);
                 if (totalLengthBinders < 33)
                     throw new TlsFatalAlert(AlertDescription.decode_error);
 
@@ -177,13 +196,13 @@ namespace Org.BouncyCastle.Tls
                 MemoryStream buf = new MemoryStream(bindersData, false);
                 do
                 {
-                    byte[] binder = TlsUtilities.ReadOpaque8(input, 32);
+                    byte[] binder = TlsUtilities.ReadOpaque8(buf, 32);
                     binders.Add(binder);
                 }
                 while (buf.Position < buf.Length);
             }
 
-            return new OfferedPsks(identities, binders);
+            return new OfferedPsks(identities, binders, 2 + totalLengthBinders);
         }
     }
 }
diff --git a/crypto/src/tls/PskIdentity.cs b/crypto/src/tls/PskIdentity.cs
index 082907419..1887d0af4 100644
--- a/crypto/src/tls/PskIdentity.cs
+++ b/crypto/src/tls/PskIdentity.cs
@@ -1,6 +1,8 @@
 using System;
 using System.IO;
 
+using Org.BouncyCastle.Utilities;
+
 namespace Org.BouncyCastle.Tls
 {
     public sealed class PskIdentity
@@ -48,5 +50,20 @@ namespace Org.BouncyCastle.Tls
             long obfuscatedTicketAge = TlsUtilities.ReadUint32(input);
             return new PskIdentity(identity, obfuscatedTicketAge);
         }
+
+        public override bool Equals(object obj)
+        {
+            PskIdentity that = obj as PskIdentity;
+            if (null == that)
+                return false;
+
+            return this.m_obfuscatedTicketAge == that.m_obfuscatedTicketAge
+                && Arrays.ConstantTimeAreEqual(this.m_identity, that.m_identity);
+        }
+
+        public override int GetHashCode()
+        {
+            return Arrays.GetHashCode(m_identity) ^ m_obfuscatedTicketAge.GetHashCode();
+        }
     }
 }
diff --git a/crypto/src/tls/TlsServer.cs b/crypto/src/tls/TlsServer.cs
index 783c8c14d..fe88d7c43 100644
--- a/crypto/src/tls/TlsServer.cs
+++ b/crypto/src/tls/TlsServer.cs
@@ -23,6 +23,17 @@ namespace Org.BouncyCastle.Tls
 
         byte[] GetNewSessionID();
 
+        /// <summary>Return the <see cref="TlsPskExternal">external PSK</see> to select from the ClientHello.</summary>
+        /// <remarks>
+        /// WARNING: EXPERIMENTAL FEATURE, UNSTABLE API
+        /// Note that this will only be called when TLS 1.3 or higher is amongst the offered protocol versions, and one
+        /// or more PSKs are actually offered.
+        /// </remarks>
+        /// <param name="identities">an <see cref="IList"/> of <see cref="PskIdentity"/> instances.</param>
+        /// <returns>The <see cref="TlsPskExternal"/> corresponding to the selected identity, or null to not select
+        /// any.</returns>
+        TlsPskExternal GetExternalPsk(IList identities);
+
         void NotifySession(TlsSession session);
 
         /// <exception cref="IOException"/>