<?php
###############################################################################
# SSL.php
#
# @author Anil Kumar <akumar@codepunch.com>
# @link   https://codepunch.com
#
############################################################################### 

namespace 	CodePunch\LU;
use 		CodePunch\Base\Util as UTIL;
use			CodePunch\Base\Text as TEXT;

###############################################################################

class SSL  {
	
	private $lookupManager = null;
	
	###########################################################################
	
	public function __construct($lum=null) {
		$this->lookupManager = $lum;
	}
	
	###############################################################################

	public function SSL(&$ludata)
	{
		$db = $this->lookupManager->getAuthentication()->getDatabase();
		$did = $ludata['sid'];
		$domain = $db->getDomainName($did);
		$lookupcount = 0;
		$data = array();
		if($did !== false && $did > 0) {
			$sdinfo = $db->getFromTable("hid,subdomain", $db->getSubdomainTableName(), "sid = ? AND subdomain != '@' AND auto_added = ?", array($did,\CodePunch\LU\LookupManager::SD_USER_ROWS));
			if($sdinfo !== false && is_array($sdinfo)) {
				foreach($sdinfo as $sdi) {
					$sdi = array_change_key_case($sdi, CASE_LOWER);
					$db->deleteFromTable($db->getSubdomainTableName(), "auto_added=? AND sid=? AND subdomain=?", array(\CodePunch\LU\LookupManager::SD_AUTO_SSL_ROWS, $did, $sdi['subdomain']));
					
					// Avoid lookups of NS entries
					$sdname = $sdi['subdomain'];
					if(substr(strtolower($sdname), 0, 2) == "ns" && strlen($sdname) < 5 && ctype_digit(substr($sdname, 2)))
						continue;
					
					$dataarray = $this->get_ssl_records($domain, $sdi['subdomain']);
					if(count($dataarray)) {
						$db->insertIntoTable($db->getSubdomainTableName(), $dataarray);
					}
				}
			}
			$dataarray = $this->get_ssl_records($domain, "");
			$db->deleteFromTable($db->getSubdomainTableName(), "auto_added=? AND sid=? AND subdomain=?", array(\CodePunch\LU\LookupManager::SD_AUTO_SSL_ROWS, $did, '@'));
			if(count($dataarray)) {
				$db->insertIntoTable($db->getSubdomainTableName(), $dataarray);
				$lookupcount++;
			}
			
			$dataarray = array();
			$dataarray['domain'] = $domain;
			$dataarray['ssl_checked_at'] = date("Y-m-d H:i:s");
			//$db->updateDomainTable($dataarray);
			$status = $this->lookupManager->updateDomainTable(\CodePunch\LU\LookupManager::SSL_CERTS, $dataarray);
		}
		$ludata['status'] = \CodePunch\LU\LookupManager::LUQ_COMPLETE;
		return $lookupcount;
	}
	
	###########################################################################
	
	private function openssl_to_timestamp ($in) 
	{
		$year  = substr($in, 0, 2); /* NOTE: Yes, this returns a two digit year */
		$month = substr($in, 2, 2);
		$day   = substr($in, 4, 2);
		$hour  = substr($in, 6, 2);
		$min   = substr($in, 8, 2);
		$sec   = substr($in, 10, 2);
		return gmmktime($hour, $min, $sec, $month, $day, $year);
	}
	
	###########################################################################
	
