-
Notifications
You must be signed in to change notification settings - Fork 0
MS_WindowsSecurityCredentials
- 戻る(Microsoft Passport)
- Windows.Security.Credentials
- Windows Hello
- Windows Hello for Business
- FIDO
- Microsoft Passport が提供するプログラミングシステムの API
- Windows デバイス上で、FIDO を実装する場合に、この API を利用する。
補足(現在は WebAuthn が標準): 本ページの
KeyCredentialManagerは
UWP アプリ向けの API で、ブラウザからは使えない。
Web アプリケーションから Windows Hello を認証器として使う場合は、
現在は W3C の **Web Authentication API(WebAuthn)**を用いる。
「鍵ペアを作り、公開鍵をサーバに登録し、チャレンジに署名する」という
流れは同じなので、本ページの構成はそのまま WebAuthn の理解にも使える。
詳しくは「Web Authentication API」
「WebAuthnを実装する。」を参照。
- アプリケーションに登録開始リクエストを送る。
- challenge、policy、appID などが返される。
- ユーザーが Windows Hello をセットアップしたかどうかを調べる
if (await KeyCredentialManager.IsSupportedAsync() == false)
{
・・・当該ユーザ&アプリケーションのキーのストア&コンテナを開く。
// retrieve private key for sign
KeyCredentialRetrievalResult res =
await KeyCredentialManager.OpenAsync("keyName");if (res.Status == KeyCredentialStatus.NotFound)
{
・・・の場合、
- ≒ 新規の device を登録する場合、若しくは、追加のデバイスを登録する場合。
-
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.
}移行メモ(変数名の不一致): 上記のコードは、
作成結果をcreateResに受けておきながら
分岐ではkeyCreationResultを参照している。
元ページのままとしたが、実装時はどちらかに統一すること
(以降のコードはkeyCreationResultを前提にしている)。
-
public key を取得する。
-
実装
KeyCredential userKey = keyCreationResult.Credential;
IBuffer publicKey = userKey.RetrievePublicKey();-
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);
}補足(attestation は「鍵の出自の証明」): attestation は
その鍵が本当に TPM の中で作られ、外に出ていないことを
デバイス側が証明するものである。
NotSupported(TPM を持たないソフトウェア鍵)や
TemporaryFailure(構成証明サービスに到達できない)でも
鍵自体は使えるため、サーバ側で
「attestation なしの登録を受け入れるか」を方針として決める必要がある。
上のコードが状態を細かく持ち回っているのはこのためである。
-
PublicKey
IBuffer publicKey
-
KeyAttestation
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)
{
・・・の場合、
登録後、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)
{
}
}サーバ実装の「認証」を参照。
ある特定の箇所で生体認証を呼び出して 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 …
}
}補足(署名を伴わない確認):
UserConsentVerifierは
その場で本人確認のダイアログを出すだけで、鍵による署名は行わない。
端末内での再確認(重要操作の前の確認)には使えるが、
サーバ側で検証可能な証跡は残らないため、
認証そのものにはRequestSignAsyncを使う。
private key を削除する。
await KeyCredentialManager.DeleteAsync("keyName");- id
- e-mail address
- first name
- last name
- id
- user id
- public key
- attestation
- device id
- last logontime
補足(1 ユーザに複数の鍵): 鍵は端末ごとに作られるため、
User : UserKeysは 1 対多になる。
端末を買い替えたら新しい鍵を追加登録し、
紛失した端末の鍵は削除する、という運用になる。
上のスキーマにdevice idがあるのはこのためである。
UserKeys レコードを追加。
using (RSACng pubKey = new RSACng(publicKey))
{
retval = pubKey.VerifyData(
originalChallenge, responseSignature,
HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
}補足(challenge はサーバが作って覚えておく): 検証で使う
originalChallengeは、サーバが毎回生成してセッションに保持したものでなければ
リプレイ攻撃を防げない。クライアントから送り返された値をそのまま使ってはならない。
- Windows Hello を使った App 開発 – Tsmatz
https://blogs.msdn.microsoft.com/tsmatsuz/2015/07/30/windows-hello-app/
- UWP app developer
-
Windows Hello
https://docs.microsoft.com/ja-jp/windows/uwp/security/microsoft-passport- Windows Hello ログイン アプリの作成
https://docs.microsoft.com/ja-jp/windows/uwp/security/microsoft-passport-login - Windows Hello ログイン サービスの作成
https://docs.microsoft.com/ja-jp/windows/uwp/security/microsoft-passport-login-auth-service
- Windows Hello ログイン アプリの作成
-
(Windows.Security.Credentials)
- KeyCredential Class (Windows.Security.Credentials)
https://docs.microsoft.com/en-us/uwp/api/windows.security.credentials.keycredential - KeyCredentialManager Class (Windows.Security.Credentials)
https://docs.microsoft.com/en-us/uwp/api/windows.security.credentials.keycredentialmanager - KeyCredentialAttestationResult Class (Windows.Security.Credentials)
https://docs.microsoft.com/en-us/uwp/api/windows.security.credentials.keycredentialattestationresult
- KeyCredential Class (Windows.Security.Credentials)
-
- MicrosoftPassport
https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/MicrosoftPassport
Tags: Windows, 認証基盤
このWikiは「Open棟梁Project」,「OSSコンソーシアム 開発基盤部会」によって運営されています。