Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
 
3
namespace lbuchs\WebAuthn\Attestation;
4
use lbuchs\WebAuthn\WebAuthnException;
5
use lbuchs\WebAuthn\CBOR\CborDecoder;
6
use lbuchs\WebAuthn\Binary\ByteBuffer;
7
 
8
/**
9
 * @author Lukas Buchs
10
 * @license https://github.com/lbuchs/WebAuthn/blob/master/LICENSE MIT
11
 */
12
class AttestationObject {
13
    private $_authenticatorData;
14
    private $_attestationFormat;
15
    private $_attestationFormatName;
16
 
17
    public function __construct($binary , $allowedFormats) {
18
        $enc = CborDecoder::decode($binary);
19
        // validation
20
        if (!\is_array($enc) || !\array_key_exists('fmt', $enc) || !is_string($enc['fmt'])) {
21
            throw new WebAuthnException('invalid attestation format', WebAuthnException::INVALID_DATA);
22
        }
23
 
24
        if (!\array_key_exists('attStmt', $enc) || !\is_array($enc['attStmt'])) {
25
            throw new WebAuthnException('invalid attestation format (attStmt not available)', WebAuthnException::INVALID_DATA);
26
        }
27
 
28
        if (!\array_key_exists('authData', $enc) || !\is_object($enc['authData']) || !($enc['authData'] instanceof ByteBuffer)) {
29
            throw new WebAuthnException('invalid attestation format (authData not available)', WebAuthnException::INVALID_DATA);
30
        }
31
 
32
        $this->_authenticatorData = new AuthenticatorData($enc['authData']->getBinaryString());
33
        $this->_attestationFormatName = $enc['fmt'];
34
 
35
        // Format ok?
36
        if (!in_array($this->_attestationFormatName, $allowedFormats)) {
37
            throw new WebAuthnException('invalid atttestation format: ' . $this->_attestationFormatName, WebAuthnException::INVALID_DATA);
38
        }
39
 
40
 
41
        switch ($this->_attestationFormatName) {
42
            case 'android-key': $this->_attestationFormat = new Format\AndroidKey($enc, $this->_authenticatorData); break;
43
            case 'android-safetynet': $this->_attestationFormat = new Format\AndroidSafetyNet($enc, $this->_authenticatorData); break;
44
            case 'apple': $this->_attestationFormat = new Format\Apple($enc, $this->_authenticatorData); break;
45
            case 'fido-u2f': $this->_attestationFormat = new Format\U2f($enc, $this->_authenticatorData); break;
46
            case 'none': $this->_attestationFormat = new Format\None($enc, $this->_authenticatorData); break;
47
            case 'packed': $this->_attestationFormat = new Format\Packed($enc, $this->_authenticatorData); break;
48
            case 'tpm': $this->_attestationFormat = new Format\Tpm($enc, $this->_authenticatorData); break;
49
            default: throw new WebAuthnException('invalid attestation format: ' . $enc['fmt'], WebAuthnException::INVALID_DATA);
50
        }
51
    }
52
 
53
    /**
54
     * returns the attestation format name
55
     * @return string
56
     */
57
    public function getAttestationFormatName() {
58
        return $this->_attestationFormatName;
59
    }
60
 
61
    /**
62
     * returns the attestation format class
63
     * @return Format\FormatBase
64
     */
65
    public function getAttestationFormat() {
66
        return $this->_attestationFormat;
67
    }
68
 
69
    /**
70
     * returns the attestation public key in PEM format
71
     * @return AuthenticatorData
72
     */
73
    public function getAuthenticatorData() {
74
        return $this->_authenticatorData;
75
    }
76
 
77
    /**
78
     * returns the certificate chain as PEM
79
     * @return string|null
80
     */
81
    public function getCertificateChain() {
82
        return $this->_attestationFormat->getCertificateChain();
83
    }
84
 
85
    /**
86
     * return the certificate issuer as string
87
     * @return string
88
     */
89
    public function getCertificateIssuer() {
90
        $pem = $this->getCertificatePem();
91
        $issuer = '';
92
        if ($pem) {
93
            $certInfo = \openssl_x509_parse($pem);
94
            if (\is_array($certInfo) && \array_key_exists('issuer', $certInfo) && \is_array($certInfo['issuer'])) {
95
 
96
                $cn = $certInfo['issuer']['CN'] ?? '';
97
                $o = $certInfo['issuer']['O'] ?? '';
98
                $ou = $certInfo['issuer']['OU'] ?? '';
99
 
100
                if ($cn) {
101
                    $issuer .= $cn;
102
                }
103
                if ($issuer && ($o || $ou)) {
104
                    $issuer .= ' (' . trim($o . ' ' . $ou) . ')';
105
                } else {
106
                    $issuer .= trim($o . ' ' . $ou);
107
                }
108
            }
109
        }
110
 
111
        return $issuer;
112
    }
113
 
114
    /**
115
     * return the certificate subject as string
116
     * @return string
117
     */
118
    public function getCertificateSubject() {
119
        $pem = $this->getCertificatePem();
120
        $subject = '';
121
        if ($pem) {
122
            $certInfo = \openssl_x509_parse($pem);
123
            if (\is_array($certInfo) && \array_key_exists('subject', $certInfo) && \is_array($certInfo['subject'])) {
124
 
125
                $cn = $certInfo['subject']['CN'] ?? '';
126
                $o = $certInfo['subject']['O'] ?? '';
127
                $ou = $certInfo['subject']['OU'] ?? '';
128
 
129
                if ($cn) {
130
                    $subject .= $cn;
131
                }
132
                if ($subject && ($o || $ou)) {
133
                    $subject .= ' (' . trim($o . ' ' . $ou) . ')';
134
                } else {
135
                    $subject .= trim($o . ' ' . $ou);
136
                }
137
            }
138
        }
139
 
140
        return $subject;
141
    }
142
 
143
    /**
144
     * returns the key certificate in PEM format
145
     * @return string
146
     */
147
    public function getCertificatePem() {
148
        return $this->_attestationFormat->getCertificatePem();
149
    }
150
 
151
    /**
152
     * checks validity of the signature
153
     * @param string $clientDataHash
154
     * @return bool
155
     * @throws WebAuthnException
156
     */
157
    public function validateAttestation($clientDataHash) {
158
        return $this->_attestationFormat->validateAttestation($clientDataHash);
159
    }
160
 
161
    /**
162
     * validates the certificate against root certificates
163
     * @param array $rootCas
164
     * @return boolean
165
     * @throws WebAuthnException
166
     */
167
    public function validateRootCertificate($rootCas) {
168
        return $this->_attestationFormat->validateRootCertificate($rootCas);
169
    }
170
 
171
    /**
172
     * checks if the RpId-Hash is valid
173
     * @param string$rpIdHash
174
     * @return bool
175
     */
176
    public function validateRpIdHash($rpIdHash) {
177
        return $rpIdHash === $this->_authenticatorData->getRpIdHash();
178
    }
179
}