Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions Sources/NIOSSL/SSLContext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -569,8 +569,10 @@ extension NIOSSLContext {
private static func configureCertificateValidation(context: OpaquePointer, verification: CertificateVerification, trustRoots: NIOSSLTrustRoots?, additionalTrustRoots: [NIOSSLAdditionalTrustRoots], sendCANames: Bool) throws {
// If validation is turned on, set the trust roots and turn on cert validation.
switch verification {
case .fullVerification, .noHostnameVerification:
CNIOBoringSSL_SSL_CTX_set_verify(context, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nil)
case .fullVerification, .noHostnameVerification, .noHostnameNoPeerVerification:
let flags = verification == .noHostnameNoPeerVerification ? SSL_VERIFY_PEER
: SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT
CNIOBoringSSL_SSL_CTX_set_verify(context, flags, nil)

// Also, set TRUSTED_FIRST to work around dumb clients that don't know what they're doing and send
// untrusted root certs. X509_VERIFY_PARAM will or-in the flags, so we don't need to load them first.
Expand Down
3 changes: 3 additions & 0 deletions Sources/NIOSSL/TLSConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,9 @@ public enum CertificateVerification: Sendable {
/// be checked to see if they are valid for the given hostname.
case noHostnameVerification

/// Peer certificate is optional
case noHostnameNoPeerVerification

/// Certificates will be validated against the trust store and checked
/// against the hostname of the service we are contacting.
case fullVerification
Expand Down
32 changes: 32 additions & 0 deletions Tests/NIOSSLTests/TLSConfigurationTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,38 @@ class TLSConfigurationTest: XCTestCase {

try assertPostHandshakeError(withClientConfig: clientConfig, andServerConfig: serverConfig, errorTextContainsAnyOf: ["CERTIFICATE_REQUIRED"])
}

func testMutualValidationOptionalClientCertificatePreTLS13() throws {
var clientConfig = TLSConfiguration.makeClientConfiguration()
clientConfig.maximumTLSVersion = .tlsv12
clientConfig.certificateVerification = .none

var serverConfig = TLSConfiguration.makeServerConfiguration(
certificateChain: [.certificate(TLSConfigurationTest.cert1)],
privateKey: .privateKey(TLSConfigurationTest.key1)
)
serverConfig.maximumTLSVersion = .tlsv12
serverConfig.certificateVerification = .noHostnameNoPeerVerification
serverConfig.trustRoots = .certificates([TLSConfigurationTest.cert2])

try assertHandshakeSucceeded(withClientConfig: clientConfig, andServerConfig: serverConfig)
}

func testMutualValidationOptionalClientCertificatePostTLS13() throws {
var clientConfig = TLSConfiguration.makeClientConfiguration()
clientConfig.minimumTLSVersion = .tlsv13
clientConfig.certificateVerification = .none

var serverConfig = TLSConfiguration.makeServerConfiguration(
certificateChain: [.certificate(TLSConfigurationTest.cert1)],
privateKey: .privateKey(TLSConfigurationTest.key1)
)
serverConfig.minimumTLSVersion = .tlsv13
serverConfig.certificateVerification = .noHostnameNoPeerVerification
serverConfig.trustRoots = .certificates([TLSConfigurationTest.cert2])

try assertHandshakeSucceeded(withClientConfig: clientConfig, andServerConfig: serverConfig)
}

func testIncompatibleSignatures() throws {
var clientConfig = TLSConfiguration.makeClientConfiguration()
Expand Down