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
;
405 Buffer
= AllocateZeroPool (DataSize
+ OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER
, Data
) + OFFSET_OF (OPAL_SMM_COMMUNICATE_HEADER
, Data
));
406 ASSERT (Buffer
!= NULL
);
408 SmmCommunicateHeader
= (EFI_SMM_COMMUNICATE_HEADER
*) Buffer
;
409 CopyGuid (&SmmCommunicateHeader
->HeaderGuid
, &gOpalPasswordNotifyProtocolGuid
);
410 SmmCommunicateHeader
->MessageLength
= DataSize
+ OFFSET_OF (OPAL_SMM_COMMUNICATE_HEADER
, Data
);
412 SmmFunctionHeader
= (OPAL_SMM_COMMUNICATE_HEADER
*) SmmCommunicateHeader
->Data
;
413 SmmFunctionHeader
->Function
= Function
;
414 if (DataPtr
!= NULL
) {
415 *DataPtr
= SmmFunctionHeader
->Data
;
422 Send the Data in communicate Buffer to SMM.
424 @param[in] Buffer Points to the Data in the communicate Buffer.
425 @param[in] DataSize This Size of the function Header and the Data.
427 @retval EFI_SUCCESS Success is returned from the functin in SMM.
428 @retval Others Failure is returned from the function in SMM.
432 OpalSendCommunicateBuffer (
439 EFI_SMM_COMMUNICATE_HEADER
*SmmCommunicateHeader
;
440 OPAL_SMM_COMMUNICATE_HEADER
*SmmFunctionHeader
;
441 EFI_SMM_COMMUNICATION_PROTOCOL
*SmmCommunication
;
443 Status
= gBS
->LocateProtocol (&gEfiSmmCommunicationProtocolGuid
, NULL
, (VOID
**) &SmmCommunication
);
444 if (EFI_ERROR (Status
)) {
448 CommSize
= DataSize
+ OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER
, Data
) + OFFSET_OF (OPAL_SMM_COMMUNICATE_HEADER
, Data
);
449 Status
= SmmCommunication
->Communicate (SmmCommunication
, Buffer
, &CommSize
);
450 if (EFI_ERROR (Status
)) {
454 SmmCommunicateHeader
= (EFI_SMM_COMMUNICATE_HEADER
*) Buffer
;
455 SmmFunctionHeader
= (OPAL_SMM_COMMUNICATE_HEADER
*)SmmCommunicateHeader
->Data
;
457 return SmmFunctionHeader
->ReturnStatus
;
461 Transfer the password to the smm driver.
463 @param[in] DevicePath The device path for the opal devcie.
464 @param PasswordLen The input password length.
465 @param Password Input password buffer.
467 @retval EFI_SUCCESS Do the required action success.
468 @retval Others Error occured.
473 OpalSupportSendPasword(
474 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
479 OPAL_COMM_DEVICE_LIST
*Parameter
;
488 if (DevicePath
== NULL
) {
490 // Assume DevicePath == NULL only when library used by SMM driver
491 // and should not run to here, just return success.
496 DevicePathLen
= GetDevicePathSize (DevicePath
);
497 Length
= OFFSET_OF (OPAL_COMM_DEVICE_LIST
, OpalDevicePath
) + DevicePathLen
;
498 Buffer
= OpalInitCommunicateBuffer((VOID
**)&Parameter
, Length
, SMM_FUNCTION_SET_OPAL_PASSWORD
);
499 if (Buffer
== NULL
) {
500 return EFI_OUT_OF_RESOURCES
;
503 if (Password
!= NULL
) {
504 CopyMem((VOID
*)Parameter
->Password
, Password
, PasswordLen
);
505 Parameter
->PasswordLength
= (UINT8
)PasswordLen
;
507 CopyMem (&Parameter
->OpalDevicePath
, DevicePath
, DevicePathLen
);
509 Status
= OpalSendCommunicateBuffer(Buffer
, Length
);
510 if (EFI_ERROR(Status
)) {
515 ZeroMem(Parameter
, Length
);
522 Get saved Opal device list.
524 @retval return opal device list.
529 OpalSupportGetOpalDeviceList (
537 Check if the password is full zero.
539 @param[in] Password Points to the Data Buffer
541 @retval TRUE This password string is full zero.
542 @retval FALSE This password string is not full zero.
546 OpalPasswordIsFullZero (
552 for (Index
= 0; Index
< OPAL_PASSWORD_MAX_LENGTH
; Index
++) {
553 if (Password
[Index
] != 0) {
562 Save hdd password to SMM.
564 @param[in] DevicePath Input device path info for the device.
565 @param[in] Password The hdd password of attached ATA device.
566 @param[in] PasswordLength The hdd password length.
568 @retval EFI_OUT_OF_RESOURCES Insufficient resources to create database record
569 @retval EFI_SUCCESS The function has been successfully executed.
573 OpalSavePasswordToSmm (
574 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
576 IN UINT8 PasswordLength
579 OPAL_DISK_AND_PASSWORD_INFO
*List
;
580 OPAL_DISK_AND_PASSWORD_INFO
*Dev
;
584 DevicePathLen
= GetDevicePathSize (DevicePath
);
586 for (Entry
= mDeviceList
.ForwardLink
; Entry
!= &mDeviceList
; Entry
= Entry
->ForwardLink
) {
587 List
= BASE_CR (Entry
, OPAL_DISK_AND_PASSWORD_INFO
, Link
);
588 if (CompareMem (&List
->OpalDevicePath
, DevicePath
, DevicePathLen
) == 0) {
589 CopyMem(List
->Password
, Password
, OPAL_PASSWORD_MAX_LENGTH
);
594 Dev
= AllocateZeroPool (OFFSET_OF (OPAL_DISK_AND_PASSWORD_INFO
, OpalDevicePath
) + DevicePathLen
);
596 return EFI_OUT_OF_RESOURCES
;
599 Dev
->PasswordLength
= PasswordLength
;
600 CopyMem(&(Dev
->Password
), Password
, OPAL_PASSWORD_MAX_LENGTH
);
601 CopyMem(&(Dev
->OpalDevicePath
), DevicePath
, DevicePathLen
);
603 InsertHeadList (&mDeviceList
, &Dev
->Link
);
609 Communication service SMI Handler entry.
611 This SMI handler provides services for saving HDD password and saving S3 boot script when ready to boot.
613 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
614 @param[in] RegisterContext Points to an optional handler context which was specified when the
615 handler was registered.
616 @param[in, out] CommBuffer A pointer to a collection of Data in memory that will
617 be conveyed from a non-SMM environment into an SMM environment.
618 @param[in, out] CommBufferSize The Size of the CommBuffer.
620 @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
621 should still be called.
622 @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
624 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
626 @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
630 SmmOpalPasswordHandler (
631 IN EFI_HANDLE DispatchHandle
,
632 IN CONST VOID
*RegisterContext
,
633 IN OUT VOID
*CommBuffer
,
634 IN OUT UINTN
*CommBufferSize
638 OPAL_SMM_COMMUNICATE_HEADER
*SmmFunctionHeader
;
639 UINTN TempCommBufferSize
;
641 UINT8 PasswordLength
;
642 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
644 if (CommBuffer
== NULL
|| CommBufferSize
== NULL
) {
648 TempCommBufferSize
= *CommBufferSize
;
649 if (TempCommBufferSize
< OFFSET_OF (OPAL_SMM_COMMUNICATE_HEADER
, Data
)) {
653 Status
= EFI_SUCCESS
;
654 SmmFunctionHeader
= (OPAL_SMM_COMMUNICATE_HEADER
*)CommBuffer
;
656 DevicePath
= &((OPAL_COMM_DEVICE_LIST
*)(SmmFunctionHeader
->Data
))->OpalDevicePath
;
657 PasswordLength
= ((OPAL_COMM_DEVICE_LIST
*)(SmmFunctionHeader
->Data
))->PasswordLength
;
658 NewPassword
= ((OPAL_COMM_DEVICE_LIST
*)(SmmFunctionHeader
->Data
))->Password
;
660 switch (SmmFunctionHeader
->Function
) {
661 case SMM_FUNCTION_SET_OPAL_PASSWORD
:
662 if (OpalPasswordIsFullZero (NewPassword
) || PasswordLength
== 0) {
663 Status
= EFI_INVALID_PARAMETER
;
667 Status
= OpalSavePasswordToSmm (DevicePath
, NewPassword
, PasswordLength
);
671 Status
= EFI_UNSUPPORTED
;
676 SmmFunctionHeader
->ReturnStatus
= Status
;
679 // Return EFI_SUCCESS cause only one handler can be trigged.
680 // so return EFI_WARN_INTERRUPT_SOURCE_PENDING to make all handler can be trigged.
682 return EFI_WARN_INTERRUPT_SOURCE_PENDING
;
686 The constructor function.
688 Register SMI handler when link to SMM driver.
690 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
695 OpalPasswordSupportLibConstructor (
699 EFI_SMM_BASE2_PROTOCOL
*SmmBase2
;
700 EFI_SMM_SYSTEM_TABLE2
*Smst
;
701 EFI_HANDLE SmmHandle
;
704 Status
= gBS
->LocateProtocol (&gEfiSmmBase2ProtocolGuid
, NULL
, (VOID
**) &SmmBase2
);
705 if (EFI_ERROR (Status
)) {
706 return RETURN_SUCCESS
;
708 Status
= SmmBase2
->InSmm (SmmBase2
, &gInSmm
);
709 if (EFI_ERROR (Status
)) {
710 return RETURN_SUCCESS
;
713 return RETURN_SUCCESS
;
717 // Good, we are in SMM
719 Status
= SmmBase2
->GetSmstLocation (SmmBase2
, &Smst
);
720 if (EFI_ERROR (Status
)) {
721 return RETURN_SUCCESS
;
725 Status
= Smst
->SmiHandlerRegister (SmmOpalPasswordHandler
, &gOpalPasswordNotifyProtocolGuid
, &SmmHandle
);
726 ASSERT_EFI_ERROR (Status
);
732 The Destructor function.
734 Clean the saved opal device list.
736 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
741 OpalPasswordSupportLibDestructor (
745 OPAL_DISK_AND_PASSWORD_INFO
*Device
;
747 while (!IsListEmpty (&mDeviceList
)) {
748 Device
= BASE_CR (mDeviceList
.ForwardLink
, OPAL_DISK_AND_PASSWORD_INFO
, Link
);
750 RemoveEntryList (&Device
->Link
);