1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
|
using System;
using System.Collections;
using System.IO;
using Org.BouncyCastle.Tls.Crypto;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Tls
{
public sealed class OfferedPsks
{
private readonly IList m_identities;
private readonly IList m_binders;
public OfferedPsks(IList identities)
: this(identities, null)
{
}
private OfferedPsks(IList identities, IList binders)
{
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");
this.m_identities = identities;
this.m_binders = binders;
}
public IList Binders
{
get { return m_binders; }
}
public IList Identities
{
get { return m_identities; }
}
/// <exception cref="IOException"/>
public void Encode(Stream output)
{
// identities
{
int lengthOfIdentitiesList = 0;
foreach (PskIdentity identity in m_identities)
{
lengthOfIdentitiesList += identity.GetEncodedLength();
}
TlsUtilities.CheckUint16(lengthOfIdentitiesList);
TlsUtilities.WriteUint16(lengthOfIdentitiesList, output);
foreach (PskIdentity identity in m_identities)
{
identity.Encode(output);
}
}
// binders
if (null != m_binders)
{
int lengthOfBindersList = 0;
foreach (byte[] binder in m_binders)
{
lengthOfBindersList += 1 + binder.Length;
}
TlsUtilities.CheckUint16(lengthOfBindersList);
TlsUtilities.WriteUint16(lengthOfBindersList, output);
foreach (byte[] binder in m_binders)
{
TlsUtilities.WriteOpaque8(binder, output);
}
}
}
/// <exception cref="IOException"/>
internal static void EncodeBinders(Stream output, TlsCrypto crypto, TlsHandshakeHash handshakeHash,
TlsPsk[] psks, TlsSecret[] earlySecrets, int expectedLengthOfBindersList)
{
TlsUtilities.CheckUint16(expectedLengthOfBindersList);
TlsUtilities.WriteUint16(expectedLengthOfBindersList, output);
int lengthOfBindersList = 0;
for (int i = 0; i < psks.Length; ++i)
{
TlsPsk psk = psks[i];
TlsSecret earlySecret = earlySecrets[i];
// TODO[tls13-psk] Handle resumption PSKs
bool isExternalPsk = true;
int pskCryptoHashAlgorithm = TlsCryptoUtilities.GetHashForPrf(psk.PrfAlgorithm);
// TODO[tls13-psk] Cache the transcript hashes per algorithm to avoid duplicates for multiple PSKs
TlsHash hash = crypto.CreateHash(pskCryptoHashAlgorithm);
handshakeHash.CopyBufferTo(new TlsHashSink(hash));
byte[] transcriptHash = hash.CalculateHash();
byte[] binder = TlsUtilities.CalculatePskBinder(crypto, isExternalPsk, pskCryptoHashAlgorithm,
earlySecret, transcriptHash);
lengthOfBindersList += 1 + binder.Length;
TlsUtilities.WriteOpaque8(binder, output);
}
if (expectedLengthOfBindersList != lengthOfBindersList)
throw new TlsFatalAlert(AlertDescription.internal_error);
}
/// <exception cref="IOException"/>
internal static int GetLengthOfBindersList(TlsPsk[] psks)
{
int lengthOfBindersList = 0;
for (int i = 0; i < psks.Length; ++i)
{
TlsPsk psk = psks[i];
int prfAlgorithm = psk.PrfAlgorithm;
int prfCryptoHashAlgorithm = TlsCryptoUtilities.GetHashForPrf(prfAlgorithm);
lengthOfBindersList += 1 + TlsCryptoUtilities.GetHashOutputSize(prfCryptoHashAlgorithm);
}
TlsUtilities.CheckUint16(lengthOfBindersList);
return lengthOfBindersList;
}
/// <exception cref="IOException"/>
public static OfferedPsks Parse(Stream input)
{
IList identities = Platform.CreateArrayList();
{
int totalLengthIdentities = TlsUtilities.ReadUint16(input);
if (totalLengthIdentities < 7)
throw new TlsFatalAlert(AlertDescription.decode_error);
byte[] identitiesData = TlsUtilities.ReadFully(totalLengthIdentities, input);
MemoryStream buf = new MemoryStream(identitiesData, false);
do
{
PskIdentity identity = PskIdentity.Parse(buf);
identities.Add(identity);
}
while (buf.Position < buf.Length);
}
IList binders = Platform.CreateArrayList();
{
int totalLengthBinders = TlsUtilities.ReadUint16(input);
if (totalLengthBinders < 33)
throw new TlsFatalAlert(AlertDescription.decode_error);
byte[] bindersData = TlsUtilities.ReadFully(totalLengthBinders, input);
MemoryStream buf = new MemoryStream(bindersData, false);
do
{
byte[] binder = TlsUtilities.ReadOpaque8(input, 32);
binders.Add(binder);
}
while (buf.Position < buf.Length);
}
return new OfferedPsks(identities, binders);
}
}
}
|