Android N 指纹框架

1. 指纹框架UML

image.png

2. Fingerprint

2.1 Fingerprint数据流图

图片.png
  • FingerprintManager API. 直接与应用程序交互的API,属于当前APP进程.

    • 每个应用程序都可以获取FingerprintManager.

    • FingerprintManager主要是应用程序与FingerprintService的交互封装

  • FingerprintService. 一个运行在SystemServer进程中的单例service,主要负责与fingerprintd通讯.

  • fingerprintd (Fingerprint daemon). A C/C++ implementation of the binder interface from FingerprintService. The fingerprintd daemon operates in its own process and wraps the Fingerprint HAL vendor-specific library.

  • Fingerprint HAL vendor-specific library. A hardware vendor's implementation of the Fingerprint HAL. The vendor-specific library communicates with the device-specific hardware.

  • Keystore API and Keymaster. These components provide hardware-backed cryptography for secure key storage in a Trusted Execution Environment (TEE).

2.2 HAL层的初始化工作

2.2.1 HAL初始化

每个Hal层库文件有一个入口,即HAL_MODULE_INFO_SYM,上层在调用hal层库文件时会在/system/lib/hw/下面寻找对应库文件,找到对应库文件后便从入口HAL_MODULE_INFO_SYM调用Hal层里面的open, init, write, read等接口,Hal层再通过这个接口去读写设备节点。

static struct hw_module_methods_t fingerprint_module_methods = {
    .open = fingerprint_open,
};

Fingerprintd 调用hw_get_module函数获取了一个fingerprint_module_t类型的数据结构。 这个就是在fingerprint.default.so中,由指纹芯片厂商填充实现的。

static int fingerprint_open(const hw_module_t* module, const char __unused *id,
hw_device_t** device) {
  if (fpc_init() < 0) {
ALOGE("Could not init FPC device");
return -EINVAL;
}
fingerprint_device_t *dev = malloc(sizeof(fingerprint_device_t));
memset(dev, 0, sizeof(fingerprint_device_t));
dev->common.tag = HARDWARE_DEVICE_TAG;
dev->common.version = FINGERPRINT_MODULE_API_VERSION_2_0;
dev->common.module = (struct hw_module_t*) module;
dev->common.close = fingerprint_close;
dev->pre_enroll = fingerprint_pre_enroll;
dev->enroll = fingerprint_enroll;
dev->get_authenticator_id = fingerprint_get_auth_id;
dev->cancel = fingerprint_cancel;
dev->remove = fingerprint_remove;
dev->set_active_group = fingerprint_set_active_group;
dev->enumerate = fingerprint_enumerate;
dev->authenticate = fingerprint_authenticate;
dev->set_notify = set_notify_callback;
dev->notify = NULL;
*device = (hw_device_t*) dev;
return 0;
}

fingerprint_open就是填充实现Android 在fingerprint.h定义fingerprint_device_t需要实现的这些接口。然后赋给指针device。上层,也就是fingerprintd,就能用这个device来操作hal层的指纹模块了。
fpc_init() 应该是初始化指纹驱动,并与Trusted Execution Environment (TEE)建立安全链接,TEE提供的一个安全的硬件运行环境。指纹就是运行在这样一个硬件安全环境下的程序。它保证了指纹敏感数据的安全性。

  • HAL必须通过TEE来与指纹建立通讯,一般是采用SPI通讯。指纹采集的生物图像必须在TEE中完成,不能传输到TEE外
  • 指纹的采集、登记和认可都必须在TEE中指纹数据也必须是加密(比如采用对称加密AES等加密手段),并且不能拷贝

2.2.2 HAL主要接口

HAL主要接口函数都会在/hardware/libhardware/include/hardware/fingerprint.h 中,主要的接口主要是enroll和authenticate,以及相应的回调函数


图片.png

其他的函数还有以下:

  • enroll. Switches the HAL state machine to start the collection and storage of a fingerprint template. As soon as enrollment is complete, or after a timeout, the HAL state machine is returned to the idle state.
  • pre_enroll. Generates a unique token to indicate the start of a fingerprint enrollment. Provides a token to the enroll function to ensure there was prior authentication, e.g. using a password. The token is wrapped and, for example, HMAC'd, once the device credential is confirmed, to prevent tampering. The token must be checked during enrollment to verify that the token is still valid.
  • get_authenticator_id. Returns a token associated with the current fingerprint set.
  • cancel. Cancels any pending enroll or authenticate operations. The HAL state machine is returned to the idle state.
  • enumerate. Synchronous call for enumerating all known fingerprint templates.
  • remove. Deletes a fingerprint template.
  • set_active_group. Restricts a HAL operation to a set of fingerprints that belong to a specified group (identified by a group identifier, or GID).
  • authenticate. Authenticates a fingerprint-related operation (identified by an operation ID).
  • set_notify. Registers a user function that will get notifications from the HAL. If the HAL state machine is in a busy state, the function is blocked until the HAL leaves the busy state.

