php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #71519 SSL Serial Number wildly wrong
Submitted: 2016-02-04 03:17 UTC Modified: 2017-04-28 15:34 UTC
Votes:6
Avg. Score:2.7 ± 1.4
Reproduced:3 of 4 (75.0%)
Same Version:3 (100.0%)
Same OS:1 (33.3%)
From: xrobau at gmail dot com Assigned: bukka (profile)
Status: Closed Package: OpenSSL related
PHP Version: 5.6.17 OS: CentOS 7.2
Private report: No CVE-ID: None
 [2016-02-04 03:17 UTC] xrobau at gmail dot com
Description:
------------
When a certificate's serial number starts with a null, the serial number reported is wildly wrong.

For example:

-----BEGIN CERTIFICATE-----
MIIEVzCCAz+gAwIBAgIVAJBE2ako0aG8TmE0MR3X60rpaxRoMA0GCSqGSIb3DQEB
CwUAMIGhMQswCQYDVQQGEwJDQTEQMA4GA1UECAwHT250YXJpbzEcMBoGA1UECgwT
U2FuZ29tYSBDb3Jwb3JhdGlvbjEVMBMGA1UECwwMUHJvdmlzaW9uaW5nMSYwJAYD
VQQDDB1QaG9uZSBTaWduaW5nIEtleSAoMjAxNi0yMDE4KTEjMCEGCSqGSIb3DQEJ
ARYUc2VjdXJpdHlAc2FuZ29tYS5jb20wHhcNMTYwMjAzMDYwNTAyWhcNMzYwMTI5
MDYwNTAyWjB1MQswCQYDVQQGEwJDQTEQMA4GA1UECAwHT250YXJpbzEQMA4GA1UE
BwwHVG9yb250bzEQMA4GA1UECgwHU2FuZ29tYTEVMBMGA1UECwwMUHJvdmlzaW9u
aW5nMRkwFwYDVQQDDBBNQUMtMDA1MDU4NTAwMTAwMIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEA1owwYWRaOZceTr5Fa6iuUoBArWnQ5+JzdgA+qPCrbu0/
V87OpvIWRk+141D40xT278Ae4fExqsI/R+MQN5MQcGkWDWZ+t7Cr/QQVmtdcuoXQ
NXM8VyaiHF8pfOs/wC9GE78Qnry/S5cPUt0S5DXgyzGADDTYwE0kC9P2RNrNvv6y
/VkmJbwo+sW7540s9Zue4aaKCBQ8VVL9gBPNUt25+NL8gFIqmXY2Zoq/lnFEw3X2
3pjILimb5FVVqmYrKkQYG/KANBJBieYURX6htUnS6LS3fxcwaxFU0hIw/kVs8Bw0
76y41ii6p/LYQkGJdR/EjCauNvagqfTdnI9qlQJK4wIDAQABo4GwMIGtMAkGA1Ud
EwQCMAAwEQYJYIZIAYb4QgEBBAQDAgeAMCgGCWCGSAGG+EIBDQQbFhlTYW5nb21h
IFBob25lIENlcnRpZmljYXRlMB0GA1UdDgQWBBR703JYf9BRTQus+ZCS7G/ZJDdb
mjAfBgNVHSMEGDAWgBRhRHZJs4QP8YONN/WWkAAls8liXDAOBgNVHQ8BAf8EBAMC
BLAwEwYDVR0lBAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQELBQADggEBAEQKEeMk
zJ2khQXqTmVQ45Y5GmV39YQsoKvIHd+UUypvQvrIAW3ETqq2MYpr+9H0UaofLMcC
9SSDAzuPgLSlQ/pD+EnAx7SFV4Z9uQoODJ6jy6Bed3lB7XnMuyiNZemlJlplT0UB
le3W8BZkJJ8evBPY3xlmih+IWE71bpD5o7zehY0F3iMGTEAM79xORu16dgYsWfNR
xA5lZ3VqszNJIlva1jcFxyK7JgYwTAh+E5QL9w5HuFyWxfhwiuHARGzan2My4hkB
xzEkyWB8rcfqB4WlLumbxdBgOPBrmz0mVqCW1Akz3jmOwM/Xn84KKey6kO5S8zSe
oOvl9VZbYyXMaPo=
-----END CERTIFICATE-----

The certificate serial number starts with 00:90:44, and openssl (correctly) drops the leading zeros:

[user@dev ~]$ openssl x509 -in test.crt -noout -serial
serial=9044D9A928D1A1BC4E6134311DD7EB4AE96B1468
[user@dev ~]$

Mozilla, on the other hand, displays the Serial number with its leading zeros:

