Open Closed

How to add encryption key in OpenIdDict JWKS URL? #4679


User avatar
0
nhontran created

Hi, our application needs to expose an encryption key in JWKS URL for the other party using it to encrypt their data before returning to us, and we have implemented it in IdentityServer, below is how the JWKS URL response look like:

{
  "keys": [
    {
      "kty": "EC",
      "use": "sig",
      "kid": "esj_keyid",
      "alg": "ES256",
      "x": "nLrNw5uYtDmFjCTk0wOlukLil3gJyCEYYl5Seat0AXM",
      "y": "OIgBQXQFSdvmnOFa59MTQyHhyy6t17yNIbbOFKJdQTw",
      "crv": "P-256"
    },
    {
      "kty": "EC",
      "use": "enc",
      "kid": "6HFIeNOix6zxe2En3bjhZJBX78OY0IG8u1KU41HeNoU",
      "alg": "ECDH-ES+A192KW",
      "x": "nLrNw5uYtDmFjCTk0wOlukLil3gJyCEYYl5Seat0AXM",
      "y": "OIgBQXQFSdvmnOFa59MTQyHhyy6t17yNIbbOFKJdQTw",
      "crv": "P-256"
    }
  ]
}

I tried the code below, but it did not succeed in OpenIdDict:

    PreConfigure< OpenIddictServerBuilder >(builder =>
    {
        // get ECDSA certificate
        var ecdsaCertificate = CertificateHelper.GetCertificate(configuration["Key:ThumbPrint"]);
        ECDsaSecurityKey ecdsaCertificatePublicKey = new ECDsaSecurityKey(ecdsaCertificate.GetECDsaPrivateKey());
        
        // add signing key
        builder.AddSigningKey(new ECDsaSecurityKey(ecdsaCertificate.GetECDsaPrivateKey()));
        
        // add encryption credentials
        var encryptionKey = JsonWebKeyConverter.ConvertFromECDsaSecurityKey(ecdsaCertificatePublicKey);
        encryptionKey.KeyId = "encryption_key_id";
        encryptionKey.Use = JsonWebKeyUseNames.Enc;
        builder.AddEncryptionCredentials(new EncryptingCredentials(encryptionKey, SecurityAlgorithms.EcdsaSha256, "ECDH-ES+A192KW"));
    });

Any idea how to do it?


