เซิร์ฟเวอร์ HTTPS ในเครื่องพร้อม SNI

มีข้อมูลมากมายเกี่ยวกับ cURL และ SSL แต่ไม่มีข้อมูลเกี่ยวกับการเขียนเซิร์ฟเวอร์มากนัก ฉันมีเซิร์ฟเวอร์ท้องถิ่นขนาดเล็กที่เขียนด้วย PHP ซึ่งฉันต้องการเปิดใช้งาน TLS/SSL ฉันมีปัญหากับเซิร์ฟเวอร์ของฉันหยุดทำงานเมื่อมีการเชื่อมต่อที่ปลอดภัย ฉันได้รับเฉพาะข้อผิดพลาด "คำเตือน PHP: stream_socket_accept(): ไม่สามารถเปิดใช้งาน crypto" ฉันมีเซิร์ฟเวอร์เหมือนกันที่ทำงานโดยไม่มี TLS และทำงานได้ดี ฉันมีความคิดว่ามันเป็นใบรับรอง หรือการเชื่อมต่อกับ/การอ่านใบรับรอง อย่างไรก็ตาม ฉันไม่แน่ใจว่าเป็นข้อผิดพลาดเกี่ยวกับวิธีสร้างใบรับรอง วิธีเข้าร่วม PEM หรืออย่างอื่น นอกจากนี้ สำหรับโดเมนของเรา ฉันใช้ *.domain.tld ทั้งในโค้ดด้านล่างและชื่อท้องถิ่นในการสร้างใบรับรอง

นอกจากนี้ ใบรับรองที่แสดงในเว็บเบราว์เซอร์จะแสดงใบรับรอง 127.0.0.1 ไม่ใช่ใบรับรอง localhost (หรือโดเมนอื่น) โดยไม่คำนึงถึงโดเมนที่ร้องขอ นั่นเป็นเพราะว่า 127.0.0.1 ถูกตั้งค่าเป็นใบรับรองท้องถิ่นใช่ไหม เกี่ยวกับใบรับรอง- นี่คือรหัสปัจจุบันของฉันสำหรับการสร้างไฟล์ .pem เพื่อใช้บนเซิร์ฟเวอร์:

sudo openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout apache.key -out apache.crt

apache.crt apache.key > joined.pem

ความหมายพื้นฐานของรหัสเซิร์ฟเวอร์คือ:

<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

$flags = STREAM_SERVER_BIND|STREAM_SERVER_LISTEN;

$ctx = stream_context_create(['ssl' => [
    'local_cert' => "{path}/Websites/127.0.0.1/certs/joined.pem",
    'SNI_server_certs' => [
        "127.0.0.1" => "{path}/Websites/127.0.0.1/certs/joined.pem",
        "localhost" => "{path}//Websites/localhost/certs/joined.pem",
    ]
]]);
stream_context_set_option($ctx, 'ssl', 'ssl_method', 'STREAM_CRYPTO_METHOD_TLSv23_SERVER');
stream_context_set_option($ctx, 'ssl', 'allow_self_signed', true);
stream_context_set_option($ctx, 'ssl', 'verify_peer', false);
stream_context_set_option($ctx, 'ssl', 'ciphers', "HIGH");


$socket = stream_socket_server("tls://127.0.0.1:8443", $errno, $errstr, $flags, $ctx);


while ( $client = stream_socket_accept($socket, "-1", $clientIP)):

    $msg = fread($client, 8192);

    $resp = "HTTP/1.1 200 OK\r\nContent-type: text/html\r\n\r\n<h1>Hi, you are secured.<br>{$msg}";
    fwrite($client,$resp );
    fclose($client);        

endwhile;

อีกประการหนึ่งคือรหัสที่เหมาะสมในการตั้งค่าเพื่อทำให้เบราว์เซอร์หลัก ๆ ทั้งหมดพอใจ Chrome ดูเหมือนจะเล่นตามกฎของมันเอง

มีความคิดใดที่ฉันขาดหายไปที่นี่?


person Keith Kirkland    schedule 27.04.2018    source แหล่งที่มา
comment
(1) คำสั่งที่สองของคุณดูเหมือนจะไม่มีแมว (เหมียว?) (2) คุณบอกว่าคุณใช้ '*.domain.tld' แต่โค้ดที่ดูเหมือนจะยุ่งเหยิงของคุณใช้ 'localhost' และ '127.0.0.1' - สิ่งเหล่านี้สามารถทำได้ เทียบเท่ากับบางโปรโตคอล แต่ไม่เหมือนกันทั้งหมดสำหรับ TLS/HTTPS (3) คุณไม่ได้บอกว่าคุณตั้งค่าส่วนขยาย SubjectAltNames (SAN) หรือไม่/อย่างไร ซึ่งจะต้องอยู่ในไฟล์กำหนดค่าที่ไม่อยู่ในบรรทัดคำสั่ง (เว้นแต่ คุณใช้เชลล์ที่มีการทดแทนกระบวนการ) ปัจจุบัน Chrome แต่ไม่ใช่เบราว์เซอร์หลักอื่นๆ ปฏิเสธใบรับรองที่ไม่มี SAN (สิ่งนี้ไม่เกี่ยวข้องกับการเข้ารหัสและ Chrome ก็ยอมรับการเข้ารหัสแบบเดียวกันกับรหัสอื่นๆ)   -  person dave_thompson_085    schedule 27.04.2018
comment
ขอบคุณสำหรับการตอบกลับ. ฉันเห็นว่าการจัดรูปแบบเปลี่ยนไปเล็กน้อยในการคัดลอกและวาง ฉันยังไม่ได้รวม cat ไว้ในการสร้างไฟล์ pem คุณสามารถขยายเพิ่มเติมเกี่ยวกับ SAN ได้หรือไม่? ฉันคิดว่าคุณกำลังทำอะไรบางอย่างอยู่ตรงนั้น....   -  person Keith Kirkland    schedule 27.04.2018
comment
ขอบคุณ @ dave_thompson_085 ปัญหาคือ SAN ตั้งค่าไม่ถูกต้อง ชื่อลิงก์ serverfault.com/questions/880804/ แก้ไขปัญหาของฉันแล้ว ไม่สามารถทำได้หากไม่มีคุณ!   -  person Keith Kirkland    schedule 01.05.2018


คำตอบ (1)


ปัญหาของฉันไม่ได้ตั้งค่า SAN ในระหว่างการสร้างใบรับรอง ลิงก์ https://serverfault.com/questions/880804/can-not-get-rid-of-neterr-cert-common-name-invalid-error-in-chrome-with-self แก้ไขปัญหาของฉัน

person Keith Kirkland    schedule 01.05.2018