blob: 930e6486515f76d8bca452870d4dcd799ddfe590 [file] [log] [blame]
<html devsite>
<head>
<title>Version Binding</title>
<meta name="project_path" value="/_project.yaml" />
<meta name="book_path" value="/_book.yaml" />
</head>
<body>
<!--
Copyright 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
//www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<p>
In Keymaster1, all keymaster keys were cryptographically bound to the device
<em>Root of Trust</em>, the <a href="/security/verifiedboot/">verified boot
key</a>. In Keymaster2, all keys are
also bound to the operating system and patch level of the system image.
This ensures that an attacker who discovers a weakness in an old
version of system or TEE software cannot roll a device back to the vulnerable
version and use keys created with the newer version. In addition, when a key
with a given version and patch level is used on a device that has been upgraded
to a newer version or patch level, the key is upgraded before it can be used,
and the previous version of the key invalidated. In this way, as the device is
upgraded, the keys will "ratchet" forward along with the device, but any
reversion of the device to a previous release will cause the keys to be
unusable.
</p>
<h2 id="hal-changes">HAL changes</h2>
<p>
To support version binding and version attestation, Android 7.1 added the tags
<code>KM_TAG_OS_VERSION</code> and <code>KM_TAG_OS_PATCHLEVEL</code> and the
methods <code>configure</code> and <code>upgrade_key</code>. The version tags
are automatically added by keymaster2 implementations to all newly-generated (or
updated) keys. Further, any attempt to use a key that does not have an OS
version or patch level matching the current system OS version or patch level,
respectively, is rejected with <code>KM_ERROR_KEY_REQUIRES_UPGRADE</code>.
</p>
<p>
<code>KM_TAG_OS_VERSION</code> is a <code>KM_UINT</code> that represents the
major, minor, and sub-minor portions of an Android system version as MMmmss,
where MM is the major version, mm is the minor version and ss is the sub-minor
version. For example 6.1.2 would be represented as 060102.
</p>
<p>
<code>KM_TAG_OS_PATCHLEVEL</code> is a <code>KM_UINT</code> that represents the
year and month of the last update to the system as YYYYMM, where YYYY is the
four-digit year and MM is the two-digit month. For example, March 2016 would be
represented as 201603.
</p>
<h3 id="upgrade_key">Upgrade_key</h3>
<p>
To allow keys to be upgraded to the new OS version and patch level of the system
image, Android 7.1 added the <code>upgrade_key</code> method to the HAL:
</p>
<pre
class="prettyprint">keymaster_error_t (*upgrade_key)(const struct keymaster2_device* dev,
const keymaster_key_blob_t* key_to_upgrade,
const keymaster_key_param_set_t* upgrade_params,
keymaster_key_blob_t* upgraded_key);
</pre>
<ul>
<li><code>dev</code> is the device structure</li>
<li><code>key_to_upgrade</code> is the key which needs to be upgraded</li>
<li><code>upgrade_params</code> are parameters needed to upgrade the key. These
will include <code>KM_TAG_APPLICATION_ID</code> and
<code>KM_TAG_APPLICATION_DATA</code>, which are necessary to decrypt the key
blob, if they were provided during generation.</li>
<li><code>upgraded_key</code> is the output parameter, used to return the new
key blob.</li>
</ul>
<p>
If <code>upgrade_key</code> is called with a key blob that cannot be parsed or
is otherwise invalid, it returns <code>KM_ERROR_INVALID_KEY_BLOB</code>. If it
is called with a key whose patch level is greater than the current system value,
it returns <code>KM_ERROR_INVALID_ARGUMENT</code>. If it is called with a key
whose OS version is greater than the current system value, and the system value
is non-zero, it returns KM_ERROR_INVALID_ARGUMENT. OS version upgrades from
non-zero to zero are allowed. In the event of errors communicating with the
secure world, it returns an appropriate error value (e.g.
<code>KM_SECURE_HW_ACCESS_DENIED</code>, <code>KM_SECURE_HW_BUSY</code>, etc.)
Otherwise, it returns <code>KM_ERROR_OK</code> and returns a new key blob in
<code>upgraded_key</code>.
</p>
<p>
<code>key_to_upgrade</code> remains valid after the <code>upgrade_key</code>
call, and could theoretically be used again if the device were downgraded. In
practice, keystore generally calls <code>delete_key</code> on the
<code>key_to_upgrade</code> blob shortly after the call to upgrade_key. If
<code>key_to_upgrade</code> had tag <code>KM_TAG_ROLLBACK_RESISTANT</code>, then
<code>upgraded_key</code> should have it as well (and should be rollback
resistant).
</p>
<h2 id="secure-configuration">Secure configuration</h2>
<p>
To implement version binding, the keymaster TA needs a way to securely receive
the current OS version and patch level (version information), and to ensure that
the information it receives strongly matches the information about the running
system.
</p>
<p>
To support secure delivery of version information to the TA, an <code><a
href="https://android.googlesource.com/platform/system/core/+/master/mkbootimg/bootimg.h#48">os_version
field</a></code> has been added to the boot image header. The boot image build
script automatically populates this field. OEMs and keymaster TA implementers
need to work together to modify device bootloaders to extract the version
information from the boot image and pass it to the TA before the non-secure
system is booted. This ensures that attackers cannot interfere with provisioning
of version information to the TA.
</p>
<p>
It is also necessary to ensure that the system image has the same version
information as the boot image. To that end, the configure method has been added
to the keymaster HAL:
</p>
<pre
class="prettyprint">keymaster_error_t (*configure)(const struct keymaster2_device* dev,
const keymaster_key_param_set_t* params);
</pre>
<p>
The <code>params</code> argument contains <code>KM_TAG_OS_VERSION</code> and
<code>KM_TAG_OS_PATCHLEVEL</code>. This method is called by keymaster2 clients
after opening the HAL, but before calling any other methods. If any other method
is called before configure, the TA returns
<code>KM_ERROR_KEYMASTER_NOT_CONFIGURED</code>.
</p>
<p>
The first time <code>configure</code> is called after the device boots, it
should verify that the version information provided matches what was provided by
the bootloader. If the version information does not match,
<code>configure</code> returns <code>KM_ERROR_INVALID_ARGUMENT</code>, and all
other keymaster methods continue returning
<code>KM_ERROR_KEYMASTER_NOT_CONFIGURED</code>. If the information matches,
<code>configure</code> returns <code>KM_ERROR_OK</code>, and other keymaster
methods begin functioning normally.
</p>
<p>
Subsequent calls to <code>configure</code> return the same value returned by the
first call, and do not change the state of keymaster. Note that this process
will REQUIRErequire that all OTAs update both system and boot images; they can't
be updated separately in order to keep the version information in sync.
</p>
<p>
Because <code>configure</code> will be called by the system whose contents it is
intended to validate, there is a narrow window of opportunity for an attacker to
compromise the system image and force it to provide version information that
matches the boot image, but which is not the actual version of the system. The
combination of boot image verification, dm-verity validation of the system image
contents, and the fact that <code>configure</code> is called very early in the
system boot should make this window of opportunity difficult to exploit.
</p>
</body>
</html>