15
15
| Authors: Wez Furlong <wez@thebrainroom.com> |
16
16
| Daniel Lowrey <rdlowrey@php.net> |
17
17
| Chris Wright <daverandom@php.net> |
18
+ | Jakub Zelenka <bukka@php.net> |
18
19
+----------------------------------------------------------------------+
19
20
*/
20
21
52
53
#undef X509_EXTENSIONS
53
54
#endif
54
55
56
+ /* Flags for determining allowed stream crypto methods */
57
+ #define STREAM_CRYPTO_IS_CLIENT (1<<0)
58
+ #define STREAM_CRYPTO_METHOD_SSLv2 (1<<1)
59
+ #define STREAM_CRYPTO_METHOD_SSLv3 (1<<2)
60
+ #define STREAM_CRYPTO_METHOD_TLSv1_0 (1<<3)
61
+ #define STREAM_CRYPTO_METHOD_TLSv1_1 (1<<4)
62
+ #define STREAM_CRYPTO_METHOD_TLSv1_2 (1<<5)
63
+
55
64
#ifndef OPENSSL_NO_SSL3
56
65
#define HAVE_SSL3 1
66
+ #define PHP_OPENSSL_MIN_PROTO_VERSION STREAM_CRYPTO_METHOD_SSLv3
67
+ #else
68
+ #define PHP_OPENSSL_MIN_PROTO_VERSION STREAM_CRYPTO_METHOD_TLSv1_0
57
69
#endif
70
+ #define PHP_OPENSSL_MAX_PROTO_VERSION STREAM_CRYPTO_METHOD_TLSv1_2
71
+
58
72
59
73
#define HAVE_TLS11 1
60
74
#define HAVE_TLS12 1
74
88
#define HAVE_SEC_LEVEL 1
75
89
#endif
76
90
77
- /* Flags for determining allowed stream crypto methods */
78
- #define STREAM_CRYPTO_IS_CLIENT (1<<0)
79
- #define STREAM_CRYPTO_METHOD_SSLv2 (1<<1)
80
- #define STREAM_CRYPTO_METHOD_SSLv3 (1<<2)
81
- #define STREAM_CRYPTO_METHOD_TLSv1_0 (1<<3)
82
- #define STREAM_CRYPTO_METHOD_TLSv1_1 (1<<4)
83
- #define STREAM_CRYPTO_METHOD_TLSv1_2 (1<<5)
84
-
85
91
/* Simplify ssl context option retrieval */
86
92
#define GET_VER_OPT (name ) \
87
93
(PHP_STREAM_CONTEXT(stream) && (val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", name)) != NULL)
@@ -945,46 +951,6 @@ static int php_openssl_set_local_cert(SSL_CTX *ctx, php_stream *stream) /* {{{ *
945
951
}
946
952
/* }}} */
947
953
948
- static const SSL_METHOD * php_openssl_select_crypto_method (zend_long method_value , int is_client ) /* {{{ */
949
- {
950
- if (method_value == STREAM_CRYPTO_METHOD_SSLv2 ) {
951
- php_error_docref (NULL , E_WARNING ,
952
- "SSLv2 unavailable in this PHP version" );
953
- return NULL ;
954
- } else if (method_value == STREAM_CRYPTO_METHOD_SSLv3 ) {
955
- #ifdef HAVE_SSL3
956
- return is_client ? SSLv3_client_method () : SSLv3_server_method ();
957
- #else
958
- php_error_docref (NULL , E_WARNING ,
959
- "SSLv3 unavailable in the OpenSSL library against which PHP is linked" );
960
- return NULL ;
961
- #endif
962
- } else if (method_value == STREAM_CRYPTO_METHOD_TLSv1_0 ) {
963
- return is_client ? TLSv1_client_method () : TLSv1_server_method ();
964
- } else if (method_value == STREAM_CRYPTO_METHOD_TLSv1_1 ) {
965
- #ifdef HAVE_TLS11
966
- return is_client ? TLSv1_1_client_method () : TLSv1_1_server_method ();
967
- #else
968
- php_error_docref (NULL , E_WARNING ,
969
- "TLSv1.1 unavailable in the OpenSSL library against which PHP is linked" );
970
- return NULL ;
971
- #endif
972
- } else if (method_value == STREAM_CRYPTO_METHOD_TLSv1_2 ) {
973
- #ifdef HAVE_TLS12
974
- return is_client ? TLSv1_2_client_method () : TLSv1_2_server_method ();
975
- #else
976
- php_error_docref (NULL , E_WARNING ,
977
- "TLSv1.2 unavailable in the OpenSSL library against which PHP is linked" );
978
- return NULL ;
979
- #endif
980
- } else {
981
- php_error_docref (NULL , E_WARNING ,
982
- "Invalid crypto method" );
983
- return NULL ;
984
- }
985
- }
986
- /* }}} */
987
-
988
954
#define PHP_SSL_MAX_VERSION_LEN 32
989
955
990
956
static char * php_openssl_cipher_get_version (const SSL_CIPHER * c , char * buffer , size_t max_len ) /* {{{ */
@@ -1000,6 +966,7 @@ static char *php_openssl_cipher_get_version(const SSL_CIPHER *c, char *buffer, s
1000
966
}
1001
967
/* }}} */
1002
968
969
+ #if PHP_OPENSSL_API_VERSION < 0x10100
1003
970
static int php_openssl_get_crypto_method_ctx_flags (int method_flags ) /* {{{ */
1004
971
{
1005
972
int ssl_ctx_options = SSL_OP_ALL ;
@@ -1029,6 +996,89 @@ static int php_openssl_get_crypto_method_ctx_flags(int method_flags) /* {{{ */
1029
996
return ssl_ctx_options ;
1030
997
}
1031
998
/* }}} */
999
+ #endif
1000
+
1001
+ static inline int php_openssl_get_min_proto_version_flag (int flags ) /* {{{ */
1002
+ {
1003
+ int ver ;
1004
+ for (ver = PHP_OPENSSL_MIN_PROTO_VERSION ; ver <= PHP_OPENSSL_MAX_PROTO_VERSION ; ver <<= 1 ) {
1005
+ if (flags & ver ) {
1006
+ return ver ;
1007
+ }
1008
+ }
1009
+ return STREAM_CRYPTO_METHOD_TLSv1_2 ;
1010
+ }
1011
+ /* }}} */
1012
+
1013
+ static inline int php_openssl_get_max_proto_version_flag (int flags ) /* {{{ */
1014
+ {
1015
+ int ver ;
1016
+ for (ver = PHP_OPENSSL_MAX_PROTO_VERSION ; ver >= PHP_OPENSSL_MIN_PROTO_VERSION ; ver >>= 1 ) {
1017
+ if (flags & ver ) {
1018
+ return ver ;
1019
+ }
1020
+ }
1021
+ return STREAM_CRYPTO_METHOD_TLSv1_2 ;
1022
+ }
1023
+ /* }}} */
1024
+
1025
+ #if PHP_OPENSSL_API_VERSION >= 0x10100
1026
+ static inline int php_openssl_map_proto_version (int flag ) /* {{{ */
1027
+ {
1028
+ switch (flag ) {
1029
+ #ifdef HAVE_SSL3
1030
+ case STREAM_CRYPTO_METHOD_SSLv3 :
1031
+ return SSL3_VERSION ;
1032
+ #endif
1033
+ case STREAM_CRYPTO_METHOD_TLSv1_0 :
1034
+ return TLS1_VERSION ;
1035
+ case STREAM_CRYPTO_METHOD_TLSv1_1 :
1036
+ return TLS1_1_VERSION ;
1037
+ /* case STREAM_CRYPTO_METHOD_TLSv1_2: */
1038
+ default :
1039
+ return TLS1_2_VERSION ;
1040
+
1041
+ }
1042
+ }
1043
+ /* }}} */
1044
+
1045
+ static int php_openssl_get_min_proto_version (int flags ) /* {{{ */
1046
+ {
1047
+ return php_openssl_map_proto_version (php_openssl_get_min_proto_version_flag (flags ));
1048
+ }
1049
+ /* }}} */
1050
+
1051
+ static int php_openssl_get_max_proto_version (int flags ) /* {{{ */
1052
+ {
1053
+ return php_openssl_map_proto_version (php_openssl_get_max_proto_version_flag (flags ));
1054
+ }
1055
+ /* }}} */
1056
+ #endif
1057
+
1058
+ static int php_openssl_get_proto_version_flags (int flags , int min , int max ) /* {{{ */
1059
+ {
1060
+ int ver ;
1061
+
1062
+ if (!min ) {
1063
+ min = php_openssl_get_min_proto_version_flag (flags );
1064
+ }
1065
+ if (!max ) {
1066
+ max = php_openssl_get_max_proto_version_flag (flags );
1067
+ }
1068
+
1069
+ for (ver = PHP_OPENSSL_MIN_PROTO_VERSION ; ver <= PHP_OPENSSL_MAX_PROTO_VERSION ; ver <<= 1 ) {
1070
+ if (ver >= min && ver <= max ) {
1071
+ if (!(flags & ver )) {
1072
+ flags |= ver ;
1073
+ }
1074
+ } else if (flags & ver ) {
1075
+ flags &= ~ver ;
1076
+ }
1077
+ }
1078
+
1079
+ return flags ;
1080
+ }
1081
+ /* }}} */
1032
1082
1033
1083
static void php_openssl_limit_handshake_reneg (const SSL * ssl ) /* {{{ */
1034
1084
{
@@ -1538,6 +1588,8 @@ int php_openssl_setup_crypto(php_stream *stream,
1538
1588
const SSL_METHOD * method ;
1539
1589
int ssl_ctx_options ;
1540
1590
int method_flags ;
1591
+ zend_long min_version = 0 ;
1592
+ zend_long max_version = 0 ;
1541
1593
char * cipherlist = NULL ;
1542
1594
char * alpn_protocols = NULL ;
1543
1595
zval * val ;
@@ -1558,23 +1610,18 @@ int php_openssl_setup_crypto(php_stream *stream,
1558
1610
sslsock -> is_client = cparam -> inputs .method & STREAM_CRYPTO_IS_CLIENT ;
1559
1611
method_flags = ((cparam -> inputs .method >> 1 ) << 1 );
1560
1612
1561
- /* Should we use a specific crypto method or is generic SSLv23 okay? */
1562
- if ((method_flags & (method_flags - 1 )) == 0 ) {
1563
- ssl_ctx_options = SSL_OP_ALL ;
1564
- method = php_openssl_select_crypto_method (method_flags , sslsock -> is_client );
1565
- if (method == NULL ) {
1566
- return FAILURE ;
1567
- }
1568
- } else {
1569
- method = sslsock -> is_client ? SSLv23_client_method () : SSLv23_server_method ();
1570
- ssl_ctx_options = php_openssl_get_crypto_method_ctx_flags (method_flags );
1571
- if (ssl_ctx_options == -1 ) {
1572
- return FAILURE ;
1573
- }
1574
- }
1575
-
1613
+ method = sslsock -> is_client ? SSLv23_client_method () : SSLv23_server_method ();
1576
1614
sslsock -> ctx = SSL_CTX_new (method );
1577
1615
1616
+ GET_VER_OPT_LONG ("min_proto_version" , min_version );
1617
+ GET_VER_OPT_LONG ("max_proto_version" , max_version );
1618
+ method_flags = php_openssl_get_proto_version_flags (method_flags , min_version , max_version );
1619
+ #if PHP_OPENSSL_API_VERSION < 0x10100
1620
+ ssl_ctx_options = php_openssl_get_crypto_method_ctx_flags (method_flags );
1621
+ #else
1622
+ ssl_ctx_options = SSL_OP_ALL ;
1623
+ #endif
1624
+
1578
1625
if (sslsock -> ctx == NULL ) {
1579
1626
php_error_docref (NULL , E_WARNING , "SSL context creation failure" );
1580
1627
return FAILURE ;
@@ -1663,6 +1710,11 @@ int php_openssl_setup_crypto(php_stream *stream,
1663
1710
1664
1711
SSL_CTX_set_options (sslsock -> ctx , ssl_ctx_options );
1665
1712
1713
+ #if PHP_OPENSSL_API_VERSION >= 0x10100
1714
+ SSL_CTX_set_min_proto_version (sslsock -> ctx , php_openssl_get_min_proto_version (method_flags ));
1715
+ SSL_CTX_set_max_proto_version (sslsock -> ctx , php_openssl_get_max_proto_version (method_flags ));
1716
+ #endif
1717
+
1666
1718
if (sslsock -> is_client == 0 &&
1667
1719
PHP_STREAM_CONTEXT (stream ) &&
1668
1720
FAILURE == php_openssl_set_server_specific_opts (stream , sslsock -> ctx )
0 commit comments