Skip to content

Commit cbb2e78

Browse files
committed
ECDSA-SHA256 refactor to use phpseclib instead of openssl
1 parent 7e22e81 commit cbb2e78

1 file changed

Lines changed: 14 additions & 88 deletions

File tree

src/XMLSecurityKey.php

Lines changed: 14 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ public function __construct($type, $params=null)
234234
}
235235
throw new Exception('Certificate "type" (private/public) must be passed via parameters');
236236
case (self::ECDSA_SHA256):
237-
$this->cryptParams['library'] = 'openssl';
237+
$this->cryptParams['library'] = 'phpseclib';
238238
$this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256';
239239
$this->cryptParams['digest'] = 'SHA256';
240240
if (is_array($params) && ! empty($params['type'])) {
@@ -591,9 +591,6 @@ private function signOpenSSL($data)
591591
if (! openssl_sign($data, $signature, $this->key, $algo)) {
592592
throw new Exception('Failure Signing Data: ' . openssl_error_string() . ' - ' . $algo);
593593
}
594-
if ($this->type === self::ECDSA_SHA256) {
595-
$signature = $this->derToRawEcdsa($signature, 32);
596-
}
597594
return $signature;
598595
}
599596

@@ -619,9 +616,6 @@ private function verifyOpenSSL($data, $signature)
619616
if (! empty($this->cryptParams['digest'])) {
620617
$algo = $this->cryptParams['digest'];
621618
}
622-
if ($this->type === self::ECDSA_SHA256) {
623-
$signature = $this->rawToDerEcdsa($signature);
624-
}
625619
return openssl_verify($data, $signature, $this->key, $algo);
626620
}
627621

@@ -693,6 +687,12 @@ public function signData($data)
693687
return $this->signOpenSSL($data);
694688
case 'phpseclib':
695689
$private = PublicKeyLoader::load($this->key);
690+
if ($this->type === self::ECDSA_SHA256) {
691+
return $private
692+
->withHash($this->cryptParams['digest'])
693+
->withSignatureFormat('IEEE')
694+
->sign($data);
695+
}
696696
return $private
697697
->withPadding($this->cryptParams['padding'])
698698
->withHash($this->cryptParams['digest'])
@@ -726,6 +726,13 @@ public function verifySignature($data, $signature)
726726
return $this->verifyOpenSSL($data, $signature);
727727
case 'phpseclib':
728728
$public = PublicKeyLoader::load($this->key);
729+
if ($this->type === self::ECDSA_SHA256) {
730+
$result = $public
731+
->withHash($this->cryptParams['digest'])
732+
->withSignatureFormat('IEEE')
733+
->verify($data, $signature);
734+
return $result === true ? 1 : 0;
735+
}
729736
$result = $public
730737
->withPadding($this->cryptParams['padding'])
731738
->withHash($this->cryptParams['digest'])
@@ -874,85 +881,4 @@ public static function fromEncryptedKeyElement(DOMElement $element)
874881
return $objKey;
875882
}
876883

877-
/**
878-
* Converts ASN.1 DER ECDSA signature to RAW (IEEE P1363) format
879-
*
880-
* @param string $derSignature
881-
* @param int $curveByteSize
882-
* @return string
883-
* @throws Exception
884-
*/
885-
private function derToRawEcdsa($derSignature, $curveByteSize = 32) {
886-
$offset = 0;
887-
888-
// 1. SEQUENCE (0x30) check
889-
if (ord($derSignature[$offset++]) !== 0x30) {
890-
throw new Exception("Invalid DER signature.");
891-
}
892-
893-
$offset++; // Skip total length
894-
895-
// 2. R value (0x02)
896-
if (ord($derSignature[$offset++]) !== 0x02) {
897-
throw new Exception("Invalid DER format (missing R).");
898-
}
899-
$rLen = ord($derSignature[$offset++]);
900-
$r = substr($derSignature, $offset, $rLen);
901-
$offset += $rLen;
902-
903-
// 3. S value (0x02)
904-
if (ord($derSignature[$offset++]) !== 0x02) {
905-
throw new Exception("Invalid DER format (missing S).");
906-
}
907-
$sLen = ord($derSignature[$offset++]);
908-
$s = substr($derSignature, $offset, $sLen);
909-
910-
// 4. Clean up DER padding (leading 0x00 bytes) if any
911-
$r = ltrim($r, "\x00");
912-
$s = ltrim($s, "\x00");
913-
914-
// 5. Adjust to curve size (32 bytes) with padding
915-
$r = str_pad($r, $curveByteSize, "\x00", STR_PAD_LEFT);
916-
$s = str_pad($s, $curveByteSize, "\x00", STR_PAD_LEFT);
917-
918-
// 6. Concat and return
919-
return $r . $s;
920-
}
921-
922-
/**
923-
* Converts RAW (IEEE P1363) ECDSA signature to ASN.1 DER format
924-
*
925-
* @param string $rawSignature
926-
* @return string
927-
* @throws Exception
928-
*/
929-
private function rawToDerEcdsa($rawSignature) {
930-
// P-256 RAW signature should be exactly 64 bytes
931-
if (strlen($rawSignature) !== 64) {
932-
throw new Exception("Invalid RAW signature length. Expected 64 bytes for P-256.");
933-
}
934-
935-
$r = substr($rawSignature, 0, 32);
936-
$s = substr($rawSignature, 32, 32);
937-
938-
// Remove leading zeros
939-
$r = ltrim($r, "\x00");
940-
$s = ltrim($s, "\x00");
941-
942-
// If high bit is set, prepend 0x00 to make it positive integer in ASN.1
943-
if (ord($r[0]) >= 0x80) {
944-
$r = "\x00" . $r;
945-
}
946-
if (ord($s[0]) >= 0x80) {
947-
$s = "\x00" . $s;
948-
}
949-
950-
$rDer = chr(0x02) . chr(strlen($r)) . $r;
951-
$sDer = chr(0x02) . chr(strlen($s)) . $s;
952-
953-
$sequence = $rDer . $sDer;
954-
955-
return chr(0x30) . chr(strlen($sequence)) . $sequence;
956-
}
957-
958884
}

0 commit comments

Comments
 (0)