Gatekeeper/密码锁/locksetting
1 什么是 Gatekeeper
1.1 enroll 过程
- CA 发送带加密的明文到TEE
- TEE 对明文(data)加密得道密文(signature),密文填充到 password_handle
- TEE 返回 password_handle (含密文)给ca
- ca 将 password_handle(含密文) 保存
1.2 verify 过程
- CA 发送明文和 password_handle(含密文) 给TEE
- TEE 计算 密文(signature)
- 如果 两个密文相等 则TEE 返回Authtoken 给ca
- CA 将 Authtoken 保存到keystore
2 Gatekeeper 框架
3 Gatekeeper的实现
4 locksetting 架构
4.1 4个测试接口
APP
cts
cmd
vts
5 Vendor Hal
vendor/mediatek/proprietary/trustzone/trustonic/source/external/gatekeeper/comon/400b/include/HalAdaptationLayer.h
static int enroll(const struct gatekeeper_device *dev, uint32_t uid,
const uint8_t *current_password_handle, uint32_t current_password_handle_length,
const uint8_t *current_password, uint32_t current_password_length,
const uint8_t *desired_password, uint32_t desired_password_length,
uint8_t **enrolled_password_handle, uint32_t *enrolled_password_handle_length);
static int verify(const struct gatekeeper_device *dev, uint32_t uid, uint64_t challenge,
const uint8_t *enrolled_password_handle, uint32_t enrolled_password_handle_length,
uint8_t *provided_password, uint32_t provided_password_length,
uint8_t **auth_token, uint32_t *auth_token_length, bool *request_reenroll);
5.1 Enroll Parameter:
- current_password_handle : password_handle_t structure, It is null if enroll firstly. For changing password
- current_password : The old password. It is null if enroll firstly. For changing password
- desired_password : The new password
- enrolled_password_handle : return password_handle_t structure
如果之前已经存在密码,则要传 current_password 和 current_password_handle
5.2 Verify Parameter:
- enrolled_password_handle : password_handle_t structure
- provided_password : Password to be validated
- auth_token : return authtoken
6 password handle
(system/gatekeeper/include/gatekeeper/password_handle.h)
(struct __attribute__((__packed__)) password_handle_t {
uint8_t version;
secure_id_t user_id;
uint64_t flags;
salt_t salt;
uint8_t signature[32];
bool hardware_backed;
});
enrolled_password_handle->version = handle_version;
enrolled_password_handle->salt = salt;
enrolled_password_handle->user_id = user_id;
enrolled_password_handle->flags = flags;
enrolled_password_handle->hardware_backed = gkbase_IsHardwareBacked();
enrolled_signature = signature;
/*
- handle_version: hardcode 2
- salt: random every enroll
- user_id: random When calling enroll() firstly, also named SID
- flags : throttle flag,hardcode 2. the flag of enabling the failed password count function.
- hardware_backed : hardcode 1
- signature: HMAC(data,key) = signature
- handle_version:硬编码为2。
- salt:每次注册时生成的随机数。
- user_id:首次调用`enroll()`时的随机数,也称为SID。
- flags:节流标志,硬编码为2,代表启用失败密码计数功能的标志。
- hardware_backed:硬编码为1。
- signature:HMAC(数据,密钥)= 签名。
*/
7 auth_token
(hardware/libhardware/include/hardware/hw_auth_token.h)
typedef enum {
HW_AUTH_NONE = 0,
HW_AUTH_PASSWORD = 1 << 0,
HW_AUTH_FINGERPRINT = 1 << 1, //指纹
// Additional entries should be powers of two.
HW_AUTH_ANY = UINT32_MAX,
} hw_authenticator_type_t;
typedef struct attribute((packed)) {
uint8_t version; // Current version is 0
uint64_t challenge;
uint64_t user_id; // secure user ID, not Android user ID
uint64_t authenticator_id; // secure authenticator ID
uint32_t authenticator_type; // hw_authenticator_type_t, in network order
uint64_t timestamp; // in network order
uint8_t hmac[32];
} hw_auth_token_t;
/*实例 */
auth_token->version = HW_AUTH_TOKEN_VERSION;
auth_token->challenge = challenge;
auth_token->user_id = secure_user_id;
auth_token->authenticator_id = 0; // Reserved for future use
auth_token->authenticator_type = htonl(HW_AUTH_PASSWORD);
auth_token->timestamp = htobe64(timestamp);
/*生成 hmac key*/
TEE_ReturnCode_t ret = create_hmac_sha256(
auth_token->hmac, sizeof(auth_token->hmac),
(uint8_t*)auth_token, token_len, hkey, sizeof(hkey), 0
);
8 failure record
counter 存文件系统
9 密码保存的路径
/sysytem/ 目录下
/*
/aosp/frameworks/base/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
*/
public void writeCredentialHash(CredentialHash hash, int userId) {
byte[] patternHash = null;
byte[] passwordHash = null;
if (hash.type == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD ||
hash.type == LockPatternUtils.CREDENTIAL_TYPE_PIN ||
hash.type == LockPatternUtils.CREDENTIAL_TYPE_PIN) {
passwordHash = hash.hash;
} else if (hash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) {
patternHash = hash.hash;
} else {
Preconditions.checkArgument(hash.type == LockPatternUtils.CREDENTIAL_TYPE_NONE,
"Unknown credential type");
}
writeFile(getLockPasswordFilename(userId), passwordHash);
writeFile(getLockPatternFilename(userId), patternHash);
}
private static final String SYSTEM_DIRECTORY = "/system/";
private static final String LOCK_PATTERN_FILE = "gatekeeper.pattern.key";
private static final String LOCK_PASSWORD_FILE = "gatekeeper.password.key";
/*
如果密码或pin,
保存password_handle到“gatekeeper.password.key”
保存NULL到“gatekeeper.pattern.key”
*/
/*
如果是pattern,
保存password_handle到“gatekeeper.pattern.key”
保存NULL到“gatekeeper.password.key”
*/
}
10 Andriod Security architecture
要保持三者的hmac key 一致