从Android FIDO2 SDK v1.1.0开始,safetynet attestation格式已被弃用。相反,Google建议使用Tink库来对FIDO2 attestation进行验证。以下是一个简单的示例代码,展示如何使用Tink验证FIDO2 attestation:
import com.google.crypto.tink.subtle.CommonValidator;
import com.google.crypto.tink.proto.Empty;
import com.google.crypto.tink.proto.TinkPublicKey;
import com.google.crypto.tink.subtle.Validators;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertPath;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
public class Fido2Verifier {
// 定义待验证的FIDO2 attestation
private JSONObject attestation;
public Fido2Verifier(String base64Attestation) throws JSONException {
this.attestation = new JSONObject(base64Attestation);
}
// 根据Tink库来验证FIDO2 attestation
public boolean verify() throws Exception {
// 获取attestation statement
JSONObject attStmt = attestation.getJSONObject("attStmt");
// 获取签名算法
String sigAlg = attStmt.getString("alg");
// 获取签名数据
byte[] sigData = Base64.decode(attStmt.getString("sig"));
// 获取证书链
JSONArray x5cArray = attStmt.getJSONArray("x5c");
X509Certificate[] certChain = new X509Certificate[x5cArray.length()];
CertificateFactory cf = CertificateFactory.getInstance("X.509");
for (int i = 0; i < x5cArray.length(); i++) {
byte[] encodedCert = Base64.decode(x5cArray.getString(i));
certChain[i] = (X509Certificate) cf.generateCertificate(
new ByteArrayInputStream(encodedCert));
}
// 验证证书链
CertPath certPath = cf.generateCertPath(Arrays.asList(certChain));
Validator validator = new SimpleValidator(certPath);
validator.validate();
// 从证书中获取公钥
byte[] publicKeyDer = certChain[0].getPublicKey().getEncoded();
TinkPublicKey publicKeyProto = TinkPublicKey.newBuilder()
.setDerPublicKey(ByteString.copyFrom(publicKeyDer))
.build();
// 验证签名
CommonValidator.validateSignature(
sigData,
publicKeyProto,
KeyType.UNKNOWN_PREFIX,
sigAlg,
Empty.getDefaultInstance());
return true;
}
//