Subversion Repositories oidplus

Rev

Rev 1079 | Rev 1116 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
635 daniel-mar 1
<?php
2
 
3
/*
4
 * OIDplus 2.0
1086 daniel-mar 5
 * Copyright 2019 - 2023 Daniel Marschall, ViaThinkSoft
635 daniel-mar 6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
 
1050 daniel-mar 20
namespace ViaThinkSoft\OIDplus;
635 daniel-mar 21
 
1086 daniel-mar 22
// phpcs:disable PSR1.Files.SideEffects
23
\defined('INSIDE_OIDPLUS') or die;
24
// phpcs:enable PSR1.Files.SideEffects
25
 
635 daniel-mar 26
class OIDplusOid extends OIDplusObject {
27
        private $oid;
28
 
29
        public function __construct($oid) {
30
                $bak_oid = $oid;
31
 
32
                $oid = sanitizeOID($oid, 'auto');
33
                if ($oid === false) {
34
                        throw new OIDplusException(_L('Invalid OID %1',$bak_oid));
35
                }
36
 
37
                if (($oid != '') && (!oid_valid_dotnotation($oid, false, true, 0))) {
38
                        // avoid OIDs like 3.0
39
                        throw new OIDplusException(_L('Invalid OID %1',$bak_oid));
40
                }
41
 
42
                $this->oid = $oid;
43
        }
44
 
45
        public static function parse($node_id) {
46
                @list($namespace, $oid) = explode(':', $node_id, 2);
860 daniel-mar 47
                if ($namespace !== self::ns()) return false;
635 daniel-mar 48
                return new self($oid);
49
        }
50
 
51
        public static function objectTypeTitle() {
52
                return _L('Object Identifier (OID)');
53
        }
54
 
55
        public static function objectTypeTitleShort() {
56
                return _L('OID');
57
        }
58
 
59
        public static function ns() {
60
                return 'oid';
61
        }
62
 
63
        public static function root() {
860 daniel-mar 64
                return self::ns().':';
635 daniel-mar 65
        }
66
 
67
        public function isRoot() {
68
                return $this->oid == '';
69
        }
70
 
71
        public function nodeId($with_ns=true) {
859 daniel-mar 72
                return $with_ns ? self::root().$this->oid : $this->oid;
635 daniel-mar 73
        }
74
 
75
        public function addString($str) {
76
                if (!$this->isRoot()) {
77
                        if (strpos($str,'.') !== false) throw new OIDplusException(_L('Please only submit one arc (not an absolute OID or multiple arcs).'));
78
                }
79
 
80
                return $this->appendArcs($str)->nodeId();
81
        }
82
 
83
        public function crudShowId(OIDplusObject $parent) {
84
                if ($parent instanceof OIDplusOid) {
85
                        return $this->deltaDotNotation($parent);
86
                }
87
        }
88
 
89
        public function jsTreeNodeName(OIDplusObject $parent = null) {
90
                if ($parent == null) return $this->objectTypeTitle();
91
                if ($parent instanceof OIDplusOid) {
92
                        return $this->viewGetArcAsn1s($parent);
93
                } else {
94
                        return '';
95
                }
96
        }
97
 
98
        public function defaultTitle() {
99
                return _L('OID %1',$this->oid);
100
        }
101
 
102
        public function isLeafNode() {
103
                return false;
104
        }
105
 
753 daniel-mar 106
        private function getTechInfo() {
107
                $tech_info = array();
108
 
109
                $tmp = _L('Dot notation');
1052 daniel-mar 110
                $tmp = str_replace(explode(' ', $tmp, 2)[0], '<a href="https://oid-rep.orange-labs.fr/faq.htm#14" target="_blank">'.explode(' ', $tmp, 2)[0].'</a>', $tmp);
753 daniel-mar 111
                $tech_info[$tmp] = $this->getDotNotation();
112
 
113
                $tmp = _L('ASN.1 notation');
1052 daniel-mar 114
                $tmp = str_replace(explode(' ', $tmp, 2)[0], '<a href="https://oid-rep.orange-labs.fr/faq.htm#17" target="_blank">'.explode(' ', $tmp, 2)[0].'</a>', $tmp);
753 daniel-mar 115
                $tech_info[$tmp] = $this->getAsn1Notation();
116
 
117
                $tmp = _L('OID-IRI notation');
1052 daniel-mar 118
                $tmp = str_replace(explode(' ', $tmp, 2)[0], '<a href="https://oid-rep.orange-labs.fr/faq.htm#iri" target="_blank">'.explode(' ', $tmp, 2)[0].'</a>', $tmp);
753 daniel-mar 119
                $tech_info[$tmp] = $this->getIriNotation();
120
 
121
                $tmp = _L('WEID notation');
122
                $tmp = str_replace(explode(' ', $tmp, 2)[0], '<a href="https://weid.info/" target="_blank">'.explode(' ', $tmp, 2)[0].'</a>', $tmp);
123
                $tech_info[$tmp] = $this->getWeidNotation();
124
 
930 daniel-mar 125
                $tmp = _L('DER encoding');
126
                $tmp = str_replace(explode(' ', $tmp, 2)[0], '<a href="https://misc.daniel-marschall.de/asn.1/oid-converter/online.php" target="_blank">'.explode(' ', $tmp, 2)[0].'</a>', $tmp);
1050 daniel-mar 127
                $tech_info[$tmp] = str_replace(' ', ':', \OidDerConverter::hexarrayToStr(\OidDerConverter::oidToDER($this->nodeId(false))));
930 daniel-mar 128
 
753 daniel-mar 129
                return $tech_info;
130
        }
131
 
772 daniel-mar 132
        protected function isClassCWeid() {
133
                $dist = oid_distance($this->oid, '1.3.6.1.4.1.37553.8');
134
                if ($dist === false) return false;
135
                return $dist >= 0;
136
        }
137
 
635 daniel-mar 138
        public function getContentPage(&$title, &$content, &$icon) {
772 daniel-mar 139
                if ($this->isClassCWeid()) {
140
                        // TODO: Also change treeview menu mini-icon?
801 daniel-mar 141
                        $icon = file_exists(__DIR__.'/img/weid_icon.png') ? OIDplus::webpath(__DIR__,OIDplus::PATH_RELATIVE).'img/weid_icon.png' : '';
772 daniel-mar 142
                } else {
801 daniel-mar 143
                        $icon = file_exists(__DIR__.'/img/main_icon.png') ? OIDplus::webpath(__DIR__,OIDplus::PATH_RELATIVE).'img/main_icon.png' : '';
772 daniel-mar 144
                }
635 daniel-mar 145
 
146
                if ($this->isRoot()) {
147
                        $title = OIDplusOid::objectTypeTitle();
148
 
149
                        $res = OIDplus::db()->query("select id from ###objects where parent = ?", array(self::root()));
790 daniel-mar 150
                        if ($res->any()) {
635 daniel-mar 151
                                $content = _L('Please select an OID in the tree view at the left to show its contents.');
152
                        } else {
153
                                $content = _L('Currently, no OID is registered in the system.');
154
                        }
155
 
156
                        if (!$this->isLeafNode()) {
157
                                if (OIDplus::authUtils()->isAdminLoggedIn()) {
158
                                        $content .= '<h2>'._L('Manage your root OIDs').'</h2>';
159
                                } else {
160
                                        $content .= '<h2>'._L('Root OIDs').'</h2>';
161
                                }
162
                                $content .= '%%CRUD%%';
163
                        }
164
                } else {
165
                        $title = $this->getTitle();
166
 
753 daniel-mar 167
                        $tech_info = $this->getTechInfo();
168
                        $tech_info_html = '';
169
                        if (count($tech_info) > 0) {
170
                                $tech_info_html .= '<h2>'._L('Technical information').'</h2>';
171
                                $tech_info_html .= '<table border="0">';
172
                                foreach ($tech_info as $key => $value) {
173
                                        $tech_info_html .= '<tr><td>'.$key.': </td><td><code>'.$value.'</code></td></tr>';
174
                                }
175
                                $tech_info_html .= '</table>';
176
                        }
635 daniel-mar 177
 
753 daniel-mar 178
                        $content = $tech_info_html;
179
 
180
                        $content .= '<h2>'._L('Description').'</h2>%%DESC%%'.
181
                                    '<h2>'._L('Registration Authority').'</h2>%%RA_INFO%%';
182
 
635 daniel-mar 183
                        if (!$this->isLeafNode()) {
184
                                if ($this->userHasWriteRights()) {
928 daniel-mar 185
                                        $content .= '<h2>'._L('Create or change subordinate objects').'</h2>';
635 daniel-mar 186
                                } else {
928 daniel-mar 187
                                        $content .= '<h2>'._L('Subordinate objects').'</h2>';
635 daniel-mar 188
                                }
189
                                $content .= '%%CRUD%%';
190
                        }
191
                }
192
        }
193
 
194
        # ---
195
 
683 daniel-mar 196
        // Gets the last arc of an WEID
635 daniel-mar 197
        public function weidArc() {
689 daniel-mar 198
                // Dirty hack: We prepend '0.' in front of the OID to enforce the
199
                //             creation of a Class A weid (weid:root:) . Otherwise we could not
200
                //             get the hidden arc value "8" from "weid:4" (which is actually "weid:pen:SZ5-8-?"
1050 daniel-mar 201
                $weid = \Frdl\Weid\WeidOidConverter::oid2weid('0.'.$this->getDotNotation());
635 daniel-mar 202
                if ($weid === false) return false;
683 daniel-mar 203
                $ary = explode(':', $weid);
204
                $weid = array_pop($ary); // remove namespace and sub-namespace if existing
635 daniel-mar 205
                $x = explode('-', $weid);
206
                if (count($x) < 2) return ''; // WEID root arc. Has no name
207
                return $x[count($x)-2];
208
        }
209
 
210
        public function getWeidNotation($withAbbr=true) {
1050 daniel-mar 211
                $weid = \Frdl\Weid\WeidOidConverter::oid2weid($this->getDotNotation());
635 daniel-mar 212
                if ($withAbbr) {
683 daniel-mar 213
                        $ary = explode(':', $weid);
214
                        $weid = array_pop($ary); // remove namespace and sub-namespace if existing
215
                        $ns = implode(':', $ary).':';
216
 
635 daniel-mar 217
                        $weid_arcs = explode('-', $weid);
218
                        foreach ($weid_arcs as $i => &$weid) {
219
                                if ($i == count($weid_arcs)-1) {
220
                                        $weid = '<abbr title="'._L('weLuhn check digit').'">'.$weid.'</abbr>';
221
                                } else {
222
                                        $oid_arcs = explode('.',$this->oid);
223
                                        $weid_num = $oid_arcs[(count($oid_arcs)-1)-(count($weid_arcs)-1)+($i+1)];
224
                                        if ($weid_num != $weid) {
225
                                                $weid = '<abbr title="'._L('Numeric value').': '.$weid_num.'">'.$weid.'</abbr>';
226
                                        }
227
                                }
228
                        }
683 daniel-mar 229
                        $base_arc = '???';
230
                        if ($ns === 'weid:')      $base_arc = '1.3.6.1.4.1.37553.8';
231
                        if ($ns === 'weid:pen:')  $base_arc = '1.3.6.1.4.1';
688 daniel-mar 232
                        if ($ns === 'weid:root:') $base_arc = _L('OID tree root');
683 daniel-mar 233
 
234
                        $weid = '<abbr title="'._L('Base OID').': '.$base_arc.'">' . rtrim($ns,':') . '</abbr>:' . implode('-',$weid_arcs);
635 daniel-mar 235
                }
236
                return $weid;
237
        }
238
 
239
        public function appendArcs(String $arcs) {
240
                $out = new self($this->oid);
241
 
242
                if ($out->isRoot()) {
243
                        $out->oid .= $arcs;
244
                } else {
245
                        $out->oid .= '.' . $arcs;
246
                }
247
 
248
                $bak_oid = $out->oid;
249
                $out->oid = sanitizeOID($out->oid);
250
                if ($out->oid === false) throw new OIDplusException(_L('%1 is not a valid OID!',$bak_oid));
251
 
859 daniel-mar 252
                $maxlen = OIDplus::baseConfig()->getValue('LIMITS_MAX_ID_LENGTH')-strlen(self::root());
635 daniel-mar 253
                if (strlen($out->oid) > $maxlen) {
254
                        throw new OIDplusException(_L('The resulting OID "%1" is too long (max allowed length: %2).',$out->oid,$maxlen));
255
                }
256
 
257
                $depth = 0;
258
                foreach (explode('.',$out->oid) as $arc) {
259
                        if (strlen($arc) > OIDplus::baseConfig()->getValue('LIMITS_MAX_OID_ARC_SIZE')) {
260
                                $maxlen = OIDplus::baseConfig()->getValue('LIMITS_MAX_OID_ARC_SIZE');
261
                                throw new OIDplusException(_L('Arc "%1" is too long and therefore cannot be appended to the OID "%2" (max allowed arc size is "%3")',$arc,$this->oid,$maxlen));
262
                        }
263
                        $depth++;
264
                }
265
                if ($depth > OIDplus::baseConfig()->getValue('LIMITS_MAX_OID_DEPTH')) {
266
                        $maxdepth = OIDplus::baseConfig()->getValue('LIMITS_MAX_OID_DEPTH');
267
                        throw new OIDplusException(_L('OID %1 has too many arcs (current depth %2, max depth %3)',$out->oid,$depth,$maxdepth));
268
                }
269
 
270
                return $out;
271
        }
272
 
273
        public function deltaDotNotation(OIDplusOid $parent) {
274
                if (!$parent->isRoot()) {
275
                        if (substr($this->oid, 0, strlen($parent->oid)+1) == $parent->oid.'.') {
276
                                return substr($this->oid, strlen($parent->oid)+1);
277
                        } else {
278
                                return false;
279
                        }
280
                } else {
281
                        return $this->oid;
282
                }
283
        }
284
 
979 daniel-mar 285
        public function getAsn1Ids() {
286
                $asn_ids = array();
287
                $res_asn = OIDplus::db()->query("select * from ###asn1id where oid = ? order by lfd", array("oid:".$this->oid));
288
                while ($row_asn = $res_asn->fetch_array()) {
289
                        $name = $row_asn['name'];
290
                        $standardized = $row_asn['standardized'];
291
                        $well_known = $row_asn['well_known'];
292
                        $asn_ids[] = new OIDplusOidAsn1Id($name, $standardized, $well_known);
293
                }
294
                return $asn_ids;
295
        }
296
 
297
        public function getIris() {
298
                $iri_ids = array();
299
                $res_iri = OIDplus::db()->query("select * from ###iri where oid = ? order by lfd", array("oid:".$this->oid));
300
                while ($row_iri = $res_iri->fetch_array()) {
301
                        $name = $row_iri['name'];
302
                        $longarc = $row_iri['longarc'];
303
                        $well_known = $row_iri['well_known'];
304
                        $iri_ids[] = new OIDplusOidIri($name, $longarc, $well_known);
305
                }
306
                return $iri_ids;
307
        }
308
 
635 daniel-mar 309
        public function viewGetArcAsn1s(OIDplusOid $parent=null, $separator = ' | ') {
310
                $asn_ids = array();
311
 
859 daniel-mar 312
                if (is_null($parent)) $parent = OIDplusOid::parse(self::root());
635 daniel-mar 313
 
314
                $part = $this->deltaDotNotation($parent);
315
 
316
                if (strpos($part, '.') === false) {
979 daniel-mar 317
                        $asn_id_objs = $this->getAsn1Ids();
318
                        foreach ($asn_id_objs as $asn_id_obj) {
319
                                $asn_ids[] = $asn_id_obj->getName().'('.$part.')';
635 daniel-mar 320
                        }
321
                }
322
 
323
                if (count($asn_ids) == 0) $asn_ids = array($part);
324
                return implode($separator, $asn_ids);
325
        }
326
 
327
        public function getAsn1Notation($withAbbr=true) {
328
                $asn1_notation = '';
329
                $arcs = explode('.', $this->oid);
330
 
331
                foreach ($arcs as $arc) {
859 daniel-mar 332
                        $res = OIDplus::db()->query("select name, standardized from ###asn1id where oid = ? order by lfd", array(self::root().implode('.',$arcs)));
635 daniel-mar 333
 
334
                        $names = array();
335
                        while ($row = $res->fetch_array()) {
336
                                $names[] = $row['name']."(".end($arcs).")";
337
                                if ($row['standardized']) {
338
                                        $names[] = $row['name'];
339
                                }
340
                        }
341
 
342
                        $numeric = array_pop($arcs);
343
                        if (count($names) > 1) {
344
                                $first_name = array_shift($names);
345
                                $abbr = _L('Other identifiers').':&#10;      '.implode('&#10;      ',$names);
346
                                if ($withAbbr) {
347
                                        $asn1_notation = '<abbr title="'.$abbr.'">'.$first_name.'</abbr> '.$asn1_notation;
348
                                } else {
349
                                        $asn1_notation = $first_name.' '.$asn1_notation;
350
                                }
351
                        } else if (count($names) == 1) {
352
                                $asn1_notation = array_shift($names).' '.$asn1_notation;
353
                        } else {
354
                                $asn1_notation = $numeric.' '.$asn1_notation;
355
                        }
356
                }
357
 
758 daniel-mar 358
                return "{ ".trim($asn1_notation)." }";
635 daniel-mar 359
        }
360
 
361
        public function getIriNotation($withAbbr=true) {
362
                $iri_notation = '';
363
                $arcs = explode('.', $this->oid);
364
 
365
                foreach ($arcs as $arc) {
859 daniel-mar 366
                        $res = OIDplus::db()->query("select name, longarc from ###iri where oid = ? order by lfd", array(self::root().implode('.',$arcs)));
635 daniel-mar 367
 
368
                        $is_longarc = false;
369
                        $names = array();
370
                        while ($row = $res->fetch_array()) {
371
                                $is_longarc = $row['longarc'];
372
                                $names[] = $row['name'];
373
 
374
                                if ($is_longarc) {
375
                                        $names[] = 'Joint-ISO-ITU-T/'.$row['name']; // Long arcs can only be inside root OID 2
376
                                }
377
                        }
378
 
379
                        $names[] = array_pop($arcs);
380
                        if (count($names) > 2) {
381
                                $first_name = array_shift($names);
382
                                $numeric = array_pop($names);
383
                                $abbr = _L('Other identifiers').':&#10;      '.implode('&#10;      ',$names).'&#10;'._L('Numeric value').': '.$numeric;
384
                                $iri_notation = $withAbbr ? '<abbr title="'.$abbr.'">'.$first_name.'</abbr>/'.$iri_notation : $first_name.'/'.$iri_notation;
385
                        } else if (count($names) > 1) {
386
                                $first_name = array_shift($names);
387
                                $abbr = _L('Numeric value').': '.array_shift($names);
388
                                $iri_notation = $withAbbr ? '<abbr title="'.$abbr.'">'.$first_name.'</abbr>/'.$iri_notation : $first_name.'/'.$iri_notation;
389
                        } else if (count($names) == 1) {
390
                                $iri_notation = array_shift($names) . '/' . $iri_notation;
391
                        }
392
 
393
                        if ($is_longarc) break; // we don't write /ITU-T/ at the beginning, when /ITU-T/xyz is a long arc
394
                }
395
                $iri_notation = '/' . substr($iri_notation, 0, strlen($iri_notation)-1);
396
 
397
                return $iri_notation;
398
        }
399
 
400
        public function getDotNotation() {
401
                return $this->oid;
402
        }
403
 
404
        public function isWellKnown() {
405
                $res = OIDplus::db()->query("select oid from ###asn1id where oid = ? and well_known = ?", array("oid:".$this->oid,true));
790 daniel-mar 406
                if ($res->any()) return true;
635 daniel-mar 407
 
408
                $res = OIDplus::db()->query("select oid from ###iri where oid = ? and well_known = ?", array("oid:".$this->oid,true));
790 daniel-mar 409
                if ($res->any()) return true;
635 daniel-mar 410
 
411
                return false;
412
        }
413
 
414
        public function replaceAsn1Ids($demandedASN1s=array(), $simulate=false) {
415
                if ($this->isWellKnown()) {
416
                        throw new OIDplusException(_L('OID "%1" is a "well-known" OID. Its identifiers cannot be changed.',$this->oid));
417
                }
418
 
419
                // First do a few checks
420
                foreach ($demandedASN1s as &$asn1) {
421
                        $asn1 = trim($asn1);
422
 
423
                        if (strlen($asn1) > OIDplus::baseConfig()->getValue('LIMITS_MAX_OID_ASN1_ID_LEN')) {
424
                                $maxlen = OIDplus::baseConfig()->getValue('LIMITS_MAX_OID_ASN1_ID_LEN');
425
                                throw new OIDplusException(_L('ASN.1 alphanumeric identifier "%1" is too long (max allowed length %2)',$asn1,$maxlen));
426
                        }
427
 
428
                        // Validate identifier
429
                        if (!oid_id_is_valid($asn1)) throw new OIDplusException(_L('"%1" is not a valid ASN.1 identifier!',$asn1));
430
 
431
                        // Check if the (real) parent has any conflict
432
                        // Unlike IRI identifiers, ASN.1 identifiers may be used multiple times (not recommended), except if one of them is standardized
433
                        $res = OIDplus::db()->query("select oid from ###asn1id where name = ? and standardized = ?", array($asn1,true));
434
                        while ($row = $res->fetch_array()) {
435
                                $check_oid = OIDplusOid::parse($row['oid'])->oid;
436
                                if ((oid_up($check_oid) === oid_up($this->oid)) && // same parent
437
                                   ($check_oid !== $this->oid))                    // different OID
438
                                {
439
                                        throw new OIDplusException(_L('ASN.1 identifier "%1" is a standardized identifier belonging to OID %2',$asn1,$check_oid));
440
                                }
441
                        }
442
                }
443
 
444
                // Now do the real replacement
445
                if (!$simulate) {
446
                        OIDplus::db()->query("delete from ###asn1id where oid = ?", array("oid:".$this->oid));
447
                        foreach ($demandedASN1s as &$asn1) {
448
                                OIDplus::db()->query("insert into ###asn1id (oid, name) values (?, ?)", array("oid:".$this->oid, $asn1));
449
                        }
450
                }
451
        }
452
 
453
        public function replaceIris($demandedIris=array(), $simulate=false) {
454
                if ($this->isWellKnown()) {
455
                        throw new OIDplusException(_L('OID "%1" is a "well-known" OID. Its identifiers cannot be changed.',$this->oid));
456
                }
457
 
458
                // First do a few checks
459
                foreach ($demandedIris as &$iri) {
460
                        $iri = trim($iri);
461
 
462
                        if (strlen($iri) > OIDplus::baseConfig()->getValue('LIMITS_MAX_OID_UNICODE_LABEL_LEN')) {
463
                                $maxlen = OIDplus::baseConfig()->getValue('LIMITS_MAX_OID_UNICODE_LABEL_LEN');
464
                                throw new OIDplusException(_L('Unicode label "%1" is too long (max allowed length %2)',$iri,$maxlen));
465
                        }
466
 
467
                        // Validate identifier
468
                        if (!iri_arc_valid($iri, false)) throw new OIDplusException(_L('"%1" is not a valid IRI!',$iri));
469
 
470
                        // Check if the (real) parent has any conflict
471
                        $res = OIDplus::db()->query("select oid from ###iri where name = ?", array($iri));
472
                        while ($row = $res->fetch_array()) {
473
                                $check_oid = OIDplusOid::parse($row['oid'])->oid;
474
                                if ((oid_up($check_oid) === oid_up($this->oid)) && // same parent
475
                                   ($check_oid !== $this->oid))                    // different OID
476
                                {
477
                                        throw new OIDplusException(_L('IRI "%1" is already used by another OID (%2)',$iri,$check_oid));
478
                                }
479
                        }
480
                }
481
 
482
                // Now do the real replacement
483
                if (!$simulate) {
484
                        OIDplus::db()->query("delete from ###iri where oid = ?", array("oid:".$this->oid));
485
                        foreach ($demandedIris as &$iri) {
486
                                OIDplus::db()->query("insert into ###iri (oid, name) values (?, ?)", array("oid:".$this->oid, $iri));
487
                        }
488
                }
489
        }
490
 
491
        public function one_up() {
492
                return self::parse(self::ns().':'.oid_up($this->oid));
493
        }
494
 
495
        public function distance($to) {
496
                if (!is_object($to)) $to = OIDplusObject::parse($to);
497
                if (!($to instanceof $this)) return false;
498
                return oid_distance($to->oid, $this->oid);
499
        }
500
 
501
        public function getAltIds() {
502
                if ($this->isRoot()) return array();
503
                $ids = parent::getAltIds();
945 daniel-mar 504
 
635 daniel-mar 505
                if ($uuid = oid_to_uuid($this->oid)) {
929 daniel-mar 506
                        // UUID-OIDs are representation of an UUID
635 daniel-mar 507
                        $ids[] = new OIDplusAltId('guid', $uuid, _L('GUID representation of this OID'));
929 daniel-mar 508
                } else {
509
                        // All other OIDs can be formed into an UUID by making them a namebased OID
510
                        // You could theoretically also do this to an UUID-OID, but we exclude this case to avoid that users are confused
511
                        $ids[] = new OIDplusAltId('guid', gen_uuid_md5_namebased(UUID_NAMEBASED_NS_OID, $this->oid), _L('Name based version 3 / MD5 UUID with namespace %1','UUID_NAMEBASED_NS_OID'));
512
                        $ids[] = new OIDplusAltId('guid', gen_uuid_sha1_namebased(UUID_NAMEBASED_NS_OID, $this->oid), _L('Name based version 5 / SHA1 UUID with namespace %1','UUID_NAMEBASED_NS_OID'));
635 daniel-mar 513
                }
930 daniel-mar 514
 
1078 daniel-mar 515
                $oid_parts = explode('.',$this->nodeId(false));
516
 
1077 daniel-mar 517
                // (VTS B1) Members
518
                if ($this->nodeId(false) == '1.3.6.1.4.1.37476.1') {
519
                        $aid = 'D276000186B1';
520
                        $aid_is_ok = aid_canonize($aid);
521
                        if ($aid_is_ok) $ids[] = new OIDplusAltId('aid', $aid, _L('Application Identifier (ISO/IEC 7816)'), ' ('._L('No PIX allowed').')');
522
                } else {
523
                        if ((count($oid_parts) == 9) && ($oid_parts[0] == '1') && ($oid_parts[1] == '3') && ($oid_parts[2] == '6') && ($oid_parts[3] == '1') && ($oid_parts[4] == '4') && ($oid_parts[5] == '1') && ($oid_parts[6] == '37476') && ($oid_parts[7] == '1')) {
524
                                $number = str_pad($oid_parts[8],4,'0',STR_PAD_LEFT);
525
                                $aid = 'D276000186B1'.$number;
526
                                $aid_is_ok = aid_canonize($aid);
1079 daniel-mar 527
                                if ($aid_is_ok) $ids[] = new OIDplusAltId('aid', $aid, _L('Application Identifier (ISO/IEC 7816)'), ' ('._L('Optional PIX allowed, without prefix').')');
1077 daniel-mar 528
                        }
529
                }
530
 
531
                // (VTS B2) Products
532
                if ($this->nodeId(false) == '1.3.6.1.4.1.37476.2') {
533
                        $aid = 'D276000186B2';
534
                        $aid_is_ok = aid_canonize($aid);
535
                        if ($aid_is_ok) $ids[] = new OIDplusAltId('aid', $aid, _L('Application Identifier (ISO/IEC 7816)'), ' ('._L('No PIX allowed').')');
536
                } else {
537
                        if ((count($oid_parts) == 9) && ($oid_parts[0] == '1') && ($oid_parts[1] == '3') && ($oid_parts[2] == '6') && ($oid_parts[3] == '1') && ($oid_parts[4] == '4') && ($oid_parts[5] == '1') && ($oid_parts[6] == '37476') && ($oid_parts[7] == '2')) {
538
                                $number = str_pad($oid_parts[8],4,'0',STR_PAD_LEFT);
539
                                $aid = 'D276000186B2'.$number;
540
                                $aid_is_ok = aid_canonize($aid);
1079 daniel-mar 541
                                if ($aid_is_ok) $ids[] = new OIDplusAltId('aid', $aid, _L('Application Identifier (ISO/IEC 7816)'), ' ('._L('Optional PIX allowed, without prefix').')');
1077 daniel-mar 542
                        }
543
                }
544
 
1078 daniel-mar 545
                // (VTS B2 00 05) OIDplus System AID / Information Object AID
546
                if ((count($oid_parts) == 10) && ($oid_parts[0] == '1') && ($oid_parts[1] == '3') && ($oid_parts[2] == '6') && ($oid_parts[3] == '1') && ($oid_parts[4] == '4') && ($oid_parts[5] == '1') && ($oid_parts[6] == '37476') && ($oid_parts[7] == '30') && ($oid_parts[8] == '9')) {
547
                        $sid = $oid_parts[9];
548
                        $sid_hex = strtoupper(str_pad(dechex((int)$sid),8,'0',STR_PAD_LEFT));
549
                        $aid = 'D276000186B20005'.$sid_hex;
550
                        $aid_is_ok = aid_canonize($aid);
551
                        if ($aid_is_ok) $ids[] = new OIDplusAltId('aid', $aid, _L('OIDplus System Application Identifier (ISO/IEC 7816)'), ' ('._L('No PIX allowed').')');
552
                }
553
                else if ((count($oid_parts) == 11) && ($oid_parts[0] == '1') && ($oid_parts[1] == '3') && ($oid_parts[2] == '6') && ($oid_parts[3] == '1') && ($oid_parts[4] == '4') && ($oid_parts[5] == '1') && ($oid_parts[6] == '37476') && ($oid_parts[7] == '30') && ($oid_parts[8] == '9')) {
554
                        $sid = $oid_parts[9];
555
                        $obj = $oid_parts[10];
556
                        $sid_hex = strtoupper(str_pad(dechex((int)$sid),8,'0',STR_PAD_LEFT));
557
                        $obj_hex = strtoupper(str_pad(dechex((int)$obj),8,'0',STR_PAD_LEFT));
558
                        $aid = 'D276000186B20005'.$sid_hex.$obj_hex;
559
                        $aid_is_ok = aid_canonize($aid);
560
                        if ($aid_is_ok) $ids[] = new OIDplusAltId('aid', $aid, _L('OIDplus Information Object Application Identifier (ISO/IEC 7816)'), ' ('._L('No PIX allowed').')');
561
                }
562
 
945 daniel-mar 563
                // (VTS F0) IANA PEN to AID Mapping (PIX allowed)
564
                if ((count($oid_parts) == 7) && ($oid_parts[0] == '1') && ($oid_parts[1] == '3') && ($oid_parts[2] == '6') && ($oid_parts[3] == '1') && ($oid_parts[4] == '4') && ($oid_parts[5] == '1')) {
565
                        $pen = $oid_parts[6];
566
                        $aid = 'D276000186F0'.$pen;
567
                        if (strlen($aid)%2 == 1) $aid .= 'F';
568
                        $aid_is_ok = aid_canonize($aid);
959 daniel-mar 569
                        if ($aid_is_ok) $ids[] = new OIDplusAltId('aid', $aid, _L('Application Identifier (ISO/IEC 7816)'), ' ('._L('Optional PIX allowed, with "FF" prefix').')');
961 daniel-mar 570
                        $ids[] = new OIDplusAltId('iana-pen', $pen, _L('IANA Private Enterprise Number (PEN)'));
945 daniel-mar 571
                }
572
 
573
                // (VTS F1) FreeOID to AID Mapping (PIX allowed)
574
                if ((count($oid_parts) == 9) && ($oid_parts[0] == '1') && ($oid_parts[1] == '3') && ($oid_parts[2] == '6') && ($oid_parts[3] == '1') && ($oid_parts[4] == '4') && ($oid_parts[5] == '1') && ($oid_parts[6] == '37476') && ($oid_parts[7] == '9000')) {
575
                        $number = $oid_parts[8];
576
                        $aid = 'D276000186F1'.$number;
577
                        if (strlen($aid)%2 == 1) $aid .= 'F';
578
                        $aid_is_ok = aid_canonize($aid);
959 daniel-mar 579
                        if ($aid_is_ok) $ids[] = new OIDplusAltId('aid', $aid, _L('Application Identifier (ISO/IEC 7816)'), ' ('._L('Optional PIX allowed, with "FF" prefix').')');
945 daniel-mar 580
                }
581
 
582
                // (VTS F6) Mapping OID-to-AID if possible
933 daniel-mar 583
                try {
1050 daniel-mar 584
                        $test_der = \OidDerConverter::hexarrayToStr(\OidDerConverter::oidToDER($this->nodeId(false)));
585
                } catch (\Exception $e) {
933 daniel-mar 586
                        $test_der = '00'; // error, should not happen
587
                }
588
                if (substr($test_der,0,3) == '06 ') { // 06 = ASN.1 type of Absolute ID
957 daniel-mar 589
                        if (($oid_parts[0] == '2') && ($oid_parts[1] == '999')) {
933 daniel-mar 590
                                // Note that "ViaThinkSoft E0" AID are not unique!
591
                                // OIDplus will use the relative DER of the 2.999.xx OID as PIX
592
                                $aid_candidate = 'D2 76 00 01 86 E0 ' . substr($test_der, strlen('06 xx 88 37 ')); // Remove ASN.1 06=Type, xx=Length and the 2.999 arcs "88 37"
945 daniel-mar 593
                                $aid_is_ok = aid_canonize($aid_candidate);
933 daniel-mar 594
                                if (!$aid_is_ok) {
595
                                        // If DER encoding is not possible (too long), then we will use a 32 bit small hash.
596
                                        $small_hash = str_pad(dechex(smallhash($this->nodeId(false))),8,'0',STR_PAD_LEFT);
597
                                        $aid_candidate = 'D2 76 00 01 86 E0 ' . strtoupper(implode(' ',str_split($small_hash,2)));
945 daniel-mar 598
                                        $aid_is_ok = aid_canonize($aid_candidate);
933 daniel-mar 599
                                }
959 daniel-mar 600
                                if ($aid_is_ok) $ids[] = new OIDplusAltId('aid', $aid_candidate, _L('Application Identifier (ISO/IEC 7816)'));
957 daniel-mar 601
                        } else if (($oid_parts[0] == '0') && ($oid_parts[1] == '4') && ($oid_parts[2] == '0') && ($oid_parts[3] == '127') && ($oid_parts[4] == '0') && ($oid_parts[5] == '7')) {
602
                                // Illegal usage of E8 by German BSI, plus using E8+Len+OID instead of E8+OID like ISO does
603
                                // PIX probably not used
604
                                $aid_candidate = 'E8 '.substr($test_der, strlen('06 ')); // Remove ASN.1 06=Type
605
                                $aid_is_ok = aid_canonize($aid_candidate);
959 daniel-mar 606
                                if ($aid_is_ok) $ids[] = new OIDplusAltId('aid', $aid_candidate, _L('Application Identifier (ISO/IEC 7816)'));
957 daniel-mar 607
                        } else if (($oid_parts[0] == '1') && ($oid_parts[1] == '0')) {
933 daniel-mar 608
                                // ISO Standard AID (OID 1.0.xx)
609
                                // Optional PIX allowed
610
                                $aid_candidate = 'E8 '.substr($test_der, strlen('06 xx ')); // Remove ASN.1 06=Type and xx=Length
945 daniel-mar 611
                                $aid_is_ok = aid_canonize($aid_candidate);
959 daniel-mar 612
                                if ($aid_is_ok) $ids[] = new OIDplusAltId('aid', $aid_candidate, _L('Application Identifier (ISO/IEC 7816)'), ' ('._L('Optional PIX allowed, without prefix').')');
930 daniel-mar 613
                        } else {
933 daniel-mar 614
                                // All other OIDs can be mapped using the "ViaThinkSoft F6" scheme, but only if the DER encoding is not too long
615
                                // No PIX allowed
616
                                $aid_candidate = 'D2 76 00 01 86 F6 '.substr($test_der, strlen('06 xx ')); // Remove ASN.1 06=Type and xx=Length
945 daniel-mar 617
                                $aid_is_ok = aid_canonize($aid_candidate);
959 daniel-mar 618
                                if ($aid_is_ok) $ids[] = new OIDplusAltId('aid', $aid_candidate, _L('Application Identifier (ISO/IEC 7816)'), ' ('._L('No PIX allowed').')');
930 daniel-mar 619
                        }
620
                }
621
 
635 daniel-mar 622
                return $ids;
623
        }
624
 
625
        public function getDirectoryName() {
626
                if ($this->isRoot()) return $this->ns();
627
                $oid = $this->nodeId(false);
628
                return $this->ns().'_'.str_replace('.', '_', $oid);
629
        }
800 daniel-mar 630
 
805 daniel-mar 631
        public static function treeIconFilename($mode) {
800 daniel-mar 632
                return 'img/'.$mode.'_icon16.png';
633
        }
635 daniel-mar 634
}