Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 16 additions & 6 deletions ext/openssl/openssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -1014,6 +1014,7 @@ PHP_FUNCTION(openssl_x509_parse)
char *str_serial;
char *hex_serial;
char buf[256];
zval altname;

ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_OBJ_OF_CLASS_OR_STR(cert_obj, php_openssl_certificate_ce, cert_str)
Expand All @@ -1033,15 +1034,17 @@ PHP_FUNCTION(openssl_x509_parse)
add_assoc_string(return_value, "name", cert_name);
OPENSSL_free(cert_name);

php_openssl_add_assoc_name_entry(return_value, "subject", subject_name, useshortnames);
php_openssl_add_assoc_name_entry(return_value, "subject", subject_name, useshortnames ?
PHP_OPENSSL_SHORT_NAME : PHP_OPENSSL_LONG_NAME);
/* hash as used in CA directories to lookup cert by subject name */
{
char buf[32];
snprintf(buf, sizeof(buf), "%08lx", X509_subject_name_hash(cert));
add_assoc_string(return_value, "hash", buf);
}

php_openssl_add_assoc_name_entry(return_value, "issuer", X509_get_issuer_name(cert), useshortnames);
php_openssl_add_assoc_name_entry(return_value, "issuer", X509_get_issuer_name(cert), useshortnames ?
PHP_OPENSSL_SHORT_NAME : PHP_OPENSSL_LONG_NAME);
add_assoc_long(return_value, "version", X509_get_version(cert));

asn1_serial = X509_get_serialNumber(cert);
Expand Down Expand Up @@ -1115,8 +1118,7 @@ PHP_FUNCTION(openssl_x509_parse)
add_assoc_zval(return_value, "purposes", &subitem);

array_init(&subitem);


