Trusted Environment Creation
Windows Embedded CE powered devices send, receive, and process information that requires protection from potentially unsafe applications. To protect your device, you can implement security measures that prevent the operating system (OS) from loading unknown modules, restrict access to system application programming interfaces (APIs), and prevent write access to parts of the system registry. The kernel uses this information to prevent unauthorized applications from loading or limits their access to the system.
To create a privileged environment, you must disable full-kernel mode by setting the second bit of ROMFLAGS in the Config.bib file for the Windows Embedded CE-based run-time image. Depending on what other flags are set, the value of ROMFLAGS might vary. In Windows Embedded CE 6.0, OEM_CERTIFY_RUN is no longer supported. The OS either fully trusts the calling process and loads the module, or it does not.
In Windows Embedded CE 6.0, OEMCertifyModule is no longer supported.
Windows Embedded CE 6.0 Security Model:
This topic covers the changes in the Windows Embedded CE 6.0 security model.
Old Security Model: Trust Level for Modules
In releases prior to Windows Embedded CE 6.0, there was a concept of trust associated with each module (DLL or EXE). Each module could be categorized as one of the following:
- Loaded with “full trust” privileges: This was typically the case for a DLL or EXE signed with a certificate that chains to a privileged certification store on the device. In this case the module was allowed to load and the module code can also call all the APIs in the system.
- Loaded with “run” privileges: This was typically the case for a DLL or EXE signed with a certificate that chains to an unprivileged certification store on the device. In this case the module was allowed to load, but specific API calls (such as SetKMode) could not be made from this module.
- No privileges: This was typically the case if the DLL or EXE signed with a certificate which is not in any of the certification stores on the device or the module was not signed at all, and the module was being loaded on a trust-enabled system.
In this security model, module trust was fully governed by the certificate (or the lack of a certificate) associated with the given module. On general embedded systems where a certification subsystem was not in the image by default, an OEM could still have limited the API calls to only those modules that reside in ROM.
New Security Model: Trust Level for Modules and APIs
In CE 6.0, the concept of module trust is treated slightly differently and is divided into two parts:
- Load Privilege: This is used by Windows Embedded CE to decide if a module can be loaded or not (for example, when an application calls CreateProcess or LoadLibrary to launch or load a module). Load privilege decides whether to load the module by determining whether a certification module is built into the Windows Embedded CE powered device or not. For more information, see Load Privilege later in this topic.
- API Privilege: This is used by Windows Embedded CE to decide if module code can call specific APIs that are categorized as kernel-mode only. The decision for this is based on where the module is loaded. Any code which is loaded above 0x8000_0000 is considered to be running in kernel mode, and any code which is loaded below that address is considered to be running in user mode. Therefore, whether a module can call specific APIs entirely depends on which address space that the module is loaded in. The decision is not related to which certificate is associated with the given module. For more information, see Kernel Mode APIs.
Load Privilege Overview
In CE 6.0, load privilege for a module is based on the following rules:
- Any module with ROM attribute set on the file is considered to be fully trusted.
- Any module which is signed with a certificate that chains to a codesign certificate stored on the device is considered to be fully trusted.
- All other modules are considered to be untrusted.
Considering these rules, the following three cases represent the possible ways that a Windows Embedded CE powered device can be built to accommodate load privilege.
Case 1: Closed box solution
If you want to develop a closed box solution using CE 6.0, then you should consider doing the following:
- Enable SYSGEN_CERTMOD in the image. You can set this Sysgen variable at the command-line during a build.
- Do not add any certificates to the codesign store on the device.
- Ensure that all the modules which are needed to run on the closed box system are in ROM.
Once an image is built with the above properties, then no third-party applications or modules can be loaded on that system.
Case 2: Semi-closed box solution
If you want to develop a semi-closed box solution using CE 6.0, in which only signed modules can be loaded in the system, then you should consider doing the following:
- Enable SYSGEN_CERTMOD in the image. You can set this Sysgen variable at the command-line during a build.
- Add one or more certificates to the codesign store on the device.
- Ensure that all the modules which needed to run on this system are either in ROM or signed with a certificate that is in the codesign store on the device.
A semi-closed box solution is appropriate for an OEM who wants to publish an SDK for their Windows Embedded CE powered device so that ISVs can write applications that target their platform. By enforcing that applications must be signed with an OEM certificate, OEMs can control which applications are permitted to run on the device.
Case 3: Open solution
If you want to develop an open solution using CE 6.0, then you should consider the following:
- Ensure that SYSGEN_CERTMOD is not set in the image.
When SYSGEN_CERTMOD is not set in the image, all modules in the system are considered as fully trusted for Load Privilege, and any attempt to load any module will proceed normally.
Note that SYSGEN_CERTMOD just governs the load privileges for a module. Once the module is loaded, the set of APIs that the module is permitted to call depends on which mode (kernel mode or user mode) that threads in that module are running in. This is determined by which address space the module is loaded in.
For more information, see the description on API Privilege earlier in this topic.
Signature Creation:
A digital signature is used for verification of the origination of an electronic document and for nonrepudiation. The use of a digital signature does not change the data in the file. Instead, a hash of the document is generated that can either be bundled with the document or transmitted separately. Digital signatures use a public-key algorithm.
To create a digital signature from a file, run the file through a hash function, and then sign the resulting hash with a private key. An easy way to create a digital signature from a file is to use Signfile.exe, which is included in Microsoft Platform Builder. Signfile.exe is a tool for signing an executable file with a private key supplied by a cryptographic service provider (CSP).
Signfile.exe uses the Secure Hashing Algorithm (SHA) to compute the cryptographic hash. SHA generates a 20-byte hash from an arbitrarily sized byte string. Signfile.exe pads the hash as specified by Public-Key Cryptography Standards #1 (PKCS1) and encrypts it by using the RSA public key algorithm. The key modulus length can be from 512 through 1,024 bits. The resulting signature is the same size as the modulus. For example, the signature for a 1,024 bit key is 128 bytes. Signfile.exe then uses the ImageAddCertificate and ImageGetDigestStream Microsoft® Windows NT® functions to embed the signature in a portable executable (PE) file.
The following list shows the contents of the PE file memory:
- MS-DOS header
- Offset of PE header (offset 0x3c)
- PE header
- Section headers
- Section
- Debug information and certificates (if any)
The PE header begins with a 4-byte sequence, "PE\0\0", that identifies the MS-DOS® header. The MS-DOS header is followed by a standard Common Object File Format (COFF) header. This COFF header is followed by an optional header that is always present on Windows .exe and .dll files. The last field in a PE header is an optional data directory table. The following table shows the size of the PE header elements.
PE header element | Size |
---|---|
"PE\0\0" | 4 bytes |
COFF header | 20 bytes |
Optional header; standard for Windows files | 96 bytes |
Optional header; data directory table | Size varies |
Each entry in the data directory table consists of an IMAGE_DATA_DIRECTORY structure. The fifth structure in the data directory table contains certificate table information. This is stored in an array of WIN_CERTIFICATE structures. A certificate is a digitally signed statement that contains information about an entity and that entity's public key. Certificates are not loaded into memory as part of the PE file.
The following code example shows the format of a WIN_CERTIFICATE structure that is needed to support the PKCS1 standard.
Copy Code | |
---|---|
typedef struct { // Standard WIN_CERTIFICATE fields (8 bytes) DWORD dwLength; WORD wRevision; WORD wCertificateType; // = WIN_CERT_TYPE_PKCS1_SIGN // WIN_CERT_TYPE_PKCS1_SIGN fields follow DWORD cbSignedData; // optional signed attributes BYTE bSignedData[MAX_WIN_CERT_SIGN_DATA_LEN]; BYTE bSign[MAX_RSA_KEY_BITS/8]; // PKCS1 signature } PKCS1_MODULE_SIGN ; |
Signfile.exe appends the WIN_CERTIFICATE structure to the end of the file and updates the file header accordingly. For sample Signfile.exe code, see %_WINCEROOT%\Public\Common\Oak\Tools\Signfile.
Database Security:
Windows Embedded CE allows privileged applications to mark a system flag on databases to deny access to normal callers. Normal applications cannot open, read, or modify databases that are marked with the system flag. Privileged callers can set the CEDB_SYSTEMDB flag inside the CEDBASEINFOEX structure passed to CeCreateDatabaseEx2 or CeSetDatabaseInfoEx2 to protect a database.
This functionality protects a single database, not an entire database volume. Setting FILE_ATTRIBUTE_SYSTEM on the volume file protects database volumes. System databases cannot be created inside database volumes that do not have FILE_ATTRIBUTE_SYSTEM set to block normal applications from accessing and/or deleting a file containing a system database using the Microsoft Win32® file APIs. Because an normal application cannot access any file with the system file attribute set, adding the system flag to a database inside a database volume does not give it any additional security. Therefore, this functionality is most useful in databases that are stored within the object store. Removing the system file attribute from a database volume that contains a system database will expose that database to access by normal applications and is not recommended.
Database Security:
Windows Embedded CE allows privileged applications to mark a system flag on databases to deny access to normal callers. Normal applications cannot open, read, or modify databases that are marked with the system flag. Privileged callers can set the CEDB_SYSTEMDB flag inside the CEDBASEINFOEX structure passed to CeCreateDatabaseEx2 or CeSetDatabaseInfoEx2 to protect a database.
This functionality protects a single database, not an entire database volume. Setting FILE_ATTRIBUTE_SYSTEM on the volume file protects database volumes. System databases cannot be created inside database volumes that do not have FILE_ATTRIBUTE_SYSTEM set to block normal applications from accessing and/or deleting a file containing a system database using the Microsoft Win32® file APIs. Because an normal application cannot access any file with the system file attribute set, adding the system flag to a database inside a database volume does not give it any additional security. Therefore, this functionality is most useful in databases that are stored within the object store. Removing the system file attribute from a database volume that contains a system database will expose that database to access by normal applications and is not recommended.
CE"可信任环境"说通俗一点就是让你定制的CE内核启动后,只能运行内核包含的EXE、DLL模块和签名过的EXE、DLL模块,非签名EXE、DLL无法运行。"可信任环境"保证了你的内核的安全性,防止其他人非法研究你的内核或者非法在其上运行EXE、DLL。在讲述这个技术之前,请允许我先罗嗦几句。
下面开始讲解。Windows CE提供了一种机制,使定制操作系统内核的开发者能够保护自己定制的内核,加入了这种机制后,所有nk.bin解开的模块(EXE、DLL、OCX)都能够正常运行,存放在永久存储器上的模块在开发者数字签名后也能够运行,而没有数字签名的模块则不能运行。读者有兴趣可以查看CE帮助文档中标题为《Create a Trusted Environment》的文章。言简意赅,下面就开始讲解如何实现可信任环境。
1、得到钥容器
得到钥容器(key container)的方法是调用Win32 Security API。先得到CSP(cryptographic service provider),再得到key container。默认的CSP为Microsoft Base Cryptographic Provider。默认的key container以当前登录用户名为名称。如果你熟悉加密方面知识的话可以另外调用其他CSP。在此我们以Microsoft Base Cryptographic Provider默认的key container为signfile需要的钥容器。
2、对模块签名
signfile.exe用于对模块签名。这个文件在CE安装目录里(包括源码)可以找到,下面是参数说明:
-o<out filename>输出签名数据到指定的文件
-k<CAPI key container>指定CAPI 钥容器
-p<output C file to hold CAPI public key >输出公钥到指定文件(内容为一个C语言数组)
-s<string to sign and embed in signature>嵌入指定字符
-a在指定的PE格式的文件中附加签名数据
-f<PEFile >要签名的文件(EXE、DLL)
假如我们要将myproc.exe签名,假设我们以fulinlin名字在桌面 Windows 上登录,那么在命令行输入如下命令:
双击代码全选 | |
1 | signfile -fmyproc.exe -a -kfulinlin -pmyproc.txt |
上面参数告诉signfile.exe用钥容器fulinlin中的私钥将文件myproc.exe签名,并且将公钥存放到名为myproc.txt的文件中。加密具体过程很复杂,我对加密不了解,只能理解到这么低级的程度。如果说错了希望读者指教。
3、编写检验函数
编写检验函数前请参考CE的帮助文档中标题为《Verifying a Signature》的文章。我们只需要把这篇文章中最下面的代码复制到CE安装目录下定义OEMInit函数的.c文件中。因为我的调试平台属于X86系列,所以定义OEMInit函数是在cfwpc.c文件中。为了使读者能够简单弄懂这个机制,我把相关函数、变量做一个简单说明,如下:
初始化公钥函数
双击代码全选 | |
1 | externBOOLInitPubKey(constBYTE*KeyBlob, DWORDcbKeyBlob); |
/这两个指针是在loader.c文件中定义的,loader.c实现加载器的功能,加载模块(EXE、DLL)。这两个指针指向两个函数,pOEMLoadInit
指向的函数的功能是:每当加载一个模块的时候这个函数决定是否需要验证。TRUE表示需要,FALSE不需要。pOEMLoadModule指向的
函数的功能是:验证将要加载的模块是否具有合法的签名。有三个返回值,具体请看帮助文档。
双击代码全选 | |
1 2 | externOEMLoadInit_t pOEMLoadInit; externOEMLoadModule_t pOEMLoadModule; |
/以"CertifyModule"开头的函数为系统自带的验证函数。有了这三个函数你就不用去了解加密知识了。
双击代码全选 | |
1 2 3 | externBOOLCertifyModuleInit(void); externBOOLCertifyModule(PBYTEpbBlock, DWORDcbBlock); externBOOLCertifyModuleFinal(PBYTE*ppbSignData, PDWORD pcbSignData); |
注意公钥数据g_bSignPublicKeyBlob,要把signfile导出的公钥覆盖代码中原有的g_bSignPublicKeyBlob。
4、编译并测试
用PB打开一个内核工程,进入命令行状态(菜单open build release directory)。键入"build -c"和"sysgen i486oal",因为cfwpc.c是i486oal.lib的一部分。之后重新编译内核。测试方法是把任何一个CE下运行的EXE复制一份,一份不改变,另一份由signfile签名。然后把这两个文件复制到永久存储器上运行。测试结果签名的能运行,而不签名的不能运行(弹出对话框显示"找不到XXX(或它的某一个组件)。请确认......")。