http://imgur.com/GN7Y43M

[user@dev ~]$ php fail.php
Serial should be 9044D9A928D1A1BC4E6134311DD7EB4AE96B1468 or 009044D9A928D1A1BC4E6134311DD7EB4AE96B1468:
Serial reported as: '823630082600157765737248287472764421210987238504'
[user@dev ~]$




Test script:
---------------
$cert="-----BEGIN CERTIFICATE-----
MIIEVzCCAz+gAwIBAgIVAJBE2ako0aG8TmE0MR3X60rpaxRoMA0GCSqGSIb3DQEB
CwUAMIGhMQswCQYDVQQGEwJDQTEQMA4GA1UECAwHT250YXJpbzEcMBoGA1UECgwT
U2FuZ29tYSBDb3Jwb3JhdGlvbjEVMBMGA1UECwwMUHJvdmlzaW9uaW5nMSYwJAYD
VQQDDB1QaG9uZSBTaWduaW5nIEtleSAoMjAxNi0yMDE4KTEjMCEGCSqGSIb3DQEJ
ARYUc2VjdXJpdHlAc2FuZ29tYS5jb20wHhcNMTYwMjAzMDYwNTAyWhcNMzYwMTI5
MDYwNTAyWjB1MQswCQYDVQQGEwJDQTEQMA4GA1UECAwHT250YXJpbzEQMA4GA1UE
BwwHVG9yb250bzEQMA4GA1UECgwHU2FuZ29tYTEVMBMGA1UECwwMUHJvdmlzaW9u
aW5nMRkwFwYDVQQDDBBNQUMtMDA1MDU4NTAwMTAwMIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEA1owwYWRaOZceTr5Fa6iuUoBArWnQ5+JzdgA+qPCrbu0/
V87OpvIWRk+141D40xT278Ae4fExqsI/R+MQN5MQcGkWDWZ+t7Cr/QQVmtdcuoXQ
NXM8VyaiHF8pfOs/wC9GE78Qnry/S5cPUt0S5DXgyzGADDTYwE0kC9P2RNrNvv6y
/VkmJbwo+sW7540s9Zue4aaKCBQ8VVL9gBPNUt25+NL8gFIqmXY2Zoq/lnFEw3X2
3pjILimb5FVVqmYrKkQYG/KANBJBieYURX6htUnS6LS3fxcwaxFU0hIw/kVs8Bw0
76y41ii6p/LYQkGJdR/EjCauNvagqfTdnI9qlQJK4wIDAQABo4GwMIGtMAkGA1Ud
EwQCMAAwEQYJYIZIAYb4QgEBBAQDAgeAMCgGCWCGSAGG+EIBDQQbFhlTYW5nb21h
IFBob25lIENlcnRpZmljYXRlMB0GA1UdDgQWBBR703JYf9BRTQus+ZCS7G/ZJDdb
mjAfBgNVHSMEGDAWgBRhRHZJs4QP8YONN/WWkAAls8liXDAOBgNVHQ8BAf8EBAMC
BLAwEwYDVR0lBAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQELBQADggEBAEQKEeMk
zJ2khQXqTmVQ45Y5GmV39YQsoKvIHd+UUypvQvrIAW3ETqq2MYpr+9H0UaofLMcC
9SSDAzuPgLSlQ/pD+EnAx7SFV4Z9uQoODJ6jy6Bed3lB7XnMuyiNZemlJlplT0UB
le3W8BZkJJ8evBPY3xlmih+IWE71bpD5o7zehY0F3iMGTEAM79xORu16dgYsWfNR
xA5lZ3VqszNJIlva1jcFxyK7JgYwTAh+E5QL9w5HuFyWxfhwiuHARGzan2My4hkB
xzEkyWB8rcfqB4WlLumbxdBgOPBrmz0mVqCW1Akz3jmOwM/Xn84KKey6kO5S8zSe
oOvl9VZbYyXMaPo=
-----END CERTIFICATE-----";

$x509 = openssl_x509_parse($cert);
print "Serial should be 9044D9A928D1A1BC4E6134311DD7EB4AE96B1468 or 009044D9A928D1A1BC4E6134311DD7EB4AE96B1468:\n";
print "Serial reported as: '".$x509['serialNumber']."'\n";



Patches

php-bug-71519.patch (last revision 2016-02-04 06:01 UTC by moises dot silva at gmail dot com)

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-02-04 04:14 UTC] xrobau at gmail dot com
Note to clarify:  The first byte of the serial number being 00 specifically means that the serial number is a hex digit, and should be reported as such.  

