'Domain-Parameter fehlt']); exit; } // Protokoll und Pfad entfernen $domain = preg_replace('/^(https?:\/\/)?/', '', $domain); $domain = explode('/', $domain)[0]; $domain = explode(':', $domain)[0]; // Port entfernen if (!preg_match('/^[a-zA-Z0-9][a-zA-Z0-9\-\.]*\.[a-zA-Z]{2,}$/', $domain)) { http_response_code(400); echo json_encode(['error' => 'Ungültiges Domain-Format']); exit; } $startTime = microtime(true); $sslData = checkSslCertificate($domain); $queryTime = round((microtime(true) - $startTime) * 1000, 2); echo json_encode([ 'success' => $sslData['success'], 'domain' => $domain, 'query_time_ms' => $queryTime, 'timestamp' => date('Y-m-d H:i:s'), 'ssl' => $sslData ], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); /** * Prüft SSL-Zertifikat einer Domain */ function checkSslCertificate(string $domain): array { $result = [ 'success' => false, 'has_ssl' => false, 'is_valid' => false, 'error' => null, 'certificate' => null ]; // Stream Context für SSL $context = stream_context_create([ 'ssl' => [ 'capture_peer_cert' => true, 'verify_peer' => false, 'verify_peer_name' => false, ] ]); // Verbindung herstellen $socket = @stream_socket_client( "ssl://{$domain}:443", $errno, $errstr, 10, // Timeout STREAM_CLIENT_CONNECT, $context ); if (!$socket) { // Versuche ohne SSL (um zu prüfen ob Server erreichbar) $httpSocket = @fsockopen($domain, 80, $errno, $errstr, 5); if ($httpSocket) { fclose($httpSocket); $result['error'] = 'Kein SSL-Zertifikat auf Port 443 gefunden'; } else { $result['error'] = "Verbindung fehlgeschlagen: {$errstr}"; } return $result; } $result['has_ssl'] = true; $result['success'] = true; // Zertifikat extrahieren $params = stream_context_get_params($socket); $cert = $params['options']['ssl']['peer_certificate'] ?? null; if ($cert) { $certInfo = openssl_x509_parse($cert); if ($certInfo) { $validFrom = $certInfo['validFrom_time_t'] ?? 0; $validTo = $certInfo['validTo_time_t'] ?? 0; $now = time(); $isExpired = $now > $validTo; $isNotYetValid = $now < $validFrom; $result['is_valid'] = !$isExpired && !$isNotYetValid; // Tage bis Ablauf $daysUntilExpiry = floor(($validTo - $now) / 86400); // Subject Alternative Names (SANs) $sans = []; if (isset($certInfo['extensions']['subjectAltName'])) { $sanStr = $certInfo['extensions']['subjectAltName']; preg_match_all('/DNS:([^,\s]+)/', $sanStr, $matches); $sans = $matches[1] ?? []; } // Issuer aufbereiten $issuer = []; if (isset($certInfo['issuer'])) { if (isset($certInfo['issuer']['O'])) $issuer['organization'] = $certInfo['issuer']['O']; if (isset($certInfo['issuer']['CN'])) $issuer['common_name'] = $certInfo['issuer']['CN']; if (isset($certInfo['issuer']['C'])) $issuer['country'] = $certInfo['issuer']['C']; } // Subject aufbereiten $subject = []; if (isset($certInfo['subject'])) { if (isset($certInfo['subject']['CN'])) $subject['common_name'] = $certInfo['subject']['CN']; if (isset($certInfo['subject']['O'])) $subject['organization'] = $certInfo['subject']['O']; } $result['certificate'] = [ 'subject' => $subject, 'issuer' => $issuer, 'valid_from' => date('Y-m-d H:i:s', $validFrom), 'valid_to' => date('Y-m-d H:i:s', $validTo), 'days_until_expiry' => $daysUntilExpiry, 'is_expired' => $isExpired, 'serial_number' => $certInfo['serialNumberHex'] ?? null, 'signature_algorithm' => $certInfo['signatureTypeSN'] ?? null, 'san_domains' => $sans, 'version' => $certInfo['version'] ?? null, ]; // Warnung wenn bald ablaufend if ($daysUntilExpiry <= 30 && $daysUntilExpiry > 0) { $result['warning'] = "Zertifikat läuft in {$daysUntilExpiry} Tagen ab!"; } elseif ($isExpired) { $result['error'] = 'Zertifikat ist abgelaufen!'; $result['is_valid'] = false; } } } fclose($socket); return $result; }