array_init(&altname);
for (i = 0; i < X509_get_ext_count(cert); i++) {
int nid;
extension = X509_get_ext(cert, i);
Expand All @@ -1133,7 +1135,7 @@ PHP_FUNCTION(openssl_x509_parse)
goto err_subitem;
}
if (nid == NID_subject_alt_name) {
if (openssl_x509v3_subjectAltName(bio_out, extension) == 0) {
if (openssl_x509v3_subjectAltName(bio_out, extension, &altname) == 0) {
BIO_get_mem_ptr(bio_out, &bio_buf);
add_assoc_stringl(&subitem, extname, bio_buf->data, bio_buf->length);
} else {
Expand All @@ -1150,13 +1152,20 @@ PHP_FUNCTION(openssl_x509_parse)
BIO_free(bio_out);
}
add_assoc_zval(return_value, "extensions", &subitem);
zend_long altcount = zend_hash_num_elements(Z_ARRVAL_P(&altname));
if (altcount > 0) {
add_assoc_zval(return_value, "subjectAlternativeName", &altname);
} else {
zval_ptr_dtor(&altname);
}
if (cert_str) {
X509_free(cert);
}
return;

err_subitem:
zval_ptr_dtor(&subitem);
zval_ptr_dtor(&altname);
err:
zend_array_destroy(Z_ARR_P(return_value));
if (cert_str) {
Expand Down Expand Up @@ -1953,7 +1962,8 @@ PHP_FUNCTION(openssl_csr_get_subject)
subject = X509_REQ_get_subject_name(csr);

array_init(return_value);
php_openssl_add_assoc_name_entry(return_value, NULL, subject, use_shortnames);
php_openssl_add_assoc_name_entry(return_value, NULL, subject, use_shortnames ?
PHP_OPENSSL_SHORT_NAME : PHP_OPENSSL_LONG_NAME);

if (csr_str) {
X509_REQ_free(csr);
Expand Down
182 changes: 166 additions & 16 deletions ext/openssl/openssl_backend_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@

/* Common */
#include <time.h>
#ifdef PHP_WIN32
# include <Ws2tcpip.h>
#else
# include <arpa/inet.h>
#endif

#if (defined(PHP_WIN32) && defined(_MSC_VER))
#define timezone _timezone /* timezone is called _timezone in LibC */
Expand All @@ -35,12 +40,14 @@
/* true global; readonly after module startup */
static char default_ssl_conf_filename[MAXPATHLEN];

void php_openssl_add_assoc_name_entry(zval * val, char * key, X509_NAME * name, int shortname)
void php_openssl_add_assoc_name_entry(zval * val, char * key, X509_NAME * name,
enum php_openssl_name_type nametype)
{
zval *data;
zval subitem, tmp;
int i;
char *sname;
char *sname = NULL;
char oname[1024];
int nid;
X509_NAME_ENTRY * ne;
ASN1_STRING * str = NULL;
Expand All @@ -59,12 +66,20 @@ void php_openssl_add_assoc_name_entry(zval * val, char * key, X509_NAME * name,

ne = X509_NAME_get_entry(name, i);
obj = X509_NAME_ENTRY_get_object(ne);
nid = OBJ_obj2nid(obj);

if (shortname) {
sname = (char *) OBJ_nid2sn(nid);
} else {
sname = (char *) OBJ_nid2ln(nid);
switch (nametype) {
case PHP_OPENSSL_SHORT_NAME:
nid = OBJ_obj2nid(obj);
sname = (char *) OBJ_nid2sn(nid);
break;
case PHP_OPENSSL_LONG_NAME:
nid = OBJ_obj2nid(obj);
sname = (char *) OBJ_nid2ln(nid);
break;
case PHP_OPENSSL_OID:
OBJ_obj2txt(oname, sizeof(oname)-1, obj, 1);
sname = oname;
break;
}

str = X509_NAME_ENTRY_get_data(ne);
Expand Down Expand Up @@ -613,16 +628,60 @@ zend_string* php_openssl_x509_fingerprint(X509 *peer, const char *method, bool r
return ret;
}

/* proto void print_asn1_type(BIO *bio, ASN1_TYPE *ptr)
Print the value of an ASN1_TYPE to a BIO */
static void print_asn1_type(BIO *bio, ASN1_TYPE *ptr)
{
char objbuf[1024];

switch (ptr->type) {
case V_ASN1_BOOLEAN:
BIO_puts(bio, ptr->value.boolean ? "true" : "false");
break;

case V_ASN1_INTEGER:
BIO_puts(bio, i2s_ASN1_INTEGER(NULL, ptr->value.integer));
break;

case V_ASN1_ENUMERATED:
BIO_puts(bio, i2s_ASN1_INTEGER(NULL, ptr->value.enumerated));
break;

case V_ASN1_NULL:
BIO_puts(bio, "NULL");
break;

case V_ASN1_UTCTIME:
ASN1_UTCTIME_print(bio, ptr->value.utctime);
break;

case V_ASN1_GENERALIZEDTIME:
ASN1_GENERALIZEDTIME_print(bio, ptr->value.generalizedtime);
break;

case V_ASN1_OBJECT:
OBJ_obj2txt(objbuf, sizeof(objbuf), ptr->value.object, 1);
BIO_puts(bio, objbuf);
break;

default :
ASN1_STRING_print_ex(bio, ptr->value.visiblestring,
ASN1_STRFLGS_DUMP_UNKNOWN);
break;
}
}

/* Special handling of subjectAltName, see CVE-2013-4073
* Christian Heimes
*/
int openssl_x509v3_subjectAltName(BIO *bio, X509_EXTENSION *extension)
int openssl_x509v3_subjectAltName(BIO *bio, X509_EXTENSION *extension, zval *altname)
{
GENERAL_NAMES *names;
const X509V3_EXT_METHOD *method = NULL;
ASN1_OCTET_STRING *extension_data;
long i, length, num;
const unsigned char *p;
zend_ulong index = 0;

method = X509V3_EXT_get(extension);
if (method == NULL) {
Expand All @@ -647,36 +706,127 @@ int openssl_x509v3_subjectAltName(BIO *bio, X509_EXTENSION *extension)
for (i = 0; i < num; i++) {
GENERAL_NAME *name;
ASN1_STRING *as;
zval entry;
array_init(&entry);
name = sk_GENERAL_NAME_value(names, i);
switch (name->type) {
case GEN_EMAIL:
BIO_puts(bio, "email:");
as = name->d.rfc822Name;
BIO_write(bio, ASN1_STRING_get0_data(as),
ASN1_STRING_length(as));
if (altname != NULL) {
add_assoc_string(&entry, "type", "email");
php_openssl_add_assoc_asn1_string(&entry, "value", as);
add_index_zval(altname, index++, &entry);
}
break;
case GEN_DNS:
BIO_puts(bio, "DNS:");
as = name->d.dNSName;
BIO_write(bio, ASN1_STRING_get0_data(as),
ASN1_STRING_length(as));
if (altname != NULL) {
add_assoc_string(&entry, "type", "DNS");
php_openssl_add_assoc_asn1_string(&entry, "value", as);
add_index_zval(altname, index++, &entry);
}
break;
case GEN_URI:
BIO_puts(bio, "URI:");
as = name->d.uniformResourceIdentifier;
BIO_write(bio, ASN1_STRING_get0_data(as),
ASN1_STRING_length(as));
if (altname != NULL) {
add_assoc_string(&entry, "type", "URI");
php_openssl_add_assoc_asn1_string(&entry, "value", as);
add_index_zval(altname, index++, &entry);
}
break;
case GEN_DIRNAME:
GENERAL_NAME_print(bio, name);
if (altname != NULL) {
add_assoc_string(&entry, "type", "DirName");
php_openssl_add_assoc_name_entry(&entry, "value", name->d.dirn, PHP_OPENSSL_OID);
add_index_zval(altname, index++, &entry);
}
break;
case GEN_RID:
GENERAL_NAME_print(bio, name);
if (altname != NULL) {
char buf[1024];
OBJ_obj2txt(buf, sizeof(buf)-1, name->d.rid, 1);
add_assoc_string(&entry, "type", "Registered ID");
add_assoc_string(&entry, "value", buf);
add_index_zval(altname, index++, &entry);
}
break;
case GEN_IPADD:
GENERAL_NAME_print(bio, name);
if (altname != NULL) {
char buf[1024];
if (name->d.ip->length == 4) {
inet_ntop(AF_INET, name->d.ip->data, buf, sizeof(buf)-1);
} else if (name->d.ip->length == 16) {
inet_ntop(AF_INET6, name->d.ip->data, buf, sizeof(buf)-1);
} else {
sprintf(buf, "<invalid>");
}
add_assoc_string(&entry, "type", "IP Address");
add_assoc_string(&entry, "value", buf);
add_index_zval(altname, index++, &entry);
}
break;
case GEN_OTHERNAME:
GENERAL_NAME_print(bio, name);
if (altname != NULL) {
char oid[1024];
zval value;
array_init(&value);

OBJ_obj2txt(oid, sizeof(oid)-1, name->d.otherName->type_id, 1);

BIO *bio_out;
BUF_MEM *bio_buf;
bio_out = BIO_new(BIO_s_mem());
print_asn1_type(bio_out, name->d.otherName->value);
BIO_get_mem_ptr(bio_out, &bio_buf);

add_assoc_stringl(&value, oid, bio_buf->data, bio_buf->length);
add_assoc_string(&entry, "type", "othername");
add_assoc_zval(&entry, "value", &value);
add_index_zval(altname, index++, &entry);
BIO_free(bio_out);
}
break;
default:
/* use builtin print for GEN_OTHERNAME, GEN_X400,
* GEN_EDIPARTY, GEN_DIRNAME, GEN_IPADD and GEN_RID
*/
GENERAL_NAME_print(bio, name);
}
/* trailing ', ' except for last element */
if (i < (num - 1)) {
BIO_puts(bio, ", ");
}
if (altname != NULL) {
BIO *bio_out;
BUF_MEM *bio_buf;
bio_out = BIO_new(BIO_s_mem());
GENERAL_NAME_print(bio_out, name);
BIO_get_mem_ptr(bio_out, &bio_buf);
switch (name->type) {
case GEN_X400:
add_assoc_string(&entry, "type", "X400Name");
break;
case GEN_EDIPARTY:
add_assoc_string(&entry, "type", "EdiPartyName");
break;
default:
add_assoc_string(&entry, "type", "Unknown");
break;
}
add_assoc_stringl(&entry, "value", bio_buf->data, bio_buf->length);
add_index_zval(altname, index++, &entry);
BIO_free(bio_out);
}
}
/* trailing ', ' except for last element */
if (i < (num - 1)) {
BIO_puts(bio, ", ");
}
}
sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);

Expand Down
12 changes: 10 additions & 2 deletions ext/openssl/php_openssl_backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,13 @@ enum php_openssl_cipher_type {
PHP_OPENSSL_CIPHER_DEFAULT = PHP_OPENSSL_CIPHER_AES_128_CBC
};

/* Name display options for php_openssl_add_assoc_name_entry */
enum php_openssl_name_type {
PHP_OPENSSL_LONG_NAME,
PHP_OPENSSL_SHORT_NAME,
PHP_OPENSSL_OID
};

/* Add some encoding rules. This is normally handled through filters
* in the OpenSSL code, but we will do that part as if we were one
* of the OpenSSL binaries along the lines of -outform {DER|CMS|PEM}
Expand Down Expand Up @@ -168,7 +175,8 @@ struct php_x509_request {
const EVP_CIPHER * priv_key_encrypt_cipher;
};

void php_openssl_add_assoc_name_entry(zval * val, char * key, X509_NAME * name, int shortname);
void php_openssl_add_assoc_name_entry(zval * val, char * key, X509_NAME * name,
enum php_openssl_name_type nametype);
void php_openssl_add_assoc_asn1_string(zval * val, char * key, ASN1_STRING * str);
time_t php_openssl_asn1_time_to_time_t(ASN1_UTCTIME * timestr);
int php_openssl_config_check_syntax(const char * section_label, const char * config_filename, const char * section, CONF *config);
Expand Down Expand Up @@ -266,7 +274,7 @@ X509 *php_openssl_x509_from_zval(

zend_string* php_openssl_x509_fingerprint(X509 *peer, const char *method, bool raw);

int openssl_x509v3_subjectAltName(BIO *bio, X509_EXTENSION *extension);
int openssl_x509v3_subjectAltName(BIO *bio, X509_EXTENSION *extension, zval *altname);

STACK_OF(X509) *php_openssl_load_all_certs_from_file(
char *cert_file, size_t cert_file_len, uint32_t arg_num);
Expand Down
20 changes: 20 additions & 0 deletions ext/openssl/tests/subjectAlternativeName.crt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
-----BEGIN CERTIFICATE-----
MIIDRzCCAuygAwIBAgIUDcQjrtk7F/g4Mdm+NiAzKpInXDEwCgYIKoZIzj0EAwIw
ezELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNh
biBGcmFuY2lzY28xKTARBgNVBAoMCk15IENvbXBhbnkwFAYDVQQLDA1NeSBEZXBh
cnRtZW50MRQwEgYDVQQDDAtleGFtcGxlLmNvbTAeFw0yNTExMDMxOTEzNDBaFw0y
NjExMDMxOTEzNDBaMHsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlh
MRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMSkwEQYDVQQKDApNeSBDb21wYW55MBQG
A1UECwwNTXkgRGVwYXJ0bWVudDEUMBIGA1UEAwwLZXhhbXBsZS5jb20wWTATBgcq
hkjOPQIBBggqhkjOPQMBBwNCAAQ+riFshYe8HnWt1avx6OuNajipU1ZW6BgW0+D/
EtDDSYeQg9ngO8qyo5M6cyh7ORtKZVUy7DP1+W+eocaZC+a6o4IBTDCCAUgwggEl
BgNVHREEggEcMIIBGIILZXhhbXBsZS5jb22CD3d3dy5leGFtcGxlLmNvbYIVc3Vi
ZG9tYWluLmV4YW1wbGUuY29thwTAqAEBhxAmB/DQEAIAUQAAAAAAAAAEgRFhZG1p
bkBleGFtcGxlLmNvbaROMEwxETAPBgNVBAMMCEpvaG4gRG9lMSowDgYDVQQLDAdU
ZXN0aW5nMBgGA1UECgwRRXhhbXBsZSBPcmcsIEluYy4xCzAJBgNVBAYTAlVToCMG
CSqGSIb3DQEJAqAWDBRVSURfdW5zdHJ1Y3R1cmVkTmFtZaAfBgkqhkiG9w0BCRSg
EhYQVUlEX2ZyaWVuZGx5TmFtZYgDKgMEhhtodHRwOi8vZXhhbXBsZS5jb20vcmVz
b3VyY2UwHQYDVR0OBBYEFICesJGN6QyOP89fyTVAmhL28E0NMAoGCCqGSM49BAMC
A0kAMEYCIQDah0YhiFdhHPZIMkHS91QsN2A9HZ4YwZi0wObHcB8r5gIhAJc+Szee
2PfEQatjoWj/K1xZBV8ZNF6UtjzdY/5VD52z
-----END CERTIFICATE-----
Loading
Loading