This is an attempt to cover the implementation choices and consideration for the Windows implementation of Custodian. I will actively avoid talking about the use-cases, goals and motivation here and leave that for a future me to write about.
CNG is Microsofts Win32 cryptography system API, it supersedes CryptoAPI, which is now deprecated (mostly).
Everything starts with KSPs, Key Storage Providers, there are three important ones: Software, TPM and Smart Card. The subsequent API is the same for all providers.
There are some issues that come with the nature of KSPs:
- they are almost like drivers, there might be other unexpected KSPs depending on connected and installed devices
- they don’t behave the same, return undocumented error codes or don’t work at all
- some use-cases aren’t covered well because they would only apply to one of those devices (e.g. PINs for smart cards, attestation for TPMs, passwords for keychains)
After you open a KSP, you can get and store asymmetric key pairs with an algorithm of your choosing. After acquiring access to a key, you can use it to sign a message, without ever gaining direct access to the underlying private key.
This can be directly used in mutual TLS for example, to authenticate a user through the client certificate. This way, what you really authenticate, is the device, that stores the private key, which is perfect for session endurance, because the idea of session endurance is that it is device specific.
The private key can’t be stolen or exported, it can also not be migrated or backed up, which is okay if the goal is only session endurance. I will talk about this more in detail in a future devlog.
Microsoft software KSP is an acceptable backup, it should be noted that it isn’t fool proof and an attacker could gain access to the stored key.
Some interesting notes about implementation details and possible extraction: DPAPI Secrets. Security analysis and data recovery in DPAPI.
To handle client certificates, we need to access the OS certificate store and let the user select a certificate that they want to use. The private key of that certificate can still be backed by a TPM or security key. CNG doesn’t have support for this at all.
This isn’t necessary for session persistence, for those raw key pairs are used, that the user doesn’t manage himself and aren’t actually valid X.509 certificates.
TPM and security key attestation can be done through CNG, there are some details that can’t though (or at least I wasn’t able to, yet). Attestation offers some challenges to privacy and security.
We need to make sure we aren’t collecting any uniquely identifying data, which should be prevented by the device itself.
Additionally we will have to make sure that our root certificates that we attest against are up-to-date, I still have to do a lot of research in this area.
I will talk more about the need for attestation in a future devlog.
CNGs API doesn’t offer support for all available algorithms on a TPM or security key. ECDSA and RSA are supported, which is mainly what we are looking for. EdDSA would be great though.
I spent some time thinking about symmetric algorithms, but in the end I don’t believe we will need them at all.
CNG doesn’t handle biometrics at all, unless your KSP does for you, for example in a fingerprint-enabled security key. This probably has quiet low priority, because most users use Windows Hello for biometrics on Windows.
This is definitely something we want to support, it is the most straightforward and widespread use of security keys for authorization.
Devices usually have a very reliable and correct implementation of their corresponding standards compared to the inter-op with CNG, in the case of TPMs this is TCGs TSS and in the case of security keys this is PC/SC.
This is the aforementioned deprecated API, it isn’t actually deprecated, just most of its API dealing directly with providers is, in favor of CNG. This API is fully compatible with CNG and quiet straightforward to use. We will only use this to communicate with the client certificate store.
Microsoft offers a TSS standard interface to access TPMs directly. This allows us to communicate with raw commands directly and hopefully the device will follow that standard more reliably then CNGs interface.
It looks quiet daunting to send byte encoded commands around, but I did some successful attempts that turned out be quiet feasible.
Apparently some settings in Windows can disable access to this API without administrator privileges, which might limit it’s use.
This is just the name of the API header file, but I couldn’t find an official one. This is Microsofts PC/SC implementation. PC/SC is a standard for security keys, like with TBS this API allows you to send direct command, it is a bit simpler though, additionally there is a cross-platform Rust implementation already: pcsc | crates.io.
This is probably the same API that Windows Hello is using under the hood. I didn’t do too much research into it, but as mentioned above, we might want to opt-out for Windows Hello here and be done with it, for now.
Potentially, in the case of security keys, one could directly communicate through USB HID, I didn’t look into this in detail, but Rust CTAP implementations do this (crap-hid-fido2 | crates.io).
Microsoft actually has an undocumented WebAuthn documentation that is already being used in Firefox: GitHub - microsoft/webauthn: Win32 APIs for WebAuthN standard.
This uses Windows Hello under the hood, I’m not aware of the implementation details, but through my testing I discovered that it offers much more powerful interactions and checks that aren’t possible with the UWP API of Windows Hello.
The initial implementation will tackle Software, TPM and Smart Card backed asymmetric keys that we will use for session endurance with the help of CNG. I will throw in secret storage because it’s very simple, but I’m not sure what we might use this for.
Additionally a simple API to select or generate a client certificate with CryptoAPI and CNG backed keys will be present.
Initially I planned to use the direct USB HID implementation of CTAP used by Firefox (authenticator | crates.io), but after discovering Microsofts undocumented API and how simple it is, this will be in there too right from the start.
Next time I will talk about the UWP implementation and other issues I didn’t cover here.
After completing the Windows implementation I will make a post about our original motivation, details and goals of this project (probably I should have started with that, but I mostly covered it in Mays Rustlang Gamedev Meetup).
CNG (Cryptography API: Next Generation): Cryptography API: Next Generation - Win32 apps | Microsoft Docs
CryptoAPI: CryptoAPI System Architecture - Win32 apps | Microsoft Docs
TBS (TPM Base Services): TPM Base Services - Win32 apps | Microsoft Docs
TGC TSS: TPM 2.0 Library | Trusted Computing Group
Winscard: Winscard.h header - Win32 apps | Microsoft Docs
PC/SC: PC/SC Workgroup Specifications Overview – PC/SC Workgroup
Windows Biometric Framework API: Windows Biometric Framework API Reference - Win32 apps | Microsoft Docs
WebAuthn: Web Authentication: An API for accessing Public Key Credentials - Level 2