Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Deep Dive to "com.google.android.gms.fido.fido2"

406ea2cac59924cedae4629c3c6c84fb?s=47 Kengo Suzuki
February 07, 2019

Deep Dive to "com.google.android.gms.fido.fido2"

# English Description (Japanese below)
We are exhausted with passwords. Users are exhausted with passwords because of too many web-services. Operators are exhausted with passwords because of defense against password-related attacks like Phishing. We, as developers, are also exhausted because of poor UX in passwords.

In last DroidKaigi, I have presented “AuthN and AuthZ with Android”(認証と認可と君と) for the purpose of introducing FIDO UAF 1.1, the password-less authentication framework. Since the presentation, a lot of innovation has been made. For example, major browsers adopted, implemented, and released WebAuthN which will play important role in FIDO 2.0, which will be the new version of UAF 1.1.

Android hasn’t been left behind by the advancement in Authentication. In March 2018, FIDO2.0 package was released in Android API, and that is exactly what I am going to talk about. At the end of this session, the audience will understand what `com.google.android.gms.fido.fido2*` will do, how to use it with `BiometricPromptAPI`, and how it is related to WebAuthN.

## Outline
1. Reviewing FIDO UAF 1.1
2. Safetynet Attestation vs Key Attestation
3. com.google.android.gms.fido.fido2
4. fido2 with BiometricPrompt
5. fido2 with WebAuthN

# 日本語Description
去年のDroidKaigi2018「認証と認可と君と」ではそういった苦労から我々を開放するパスワードレス認証「FIDO UAF 1.1」とAndroid上での実装方法についてお話しました。それから早1年、次バージョンにあたるFIDO 2.0の一翼を担うWebAuthNが主ブラウザに実装され、更にChromeの最新Ver70ではAndroidの指紋認証との連携ができるようになりました。勿論、Android自体にも大きな動きがあり、2018年にはAndroidのAPIに新しくFIDO2.0用パッケージが登場しました。本セッションでは、com.google.android.gms.fido.fido2* についてBiometricPromptAPIなどのAndroid内のFIDO2関連のAPIと絡めつつ、実装方法をお話します。

## Outline
1. Reviewing FIDO UAF 1.1
2. Safetynet Attestation vs Key Attestation
3. com.google.android.gms.fido.fido2
4. fido2 with BiometricPrompt
5. fido2 with WebAuthN

Intended Audience

- anyone interested in Authentication
- anyone interested in FIDO
- whoever wants to understand the difference between FIDO in Android and WebAuthN

406ea2cac59924cedae4629c3c6c84fb?s=128

Kengo Suzuki

February 07, 2019
Tweet

