private void Authenticate() { Debug.Assert(Monitor.IsEntered(Gate)); var credentials = _clientSettings.Credentials; if (credentials == null || credentials.Count == 0) { credentials = GetDefaultCredentials(); } bool ignoreErrors = credentials.Count > 1; while (true) { int credentialIndex = _authState.CredentialIndex; if (credentialIndex >= credentials.Count) { CompleteConnectStep(new SshSessionException("Client authentication failed.")); return; } Credential credential = credentials[credentialIndex]; string?errorMessage = null; CredentialAuthResult result = credential switch { PrivateKeyFileCredential ifc => Authenticate(ifc, ignoreErrors, out errorMessage), _ => throw new IndexOutOfRangeException($"Unexpected credential type: {credential.GetType().FullName}") }; if (result != CredentialAuthResult.Again) { _authState.Reset(); } if (result == CredentialAuthResult.Success) { _state = SessionState.Connected; CompleteConnectStep(null); return; } else if (result == CredentialAuthResult.Error) { CompleteConnectStep(new SshSessionException(errorMessage ?? ssh_get_error(_ssh))); return; } else if (result == CredentialAuthResult.NextCredential) { _authState.CredentialIndex = credentialIndex + 1; } else { Debug.Assert(result == CredentialAuthResult.Again); return; } } }
private CredentialAuthResult Authenticate(PrivateKeyFileCredential credential, bool ignoreErrors, out string?errorMessage) { errorMessage = null; string privateKeyFile = credential.FileName; if (_authState.Step == AuthStep.Initial) { Debug.Assert(_authState.PublicKey == null); Debug.Assert(_authState.PrivateKey == null); string publicKeyFile = $"{privateKeyFile}.pub"; int rv = ssh_pki_import_pubkey_file(publicKeyFile, out _authState.PublicKey); if (rv == SSH_ERROR) { return(CredentialAuthResult.NextCredential); } else if (rv == SSH_EOF) // File not found. { // TODO: Read the private key and save the public key to file if (!ignoreErrors) { errorMessage = $"Failed to read public key file: {publicKeyFile}."; return(CredentialAuthResult.Error); } return(CredentialAuthResult.NextCredential); } Debug.Assert(rv == SSH_OK); _authState.Step = AuthStep.IdentityFileKeyImported; } if (_authState.Step == AuthStep.IdentityFileKeyImported) { AuthResult rv = ssh_userauth_try_publickey(_ssh, null, _authState.PublicKey !); if (rv == AuthResult.Error) { return(CredentialAuthResult.Error); } else if (rv == AuthResult.Again) { return(CredentialAuthResult.Again); } else if (rv != AuthResult.Success) { return(CredentialAuthResult.NextCredential); } _authState.Step = AuthStep.IdentityFilePubKeyAccepted; } Debug.Assert(_authState.Step == AuthStep.IdentityFilePubKeyAccepted); if (_authState.PrivateKey == null) { int rv = ssh_pki_import_privkey_file(privateKeyFile, null, out _authState.PrivateKey); if (rv == SSH_ERROR) { if (!ignoreErrors) { errorMessage = $"Failed to read private key file: {privateKeyFile}."; return(CredentialAuthResult.Error); } return(CredentialAuthResult.NextCredential); } else if (rv == SSH_EOF) { if (!ignoreErrors) { errorMessage = $"Private key file is missing: {privateKeyFile}."; return(CredentialAuthResult.Error); } return(CredentialAuthResult.NextCredential); } Debug.Assert(rv == SSH_OK); } { AuthResult rv = ssh_userauth_publickey(_ssh, null, _authState.PrivateKey !); if (rv == AuthResult.Success) { return(CredentialAuthResult.Success); } else if (rv == AuthResult.Again) { return(CredentialAuthResult.Again); } else if (rv == AuthResult.Error) { return(CredentialAuthResult.Error); } return(CredentialAuthResult.NextCredential); } }