Subversion Repositories php_utils

Compare Revisions

Regard whitespace Rev 44 → Rev 45

/trunk/aid_decoder.inc.php
24,13 → 24,15
# ---
 
/*
#test2('A000000051AABBCC');
#test2('B01234567890');
#test2('D276000098AABBCCDDEEFFAABBCCDDEE');
#test2('F01234567890');
#test('91234FFF999');
#test('51234FFF999');
#test2('E828BD080F014E585031');
#test2('A000000051AABBCC'); // International Registration
#test2('B01234567890'); // Illegal AID (RFU)
#test2('D276000098AABBCCDDEEFFAABBCCDDEE'); // National Registration
#test2('F01234567890'); // Unregistered AID
#test('91234FFF999'); // IIN based AID
#test('51234FFF999'); // IIN based AID
test('E828BD080F014E585031'); // ISO E8-OID 1.0.aaaa
test('E80704007F00070304'); // BSI Illegal E8-OID-AID (with DER Length)
test('E80704007F0007030499'); // BSI Illegal E8-OID-AID + PIX (PIX is never used by BSI; it's just for us to test)
 
function test2($aid) {
while ($aid != '') {
60,15 → 62,49
 
# ---
 
function _aid_e8_interpretations($aid) {
function _aid_e8_oid_helper($output_oid,$by,$ii,&$ret,$minmax_measure,$min,$max) {
if ($minmax_measure == 'ARC') {
if (($min!=-1) && (count($output_oid)<$min)) return true; // continue
if (($max!=-1) && (count($output_oid)>$max)) return false; // stop
} else if ($minmax_measure == 'DER') {
if (($min!=-1) && ($ii+1<$min)) return true; // continue
if (($max!=-1) && ($ii+1>$max)) return false; // stop
}
 
$byy = $by;
for ($i=0;$i<=$ii;$i++) array_shift($byy);
 
$is_iso_standard = (count($output_oid) >= 3) && ($output_oid[0] == '1') && ($output_oid[1] == '0');
 
$s_oid = implode('.',$output_oid);
 
if ($is_iso_standard) {
$std_hf = 'Standard ISO/IEC '.$output_oid[2];
if (isset($output_oid[3])) $std_hf .= "-".$output_oid[3];
} else {
$std_hf = "Unknown Standard"; // should not happen
}
 
$pix = implode(':',$byy);
 
if ($pix !== '') {
$ret[] = array($ii+1,"$std_hf (OID $s_oid)",$pix);
} else {
$ret[] = array($ii+1,"$std_hf (OID $s_oid)","");
}
 
return true;
}
 
function _aid_e8_interpretations($pure_der, $minmax_measure='ARC', $min=-1, $max=-1) {
$ret = array();
 
$output_oid = array();
 
$aid = strtoupper(str_replace(' ','',$aid));
$aid = strtoupper(str_replace(':','',$aid));
$by = str_split($aid,2);
if ((array_shift($by) == 'E8') ) {
$pure_der = strtoupper(str_replace(' ','',$pure_der));
$pure_der = strtoupper(str_replace(':','',$pure_der));
$by = str_split($pure_der,2);
 
// The following part is partially taken from the DER decoder/encoder by Daniel Marschall:
// https://github.com/danielmarschall/oidconverter/blob/master/php/OidDerConverter.class.phps
// (Only the DER "value" part, without "type" and "length")
88,6 → 124,7
if ($first > 2) {
$first = 2;
$output_oid[] = $first;
if (!_aid_e8_oid_helper($output_oid, $by, $ii, $ret, $minmax_measure, $min, $max)) break;
$arcBeginning = true;
 
if (($pb & 0x80) != 0) {
107,6 → 144,7
// 2.0 till 2.47 => 1 octet
$second = $pb - 80;
$output_oid[] = $second;
if (!_aid_e8_oid_helper($output_oid, $by, $ii, $ret, $minmax_measure, $min, $max)) break;
$arcBeginning = true;
$fOK = true;
$ll = gmp_init(0);
116,6 → 154,7
// 1.0 till 1.37 => 1 octet
$output_oid[] = $first;
$output_oid[] = $second;
if (!_aid_e8_oid_helper($output_oid, $by, $ii, $ret, $minmax_measure, $min, $max)) break;
$arcBeginning = true;
$fOK = true;
$ll = gmp_init(0);
139,32 → 178,8
$ll = gmp_sub($ll, $fSub);
$output_oid[] = gmp_strval($ll, 10);
 
$is_iso_standard = ($output_oid[0] == '1') && ($output_oid[1] == '0');
if (!_aid_e8_oid_helper($output_oid, $by, $ii, $ret, $minmax_measure, $min, $max)) break;
 
$byy = $by;
for ($i=0;$i<=$ii;$i++) array_shift($byy);
 
$s_oid = implode('.',$output_oid);
 
if ($is_iso_standard) {
$std_hf = 'Standard ISO/IEC '.$output_oid[2];
if (isset($output_oid[3])) $std_hf .= "-".$output_oid[3];
} else {
$std_hf = "Unknown Standard"; // should not happen
}
 
$pix = implode(':',$byy);
 
if ($pix !== '') {
$ret[] = array($ii+1,"$std_hf (OID $s_oid)",$pix);
} else {
$ret[] = array($ii+1,"$std_hf (OID $s_oid)","");
}
 
// ISO Standards (OID 1.0) will only have 1 or 2 numbers. (Number 1 is the standard, and number 2
// is the part in case of a multi-part standard).
if ($is_iso_standard && (count($output_oid) == 4)) break;
 
// Happens only if 0x80 paddings are allowed
// $fOK = gmp_cmp($ll, 0) >= 0;
$ll = gmp_init(0);
173,12 → 188,13
}
}
}
}
 
return $ret;
}
 
function decode_aid($aid,$compact=true) {
$sout = '';
if (strtolower(substr($aid,0,2)) == '0x') $aid = substr($aid,2);
$out = _decode_aid($aid);
if ($compact) {
$max_key_len = 0;
207,7 → 223,7
function _decode_aid($aid) {
 
// based on https://github.com/thephpleague/iso3166/blob/main/src/ISO3166.php
// commit 26.07.2022
// commit 26 July 2022
// Generated using:
/*
$x = new ISO3166();
692,16 → 708,56
if ($std_schema == '8') {
$out[] = array(" $std_schema", "Standard identified by OID");
 
$data = substr($aid,2);
// Including the DER Encoding "Length" is not defined by ISO but used illegally
// by German BSI (beside the fact that ISO never allowed anyone else to use E8-AIDs outside
// of OID arc 1.0),
// e.g. 0xE80704007F00070302 defined by "BSI TR-03110" was intended to represent 0.4.0.127.0.7.3.2
// "more correct" would have been 0xE804007F00070302
// 0xE80704007F00070304 defined by "BSI TR-03109-2" was intended to represent 0.4.0.127.0.7.3.4
// "more correct" would have been 0xE804007F00070304
$include_der_length_roots = array(
'04007F0007' /* bsi-de (0.4.0.127.0.7) */
);
$include_der_length = false;
foreach ($include_der_length_roots as $include_der_length_root) {
$der_length_hex = null;
$der_length_dec = null;
if (substr($aid,4,strlen($include_der_length_root)) == $include_der_length_root) {
$der_length_hex = substr($aid,2,2);
$der_length_dec = hexdec($der_length_hex);
if ($der_length_dec <= 14) {
$include_der_length = true;
break;
}
}
}
if ($include_der_length) {
$out[] = array(" $der_length_hex", "DER encoding length (illegal usage not defined by ISO)");
$pure_der = substr($aid,4);
$indent = 4;
$e8_minmax_measure = 'DER';
$e8_min = $der_length_dec;
$e8_max = $der_length_dec;
} else {
$pure_der = substr($aid,2);
$indent = 2;
// ISO Standards (OID 1.0) will only have 1 or 2 numbers. (Number 1 is the standard, and number 2
// is the part in case of a multi-part standard).
$e8_minmax_measure = 'ARC';
$e8_min = 3; // 1.0.aaaa (ISO AAAA)
$e8_max = 4; // 1.0.aaaa.b (ISO AAAA-B)
}
// --- End of BSI compatibility hack ---
 
try {
$interpretations = _aid_e8_interpretations($aid);
$interpretations = _aid_e8_interpretations($pure_der,$e8_minmax_measure,$e8_min,$e8_max);
foreach ($interpretations as $ii => $interpretation) {
$pos = $interpretation[0];
$txt1 = $interpretation[1]; // Standard
$txt2 = $interpretation[2]; // PIX (optional)
 
$aid1 = ' '.substr($aid,2,$pos*2);
$aid2 = substr($aid,2+$pos*2);
$aid1 = str_repeat(' ',$indent).substr($pure_der,0,$pos*2);
$aid2 = substr($pure_der,$pos*2);
 
$out[] = array("$aid1", "$txt1");
if ($txt2 !== '') {
713,8 → 769,7
}
}
} catch (Exception $e) {
$out[] = array(" $data", "ERROR: ".$e->getMessage());
 
$out[] = array(str_repeat(' ',$indent).$pure_der, "ERROR: ".$e->getMessage());
}
} else if ($std_schema != '') {
// E0..E7, E9..EF are RFU