Transcript

  1. Deep Dive to FIDO.FIDO2 2018/11/4 @ken5scal

  2. 1. Motivation 2. Overview of FIDO 3. Implementing FIDO2 in

    Android 4. Attestation in Android 5. Assertion in Android Outline
  3. 1. Motivation 2. Overview of FIDO 3. Implementing FIDO2 in

    Android 4. Attestation in Android 5. Assertion in Android Outline
  4. Motivation

  5. ʮಥવͰ͕͢…ʯΈ͍ͨͳ ஫ҙऒ͖͚͍ͭͨͱ͖࢖͏

  6. v 1.1

  7. 8FC"VUIO CFDPNFT XDQSPQPTFE SFDDFPNFOEBUJPO HNTpEPpEP 'FC 'FC +BO 8FC"VUIO CFDPNFT

    XDQSPQPTFE SFDDFPNFOEBUJPO .BSDI .BZ 8FC"VUIO XDDBOEJEBUF SFDDFPNFOEBUJPO 8FC"VUIO XDQSPQPTFE SFDDFPNFOEBUJPO +VOF
  8. 'FC 'FC +BO 8FC"VUIO CFDPNFT XDQSPQPTFE SFDDFPNFOEBUJPO 8FC"VUIO CFDPNFT XDQSPQPTFE

    SFDDFPNFOEBUJPO .BSDI .BZ 8FC"VUIO XDDBOEJEBUF SFDDFPNFOEBUJPO 8FC"VUIO XDQSPQPTFE SFDDFPNFOEBUJPO HNTpEPpEP +VOF HNTpEPpEP
  9. v 2

  10. - Understand general idea of FIDO - Understand FIDO v2

    in Android The Goal
  11. 1. Motivation 2. Overview of FIDO 3. Implementing FIDO2 in

    Android 4. Attestation in Android 5. Assertion in Android Outline
  12. Overview of FIDO

  13. - Fast IDentity Online - Alliance - Authentication Protocol What

    is FIDO
  14. - Scalable - Inter-Operable - anti-Phishing - Secure User Privacy

    What FIDO is trying to achieve?
  15. - Scalable - Inter-Operable - Kill Phishing - Protect User

    Privacy - Elimination Password as Credential What FIDO is trying to achieve?
  16. Why eliminating Password

  17. IUUQTXXXEBSLSFBEJOHDPNJOGPSNBUJPOXFFLIPNFQBTTXPSESFVTFBCPVOETOFXTVSWFZTIPXTEEJE

  18. IUUQTXXXEBSLSFBEJOHDPNJOGPSNBUJPOXFFLIPNFQBTTXPSESFVTFBCPVOETOFXTVSWFZTIPXTEEJE

  19. None
  20.  *%1BTT *%1BTT Where does fire come from?  4UPSF

     7FSJGZ  *EFOUJGZ
  21.  *%1BTT *%1BTT Physhing 

  22.  *%1BTT *%1BTT Interception

  23.  3FVTFE1BTT  *%1BTT *%1BTT Credential re-used

  24. 3FQMBZ Even 2FA is not entirely safe 1BTT 5051 1VTI/PUJpDBUJPO

  25. None
  26. IUUQTNFEJVNDPNNFUBDFSUDSZQUPDVSSFODZTDBNNFSTUBSHFUCJOBODFVTFSTTFFLJOHHPPHMFBVUIFOUJDBUPSCBDLVQDPEFTBCDCC

  27. IUUQTXXXHSPPWZQPTUDPNVOQMVHHFEQIJTIFSIBDLFEHNBJMGBDUPSBVUIFOUJDBUJPO

  28. As long as human involves, There is a vulnerability.

  29. - Break down AuthN responsibility - bounding credentials to origin

    - customize challenge-response to make 2FA by default How FIDO2 addresses problems?
  30. General FIDO Model

  31.  *%1BTT *%1BTT Current Authentication Model  WFSJGZ  JEFOUJGZ

     TUPSF
  32. "VUIFOUJDBUPS $MJFOU 3FMZJOH 1BSUZ 3FMZJOH 1BSUZ $SFEFOUJBM,FZ ,FZ1BJS  ,FZ1BJS

    $SFEFOUJBM,FZ ,FZ1BJS 
  33. 7FSJGZ6TFS 4UPSF$SFET $MJFOU ,FZ1BJS 7FSJGZ3FVTMU

  34. "VUIFOUJDBUPS $MJFOU 3FMZJOH 1BSUZ 3FMZJOH 1BSUZ $SFEFOUJBM,FZ ,FZ1BJS  ,FZ1BJS

    $SFEFOUJBM,FZ ,FZ1BJS  5IJTLFZJTCPVOEUP0SJHJO *UBDUVBMMIBTBOJE
  35. Registration

  36. Registration Attestation

  37. ᶄ3FRVFTU $SFEFOUJBM ᶃ4FOEDIBMMFOHFX DSFEFOUJBMPQUJPOT

  38. ᶄ1BTT $SFEFOUJBM ᶅ$SFBUF $SFEFOUJBM $SFEFOUJBM ,FZ1BJS "TTFSUJPO,FZT

  39. ᶆ4FOEQVCLFZ XDIBMMFOHFSFTQPOTF 4UPSF1SJWBUF ,FZJO4FDVSF4UPSBHF

  40. ᶇ  7FSJGZ$SFE*OGP  4UPSF1VC,FZ

  41. Authentication

  42. Authentication Attestation

  43. ᶄ3FRVFTU $SFEFOUJBM ᶃ4FOEDIBMMFOHFX BVUI/PQUJPOT

  44. ᶄ1BTT $SFEFOUJBM ᶅ7FSJGZ $SFEFOUJBM

  45. ᶆ4JHO3FTVMUT X$SFEFOUJBM*OGP CZ1SJW,FZ

  46. ᶇ$IFDL4JHOBUVSF BOE7FSJGZ"VUI/ 3FTVMU

  47. But there is more

  48. )PXXPVME*LOPX UIFBTTFSUJPOLFZJT UIFl$PSSFDUPOFz 

  49. - “attestation is a statement serving to bear witness, confirm,

    or authenticate” - “attest to the provenance of an authenticator and the data it emits; including, for example: credential IDs, credential key pairs, signature counters, etc. An attestation statement is conveyed in an attestation object during registration What is Attestation? https://www.w3.org/TR/webauthn
  50. Android Key Attestation (FOFSBUF "UUFTUBUJPO,FZ1BJS ᶅ4IJQ #VSOLFZTUP EFWJDFEVSJOH NBOVGBDUVSJOH 4JHO

    BTTFSUJPOQVCLFZ CZ"UUTUQSJWLFZ
  51. val params = KeyGenParameterSpec .Builder(storeAlias,KeyProperties.PURPOSE_SIGN) .setAlgorithmParameterSpec(ECGenParameterSpec(“secp256r1")) .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA384, KeyProperties.DIGEST_SHA512) .setAttestationChallenge(challenge.toByteArray())

    val keyPairGenerator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC, provider) keyPairGenerator.initialize(params) val pair : KeyPair = keyPairGenerator.generateKeyPair()
  52. val certs = keyStore.getCertificateChain(keyStoreAlias) val x509Certs: Array<ByteArray?> = arrayOfNulls(certs.size) certs.forEachIndexed

    { index, certificate -> x509Certs[index] = certificate.encoded } // key attestation -> x509Certs[0]
  53. Certificate: Data: Version: 3 (0x2) Serial Number: 1 (0x1) Signature

    Algorithm: ecdsa-with-SHA256 Issuer: serialNumber=0fccf0d5489ba04c/title=TEE Validity Not Before: Jan 1 00:00:00 1970 GMT Not After : Feb 7 06:28:15 2106 GMT Subject: CN=Android Keystore Key X509v3 extensions: X509v3 Key Usage: critical Digital Signature 1.3.6.1.4.1.11129.2.1.17:
  54. Certificate: Data: Version: 3 (0x2) Serial Number: 1 (0x1) Signature

    Algorithm: ecdsa-with-SHA256 Issuer: serialNumber=0fccf0d5489ba04c/title=TEE Validity Not Before: Jan 1 00:00:00 1970 GMT Not After : Feb 7 06:28:15 2106 GMT Subject: CN=Android Keystore Key X509v3 extensions: X509v3 Key Usage: critical Digital Signature 1.3.6.1.4.1.11129.2.1.17:
  55. - Check device integrity by collecting from HW/SW and testing

    against Android Compatibility Test Suite (CTS) - Send result in JWS - contains pub key SafetyNet Attestation API
  56. type AndroidSafetyNetAttestationResponse struct { Nonce string `json:"nonce"` TimestampMs int64 `json:"timestampMs"`

    ApkPackageName string `json:"apkPackageName"` ApkCertificateDigestSha256 []string `json:"apkCertificateDigestSha256"` ApkDigestSha256 string `json:"apkDigestSha256"` CtsProfileMatch bool `json:”ctsProfileMatch”` BasicIntegrity bool `json:"basicIntegrity"` Error string `json:"error"` }
  57. - It only checks Device Integrity - So not really

    Attesting it - Requires unnecessary(?) access to Google Backend - Logic verifying device profile completely up to Google - Device Profile requires out of scope contects - FIDO cares about privacy - FIDO is authN protocol, so if it does not need it, then it is desire to not collect unnecessary data - 10,000 requests per day for each API key Drawback in SafetyNet Attestation API
  58. Better use Android Key Attestation over SafetyNet Attesation

  59. 1. Motivation 2. Overview of FIDO 3. Implementing FIDO2 in

    Android 4. Attestation in Android 5. Assertion in Android Outline
  60. Implementing FIDO2 in Android

  61. - .fido - .common - .u2f (out of scope) -

    .fido2 - .api.common. - .ui (internal) - .AuthenticateActivity - .Fido2FullScreenActivity - .PolluxActivity - .GenericActivity - .pollux (internal) - .GcmReceiverService - .CableAuthenticatorService com.google.android.gms packages "QQ "DUJWJUZ pEP  "DUJWJ UZ 3FTVMU *OUFSOBM VJ QPMMV Y
  62. None
  63. Attestation in Android

  64. - Params to create credential Get Option "QQ "DUJWJUZ pEP

    "DUJWJUZ 3FTVMU *OUFSOBM VJ QPMMVY
  65. Generate Credential "QQ "DUJWJUZ pEP "DUJWJUZ 3FTVMU *OUFSOBM VJ QPMMVY

  66. Register "QQ "DUJWJUZ pEP "DUJWJUZ 3FTVMU *OUFSOBM VJ QPMMVY

  67. How to see slides

  68. EJDUJPOBSZ4FSWFS1VCMJD,FZ$SFEFOUJBM$SFBUJPO0QUJPOT3FRVFTU\ SFRVJSFE%0.4USJOHVTFSOBNF SFRVJSFE%0.4USJOHEJTQMBZ/BNF "VUIFOUJDBUPS4FMFDUJPO$SJUFSJBBVUIFOUJDBUPS4FMFDUJPO "UUFTUBUJPO$POWFZBODF1SFGFSFODFBUUFTUBUJPOOPOF ^ data class ServerPublicKeyCredentialCreationOptionsRequest( val

    username: String, val displayName: String, val authenticatorSelection: AuthenticatorSelectionCriter val attestation: AttestationConveyancePreference) Specs(FIDO2, Webauthn) Android Implementation
  69. - Params to create credential Get Option "QQ "DUJWJUZ pEP

    "DUJWJUZ 3FTVMU *OUFSOBM VJ QPMMVY
  70. data class ServerPublicKeyCredentialCreationOptionsRequest( val username: String, val displayName: String, val

    authenticatorSelection: AuthenticatorSelectionCriter val attestation: AttestationConveyancePreference) EJDUJPOBSZ4FSWFS1VCMJD,FZ$SFEFOUJBM$SFBUJPO0QUJPOT3FRVFTU\ SFRVJSFE%0.4USJOHVTFSOBNF SFRVJSFE%0.4USJOHEJTQMBZ/BNF "VUIFOUJDBUPS4FMFDUJPO$SJUFSJBBVUIFOUJDBUPS4FMFDUJPO "UUFTUBUJPO$POWFZBODF1SFGFSFODFBUUFTUBUJPOOPOF ^ https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-server-v2.0- rd-20180702.html#serverpublickeycredentialcreationoptionsrequest
  71. val criteria = AuthenticatorSelectionCriteria.Builder() .setAttachment(Attachment.PLATFORM) //or .CROSS-PLATFORM //.setResidentKey(true) // No

    method exists //.setUserVerification() // No method exists .build() EJDUJPOBSZ"VUIFOUJDBUPS4FMFDUJPO$SJUFSJB\ "VUIFOUJDBUPS"UUBDINFOUBVUIFOUJDBUPS"UUBDINFOU CPPMFBOSFRVJSF3FTJEFOU,FZGBMTF 6TFS7FSJpDBUJPO3FRVJSFNFOUVTFS7FSJpDBUJPOQSFGFSSFE ^ https://w3c.github.io/webauthn/#authenticatorSelection
  72. FOVN"UUFTUBUJPO$POWFZBODF1SFGFSFODF\ OPOF %POPUSFRVJSFBVUIFOUJDBUPSUPSFUVSO"UUFTUBUJPOTUNU JOEJSFDU $MJFOUDBODPOUSPMT'PSFYBNQMF DMJFOUDBOTFMGEFpOFTUNU EJSFDU3FRVJSFUPQBTTBUUFTUBUJPOTUNUBT"VUIFOUJDBUPSHFOFSBUFE ^ https://w3c.github.io/webauthn/#attestation-conveyance AttestationConveryancePreference.NONE

    //Direct //Indirect
  73. EJDUJPOBSZ4FSWFS1VCMJD,FZ$SFEFOUJBM$SFBUJPO0QUJPOT3FRVFTU\ SFRVJSFE%0.4USJOHVTFSOBNF SFRVJSFE%0.4USJOHEJTQMBZ/BNF "VUIFOUJDBUPS4FMFDUJPO$SJUFSJBBVUIFOUJDBUPS4FMFDUJPO "UUFTUBUJPO$POWFZBODF1SFGFSFODFBUUFTUBUJPOOPOF ^ https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-server-v2.0- rd-20180702.html#serverpublickeycredentialcreationoptionsrequest data class

    ServerPublicKeyCredentialCreationOptionsRequest( val username: String, val displayName: String, val authenticatorSelection: AuthenticatorSelectionCriter val attestation: AttestationConveyancePreference)
  74. Generate Credential "QQ "DUJWJUZ pEP "DUJWJUZ 3FTVMU *OUFSOBM VJ QPMMVY

  75. EJDUJPOBSZ4FSWFS1VCMJD,FZ$SFEFOUJBM$SFBUJPO0QUJPOT3FTQPOTF\ SFRVJSFE4UBUVTTUBUVT SFRVJSFE%0.4USJOHFSSPS.FTTBHFl SFRVJSFE1VCMJD,FZ$SFEFOUJBM3Q&OUJUZSQ SFRVJSFE4FSWFS1VCMJD,FZ$SFEFOUJBM6TFS&OUJUZVTFS SFRVJSFE%0.4USJOHDIBMMFOHF SFRVJSFETFRVFODF1VCMJD,FZ$SFEFOUJBM1BSBNFUFSTQVC,FZ$SFE1BSBNT VOTJHOFEMPOHUJNFPVU TFRVFODF4FSWFS1VCMJD,FZ$SFEFOUJBM%FTDSJQUPSFYDMVEF$SFEFOUJBMT<> "VUIFOUJDBUPS4FMFDUJPO$SJUFSJBBVUIFOUJDBUPS4FMFDUJPO

    "UUFTUBUJPO$POWFZBODF1SFGFSFODFBUUFTUBUJPOOPOF "VUIFOUJDBUJPO&YUFOTJPOT$MJFOU*OQVUTFYUFOTJPOT ^ https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-server-v2.0-rd- 20180702.html#serverpublickeycredentialcreationoptionsresponse
  76. val options = PublicKeyCredentialCreationOptions.Builder() .setRp(rp) .setUser(user) .setChallenge("challenge".toByteArray()) .setParameters(pubKeyParams) .setTimeoutSeconds(3600.toDouble()) .setExcludeList(exclusionList)

    .setAuthenticatorSelection(criteria) .setAttestationConveyancePreference(AttestationConveyancePreference.DIR .build() val client = Fido.getFido2ApiClient(this.applicationContext) val clientTask = client.getRegisterIntent(options) clientTask.addOnSuccessListener { it.launchPendingIntent(this, REGISTER_RESULT_CODE) }
  77. val options = PublicKeyCredentialCreationOptions.Builder() .setRp(rp) // required .setUser(user) // required

    .setChallenge("challenge".toByteArray()) // required .setParameters(pubKeyParams) // required .setTimeoutSeconds(3600.toDouble()) .setExcludeList(exclusionList) .setAuthenticatorSelection(criteria) .setAttestationConveyancePreference(AttestationConveyancePreference.DIR .build() val client = Fido.getFido2ApiClient(this.applicationContext) val clientTask = client.getRegisterIntent(options) clientTask.addOnSuccessListener { it.launchPendingIntent(this, REGISTER_RESULT_CODE) }
  78. val options = PublicKeyCredentialCreationOptions.Builder() .setRp(rp) .setUser(user) .setChallenge("challenge".toByteArray()) .setParameters(pubKeyParams) .setTimeoutSeconds(3600.toDouble()) .setExcludeList(exclusionList)

    .setAuthenticatorSelection(criteria) .setAttestationConveyancePreference(AttestationConveyancePreference.DIR .build() val client = Fido.getFido2ApiClient(this.applicationContext) val clientTask = client.getRegisterIntent(options) clientTask.addOnSuccessListener { it.launchPendingIntent(this, REGISTER_RESULT_CODE) }
  79. val rp = PublicKeyCredentialRpEntity( "login.example.com", "Example Company", “https://ex.com/icon.svg“) EJDUJPOBSZ1VCMJD,FZ$SFEFOUJBM3Q&OUJUZ1VCMJD,FZ$SFEFOUJBM&OUJUZ\ %0.4USJOHJE

    ^ EJDUJPOBSZ1VCMJD,FZ$SFEFOUJBM&OUJUZ\ SFRVJSFE%0.4USJOHOBNF 6474USJOHJDPO ^ https://w3c.github.io/webauthn/#sctn-rp-credential-params
  80. val options = PublicKeyCredentialCreationOptions.Builder() .setRp(rp) .setUser(user) .setChallenge(“challenge".toByteArray()) .setTimeoutSeconds(3600.toDouble()) .setParameters(pubKeyParams) .setExcludeList(exclusionList)

    .setAuthenticatorSelection(criteria) .setAttestationConveyancePreference(AttestationConveyancePreference.DIR .build() val client = Fido.getFido2ApiClient(this.applicationContext) val clientTask = client.getRegisterIntent(options) clientTask.addOnSuccessListener { it.launchPendingIntent(this, REGISTER_RESULT_CODE) }
  81. val user = PublicKeyCredentialUserEntity( "user-id-like-uuid".toByteArray(), "ken5scal", "https://gravata.com/ken5scal", "Kengo Suzuki") EJDUJPOBSZ1VCMJD,FZ$SFEFOUJBM6TFS&OUJUZ1VCMJD,FZ$SFEFOUJBM&OUJUZ\

    SFRVJSFE#V⒎FS4PVSDFJE SFRVJSFE%0.4USJOHEJTQMBZ/BNF ^ EJDUJPOBSZ1VCMJD,FZ$SFEFOUJBM&OUJUZ\ SFRVJSFE%0.4USJOHOBNF 6474USJOHJDPO ^ https://w3c.github.io/webauthn/#sctn-user-credential-params
  82. val options = PublicKeyCredentialCreationOptions.Builder() .setRp(rp) .setUser(user) .setChallenge(“challenge".toByteArray()) .setTimeoutSeconds(3600.toDouble()) .setParameters(pubKeyParams) .setExcludeList(exclusionList)

    .setAuthenticatorSelection(criteria) .setAttestationConveyancePreference(AttestationConveyancePreference .DIRECT) .build() val client = Fido.getFido2ApiClient(this.applicationContext) val clientTask = client.getRegisterIntent(options) clientTask.addOnSuccessListener { it.launchPendingIntent(this, REGISTER_RESULT_CODE) }
  83. val options = PublicKeyCredentialCreationOptions.Builder() .setRp(rp) .setUser(user) .setChallenge(“challenge".toByteArray()) .setTimeoutSeconds(3600.toDouble()) .setParameters(pubKeyParams) .setExcludeList(exclusionList)

    .setAuthenticatorSelection(criteria) .setAttestationConveyancePreference(AttestationConveyancePreference .DIRECT) .build() val client = Fido.getFido2ApiClient(this.applicationContext) val clientTask = client.getRegisterIntent(options) clientTask.addOnSuccessListener { it.launchPendingIntent(this, REGISTER_RESULT_CODE) }
  84. val pubKeyParam = PublicKeyCredentialParameters( // Essentially, only “public-key” can be

    chosen PublicKeyCredentialType.PUBLIC_KEY.toString(), //“public-key EC2Algorithm.ES512.algoValue ɹɹɹ// Recommended // EC2Algorithm.ES256.algoValue // Recommended // RSAAlgorithm.PS*.algoValue // RSAAlgorithm.RS*.algoValue ) EJDUJPOBSZ1VCMJD,FZ$SFEFOUJBM1BSBNFUFST\ SFRVJSFE1VCMJD,FZ$SFEFOUJBM5ZQFUZQF SFRVJSFE$04&"MHPSJUIN*EFOUJpFSBMH ^ https://w3c.github.io/webauthn/#credential-params
  85. val options = PublicKeyCredentialCreationOptions.Builder() .setRp(rp) .setUser(user) .setChallenge(“challenge".toByteArray()) .setTimeoutSeconds(3600.toDouble()) .setParameters(pubKeyParams) .setExcludeList(exclusionList)

    .setAuthenticatorSelection(criteria) .setAttestationConveyancePreference(AttestationConveyancePreference .DIRECT) .build() val client = Fido.getFido2ApiClient(this.applicationContext) val clientTask = client.getRegisterIntent(options) clientTask.addOnSuccessListener { it.launchPendingIntent(this, REGISTER_RESULT_CODE) }
  86. val excludedCredOne = PublicKeyCredentialDescriptor( PublicKeyCredentialType.PUBLIC_KEY.toString(),//“public-key” "base64url-credential-id".toByteArray()) val exclusionList = listOf(excludedCredOne)

    //, excludedCredTwo EJDUJPOBSZ4FSWFS1VCMJD,FZ$SFEFOUJBM%FTDSJQUPS\ SFRVJSFE1VCMJD,FZ$SFEFOUJBM5ZQFUZQF SFRVJSFE%0.4USJOHJE TFRVFODF"VUIFOUJDBUPS5SBOTQPSUUSBOTQPSUT ^ https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-server-v2.0-rd-20180702.html#serverpublickeycredentialdescriptor
  87. val options = PublicKeyCredentialCreationOptions.Builder() .setRp(rp) .setUser(user) .setChallenge(“challenge".toByteArray()) .setTimeoutSeconds(3600.toDouble()) .setParameters(pubKeyParams) .setExcludeList(exclusionList)

    .setAuthenticatorSelection(criteria) .setAttestationConveyancePreference(AttestationConveyancePreference .DIRECT) .build() val client = Fido.getFido2ApiClient(this.applicationContext) val clientTask = client.getRegisterIntent(options) clientTask.addOnSuccessListener { it.launchPendingIntent(this, REGISTER_RESULT_CODE) }
  88. val criteria = AuthenticatorSelectionCriteria.Builder() .setAttachment(Attachment.PLATFORM) //.setResidentKey(true) // No method exists

    //.setUserVerification() // No method exists .build() EJDUJPOBSZ"VUIFOUJDBUPS4FMFDUJPO$SJUFSJB\ "VUIFOUJDBUPS"UUBDINFOUBVUIFOUJDBUPS"UUBDINFOU CPPMFBOSFRVJSF3FTJEFOU,FZGBMTF 6TFS7FSJpDBUJPO3FRVJSFNFOUVTFS7FSJpDBUJPOQSFGFSSFE ^ https://w3c.github.io/webauthn/#authenticatorSelection
  89. val options = PublicKeyCredentialCreationOptions.Builder() .setRp(rp) .setUser(user) .setChallenge(“challenge".toByteArray()) .setTimeoutSeconds(3600.toDouble()) .setParameters(pubKeyParams) .setExcludeList(exclusionList)

    .setAuthenticatorSelection(criteria) .setAttestationConveyancePreference( AttestationConveyancePreference.DIRECT) .build() val client = Fido.getFido2ApiClient(this.applicationContext) val clientTask = client.getRegisterIntent(options) clientTask.addOnSuccessListener { it.launchPendingIntent(this, REGISTER_RESULT_CODE) }
  90. "QQ "DUJWJUZ pEP "DUJWJUZ 3FTVMU *OUFSOBM VJ QPMMVY - .fido

    - .common - .u2f (out of scope) - .fido2 - .api.common. - .ui (internal) - .AuthenticateActivity - .Fido2FullScreenActivity - .PolluxActivity - .GenericActivity - .pollux (internal) - .GcmReceiverService - .CableAuthenticatorService
  91. val options = PublicKeyCredentialCreationOptions.Builder() .setRp(rp) .setUser(user) .setChallenge("challenge".toByteArray()) .setParameters(pubKeyParams) .setTimeoutSeconds(3600.toDouble()) .setExcludeList(exclusionList)

    .setAuthenticatorSelection(criteria) .setAttestationConveyancePreference(AttestationConveyancePreference. DIRECT) .build() val client = Fido.getFido2ApiClient(this.Context) val clientTask = client.getRegisterIntent(options) clientTask.addOnSuccessListener { it.launchPendingIntent(this, REGISTER_RESULT_CODE)} }
  92. Register "QQ "DUJWJUZ pEP "DUJWJUZ 3FTVMU *OUFSOBM VJ QPMMVY

  93. val attestedResponse = intent? .getParcelableExtra<AuthenticatorAttestationResponse>( Fido.FIDO2_KEY_RESPONSE_EXTRA)

  94. val clientDataJSON = Base64.getUrlEncoder().encodeToString(attestedData?.clientDataJSON) val ao = Cbor.plain.dumps(AttestationObject(attestedData?.attestationObject)) val attstObject

    = Base64.getUrlEncoder.encode(ao.toByteArray()) EJDUJPOBSZ4FSWFS"VUIFOUJDBUPS"UUFTUBUJPO3FTQPOTF 4FSWFS"VUIFOUJDBUPS3FTQPOTF\ SFRVJSFE%0.4USJOHDMJFOU%BUB+40/ SFRVJSFE%0.4USJOHBUUFTUBUJPO0CKFDU ^ https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-server-v2.0-rd-20180702.html#serverauthenticatorattestationresponse
  95. EJDUJPOBSZ4FSWFS"VUIFOUJDBUPS"UUFTUBUJPO3FTQPOTF 4FSWFS"VUIFOUJDBUPS3FTQPOTF\ SFRVJSFE%0.4USJOHDMJFOU%BUB+40/ SFRVJSFE%0.4USJOHBUUFTUBUJPO0CKFDU ^ https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-server-v2.0-rd-20180702.html#serverauthenticatorattestationresponse val clientDataJSON = Base64.getUrlEncoder().encodeToString(attestedData?.clientDataJSON)

    val ao = Cbor.plain.dumps(AttestationObject(attestedData?.attestationObject)) val attstObject = Base64.getUrlEncoder.encode(ao.toByteArray())
  96. EJDUJPOBSZ$PMMFDUFE$MJFOU%BUB\ SFRVJSFE%0.4USJOHUZQF SFRVJSFE%0.4USJOHDIBMMFOHF SFRVJSFE%0.4USJOHPSJHJO 5PLFO#JOEJOHUPLFO#JOEJOH ^ https://w3c.github.io/webauthn/#sec-client-data val clientDataJSON =

    Base64.getUrlEncoder().encodeToString(attestedData?.clientDataJSON) val ao = Cbor.plain.dumps(AttestationObject(attestedData?.attestationObject)) val attstObject = Base64.getUrlEncoder.encode(ao.toByteArray())
  97. EJDUJPOBSZ4FSWFS"VUIFOUJDBUPS"UUFTUBUJPO3FTQPOTF 4FSWFS"VUIFOUJDBUPS3FTQPOTF\ SFRVJSFE%0.4USJOHDMJFOU%BUB+40/ SFRVJSFE%0.4USJOHBUUFTUBUJPO0CKFDU ^ https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-server-v2.0-rd-20180702.html#serverauthenticatorattestationresponse val clientDataJSON = Base64.getUrlEncoder().encodeToString(attestedData?.clientDataJSON)

    val ao = Cbor.plain.dumps(AttestationObject(attestedData?.attestationObject)) val attstObject = Base64.getUrlEncoder.encode(ao.toByteArray())
  98. Assertion in Android

  99. - Params for identify credential Get Option "QQ "DUJWJUZ pEP

    "DUJWJUZ 3FTVMU *OUFSOBM VJ QPMMVY
  100. "QQ "DUJWJUZ pEP "DUJWJUZ 3FTVMU *OUFSOBM VJ QPMMVY Authenticate

  101. Send Result "QQ "DUJWJUZ pEP "DUJWJUZ 3FTVMU *OUFSOBM VJ QPMMVY

  102. Flow "QQ "DUJWJUZ pEP "DUJWJUZ 3FTVMU *OUFSOBM VJ QPMMVY

  103. - Params for identify credential Get Option "QQ "DUJWJUZ pEP

    "DUJWJUZ 3FTVMU *OUFSOBM VJ QPMMVY
  104. EJDUJPOBSZ4FSWFS1VCMJD,FZ$SFEFOUJBM(FU0QUJPOT3FRVFTU\ SFRVJSFE%0.4USJOHVTFSOBNF 6TFS7FSJpDBUJPO3FRVJSFNFOUVTFS7FSJpDBUJPOQSFGFSSFE ^ https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-server-v2.0- rd-20180702.html#serverpublickeycredentialgetoptionsrequest data class ServerPublicKeyCredentialGetOptionsRequest( val

    username: String, val userVerificationRequirement: bool)
  105. Get Credential "QQ "DUJWJUZ pEP "DUJWJUZ 3FTVMU *OUFSOBM VJ QPMMVY

  106. EJDUJPOBSZ4FSWFS1VCMJD,FZ$SFEFOUJBM(FU0QUJPOT3FTQPOTF4FSWFS3FTQPOTF SFRVJSFE4UBUVTTUBUVT SFRVJSFE%0.4USJOHFSSPS.FTTBHFl SFRVJSFE%0.4USJOHDIBMMFOHF VOTJHOFEMPOHUJNFPVU 6474USJOHSQ*E TFRVFODF4FSWFS1VCMJD,FZ$SFEFOUJBM%FTDSJQUPSBMMPX$SFEFOUJBMT<> 6TFS7FSJpDBUJPO3FRVJSFNFOUVTFS7FSJpDBUJPOQSFGFSSFE "VUIFOUJDBUJPO&YUFOTJPOT$MJFOU*OQVUTFYUFOTJPOT ^

    https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-server-v2.0-rd- 20180702.html#serverpublickeycredentialcreationoptionsresponse
  107. val getOptions = PublicKeyCredentialRequestOptions.Builder() .setChallenge(“challenge".toByteArray()) //required .setTimeoutSeconds(3600.toDouble()) .setRpId("login.example.com") .setAllowList(allowList) .setAuthenticationExtensions(extensions)

    .build() val client = Fido.getFido2ApiClient(this.applicationContext) val clientTask = client.getRegisterIntent(options) clientTask.addOnSuccessListener { if (it.hasPendingIntent()) { it.launchPendingIntent(this, AUTHN_RESULT_CODE)} }
  108. val getOptions = PublicKeyCredentialRequestOptions.Builder() .setChallenge(“challenge".toByteArray()) .setTimeoutSeconds(3600.toDouble()) .setRpId("login.example.com") .setAllowList(allowList) .setAuthenticationExtensions(extensions) .build()

    val client = Fido.getFido2ApiClient(this.applicationContext) val clientTask = client.getRegisterIntent(options) clientTask.addOnSuccessListener { if (it.hasPendingIntent()) { it.launchPendingIntent(this, AUTHN_RESULT_CODE)} }
  109. val getOptions = PublicKeyCredentialRequestOptions.Builder() .setChallenge("challenge".toByteArray()) .setTimeoutSeconds(3600.toDouble()) .setRpId("login.example.com") .setAllowList(allowList) .setAuthenticationExtensions(extensions) .build()

    val client = Fido.getFido2ApiClient(this.applicationCont val clientTask = client.getRegisterIntent(options) clientTask.addOnSuccessListener { if (it.hasPendingIntent()) { it.launchPendingIntent(this, AUTHN_RESULT_CODE)} }
  110. val getOptions = PublicKeyCredentialRequestOptions.Builder() .setChallenge("challenge".toByteArray()) .setTimeoutSeconds(3600.toDouble()) .setRpId("login.example.com") .setAllowList(allowList) .setAuthenticationExtensions(extensions) .build()

    val client = Fido.getFido2ApiClient(this.applicationContext) val clientTask = client.getRegisterIntent(options) clientTask.addOnSuccessListener { if (it.hasPendingIntent()) { it.launchPendingIntent(this, AUTHN_RESULT_CODE)} }
  111. val allowedCred = PublicKeyCredentialDescriptor( PublicKeyCredentialType.PUBLIC_KEY.toString(), "base64url-credential-id".toByteArray()) val allowList = listOf(allowedCred)

    EJDUJPOBSZ4FSWFS1VCMJD,FZ$SFEFOUJBM%FTDSJQUPS\ SFRVJSFE1VCMJD,FZ$SFEFOUJBM5ZQFUZQF SFRVJSFE%0.4USJOHJE TFRVFODF"VUIFOUJDBUPS5SBOTQPSUUSBOTQPSUT ^ https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-server-v2.0-rd-20180702.html#serverpublickeycredentialdescriptor
  112. val getOptions = PublicKeyCredentialRequestOptions.Builder() .setChallenge("challenge".toByteArray()) .setTimeoutSeconds(3600.toDouble()) .setRpId("login.example.com") .setAllowList(allowList) .setAuthenticationExtensions(extensions) .build()

    val client = Fido.getFido2ApiClient(this.applicationContext) val clientTask = client.getRegisterIntent(options) clientTask.addOnSuccessListener { if (it.hasPendingIntent()) { it.launchPendingIntent(this, AUTHN_RESULT_CODE)} }
  113. EJDUJPOBSZ4FSWFS1VCMJD,FZ$SFEFOUJBM(FU0QUJPOT3FTQPOTF4FSWFS3FTQPOTF SFRVJSFE4UBUVTTUBUVT SFRVJSFE%0.4USJOHFSSPS.FTTBHFl SFRVJSFE%0.4USJOHDIBMMFOHF VOTJHOFEMPOHUJNFPVU 6474USJOHSQ*E TFRVFODF4FSWFS1VCMJD,FZ$SFEFOUJBM%FTDSJQUPSBMMPX$SFEFOUJBMT<> 6TFS7FSJpDBUJPO3FRVJSFNFOUVTFS7FSJpDBUJPOQSFGFSSFE "VUIFOUJDBUJPO&YUFOTJPOT$MJFOU*OQVUTFYUFOTJPOT ^

    https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-server-v2.0-rd- 20180702.html#serverpublickeycredentialcreationoptionsresponse  5IJTpFMEJTNJTTJOHGSPN'*%0QBDLBHF  :PVDBOOPUDIPPTFUPSFRVJSFVTFSWFSJpDBUJPO 67 
  114. val getOptions = PublicKeyCredentialRequestOptions.Builder() .setChallenge("challenge".toByteArray()) .setTimeoutSeconds(3600.toDouble()) .setRpId("login.example.com") .setAllowList(allowList) .setAuthenticationExtensions(extensions) .build()

    val client = Fido.getFido2ApiClient(this.applicationContext) val clientTask = client.getRegisterIntent(options) clientTask.addOnSuccessListener { if (it.hasPendingIntent()) { it.launchPendingIntent(this, AUTHN_RESULT_CODE)} }
  115. Send Result "QQ "DUJWJUZ pEP "DUJWJUZ 3FTVMU *OUFSOBM VJ QPMMVY

  116. val signedData = data?.getParcelableExtra<AuthenticatorAssertionResponse> (Fido.FIDO2_KEY_RESPONSE_EXTRA)

  117. EJDUJPOBSZ4FSWFS"VUIFOUJDBUPS"TTFSUJPO3FTQPOTF 4FSWFS"VUIFOUJDBUPS3FTQPOTF\ SFRVJSFE%0.4USJOHDMJFOU%BUB+40/ SFRVJSFE%0.4USJOHBVUIFOUJDBUPS%BUB SFRVJSFE%0.4USJOHTJHOBUVSF SFRVJSFE%0.4USJOHVTFS)BOEMF ^ https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-server-v2.0-rd-20180702.html#serverauthenticatorattestationresponse val cd

    = Base64.getUrlEncoder().encodeToString(signedData?.clientDataJ SON) val ad = Base64.getUrlEncoder().encodeToString(signedData?.authenticat orData) // Do same for signature and userHandle (got too lazy)
  118. EJDUJPOBSZ4FSWFS"VUIFOUJDBUPS"TTFSUJPO3FTQPOTF 4FSWFS"VUIFOUJDBUPS3FTQPOTF\ SFRVJSFE%0.4USJOHDMJFOU%BUB+40/ SFRVJSFE%0.4USJOHBVUIFOUJDBUPS%BUB SFRVJSFE%0.4USJOHTJHOBUVSF SFRVJSFE%0.4USJOHVTFS)BOEMF ^ https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-server-v2.0-rd-20180702.html#serverauthenticatorattestationresponse val cd

    = Base64.getUrlEncoder().encodeToString(signedData?.clientDataJ SON) val ad = Base64.getUrlEncoder().encodeToString(signedData?.authenticat orData) // Do same for signature and userHandle (got too lazy)
  119. EJDUJPOBSZ4FSWFS"VUIFOUJDBUPS"TTFSUJPO3FTQPOTF 4FSWFS"VUIFOUJDBUPS3FTQPOTF\ SFRVJSFE%0.4USJOHDMJFOU%BUB+40/ SFRVJSFE%0.4USJOHBVUIFOUJDBUPS%BUB SFRVJSFE%0.4USJOHTJHOBUVSF SFRVJSFE%0.4USJOHVTFS)BOEMF ^ https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-server-v2.0-rd-20180702.html#serverauthenticatorattestationresponse val cd

    = Base64.getUrlEncoder().encodeToString(signedData?.clientDataJ SON) val ad = Base64.getUrlEncoder().encodeToString(signedData?.authenticat orData) // Do same for signature and userHandle (got too lazy)
  120. https://w3c.github.io/webauthn/#attestation-object

  121. EJDUJPOBSZ4FSWFS"VUIFOUJDBUPS"UUFTUBUJPO3FTQPOTF 4FSWFS"VUIFOUJDBUPS3FTQPOTF\ SFRVJSFE%0.4USJOHDMJFOU%BUB+40/ SFRVJSFE%0.4USJOHBVUIFOUJDBUPS%BUB SFRVJSFE%0.4USJOHTJHOBUVSF SFRVJSFE%0.4USJOHVTFS)BOEMF ^ https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-server-v2.0-rd-20180702.html#serverauthenticatorattestationresponse val cd

    = Base64.getUrlEncoder().encodeToString(signedData?.clientDataJ SON) val ad = Base64.getUrlEncoder().encodeToString(signedData?.authenticat orData) // Do same for signature and userHandle (got too lazy)
  122. function LiftUp (someone) { alert("Hello" + someone) } LiftUp("Me");

  123. That’s it

  124. 1. Motivation 2. Overview of FIDO 3. Implementing FIDO2 in

    Android 4. Attestation in Android 5. Assertion in Android What we have covered
  125. Future of FIDO2 (for developers)

  126. - Avoid reinventing the wheel - Instead focus on each

    params and patters - Be prepared to communicate with other departments - For example, you should cooperate with CS in case of device lose Things we should care
  127. Conclusion

  128. - FIDO2 may solve current pain in Password-centric Authentication -

    Android has nice and thorough package - Be prepared to inconvenient environment without password Conclusion
  129. @ken5scal Thank you!

  130. None