/// <summary> /// Click handler for the 'ResetPin' button. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private async void ResetPin_Click(object sender, RoutedEventArgs e) { if (!rootPage.ValidateTPMSmartCard()) { rootPage.NotifyUser("Use Scenario One to create a TPM virtual smart card.", NotifyType.ErrorMessage); return; } Button b = sender as Button; b.IsEnabled = false; try { SmartCard card = await rootPage.GetSmartCard(); SmartCardProvisioning provisioning = await SmartCardProvisioning.FromSmartCardAsync(card); rootPage.NotifyUser("Resetting smart card PIN...", NotifyType.StatusMessage); // When requesting a PIN reset, a SmartCardPinResetHandler must be // provided as an argument. This handler must use the challenge // it receives and the card's admin key to calculate and set the // response. bool result = await provisioning.RequestPinResetAsync( (pinResetSender, request) => { SmartCardPinResetDeferral deferral = request.GetDeferral(); try { IBuffer response = ChallengeResponseAlgorithm.CalculateResponse(request.Challenge, rootPage.AdminKey); request.SetResponse(response); } finally { deferral.Complete(); } }); if (result) { rootPage.NotifyUser("Smart card PIN reset operation completed.", NotifyType.StatusMessage); } else { rootPage.NotifyUser("Smart card PIN reset operation was canceled by the user.", NotifyType.StatusMessage); } } catch (Exception ex) { rootPage.NotifyUser("Resetting smart card PIN failed with exception: " + ex.ToString(), NotifyType.ErrorMessage); } finally { b.IsEnabled = true; } }
/// <summary> /// Click handler for the 'ChangeAdminKey' button. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private async void ChangeAdminKey_Click(object sender, RoutedEventArgs e) { if (!rootPage.ValidateTPMSmartCard()) { rootPage.NotifyUser( "Use Scenario One to create a TPM virtual smart card.", NotifyType.ErrorMessage); return; } Button b = sender as Button; b.IsEnabled = false; try { IBuffer newadminkey = CryptographicBuffer.GenerateRandom( MainPage.ADMIN_KEY_LENGTH_IN_BYTES); SmartCard card = await rootPage.GetSmartCard(); SmartCardProvisioning provisioning = await SmartCardProvisioning.FromSmartCardAsync(card); rootPage.NotifyUser("Changing smart card admin key...", NotifyType.StatusMessage); using (SmartCardChallengeContext context = await provisioning.GetChallengeContextAsync()) { IBuffer response = ChallengeResponseAlgorithm.CalculateResponse( context.Challenge, rootPage.AdminKey); await context.ChangeAdministrativeKeyAsync(response, newadminkey); rootPage.AdminKey = newadminkey; } rootPage.NotifyUser( "Smart card change admin key operation completed.", NotifyType.StatusMessage); } catch (Exception ex) { rootPage.NotifyUser( "Changing smart card admin key operation failed " + "with exception: " + ex.ToString(), NotifyType.ErrorMessage); } finally { b.IsEnabled = true; } }
/// <summary> /// Click handler for the 'Delete' button. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private async void Delete_Click(object sender, RoutedEventArgs e) { if (!rootPage.ValidateTPMSmartCard()) { rootPage.NotifyUser("Use Scenario One to create a TPM virtual smart card.", NotifyType.ErrorMessage); return; } Button b = sender as Button; b.IsEnabled = false; rootPage.NotifyUser("Deleting the TPM virtual smart card...", NotifyType.ErrorMessage); try { SmartCard card = await rootPage.GetSmartCard(); // The following two lines are not directly related to TPM virtual // smart card creation, but are used to demonstrate how to handle // CardRemoved events by registering an event handler with a // SmartCardReader object. Since we are using a TPM virtual smart // card in this case, the card cannot actually be added to or // removed from the reader, but a CardRemoved event will fire // when the reader and card are deleted. // // We must retain a reference to the SmartCardReader object to // which we are adding the event handler. We use += to add the // HandleCardRemoved method as an event handler. The function // will be automatically boxed in a TypedEventHandler, but // the function signature match the template arguments for // the specific event - in this case, // <SmartCardReader, CardRemovedEventArgs> reader = card.Reader; reader.CardRemoved += HandleCardRemoved; bool result = await SmartCardProvisioning.RequestVirtualSmartCardDeletionAsync(card); if (result) { rootPage.NotifyUser("TPM virtual smart card deletion completed.", NotifyType.StatusMessage); rootPage.SmartCardReaderDeviceId = null; } else { rootPage.NotifyUser("TPM virtual smart card deletion was canceled by the user.", NotifyType.StatusMessage); } } catch (Exception ex) { rootPage.NotifyUser("TPM virtual smartcard deletion failed with exception: " + ex.ToString(), NotifyType.ErrorMessage); } finally { b.IsEnabled = true; } }
/// <summary> /// Click handler for the 'VerifyResponse' button. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private async void VerifyResponse_Click(object sender, RoutedEventArgs e) { if (!rootPage.ValidateTPMSmartCard()) { rootPage.NotifyUser( "Use Scenario One to create a TPM virtual smart card.", NotifyType.ErrorMessage); return; } Button b = sender as Button; b.IsEnabled = false; try { bool verifyResult = false; SmartCard card = await rootPage.GetSmartCard(); SmartCardProvisioning provisioning = await SmartCardProvisioning.FromSmartCardAsync(card); rootPage.NotifyUser("Verifying smart card response...", NotifyType.StatusMessage); using (SmartCardChallengeContext context = await provisioning.GetChallengeContextAsync()) { IBuffer response = ChallengeResponseAlgorithm.CalculateResponse( context.Challenge, rootPage.AdminKey); verifyResult = await context.VerifyResponseAsync(response); } rootPage.NotifyUser( "Smart card response verification completed. Result: " + verifyResult.ToString(), NotifyType.StatusMessage); } catch (Exception ex) { rootPage.NotifyUser( "Verifying smart card response operation failed " + "with exception: " + ex.ToString(), NotifyType.ErrorMessage); } finally { b.IsEnabled = true; } }
/// <summary> /// Click handler for the 'ChangePin' button. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private async void ChangePin_Click(object sender, RoutedEventArgs e) { if (!rootPage.ValidateTPMSmartCard()) { rootPage.NotifyUser( "Use Scenario One to create a TPM virtual smart card.", NotifyType.ErrorMessage); return; } Button b = sender as Button; b.IsEnabled = false; try { SmartCard card = await rootPage.GetSmartCard(); SmartCardProvisioning provisioning = await SmartCardProvisioning.FromSmartCardAsync(card); rootPage.NotifyUser("Changing smart card PIN...", NotifyType.StatusMessage); bool result = await provisioning.RequestPinChangeAsync(); if (result) { rootPage.NotifyUser( "Smart card change PIN operation completed.", NotifyType.StatusMessage); } else { rootPage.NotifyUser( "Smart card change PIN operation was canceled by " + "the user.", NotifyType.StatusMessage); } } catch (Exception ex) { rootPage.NotifyUser( "Changing smart card PIN failed with exception: " + ex.ToString(), NotifyType.ErrorMessage); } finally { b.IsEnabled = true; } }
/// <summary> /// Click handler for the 'ListSmartCard' button. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private async void ListSmartCard_Click(object sender, RoutedEventArgs e) { Button b = sender as Button; b.IsEnabled = false; try { rootPage.NotifyUser("Enumerating smart cards...", NotifyType.StatusMessage); // This list will be bound to our ItemListView once it has been // filled with SmartCardListItems. The SmartCardListItem class // is defined above, and describes a reader/card pair with a // reader name and a card name. List <SmartCardListItem> cardItems = new List <SmartCardListItem>(); // First we get the device selector for smart card readers using // the static GetDeviceSelector method of the SmartCardReader // class. The selector is a string which describes a class of // devices to query for, and is used as the argument to // DeviceInformation.FindAllAsync. GetDeviceSelector is // overloaded so that you can provide a SmartCardReaderKind // to specify if you are only interested in a particular type // of card/reader (e.g. TPM virtual smart card.) In this case // we will list all cards and readers. string selector = SmartCardReader.GetDeviceSelector(); DeviceInformationCollection devices = await DeviceInformation.FindAllAsync(selector); // DeviceInformation.FindAllAsync gives us a // DeviceInformationCollection, which is essentially a list // of DeviceInformation objects. We must iterate through that // list and instantiate SmartCardReader objects from the // DeviceInformation objects. foreach (DeviceInformation device in devices) { SmartCardReader reader = await SmartCardReader.FromIdAsync(device.Id); // For each reader, we want to find all the cards associated // with it. Then we will create a SmartCardListItem for // each (reader, card) pair. IReadOnlyList <SmartCard> cards = await reader.FindAllCardsAsync(); foreach (SmartCard card in cards) { SmartCardProvisioning provisioning = await SmartCardProvisioning.FromSmartCardAsync(card); SmartCardListItem item = new SmartCardListItem() { ReaderName = card.Reader.Name, CardName = await provisioning.GetNameAsync() }; cardItems.Add(item); } } // Bind the source of ItemListView to our SmartCardListItem list. ItemListView.ItemsSource = cardItems; rootPage.NotifyUser("Enumerating smart cards completed.", NotifyType.StatusMessage); } catch (Exception ex) { rootPage.NotifyUser("Enumerating smart cards failed with exception: " + ex.ToString(), NotifyType.ErrorMessage); } finally { b.IsEnabled = true; } }
/// <summary> /// Click handler for the 'create' button. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private async void Create_Click(object sender, RoutedEventArgs e) { Button b = sender as Button; b.IsEnabled = false; rootPage.NotifyUser("Creating TPM virtual smart card...", NotifyType.StatusMessage); try { SmartCardPinPolicy pinPolicy = ParsePinPolicy(); IBuffer adminkey = CryptographicBuffer.GenerateRandom( MainPage.ADMIN_KEY_LENGTH_IN_BYTES); SmartCardProvisioning provisioning = await SmartCardProvisioning.RequestVirtualSmartCardCreationAsync( FriendlyNameText.Text, adminkey, pinPolicy); // If card creation is cancelled by the user, // RequestVirtualSmartCard will return null instead of a // SmartCardProvisioning object. if (null == provisioning) { rootPage.NotifyUser( "TPM virtual smart card creation was canceled by " + "the user.", NotifyType.StatusMessage); b.IsEnabled = true; return; } // The following two lines are not directly related to TPM virtual // smart card creation, but are used to demonstrate how to handle // CardAdded events by registering an event handler with a // SmartCardReader object. Since we are using a TPM virtual smart // card in this case, the card cannot actually be added to or // removed from the reader, but a CardAdded event will fire as // soon as the event handler is added, since the card is already // inserted. // // We must retain a reference to the SmartCardReader object to // which we are adding the event handler. Hence we assign the // reader object associated with the SmartCardProvisioning we // received from RequestVirtualSmartCardCreationAsync to the // class's "reader" member. Then, we use += to add the // HandleCardAdded method as an event handler. The function // will be automatically boxed in a TypedEventHandler, but // the function signature match the template arguments for // the specific event - in this case, // <SmartCardReader, CardAddedEventArgs> reader = provisioning.SmartCard.Reader; reader.CardAdded += HandleCardAdded; // Store the reader's device ID and admin key to enable the // following scenarios in the sample. rootPage.SmartCardReaderDeviceId = provisioning.SmartCard.Reader.DeviceId; rootPage.AdminKey = adminkey; // Once RequestVirtualSmartCardCreationAsync has returned, the card // is already provisioned and ready to use. Therefore, the steps // in this using block are not actually necessary at this point. // However, should you want to re-provision the card in the future, // you would follow this sequence: acquire a challenge context, // calculate a response, and then call ProvisionAsync on the // challenge context with the calculated response. using (var context = await provisioning.GetChallengeContextAsync()) { IBuffer response = ChallengeResponseAlgorithm.CalculateResponse( context.Challenge, adminkey); await context.ProvisionAsync(response, true); } rootPage.NotifyUser( "TPM virtual smart card is provisioned and ready for use.", NotifyType.StatusMessage); } catch (Exception ex) { // Two potentially common error scenarios when creating a TPM // virtual smart card are that the user's machine may not have // a TPM, or the TPM may not be ready for use. It is important // to explicitly check for these scenarios by checking the // HResult of any exceptions thrown by // RequestVirtualSmartCardCreationAsync and gracefully // providing a suitable message to the user. if(NTE_DEVICE_NOT_FOUND == ex.HResult) { rootPage.NotifyUser( "We were unable to find a Trusted Platform Module on " + "your machine. A TPM is required to use a TPM Virtual " + "Smart Card.", NotifyType.ErrorMessage); } else if (NTE_DEVICE_NOT_READY == ex.HResult) { rootPage.NotifyUser( "Your Trusted Platform Module is not ready for use. " + "Please contact your administrator for assistance with " + "initializing your TPM.", NotifyType.ErrorMessage); } else { rootPage.NotifyUser( "TPM virtual smart card creation failed with exception: " + ex.ToString(), NotifyType.ErrorMessage); } } finally { b.IsEnabled = true; } }
public static async Task RegisterDevice_Click(string deviceFriendlyName) { String deviceId = ""; IBuffer deviceKey = CryptographicBuffer.GenerateRandom(32); IBuffer authKey = CryptographicBuffer.GenerateRandom(32); byte[] deviceKeyArray = new byte[32]; byte[] authKeyArray = new byte[32]; byte[] deviceIdArray = new byte[16]; byte[] deviceDlockState = new byte[1]; byte[] response = { 0 }; int numberOfDevices = 0; int numberOfRegisteredDevices = 0; string sw1sw2 = null; //byte[] combinedDataArray = new byte[64]; string NanosATR = "3b00"; String deviceModelNumber = "0001"; //List<SmartCardListItem> cardItems = new List<SmartCardListItem>(); MessageDialog myDlg; bool isSupported; isSupported = await KeyCredentialManager.IsSupportedAsync(); if (!isSupported) { var loader = new Windows.ApplicationModel.Resources.ResourceLoader(); string PleaseSetUpPinContent = loader.GetString("PleaseSetupPin_content_error"); string PleaseSetUpPinTitle = loader.GetString("PleaseSetupPin_title_error"); myDlg = new MessageDialog(PleaseSetUpPinContent, PleaseSetUpPinTitle); await myDlg.ShowAsync(); return; } IReadOnlyList <User> users = await User.FindAllAsync(UserType.LocalUser, UserAuthenticationStatus.LocallyAuthenticated); string userId = users.ElementAt(0).NonRoamableId; string selector = SmartCardReader.GetDeviceSelector(); selector += " AND System.Devices.DeviceInstanceId:~~\"Ledger\""; //string test = selector.Replace(" ", ((char)34).ToString()); DeviceInformationCollection devices = await DeviceInformation.FindAllAsync(selector); foreach (DeviceInformation device in devices) { SmartCardReader reader = await SmartCardReader.FromIdAsync(device.Id); IReadOnlyList <SmartCard> cards = await reader.FindAllCardsAsync(); foreach (SmartCard card in cards) { SmartCardProvisioning provisioning = await SmartCardProvisioning.FromSmartCardAsync(card); IBuffer ATR = await card.GetAnswerToResetAsync(); string ATR_str = CryptographicBuffer.EncodeToHexString(ATR); if (ATR_str.Equals(NanosATR)) { numberOfDevices++; bool foundCompanionDevice = false; // List the registered devices to prevent registering twice the same device IReadOnlyList <SecondaryAuthenticationFactorInfo> registeredDeviceList = await SecondaryAuthenticationFactorRegistration.FindAllRegisteredDeviceInfoAsync( SecondaryAuthenticationFactorDeviceFindScope.AllUsers); SmartCardConnection connection = await card.ConnectAsync(); response = await Apdu.TransmitApduAsync(connection, Apdu.getDeviceGuidCmdApdu); sw1sw2 = Apdu.ApduResponseParser(response, out response); connection.Dispose(); deviceIdArray = response; deviceId = BitConverter.ToString(response).Replace("-", ""); // Loop on registered devices to check if device to register has already been registered for (int i = 0; i < registeredDeviceList.Count(); i++) { if (registeredDeviceList.ElementAt(i).DeviceId == deviceId) { //deviceFriendlyName = registeredDeviceList.ElementAt(i).DeviceFriendlyName; numberOfRegisteredDevices++; foundCompanionDevice = true; break; } } if (foundCompanionDevice)// This device has already been registered { // New message dialog to inform user, and break from card loop //myDlg = null; //myDlg = new MessageDialog("The device \"" + deviceFriendlyName + "\" has already been registered"); //await myDlg.ShowAsync(); continue; } connection = await card.ConnectAsync(); response = await Apdu.TransmitApduAsync(connection, Apdu.getDlockStateCmdApdu); sw1sw2 = Apdu.ApduResponseParser(response, out response); deviceDlockState = response; response = await Apdu.TransmitApduAsync(connection, Apdu.startRegistrationCmdApdu); sw1sw2 = Apdu.ApduResponseParser(response, out response); connection.Dispose(); if (sw1sw2 != "9000") { var loader = new Windows.ApplicationModel.Resources.ResourceLoader(); string RegistrationDeniedContent = loader.GetString("RegsitrationDenied_content_error"); string RegistrationDeniedTitle = loader.GetString("RegsitrationDenied_title_error"); myDlg = null; myDlg = new MessageDialog(RegistrationDeniedContent, RegistrationDeniedTitle); await myDlg.ShowAsync(); return; } // Get device key from response for (int index = 0; index < 32; index++) { deviceKeyArray[index] = response[index]; } deviceKey = CryptographicBuffer.CreateFromByteArray(deviceKeyArray); // Get auth key from response for (int index = 0; index < 32; index++) { authKeyArray[index] = response[index + 32]; } authKey = CryptographicBuffer.CreateFromByteArray(authKeyArray); byte[] deviceConfigDataArray = new byte[18]; //16 bytes for GUID and 1 byte for dLockstate for (int i = 0; i < 16; i++) { deviceConfigDataArray[i] = deviceIdArray[i]; } deviceConfigDataArray[16] = deviceDlockState[0]; deviceConfigDataArray[17] = 0; // 1 if used for last logon, 0 instead string deviceConfigString = ""; DateTime addDate = DateTime.Now; //DateTime addDate = new DateTime(2017, 5, 31, 13, 23, 45); if (deviceDlockState[0] == 0) { deviceConfigString = deviceId + "-0-0-" + deviceFriendlyName + "-" + addDate.ToString() + "-" + userId; } else { deviceConfigString = deviceId + "-1-0-" + deviceFriendlyName + "-" + addDate.ToString() + "-" + userId; } // Get a Ibuffer from combinedDataArray IBuffer deviceConfigData = CryptographicBuffer.ConvertStringToBinary(deviceConfigString, 0); //IBuffer deviceConfigData = CryptographicBuffer.CreateFromByteArray(deviceConfigDataArray); SecondaryAuthenticationFactorDeviceCapabilities capabilities = SecondaryAuthenticationFactorDeviceCapabilities.SecureStorage | SecondaryAuthenticationFactorDeviceCapabilities.HMacSha256 | SecondaryAuthenticationFactorDeviceCapabilities.StoreKeys | SecondaryAuthenticationFactorDeviceCapabilities.SupportSecureUserPresenceCheck; SecondaryAuthenticationFactorRegistrationResult registrationResult = await SecondaryAuthenticationFactorRegistration.RequestStartRegisteringDeviceAsync( deviceId, capabilities, deviceFriendlyName, deviceModelNumber, deviceKey, authKey); if (registrationResult.Status != SecondaryAuthenticationFactorRegistrationStatus.Started) { myDlg = null; if (registrationResult.Status == SecondaryAuthenticationFactorRegistrationStatus.DisabledByPolicy) { //For DisaledByPolicy Exception:Ensure secondary auth is enabled. //Use GPEdit.msc to update group policy to allow secondary auth //Local Computer Policy\Computer Configuration\Administrative Templates\Windows Components\Microsoft Secondary Authentication Factor\Allow Companion device for secondary authentication myDlg = new MessageDialog("Disabled by Policy. Please update the policy and try again."); } if (registrationResult.Status == SecondaryAuthenticationFactorRegistrationStatus.PinSetupRequired) { //For PinSetupRequired Exception:Ensure PIN is setup on the device //Either use gpedit.msc or set reg key //This setting can be enabled by creating the AllowDomainPINLogon REG_DWORD value under the HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\System Registry key and setting it to 1. var loader = new Windows.ApplicationModel.Resources.ResourceLoader(); var str = loader.GetString("PleaseSetupPin_error"); myDlg = new MessageDialog(str); } if (myDlg != null) { await myDlg.ShowAsync(); return; } } System.Diagnostics.Debug.WriteLine("[RegisterDevice_Click] Device Registration Started!"); await registrationResult.Registration.FinishRegisteringDeviceAsync(deviceConfigData); //DeviceListBox.Items.Add(deviceFriendlyName); System.Diagnostics.Debug.WriteLine("[RegisterDevice_Click] Device Registration is Complete!"); IReadOnlyList <SecondaryAuthenticationFactorInfo> deviceList = await SecondaryAuthenticationFactorRegistration.FindAllRegisteredDeviceInfoAsync( SecondaryAuthenticationFactorDeviceFindScope.AllUsers); SecondaryAuthenticationFactorDevicePresenceMonitoringRegistrationStatus status = await SecondaryAuthenticationFactorRegistration.RegisterDevicePresenceMonitoringAsync( deviceId, device.Id, SecondaryAuthenticationFactorDevicePresenceMonitoringMode.AppManaged /*, * deviceFriendlyName, * deviceModelNumber, * deviceConfigData*/); switch (status) { //case SecondaryAuthenticationFactorDevicePresenceMonitoringRegistrationStatus.Succeeded: // await new MessageDialog("Registered for presence monitoring!").ShowAsync(); // break; case SecondaryAuthenticationFactorDevicePresenceMonitoringRegistrationStatus.DisabledByPolicy: await new MessageDialog("Registered for presence disabled by policy!").ShowAsync(); break; } listContent listItem = new listContent(); listItem.deviceFriendlyName = deviceFriendlyName; listItem.deviceGUID = deviceId; //listItem.isVisible = false; listItem.date = addDate; listItem.dateString = FormatDate(addDate); //DeviceListBox.Items.Add(listItem); //StartWatcher(); //this.Frame.Navigate(typeof(MainPage), "false"); } } } if (numberOfDevices == numberOfRegisteredDevices) { var loader = new Windows.ApplicationModel.Resources.ResourceLoader(); string str = loader.GetString("DeviceAlreadyRegistered_content_error"); throw new Exception(str); //myDlg = new MessageDialog("Ledger Nano-s for Windows Hello not found" + Environment.NewLine + Environment.NewLine + "Please plug a ledger Nano-s in a usb port"); //await myDlg.ShowAsync(); //return; } return; }