จะตรวจสอบ CRL และ OSCP เพื่อทำงานบน iOS ได้อย่างไร


9

ฉันไม่สามารถให้ CRL ทำงานบน iOS ได้ ฉันสร้างกรณีทดสอบสองกรณี ฉันมีใบรับรองที่ถูกต้องออกโดย CA ฉันมีใบรับรองอื่นที่ถูกต้องออกโดย CA แต่ CA ได้เพิ่มใบรับรองนั้นใน CRL

ฉันตั้งค่านโยบายการเพิกถอนที่เปิดใช้งานการตรวจสอบ CRL และต้องการให้สำเร็จ

func crlValidationTest(trustedCert: SecCertificate, certToVerify: SecCertificate) -> Bool {

    let basicPolicy = SecPolicyCreateBasicX509()

    let crlPolicy = SecPolicyCreateRevocation(kSecRevocationOCSPMethod | kSecRevocationCRLMethod | kSecRevocationRequirePositiveResponse)!

    var trust: SecTrust?

    SecTrustCreateWithCertificates(NSArray(object: certToVerify), NSArray(objects: basicPolicy, crlPolicy), &trust)
    SecTrustSetAnchorCertificates(trust!, NSArray(object: trustedCert))
    SecTrustSetNetworkFetchAllowed(trust!, true)

    var trustResult = SecTrustResultType.invalid

    guard SecTrustEvaluate(trust!, &trustResult) == errSecSuccess else {
        return false
    }

    return trustResult == SecTrustResultType.proceed || trustResult == SecTrustResultType.unspecified
}

ความคาดหวังของฉันคือใบรับรองที่อยู่ใน CRL จะไม่น่าเชื่อถือและใบรับรองที่สะอาดจะเชื่อถือได้

รับการกำหนดค่าข้างต้นทั้งสองล้มเหลวในฐานะที่ไม่น่าเชื่อถือ หากฉันลบkSecRevocationRequirePositiveResponseแฟล็กทั้งคู่จะสำเร็จ ฉันลองใช้พีชคณิตต่าง ๆ ทั้งหมดของการใช้ OSCP หรือ CRL เท่านั้นและไม่มีอะไรทำงานตามที่ฉันคาดหวัง

เอกสารประกอบของแอปเปิ้ลสำหรับSecPolicyCreateRevocationรัฐ:

โดยปกติแล้วคุณไม่จำเป็นต้องสร้างนโยบายการเพิกถอนด้วยตนเองเว้นแต่คุณต้องการแทนที่การทำงานของระบบเริ่มต้นตัวอย่างเช่นบังคับใช้วิธีการเฉพาะหรือปิดใช้งานการตรวจสอบการเพิกถอนทั้งหมด

การใช้SecPolicyCreateBasicX509นโยบายอนุญาตให้ทั้งคู่สำเร็จเท่านั้น (เมื่อใบรับรองที่สองควรล้มเหลว) ดังนั้นพฤติกรรมเริ่มต้นของ Apple จึงไม่ทำการตรวจสอบ CRL เลย?

ฉันแนบCharlesProxyกับอุปกรณ์ของฉันและรันโค้ดหลาย ๆ ครั้งในขณะที่รับฟังการรับส่งข้อมูลเครือข่ายทั้งหมดและไม่มีการร้องขอขาออกไปที่ CRL ซึ่งอธิบายว่าทำไมทั้งหมดล้มเหลวเมื่อRequirePositiveResponseตรวจสอบการตั้งค่าสถานะ

ฉันยังพยายามนำทางโดยตรงจากอุปกรณ์ไปยัง CRL โดยใช้ a URLRequestและสามารถรับข้อมูล CRL บนอุปกรณ์ได้โดยไม่มีปัญหาใด ๆ

การตรวจสอบ CRL ไม่รองรับผ่านห้องสมุดความปลอดภัยของ Apple หรือไม่? ถ้าเป็นเช่นนั้นมีใครคิดการกำหนดค่าเพื่อให้ตอบสนองได้อย่างถูกต้องหรือไม่ ทางเลือกอื่นใดที่ใช้ในการตรวจสอบความถูกต้องของ CRL ฉันคิดว่าแอพพลิเคชั่นมือถือที่มีความปลอดภัยสูงกำลังติดต่ออยู่ในย่านธุรกิจการเงินหรือพื้นที่อ่อนไหวอื่น ๆ

