Google ウォレットの身分証明書を確認する

オンライン

デジタル ID は、アプリ内フローおよびウェブフローでも受け付けることができます。Google ウォレットの認証情報を確認するには、次の要件を満たす必要があります。

  1. 提供された手順に沿ってアプリまたはウェブを使用して統合します。
  2. こちらのフォームに記入して、Google ウォレットからの認証情報の受け入れに関する利用規約をリクエストし、同意します。

前提条件

身分証明書の提示をテストするには、まず対象のテスト アカウントを使用して公開ベータ版プログラムに登録する必要があります。その後、Google の担当者に詳細情報を提供してください。

  • 利用規約のリンク
  • ロゴ
  • ウェブサイト
  • Play ストアのパッケージ ID(Android アプリの統合用)
  • 公開ベータ版への参加に使用した Gmail ID

サポートされている認証情報の形式

デジタル身分証明書のデータ形式を定義する提案された標準がいくつかありますが、業界で注目を集めているものは 2 つあります。

  1. mdoc - ISO で定義されています。
  2. W3C 検証可能な認証情報 - W3C で定義されています。

Android 認証情報マネージャーは両方の形式をサポートしていますが、Google ウォレットは現在、mdoc ベースのデジタル ID のみをサポートしています。

ユーザー エクスペリエンス

アプリケーションが ID 属性をリクエストすると、次の処理が行われます。

  1. 認証情報の検出: アプリケーションは、使用可能なウォレットをクエリして、リクエストを満たす認証情報を特定します。Android は、共有する情報を表示するシステム UI セレクタを表示します。これにより、ユーザーはどの認証情報を使用するかを十分な情報に基づいて判断できます。

  2. ユーザーの選択とウォレットの操作: ユーザーが認証情報を選択すると、Android は対応するウォレット アプリを呼び出して取引を完了します。ウォレット アプリが独自の同意画面を表示したり、生体認証による確認を求めたりする場合があります。

結果: ユーザーが同意すると、選択した ID 認証情報がリクエスト元のアプリと共有されます。ユーザーが拒否すると、エラーが返されます。

アプリ内

Android アプリから ID 認証情報をリクエストする手順は次のとおりです。

依存関係を更新する

プロジェクトの build.gradle で、認証情報マネージャー(ベータ版)を使用するように依存関係を更新します。

dependencies {
    implementation("androidx.credentials:credentials:1.5.0-beta01")
    // optional - needed for credentials support from play services, for devices running Android 13 and below.
    implementation("androidx.credentials:credentials-play-services-auth:1.5.0-beta01")
}

Credential Manager を構成する

CredentialManager オブジェクトを構成して初期化するには、次のようなロジックを追加します。

// Use your app or activity context to instantiate a client instance of CredentialManager.
val credentialManager = CredentialManager.create(context)

リクエスト ID 属性

アプリは、ID リクエストに個々のパラメータを指定するのではなく、CredentialOption 内で JSON 文字列としてすべて提供します。認証情報マネージャーは、この JSON 文字列の内容を検証せずに、利用可能なデジタル ウォレットに渡します。各ウォレットは、次の処理を行います。 - JSON 文字列を解析して ID リクエストを把握します。 - 保存されている認証情報のうち、リクエストを満たすもの(存在する場合)を特定します。

W3C は、この JSON リクエストの構造を、ウェブ API 仕様の一部として正式に定義する予定です。ただし、仕様はドラフト形式であり、変更される可能性があることに注意してください。

最初は、プレビュー プロトコルを使用して Google ウォレットから身分証明書を取得します。これにより、Web API 仕様が確定する前に統合とテストを開始できます。

プレビュー プロトコルの mdoc requestJson の例を次に示します。

{
  identity: {
    providers: [{
      holder: {
        selector: {
          format: ['mdoc'],
          type: 'org.iso.18013.5.1.mDL',
          fields: [
            'org.iso.18013.5.1.family_name',
            'org.iso.18013.5.1.portrait',
          ]
        },
        params: {
          nonce: '1234',
          readerPublicKey: '<public_key>',
          extraParamAsNeededByWallets: true,
        },
      },
    }]
  }
}
// The request in the JSON format to conform with
// the JSON-ified Digital Credentials API request definition.
val requestJson = generateRequestFromServer()
val digitalCredentialOption =
    GetDigitalCredentialOption(requestJson = requestJson)

// Use the option from the previous step to build the `GetCredentialRequest`.
val getCredRequest = GetCredentialRequest(
    listOf(digitalCredentialOption)
)

coroutineScope.launch {
    try {
        val result = credentialManager.getCredential(
            context = activityContext,
            request = getCredRequest
        )
        verifyResult(result)
    } catch (e : GetCredentialException) {
        handleFailure(e)
    }
}

// Handle the successfully returned credential.
fun verifyResult(result: GetCredentialResponse) {
    val credential = result.credential
    when (credential) {
        is DigitalCredential -> {
            val responseJson = credential.credentialJson
            validateResponseOnServer(responseJson)
        }
        else -> {
            // Catch any unrecognized credential type here.
            Log.e(TAG, "Unexpected type of credential ${credential.type}")
        }
    }
}

