mirror of
https://github.com/phpseclib/phpseclib.git
synced 2025-01-13 10:01:47 +00:00
System/Agent: add support for DSA / ECDSA keys
This commit is contained in:
parent
85e2bd4811
commit
7c7d500d80
@ -70,6 +70,29 @@ trait Common
|
||||
// brainpool*r* curves are regular prime finite field curves
|
||||
// brainpool*t* curves are twisted versions of the brainpool*r* curves
|
||||
self::$curveOIDs = [
|
||||
'prime192v1' => '1.2.840.10045.3.1.1', // J.5.1, example 1 (aka secp192r1)
|
||||
'prime192v2' => '1.2.840.10045.3.1.2', // J.5.1, example 2
|
||||
'prime192v3' => '1.2.840.10045.3.1.3', // J.5.1, example 3
|
||||
'prime239v1' => '1.2.840.10045.3.1.4', // J.5.2, example 1
|
||||
'prime239v2' => '1.2.840.10045.3.1.5', // J.5.2, example 2
|
||||
'prime239v3' => '1.2.840.10045.3.1.6', // J.5.2, example 3
|
||||
'prime256v1' => '1.2.840.10045.3.1.7', // J.5.3, example 1 (aka secp256r1)
|
||||
|
||||
// https://tools.ietf.org/html/rfc5656#section-10
|
||||
'nistp256' => '1.2.840.10045.3.1.7', // aka secp256r1
|
||||
'nistp384' => '1.3.132.0.34', // aka secp384r1
|
||||
'nistp521' => '1.3.132.0.35', // aka secp521r1
|
||||
|
||||
'nistk163' => '1.3.132.0.1', // aka sect163k1
|
||||
'nistp192' => '1.2.840.10045.3.1.1', // aka secp192r1
|
||||
'nistp224' => '1.3.132.0.33', // aka secp224r1
|
||||
'nistk233' => '1.3.132.0.26', // aka sect233k1
|
||||
'nistb233' => '1.3.132.0.27', // aka sect233r1
|
||||
'nistk283' => '1.3.132.0.16', // aka sect283k1
|
||||
'nistk409' => '1.3.132.0.36', // aka sect409k1
|
||||
'nistb409' => '1.3.132.0.37', // aka sect409r1
|
||||
'nistt571' => '1.3.132.0.38', // aka sect571k1
|
||||
|
||||
// from https://tools.ietf.org/html/rfc5915
|
||||
'secp192r1' => '1.2.840.10045.3.1.1', // aka prime192v1
|
||||
'sect163k1' => '1.3.132.0.1',
|
||||
@ -131,29 +154,6 @@ trait Common
|
||||
'c2tnb431r1' => '1.2.840.10045.3.0.20', // J.4.10, example 1
|
||||
*/
|
||||
|
||||
'prime192v1' => '1.2.840.10045.3.1.1', // J.5.1, example 1 (aka secp192r1)
|
||||
'prime192v2' => '1.2.840.10045.3.1.2', // J.5.1, example 2
|
||||
'prime192v3' => '1.2.840.10045.3.1.3', // J.5.1, example 3
|
||||
'prime239v1' => '1.2.840.10045.3.1.4', // J.5.2, example 1
|
||||
'prime239v2' => '1.2.840.10045.3.1.5', // J.5.2, example 2
|
||||
'prime239v3' => '1.2.840.10045.3.1.6', // J.5.2, example 3
|
||||
'prime256v1' => '1.2.840.10045.3.1.7', // J.5.3, example 1 (aka secp256r1)
|
||||
|
||||
// https://tools.ietf.org/html/rfc5656#section-10
|
||||
'nistp256' => '1.2.840.10045.3.1.7', // aka secp256r1
|
||||
'nistp384' => '1.3.132.0.34', // aka secp384r1
|
||||
'nistp521' => '1.3.132.0.35', // aka secp521r1
|
||||
|
||||
'nistk163' => '1.3.132.0.1', // aka sect163k1
|
||||
'nistp192' => '1.2.840.10045.3.1.1', // aka secp192r1
|
||||
'nistp224' => '1.3.132.0.33', // aka secp224r1
|
||||
'nistk233' => '1.3.132.0.26', // aka sect233k1
|
||||
'nistb233' => '1.3.132.0.27', // aka sect233r1
|
||||
'nistk283' => '1.3.132.0.16', // aka sect283k1
|
||||
'nistk409' => '1.3.132.0.36', // aka sect409k1
|
||||
'nistb409' => '1.3.132.0.37', // aka sect409r1
|
||||
'nistt571' => '1.3.132.0.38', // aka sect571k1
|
||||
|
||||
// http://www.ecc-brainpool.org/download/Domain-parameters.pdf
|
||||
// https://tools.ietf.org/html/rfc5639
|
||||
'brainpoolP160r1' => '1.3.36.3.3.2.8.1.1.1',
|
||||
@ -350,6 +350,10 @@ trait Common
|
||||
$reflect = new \ReflectionClass($curve);
|
||||
$name = $reflect->getShortName();
|
||||
if (isset(self::$curveOIDs[$name]) && self::$useNamedCurves) {
|
||||
if ($reflect->isFinal()) {
|
||||
$reflect = $reflect->getParentClass();
|
||||
$name = $reflect->getShortName();
|
||||
}
|
||||
return $returnArray ?
|
||||
['namedCurve' => $name] :
|
||||
ASN1::encodeDER(['namedCurve' => $name], Maps\ECParameters::MAP);
|
||||
|
@ -80,9 +80,14 @@ abstract class SSH2
|
||||
public static function save(BigInteger $r, BigInteger $s, $curve)
|
||||
{
|
||||
switch ($curve) {
|
||||
case 'nistp256':
|
||||
case 'nistp384':
|
||||
case 'nistp521':
|
||||
case 'secp256r1':
|
||||
$curve = 'nistp256';
|
||||
break;
|
||||
case 'secp384r1':
|
||||
$curve = 'nistp384';
|
||||
break;
|
||||
case 'secp521r1':
|
||||
$curve = 'nistp521';
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
|
@ -33,7 +33,6 @@
|
||||
|
||||
namespace phpseclib\System\SSH;
|
||||
|
||||
use ParagonIE\ConstantTime\Base64;
|
||||
use phpseclib\Crypt\RSA;
|
||||
use phpseclib\Exception\BadConfigurationException;
|
||||
use phpseclib\System\SSH\Agent\Identity;
|
||||
@ -192,25 +191,22 @@ class Agent
|
||||
$identities = [];
|
||||
for ($i = 0; $i < $keyCount; $i++) {
|
||||
list($key_blob, $comment) = Strings::unpackSSH2('ss', $packet);
|
||||
$key_str = 'ssh-rsa ' . base64_encode($key_blob);
|
||||
if (strlen($comment)) {
|
||||
$key_str.= " $comment";
|
||||
}
|
||||
$temp = $key_blob;
|
||||
list($key_type) = Strings::unpackSSH2('s', $temp);
|
||||
switch ($key_type) {
|
||||
case 'ssh-rsa':
|
||||
$key = PublicKeyLoader::load(base64_encode($key_blob));
|
||||
break;
|
||||
case 'ssh-rsa':
|
||||
case 'ssh-dss':
|
||||
// not currently supported
|
||||
break;
|
||||
case 'ssh-ed25519':
|
||||
case 'ecdsa-sha2-nistp256':
|
||||
case 'ecdsa-sha2-nistp384':
|
||||
case 'ecdsa-sha2-nistp521':
|
||||
$key = PublicKeyLoader::load($key_type . ' ' . base64_encode($key_blob));
|
||||
}
|
||||
// resources are passed by reference by default
|
||||
if (isset($key)) {
|
||||
$identity = new Identity($this->fsock);
|
||||
$identity->setPublicKey($key);
|
||||
$identity->setPublicKeyBlob($key_blob);
|
||||
$identity = (new Identity($this->fsock))
|
||||
->withPublicKey($key)
|
||||
->withPublicKeyBlob($key_blob);
|
||||
$identities[] = $identity;
|
||||
unset($key);
|
||||
}
|
||||
|
@ -17,6 +17,8 @@
|
||||
namespace phpseclib\System\SSH\Agent;
|
||||
|
||||
use phpseclib\Crypt\RSA;
|
||||
use phpseclib\Crypt\DSA;
|
||||
use phpseclib\Crypt\ECDSA;
|
||||
use phpseclib\Exception\UnsupportedAlgorithmException;
|
||||
use phpseclib\System\SSH\Agent;
|
||||
use phpseclib\Common\Functions\Strings;
|
||||
@ -84,7 +86,20 @@ class Identity implements PrivateKey
|
||||
* @see self::sign()
|
||||
* @see self::setHash()
|
||||
*/
|
||||
var $flags = 0;
|
||||
private $flags = 0;
|
||||
|
||||
/**
|
||||
* Curve Aliases
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
private static $curveAliases = [
|
||||
'secp256r1' => 'nistp256',
|
||||
'secp384r1' => 'nistp384',
|
||||
'secp521r1' => 'nistp521',
|
||||
'Ed25519' => 'Ed25519'
|
||||
];
|
||||
|
||||
/**
|
||||
* Default Constructor.
|
||||
@ -103,12 +118,20 @@ class Identity implements PrivateKey
|
||||
*
|
||||
* Called by \phpseclib\System\SSH\Agent::requestIdentities()
|
||||
*
|
||||
* @param \phpseclib\Crypt\RSA $key
|
||||
* @param \phpseclib\Crypt\Common\PublicKey $key
|
||||
* @access private
|
||||
*/
|
||||
public function setPublicKey($key)
|
||||
public function withPublicKey($key)
|
||||
{
|
||||
$this->key = $key;
|
||||
if ($key instanceof ECDSA) {
|
||||
if (is_array($key->getCurve()) || !isset(self::$curveAliases[$key->getCurve()])) {
|
||||
throw new UnsupportedAlgorithmException('The only supported curves are nistp256, nistp384, nistp512 and Ed25519');
|
||||
}
|
||||
}
|
||||
|
||||
$new = clone $this;
|
||||
$new->key = $key;
|
||||
return $new;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -120,9 +143,11 @@ class Identity implements PrivateKey
|
||||
* @param string $key_blob
|
||||
* @access private
|
||||
*/
|
||||
public function setPublicKeyBlob($key_blob)
|
||||
public function withPublicKeyBlob($key_blob)
|
||||
{
|
||||
$this->key_blob = $key_blob;
|
||||
$new = clone $this;
|
||||
$new->key_blob = $key_blob;
|
||||
return $new;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -148,18 +173,45 @@ class Identity implements PrivateKey
|
||||
public function withHash($hash)
|
||||
{
|
||||
$new = clone $this;
|
||||
$new->flags = 0;
|
||||
switch ($hash) {
|
||||
case 'sha1':
|
||||
break;
|
||||
case 'sha256':
|
||||
$new->flags = self::SSH_AGENT_RSA2_256;
|
||||
break;
|
||||
case 'sha512':
|
||||
$new->flags = self::SSH_AGENT_RSA2_512;
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedAlgorithmException('The only supported hashes for RSA are sha1, sha256 and sha512');
|
||||
|
||||
$hash = strtolower($hash);
|
||||
|
||||
if ($this->key instanceof RSA) {
|
||||
$new->flags = 0;
|
||||
switch ($hash) {
|
||||
case 'sha1':
|
||||
break;
|
||||
case 'sha256':
|
||||
$new->flags = self::SSH_AGENT_RSA2_256;
|
||||
break;
|
||||
case 'sha512':
|
||||
$new->flags = self::SSH_AGENT_RSA2_512;
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedAlgorithmException('The only supported hashes for RSA are sha1, sha256 and sha512');
|
||||
}
|
||||
}
|
||||
if ($this->key instanceof ECDSA) {
|
||||
switch ($this->key->getCurve()) {
|
||||
case 'secp256r1':
|
||||
$expectedHash = 'sha256';
|
||||
break;
|
||||
case 'secp384r1':
|
||||
$expectedHash = 'sha384';
|
||||
break;
|
||||
//case 'secp521r1':
|
||||
//case 'Ed25519':
|
||||
default:
|
||||
$expectedHash = 'sha512';
|
||||
}
|
||||
if ($hash != $expectedHash) {
|
||||
throw new UnsupportedAlgorithmException('The only supported hash for ' . self::$curveAliases[$key->getCurve()] . ' is ' . $expectedHash);
|
||||
}
|
||||
}
|
||||
if ($this->key instanceof DSA) {
|
||||
if ($hash != 'sha1') {
|
||||
throw new UnsupportedAlgorithmException('The only supported hash for DSA is sha1');
|
||||
}
|
||||
}
|
||||
return $new;
|
||||
}
|
||||
@ -172,14 +224,54 @@ class Identity implements PrivateKey
|
||||
* @param string $padding
|
||||
* @access public
|
||||
*/
|
||||
public function withPadding($padding = RSA::SIGNATURE_PKCS1)
|
||||
public function withPadding($padding)
|
||||
{
|
||||
if (!$this->key instanceof RSA) {
|
||||
throw new UnsupportedAlgorithmException('Only RSA keys support padding');
|
||||
}
|
||||
if ($padding != RSA::SIGNATURE_PKCS1 && $padding != RSA::SIGNATURE_RELAXED_PKCS1) {
|
||||
throw new UnsupportedAlgorithmException('ssh-agent can only create PKCS1 signatures');
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the signature padding mode
|
||||
*
|
||||
* Valid values are: ASN1, SSH2, Raw
|
||||
*
|
||||
* @access public
|
||||
* @param string $padding
|
||||
*/
|
||||
public function withSignatureFormat($format)
|
||||
{
|
||||
if ($this->key instanceof RSA) {
|
||||
throw new UnsupportedAlgorithmException('Only DSA and ECDSA keys support signature format setting');
|
||||
}
|
||||
if ($format != 'SSH2') {
|
||||
throw new UnsupportedAlgorithmException('ssh-agent can only create SSH2-formatted signatures');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the curve
|
||||
*
|
||||
* Returns a string if it's a named curve, an array if not
|
||||
*
|
||||
* @access public
|
||||
* @return string|array
|
||||
*/
|
||||
public function getCurve()
|
||||
{
|
||||
if (!$this->key instanceof ECDSA) {
|
||||
throw new UnsupportedAlgorithmException('Only ECDSA keys have curves');
|
||||
}
|
||||
|
||||
return $this->key->getCurve();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a signature
|
||||
*
|
||||
@ -215,6 +307,10 @@ class Identity implements PrivateKey
|
||||
throw new \RuntimeException('Unable to retrieve signature');
|
||||
}
|
||||
|
||||
if (!$this->key instanceof RSA) {
|
||||
return $signature_blob;
|
||||
}
|
||||
|
||||
list($type, $signature_blob) = Strings::unpackSSH2('ss', $signature_blob);
|
||||
|
||||
return $signature_blob;
|
||||
|
@ -276,13 +276,13 @@ Private-Lines: 1
|
||||
AAAAIQDwaPlajbXY1SxhuwsUqN1CEZ5g4adsbmJsKm+ZbUVm4g==
|
||||
Private-MAC: b85ca0eb7c612df5d18af85128821bd53faaa3ef
|
||||
');
|
||||
$this->assertSame('nistp256', $key->getCurve());
|
||||
$this->assertSame('secp256r1', $key->getCurve());
|
||||
|
||||
PuTTY::setComment('ecdsa-key-20181105');
|
||||
$this->assertSame($expected, $key->toString('PuTTY'));
|
||||
|
||||
$key = PublicKeyLoader::load($expected = 'ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJEXCsWA8s18m25MJlVE1urbXPYFi4q8oMbb2H0kE2f5WPxizsKXRmb1J68paXQizryL9fC4FTqICJ1+UnaPfk0= ecdsa-key-20181105');
|
||||
$this->assertSame('nistp256', $key->getCurve());
|
||||
$this->assertSame('secp256r1', $key->getCurve());
|
||||
|
||||
OpenSSH::setComment('ecdsa-key-20181105');
|
||||
$this->assertSame($expected, $key->toString('OpenSSH'));
|
||||
@ -302,13 +302,13 @@ AAAAMQCEMkGMDg6N7bUqdvLXe0YmY4qBSi8hmAuMvU38RDoVFVmV+R4RYmMueyrX
|
||||
be9Oyus=
|
||||
Private-MAC: 97a990a3d5f6b8f268d4be9c4ab9ebfd8fa79849
|
||||
');
|
||||
$this->assertSame('nistp384', $key->getCurve());
|
||||
$this->assertSame('secp384r1', $key->getCurve());
|
||||
|
||||
PuTTY::setComment('ecdsa-key-20181105');
|
||||
$this->assertSame($expected, $key->toString('PuTTY'));
|
||||
|
||||
$key = PublicKeyLoader::load($expected = 'ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBOI53wHG3CdcAJZq5PXWZAEAxxsNVFQlQgOX9toWEOgqQF5LbK2nWLKRvaHMzocUXaTYZDccSS0ATZFPT3j1Er1LU9cu4PHpyS07v262jdzkxIvKCPcAeISuV80MC7rHog== ecdsa-key-20181105');
|
||||
$this->assertSame('nistp384', $key->getCurve());
|
||||
$this->assertSame('secp384r1', $key->getCurve());
|
||||
|
||||
OpenSSH::setComment('ecdsa-key-20181105');
|
||||
$this->assertSame($expected, $key->toString('OpenSSH'));
|
||||
@ -330,13 +330,13 @@ AAAAQgHJl8/dIArolFymdzhagXCfd2l8UF3CQXWGVGDQ0R04nnntlyztYiVdRXXK
|
||||
r84NnzS7dJcAsR9YaUOZ69NRKNiUAQ==
|
||||
Private-MAC: 6d49ce289b85549a43d74422dd8bb3ba8798c72c
|
||||
');
|
||||
$this->assertSame('nistp521', $key->getCurve());
|
||||
$this->assertSame('secp521r1', $key->getCurve());
|
||||
|
||||
PuTTY::setComment('ecdsa-key-20181105');
|
||||
$this->assertSame($expected, $key->toString('PuTTY'));
|
||||
|
||||
$key = PublicKeyLoader::load($expected = 'ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAF1Eg0MjaJwooFj6HCNh4RWbvmQRY+sdczJyBdT3EaTc/6IUcCfW7w7rAeRp2CDdE9RlAVD8IuLqW7DJH06Xeov8wBO5G6jUqXu0rlHsOSiC6VcCxBJuWVNB1IorHnS7PX0f6HdLlIEme73P77drqpn5YY0XLtP6hFrF7H5XfCxpNyaJA== ecdsa-key-20181105');
|
||||
$this->assertSame('nistp521', $key->getCurve());
|
||||
$this->assertSame('secp521r1', $key->getCurve());
|
||||
|
||||
OpenSSH::setComment('ecdsa-key-20181105');
|
||||
$this->assertSame($expected, $key->toString('OpenSSH'));
|
||||
@ -418,7 +418,7 @@ pomV7r6gmoMYteGVABfgAAAAD3ZhZ3JhbnRAdmFncmFudAECAwQFBg==
|
||||
<Y Value="102403352136827775240910267217779508359028642524881540878079119895764161434936" />
|
||||
</PublicKey>
|
||||
</ECDSAKeyValue>');
|
||||
$this->assertSame('nistp256', $key->getCurve());
|
||||
$this->assertSame('secp256r1', $key->getCurve());
|
||||
|
||||
XML::enableRFC4050Syntax();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user