From 18f8735c495a12e4fa989a134768af6367ee25f9 Mon Sep 17 00:00:00 2001 From: Olivier Gayot Date: Mon, 21 Nov 2022 23:46:16 +0100 Subject: [PATCH] ssh: call ssh-keygen once for each key to import MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ssh-keygen -l supports an input file that has multiple keys. As a result, it will output multiple key fingerprints. That being said, ssh-keygen will ignore empty newlines from the input (and maybe other things?). It makes it slightly challenging to associate each key with its fingerprint because the number of lines in the input and output can differ, e.g.: input | output ----------------------------------------------------------------------- ssh-rsa AA[...] user@host ◀-▶ 256 SHA256:[...] user@host (RSA) ┌▶ 3072 SHA256:[...] user@host (ED25519) ssh-ed25519 AA[...] user@host ◀┘ To simplify this process, we will do one call to ssh-keygen -l for each key from the input. Signed-off-by: Olivier Gayot --- subiquity/server/controllers/ssh.py | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/subiquity/server/controllers/ssh.py b/subiquity/server/controllers/ssh.py index 52196943..c24b5b51 100644 --- a/subiquity/server/controllers/ssh.py +++ b/subiquity/server/controllers/ssh.py @@ -91,25 +91,23 @@ class SSHController(SubiquityController): identities=None, error=e.stderr) keys_material: str = cp.stdout.replace('\r', '').strip() - # ssh-keygen supports multiple keys at once. + # ssh-keygen supports multiple keys at once, but it is simpler to + # associate each key with its resulting fingerprint if we call + # ssh-keygen multiple times. fingerprint_command = ('ssh-keygen', '-l', '-f', '-') - try: - cp = await arun_command(fingerprint_command, check=True, - input=keys_material) - except subprocess.CalledProcessError as e: - log.exception("ssh-import-id failed. stderr: %s", e.stderr) - return SSHFetchIdResponse( - tatus=SSHFetchIdStatus.FINGERPRINT_ERROR, - identities=None, error=e.stderr) + for key_material in (mat for mat in keys_material.splitlines() if mat): + try: + cp = await arun_command(fingerprint_command, check=True, + input=key_material) + except subprocess.CalledProcessError as e: + log.exception("ssh-import-id failed. stderr: %s", e.stderr) + return SSHFetchIdResponse( + tatus=SSHFetchIdStatus.FINGERPRINT_ERROR, + identities=None, error=e.stderr) - fingerprints: str = cp.stdout.replace( + fingerprint: str = cp.stdout.replace( f'# ssh-import-id {user_id}', '').strip() - zipped = zip( - [mat for mat in keys_material.splitlines() if mat], - fingerprints.splitlines()) - - for key_material, fingerprint in zipped: key_type, key, key_comment = key_material.split(' ', maxsplit=2) identities.append(SSHIdentity( key_type=key_type, key=key, key_comment=key_comment,