1/** @file
2  The Driver Binding and Service Binding Protocol for TlsDxe driver.
3
4  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
5
6  This program and the accompanying materials
7  are licensed and made available under the terms and conditions of the BSD License
8  which accompanies this distribution.  The full text of the license may be found at
9  http://opensource.org/licenses/bsd-license.php.
10
11  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14**/
15
16#include "TlsImpl.h"
17
18EFI_SERVICE_BINDING_PROTOCOL mTlsServiceBinding = {
19  TlsServiceBindingCreateChild,
20  TlsServiceBindingDestroyChild
21};
22
23/**
24  Release all the resources used by the TLS instance.
25
26  @param[in]  Instance        The TLS instance data.
27
28**/
29VOID
30TlsCleanInstance (
31  IN TLS_INSTANCE           *Instance
32  )
33{
34  if (Instance != NULL) {
35    if (Instance->TlsConn != NULL) {
36      TlsFree (Instance->TlsConn);
37    }
38
39    FreePool (Instance);
40  }
41}
42
43/**
44  Create the TLS instance and initialize it.
45
46  @param[in]  Service              The pointer to the TLS service.
47  @param[out] Instance             The pointer to the TLS instance.
48
49  @retval EFI_OUT_OF_RESOURCES   Failed to allocate resources.
50  @retval EFI_SUCCESS            The TLS instance is created.
51
52**/
53EFI_STATUS
54TlsCreateInstance (
55  IN  TLS_SERVICE         *Service,
56  OUT TLS_INSTANCE        **Instance
57  )
58{
59  TLS_INSTANCE            *TlsInstance;
60
61  *Instance = NULL;
62
63  TlsInstance = AllocateZeroPool (sizeof (TLS_INSTANCE));
64  if (TlsInstance == NULL) {
65    return EFI_OUT_OF_RESOURCES;
66  }
67
68  TlsInstance->Signature = TLS_INSTANCE_SIGNATURE;
69  InitializeListHead (&TlsInstance->Link);
70  TlsInstance->InDestroy = FALSE;
71  TlsInstance->Service   = Service;
72
73  CopyMem (&TlsInstance->Tls, &mTlsProtocol, sizeof (TlsInstance->Tls));
74  CopyMem (&TlsInstance->TlsConfig, &mTlsConfigurationProtocol, sizeof (TlsInstance->TlsConfig));
75
76  TlsInstance->TlsSessionState = EfiTlsSessionNotStarted;
77
78  *Instance = TlsInstance;
79
80  return EFI_SUCCESS;
81}
82
83/**
84  Release all the resources used by the TLS service binding instance.
85
86  @param[in]  Service        The TLS service data.
87
88**/
89VOID
90TlsCleanService (
91  IN TLS_SERVICE     *Service
92  )
93{
94  if (Service != NULL) {
95    if (Service->TlsCtx != NULL) {
96      TlsCtxFree (Service->TlsCtx);
97    }
98
99    FreePool (Service);
100  }
101}
102
103/**
104  Create then initialize a TLS service.
105
106  @param[in]  Image                  ImageHandle of the TLS driver
107  @param[out] Service                The service for TLS driver
108
109  @retval EFI_OUT_OF_RESOURCES   Failed to allocate resource to create the service.
110  @retval EFI_SUCCESS            The service is created for the driver.
111
112**/
113EFI_STATUS
114TlsCreateService (
115  IN  EFI_HANDLE            Image,
116  OUT TLS_SERVICE           **Service
117  )
118{
119  TLS_SERVICE            *TlsService;
120
121  ASSERT (Service != NULL);
122
123  *Service = NULL;
124
125  //
126  // Allocate a TLS Service Data
127  //
128  TlsService = AllocateZeroPool (sizeof (TLS_SERVICE));
129  if (TlsService == NULL) {
130    return EFI_OUT_OF_RESOURCES;
131  }
132
133  //
134  // Initialize TLS Service Data
135  //
136  TlsService->Signature        = TLS_SERVICE_SIGNATURE;
137  CopyMem (&TlsService->ServiceBinding, &mTlsServiceBinding, sizeof (TlsService->ServiceBinding));
138  TlsService->TlsChildrenNum   = 0;
139  InitializeListHead (&TlsService->TlsChildrenList);
140  TlsService->ImageHandle      = Image;
141
142  *Service = TlsService;
143
144  return EFI_SUCCESS;
145}
146
147/**
148  Unloads an image.
149
150  @param[in]  ImageHandle           Handle that identifies the image to be unloaded.
151
152  @retval EFI_SUCCESS           The image has been unloaded.
153  @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle.
154
155**/
156EFI_STATUS
157EFIAPI
158TlsUnload (
159  IN EFI_HANDLE  ImageHandle
160  )
161{
162  EFI_STATUS                      Status;
163  UINTN                           HandleNum;
164  EFI_HANDLE                      *HandleBuffer;
165  UINT32                          Index;
166  EFI_SERVICE_BINDING_PROTOCOL    *ServiceBinding;
167  TLS_SERVICE                     *TlsService;
168
169  HandleBuffer   = NULL;
170  ServiceBinding = NULL;
171  TlsService     = NULL;
172
173  //
174  // Locate all the handles with Tls service binding protocol.
175  //
176  Status = gBS->LocateHandleBuffer (
177                  ByProtocol,
178                  &gEfiTlsServiceBindingProtocolGuid,
179                  NULL,
180                  &HandleNum,
181                  &HandleBuffer
182                  );
183  if (EFI_ERROR (Status)) {
184    return Status;
185  }
186
187  for (Index = 0; Index < HandleNum; Index++) {
188    //
189    // Firstly, find ServiceBinding interface
190    //
191    Status = gBS->OpenProtocol (
192                    HandleBuffer[Index],
193                    &gEfiTlsServiceBindingProtocolGuid,
194                    (VOID **) &ServiceBinding,
195                    ImageHandle,
196                    NULL,
197                    EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
198                    );
199    if (EFI_ERROR (Status)) {
200      return Status;
201    }
202
203    TlsService = TLS_SERVICE_FROM_THIS (ServiceBinding);
204
205    //
206    // Then, uninstall ServiceBinding interface
207    //
208    Status = gBS->UninstallMultipleProtocolInterfaces (
209                    HandleBuffer[Index],
210                    &gEfiTlsServiceBindingProtocolGuid, ServiceBinding,
211                    NULL
212                    );
213    if (EFI_ERROR (Status)) {
214      return Status;
215    }
216
217    TlsCleanService (TlsService);
218  }
219
220  if (HandleBuffer != NULL) {
221    FreePool (HandleBuffer);
222  }
223
224  return EFI_SUCCESS;
225}
226
227/**
228  This is the declaration of an EFI image entry point. This entry point is
229  the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
230  both device drivers and bus drivers.
231
232  @param  ImageHandle           The firmware allocated handle for the UEFI image.
233  @param  SystemTable           A pointer to the EFI System Table.
234
235  @retval EFI_SUCCESS           The operation completed successfully.
236  @retval Others                An unexpected error occurred.
237**/
238EFI_STATUS
239EFIAPI
240TlsDriverEntryPoint (
241  IN EFI_HANDLE        ImageHandle,
242  IN EFI_SYSTEM_TABLE  *SystemTable
243  )
244{
245  EFI_STATUS             Status;
246
247  TLS_SERVICE            *TlsService;
248
249  //
250  // Create TLS Service
251  //
252  Status = TlsCreateService (ImageHandle, &TlsService);
253  if (EFI_ERROR (Status)) {
254    return Status;
255  }
256
257  ASSERT (TlsService != NULL);
258
259  //
260  // Initializes the OpenSSL library.
261  //
262  TlsInitialize ();
263
264  //
265  // Create a new SSL_CTX object as framework to establish TLS/SSL enabled
266  // connections. TLS 1.0 is used as the default version.
267  //
268  TlsService->TlsCtx = TlsCtxNew (TLS10_PROTOCOL_VERSION_MAJOR, TLS10_PROTOCOL_VERSION_MINOR);
269  if (TlsService->TlsCtx == NULL) {
270    FreePool (TlsService);
271    return EFI_ABORTED;
272  }
273
274  //
275  // Install the TlsServiceBinding Protocol onto Handle
276  //
277  Status = gBS->InstallMultipleProtocolInterfaces (
278                  &TlsService->Handle,
279                  &gEfiTlsServiceBindingProtocolGuid,
280                  &TlsService->ServiceBinding,
281                  NULL
282                  );
283  if (EFI_ERROR (Status)) {
284    goto ON_CLEAN_SERVICE;
285  }
286
287  return Status;
288
289ON_CLEAN_SERVICE:
290  TlsCleanService (TlsService);
291
292  return Status;
293}
294
295/**
296  Creates a child handle and installs a protocol.
297
298  The CreateChild() function installs a protocol on ChildHandle.
299  If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle.
300  If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle.
301
302  @param[in] This        Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
303  @param[in] ChildHandle Pointer to the handle of the child to create. If it is NULL,
304                         then a new handle is created. If it is a pointer to an existing UEFI handle,
305                         then the protocol is added to the existing UEFI handle.
306
307  @retval EFI_SUCCES            The protocol was added to ChildHandle.
308  @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
309  @retval EFI_OUT_OF_RESOURCES  There are not enough resources available to create
310                                the child.
311  @retval other                 The child handle was not created.
312
313**/
314EFI_STATUS
315EFIAPI
316TlsServiceBindingCreateChild (
317  IN EFI_SERVICE_BINDING_PROTOCOL  *This,
318  IN EFI_HANDLE                    *ChildHandle
319  )
320{
321  TLS_SERVICE         *TlsService;
322  TLS_INSTANCE        *TlsInstance;
323  EFI_STATUS           Status;
324  EFI_TPL              OldTpl;
325
326  if ((This == NULL) || (ChildHandle == NULL)) {
327    return EFI_INVALID_PARAMETER;
328  }
329
330  TlsService = TLS_SERVICE_FROM_THIS (This);
331
332  Status = TlsCreateInstance (TlsService, &TlsInstance);
333  if (EFI_ERROR (Status)) {
334    return Status;
335  }
336
337  ASSERT (TlsInstance != NULL);
338
339  //
340  // Create a new TLS connection object.
341  //
342  TlsInstance->TlsConn = TlsNew (TlsService->TlsCtx);
343  if (TlsInstance->TlsConn == NULL) {
344    Status = EFI_ABORTED;
345    goto ON_ERROR;
346  }
347
348  //
349  // Set default ConnectionEnd to EfiTlsClient
350  //
351  Status = TlsSetConnectionEnd (TlsInstance->TlsConn, EfiTlsClient);
352  if (EFI_ERROR (Status)) {
353    goto ON_ERROR;
354  }
355
356  //
357  // Install TLS protocol and configuration protocol onto ChildHandle
358  //
359  Status = gBS->InstallMultipleProtocolInterfaces (
360                  ChildHandle,
361                  &gEfiTlsProtocolGuid,
362                  &TlsInstance->Tls,
363                  &gEfiTlsConfigurationProtocolGuid,
364                  &TlsInstance->TlsConfig,
365                  NULL
366                  );
367  if (EFI_ERROR (Status)) {
368    goto ON_ERROR;
369  }
370
371  TlsInstance->ChildHandle = *ChildHandle;
372
373  //
374  // Add it to the TLS service's child list.
375  //
376  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
377
378  InsertTailList (&TlsService->TlsChildrenList, &TlsInstance->Link);
379  TlsService->TlsChildrenNum++;
380
381  gBS->RestoreTPL (OldTpl);
382
383  return EFI_SUCCESS;
384
385ON_ERROR:
386  TlsCleanInstance (TlsInstance);
387  return Status;
388}
389
390/**
391  Destroys a child handle with a protocol installed on it.
392
393  The DestroyChild() function does the opposite of CreateChild(). It removes a protocol
394  that was installed by CreateChild() from ChildHandle. If the removed protocol is the
395  last protocol on ChildHandle, then ChildHandle is destroyed.
396
397  @param  This        Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
398  @param  ChildHandle Handle of the child to destroy.
399
400  @retval EFI_SUCCES            The protocol was removed from ChildHandle.
401  @retval EFI_UNSUPPORTED       ChildHandle does not support the protocol that is being removed.
402  @retval EFI_INVALID_PARAMETER Child handle is NULL.
403  @retval EFI_ACCESS_DENIED     The protocol could not be removed from the ChildHandle
404                                because its services are being used.
405  @retval other                 The child handle was not destroyed.
406
407**/
408EFI_STATUS
409EFIAPI
410TlsServiceBindingDestroyChild (
411  IN EFI_SERVICE_BINDING_PROTOCOL  *This,
412  IN EFI_HANDLE                    ChildHandle
413  )
414{
415  TLS_SERVICE                    *TlsService;
416  TLS_INSTANCE                   *TlsInstance;
417
418  EFI_TLS_PROTOCOL               *Tls;
419  EFI_TLS_CONFIGURATION_PROTOCOL *TlsConfig;
420  EFI_STATUS                     Status;
421  EFI_TPL                        OldTpl;
422
423  if ((This == NULL) || (ChildHandle == NULL)) {
424    return EFI_INVALID_PARAMETER;
425  }
426
427  TlsService = TLS_SERVICE_FROM_THIS (This);
428
429  //
430  // Find TLS protocol interface installed in ChildHandle
431  //
432  Status = gBS->OpenProtocol (
433                  ChildHandle,
434                  &gEfiTlsProtocolGuid,
435                  (VOID **) &Tls,
436                  TlsService->ImageHandle,
437                  NULL,
438                  EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
439                  );
440  if (EFI_ERROR (Status)) {
441    return Status;
442  }
443
444  //
445  // Find TLS configuration protocol interface installed in ChildHandle
446  //
447  Status = gBS->OpenProtocol (
448                  ChildHandle,
449                  &gEfiTlsConfigurationProtocolGuid,
450                  (VOID **) &TlsConfig,
451                  TlsService->ImageHandle,
452                  NULL,
453                  EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
454                  );
455  if (EFI_ERROR (Status)) {
456    return Status;
457  }
458
459  TlsInstance  = TLS_INSTANCE_FROM_PROTOCOL (Tls);
460
461  if (TlsInstance->Service != TlsService) {
462    return EFI_INVALID_PARAMETER;
463  }
464
465  if (TlsInstance->InDestroy) {
466    return EFI_SUCCESS;
467  }
468
469  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
470
471  TlsInstance->InDestroy = TRUE;
472
473  //
474  // Uninstall the TLS protocol and TLS Configuration Protocol interface installed in ChildHandle.
475  //
476  Status = gBS->UninstallMultipleProtocolInterfaces (
477                  ChildHandle,
478                  &gEfiTlsProtocolGuid,
479                  Tls,
480                  &gEfiTlsConfigurationProtocolGuid,
481                  TlsConfig,
482                  NULL
483                  );
484  if (EFI_ERROR (Status)) {
485    return Status;
486  }
487
488  RemoveEntryList (&TlsInstance->Link);
489  TlsService->TlsChildrenNum--;
490
491  gBS->RestoreTPL (OldTpl);
492
493  TlsCleanInstance (TlsInstance);
494
495  return EFI_SUCCESS;
496}
497