// app/src/main/java/io/github/vvb2060/keyattestation/home/HomeViewModel.kt@Throws(AttestationException::class)privatefundoAttestation(useStrongBox:Boolean,includeProps:Boolean,useAttestKey:Boolean):AttestationResult{valcerts=ArrayList<Certificate>()valalias=if(useStrongBox)"${AppApplication.TAG}_strongbox"elseAppApplication.TAGvalattestKeyAlias=if(useAttestKey)"${alias}_persistent"elsenulltry{// 1. generateKeyif(useAttestKey&&!keyStore.containsAlias(attestKeyAlias)){generateKey(attestKeyAlias!!,useStrongBox,includeProps,attestKeyAlias)}generateKey(alias,useStrongBox,includeProps,attestKeyAlias)// 2. certs collectvalcertChain=keyStore.getCertificateChain(alias)?:throwCertificateException("Unable to get certificate chain")for(certincertChain){valbuf=ByteArrayInputStream(cert.encoded)certs.add(certificateFactory.generateCertificate(buf))}if(useAttestKey){valpersistChain=keyStore.getCertificateChain(attestKeyAlias)?:throwCertificateException("Unable to get certificate chain")for(certinpersistChain){valbuf=ByteArrayInputStream(cert.encoded)certs.add(certificateFactory.generateCertificate(buf))}}}catch(e:ProviderException){// 异常流程,可忽略......}catch(e:Exception){throwAttestationException(CODE_UNKNOWN,e)}@Suppress("UNCHECKED_CAST")// 3. parseCertificateChaincurrentCerts=certsasList<X509Certificate>returnparseCertificateChain(certs)}
在 Android 8.0 中,Keymaster 3 从旧式 C 结构硬件抽象层 (HAL) 转换到根据新硬件接口定义语言 (HIDL) 中的定义生成的 C++ HAL 接口。在此变更过程中,很多参数类型发生了变化,但这些类型和方法与旧的类型和 HAL 结构体方法一一对应。如需了解详情,请参阅函数页面
除了此接口修订之外,Android 8.0 还扩展了 Keymaster 2 的认证功能,以支持 ID 认证。 ID 认证提供了一种受限且可选的机制来严格认证硬件标识符,例如设备序列号、产品名称和手机 ID (IMEI/MEID)。为了实现此新增功能,Android 8.0 更改了 ASN.1 认证架构,添加了 ID 认证。Keymaster 实现需要通过某种安全方式来检索相关的数据项,还需要定义一种安全永久地停用该功能的机制。
valcertChain=keyStore.getCertificateChain(alias)?:throwCertificateException("Unable to get certificate chain")for(certincertChain){valbuf=ByteArrayInputStream(cert.encoded)certs.add(certificateFactory.generateCertificate(buf))}if(useAttestKey){valpersistChain=keyStore.getCertificateChain(attestKeyAlias)?:throwCertificateException("Unable to get certificate chain")for(certinpersistChain){valbuf=ByteArrayInputStream(cert.encoded)certs.add(certificateFactory.generateCertificate(buf))}}
// app/src/main/java/io/github/vvb2060/keyattestation/attestation/CertificateInfo.javaprivatebooleancheckAttestation(){booleanterminate;try{attestation=Attestation.loadFromCertificate(cert);// If key purpose included KeyPurpose::SIGN,// then it could be used to sign arbitrary data, including any tbsCertificate,// and so an attestation produced by the key would have no security properties.// If the parent certificate can attest that the key purpose is only KeyPurpose::ATTEST_KEY,// then the child certificate can be trusted.varpurposes=attestation.getTeeEnforced().getPurposes();terminate=purposes==null||!purposes.contains(AuthorizationList.KM_PURPOSE_ATTEST_KEY);}catch(CertificateParsingExceptione){certException=e;terminate=false;checkProvisioningInfo();}returnterminate;}// app/src/main/java/io/github/vvb2060/keyattestation/attestation/Attestation.javapublicstaticAttestationloadFromCertificate(X509Certificatex509Cert)throwsCertificateParsingException{if(x509Cert.getExtensionValue(EAT_OID)==null&&x509Cert.getExtensionValue(ASN1_OID)==null){thrownewCertificateParsingException("No attestation extensions found");}if(x509Cert.getExtensionValue(EAT_OID)!=null){if(x509Cert.getExtensionValue(ASN1_OID)!=null){thrownewCertificateParsingException("Multiple attestation extensions found");}try{returnnewEatAttestation(x509Cert);}catch(CborExceptioncbe){thrownewCertificateParsingException("Unable to parse EAT extension",cbe);}}if(x509Cert.getExtensionValue(CRL_DP_OID)!=null){Log.w(AppApplication.TAG,"CRL Distribution Points extension found in leaf certificate.");}if(x509Cert.getExtensionValue(KNOX_OID)!=null){returnnewKnoxAttestation(x509Cert);}returnnewAsn1Attestation(x509Cert);}
// app/src/main/java/io/github/vvb2060/keyattestation/attestation/CertificateInfo.java// If key purpose included KeyPurpose::SIGN,// then it could be used to sign arbitrary data, including any tbsCertificate,// and so an attestation produced by the key would have no security properties.// If the parent certificate can attest that the key purpose is only KeyPurpose::ATTEST_KEY,// then the child certificate can be trusted.varpurposes=attestation.getTeeEnforced().getPurposes();terminate=purposes==null||!purposes.contains(AuthorizationList.KM_PURPOSE_ATTEST_KEY);// app/src/main/java/io/github/vvb2060/keyattestation/attestation/AuthorizationList.javapublicAuthorizationList(ASN1Encodableasn1Encodable)throwsCertificateParsingException{if(!(asn1EncodableinstanceofASN1Sequencesequence)){thrownewCertificateParsingException("Expected sequence for authorization list, found "+asn1Encodable.getClass().getName());}for(varentry:sequence){if(!(entryinstanceofASN1TaggedObjecttaggedObject)){thrownewCertificateParsingException("Expected tagged object, found "+entry.getClass().getName());}inttag=taggedObject.getTagNo();varvalue=taggedObject.getBaseObject().toASN1Primitive();switch(tag){default:thrownewCertificateParsingException("Unknown tag "+tag+" found");caseKM_TAG_PURPOSE&KEYMASTER_TAG_TYPE_MASK:purposes=Asn1Utils.getIntegersFromAsn1Set(value);break;}}}