Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support ED25519 ssh key #299

Merged
merged 2 commits into from
Nov 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions src/Composer/PackagistFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use Packeton\Integrations\Model\AppUtils;
use Packeton\Model\CredentialsInterface;
use Packeton\Package\RepTypes;
use Packeton\Util\SshKeyHelper;

class PackagistFactory
{
Expand Down Expand Up @@ -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");
Expand Down
4 changes: 2 additions & 2 deletions src/Form/Type/CredentialType.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
11 changes: 7 additions & 4 deletions src/Form/Type/PrivateKeyType.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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');
Expand Down
20 changes: 18 additions & 2 deletions src/Util/SshKeyHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand All @@ -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);
Expand Down
10 changes: 1 addition & 9 deletions templates/user/sshkey.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,7 @@
<b>Notice. Only owner can edit the ssh keys</b>
<h4>Git SSH Key</h4>
<p>
Application requires the keys to be in PEM format. You receive the following error
<code>"This private key is not valid"</code> 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.
</p>
<pre>
cp ~/.ssh/id_rsa id_rsa.pem
ssh-keygen -p -m PEM -f id_rsa.pem
cat id_rsa.pem
</pre>
Application requires the keys to be in PEM format. Supported ED25519 ssh and RSA keys
<br>

<h4>Composer auth config</h4>
Expand Down