Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V1.Secrets.Transit.ReadEncryptionKeyAsync doesn't work for other than aes256-gcm96 key. #194

Closed
faddiv opened this issue Jun 10, 2021 · 6 comments
Assignees
Labels

Comments

@faddiv
Copy link

faddiv commented Jun 10, 2021

Describe the bug
V1.Secrets.Transit.ReadEncryptionKeyAsync doesn't work for other than aes256-gcm96 key.

VaultSharp Version
1.6.2.3

Vault Version
1.7.2

Does this work with Vault CLI?
Yes

Sample Code Snippet
public async Task<byte[]> GetEncryptionKey(string path)
{
var keyInfo = await _vaultClient.V1.Secrets.Transit.ReadEncryptionKeyAsync(path, mountPoint: "transit");
// ...
}

Exception Details/Stack Trace/Error Message
JsonSerializationException: Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Int64' because the type requires a JSON primitive value (e.g. string, number, boolean, null) to deserialize correctly. To fix this error either change the JSON to a JSON primitive value (e.g. string, number, boolean, null) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object. Path 'data.keys.1.creation_time', line 1, position 231.
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue)
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue)
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateDictionary(IDictionary dictionary, JsonReader reader, JsonDictionaryContract contract, JsonProperty containerProperty, string id)
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue)
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue)
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, object target)
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, string id)
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue)
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue)
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, object target)
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, string id)
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue)
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue)
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, bool checkAdditionalContent)
Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
Newtonsoft.Json.JsonSerializer.Deserialize(JsonReader reader, Type objectType)
Newtonsoft.Json.JsonConvert.DeserializeObject(string value, Type type, JsonSerializerSettings settings)
Newtonsoft.Json.JsonConvert.DeserializeObject(string value, JsonSerializerSettings settings)
Newtonsoft.Json.JsonConvert.DeserializeObject(string value)
VaultSharp.Core.Polymath.MakeRequestAsync(string resourcePath, HttpMethod httpMethod, object requestData, IDictionary<string, string> headers, bool rawResponse, Action postResponseAction)
VaultSharp.Core.Polymath.MakeVaultApiRequest(string resourcePath, HttpMethod httpMethod, object requestData, bool rawResponse, Action postResponseAction, string wrapTimeToLive, bool unauthenticated)
VaultSharp.Core.Polymath.MakeVaultApiRequest(string mountPoint, string path, HttpMethod httpMethod, object requestData, bool rawResponse, Action postResponseAction, string wrapTimeToLive, bool unauthenticated)
VaultSharp.V1.SecretsEngines.Transit.TransitSecretsEngineProvider.ReadEncryptionKeyAsync(string keyName, string mountPoint)
NewcomerKeyManagement.Services.HashiCorpVaultFacade.GetEncryptionKey(string path) in HashiCorpVaultFacade.cs
+
var keyInfo = await _vaultClient.V1.Secrets.Transit.ReadEncryptionKeyAsync(path, mountPoint: "transit");
NewcomerKeyManagement.Controllers.KeyProviderController.GetV2() in KeyProviderController.cs
+
var result2 = await _hashi.GetEncryptionKey("database_encryption_key");
lambda_method32(Closure , object )
Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor+TaskOfActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, object controller, object[] arguments)
System.Threading.Tasks.ValueTask.get_Result()
System.Runtime.CompilerServices.ValueTaskAwaiter.GetResult()
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask actionResultValueTask)
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

Any additional info
I use an rsa encryption key in the transit and as turns out it returns a slightly different response than it was described in the api documentation.
In the keys property there is a whole object instead of long number.
Here is an example:
{
"request_id": "ce091ea5-d5a8-de2a-9b23-ae46c7cfbf25",
"lease_id": "",
"renewable": false,
"lease_duration": 0,
"data": {
"allow_plaintext_backup": false,
"deletion_allowed": false,
"derived": false,
"exportable": false,
"keys": {
"1": {
"creation_time": "2021-06-10T14:36:45.189648723+02:00",
"name": "rsa-2048",
"public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8ZqGOG6CYms35FgR1QCA\nRd46zTZ7lV5e0BlXnWqag6p5S2TeX201o9HpUP1av/RZGw8APK6mR8LGZUcgn32b\neGSvEIe0hrEPplD+KOkBCd6jpZ0qkctfpFrd8NZoZ8hqw91k0Sxugg6aLr5htBsy\nZSd3velrihoGH0XJufnB+tzdeWIx+K78LFBW/TwFsWI5/Hzmf/FOyyZcsAmqNMNq\njZSyKHgTFE+qKNTODdzg3d+wrIdD2ox/Gm+0VSHf8r6C4jL+we72v/WT+cOEqUue\nBppWc+gHfJE0tYaDzLEhH74+O6msepoEwwpLCuBciNInr0wnn8v5FpViPdb8HNZh\nWwIDAQAB\n-----END PUBLIC KEY-----\n"
}
},
"latest_version": 1,
"min_available_version": 0,
"min_decryption_version": 1,
"min_encryption_version": 0,
"name": "t2",
"supports_decryption": true,
"supports_derivation": false,
"supports_encryption": true,
"supports_signing": true,
"type": "rsa-2048"
},
"wrap_info": null,
"warnings": null,
"auth": null
}

I would like to offer my help to fix this. (And explore all the possible response of this query.)
If I can help then I would like a guidenance about how should I modify the EncryptionKeyInfo class.
(The property in question: public Dictionary<string, long> Keys { get; set; } )

@rajanadar rajanadar self-assigned this Jun 11, 2021
@rajanadar rajanadar added the bug label Jun 11, 2021
@rajanadar
Copy link
Owner

I'll have a look this weekend.

@rajanadar
Copy link
Owner

You did 90% of the work already with a nice bug description and root cause @faddiv

The response is pretty dynamic based on the type of key. So the value-datatype of the Dictionary cannot be long. It can be anything and hence I switched it to a Object. (so that it can deserialize primitive values as well as dictionaries etc.)

@rajanadar
Copy link
Owner

Will publish a version in a couple of days.

rajanadar added a commit that referenced this issue Jun 13, 2021
@rajanadar
Copy link
Owner

@faddiv This should have your fix. https://www.nuget.org/packages/VaultSharp/1.6.2.4

@faddiv
Copy link
Author

faddiv commented Jun 14, 2021

Thank you. It's working.
One more thing that should be exposed here: "latest_version"
That could help grabbing the latest key.

rajanadar added a commit that referenced this issue Jun 15, 2021
@rajanadar
Copy link
Owner

@faddiv

Makes sense. Exposed both latest version and min version fields. Please use https://www.nuget.org/packages/VaultSharp/1.6.2.5

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants