From 3c200c20a53f7fa53b7144da810dbaf4ec4047b4 Mon Sep 17 00:00:00 2001 From: pedro martelletto Date: Thu, 1 Jul 2021 16:05:36 +0200 Subject: [PATCH 01/35] sk-usbhid: use fido_{assert,cred}_set_clientdata() --- sk-usbhid.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/sk-usbhid.c b/sk-usbhid.c index c85b9857d2c..df19412cf0a 100644 --- a/sk-usbhid.c +++ b/sk-usbhid.c @@ -721,9 +721,9 @@ sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len, skdebug(__func__, "fido_cred_set_type: %s", fido_strerr(r)); goto out; } - if ((r = fido_cred_set_clientdata_hash(cred, challenge, + if ((r = fido_cred_set_clientdata(cred, challenge, challenge_len)) != FIDO_OK) { - skdebug(__func__, "fido_cred_set_clientdata_hash: %s", + skdebug(__func__, "fido_cred_set_clientdata: %s", fido_strerr(r)); goto out; } @@ -972,7 +972,6 @@ sk_sign(uint32_t alg, const uint8_t *data, size_t datalen, char *device = NULL; struct sk_usbhid *sk = NULL; struct sk_sign_response *response = NULL; - uint8_t message[32]; int ret = SSH_SK_ERR_GENERAL; int r; @@ -985,11 +984,6 @@ sk_sign(uint32_t alg, const uint8_t *data, size_t datalen, *sign_response = NULL; if (check_sign_load_resident_options(options, &device) != 0) goto out; /* error already logged */ - /* hash data to be signed before it goes to the security key */ - if ((r = sha256_mem(data, datalen, message, sizeof(message))) != 0) { - skdebug(__func__, "hash message failed"); - goto out; - } if (device != NULL) sk = sk_open(device); else if (pin != NULL || (flags & SSH_SK_USER_VERIFICATION_REQD)) @@ -1004,9 +998,9 @@ sk_sign(uint32_t alg, const uint8_t *data, size_t datalen, skdebug(__func__, "fido_assert_new failed"); goto out; } - if ((r = fido_assert_set_clientdata_hash(assert, message, - sizeof(message))) != FIDO_OK) { - skdebug(__func__, "fido_assert_set_clientdata_hash: %s", + if ((r = fido_assert_set_clientdata(assert, data, + datalen)) != FIDO_OK) { + skdebug(__func__, "fido_assert_set_clientdata: %s", fido_strerr(r)); goto out; } @@ -1050,7 +1044,6 @@ sk_sign(uint32_t alg, const uint8_t *data, size_t datalen, response = NULL; ret = 0; out: - explicit_bzero(message, sizeof(message)); free(device); if (response != NULL) { free(response->sig_r); From 41c396c3e33fc9048107e43fd22af9ec254e92f2 Mon Sep 17 00:00:00 2001 From: pedro martelletto Date: Wed, 27 Oct 2021 08:00:51 +0200 Subject: [PATCH 02/35] sk-usbhid: always prefer windows://hello if device == NULL --- sk-usbhid.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/sk-usbhid.c b/sk-usbhid.c index df19412cf0a..fec5f0d362d 100644 --- a/sk-usbhid.c +++ b/sk-usbhid.c @@ -706,8 +706,10 @@ sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len, } if (device != NULL) sk = sk_open(device); - else - sk = sk_probe(NULL, NULL, 0); + else { + if ((sk = sk_open("windows://hello")) == NULL) + sk = sk_probe(NULL, NULL, 0); + } if (sk == NULL) { skdebug(__func__, "failed to find sk"); goto out; @@ -986,10 +988,16 @@ sk_sign(uint32_t alg, const uint8_t *data, size_t datalen, goto out; /* error already logged */ if (device != NULL) sk = sk_open(device); - else if (pin != NULL || (flags & SSH_SK_USER_VERIFICATION_REQD)) - sk = sk_probe(NULL, NULL, 0); - else - sk = sk_probe(application, key_handle, key_handle_len); + else { + if ((sk = sk_open("windows://hello")) == NULL) { + if (pin != NULL || + (flags & SSH_SK_USER_VERIFICATION_REQD)) + sk = sk_probe(NULL, NULL, 0); + else + sk = sk_probe(application, key_handle, + key_handle_len); + } + } if (sk == NULL) { skdebug(__func__, "failed to find sk"); goto out; From bb6503cad5b29278e0f0538e243e690e1c32a5dd Mon Sep 17 00:00:00 2001 From: pedro martelletto Date: Fri, 29 Oct 2021 10:26:18 +0200 Subject: [PATCH 03/35] sk-usbhid: randomise user_id by default requested by akshayku@ --- sk-usbhid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sk-usbhid.c b/sk-usbhid.c index fec5f0d362d..988e937d3e8 100644 --- a/sk-usbhid.c +++ b/sk-usbhid.c @@ -686,7 +686,7 @@ sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len, goto out; } *enroll_response = NULL; - memset(user_id, 0, sizeof(user_id)); + arc4random_buf(user_id, sizeof(user_id)); if (check_enroll_options(options, &device, user_id, sizeof(user_id)) != 0) goto out; /* error already logged */ From 867d766689dac49b142fcd9b727b90824dcb5da9 Mon Sep 17 00:00:00 2001 From: pedro martelletto Date: Fri, 2 Jul 2021 09:07:25 +0200 Subject: [PATCH 04/35] ssh-sk-client: use posix_spawn() to run ssh-sk-helper --- ssh-sk-client.c | 114 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 108 insertions(+), 6 deletions(-) diff --git a/ssh-sk-client.c b/ssh-sk-client.c index 2c66bcbfe61..cb0095f870b 100644 --- a/ssh-sk-client.c +++ b/ssh-sk-client.c @@ -43,15 +43,117 @@ /* #define DEBUG_SK 1 */ +#ifdef WINDOWS +static char module_path[PATH_MAX + 1]; + +static char * +find_helper_in_module_path(void) +{ + DWORD n; + char *ep; + + memset(module_path, 0, sizeof(module_path)); + if ((n = GetModuleFileNameA(NULL, module_path, + sizeof(module_path) - 1)) == 0 || n >= sizeof(module_path) - 1) { + error_f("GetModuleFileNameA failed"); + return NULL; + } + if ((ep = strrchr(module_path, '\\')) == NULL) { + error_f("couldn't locate trailing \\"); + return NULL; + } + *(++ep) = '\0'; /* trim */ + strlcat(module_path, "ssh-sk-helper.exe", sizeof(module_path) - 1); + + return module_path; +} + +static char * +find_helper(void) +{ + char *helper; + char module_path[PATH_MAX + 1]; + char *ep; + DWORD n; + + if ((helper = getenv("SSH_SK_HELPER")) == NULL || strlen(helper) == 0) { + if ((helper = find_helper_in_module_path()) == NULL) + helper = _PATH_SSH_SK_HELPER; + } + if (!path_absolute(helper)) { + error_f("helper \"%s\" unusable: path not absolute", helper); + return NULL; + } + debug_f("using \"%s\" as helper", helper); + + return helper; +} + static int start_helper(int *fdp, pid_t *pidp, void (**osigchldp)(int)) { -#ifndef ENABLE_SK - /* TODO - This is added temporarily to resolve build errors. - * The below logic has to be converted using posix_internal() APIs as windows doesn't support fork. - */ - return SSH_ERR_SYSTEM_ERROR; + void (*osigchld)(int); + int r, pair[2], actions_inited = 0; + pid_t pid; + char *helper, *av[3], *verbosity = NULL; + posix_spawn_file_actions_t actions; + + *fdp = -1; + *pidp = 0; + *osigchldp = SIG_DFL; + r = SSH_ERR_SYSTEM_ERROR; + pair[0] = pair[1] = -1; + + if ((helper = find_helper()) == NULL) + goto out; + osigchld = ssh_signal(SIGCHLD, SIG_DFL); + if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) { + error_f("socketpair: %s", strerror(errno)); + goto out; + } + if (posix_spawn_file_actions_init(&actions) != 0) { + error_f("posix_spawn_file_actions_init failed"); + goto out; + } + actions_inited = 1; + if (posix_spawn_file_actions_adddup2(&actions, pair[1], + STDIN_FILENO) != 0 || + posix_spawn_file_actions_adddup2(&actions, pair[1], + STDOUT_FILENO) != 0) { + error_f("posix_spawn_file_actions_adddup2 failed"); + goto out; + } +#ifdef DEBUG_SK + verbosity = "-vvv"; +#endif + av[0] = helper; + av[1] = verbosity; + av[2] = NULL; + if (posix_spawnp((pid_t *)&pid, av[0], &actions, NULL, av, NULL) != 0) { + error_f("posix_spawnp failed"); + goto out; + } + /* success */ + debug3_f("started pid=%ld", (long)pid); + r = 0; + *fdp = pair[0]; + *pidp = pid; + *osigchldp = osigchld; + pair[0] = -1; +out: + if (pair[0] != -1) + close(pair[0]); + if (pair[1] != -1) + close(pair[1]); + if (actions_inited) + posix_spawn_file_actions_destroy(&actions); + + return r; +} #else +static int +start_helper(int *fdp, pid_t *pidp, void (**osigchldp)(int)) +{ void (*osigchld)(int); int oerrno, pair[2]; pid_t pid; @@ -112,8 +214,8 @@ start_helper(int *fdp, pid_t *pidp, void (**osigchldp)(int)) *pidp = pid; *osigchldp = osigchld; return 0; -#endif } +#endif /* WINDOWS */ static int reap_helper(pid_t pid) From e582f7b22af925d372ab7274eef8a1f713ba0c13 Mon Sep 17 00:00:00 2001 From: pedro martelletto Date: Fri, 2 Jul 2021 10:49:28 +0200 Subject: [PATCH 05/35] ssh-keygen: don't prompt for FIDO PINs by default on Windows only prompt for a FIDO PIN if sshsk_enroll() fails with SSH_ERR_KEY_WRONG_PASSPHRASE, which never happens when sk-usbhid uses webauthn.dll and means we are communicating directly with a security key. --- ssh-keygen.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ssh-keygen.c b/ssh-keygen.c index fc6c21a53a3..1dffb4b0534 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c @@ -3615,6 +3615,7 @@ main(int argc, char **argv) } if ((attest = sshbuf_new()) == NULL) fatal("sshbuf_new failed"); +#ifndef WINDOWS if ((sk_flags & (SSH_SK_USER_VERIFICATION_REQD|SSH_SK_RESIDENT_KEY))) { passphrase = read_passphrase("Enter PIN for " @@ -3622,6 +3623,9 @@ main(int argc, char **argv) } else { passphrase = NULL; } +#else + passphrase = NULL; +#endif for (i = 0 ; ; i++) { fflush(stdout); r = sshsk_enroll(type, sk_provider, sk_device, From ba764664f396e16f113f7ab817d3918eda2c255d Mon Sep 17 00:00:00 2001 From: pedro martelletto Date: Fri, 2 Jul 2021 10:50:23 +0200 Subject: [PATCH 06/35] ssh: don't prompt for FIDO PINs by default on Windows only prompt for a FIDO PIN if sshsk_sign() fails with SSH_ERR_KEY_WRONG_PASSPHRASE, which never happens when sk-usbhid uses webauthn.dll and means we are communicating directly with a security key. --- sshconnect2.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sshconnect2.c b/sshconnect2.c index a33daa5fa72..ea95d581545 100644 --- a/sshconnect2.c +++ b/sshconnect2.c @@ -1281,8 +1281,13 @@ identity_sign(struct identity *id, u_char **sigp, size_t *lenp, } sign_key = prv; if (sshkey_is_sk(sign_key)) { +#ifdef WINDOWS + if ((sign_key->sk_flags & + SSH_SK_USER_VERIFICATION_REQD) && 0) { +#else if ((sign_key->sk_flags & SSH_SK_USER_VERIFICATION_REQD)) { +#endif retry_pin: xasprintf(&prompt, "Enter PIN for %s key %s: ", sshkey_type(sign_key), id->filename); From 3123f253fdede07acc56e3c1b30d4a8aa4a37145 Mon Sep 17 00:00:00 2001 From: pedro martelletto Date: Thu, 11 Nov 2021 15:19:56 +0100 Subject: [PATCH 07/35] fetch libfido2 using an auxiliary script --- contrib/win32/openssh/GetFIDO2.ps1 | 63 ++++++++++++++++++++++++++++ contrib/win32/openssh/config.vcxproj | 10 ++++- 2 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 contrib/win32/openssh/GetFIDO2.ps1 diff --git a/contrib/win32/openssh/GetFIDO2.ps1 b/contrib/win32/openssh/GetFIDO2.ps1 new file mode 100644 index 00000000000..8a13020f0cd --- /dev/null +++ b/contrib/win32/openssh/GetFIDO2.ps1 @@ -0,0 +1,63 @@ +param ( + [string] $paths_target_file_path, + [string] $destDir, + [switch] $override +) + +# Workaround that $PSScriptRoot is not support on ps version 2 +If ($PSVersiontable.PSVersion.Major -le 2) {$PSScriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path} + +if([string]::IsNullOrEmpty($paths_target_file_path)) +{ + $paths_target_file_path = Join-Path $PSScriptRoot "paths.targets" +} + +if([string]::IsNullOrEmpty($destDir)) +{ + $destDir = $PSScriptRoot +} + +if($override) +{ + Remove-Item (join-path $destDir "libfido2") -Recurse -Force -ErrorAction SilentlyContinue +} +elseif (Test-Path (Join-Path $destDir "libfido2") -PathType Container) +{ + return +} + +[xml] $buildConfig = Get-Content $paths_target_file_path +$version = $buildConfig.Project.PropertyGroup.fido2Version + +Write-Host "Downloading libfido2 version:$version" +Write-Host "paths_target_file_path:$paths_target_file_path" +Write-Host "destDir:$destDir" +Write-Host "override:$override" + +$zip_path = Join-Path $PSScriptRoot "libfido2.zip" + +$release_url = "https://ambientworks.net/tmp/libfido2-1.10-b32020cc-win.zip" +Write-Host "release_url:$release_url" + +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -bor ` + [Net.SecurityProtocolType]::Tls11 -bor ` + [Net.SecurityProtocolType]::Tls + +Remove-Item $zip_path -Force -ErrorAction SilentlyContinue +Invoke-WebRequest -Uri $release_url -OutFile $zip_path -UseBasicParsing +if(-not (Test-Path $zip_path)) +{ + throw "failed to download libfido2 version:$version" +} + +# XXX check pgp sig? +Expand-Archive -Path $zip_path -DestinationPath $destDir -Force -ErrorAction SilentlyContinue -ErrorVariable e +if($e -ne $null) +{ + throw "Error when expand zip file. libfido2 version:$version" +} + +Rename-Item -Path $destDir\libfido2-1.10-b32020cc-win -NewName libfido2 +Remove-Item $zip_path -Force -ErrorAction SilentlyContinue + +Write-Host "Succesfully downloaded libfido2 version:$version" diff --git a/contrib/win32/openssh/config.vcxproj b/contrib/win32/openssh/config.vcxproj index 8b4f291a5ee..fda66212a35 100644 --- a/contrib/win32/openssh/config.vcxproj +++ b/contrib/win32/openssh/config.vcxproj @@ -187,6 +187,7 @@ powershell.exe -Executionpolicy Bypass -File "$(SolutionDir)config.ps1" -Config_h_vs "$(SolutionDir)config.h.vs" -Config_h "$(OpenSSH-Src-Path)config.h" -VCIncludePath "$(VC_IncludePath)" -OutCRTHeader "$(OpenSSH-Src-Path)contrib\win32\win32compat\inc\crtheaders.h" +powershell.exe -Executionpolicy Bypass -File "$(SolutionDir)GetFIDO2.ps1 powershell.exe -Executionpolicy Bypass -File "$(SolutionDir)GetLibreSSL.ps1 powershell.exe -Executionpolicy Bypass -File "$(SolutionDir)GetZlib.ps1" @@ -224,6 +225,7 @@ copy /Y "$(SolutionDir)openssh-events.man" "$(OutDir)" powershell.exe -Executionpolicy Bypass -File "$(SolutionDir)config.ps1" -Config_h_vs "$(SolutionDir)config.h.vs" -Config_h "$(OpenSSH-Src-Path)config.h" -VCIncludePath "$(VC_IncludePath)" -OutCRTHeader "$(OpenSSH-Src-Path)contrib\win32\win32compat\inc\crtheaders.h" +powershell.exe -Executionpolicy Bypass -File "$(SolutionDir)GetFIDO2.ps1 powershell.exe -Executionpolicy Bypass -File "$(SolutionDir)GetLibreSSL.ps1 powershell.exe -Executionpolicy Bypass -File "$(SolutionDir)GetZlib.ps1" @@ -261,6 +263,7 @@ copy /Y "$(SolutionDir)openssh-events.man" "$(OutDir)" powershell.exe -Executionpolicy Bypass -File "$(SolutionDir)config.ps1" -Config_h_vs "$(SolutionDir)config.h.vs" -Config_h "$(OpenSSH-Src-Path)config.h" -VCIncludePath "$(VC_IncludePath)" -OutCRTHeader "$(OpenSSH-Src-Path)contrib\win32\win32compat\inc\crtheaders.h" +powershell.exe -Executionpolicy Bypass -File "$(SolutionDir)GetFIDO2.ps1 powershell.exe -Executionpolicy Bypass -File "$(SolutionDir)GetLibreSSL.ps1 powershell.exe -Executionpolicy Bypass -File "$(SolutionDir)GetZlib.ps1" @@ -298,6 +301,7 @@ copy /Y "$(SolutionDir)openssh-events.man" "$(OutDir)" powershell.exe -Executionpolicy Bypass -File "$(SolutionDir)config.ps1" -Config_h_vs "$(SolutionDir)config.h.vs" -Config_h "$(OpenSSH-Src-Path)config.h" -VCIncludePath "$(VC_IncludePath)" -OutCRTHeader "$(OpenSSH-Src-Path)contrib\win32\win32compat\inc\crtheaders.h" +powershell.exe -Executionpolicy Bypass -File "$(SolutionDir)GetFIDO2.ps1 powershell.exe -Executionpolicy Bypass -File "$(SolutionDir)GetLibreSSL.ps1 powershell.exe -Executionpolicy Bypass -File "$(SolutionDir)GetZlib.ps1" @@ -339,6 +343,7 @@ copy /Y "$(SolutionDir)openssh-events.man" "$(OutDir)" powershell.exe -Executionpolicy Bypass -File "$(SolutionDir)config.ps1" -Config_h_vs "$(SolutionDir)config.h.vs" -Config_h "$(OpenSSH-Src-Path)config.h" -VCIncludePath "$(VC_IncludePath)" -OutCRTHeader "$(OpenSSH-Src-Path)contrib\win32\win32compat\inc\crtheaders.h" +powershell.exe -Executionpolicy Bypass -File "$(SolutionDir)GetFIDO2.ps1 powershell.exe -Executionpolicy Bypass -File "$(SolutionDir)GetLibreSSL.ps1 powershell.exe -Executionpolicy Bypass -File "$(SolutionDir)GetZlib.ps1" @@ -380,6 +385,7 @@ copy /Y "$(SolutionDir)openssh-events.man" "$(OutDir)" powershell.exe -Executionpolicy Bypass -File "$(SolutionDir)config.ps1" -Config_h_vs "$(SolutionDir)config.h.vs" -Config_h "$(OpenSSH-Src-Path)config.h" -VCIncludePath "$(VC_IncludePath)" -OutCRTHeader "$(OpenSSH-Src-Path)contrib\win32\win32compat\inc\crtheaders.h" +powershell.exe -Executionpolicy Bypass -File "$(SolutionDir)GetFIDO2.ps1 powershell.exe -Executionpolicy Bypass -File "$(SolutionDir)GetLibreSSL.ps1 powershell.exe -Executionpolicy Bypass -File "$(SolutionDir)GetZlib.ps1" @@ -421,6 +427,7 @@ copy /Y "$(SolutionDir)openssh-events.man" "$(OutDir)" powershell.exe -Executionpolicy Bypass -File "$(SolutionDir)config.ps1" -Config_h_vs "$(SolutionDir)config.h.vs" -Config_h "$(OpenSSH-Src-Path)config.h" -VCIncludePath "$(VC_IncludePath)" -OutCRTHeader "$(OpenSSH-Src-Path)contrib\win32\win32compat\inc\crtheaders.h" +powershell.exe -Executionpolicy Bypass -File "$(SolutionDir)GetFIDO2.ps1 powershell.exe -Executionpolicy Bypass -File "$(SolutionDir)GetLibreSSL.ps1 powershell.exe -Executionpolicy Bypass -File "$(SolutionDir)GetZlib.ps1" @@ -462,6 +469,7 @@ copy /Y "$(SolutionDir)openssh-events.man" "$(OutDir)" powershell.exe -Executionpolicy Bypass -File "$(SolutionDir)config.ps1" -Config_h_vs "$(SolutionDir)config.h.vs" -Config_h "$(OpenSSH-Src-Path)config.h" -VCIncludePath "$(VC_IncludePath)" -OutCRTHeader "$(OpenSSH-Src-Path)contrib\win32\win32compat\inc\crtheaders.h" +powershell.exe -Executionpolicy Bypass -File "$(SolutionDir)GetFIDO2.ps1 powershell.exe -Executionpolicy Bypass -File "$(SolutionDir)GetLibreSSL.ps1 powershell.exe -Executionpolicy Bypass -File "$(SolutionDir)GetZlib.ps1" @@ -486,4 +494,4 @@ copy /Y "$(SolutionDir)openssh-events.man" "$(OutDir)" - \ No newline at end of file + From fff6e73abe570db299adbd6a77a1e279bdf896ab Mon Sep 17 00:00:00 2001 From: pedro martelletto Date: Thu, 1 Jul 2021 16:27:52 +0200 Subject: [PATCH 08/35] build definitions for libfido2 --- contrib/win32/openssh/paths.targets | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/contrib/win32/openssh/paths.targets b/contrib/win32/openssh/paths.targets index 74212fb5259..0e14f3f7994 100644 --- a/contrib/win32/openssh/paths.targets +++ b/contrib/win32/openssh/paths.targets @@ -6,11 +6,17 @@ $(SolutionDir)lib\ 3.3.3.0 1.2.11 + 1.9.0 $(SolutionDir)\LibreSSL\sdk\ $(SolutionDir)\LibreSSL\bin\desktop\x86\ $(SolutionDir)\LibreSSL\bin\desktop\x64\ $(SolutionDir)\LibreSSL\bin\desktop\arm64\ $(SolutionDir)\LibreSSL\bin\desktop\arm\ + $(SolutionDir)\libfido2\ + $(SolutionDir)\libfido2\Win32\Release\v143\static\ + $(SolutionDir)\libfido2\Win64\Release\v143\static\ + $(SolutionDir)\libfido2\ARM64\Release\v143\static\ + $(SolutionDir)\libfido2\ARM\Release\v143\static\ $(SolutionDir)\ZLib\sdk\ $(SolutionDir)\ZLib\bin\x86\ $(SolutionDir)\ZLib\bin\x64\ @@ -22,4 +28,4 @@ bcrypt.lib;Userenv.lib;Crypt32.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;Netapi32.lib;Rpcrt4.lib;ntdll.lib false - \ No newline at end of file + From bd0c9b9e2c96684beeac66b17cc8c917cd357dac Mon Sep 17 00:00:00 2001 From: pedro martelletto Date: Thu, 1 Jul 2021 16:23:12 +0200 Subject: [PATCH 09/35] build ssh-sk-helper --- contrib/win32/openssh/OpenSSHBuildHelper.psm1 | 2 +- contrib/win32/openssh/Win32-OpenSSH.sln | 18 + contrib/win32/openssh/ssh-sk-helper.vcxproj | 409 ++++++++++++++++++ 3 files changed, 428 insertions(+), 1 deletion(-) create mode 100644 contrib/win32/openssh/ssh-sk-helper.vcxproj diff --git a/contrib/win32/openssh/OpenSSHBuildHelper.psm1 b/contrib/win32/openssh/OpenSSHBuildHelper.psm1 index 52440544962..35ddeafb6ec 100644 --- a/contrib/win32/openssh/OpenSSHBuildHelper.psm1 +++ b/contrib/win32/openssh/OpenSSHBuildHelper.psm1 @@ -344,7 +344,7 @@ function Start-OpenSSHPackage $buildDir = Join-Path $repositoryRoot ("bin\" + $folderName + "\" + $Configuration) $payload = "sshd.exe", "ssh.exe", "ssh-agent.exe", "ssh-add.exe", "sftp.exe" - $payload += "sftp-server.exe", "scp.exe", "ssh-shellhost.exe", "ssh-keygen.exe", "ssh-keyscan.exe" + $payload += "sftp-server.exe", "scp.exe", "ssh-shellhost.exe", "ssh-keygen.exe", "ssh-keyscan.exe", "ssh-sk-helper.exe" $payload += "sshd_config_default", "install-sshd.ps1", "uninstall-sshd.ps1" $payload += "FixHostFilePermissions.ps1", "FixUserFilePermissions.ps1", "OpenSSHUtils.psm1", "OpenSSHUtils.psd1" $payload += "openssh-events.man", "moduli", "LICENSE.txt" diff --git a/contrib/win32/openssh/Win32-OpenSSH.sln b/contrib/win32/openssh/Win32-OpenSSH.sln index 0761f52adcd..d45bd1b52ab 100644 --- a/contrib/win32/openssh/Win32-OpenSSH.sln +++ b/contrib/win32/openssh/Win32-OpenSSH.sln @@ -156,6 +156,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ssh-keyscan", "ssh-keyscan. {0D02F0F0-013B-4EE3-906D-86517F3822C0} = {0D02F0F0-013B-4EE3-906D-86517F3822C0} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ssh-sk-helper", "ssh-sk-helper.vcxproj", "{7D0A75FC-F366-4B60-B72F-B37C3EA07CCB}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM = Debug|ARM @@ -504,6 +506,22 @@ Global {7D0A75FC-F366-4B60-B72F-B37C3EA07CCA}.Release|x64.Build.0 = Release|x64 {7D0A75FC-F366-4B60-B72F-B37C3EA07CCA}.Release|x86.ActiveCfg = Release|Win32 {7D0A75FC-F366-4B60-B72F-B37C3EA07CCA}.Release|x86.Build.0 = Release|Win32 + {7D0A75FC-F366-4B60-B72F-B37C3EA07CCB}.Debug|ARM.ActiveCfg = Debug|ARM + {7D0A75FC-F366-4B60-B72F-B37C3EA07CCB}.Debug|ARM.Build.0 = Debug|ARM + {7D0A75FC-F366-4B60-B72F-B37C3EA07CCB}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {7D0A75FC-F366-4B60-B72F-B37C3EA07CCB}.Debug|ARM64.Build.0 = Debug|ARM64 + {7D0A75FC-F366-4B60-B72F-B37C3EA07CCB}.Debug|x64.ActiveCfg = Debug|x64 + {7D0A75FC-F366-4B60-B72F-B37C3EA07CCB}.Debug|x64.Build.0 = Debug|x64 + {7D0A75FC-F366-4B60-B72F-B37C3EA07CCB}.Debug|x86.ActiveCfg = Debug|Win32 + {7D0A75FC-F366-4B60-B72F-B37C3EA07CCB}.Debug|x86.Build.0 = Debug|Win32 + {7D0A75FC-F366-4B60-B72F-B37C3EA07CCB}.Release|ARM.ActiveCfg = Release|ARM + {7D0A75FC-F366-4B60-B72F-B37C3EA07CCB}.Release|ARM.Build.0 = Release|ARM + {7D0A75FC-F366-4B60-B72F-B37C3EA07CCB}.Release|ARM64.ActiveCfg = Release|ARM64 + {7D0A75FC-F366-4B60-B72F-B37C3EA07CCB}.Release|ARM64.Build.0 = Release|ARM64 + {7D0A75FC-F366-4B60-B72F-B37C3EA07CCB}.Release|x64.ActiveCfg = Release|x64 + {7D0A75FC-F366-4B60-B72F-B37C3EA07CCB}.Release|x64.Build.0 = Release|x64 + {7D0A75FC-F366-4B60-B72F-B37C3EA07CCB}.Release|x86.ActiveCfg = Release|Win32 + {7D0A75FC-F366-4B60-B72F-B37C3EA07CCB}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/contrib/win32/openssh/ssh-sk-helper.vcxproj b/contrib/win32/openssh/ssh-sk-helper.vcxproj new file mode 100644 index 00000000000..895df9bc500 --- /dev/null +++ b/contrib/win32/openssh/ssh-sk-helper.vcxproj @@ -0,0 +1,409 @@ + + + + + + Debug + ARM + + + Debug + ARM64 + + + Debug + Win32 + + + Release + ARM + + + Release + ARM64 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {7D0A75FC-F366-4B60-B72F-B37C3EA07CCB} + Win32Proj + sshskhelper + $(WindowsSDKVersion) + ssh-sk-helper + + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + Application + true + v140 + MultiByte + + + Application + true + v141 + MultiByte + + + Application + true + v141 + MultiByte + + + Application + false + v140 + true + MultiByte + + + Application + false + v141 + true + MultiByte + + + Application + false + v141 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + $(fido2-Path)include;$(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath) + + + true + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + $(fido2-Path)include;$(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath) + + + true + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + $(fido2-Path)include;$(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath) + + + true + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + $(fido2-Path)include;$(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath) + + + true + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + $(fido2-Path)include;$(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath) + + + true + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + $(fido2-Path)include;$(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath) + + + true + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + $(fido2-Path)include;$(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath) + + + true + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + $(fido2-Path)include;$(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath) + + + + NotUsing + Level1 + Disabled + _WIN32_WINNT=0x600;WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + false + $(SolutionDir);$(LibreSSL-Path)include;$(ZLib-Path);$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreadedDebug + ProgramDatabase + Guard + /Gy %(AdditionalOptions) + + + Console + true + posix_compat.lib;libssh.lib;openbsd_compat.lib;zlib.lib;fido2.lib;cbor.lib;setupapi.lib;hid.lib;$(SSLLib)$(AdditionalDependentLibs);%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(LibreSSL-x86-Path);$(ZLib-x86-Path);$(fido2-x86-Path);%(AdditionalLibraryDirectories) + wmainCRTStartup + /debug /debugtype:cv,fixup /opt:ref /opt:icf /incremental:no /ignore:4099 /ignore:4098 %(AdditionalOptions) + + + targetos.manifest + + + + + NotUsing + Level1 + Disabled + _WIN32_WINNT=0x600;WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + false + $(SolutionDir);$(LibreSSL-Path)include;$(ZLib-Path);$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreadedDebug + ProgramDatabase + Guard + /Gy %(AdditionalOptions) + + + Console + true + posix_compat.lib;libssh.lib;openbsd_compat.lib;zlib.lib;fido2.lib;cbor.lib;setupapi.lib;hid.lib;$(SSLLib)$(AdditionalDependentLibs);%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(LibreSSL-x64-Path);$(ZLib-x64-Path);$(fido2-x64-Path);%(AdditionalLibraryDirectories) + wmainCRTStartup + /debug /debugtype:cv,fixup /opt:ref /opt:icf /incremental:no /ignore:4099 /ignore:4098 %(AdditionalOptions) + + + targetos.manifest + + + + + NotUsing + Level1 + Disabled + _WIN32_WINNT=0x600;WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + false + $(SolutionDir);$(LibreSSL-Path)include;$(ZLib-Path);$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreadedDebug + ProgramDatabase + Guard + /Gy %(AdditionalOptions) + + + Console + true + posix_compat.lib;libssh.lib;openbsd_compat.lib;zlib.lib;fido2.lib;cbor.lib;setupapi.lib;hid.lib;$(SSLLib)$(AdditionalDependentLibs);%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(LibreSSL-arm64-Path);$(ZLib-arm64-Path);$(fido2-arm64-Path);%(AdditionalLibraryDirectories) + wmainCRTStartup + /debug /debugtype:cv,fixup /opt:ref /opt:icf /incremental:no /ignore:4099 /ignore:4098 %(AdditionalOptions) + + + targetos.manifest + + + + + NotUsing + Level1 + Disabled + _WIN32_WINNT=0x600;WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + false + $(SolutionDir);$(LibreSSL-Path)include;$(ZLib-Path);$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreadedDebug + ProgramDatabase + Guard + /Gy %(AdditionalOptions) + + + Console + true + posix_compat.lib;libssh.lib;openbsd_compat.lib;zlib.lib;fido2.lib;cbor.lib;setupapi.lib;hid.lib;$(SSLLib)$(AdditionalDependentLibs);%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(LibreSSL-arm-Path);$(ZLib-arm-Path);$(fido2-arm-Path);%(AdditionalLibraryDirectories) + wmainCRTStartup + /debug /debugtype:cv,fixup /opt:ref /opt:icf /incremental:no /ignore:4099 /ignore:4098 %(AdditionalOptions) + + + targetos.manifest + + + + + Level1 + NotUsing + MaxSpeed + true + true + _WIN32_WINNT=0x600;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + false + $(SolutionDir);$(LibreSSL-Path)include;$(ZLib-Path);$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreaded + Guard + /Gy %(AdditionalOptions) + + + Console + true + true + true + posix_compat.lib;libssh.lib;openbsd_compat.lib;zlib.lib;fido2.lib;cbor.lib;setupapi.lib;hid.lib;$(SSLLib)$(AdditionalDependentLibs);%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(LibreSSL-x86-Path);$(ZLib-x86-Path);$(fido2-x86-Path);%(AdditionalLibraryDirectories) + wmainCRTStartup + true + /debug /debugtype:cv,fixup /opt:ref /opt:icf /incremental:no /ignore:4099 %(AdditionalOptions) + + + targetos.manifest + + + + + Level1 + NotUsing + MaxSpeed + true + true + _WIN32_WINNT=0x600;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + false + $(SolutionDir);$(LibreSSL-Path)include;$(ZLib-Path);$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreaded + true + Guard + /Gy %(AdditionalOptions) + + + Console + true + true + true + posix_compat.lib;libssh.lib;openbsd_compat.lib;zlib.lib;fido2.lib;cbor.lib;setupapi.lib;hid.lib;$(SSLLib)$(AdditionalDependentLibs);%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(LibreSSL-x64-Path);$(ZLib-x64-Path);$(fido2-x64-Path);%(AdditionalLibraryDirectories) + wmainCRTStartup + true + /debug /debugtype:cv,fixup /opt:ref /opt:icf /incremental:no /ignore:4099 %(AdditionalOptions) + + + targetos.manifest + + + + + Level1 + NotUsing + MaxSpeed + true + true + _WIN32_WINNT=0x600;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + false + $(SolutionDir);$(LibreSSL-Path)include;$(ZLib-Path);$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreaded + true + Guard + /Gy %(AdditionalOptions) + + + Console + true + true + true + posix_compat.lib;libssh.lib;openbsd_compat.lib;zlib.lib;fido2.lib;cbor.lib;setupapi.lib;hid.lib;$(SSLLib)$(AdditionalDependentLibs);%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(LibreSSL-arm64-Path);$(ZLib-arm64-Path);$(fido2-arm64-Path);%(AdditionalLibraryDirectories) + wmainCRTStartup + true + /debug /debugtype:cv,fixup /opt:ref /opt:icf /incremental:no /ignore:4099 %(AdditionalOptions) + + + targetos.manifest + + + + + Level1 + NotUsing + MaxSpeed + true + true + _WIN32_WINNT=0x600;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + false + $(SolutionDir);$(LibreSSL-Path)include;$(ZLib-Path);$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreaded + true + Guard + /Gy %(AdditionalOptions) + + + Console + true + true + true + posix_compat.lib;libssh.lib;openbsd_compat.lib;zlib.lib;fido2.lib;cbor.lib;setupapi.lib;hid.lib;$(SSLLib)$(AdditionalDependentLibs);%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(LibreSSL-arm-Path);$(ZLib-arm-Path);$(fido2-arm-Path);%(AdditionalLibraryDirectories) + wmainCRTStartup + true + /debug /debugtype:cv,fixup /opt:ref /opt:icf /incremental:no /ignore:4099 %(AdditionalOptions) + + + targetos.manifest + + + + + + + + $(OpenSSH-Src-Path)contrib\libfido2\include;%(AdditionalIncludeDirectories) + + + + + + + + + From 73a3af65552ba6fcb1fb2cd16add9295b7acee9f Mon Sep 17 00:00:00 2001 From: pedro martelletto Date: Thu, 1 Jul 2021 16:32:35 +0200 Subject: [PATCH 10/35] enable ssh-sk --- contrib/win32/openssh/config.h.vs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/contrib/win32/openssh/config.h.vs b/contrib/win32/openssh/config.h.vs index 42c1301b001..2420ea0a13e 100644 --- a/contrib/win32/openssh/config.h.vs +++ b/contrib/win32/openssh/config.h.vs @@ -137,6 +137,17 @@ /* Enable for PKCS#11 support */ #define ENABLE_PKCS11 1 +/* Enable for U2F/FIDO support */ +#define ENABLE_SK + +/* Enable for built-in U2F/FIDO support */ +#define ENABLE_SK_INTERNAL + +/* Define for discoverable credential support */ +#define HAVE_FIDO_CRED_PROT +#define HAVE_FIDO_CRED_SET_PROT +#define HAVE_FIDO_DEV_SUPPORTS_CRED_PROT + /* File names may not contain backslash characters */ /* #undef FILESYSTEM_NO_BACKSLASH */ From 6de170f99b2ea06aed9bb0fa7f0fd6847f2fcea6 Mon Sep 17 00:00:00 2001 From: pedro martelletto Date: Thu, 1 Jul 2021 16:28:42 +0200 Subject: [PATCH 11/35] gitignore bits --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 0e0efe9982d..c1a6c28121a 100644 --- a/.gitignore +++ b/.gitignore @@ -46,6 +46,7 @@ tags /config.h /contrib/win32/openssh/LibreSSL /contrib/win32/openssh/ZLib +/contrib/win32/openssh/libfido2 ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. From 98e9c689ed5b35df2fd943cdd803fb14a1238413 Mon Sep 17 00:00:00 2001 From: pedro martelletto Date: Fri, 2 Jul 2021 11:24:41 +0200 Subject: [PATCH 12/35] README blurb --- contrib/win32/openssh/README.txt | 48 ++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/contrib/win32/openssh/README.txt b/contrib/win32/openssh/README.txt index 14b40d4d603..0779315e22c 100644 --- a/contrib/win32/openssh/README.txt +++ b/contrib/win32/openssh/README.txt @@ -10,3 +10,51 @@ OpenSSH-Lib-Path = The directory path of the location to which libra LibreSSL-x86-Path = The directory path of LibreSSL statically compiled for x86 platform. LibreSSL-x64-Path = The directory path of LibreSSL statically compiled for x64 platform. +Notes on FIDO2 support +---------------------- + +* How to build: + + - Open Windows PowerShell. + + - Build OpenSSH for Windows: + + $ cd \path\to\openssh-portable\.. + $ .\openssh-portable\contrib\win32\openssh\OpenSSH-build.ps1 + +* What has been tested: + + * Using a Yubico Security Key. + + - Create a new SSH key: + + $ ssh-keygen.exe -t ecdsa-sk + + * Save the key material in SSH's default paths without an associated passphrase. + + - Add the SSH key to your GitHub account. + + - Tell git to use our SSH build: + + $ $Env:GIT_SSH = '\path\to\ssh.exe' + + - Clone a repository using the SSH key for authentication: + + $ git clone ssh://git@github.com/org/some-private-repo + +* WSL2: + + - Export GIT_SSH: + + $ export GIT_SSH=/mnt/c/.../path/to/ssh.exe + + - Optionally, alias ssh: + + $ alias ssh=/mnt/c/.../path/to/ssh.exe + +* What definitely doesn't work: + + * ssh-keygen -O no-touch-required: + - there does not appear to be a way to toggle user presence in WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS. + * ssh-keygen -K, ssh-add -K: + - these use Credential Management to reconstruct the SSH private key. From 0d4e6f65df57663f66549e4ead0757d277f4dadd Mon Sep 17 00:00:00 2001 From: pedro martelletto Date: Fri, 26 Nov 2021 17:07:14 +0100 Subject: [PATCH 13/35] sshsig: don't prompt for FIDO PINs by default on Windows only prompt for a FIDO PIN if sshsig_wrap_sign() fails with SSH_ERR_KEY_WRONG_PASSPHRASE, which never happens when sk-usbhid uses webauthn.dll and means we are communicating directly with a security key. --- ssh-keygen.c | 2 ++ sshsig.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/ssh-keygen.c b/ssh-keygen.c index 1dffb4b0534..9df4d3bcc90 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c @@ -2530,6 +2530,7 @@ sign_one(struct sshkey *signkey, const char *filename, int fd, fprintf(stderr, "Signing file %s\n", filename); } if (signer == NULL && sshkey_is_sk(signkey)) { +#ifndef WINDOWS if ((signkey->sk_flags & SSH_SK_USER_VERIFICATION_REQD)) { xasprintf(&prompt, "Enter PIN for %s key: ", sshkey_type(signkey)); @@ -2537,6 +2538,7 @@ sign_one(struct sshkey *signkey, const char *filename, int fd, RP_ALLOW_STDIN)) == NULL) fatal_f("couldn't read PIN"); } +#endif if ((signkey->sk_flags & SSH_SK_USER_PRESENCE_REQD)) { if ((fp = sshkey_fingerprint(signkey, fingerprint_hash, SSH_FP_DEFAULT)) == NULL) diff --git a/sshsig.c b/sshsig.c index 4ce4674cd42..3b55243828e 100644 --- a/sshsig.c +++ b/sshsig.c @@ -32,6 +32,9 @@ #include "sshsig.h" #include "ssherr.h" #include "sshkey.h" +#ifdef WINDOWS +#include "sk-api.h" /* XXX for SSH_SK_USER_VERIFICATION_REQD */ +#endif #include "match.h" #include "digest.h" @@ -555,6 +558,55 @@ hash_file(int fd, const char *hashalg, struct sshbuf **bp) return r; } +#ifdef WINDOWS +int +sshsig_sign_fd(struct sshkey *key, const char *hashalg, + const char *sk_provider, const char *sk_pin, + int fd, const char *sig_namespace, struct sshbuf **out, + sshsig_signer *signer, void *signer_ctx) +{ + struct sshbuf *b = NULL; + int r = SSH_ERR_INTERNAL_ERROR, retried = 0; + char *pin = NULL, *prompt = NULL; + + if (hashalg == NULL) + hashalg = HASHALG_DEFAULT; + if (out != NULL) + *out = NULL; + if ((r = hash_file(fd, hashalg, &b)) != 0) { + error_fr(r, "hash_file"); + return r; + } + retry: + if ((r = sshsig_wrap_sign(key, hashalg, sk_provider, sk_pin, b, + sig_namespace, out, signer, signer_ctx)) != 0) { + if (r == SSH_ERR_KEY_WRONG_PASSPHRASE && signer == NULL && + sshkey_is_sk(key) && sk_pin == NULL && !retried && + (key->sk_flags & SSH_SK_USER_VERIFICATION_REQD)) { + xasprintf(&prompt, "Enter PIN for %s key: ", + sshkey_type(key)); + if ((pin = read_passphrase(prompt, + RP_ALLOW_STDIN)) == NULL) { + debug_f("couldn't read PIN"); + goto out; + } + sk_pin = pin; + retried = 1; + goto retry; + } + error_fr(r, "sshsig_wrap_sign"); + goto out; + } + /* success */ + r = 0; + out: + free(prompt); + if (pin != NULL) + freezero(pin, strlen(pin)); + sshbuf_free(b); + return r; +} +#else int sshsig_sign_fd(struct sshkey *key, const char *hashalg, const char *sk_provider, const char *sk_pin, @@ -581,6 +633,7 @@ sshsig_sign_fd(struct sshkey *key, const char *hashalg, sshbuf_free(b); return r; } +#endif /* WINDOWS */ int sshsig_verify_fd(struct sshbuf *signature, int fd, From 14e3877c08d2f4992afcd033f96e76c53e2be79f Mon Sep 17 00:00:00 2001 From: pedro martelletto Date: Mon, 29 Nov 2021 09:01:13 +0100 Subject: [PATCH 14/35] ssh-keygen -s: don't prompt for FIDO PINs by default on Windows only prompt for a FIDO PIN if sshkey_certify() fails with SSH_ERR_KEY_WRONG_PASSPHRASE, which never happens when sk-usbhid uses webauthn.dll and means we are communicating directly with a security key. --- ssh-keygen.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/ssh-keygen.c b/ssh-keygen.c index 9df4d3bcc90..f054a0ed38d 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c @@ -1738,7 +1738,7 @@ do_ca_sign(struct passwd *pw, const char *ca_key_path, int prefer_agent, unsigned long long cert_serial, int cert_serial_autoinc, int argc, char **argv) { - int r, i, found, agent_fd = -1; + int r, i, found, agent_fd = -1, retried = 0; u_int n; struct sshkey *ca, *public; char valid[64], *otmp, *tmp, *cp, *out, *comment; @@ -1781,12 +1781,14 @@ do_ca_sign(struct passwd *pw, const char *ca_key_path, int prefer_agent, } else { /* CA key is assumed to be a private key on the filesystem */ ca = load_identity(tmp, NULL); +#ifndef WINDOWS if (sshkey_is_sk(ca) && (ca->sk_flags & SSH_SK_USER_VERIFICATION_REQD)) { if ((pin = read_passphrase("Enter PIN for CA key: ", RP_ALLOW_STDIN)) == NULL) fatal_f("couldn't read PIN"); } +#endif } free(tmp); @@ -1848,6 +1850,7 @@ do_ca_sign(struct passwd *pw, const char *ca_key_path, int prefer_agent, &agent_fd)) != 0) fatal_r(r, "Couldn't certify %s via agent", tmp); } else { + retry: if (sshkey_is_sk(ca) && (ca->sk_flags & SSH_SK_USER_PRESENCE_REQD)) { notifier = notify_start(0, @@ -1857,6 +1860,17 @@ do_ca_sign(struct passwd *pw, const char *ca_key_path, int prefer_agent, r = sshkey_certify(public, ca, key_type_name, sk_provider, pin); notify_complete(notifier, "User presence confirmed"); +#ifdef WINDOWS + if (r == SSH_ERR_KEY_WRONG_PASSPHRASE && + pin == NULL && !retried && sshkey_is_sk(ca) && + (ca->sk_flags & SSH_SK_USER_VERIFICATION_REQD)) { + if ((pin = read_passphrase("Enter PIN for CA " + "key: ", RP_ALLOW_STDIN)) == NULL) + fatal_f("couldn't read PIN"); + retried = 1; + goto retry; + } +#endif if (r != 0) fatal_r(r, "Couldn't certify key %s", tmp); } From 1e3d6d4ac625280e17aa6807eb9d27b71b789080 Mon Sep 17 00:00:00 2001 From: pedro martelletto Date: Wed, 1 Dec 2021 09:53:03 +0100 Subject: [PATCH 15/35] sk-usbhid: +#ifdef WINDOWS; requested by bagajjal@ --- sk-usbhid.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sk-usbhid.c b/sk-usbhid.c index 988e937d3e8..41270077824 100644 --- a/sk-usbhid.c +++ b/sk-usbhid.c @@ -686,7 +686,11 @@ sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len, goto out; } *enroll_response = NULL; +#ifdef WINDOWS arc4random_buf(user_id, sizeof(user_id)); +#else + memset(user_id, 0, sizeof(user_id)); +#endif if (check_enroll_options(options, &device, user_id, sizeof(user_id)) != 0) goto out; /* error already logged */ From 3dd1a01959793fdcbac9afb9647d035757375e5e Mon Sep 17 00:00:00 2001 From: pedro martelletto Date: Wed, 1 Dec 2021 10:30:57 +0100 Subject: [PATCH 16/35] sshsig: merge sshsig_sign_fd(), requested by bagajjal@ --- sshsig.c | 40 ++++++++++------------------------------ 1 file changed, 10 insertions(+), 30 deletions(-) diff --git a/sshsig.c b/sshsig.c index 3b55243828e..1fbabf66612 100644 --- a/sshsig.c +++ b/sshsig.c @@ -558,7 +558,6 @@ hash_file(int fd, const char *hashalg, struct sshbuf **bp) return r; } -#ifdef WINDOWS int sshsig_sign_fd(struct sshkey *key, const char *hashalg, const char *sk_provider, const char *sk_pin, @@ -566,8 +565,11 @@ sshsig_sign_fd(struct sshkey *key, const char *hashalg, sshsig_signer *signer, void *signer_ctx) { struct sshbuf *b = NULL; - int r = SSH_ERR_INTERNAL_ERROR, retried = 0; + int r = SSH_ERR_INTERNAL_ERROR; +#ifdef WINDOWS + int retried = 0; char *pin = NULL, *prompt = NULL; +#endif if (hashalg == NULL) hashalg = HASHALG_DEFAULT; @@ -577,9 +579,12 @@ sshsig_sign_fd(struct sshkey *key, const char *hashalg, error_fr(r, "hash_file"); return r; } +#ifdef WINDOWS retry: +#endif if ((r = sshsig_wrap_sign(key, hashalg, sk_provider, sk_pin, b, sig_namespace, out, signer, signer_ctx)) != 0) { +#ifdef WINDOWS if (r == SSH_ERR_KEY_WRONG_PASSPHRASE && signer == NULL && sshkey_is_sk(key) && sk_pin == NULL && !retried && (key->sk_flags & SSH_SK_USER_VERIFICATION_REQD)) { @@ -595,45 +600,20 @@ sshsig_sign_fd(struct sshkey *key, const char *hashalg, goto retry; } error_fr(r, "sshsig_wrap_sign"); +#endif goto out; } /* success */ r = 0; out: +#ifdef WINDOWS free(prompt); if (pin != NULL) freezero(pin, strlen(pin)); +#endif sshbuf_free(b); return r; } -#else -int -sshsig_sign_fd(struct sshkey *key, const char *hashalg, - const char *sk_provider, const char *sk_pin, - int fd, const char *sig_namespace, struct sshbuf **out, - sshsig_signer *signer, void *signer_ctx) -{ - struct sshbuf *b = NULL; - int r = SSH_ERR_INTERNAL_ERROR; - - if (hashalg == NULL) - hashalg = HASHALG_DEFAULT; - if (out != NULL) - *out = NULL; - if ((r = hash_file(fd, hashalg, &b)) != 0) { - error_fr(r, "hash_file"); - return r; - } - if ((r = sshsig_wrap_sign(key, hashalg, sk_provider, sk_pin, b, - sig_namespace, out, signer, signer_ctx)) != 0) - goto out; - /* success */ - r = 0; - out: - sshbuf_free(b); - return r; -} -#endif /* WINDOWS */ int sshsig_verify_fd(struct sshbuf *signature, int fd, From dee6c5e7aaee3c58633e80f754adc79a8ea0f5ee Mon Sep 17 00:00:00 2001 From: pedro martelletto Date: Wed, 1 Dec 2021 10:59:04 +0100 Subject: [PATCH 17/35] ssh-sk-client: merge start_helper(), requested by bagajjal@ --- ssh-sk-client.c | 106 +++++++++++++++++++++++------------------------- 1 file changed, 51 insertions(+), 55 deletions(-) diff --git a/ssh-sk-client.c b/ssh-sk-client.c index cb0095f870b..901ac067904 100644 --- a/ssh-sk-client.c +++ b/ssh-sk-client.c @@ -88,29 +88,60 @@ find_helper(void) return helper; } +#endif /* WINDOWS */ static int start_helper(int *fdp, pid_t *pidp, void (**osigchldp)(int)) { void (*osigchld)(int); - int r, pair[2], actions_inited = 0; + int oerrno, pair[2]; pid_t pid; - char *helper, *av[3], *verbosity = NULL; + char *helper, *verbosity = NULL; +#ifdef WINDOWS + int r, actions_inited = 0; + char *av[3]; posix_spawn_file_actions_t actions; +#endif *fdp = -1; *pidp = 0; *osigchldp = SIG_DFL; +#ifdef WINDOWS r = SSH_ERR_SYSTEM_ERROR; pair[0] = pair[1] = -1; +#endif +#ifdef WINDOWS if ((helper = find_helper()) == NULL) goto out; - osigchld = ssh_signal(SIGCHLD, SIG_DFL); +#else + helper = getenv("SSH_SK_HELPER"); + if (helper == NULL || strlen(helper) == 0) + helper = _PATH_SSH_SK_HELPER; + if (access(helper, X_OK) != 0) { + oerrno = errno; + error_f("helper \"%s\" unusable: %s", helper, strerror(errno)); + errno = oerrno; + return SSH_ERR_SYSTEM_ERROR; + } +#endif + +#ifdef DEBUG_SK + verbosity = "-vvv"; +#endif + + /* Start helper */ if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) { - error_f("socketpair: %s", strerror(errno)); + error("socketpair: %s", strerror(errno)); +#ifdef WINDOWS goto out; +#else + return SSH_ERR_SYSTEM_ERROR; +#endif } + osigchld = ssh_signal(SIGCHLD, SIG_DFL); + +#ifdef WINDOWS if (posix_spawn_file_actions_init(&actions) != 0) { error_f("posix_spawn_file_actions_init failed"); goto out; @@ -123,9 +154,9 @@ start_helper(int *fdp, pid_t *pidp, void (**osigchldp)(int)) error_f("posix_spawn_file_actions_adddup2 failed"); goto out; } -#ifdef DEBUG_SK - verbosity = "-vvv"; #endif + +#ifdef WINDOWS av[0] = helper; av[1] = verbosity; av[2] = NULL; @@ -133,55 +164,8 @@ start_helper(int *fdp, pid_t *pidp, void (**osigchldp)(int)) error_f("posix_spawnp failed"); goto out; } - /* success */ - debug3_f("started pid=%ld", (long)pid); r = 0; - *fdp = pair[0]; - *pidp = pid; - *osigchldp = osigchld; - pair[0] = -1; -out: - if (pair[0] != -1) - close(pair[0]); - if (pair[1] != -1) - close(pair[1]); - if (actions_inited) - posix_spawn_file_actions_destroy(&actions); - - return r; -} #else -static int -start_helper(int *fdp, pid_t *pidp, void (**osigchldp)(int)) -{ - void (*osigchld)(int); - int oerrno, pair[2]; - pid_t pid; - char *helper, *verbosity = NULL; - - *fdp = -1; - *pidp = 0; - *osigchldp = SIG_DFL; - - helper = getenv("SSH_SK_HELPER"); - if (helper == NULL || strlen(helper) == 0) - helper = _PATH_SSH_SK_HELPER; - if (access(helper, X_OK) != 0) { - oerrno = errno; - error_f("helper \"%s\" unusable: %s", helper, strerror(errno)); - errno = oerrno; - return SSH_ERR_SYSTEM_ERROR; - } -#ifdef DEBUG_SK - verbosity = "-vvv"; -#endif - - /* Start helper */ - if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) { - error("socketpair: %s", strerror(errno)); - return SSH_ERR_SYSTEM_ERROR; - } - osigchld = ssh_signal(SIGCHLD, SIG_DFL); if ((pid = fork()) == -1) { oerrno = errno; error("fork: %s", strerror(errno)); @@ -207,15 +191,27 @@ start_helper(int *fdp, pid_t *pidp, void (**osigchldp)(int)) _exit(1); } close(pair[1]); - +#endif /* success */ debug3_f("started pid=%ld", (long)pid); *fdp = pair[0]; *pidp = pid; *osigchldp = osigchld; +#ifdef WINDOWS + pair[0] = -1; +out: + if (pair[0] != -1) + close(pair[0]); + if (pair[1] != -1) + close(pair[1]); + if (actions_inited) + posix_spawn_file_actions_destroy(&actions); + + return r; +#else return 0; +#endif } -#endif /* WINDOWS */ static int reap_helper(pid_t pid) From 783697f28791a95a487ad0838f29e743f7c082d6 Mon Sep 17 00:00:00 2001 From: pedro martelletto Date: Wed, 1 Dec 2021 11:24:16 +0100 Subject: [PATCH 18/35] identity_sign: add a clarification comment --- sshconnect2.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sshconnect2.c b/sshconnect2.c index ea95d581545..c302d832866 100644 --- a/sshconnect2.c +++ b/sshconnect2.c @@ -1282,6 +1282,14 @@ identity_sign(struct identity *id, u_char **sigp, size_t *lenp, sign_key = prv; if (sshkey_is_sk(sign_key)) { #ifdef WINDOWS + /* + * Don't prompt for FIDO2 PINs by default on Windows. + * The odds are we are communicating with webauthn.dll, + * which handles this internally. In the event we are + * talking directly to a FIDO2 device and a PIN is + * required, sshkey_sign() will return WRONG_PASSPHRASE + * and we will prompt for a PIN when we retry. + */ if ((sign_key->sk_flags & SSH_SK_USER_VERIFICATION_REQD) && 0) { #else From ed39b666b95b12e8952b91016fd589218163c95e Mon Sep 17 00:00:00 2001 From: pedro martelletto Date: Wed, 1 Dec 2021 13:18:42 +0100 Subject: [PATCH 19/35] pathnames: adjust _PATH_SSH_SK_HELPER on Windows --- pathnames.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pathnames.h b/pathnames.h index f7ca5a75a0d..9f296bfe727 100644 --- a/pathnames.h +++ b/pathnames.h @@ -136,8 +136,12 @@ /* Location of ssh-sk-helper to support keys in security keys */ #ifndef _PATH_SSH_SK_HELPER +#ifdef WINDOWS +#define _PATH_SSH_SK_HELPER "C:\Windows\System32\OpenSSH\ssh-sk-helper.exe" +#else #define _PATH_SSH_SK_HELPER "/usr/libexec/ssh-sk-helper" #endif +#endif /* xauth for X11 forwarding */ #ifndef _PATH_XAUTH From 3e47db810e2ccd80f382367636e9a2fc93264b03 Mon Sep 17 00:00:00 2001 From: pedro martelletto Date: Wed, 1 Dec 2021 14:00:00 +0100 Subject: [PATCH 20/35] fix previous --- pathnames.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pathnames.h b/pathnames.h index 9f296bfe727..608cd176bd4 100644 --- a/pathnames.h +++ b/pathnames.h @@ -137,7 +137,7 @@ /* Location of ssh-sk-helper to support keys in security keys */ #ifndef _PATH_SSH_SK_HELPER #ifdef WINDOWS -#define _PATH_SSH_SK_HELPER "C:\Windows\System32\OpenSSH\ssh-sk-helper.exe" +#define _PATH_SSH_SK_HELPER "C:\\Windows\\System32\\OpenSSH\\ssh-sk-helper.exe" #else #define _PATH_SSH_SK_HELPER "/usr/libexec/ssh-sk-helper" #endif From 6b54b8dee954f45899f2ae3defc86577e4d2231f Mon Sep 17 00:00:00 2001 From: pedro martelletto Date: Wed, 1 Dec 2021 13:45:30 +0100 Subject: [PATCH 21/35] ssh-sk-client: use GetModuleFileNameW(), requested by bagajjal@ --- ssh-sk-client.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/ssh-sk-client.c b/ssh-sk-client.c index 901ac067904..431b672ef35 100644 --- a/ssh-sk-client.c +++ b/ssh-sk-client.c @@ -49,13 +49,20 @@ static char module_path[PATH_MAX + 1]; static char * find_helper_in_module_path(void) { + wchar_t path[PATH_MAX + 1]; DWORD n; char *ep; memset(module_path, 0, sizeof(module_path)); - if ((n = GetModuleFileNameA(NULL, module_path, - sizeof(module_path) - 1)) == 0 || n >= sizeof(module_path) - 1) { - error_f("GetModuleFileNameA failed"); + memset(path, 0, sizeof(path)); + if ((n = GetModuleFileNameW(NULL, path, PATH_MAX)) == 0 || + n >= PATH_MAX) { + error_f("GetModuleFileNameW failed"); + return NULL; + } + if (wcstombs_s(NULL, module_path, sizeof(module_path), path, + sizeof(module_path) - 1) != 0) { + error_f("wcstombs_s failed"); return NULL; } if ((ep = strrchr(module_path, '\\')) == NULL) { From 7606c43ff507dcc3b483c6803573dfe5ca2da567 Mon Sep 17 00:00:00 2001 From: pedro martelletto Date: Wed, 1 Dec 2021 14:13:00 +0100 Subject: [PATCH 22/35] ssh-keygen: move Windows-specific bits under #ifdef WINDOWS; requested by bagajjal@ --- ssh-keygen.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ssh-keygen.c b/ssh-keygen.c index f054a0ed38d..1da25f47886 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c @@ -1738,7 +1738,7 @@ do_ca_sign(struct passwd *pw, const char *ca_key_path, int prefer_agent, unsigned long long cert_serial, int cert_serial_autoinc, int argc, char **argv) { - int r, i, found, agent_fd = -1, retried = 0; + int r, i, found, agent_fd = -1; u_int n; struct sshkey *ca, *public; char valid[64], *otmp, *tmp, *cp, *out, *comment; @@ -1746,6 +1746,9 @@ do_ca_sign(struct passwd *pw, const char *ca_key_path, int prefer_agent, struct ssh_identitylist *agent_ids; size_t j; struct notifier_ctx *notifier = NULL; +#ifdef WINDOWS + int retried = 0; +#endif #ifdef ENABLE_PKCS11 pkcs11_init(1); @@ -1850,7 +1853,9 @@ do_ca_sign(struct passwd *pw, const char *ca_key_path, int prefer_agent, &agent_fd)) != 0) fatal_r(r, "Couldn't certify %s via agent", tmp); } else { +#ifdef WINDOWS retry: +#endif if (sshkey_is_sk(ca) && (ca->sk_flags & SSH_SK_USER_PRESENCE_REQD)) { notifier = notify_start(0, From b6c982fa26371506edb0ed4549d621ef757b1ec0 Mon Sep 17 00:00:00 2001 From: pedro martelletto Date: Wed, 1 Dec 2021 14:19:21 +0100 Subject: [PATCH 23/35] sk-usbhid: move Windows-specific bits under #ifdef WINDOWS; requested by bagajjal@ --- sk-usbhid.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sk-usbhid.c b/sk-usbhid.c index 41270077824..d50db8a9767 100644 --- a/sk-usbhid.c +++ b/sk-usbhid.c @@ -711,9 +711,14 @@ sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len, if (device != NULL) sk = sk_open(device); else { +#ifdef WINDOWS if ((sk = sk_open("windows://hello")) == NULL) sk = sk_probe(NULL, NULL, 0); +#else + sk = sk_probe(NULL, NULL, 0); +#endif } + if (sk == NULL) { skdebug(__func__, "failed to find sk"); goto out; @@ -992,6 +997,7 @@ sk_sign(uint32_t alg, const uint8_t *data, size_t datalen, goto out; /* error already logged */ if (device != NULL) sk = sk_open(device); +#ifdef WINDOWS else { if ((sk = sk_open("windows://hello")) == NULL) { if (pin != NULL || @@ -1002,6 +1008,12 @@ sk_sign(uint32_t alg, const uint8_t *data, size_t datalen, key_handle_len); } } +#else + else if (pin != NULL || (flags & SSH_SK_USER_VERIFICATION_REQD)) + sk = sk_probe(NULL, NULL, 0); + else + sk = sk_probe(application, key_handle, key_handle_len); +#endif if (sk == NULL) { skdebug(__func__, "failed to find sk"); goto out; From deecf32100e6232d340ab666d6925779424cce7d Mon Sep 17 00:00:00 2001 From: pedro martelletto Date: Wed, 8 Dec 2021 14:10:26 +0100 Subject: [PATCH 24/35] config.h: define HAVE_FIDO_DEV_GET_TOUCH_{BEGIN,STATUS} these are needed by sk-usbhid.c when operating in environments with multiple authenticators attached. --- contrib/win32/openssh/config.h.vs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/contrib/win32/openssh/config.h.vs b/contrib/win32/openssh/config.h.vs index 2420ea0a13e..71caf87e290 100644 --- a/contrib/win32/openssh/config.h.vs +++ b/contrib/win32/openssh/config.h.vs @@ -147,6 +147,8 @@ #define HAVE_FIDO_CRED_PROT #define HAVE_FIDO_CRED_SET_PROT #define HAVE_FIDO_DEV_SUPPORTS_CRED_PROT +#define HAVE_FIDO_DEV_GET_TOUCH_BEGIN +#define HAVE_FIDO_DEV_GET_TOUCH_STATUS /* File names may not contain backslash characters */ /* #undef FILESYSTEM_NO_BACKSLASH */ @@ -1726,4 +1728,4 @@ #define HAVE_LOCALTIME_R #define HAVE_DECL_MEMMEM 0 #define WITH_ZLIB -#define _PATH_TTY "conin$" \ No newline at end of file +#define _PATH_TTY "conin$" From 7393b4860833c8552f62f8379aec422e04d2ed72 Mon Sep 17 00:00:00 2001 From: pedro martelletto Date: Thu, 9 Dec 2021 15:24:01 +0100 Subject: [PATCH 25/35] ssh-add: don't consider a sk_provider a key constraint unless explicitly specified, don't consider a sk_provider a key constraint, allowing ssh-sk keys using the default internal provider to be added with SSH2_AGENTC_ADD_IDENTITY instead of SSH2_AGENTC_ADD_ID_CONSTRAINED. --- ssh-add.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ssh-add.c b/ssh-add.c index 92192fcfa23..19c985205fd 100644 --- a/ssh-add.c +++ b/ssh-add.c @@ -347,7 +347,7 @@ add_file(int agent_fd, const char *filename, int key_only, int qflag, } ssh_free_identitylist(idlist); } - +#ifndef WINDOWS if (sshkey_is_sk(private)) { if (skprovider == NULL) { fprintf(stderr, "Cannot load FIDO key %s " @@ -363,7 +363,10 @@ add_file(int agent_fd, const char *filename, int key_only, int qflag, /* Don't send provider constraint for other keys */ skprovider = NULL; } - +#else + if (!sshkey_is_sk(private)) + skprovider = NULL; +#endif if ((r = ssh_add_identity_constrained(agent_fd, private, comment, lifetime, confirm, maxsign, skprovider)) == 0) { ret = 0; @@ -796,7 +799,7 @@ main(int argc, char **argv) goto done; } -#ifdef ENABLE_SK_INTERNAL +#if !defined(WINDOWS) && defined(ENABLE_SK_INTERNAL) if (skprovider == NULL) skprovider = "internal"; #endif From b31d77e1c732b9d889e7bd85e32769a5714fede5 Mon Sep 17 00:00:00 2001 From: pedro martelletto Date: Thu, 9 Dec 2021 15:27:19 +0100 Subject: [PATCH 26/35] ssh-agent: promote sk_provider == NULL to "internal" a sk_provider is required by ssh-sk-helper. as such, treat ssh-sk keys without a provider as belonging to the "internal" provider. --- .../win32/win32compat/ssh-agent/keyagent-request.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/contrib/win32/win32compat/ssh-agent/keyagent-request.c b/contrib/win32/win32compat/ssh-agent/keyagent-request.c index 9d7dfce77aa..76b81b04984 100644 --- a/contrib/win32/win32compat/ssh-agent/keyagent-request.c +++ b/contrib/win32/win32compat/ssh-agent/keyagent-request.c @@ -208,6 +208,7 @@ static int sign_blob(const struct sshkey *pubkey, u_char ** sig, size_t *siglen, DWORD regdatalen = 0, keyblob_len = 0; struct sshbuf* tmpbuf = NULL; char *keyblob = NULL; + const char *sk_provider = NULL; *sig = NULL; *siglen = 0; @@ -230,8 +231,14 @@ static int sign_blob(const struct sshkey *pubkey, u_char ** sig, size_t *siglen, else if (flags & SSH_AGENT_RSA_SHA2_512) algo = "rsa-sha2-512"; - if (sshkey_private_deserialize(tmpbuf, &prikey) != 0 || - sshkey_sign(prikey, sig, siglen, blob, blen, algo, NULL, NULL, 0) != 0) { + if (sshkey_private_deserialize(tmpbuf, &prikey) != 0) { + debug("cannot deserialize key"); + goto done; + } + if (sshkey_is_sk(prikey)) + sk_provider = "internal"; + if (sshkey_sign(prikey, sig, siglen, blob, blen, algo, sk_provider, + NULL, 0) != 0) { debug("cannot sign using retrieved key"); goto done; } @@ -472,4 +479,4 @@ int process_keyagent_request(struct sshbuf* request, struct sshbuf* response, st } } -#pragma warning(pop) \ No newline at end of file +#pragma warning(pop) From e7b9c097dfdf7027bcd55187a5bf68638ce7d7ad Mon Sep 17 00:00:00 2001 From: pedro martelletto Date: Thu, 9 Dec 2021 17:15:00 +0100 Subject: [PATCH 27/35] README: mention FIDO2 ssh-agent support --- contrib/win32/openssh/README.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contrib/win32/openssh/README.txt b/contrib/win32/openssh/README.txt index 0779315e22c..14b250eb6d6 100644 --- a/contrib/win32/openssh/README.txt +++ b/contrib/win32/openssh/README.txt @@ -52,6 +52,8 @@ Notes on FIDO2 support $ alias ssh=/mnt/c/.../path/to/ssh.exe +* Note: FIDO2 keys are supported by ssh-agent. + * What definitely doesn't work: * ssh-keygen -O no-touch-required: From 78920431ab01006fedb63ab136a87665db0c2ce7 Mon Sep 17 00:00:00 2001 From: pedro martelletto Date: Tue, 14 Dec 2021 08:31:49 +0100 Subject: [PATCH 28/35] sk-usbhid: clarify arc4random_buf() usage in sk_enroll() --- sk-usbhid.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sk-usbhid.c b/sk-usbhid.c index d50db8a9767..e3a932e9382 100644 --- a/sk-usbhid.c +++ b/sk-usbhid.c @@ -687,6 +687,7 @@ sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len, } *enroll_response = NULL; #ifdef WINDOWS + /* Don't overwrite existing credentials on FIDO authenticators. */ arc4random_buf(user_id, sizeof(user_id)); #else memset(user_id, 0, sizeof(user_id)); From 6bd15af4243ae1ce1f18060c8e7e55610e7b50ca Mon Sep 17 00:00:00 2001 From: pedro martelletto Date: Tue, 14 Dec 2021 08:45:13 +0100 Subject: [PATCH 29/35] sk-usbhid: more comments, ifdef blocks no functional change --- sk-usbhid.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/sk-usbhid.c b/sk-usbhid.c index e3a932e9382..f96f7f5d9d0 100644 --- a/sk-usbhid.c +++ b/sk-usbhid.c @@ -733,12 +733,31 @@ sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len, skdebug(__func__, "fido_cred_set_type: %s", fido_strerr(r)); goto out; } +#ifndef WINDOWS + if (sha256_mem(challenge, challenge_len, + chall_hash, sizeof(chall_hash)) != 0) { + skdebug(__func__, "hash challenge failed"); + goto out; + } + if ((r = fido_cred_set_clientdata_hash(cred, chall_hash, + sizeof(chall_hash))) != FIDO_OK) { + skdebug(__func__, "fido_cred_set_clientdata_hash: %s", + fido_strerr(r)); + goto out; + } +#else + /* + * webauthn.dll (windows://hello in libfido2) requires the unhashed + * clientdata body, so we use fido_cred_set_clientdata() instead of + * fido_cred_set_clientdata_hash(). + */ if ((r = fido_cred_set_clientdata(cred, challenge, challenge_len)) != FIDO_OK) { skdebug(__func__, "fido_cred_set_clientdata: %s", fido_strerr(r)); goto out; } +#endif if ((r = fido_cred_set_rk(cred, (flags & SSH_SK_RESIDENT_KEY) != 0 ? FIDO_OPT_TRUE : FIDO_OPT_OMIT)) != FIDO_OK) { skdebug(__func__, "fido_cred_set_rk: %s", fido_strerr(r)); @@ -984,6 +1003,9 @@ sk_sign(uint32_t alg, const uint8_t *data, size_t datalen, char *device = NULL; struct sk_usbhid *sk = NULL; struct sk_sign_response *response = NULL; +#ifndef WINDOWS + uint8_t message[32]; +#endif int ret = SSH_SK_ERR_GENERAL; int r; @@ -996,6 +1018,14 @@ sk_sign(uint32_t alg, const uint8_t *data, size_t datalen, *sign_response = NULL; if (check_sign_load_resident_options(options, &device) != 0) goto out; /* error already logged */ +#ifndef WINDOWS + /* hash data to be signed before it goes to the security key */ + /* This happens elsewhere on Windows; see note below. */ + if ((r = sha256_mem(data, datalen, message, sizeof(message))) != 0) { + skdebug(__func__, "hash message failed"); + goto out; + } +#endif if (device != NULL) sk = sk_open(device); #ifdef WINDOWS @@ -1023,12 +1053,26 @@ sk_sign(uint32_t alg, const uint8_t *data, size_t datalen, skdebug(__func__, "fido_assert_new failed"); goto out; } +#ifndef WINDOWS + if ((r = fido_assert_set_clientdata_hash(assert, message, + sizeof(message))) != FIDO_OK) { + skdebug(__func__, "fido_assert_set_clientdata_hash: %s", + fido_strerr(r)); + goto out; + } +#else + /* + * webauthn.dll (windows://hello in libfido2) requires the unhashed + * clientdata body, so we use fido_assert_set_clientdata() instead of + * fido_assert_set_clientdata_hash(). + */ if ((r = fido_assert_set_clientdata(assert, data, datalen)) != FIDO_OK) { skdebug(__func__, "fido_assert_set_clientdata: %s", fido_strerr(r)); goto out; } +#endif if ((r = fido_assert_set_rp(assert, application)) != FIDO_OK) { skdebug(__func__, "fido_assert_set_rp: %s", fido_strerr(r)); goto out; From ebc802a36e2585283e29b82162d479a10cc07101 Mon Sep 17 00:00:00 2001 From: pedro martelletto Date: Tue, 14 Dec 2021 09:32:39 +0100 Subject: [PATCH 30/35] Win32-OpenSSH.sln: specify ssh-sk-helper's dependencies --- contrib/win32/openssh/Win32-OpenSSH.sln | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/contrib/win32/openssh/Win32-OpenSSH.sln b/contrib/win32/openssh/Win32-OpenSSH.sln index d45bd1b52ab..b24cab318d3 100644 --- a/contrib/win32/openssh/Win32-OpenSSH.sln +++ b/contrib/win32/openssh/Win32-OpenSSH.sln @@ -157,6 +157,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ssh-keyscan", "ssh-keyscan. EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ssh-sk-helper", "ssh-sk-helper.vcxproj", "{7D0A75FC-F366-4B60-B72F-B37C3EA07CCB}" + ProjectSection(ProjectDependencies) = postProject + {05E1115F-8529-46D0-AAAF-52A404CE79A7} = {05E1115F-8529-46D0-AAAF-52A404CE79A7} + {8F9D3B74-8D33-448E-9762-26E8DCC6B2F4} = {8F9D3B74-8D33-448E-9762-26E8DCC6B2F4} + {DD483F7D-C553-4740-BC1A-903805AD0174} = {DD483F7D-C553-4740-BC1A-903805AD0174} + {0D02F0F0-013B-4EE3-906D-86517F3822C0} = {0D02F0F0-013B-4EE3-906D-86517F3822C0} + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution From f6e5ad4c99683579d4e63c3b75ab1a3f2d1892e1 Mon Sep 17 00:00:00 2001 From: pedro martelletto Date: Thu, 16 Dec 2021 11:02:00 +0100 Subject: [PATCH 31/35] Win32-OpenSSH.sln: move ssh-sk-helper to 'core' --- contrib/win32/openssh/Win32-OpenSSH.sln | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/win32/openssh/Win32-OpenSSH.sln b/contrib/win32/openssh/Win32-OpenSSH.sln index b24cab318d3..c1667f5caf4 100644 --- a/contrib/win32/openssh/Win32-OpenSSH.sln +++ b/contrib/win32/openssh/Win32-OpenSSH.sln @@ -554,6 +554,7 @@ Global {FC568FF0-60F2-4B2E-AF62-FD392EDBA1B9} = {A8096E32-E084-4FA0-AE01-A8D909EB2BB4} {484A8CDE-B949-4BDA-B447-74685C8E032F} = {A8096E32-E084-4FA0-AE01-A8D909EB2BB4} {7D0A75FC-F366-4B60-B72F-B37C3EA07CCA} = {17322AAF-808F-4646-AD37-5B0EDDCB8F3E} + {7D0A75FC-F366-4B60-B72F-B37C3EA07CCB} = {17322AAF-808F-4646-AD37-5B0EDDCB8F3E} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {0AC224E8-C215-4270-954A-A2ACEE06DE58} From 843d4d79fa53fe97c4017db387de4b524f724e02 Mon Sep 17 00:00:00 2001 From: pedro martelletto Date: Thu, 16 Dec 2021 11:13:44 +0100 Subject: [PATCH 32/35] sk-usbhid: another #ifndef WINDOWS chunk --- sk-usbhid.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sk-usbhid.c b/sk-usbhid.c index f96f7f5d9d0..92b25552c2e 100644 --- a/sk-usbhid.c +++ b/sk-usbhid.c @@ -1113,6 +1113,9 @@ sk_sign(uint32_t alg, const uint8_t *data, size_t datalen, response = NULL; ret = 0; out: +#ifndef WINDOWS + explicit_bzero(message, sizeof(message)); +#endif free(device); if (response != NULL) { free(response->sig_r); From 524298e252d04d2b268a7c0efd9667b0cb1caa46 Mon Sep 17 00:00:00 2001 From: pedro martelletto Date: Thu, 16 Dec 2021 15:05:09 +0100 Subject: [PATCH 33/35] empty commit to trigger ci From b5432080cd7b62130c6dca25365fc5a13f0242d1 Mon Sep 17 00:00:00 2001 From: pedro martelletto Date: Thu, 16 Dec 2021 16:07:48 +0100 Subject: [PATCH 34/35] (another) empty commit to trigger ci From dd2561c28fa9dbf1b7d7219ebb021961de5ecf28 Mon Sep 17 00:00:00 2001 From: pedro martelletto Date: Fri, 17 Dec 2021 11:19:44 +0100 Subject: [PATCH 35/35] another attempt to get ci to pass