Windows Hello, Microsoft Passport and the KeyCredentialManager API

I’m a big fan of multi-factor authentication where some party authenticates me not just on the basis of my providing the right combination of username and password but, in addition, asks me to prove that I have access to some other piece of material that’s, hopefully, unlikely to be available to anyone but me.

This is pretty common in the physical world – when we sign up for new domestic services, it’s quite common to have to be asked to provide;

  1. An identity card (e.g. a UK driving license has a photo, signature and address).
  2. A recent utility bill.

and the two factors are taken as being a stronger proof than just the one although it’s perhaps a bit of a stretched analogy.

Back in the virtual world, there’s 2 places where I encounter 2-factor authentication frequently;

  1. In the public space, when I sign in to sites with my Microsoft Account, I have 2-factor authentication turned on and so, often, the server-side bits will send a text message to my mobile phone with some random code number that I need to enter back on the website before authentication will complete.
    1. This only works because I have previously registered my mobile phone number as being associated with my account.
  2. In the enterprise space, when I try and sign on to Microsoft properties these days with a username and password, the server-side bits send out a voice call to my mobile phone and I’m asked to provide an additional PIN number to complete the authentication.
    1. This only works because my employer knows my mobile phone number and I have previously set up a PIN with their servers.

As the sub-bullets note in both cases, the authentication system is using some additional ‘prior knowledge’ that it has about me (e.g. my phone number and/or an extra PIN) in order to make doubly sure that it’s me that is sending the authentication request rather than just someone who’s somehow got hold of my user name and password.

In order for that to work, there needs to be some kind of registration step where I provide the authentication mechanism with whatever information the second factor authentication relies upon – for example, this would be my mobile phone number in (1) above.

The additional security is welcome but, naturally, it does come with slightly more friction than a regular ‘username + password’ style login and the increasing use of these multi-factor mechanisms relies on finding the right security/convenience trade-off for me as a user.

Windows 10 has new technologies that are trying to find that security/convenience balance – Windows Hello and Microsoft Passport – and which radically change the way in which we sign in to a Windows machine and how we might then authenticate ourselves from that Windows machine to other services.

In short, I think Windows 10 changes 2 things;

  1. The user can sign in to their device with a short PIN code or with a biometric mechanism such as facial recognition, fingerprint or iris scanner known as a “Hello”;
    1. A “Hello” should be more convenient for the user than a username and password.
    2. A “Hello” is a local mechanism to unlock one device. It’s local to that device and the data for it never leaves that device. It is not part of the data used to authenticate with a service and so it is hard for a hacker to steal. Additionally, a “Hello” for one device (like a PIN) will not unlock another device.
  2. The device becomes part of the authentication process when the user attempts to access other services;
    1. The device can generate and store a ‘Passport’ for the user to access a particular service.
    2. The device can secure a user’s ‘Passports’ such that access to them is only granted to that signed-on user and only then for specific scenarios.
    3. The device can ‘prove’ to a particular service that it holds a ‘Passport’ for access to that service.

The pieces under (2) above make use of cryptography and 2.2 would usually involve special hardware support from something like a TPM chip although I don’t believe that the Windows 10 bits mandate a TPM chip.

Clearly for 2 to work with backend services (including e.g. accessing services across machines within a managed Windows domain/AD environment) then some back-end services would need to change and I believe that work is already done for identities that are represented by Microsoft Accounts, Active Directory Accounts, Azure Active Directory Accounts and, beyond Microsoft, for services that support the Fast ID Online standard.

In terms of background reading around Windows Hello and Microsoft Passport, I found this Technet article to be a really good read.

Then in terms of background watching, this video arrived recently on Channel 9 from my friends @andy_wigley and @rajen_k and it’s one of the best that I’ve seen to date.

Windows Hello and Microsoft Passport on Channel9

Along with that video, there’s also the code sample on GitHub;

Microsoft Passport and Windows Hello Sample

