AzureAD / azure-activedirectory-identitymodel-extensions-for-dotnet

IdentityModel extensions for .Net
MIT License
1.06k stars 401 forks source link

[Feature request / Design proposal] Allow EcdhKeyExchangeProvider to be extensible like the other security providers #2731

Open GregDomzalski opened 3 months ago

GregDomzalski commented 3 months ago

Summary

Microsoft.IdentityModel.Tokens should expose extension points for custom EcdhKeyExchangeProvider implementations where the private key may not be available in memory. Providing these extensions would bring EcdhKeyExchangeProvider in line with the other cryptographic providers within the library.

Motivation and goals

The Microsoft.IdentityModel.Tokens library provides the ability for consumers to provide custom SecurityKey implementations and cryptographic providers. This is useful when one wants (or needs) to store private key material in a way that is otherwise inaccessible to the built-in .NET cryptographic libraries. This could be a key exposed through a 3rd party crypto library such as BouncyCastle, a secrets manager such as 1Password (or an SSH agent), or on a hardware backed device such as an HSM.

Yubico (CC: @JamieHankins @aafortner) is collaborating with a sister-team within Entra ID that requires the use of the ECDH functionality within the Microsoft.IdentityModel.Tokens library. One set of private keys used for key agreement is stored on Yubico's YubiHSM product. These are private keys are never available to the host computer that is executing the Microsoft.IdentityModel.Tokens library. This also implies that the actual ECDH key agreement operation must be performed on the YubiHSM.

The current implementation of EcdhKeyExchangeProvider is currently not extensible. There are no override-able methods like there are on other *Provider classes. The current implementation also assumes in-memory access to the private key which may not always be available in the case of custom implementations.

This feature would allow for custom implementations of EcdhKeyExchangeProvider in a similar manner to how other providers (e.g. SignatureProvider) allow for extension.

A possible implementation has been created here: YubicoLabs azure-activedirectory-identitymodel-extensions-for-dotnet:ecdh-keyexchange-provider

In scope

Out of scope

Risks / unknowns

Examples

Extending EcdhKeyExchangeProvider:

public class MyProvider : EcdhKeyExchangeProvider
{
    private IKeyStore _keyStore;
    private ICustomKey _myKey;

    public MyProvider(
        IKeyStore keyStore, // Representation of the out-of-band crypto
        SecurityKey privateKey,
        SecurityKey publicKey,
        string alg,
        string enc) :
        base(
            keyStore.GetByKeyId(privateKey.KeyId),
            publicKey,
            alg,
            enc)
    {
        _keyStore = keyStore;
        _myKey = keyStore.GetByKeyId(privateKey.keyId);
    }

    public override byte[] DeriveKeyFromHash(
        ECDiffieHellmanPublicKey otherPartyPublicKey,
        HashAlgorithmName hashAlgorithm,
        byte[] prepend,
        byte[] append)
    {
        byte[] keyAgreement = _keyStore.EcdhKeyAgreement(_myKey, otherPartyPublicKey);
        return _keyStore.Hash(hashAlgorithm, [prepend, keyAgreement, append]);
    }
}
brentschmaltz commented 3 months ago

@GregDomzalski @jennyf19 i think the overall this feature makes sense.

GregDomzalski commented 3 months ago

@brentschmaltz @jennyf19 Great! Would you like me to add the next level of detail mentioned in the issue template for feature requests? Or should we open the PR and go through any feedback there?