ปรับปรุง สำหรับการเปรียบเทียบฉันวิ่งcertutil -f -urlfetch -verify MYCERT.cerโดยใช้ certutil และฉันแนบพู้ทำเล่นกับกล่องที่ใช้คำสั่ง ฉันได้รับผลลัพธ์ที่คาดหวังว่า iOS ไม่ให้ฉันและฉันเห็นคำขอขาออกไปยัง CRL ผ่าน HTTP ผ่านพู้ทำเล่น

ฉันได้สร้างความโปรดปรานเพื่อสร้างความสนใจในเรื่องนี้ ฉันหวังว่าบางคนจะมีรายละเอียดเพิ่มเติมเกี่ยวกับสิ่งที่ทำผิดข้างต้นหรือเหตุใดจึงไม่ทำงานบน iOS

คำตอบ:


7

บนแพลตฟอร์ม Apple ลูกค้าไม่ตรวจสอบรายการเพิกถอนใบรับรอง (CRL) ของ CA และไม่ใช้ OCSP ตามค่าเริ่มต้น

อย่างไรก็ตามแพลตฟอร์มของ Apple สนับสนุนการเย็บเล่ม OCSP และยังมีกลไกที่เรียกการปรับปรุงการเพิกถอนซึ่งอาจนำไปสู่การโทร OCSP ได้อย่างแท้จริงดูรายละเอียดด้านล่าง

OCSP Stapling

การอธิบายครั้งแรกของการเย็บเล่ม OCSP:

การเย็บเล่มสถานะใบรับรองออนไลน์ (OCSP)ออนไลน์หรือที่รู้จักกันอย่างเป็นทางการว่าเป็นส่วนขยายคำขอสถานะใบรับรอง TLSเป็นมาตรฐานสำหรับการตรวจสอบสถานะการเพิกถอนใบรับรองดิจิทัล X.509 1ช่วยให้ผู้นำเสนอใบรับรองแบกรับต้นทุนทรัพยากรที่เกี่ยวข้องในการตอบสนองออนไลน์โพรโทคอลสถานะโพรโทคอลการรับรอง (OCSP) โดยการผนวก ("เย็บเล่ม") การตอบสนอง OCSP ประทับเวลาลงนามโดย CA เพื่อจับมือ TLS เริ่มต้น สำหรับลูกค้าที่จะติดต่อ CA โดยมีวัตถุประสงค์เพื่อปรับปรุงความปลอดภัยและประสิทธิภาพ

ดูhttps://en.wikipedia.org/wiki/OCSP_stapling

ความแตกต่างระหว่าง OCSP และ OCSP Stapling

หากไคลเอนต์เชื่อมต่อกับเซิร์ฟเวอร์ในโฟลว์ OCSP ดั้งเดิมและดึงข้อมูลใบรับรองตรวจสอบว่าใบรับรองที่ได้รับนั้นถูกเพิกถอนโดยทำการร้องขอไปยัง CA หรือไม่ นี่มีข้อเสียบางอย่างเช่นจำเป็นต้องมีการเชื่อมต่อเครือข่ายเพิ่มเติมข้อมูลไม่ได้เข้ารหัสและดังนั้นจึงแสดงถึงปัญหาความเป็นส่วนตัวของข้อมูล

ผ่านการเย็บเล่ม OCSP เซิร์ฟเวอร์ร้องขอข้อมูลการเพิกถอนที่ลงนามจาก CA และเพิ่มลงในการจับมือ TLS

นอกจากนี้ยังหมายถึงเมื่อใช้การเย็บเล่ม OCSP คุณไม่เห็นคำขอ OCSP จาก iOS ไปยังเซิร์ฟเวอร์ CA

ข้อเสียของการเย็บ OCSP

เซิร์ฟเวอร์ที่คุณกำลังเชื่อมต่อจะต้องสนับสนุนการเย็บเล่ม OCSP สิ่งนี้ไม่ได้ป้องกันเซิร์ฟเวอร์ที่เป็นอันตราย

นี่คือเหตุผลหลักที่ Apple ให้การปรับปรุงการเพิกถอน

การปรับปรุงการเพิกถอนของ Apple