I read up and watched but, naturally, it doesn’t turn me into some kind of ‘security expert’ over night so apply a pinch of salt to my ramblings on these topics but I wanted to understand what’s going on here and experiment with the UWP APIs that enable these types of scenarios.

The way that I think about the changes here is something like;

  • Without ‘Hello’ and ‘Passport’ I authenticate by following a process that’s something like;
    • I send a username and password combination over the network (hopefully using some secure transport protocol).
    • The service on the other side of that connection looks up the username in a database and finds a (salted) hashed password value associated with it.
    • The service performs a (salted) hash on the password it has received and checks that against the stored hash.
    • If the values match, the service issues some token that lets me access that service for some period of time and the process is repeated when it times out.
  • With ‘Hello’ and ‘Passport’ I authenticate by following a process that’s something like;
    • I send some identifying data over the network – perhaps a user id and a device id.
    • The service on the other side looks up the username and device in a database to find the public component of a ‘Passport’ associated with me on that device.
    • The service sends a response asking for proof that I have access to the private component of the ‘Passport’ in question.
    • The device asks me to provide a PIN/‘Hello’ to unlock my stored ‘Passport’ for that service. 
    • The device uses the unlocked ‘Passport’ to generate proof that the user has access to that ‘Passport’.
    • The device might also generate proof that the ‘Passport’ is being accessed securely under the remit of a TPM chip.
    • The service receives the proof that the user owns the ‘Passport’ and possibly proof that it is being stored securely by a TPM chip that the service trusts and, if so, issues a token that lets me access the service for some period of time.
    • At some point, the token times out and the process is repeated.

and I hope that I’ve got that ‘close enough’ to how things work but feel free to let me know if I’ve got things wrong.

For the client-side of this interaction, there’s clearly a need to be able to do at least;

  1. Request a new ‘passport’ for access to some service.
  2. Send the public component of that ‘passport’ to the service such that it can be registered for later retrieval.
  3. Prove to a service that the user of the device has access to the private component of a ‘passport’.
  4. Prove to a service that the private component of a ‘passport’ has been accessed under suitable restrictions (e.g. managed by a TMP chip).

and what’s surprising (in a good way) about all of this is that the APIs involved are really neat, simple and don’t involve going off to crypto-school for the next 12 months.

They key class in the UWP is the KeyCredentialManager and I wanted to walk through it’s methods to see if I could try and understand how it can enable using ‘Passport’ and ‘Hello’ for an app.

These are the steps that I took.

Request a New ‘Passport’ for Access to Some Service

I made a little UI, just some XAML with 4 TextBoxes in it and a couple of buttons. It’s as below;


  <Grid
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <!-- Naturally, hard coded strings here should be moved to x:Uid resources -->
    <Grid.Resources>
      <Style
        x:Key="baseStyle"
        TargetType="FrameworkElement">
        <Setter
          Property="Margin"
          Value="8" />
      </Style>
      <Style
        TargetType="TextBox" BasedOn="{StaticResource baseStyle}">
      </Style>
      <Style
        TargetType="Button"
        BasedOn="{StaticResource baseStyle}">
      </Style>
    </Grid.Resources>
    <Grid.RowDefinitions>
      <RowDefinition
        Height="Auto" />
      <RowDefinition
        Height="Auto" />
      <RowDefinition
        Height="*" />
    </Grid.RowDefinitions>
    <TextBox
      Header="Name of Service to Create Passport for"
      Text="{Binding ServiceName, Mode=TwoWay}"
      Grid.Row="0" />
    <StackPanel
      Grid.Row="1"
      HorizontalAlignment="Right"
      Orientation="Horizontal">
      <Button
        Content="Get Existing Passport"
        HorizontalAlignment="Right"
        IsEnabled="{Binding HasServiceName}">
        <b:Interaction.Behaviors>
          <bc:EventTriggerBehavior
            EventName="Click">
            <bc:CallMethodAction
              TargetObject="{Binding}"
              MethodName="GetExistingPassport" />
          </bc:EventTriggerBehavior>
        </b:Interaction.Behaviors>
      </Button>
      <Button
        Content="Create or Replace Passport"
        HorizontalAlignment="Right"
        IsEnabled="{Binding HasServiceName}">
        <b:Interaction.Behaviors>
          <bc:EventTriggerBehavior
            EventName="Click">
            <bc:CallMethodAction
              TargetObject="{Binding}"
              MethodName="CreatePassportAsync" />
          </bc:EventTriggerBehavior>
        </b:Interaction.Behaviors>
      </Button>
    </StackPanel>
    
    <!-- Grid that displays the passport details -->
    <Grid
      Grid.Row="2">
      <Grid.RowDefinitions>
        <RowDefinition
          Height="Auto" />
        <RowDefinition
          Height="Auto" />
        <RowDefinition
          Height="Auto" />
      </Grid.RowDefinitions>
      <TextBox
        Header="Passport Name"
        IsReadOnly="True"
        Text="{Binding PassportName}" 
        Grid.Row="0"/>
      <TextBox
        Header="Passport Public Key"
        IsReadOnly="True"
        TextWrapping="Wrap"
        Text="{Binding PassportPublicKey}"
        Grid.Row="1" />
      <TextBox
        Header="Passport Attestation"
        IsReadOnly="True"
        Text="{Binding PassportAttestation}"
        Grid.Row="2" />
    </Grid>
  </Grid>

