1. FIDO与U2F
FIDO(Fast IDentity Online联盟)是一个基于标准、可互操作的身份认证生态系统。
U2F(Universal 2nd Factor)是FIDO联盟提出的使用标准公钥密码学技术提供更强有力的身份认证协议。
U2F在常用的用户名/密码的认证基础上又增加了一层第二因子(2nd Factor)的保护,这重保护是通过物理硬件来支持的。
2. U2F协议原理
FIDO的官方网站用两张图介绍了U2F的应用原理,它把应用过程分解为两个阶段:
注册阶段,如图1所示:
图1中的流程如下:
- 客户端提示用户选择符合在线服务策略的可用 的U2F设备。
- 用户使用U2F设备上的按钮解锁 U2F设备。
- U2F设备创建一对针对本地设备、在线服务和用户账户的独有的全新公/私钥对。
- 客户端将公钥发送给在线服务,并将其与用户的账户关联,私钥存放在U2F设备中。
鉴权阶段,如图2所示:
图2中的流程如下:- 在线服务要求用户使用之前注册使用的U2F设备登录。
- 用户使用U2F设备上的按钮解锁 U2F设备。
- 设备使用由服务器提供的用户的账户标识来选择正确的密钥并签名服务器发出的挑战值。
- U2F设备将经过签名的挑战发送回服务器,由其使用存储的公钥进行验证,服务器验证成功后允许用户登录。
U2F的原理很简单:用户需要使用用户名/口令、客户端设备(物理设备)两重安全因子完成在线服务网站的注册与登录鉴权工作;用户在向在线服务注册期间,用户的客户端设备会创建一个新的密钥对。该设备保留私钥,并向在线服务注册公钥;用户在登录鉴权期间,客户端通过对挑战值签名的方式向该服务证明私钥的拥有权,以此完成身份认证。其实这与我们日常使用的网上银行登录时需要插入USB Key没有什么区别,可能唯一的技术差别在于浏览器在识别银行的USB Key使用的是特定的插件,而对于U2F设备,浏览器已经内置了识别接口。
3. U2F协议的消息格式
U2F协议支持两个操作:注册(registration)与鉴权(authentication),这两个操作可分解为三个阶段,如图3所示。
在图3中,Relying Party(简称RP)就是第2节描述的在线服务网站。FIDO Client为客户端,三个阶段的流程如下:
1. Setup:在这个阶段,客户端向在线服务网站请求一个挑战值,客户端使用这个挑战值生成一个请求消息发送到U2F设备。
2. Processing:在这个阶段,U2F设备针对请求消息做一些密码学的操作,并创建回应消息。
3. Verification:在这个阶段,客户端将U2F设备的回应消息交给服务端进行验证,服务端处理回应消息并验证其正确性。对于一个正确的注册回应使得服务端为用户注册一个公钥;对于一个正确的鉴权回应使得服务端相信用户拥有一个正确的私钥以通过身份认证。
FIDO提供了HID协议实现浏览器与U2F设备(使用USB接口)之间的消息通讯,协议细节可参见对应定义文档。
下面我们了解一下浏览器与U2F设备之间的数据帧格式。
3.1. 注册请求消息
注册请求消息如图4所示:
消息中各字段含义如下:
- challenge parameter [32 bytes]:是对由挑战值组成的Client Data(后面会介绍,客户端生成的一个JSON字符串)使用SHA-256算法得到32位摘要。
- application parameter [32 bytes]:对使用UTF-8编码的应用ID(application identity)使用使用SHA-256算法得到32位摘要。
3.2. 注册回应消息
注册回应消息如图5所示:
消息中字段含义如下:
- reserved byte [1 byte]:固定值0x05。
- user public key [65 bytes]:65字节的公钥。
- key handle length byte [1 byte]:key handle用于定位私钥,这里使用1字节表示长度。
- key handle [length specified in previous field]:key handle的值。
- attestation certificate [variable length]:使用X.509 DER格式的证书(有点类似于厂商提供的根证书),其中的公钥用于验证后面的签名。
- signature [variable length, 71-73 bytes]:使用ECDSA算法的签名值,使用ANSI X9.62 格式编码。签名的原文为:
- 一个为0x00的字节
- 请求中的application parameter
- 请求中的challenge parameter
- 上面提及的key handle的值
- 上面提及的user public key
3.3. 鉴权请求消息
鉴权请求消息如图6所示:
消息中字段含义如下:
- Control byte (P1):取值可为3个值:0x07 ("check-only"),0x03 ("enforce-user-presence-and-sign"),0x08 ("dont-enforce-user-presence-and-sign")
- challenge parameter [32 bytes]:是对由挑战值组成的Client Data(后面会介绍,客户端生成的一个JSON字符串)使用SHA-256算法得到32位摘要。
- application parameter [32 bytes]:对使用UTF-8编码的应用ID(application identity)使用使用SHA-256算法得到32位摘要。
- key handle length byte [1 byte]:1字节表示key handle的长度。
- key handle [length specified in previous field]:key handle的值。
3.4. 鉴权回应消息
鉴权回应消息如图7所示:
消息中各字段含义如下:
- user presence byte [1 byte]:0表示用户不存在,1表示用户存在。
- counter [4 bytes]:U2F设备鉴权计数,大字节序。
- signature:使用ECDSA算法的签名值,使用ANSI X9.62 格式编码。签名的原文为:
- application parameter [32 bytes]:鉴权请求中的application parameter。
- user presence byte [1 byte]:上面提到的user presence byte。
- counter:上面提到的counter。
- challenge parameter [32 bytes]:鉴权请求中的challenge parameter值。
3.5. clientdata
前面的请求/回应消息中对challenge parameter的构建使用到clientdata,clientdata为一个JSON对象字符串,其对象结构ClientData定义如下:
dictionary ClientData {
DOMString typ;
DOMString challenge;
DOMString origin;
(DOMString or JwkKey) cid_pubkey;
};
ClientData结构中各属性含义如下:
- typ:注册时使用值'navigator.id.finishEnrollment',鉴权时使用值'navigator.id.getAssertion' 。
- challenge:使用websafe-base64编码(通常也叫urlbase64编码,见RFC4648第5章)的字符串,由在线服务网站提供。
- origin: 网站标识。
- cid_pubkey:可选参数。
4 参考文献
1.https://fidoalliance.org/how-fido-works/
2.https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/FIDO-U2F-COMPLETE-v1.2-ps-20170411.pdf
3.http://www.ietf.org/rfc/rfc4648.txt