Skip to content

Commit 94d16d3

Browse files
committed
Validate the security.txt file even when the GPG signature is damaged
Close #43
1 parent 8c446c1 commit 94d16d3

File tree

8 files changed

+53
-30
lines changed

8 files changed

+53
-30
lines changed

src/Check/SecurityTxtCheckHost.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
use Spaze\SecurityTxt\Fetcher\SecurityTxtFetcher;
1818
use Spaze\SecurityTxt\Parser\SecurityTxtParser;
1919
use Spaze\SecurityTxt\Parser\SecurityTxtUrlParser;
20-
use Spaze\SecurityTxt\Signature\Exceptions\SecurityTxtCannotVerifySignatureException;
2120
use Spaze\SecurityTxt\Violations\SecurityTxtSpecViolation;
2221

2322
final class SecurityTxtCheckHost
@@ -86,7 +85,6 @@ public function __construct(
8685
* @throws SecurityTxtOnlyIpv6HostButIpv6DisabledException
8786
* @throws SecurityTxtHostIpAddressInvalidTypeException
8887
* @throws SecurityTxtHostIpAddressNotFoundException
89-
* @throws SecurityTxtCannotVerifySignatureException
9088
*/
9189
public function check(string $url, ?int $expiresWarningThreshold = null, bool $strictMode = false, bool $requireTopLevelLocation = false, bool $noIpv6 = false): SecurityTxtCheckHostResult
9290
{

src/Check/SecurityTxtCheckHostCli.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
use DateTimeImmutable;
77
use Spaze\SecurityTxt\Fetcher\Exceptions\SecurityTxtFetcherException;
8-
use Spaze\SecurityTxt\Signature\Exceptions\SecurityTxtCannotVerifySignatureException;
98

109
final readonly class SecurityTxtCheckHostCli
1110
{
@@ -120,7 +119,7 @@ function (string $keyFingerprint, DateTimeImmutable $signatureDate): void {
120119
} else {
121120
$this->exit(CheckExitStatus::Ok);
122121
}
123-
} catch (SecurityTxtFetcherException | SecurityTxtCannotVerifySignatureException $e) {
122+
} catch (SecurityTxtFetcherException $e) {
124123
$this->consolePrinter->error($e->getMessage());
125124
$this->exit(CheckExitStatus::FileError);
126125
}

src/Parser/SecurityTxtParser.php

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
use Spaze\SecurityTxt\Parser\FieldProcessors\PreferredLanguagesSetFieldValue;
2424
use Spaze\SecurityTxt\SecurityTxt;
2525
use Spaze\SecurityTxt\SecurityTxtValidationLevel;
26-
use Spaze\SecurityTxt\Signature\Exceptions\SecurityTxtCannotVerifySignatureException;
2726
use Spaze\SecurityTxt\Signature\SecurityTxtSignature;
2827
use Spaze\SecurityTxt\Validator\SecurityTxtValidator;
2928
use Spaze\SecurityTxt\Violations\SecurityTxtLineNoEol;
@@ -109,9 +108,6 @@ private function processField(int $lineNumber, string $value, SecurityTxtField $
109108
}
110109

111110

112-
/**
113-
* @throws SecurityTxtCannotVerifySignatureException
114-
*/
115111
public function parseString(string $contents, ?string $fileLocation = null, ?int $expiresWarningThreshold = null, bool $strictMode = false): SecurityTxtParseStringResult
116112
{
117113
$this->expiresWarningThreshold = $expiresWarningThreshold;
@@ -168,9 +164,6 @@ public function parseString(string $contents, ?string $fileLocation = null, ?int
168164
}
169165

170166

171-
/**
172-
* @throws SecurityTxtCannotVerifySignatureException
173-
*/
174167
public function parseFetchResult(SecurityTxtFetchResult $fetchResult, ?int $expiresWarningThreshold = null, bool $strictMode = false): SecurityTxtParseHostResult
175168
{
176169
$parseResult = $this->parseString($fetchResult->getContents(), $fetchResult->getFinalUrl(), $expiresWarningThreshold, $strictMode);
@@ -184,7 +177,6 @@ public function parseFetchResult(SecurityTxtFetchResult $fetchResult, ?int $expi
184177

185178
/**
186179
* @param int<1, max> $lineNumber
187-
* @throws SecurityTxtCannotVerifySignatureException
188180
*/
189181
private function checkSignature(int $lineNumber, string $line, string $contents, SecurityTxt $securityTxt): SecurityTxt
190182
{

src/Signature/Exceptions/SecurityTxtSignatureErrorInfoException.php

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,24 @@
99
abstract class SecurityTxtSignatureErrorInfoException extends SecurityTxtSignatureException
1010
{
1111

12-
public function __construct(string $message, SecurityTxtSignatureErrorInfo $errorInfo, ?Throwable $previous = null)
12+
public function __construct(
13+
string $message,
14+
private readonly SecurityTxtSignatureErrorInfo $errorInfo,
15+
?Throwable $previous = null,
16+
) {
17+
parent::__construct("{$message}: " . $this->getErrorInfoMessage(), $this->errorInfo->getCode() ?? 0, previous: $previous);
18+
}
19+
20+
21+
public function getErrorInfoMessage(): string
1322
{
14-
$message = sprintf(
15-
'%s: %s; code: %s, source: %s, library message: %s',
16-
$message,
17-
$errorInfo->getMessage() === false ? '<false>' : ($errorInfo->getMessage() === null ? '<null>' : $errorInfo->getMessage()),
18-
$errorInfo->getCode() ?? '<null>',
19-
$errorInfo->getSource() ?? '<null>',
20-
$errorInfo->getLibraryMessage() ?? '<null>',
23+
return sprintf(
24+
'%s, %s, %s, %s',
25+
$this->errorInfo->getMessage() === false ? '<false>' : ($this->errorInfo->getMessage() === null ? '<null>' : $this->errorInfo->getMessage()),
26+
$this->errorInfo->getCode() ?? '<null>',
27+
$this->errorInfo->getSource() ?? '<null>',
28+
$this->errorInfo->getLibraryMessage() ?? '<null>',
2129
);
22-
parent::__construct($message, $errorInfo->getCode() ?? 0, previous: $previous);
2330
}
2431

2532
}

src/Signature/SecurityTxtSignature.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Spaze\SecurityTxt\Signature\Exceptions\SecurityTxtUnknownSigningKeyException;
1616
use Spaze\SecurityTxt\Signature\Exceptions\SecurityTxtUnusableSigningKeyException;
1717
use Spaze\SecurityTxt\Signature\Providers\SecurityTxtSignatureProvider;
18+
use Spaze\SecurityTxt\Violations\SecurityTxtSignatureCannotVerify;
1819
use Spaze\SecurityTxt\Violations\SecurityTxtSignatureExtensionNotLoaded;
1920
use Spaze\SecurityTxt\Violations\SecurityTxtSignatureInvalid;
2021

@@ -37,14 +38,15 @@ public function __construct(private SecurityTxtSignatureProvider $signatureProvi
3738
/**
3839
* @throws SecurityTxtError
3940
* @throws SecurityTxtWarning
40-
* @throws SecurityTxtCannotVerifySignatureException
4141
*/
4242
public function verify(string $contents): SecurityTxtSignatureVerifyResult
4343
{
4444
try {
4545
$signature = $this->signatureProvider->verify($contents);
4646
} catch (SecurityTxtCannotCreateSignatureExtensionNotLoadedException $e) {
4747
throw new SecurityTxtWarning(new SecurityTxtSignatureExtensionNotLoaded(), $e);
48+
} catch (SecurityTxtCannotVerifySignatureException $e) {
49+
throw new SecurityTxtWarning(new SecurityTxtSignatureCannotVerify($e->getErrorInfoMessage()), $e);
4850
}
4951

5052
if (!$this->isSignatureKindaOkay($signature->getSummary())) {
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
declare(strict_types = 1);
3+
4+
namespace Spaze\SecurityTxt\Violations;
5+
6+
final class SecurityTxtSignatureCannotVerify extends SecurityTxtSpecViolation
7+
{
8+
9+
public function __construct(string $message)
10+
{
11+
parent::__construct(
12+
func_get_args(),
13+
"The file is digitally signed using an OpenPGP cleartext signature but the signature is damaged and cannot be verified ({$message})",
14+
[],
15+
'draft-foudil-securitytxt-01',
16+
null,
17+
'Sign the file again',
18+
[],
19+
'2.3',
20+
);
21+
}
22+
23+
}

tests/Signature/Providers/SecurityTxtSignatureGnuPgProviderTest.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ final class SecurityTxtSignatureGnuPgProviderTest extends TestCase
6262
$gnuPg->verify('fifteen hundred and seven systems in one day');
6363
}, SecurityTxtCannotVerifySignatureException::class);
6464
assert($e instanceof SecurityTxtCannotVerifySignatureException);
65-
Assert::same('Cannot verify signature: verify failed; code: 117440570, source: GPGME, library message: No data', $e->getMessage());
65+
Assert::same('Cannot verify signature: verify failed, 117440570, GPGME, No data', $e->getMessage());
6666
$errorInfo = $gnuPg->getErrorInfo();
6767
Assert::same('verify failed', $errorInfo->getMessage());
6868
}

tests/Signature/SecurityTxtSignatureTest.phpt

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use Spaze\SecurityTxt\Signature\Exceptions\SecurityTxtSigningKeyNoPassphraseSetE
2020
use Spaze\SecurityTxt\Signature\Exceptions\SecurityTxtUnknownSigningKeyException;
2121
use Spaze\SecurityTxt\Signature\Exceptions\SecurityTxtUnusableSigningKeyException;
2222
use Spaze\SecurityTxt\Signature\Providers\SecurityTxtSignatureProvider;
23+
use Spaze\SecurityTxt\Violations\SecurityTxtSignatureCannotVerify;
2324
use Spaze\SecurityTxt\Violations\SecurityTxtSignatureExtensionNotLoaded;
2425
use Spaze\SecurityTxt\Violations\SecurityTxtSignatureInvalid;
2526
use Tester\Assert;
@@ -54,22 +55,22 @@ final class SecurityTxtSignatureTest extends TestCase
5455
$signature = new SecurityTxtSignature($this->getSignatureProvider(addSignKeyReturnValue: false, errorInfo: new SecurityTxtSignatureErrorInfo(false, 31336, 'unusable key source', 'unusable key lib error')));
5556
Assert::throws(function () use ($signature): void {
5657
$signature->sign('foo', 'unusable sign key', 'irrelevant');
57-
}, SecurityTxtUnusableSigningKeyException::class, 'Unusable signing key unusable sign key: <false>; code: 31336, source: unusable key source, library message: unusable key lib error', 31336);
58+
}, SecurityTxtUnusableSigningKeyException::class, 'Unusable signing key unusable sign key: <false>, 31336, unusable key source, unusable key lib error', 31336);
5859

5960
$signature = new SecurityTxtSignature($this->getSignatureProvider(addSignKeyReturnValue: false, errorInfo: new SecurityTxtSignatureErrorInfo('unusable key', 31336, 'unusable key source', 'unusable key lib error')));
6061
Assert::throws(function () use ($signature): void {
6162
$signature->sign('foo', 'unusable sign key', 'irrelevant');
62-
}, SecurityTxtUnusableSigningKeyException::class, 'Unusable signing key unusable sign key: unusable key; code: 31336, source: unusable key source, library message: unusable key lib error', 31336);
63+
}, SecurityTxtUnusableSigningKeyException::class, 'Unusable signing key unusable sign key: unusable key, 31336, unusable key source, unusable key lib error', 31336);
6364

6465
$signature = new SecurityTxtSignature($this->getSignatureProvider(addSignKeyReturnValue: true, errorInfo: new SecurityTxtSignatureErrorInfo(false, 1, 'sign source', 'sign lib error'), signReturnValue: false));
6566
Assert::throws(function () use ($signature): void {
6667
$signature->sign('foo', 'sign key 1', 'passphrase');
67-
}, SecurityTxtCannotCreateSignatureException::class, 'Cannot create a signature using key sign key 1: <false>; code: 1, source: sign source, library message: sign lib error');
68+
}, SecurityTxtCannotCreateSignatureException::class, 'Cannot create a signature using key sign key 1: <false>, 1, sign source, sign lib error');
6869

6970
$signature = new SecurityTxtSignature($this->getSignatureProvider(addSignKeyReturnValue: true, errorInfo: new SecurityTxtSignatureErrorInfo('sign error', 1, 'sign source', 'sign lib error'), signReturnValue: false));
7071
Assert::throws(function () use ($signature): void {
7172
$signature->sign('foo', 'sign key 1', 'passphrase');
72-
}, SecurityTxtCannotCreateSignatureException::class, 'Cannot create a signature using key sign key 1: sign error; code: 1, source: sign source, library message: sign lib error');
73+
}, SecurityTxtCannotCreateSignatureException::class, 'Cannot create a signature using key sign key 1: sign error, 1, sign source, sign lib error');
7374

