.github
data
Dockerfiles
assets
conf
hooks
web
api
css
fonts
img
inc
ajax
lib
WebAuthn
Attestation
Format
AndroidKey.php
AndroidSafetyNet.php
Apple.php
FormatBase.php
None.php
Packed.php
Tpm.php
U2f.php
AttestationObject.php
AuthenticatorData.php
Binary
CBOR
rootCertificates
WebAuthn.php
WebAuthnException.php
sieve
vendor
CSSminifierExtended.php
JSminifierExtended.php
Yubico.php
array_merge_real.php
composer.json
composer.lock
presets
footer.inc.php
functions.acl.inc.php
functions.address_rewriting.inc.php
functions.admin.inc.php
functions.app_passwd.inc.php
functions.customize.inc.php
functions.dkim.inc.php
functions.docker.inc.php
functions.domain_admin.inc.php
functions.fail2ban.inc.php
functions.fwdhost.inc.php
functions.inc.php
functions.mailbox.inc.php
functions.mailq.inc.php
functions.oauth2.inc.php
functions.policy.inc.php
functions.presets.inc.php
functions.pushover.inc.php
functions.quarantine.inc.php
functions.quota_notification.inc.php
functions.ratelimit.inc.php
functions.rspamd.inc.php
functions.tls_policy_maps.inc.php
functions.transports.inc.php
header.inc.php
init_db.inc.php
prerequisites.inc.php
sessions.inc.php
spf.inc.php
triggers.inc.php
twig.inc.php
vars.inc.php
js
lang
oauth
templates
_rspamderror.php
_status.502.html
admin.php
autoconfig.php
autodiscover-json.php
autodiscover.php
debug.php
edit.php
favicon.png
index.php
json_api.php
mailbox.php
mobileconfig.php
qhandler.php
quarantine.php
queue.php
resource.php
robots.txt
sogo-auth.php
user.php
helper-scripts
.editorconfig
.env
.gitignore
CODE_OF_CONDUCT.md
CONTRIBUTING.md
LICENSE
README.md
SECURITY.md
create_cold_standby.sh
docker-compose.yml
generate_config.sh
update.sh
94 lines
3.4 KiB
PHP
94 lines
3.4 KiB
PHP
<?php
|
|
|
|
|
|
namespace lbuchs\WebAuthn\Attestation\Format;
|
|
use lbuchs\WebAuthn\Attestation\AuthenticatorData;
|
|
use lbuchs\WebAuthn\WebAuthnException;
|
|
use lbuchs\WebAuthn\Binary\ByteBuffer;
|
|
|
|
class U2f extends FormatBase {
|
|
private $_alg = -7;
|
|
private $_signature;
|
|
private $_x5c;
|
|
|
|
public function __construct($AttestionObject, AuthenticatorData $authenticatorData) {
|
|
parent::__construct($AttestionObject, $authenticatorData);
|
|
|
|
// check u2f data
|
|
$attStmt = $this->_attestationObject['attStmt'];
|
|
|
|
if (\array_key_exists('alg', $attStmt) && $attStmt['alg'] !== $this->_alg) {
|
|
throw new WebAuthnException('u2f only accepts algorithm -7 ("ES256"), but got ' . $attStmt['alg'], WebAuthnException::INVALID_DATA);
|
|
}
|
|
|
|
if (!\array_key_exists('sig', $attStmt) || !\is_object($attStmt['sig']) || !($attStmt['sig'] instanceof ByteBuffer)) {
|
|
throw new WebAuthnException('no signature found', WebAuthnException::INVALID_DATA);
|
|
}
|
|
|
|
if (!\array_key_exists('x5c', $attStmt) || !\is_array($attStmt['x5c']) || \count($attStmt['x5c']) !== 1) {
|
|
throw new WebAuthnException('invalid x5c certificate', WebAuthnException::INVALID_DATA);
|
|
}
|
|
|
|
if (!\is_object($attStmt['x5c'][0]) || !($attStmt['x5c'][0] instanceof ByteBuffer)) {
|
|
throw new WebAuthnException('invalid x5c certificate', WebAuthnException::INVALID_DATA);
|
|
}
|
|
|
|
$this->_signature = $attStmt['sig']->getBinaryString();
|
|
$this->_x5c = $attStmt['x5c'][0]->getBinaryString();
|
|
}
|
|
|
|
|
|
/*
|
|
* returns the key certificate in PEM format
|
|
* @return string
|
|
*/
|
|
public function getCertificatePem() {
|
|
$pem = '-----BEGIN CERTIFICATE-----' . "\n";
|
|
$pem .= \chunk_split(\base64_encode($this->_x5c), 64, "\n");
|
|
$pem .= '-----END CERTIFICATE-----' . "\n";
|
|
return $pem;
|
|
}
|
|
|
|
/**
|
|
* @param string $clientDataHash
|
|
*/
|
|
public function validateAttestation($clientDataHash) {
|
|
$publicKey = \openssl_pkey_get_public($this->getCertificatePem());
|
|
|
|
if ($publicKey === false) {
|
|
throw new WebAuthnException('invalid public key: ' . \openssl_error_string(), WebAuthnException::INVALID_PUBLIC_KEY);
|
|
}
|
|
|
|
// Let verificationData be the concatenation of (0x00 || rpIdHash || clientDataHash || credentialId || publicKeyU2F)
|
|
$dataToVerify = "\x00";
|
|
$dataToVerify .= $this->_authenticatorData->getRpIdHash();
|
|
$dataToVerify .= $clientDataHash;
|
|
$dataToVerify .= $this->_authenticatorData->getCredentialId();
|
|
$dataToVerify .= $this->_authenticatorData->getPublicKeyU2F();
|
|
|
|
$coseAlgorithm = $this->_getCoseAlgorithm($this->_alg);
|
|
|
|
// check certificate
|
|
return \openssl_verify($dataToVerify, $this->_signature, $publicKey, $coseAlgorithm->openssl) === 1;
|
|
}
|
|
|
|
/**
|
|
* validates the certificate against root certificates
|
|
* @param array $rootCas
|
|
* @return boolean
|
|
* @throws WebAuthnException
|
|
*/
|
|
public function validateRootCertificate($rootCas) {
|
|
$chainC = $this->_createX5cChainFile();
|
|
if ($chainC) {
|
|
$rootCas[] = $chainC;
|
|
}
|
|
|
|
$v = \openssl_x509_checkpurpose($this->getCertificatePem(), -1, $rootCas);
|
|
if ($v === -1) {
|
|
throw new WebAuthnException('error on validating root certificate: ' . \openssl_error_string(), WebAuthnException::CERTIFICATE_NOT_TRUSTED);
|
|
}
|
|
return $v;
|
|
}
|
|
}
|