decentralized-identity / did-common-dotnet

MIT License
17 stars 9 forks source link

Notes on cryptography implementation #6

Open veikkoeeva opened 3 years ago

veikkoeeva commented 3 years ago

This issue is for recording concerns and thoughts based on spike at https://github.com/decentralized-identity/did-common-dotnet/pull/4. Maybe this is a starting point for a discussion and eventually design guides recorded more permanently.

The case of cryptography in the spike of @veikkoeeva

The cryptographic goals of that spike were:

  1. Explore the interface between DIF data modes and protocol and how they could be interfaced in using .NET Core and .NET5/6.
  2. Explore if the framework exposes common extension points and how could they be used in this library.
  3. Come up with understanding if there are frameworks larger than .NET which could be used or adopted to have the benefit of mindshare and proven practice.
  4. Create one implementation so it's possible to move forwards in particular and expose implementation friction points in general.

It was assumed this would be a point of friction. It was assumed regulations, approval processed and such are so complicated that for uptake there needs to be flexibility on using approved libraries and methods.

For .NET result, it appears that Microsoft seem to like maintain a tight cryptographic chain and so consequently there are no extension points where new providers can plugged in .NET framework. The .NET cryptographic bits are in System.Security.Cryptography.

So the spike implementation used Microsoft.IdentityModel.Tokens (MIT) as the starting point to wrap Portable.BouncyCastle by @clairernovotny for EdDSA support that does not exist currently in .NET. This had the benefit of using one library from Microsoft that is somewhat widely in use and see how it operates.

The finding is that MIT separates key material into sepearate classes and a class hierarchy that separates symmetric and asymmetric key material and in their GitHub repository there are some examples showing how the key material could be used in Azure KeyVault (a HSM in Azure). The key extension point for new providers is ICryptoProvider that allows one to query with arbitrary string if certain cryptographic operation is supported, then to return an object (needs to be cast to expected type) that implements those operations and a method to signal the release of the returned object.

MIT tries to make a hard separation between public and private key material so that they do not accidentally end up in same type and consequently accidentally get leaked (e.g. serialized). While not apparently discussed, this separation makes it possible to limit the exposure to key material by either shortening the time it's exposed, by using OS protection or using it in a key vault.

As is System.Security.Cryptography fairly locked down and provides only OS supported cryptographic operations, so is Microsoft.IdentityModel.Tokens (MIT) but less so.

During this implementation GoDaddy published a .NET implementation Asherah, which is described as

Asherah is an application-layer encryption SDK, currently in incubator status, that provides advanced encryption features and defense in depth against compromise.

which sport a design for using OS protections for key materials and use of HSM. Also Solokeys, an open source hardware WebAuthn provider, had explored cryptographic provider space during this time and wrote a short post about this at in their Kickstarter campaign accnouncing a future low-level library. They also mention PKCS #11, WebCrypto and PARSEC.

Of these it would make sense to create a design that would allow Asherah or other such systems easily.

The way forward

On the subjective experience of @veikkoeeva it looks like the way forward is to have an interface something like ICryptoprovider to allow loading different providers and have them also mixed and matched. The .NET reference implementation can provide implementation(s) while it needs some to run tests effectively (e.g. Portable.BouncyCastle).

As there can be "all kinds of providers", there is a need for a simple wrapper for these with enough support to realize DIF use cases and ensuring that:

While the spike got merged before it was accomplished, a workable design could be just a simple function that takes an appropriate DID type (e.g. see in DidDocument) and a provider and the provider is used for signing, verifying and encryption (the provider may separate these operations). This may require for the core extension point to have a concept of releasing a loaded provider and caching it, like ICryptoProvider has.

This would make it easy to both add new operations and methods to Core when they appear to DID Core or as registered extensions, allow experimenting them when discussion about extensions to Core and registry and also substitute providers in use.

juanfranblanco commented 3 years ago

Great thoughts as usual @veikkoeeva and references.

Yes totally agree on ICryptoProvider as it was the original thought, following the Microsoft Identity interface pattern will allow for an easier mapping across. Not forgetting from a decentralized user perspective compatibility with Secp256k1 as it is widely used in DIDs https://www.nuget.org/packages/NBitcoin.Secp256k1/ and hardware wallets using https://github.com/MelbourneDeveloper/Device.Net