NetworkPkg: Convert files to CRLF line ending
[mirror_edk2.git] / NetworkPkg / TlsDxe / TlsImpl.c
1 /** @file\r
2   The Miscellaneous Routines for TlsDxe driver.\r
3 \r
4 Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.<BR>\r
5 \r
6 This program and the accompanying materials\r
7 are licensed and made available under the terms and conditions of the BSD License\r
8 which accompanies this distribution.  The full text of the license may be found at\r
9 http://opensource.org/licenses/bsd-license.php\r
10 \r
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13 \r
14 **/\r
15 \r
16 #include "TlsImpl.h"\r
17 \r
18 /**\r
19   Encrypt the message listed in fragment.\r
20 \r
21   @param[in]       TlsInstance    The pointer to the TLS instance.\r
22   @param[in, out]  FragmentTable  Pointer to a list of fragment.\r
23                                   On input these fragments contain the TLS header and\r
24                                   plain text TLS payload;\r
25                                   On output these fragments contain the TLS header and\r
26                                   cipher text TLS payload.\r
27   @param[in]       FragmentCount  Number of fragment.\r
28 \r
29   @retval EFI_SUCCESS             The operation completed successfully.\r
30   @retval EFI_OUT_OF_RESOURCES    Can't allocate memory resources.\r
31   @retval EFI_ABORTED             TLS session state is incorrect.\r
32   @retval Others                  Other errors as indicated.\r
33 **/\r
34 EFI_STATUS\r
35 TlsEncryptPacket (\r
36   IN     TLS_INSTANCE                  *TlsInstance,\r
37   IN OUT EFI_TLS_FRAGMENT_DATA         **FragmentTable,\r
38   IN     UINT32                        *FragmentCount\r
39   )\r
40 {\r
41   EFI_STATUS          Status;\r
42   UINTN               Index;\r
43   UINT32              BytesCopied;\r
44   UINT32              BufferInSize;\r
45   UINT8               *BufferIn;\r
46   UINT8               *BufferInPtr;\r
47   TLS_RECORD_HEADER   *RecordHeaderIn;\r
48   UINT16              ThisPlainMessageSize;\r
49   TLS_RECORD_HEADER   *TempRecordHeader;\r
50   UINT16              ThisMessageSize;\r
51   UINT32              BufferOutSize;\r
52   UINT8               *BufferOut;\r
53   INTN                Ret;\r
54 \r
55   Status           = EFI_SUCCESS;\r
56   BytesCopied      = 0;\r
57   BufferInSize     = 0;\r
58   BufferIn         = NULL;\r
59   BufferInPtr      = NULL;\r
60   RecordHeaderIn   = NULL;\r
61   TempRecordHeader = NULL;\r
62   BufferOutSize    = 0;\r
63   BufferOut        = NULL;\r
64   Ret              = 0;\r
65 \r
66   //\r
67   // Calculate the size according to the fragment table.\r
68   //\r
69   for (Index = 0; Index < *FragmentCount; Index++) {\r
70     BufferInSize += (*FragmentTable)[Index].FragmentLength;\r
71   }\r
72 \r
73   //\r
74   // Allocate buffer for processing data.\r
75   //\r
76   BufferIn = AllocateZeroPool (BufferInSize);\r
77   if (BufferIn == NULL) {\r
78     Status = EFI_OUT_OF_RESOURCES;\r
79     goto ERROR;\r
80   }\r
81 \r
82   //\r
83   // Copy all TLS plain record header and payload into BufferIn.\r
84   //\r
85   for (Index = 0; Index < *FragmentCount; Index++) {\r
86     CopyMem (\r
87       (BufferIn + BytesCopied),\r
88       (*FragmentTable)[Index].FragmentBuffer,\r
89       (*FragmentTable)[Index].FragmentLength\r
90       );\r
91     BytesCopied += (*FragmentTable)[Index].FragmentLength;\r
92   }\r
93 \r
94   BufferOut = AllocateZeroPool (MAX_BUFFER_SIZE);\r
95   if (BufferOut == NULL) {\r
96     Status = EFI_OUT_OF_RESOURCES;\r
97     goto ERROR;\r
98   }\r
99 \r
100   //\r
101   // Parsing buffer.\r
102   //\r
103   BufferInPtr = BufferIn;\r
104   TempRecordHeader = (TLS_RECORD_HEADER *) BufferOut;\r
105   while ((UINTN) BufferInPtr < (UINTN) BufferIn + BufferInSize) {\r
106     RecordHeaderIn = (TLS_RECORD_HEADER *) BufferInPtr;\r
107 \r
108     if (RecordHeaderIn->ContentType != TlsContentTypeApplicationData) {\r
109       Status = EFI_INVALID_PARAMETER;\r
110       goto ERROR;\r
111     }\r
112 \r
113     ThisPlainMessageSize = RecordHeaderIn->Length;\r
114 \r
115     TlsWrite (TlsInstance->TlsConn, (UINT8 *) (RecordHeaderIn + 1), ThisPlainMessageSize);\r
116 \r
117     Ret = TlsCtrlTrafficOut (TlsInstance->TlsConn, (UINT8 *)(TempRecordHeader), MAX_BUFFER_SIZE - BufferOutSize);\r
118 \r
119     if (Ret > 0) {\r
120       ThisMessageSize = (UINT16) Ret;\r
121     } else {\r
122       //\r
123       // No data was successfully encrypted, continue to encrypt other messages.\r
124       //\r
125       DEBUG ((EFI_D_WARN, "TlsEncryptPacket: No data read from TLS object.\n"));\r
126 \r
127       ThisMessageSize = 0;\r
128     }\r
129 \r
130     BufferOutSize += ThisMessageSize;\r
131 \r
132     BufferInPtr += RECORD_HEADER_LEN + ThisPlainMessageSize;\r
133     TempRecordHeader += ThisMessageSize;\r
134   }\r
135 \r
136   FreePool (BufferIn);\r
137   BufferIn = NULL;\r
138 \r
139   //\r
140   // The caller will be responsible to handle the original fragment table.\r
141   //\r
142   *FragmentTable = AllocateZeroPool (sizeof (EFI_TLS_FRAGMENT_DATA));\r
143   if (*FragmentTable == NULL) {\r
144     Status = EFI_OUT_OF_RESOURCES;\r
145     goto ERROR;\r
146   }\r
147 \r
148   (*FragmentTable)[0].FragmentBuffer  = BufferOut;\r
149   (*FragmentTable)[0].FragmentLength  = BufferOutSize;\r
150   *FragmentCount                      = 1;\r
151 \r
152   return Status;\r
153 \r
154 ERROR:\r
155 \r
156   if (BufferIn != NULL) {\r
157     FreePool (BufferIn);\r
158     BufferIn = NULL;\r
159   }\r
160 \r
161   if (BufferOut != NULL) {\r
162     FreePool (BufferOut);\r
163     BufferOut = NULL;\r
164   }\r
165 \r
166   return Status;\r
167 }\r
168 \r
169 /**\r
170   Decrypt the message listed in fragment.\r
171 \r
172   @param[in]       TlsInstance    The pointer to the TLS instance.\r
173   @param[in, out]  FragmentTable  Pointer to a list of fragment.\r
174                                   On input these fragments contain the TLS header and\r
175                                   cipher text TLS payload;\r
176                                   On output these fragments contain the TLS header and\r
177                                   plain text TLS payload.\r
178   @param[in]       FragmentCount  Number of fragment.\r
179 \r
180   @retval EFI_SUCCESS             The operation completed successfully.\r
181   @retval EFI_OUT_OF_RESOURCES    Can't allocate memory resources.\r
182   @retval EFI_ABORTED             TLS session state is incorrect.\r
183   @retval Others                  Other errors as indicated.\r
184 **/\r
185 EFI_STATUS\r
186 TlsDecryptPacket (\r
187   IN     TLS_INSTANCE                  *TlsInstance,\r
188   IN OUT EFI_TLS_FRAGMENT_DATA         **FragmentTable,\r
189   IN     UINT32                        *FragmentCount\r
190   )\r
191 {\r
192   EFI_STATUS          Status;\r
193   UINTN               Index;\r
194   UINT32              BytesCopied;\r
195   UINT8               *BufferIn;\r
196   UINT32              BufferInSize;\r
197   UINT8               *BufferInPtr;\r
198   TLS_RECORD_HEADER   *RecordHeaderIn;\r
199   UINT16              ThisCipherMessageSize;\r
200   TLS_RECORD_HEADER   *TempRecordHeader;\r
201   UINT16              ThisPlainMessageSize;\r
202   UINT8               *BufferOut;\r
203   UINT32              BufferOutSize;\r
204   INTN                Ret;\r
205 \r
206   Status           = EFI_SUCCESS;\r
207   BytesCopied      = 0;\r
208   BufferIn         = NULL;\r
209   BufferInSize     = 0;\r
210   BufferInPtr      = NULL;\r
211   RecordHeaderIn   = NULL;\r
212   TempRecordHeader = NULL;\r
213   BufferOut        = NULL;\r
214   BufferOutSize    = 0;\r
215   Ret              = 0;\r
216 \r
217   //\r
218   // Calculate the size according to the fragment table.\r
219   //\r
220   for (Index = 0; Index < *FragmentCount; Index++) {\r
221     BufferInSize += (*FragmentTable)[Index].FragmentLength;\r
222   }\r
223 \r
224   //\r
225   // Allocate buffer for processing data\r
226   //\r
227   BufferIn = AllocateZeroPool (BufferInSize);\r
228   if (BufferIn == NULL) {\r
229     Status = EFI_OUT_OF_RESOURCES;\r
230     goto ERROR;\r
231   }\r
232 \r
233   //\r
234   // Copy all TLS plain record header and payload to BufferIn\r
235   //\r
236   for (Index = 0; Index < *FragmentCount; Index++) {\r
237     CopyMem (\r
238       (BufferIn + BytesCopied),\r
239       (*FragmentTable)[Index].FragmentBuffer,\r
240       (*FragmentTable)[Index].FragmentLength\r
241       );\r
242     BytesCopied += (*FragmentTable)[Index].FragmentLength;\r
243   }\r
244 \r
245   BufferOut = AllocateZeroPool (MAX_BUFFER_SIZE);\r
246   if (BufferOut == NULL) {\r
247     Status = EFI_OUT_OF_RESOURCES;\r
248     goto ERROR;\r
249   }\r
250 \r
251   //\r
252   // Parsing buffer. Received packet may have multiple TLS record messages.\r
253   //\r
254   BufferInPtr = BufferIn;\r
255   TempRecordHeader = (TLS_RECORD_HEADER *) BufferOut;\r
256   while ((UINTN) BufferInPtr < (UINTN) BufferIn + BufferInSize) {\r
257     RecordHeaderIn = (TLS_RECORD_HEADER *) BufferInPtr;\r
258 \r
259     if (RecordHeaderIn->ContentType != TlsContentTypeApplicationData) {\r
260       Status = EFI_INVALID_PARAMETER;\r
261       goto ERROR;\r
262     }\r
263 \r
264     ThisCipherMessageSize = NTOHS (RecordHeaderIn->Length);\r
265 \r
266     Ret = TlsCtrlTrafficIn (TlsInstance->TlsConn, (UINT8 *) (RecordHeaderIn), RECORD_HEADER_LEN + ThisCipherMessageSize);\r
267     if (Ret != RECORD_HEADER_LEN + ThisCipherMessageSize) {\r
268       TlsInstance->TlsSessionState = EfiTlsSessionError;\r
269       Status = EFI_ABORTED;\r
270       goto ERROR;\r
271     }\r
272 \r
273     Ret = 0;\r
274     Ret = TlsRead (TlsInstance->TlsConn, (UINT8 *) (TempRecordHeader + 1), MAX_BUFFER_SIZE - BufferOutSize);\r
275 \r
276     if (Ret > 0) {\r
277       ThisPlainMessageSize = (UINT16) Ret;\r
278     } else {\r
279       //\r
280       // No data was successfully decrypted, continue to decrypt other messages.\r
281       //\r
282       DEBUG ((EFI_D_WARN, "TlsDecryptPacket: No data read from TLS object.\n"));\r
283 \r
284       ThisPlainMessageSize = 0;\r
285     }\r
286 \r
287     CopyMem (TempRecordHeader, RecordHeaderIn, RECORD_HEADER_LEN);\r
288     TempRecordHeader->Length = ThisPlainMessageSize;\r
289     BufferOutSize += RECORD_HEADER_LEN + ThisPlainMessageSize;\r
290 \r
291     BufferInPtr += RECORD_HEADER_LEN + ThisCipherMessageSize;\r
292     TempRecordHeader += RECORD_HEADER_LEN + ThisPlainMessageSize;\r
293   }\r
294 \r
295   FreePool (BufferIn);\r
296   BufferIn = NULL;\r
297 \r
298   //\r
299   // The caller will be responsible to handle the original fragment table\r
300   //\r
301   *FragmentTable = AllocateZeroPool (sizeof (EFI_TLS_FRAGMENT_DATA));\r
302   if (*FragmentTable == NULL) {\r
303     Status = EFI_OUT_OF_RESOURCES;\r
304     goto ERROR;\r
305   }\r
306 \r
307   (*FragmentTable)[0].FragmentBuffer  = BufferOut;\r
308   (*FragmentTable)[0].FragmentLength  = BufferOutSize;\r
309   *FragmentCount                      = 1;\r
310 \r
311   return Status;\r
312 \r
313 ERROR:\r
314 \r
315   if (BufferIn != NULL) {\r
316     FreePool (BufferIn);\r
317     BufferIn = NULL;\r
318   }\r
319 \r
320   if (BufferOut != NULL) {\r
321     FreePool (BufferOut);\r
322     BufferOut = NULL;\r
323   }\r
324 \r
325   return Status;\r
326 }\r
327 \r