Security/Tizen 3.X Key Manager initial value setting
- 1 Requirements
- 2 High Level Design
- 3 Detailed Design
- 4 Encrypted Initial Values enhancement
- Required to import keys, certs, and data from an external world to a device at the first boot time.
- The device manufacturer can inject a key into a device. Applications and modules within the device can use it.
- The imported key values should not be exposed.
- Required to generate keys at the first boot time
- A device can have its own platform key which are randomly generated at the first boot time and applications encrypt/decrypt data using this key. The key value is not exposed to applications but the application can use the key.
- Support for data sharing of data imported or generated at the first boot time
- Data imported/generated by system process must be available to user applications
High Level Design
The purpose of this feature is to load initial values from predefined location, store them in key-manager and remove them from filesystem.
The file format is XML. Document structure will be validated with the following schema: initial_values.xsd
Initial value files should be placed at:
Initial values file example: example.xml
XML validation and parsing will be implemented using libxml2.
All initial values will be stored in system database. That is a database reserved for and accessible only by system daemons with UID<5000 (according to ). We don't want to identify system processes by smack label (System) because non-system users are already identified by uid. To support system database key-manager will need the following changes:
- Most of system daemons run with root privileges, uid=0 and label="System". We can't rely on anything except process uid. Therefore such processes will be identified only by uid (not by smack label/pkg id).
- System users won't log in so database can't be protected with user password.
- Key-manager can derive the domain key encryption key (Domain KEK) from some hardcoded password and use it to encrypt/decrypt the database data encryption key (DB DEK) on-demand. This way the database would remain decrypted in the memory after first use.
- Domain KEK can be used as usual to derive an application data encryption key (App DEK). However, there would be only one common App DEK for all system daemons (there won't be any actual applications and we have to share system database contents between all system daemons).
- System daemon can also provide a custom hardcoded password to additionally encrypt a single row in database.
- It won't be safe unless hardware assisted encryption/decryption/key wrapping is used.
- Processes with system uids will have to be redirected to the common system database.
- The database must not be removed when a system user is removed.
- It won't be possible to change the key-manager password for system user.
- If for some reason a system user logs in/out key-manager should ignore it.
The system database will be populated by a privileged user (probably root) but objects must be accessible to ordinary users (Web_App_Encryption_Support). We don't want to populate user's databases because:
- Newly created user's wouldn't get initial values.
- Values would be duplicated in every user database.
- User should not be able to remove such "global" objects.
Instead, the system user will be able to grant read-only permissions to specific application running as an ordinary user (any user).
There will be 3 types of processes:
- System processes running with uid < 5000 and System label. They will be mapped to system database. System processes should be able to use control API.
- Applications running as an ordinary user with App* label. This is untrusted software and will be mapped to a proper database depending on uid and to a proper owner/application namespace depending on it's identifier. On tizen.org the process Smack label will be converted to pkg_id. The conversion will be performed by security-manager. Applications should not be able to use control API.
- Preinstalled software running as an ordinary user with User label. This is trusted software usually running separately for each user. Such processes will be mapped to a proper database depending on uid. Because it's not an application it will not be possible to get it's pkg_id. Instead such process will be mapped to a default namespace "-". Such processes should not be able to use control API.
Integration with installer (use case)
Preloaded application example (based on Web_App_Encryption_Support):
- Wrt-installer running as root during image creation installs preloaded a application PKG1.
- It generates APP_DEK and stores it in initial values file as an AES key under a name APP_DEK_PKG1.
- It encrypts the application with specific AES algorithm with specific configuration.
- It stores the algorithm type and configuration (like initialization vector) by itself.
- It gives PKG1 permission to access APP_DEK_PKG1.
- Wrt-launcher running as an ordinary logged in user during normal system operation launches the application PKG1.
- Webappenc gets AES key APP_DEK_PKG1 from system database.
- Webappenc uses the key and previously stored decryption parameters to decrypt the web application in runtime.
System database permissions
The following assumptions are made:
- There will be only one system-like database in key-manager.
- System database is not password protected and therefore key-manager service can access it at any time.
- There's no such thing as application in system database. All objects exist in a common namespace. Therefore, the label column in NAMES table will be hardcoded and common for all system database objects.
- By default no system users will have no access to system database (objects will be invisible to the client)
- It's not possible to share objects between ordinary users.
- Object names interpretation will be handled differently
- pkg1 object1 will refer to an object in users database owned by pkg1 named object1 as before.
- / object2 will refer to an object in system database in common namespace "/" named object2 ("/" is used to not clutter the app identifier namespace)
- Non-system user can use the second format to perform read-only operations using system database objects via API: <source lang="c">ckmc_get_key(“/ key1”, NULL, &key);</source>
- Object permissions will be handled differently for system database:
- System daemons (uid < 5000) have full access rights to the system database. No permission rules are required for system daemons (there are no apps and no accessor label).
- System user can grant read-only permissions to specific application running as an ordinary user: <source lang="c">ckmc_set_permission(“/ data1”, “pkg1”, “r”);</source>
- In case of system database permissionLabel column in PERMISSIONS table will identify accessing application label of any non-system user.
- Exportable flag works as usual.
- Modify object name validation to allow special owner "/".
- Support system database unlock with first access attempt.
- Introduce hardcoded app namespace in system database. All system database objects should be encrypted with common app DEK derived from Domain KEK
- Provide method responsible for system database access logic:
- Map uid < 5000 to database uid 0.
- Map "/" owner name to database uid 0.
- Database uid should be used to locate appropriate database but real uid should be used for permission check.
- Introduce separate permission logic for system database (AccessControl).
- Write operations on system database should be disallowed for ordinary users.
- Non-system user must be logged in to access system database (that is his DomainKEK should be unlocked).
- Handle system user login/logout (Ignore it but log warning).
- Prepare system database tests.
Initial value support
The whole operation of initial value parsing and saving should take place in key-manager server. Specifically in CKM service which is responsible for DB access. Initial values should be processed before any other requests to the service. Subtasks:
- Xml validation. If validation fails the XML file should be removed. Appropriate log should be produced.
- Xml parsing.
- Parser types:
- SAX - Low memory consumption, fast, harder to implement, RO access. [RECOMMENDED]
- DOM - High memory consumption (loads entire tree into memory), slower, easy to implement, RW access.
- XPath - Similar to DOM (loads tree into memory), easy to implement. Allows accessing individual elements by path.
- Error handling:
- Detecting version different than the current -> Log + remove file
- Receiving error callback from parser -> Log + remove file
- Logical error during parsing (incorrect parameters) -> Log + ignore current element
- Parser types:
- Storing initial values in system database.
- Xml removal.
- Prepare initial values tests.
- Parser - a generic class wrapping a SAX XML interface. Allows XML validation and parsing. Custom objects can be registered as listeners for specific events.
- ElementHandler - a base class for custom xml element handlers. The object is notified when an element starts, ends or some characters appear within it.
- InitialValuesFile - a class responsible for processing of single XML file with initial values. The class registers itself for document events and holds InitialValueLogic.
- InitialValuesLogic - a class providing different element handlers. It is registered in Parser. When new element starts, the InitialValuesLogic is asked to provide a handler object. It then returns custom ElementHandler derived class, which is again notified about XML events. Upon element end, after ElementHandler is notified the InitialValuesLogic is notified so that it can set the release the element handler. The class holds a connection to Database and passes it to current InitialValueHandler upon creation.
- InitialValueHandler - base class for key, cert and data elements. It holds the buffer and permissions handlers.
- KeyHandler - class for handling keys. When key element is finished an object of this class has all required information to save the key and permissions in database.
- CertHandler - class for handling certificates. When certificate element is finished an object of this class has all required information to save the certificate and permissions in database.
- DataHandler - class for handling data. When data element is finished an object of this class has all required information to save the data and permissions in database.
- BufferHandler - class for handling actual data.
- PermissionHandler - class for handling permissions to objects.
[NOTE] Diagram does not include a handler for main InitialValues element for clarity.
Example sequence for following initial values document: <source lang="xml"> <InitialValues version="0">
<Key name="key1" type="RSA_PRV" password="123"> <PEM> -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2b1bXDa+S8/MGWnMkru4 T4tUddtZNi0NVjQn9RFH1NMa220GsRhRO56F77FlSVFKfSfVZKIiWg6C+DVCkcLf zXJ/Z0pvwOQYBAqVMFjV6efQGN0JzJ1Unu7pPRiZl7RKGEI+cyzzrcDyrLLrQ2W7 0ZySkNEOv6Frx9JgC5NExuYY4lk2fQQa38JXiZkfyzif2em0px7mXbyf5LjccsKq v1e+XLtMsL0ZefRcqsP++NzQAI8fKX7WBT+qK0HJDLiHrKOTWYzx6CwJ66LD/vvf j55xtsKDLVDbsotvf8/m6VLMab+vqKk11TP4tq6yo0mwyTADvgl1zowQEO9I1W6o zQIDAQAB -----END PUBLIC KEY----- </PEM> </Key>
</InitialValues> </source> [NOTE] For clarity, the diagram does not include a InitialValues element parsing sequence.
Encrypted Initial Values enhancement
- keys in initial values file encrypted using the device key
- encryption: RSA OAEP
- new requirement: encryption of certificates and data items
High Level Design
Key problem with RSA OAEP encryption is the limitation on encrypted block size. It is 86[B] for 1024-bit key, 214[B] for 2048-bit key and 470[B] for 4096-bit key. This is far too low to encrypt any certificate or asymmetric key, but fair enough to encrypt an AES key.
This leads to a hybrid solution: values are encrypted using an AES-CBC encryption, while only the AES key is encrypted using the device key. Initial values file contains encrypted AES key and plain or AES-CBC encrypted values.
On startup, Key Manager would try to decrypt the AES key using device key (coming from hardware or a special, preloaded file storing just the RSA private, device key). If succeeds, Key Manager decrypts the items and proceed as in the original Initial Values solution.
initial_values.xsd has to be enhanced to support new elements. New items are:
- <EncryptionKey> element storing encrypted AES key in Base64 format. This element can appear only once.
- keys and certificates can provide the data using <EncryptedDer> tag, which contains item DER after AES-CBC encryption in Base64 format.
- data items can provide the data using following tags:
- <EncryptedASCII>: AES-CBC encrypted ASCII data (encoded with Base64)
- <EncryptedBinary>: AES-CBC encrypted binary data (encoded with Base64)
- all <EncryptedDer>, <EncryptedASCII> and <EncryptedBinary> tags require providing IV attribute containing 16[B] IV for it's item. IV must differ between items for security reasons!
Example file contents: <source lang="xml"> <InitialValues version="1">
<EncryptionKey> QL/5RW1VfS1uya04CWkVy1eykdhnRaTFiQ6Lcv0XFYhqgUKp6+PxxT1xjaz8TCVp UcKorZayMPCuStRAylViZfxHFhXKR3awH+FcnGMZrhV6kORy39YCba0NGc5eAk3s CBPYdRRiV7ejJSOI8n3zFjituVhHLcLuZB6xHvQQpQFFYV0BuF3BXfx6roP4+Olj bZ1fYDrj8QIzqi3RV/ORGbl1BqHVRoMN/5XB+8oVKVn/EMRZPao4hnkV3pTI01Ss Wid4fIHzBpi8rkkxr80/ym2BkeA/piaPNGOQtKjVfBOn/SuR2LQJreG6QbI6MYXC ZVOanzc0euaenw1q9b+yEQ== </EncryptionKey> <EncryptedASCII IV="__another_IV_2__">zuBDjp8ptFthrU69Ua5cfg==</EncryptedASCII>
Note the data above can be decrypted only when having access to original RSA device private key! Check the XSD and example.xml details: Gerrit link - in example.xml note please no size limit on encrypted items.
- implement schema changes.
- SW device key requires providing additional sw_key.xsd and appropriate key XML file.
- initial values parser must:
- obtain the device key:
- parse the SW device key if TZ not present; or
- ask TZ to provide device key alias; then
- parse the initial value file:
- if encrypted AES key present, use RSA-OAEP decryption using SW or TZ mechanism.
- if any encrypted item found, use AES-CBC decryption using SW or TZ mechanism.
- obtain the device key:
SW or TZ decryption
Device may or may not support TZ. Key Manager provides convenient Crypto::Decider class that decides if requested functionality should be performed using SW or TZ.
Key Manager TZ backend required changes:
- make Crypto::Decider select TZ on the very specific platform that supports TZ.;
- implement mechanism to obtain the device private key alias from TZ. This alias will be provided to crypto/tz-backend/store.hpp::getKey();
- implement RSA-OAEP decryption (manager/crypto/tz-backend/key.cpp).;
- implement AES-CBC decryption (manager/crypto/tz-backend/key.cpp).;
Encrypted file preparation
- [general] to Base64 encode any data: <source lang="bash">openssl enc -base64 -in binary.encrypted -out binary.encrypted.base64</source>
- to RSA-OAEP encrypt AES key:
- encrypt AES key: <source lang="bash">openssl rsautl -encrypt -oaep -pubin -inkey device.pub -in encryption_AES_key -out encryption_AES_key.encrypted</source>
- Base64 encode encrypted AES key: <source lang="bash">openssl enc -base64 -in encryption_AES_key.encrypted -out encryption_AES_key.encrypted.base64</source>
- put contents of encryption_AES_key.encrypted.base64 to the initial values file <EncryptionKey> tag.
- to AES-CBC an item:
- put your 16B IV to encryption_AES_IV
- encrypt your data: <source lang="bash">openssl aes-256-cbc -K `xxd -p -c 64 encryption_AES_key` -iv `xxd -p -c 64 encryption_AES_IV` -e -in data_to_crypt -out data_to_crypt.encrypted</source>
- Base64 encode encrypted item: <source lang="bash">openssl enc -base64 -in data_to_crypt.encrypted -out data_to_crypt.encrypted.base64</source>
- put contents of data_to_crypt.encrypted.base64 to the initial values file under your Key, Cert or Data item
- put IV from encryption_AES_IV into the IV attribute