Enroll流程

2.3.1 preEnroll点击设置中的添加指纹,setting就会调到fingerprintd的preEnroll接口。

  • preEnroll会在指纹设备中生成并保存一个64位的随机数。这个随机数有两个用途:返回给上层,用于填充enroll中的authenticated token challenge.
  • 指纹设备会用它对下次enroll做初步校验,保证enroll没有被第三方篡改。

2.3.2 enroll

  • 1 、对enroll接口的定义
int (*enroll)(struct fingerprint_device *dev, const hw_auth_token_t *hat,uint32_t gid, uint32_t timeout_sec);
  • hw_auth_token_t:保证此次enroll的合法性,我们具体看一下android怎么定义此结构。
  • AuthToken version :此token的版本号
  • Challenge:就是前面调用preEnroll的到的64位随机数,防止此次enroll被第三方假冒
  • User SID : 安全性id,不是android user id
  • Athenticator ID: 用于标明不同的认证权限
  • Authenticator Type:0x00表示Gatekeeper,0x01表示Fingerprint
  • Timestamp:最近一次开机时间戳
  • AuthToken HMAC key: 用一个特殊的key和SHA-256算法去计算前面一堆参数后,得到的一个 hmac值,保证前面参数的合法性和安全性。
  • gid:说明是哪个用户注册指纹(anroid支持多用户),在FingerprintService中通过UserManager拿到的。
  • timeout_sec:超时设置。
  • 2、上层调用enroll接口,一直将上述参数传递到指纹设备中。指纹设备拿到参数之后会先检查参数是否合法。
  • 3、验证完参数合法之后,指纹设备会将指纹IC切换到一种等待手指按下采图的工作模式。此时一旦手指按下,会进入中断处理函数,该函数主要的工作流程如下图:


    图片.png
  • 4、注册成功后会将获取到相应的type,gid,fingerid, samples_ remaining回传给fingerprintd,samples_ remaining是录入指纹剩余次数。
void *enroll_thread_loop() {
fingerprint_msg_t msg;
msg.type = FINGERPRINT_TEMPLATE_ENROLLING;
msg.data.enroll.finger.fid = print_id;
msg.data.enroll.finger.gid = fpc_gid;
msg.data.enroll.samples_remaining = 0;
msg.data.enroll.msg = 0;
callback(&msg);
}

最终会在FingerprintService保存一份Fingerprint,Fingerprint包含以下数据,主要用于FingerprintService判断是否有指纹template存在。

2.3.3 postEnroll

postEnroll主要工作是更新一下指纹设备中保存的Challenge。

2.4 Authenticate流程

当按下power键锁屏时,APP会调用FingerprintManager api,进入到authenticate流程。和enroll一样,框架层工作工作很少,基本就是一个简单的接口调用。其中CryptoObject是加密对象,这是由于验证结果有可能被第三方软件篡改,这个加密对象会随着验证结果返回并验证。
void authenticate (FingerprintManager.CryptoObject crypto,CancellationSignal cancel,int flags,FingerprintManager.AuthenticationCallback callback,Handler handler)

parameter
crypto FingerprintManager.CryptoObject: object associated with the call or null if none required.
cancel CancellationSignal: an object that can be used to cancel authentication
flags int: optional flags; should be 0
callback FingerprintManager.AuthenticationCallback: an object to receive authentication events
handler Handler: an optional handler to handle callback events

主要工作还是在hal层以下完成。重点看hal层之下的部分。authenticate一直调用到指纹服务进程fingerprintd。在有fingerprintd根据加载的fingerprint module调用hal层的接口。我们看看HAl怎样定义authenticate接口的,在fingerprint.h中
int (*authenticate)(struct fingerprint_device *dev, uint64_t operation_id, uint32_t gid);

  • operation_id:64位的session id标识本次识别流程。
  • gid:用户id,android是多用户系统,每个用户可以录入多个指纹(一般是5个)TEE也会根据gid来加载不同的用户模板。

2.4.1 加载用户模板、切换采图模式

  • 调用authenticate接口之后,会在TEE中保存好operation_id,这个operation_id 会被用来做authenticate token的challenge保存到keystore service中去指纹支付会用到。然后TEE会根据gid从安全存储区加载之前该用户注册好的模板。
  • 通过spi发送指令到指纹IC,让其切换到采图模式,最后等待手指按压。

2.4.2 采图与识别

之后的主要工作流程如下图