and I then wrote a little code behind it in an attempt to be able to both create a new ‘Passport’ and/or to retrieve an existing one by name;

namespace App2
{
  using System;
  using System.ComponentModel;
  using System.Runtime.CompilerServices;
  using System.Runtime.InteropServices.WindowsRuntime;
  using System.Threading.Tasks;
  using Windows.Security.Credentials;
  using Windows.Security.Cryptography;
  using Windows.Storage.Streams;
  using Windows.UI.Popups;
  using Windows.UI.Xaml.Controls;

  public sealed partial class MainPage : Page, INotifyPropertyChanged
  {
    public event PropertyChangedEventHandler PropertyChanged;

    public MainPage()
    {
      this.InitializeComponent();
      this.Loaded += (s, e) =>
      {
        this.DataContext = this;
      };
    }

    public string PassportName
    {
      get
      {
        return (this.passportName);
      }
      set
      {
        if (this.passportName != value)
        {
          this.passportName = value;
          this.RaisePropertyChanged();
        }
      }
    }
    public string PassportPublicKey
    {
      get
      {
        return (this.passportPublicKey);
      }
      set
      {
        if (this.passportPublicKey != value)
        {
          this.passportPublicKey = value;
          this.RaisePropertyChanged();
        }
      }
    }
    public string PassportAttestation
    {
      get
      {
        return (this.passportAttestation);
      }
      set
      {
        if (this.passportAttestation != value)
        {
          this.passportAttestation = value;
          this.RaisePropertyChanged();
        }
      }
    }
    public string ServiceName
    {
      get
      {
        return (this.serviceName);
      }
      set
      {
        if (this.serviceName != value)
        {
          this.serviceName = value;
          this.RaisePropertyChanged();
          this.RaisePropertyChanged("HasServiceName");
        }
      }
    }
    public bool HasServiceName
    {
      get
      {
        return (!string.IsNullOrEmpty(this.ServiceName));
      }
    }
    public async void CreatePassportAsync()
    {
      if (await this.CheckSupportAsync())
      {
        var result = await KeyCredentialManager.RequestCreateAsync(
          this.ServiceName,
          KeyCredentialCreationOption.ReplaceExisting);

        if (result.Status == KeyCredentialStatus.Success)
        {
          // We have a new 'passport', what can we get from it?
          this.keyCredential = result.Credential;
          this.OnKeyCredentialChange();
        }
        else
        {
          // TODO: put text into resources.
          await this.ShowDialogAsync(
            $"Failed to create a passport for the service named {this.ServiceName}",
            "Failed to Create Passport");
        }
      }
    }
    public async void GetExistingPassport()
    {
      this.keyCredential = null;

      if (await this.CheckSupportAsync())
      {
        var result = await KeyCredentialManager.OpenAsync(
          this.ServiceName);

        if (result.Status != KeyCredentialStatus.Success)
        {
          await this.ShowDialogAsync(
            $"Sorry, failed to open the passport called {this.ServiceName}",
            "Failed to Open Passport");
        }
        else
        {
          this.keyCredential = result.Credential;
        }
        this.OnKeyCredentialChange();
      }
    }
    async void OnKeyCredentialChange()
    {
      if (this.keyCredential == null)
      {
        this.PassportName = null;
        this.PassportPublicKey = null;
        this.PassportAttestation = null;
      }
      else
      {
        this.PassportName = this.keyCredential.Name;

        this.PassportPublicKey =
          CryptographicBuffer.EncodeToHexString(
            this.keyCredential.RetrievePublicKey());

        var result = await this.keyCredential.GetAttestationAsync();

        if (result.Status == KeyCredentialAttestationStatus.Success)
        {
          this.PassportAttestation = 
            CryptographicBuffer.EncodeToHexString(result.AttestationBuffer);
        }
        else
        {
          this.PassportAttestation = 
            $"Failed to get attestation - status is {result.Status}";
        }
      }
    }
    void RaiseKeyCredentialPropertiesChanged()
    {
      this.RaisePropertyChanged("PassportName");
      this.RaisePropertyChanged("PassportPublicKey");
      this.RaisePropertyChanged("PassportAttestation");
    }
    async Task<bool> CheckSupportAsync()
    {
      bool supported = await KeyCredentialManager.IsSupportedAsync();

      if (!supported)
      {
        // TODO: put text into resources.
        await this.ShowDialogAsync(
          "Sorry, we can't do this - maybe you haven't set a PIN?",
          "Functionality Not Supported"
        );
      }
      return (supported);
    }
    async Task ShowDialogAsync(string text, string title)
    {
      // Naturally, this text would belong in a resource.
      var dialog = new MessageDialog(text, title);

      await dialog.ShowAsync();
    }
    void RaisePropertyChanged([CallerMemberName] string callerName = "")
    {
      this.PropertyChanged?.Invoke(this,
        new PropertyChangedEventArgs(callerName));
    }
    KeyCredential keyCredential;
    string serviceName;
    string passportAttestation;
    string passportPublicKey;
    string passportName;
  }
}