	public function get_ssl_records($domain, $subdomain)
	{
		$db = $this->lookupManager->getAuthentication()->getDatabase();
		$data_array = Array();
		$hostname = UTIL::idn_convert_to_host_name($domain, $subdomain);
		UTIL::debug_cli_print("SSL: " . $hostname);
		$get = @stream_context_create(array("ssl" => array("capture_peer_cert" => TRUE, "verify_peer"=>false, "verify_peer_name"=>true)));
		$read = @stream_socket_client("ssl://" . $hostname . ":443", $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $get);
		if($read != false)
		{
			$cert = stream_context_get_params($read);
			if(isset($cert["options"]["ssl"]["peer_certificate"])) {
				//$certd = $cert["options"]["ssl"]["peer_certificate"];
				$parsed = openssl_x509_parse($cert["options"]["ssl"]["peer_certificate"]);
				
				if(isset($parsed['validFrom']))
					$data_array['ssl_valid_from'] = date("Y-m-d H:i:s", $this->openssl_to_timestamp($parsed['validFrom']));
				if(isset($parsed['validTo']))
					$data_array['ssl_valid_to'] = date("Y-m-d H:i:s", $this->openssl_to_timestamp($parsed['validTo']));
				if(isset($parsed['subject']['CN']))
					$data_array['ssl_issued_to'] = $parsed['subject']['CN'];
				if(isset($parsed['issuer']['CN']))
					$data_array['ssl_issued_by'] = $parsed['issuer']['CN'];
				if(isset($parsed['extensions']['subjectKeyIdentifier']))
					$data_array['subject_key_id'] = $parsed['extensions']['subjectKeyIdentifier'];
				if(isset($parsed['extensions']['subjectAltName'])) {
					$data_array['subject_alt_name_text'] = $parsed['extensions']['subjectAltName'];
					$data_array['subject_alt_name'] = substr($parsed['extensions']['subjectAltName'], 0, 2047);
				}
				$data_array['serial'] = UTIL::get_from_array($parsed['serialNumber'], "");
				if(strlen($data_array['serial']) > 2 && stripos($data_array['serial'], "0x") === false && function_exists('bcmod')) {
					$dec = $data_array['serial'];
					$hex = array();
					while ($dec) {
						$modulus = bcmod($dec, '16');
						array_unshift($hex, dechex($modulus));
						$dec = bcdiv(bcsub($dec, $modulus), 16);
					}
					$data_array['serial'] = '0x' . strtoupper(implode('', $hex));
				}
				$signtypeln = "";
				$signtypesn = "";
				if(isset($parsed['signatureTypeLN']))
					$signtypeln = $parsed['signatureTypeLN'];
				if(isset($parsed['signatureTypeSN']))
					$signtypesn = $parsed['signatureTypeSN'];
				$data_array['signature_type'] = "$signtypeln [$signtypesn]";
				if($this->lookupManager->getAuthentication()->getProClass('SSL', true))
					$db->addSSLCertificate($this->lookupManager->getAuthentication(), $parsed, $cert["options"]["ssl"]["peer_certificate"], $domain, $hostname);
			}
			else
				$data_array['ssl_issued_to'] = "Error: No peer cert";
		}
		else {
			if($errno == 0)
				$errstr = "Socket Initialization";
			$data_array['ssl_issued_to'] = "Error: [{$errno}] {$errstr}";
		}
		
		$ip = gethostbyname($hostname);
		if($ip != $hostname) {
			$data_array['ip'] = $ip;
			$revptr = gethostbyaddr($ip);
			if($revptr != $ip)
				$data_array['ptr'] = $revptr;
		}
		
		$data_array['auto_added'] = \CodePunch\LU\LookupManager::SD_AUTO_SSL_ROWS;
		$data_array['subdomain'] = $subdomain == "" ? "@" : $subdomain;
		$data_array['added_on'] = date("Y-m-d H:i:s");
		$data_array['sid'] = $db->getDomainID($domain);
		
		// 2020-16-05, Check for manually added data in DB
		$aamode = \CodePunch\LU\LookupManager::SD_MAN_SSL_ROWS;
		$mainrow = $db->getFromTable("*", $db->getSubdomainTableName(), "sid=? AND subdomain=? AND auto_added=?", array($data_array['sid'], $data_array['subdomain'], $aamode));
		if($mainrow !== false && is_array($mainrow) && count($mainrow) == 1) {
			$mainrow = $db->fetchRow($mainrow, 0);
			$editable = $db->getEditableSubdomainColumnNames();
			foreach($mainrow as $cpkey => $cpval) {
				$cpkey = strtolower($cpkey);
				if(in_array($cpkey, $editable) && $cpval != "") {
					$data_array[$cpkey] = $cpval;
				}
				$data_array['manual_edited_at'] = $mainrow['manual_edited_at'];
				$data_array['edited'] = '1';
			}
			UTIL::debug_cli_print("Manually edited SSL Row");
			UTIL::debug_cli_print($mainrow);
		}
		// 2020-16-05

		return $data_array;
	}

}