นี่คือวิธีการทำงาน:

  • รายการบันทึกความโปร่งใสของใบรับรองจะถูกรวบรวมโดย Apple
  • ด้วยข้อมูลนี้ Apple จะรวบรวมข้อมูลเกี่ยวกับการเพิกถอนจาก CA
  • ข้อมูลที่รวบรวมนี้จะถูกเปิดเผยโดยอัตโนมัติให้กับลูกค้าของ Apple ทุกเครื่องเป็นประจำ
  • ตามข้อมูลนี้เมื่อแอป iOS พยายามเชื่อมต่อกับเซิร์ฟเวอร์ที่มีใบรับรองที่ถูกเพิกถอนจะทำการตรวจสอบเพิ่มเติมผ่าน OCSP

ความต้องการ

ข้อกำหนดเพียงอย่างเดียวสำหรับแอปที่ให้การสนับสนุนนี่คือการเพิ่มใบรับรองเซิร์ฟเวอร์ที่ใช้ในบันทึกความโปร่งใสของใบรับรอง โดยปกติ CA ทำเช่นนั้นแล้ว แต่คุณควรตรวจสอบว่าใบรับรองโดเมนอยู่ในบันทึกความโปร่งใสที่ใช้งานอยู่สำหรับใบรับรองสาธารณะเช่นโดยใช้ลิงก์ต่อไปนี้: https://transparencyreport.google.com/https/certificates

WWDC 2017 เซสชัน 701

มีเซสชัน WWDC ที่ยอดเยี่ยมที่มีการอธิบายหัวข้อและแรงจูงใจของ Apple ในรายละเอียด: WWDC 2017, เซสชัน 701: https://developer.apple.com/videos/play/wwdc2017/701/

ประมาณ 12:10 น. วิศวกรของ Apple จะอธิบายหัวข้อการเพิกถอนทั้งหมดอย่างละเอียด เมื่อเวลาประมาณ 15:30 น. เธออธิบายว่า OCSP ปกติจะต้องใช้ API เพิ่มเติม

ทดสอบการเย็บ OCSP บน iOS

สำหรับการทดสอบเราต้องการเซิร์ฟเวอร์ที่รองรับการเย็บเล่ม OCSP และใช้ใบรับรองที่ถูกเพิกถอน: https://revoked.grc.com (พบเซิร์ฟเวอร์นี้ในคำตอบข้อผิดพลาดเซิร์ฟเวอร์นี้: https://serverfault.com/a/645066 )

จากนั้นเราสามารถลองเชื่อมต่อจาก iOS ด้วยโปรแกรมทดสอบขนาดเล็กที่พยายามดาวน์โหลดการตอบสนอง HTML และส่งออกไปยังคอนโซล

ตามข้อมูลจากเซสชัน WWDC ที่กล่าวถึงข้างต้นความพยายามในการเชื่อมต่อควรล้มเหลว

...
let session = URLSession(configuration: .default)
...

func onDownloadAction() {
    let url = URL(string: "https://revoked.grc.com")!
    self.download(from: url) { (result, error) in
        if let result = result {
            print("result: " + result)
        } else {
            print("download failed")
            if let error = error {
                print("error: \(error)")
            }
        }
    }
}


func download(from url: URL, completion: @escaping(String?, Error?)->Void) {
    let dataTask = self.session.dataTask(with: url) { data, response, error in
        guard let data = data else {
            if let error = error {
                completion(nil, error)
                return
            }
            completion(nil, NSError(domain: "DownloadFailure", code: 0, userInfo:nil))
            return
        }

        guard let response = response as? HTTPURLResponse else {
            completion(nil, NSError(domain: "ResponseFailure", code: 0, userInfo:nil))
            return
        }
        print("http status: \(response.statusCode)")
        let res = String(bytes: data, encoding: .utf8)
        completion(res, nil)
    }
    dataTask.resume()
}

หากเราดำเนินการตามขั้นตอนข้างต้นใน iOS Simulator เราสามารถใช้ Wireshark เพื่อตรวจสอบว่าการตอบสนอง OCSP แบบประทับเวลาที่ลงนามโดย CA นั้นได้รับการเย็บเล่มไปยัง TLS handshake หรือไม่

ด้วยการnslookup revoked.grc.comที่เราได้รับที่อยู่ IP ของเซิร์ฟเวอร์และสามารถกรองใน Wireshark ip.addr==4.79.142.205กับ

revokedในภาพหนึ่งจะเห็นว่าใบรับรองมีสถานะ

Wireshark

ดังนั้นการดูในคอนโซล Xcodes สามารถเห็นผลลัพธ์ต่อไปนี้:

