MOBILE

Mobile Application Security : SymbianOS Security - Persistent Data Storage

2/23/2011 9:23:03 AM
SymbianOS supports several methods for maintaining persistent data storage, residing on both fixed internal and removable storage devices. At the bottom resides a traditional file system model, accessed through the file server process. Built on top of this resides an optional DBMS layer than can operate in two modes—integrated within a process as a library, accessing data stored within the process’s storage space, or as a server process that can store and police access within a separate storage location.

File Storage

Writable storage devices used with Symbian devices are formatted with the VFAT file system—a very simple format that is widely supported throughout the computer industry. In fact, this near universal support is one of the key reasons for its selection. Removable storage had to be capable of being read by other devices, such as general-purpose computers.

Unfortunately, VFAT does not support several features that assist with appropriate file access controls, recording neither the creator/owner nor access permissions. Instead, these are enforced by the file server process through which file access operations are performed. The file server dynamically evaluates whether a process is allowed to access a particular file based on the file path, the file operation, and four simple rules. Access to the \sys directory is restricted to processes that contain the AllFiles or TCB capabilities. Write access to \resource is restricted to processes that have TCB. Directories under \private are restricted based on the SecureID of the requesting process. If the directory name is the process SecureID, no capabilities are required; otherwise, AllFiles is required. Finally, all other files have no access restrictions. These rules are summarized in Table 1. These rules apply equally across all mounted file systems—Z:\ (ROM), C:\ (internal), and so on.

Table 1. Directory Access Restrictions
PathCapability Required To ReadCapability Required To Write
\sysAllFilesTCB
\resourceNoneTCB
\private\ [SecureID]None (process with same SID)None (process with same SID)
 AllFiles (process with different SID)AllFiles (process with different SID)
\[Other]NoneNone

Data Caging

Any data that generally should not be accessible on the device should be placed within the executable’s private data storage. Note that two process instances loaded from the same executable will share the same private directory because it is keyed off the SecureID. The file server API provides several methods for easily accessing the private directory for a given executable, including CreatePrivatePath(TInt TargetDrive) and SetSessionToPrivate(TInt TargetDrive).

File Handle Sharing

It may be desirable to provide limited access to files stored within a private directory. The file server provides support for sharing open file handles between processes, similar in function to other platforms. The sharing process will create a session with the file server and mark the session as sharable by calling RFs::ShareProtected(). It will then open the files to be shared; access controls are performed once at this time. It will then call RFile::TransferToClient() on the target file. The client will than call RFile::AdoptFromServer() on the received file handle. The client now has access to the file in whatever mode it was opened with. There are three separate transfer and adopt functions, depending on the relationship between sharing processes. Files can be shared from a server to a client, from a client to a server, and from a parent to a spawned child.

In actuality, it is the file server session that is shared with the target process. RFile objects are actually subsessions associated with a specific session to the file server and maintain an internal reference to the session. One important consequence of this is that any open files within a file server session are accessible to a client that a file has been shared with. Whenever a file is to be shared with a target process, a new file server session should be established and only the target files should be opened. This prevents a malicious executable from viewing or modifying other open files.

Structured Storage

In addition to private file storage within an application’s private directory, there is also a system-wide service for providing SQL database storage. Access to this service is handled through the RSqlDatabase class, similar to how file access is mediated through the RFs class. Databases can be created in two ways: by specifying a filename and by specifying a database name and a security policy. When a new database is created via filename, any other application that can access that file location can read the database. When a new database is created via a specified name and policy, only applications that conform to the policy can access the database (that is, it is shared in a secure fashion). In this case, the database is stored within the SQL database private directory. The format of the name for a shared secure database is <drive>:[<SID>]dbname. To create a database, the SID must match that of the current process.

Use the RSqlSecurityPolicy class to define the policy for access to the secure shared database upon creation. Once the policy is set, it cannot be changed for the lifetime of the database. A separate policy can be set for the database schema, global database read, global database write, table read, and table write. This means you can create a database where some tables can be read by any process, but others are restricted based on capabilities, SecureID, or VendorID.

When you’re using the RSqlDatabase object, the same concern about mixing data and statements applies as would apply to any SQL database. Namely, be aware of SQL injection when integrating untrusted input into database queries. Use prepared statements, rather than raw string concatenation, in order to safely make database queries. This is done by calling RSqlStatment::Prepare with a descriptor containing the parameterized query. Parameters are identified with a colon (:) prepended to them. Then the appropriate Bind method is called for the type of data that is to replace the parameter.

Encrypted Storage

SymbianOS does not provide a standard encrypted storage feature. In addition, the cryptography APIs must be downloaded and installed separately from the Symbian ^ 1 SDK. This support is changing at a rapid pace and may be offered within the base SDK in a future release. Unfortunately, such support may provide a wholly different API from what’s described here.

