This passage will introduce the details of implementing Remote Attestation in Pre-OS System and the necessary accessories or processes involved.
(1) Simple Introduction to Authentication Mechanism in the Design
As mentioned in the last part of the previous passage, the event log confidentiality is to be ensured. Simply using some symmetrical encryption algorithm cannot satisfy the requirement. The SSL/TLS(Secure Socket layer/Transmission Layer Security) Protocol to ensure the confidentiality of the transmission.
In SSL/TLS to verify the identification of the server and client before transmitting and receiving the data for remote attestation, the signature and verification process is necessary.
- Signing UEFI Applications and Drivers for UEFI Secure Boot
- BIOS Implementing UEFI Authenticated Variables in SMM with EDKII
<Note> the different between certificate and digital signature
-
什么是数字签名和证书?
The digital signature is used to prove the identification the information provider; certificate includes public key and its digital signature, which is used to verify the trustfulness of the public key.
However, the definition of Signature of Image is the SHA256 hash of PE/COFF image in UEFI Specification. - The idea is to dump the Event log && PCR Values into a recording file and signed the file and sign it with a private signature. Afterwards the recording file will be transmitted to the server and its trustfulness will be verified before and action is taken.
(2) Implementation of Remote Attestation
An important question here: we can make sure whether the IMA log is matching the PCR values from the quote report of TPM, but what if the PCR is extended with the events including malicious operation?
The standard attestation of the prover is a much more complicated way. Some materials worth referring to:
- Remote Attestation for Embedded System
- Things, Trouble, Trust: On Building Trust in IoT Systems
- Using the TPM: Machine Authentication and Attestation
- Security Analysis of Remote Attestation
And to simplify the situation (since in real cases, the embedded PLC devices are off Internet and only connected to the authentication server in the LAN), we just use SSL/TLS Protocol to encrypt the connection and verify the data on the server, to prevent malicious attacks including spying
Using the HpNetworkPkg for testing purpose.
sudo apt-get install git-svn
export PATH=$PATH:/usr/lib/git-core
git-svn http://svn.code.sf.net/p/libcurledk2/code/trunk/
# Some more details please see the slides attached
The Usage of BaseLib/PrintLib
The lib provides many fundamental functions supporting string manipulation.
Transmission Encryption using CryptoPkg
- Add the CryptoRuntimeDriver into the list of DXE Drivers (Or simple use
load CryptoRuntimeDriver.efi
in UEFI Shell) - Locate and Open the EFI_RUNTIME_CRYPT_PROTOCOL
///
/// Runtime Cryptographic Protocol Structure.
///
typedef struct {
EFI_RUNTIME_CRYPT_SHA256_GET_CONTEXT_SIZE Sha256GetContextSize;
EFI_RUNTIME_CRYPT_SHA256_INIT Sha256Init;
EFI_RUNTIME_CRYPT_SHA256_UPDATE Sha256Update;
EFI_RUNTIME_CRYPT_SHA256_FINAL Sha256Final;
EFI_RUNTIME_CRYPT_RSA_NEW RsaNew;
EFI_RUNTIME_CRYPT_RSA_FREE RsaFree;
EFI_RUNTIME_CRYPT_RSA_SET_KEY RsaSetKey;
EFI_RUNTIME_CRYPT_RSA_PKCS1_VERIFY RsaPkcs1Verify;
} EFI_RUNTIME_CRYPT_PROTOCOL;
- A simple sample of using Crypto Protocol to encrypting the character:
Status = gBS->LocateProtocol(
&gEfiRuntimeCryptProtocolGuid,
NULL,
(VOID **) &mCryptProtocol);
ZeroMem (Digest, MAX_DIGEST_SIZE);
CtxSize = mCryptProtocol->Sha256GetContextSize ();
HashCtx = AllocatePool (CtxSize);
Status = mCryptProtocol->Sha256Update (HashCtx, HashData, DataSize);
Status = mCryptProtocol->Sha256Final (HashCtx, Digest);
for (Index=0;Index<SHA256_DIGEST_SIZE;Index++) {
Print (L"%2X ",Digest[Index]);
}
FreePool (HashCtx);
For some details please see Crypto 实现的 SHA256
Configuration of FTP Server Side
Setting up on the Ubuntu Server
sudo apt-get install vsftpd
sudo vi /etc/vsftpd.conf
sudo /etc/init.d/vsftpd restart
For testing purpose, username and password authentication are skipped and use anonymous signing-in:
# 请参考以下配置,不要看百度上的半吊子教程
# http://wiki.ubuntu.com.cn/Vsftpd
# Another passage worth referring
# vsftp:425 failed to establish connection解决办法
# http://blog.sina.com.cn/s/blog_4da051a60101c8ny.html
anonymous_enable=YES
anon_root=/home/server/ftp
no_anon_password=YES
write_enable=YES
anon_upload_enable=YES
anon_mkdir_write_enable=YES
With the setting shown above, the client will be able to connect to the server with FTP protocol.
# use iptables or ufw to setup the firewall rules
sudo ufw disable
ftp 10.192.13.88
...
ftp> get file
We can also use pyftpdlib
in python to build up a FTP Server:
from pyftpdlib.authorizers import DummyAuthorizer
from pyftpdlib.handlers import FTPHandler
from pyftpdlib.servers import FTPServer
#实例化虚拟用户,这是FTP验证首要条件
authorizer = DummyAuthorizer()
#添加用户权限和路径,括号内的参数是(用户名, 密码, 用户目录, 权限)
authorizer.add_user('user', '12345', '/home/', perm='elradfmw')
#添加匿名用户 只需要路径
authorizer.add_anonymous('/home/huangxm')
#初始化ftp句柄
handler = FTPHandler
handler.authorizer = authorizer
#监听ip 和 端口,因为linux里非root用户无法使用21端口,所以我使用了2121端口
server = FTPServer(('192.168.0.108', 2121), handler)
#开始服务
server.serve_forever()
For details please refer to python实现FTP服务器
Configuration of FTP Protocol in UEFI Client Side
Here is a brief description of my design. The authentication process is a improved version of HTTPS SSL/TLS Protocol
After the verification stage, the PCR value and Event log will be dumped into a reporting file and signed with the session key. And then it will be passed to the server and its integrity will be verified.
The description of EFI_FTP4_SERVICE_BINGDING_PROTOCOL in UEFI Specification 2.7 Page 1699
The description of EFI_FTP4_CONNECTION_TOKEN in UEFI Specification 2.7 Page 1703. We are to initialise the Status and EFI Event after creating the FTP4 driver child protocol on specific supported device.
So we will construct a simple FtpClient Struct to configure and set up the FTP connection. The definition is followed:
struct FtpClient{
EFI_HANDLE m_FtpHandle;
EFI_FTP4_PROTOCOL* m_pFtp4Protocol;
EFI_FTP4_CONFIG_DATA* m_pFtp4ConfigData;
EFI_FTP4_CONNECTION_TOKEN ConnectToken;
EFI_FTP4_COMMAND_TOKEN CommandToken;
};
Also be aware of the definition in UEFI
///
/// 1-byte unsigned value.
///
typedef unsigned char UINT8;
///
/// 1-byte Character.
///
typedef char CHAR8;
The m_FtpHandle is the handle on which the child Ftp4 protocol driver will be bind on. But the fundamental driver seems not to have installed relevant protocols on any handle:
Instead of modifying the DXE driver and install the FTP supported dependencies, the MTFTP(Multiple Trivial File Transmission Protocol) protocol is used as a substitution.
Configuration of TFTP Server and Client
References for implementing TFTP server with tftpd
- How-do-i-install-and-run-a-tftp-server
- [Solved]TFTP: Error code 2: Access violation
- Ubuntu 12.04 tftp 设置
- tftp中Access Violation错误
A simpler way to use Python Lib tftpy
Example Python TFTP Server: http://tftpy.sourceforge.net/sphinx/
import tftpy
server = tftpy.TftpServer('/tftpboot')
server.listen('0.0.0.0', 69)
The TFTP server can be rebooted with sudo /etc/init.d/xinetd
. Similarly, a simple struct is defined to call the EFI_MTFTP4_PROTOCOL
struct MtftpClient{
EFI_HANDLE m_MtftpHandle;
EFI_MTFTP4_PROTOCOL* m_pMtftp4Protocol;
EFI_MTFTP4_CONFIG_DATA* m_pMtftp4ConfigData;
EFI_MTFTP4_TOKEN WriteToken, ReadToken;
};
Configuration setting
EFI_STATUS Status = EFI_NOT_FOUND;
struct MtftpClient* this = MtftpClientfd[sk];
if(this->m_pMtftp4ConfigData == NULL) return Status;
// StationIp & SubnetMask & GatewayIp need to be set if FALSE
this->m_pMtftp4ConfigData->UseDefaultSetting = FALSE;
*(UINT32*)(this->m_pMtftp4ConfigData->StationIp.Addr) = (10 | 192 << 8 | 13 << 16 | 89 << 24);
*(UINT32*)(this->m_pMtftp4ConfigData->SubnetMask.Addr) = (255 | 255 << 8 | 255 << 16 | 128 << 24);
*(UINT32*)(this->m_pMtftp4ConfigData->GatewayIp.Addr) = (10 | 192 << 8 | 13 << 16 | 1 << 24);
this->m_pMtftp4ConfigData->LocalPort = (UINT16)0;
*(UINT32*)(this->m_pMtftp4ConfigData->ServerIp.Addr) = Ip32;
this->m_pMtftp4ConfigData->InitialServerPort = (UINT16)69;
this->m_pMtftp4ConfigData->TryCount = (UINT16)5;
this->m_pMtftp4ConfigData->TimeoutValue = (UINT16)10;
The protocol runs successfully in configuration, but failed in WriteFile() function. Status Error: 23 (EFI_TFTP_ERROR), which means that the client received a Error packet.
Note: The concept of Callback function.
深入浅出剖析C语言函数指针与回调函数(一)
Please make sure that the implementation of the callback function should be in form of "EFI_STATUS EFIAPI Function(....)"
The Example of Callback function to parse the return packet is like:
// The Process will be aborted with any other status but EFI_SUCCESS
// The
EFI_STATUS
EFIAPI
CheckCallback(IN EFI_MTFTP4_PROTOCOL *This,
IN EFI_MTFTP4_TOKEN *Token,
IN UINT16 PacketLen,
IN EFI_MTFTP4_PACKET *Packet)
{
EFI_STATUS Status = EFI_SUCCESS;
Print(L"Parse the received Packet\n");
Print(L"\nOperation Code: %d\n", Packet->OpCode);
AsciiPrint("Msg: %s\n", Packet->Wrq.Filename[0]);
Print(L"\nError Code: %d\n", Packet->Error.ErrorCode);
AsciiPrint("Msg: %s\n", Packet->Error.ErrorMessage[0]);
return Status;
}
Also assure that the address is passed to the token defined in WriteToken || ReadToken
struct MtftpClient* this = MtftpClientfd[sk];
this->WriteToken.CheckPacket = &CheckCallback;
this->WriteToken.TimeoutCallback = &myTimeoutCallback;
The parsing results of the RecvPacket is like (Error Packet d in this case)
MTFTP Initiliazation Success
To Cinfig the Data...6
Config Sucess Code: 0
Writing Data Now: 0
Parse the received Packet
Error Code: 512
Msg:
Wait Status: 0
The Parsing function is defined like:
FTP The Request Data: POST / HTTP/1.1
Host:10.192.13.89
Accept:* / *
Connection:Keep-Alive
InstallProtocolInterface: 41D94CD2-35B6-455A-8258-D4E51334AADD 7EC326A0
InstallProtocolInterface: 3AD9DF29-4501-478D-B1F8-7F7FE70E50F3 7EC31AB8
InstallProtocolInterface: 78247C57-63DB-4708-99C2-A8B4A9A61F6B 7EC32530
MTFTP Initiliazation Success
To Cinfig the Data...10
Config Sucess Code: 0
InstallProtocolInterface: F4B427BB-BA21-4F16-BC4E-43E416AB619C 7EC2FEB0
Writing Data Now: 0
Wait Status: 0
Writing Data Success: 0
InstallProtocolInterface: F4B427BB-BA21-4F16-BC4E-43E416AB619C 7EC29230
Reading Data Now: 0
Wait Status: 0
FTP Read Data Success: 0
Close Status Success
The TFTP Mode String is set as "octet" if left NULL. We set the default TFTP package size to be 512kb and launch the download process. The progress bar is implemented with CheckPacket
, which is a function that will be triggered every time when a packet is received.
(2) Principles of and SSL/TLS Protocol and Improvements
Generally, the remote attestation process is completed with the help of