Subversion Repositories php_utils

Rev

Rev 38 | Rev 41 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 38 Rev 40
Line 1... Line 1...
1
<?php
1
<?php
2
 
2
 
3
/*
3
/*
4
 * ISO/IEC 7816-5 Application Identifier decoder for PHP
4
 * ISO/IEC 7816-5 Application Identifier decoder for PHP
5
 * Copyright 2022 Daniel Marschall, ViaThinkSoft
5
 * Copyright 2022 Daniel Marschall, ViaThinkSoft
6
 * Version 2022-08-19
6
 * Version 2022-09-07
7
 *
7
 *
8
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
 * you may not use this file except in compliance with the License.
9
 * you may not use this file except in compliance with the License.
10
 * You may obtain a copy of the License at
10
 * You may obtain a copy of the License at
11
 *
11
 *
Line 16... Line 16...
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
18
 * limitations under the License.
19
 */
19
 */
20
 
20
 
-
 
21
include_once __DIR__ . '/misc_functions.inc.php';
-
 
22
 
-
 
23
# ---
-
 
24
 
21
/*
25
/*
22
#test2('A000000051AABBCC');
26
#test2('A000000051AABBCC');
23
#test2('B01234567890');
27
#test2('B01234567890');
24
#test2('D276000098AABBCCDDEEFFAABBCCDDEE');
28
#test2('D276000098AABBCCDDEEFFAABBCCDDEE');
25
#test2('F01234567890');
29
#test2('F01234567890');
26
test('91234FFF999');
30
#test('91234FFF999');
27
test('51234FFF999');
31
#test('51234FFF999');
-
 
32
#test2('E828BD080F014E585031');
28
 
33
 
29
function test2($aid) {
34
function test2($aid) {
30
        while ($aid != '') {
35
        while ($aid != '') {
31
                echo test($aid);
36
                echo test($aid);
32
                $aid = substr($aid,0,strlen($aid)-1);
37
                $aid = substr($aid,0,strlen($aid)-1);
Line 52... Line 57...
52
}
57
}
53
*/
58
*/
54
 
59
 
55
# ---
60
# ---
56
 
61
 
-
 
