Skip to content

Commit

Permalink
Bugs/rsapss ssa oid (#54)
Browse files Browse the repository at this point in the history
* Add RSASSA-PSS encryption algorithm support

Implemented support for the RSASSA-PSS encryption algorithm which involved adding new Classes and modifying existing ones. The RSAPSSSSAEncryptionAlgorithmIdentifier and RSASSAPSSPrivateKey Classes were added while the OneAsymmetricKey Class was updated to recognize the RSASSA-PSS encryption. This enhances compatibility with a wider range of RSA key types.

* Update phpstan baseline file

A new phpstan baseline rule has been added for the RSAPSSSSAEncryptionAlgorithmIdentifier class. This update aligns with the addition of the RSASSA-PSS encryption algorithm functionality, and improves the static code analysis and detection of potential issues.
  • Loading branch information
Spomky authored Mar 30, 2024
1 parent 2547e68 commit 0b10c8b
Show file tree
Hide file tree
Showing 4 changed files with 299 additions and 2 deletions.
5 changes: 5 additions & 0 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,11 @@ parameters:
count: 1
path: src/CryptoTypes/AlgorithmIdentifier/Asymmetric/RSAEncryptionAlgorithmIdentifier.php

-
message: "#^Method SpomkyLabs\\\\Pki\\\\CryptoTypes\\\\AlgorithmIdentifier\\\\Asymmetric\\\\RSAPSSSSAEncryptionAlgorithmIdentifier\\:\\:paramsASN1\\(\\) never returns null so it can be removed from the return type\\.$#"
count: 1
path: src/CryptoTypes/AlgorithmIdentifier/Asymmetric/RSAPSSSSAEncryptionAlgorithmIdentifier.php

-
message: "#^Parameter \\#2 \\$initializationVector of method SpomkyLabs\\\\Pki\\\\CryptoTypes\\\\AlgorithmIdentifier\\\\Cipher\\\\CipherAlgorithmIdentifier\\:\\:__construct\\(\\) expects string, string\\|null given\\.$#"
count: 1
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php

declare(strict_types=1);

namespace SpomkyLabs\Pki\CryptoTypes\AlgorithmIdentifier\Asymmetric;

use SpomkyLabs\Pki\ASN1\Element;
use SpomkyLabs\Pki\ASN1\Type\Primitive\NullType;
use SpomkyLabs\Pki\ASN1\Type\UnspecifiedType;
use SpomkyLabs\Pki\CryptoTypes\AlgorithmIdentifier\Feature\AsymmetricCryptoAlgorithmIdentifier;
use SpomkyLabs\Pki\CryptoTypes\AlgorithmIdentifier\SpecificAlgorithmIdentifier;
use UnexpectedValueException;

/*
From RFC 3447:
When rsaEncryption is used in an AlgorithmIdentifier the
parameters MUST be present and MUST be NULL.
*/

/**
* Algorithm identifier for RSA encryption.
*
* @see http://www.oid-info.com/get/1.2.840.113549.1.1.10
* @see https://datatracker.ietf.org/doc/html/rfc8017#section-8.1
*/
final class RSAPSSSSAEncryptionAlgorithmIdentifier extends SpecificAlgorithmIdentifier implements AsymmetricCryptoAlgorithmIdentifier
{
private function __construct()
{
parent::__construct(self::OID_RSASSA_PSS_ENCRYPTION);
}

public static function create(): self
{
return new self();
}

public function name(): string
{
return 'rsassa-pss';
}

/**
* @return self
*/
public static function fromASN1Params(?UnspecifiedType $params = null): SpecificAlgorithmIdentifier
{
if (! isset($params)) {
throw new UnexpectedValueException('No parameters.');
}
$params->asNull();
return self::create();
}

/**
* @return NullType
*/
protected function paramsASN1(): ?Element
{
return NullType::create();
}
}
7 changes: 5 additions & 2 deletions src/CryptoTypes/Asymmetric/OneAsymmetricKey.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
use SpomkyLabs\Pki\CryptoTypes\Asymmetric\RFC8410\Curve448\Ed448PrivateKey;
use SpomkyLabs\Pki\CryptoTypes\Asymmetric\RFC8410\Curve448\X448PrivateKey;
use SpomkyLabs\Pki\CryptoTypes\Asymmetric\RSA\RSAPrivateKey;
use SpomkyLabs\Pki\CryptoTypes\Asymmetric\RSA\RSASSAPSSPrivateKey;
use UnexpectedValueException;
use function in_array;

Expand Down Expand Up @@ -181,10 +182,12 @@ public function privateKey(): PrivateKey
{
$algo = $this->algorithmIdentifier();
switch ($algo->oid()) {
// RSA (including RSASSA-PSS)
// RSA
case AlgorithmIdentifier::OID_RSA_ENCRYPTION:
case AlgorithmIdentifier::OID_RSASSA_PSS_ENCRYPTION:
return RSAPrivateKey::fromDER($this->privateKeyData);
// RSASSA-PSS
case AlgorithmIdentifier::OID_RSASSA_PSS_ENCRYPTION:
return RSASSAPSSPrivateKey::fromDER($this->privateKeyData);
// elliptic curve
case AlgorithmIdentifier::OID_EC_PUBLIC_KEY:
$pk = ECPrivateKey::fromDER($this->privateKeyData);
Expand Down
226 changes: 226 additions & 0 deletions src/CryptoTypes/Asymmetric/RSA/RSASSAPSSPrivateKey.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
<?php

declare(strict_types=1);

namespace SpomkyLabs\Pki\CryptoTypes\Asymmetric\RSA;

use SpomkyLabs\Pki\ASN1\Type\Constructed\Sequence;
use SpomkyLabs\Pki\ASN1\Type\Primitive\Integer;
use SpomkyLabs\Pki\ASN1\Type\UnspecifiedType;
use SpomkyLabs\Pki\CryptoEncoding\PEM;
use SpomkyLabs\Pki\CryptoTypes\AlgorithmIdentifier\Asymmetric\RSAPSSSSAEncryptionAlgorithmIdentifier;
use SpomkyLabs\Pki\CryptoTypes\AlgorithmIdentifier\Feature\AlgorithmIdentifierType;
use SpomkyLabs\Pki\CryptoTypes\Asymmetric\PrivateKey;
use SpomkyLabs\Pki\CryptoTypes\Asymmetric\PublicKey;
use UnexpectedValueException;

/**
* Implements PKCS #1 RSASSAPSSPrivateKey ASN.1 type.
*
* @see https://datatracker.ietf.org/doc/html/rfc8017#section-8.1
*/
final class RSASSAPSSPrivateKey extends PrivateKey
{
/**
* @param string $modulus Modulus
* @param string $publicExponent Public exponent
* @param string $privateExponent Private exponent
* @param string $prime1 First prime factor
* @param string $prime2 Second prime factor
* @param string $exponent1 First factor exponent
* @param string $exponent2 Second factor exponent
* @param string $coefficient CRT coefficient of the second factor
*/
private function __construct(
private readonly string $modulus,
private readonly string $publicExponent,
private readonly string $privateExponent,
private readonly string $prime1,
private readonly string $prime2,
private readonly string $exponent1,
private readonly string $exponent2,
private readonly string $coefficient
) {
}

public static function create(
string $n,
string $e,
string $d,
string $p,
string $q,
string $dp,
string $dq,
string $qi
): self {
return new self($n, $e, $d, $p, $q, $dp, $dq, $qi);
}

/**
* Initialize from ASN.1.
*/
public static function fromASN1(Sequence $seq): self
{
$version = $seq->at(0)
->asInteger()
->intNumber();
if ($version !== 0) {
throw new UnexpectedValueException('Version must be 0.');
}
// helper function get integer from given index
$get_int = static fn ($idx) => $seq->at($idx)
->asInteger()
->number();
$n = $get_int(1);
$e = $get_int(2);
$d = $get_int(3);
$p = $get_int(4);
$q = $get_int(5);
$dp = $get_int(6);
$dq = $get_int(7);
$qi = $get_int(8);
return self::create($n, $e, $d, $p, $q, $dp, $dq, $qi);
}

/**
* Initialize from DER data.
*/
public static function fromDER(string $data): self
{
return self::fromASN1(UnspecifiedType::fromDER($data)->asSequence());
}

/**
* @see PrivateKey::fromPEM()
*/
public static function fromPEM(PEM $pem): self
{
$pk = parent::fromPEM($pem);
if (! ($pk instanceof self)) {
throw new UnexpectedValueException('Not an RSA private key.');
}
return $pk;
}

/**
* Get modulus.
*
* @return string Base 10 integer
*/
public function modulus(): string
{
return $this->modulus;
}

/**
* Get public exponent.
*
* @return string Base 10 integer
*/
public function publicExponent(): string
{
return $this->publicExponent;
}

/**
* Get private exponent.
*
* @return string Base 10 integer
*/
public function privateExponent(): string
{
return $this->privateExponent;
}

/**
* Get first prime factor.
*
* @return string Base 10 integer
*/
public function prime1(): string
{
return $this->prime1;
}

/**
* Get second prime factor.
*
* @return string Base 10 integer
*/
public function prime2(): string
{
return $this->prime2;
}

/**
* Get first factor exponent.
*
* @return string Base 10 integer
*/
public function exponent1(): string
{
return $this->exponent1;
}

/**
* Get second factor exponent.
*
* @return string Base 10 integer
*/
public function exponent2(): string
{
return $this->exponent2;
}

/**
* Get CRT coefficient of the second factor.
*
* @return string Base 10 integer
*/
public function coefficient(): string
{
return $this->coefficient;
}

public function algorithmIdentifier(): AlgorithmIdentifierType
{
return RSAPSSSSAEncryptionAlgorithmIdentifier::create();
}

/**
* @return RSAPublicKey
*/
public function publicKey(): PublicKey
{
return RSAPublicKey::create($this->modulus, $this->publicExponent);
}

/**
* Generate ASN.1 structure.
*/
public function toASN1(): Sequence
{
return Sequence::create(
Integer::create(0),
Integer::create($this->modulus),
Integer::create($this->publicExponent),
Integer::create($this->privateExponent),
Integer::create($this->prime1),
Integer::create($this->prime2),
Integer::create($this->exponent1),
Integer::create($this->exponent2),
Integer::create($this->coefficient)
);
}

public function toDER(): string
{
return $this->toASN1()
->toDER();
}

public function toPEM(): PEM
{
return PEM::create(PEM::TYPE_PRIVATE_KEY, $this->toDER());
}
}

0 comments on commit 0b10c8b

Please sign in to comment.