PageRenderTime 25ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/php-ssl.c

http://github.com/mongodb/mongo-php-driver
C | 237 lines | 151 code | 40 blank | 46 comment | 53 complexity | d1eb97a7dfe64641c8a4f0a9851ed2f6 MD5 | raw file
Possible License(s): Apache-2.0
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2015 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Authors: Wez Furlong <wez@thebrainroom.com> |
  16. | Daniel Lowrey <rdlowrey@php.net> |
  17. | Chris Wright <daverandom@php.net> |
  18. +----------------------------------------------------------------------+
  19. */
  20. #ifdef PHP_WIN32
  21. # include "config.w32.h"
  22. #else
  23. # include <php_config.h>
  24. #endif
  25. #ifdef HAVE_OPENSSL_EXT
  26. #include "php-ssl.h"
  27. int php_mongo_matches_wildcard_name(const char *subjectname, const char *certname) /* {{{ */
  28. {
  29. char *wildcard = NULL;
  30. int prefix_len, suffix_len, subject_len;
  31. if (strcasecmp(subjectname, certname) == 0) {
  32. return SUCCESS;
  33. }
  34. /* wildcard, if present, must only be present in the left-most component */
  35. if (!(wildcard = strchr(certname, '*')) || memchr(certname, '.', wildcard - certname)) {
  36. return FAILURE;
  37. }
  38. /* 1) prefix, if not empty, must match subject */
  39. prefix_len = wildcard - certname;
  40. if (prefix_len && strncasecmp(subjectname, certname, prefix_len) != 0) {
  41. return FAILURE;
  42. }
  43. suffix_len = strlen(wildcard + 1);
  44. subject_len = strlen(subjectname);
  45. if (suffix_len <= subject_len) {
  46. /* 2) suffix must match
  47. * 3) no . between prefix and suffix
  48. **/
  49. if ( strcasecmp(wildcard + 1, subjectname + subject_len - suffix_len) == 0 &&
  50. memchr(subjectname + prefix_len, '.', subject_len - suffix_len - prefix_len) == NULL) {
  51. return SUCCESS;
  52. }
  53. }
  54. return FAILURE;
  55. }
  56. /* }}} */
  57. int php_mongo_matches_san_list(X509 *peer, const char *subject_name) /* {{{ */
  58. {
  59. int i, len;
  60. unsigned char *cert_name = NULL;
  61. char ipbuffer[64];
  62. GENERAL_NAMES *alt_names = X509_get_ext_d2i(peer, NID_subject_alt_name, 0, 0);
  63. int alt_name_count = sk_GENERAL_NAME_num(alt_names);
  64. for (i = 0; i < alt_name_count; i++) {
  65. GENERAL_NAME *san = sk_GENERAL_NAME_value(alt_names, i);
  66. if (san->type == GEN_DNS) {
  67. ASN1_STRING_to_UTF8(&cert_name, san->d.dNSName);
  68. if ((size_t)ASN1_STRING_length(san->d.dNSName) != strlen((const char*)cert_name)) {
  69. OPENSSL_free(cert_name);
  70. /* prevent null-byte poisoning*/
  71. continue;
  72. }
  73. /* accommodate valid FQDN entries ending in "." */
  74. len = strlen((const char*)cert_name);
  75. if (len && strcmp((const char *)&cert_name[len-1], ".") == 0) {
  76. cert_name[len-1] = '\0';
  77. }
  78. if (php_mongo_matches_wildcard_name(subject_name, (const char *)cert_name) == SUCCESS) {
  79. OPENSSL_free(cert_name);
  80. return SUCCESS;
  81. }
  82. OPENSSL_free(cert_name);
  83. } else if (san->type == GEN_IPADD) {
  84. if (san->d.iPAddress->length == 4) {
  85. sprintf(ipbuffer, "%d.%d.%d.%d",
  86. san->d.iPAddress->data[0],
  87. san->d.iPAddress->data[1],
  88. san->d.iPAddress->data[2],
  89. san->d.iPAddress->data[3]
  90. );
  91. if (strcasecmp(subject_name, (const char*)ipbuffer) == 0) {
  92. return SUCCESS;
  93. }
  94. }
  95. /* No, we aren't bothering to check IPv6 addresses. Why?
  96. * Because IP SAN names are officially deprecated and are
  97. * not allowed by CAs starting in 2015. Deal with it.
  98. */
  99. }
  100. }
  101. return FAILURE;
  102. }
  103. /* }}} */
  104. int php_mongo_matches_common_name(X509 *peer, const char *subject_name TSRMLS_DC) /* {{{ */
  105. {
  106. char buf[1024];
  107. X509_NAME *cert_name;
  108. int cert_name_len;
  109. cert_name = X509_get_subject_name(peer);
  110. cert_name_len = X509_NAME_get_text_by_NID(cert_name, NID_commonName, buf, sizeof(buf));
  111. if (cert_name_len == -1) {
  112. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to locate peer certificate CN");
  113. } else if ((size_t) cert_name_len != strlen(buf)) {
  114. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Peer certificate CN=`%.*s' is malformed", cert_name_len, buf);
  115. } else if (php_mongo_matches_wildcard_name(subject_name, buf) == SUCCESS) {
  116. return SUCCESS;
  117. } else {
  118. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Peer certificate CN=`%.*s' did not match expected CN=`%s'", cert_name_len, buf, subject_name);
  119. }
  120. return FAILURE;
  121. }
  122. /* }}} */
  123. time_t php_mongo_asn1_time_to_time_t(ASN1_UTCTIME * timestr TSRMLS_DC) /* {{{ */
  124. {
  125. /*
  126. This is how the time string is formatted:
  127. snprintf(p, sizeof(p), "%02d%02d%02d%02d%02d%02dZ",ts->tm_year%100,
  128. ts->tm_mon+1,ts->tm_mday,ts->tm_hour,ts->tm_min,ts->tm_sec);
  129. */
  130. time_t ret;
  131. struct tm thetime;
  132. char * strbuf;
  133. char * thestr;
  134. long gmadjust = 0;
  135. if (ASN1_STRING_type(timestr) != V_ASN1_UTCTIME && ASN1_STRING_type(timestr) != V_ASN1_GENERALIZEDTIME) {
  136. php_error_docref(NULL TSRMLS_CC, E_WARNING, "illegal ASN1 data type for timestamp");
  137. return (time_t)-1;
  138. }
  139. if ((size_t)ASN1_STRING_length(timestr) != strlen((char *)ASN1_STRING_data(timestr))) {
  140. php_error_docref(NULL TSRMLS_CC, E_WARNING, "illegal length in timestamp");
  141. return (time_t)-1;
  142. }
  143. if (ASN1_STRING_length(timestr) < 13) {
  144. php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to parse time string %s correctly", timestr->data);
  145. return (time_t)-1;
  146. }
  147. if (ASN1_STRING_type(timestr) == V_ASN1_GENERALIZEDTIME && ASN1_STRING_length(timestr) < 15) {
  148. php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to parse time string %s correctly", timestr->data);
  149. return (time_t)-1;
  150. }
  151. strbuf = estrdup((char *)ASN1_STRING_data(timestr));
  152. memset(&thetime, 0, sizeof(thetime));
  153. /* we work backwards so that we can use atoi more easily */
  154. thestr = strbuf + ASN1_STRING_length(timestr) - 3;
  155. thetime.tm_sec = atoi(thestr);
  156. *thestr = '\0';
  157. thestr -= 2;
  158. thetime.tm_min = atoi(thestr);
  159. *thestr = '\0';
  160. thestr -= 2;
  161. thetime.tm_hour = atoi(thestr);
  162. *thestr = '\0';
  163. thestr -= 2;
  164. thetime.tm_mday = atoi(thestr);
  165. *thestr = '\0';
  166. thestr -= 2;
  167. thetime.tm_mon = atoi(thestr)-1;
  168. *thestr = '\0';
  169. if( ASN1_STRING_type(timestr) == V_ASN1_UTCTIME ) {
  170. thestr -= 2;
  171. thetime.tm_year = atoi(thestr);
  172. if (thetime.tm_year < 68) {
  173. thetime.tm_year += 100;
  174. }
  175. } else if( ASN1_STRING_type(timestr) == V_ASN1_GENERALIZEDTIME ) {
  176. thestr -= 4;
  177. thetime.tm_year = atoi(thestr) - 1900;
  178. }
  179. thetime.tm_isdst = -1;
  180. ret = mktime(&thetime);
  181. #if HAVE_TM_GMTOFF
  182. gmadjust = thetime.tm_gmtoff;
  183. #else
  184. /*
  185. ** If correcting for daylight savings time, we set the adjustment to
  186. ** the value of timezone - 3600 seconds. Otherwise, we need to overcorrect and
  187. ** set the adjustment to the main timezone + 3600 seconds.
  188. */
  189. gmadjust = -(thetime.tm_isdst ? (long)timezone - 3600 : (long)timezone + 3600);
  190. #endif
  191. ret += gmadjust;
  192. efree(strbuf);
  193. return ret;
  194. }
  195. /* }}} */
  196. #endif /* HAVE_OPENSSL_EXT */