2 Implementation of Opal password support library.
4 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "OpalPasswordSupportNotify.h"
17 #define OPAL_PASSWORD_MAX_LENGTH 32
19 LIST_ENTRY mDeviceList
= INITIALIZE_LIST_HEAD_VARIABLE (mDeviceList
);
20 BOOLEAN gInSmm
= FALSE
;
21 EFI_GUID gOpalPasswordNotifyProtocolGuid
= OPAL_PASSWORD_NOTIFY_PROTOCOL_GUID
;
25 The function performs determines the available actions for the OPAL_DISK provided.
27 @param[in] SupportedAttributes The support attribute for the device.
28 @param[in] LockingFeature The locking status for the device.
29 @param[in] OwnerShip The ownership for the device.
30 @param[out] AvalDiskActions Pointer to fill-out with appropriate disk actions.
35 OpalSupportGetAvailableActions(
36 IN OPAL_DISK_SUPPORT_ATTRIBUTE
*SupportedAttributes
,
37 IN TCG_LOCKING_FEATURE_DESCRIPTOR
*LockingFeature
,
39 OUT OPAL_DISK_ACTIONS
*AvalDiskActions
42 BOOLEAN ExistingPassword
;
44 NULL_CHECK(AvalDiskActions
);
46 AvalDiskActions
->AdminPass
= 1;
47 AvalDiskActions
->UserPass
= 0;
48 AvalDiskActions
->DisableUser
= 0;
49 AvalDiskActions
->Unlock
= 0;
52 // Revert is performed on locking sp, so only allow if locking sp is enabled
54 if (LockingFeature
->LockingEnabled
) {
55 AvalDiskActions
->Revert
= 1;
59 // Psid revert is available for any device with media encryption support
60 // Revert is allowed for any device with media encryption support, however it requires
62 if (SupportedAttributes
->MediaEncryption
) {
65 // Only allow psid revert if media encryption is enabled.
66 // Otherwise, someone who steals a disk can psid revert the disk and the user Data is still
67 // intact and accessible
69 AvalDiskActions
->PsidRevert
= 1;
70 AvalDiskActions
->RevertKeepDataForced
= 0;
73 // Secure erase is performed by generating a new encryption key
74 // this is only available is encryption is supported
76 AvalDiskActions
->SecureErase
= 1;
78 AvalDiskActions
->PsidRevert
= 0;
79 AvalDiskActions
->SecureErase
= 0;
82 // If no media encryption is supported, then a revert (using password) will not
83 // erase the Data (since you can't generate a new encryption key)
85 AvalDiskActions
->RevertKeepDataForced
= 1;
88 if (LockingFeature
->Locked
) {
89 AvalDiskActions
->Unlock
= 1;
91 AvalDiskActions
->Unlock
= 0;
95 // Only allow user to set password if an admin password exists
97 ExistingPassword
= OpalUtilAdminPasswordExists(OwnerShip
, LockingFeature
);
98 AvalDiskActions
->UserPass
= ExistingPassword
;
101 // This will still show up even if there isn't a user, which is fine
103 AvalDiskActions
->DisableUser
= ExistingPassword
;
105 return TcgResultSuccess
;
109 Creates a session with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY, then reverts device using Admin SP Revert method.
111 @param[in] Session The opal session for the opal device.
112 @param[in] Psid PSID of device to revert.
113 @param[in] PsidLength Length of PSID in bytes.
114 @param[in] DevicePath The device path for the opal devcie.
119 OpalSupportPsidRevert(
120 IN OPAL_SESSION
*Session
,
122 IN UINT32 PsidLength
,
123 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
131 Ret
= OpalUtilPsidRevert (Session
, Psid
, PsidLength
);
132 if (Ret
== TcgResultSuccess
&& !gInSmm
) {
133 OpalSupportSendPasword (DevicePath
, 0, NULL
);
140 Opens a session with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_SID_AUTHORITY,
141 sets OPAL_UID_ADMIN_SP_C_PIN_SID with the new password,
142 and sets OPAL_LOCKING_SP_C_PIN_ADMIN1 with the new password.
144 @param[in] Session The opal session for the opal device.
145 @param[in] OldPassword Current admin password
146 @param[in] OldPasswordLength Length of current admin password in bytes
147 @param[in] NewPassword New admin password to set
148 @param[in] NewPasswordLength Length of new password in bytes
149 @param[in] DevicePath The device path for the opal devcie.
150 @param[in] SetAdmin Whether set admin password or user password.
151 TRUE for admin, FALSE for user.
156 OpalSupportSetPassword(
157 IN OPAL_SESSION
*Session
,
158 IN VOID
*OldPassword
,
159 IN UINT32 OldPasswordLength
,
160 IN VOID
*NewPassword
,
161 IN UINT32 NewPasswordLength
,
162 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
169 NULL_CHECK(OldPassword
);
170 NULL_CHECK(NewPassword
);
173 Ret
= OpalUtilSetAdminPassword(Session
, OldPassword
, OldPasswordLength
, NewPassword
, NewPasswordLength
);
175 Ret
= OpalUtilSetUserPassword(Session
, OldPassword
, OldPasswordLength
, NewPassword
, NewPasswordLength
);
177 if (Ret
== TcgResultSuccess
&& !gInSmm
) {
178 OpalSupportSendPasword (DevicePath
, NewPasswordLength
, NewPassword
);
185 Starts a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY and disables the User1 authority.
187 @param[in] Session The opal session for the opal device.
188 @param[in] Password Admin password
189 @param[in] PasswordLength Length of password in bytes
190 @param[out] PasswordFailed Indicates if password failed (start session didn't work)
191 @param[in] DevicePath The device path for the opal devcie.
196 OpalSupportDisableUser(
197 IN OPAL_SESSION
*Session
,
199 IN UINT32 PasswordLength
,
200 OUT BOOLEAN
*PasswordFailed
,
201 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
207 NULL_CHECK(Password
);
208 NULL_CHECK(PasswordFailed
);
210 Ret
= OpalUtilDisableUser(Session
, Password
, PasswordLength
, PasswordFailed
);
211 if (Ret
== TcgResultSuccess
&& !gInSmm
) {
212 OpalSupportSendPasword (DevicePath
, PasswordLength
, Password
);
219 Enable Opal Feature for the input device.
221 @param[in] Session The opal session for the opal device.
223 @param[in] MsidLength Msid Length
224 @param[in] Password Admin password
225 @param[in] PassLength Length of password in bytes
226 @param[in] DevicePath The device path for the opal devcie.
231 OpalSupportEnableOpalFeature (
232 IN OPAL_SESSION
*Session
,
234 IN UINT32 MsidLength
,
236 IN UINT32 PassLength
,
237 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
244 NULL_CHECK(Password
);
246 Ret
= OpalUtilSetAdminPasswordAsSid(
253 if (Ret
== TcgResultSuccess
) {
255 // Enable global locking range
257 Ret
= OpalUtilSetOpalLockingRange(
261 OPAL_LOCKING_SP_LOCKING_GLOBALRANGE
,
271 if (Ret
== TcgResultSuccess
&& !gInSmm
) {
272 OpalSupportSendPasword (DevicePath
, PassLength
, Password
);
279 Opens a session with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY, then reverts the device using the RevertSP method.
281 @param[in] Session The opal session for the opal device.
282 @param[in] KeepUserData TRUE to keep existing Data on the disk, or FALSE to erase it
283 @param[in] Password Admin password
284 @param[in] PasswordLength Length of password in bytes
286 @param[in] MsidLength Msid Length
287 @param[out] PasswordFailed indicates if password failed (start session didn't work)
288 @param[in] DevicePath The device path for the opal devcie.
294 IN OPAL_SESSION
*Session
,
295 IN BOOLEAN KeepUserData
,
297 IN UINT32 PasswordLength
,
299 IN UINT32 MsidLength
,
300 OUT BOOLEAN
*PasswordFailed
,
301 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
307 NULL_CHECK(Password
);
309 NULL_CHECK(PasswordFailed
);
311 Ret
= OpalUtilRevert(Session
, KeepUserData
, Password
, PasswordLength
, PasswordFailed
, Msid
, MsidLength
);
312 if (Ret
== TcgResultSuccess
&& !gInSmm
) {
313 OpalSupportSendPasword (DevicePath
, 0, NULL
);
320 Starts a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_USER1_AUTHORITY or OPAL_LOCKING_SP_ADMIN1_AUTHORITY
321 and updates the global locking range ReadLocked and WriteLocked columns to FALSE.
323 @param[in] Session The opal session for the opal device.
324 @param[in] Password Admin or user password
325 @param[in] PasswordLength Length of password in bytes
326 @param[in] DevicePath The device path for the opal devcie.
332 IN OPAL_SESSION
*Session
,
334 IN UINT32 PasswordLength
,
335 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
341 NULL_CHECK(Password
);
343 Ret
= OpalUtilUpdateGlobalLockingRange(Session
, Password
, PasswordLength
, FALSE
, FALSE
);
344 if (Ret
== TcgResultSuccess
&& !gInSmm
) {
345 OpalSupportSendPasword (DevicePath
, PasswordLength
, Password
);
352 Starts a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_USER1_AUTHORITY or OPAL_LOCKING_SP_ADMIN1_AUTHORITY
353 and updates the global locking range ReadLocked and WriteLocked columns to TRUE.
355 @param[in] Session The opal session for the opal device.
356 @param[in] Password Admin or user password
357 @param[in] PasswordLength Length of password in bytes
358 @param[in] DevicePath The device path for the opal devcie.
364 IN OPAL_SESSION
*Session
,
366 IN UINT32 PasswordLength
,
367 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
373 NULL_CHECK(Password
);
375 Ret
= OpalUtilUpdateGlobalLockingRange(Session
, Password
, PasswordLength
, TRUE
, TRUE
);
376 if (Ret
== TcgResultSuccess
&& !gInSmm
) {
377 OpalSupportSendPasword (DevicePath
, PasswordLength
, Password
);
384 Initialize the communicate Buffer using DataSize and Function.
386 @param[out] DataPtr Points to the Data in the communicate Buffer.
387 @param[in] DataSize The Data Size to send to SMM.
388 @param[in] Function The function number to initialize the communicate Header.
390 @retval EFI_INVALID_PARAMETER The Data Size is too big.
391 @retval EFI_SUCCESS Find the specified variable.
395 OpalInitCommunicateBuffer (
396 OUT VOID
**DataPtr OPTIONAL
,
401 EFI_SMM_COMMUNICATE_HEADER
*SmmCommunicateHeader
;
402 OPAL_SMM_COMMUNICATE_HEADER
*SmmFunctionHeader
;
404 EDKII_PI_SMM_COMMUNICATION_REGION_TABLE
*SmmCommRegionTable
;
405 EFI_MEMORY_DESCRIPTOR
*SmmCommMemRegion
;
411 Status
= EfiGetSystemConfigurationTable (
412 &gEdkiiPiSmmCommunicationRegionTableGuid
,
413 (VOID
**) &SmmCommRegionTable
415 if (EFI_ERROR (Status
)) {
419 ASSERT (SmmCommRegionTable
!= NULL
);
420 SmmCommMemRegion
= (EFI_MEMORY_DESCRIPTOR
*) (SmmCommRegionTable
+ 1);
422 for (Index
= 0; Index
< SmmCommRegionTable
->NumberOfEntries
; Index
++) {
423 if (SmmCommMemRegion
->Type
== EfiConventionalMemory
) {
424 Size
= EFI_PAGES_TO_SIZE ((UINTN
) SmmCommMemRegion
->NumberOfPages
);
425 if (Size
>= (DataSize
+ OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER
, Data
) + OFFSET_OF (OPAL_SMM_COMMUNICATE_HEADER
, Data
))) {
429 SmmCommMemRegion
= (EFI_MEMORY_DESCRIPTOR
*) ((UINT8
*) SmmCommMemRegion
+ SmmCommRegionTable
->DescriptorSize
);
431 ASSERT (Index
< SmmCommRegionTable
->NumberOfEntries
);
433 Buffer
= (VOID
*)(UINTN
)SmmCommMemRegion
->PhysicalStart
;
434 ASSERT (Buffer
!= NULL
);
436 SmmCommunicateHeader
= (EFI_SMM_COMMUNICATE_HEADER
*) Buffer
;
437 CopyGuid (&SmmCommunicateHeader
->HeaderGuid
, &gOpalPasswordNotifyProtocolGuid
);
438 SmmCommunicateHeader
->MessageLength
= DataSize
+ OFFSET_OF (OPAL_SMM_COMMUNICATE_HEADER
, Data
);
440 SmmFunctionHeader
= (OPAL_SMM_COMMUNICATE_HEADER
*) SmmCommunicateHeader
->Data
;
441 SmmFunctionHeader
->Function
= Function
;
442 if (DataPtr
!= NULL
) {
443 *DataPtr
= SmmFunctionHeader
->Data
;
450 Send the Data in communicate Buffer to SMM.
452 @param[in] Buffer Points to the Data in the communicate Buffer.
453 @param[in] DataSize This Size of the function Header and the Data.
455 @retval EFI_SUCCESS Success is returned from the functin in SMM.
456 @retval Others Failure is returned from the function in SMM.
460 OpalSendCommunicateBuffer (
467 EFI_SMM_COMMUNICATE_HEADER
*SmmCommunicateHeader
;
468 OPAL_SMM_COMMUNICATE_HEADER
*SmmFunctionHeader
;
469 EFI_SMM_COMMUNICATION_PROTOCOL
*SmmCommunication
;
471 Status
= gBS
->LocateProtocol (&gEfiSmmCommunicationProtocolGuid
, NULL
, (VOID
**) &SmmCommunication
);
472 if (EFI_ERROR (Status
)) {
476 CommSize
= DataSize
+ OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER
, Data
) + OFFSET_OF (OPAL_SMM_COMMUNICATE_HEADER
, Data
);
477 Status
= SmmCommunication
->Communicate (SmmCommunication
, Buffer
, &CommSize
);
478 if (EFI_ERROR (Status
)) {
482 SmmCommunicateHeader
= (EFI_SMM_COMMUNICATE_HEADER
*) Buffer
;
483 SmmFunctionHeader
= (OPAL_SMM_COMMUNICATE_HEADER
*)SmmCommunicateHeader
->Data
;
485 return SmmFunctionHeader
->ReturnStatus
;
489 Transfer the password to the smm driver.
491 @param[in] DevicePath The device path for the opal devcie.
492 @param PasswordLen The input password length.
493 @param Password Input password buffer.
495 @retval EFI_SUCCESS Do the required action success.
496 @retval Others Error occured.
501 OpalSupportSendPasword(
502 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
507 OPAL_COMM_DEVICE_LIST
*Parameter
;
516 if (DevicePath
== NULL
) {
518 // Assume DevicePath == NULL only when library used by SMM driver
519 // and should not run to here, just return success.
524 DevicePathLen
= GetDevicePathSize (DevicePath
);
525 Length
= OFFSET_OF (OPAL_COMM_DEVICE_LIST
, OpalDevicePath
) + DevicePathLen
;
526 Buffer
= OpalInitCommunicateBuffer((VOID
**)&Parameter
, Length
, SMM_FUNCTION_SET_OPAL_PASSWORD
);
527 if (Buffer
== NULL
) {
528 return EFI_OUT_OF_RESOURCES
;
531 if (Password
!= NULL
) {
532 CopyMem((VOID
*)Parameter
->Password
, Password
, PasswordLen
);
533 Parameter
->PasswordLength
= (UINT8
)PasswordLen
;
535 CopyMem (&Parameter
->OpalDevicePath
, DevicePath
, DevicePathLen
);
537 Status
= OpalSendCommunicateBuffer(Buffer
, Length
);
538 if (EFI_ERROR(Status
)) {
543 ZeroMem(Parameter
, Length
);
548 Get saved Opal device list.
550 @retval return opal device list.
555 OpalSupportGetOpalDeviceList (
563 Check if the password is full zero.
565 @param[in] Password Points to the Data Buffer
567 @retval TRUE This password string is full zero.
568 @retval FALSE This password string is not full zero.
572 OpalPasswordIsFullZero (
578 for (Index
= 0; Index
< OPAL_PASSWORD_MAX_LENGTH
; Index
++) {
579 if (Password
[Index
] != 0) {
588 Save hdd password to SMM.
590 @param[in] DevicePath Input device path info for the device.
591 @param[in] Password The hdd password of attached ATA device.
592 @param[in] PasswordLength The hdd password length.
594 @retval EFI_OUT_OF_RESOURCES Insufficient resources to create database record
595 @retval EFI_SUCCESS The function has been successfully executed.
599 OpalSavePasswordToSmm (
600 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
602 IN UINT8 PasswordLength
605 OPAL_DISK_AND_PASSWORD_INFO
*List
;
606 OPAL_DISK_AND_PASSWORD_INFO
*Dev
;
610 DevicePathLen
= GetDevicePathSize (DevicePath
);
612 for (Entry
= mDeviceList
.ForwardLink
; Entry
!= &mDeviceList
; Entry
= Entry
->ForwardLink
) {
613 List
= BASE_CR (Entry
, OPAL_DISK_AND_PASSWORD_INFO
, Link
);
614 if (CompareMem (&List
->OpalDevicePath
, DevicePath
, DevicePathLen
) == 0) {
615 CopyMem(List
->Password
, Password
, OPAL_PASSWORD_MAX_LENGTH
);
620 Dev
= AllocateZeroPool (OFFSET_OF (OPAL_DISK_AND_PASSWORD_INFO
, OpalDevicePath
) + DevicePathLen
);
622 return EFI_OUT_OF_RESOURCES
;
625 Dev
->PasswordLength
= PasswordLength
;
626 CopyMem(&(Dev
->Password
), Password
, OPAL_PASSWORD_MAX_LENGTH
);
627 CopyMem(&(Dev
->OpalDevicePath
), DevicePath
, DevicePathLen
);
629 InsertHeadList (&mDeviceList
, &Dev
->Link
);
635 Communication service SMI Handler entry.
637 This SMI handler provides services for saving HDD password and saving S3 boot script when ready to boot.
639 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
640 @param[in] RegisterContext Points to an optional handler context which was specified when the
641 handler was registered.
642 @param[in, out] CommBuffer A pointer to a collection of Data in memory that will
643 be conveyed from a non-SMM environment into an SMM environment.
644 @param[in, out] CommBufferSize The Size of the CommBuffer.
646 @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
647 should still be called.
648 @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
650 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
652 @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
656 SmmOpalPasswordHandler (
657 IN EFI_HANDLE DispatchHandle
,
658 IN CONST VOID
*RegisterContext
,
659 IN OUT VOID
*CommBuffer
,
660 IN OUT UINTN
*CommBufferSize
664 OPAL_SMM_COMMUNICATE_HEADER
*SmmFunctionHeader
;
665 UINTN TempCommBufferSize
;
667 UINT8 PasswordLength
;
668 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
670 if (CommBuffer
== NULL
|| CommBufferSize
== NULL
) {
674 TempCommBufferSize
= *CommBufferSize
;
675 if (TempCommBufferSize
< OFFSET_OF (OPAL_SMM_COMMUNICATE_HEADER
, Data
)) {
679 Status
= EFI_SUCCESS
;
680 SmmFunctionHeader
= (OPAL_SMM_COMMUNICATE_HEADER
*)CommBuffer
;
682 DevicePath
= &((OPAL_COMM_DEVICE_LIST
*)(SmmFunctionHeader
->Data
))->OpalDevicePath
;
683 PasswordLength
= ((OPAL_COMM_DEVICE_LIST
*)(SmmFunctionHeader
->Data
))->PasswordLength
;
684 NewPassword
= ((OPAL_COMM_DEVICE_LIST
*)(SmmFunctionHeader
->Data
))->Password
;
686 switch (SmmFunctionHeader
->Function
) {
687 case SMM_FUNCTION_SET_OPAL_PASSWORD
:
688 if (OpalPasswordIsFullZero (NewPassword
) || PasswordLength
== 0) {
689 Status
= EFI_INVALID_PARAMETER
;
693 Status
= OpalSavePasswordToSmm (DevicePath
, NewPassword
, PasswordLength
);
697 Status
= EFI_UNSUPPORTED
;
702 SmmFunctionHeader
->ReturnStatus
= Status
;
705 // Return EFI_SUCCESS cause only one handler can be trigged.
706 // so return EFI_WARN_INTERRUPT_SOURCE_PENDING to make all handler can be trigged.
708 return EFI_WARN_INTERRUPT_SOURCE_PENDING
;
712 The constructor function.
714 Register SMI handler when link to SMM driver.
716 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
721 OpalPasswordSupportLibConstructor (
725 EFI_SMM_BASE2_PROTOCOL
*SmmBase2
;
726 EFI_SMM_SYSTEM_TABLE2
*Smst
;
727 EFI_HANDLE SmmHandle
;
730 Status
= gBS
->LocateProtocol (&gEfiSmmBase2ProtocolGuid
, NULL
, (VOID
**) &SmmBase2
);
731 if (EFI_ERROR (Status
)) {
732 return RETURN_SUCCESS
;
734 Status
= SmmBase2
->InSmm (SmmBase2
, &gInSmm
);
735 if (EFI_ERROR (Status
)) {
736 return RETURN_SUCCESS
;
739 return RETURN_SUCCESS
;
743 // Good, we are in SMM
745 Status
= SmmBase2
->GetSmstLocation (SmmBase2
, &Smst
);
746 if (EFI_ERROR (Status
)) {
747 return RETURN_SUCCESS
;
751 Status
= Smst
->SmiHandlerRegister (SmmOpalPasswordHandler
, &gOpalPasswordNotifyProtocolGuid
, &SmmHandle
);
752 ASSERT_EFI_ERROR (Status
);
758 The Destructor function.
760 Clean the saved opal device list.
762 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
767 OpalPasswordSupportLibDestructor (
771 OPAL_DISK_AND_PASSWORD_INFO
*Device
;
773 while (!IsListEmpty (&mDeviceList
)) {
774 Device
= BASE_CR (mDeviceList
.ForwardLink
, OPAL_DISK_AND_PASSWORD_INFO
, Link
);
776 RemoveEntryList (&Device
->Link
);