62
function _aid_e8_interpretations($aid) {
-
 
63
        $ret = array();
-
 
64
 
-
 
65
        $output_oid = array();
-
 
66
 
-
 
67
        $aid = strtoupper(str_replace(' ','',$aid));
-
 
68
        $aid = strtoupper(str_replace(':','',$aid));
-
 
69
        $by = str_split($aid,2);
-
 
70
        if ((array_shift($by) == 'E8') ) {
-
 
71
                // The following part is partially taken from the DER decoder/encoder by Daniel Marschall:
-
 
72
                // https://github.com/danielmarschall/oidconverter/blob/master/php/OidDerConverter.class.phps
-
 
73
                // (Only the DER "value" part, without "type" and "length")
-
 
74
 
-
 
75
                $part = 2; // DER part 0 (type) and part 1 (length) not present
-
 
76
                $fSub = 0; // Subtract value from next number output. Used when encoding {2 48} and up
-
 
77
                $ll = gmp_init(0);
-
 
78
                $arcBeginning = true;
-
 
79
 
-
 
80
                foreach ($by as $ii => $pb) {
-
 
81
 
-
 
82
                        $pb = hexdec($pb);
-
 
83
 
-
 
84
                        if ($part == 2) { // First two arcs
-
 
85
                                $first = $pb / 40;
-
 
86
                                $second = $pb % 40;
-
 
87
                                if ($first > 2) {
-
 
88
                                        $first = 2;
-
 
89
                                        $output_oid[] = $first;
-
 
90
                                        $arcBeginning = true;
-
 
91
 
-
 
92
                                        if (($pb & 0x80) != 0) {
-
 
93
                                                // 2.48 and up => 2+ octets
-
 
94
                                                // Output in "part 3"
-
 
95
 
-
 
96
                                                if ($pb == 0x80) {
-
 
97
                                                        throw new Exception("Encoding error. Illegal 0x80 paddings. (See Rec. ITU-T X.690, clause 8.19.2)\n");
-
 
98
                                                } else {
-
 
99
                                                        $arcBeginning = false;
-
 
100
                                                }
-
 
101
 
-
 
102
                                                $ll = gmp_add($ll, ($pb & 0x7F));
-
 
103
                                                $fSub = 80;
-
 
104
                                                $fOK = false;
-
 
105
                                        } else {
-
 
106
                                                // 2.0 till 2.47 => 1 octet
-
 
107
                                                $second = $pb - 80;
-
 
108
                                                $output_oid[] = $second;
-
 
109
                                                $arcBeginning = true;
-
 
110
                                                $fOK = true;
-
 
111
                                                $ll = gmp_init(0);
-
 
112
                                        }
-
 
113
                                } else {
-
 
114
                                        // 0.0 till 0.37 => 1 octet
-
 
115
                                        // 1.0 till 1.37 => 1 octet
-
 
116
                                        $output_oid[] = $first;
-
 
117
                                        $output_oid[] = $second;
-
 
118
                                        $arcBeginning = true;
-
 
119
                                        $fOK = true;
-
 
120
                                        $ll = gmp_init(0);
-
 
121
                                }
-
 
122
                                $part++;
-
 
123
                        } else { //else if ($part == 3) { // Arc three and higher
-
 
124
                                if (($pb & 0x80) != 0) {
-
 
125
                                        if ($arcBeginning && ($pb == 0x80)) {
-
 
126
                                                throw new Exception("Encoding error. Illegal 0x80 paddings. (See Rec. ITU-T X.690, clause 8.19.2)");
-
 
127
                                        } else {
-
 
128
                                                $arcBeginning = false;
-
 
129
                                        }
-
 
130
 
-
 
131
                                        $ll = gmp_mul($ll, 0x80);
-
 
132
                                        $ll = gmp_add($ll, ($pb & 0x7F));
-
 
133
                                        $fOK = false;
-
 
134
                                } else {
-
 
135
                                        $fOK = true;
-
 
136
                                        $ll = gmp_mul($ll, 0x80);
-
 
137
                                        $ll = gmp_add($ll, $pb);
-
 
138
                                        $ll = gmp_sub($ll, $fSub);
-
 
139
                                        $output_oid[] = gmp_strval($ll, 10);
-
 
140
 
-
 
141
                                        $is_iso_standard = ($output_oid[0] == '1') && ($output_oid[1] == '0');
-
 
142
 
-
 
143
                                        $byy = $by;
-
 
144
                                        for ($i=0;$i<=$ii;$i++) array_shift($byy);
-
 
145
 
-
 
146
                                        $s_oid = implode('.',$output_oid);
-
 
147
 
-
 
148
                                        if ($is_iso_standard) {
-
 
149
                                                $std_hf = 'Standard ISO/IEC '.$output_oid[2];
-
 
150
                                                if (isset($output_oid[3])) $std_hf .= "-".$output_oid[3];
-
 
151
                                        } else {
-
 
152
                                                $std_hf = "Unknown Standard"; // should not happen
-
 
153
                                        }
-
 
154
 
-
 
155
                                        $pix = implode(':',$byy);
-
 
156
 
-
 
157
                                        if ($pix !== '') {
-
 
158
                                                $ret[] = array($ii+1,"$std_hf (OID $s_oid)",$pix);
-
 
159
                                        } else {
-
 
160
                                                $ret[] = array($ii+1,"$std_hf (OID $s_oid)","");
-
 
161
                                        }
-
 
162
 
-
 
163
                                        // ISO Standards (OID 1.0) will only have 1 or 2 numbers. (Number 1 is the standard, and number 2
-
 
164
                                        // is the part in case of a multi-part standard).
-
 
165
                                        if ($is_iso_standard && (count($output_oid) == 4)) break;
-
 
166
 
-
 
167
                                        // Happens only if 0x80 paddings are allowed
-
 
168
                                        // $fOK = gmp_cmp($ll, 0) >= 0;
-
 
169
                                        $ll = gmp_init(0);
-
 
170
                                        $fSub = 0;
-
 
171
                                        $arcBeginning = true;
-
 
172
                                }
-
 
173
                        }
-
 
174
                }
-
 
175
        }
-
 
176
        return $ret;
-
 
177
}
-
 
178
 
