diff --git a/src/Composer/PackagistFactory.php b/src/Composer/PackagistFactory.php index 5052e461..0497b119 100644 --- a/src/Composer/PackagistFactory.php +++ b/src/Composer/PackagistFactory.php @@ -19,6 +19,7 @@ use Packeton\Integrations\Model\AppUtils; use Packeton\Model\CredentialsInterface; use Packeton\Package\RepTypes; +use Packeton\Util\SshKeyHelper; class PackagistFactory { @@ -107,12 +108,13 @@ public function createConfig(?CredentialsInterface $credentials = null) $config->merge(['config' => $credentials->getComposerConfig()]); } - if ($credentials->getKey()) { + if ($key = $credentials->getKey()) { $uid = @getmyuid(); - $keyId = method_exists($credentials, 'getId') ? $credentials->getId() : sha1((string)$credentials->getKey()); + $key = SshKeyHelper::trimKey($key); + $keyId = (method_exists($credentials, 'getId') ? $credentials->getId() : '') . '_'. substr(sha1($key), 0, 6); $credentialsFile = rtrim($this->tmpDir, '/') . '/packeton_priv_key_' . $keyId . '_' . $uid; if (!file_exists($credentialsFile)) { - file_put_contents($credentialsFile, $credentials->getKey()); + file_put_contents($credentialsFile, $key); chmod($credentialsFile, 0600); } putenv("GIT_SSH_COMMAND=ssh -o IdentitiesOnly=yes -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i $credentialsFile"); diff --git a/src/Form/Type/CredentialType.php b/src/Form/Type/CredentialType.php index 7074a916..a378b326 100644 --- a/src/Form/Type/CredentialType.php +++ b/src/Form/Type/CredentialType.php @@ -20,9 +20,9 @@ public function configureOptions(OptionsResolver $resolver): void 'choice_label' => function (SshCredentials $credentials) { $label = $credentials->getName(); if ($credentials->getFingerprint()) { - $label = $label . "(SSH_KEY {$credentials->getFingerprint()})"; + $label = $label . " ({$credentials->getFingerprint()})"; } elseif ($credentials->getComposerConfig()) { - $label = $label . "(Composer Auth)"; + $label = $label . " (Composer Auth)"; } return $label; diff --git a/src/Form/Type/PrivateKeyType.php b/src/Form/Type/PrivateKeyType.php index 896db35e..b87fa803 100644 --- a/src/Form/Type/PrivateKeyType.php +++ b/src/Form/Type/PrivateKeyType.php @@ -4,6 +4,7 @@ namespace Packeton\Form\Type; +use Packeton\Util\SshKeyHelper; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\TextareaType; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -38,10 +39,12 @@ public static function validatePrivateKey($value, ExecutionContextInterface $con return; } - if ($key = openssl_pkey_get_private($value)) { - if ($pubInfo = openssl_pkey_get_details($key)) { - return; - } + $value = SshKeyHelper::trimKey($value); + if (SshKeyHelper::isSshEd25519Key($value)) { + return; + } + if (($key = openssl_pkey_get_private($value)) && false !== openssl_pkey_get_details($key)) { + return; } $context->addViolation('This private key is not valid'); diff --git a/src/Util/SshKeyHelper.php b/src/Util/SshKeyHelper.php index bc8dc24e..0cbc7651 100644 --- a/src/Util/SshKeyHelper.php +++ b/src/Util/SshKeyHelper.php @@ -10,6 +10,17 @@ private function __construct() { } + public static function isSshEd25519Key(string $key): bool + { + return str_contains($key, 'OPENSSH PRIVATE'); + } + + public static function trimKey(string $key): string + { + $key = str_replace("\r\n", "\n", trim($key)); + return rtrim($key, "\n") . "\n"; + } + /** * @param string $key * @@ -21,15 +32,20 @@ public static function getFingerprint(string $key): ?string return null; } + $key = self::trimKey($key); $tmpName = sys_get_temp_dir() . '/sshtmp_' . time(); file_put_contents($tmpName, $key); @chmod($tmpName, 0600); + [$regex, $cmd] = self::isSshEd25519Key($key) ? + ['#(SHA256:.+)#i', "ssh-keygen -E sha256 -lf '$tmpName'"] : + ['#MD5:([0-9a-f:]+)#', "ssh-keygen -E md5 -lf '$tmpName'"]; + try { - if (!$output = @shell_exec("ssh-keygen -E md5 -lf '$tmpName'")) { + if (!$output = @shell_exec($cmd)) { return null; } - preg_match('#MD5:([0-9a-f:]+)#', $output, $match); + preg_match($regex, $output, $match); return $match[1] ?? null; } finally { @unlink($tmpName); diff --git a/templates/user/sshkey.html.twig b/templates/user/sshkey.html.twig index a76963a8..82f96bf7 100644 --- a/templates/user/sshkey.html.twig +++ b/templates/user/sshkey.html.twig @@ -22,15 +22,7 @@ Notice. Only owner can edit the ssh keys
- Application requires the keys to be in PEM format. You receive the following error
- "This private key is not valid"
because the ssh key was generated with newer OpenSSH.
- New keys with OpenSSH private key format can be converted using ssh-keygen utility to the old PEM format.
-
-cp ~/.ssh/id_rsa id_rsa.pem -ssh-keygen -p -m PEM -f id_rsa.pem -cat id_rsa.pem -+ Application requires the keys to be in PEM format. Supported ED25519 ssh and RSA keys