diff --git a/FitConnect/Services/SubmissionService.cs b/FitConnect/Services/SubmissionService.cs index 8cfc982fc13feec37358189d204cb8b76b6f2af2..cf09fa93613852b954dc0ea4070e8ab1c69c9862 100644 --- a/FitConnect/Services/SubmissionService.cs +++ b/FitConnect/Services/SubmissionService.cs @@ -155,7 +155,7 @@ internal class SubmissionService : RestCallService, ISubmissionService { // Download well known keys var valid = await ValidateSignature(events); // TODO: Check JSON Schema - valid &= await ValidateSchema(events, false); + // valid &= await ValidateSchema(events, false); if (!valid) { _logger?.LogError("Invalid SET, signature can not be verified"); @@ -226,18 +226,12 @@ internal class SubmissionService : RestCallService, ISubmissionService { return valid; } - private async Task<bool> ValidateSignature(EventLogDto? events) { - // Load Key from GET {{submission_api_url}}/v1/destinations/{{destinationId}}/keys/{{keyId}} - var keyIds = GetKeyIdsFromEvent(events); + private async Task<bool> ValidateSignature(EventLogDto events) { + var keys = await GetJsonWebKeysForEvent(events); - var keySet = new JsonWebKeySet(await Router.GetSubmissionServiceValidationJwk(_baseUrl)); - var keys = _signatureValidationKey == null - ? keySet.Keys - : keySet.Keys.Append(_signatureValidationKey); - var valid = true; - foreach (var eventJson in events.EventLog) { - valid &= FitEncryption.VerifyJwt(eventJson, keys, logger: _logger); - } + var valid = events.EventLog?.Aggregate(true, + (current, eventJson) => + current & FitEncryption.VerifyJwt(eventJson, keys, logger: _logger)) ?? true; if (!valid) { _logger?.LogDebug("Signature is invalid"); @@ -248,8 +242,49 @@ internal class SubmissionService : RestCallService, ISubmissionService { return valid; } - private IEnumerable<JsonWebKey> GetKeyIdsFromEvent(EventLogDto events) { - return new List<JsonWebKey>(); + private async Task<IEnumerable<JsonWebKey>> GetJsonWebKeysForEvent(EventLogDto events) { + var keySet = new JsonWebKeySet(await Router.GetSubmissionServiceValidationJwk(_baseUrl)); + var keys = _signatureValidationKey == null + ? keySet.Keys + : keySet.Keys.Append(_signatureValidationKey); + + return (await GetKeyIdsFromEvent(events)).Union(keys); + } + + private async Task<IEnumerable<JsonWebKey>> GetKeyIdsFromEvent(EventLogDto events) { + if (events.EventLog == null) + return new List<JsonWebKey>(); + + // Load Key from GET {{submission_api_url}}/v1/destinations/{{destinationId}}/keys/{{keyId}} + var keyIds = events.EventLog.Select(ExtractSubmissionIdFromEvent).ToList(); + + var result = new List<JsonWebKey>(); + foreach (var (submission, keyId) in keyIds) { + try { + // TODO Get destinationId from submission + var destinationId = "aa3704d6-8bd7-4d40-a8af-501851f93934"; + var keyJson = await RestCallForString($"/destinations/{destinationId}/keys/{keyId}", + HttpMethod.Get); + result.Add(new JsonWebKey(keyJson)); + } + catch (Exception e) { + _logger?.LogWarning(e, "Error loading key {KeyId}", keyId); + } + } + + return result; + } + + private (string submissionId, string keyId) ExtractSubmissionIdFromEvent(string events) { + var jwtParts = events.Split('.').Select(Base64UrlEncoder.Decode).ToList(); + + var header = JsonConvert.DeserializeObject<Dictionary<string, object>>(jwtParts[0]); + var payload = JsonConvert.DeserializeObject<Dictionary<string, object>>(jwtParts[1]); + + var keyId = (string)header["kid"]; + var submissionId = ((string)payload["sub"]).Split(':')[1]; + + return (submissionId, keyId); } public async Task GetValidationJwk() {