Appendix B. Security considerations

Because some sensors may reveal sensitive information, access to sensors needs to be protected by the security framework. The sensor access is defined as any attempt by a MIDlet in a MIDlet suite to open the connection to the sensor and retrieve data using the SensorConnection interface. Discovery of the sensors is not protected and all the sensors are visible to be found by any MIDlet. SensorManager.findSensors() methods return all the matching sensors, but they cannot necessary be opened. The Connector.open() and PushRegistry.registerConnection() methods throw a SecurityException if the application does not have the required permission to use the sensor.

Originally the MIDP security model was defined in the MIDP 2.0 Specification and the Recommended Security Policy. The JTWI JSR 185 Specification defines the policy for the third-party domain ("untrusted domain"). The MSA JSR 248 Specification defines the four domains that the MIDlet suites are categorized to and a recommended policy for them. A MIDlet suite can belong to one of the four domains:

Sensor permissions

This API specifies three permissions to restrict the usage of some sensors. Some sensors might handle confidential data that the user doesn't want to be exposed. Examples include sensors related to health, or wealth like a heart rate sensor, or scales. Such sensors are considered to be private.

Another category of sensors with restricted access are system sensors. System sensors might handle hidden, or protected system resources. Data from these sensors is provided only for trusted applications. These sensors are called protected sensors.

Sensors that are not private or protected are understood as public sensors. All these sensor groups, private, protected, and public, require the javax.microedition.io.Connector.sensor permission to open the connection.

The table below defines the names of the three sensor related permissions and the methods that are protected by each permission.

Table B.1. Sensor security permissions

Permission name

Methods protected by this permission

javax.microedition.sensor.PrivateSensor

Connector.open() , PushRegistry.registerConnection()

javax.microedition.sensor.ProtectedSensor

Connector.open() , PushRegistry.registerConnection()

javax.microedition.io.Connector.sensor

Connector.open()

The permissions must be placed into some function group. This specification does not mandate any particular function group. This is left to the MSA EG to decide.

Each function group lists modes for domains, whether:

  1. Not allowed

  2. Always allowed

  3. Ask first time

  4. Ask every time

The function group lists also the mode options, which a user can set for trusted/untrusted applications.

The permissions of the application are cut from permissions of the application domain and permissions asked in a jad descriptor in:

The needed permissions may vary between devices

In different devices the protection of specific sensors may vary. This is problematic for the developers, because they do not know in advance which permissions are required. If, for example, MIDlet-Permissions: javax.microedition.sensor.PrivateSensor is requested, but the application domain does not have rights, the application is not even installed. The solution to this problem could be to use MIDlet-Permissions-Opt instead of MIDlet-Permissions. In this case the application is installed even if the domain didn't have defined rights.

Let's take the sensor measuring the quantity "fingerprint" as an example. In some devices it might require "javax.microedition.sensor.PrivateSensor" permission, in some devices it might not. By requesting in a JAD:

    MIDlet-Permissions-Opt: javax.microedition.sensor.PrivateSensor

the application is installed in every case - even its domain has not got the required permissions to use the sensor. The installed application might even work, if the private sensor is not essential for that functionality. The application also works fine in the case the sensor is not private, i.e., requesting permissions in vain does not cause harm.

Permission for CDC

JSR 256 implementation in CDC and MIDP 3 based environments requires a permission class to be defined in addition to the traditional permission names that worked with MIDP 2. The permission class should be based on the existing permission names already defined in the JSR.

Permissions for CDC and CLDC 1.1.1 implementations use the fine-grained security permissions based on java.security.Permission. In this API the only control point is opening the sensor with the call Connector.open() or push registering the sensor for an automatic launch. Hence only one permission class, javax.microedition.sensor.SensorProtocolPermission, was defined. If the sensor can be opened, all the actions are allowed thereafter, therefore no actions are listed in the SensorProtocolPermission. This permission accepts as a name either a valid sensor URI or constants "javax.microedition.sensor.PrivateSensor" / "javax.microedition.sensor.ProtectedSensor". The constants are for granting access to private or protected sensors.

Permission class with different name options Corresponding named permission Methods protected by this permission
SensorProtocolPermission(PRIVATE) javax.microedition.sensor.PrivateSensor, javax.microedition.io.Connector.sensor Connector.open() , PushRegistry.registerConnection()
SensorProtocolPermission(PROTECTED) javax.microedition.sensor.ProtectedSensor, javax.microedition.io.Connector.sensor Connector.open() , PushRegistry.registerConnection()
SensorProtocolPermission(sensor_url) javax.microedition.io.Connector.sensor and when needed: javax.microedition.sensor.PrivateSensor and/or javax.microedition.sensor.ProtectedSensor Connector.open(), PushRegistry.registerConnection()

SensorProtocolPermission

package javax.microedition.sensor;

import java.security.Permission;

import javax.microedition.io.GCFPermission;