These APIs allow a developer to access the same cryptographic algorithms that are already installed on the device to support, such as certificate validation and secure communications protocols. They provide a wide-ranging set of cryptographic-related functionality, including key exchange, asymmetric and symmetric encryption, integrity through digital signatures and HMACs, and message digests.

Data that should be kept private regardless of where it is stored should therefore be explicitly encrypted. This is readily apparent for files placed on removable storage, but it is also important for files stored on internal media. A determined attacker could disassemble the device to gain access to such files. Performing encryption correctly and securely can be a confusing proposition. The Symbian cryptographic API attempts to mitigate this by presenting a nested and chained structure.

Proper encryption requires the use of sufficiently random numbers derived from a pool of entropy. Otherwise, an attacker who knows the approximate random seed (for example, timestamp) could guess generated keys with relative ease. SymbianOS provides the CSystemRandom class in order to obtain secure random numbers. After instantiating an instance of the class, you should provide a data descriptor of the desired length to the GenerateBytesL method to obtain the required random values. Here’s an example:

LData AESKey128, HMACKey, IV;
TRandom rng;

AESKey128.SetLengthL(16);
HMACKey.SetLengthL(20);
IV.SetLengthL(16);

rng.RandomL(AESKey128);
rng.RandomL(HMACKey);
rng.RandomL(IV);

Once a random key has been generated, it can be used to perform encryption on a binary blob of data. A symmetric block encryption algorithm only defines a block transformation. Given a key and a block, an apparently random block is returned, although the same block and the same key will always return the result. A complete system also includes padding, an initialization vector, and a method of chaining. This is done to obscure any structure between blocks from analysis. The SymbianOS cryptographic libraries provide AES and 3DES, PKCS #7 padding, and CBC mode chaining, as demonstrated here:

LCleanedupPtr< CBufferedEncryptor > encryptor(CBufferedEncryptor::NewL(
CModeCBCEncryptor::NewL(CAESEncryptor::NewL(AESKey128), IV),
CPaddingPKCS7::NewL(16)));

ctxt.ReserveFreeCapacityL(encryptor->MaxFinalOutputLength(ptxt.Size()));
encryptor->ProcessFinalL(ptxt, ctxt);

It is often assumed that encrypted data will decrypt to garbage data when tampered with, but this is not always the case. An encrypted blob should be integrity-protected in order to detect when tampering has occurred. Integrity protection can be easily provided with an HMAC, which takes a new key and a message digest algorithm. Be sure to include the initialization vector when calculating the HMAC verifier! This can be seen in the brief snippet shown next.

LCleanedupPtr< CMessageDigest >
hmac(CMessageDigestFactory::NewHMACL(CMessageDigest::ESHA1, HMACKey));
LData verifier;

hmac->Update(IV);
hmac->Update(ctxt);
verifier = hmac->Final();

In order to recover encrypted data or validate a verifier, the associated key needs to be maintained. The data-caging mechanism previously described generally provides sufficient protection, as long as keys are stored solely on internal storage. For more sensitive requirements, consider encapsulating keys by encrypting them with another key derived from a user-supplied password. In this fashion, sensitive data can be stored with a strong random key, and the encryption key (a much smaller piece of data) can be protected with a password-derived key. Be sure to generate an HMAC as well. This is demonstrated in the brief code snippet shown next:

TPBPassword password(_L("password"));
LData derivedKey, derivedKeySalt;
TRandom rng;

derivedKey.SetLengthL(16);
derivedKeySalt.SetLengthL(8);

rng.RandomL(DerivedKeySalt);

TPKCS5KDF::DeriveKeyL(derivedKey, password.Password(),
derivedKeySalt, KDefaultIterations);

The cryptographic libraries also include support for asymmetric operations—encrypting, decrypting, signing, and verification. The RSA implementation can be used for all four operations, whereas the included DSA implementation can only be used for signing and verification. Performing each of these actions can be seen in the following code:

LCleanedupPtr< CRSAKeyPair > kp(CRSAKeyPair::NewL(2048));
LCleanedupPtr< CRSASignature > signature;

LCleanedupPtr< CRSAPKCS1v15Encryptor > RSAencryptor(
CRSAPKCS1v15Encryptor::NewL(kp->PublicKey()));
RSAencryptor->EncryptL(pKey, cKey);

LCleanedupPtr< CRSAPKCS1v15Decryptor > RSAdecryptor(
CRSAPKCS1v15Decryptor::NewL(kp->PrivateKey()));
RSAdecryptor->DecryptL(cKey, pKey);

