ECDSA: make it so toString() can setspecified / named curve use

This commit is contained in:
terrafrost 2019-06-03 08:16:13 -05:00
parent 557676edd9
commit a431a1959a
7 changed files with 34 additions and 62 deletions

View File

@ -261,20 +261,12 @@ abstract class ECDSA extends AsymmetricKey
return $this->curveName; return $this->curveName;
} }
$namedCurves = PKCS1::isUsingNamedCurves(); $params = $this->getParameters()->toString('PKCS8', ['namedCurve' => true]);
PKCS1::useNamedCurve();
$params = $this->getParameters();
$decoded = ASN1::extractBER($params); $decoded = ASN1::extractBER($params);
$decoded = ASN1::decodeBER($decoded); $decoded = ASN1::decodeBER($decoded);
$decoded = ASN1::asn1map($decoded[0], ECParameters::MAP); $decoded = ASN1::asn1map($decoded[0], ECParameters::MAP);
if (isset($decoded['namedCurve'])) { if (isset($decoded['namedCurve'])) {
$this->curveName = $decoded['namedCurve']; $this->curveName = $decoded['namedCurve'];
if (!$namedCurves) {
PKCS1::useSpecifiedCurve();
}
return $decoded['namedCurve']; return $decoded['namedCurve'];
} }

View File

