我正在尝试解析一些M $生成的证书,并发现phpseclib ASN1 decodeBER函数在一些OID上窒息。在这种情况下,我真的想更好地理解这个函数及其行为。
以下是讨论的示例证书:
-----BEGIN CERTIFICATE-----
MIIG1jCCBL6gAwIBAgITUAAAAA0qg8bE6DhrLAAAAAAADTANBgkqhkiG9w0BAQsF
ADAiMSAwHgYDVQQDExcuU2VjdXJlIEVudGVycHJpc2UgQ0EgMTAeFw0xNTAyMjMx
NTE1MDdaFw0xNjAyMjMxNTE1MDdaMD8xFjAUBgoJkiaJk/IsZAEZFgZzZWN1cmUx
DjAMBgNVBAMTBVVzZXJzMRUwEwYDVQQDEwxtZXRhY2xhc3NpbmcwggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDMdG1CzR/gTalbLN9J+2cvMGeD7wsR7S78
HU5hdwE+kECROjRAcjFBOR57ezSDrkmhkTzo28tj0oAHjOh8N9vuXtASfZSCXugx
H+ImJ+E7PA4aXBp+0H2hohW9sXNNCFiVNmJLX66O4bxIeKtVRq/+eSNijV4OOEkC
zMyTHAUbOFP0t6KoJtM1syNoQ1+fKdfcjz5XtiEzSVcp2zf0MwNFSeZSgGQ0jh8A
Kd6YVKA8ZnrqOWZxKETT+bBNTjIT0ggjQfzcE4zW2RzrN7zWabUowoU92+DAp4s3
sAEywX9ISSge62DEzTnZZSf9bpoScAfT8raRFA3BkoJ/s4c4CgfPAgMBAAGjggLm
MIIC4jAdBgNVHQ4EFgQULlIyJL9+ZwAI/SkVdsJMxFOVp+EwHwYDVR0jBBgwFoAU
5nEIMEUT5mMd1WepmviwgK7dIzwwggEKBgNVHR8EggEBMIH+MIH7oIH4oIH1hoG5
bGRhcDovLy9DTj0uU2VjdXJlJTIwRW50ZXJwcmlzZSUyMENBJTIwMSxDTj1hdXRo
LENOPUNEUCxDTj1QdWJsaWMlMjBLZXklMjBTZXJ2aWNlcyxDTj1TZXJ2aWNlcyxD
Tj1Db25maWd1cmF0aW9uLERDPXNlY3VyZT9jZXJ0aWZpY2F0ZVJldm9jYXRpb25M
aXN0P2Jhc2U/b2JqZWN0Q2xhc3M9Y1JMRGlzdHJpYnV0aW9uUG9pbnSGN2h0dHA6
Ly9jcmwuc2VjdXJlb2JzY3VyZS5jb20vP2FjdGlvbj1jcmwmY2E9ZW50ZXJwcmlz
ZTEwgccGCCsGAQUFBwEBBIG6MIG3MIG0BggrBgEFBQcwAoaBp2xkYXA6Ly8vQ049
LlNlY3VyZSUyMEVudGVycHJpc2UlMjBDQSUyMDEsQ049QUlBLENOPVB1YmxpYyUy
MEtleSUyMFNlcnZpY2VzLENOPVNlcnZpY2VzLENOPUNvbmZpZ3VyYXRpb24sREM9
c2VjdXJlP2NBQ2VydGlmaWNhdGU/YmFzZT9vYmplY3RDbGFzcz1jZXJ0aWZpY2F0
aW9uQXV0aG9yaXR5MBcGCSsGAQQBgjcUAgQKHggAVQBzAGUAcjAOBgNVHQ8BAf8E
BAMCBaAwKQYDVR0lBCIwIAYKKwYBBAGCNwoDBAYIKwYBBQUHAwQGCCsGAQUFBwMC
MC4GA1UdEQQnMCWgIwYKKwYBBAGCNxQCA6AVDBNtZXRhY2xhc3NpbmdAc2VjdXJl
MEQGCSqGSIb3DQEJDwQ3MDUwDgYIKoZIhvcNAwICAgCAMA4GCCqGSIb3DQMEAgIA
gDAHBgUrDgMCBzAKBggqhkiG9w0DBzANBgkqhkiG9w0BAQsFAAOCAgEAKNmjYh+h
cObJEM0CWgz50jOYKZ4M5iIxoAWgrYY9Pv+0O9aPjvPLzjd5bY322L8lxh5wy5my
DKmip+irzjdVdxzQfoyy+ceODmCbX9L6MfEDn0RBzdwjLe1/eOxE1na0sZztrVCc
yt5nI91NNGZJUcVqVQsIA/25FWlkvo/FTfuqTuXdQiEVM5MCKJI915anmTdugy+G
0CmBJALIxtyz5P7sZhaHZFNdpKnx82QsauErqjP9H0RXc6VXX5qt+tEDvYfSlFcc
0lv3aQnV/eIdfm7APJkQ3lmNWWQwdkVf7adXJ7KAAPHSt1yvSbVxThJR/jmIkyeQ
XW/TOP5m7JI/GrmvdlzI1AgwJ+zO8fOmCDuif99pDb1CvkzQ65RZ8p5J1ZV6hzlb
VvOhn4LDnT1jnTcEqigmx1gxM/5ifvMorXn/ItMjKPlb72vHpeF7OeKE8GHsvZAm
osHcKyJXbTIcXchmpZX1efbmCMJBqHgJ/qBTBMl9BX0+YqbTZyabRJSs9ezbTRn0
oRYl21Q8EnvS71CemxEUkSsKJmfJKkQNCsOjc8AbX/V/X9R7LJkH3UEx6K2zQQKK
k6m17mi63YW/+iPCGOWZ2qXmY5HPEyyF2L4L4IDryFJ+8xLyw3pH9/yp5aHZDtp6
833K6qyjgHJT+fUzSEYpiwF5rSBJIGClOCY=
-----END CERTIFICATE-----
出于简单的测试目的,这是我的驱动程序:
$X509 = new File_X509();
$BER = $X509->_extractBER($BER);
$ASN1 = new File_ASN1();
$ASN1->loadOIDs($X509->oids);
$DECODED = $ASN1->decodeBER( $BER );
Utility::dumper($DECODED);
我认为我们遇到了麻烦〜第423行:
case FILE_ASN1_TYPE_OCTET_STRING:
if (!$constructed) {
$current['content'] = $content;
} else {
$current['content'] = '';
$length = 0;
while (substr($content, 0, 2) != "\0\0") {
$temp = $this->_decode_ber($content, $length + $start);
$this->_string_shift($content, $temp['length']);
// all subtags should be octet strings
//if ($temp['type'] != FILE_ASN1_TYPE_OCTET_STRING) {
// return false;
//}
$current['content'].= $temp['content'];
$length+= $temp['length'];
}
if (substr($content, 0, 2) == "\0\0") {
$length+= 2; // +2 for the EOC
}
}
break;
特别是在转储数组元素7的输出(subjectAltName)
时[7] => Array
(
[start] => 1104
[headerlength] => 2
[type] => 16
[content] => Array
(
[0] => Array
(
[start] => 1106
[headerlength] => 2
[type] => 6
[content] => 2.5.29.17
[length] => 5
)
[1] => Array
(
[start] => 1111
[headerlength] => 2
[type] => 4
[content] => 0% #^F+^F^A^D^A^Â7^T^B^C ^U^L^Smetaclassing@secure
[length] => 41
)
)
[length] => 48
)
似乎应该将内容解析为数组而不是二进制垃圾字符串。我相信它应该解析成更像这样的东西:
SEQUENCE(2 elem)
OBJECT IDENTIFIER2.5.29.17
OCTET STRING(1 elem)
SEQUENCE(1 elem)
Offset: 1113
Length: 2+37
(constructed)
Value:
(1 elem)
[0](2 elem)
OBJECT IDENTIFIER1.3.6.1.4.1.311.20.2.3
[0](1 elem)
UTF8String metaclassing@secure
我相信这是一个“构造”字段,但是在第298行,按位运算发生的事情有点超出我的理解:
$constructed = ($type >> 5) & 1;
我已经编写了一个匹配十六进制值的角落大小写,以强制$ this为这个特定的数组元素构造为1,但是在解析方面没有看到太大的改进。想知道下一个最好的步骤是什么来解决这个问题?我非常感谢你的帮助和想法。谢谢!
答案 0 :(得分:1)
您应该尝试递归OCTET_STRING内容并尝试解码嵌套记录以查看它是否解码为有效ASN.1。所有证书扩展值都作为嵌套到OCTET_STRING结构放置:
据我所知,以下原始标记仅以原始形式使用:BOOLEAN,INTEGER,NULL,OBJECT_IDENTIFIER,REAL,ENUMERATED和RELATIVE_OID。其余的原始标签可能具有嵌入的内容。虽然这个列表不是确定的,但OCTET_STRING肯定可能是一个容器,即使它的标签是以原始形式编码的。这也适用于BIT_STRING。
答案 1 :(得分:1)
确实,代码应该重现。以下是我迄今为止的调查结果:
$class = ($type >> 6) & 3;
问题看起来似乎是正在使用的按位操作,它没有正确识别类(对于应用程序返回0,对于特定于上下文应该为2,对于构造应为1时为0。
为了测试我在下面插入了这段代码(非常hackish,但我是ASN.1n00b:
// Manual testing for incorrect class/constructed detection!
if ( !$constructed && $class == 0 && isset($content[0]) && isset($content[1]) )
{
//print "\nSTART: $start\tTYPE IS: {$type}\t CLASS IS: {$class}\tCONTENT IS {$content}\n";
if ( ($content[0] == "0" && $content[1] == "%" ) ||
($content[0] == hex2bin("30") && $content[1] == hex2bin("81") ) ||
($content[0] == hex2bin("82") && $content[1] == hex2bin("01") ) ||
($content[0] == hex2bin("30") && $content[1] == hex2bin("20") ) ||
($content[0] == hex2bin("1e") && $content[1] == hex2bin("08") ) ||
($content[0] == hex2bin("00") && $content[1] == hex2bin("55") ) ||
($content[0] == hex2bin("04") && $content[1] == hex2bin("14") ) ||
($content[0] == hex2bin("30") && $content[1] == hex2bin("16") ) ||
($content[0] == hex2bin("00") && $content[1] == hex2bin("30") ) )
{
$class = 2; $constructed = 1; //print "SET CLASS AND CONSTRUCTED!\n";
}else{
//print "C0: {$content[0]} = (0x" . bin2hex($content[0]) . ") C1: {$content[1]} = (0x" . bin2hex($content[1]) . ") did not match!\n";
}
}
事实上,手动匹配未正确检测到的字节确实解决了我的问题:
[7] => Array
(
[start] => 1104
[headerlength] => 2
[type] => 16
[content] => Array
(
[0] => Array
(
[start] => 1106
[headerlength] => 2
[type] => 6
[content] => 2.5.29.17
[length] => 5
)
[1] => Array
(
[type] => 2
[constant] => 4
[content] => Array
(
[0] => Array
(
[start] => 1113
[headerlength] => 2
[type] => 16
[content] => Array
(
[0] => Array
(
[type] => 2
[constant] => 0
[content] => Array
(
[0] => Array
(
[start] => 1117
[headerlength] => 2
[type] => 6
[content] => 1.3.6.1.4.1.311.20.2.3
[length] => 12
)
)
[length] => 14
[start] => 1115
[headerlength] => 2
)
[1] => Array
(
[type] => 2
[constant] => 0
[content] => Array
(
[0] => Array
(
[start] => 1131
[headerlength] => 2
[type] => 12
[content] => metaclassing@secure
[length] => 21
)
)
[length] => 23
[start] => 1129
[headerlength] => 2
)
)
[length] => 39
)
)
[length] => 41
[start] => 1111
[headerlength] => 2
)
)
[length] => 48
)
此时我想我需要等待库开发人员查看ASN.1解析函数/库,并查看为什么这些证书让它非常不开心。修补此功能在某种程度上超出了我的能力。