Ejemplo n.º 1
0
        public static async Task <InitializationResult <AuthenticatedStream> > EstablishEncryptedCommunication(
            bool asServer,
            Guid serverGuid,
            IAuthenticatedConnectionFactory authenticatedConnectionFactory,
            Stream stream,
            CancellationToken token)
        {
            async Task <CommunicationResult <string> > NotifyRemotePartyAndValidateRemotePartySuccess(string message)
            {
                CommunicationResult <string> remoteResult;
                CommunicationResult          writeResult;

                if (asServer)
                {
                    remoteResult = await stream.ReceiveStringSafelyAsync(token);

                    writeResult = await stream.WriteSafelyAsync(message, token);
                }
                else
                {
                    writeResult = await stream.WriteSafelyAsync(message, token);

                    remoteResult = await stream.ReceiveStringSafelyAsync(token);
                }
                if (!writeResult.Successful && remoteResult.Successful)
                {
                    return(CommunicationResult <string> .From(writeResult));
                }
                return(remoteResult);
            }

            Task <CommunicationResult> NotifyRemoteParty(string message)
            {
                return(stream.WriteSafelyAsync(message, token));
            }

            AuthenticationResult authenticationResult;

            if (asServer)
            {
                authenticationResult = await authenticatedConnectionFactory.AuthenticateAsServerAsync(stream, token);
            }
            else
            {
                authenticationResult = await authenticatedConnectionFactory.AuthenticateAsClientAsync(stream, serverGuid, token);
            }

            var result = await authenticationResult.Match(
                async authenticated =>
            {
                var successfulInitResult = new InitializationResult
                {
                    Successful = true,
                };
                var remoteInitResult = await NotifyRemotePartyAndValidateRemotePartySuccess(JsonConvert.SerializeObject(successfulInitResult));
                if (remoteInitResult.Successful)
                {
                    var remoteInitializationResult = JsonConvert.DeserializeObject <InitializationResult>(remoteInitResult.Result);
                    if (remoteInitializationResult.Successful)
                    {
                        return(new InitializationResult <AuthenticatedStream>
                        {
                            Successful = true,
                            Result = authenticated.AuthenticatedStream,
                        });
                    }
                    else
                    {
                        var self   = asServer ? "server" : "client";
                        var remote = asServer ? "client" : "server";
                        return(new InitializationResult <AuthenticatedStream>
                        {
                            Successful = false,
                            Error = new InitializationError
                            {
                                ErrorType = InitializationErrorType.Authentication,
                                Message = $"The remote {remote} encountered a problem authentication this {self}. Their message: '{remoteInitializationResult.Error.Message}'",
                            },
                        });
                    }
                }
                else
                {
                    return(From <AuthenticatedStream>(remoteInitResult));
                }
            },
                async authenticationFailed =>
            {
                var failedInitResult = new InitializationResult
                {
                    Successful = false,
                    Error      = new InitializationError
                    {
                        ErrorType = InitializationErrorType.Authentication,
                        Message   = authenticationFailed.Exception.Message,
                    },
                };
                await NotifyRemoteParty(JsonConvert.SerializeObject(failedInitResult));
                return(InitializationResult <AuthenticatedStream> .From(failedInitResult));
            },
                async notSupported =>
            {
                var failedInitResult = new InitializationResult
                {
                    Successful = false,
                    Error      = new InitializationError
                    {
                        ErrorType = InitializationErrorType.Authentication,
                        Message   = notSupported.Exception.Message,
                    }
                };
                await NotifyRemoteParty(JsonConvert.SerializeObject(failedInitResult));
                return(InitializationResult <AuthenticatedStream> .From(failedInitResult));
            },
                taskCanceled =>
            {
                var failedInitResult = new InitializationResult <AuthenticatedStream>
                {
                    Successful = false,
                    Error      = new InitializationError
                    {
                        ErrorType = InitializationErrorType.CancellationRequested,
                    },
                };
                return(Task.FromResult(failedInitResult));
            });

            return(result);
        }
Ejemplo n.º 2
0
        public static async Task <InitializationResult> HandleInitializationOfClient(
            Stream clientStream,
            byte[] presharedKey,
            Guid serverGuid,
            IAuthenticatedConnectionFactory authenticatedConnectionFactory,
            ICryptographicService otp,
            Action <Guid, AuthenticatedStream> onClientConnected,
            Action <Guid, X509Certificate> onClientRegistered,
            Func <Guid, X509Certificate> getClientPublicKey,
            CancellationToken token)
        {
            token = token.AddTimeout(DefaultTimeout);
            if (token.IsCancellationRequested)
            {
                return(new InitializationResult
                {
                    Successful = false,
                    Error = new InitializationError
                    {
                        ErrorType = InitializationErrorType.CancellationRequested,
                    }
                });
            }
            if (!await GetAndVerifyPresharedKey(clientStream, presharedKey, token))
            {
                return(new InitializationResult
                {
                    Successful = false,
                    Error = new InitializationError
                    {
                        ErrorType = InitializationErrorType.Protocol,
                        Message = "The received pre-shared key did not match the pre-shared key for this application",
                    },
                });
            }
            await clientStream.WriteSafelyAsync(serverGuid, token);

            var clientGuidResult = await clientStream.ReceiveGuidSafelyAsync(token);

            if (!clientGuidResult.Successful)
            {
                return(InitializationResult.From(clientGuidResult));
            }
            var clientGuid           = clientGuidResult.Result;
            var initiationModeResult = await clientStream.ReceiveInt32SafelyAsync(token);

            if (!initiationModeResult.Successful)
            {
                return(InitializationResult.From(initiationModeResult));
            }
            switch ((InitiationMode)initiationModeResult.Result)
            {
            case InitiationMode.Otp:
                var clientRegistrationResult =
                    await HandleClientRegistrationSafelyAsync(clientStream, serverGuid, authenticatedConnectionFactory, otp, token);

                if (clientRegistrationResult.Successful)
                {
                    var(certificate, stream) = clientRegistrationResult.Result;
                    onClientRegistered(clientGuid, certificate);
                    onClientConnected(clientGuid, stream);
                }
                else
                {
                    return(clientRegistrationResult);
                }
                return(new InitializationResult
                {
                    Successful = true,
                });

            case InitiationMode.Standard:
                var clientCertificate = getClientPublicKey(clientGuid);
                if (clientCertificate == null)
                {
                    return(InitializationResult.Failed);
                }
                //var sessionKey = SymmetricKey.GenerateNewKey(symmetric.KeyLength);

                var encryptedStreamResult = await EstablishEncryptedCommunication(true, serverGuid, authenticatedConnectionFactory, clientStream, token);

                if (!encryptedStreamResult.Successful)
                {
                    return(encryptedStreamResult);
                }
                onClientConnected(clientGuid, encryptedStreamResult.Result);
                return(new InitializationResult
                {
                    Successful = true,
                });

            case InitiationMode.None:
                return(new InitializationResult()
                {
                    Successful = false,
                    Error = new InitializationError()
                    {
                        ErrorType = InitializationErrorType.Protocol,
                        Message = "Client did not send a valid initiation mode",
                    },
                });

            default:
                throw new ProtocolException($"invalid initiation mode {initiationModeResult.Result}");
            }
        }
Ejemplo n.º 3
0
 //private static TimeSpan DefaultTimeout = TimeSpan.FromMinutes(5);
 private static InitializationResult <TResult> From <TResult>(CommunicationResult result) =>
 InitializationResult <TResult> .From(InitializationResult.From(result));