mirror of
https://github.com/openSUSE/osc.git
synced 2025-08-11 17:54:06 +02:00
ssh: recognize gpg keys (yubikey usage)
When using ssh keys from gpg, there are no private key files on disk. The public keys are available from "ssh-add -L". Conveniently, users store the public keys in some ".pub" file under ~/.ssh (see e.g. https://serverfault.com/questions/906871/force-the-use-of-a-gpg-key-as-an-ssh-key-for-a-given-server; this is also necessary to use IdentityFile= in ssh itself). Thus public key files can't be ignored any more in list_ssh_dir_keys(). "ssh-keygen -Y sign" works nicely with a public key file if the agent has access to the private key.
This commit is contained in:
32
osc/conf.py
32
osc/conf.py
@@ -565,7 +565,7 @@ def _build_opener(apiurl):
|
|||||||
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
stdout, _ = proc.communicate()
|
stdout, _ = proc.communicate()
|
||||||
if proc.returncode == 0 and stdout.strip():
|
if proc.returncode == 0 and stdout.strip():
|
||||||
return stdout.splitlines()
|
return [self.get_fingerprint(line) for line in stdout.splitlines()]
|
||||||
else:
|
else:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
@@ -584,21 +584,43 @@ def _build_opener(apiurl):
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def is_ssh_public_keyfile(self, keyfile_path):
|
||||||
|
if not os.path.isfile(keyfile_path):
|
||||||
|
return False
|
||||||
|
return keyfile_path.endswith(".pub")
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_fingerprint(line):
|
||||||
|
parts = line.strip().split(b" ")
|
||||||
|
if len(parts) < 2:
|
||||||
|
raise ValueError("Unable to retrieve ssh key fingerprint from line: {}".format(line))
|
||||||
|
return parts[1]
|
||||||
|
|
||||||
def list_ssh_dir_keys(self):
|
def list_ssh_dir_keys(self):
|
||||||
sshdir = os.path.expanduser('~/.ssh')
|
sshdir = os.path.expanduser('~/.ssh')
|
||||||
keys_in_home_ssh = {}
|
keys_in_home_ssh = {}
|
||||||
for keyfile in os.listdir(sshdir):
|
for keyfile in os.listdir(sshdir):
|
||||||
if keyfile.endswith(".pub"):
|
if keyfile.startswith(("agent-", "authorized_keys", "config", "known_hosts")):
|
||||||
|
# skip files that definitely don't contain keys
|
||||||
continue
|
continue
|
||||||
|
|
||||||
keyfile_path = os.path.join(sshdir, keyfile)
|
keyfile_path = os.path.join(sshdir, keyfile)
|
||||||
if not self.is_ssh_private_keyfile(keyfile_path):
|
# public key alone may be sufficient because the private key
|
||||||
|
# can get loaded into ssh-agent from gpg (yubikey works this way)
|
||||||
|
is_public = self.is_ssh_public_keyfile(keyfile_path)
|
||||||
|
# skip private detection if we think the key is a public one already
|
||||||
|
is_private = False if is_public else self.is_ssh_private_keyfile(keyfile_path)
|
||||||
|
|
||||||
|
if not is_public and not is_private:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
cmd = ["ssh-keygen", "-lf", keyfile_path]
|
cmd = ["ssh-keygen", "-lf", keyfile_path]
|
||||||
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
stdout, _ = proc.communicate()
|
stdout, _ = proc.communicate()
|
||||||
if proc.returncode == 0:
|
if proc.returncode == 0:
|
||||||
fingerprint = stdout.strip()
|
fingerprint = self.get_fingerprint(stdout)
|
||||||
if fingerprint:
|
if fingerprint and (fingerprint not in keys_in_home_ssh or is_private):
|
||||||
|
# prefer path to a private key
|
||||||
keys_in_home_ssh[fingerprint] = keyfile_path
|
keys_in_home_ssh[fingerprint] = keyfile_path
|
||||||
return keys_in_home_ssh
|
return keys_in_home_ssh
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user