and so this is pretty simple apart from its use of the GetExistingPassport, CreatePassportAsync and OnKeyCredentialChange methods which make use of KeyCredentialManager.RequestCreateAsync, OpenAsync in order to get hold of a KeyCredential either by creating it or by opening up an existing one by name.

From there, the values obtained from KeyCredential.Name, KeyCredential.RetrievePublicKey and KeyCredential.GetAttestationAsync are displayed in TextBoxes on the screen.

When I run this on my system and I create a new ‘Passport’ using the button I get the prompt for a PIN;

image

whereas opening up an existing Passport doesn’t require that extra authentication step.

The data that I get back then looks like;

image

and so it seems that I can create/access a passport and get its public key but note that the ‘Passport Attestation’ field is reporting a ‘NotSupported’ value.

Send the Public Component of that ‘Passport’ to the Service

Clearly, this is something that I can do – I’ve got the public key component and so I can send it off to a web service to store alongside some information about which user and device it belongs to and, as the Channel 9 video suggests, this has impact on the back-end service as there would be a need to store this public key information for each device for a user  rather than just storing a single password hash for a user across all their devices.

Prove to a Service that the User of the Device has Access to the Private Component of a ‘Passport’

If a service sends some piece of data to the client then the client can digitally sign it to prove that it has access to the private key of the ‘Passport’ that matches up with the public key part that the service has stored for the user/device combination.