LCleanedupPtr< CRSAPKCS1v15Signer > RSAsigner(
CRSAPKCS1v15Signer::NewL(kp->PrivateKey()));
signature = RSAsigner->SignL(sha256hash);

LCleanedupPtr< CRSAPKCS1v15Verifier > RSAverifier(
CRSAPKCS1v15Verifier::NewL(kp->PublicKey()));
RSAverifier->VerifyL(sha256hash, *signature);

 
Other  
  •  Mobile Application Security : SymbianOS Security - Interprocess Communication
  •  Mobile Application Security : SymbianOS Security - Permissions and User Controls
  •  Windows Phone 7 Development : Building a Trial Application (part 3) - Verifying Trial and Full Mode & Adding Finishing Touches
  •  Windows Phone 7 Development : Building a Trial Application (part 2) - Connecting to a Web Service & Adding Page-to-Page Navigation
  •  Windows Phone 7 Development : Building a Trial Application (part 1) - Building the User Interface
  •  jQuery 1.3 : Table Manipulation - Sorting and paging (part 2) : Server-side pagination & JavaScript pagination
  •  jQuery 1.3 : Table Manipulation - Sorting and paging (part 1) : Server-side sorting & JavaScript sorting
  •  Windows Phone 7 Development : Understanding Trial and Full Modes (part 3) - Simulating Application Trial and Full Modes
  •  Windows Phone 7 Development : Understanding Trial and Full Modes (part 2) - Using the Marketplace APIs
  •  Windows Phone 7 Development : Understanding Trial and Full Modes (part 1) - Using the IsTrial Method
  •  Mobile Application Security : SymbianOS Security - Application Packaging
  •  Mobile Application Security : SymbianOS Security - Code Security
  •  iPhone Application Development : Getting the User’s Attention - Generating Alerts
  •  iPhone Application Development : Getting the User’s Attention - Exploring User Alert Methods
  •  iPhone Application Development : Using Advanced Interface Objects and Views - Using Scrolling Views
  •  Working with the Windows Phone 7 Application Life Cycle (part 2) - Managing Application State
  •  Working with the Windows Phone 7 Application Life Cycle (part 1) - Observing Application Life Cycle Events
  •  Mobile Application Security : SymbianOS Security - Development and Security Testing
  •  Mobile Application Security : SymbianOS Security - Introduction to the Platform
  •  Java Mobile Edition Security : Permissions and User Controls
  •  
    Top 10
    Exchange Server 2010 : Active Manager - Automatic database transitions & Best copy selection
    Exchange Server 2010 : Breaking the link between database and server
    iPhone 3D Programming : Drawing an FPS Counter (part 2) - Rendering the FPS Text
    iPhone 3D Programming : Drawing an FPS Counter (part 1) - Generating a Glyphs Texture with Python
    Mobile Application Security : Mobile Geolocation - Geolocation Methods & Geolocation Implementation
    Mobile Application Security : SMS Security - Application Attacks & Walkthroughs
    Transact-SQL in SQL Server 2008 : Table-Valued Parameters
    Transact-SQL in SQL Server 2008 : New date and time Data Types and Functions
    Windows 7 : Working with User Accounts (part 2)
    Windows 7 : Working with User Accounts (part 1)
    Most View
    Windows Server : Branch Office Deployment - Branch Office Services (part 2)
    Windows 7 : Using Windows Defender (part 2) - Scanning Your Computer for Spyware and Malware
    Examining Exchange Server 2010 Performance Improvements
    Beginning Android 3 : Working with Containers - LinearLayout Example & The Box Model
    Work with IIS 7.0 : Delegate Rights Assignments
    Programming .NET Security : Extending the .NET Framework (part 2) - Defining the Key Exchange Deformatter
    Active Directory Domain Services 2008 : Remove a User, Group, or Computer from the Password Replication Policy
    Programmatic Security (part 6) - Assembly-Wide Permissions
    Windows Phone 7 Development : Building a Phone Client to Access a Cloud Service (part 2) - Coding MainPage
    Windows Azure : Messaging with the queue - Decoupling your system with messaging
    Windows Phone 7 Development : Push Notifications - Understanding Push Notifications
    Working with the REST API
    Deploying a Windows Server 2008 R2 Network Policy Server
    SQL Programming Language : Ordering, Calculating, and Grouping in Queries
    Cloud Application Architectures : Web Application Design
    Algorithms for Compiler Design: SYNTAX-DIRECTED TRANSLATION SCHEMES
    Windows Mobile Security - Networking
    Installing Programs in Vista: The Essentials
    LINQ Projection Queries and Alternatives in WCF Services
    SQL Server 2008 : Retrieving and Transforming XML Data