/**
 <p>This class represents an access right to a connection/connections 
 via the "sensor" protocol. The <code>SensorProtocolPermission</code> 
 grants the permission to either sensors measuring a certain quantity 
 or to private/protected sensors. If the name given is a sensor URI 
 then the access for sensors pointed by this URI is granted.
 Because a valid sensor URI always contains a quantity, 
 <code>SensorProtocolPermissions</code> constructed with a URI 
 will always address sensors of one quantity.
 The sensor URI is defined in {@link SensorConnection}.</p>
  
 <p>{@link #PRIVATE} and {@link #PROTECTED} constants
 are for private and protected sensors; the access is granted for 
 the whole group of such sensors. The sensors of the group are most
 probably measuring different quantities.</p> 
 
 <p>In the Mobile Sensor API the only security control points  
 are opening a connection and registering for push, no other methods are protected. 
 That is why no actions are listed here.</p>
 
 <p>Note: the sensor URI as a name may refer to one or more sensors, 
 including private and protected sensors.
 If the policy prevents opening any of these sensors, the permission
 must not be granted.</p>
 */
public final class SensorProtocolPermission extends GCFPermission {

     /**
     *<p>
     The name for the permission targeted to private sensors.
     </p>
     */
     public final static String PRIVATE    
         = "javax.microedition.sensor.PrivateSensor";

    /**
     *<p>
     The name for the permission targeted to protected sensor.
     </p>
     */
     public final static String PROTECTED    
         = "javax.microedition.sensor.ProtectedSensor";



    /**
     <p>The method creates a new <code>SensorProtocolPermission</code>,
     the name of which may be:</p>
     <ul>
     <li>the sensor URI</li>
     <li>{@link #PRIVATE}</li>
     <li>{@link #PROTECTED}</li>
     </ul> 
     @param name the permission name
     @throws IllegalArgumentException if the <code>uri</code> is zero length
     or not a valid name
     @throws NullPointerException if <code>uri</code> is <code>null</code>
     */
    public SensorProtocolPermission(java.lang.String name){
    	if (name==null)
    	   throw new NullPointerException(
		   "SensorProtocolPermission called with a null value");
    	if (name.length() == 0)
    	   throw new IllegalArgumentException(
    	   "SensorProtocolPermission called with a zero-length name");
    	try{
    	   SensorManager.findSensors(name);
    	}catch (IllegalArgumentException e) {
    	   throw new IllegalArgumentException(
	   "SensorProtocolPermission called with an invalid name "+name);
	}
    			
    }


	/**<p>
	 The method checks two <code>SensorProtocolPermission</code> objects 
	 for equality. Checks that given <i>object</i> is
	 a <code>SensorProtocolPermission</code> and has the same name as this object.</p>
	 
	 @param object the object we are testing for equality with this object.
	 @return <code>true</code> if object is a <code>SensorProtocolPermission</code>, 
	 and has the same name as this <code>SensorProtocolPermission</code> object.
	 */
	public boolean equals(Object object) {
		if (object == this)
			return true;
		if (! (object instanceof SensorProtocolPermission))	
			return false;
		return getName().equals(((SensorProtocolPermission)object).getName());
	}

	/**<p>
	 The method returns actions, for this permission 
	 the method returns always <code>null</code> since no actions are defined.</p>
	 @return <code>null</code>
	 */
	public String getActions()
	{
		return null;
	}

	/**<p>
	 The method returns the hash code value for this object.
	 The value returned complies with the requirements of the
	 the hashCode method of the superclass.</p>
	 @return a hash code value for this object.
	 */
	public int hashCode() {
		return this.getName().hashCode();
	}

	
	/**<p>
	 The method checks if this <code>SensorProtocolPermission</code> 
	 object "implies" the specified
	 permission. More specifically, this method returns <code>true</code> if:</p>
	 <ul>
	 <li><i>p</i> is an instanceof <code>SensorProtocolPermission</code>, and</li>
	 <li><i>p</i>'s actions return <code>null</code>, and</li>
	 <li><i>p</i>'s name equals this object's name, or if</li>
	 <li><i>p</i>'s sensor URI defines a subset of the category
	 (private/protected), or if</li>
	 <li><i>p</i>'s sensor URI defines a subset of sensors of this object's URI</li>
	 </ul>
	 
	 @param p the permission to check against.
	 *
	 @return <code>true</code> if the specified permission is implied by this object,
	 <code>false</code> if not.
	 */

	public boolean implies(Permission p) {
		if (!(p instanceof SensorProtocolPermission)) return false;


		// Check of this SensorProtocolPermission's name implies the other's name
		String name = getName();
		String name2 = p.getName();
		if (name.equals(name2)) return true;
		

		// URI defines a subset of sensors of this object's category (private/protected)
		String[] categories = {PRIVATE, PROTECTED};
		SensorInfo[] infos2 = SensorManager.findSensors(name2);
		for (int i=0; i<categories.length; i++){
			if (!name.equals(categories[i])) continue;
			if (name2.equals(categories[i])) return false;
			
			for (int j=0; j<infos2.length; j++){
				String category = null;
				if (infos2[j].getProperty(SensorInfo.PROP_PERMISSION)!=null){
					category = (String)infos2[j].getProperty(SensorInfo.PROP_PERMISSION);
				}
				if (category == null) return false;
				if (category.indexOf(categories[i])==-1) return false;	
			}
			// true only if sensors were found
			return (infos2.length>0);
		}
		
		
		// URI defines a subset of sensors of this object's URI
		SensorInfo[] infos = SensorManager.findSensors(name);
		
		//infos2 must be a subset of infos
		for (int i=0; i<infos2.length; i++){
			String tmpUrl2 = infos2[i].getUrl();
			int j=0;
			for (; j<infos.length && !(infos[i].getUrl().equals(tmpUrl2)); j++);
			if (j==infos.length) return false;
		}
		// true only if sensors were found
		return (infos2.length>0);
	}
}