17 Answer(s)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    Did you add PreConfigure<OpenIddictServerBuilder> code on PreConfigureServices method?

    What is the result of JWKS URL after your code is added?

  • User Avatar
    0
    nhontran created

    Hi, yes, I did add the PreConfigure<OpenIddictServerBuilder>

    Below is the result of JWKS URL, it contains the signing key only:

    {
      "keys": [
        {
          "kid": "NLRNW5UYTDMFJCTK0WOLUKLIL3GJYCEYYL5SEAT0",
          "use": "sig",
          "kty": "EC",
          "alg": "ES256",
          "crv": "P-256",
          "x": "nLrNw5uYtDmFjCTk0wOlukLil3gJyCEYYl5Seat0AXM",
          "y": "OIgBQXQFSdvmnOFa59MTQyHhyy6t17yNIbbOFKJdQTw"
        }
      ]
    }
    
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    Can you try to set AddDevelopmentEncryptionAndSigningCertificate to false?

    
    public override void PreConfigureServices(ServiceConfigurationContext context)
    {
        PreConfigure<AbpOpenIddictAspNetCoreOptions>(options =>
        {
            options.AddDevelopmentEncryptionAndSigningCertificate = false;
        });
    }
    
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    if still not working, Please share the full code to reproduce. Thanks

  • User Avatar
    0
    nhontran created

    Hi, I did disable the development cert, below is my full PreConfigureServices:

    public override void PreConfigureServices(ServiceConfigurationContext context)
    {
        var environment = context.Services.GetHostingEnvironment();
        var configuration = context.Services.GetConfiguration();
    
        PreConfigure<OpenIddictBuilder>(builder =>
        {
            builder.AddValidation(options =>
            {
                options.AddAudiences("DigitalPlatform");
                options.UseLocalServer();
                options.UseAspNetCore();
            });
        });
    
        // disable developer signing credential
        PreConfigure<AbpOpenIddictAspNetCoreOptions>(options =>
        {
            options.AddDevelopmentEncryptionAndSigningCertificate = false;
        });
    
        PreConfigure<OpenIddictServerBuilder>(builder =>
        {
            // get ECDSA certificate
            var ecdsaCertificate = CertificateHelper.GetClientCertificate(configuration["Key:ThumbPrint"]);
            ECDsaSecurityKey ecdsaCertificatePublicKey = new ECDsaSecurityKey(ecdsaCertificate.GetECDsaPrivateKey());
    
            // add signing key
            builder.AddSigningKey(new ECDsaSecurityKey(ecdsaCertificate.GetECDsaPrivateKey()));
    
            // add encryption credentials
            var encryptionKey = JsonWebKeyConverter.ConvertFromECDsaSecurityKey(ecdsaCertificatePublicKey);
            encryptionKey.KeyId = "encryption_key_id";
            encryptionKey.Use = JsonWebKeyUseNames.Enc;
            builder.AddEncryptionCredentials(new EncryptingCredentials(encryptionKey, SecurityAlgorithms.EcdsaSha256, "ECDH-ES+A192KW"));
        });
    
        PreConfigure<IdentityBuilder>(builder =>
        {
            builder.AddSignInManager<CustomSignInManager>();
        });
    }
    
  • User Avatar
    0
    nhontran created

    Hi @maliming, ok, let me share the full code to you.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    Thanks you can create a new template project. liming.ma@volosoft.com

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    and you can try to use AddSigningCertificate instead of AddEncryptionCredentials

  • User Avatar
    0
    nhontran created

    Hi @maliming, I have provided the source code via email, I also attached the ECDSA cert that we use for testing.

    I tried AddSigningCertificate, it does not work with ECDSA cert.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    OK

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi nhontran

    The .well-known/jwks endpoint only AttachSigningKeys.

    https://github.com/openiddict/openiddict-core/blob/dev/src/OpenIddict.Server/OpenIddictServerHandlers.Discovery.cs#L1069

  • User Avatar
    0
    nhontran created

    Hi @maliming, is there a way to override the handler?

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    You can refer to its document

    https://documentation.openiddict.com/guides/index.html#events-model

    https://github.com/abpframework/abp/blob/dev/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictAspNetCoreModule.cs#L119 https://github.com/abpframework/abp/blob/dev/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/WildcardDomains/AbpValidateAuthorizedParty.cs

  • User Avatar
    0
    nhontran created

    Hi @maliming, thanks, I managed to add the encryption key into JWKS URL but I got the below error when using Angular UI to login to retrieve the access token:

    [09:54:04 DBG] An exception was thrown by OpenIddict.Server.OpenIddictServerHandlers+Protection+GenerateIdentityModelToken while handling the OpenIddict.Server.OpenIddictServerEvents+GenerateTokenContext event.
    System.ArgumentNullException: IDX10000: The parameter 'privateKey' cannot be a 'null' or an empty object.  (Parameter 'privateKey')
       at Microsoft.IdentityModel.Tokens.EcdhKeyExchangeProvider..ctor(SecurityKey privateKey, SecurityKey publicKey, String alg, String enc)
    

    Even the security key I put into EncryptingCredentials already had the private key, I have provided you the source code through email, able to help us check?

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    These are some algorithm/encryption things that I don't quite understand.

  • User Avatar
    0
    nhontran created

    Hi, what I want to achieve is instead of using RSA key, I want to use ECDSA key for signing credentials and encryption credentials. I find this is supported by OpenIddict in their documentation:

    Encryption and signing credentials
    To protect the tokens it issues, OpenIddict uses 2 types of credentials:
    
    Signing credentials are used to protect against tampering. They can be either asymmetric (e.g a RSA or ECDSA key) or symmetric.
    Encryption credentials are used to ensure the content of tokens cannot be read by malicious parties. They can be either asymmetric (e.g a RSA key) or symmetric.
    

    but don't know why keep getting this error:

    [09:54:04 DBG] An exception was thrown by OpenIddict.Server.OpenIddictServerHandlers+Protection+GenerateIdentityModelToken while handling the OpenIddict.Server.OpenIddictServerEvents+GenerateTokenContext event.
    System.ArgumentNullException: IDX10000: The parameter 'privateKey' cannot be a 'null' or an empty object.  (Parameter 'privateKey')
       at Microsoft.IdentityModel.Tokens.EcdhKeyExchangeProvider..ctor(SecurityKey privateKey, SecurityKey publicKey, String alg, String enc)
    

    Is there any sample code using ECDSA key instead of RSA key?

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    It seems the identitymodel doesn't support the ECDSA .

    Openiddict uses identitymodel inside.

    https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/1291#issuecomment-1063205019

Made with ❤️ on ABP v9.1.0-preview. Updated on November 01, 2024, 05:35