@ -342,23 +342,26 @@ trait Common
* *
* @todo Maybe at some point this could be moved to __toString() for each of the curves? * @todo Maybe at some point this could be moved to __toString() for each of the curves?
* @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve * @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve
* @param bool $returnArray * @param bool $returnArray optional
* @param array $options optional
* @return string|false * @return string|false
*/ */
private static function encodeParameters(BaseCurve $curve, $returnArray = false) private static function encodeParameters(BaseCurve $curve, $returnArray = false, array $options = [])
{ {
$useNamedCurves = isset($options['namedCurve']) ? $options['namedCurve'] : self::$useNamedCurves;
$reflect = new \ReflectionClass($curve); $reflect = new \ReflectionClass($curve);
$name = $reflect->getShortName(); $name = $reflect->getShortName();
if (isset(self::$curveOIDs[$name]) && self::$useNamedCurves) { if ($useNamedCurves) {
if ($reflect->isFinal()) { if (isset(self::$curveOIDs[$name])) {
$reflect = $reflect->getParentClass(); if ($reflect->isFinal()) {
$name = $reflect->getShortName(); $reflect = $reflect->getParentClass();
$name = $reflect->getShortName();
}
return $returnArray ?
['namedCurve' => $name] :
ASN1::encodeDER(['namedCurve' => $name], Maps\ECParameters::MAP);
} }
return $returnArray ?
['namedCurve' => $name] :
ASN1::encodeDER(['namedCurve' => $name], Maps\ECParameters::MAP);
}
if (self::$useNamedCurves) {
foreach (new \DirectoryIterator(__DIR__ . '/../Curves/') as $file) { foreach (new \DirectoryIterator(__DIR__ . '/../Curves/') as $file) {
if ($file->getExtension() != 'php') { if ($file->getExtension() != 'php') {
continue; continue;
@ -549,14 +552,4 @@ trait Common
{ {
self::$useNamedCurves = true; self::$useNamedCurves = true;
} }
/**
* Returns true if named curves are being used by default
*
* If a named curve is not being used by default than specified curves are being utilized
*/
public static function isUsingNamedCurves()
{
return self::$useNamedCurves;
}
} }

View File

@ -92,7 +92,7 @@ abstract class PKCS1 extends Progenitor
* @access public * @access public
* @return string * @return string
*/ */
public static function saveParameters(BaseCurve $curve) public static function saveParameters(BaseCurve $curve, array $options = [])
{ {
self::initialize_static_variables(); self::initialize_static_variables();
@ -100,7 +100,7 @@ abstract class PKCS1 extends Progenitor
throw new UnsupportedCurveException('TwistedEdwards Curves are not supported'); throw new UnsupportedCurveException('TwistedEdwards Curves are not supported');
} }
$key = self::encodeParameters($curve); $key = self::encodeParameters($curve, false, $options);
return "-----BEGIN EC PARAMETERS-----\r\n" . return "-----BEGIN EC PARAMETERS-----\r\n" .
chunk_split(Base64::encode($key), 64) . chunk_split(Base64::encode($key), 64) .

View File

@ -169,9 +169,10 @@ abstract class PKCS8 extends Progenitor
* @access public * @access public
* @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve * @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve
* @param \phpseclib\Math\Common\FiniteField\Integer[] $publicKey * @param \phpseclib\Math\Common\FiniteField\Integer[] $publicKey
* @param array $optiona optional
* @return string * @return string
*/ */
public static function savePublicKey(BaseCurve $curve, array $publicKey) public static function savePublicKey(BaseCurve $curve, array $publicKey, array $options = [])
{ {
self::initialize_static_variables(); self::initialize_static_variables();
@ -183,7 +184,7 @@ abstract class PKCS8 extends Progenitor
); );
} }
$params = new ASN1\Element(self::encodeParameters($curve)); $params = new ASN1\Element(self::encodeParameters($curve, false, $options));
$key = "\4" . $publicKey[0]->toBytes() . $publicKey[1]->toBytes(); $key = "\4" . $publicKey[0]->toBytes() . $publicKey[1]->toBytes();
@ -218,7 +219,7 @@ abstract class PKCS8 extends Progenitor
$publicKey = "\4" . $publicKey[0]->toBytes() . $publicKey[1]->toBytes(); $publicKey = "\4" . $publicKey[0]->toBytes() . $publicKey[1]->toBytes();
$params = new ASN1\Element(self::encodeParameters($curve)); $params = new ASN1\Element(self::encodeParameters($curve, false, $options));
$key = [ $key = [
'version' => 'ecPrivkeyVer1', 'version' => 'ecPrivkeyVer1',
@ -229,6 +230,6 @@ abstract class PKCS8 extends Progenitor
$key = ASN1::encodeDER($key, Maps\ECPrivateKey::MAP); $key = ASN1::encodeDER($key, Maps\ECPrivateKey::MAP);
return self::wrapPrivateKey($key, [], $params, $password, 'id-ecPublicKey', $options); return self::wrapPrivateKey($key, [], $params, $password, 'id-ecPublicKey', '', $options);
} }
} }

View File

@ -365,9 +365,10 @@ abstract class XML
* *
* @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve * @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve
* @param \phpseclib\Math\Common\FiniteField\Integer[] $publicKey * @param \phpseclib\Math\Common\FiniteField\Integer[] $publicKey
* @param array $options optional
* @return string * @return string
*/ */
public static function savePublicKey(BaseCurve $curve, array $publicKey) public static function savePublicKey(BaseCurve $curve, array $publicKey, array $options = [])
{ {
self::initialize_static_variables(); self::initialize_static_variables();
@ -384,7 +385,7 @@ abstract class XML
if (self::$rfc4050) { if (self::$rfc4050) {
return '<' . $pre . 'ECDSAKeyValue xmlns' . $post . '="http://www.w3.org/2001/04/xmldsig-more#">' . "\r\n" . return '<' . $pre . 'ECDSAKeyValue xmlns' . $post . '="http://www.w3.org/2001/04/xmldsig-more#">' . "\r\n" .
self::encodeXMLParameters($curve, $pre) . "\r\n" . self::encodeXMLParameters($curve, $pre, $options) . "\r\n" .
'<' . $pre . 'PublicKey>' . "\r\n" . '<' . $pre . 'PublicKey>' . "\r\n" .
'<' . $pre . 'X Value="' . $publicKey[0] . '" />' . "\r\n" . '<' . $pre . 'X Value="' . $publicKey[0] . '" />' . "\r\n" .
'<' . $pre . 'Y Value="' . $publicKey[1] . '" />' . "\r\n" . '<' . $pre . 'Y Value="' . $publicKey[1] . '" />' . "\r\n" .
@ -395,7 +396,7 @@ abstract class XML
$publicKey = "\4" . $publicKey[0]->toBytes() . $publicKey[1]->toBytes(); $publicKey = "\4" . $publicKey[0]->toBytes() . $publicKey[1]->toBytes();
return '<' . $pre . 'ECKeyValue xmlns' . $post . '="http://www.w3.org/2009/xmldsig11#">' . "\r\n" . return '<' . $pre . 'ECKeyValue xmlns' . $post . '="http://www.w3.org/2009/xmldsig11#">' . "\r\n" .
self::encodeXMLParameters($curve, $pre) . "\r\n" . self::encodeXMLParameters($curve, $pre, $options) . "\r\n" .
'<' . $pre . 'PublicKey>' . Base64::encode($publicKey) . '</' . $pre . 'PublicKey>' . "\r\n" . '<' . $pre . 'PublicKey>' . Base64::encode($publicKey) . '</' . $pre . 'PublicKey>' . "\r\n" .
'</' . $pre . 'ECKeyValue>'; '</' . $pre . 'ECKeyValue>';
} }
@ -405,11 +406,12 @@ abstract class XML
* *
* @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve * @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve
* @param string $pre * @param string $pre
* @param array $options optional
* @return string|false * @return string|false
*/ */
private static function encodeXMLParameters(BaseCurve $curve, $pre) private static function encodeXMLParameters(BaseCurve $curve, $pre, array $options = [])
{ {
$result = self::encodeParameters($curve, true); $result = self::encodeParameters($curve, true, $options);
if (isset($result['namedCurve'])) { if (isset($result['namedCurve'])) {
$namedCurve = '<' . $pre . 'NamedCurve URI="urn:oid:' . self::$curveOIDs[$result['namedCurve']] . '" />'; $namedCurve = '<' . $pre . 'NamedCurve URI="urn:oid:' . self::$curveOIDs[$result['namedCurve']] . '" />';

View File

@ -103,21 +103,13 @@ class PrivateKey extends ECDSA implements Common\PrivateKey
} }
if (self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods())) { if (self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods())) {
$namedCurves = PKCS8::isUsingNamedCurves();
// use specified curves to avoid issues with OpenSSL possibly not supporting a given named curve;
// doing this may mean some curve-specific optimizations can't be used but idk if OpenSSL even
// has curve-specific optimizations
PKCS8::useSpecifiedCurve();
$signature = ''; $signature = '';
// altho PHP's OpenSSL bindings only supported ECDSA key creation in PHP 7.1 they've long // altho PHP's OpenSSL bindings only supported ECDSA key creation in PHP 7.1 they've long
// supported signing / verification // supported signing / verification
$result = openssl_sign($message, $signature, $this->toString('PKCS8'), $this->hash->getHash()); // we use specified curves to avoid issues with OpenSSL possibly not supporting a given named curve;
// doing this may mean some curve-specific optimizations can't be used but idk if OpenSSL even
if ($namedCurves) { // has curve-specific optimizations
PKCS8::useNamedCurve(); $result = openssl_sign($message, $signature, $this->toString('PKCS8', ['namedCurve' => false]), $this->hash->getHash());
}
if ($result) { if ($result) {
if ($shortFormat == 'ASN1') { if ($shortFormat == 'ASN1') {

View File

@ -109,17 +109,9 @@ class PublicKey extends ECDSA implements Common\PublicKey
extract($params); extract($params);
if (self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods())) { if (self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods())) {
$namedCurves = PKCS8::isUsingNamedCurves();
PKCS8::useSpecifiedCurve();
$sig = $format != 'ASN1' ? ASN1Signature::save($r, $s) : $signature; $sig = $format != 'ASN1' ? ASN1Signature::save($r, $s) : $signature;
$result = openssl_verify($message, $sig, $this->toString('PKCS8'), $this->hash->getHash()); $result = openssl_verify($message, $sig, $this->toString('PKCS8', ['namedCurve' => false]), $this->hash->getHash());
if ($namedCurves) {
PKCS8::useNamedCurve();
}
if ($result != -1) { if ($result != -1) {
return (bool) $result; return (bool) $result;