マイクロソフト系技術情報 Wiki」は、「Open棟梁Project」,「OSSコンソーシアム .NET開発基盤部会」によって運営されています。

目次

概要

  • Microsoft Passportが提供するプログラミングシステムのAPI
  • Windowsデバイス上で、FIDOを実装する場合に、このAPIを利用する。

クライアント実装

共通

  • アプリケーションに登録開始リクエストを送る。
  • challenge、policy、appIDなどが返される。

policyに適合する認証器を調べる

認証器の調査: KeyCredentialManager?.IsSupportedAsync?()メソッド

  • ユーザーが Windows Hello をセットアップしたかどうかを調べる
if (await KeyCredentialManager.IsSupportedAsync() == false)
{
  ・・・

キーのストア&コンテナを開く: KeyCredentialManager?.OpenAsync?()メソッド

当該ユーザ&アプリケーションのキーのストア&コンテナを開く。

// retrieve private key for sign
KeyCredentialRetrievalResult res =
  await KeyCredentialManager.OpenAsync("keyName");

登録

if (res.Status == KeyCredentialStatus.NotFound)
{
  ・・・

の場合、

  • ≒新規のdeviceを登録する場合、若しくは、追加のデバイスを登録する場合。

キーペアを作成する: KeyCredentialManager?.RequestCreateAsync?()メソッド

  • RequestCreateAsync?を使用してキーペアを作成する。
    • Windows Helloに対応した認証器に生体認証の情報を入力する。
    • 入力後、内部では、private key と public key が作成される。
    • private key は TPM に登録され、以降、認証器によって保護される。
  • 実装
    // Create the credential
    // (Windows Hello is diplayed here !)
    KeyCredentialRetrievalResult createRes =
        await KeyCredentialManager.RequestCreateAsync("keyName", KeyCredentialCreationOption.ReplaceExisting);
    
    // if the status is success, retrieve the public key.
    if (createRes.Status == KeyCredentialStatus.Success)
    {
      ・・・public keyとattestationを取得する。
    }
    else if(
        keyCreationResult.Status == KeyCredentialStatus.UserCanceled ||
        keyCreationResult.Status == KeyCredentialStatus.UserPrefersPassword)
    {
        // Show error message to the user to get confirmation that user does not want to enroll.
    }

public keyを取得する: KeyCredential?.RetrievePublicKey?()メソッド

  • public keyを取得する。
  • 実装
    KeyCredential userKey = keyCreationResult.Credential;
    IBuffer publicKey = userKey.RetrievePublicKey();

attestationを取得する: KeyCredential?.GetAttestationAsync?()メソッド

  • attestation(デバイス正常性構成証明)を取得する。
  • 実装
    KeyCredentialAttestationResult keyAttestationResult = await userKey.GetAttestationAsync();
    
    IBuffer keyAttestation = null;
    IBuffer certificateChain = null;
    bool keyAttestationIncluded = false;
    bool keyAttestationCanBeRetrievedLater = false;
    KeyCredentialAttestationStatus keyAttestationRetryType = 0;
    
    if (keyAttestationResult.Status == KeyCredentialAttestationStatus.Success)
    {
        keyAttestationIncluded = true;
        keyAttestation = keyAttestationResult.AttestationBuffer;
        certificateChain = keyAttestationResult.CertificateChainBuffer;
        rootPage.NotifyUser("Successfully made key and attestation", NotifyType.StatusMessage);
    }
    else if (keyAttestationResult.Status == KeyCredentialAttestationStatus.TemporaryFailure)
    {
        keyAttestationRetryType = KeyCredentialAttestationStatus.TemporaryFailure;
        keyAttestationCanBeRetrievedLater = true;
        rootPage.NotifyUser("Successfully made key but not attestation", NotifyType.StatusMessage);
    }
    else if (keyAttestationResult.Status == KeyCredentialAttestationStatus.NotSupported)
    {
        keyAttestationRetryType = KeyCredentialAttestationStatus.NotSupported;
        keyAttestationCanBeRetrievedLater = false;
        rootPage.NotifyUser("Key created, but key attestation not supported", NotifyType.StatusMessage);
    }

上記の情報をサーバに飛ばして登録する。

  • PublicKey?
    IBuffer publicKey
  • KeyAttesation?
    IBuffer keyAttestation
  • certificate chain for attestation endorsement key
    IBuffer certificateChain
  • status code of key attestation result
    bool keyAttestationIncluded
    bool keyAttestationCanBeRetrievedLater
    KeyCredentialAttestationStatus keyAttestationRetryType
  • 実装
    // Package public key, keyAttesation if available, 
    // certificate chain for attestation endorsement key if available,  
    // status code of key attestation result: keyAttestationIncluded or 
    // keyAttestationCanBeRetrievedLater and keyAttestationRetryType
    // and send it to application server to register the user.
    bool serverAddedPassportToAccount = await AddPassportToAccountOnServer();
    
    if (serverAddedPassportToAccount == true)
    {
        return true;
    }

認証

上記のKeyCredentialManager.OpenAsyncの結果が、

if (res.Status == KeyCredentialStatus.Success)
{
  ・・・

の場合、

KeyCredentialManager?.RequestSignAsync?()メソッド

登録後、PIN や 生体認証を使って、challengeにデジタル署名 (RequestSignAsync?) する。

var openKeyResult = await KeyCredentialManager.OpenAsync(AccountId);
if (openKeyResult.Status == KeyCredentialStatus.Success)
{
    var userKey = openKeyResult.Credential;
    var publicKey = userKey.RetrievePublicKey();
    var signResult = await userKey.RequestSignAsync(message);
    if (signResult.Status == KeyCredentialStatus.Success)
    {
        return signResult.Result;
    }
    else if (signResult.Status == KeyCredentialStatus.UserPrefersPassword)
    {
    }
}

上記の情報をサーバに飛ばして認証する。

こちら

その他

UserConsentVerifier?.RequestVerificationAsync?()メソッド

ある特定の箇所で 生体認証を呼び出してOKかNOか確認したい場合

if (await UserConsentVerifier.CheckAvailabilityAsync() == 
UserConsentVerifierAvailability.Available)
{
    UserConsentVerificationResult res =
        await UserConsentVerifier.RequestVerificationAsync(
            "This is sensitive operation ! Please authenticate again.");
            
    if(res == UserConsentVerificationResult.Verified)
    {
      // some important action …
    }
}

KeyCredentialManager?.DeleteAsync?()メソッド

private keyを削除する。

await KeyCredentialManager.DeleteAsync("keyName");

サーバ実装

サンプルのデータベース スキーマ

User

  • id
  • e-mail address
  • first name
  • last name

UserKeys?

  • id
  • user id
  • public key
  • attestation
  • device id
  • last logontime

処理

登録

UserKeys?レコードを追加。

認証

using (RSACng pubKey = new RSACng(publicKey))
{
   retval = pubKey.VerifyData(
                originalChallenge, responseSignature,
                HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); 
}

参考

docs.microsoft.com

Microsoft/Windows-universal-samples


Tags: :Windows, :認証基盤


トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2018-02-03 (土) 14:11:00 (257d)