7475
$signature = new SecurityTxtSignature($this->getSignatureProvider(addSignKeyReturnValue: true, signReturnValue: 'signed'));
7576
Assert::same('signed', $signature->sign('foo', 'multiple add', 'passphrase'));
@@ -124,9 +125,10 @@ final class SecurityTxtSignatureTest extends TestCase
124125
$signature = new SecurityTxtSignature($this->getSignatureProvider(verifyThrows: new SecurityTxtCannotVerifySignatureException(null, new SecurityTxtSignatureErrorInfo('msg', 1336, null, null))));
125126
$e = Assert::throws(function () use ($signature): void {
126127
$signature->verify('gnupg::verify returns invalid array');
127-
}, SecurityTxtCannotVerifySignatureException::class);
128-
assert($e instanceof SecurityTxtCannotVerifySignatureException);
129-
Assert::same('Cannot verify signature: msg; code: 1336, source: <null>, library message: <null>', $e->getMessage());
128+
}, SecurityTxtWarning::class);
129+
assert($e instanceof SecurityTxtWarning);
130+
Assert::type(SecurityTxtSignatureCannotVerify::class, $e->getViolation());
131+
Assert::same('The file is digitally signed using an OpenPGP cleartext signature but the signature is damaged and cannot be verified (msg, 1336, <null>, <null>)', $e->getMessage());
130132
}
131133

132134

0 commit comments

Comments
 (0)