I added another grid to my UI to enable me to enter a piece of text to be signed, a button to click to sign it and somewhere to display the results;

    <!-- Grid that allows the signing of a piece of data -->
    <Grid
      Grid.Row="3">
      <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition />
        <RowDefinition />
      </Grid.RowDefinitions>
      <TextBox
        Header="Text to sign"
        Text="{Binding TextToSign,Mode=TwoWay}" />
      <Button
        Grid.Row="1"
        HorizontalAlignment="Right"
        Content="Sign with Passport"
        IsEnabled="{Binding CanSignText}">
        <b:Interaction.Behaviors>
          <bc:EventTriggerBehavior
            EventName="Click">
            <bc:CallMethodAction
              TargetObject="{Binding}"
              MethodName="SignTextWithPassport" />
          </bc:EventTriggerBehavior>
        </b:Interaction.Behaviors>
      </Button>
      <TextBox
        Grid.Row="2"
        IsReadOnly="True"
        TextWrapping="Wrap"
        Header="Signature Text"
        Text="{Binding SignatureText}" />
    </Grid>

and I made a few code additions – I’ve listed just the additions/modifications to the code behind class below with a ‘NEW’ comment on them;

    async void OnKeyCredentialChange()
    {
      if (this.keyCredential == null)
      {
        this.PassportName = null;
        this.PassportPublicKey = null;
        this.PassportAttestation = null;
      }
      else
      {
        this.PassportName = this.keyCredential.Name;

        this.PassportPublicKey =
          CryptographicBuffer.EncodeToHexString(
            this.keyCredential.RetrievePublicKey());

        var result = await this.keyCredential.GetAttestationAsync();

        if (result.Status == KeyCredentialAttestationStatus.Success)
        {
          this.PassportAttestation =
            CryptographicBuffer.EncodeToHexString(result.AttestationBuffer);
        }
        else
        {
          this.PassportAttestation =
            $"Failed to get attestation - status is {result.Status}";
        }
      }
      // NEW: added this so that we change our opinion of whether we can
      // or can't sign text based on the key credential changing.
      this.RaisePropertyChanged("CanSignText");
    }
    // NEW: all the rest of the code from here onwards is new.
    public string SignatureText
    {
      get
      {
        return (this.signatureText);
      }
      set
      {
        if (this.signatureText != value)
        {
          this.signatureText = value;
          this.RaisePropertyChanged();
        }
      }
    }
    public bool CanSignText
    {
      get
      {
        return ((this.keyCredential != null) &&
          !string.IsNullOrEmpty(this.TextToSign));
      }
    }
    public string TextToSign  
    {
      get
      {
        return (this.textToSign);
      }
      set
      {
        if (this.textToSign != value)
        {
          this.textToSign = value;
          this.RaisePropertyChanged();
          this.RaisePropertyChanged("CanSignText");
        }
      }
    }
    public async void SignTextWithPassport()
    {
      // We need to take the text that we've got in the textbox and
      // convert it into an ibuffer.
      IBuffer buffer = CryptographicBuffer.ConvertStringToBinary(
        this.TextToSign, BinaryStringEncoding.Utf8);

      var result = await this.keyCredential.RequestSignAsync(buffer);

      if (result.Status == KeyCredentialStatus.Success)
      {
        this.SignatureText = CryptographicBuffer.EncodeToHexString(result.Result);
      }
      else
      {
        this.SignatureText =
          $"Failed to sign text with passport {result.Status}";
      }
    }
    string textToSign;
    string signatureText;

and then that lets me use the UI to generate a signature over some arbitrary piece of text and when I click that ‘generate signature’ button I get asked to verify my identity again by the system as it needs to use the private key to make the signature;

image

Note that I’m signing the whole ‘Text to sign’ here whereas it might be more normal to sign a hash of that text as signing can be expensive but, regardless, after a second I get some data that I assume is the signature back from the API;

image

If I pretend that the service had originally sent the client the text ‘the quick, brown fox jumps over the lazy dog’ then the client is now in a position to send back that text signed by the private key that belongs to the ‘Passport’;

I’d imagine that the service might want to ask for a signature of something more ‘unique’ and ‘time sensitive’ than my piece of text here about foxes and dogs Smile