图片.png
  • 手指按压IC后,会报一个中断给主控
  • 主控驱动层接收到中断脚的脉冲信号,通过netlink或者信号量等跨进程通信方式将这个中断信息上报给hal层
  • hal层收到中断,根据当前状态机的工作模式,开始执行识别工作
  • 识别工作包括,从IC读取一帧指纹图像,然后将图像预处理为算法需要的格式
  • 算法模块接收到预处理后的图像,开始匹配模板库
  • 生成识别结果,向上用binder回调给fingerprintService,向下将本次识别的finger id同步给其他安全应用,譬如支付宝,微信。
  • 更新模板库
    识别成功后,会构造一个message,具体包括type,gid,fingerid和auth_token。


    图片.png
void *enroll_thread_loop() {
fingerprint_msg_t msg;
msg.type = FINGERPRINT_AUTHENTICATED;
msg.data.authenticated.finger.gid = fpc_gid;
msg.data.authenticated.finger.fid = print_id;
msg.data.authenticated.hat = hat;
callback(&msg);
}

其中auth_token会在fingerprintd中同步到keystore service中。

void FingerprintDaemonProxy::hal_notify_callback(const fingerprint_msg_t *msg) {
switch (msg->type) {
case FINGERPRINT_AUTHENTICATED:
if (msg->data.authenticated.finger.fid != 0) {
const uint8_t* hat = reinterpret_cast<const uint8_t *>(&msg->data.authenticated.hat);
instance->notifyKeystore(hat, sizeof(msg->data.authenticated.hat));
}
callback->onAuthenticated(device,
msg->data.authenticated.finger.fid,
msg->data.authenticated.finger.gid);
break;
}
}

void FingerprintDaemonProxy::notifyKeystore(const uint8_t *auth_token, const size_t auth_token_length) {
if (auth_token != NULL && auth_token_length > 0) {
// TODO: cache service?
sp < IServiceManager > sm = defaultServiceManager();
sp < IBinder > binder = sm->getService(String16("android.security.keystore"));
sp < IKeystoreService > service = interface_cast < IKeystoreService > (binder);
if (service != NULL) {
          status_t ret = service->addAuthToken(auth_token, auth_token_length);
}
}
}

2.4.3 AuthToken数据流

图片.png

安全框架

指纹安全框架一般有两种方案,一种是Fingerprint without TrustZone 和Fingerprint with TrustZone。在root情况下without TrustZone是非常危险的,所有的数据都可以轻松获取到。但是在有了TrustZone的情况下,hacker在获取了root以后依然无法读取TrustZone中的指纹信息。如果想要获取指纹信息,理论上还需要破解TrustZone才行。TrustZone是arm支持的一种安全运行环境空间,有自己运行操作系统。

Fingerprint可能存在的安全漏洞

  • 1)Replacing fingerprintd
    替换fngerprintd这个Daemon,因为指纹识别成功与否是在APP向fingerprintd注册的回调来获取结果的,只要能替换fngerprintd,将其中指纹识别成功与否,修改成无论什么时候验证都返回success即可

  • 2)Modied IPC
    由于FingerprintService与fngerprintd是通过binder获取验证结果的,同时在FingerprintService中判断是否验证成功是靠获取到的fid(finger Id)是否为0(为0则验证失败)来判断的,修改binder传输过程中的fid即可达到无论什么时候都返回success的目的。

  • 3)Replaying authentication tokens
    可以提前截取之前验证通过的auth_token,然后用此auth_token来作为身份验证的凭据。

参考

安卓指纹验证官方指南
Keystore
指纹验证APP Demo

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,980评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,422评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,130评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,553评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,408评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,326评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,720评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,373评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,678评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,722评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,486评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,335评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,738评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,283评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,692评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,893评论 2 335

推荐阅读更多精彩内容

  • Android HAL概述 Android HAL(Hardware Abstract Layer)硬件抽象层,从...
    诺远阅读 29,439评论 2 27
  • P1-P35 张居正是前东林时代的近反派人物,当然万历死后,天启、崇祯年间逐渐给张氏平反的,正是东林人士。 张居正...
    boks阅读 1,840评论 0 1
  • 华丽的词藻抵不过真挚的思念! 周末的孤独无以言表! 自我欺骗:你若安好便是晴天! 这是假话! 我爱你,在任何时候!...
    方死方生秦人阅读 257评论 0 1
  • “深圳大冲村民66套回迁房求租”事件引发的思考 最近经常有一些假新闻出现在大家的眼前,虽然很多假新闻在第一时间都被...
    LEO09阅读 324评论 0 0
  • 皎月清清光入扉,友人寂寂独凭阑。 笙歌遥奏阳关曲,情伤景萧谁忍听。 日夜思君不见君,且问流水何时归。 快马疾驰锦书...
    楚谡姑娘阅读 426评论 0 4