// Handle failure.
fun handleFailure(e: GetCredentialException) {
  when (e) {
        is GetCredentialCancellationException -> {
            // The user intentionally canceled the operation and chose not
            // to share the credential.
        }
        is GetCredentialInterruptedException -> {
            // Retry-able error. Consider retrying the call.
        }
        is NoCredentialException -> {
            // No credential was available.
        }
        is CreateCredentialUnknownException -> {
            // An unknown, usually unexpected, error has occurred. Check the
            // message error for any additional debugging information.
        }
        is CreateCredentialCustomException -> {
            // You have encountered a custom error thrown by the wallet.
            // If you made the API call with a request object that's a
            // subclass of CreateCustomCredentialRequest using a 3rd-party SDK,
            // then you should check for any custom exception type constants
            // within that SDK to match with e.type. Otherwise, drop or log the
            // exception.
        }
        else -> Log.w(TAG, "Unexpected exception type ${e::class.java}")
    }
}

レスポンスには、W3C で定義された identityToken(JSON 文字列)が返されます。このレスポンスを作成するのはウォレット アプリです。

例:

{
    "token": "<base64 encoded response>"
}

トークンを送信してサーバーで処理する

アプリケーションは、identityToken を受信したら、検証のためにアプリケーション サーバーに送信する必要があります。最初のステップでは、トークンを Base64 形式からデコードします。生成されたバイト配列は、次の CDDL に準拠する CBOR データを表します。

CredentialDocument = {
  "version": tstr,       // Set to "ANDROID-HPKE-v1"
  "pkEm": bstr,          // Public key, in uncompressed form
  "cipherText": bstr     // The encrypted data
}

次のステップでは、Android 固有のハンドオーバー構造を使用して、ISO/IEC 18013-5:2021 の SessionTranscript を計算します。

SessionTranscript = [
  null,                // DeviceEngagementBytes not available
  null,                // EReaderKeyBytes not available
  AndroidHandover      // Defined below
]

AndroidHandover = [
  "AndroidHandoverv1", // Version number
  nonce,               // nonce that comes from request
  appId,               // RP package name
  pkRHash,             // The SHA256 hash of the recipient public key
]

cipherText は HPKE 暗号化を使用して暗号化されます。復号するには、追加の認証データとして SessionTranscript を使用し、前に生成した EC 秘密鍵と次の設定を使用します。

  • KEM: DHKEM(P-256、HKDF-SHA256)
  • KDF: HKDF-SHA256
  • AEAD: AES-128-GCM

結果のクリアテキストは、ISO/IEC 18013-5:2021 で定義されている DeviceResponse CBOR バイトです。DeviceResponse は、ISO/IEC 18013-5:2021 の条項 9 に従って検証する必要があります。これには、mdoc が信頼できる発行元から発信されたこと、レスポンスが目的のデバイスによって署名されていることを確認するなどの手順が含まれます。この検証プロセスの一環として、OpenWallet Foundation ID 認証情報プロジェクトDeviceResponseParser クラスを使用できます。

ウェブ

Chrome で Digital Credentials API を使用して ID 認証情報をリクエストするには、Digital Credentials API のオリジン トライアルに登録する必要があります。

対面

Google ウォレットの身分証明書を確認する手順は次のとおりです。

  • ISO 18013-5 で定義されている身分証明書を確認するためのリーダーを作成または取得する
  • IACA 証明書をリーダーに読み込んで、確認しようとしている身分証明書が本物であることをチェックする
  • ソリューションをテストする
  • アプリケーションを Google ウォレットに登録する

ISO 18013-5 で定義されている身分証明書を確認するためのリーダーを作成または取得する

ウォレットの身分証明書は、モバイル運転免許証の ISO 18013-5 標準に従って実装されます。データ転送メカニズムとして BLE とともに NFC ベースまたは QR コードのエンゲージメントを使用しているため、標準のこのような機能を実装できるデバイスであればリーダーとして使用できます。モバイル アプリケーションをリーダーとして使用することもできます。標準が公開されているため、複数のサードパーティによる実装が市販されています。必要に応じて、自組織で機能を直接実装することもできます。

この機能を自組織で実装する方法については、Google のオープンソース リファレンス リーダーである Android アプリをご覧ください。このアプリは ISO 標準を実装しており、Google ウォレットのモバイル運転免許証を確認できます。

最初に、次の方法でリファレンス リーダー アプリをビルドして実行します。

  • リファレンス アプリのリポジトリのクローンを作成します。
  • Android Studio でプロジェクトを開きます。
  • appverifier ターゲットをビルドし、Android デバイスまたはエミュレータで実行します。

IACA 証明書をリーダーに読み込んで、確認しようとしている身分証明書が本物であることをチェックする

本物の認証情報であることを検証するには、サポートされている発行元のウォレット内に身分証明書が含まれている必要があります。Google ウォレットでサポートされている発行元のリストと、検証用の証明書へのリンクを以下に示します。

ソリューションをテストするには、Google のオープンソース リファレンス ホルダーである Android アプリをビルドして実行します。リファレンス ホルダー アプリをビルドして実行する手順は次のとおりです。

  • リファレンス アプリのリポジトリのクローンを作成します。
  • Android Studio でプロジェクトを開きます。
  • appholder ターゲットをビルドし、Android デバイスまたはエミュレータで実行します。

(省略可)Google ウォレットにアプリケーションを登録する

こちらのフォームに記入して、Google ウォレットにアプリケーションを登録します。