Skip to content
This repository was archived by the owner on Mar 25, 2024. It is now read-only.

Commit 2ce936d

Browse files
committed
Move the Attestation Certificate verification code to trait
The purpose of this change is twofold: 1. The logic in the Server code is slightly easier to follow 2. Existing Registrations can easily be re-verified outside of the token registration process, allowing implementations to effectively revoke an entire vendor if it ever becomes necessary
1 parent af1f25b commit 2ce936d

3 files changed

Lines changed: 61 additions & 6 deletions

File tree

src/AttestationCertificateTrait.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,15 @@ public function setAttestationCertificate(string $cert): self {
2929
return $this;
3030
}
3131

32+
public function verifyIssuerAgainstTrustedCAs(array $trusted_cas): bool {
33+
$result = openssl_x509_checkpurpose(
34+
$this->getAttestationCertificatePem(),
35+
\X509_PURPOSE_ANY,
36+
$trusted_cas);
37+
if ($result !== true) {
38+
throw new SecurityException(SecurityException::NO_TRUSTED_CA);
39+
}
40+
return $result;
41+
}
42+
3243
}

src/Server.php

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -200,12 +200,7 @@ public function register(RegisterResponse $resp): Registration {
200200

201201
$pem = $resp->getAttestationCertificatePem();
202202
if ($this->verifyCA) {
203-
$check = openssl_x509_checkpurpose($pem,
204-
\X509_PURPOSE_ANY,
205-
$this->trustedCAs);
206-
if ($check !== true) {
207-
throw new SE(SE::NO_TRUSTED_CA);
208-
}
203+
$resp->verifyIssuerAgainstTrustedCAs($this->trustedCAs);
209204
}
210205

211206
// Signature must validate against device issuer's public key

tests/AttestationCertificateTraitTest.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,53 @@ public function testGetAttestationCertificatePem() {
4040
$this->assertSame($expected, $obj->getAttestationCertificatePem(),
4141
'PEM-formatted certificate was incorrect');
4242
}
43+
44+
/**
45+
* @covers ::verifyIssuerAgainstTrustedCAs
46+
*/
47+
public function testSuccessfulCAVerification() {
48+
$class = $this->getObjectWithYubicoCert();
49+
$certs = [dirname(__DIR__).'/CAcerts/yubico.pem'];
50+
$this->assertTrue($class->verifyIssuerAgainstTrustedCAs($certs));
51+
}
52+
53+
/**
54+
* @covers ::verifyIssuerAgainstTrustedCAs
55+
*/
56+
public function testFailedCAVerification() {
57+
$class = $this->getObjectWithYubicoCert();
58+
$certs = [__DIR__.'/verisign_only_for_unit_tests.pem'];
59+
$this->expectException(SecurityException::class);
60+
$this->expectExceptionCode(SecurityException::NO_TRUSTED_CA);
61+
$class->verifyIssuerAgainstTrustedCAs($certs);
62+
}
63+
64+
/**
65+
* @covers ::verifyIssuerAgainstTrustedCAs
66+
*/
67+
public function testFailedCAVerificationFromNoCAs() {
68+
$class = $this->getObjectWithYubicoCert();
69+
$certs = [];
70+
$this->expectException(SecurityException::class);
71+
$this->expectExceptionCode(SecurityException::NO_TRUSTED_CA);
72+
$class->verifyIssuerAgainstTrustedCAs($certs);
73+
}
74+
75+
// -(Helper methods)-------------------------------------------------------
76+
77+
/**
78+
* Returns some concrete implementation of a class using
79+
* AttestationCertificateTrait
80+
*
81+
* @return mixed Some class using AttestationCertificateTrait
82+
*/
83+
private function getObjectWithYubicoCert() {
84+
$response = RegisterResponse::fromJson(
85+
file_get_contents(__DIR__.'/register_response.json'));
86+
// Sanity check that the response actually imlements this trait, rather
87+
// than doing all sorts of magic
88+
$check = AttestationCertificateTrait::class;
89+
$this->assertContains($check, class_uses($response));
90+
return $response;
91+
}
4392
}

0 commit comments

Comments
 (0)