2019-10-12 21:32:25.734382+0200 OCSPTests[6701:156558] ATS failed system trust
2019-10-12 21:32:25.734526+0200 OCSPTests[6701:156558] Connection 1: system TLS Trust evaluation failed(-9802)
2019-10-12 21:32:25.734701+0200 OCSPTests[6701:156558] Connection 1: TLS Trust encountered error 3:-9802
2019-10-12 21:32:25.734787+0200 OCSPTests[6701:156558] Connection 1: encountered error(3:-9802)
2019-10-12 21:32:25.737672+0200 OCSPTests[6701:156558] Task <12408947-689F-4537-9642-C8F95E86CA62>.<1> HTTP load failed, 0/0 bytes (error code: -1200 [3:-9802])
download failed
error: Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo={NSURLErrorFailingURLPeerTrustErrorKey=<SecTrustRef: 0x6000037f8510>, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9802, NSErrorPeerCertificateChainKey=(
    "<cert(0x7fda78828200) s: revoked.grc.com i: DigiCert SHA2 Secure Server CA>",
    "<cert(0x7fda7882b200) s: DigiCert SHA2 Secure Server CA i: DigiCert Global Root CA>"
), NSUnderlyingError=0x600000be9170 {Error Domain=kCFErrorDomainCFNetwork Code=-1200 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0, kCFStreamPropertySSLPeerTrust=<SecTrustRef: 0x6000037f8510>, _kCFNetworkCFStreamSSLErrorOriginalValue=-9802, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9802, kCFStreamPropertySSLPeerCertificates=(
    "<cert(0x7fda78828200) s: revoked.grc.com i: DigiCert SHA2 Secure Server CA>",
    "<cert(0x7fda7882b200) s: DigiCert SHA2 Secure Server CA i: DigiCert Global Root CA>"
)}}, NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made., NSErrorFailingURLKey=https://revoked.grc.com/, NSErrorFailingURLStringKey=https://revoked.grc.com/, NSErrorClientCertificateStateKey=0}

iOS ยกเลิกการพยายามเชื่อมต่อกับเซิร์ฟเวอร์ด้วยข้อผิดพลาด TLS

ทดสอบ revoked.badssl.com

revoked.badssl.com ไม่รองรับการเย็บเล่ม OCSP

หากเราดูรายละเอียดใบรับรองของhttps://revoked.badssl.comเราสามารถค้นหา:

หากมีใครดาวน์โหลดไฟล์. crl (2.5MB) และออก

openssl crl -inform DER -text -in ssca-sha2-g6.crl | grep 0371B58A86F6CE9C3ECB7BF42F9208FC

จะเห็นได้ว่าใบรับรองนี้ถูกเพิกถอนผ่าน CRL

น่าสนใจไม่ว่า Safari หรือ Chrome หรือ iOS จะไม่รับรู้สถานะที่ถูกเพิกถอนนี้ Mozilla Firefox เท่านั้นที่แสดงข้อความแสดงข้อผิดพลาด ( เพิกถอนใบรับรองของเพื่อนแล้วรหัสข้อผิดพลาด: SEC_ERROR_REVOKED_CERTIFICATE )

สาเหตุอาจเป็นเพราะใบรับรองได้รับการต่ออายุเพียงไม่กี่วันที่ผ่านมาและยังไม่พบวิธีในการเพิกถอนรายการเบราว์เซอร์และระบบปฏิบัติการในท้องถิ่นทั้งหมด


ข้อมูลที่ดีที่นี่ ขอบคุณสำหรับคำตอบที่รอบคอบ ในขณะที่ฉันได้ทำการวิจัยอย่างต่อเนื่องในหัวข้อนี้ฉันได้เห็นเช่นเดียวกับคุณการสนับสนุน CRL กำลังถูกทิ้งโดยเบราว์เซอร์หลัก / OS และการเย็บเล่ม OCSP น่าจะเป็นกลไกรักษาความปลอดภัยที่แนะนำใหม่ ในวิดีโอ WWDC สถานะตัวแทนของ Apple: "น่าเสียดายที่แพลตฟอร์มของเราไม่ตรวจสอบการเพิกถอนตามค่าเริ่มต้นในขณะนี้" สิ่งที่ฉันพบจากการทดลองของฉันคือไม่เพียง แต่จะไม่รองรับตามค่าเริ่มต้น แต่ไม่รองรับเลย (แม้ว่าคุณจะบังคับให้ตั้งค่า)
@Stephan
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.