57
function decode_aid($aid,$compact=true) {
179
function decode_aid($aid,$compact=true) {
58
        $sout = '';
180
        $sout = '';
59
        $out = _decode_aid($aid);
181
        $out = _decode_aid($aid);
60
        if ($compact) {
182
        if ($compact) {
61
                $max_key_len = 0;
183
                $max_key_len = 0;
Line 351... Line 473...
351
        // https://blog.actorsfit.com/a?ID=00250-166ef507-edff-4400-8d0e-9e85d6ae2310
473
        // https://blog.actorsfit.com/a?ID=00250-166ef507-edff-4400-8d0e-9e85d6ae2310
352
 
474
 
353
        $aid = strtoupper($aid);
475
        $aid = strtoupper($aid);
354
        $aid = trim($aid);
476
        $aid = trim($aid);
355
        $aid = str_replace(' ','',$aid);
477
        $aid = str_replace(' ','',$aid);
-
 
478
        $aid = str_replace(':','',$aid);
356
 
479
 
357
        if ($aid == '') {
480
        if ($aid == '') {
358
                $out[] = "INVALID: The AID is empty";
481
                $out[] = "INVALID: The AID is empty";
359
                return $out;
482
                return $out;
360
        }
483
        }
Line 362... Line 485...
362
        if (!preg_match('@^[0-9A-F]+$@', $aid, $m)) {
485
        if (!preg_match('@^[0-9A-F]+$@', $aid, $m)) {
363
                $out[] = "INVALID: AID has invalid characters. Only A..F and 0..9 are allowed";
486
                $out[] = "INVALID: AID has invalid characters. Only A..F and 0..9 are allowed";
364
                return $out;
487
                return $out;
365
        }
488
        }
366
 
489
 
367
        $aid_hf = '';
-
 
368
        for ($i=0; $i<strlen($aid); $i++) {
-
 
369
                $aid_hf .= $aid[$i];
490
        $aid_hf = implode(':',str_split($aid,2));
370
                if ($i%2 == 1) $aid_hf .= ' ';
-
 
371
        }
-
 
372
        if (strlen($aid)%2 == 1) $aid_hf .= '_';
491
        if (strlen($aid)%2 == 1) $aid_hf .= '_';
373
        $aid_hf = rtrim($aid_hf);
-
 
-
 
492
 
374
        $out[] = array("$aid", "ISO/IEC 7816-5 Application Identifier (AID)");
493
        $out[] = array("$aid", "ISO/IEC 7816-5 Application Identifier (AID)");
375
        $out[] = array('', "> $aid_hf <");
494
        $out[] = array('', "> $aid_hf <");
376
        $out[] = array('', c_literal_hexstr($aid));
495
        $out[] = array('', c_literal_hexstr($aid));
377
 
496
 
378
        if ((strlen($aid) == 32) && (substr($aid,-2) == 'FF')) {
497
        if ((strlen($aid) == 32) && (substr($aid,-2) == 'FF')) {
Line 561... Line 680...
561
                }
680
                }
562
 
681
 
563
                return $out;
682
                return $out;
564
        }
683
        }
565
 
684
 
-
 
685
        // Category 'E'
-
 
686
        // AID = 'E8' + OID + PIX   (OID is DER encoding without type and length)
-
 
687
        if ("$category" === "E") {
-
 
688
                $out[] = array("$category", "Category $category: Standard");
-
 
689
 
-
 
690
                $std_scheme = substr($aid,1,1);
-
 
691
                if ($std_scheme == '8') {
-
 
692
                        $out[] = array(" $std_scheme", "Standard identified by OID");
-
 
693
 
-
 
694
                        $data = substr($aid,2);
-
 
695
                        try {
-
 
696
                                $interpretations = _aid_e8_interpretations($aid);
-
 
697
                                foreach ($interpretations as $ii => $interpretation) {
-
 
698
                                        $pos = $interpretation[0];
-
 
699
                                        $txt1 = $interpretation[1]; // Standard
-
 
700
                                        $txt2 = $interpretation[2]; // PIX (optional)
-
 
701
 
-
 
702
                                        $aid1 = '  '.substr($aid,2,$pos*2);
-
 
703
                                        $aid2 = substr($aid,2+$pos*2);
-
 
704
 
-
 
705
                                        $out[] = array("$aid1", "$txt1");
-
 
706
                                        if ($txt2 !== '') {
-
 
707
                                                $pix = "'$txt2' (".c_literal_hexstr(str_replace(':','',$txt2)).")";
-
 
708
                                                $out[] = array(str_repeat(' ',strlen($aid1))."$aid2", "with PIX $pix");
-
 
709
                                        }
-
 
710
                                        if ($ii < count($interpretations)-1) {
-
 
711
                                                $out[] = array('', 'or:');
-
 
712
                                        }
-
 
713
                                }
-
 
714
                        } catch (Exception $e) {
-
 
715
                                $out[] = array("  $data", "ERROR: ".$e->getMessage());
-
 
716
 
-
 
717
                        }
-
 
718
                } else {
-
 
719
                        // E0..E7, E9..EF are RFU
-
 
720
                        $unknown = substr($aid,1);
-
 
721
                        $out[] = array(" $unknown", "ILLEGAL USAGE / RESERVED");
-
 
722
                }
-
 
723
 
-
 
724
                return $out;
-
 
725
        }
-
 
726
 
566
        // Category 'F'
727
        // Category 'F'
567
        // AID = 'F' + PIX
728
        // AID = 'F' + PIX
568
        if ("$category" === "F") {
729
        if ("$category" === "F") {
569
                $out[] = array("$category", "Category $category: Non-registered / Proprietary");
730
                $out[] = array("$category", "Category $category: Non-registered / Proprietary");
570
                $rid = substr($aid,0,1);
731
                $rid = substr($aid,0,1);
Line 576... Line 737...
576
                        $out[] = array('', c_literal_hexstr($pix));
737
                        $out[] = array('', c_literal_hexstr($pix));
577
                }
738
                }
578
                return $out;
739
                return $out;
579
        }
740
        }
580
 
741
 
581
        // Category 'B', 'C', and 'E' are reserved
742
        // Category 'B' and 'C' are reserved
582
        $out[] = array("$category", "Category $category: ILLEGAL USAGE / RESERVED");
743
        $out[] = array("$category", "Category $category: ILLEGAL USAGE / RESERVED");
583
        if (strlen($aid) > 1) {
744
        if (strlen($aid) > 1) {
584
                $aid_ = substr($aid,1);
745
                $aid_ = substr($aid,1);
585
                $out[] = array(" ".$aid_, "Unknown composition");
746
                $out[] = array(" ".$aid_, "Unknown composition");
586
                $out[] = array('', c_literal_hexstr($aid_));
747
                $out[] = array('', c_literal_hexstr($aid_));