Example #1
0
        // The signing function _____________________________________________________________________

        internal async Task <bool> Sign(ProtectedTask task, Identity signingIdentity)
        {
            Approval approval = null;

            // Find signing provider
            var provider = signProviders
                           .FirstOrDefault(p => p.Contains(signingIdentity.AccountID));

            if (provider == null)
            {
                Trace($"No provider found for {signingIdentity}");
                return(false);
            }

            Trace($"Operation: {task.Operation}");

            // Fetch operation data to sign later.
            // This prevents tampering with the operation during approval
            var operationData = task.Operation.HexToByteArray();

            // Check validity of operation data
            // This protects against forgery due to a compromised node
            ValidateOperation(task, operationData);

            // Approval mechanism registered?
            if (ApprovalRequired != null)
            {
                approval = new Approval
                {
                    Task    = task,
                    Signer  = signingIdentity,
                    Timeout = ApprovalTimeout,
                };

                // Send approval to UI and wait for completion
                await ExecuteSynchronized(() =>
                {
                    ApprovalRequired(approval);
                });

WaitForUser:
                Trace("Wait for user decision");

                var userResult = await approval.GetUserResult();

                Trace($"Approval result: {userResult}");

                if (userResult != SigningResult.Approved)
                {
                    // Cancel or timeout
                    approval.Close(userResult);
                    return(false);
                }

                // Unlock identity if needed
                if (signingIdentity.IsLocked)
                {
                    if (!signingIdentity.Unlock(approval.Passphrase))
                    {
                        // Wrong credentials
                        approval.Retry(SigningResult.InvalidCredentials);

                        goto WaitForUser;
                    }
                }
            }

            // Sign
            Trace("Sign CreateRequest");

            var dataToHash = new byte[1 + operationData.Length];

            dataToHash[0] = 3;
            operationData.CopyTo(dataToHash, 1);

            var hashedData = CryptoServices.Hash(dataToHash, 32);

            if (await provider.Sign(signingIdentity.AccountID, hashedData, out byte[] signature))
            {
                // Success
                task.Signature = CryptoServices.EncodePrefixed(HashType.Signature, signature);

                using (var buffer = new MemoryStream())
                {
                    buffer.Write(operationData, 0, operationData.Length);
                    buffer.Write(signature, 0, signature.Length);

                    task.SignedOperation = buffer.ToArray().ToHexString();
                }

                approval?.Close(SigningResult.Signed);
                return(true);
            }