However, there is an overflow in the serial number code. This is obvious when doing a dechex() on the number returned:

$ php fail.php
Serial should be 9044D9A928D1A1BC4E6134311DD7EB4AE96B1468 or 009044D9A928D1A1BC4E6134311DD7EB4AE96B1468:
Serial reported as: '7fffffffffffffff'
 [2016-02-04 04:17 UTC] xrobau at gmail dot com
Appears to be related to 2010-era-bug 

https://bugs.php.net/bug.php?id=52093
 [2016-02-04 04:22 UTC] xrobau at gmail dot com
Additional information:

This appears to be related to long-forgotten bug https://bugs.php.net/bug.php?id=52093

After doing some further diagnosis after reporting the bug, I tried doing a dechex on the number provided by serialNumber, and that immediately exposed an overflow there:

$ php fail.php
Serial should be 9044D9A928D1A1BC4E6134311DD7EB4AE96B1468 or 009044D9A928D1A1BC4E6134311DD7EB4AE96B1468:
Serial reported as: '7fffffffffffffff'
$

Additionally, as I didn't make it clear in the original report, the leading byte of a serial number being zero means that the serial number is to be reported as hex, not interpreted as a decimal number.
 [2016-02-04 05:57 UTC] moises dot silva at gmail dot com
I'm awfully rusty on php internals and openssl API, but here is a patch that seems to solve the issue. It may very well break something else or blow up your machine, but at least should point the devs in the right direction to find the problem. It seems to me like some sort of integer overflow problem.

For reference on the way to convert the serial to string:
http://stackoverflow.com/questions/9646929/asn1-integer-to-asn1-string

And the openssl multiprecision integer arithmetics API:
https://www.openssl.org/docs/manmaster/crypto/bn.html
https://www.openssl.org/docs/manmaster/crypto/BN_bn2bin.html

Finally, I apologize for the inline patch, I didn't find an option to attach a file to this issue:

--- php-5.6.17/ext/openssl/openssl.c	2016-01-06 10:14:47.000000000 -0500
+++ php-5.6.17-patched/ext/openssl/openssl.c	2016-02-04 00:46:30.763746683 -0500
@@ -1944,6 +1944,7 @@
 	char *extname;
 	BIO  *bio_out;
 	BUF_MEM *bio_buf;
+	char * serial;
 	char buf[256];
 
 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|b", &zcert, &useshortnames) == FAILURE) {
@@ -1971,7 +1972,12 @@
 	add_assoc_name_entry(return_value, "issuer", 		X509_get_issuer_name(cert), useshortnames TSRMLS_CC);
 	add_assoc_long(return_value, "version", 			X509_get_version(cert));
 
-	add_assoc_string(return_value, "serialNumber", i2s_ASN1_INTEGER(NULL, X509_get_serialNumber(cert)), 1); 
+	serial = BN_bn2hex(ASN1_INTEGER_to_BN(X509_get_serialNumber(cert), NULL));
+	if (!serial) {
+		RETURN_FALSE;
+	}
+	add_assoc_string(return_value, "serialNumber", serial, 1); 
+	OPENSSL_free(serial);
 
 	add_assoc_asn1_string(return_value, "validFrom", 	X509_get_notBefore(cert));
 	add_assoc_asn1_string(return_value, "validTo", 		X509_get_notAfter(cert));
 [2016-02-04 07:15 UTC] moises dot silva at gmail dot com
Heh, I should read twice before jumping into fixing mode at midnight. This isn't a bug. The problem is just the returned string is in decimal and represents an integer larger than PHP_INTMAX, and hence you cannot use dec2hex as you just found out.

If you want to convert it to hex you can do something like this:
http://stackoverflow.com/questions/14539727/how-to-convert-a-huge-integer-to-hex-in-php
 [2016-02-04 20:06 UTC] xrobau at gmail dot com
Thinking more about this, this isn't really a bug, but more of a feature request. As you can't trust php to dechex() the returned serial number, the hex serial number (as per moises patch, above) should probably be returned as an *additional* field - for example 'serialNumberHex' - when parsing the x509 cert.

As the code for translating it to hex is then done by OpenSSL in https://www.openssl.org/docs/manmaster/crypto/BN_bn2bin.html you can be sure that the serial number is authoritatively correct.
 [2017-04-28 15:34 UTC] bukka@php.net
-Status: Open +Status: Closed -Assigned To: +Assigned To: bukka
 [2017-04-28 15:34 UTC] bukka@php.net
This has been resolved by https://github.com/php/php-src/pull/1755
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Tue Mar 19 05:01:29 2024 UTC