PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 5.7.2
Defender Security – Malware Scanner, Login Security & Firewall v5.7.2
6.3.0 6.2.3 6.2.4 6.2.0 6.2.1 6.2.2 6.1.0 5.3.1 5.4.0 5.4.1 5.5.0 5.5.1 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.7.2 5.8.0 5.8.1 5.9.0 6.0.0 6.0.1 3.0.1 3.1.0 All 141 releases
defender-security / vendor / web-auth / webauthn-lib / src / Server.php

Server.php in Defender Security – Malware Scanner, Login Security & Firewall 5.7.2, at vendor/web-auth/webauthn-lib/src/Server.php

352 lines 13.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 declare(strict_types=1);
4
5 /*
6 * The MIT License (MIT)
7 *
8 * Copyright (c) 2014-2021 Spomky-Labs
9 *
10 * This software may be modified and distributed under the terms
11 * of the MIT license. See the LICENSE file for details.
12 */
13
14 namespace Webauthn;
15
16 use Assert\Assertion;
17 use Cose\Algorithm\Algorithm;
18 use Cose\Algorithm\ManagerFactory;
19 use Cose\Algorithm\Signature\ECDSA;
20 use Cose\Algorithm\Signature\EdDSA;
21 use Cose\Algorithm\Signature\RSA;
22 use Jose\Component\KeyManagement\JWKFactory;
23 use Jose\Component\Signature\Algorithm\RS256;
24 use Psr\Http\Client\ClientInterface;
25 use Psr\Http\Message\RequestFactoryInterface;
26 use Psr\Http\Message\ServerRequestInterface;
27 use Psr\Log\LoggerInterface;
28 use Psr\Log\NullLogger;
29 use Webauthn\AttestationStatement\AndroidKeyAttestationStatementSupport;
30 use Webauthn\AttestationStatement\AndroidSafetyNetAttestationStatementSupport;
31 use Webauthn\AttestationStatement\AttestationObjectLoader;
32 use Webauthn\AttestationStatement\AttestationStatementSupportManager;
33 use Webauthn\AttestationStatement\FidoU2FAttestationStatementSupport;
34 use Webauthn\AttestationStatement\NoneAttestationStatementSupport;
35 use Webauthn\AttestationStatement\PackedAttestationStatementSupport;
36 use Webauthn\AttestationStatement\TPMAttestationStatementSupport;
37 use Webauthn\AuthenticationExtensions\AuthenticationExtensionsClientInputs;
38 use Webauthn\AuthenticationExtensions\ExtensionOutputCheckerHandler;
39 use Webauthn\Counter\CounterChecker;
40 use Webauthn\MetadataService\MetadataStatementRepository;
41 use Webauthn\TokenBinding\IgnoreTokenBindingHandler;
42 use Webauthn\TokenBinding\TokenBindingHandler;
43
44 class Server
45 {
46 /**
47 * @var int
48 */
49 public $timeout = 60000;
50
51 /**
52 * @var int
53 */
54 public $challengeSize = 32;
55
56 /**
57 * @var PublicKeyCredentialRpEntity
58 */
59 private $rpEntity;
60
61 /**
62 * @var ManagerFactory
63 */
64 private $coseAlgorithmManagerFactory;
65
66 /**
67 * @var PublicKeyCredentialSourceRepository
68 */
69 private $publicKeyCredentialSourceRepository;
70
71 /**
72 * @var TokenBindingHandler
73 */
74 private $tokenBindingHandler;
75
76 /**
77 * @var ExtensionOutputCheckerHandler
78 */
79 private $extensionOutputCheckerHandler;
80
81 /**
82 * @var string[]
83 */
84 private $selectedAlgorithms;
85
86 /**
87 * @var MetadataStatementRepository|null
88 */
89 private $metadataStatementRepository;
90
91 /**
92 * @var ClientInterface|null
93 */
94 private $httpClient;
95
96 /**
97 * @var string|null
98 */
99 private $googleApiKey;
100
101 /**
102 * @var RequestFactoryInterface|null
103 */
104 private $requestFactory;
105
106 /**
107 * @var CounterChecker|null
108 */
109 private $counterChecker;
110
111 /**
112 * @var LoggerInterface
113 */
114 private $logger;
115
116 /**
117 * @var string[]
118 */
119 private $securedRelyingPartyId = [];
120
121 public function __construct(PublicKeyCredentialRpEntity $relyingParty, PublicKeyCredentialSourceRepository $publicKeyCredentialSourceRepository, ?MetadataStatementRepository $metadataStatementRepository = null)
122 {
123 if (null !== $metadataStatementRepository) {
124 @trigger_error('The argument "metadataStatementRepository" is deprecated since version 3.3 and will be removed in 4.0. Please use the method "setMetadataStatementRepository".', E_USER_DEPRECATED);
125 }
126 $this->rpEntity = $relyingParty;
127 $this->logger = new NullLogger();
128
129 $this->coseAlgorithmManagerFactory = new ManagerFactory();
130 $this->coseAlgorithmManagerFactory->add('RS1', new RSA\RS1());
131 $this->coseAlgorithmManagerFactory->add('RS256', new RSA\RS256());
132 $this->coseAlgorithmManagerFactory->add('RS384', new RSA\RS384());
133 $this->coseAlgorithmManagerFactory->add('RS512', new RSA\RS512());
134 $this->coseAlgorithmManagerFactory->add('PS256', new RSA\PS256());
135 $this->coseAlgorithmManagerFactory->add('PS384', new RSA\PS384());
136 $this->coseAlgorithmManagerFactory->add('PS512', new RSA\PS512());
137 $this->coseAlgorithmManagerFactory->add('ES256', new ECDSA\ES256());
138 $this->coseAlgorithmManagerFactory->add('ES256K', new ECDSA\ES256K());
139 $this->coseAlgorithmManagerFactory->add('ES384', new ECDSA\ES384());
140 $this->coseAlgorithmManagerFactory->add('ES512', new ECDSA\ES512());
141 $this->coseAlgorithmManagerFactory->add('Ed25519', new EdDSA\Ed25519());
142
143 $this->selectedAlgorithms = ['RS256', 'RS512', 'PS256', 'PS512', 'ES256', 'ES512', 'Ed25519'];
144 $this->publicKeyCredentialSourceRepository = $publicKeyCredentialSourceRepository;
145 $this->tokenBindingHandler = new IgnoreTokenBindingHandler();
146 $this->extensionOutputCheckerHandler = new ExtensionOutputCheckerHandler();
147 $this->metadataStatementRepository = $metadataStatementRepository;
148 }
149
150 public function setMetadataStatementRepository(MetadataStatementRepository $metadataStatementRepository): self
151 {
152 $this->metadataStatementRepository = $metadataStatementRepository;
153
154 return $this;
155 }
156
157 /**
158 * @param string[] $selectedAlgorithms
159 */
160 public function setSelectedAlgorithms(array $selectedAlgorithms): self
161 {
162 $this->selectedAlgorithms = $selectedAlgorithms;
163
164 return $this;
165 }
166
167 public function setTokenBindingHandler(TokenBindingHandler $tokenBindingHandler): self
168 {
169 $this->tokenBindingHandler = $tokenBindingHandler;
170
171 return $this;
172 }
173
174 public function addAlgorithm(string $alias, Algorithm $algorithm): self
175 {
176 $this->coseAlgorithmManagerFactory->add($alias, $algorithm);
177 $this->selectedAlgorithms[] = $alias;
178 $this->selectedAlgorithms = array_unique($this->selectedAlgorithms);
179
180 return $this;
181 }
182
183 public function setExtensionOutputCheckerHandler(ExtensionOutputCheckerHandler $extensionOutputCheckerHandler): self
184 {
185 $this->extensionOutputCheckerHandler = $extensionOutputCheckerHandler;
186
187 return $this;
188 }
189
190 /**
191 * @param string[] $securedRelyingPartyId
192 */
193 public function setSecuredRelyingPartyId(array $securedRelyingPartyId): self
194 {
195 Assertion::allString($securedRelyingPartyId, 'Invalid list. Shall be a list of strings');
196 $this->securedRelyingPartyId = $securedRelyingPartyId;
197
198 return $this;
199 }
200
201 /**
202 * @param PublicKeyCredentialDescriptor[] $excludedPublicKeyDescriptors
203 */
204 public function generatePublicKeyCredentialCreationOptions(PublicKeyCredentialUserEntity $userEntity, ?string $attestationMode = null, array $excludedPublicKeyDescriptors = [], ?AuthenticatorSelectionCriteria $criteria = null, ?AuthenticationExtensionsClientInputs $extensions = null): PublicKeyCredentialCreationOptions
205 {
206 $coseAlgorithmManager = $this->coseAlgorithmManagerFactory->create($this->selectedAlgorithms);
207 $publicKeyCredentialParametersList = [];
208 foreach ($coseAlgorithmManager->all() as $algorithm) {
209 $publicKeyCredentialParametersList[] = new PublicKeyCredentialParameters(
210 PublicKeyCredentialDescriptor::CREDENTIAL_TYPE_PUBLIC_KEY,
211 $algorithm::identifier()
212 );
213 }
214 $criteria = $criteria ?? new AuthenticatorSelectionCriteria();
215 $extensions = $extensions ?? new AuthenticationExtensionsClientInputs();
216 $challenge = random_bytes($this->challengeSize);
217
218 return PublicKeyCredentialCreationOptions::create(
219 $this->rpEntity,
220 $userEntity,
221 $challenge,
222 $publicKeyCredentialParametersList
223 )
224 ->excludeCredentials($excludedPublicKeyDescriptors)
225 ->setAuthenticatorSelection($criteria)
226 ->setAttestation($attestationMode ?? PublicKeyCredentialCreationOptions::ATTESTATION_CONVEYANCE_PREFERENCE_NONE)
227 ->setExtensions($extensions)
228 ->setTimeout($this->timeout)
229 ;
230 }
231
232 /**
233 * @param PublicKeyCredentialDescriptor[] $allowedPublicKeyDescriptors
234 */
235 public function generatePublicKeyCredentialRequestOptions(?string $userVerification = null, array $allowedPublicKeyDescriptors = [], ?AuthenticationExtensionsClientInputs $extensions = null): PublicKeyCredentialRequestOptions
236 {
237 return PublicKeyCredentialRequestOptions::create(random_bytes($this->challengeSize))
238 ->setRpId($this->rpEntity->getId())
239 ->setUserVerification($userVerification ?? PublicKeyCredentialRequestOptions::USER_VERIFICATION_REQUIREMENT_PREFERRED)
240 ->allowCredentials($allowedPublicKeyDescriptors)
241 ->setTimeout($this->timeout)
242 ->setExtensions($extensions ?? new AuthenticationExtensionsClientInputs())
243 ;
244 }
245
246 public function loadAndCheckAttestationResponse(string $data, PublicKeyCredentialCreationOptions $publicKeyCredentialCreationOptions, ServerRequestInterface $serverRequest): PublicKeyCredentialSource
247 {
248 $attestationStatementSupportManager = $this->getAttestationStatementSupportManager();
249 $attestationObjectLoader = AttestationObjectLoader::create($attestationStatementSupportManager)
250 ->setLogger($this->logger)
251 ;
252 $publicKeyCredentialLoader = PublicKeyCredentialLoader::create($attestationObjectLoader)
253 ->setLogger($this->logger)
254 ;
255
256 $publicKeyCredential = $publicKeyCredentialLoader->load($data);
257 $authenticatorResponse = $publicKeyCredential->getResponse();
258 Assertion::isInstanceOf($authenticatorResponse, AuthenticatorAttestationResponse::class, 'Not an authenticator attestation response');
259
260 $authenticatorAttestationResponseValidator = new AuthenticatorAttestationResponseValidator(
261 $attestationStatementSupportManager,
262 $this->publicKeyCredentialSourceRepository,
263 $this->tokenBindingHandler,
264 $this->extensionOutputCheckerHandler,
265 $this->metadataStatementRepository
266 );
267 $authenticatorAttestationResponseValidator->setLogger($this->logger);
268
269 return $authenticatorAttestationResponseValidator->check($authenticatorResponse, $publicKeyCredentialCreationOptions, $serverRequest, $this->securedRelyingPartyId);
270 }
271
272 public function loadAndCheckAssertionResponse(string $data, PublicKeyCredentialRequestOptions $publicKeyCredentialRequestOptions, ?PublicKeyCredentialUserEntity $userEntity, ServerRequestInterface $serverRequest): PublicKeyCredentialSource
273 {
274 $attestationStatementSupportManager = $this->getAttestationStatementSupportManager();
275 $attestationObjectLoader = AttestationObjectLoader::create($attestationStatementSupportManager)
276 ->setLogger($this->logger)
277 ;
278 $publicKeyCredentialLoader = PublicKeyCredentialLoader::create($attestationObjectLoader)
279 ->setLogger($this->logger)
280 ;
281
282 $publicKeyCredential = $publicKeyCredentialLoader->load($data);
283 $authenticatorResponse = $publicKeyCredential->getResponse();
284 Assertion::isInstanceOf($authenticatorResponse, AuthenticatorAssertionResponse::class, 'Not an authenticator assertion response');
285
286 $authenticatorAssertionResponseValidator = new AuthenticatorAssertionResponseValidator(
287 $this->publicKeyCredentialSourceRepository,
288 $this->tokenBindingHandler,
289 $this->extensionOutputCheckerHandler,
290 $this->coseAlgorithmManagerFactory->create($this->selectedAlgorithms),
291 $this->counterChecker
292 );
293 $authenticatorAssertionResponseValidator->setLogger($this->logger);
294
295 return $authenticatorAssertionResponseValidator->check(
296 $publicKeyCredential->getRawId(),
297 $authenticatorResponse,
298 $publicKeyCredentialRequestOptions,
299 $serverRequest,
300 null !== $userEntity ? $userEntity->getId() : null,
301 $this->securedRelyingPartyId
302 );
303 }
304
305 public function setCounterChecker(CounterChecker $counterChecker): self
306 {
307 $this->counterChecker = $counterChecker;
308
309 return $this;
310 }
311
312 public function setLogger(LoggerInterface $logger): self
313 {
314 $this->logger = $logger;
315
316 return $this;
317 }
318
319 public function enforceAndroidSafetyNetVerification(ClientInterface $client, string $apiKey, RequestFactoryInterface $requestFactory): self
320 {
321 $this->httpClient = $client;
322 $this->googleApiKey = $apiKey;
323 $this->requestFactory = $requestFactory;
324
325 return $this;
326 }
327
328 private function getAttestationStatementSupportManager(): AttestationStatementSupportManager
329 {
330 $attestationStatementSupportManager = new AttestationStatementSupportManager();
331 $attestationStatementSupportManager->add(new NoneAttestationStatementSupport());
332 $attestationStatementSupportManager->add(new FidoU2FAttestationStatementSupport());
333 if (class_exists(RS256::class) && class_exists(JWKFactory::class)) {
334 $androidSafetyNetAttestationStatementSupport = new AndroidSafetyNetAttestationStatementSupport();
335 if (null !== $this->httpClient && null !== $this->googleApiKey && null !== $this->requestFactory) {
336 $androidSafetyNetAttestationStatementSupport
337 ->enableApiVerification($this->httpClient, $this->googleApiKey, $this->requestFactory)
338 ->setLeeway(2000)
339 ->setMaxAge(60000)
340 ;
341 }
342 $attestationStatementSupportManager->add($androidSafetyNetAttestationStatementSupport);
343 }
344 $attestationStatementSupportManager->add(new AndroidKeyAttestationStatementSupport());
345 $attestationStatementSupportManager->add(new TPMAttestationStatementSupport());
346 $coseAlgorithmManager = $this->coseAlgorithmManagerFactory->create($this->selectedAlgorithms);
347 $attestationStatementSupportManager->add(new PackedAttestationStatementSupport($coseAlgorithmManager));
348
349 return $attestationStatementSupportManager;
350 }
351 }
352