1 // Transport Security Layer (TLS)
2 // Copyright (c) 2003-2004 Carlos Guzman Alvarez
3 // Copyright (C) 2006 Novell, Inc (http://www.novell.com)
5 // Permission is hereby granted, free of charge, to any person obtaining
6 // a copy of this software and associated documentation files (the
7 // "Software"), to deal in the Software without restriction, including
8 // without limitation the rights to use, copy, modify, merge, publish,
9 // distribute, sublicense, and/or sell copies of the Software, and to
10 // permit persons to whom the Software is furnished to do so, subject to
11 // the following conditions:
13 // The above copyright notice and this permission notice shall be
14 // included in all copies or substantial portions of the Software.
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 using System
.Security
.Cryptography
;
29 namespace Mono
.Security
.Protocol
.Tls
31 internal class TlsCipherSuite
: CipherSuite
33 private const int MacHeaderLength
= 13;
34 private byte[] header
;
38 public TlsCipherSuite(
39 short code
, string name
, CipherAlgorithmType cipherAlgorithmType
,
40 HashAlgorithmType hashAlgorithmType
, ExchangeAlgorithmType exchangeAlgorithmType
,
41 bool exportable
, bool blockMode
, byte keyMaterialSize
,
42 byte expandedKeyMaterialSize
, short effectiveKeyBytes
,
43 byte ivSize
, byte blockSize
)
44 :base(code
, name
, cipherAlgorithmType
, hashAlgorithmType
,
45 exchangeAlgorithmType
, exportable
, blockMode
, keyMaterialSize
,
46 expandedKeyMaterialSize
, effectiveKeyBytes
, ivSize
, blockSize
)
52 #region MAC Generation Methods
54 public override byte[] ComputeServerRecordMAC(ContentType contentType
, byte[] fragment
)
57 header
= new byte [MacHeaderLength
];
59 ulong seqnum
= (Context
is ClientContext
) ? Context
.ReadSequenceNumber
: Context
.WriteSequenceNumber
;
60 Write (header
, 0, seqnum
);
61 header
[8] = (byte) contentType
;
62 Write (header
, 9, this.Context
.Protocol
);
63 Write (header
, 11, (short)fragment
.Length
);
65 HashAlgorithm mac
= this.ServerHMAC
;
66 mac
.TransformBlock (header
, 0, header
.Length
, header
, 0);
67 mac
.TransformBlock (fragment
, 0, fragment
.Length
, fragment
, 0);
68 // hack, else the method will allocate a new buffer of the same length (negative half the optimization)
69 mac
.TransformFinalBlock (CipherSuite
.EmptyArray
, 0, 0);
73 public override byte[] ComputeClientRecordMAC(ContentType contentType
, byte[] fragment
)
76 header
= new byte [MacHeaderLength
];
78 ulong seqnum
= (Context
is ClientContext
) ? Context
.WriteSequenceNumber
: Context
.ReadSequenceNumber
;
79 Write (header
, 0, seqnum
);
80 header
[8] = (byte) contentType
;
81 Write (header
, 9, this.Context
.Protocol
);
82 Write (header
, 11, (short)fragment
.Length
);
84 HashAlgorithm mac
= this.ClientHMAC
;
85 mac
.TransformBlock (header
, 0, header
.Length
, header
, 0);
86 mac
.TransformBlock (fragment
, 0, fragment
.Length
, fragment
, 0);
87 // hack, else the method will allocate a new buffer of the same length (negative half the optimization)
88 mac
.TransformFinalBlock (CipherSuite
.EmptyArray
, 0, 0);
94 #region Key Generation Methods
96 public override void ComputeMasterSecret(byte[] preMasterSecret
)
98 // Create master secret
99 this.Context
.MasterSecret
= new byte[preMasterSecret
.Length
];
100 this.Context
.MasterSecret
= this.PRF(
101 preMasterSecret
, "master secret", this.Context
.RandomCS
, 48);
103 DebugHelper
.WriteLine(">>>> MasterSecret", this.Context
.MasterSecret
);
106 public override void ComputeKeys()
109 TlsStream keyBlock
= new TlsStream(
111 this.Context
.MasterSecret
,
113 this.Context
.RandomSC
,
116 this.Context
.Negotiating
.ClientWriteMAC
= keyBlock
.ReadBytes(this.HashSize
);
117 this.Context
.Negotiating
.ServerWriteMAC
= keyBlock
.ReadBytes(this.HashSize
);
118 this.Context
.ClientWriteKey
= keyBlock
.ReadBytes(this.KeyMaterialSize
);
119 this.Context
.ServerWriteKey
= keyBlock
.ReadBytes(this.KeyMaterialSize
);
121 if (!this.IsExportable
)
123 if (this.IvSize
!= 0)
125 this.Context
.ClientWriteIV
= keyBlock
.ReadBytes(this.IvSize
);
126 this.Context
.ServerWriteIV
= keyBlock
.ReadBytes(this.IvSize
);
130 this.Context
.ClientWriteIV
= CipherSuite
.EmptyArray
;
131 this.Context
.ServerWriteIV
= CipherSuite
.EmptyArray
;
136 // Generate final write keys
137 byte[] finalClientWriteKey
= PRF(this.Context
.ClientWriteKey
, "client write key", this.Context
.RandomCS
, this.ExpandedKeyMaterialSize
);
138 byte[] finalServerWriteKey
= PRF(this.Context
.ServerWriteKey
, "server write key", this.Context
.RandomCS
, this.ExpandedKeyMaterialSize
);
140 this.Context
.ClientWriteKey
= finalClientWriteKey
;
141 this.Context
.ServerWriteKey
= finalServerWriteKey
;
146 byte[] ivBlock
= PRF(CipherSuite
.EmptyArray
, "IV block", this.Context
.RandomCS
, this.IvSize
*2);
149 this.Context
.ClientWriteIV
= new byte[this.IvSize
];
150 Buffer
.BlockCopy(ivBlock
, 0, this.Context
.ClientWriteIV
, 0, this.Context
.ClientWriteIV
.Length
);
152 this.Context
.ServerWriteIV
= new byte[this.IvSize
];
153 Buffer
.BlockCopy(ivBlock
, this.IvSize
, this.Context
.ServerWriteIV
, 0, this.Context
.ServerWriteIV
.Length
);
157 this.Context
.ClientWriteIV
= CipherSuite
.EmptyArray
;
158 this.Context
.ServerWriteIV
= CipherSuite
.EmptyArray
;
162 DebugHelper
.WriteLine(">>>> KeyBlock", keyBlock
.ToArray());
163 DebugHelper
.WriteLine(">>>> ClientWriteKey", this.Context
.ClientWriteKey
);
164 DebugHelper
.WriteLine(">>>> ClientWriteIV", this.Context
.ClientWriteIV
);
165 DebugHelper
.WriteLine(">>>> ClientWriteMAC", this.Context
.Negotiating
.ClientWriteMAC
);
166 DebugHelper
.WriteLine(">>>> ServerWriteKey", this.Context
.ServerWriteKey
);
167 DebugHelper
.WriteLine(">>>> ServerWriteIV", this.Context
.ServerWriteIV
);
168 DebugHelper
.WriteLine(">>>> ServerWriteMAC", this.Context
.Negotiating
.ServerWriteMAC
);
170 ClientSessionCache
.SetContextInCache (this.Context
);
171 // Clear no more needed data