public async Task <IActionResult> RegisterPerson([FromBody] BiometricPersonDataDto biometricPersonData) { byte[] imageContent = null; _logger.LogIfDebug(() => $"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey}, {biometricPersonData.Images?.Count ?? -1} {nameof(biometricPersonData.Images)}"); Contract.Requires(biometricPersonData != null, nameof(biometricPersonData)); Contract.Requires(biometricPersonData.Images != null, $"{nameof(biometricPersonData)}.{nameof(biometricPersonData.Images)}"); Contract.Requires(biometricPersonData.Images.Count > 0, $"Count {nameof(biometricPersonData)}.{nameof(biometricPersonData.Images)} > 0"); foreach (var image in biometricPersonData.Images) { _logger.LogIfDebug(() => $"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey}, {nameof(image.Key)}={image.Key}, image length: {image.Value?.Length ?? -1}"); } TaskCompletionSource <InherenceData> taskCompletionSource = _inherenceService.GetIdentityProofsAwaiter(biometricPersonData.SessionKey); InherenceData inherenceData; if (taskCompletionSource.Task.IsCompleted) { inherenceData = taskCompletionSource.Task.Result; } else { try { inherenceData = await taskCompletionSource.Task.TimeoutAfter(30000).ConfigureAwait(false); } catch (TimeoutException ex) { _logger.Error($"[{_inherenceService.AccountId}]: Identity Proofs not received for the SessionKey {biometricPersonData.SessionKey}", ex); return(BadRequest("Identity Proofs not received")); } catch (Exception ex) { _logger.Error($"[{_inherenceService.AccountId}]: Identity Proofs failed", ex); return(BadRequest($"Identity Proofs failed: {ex.Message}")); } finally { _inherenceService.RemoveIdentityProofsAwaiter(biometricPersonData.SessionKey); } } _inherenceService.RemoveIdentityProofsAwaiter(biometricPersonData.SessionKey); if (inherenceData == null) { _logger.Error($"[{_inherenceService.AccountId}]: Identity Proofs failed for {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey}"); return(BadRequest("Identity Proofs failed")); } _logger.LogIfDebug(() => $"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, {nameof(InherenceData)} with {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey} obtained"); string registrationKey = inherenceData.RootRegistrationProof.AssetCommitments[0].ToHexString(); _logger.LogIfDebug(() => $"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, root commitment is {inherenceData.AssetRootCommitment.ToHexString()} and registration key is {registrationKey} for {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey} obtained"); string personGroupId = _portalConfiguration.DemoMode ? _portalConfiguration.FacePersonGroupId.ToLower() : inherenceData.Issuer.ToHexString().ToLower(); string commitmentToRoot = inherenceData.AssetRootCommitment.ToHexString(); if (!ConfidentialAssetsHelper.VerifySurjectionProof(inherenceData.RootRegistrationProof, inherenceData.AssetRootCommitment)) { _logger.Error($"[{_inherenceService.AccountId}]: Registration Proofs failed for {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey}"); throw new InherenceRegistrationProofsIncorrectException(); } if (inherenceData.AssociatedRootCommitment != null) { //============================================================================= // In the case when AssociatedRootCommitment is not null one of the following scenarios can occur: // 1. The user already has Root Inherence Protection attribute - in this case // image provided for registration must be checked for compliance with the existing factor // 2. The user does not have yet Root Protection attribute - in this case user must provide two images, // one for the Root Inherence protection attribute and the second for associated one. // Both images must be checked for matching and then two attributes will be created. //============================================================================= _logger.LogIfDebug(() => $"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, {nameof(InherenceData)} with {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey} contains {nameof(inherenceData.AssociatedRootCommitment)}"); byte[] commitment = ConfidentialAssetsHelper.SumCommitments(inherenceData.AssetRootCommitment, inherenceData.AssociatedRootCommitment); if (!ConfidentialAssetsHelper.VerifySurjectionProof(inherenceData.AssociatedRegistrationProof, commitment)) { _logger.Error($"[{_inherenceService.AccountId}]: {nameof(inherenceData.AssociatedRegistrationProof)} failed for {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey}"); return(BadRequest(Resources.ERR_INHERENCE_REGISTRATION_PROOFS_INCORRECT)); } string commitmentToAssociated = inherenceData.AssociatedRootCommitment.ToHexString(); string associatedRegistrationKey = inherenceData.AssociatedRegistrationProof.AssetCommitments[0].ToHexString(); _logger.LogIfDebug(() => $"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, associated commitment is {commitmentToAssociated} and registration key is {associatedRegistrationKey} for {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey} obtained"); if (!biometricPersonData.Images.ContainsKey(commitmentToAssociated)) { _logger.Error($"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, no image found for the associated commitment {commitmentToAssociated}"); return(BadRequest($"No image found for the associated commitment {commitmentToAssociated}")); } Guid rootRegistrationGuid = await GetPersonRegistrationGuid(personGroupId, registrationKey).ConfigureAwait(false); if (Guid.Empty.Equals(rootRegistrationGuid)) { _logger.LogIfDebug(() => $"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, No root registration found for {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey}"); if (!biometricPersonData.Images.ContainsKey(commitmentToRoot)) { _logger.Error($"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, no image found for the root commitment {commitmentToRoot}"); return(BadRequest($"No image found for the root commitment {commitmentToRoot}")); } imageContent = biometricPersonData.Images[commitmentToRoot]; byte[] faceAssociated = biometricPersonData.Images[commitmentToAssociated]; bool matches = await _facesService.VerifyFaces(imageContent, faceAssociated).ConfigureAwait(false); if (!matches) { _logger.Error($"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, faces do not match for {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey}"); return(BadRequest("Provided face images do not match one to another")); } PersonFaceData rootFaceData = new PersonFaceData { PersonGroupId = personGroupId, Name = registrationKey, UserData = registrationKey, ImageContent = imageContent }; _logger.LogIfDebug(() => $"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, adding root registration {registrationKey} for {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey}"); await AddPerson(rootFaceData).ConfigureAwait(false); registrationKey = inherenceData.AssociatedRegistrationProof.AssetCommitments[0].ToHexString(); imageContent = faceAssociated; _logger.LogIfDebug(() => $"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, proceeding with associated registration {registrationKey} for {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey}"); } else { _logger.LogIfDebug(() => $"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, Root registration with key {registrationKey} found for {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey}"); registrationKey = inherenceData.AssociatedRegistrationProof.AssetCommitments[0].ToHexString(); imageContent = biometricPersonData.Images.ContainsKey(commitmentToAssociated) ? biometricPersonData.Images[commitmentToAssociated] : null; bool isIdentical = await VerifyPersonFace(personGroupId, rootRegistrationGuid, imageContent).ConfigureAwait(false); if (!isIdentical) { _logger.Error($"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, face do not match to registered one for {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey}"); throw new InherenceCrossMatchingFailedException(inherenceData.RootRegistrationProof.AssetCommitments[0].ToHexString()); } _logger.LogIfDebug(() => $"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, proceeding with associated registration {registrationKey} for {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey}"); } } else { _logger.LogIfDebug(() => $"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, {nameof(InherenceData)} with {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey} does not contain {nameof(inherenceData.AssociatedRootCommitment)}"); if (!biometricPersonData.Images.ContainsKey(commitmentToRoot)) { _logger.Error($"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, no image found for the root commitment {commitmentToRoot}"); return(BadRequest($"No image found for the root commitment {commitmentToRoot}")); } imageContent = biometricPersonData.Images[commitmentToRoot]; } Guid guid = _dataAccessService.FindPersonGuid(registrationKey); PersonFaceData personFaceData = new PersonFaceData { PersonGroupId = personGroupId, Name = registrationKey, UserData = registrationKey, ImageContent = imageContent }; try { if (guid == Guid.Empty) { _logger.LogIfDebug(() => $"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, adding registration {registrationKey} for {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey}"); await AddPerson(personFaceData).ConfigureAwait(false); } else { _logger.LogIfDebug(() => $"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, replacing registration {registrationKey} for {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey}"); await ReplacePerson(personFaceData).ConfigureAwait(false); } } catch (Exception ex) { if (ex is AggregateException aex) { _logger.Error($"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)} failed with aggregated exception", aex.InnerException); } else { _logger.Error($"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)} failed with exception", ex); } throw; } _logger.LogIfDebug(() => $"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, completed successfully for {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey}"); return(Ok()); }
private async Task CheckAssociatedProof(Memory <byte> rootCommitment, IEnumerable <AttributesByIssuer> associatedAttributes, string schemeName) { AttributesByIssuer associatedAttributesForCheck = associatedAttributes.FirstOrDefault(c => c.RootAttribute.SchemeName == schemeName || c.Attributes.Any(a => a.SchemeName == schemeName)); if (associatedAttributesForCheck == null) { throw new ValidationProofsWereNotCompleteException(schemeName); } //_logger.LogIfDebug(() => $"{nameof(CheckAssociatedProof)}: \r\n{nameof(rootCommitment)}={rootCommitment.ToHexString()}, \r\n{nameof(associatedRootAttribute)}={{0}}"); bool proofToRoot = ConfidentialAssetsHelper.VerifySurjectionProof(associatedAttributesForCheck.RootAttribute.BindingProof, rootCommitment.Span); if (!proofToRoot) { _logger.Error("Proof of binding to Root failed"); throw new ValidationProofFailedException(schemeName); } AttributeProofs attributeForCheck; if (schemeName == associatedAttributesForCheck.RootAttribute.SchemeName) { attributeForCheck = associatedAttributesForCheck.RootAttribute; if (attributeForCheck == null) { throw new ValidationProofsWereNotCompleteException(schemeName); } } else { attributeForCheck = associatedAttributesForCheck.Attributes.FirstOrDefault(a => a.SchemeName == schemeName); if (attributeForCheck == null) { throw new ValidationProofsWereNotCompleteException(schemeName); } // Check binding to the Root Attribute bool proofToAssociatedRoot = ConfidentialAssetsHelper.VerifySurjectionProof(attributeForCheck.BindingProof, associatedAttributesForCheck.RootAttribute.Commitment.Value.Span); if (!proofToAssociatedRoot) { _logger.Error("Proof of binding to Associated Root failed"); throw new ValidationProofFailedException(schemeName); } } if (attributeForCheck.CommitmentProof.Values?.Any() ?? false) { long schemeId = await _assetsService.GetSchemeId(schemeName, associatedAttributesForCheck.Issuer.ToString()).ConfigureAwait(false); byte[][] assetIds = attributeForCheck.CommitmentProof.Values.Select(v => _assetsService.GenerateAssetId(schemeId, v)).ToArray(); bool proofOfValue = ConfidentialAssetsHelper.VerifyIssuanceSurjectionProof(attributeForCheck.CommitmentProof.SurjectionProof, attributeForCheck.Commitment.Value.Span, assetIds); if (!proofOfValue) { _logger.Error("Proof of value failed"); throw new ValidationProofFailedException(schemeName); } } else { bool proofOfValueKnowledge = ConfidentialAssetsHelper.VerifySurjectionProof(attributeForCheck.CommitmentProof.SurjectionProof, attributeForCheck.Commitment.Value.Span); if (!proofOfValueKnowledge) { _logger.Error("Proof of value knowledge failed"); throw new ValidationProofFailedException(schemeName); } } }