Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
 
3
 
4
namespace lbuchs\WebAuthn\CBOR;
5
use lbuchs\WebAuthn\WebAuthnException;
6
use lbuchs\WebAuthn\Binary\ByteBuffer;
7
 
8
/**
9
 * Modified version of https://github.com/madwizard-thomas/webauthn-server/blob/master/src/Format/CborDecoder.php
10
 * Copyright © 2018 Thomas Bleeker - MIT licensed
11
 * Modified by Lukas Buchs
12
 * Thanks Thomas for your work!
13
 */
14
class CborDecoder {
15
    const CBOR_MAJOR_UNSIGNED_INT = 0;
16
    const CBOR_MAJOR_TEXT_STRING = 3;
17
    const CBOR_MAJOR_FLOAT_SIMPLE = 7;
18
    const CBOR_MAJOR_NEGATIVE_INT = 1;
19
    const CBOR_MAJOR_ARRAY = 4;
20
    const CBOR_MAJOR_TAG = 6;
21
    const CBOR_MAJOR_MAP = 5;
22
    const CBOR_MAJOR_BYTE_STRING = 2;
23
 
24
    /**
25
     * @param ByteBuffer|string $bufOrBin
26
     * @return mixed
27
     * @throws WebAuthnException
28
     */
29
    public static function decode($bufOrBin) {
30
        $buf = $bufOrBin instanceof ByteBuffer ? $bufOrBin : new ByteBuffer($bufOrBin);
31
 
32
        $offset = 0;
33
        $result = self::_parseItem($buf, $offset);
34
        if ($offset !== $buf->getLength()) {
35
            throw new WebAuthnException('Unused bytes after data item.', WebAuthnException::CBOR);
36
        }
37
        return $result;
38
    }
39
 
40
    /**
41
     * @param ByteBuffer|string $bufOrBin
42
     * @param int $startOffset
43
     * @param int|null $endOffset
44
     * @return mixed
45
     */
46
    public static function decodeInPlace($bufOrBin, $startOffset, &$endOffset = null) {
47
        $buf = $bufOrBin instanceof ByteBuffer ? $bufOrBin : new ByteBuffer($bufOrBin);
48
 
49
        $offset = $startOffset;
50
        $data = self::_parseItem($buf, $offset);
51
        $endOffset = $offset;
52
        return $data;
53
    }
54
 
55
    // ---------------------
56
    // protected
57
    // ---------------------
58
 
59
    /**
60
     * @param ByteBuffer $buf
61
     * @param int $offset
62
     * @return mixed
63
     */
64
    protected static function _parseItem(ByteBuffer $buf, &$offset) {
65
        $first = $buf->getByteVal($offset++);
66
        $type = $first >> 5;
67
        $val = $first & 0b11111;
68
 
69
        if ($type === self::CBOR_MAJOR_FLOAT_SIMPLE) {
70
            return self::_parseFloatSimple($val, $buf, $offset);
71
        }
72
 
73
        $val = self::_parseExtraLength($val, $buf, $offset);
74
 
75
        return self::_parseItemData($type, $val, $buf, $offset);
76
    }
77
 
78
    protected static function _parseFloatSimple($val, ByteBuffer $buf, &$offset) {
79
        switch ($val) {
80
            case 24:
81
                $val = $buf->getByteVal($offset);
82
                $offset++;
83
                return self::_parseSimple($val);
84
 
85
            case 25:
86
                $floatValue = $buf->getHalfFloatVal($offset);
87
                $offset += 2;
88
                return $floatValue;
89
 
90
            case 26:
91
                $floatValue = $buf->getFloatVal($offset);
92
                $offset += 4;
93
                return $floatValue;
94
 
95
            case 27:
96
                $floatValue = $buf->getDoubleVal($offset);
97
                $offset += 8;
98
                return $floatValue;
99
 
100
            case 28:
101
            case 29:
102
            case 30:
103
                throw new WebAuthnException('Reserved value used.', WebAuthnException::CBOR);
104
 
105
            case 31:
106
                throw new WebAuthnException('Indefinite length is not supported.', WebAuthnException::CBOR);
107
        }
108
 
109
        return self::_parseSimple($val);
110
    }
111
 
112
    /**
113
     * @param int $val
114
     * @return mixed
115
     * @throws WebAuthnException
116
     */
117
    protected static function _parseSimple($val) {
118
        if ($val === 20) {
119
            return false;
120
        }
121
        if ($val === 21) {
122
            return true;
123
        }
124
        if ($val === 22) {
125
            return null;
126
        }
127
        throw new WebAuthnException(sprintf('Unsupported simple value %d.', $val), WebAuthnException::CBOR);
128
    }
129
 
130
    protected static function _parseExtraLength($val, ByteBuffer $buf, &$offset) {
131
        switch ($val) {
132
            case 24:
133
                $val = $buf->getByteVal($offset);
134
                $offset++;
135
                break;
136
 
137
            case 25:
138
                $val = $buf->getUint16Val($offset);
139
                $offset += 2;
140
                break;
141
 
142
            case 26:
143
                $val = $buf->getUint32Val($offset);
144
                $offset += 4;
145
                break;
146
 
147
            case 27:
148
                $val = $buf->getUint64Val($offset);
149
                $offset += 8;
150
                break;
151
 
152
            case 28:
153
            case 29:
154
            case 30:
155
                throw new WebAuthnException('Reserved value used.', WebAuthnException::CBOR);
156
 
157
            case 31:
158
                throw new WebAuthnException('Indefinite length is not supported.', WebAuthnException::CBOR);
159
        }
160
 
161
        return $val;
162
    }
163
 
164
    protected static function _parseItemData($type, $val, ByteBuffer $buf, &$offset) {
165
        switch ($type) {
166
            case self::CBOR_MAJOR_UNSIGNED_INT: // uint
167
                return $val;
168
 
169
            case self::CBOR_MAJOR_NEGATIVE_INT:
170
                return -1 - $val;
171
 
172
            case self::CBOR_MAJOR_BYTE_STRING:
173
                $data = $buf->getBytes($offset, $val);
174
                $offset += $val;
175
                return new ByteBuffer($data); // bytes
176
 
177
            case self::CBOR_MAJOR_TEXT_STRING:
178
                $data = $buf->getBytes($offset, $val);
179
                $offset += $val;
180
                return $data; // UTF-8
181
 
182
            case self::CBOR_MAJOR_ARRAY:
183
                return self::_parseArray($buf, $offset, $val);
184
 
185
            case self::CBOR_MAJOR_MAP:
186
                return self::_parseMap($buf, $offset, $val);
187
 
188
            case self::CBOR_MAJOR_TAG:
189
                return self::_parseItem($buf, $offset); // 1 embedded data item
190
        }
191
 
192
        // This should never be reached
193
        throw new WebAuthnException(sprintf('Unknown major type %d.', $type), WebAuthnException::CBOR);
194
    }
195
 
196
    protected static function _parseMap(ByteBuffer $buf, &$offset, $count) {
197
        $map = array();
198
 
199
        for ($i = 0; $i < $count; $i++) {
200
            $mapKey = self::_parseItem($buf, $offset);
201
            $mapVal = self::_parseItem($buf, $offset);
202
 
203
            if (!\is_int($mapKey) && !\is_string($mapKey)) {
204
                throw new WebAuthnException('Can only use strings or integers as map keys', WebAuthnException::CBOR);
205
            }
206
 
207
            $map[$mapKey] = $mapVal; // todo dup
208
        }
209
        return $map;
210
    }
211
 
212
    protected static function _parseArray(ByteBuffer $buf, &$offset, $count) {
213
        $arr = array();
214
        for ($i = 0; $i < $count; $i++) {
215
            $arr[] = self::_parseItem($buf, $offset);
216
        }
217
 
218
        return $arr;
219
    }
220
}