assertEquals('test-key', $key->keyId); $this->assertEquals('my-secret-that-is-long-enough-for-security', $key->keyMaterial); $this->assertEquals(SigningAlgorithm::HMAC_SHA256, $key->algorithm); $this->assertTrue($key->isActive); $this->assertNull($key->expiresAt); } #[Test] public function it_can_create_hmac_key_with_expiration(): void { $expiresAt = new \DateTimeImmutable('+1 hour'); $key = SigningKey::createHmac( 'test-key', 'my-secret-that-is-long-enough-for-security', SigningAlgorithm::HMAC_SHA512, $expiresAt ); $this->assertEquals(SigningAlgorithm::HMAC_SHA512, $key->algorithm); $this->assertEquals($expiresAt, $key->expiresAt); $this->assertFalse($key->isExpired()); } #[Test] public function it_can_generate_random_hmac_key(): void { $key = SigningKey::generateHmac('random-key'); $this->assertEquals('random-key', $key->keyId); $this->assertEquals(SigningAlgorithm::HMAC_SHA256, $key->algorithm); $this->assertGreaterThanOrEqual(64, strlen($key->keyMaterial)); // 32 bytes = 64 hex chars $this->assertTrue($key->isValid()); } #[Test] public function it_can_create_rsa_key(): void { // Generate test RSA key pair $keyPair = openssl_pkey_new([ 'digest_alg' => 'sha256', 'private_key_bits' => 2048, 'private_key_type' => OPENSSL_KEYTYPE_RSA, ]); openssl_pkey_export($keyPair, $privateKey); $key = SigningKey::createRsa('rsa-key', $privateKey); $this->assertEquals('rsa-key', $key->keyId); $this->assertEquals(SigningAlgorithm::RSA_SHA256, $key->algorithm); $this->assertEquals($privateKey, $key->keyMaterial); $this->assertTrue($key->isValid()); } #[Test] public function it_throws_exception_for_short_key_material(): void { $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('Key material must be at least 32 bytes long'); new SigningKey('test', 'short-key', SigningAlgorithm::HMAC_SHA256); } #[Test] public function it_throws_exception_for_invalid_rsa_key(): void { $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('Invalid RSA private key'); SigningKey::createRsa('invalid-rsa', 'not-a-valid-rsa-key'); } #[Test] public function it_detects_expired_keys(): void { $expiredKey = SigningKey::createHmac( 'expired-key', 'my-secret-that-is-long-enough-for-security', expiresAt: new \DateTimeImmutable('2020-01-01') ); $this->assertTrue($expiredKey->isExpired()); $this->assertFalse($expiredKey->isValid()); } #[Test] public function it_validates_non_expired_keys(): void { $futureKey = SigningKey::createHmac( 'future-key', 'my-secret-that-is-long-enough-for-security', expiresAt: new \DateTimeImmutable('+1 hour') ); $this->assertFalse($futureKey->isExpired()); $this->assertTrue($futureKey->isValid()); } #[Test] public function it_handles_keys_without_expiration(): void { $permanentKey = SigningKey::createHmac( 'permanent-key', 'my-secret-that-is-long-enough-for-security' ); $this->assertFalse($permanentKey->isExpired()); $this->assertTrue($permanentKey->isValid()); } #[Test] public function it_throws_exception_for_asymmetric_algorithm_with_hmac_factory(): void { $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('Algorithm must be symmetric for HMAC keys'); SigningKey::createHmac('test', 'my-secret-that-is-long-enough-for-security', SigningAlgorithm::RSA_SHA256); } #[Test] public function it_throws_exception_for_asymmetric_algorithm_with_generate_factory(): void { $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('Algorithm must be symmetric for HMAC keys'); SigningKey::generateHmac('test', SigningAlgorithm::RSA_SHA256); } }