How would the service then verify that this has been signed by that private key given that it would now have access to the original data, the signed data and the public key?

Without getting into having to write a service, I can replicate how that might happen by adding another button to my UI to invoke signature verification;

      <Button
        Grid.Row="3"
        HorizontalAlignment="Right"
        Content="Verify Signature"
        IsEnabled="{Binding CanVerifySignature}">
        <b:Interaction.Behaviors>
          <bc:EventTriggerBehavior
            EventName="Click">
            <bc:CallMethodAction
              TargetObject="{Binding}"
              MethodName="VerifySignature" />
          </bc:EventTriggerBehavior>
        </b:Interaction.Behaviors>
      </Button>

and then I can add some code to my code-behind in order to attempt to verify that signature using only the information that the service would have, namely;

  • the public key
  • the original text (which the service sent to the client)
  • the signature (which the client would send to the service)

and the service would more than likely not be using WinRT APIs so would end up with different code to what I will write here in my ‘client-side, WinRT simulation’ of the process but here’s how I am trying to do it – again, I’m listing only the code-behind modifications/additions with NEW comments;

    public string SignatureText
    {
      get
      {
        return (this.signatureText);
      }
      set
      {
        if (this.signatureText != value)
        {
          this.signatureText = value;
          this.RaisePropertyChanged();

          // NEW!
          this.RaisePropertyChanged("CanVerifySignature");
        }
      }
    }
    // NEW from here on.
    public bool CanVerifySignature
    {
      get
      {
        return (!string.IsNullOrEmpty(this.SignatureText));
      }
    }
    public void VerifySignature()
    {
      // not 100% sure that I have this algorithm right, needs more checking.
      var algorithm = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(
        AsymmetricAlgorithmNames.RsaSignPkcs1Sha256);

      // the original data, pulled from the textbox on screen
      var textBuffer = CryptographicBuffer.ConvertStringToBinary(
        this.TextToSign, BinaryStringEncoding.Utf8);

      // the signature data, pulled from the textbox on screen
      var signatureBuffer = CryptographicBuffer.DecodeFromHexString(
        this.SignatureText);

      // the public key, pulled from the textbox on screen
      var keyBuffer = CryptographicBuffer.DecodeFromHexString(
        this.PassportPublicKey);

      var cryptoKey = algorithm.ImportPublicKey(keyBuffer);

      var verified = 
        CryptographicEngine.VerifySignature(cryptoKey, textBuffer, signatureBuffer);

      ShowDialogAsync(
        $"The signature verification result was {verified}",
        "Signature Verification");
    }

and that seems to verify a correct signature and fail an incorrect one;

image

Prove to a Service that the Private Component of a ‘Passport’ has been Suitably Accessed

At this point, the service knows that the client has the private portion of the ‘Passport’ that it has stored as being associated with that user on that device.

What the service doesn’t ‘know’ is how that private portion is being managed – i.e. is it being secured by hardware like a TPM chip and, if so, is that a TPM chip that the service thinks that it can trust?

Or…has the private portion been exported and is being stored on a USB key or similar?

How can the service decide? The process is known as ‘TPM key attestation’ and you can read up on it on Technet here;

TPM Key Attestation

Again, I claim no expertise whatsoever here but this means that the TPM chip can then provide ‘proof’ to a service that it is managing the ‘Passport’ in question and that ultimately means doing some more signing by a certificate that’s on the chip and part of a certificate chain that the service is willing to trust.

The API calls that I’ve made so far to ask for attestation seem to return ‘NotSupported’ and back in this article;

Microsoft Passport Guide

there is a comment that a future feature would be to add;

“TPM attestation to protect keys so that a malicious user or program can’t create keys in software (because those keys won’t be TPM attested and can thus be identified as fake)

so perhaps that’s why my API calls are coming back with ‘NotSupported’ for the moment.

Wrapping Up, Code

I learned quite a lot while writing this post. If you want the code that I played with above then it’s linked here but remember that this was put together quickly for my experimentation.