Skip to content

Commit

Permalink
Merge pull request #299 from vtsykun/feat/support-ed25519
Browse files Browse the repository at this point in the history
Support ED25519 ssh key
  • Loading branch information
vtsykun authored Nov 9, 2024
2 parents 0ea666e + 9ecfb3f commit b6a0c7f
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 20 deletions.
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

0 comments on commit b6a0c7f

Please sign in to comment.