diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml new file mode 100644 index 000000000..284633f30 --- /dev/null +++ b/.github/workflows/pull_request.yml @@ -0,0 +1,37 @@ +name: PR + +on: + pull_request: + types: [opened, reopened, synchronize] + +jobs: + soundness: + name: Soundness + uses: swiftlang/github-workflows/.github/workflows/soundness.yml@main + with: + license_header_check_project_name: "SwiftNIO" + unit-tests: + name: Unit tests + uses: apple/swift-nio/.github/workflows/unit_tests.yml@main + with: + linux_5_9_arguments_override: "--explicit-target-dependency-import-check error" + linux_5_10_arguments_override: "--explicit-target-dependency-import-check error" + linux_6_0_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable" + linux_nightly_6_0_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable" + linux_nightly_main_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable" + + integration-tests: + name: Integration test + uses: apple/swift-nio/.github/workflows/swift_matrix.yml@main + with: + name: "Integration test" + matrix_linux_command: "apt-get update -yq && apt-get install -yq execstack lsof dnsutils netcat-openbsd net-tools expect curl jq && ./scripts/integration_tests.sh -f test_01_renegotiation" + + cxx-interop: + name: Cxx interop + uses: apple/swift-nio/.github/workflows/cxx_interop.yml@main + + swift-6-language-mode: + name: Swift 6 Language Mode + uses: apple/swift-nio/.github/workflows/swift_6_language_mode.yml@main + if: false # Disabled for now. diff --git a/.github/workflows/pull_request_label.yml b/.github/workflows/pull_request_label.yml new file mode 100644 index 000000000..86f199f32 --- /dev/null +++ b/.github/workflows/pull_request_label.yml @@ -0,0 +1,18 @@ +name: PR label + +on: + pull_request: + types: [labeled, unlabeled, opened, reopened, synchronize] + +jobs: + semver-label-check: + name: Semantic Version label check + runs-on: ubuntu-latest + timeout-minutes: 1 + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + persist-credentials: false + - name: Check for Semantic Version label + uses: apple/swift-nio/.github/actions/pull_request_semver_label_checker@main diff --git a/.github/workflows/scheduled.yml b/.github/workflows/scheduled.yml new file mode 100644 index 000000000..12e8e5366 --- /dev/null +++ b/.github/workflows/scheduled.yml @@ -0,0 +1,24 @@ +name: Scheduled + +on: + schedule: + - cron: "0 8,20 * * *" + +jobs: + unit-tests: + name: Unit tests + uses: apple/swift-nio/.github/workflows/unit_tests.yml@main + with: + linux_5_8_enabled: false + linux_5_9_arguments_override: "--explicit-target-dependency-import-check error" + linux_5_10_arguments_override: "--explicit-target-dependency-import-check error" + linux_6_0_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable" + linux_nightly_6_0_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable" + linux_nightly_main_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable" + + integration-tests: + name: Integration test + uses: apple/swift-nio/.github/workflows/swift_matrix.yml@main + with: + name: "Integration test" + matrix_linux_command: "apt-get update -yq && apt-get install -yq execstack lsof dnsutils netcat-openbsd net-tools expect curl jq && ./scripts/integration_tests.sh -f test_01_renegotiation" diff --git a/.licenseignore b/.licenseignore new file mode 100644 index 000000000..f980f400f --- /dev/null +++ b/.licenseignore @@ -0,0 +1,45 @@ +.gitignore +**/.gitignore +.licenseignore +.gitattributes +.git-blame-ignore-revs +.mailfilter +.mailmap +.spi.yml +.swift-format +.editorconfig +.github/* +*.md +*.txt +*.yml +*.yaml +*.json +Package.swift +**/Package.swift +Package@-*.swift +**/Package@-*.swift +Package.resolved +**/Package.resolved +Makefile +*.modulemap +**/*.modulemap +**/*.docc/* +*.xcprivacy +**/*.xcprivacy +*.symlink +**/*.symlink +Dockerfile +**/Dockerfile +Snippets/* +Sources/CNIOBoringSSL/* +dev/alloc-limits-from-test-output +dev/boxed-existentials.d +dev/git.commit.template +dev/lldb-smoker +dev/make-single-file-spm +dev/malloc-aggregation.d +dev/update-alloc-limits-to-last-completed-ci-build +scripts/patch-1-inttypes.patch +scripts/patch-2-inttypes.patch +scripts/patch-3-more-inttypes.patch +.unacceptablelanguageignore diff --git a/.swift-format b/.swift-format new file mode 100644 index 000000000..7fa06fb30 --- /dev/null +++ b/.swift-format @@ -0,0 +1,62 @@ +{ + "version" : 1, + "indentation" : { + "spaces" : 4 + }, + "tabWidth" : 4, + "fileScopedDeclarationPrivacy" : { + "accessLevel" : "private" + }, + "spacesAroundRangeFormationOperators" : false, + "indentConditionalCompilationBlocks" : false, + "indentSwitchCaseLabels" : false, + "lineBreakAroundMultilineExpressionChainComponents" : false, + "lineBreakBeforeControlFlowKeywords" : false, + "lineBreakBeforeEachArgument" : true, + "lineBreakBeforeEachGenericRequirement" : true, + "lineLength" : 120, + "maximumBlankLines" : 1, + "respectsExistingLineBreaks" : true, + "prioritizeKeepingFunctionOutputTogether" : true, + "rules" : { + "AllPublicDeclarationsHaveDocumentation" : false, + "AlwaysUseLiteralForEmptyCollectionInit" : false, + "AlwaysUseLowerCamelCase" : false, + "AmbiguousTrailingClosureOverload" : true, + "BeginDocumentationCommentWithOneLineSummary" : false, + "DoNotUseSemicolons" : true, + "DontRepeatTypeInStaticProperties" : true, + "FileScopedDeclarationPrivacy" : true, + "FullyIndirectEnum" : true, + "GroupNumericLiterals" : true, + "IdentifiersMustBeASCII" : true, + "NeverForceUnwrap" : false, + "NeverUseForceTry" : false, + "NeverUseImplicitlyUnwrappedOptionals" : false, + "NoAccessLevelOnExtensionDeclaration" : true, + "NoAssignmentInExpressions" : true, + "NoBlockComments" : true, + "NoCasesWithOnlyFallthrough" : true, + "NoEmptyTrailingClosureParentheses" : true, + "NoLabelsInCasePatterns" : true, + "NoLeadingUnderscores" : false, + "NoParensAroundConditions" : true, + "NoVoidReturnOnFunctionSignature" : true, + "OmitExplicitReturns" : true, + "OneCasePerLine" : true, + "OneVariableDeclarationPerLine" : true, + "OnlyOneTrailingClosureArgument" : true, + "OrderedImports" : true, + "ReplaceForEachWithForLoop" : true, + "ReturnVoidInsteadOfEmptyTuple" : true, + "UseEarlyExits" : false, + "UseExplicitNilCheckInConditions" : false, + "UseLetInEveryBoundCaseVariable" : false, + "UseShorthandTypeNames" : true, + "UseSingleLinePropertyGetter" : false, + "UseSynthesizedInitializer" : false, + "UseTripleSlashForDocumentationComments" : true, + "UseWhereClausesInForLoops" : false, + "ValidateDocumentationComments" : false + } +} diff --git a/.unacceptablelanguageignore b/.unacceptablelanguageignore new file mode 100644 index 000000000..1372c3419 --- /dev/null +++ b/.unacceptablelanguageignore @@ -0,0 +1,2 @@ +Sources/CNIOBoringSSL/* +NOTICE.txt diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 54f79b80b..5e343aa6c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -67,6 +67,11 @@ We require that your commit messages match our template. The easiest way to do t SwiftNIO uses XCTest to run tests on both macOS and Linux. While the macOS version of XCTest is able to use the Objective-C runtime to discover tests at execution time, the Linux version is not. For this reason, whenever you add new tests you will want to run a script that generates the hooks needed to run those tests on Linux, or our CI will complain that the tests are not all present on Linux. To do this, merely execute `ruby generate_linux_tests.rb` at the root of the package and check the changes it made. +### Run CI checks locally + +You can run the Github Actions workflows locally using [act](https://github.com/nektos/act). For detailed steps on how to do this please see [https://github.com/swiftlang/github-workflows?tab=readme-ov-file#running-workflows-locally](https://github.com/swiftlang/github-workflows?tab=readme-ov-file#running-workflows-locally). + + ## How to contribute your work Please open a pull request at https://github.com/apple/swift-nio. Make sure the CI passes, and then wait for code review. diff --git a/IntegrationTests/plugin_junit_xml.sh b/IntegrationTests/plugin_junit_xml.sh index d88a51c7d..f59ea28ca 100644 --- a/IntegrationTests/plugin_junit_xml.sh +++ b/IntegrationTests/plugin_junit_xml.sh @@ -44,9 +44,9 @@ function junit_output_replace() { function plugin_junit_xml_test_suite_begin() { junit_testsuite_time=0 - junit_output_write "" } diff --git a/IntegrationTests/run-single-test.sh b/IntegrationTests/run-single-test.sh index 365010299..7ec19d626 100755 --- a/IntegrationTests/run-single-test.sh +++ b/IntegrationTests/run-single-test.sh @@ -20,12 +20,17 @@ set -x set -o pipefail test="$1" +# shellcheck disable=SC2034 # Used by whatever we source transpile in tmp="$2" +# shellcheck disable=SC2034 # Used by whatever we source transpile in root="$3" +# shellcheck disable=SC2034 # Used by whatever we source transpile in g_show_info="$4" here="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +# shellcheck source=IntegrationTests/test_functions.sh source "$here/test_functions.sh" +# shellcheck source=/dev/null source "$test" wait ) diff --git a/IntegrationTests/run-tests.sh b/IntegrationTests/run-tests.sh index 9250b83ed..0ed61e945 100755 --- a/IntegrationTests/run-tests.sh +++ b/IntegrationTests/run-tests.sh @@ -36,7 +36,9 @@ function plugins_do() { done } +# shellcheck source=IntegrationTests/plugin_echo.sh source "$here/plugin_echo.sh" +# shellcheck source=/dev/null source "$here/plugin_junit_xml.sh" plugins="echo" @@ -88,7 +90,7 @@ function run_test() { if $verbose; then "$@" 2>&1 | tee -a "$out" # we need to return the return value of the first command - return ${PIPESTATUS[0]} + return "${PIPESTATUS[0]}" else "$@" >> "$out" 2>&1 fi @@ -113,13 +115,13 @@ for f in tests_*; do plugins_do test_begin "$t" "$f" start=$(date +%s) if run_test "$here/run-single-test.sh" "$here/$f/$t" "$test_tmp" "$here/.." "$show_info"; then - plugins_do test_ok "$(time_diff_to_now $start)" + plugins_do test_ok "$(time_diff_to_now "$start")" suite_ok=$((suite_ok+1)) if $verbose; then cat "$out" fi else - plugins_do test_fail "$(time_diff_to_now $start)" "$out" + plugins_do test_fail "$(time_diff_to_now "$start")" "$out" suite_fail=$((suite_fail+1)) fi if ! $debug; then @@ -131,7 +133,7 @@ for f in tests_*; do cnt_ok=$((cnt_ok + suite_ok)) cnt_fail=$((cnt_fail + suite_fail)) cd .. - plugins_do test_suite_end "$(time_diff_to_now $start_suite)" "$suite_ok" "$suite_fail" + plugins_do test_suite_end "$(time_diff_to_now "$start_suite")" "$suite_ok" "$suite_fail" done if ! $debug; then @@ -142,17 +144,17 @@ fi # report -if [[ $cnt_fail > 0 ]]; then - # kill leftovers (the whole process group) +if [[ $cnt_fail -gt 0 ]]; then + # terminate leftovers (the whole process group) trap '' TERM - kill 0 + kill 0 # ignore-unacceptable-language plugins_do summary_fail "$cnt_ok" "$cnt_fail" else plugins_do summary_ok "$cnt_ok" "$cnt_fail" fi -if [[ $cnt_fail > 0 ]]; then +if [[ $cnt_fail -gt 0 ]]; then exit 1 else exit 0 diff --git a/IntegrationTests/test_functions.sh b/IntegrationTests/test_functions.sh index 2eafeb71b..ee4036a15 100644 --- a/IntegrationTests/test_functions.sh +++ b/IntegrationTests/test_functions.sh @@ -64,6 +64,7 @@ function assert_greater_than_or_equal() { g_has_previously_infoed=false function info() { + # shellcheck disable=SC2154 # Defined by an include our by being source transpiled in if $g_show_info; then if ! $g_has_previously_infoed; then echo >&3 || true # echo an extra newline so it looks better diff --git a/IntegrationTests/tests_01_general/test_01_renegotiation.sh b/IntegrationTests/tests_01_general/test_01_renegotiation.sh index 7aa210785..10f40c85b 100644 --- a/IntegrationTests/tests_01_general/test_01_renegotiation.sh +++ b/IntegrationTests/tests_01_general/test_01_renegotiation.sh @@ -13,11 +13,14 @@ ## ##===----------------------------------------------------------------------===## +# shellcheck source=IntegrationTests/tests_01_general/defines.sh source defines.sh swift build # Generate a self-signed certificate. + +# shellcheck disable=SC2154 # Provided by framework cat << EOF > "$tmp/openssl.cnf" [ req ] distinguished_name = subject diff --git a/IntegrationTests/tests_01_general/test_02_execstack.sh b/IntegrationTests/tests_01_general/test_02_execstack.sh index 79fb6a685..9b13c745a 100644 --- a/IntegrationTests/tests_01_general/test_02_execstack.sh +++ b/IntegrationTests/tests_01_general/test_02_execstack.sh @@ -13,6 +13,7 @@ ## ##===----------------------------------------------------------------------===## +# shellcheck source=IntegrationTests/tests_01_general/defines.sh source defines.sh if [[ "$(uname -s)" == "Darwin" ]]; then @@ -26,7 +27,7 @@ swift build -c release DEBUG_SERVER_PATH="$(swift build --show-bin-path)/NIOTLSServer" RELEASE_SERVER_PATH="$(swift build --show-bin-path -c release)/NIOTLSServer" -results=$(execstack $DEBUG_SERVER_PATH $RELEASE_SERVER_PATH) +results=$(execstack "$DEBUG_SERVER_PATH" "$RELEASE_SERVER_PATH") count=$(echo "$results" | grep -c '^X' || true) if [ "$count" -ne 0 ]; then exit 1 diff --git a/IntegrationTests/tests_02_allocation_counters/test_01_allocation_counts.sh b/IntegrationTests/tests_02_allocation_counters/test_01_allocation_counts.sh index 2025109d2..0fa1bc6d7 100644 --- a/IntegrationTests/tests_02_allocation_counters/test_01_allocation_counts.sh +++ b/IntegrationTests/tests_02_allocation_counters/test_01_allocation_counts.sh @@ -13,6 +13,7 @@ ## ##===----------------------------------------------------------------------===## +# shellcheck source=IntegrationTests/tests_02_allocation_counters/defines.sh source defines.sh set -eu @@ -26,6 +27,7 @@ for file in "$here/test_01_resources/"test_*.swift; do all_tests+=( "$test_name" ) done +# shellcheck disable=SC2154 # Provided by framework "$here/test_01_resources/run-nio-ssl-alloc-counter-tests.sh" -t "$tmp" > "$tmp/output" for test in "${all_tests[@]}"; do diff --git a/IntegrationTests/tests_02_allocation_counters/test_01_resources/shared.swift b/IntegrationTests/tests_02_allocation_counters/test_01_resources/shared.swift index 725d232af..011f80f53 100644 --- a/IntegrationTests/tests_02_allocation_counters/test_01_resources/shared.swift +++ b/IntegrationTests/tests_02_allocation_counters/test_01_resources/shared.swift @@ -21,7 +21,6 @@ class BackToBackEmbeddedChannel { private(set) var server: EmbeddedChannel private var loop: EmbeddedEventLoop - init() { self.loop = EmbeddedEventLoop() self.client = EmbeddedChannel(loop: self.loop) @@ -37,7 +36,7 @@ class BackToBackEmbeddedChannel { while workToDo { workToDo = false - + self.loop.run() let clientDatum = try self.client.readOutbound(as: IOData.self) let serverDatum = try self.server.readOutbound(as: IOData.self) @@ -55,46 +54,45 @@ class BackToBackEmbeddedChannel { } } - extension BackToBackEmbeddedChannel { enum Error: Swift.Error { case nonCleanExit } } - extension NIOSSLCertificate { static func forTesting() throws -> NIOSSLCertificate { - return try .init(bytes: certificatePemBytes, format: .pem) + try .init(bytes: certificatePemBytes, format: .pem) } } - extension NIOSSLPrivateKey { static func forTesting() throws -> NIOSSLPrivateKey { - return try .init(bytes: keyPemBytes, format: .pem) + try .init(bytes: keyPemBytes, format: .pem) } } - -fileprivate let certificatePemBytes = Array(""" ------BEGIN CERTIFICATE----- -MIIBTzCB9qADAgECAhQkvv72Je/v+B/cgJ53f84O82z6WTAKBggqhkjOPQQDAjAU -MRIwEAYDVQQDDAlsb2NhbGhvc3QwHhcNMTkxMTI3MTAxMjMwWhcNMjkxMTI0MTAx -MjMwWjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwWTATBgcqhkjOPQIBBggqhkjOPQMB -BwNCAAShtZ9TRt7I+7Y0o99XUkrgSYmUmpr4K8CB0IkTCX6b1tXp3Xqs1V5BckTd -qrls+zsm3AfeiNBb9EDdxiX9DdzuoyYwJDAUBgNVHREEDTALgglsb2NhbGhvc3Qw -DAYDVR0TAQH/BAIwADAKBggqhkjOPQQDAgNIADBFAiAKxYON+YTnIHNR0R6SLP8R -R7hjsjV5NDs18XLoeRnA1gIhANwyggmE6NQW/r9l59fexj/ZrjaS3jYOTNCfC1Lo -5NgJ ------END CERTIFICATE----- -""".utf8) - - -fileprivate let keyPemBytes = Array(""" ------BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgCn182hBmYVMAiNPO -+7w05F40SlAqqxgBEYJZOeK47aihRANCAAShtZ9TRt7I+7Y0o99XUkrgSYmUmpr4 -K8CB0IkTCX6b1tXp3Xqs1V5BckTdqrls+zsm3AfeiNBb9EDdxiX9Ddzu ------END PRIVATE KEY----- -""".utf8) +private let certificatePemBytes = Array( + """ + -----BEGIN CERTIFICATE----- + MIIBTzCB9qADAgECAhQkvv72Je/v+B/cgJ53f84O82z6WTAKBggqhkjOPQQDAjAU + MRIwEAYDVQQDDAlsb2NhbGhvc3QwHhcNMTkxMTI3MTAxMjMwWhcNMjkxMTI0MTAx + MjMwWjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwWTATBgcqhkjOPQIBBggqhkjOPQMB + BwNCAAShtZ9TRt7I+7Y0o99XUkrgSYmUmpr4K8CB0IkTCX6b1tXp3Xqs1V5BckTd + qrls+zsm3AfeiNBb9EDdxiX9DdzuoyYwJDAUBgNVHREEDTALgglsb2NhbGhvc3Qw + DAYDVR0TAQH/BAIwADAKBggqhkjOPQQDAgNIADBFAiAKxYON+YTnIHNR0R6SLP8R + R7hjsjV5NDs18XLoeRnA1gIhANwyggmE6NQW/r9l59fexj/ZrjaS3jYOTNCfC1Lo + 5NgJ + -----END CERTIFICATE----- + """.utf8 +) + +private let keyPemBytes = Array( + """ + -----BEGIN PRIVATE KEY----- + MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgCn182hBmYVMAiNPO + +7w05F40SlAqqxgBEYJZOeK47aihRANCAAShtZ9TRt7I+7Y0o99XUkrgSYmUmpr4 + K8CB0IkTCX6b1tXp3Xqs1V5BckTdqrls+zsm3AfeiNBb9EDdxiX9Ddzu + -----END PRIVATE KEY----- + """.utf8 +) diff --git a/IntegrationTests/tests_02_allocation_counters/test_01_resources/test_many_writes.swift b/IntegrationTests/tests_02_allocation_counters/test_01_resources/test_many_writes.swift index fe4357f59..f984ac73b 100644 --- a/IntegrationTests/tests_02_allocation_counters/test_01_resources/test_many_writes.swift +++ b/IntegrationTests/tests_02_allocation_counters/test_01_resources/test_many_writes.swift @@ -17,10 +17,12 @@ import NIOEmbedded import NIOSSL func run(identifier: String) { - let serverContext = try! NIOSSLContext(configuration: .makeServerConfiguration( - certificateChain: [.certificate(.forTesting())], - privateKey: .privateKey(.forTesting()) - )) + let serverContext = try! NIOSSLContext( + configuration: .makeServerConfiguration( + certificateChain: [.certificate(.forTesting())], + privateKey: .privateKey(.forTesting()) + ) + ) var clientConfig = TLSConfiguration.makeClientConfiguration() clientConfig.trustRoots = try! .certificates([.forTesting()]) @@ -54,7 +56,7 @@ func run(identifier: String) { try! backToBack.interactInMemory() // Pull any data out of the server to avoid ballooning in memory. - while let _ = try! backToBack.server.readInbound(as: ByteBuffer.self) { } + while let _ = try! backToBack.server.readInbound(as: ByteBuffer.self) {} } return 1000 diff --git a/IntegrationTests/tests_02_allocation_counters/test_01_resources/test_simple_handshake.swift b/IntegrationTests/tests_02_allocation_counters/test_01_resources/test_simple_handshake.swift index 9fa34cfd3..1b11300dd 100644 --- a/IntegrationTests/tests_02_allocation_counters/test_01_resources/test_simple_handshake.swift +++ b/IntegrationTests/tests_02_allocation_counters/test_01_resources/test_simple_handshake.swift @@ -17,10 +17,12 @@ import NIOEmbedded import NIOSSL func run(identifier: String) { - let serverContext = try! NIOSSLContext(configuration: .makeServerConfiguration( - certificateChain: [.certificate(.forTesting())], - privateKey: .privateKey(.forTesting()) - )) + let serverContext = try! NIOSSLContext( + configuration: .makeServerConfiguration( + certificateChain: [.certificate(.forTesting())], + privateKey: .privateKey(.forTesting()) + ) + ) var clientConfig = TLSConfiguration.makeClientConfiguration() clientConfig.trustRoots = try! .certificates([.forTesting()]) diff --git a/Package.swift b/Package.swift index c061ebe5d..1f804664d 100644 --- a/Package.swift +++ b/Package.swift @@ -36,12 +36,11 @@ import class Foundation.ProcessInfo func generateDependencies() -> [Package.Dependency] { if ProcessInfo.processInfo.environment["SWIFTCI_USE_LOCAL_DEPS"] == nil { return [ - .package(url: "https://github.com/apple/swift-nio.git", from: "2.54.0"), - .package(url: "https://github.com/swiftlang/swift-docc-plugin.git", from: "1.0.0"), + .package(url: "https://github.com/apple/swift-nio.git", from: "2.54.0") ] } else { return [ - .package(path: "../swift-nio"), + .package(path: "../swift-nio") ] } } @@ -55,33 +54,36 @@ let includePrivacyManifest = true let includePrivacyManifest = false #endif +// swift-format-ignore: NoBlockComments let package = Package( name: "swift-nio-ssl", products: [ .library(name: "NIOSSL", targets: ["NIOSSL"]), .executable(name: "NIOTLSServer", targets: ["NIOTLSServer"]), .executable(name: "NIOSSLHTTP1Client", targets: ["NIOSSLHTTP1Client"]), -/* This target is used only for symbol mangling. It's added and removed automatically because it emits build warnings. MANGLE_START - .library(name: "CNIOBoringSSL", type: .static, targets: ["CNIOBoringSSL"]), -MANGLE_END */ + /* This target is used only for symbol mangling. It's added and removed automatically because it emits build warnings. MANGLE_START + .library(name: "CNIOBoringSSL", type: .static, targets: ["CNIOBoringSSL"]), + MANGLE_END */ ], dependencies: generateDependencies(), targets: [ .target( name: "CNIOBoringSSL", cSettings: [ - .define("_GNU_SOURCE"), - .define("_POSIX_C_SOURCE", to: "200112L"), - .define("_DARWIN_C_SOURCE") - ]), + .define("_GNU_SOURCE"), + .define("_POSIX_C_SOURCE", to: "200112L"), + .define("_DARWIN_C_SOURCE"), + ] + ), .target( name: "CNIOBoringSSLShims", dependencies: [ "CNIOBoringSSL" ], cSettings: [ - .define("_GNU_SOURCE"), - ]), + .define("_GNU_SOURCE") + ] + ), .target( name: "NIOSSL", dependencies: [ @@ -105,7 +107,8 @@ MANGLE_END */ ], exclude: [ "README.md" - ]), + ] + ), .executableTarget( name: "NIOSSLHTTP1Client", dependencies: [ @@ -117,7 +120,8 @@ MANGLE_END */ ], exclude: [ "README.md" - ]), + ] + ), .executableTarget( name: "NIOSSLPerformanceTester", dependencies: [ @@ -125,7 +129,8 @@ MANGLE_END */ .product(name: "NIOCore", package: "swift-nio"), .product(name: "NIOEmbedded", package: "swift-nio"), .product(name: "NIOTLS", package: "swift-nio"), - ]), + ] + ), .testTarget( name: "NIOSSLTests", dependencies: [ @@ -134,7 +139,8 @@ MANGLE_END */ .product(name: "NIOEmbedded", package: "swift-nio"), .product(name: "NIOPosix", package: "swift-nio"), .product(name: "NIOTLS", package: "swift-nio"), - ]), + ] + ), ], cxxLanguageStandard: .cxx14 ) diff --git a/Sources/NIOSSL/AndroidCABundle.swift b/Sources/NIOSSL/AndroidCABundle.swift index dd5a2d8a6..fa4a32cdf 100644 --- a/Sources/NIOSSL/AndroidCABundle.swift +++ b/Sources/NIOSSL/AndroidCABundle.swift @@ -31,6 +31,6 @@ private let rootCADirectorySearchPaths = [ ] private func locateRootCADirectory() -> String? { - return rootCADirectorySearchPaths.first(where: { FileSystemObject.pathType(path: $0) == .directory }) + rootCADirectorySearchPaths.first(where: { FileSystemObject.pathType(path: $0) == .directory }) } #endif diff --git a/Sources/NIOSSL/ByteBufferBIO.swift b/Sources/NIOSSL/ByteBufferBIO.swift index 1a8144fb3..5a620fb18 100644 --- a/Sources/NIOSSL/ByteBufferBIO.swift +++ b/Sources/NIOSSL/ByteBufferBIO.swift @@ -12,8 +12,8 @@ // //===----------------------------------------------------------------------===// -import NIOCore @_implementationOnly import CNIOBoringSSL +import NIOCore #if canImport(Darwin) import Darwin.C @@ -27,7 +27,6 @@ import Bionic #error("unsupported os") #endif - /// The BoringSSL entry point to write to the `ByteBufferBIO`. This thunk unwraps the user data /// and then passes the call on to the specific BIO reference. /// @@ -36,7 +35,9 @@ import Bionic /// function pointer and so needs to be @convention(c). internal func boringSSLBIOWriteFunc(bio: UnsafeMutablePointer?, buf: UnsafePointer?, len: CInt) -> CInt { guard let concreteBIO = bio, let concreteBuf = buf else { - preconditionFailure("Invalid pointers in boringSSLBIOWriteFunc: bio: \(String(describing: bio)) buf: \(String(describing: buf))") + preconditionFailure( + "Invalid pointers in boringSSLBIOWriteFunc: bio: \(String(describing: bio)) buf: \(String(describing: buf))" + ) } // This unwrap may fail if the user has dropped the ref to the ByteBufferBIO but still has @@ -64,9 +65,15 @@ internal func boringSSLBIOWriteFunc(bio: UnsafeMutablePointer?, buf: Unsafe /// This specific type signature is annoying (I'd rather have UnsafeRawPointer, and rather than a separate /// len I'd like a buffer pointer), but this interface is required because this is passed to an BoringSSL /// function pointer and so needs to be @convention(c). -internal func boringSSLBIOReadFunc(bio: UnsafeMutablePointer?, buf: UnsafeMutablePointer?, len: CInt) -> CInt { +internal func boringSSLBIOReadFunc( + bio: UnsafeMutablePointer?, + buf: UnsafeMutablePointer?, + len: CInt +) -> CInt { guard let concreteBIO = bio, let concreteBuf = buf else { - preconditionFailure("Invalid pointers in boringSSLBIOReadFunc: bio: \(String(describing: bio)) buf: \(String(describing: buf))") + preconditionFailure( + "Invalid pointers in boringSSLBIOReadFunc: bio: \(String(describing: bio)) buf: \(String(describing: buf))" + ) } // This unwrap may fail if the user has dropped the ref to the ByteBufferBIO but still has @@ -96,7 +103,9 @@ internal func boringSSLBIOReadFunc(bio: UnsafeMutablePointer?, buf: UnsafeM /// function pointer and so needs to be @convention(c). internal func boringSSLBIOPutsFunc(bio: UnsafeMutablePointer?, buf: UnsafePointer?) -> CInt { guard let concreteBIO = bio, let concreteBuf = buf else { - preconditionFailure("Invalid pointers in boringSSLBIOPutsFunc: bio: \(String(describing: bio)) buf: \(String(describing: buf))") + preconditionFailure( + "Invalid pointers in boringSSLBIOPutsFunc: bio: \(String(describing: bio)) buf: \(String(describing: buf))" + ) } return boringSSLBIOWriteFunc(bio: concreteBIO, buf: concreteBuf, len: CInt(strlen(concreteBuf))) } @@ -107,12 +116,21 @@ internal func boringSSLBIOPutsFunc(bio: UnsafeMutablePointer?, buf: UnsafeP /// This specific type signature is annoying (I'd rather have UnsafeRawPointer, and rather than a separate /// len I'd like a buffer pointer), but this interface is required because this is passed to an BoringSSL /// function pointer and so needs to be @convention(c). -internal func boringSSLBIOGetsFunc(bio: UnsafeMutablePointer?, buf: UnsafeMutablePointer?, len: CInt) -> CInt { - return -2 +internal func boringSSLBIOGetsFunc( + bio: UnsafeMutablePointer?, + buf: UnsafeMutablePointer?, + len: CInt +) -> CInt { + -2 } /// The BoringSSL entry point for `BIO_ctrl`. We don't support most of these. -internal func boringSSLBIOCtrlFunc(bio: UnsafeMutablePointer?, cmd: CInt, larg: CLong, parg: UnsafeMutableRawPointer?) -> CLong { +internal func boringSSLBIOCtrlFunc( + bio: UnsafeMutablePointer?, + cmd: CInt, + larg: CLong, + parg: UnsafeMutableRawPointer? +) -> CLong { switch cmd { case BIO_CTRL_GET_CLOSE: return CLong(CNIOBoringSSL_BIO_get_shutdown(bio)) @@ -127,14 +145,13 @@ internal func boringSSLBIOCtrlFunc(bio: UnsafeMutablePointer?, cmd: CInt, l } internal func boringSSLBIOCreateFunc(bio: UnsafeMutablePointer?) -> CInt { - return 1 + 1 } internal func boringSSLBIODestroyFunc(bio: UnsafeMutablePointer?) -> CInt { - return 1 + 1 } - /// An BoringSSL BIO object that wraps `ByteBuffer` objects. /// /// BoringSSL extensively uses an abstraction called `BIO` to manage its input and output @@ -223,12 +240,12 @@ final class ByteBufferBIO { /// wants to be delayed as long as possible to maximise the possibility that it does not /// trigger an allocation. private var mustClearOutboundBuffer: Bool { - return outboundBuffer.readerIndex == outboundBuffer.writerIndex && outboundBuffer.readerIndex > 0 + outboundBuffer.readerIndex == outboundBuffer.writerIndex && outboundBuffer.readerIndex > 0 } /// A test helper to provide the outbound buffer capacity. internal var _testOnly_outboundBufferCapacity: Int { - return self.outboundBuffer.capacity + self.outboundBuffer.capacity } init(allocator: ByteBufferAllocator, maximumPreservedOutboundBufferCapacity: Int) { @@ -286,7 +303,6 @@ final class ByteBufferBIO { return self.bioPtr } - /// Called to obtain the outbound ciphertext written by BoringSSL. /// /// This function obtains a buffer of ciphertext that needs to be written to the network. In a @@ -362,8 +378,14 @@ final class ByteBufferBIO { let bytesToCopy = min(buffer.count, inboundBuffer.readableBytes) _ = inboundBuffer.readWithUnsafeReadableBytes { bytePointer in - assert(bytePointer.count >= bytesToCopy, "Copying more bytes (\(bytesToCopy)) than fits in readable bytes \((bytePointer.count))") - assert(buffer.count >= bytesToCopy, "Copying more bytes (\(bytesToCopy) than contained in source buffer (\(buffer.count))") + assert( + bytePointer.count >= bytesToCopy, + "Copying more bytes (\(bytesToCopy)) than fits in readable bytes \((bytePointer.count))" + ) + assert( + buffer.count >= bytesToCopy, + "Copying more bytes (\(bytesToCopy) than contained in source buffer (\(buffer.count))" + ) buffer.baseAddress!.copyMemory(from: bytePointer.baseAddress!, byteCount: bytesToCopy) return bytesToCopy } @@ -387,7 +409,9 @@ final class ByteBufferBIO { if self.mustClearOutboundBuffer { // We just flushed, and this is a new write. Let's clear the buffer now. if self.outboundBuffer.capacity > self.maximumPreservedOutboundBufferCapacity { - self.outboundBuffer = self.allocator.buffer(capacity: max(buffer.count, self.maximumPreservedOutboundBufferCapacity)) + self.outboundBuffer = self.allocator.buffer( + capacity: max(buffer.count, self.maximumPreservedOutboundBufferCapacity) + ) } else { self.outboundBuffer.clear() assert(!self.mustClearOutboundBuffer) diff --git a/Sources/NIOSSL/CustomPrivateKey.swift b/Sources/NIOSSL/CustomPrivateKey.swift index f833cca5d..94f46e820 100644 --- a/Sources/NIOSSL/CustomPrivateKey.swift +++ b/Sources/NIOSSL/CustomPrivateKey.swift @@ -12,8 +12,8 @@ // //===----------------------------------------------------------------------===// -import NIOCore @_implementationOnly import CNIOBoringSSL +import NIOCore /// ``NIOSSLCustomPrivateKey`` defines the interface of a custom, non-BoringSSL private key. /// @@ -92,19 +92,23 @@ internal struct AnyNIOSSLCustomPrivateKey: NIOSSLCustomPrivateKey, Hashable { // This method does not need to be @inlinable for performance, but it needs to be _at least_ // @usableFromInline as it's a protocol requirement on a @usableFromInline type. @inlinable var signatureAlgorithms: [SignatureAlgorithm] { - return self._value.signatureAlgorithms + self._value.signatureAlgorithms } // This method does not need to be @inlinable for performance, but it needs to be _at least_ // @usableFromInline as it's a protocol requirement on a @usableFromInline type. - @inlinable func sign(channel: Channel, algorithm: SignatureAlgorithm, data: ByteBuffer) -> EventLoopFuture { - return self._value.sign(channel: channel, algorithm: algorithm, data: data) + @inlinable func sign( + channel: Channel, + algorithm: SignatureAlgorithm, + data: ByteBuffer + ) -> EventLoopFuture { + self._value.sign(channel: channel, algorithm: algorithm, data: data) } // This method does not need to be @inlinable for performance, but it needs to be _at least_ // @usableFromInline as it's a protocol requirement on a @usableFromInline type. @inlinable func decrypt(channel: Channel, data: ByteBuffer) -> EventLoopFuture { - return self._value.decrypt(channel: channel, data: data) + self._value.decrypt(channel: channel, data: data) } // This method does not need to be @inlinable for performance, but it needs to be _at least_ @@ -115,15 +119,16 @@ internal struct AnyNIOSSLCustomPrivateKey: NIOSSLCustomPrivateKey, Hashable { // This method does not need to be @inlinable for performance, but it needs to be _at least_ // @usableFromInline as it's a protocol requirement on a @usableFromInline type. - @inlinable static func ==(lhs: AnyNIOSSLCustomPrivateKey, rhs: AnyNIOSSLCustomPrivateKey) -> Bool { - return lhs._equalsFunction(rhs._value) + @inlinable static func == (lhs: AnyNIOSSLCustomPrivateKey, rhs: AnyNIOSSLCustomPrivateKey) -> Bool { + lhs._equalsFunction(rhs._value) } } extension SSLConnection { fileprivate var customKey: NIOSSLCustomPrivateKey? { guard case .some(.privateKey(let key)) = self.parentContext.configuration.privateKey, - case .custom(let customKey) = key.representation else { + case .custom(let customKey) = key.representation + else { return nil } @@ -180,7 +185,8 @@ extension SSLConnection { return ssl_private_key_retry } - fileprivate func customPrivateKeyComplete(out: inout UnsafeMutableBufferPointer) -> ssl_private_key_result_t { + fileprivate func customPrivateKeyComplete(out: inout UnsafeMutableBufferPointer) -> ssl_private_key_result_t + { switch self.customPrivateKeyResult { case .none: return ssl_private_key_retry @@ -218,9 +224,14 @@ internal let customPrivateKeyMethod: UnsafePointer = { }() /// This is our entry point from BoringSSL when we've been asked to do a sign. -fileprivate func customKeySign( - ssl: OpaquePointer?, out: UnsafeMutablePointer?, outLen: UnsafeMutablePointer?, - maxOut: size_t, signatureAlgorithm: UInt16, in: UnsafePointer?, inLen: Int +private func customKeySign( + ssl: OpaquePointer?, + out: UnsafeMutablePointer?, + outLen: UnsafeMutablePointer?, + maxOut: size_t, + signatureAlgorithm: UInt16, + in: UnsafePointer?, + inLen: Int ) -> ssl_private_key_result_t { guard let ssl = ssl, out != nil, let outLen = outLen, let `in` = `in` else { preconditionFailure() @@ -236,9 +247,13 @@ fileprivate func customKeySign( } /// This is our entry point from BoringSSL when we've been asked to do a decrypt. -fileprivate func customKeyDecrypt( - ssl: OpaquePointer?, out: UnsafeMutablePointer?, outLen: UnsafeMutablePointer?, - maxOut: Int, in: UnsafePointer?, inLen: Int +private func customKeyDecrypt( + ssl: OpaquePointer?, + out: UnsafeMutablePointer?, + outLen: UnsafeMutablePointer?, + maxOut: Int, + in: UnsafePointer?, + inLen: Int ) -> ssl_private_key_result_t { guard let ssl = ssl, out != nil, let outLen = outLen, let `in` = `in` else { preconditionFailure() @@ -253,10 +268,11 @@ fileprivate func customKeyDecrypt( return connection.customPrivateKeyDecrypt(in: inBuffer) } - /// When BoringSSL is asking if we're done with our key operation, we come here. -fileprivate func customKeyComplete( - ssl: OpaquePointer?, out: UnsafeMutablePointer?, outLen: UnsafeMutablePointer?, +private func customKeyComplete( + ssl: OpaquePointer?, + out: UnsafeMutablePointer?, + outLen: UnsafeMutablePointer?, maxOut: Int ) -> ssl_private_key_result_t { guard let ssl = ssl, let out = out, let outLen = outLen else { diff --git a/Sources/NIOSSL/IdentityVerification.swift b/Sources/NIOSSL/IdentityVerification.swift index 5306ed586..dc22233bf 100644 --- a/Sources/NIOSSL/IdentityVerification.swift +++ b/Sources/NIOSSL/IdentityVerification.swift @@ -26,7 +26,6 @@ import Android #error("unsupported os") #endif - private let asciiIDNAIdentifier: ArraySlice = Array("xn--".utf8)[...] private let asciiCapitals: ClosedRange = (UInt8(ascii: "A")...UInt8(ascii: "Z")) private let asciiLowercase: ClosedRange = (UInt8(ascii: "a")...UInt8(ascii: "z")) @@ -35,7 +34,6 @@ private let asciiHyphen: UInt8 = UInt8(ascii: "-") private let asciiPeriod: UInt8 = UInt8(ascii: ".") private let asciiAsterisk: UInt8 = UInt8(ascii: "*") - extension String { /// Calls `fn` with an `Array` pointing to a /// non-NULL-terminated sequence of ASCII bytes. If the string this method @@ -45,7 +43,7 @@ extension String { /// In a naive implementation we'd loop at least three times: once to lowercase /// the string, once to get a buffer pointer to a contiguous buffer, and once /// to confirm the string is ASCII. Here we can do that all in one loop. - fileprivate func withLowercaseASCIIBuffer(_ fn: (Array) throws -> T) throws -> T { + fileprivate func withLowercaseASCIIBuffer(_ fn: ([UInt8]) throws -> T) throws -> T { let buffer: [UInt8] = try self.utf8.map { codeUnit in guard codeUnit.isValidDNSCharacter else { throw NIOSSLExtraError.serverHostnameImpossibleToMatch(hostname: self) @@ -59,7 +57,6 @@ extension String { } } - extension Collection { /// Splits a collection in two around a given index. This index may be nil, in which case the split /// will occur around the end. @@ -96,7 +93,6 @@ extension UInt8 { } } - /// Validates that a given leaf certificate is valid for a service. /// /// This function implements the logic for service validation as specified by @@ -106,25 +102,33 @@ extension UInt8 { /// /// The algorithm we're implementing is specified in RFC 6125 Section 6 if you want to /// follow along at home. -internal func validIdentityForService(serverHostname: String?, - socketAddress: SocketAddress, - leafCertificate: NIOSSLCertificate) throws -> Bool { +internal func validIdentityForService( + serverHostname: String?, + socketAddress: SocketAddress, + leafCertificate: NIOSSLCertificate +) throws -> Bool { if let serverHostname = serverHostname { return try serverHostname.withLowercaseASCIIBuffer { - try validIdentityForService(serverHostname: $0, - socketAddress: socketAddress, - leafCertificate: leafCertificate) + try validIdentityForService( + serverHostname: $0, + socketAddress: socketAddress, + leafCertificate: leafCertificate + ) } } else { - return try validIdentityForService(serverHostname: nil as Array?, - socketAddress: socketAddress, - leafCertificate: leafCertificate) + return try validIdentityForService( + serverHostname: nil as [UInt8]?, + socketAddress: socketAddress, + leafCertificate: leafCertificate + ) } } -private func validIdentityForService(serverHostname: Array?, - socketAddress: SocketAddress, - leafCertificate: NIOSSLCertificate) throws -> Bool { +private func validIdentityForService( + serverHostname: [UInt8]?, + socketAddress: SocketAddress, + leafCertificate: NIOSSLCertificate +) throws -> Bool { // Before we begin, we want to locate the first period in our own domain name. We need to do // this because we may need to match a wildcard label. var serverHostnameSlice: ArraySlice? = nil @@ -133,7 +137,6 @@ private func validIdentityForService(serverHostname: Array?, if let serverHostname = serverHostname { var tempServerHostnameSlice = serverHostname[...] - // Strip trailing period if tempServerHostnameSlice.last == .some(asciiPeriod) { tempServerHostnameSlice = tempServerHostnameSlice.dropLast() @@ -159,7 +162,7 @@ private func validIdentityForService(serverHostname: Array?, } case .ipAddress: if let ip = _SubjectAlternativeName.IPAddress(name), - matchIpAddress(socketAddress: socketAddress, certificateIP: ip) + matchIpAddress(socketAddress: socketAddress, certificateIP: ip) { return true } @@ -186,8 +189,11 @@ private func validIdentityForService(serverHostname: Array?, return matchHostname(ourHostname: serverHostnameSlice, firstPeriodIndex: firstPeriodIndex, dnsName: commonName) } - -private func matchHostname(ourHostname: ArraySlice?, firstPeriodIndex: ArraySlice.Index?, dnsName: Array) -> Bool { +private func matchHostname( + ourHostname: ArraySlice?, + firstPeriodIndex: ArraySlice.Index?, + dnsName: [UInt8] +) -> Bool { guard let ourHostname = ourHostname else { // No server hostname was provided, so we cannot match. return false @@ -202,7 +208,6 @@ private func matchHostname(ourHostname: ArraySlice?, firstPeriodIndex: Ar return validatedHostname.validMatchForName(ourHostname, firstPeriodIndexForName: firstPeriodIndex) } - private func matchIpAddress(socketAddress: SocketAddress, certificateIP: _SubjectAlternativeName.IPAddress) -> Bool { // These match if the two underlying IP address structures match. switch (socketAddress, certificateIP) { @@ -218,7 +223,6 @@ private func matchIpAddress(socketAddress: SocketAddress, certificateIP: _Subjec } } - /// This structure contains a certificate hostname that has been analysed and prepared for matching. /// /// A certificate hostname that is valid for matching meets the following criteria: @@ -232,7 +236,7 @@ private func matchIpAddress(socketAddress: SocketAddress, certificateIP: _Subjec /// ideal: it'd be better to do a single search that both validates the domain name meets the criteria /// and that also records information needed to validate that the name matches the one we're searching for. /// That's what this structure does. -fileprivate struct AnalysedCertificateHostname { +private struct AnalysedCertificateHostname { /// The type we use to store the base name. The other types on this object are chosen relative to that. fileprivate typealias BaseNameType = ArraySlice @@ -246,8 +250,8 @@ fileprivate struct AnalysedCertificateHostname { // Ok, start looping. var index = baseName.startIndex - var firstPeriodIndex: Optional = nil - var asteriskIndex: Optional = nil + var firstPeriodIndex: BaseNameType.Index? = nil + var asteriskIndex: BaseNameType.Index? = nil while index < baseName.endIndex { switch baseName[index] { @@ -296,7 +300,7 @@ fileprivate struct AnalysedCertificateHostname { // For non-wildcard names, we just do a straightforward string comparison. return baseName.caseInsensitiveElementsEqual(target) - case .wildcard(let baseName, asteriskIndex: let asteriskIndex, firstPeriodIndex: let firstPeriodIndex): + case .wildcard(let baseName, let asteriskIndex, let firstPeriodIndex): // The wildcard can appear more-or-less anywhere in the first label. The wildcard // character itself can match any number of characters, though it must match at least // one. @@ -332,11 +336,9 @@ fileprivate struct AnalysedCertificateHostname { } } - extension AnalysedCertificateHostname { private enum NameType { - case wildcard(BaseNameType, asteriskIndex: BaseNameType.Index, firstPeriodIndex: Optional) + case wildcard(BaseNameType, asteriskIndex: BaseNameType.Index, firstPeriodIndex: BaseNameType.Index?) case singleName(BaseNameType) } } - diff --git a/Sources/NIOSSL/LinuxCABundle.swift b/Sources/NIOSSL/LinuxCABundle.swift index 2702504fa..e18be089e 100644 --- a/Sources/NIOSSL/LinuxCABundle.swift +++ b/Sources/NIOSSL/LinuxCABundle.swift @@ -23,7 +23,6 @@ internal let rootCAFilePath: String? = locateRootCAFile() /// May be nil if we could not find the root CA bundle directory. internal let rootCADirectoryPath: String? = locateRootCADirectory() - /// This is a list of root CA file search paths. This list contains paths as validated against several distributions. /// If you are attempting to use SwiftNIO SSL on a platform that is not covered here and certificate validation is /// failing, please open a pull request that adds the appropriate search path. @@ -32,7 +31,6 @@ private let rootCAFileSearchPaths = [ "/etc/pki/tls/certs/ca-bundle.crt", // Fedora ] - /// This is a list of root CA directory search paths. /// /// This list contains paths as validated against several distributions. If you are aware of a CA bundle on a specific distribution @@ -40,16 +38,15 @@ private let rootCAFileSearchPaths = [ /// Some distributions do not ship CA directories: as such, it is not a problem if a distribution that is present in rootCAFileSearchPaths /// is not present in this list. private let rootCADirectorySearchPaths = [ - "/etc/ssl/certs", // Ubuntu, Debian, Arch, Alpine + "/etc/ssl/certs" // Ubuntu, Debian, Arch, Alpine ] - private func locateRootCAFile() -> String? { // We need to find the root CA file. We have a list of search paths: let's use them. - return rootCAFileSearchPaths.first(where: { FileSystemObject.pathType(path: $0) == .file }) + rootCAFileSearchPaths.first(where: { FileSystemObject.pathType(path: $0) == .file }) } private func locateRootCADirectory() -> String? { - return rootCADirectorySearchPaths.first(where: { FileSystemObject.pathType(path: $0) == .directory }) + rootCADirectorySearchPaths.first(where: { FileSystemObject.pathType(path: $0) == .directory }) } #endif diff --git a/Sources/NIOSSL/NIOSSLClientHandler.swift b/Sources/NIOSSL/NIOSSLClientHandler.swift index 7133da7ca..85208c537 100644 --- a/Sources/NIOSSL/NIOSSLClientHandler.swift +++ b/Sources/NIOSSL/NIOSSLClientHandler.swift @@ -33,8 +33,7 @@ extension String { var ipv6Addr = in6_addr() return self.withCString { ptr in - return inet_pton(AF_INET, ptr, &ipv4Addr) == 1 || - inet_pton(AF_INET6, ptr, &ipv6Addr) == 1 + inet_pton(AF_INET, ptr, &ipv4Addr) == 1 || inet_pton(AF_INET6, ptr, &ipv6Addr) == 1 } } @@ -48,7 +47,7 @@ extension String { throw NIOSSLExtraError.invalidSNIHostname } - guard (1 ... 255).contains(self.utf8.count) else { + guard (1...255).contains(self.utf8.count) else { throw NIOSSLExtraError.invalidSNIHostname } } @@ -65,11 +64,20 @@ public final class NIOSSLClientHandler: NIOSSLHandler { /// - serverHostname: The hostname of the server we're trying to connect to, if known. This will be used in the SNI extension, /// and used to validate the server certificate. public convenience init(context: NIOSSLContext, serverHostname: String?) throws { - try self.init(context: context, serverHostname: serverHostname, optionalCustomVerificationCallback: nil, optionalAdditionalPeerCertificateVerificationCallback: nil) + try self.init( + context: context, + serverHostname: serverHostname, + optionalCustomVerificationCallback: nil, + optionalAdditionalPeerCertificateVerificationCallback: nil + ) } @available(*, deprecated, renamed: "init(context:serverHostname:customVerificationCallback:)") - public init(context: NIOSSLContext, serverHostname: String?, verificationCallback: NIOSSLVerificationCallback? = nil) throws { + public init( + context: NIOSSLContext, + serverHostname: String?, + verificationCallback: NIOSSLVerificationCallback? = nil + ) throws { guard let connection = context.createConnection() else { fatalError("Failed to create new connection in NIOSSLContext") } @@ -82,7 +90,9 @@ public final class NIOSSLClientHandler: NIOSSLHandler { do { try connection.setServerName(name: serverHostname) } catch { - preconditionFailure("Bug in NIOSSL (please report): \(Array(serverHostname.utf8)) passed NIOSSL's hostname test but failed in BoringSSL.") + preconditionFailure( + "Bug in NIOSSL (please report): \(Array(serverHostname.utf8)) passed NIOSSL's hostname test but failed in BoringSSL." + ) } } @@ -109,8 +119,17 @@ public final class NIOSSLClientHandler: NIOSSLHandler { /// /// If set, this callback is provided the certificates presented by the peer. NIOSSL will not have pre-processed them. The callback will not be used if the /// ``TLSConfiguration`` that was used to construct the ``NIOSSLContext`` has ``TLSConfiguration/certificateVerification`` set to ``CertificateVerification/none``. - public convenience init(context: NIOSSLContext, serverHostname: String?, customVerificationCallback: @escaping NIOSSLCustomVerificationCallback) throws { - try self.init(context: context, serverHostname: serverHostname, optionalCustomVerificationCallback: customVerificationCallback, optionalAdditionalPeerCertificateVerificationCallback: nil) + public convenience init( + context: NIOSSLContext, + serverHostname: String?, + customVerificationCallback: @escaping NIOSSLCustomVerificationCallback + ) throws { + try self.init( + context: context, + serverHostname: serverHostname, + optionalCustomVerificationCallback: customVerificationCallback, + optionalAdditionalPeerCertificateVerificationCallback: nil + ) } /// Construct a new ``NIOSSLClientHandler`` with the given `context` and a specific `serverHostname`. @@ -124,7 +143,12 @@ public final class NIOSSLClientHandler: NIOSSLHandler { /// If set, this callback is provided the certificates presented by the peer. NIOSSL will not have pre-processed them. The callback will not be used if the /// ``TLSConfiguration`` that was used to construct the ``NIOSSLContext`` has ``TLSConfiguration/certificateVerification`` set to ``CertificateVerification/none``. /// - configuration: Configuration for this handler. - public convenience init(context: NIOSSLContext, serverHostname: String?, customVerificationCallback: NIOSSLCustomVerificationCallback? = nil, configuration: Configuration) throws { + public convenience init( + context: NIOSSLContext, + serverHostname: String?, + customVerificationCallback: NIOSSLCustomVerificationCallback? = nil, + configuration: Configuration + ) throws { try self.init( context: context, serverHostname: serverHostname, @@ -140,7 +164,12 @@ public final class NIOSSLClientHandler: NIOSSLHandler { serverHostname: String?, additionalPeerCertificateVerificationCallback: @escaping _NIOAdditionalPeerCertificateVerificationCallback ) throws -> Self { - try .init(context: context, serverHostname: serverHostname, optionalCustomVerificationCallback: nil, optionalAdditionalPeerCertificateVerificationCallback: additionalPeerCertificateVerificationCallback) + try .init( + context: context, + serverHostname: serverHostname, + optionalCustomVerificationCallback: nil, + optionalAdditionalPeerCertificateVerificationCallback: additionalPeerCertificateVerificationCallback + ) } // This exists to handle the explosion of initializers we got when I tried to deprecate the first one. At least they all pass through one path now. @@ -164,7 +193,9 @@ public final class NIOSSLClientHandler: NIOSSLHandler { do { try connection.setServerName(name: serverHostname) } catch { - preconditionFailure("Bug in NIOSSL (please report): \(Array(serverHostname.utf8)) passed NIOSSL's hostname test but failed in BoringSSL.") + preconditionFailure( + "Bug in NIOSSL (please report): \(Array(serverHostname.utf8)) passed NIOSSL's hostname test but failed in BoringSSL." + ) } } diff --git a/Sources/NIOSSL/NIOSSLHandler.swift b/Sources/NIOSSL/NIOSSLHandler.swift index 15e11f5fc..0cd32d0ea 100644 --- a/Sources/NIOSSL/NIOSSLHandler.swift +++ b/Sources/NIOSSL/NIOSSLHandler.swift @@ -12,8 +12,8 @@ // //===----------------------------------------------------------------------===// -import NIOCore @_implementationOnly import CNIOBoringSSL +import NIOCore import NIOTLS /// The base class for all NIOSSL handlers. @@ -25,7 +25,7 @@ import NIOTLS /// of a TLS connection there is no meaningful distinction between a server and a client. /// For this reason almost the entirety of the implementation for the channel and server /// handlers in NIOSSL is shared, in the form of this parent class. -public class NIOSSLHandler : ChannelInboundHandler, ChannelOutboundHandler, RemovableChannelHandler { +public class NIOSSLHandler: ChannelInboundHandler, ChannelOutboundHandler, RemovableChannelHandler { /// The default maximum write size. We cannot pass writes larger than this size to /// BoringSSL. /// @@ -65,7 +65,7 @@ public class NIOSSLHandler : ChannelInboundHandler, ChannelOutboundHandler, Remo private var configuration: Configuration internal var channel: Channel? { - return self.storedContext?.channel + self.storedContext?.channel } internal init( @@ -77,12 +77,12 @@ public class NIOSSLHandler : ChannelInboundHandler, ChannelOutboundHandler, Remo ) { let tlsConfiguration = connection.parentContext.configuration precondition( - additionalPeerCertificateVerificationCallback == nil || - tlsConfiguration.certificateVerification != .none, + additionalPeerCertificateVerificationCallback == nil || tlsConfiguration.certificateVerification != .none, "TLSConfiguration.certificateVerification must be either set to .noHostnameVerification or .fullVerification if additionalPeerCertificateVerificationCallback is specified" ) self.connection = connection - self.bufferedActions = MarkedCircularBuffer(initialCapacity: 96) // 96 brings the total size of the buffer to just shy of one page + // 96 brings the total size of the buffer to just shy of one page + self.bufferedActions = MarkedCircularBuffer(initialCapacity: 96) self.shutdownTimeout = shutdownTimeout self.additionalPeerCertificateVerificationCallback = additionalPeerCertificateVerificationCallback self.maxWriteSize = maxWriteSize @@ -378,11 +378,13 @@ public class NIOSSLHandler : ChannelInboundHandler, ChannelOutboundHandler, Remo if let additionalPeerCertificateVerificationCallback = self.additionalPeerCertificateVerificationCallback { state = .additionalVerification guard let peerCertificate = connection.getPeerCertificate() else { - preconditionFailure(""" - Couldn't get peer certificate after chain verification was successful. - This should be impossible as we have a precondition during creation of this handler that requires certificate verification. - Please file an issue. - """) + preconditionFailure( + """ + Couldn't get peer certificate after chain verification was successful. + This should be impossible as we have a precondition during creation of this handler that requires certificate verification. + Please file an issue. + """ + ) } additionalPeerCertificateVerificationCallback(peerCertificate, context.channel) .hop(to: context.eventLoop) @@ -451,7 +453,7 @@ public class NIOSSLHandler : ChannelInboundHandler, ChannelOutboundHandler, Remo } case .unwrapping, .closing, .unwrapped, .closed: break - // we are already about to close, we can safely ignore this event + // we are already about to close, we can safely ignore this event } } @@ -528,7 +530,7 @@ public class NIOSSLHandler : ChannelInboundHandler, ChannelOutboundHandler, Remo /// Creates a scheduled task to perform an unclean shutdown in event of a clean shutdown timing /// out. This task should be cancelled if the shutdown does not time out. private func scheduleTimedOutShutdown(context: ChannelHandlerContext) -> Scheduled { - return context.eventLoop.scheduleTask(in: self.shutdownTimeout) { + context.eventLoop.scheduleTask(in: self.shutdownTimeout) { switch self.state { case .inputClosed, .outputClosed, .idle, .handshaking, .additionalVerification, .active: preconditionFailure("Cannot schedule timed out shutdown on non-shutting down handler") @@ -753,7 +755,7 @@ public class NIOSSLHandler : ChannelInboundHandler, ChannelOutboundHandler, Remo if let promise = shutdownPromise { removalFuture.whenComplete { result in switch (result, error) { - case(.success, .none): + case (.success, .none): promise.succeed(()) case (.success, .some(let error)): promise.fail(error) @@ -794,14 +796,14 @@ extension NIOSSLHandler { /// This variable **is not thread-safe**: you **must** call it from the correct event /// loop thread. public var tlsVersion: TLSVersion? { - return self.connection.getTLSVersionForConnection() + self.connection.getTLSVersionForConnection() } } extension Channel { /// API to extract the ``TLSVersion`` from off the `Channel`. public func nioSSL_tlsVersion() -> EventLoopFuture { - return self.pipeline.handler(type: NIOSSLHandler.self).map { + self.pipeline.handler(type: NIOSSLHandler.self).map { $0.tlsVersion } } @@ -875,7 +877,6 @@ extension NIOSSLHandler { } } - // MARK: Code that handles buffering/unbuffering actions. extension NIOSSLHandler { private typealias BufferedWrite = (data: ByteBuffer, promise: EventLoopPromise?) @@ -983,7 +984,9 @@ extension NIOSSLHandler { // We spun the outer loop too many times, something isn't right so let's bail out // instead of looping any longer. if bufferedActionsLoopCount >= 1000 { - assertionFailure("\(#function) looped too many times, please file a GitHub issue against swift-nio-ssl.") + assertionFailure( + "\(#function) looped too many times, please file a GitHub issue against swift-nio-ssl." + ) throw NIOSSLExtraError.noForwardProgress } } catch { @@ -991,7 +994,7 @@ extension NIOSSLHandler { channelClose(context: context, reason: error) // Fail any writes we've previously encoded but not flushed. - promises.forEach { $0.fail(error) } + for promise in promises { promise.fail(error) } // Fail close output promise if present let closeOutputPromise = self.closeOutputPromise @@ -1021,10 +1024,10 @@ extension NIOSSLHandler { } } -fileprivate extension Array where Element == EventLoopPromise { +extension Array where Element == EventLoopPromise { /// Given an array of promises, flattens it out to a single promise. /// If the array is empty, returns nil. - func flattenPromises(on loop: EventLoop) -> EventLoopPromise? { + fileprivate func flattenPromises(on loop: EventLoop) -> EventLoopPromise? { guard self.count > 0 else { return nil } @@ -1037,9 +1040,9 @@ fileprivate extension Array where Element == EventLoopPromise { ourPromise.futureResult.whenComplete { result in switch result { case .success: - self.forEach { $0.succeed(()) } + for result in self { result.succeed(()) } case .failure(let error): - self.forEach { $0.fail(error) } + for result in self { result.fail(error) } } } @@ -1047,7 +1050,6 @@ fileprivate extension Array where Element == EventLoopPromise { } } - // MARK:- Code for handling asynchronous handshake resumption. extension NIOSSLHandler { internal func resumeHandshake() { diff --git a/Sources/NIOSSL/NIOSSLServerHandler.swift b/Sources/NIOSSL/NIOSSLServerHandler.swift index e0602d30f..a5bc44fb0 100644 --- a/Sources/NIOSSL/NIOSSLServerHandler.swift +++ b/Sources/NIOSSL/NIOSSLServerHandler.swift @@ -23,7 +23,11 @@ public final class NIOSSLServerHandler: NIOSSLHandler { /// - parameters: /// - context: The ``NIOSSLContext`` to use on this connection. public convenience init(context: NIOSSLContext) { - self.init(context: context, optionalCustomVerificationCallback: nil, optionalAdditionalPeerCertificateVerificationCallback: nil) + self.init( + context: context, + optionalCustomVerificationCallback: nil, + optionalAdditionalPeerCertificateVerificationCallback: nil + ) } @available(*, deprecated, renamed: "init(context:customVerificationCallback:)") @@ -55,8 +59,15 @@ public final class NIOSSLServerHandler: NIOSSLHandler { /// /// If set, this callback is provided the certificates presented by the peer. NIOSSL will not have pre-processed them. The callback will not be used if the /// ``TLSConfiguration`` that was used to construct the ``NIOSSLContext`` has ``TLSConfiguration/certificateVerification`` set to ``CertificateVerification/none``. - public convenience init(context: NIOSSLContext, customVerificationCallback: @escaping NIOSSLCustomVerificationCallback) { - self.init(context: context, optionalCustomVerificationCallback: customVerificationCallback, optionalAdditionalPeerCertificateVerificationCallback: nil) + public convenience init( + context: NIOSSLContext, + customVerificationCallback: @escaping NIOSSLCustomVerificationCallback + ) { + self.init( + context: context, + optionalCustomVerificationCallback: customVerificationCallback, + optionalAdditionalPeerCertificateVerificationCallback: nil + ) } /// Construct a new ``NIOSSLClientHandler`` with the given `context` and a specific `serverHostname`. @@ -68,7 +79,11 @@ public final class NIOSSLServerHandler: NIOSSLHandler { /// If set, this callback is provided the certificates presented by the peer. NIOSSL will not have pre-processed them. The callback will not be used if the /// ``TLSConfiguration`` that was used to construct the ``NIOSSLContext`` has ``TLSConfiguration/certificateVerification`` set to ``CertificateVerification/none``. /// - configuration: Configuration for this handler. - public convenience init(context: NIOSSLContext, customVerificationCallback: NIOSSLCustomVerificationCallback? = nil, configuration: Configuration) { + public convenience init( + context: NIOSSLContext, + customVerificationCallback: NIOSSLCustomVerificationCallback? = nil, + configuration: Configuration + ) { self.init( context: context, optionalCustomVerificationCallback: customVerificationCallback, @@ -82,7 +97,11 @@ public final class NIOSSLServerHandler: NIOSSLHandler { context: NIOSSLContext, additionalPeerCertificateVerificationCallback: @escaping _NIOAdditionalPeerCertificateVerificationCallback ) -> Self { - .init(context: context, optionalCustomVerificationCallback: nil, optionalAdditionalPeerCertificateVerificationCallback: additionalPeerCertificateVerificationCallback) + .init( + context: context, + optionalCustomVerificationCallback: nil, + optionalAdditionalPeerCertificateVerificationCallback: additionalPeerCertificateVerificationCallback + ) } /// This exists to handle the explosion of initializers I got when I deprecated the first one. diff --git a/Sources/NIOSSL/ObjectIdentifier.swift b/Sources/NIOSSL/ObjectIdentifier.swift index 9c92b9aba..96b28ce71 100644 --- a/Sources/NIOSSL/ObjectIdentifier.swift +++ b/Sources/NIOSSL/ObjectIdentifier.swift @@ -20,27 +20,27 @@ public struct NIOSSLObjectIdentifier { private enum Storage { final class Deallocator { var reference: OpaquePointer! - + init(takeOwnershipOf reference: OpaquePointer!) { self.reference = reference } - + deinit { CNIOBoringSSL_ASN1_OBJECT_free(self.reference) } } - + case owned(Deallocator) case borrowed(reference: OpaquePointer!, owner: AnyObject) - + init(takeOwnershipOf reference: OpaquePointer!) { self = .owned(.init(takeOwnershipOf: reference)) } - + init(borrowing reference: OpaquePointer!, owner: AnyObject) { self = .borrowed(reference: reference, owner: owner) } - + /// All operations accessing `reference` need to be implemented while guaranteeing that we still have a reference to the memory owner. /// Otherwise `reference` could already be freed. This would result in undefined behaviour as we access a dangling pointer. /// This method guarantees that `reference` is valid during execution of `body`. @@ -57,9 +57,9 @@ public struct NIOSSLObjectIdentifier { } } } - + private let storage: Storage - + /// Creates a Object Identifier (OID) from its textual dotted representation (e.g. `1.2.3`) /// /// - Parameter string: textual dotted representation of an OID @@ -76,15 +76,15 @@ public struct NIOSSLObjectIdentifier { } self.storage = .init(takeOwnershipOf: reference) } - + /// Creates an Object Identifier (OID) from an OpenSSL reference. - /// + /// /// - Note: initialising an ``NIOSSLObjectIdentifier`` takes ownership of the reference and will free it after the reference count drops to zero /// - Parameter reference: reference to a valid OpenSSL OID aka OBJ internal init(takingOwnershipOf reference: OpaquePointer!) { self.storage = .init(takeOwnershipOf: reference) } - + /// Creates an Object Identifier (OID) from an OpenSSL reference. /// - Note: initialising an ``NIOSSLObjectIdentifier`` with *this* constructor does **not** take ownership of the memory. Instead ``NIOSSLObjectIdentifier`` keeps a reference to the owning object which it will retain for the lifetime of itself. /// - Parameters @@ -93,7 +93,7 @@ public struct NIOSSLObjectIdentifier { internal init(borrowing reference: OpaquePointer!, owner: AnyObject) { self.storage = .init(borrowing: reference, owner: owner) } - + /// Creates a copy of an Object Identifier (OID) from an OpenSSL reference /// - Parameter reference: reference to a valid OpenSSL OID aka OBJ internal init(copyOf reference: OpaquePointer!) { diff --git a/Sources/NIOSSL/PosixPort.swift b/Sources/NIOSSL/PosixPort.swift index 2000a8011..34fdd7b63 100644 --- a/Sources/NIOSSL/PosixPort.swift +++ b/Sources/NIOSSL/PosixPort.swift @@ -12,6 +12,8 @@ // //===----------------------------------------------------------------------===// +import NIOCore + // This file contains a version of the SwiftNIO Posix enum. This is necessary // because SwiftNIO's version is internal. Our version exists for the same reason: // to ensure errno is captured correctly when doing syscalls, and that no ARC traffic @@ -32,8 +34,6 @@ import Android #error("unsupported os") #endif -import NIOCore - #if os(Android) internal typealias FILEPointer = OpaquePointer #else @@ -58,9 +58,10 @@ private func isUnacceptableErrno(_ code: CInt) -> Bool { } } -/* Sorry, we really try hard to not use underscored attributes. In this case however we seem to break the inlining threshold which makes a system call take twice the time, ie. we need this exception. */ +// Sorry, we really try hard to not use underscored attributes. In this case however we seem to break the inlining threshold which makes a system call take twice the time, ie. we need this exception. @inline(__always) -internal func wrapSyscall(where function: String = #function, _ body: () throws -> T) throws -> T { +internal func wrapSyscall(where function: String = #function, _ body: () throws -> T) throws -> T +{ while true { let res = try body() if res == -1 { @@ -75,9 +76,12 @@ internal func wrapSyscall(where function: String = #functi } } -/* Sorry, we really try hard to not use underscored attributes. In this case however we seem to break the inlining threshold which makes a system call take twice the time, ie. we need this exception. */ +// Sorry, we really try hard to not use underscored attributes. In this case however we seem to break the inlining threshold which makes a system call take twice the time, ie. we need this exception. @inline(__always) -internal func wrapErrorIsNullReturnCall(errorReason: @autoclosure () -> String = #function, _ body: () throws -> T?) throws -> T { +internal func wrapErrorIsNullReturnCall( + errorReason: @autoclosure () -> String = #function, + _ body: () throws -> T? +) throws -> T { while true { guard let res = try body() else { let err = errno @@ -104,14 +108,18 @@ internal enum Posix { @inline(never) internal static func fclose(file: FILEPointer) throws -> CInt { - return try wrapSyscall { + try wrapSyscall { sysFclose(file) } } - + @inline(never) - internal static func readlink(path: UnsafePointer, buf: UnsafeMutablePointer, bufSize: Int) throws -> Int { - return try wrapSyscall { + internal static func readlink( + path: UnsafePointer, + buf: UnsafeMutablePointer, + bufSize: Int + ) throws -> Int { + try wrapSyscall { sysReadlink(path, buf, bufSize) } } @@ -119,15 +127,15 @@ internal enum Posix { @inline(never) @discardableResult internal static func stat(path: UnsafePointer, buf: UnsafeMutablePointer) throws -> CInt { - return try wrapSyscall { + try wrapSyscall { sysStat(path, buf) } } - + @inline(never) @discardableResult internal static func lstat(path: UnsafePointer, buf: UnsafeMutablePointer) throws -> Int32 { - return try wrapSyscall { + try wrapSyscall { sysLstat(path, buf) } } @@ -135,7 +143,7 @@ internal enum Posix { @inline(never) @discardableResult internal static func mlock(addr: UnsafeRawPointer, len: size_t) throws -> CInt { - return try wrapSyscall { + try wrapSyscall { sysMlock(addr, len) } } @@ -143,7 +151,7 @@ internal enum Posix { @inline(never) @discardableResult internal static func munlock(addr: UnsafeRawPointer, len: size_t) throws -> CInt { - return try wrapSyscall { + try wrapSyscall { sysMunlock(addr, len) } } diff --git a/Sources/NIOSSL/SSLCallbacks.swift b/Sources/NIOSSL/SSLCallbacks.swift index e006d67c5..1995f9788 100644 --- a/Sources/NIOSSL/SSLCallbacks.swift +++ b/Sources/NIOSSL/SSLCallbacks.swift @@ -72,7 +72,6 @@ public enum NIOSSLVerificationResult: Sendable { /// and also supports asynchronous certificate verification. public typealias NIOSSLVerificationCallback = (NIOSSLVerificationResult, NIOSSLCertificate) -> NIOSSLVerificationResult - /// A custom verification callback that allows completely overriding the certificate verification logic of BoringSSL. /// /// This verification callback is called no more than once per connection attempt. It is invoked with two arguments: @@ -91,7 +90,8 @@ public typealias NIOSSLVerificationCallback = (NIOSSLVerificationResult, NIOSSLC /// as this will not be re-entrant. /// /// Note that setting this callback will override _all_ verification logic that BoringSSL provides. -public typealias NIOSSLCustomVerificationCallback = ([NIOSSLCertificate], EventLoopPromise) -> Void +public typealias NIOSSLCustomVerificationCallback = ([NIOSSLCertificate], EventLoopPromise) -> + Void /// A custom verification callback that allows additional peer certificate verification logic after the logic of BoringSSL has completed successfully. /// @@ -102,8 +102,9 @@ public typealias NIOSSLCustomVerificationCallback = ([NIOSSLCertificate], EventL /// The handshake will only succeed if the returned promise completes successfully. /// /// - warning: This API is not guaranteed to be stable and is likely to be changed without further notice, hence the underscore prefix. -public typealias _NIOAdditionalPeerCertificateVerificationCallback = (NIOSSLCertificate, Channel) -> EventLoopFuture - +public typealias _NIOAdditionalPeerCertificateVerificationCallback = (NIOSSLCertificate, Channel) -> EventLoopFuture< + Void +> /// A callback that can be used to implement `SSLKEYLOGFILE` support. /// @@ -120,7 +121,6 @@ public typealias _NIOAdditionalPeerCertificateVerificationCallback = (NIOSSLCert /// public typealias NIOSSLKeyLogCallback = @Sendable (ByteBuffer) -> Void - /// An object that provides helpers for working with a NIOSSLKeyLogCallback internal struct KeyLogCallbackManager { private var callback: NIOSSLKeyLogCallback @@ -262,7 +262,9 @@ extension NIOSSLContextConfigurationOverride { /// Within this callback, the user can create and return a new `NIOSSLContextConfigurationOverride` for the given host, /// and the delta will be applied to the current handshake configuration. /// -public typealias NIOSSLContextCallback = @Sendable (NIOSSLClientExtensionValues, EventLoopPromise) -> Void +public typealias NIOSSLContextCallback = @Sendable ( + NIOSSLClientExtensionValues, EventLoopPromise +) -> Void /// A struct that provides helpers for working with a NIOSSLContextCallback. internal struct CustomContextManager: Sendable { @@ -311,10 +313,12 @@ extension CustomContextManager { let connection = SSLConnection.loadConnectionFromSSL(ssl) guard let eventLoop = connection.eventLoop else { - preconditionFailure(""" - SSL_CTX_set_cert_cb was executed without an event loop assigned to the connection. - This should not be possible, please file an issue. - """) + preconditionFailure( + """ + SSL_CTX_set_cert_cb was executed without an event loop assigned to the connection. + This should not be possible, please file an issue. + """ + ) } // Construct extension values to be passed to callback @@ -403,7 +407,6 @@ internal struct CustomVerifyManager { } } - extension CustomVerifyManager { private enum PendingResult: Hashable { case notStarted @@ -414,7 +417,6 @@ extension CustomVerifyManager { } } - extension CustomVerifyManager { mutating func process(on connection: SSLConnection) -> ssl_verify_result_t { // First, check if we have a result. @@ -450,7 +452,10 @@ extension CustomVerifyManager { eventLoop.execute { // Note that we don't close over self here: that's to deal with the fact that this is a struct, and we don't want to // escape the mutable ownership of self. - precondition(connection.customVerificationManager == nil || connection.customVerificationManager?.result == .some(.pendingResult)) + precondition( + connection.customVerificationManager == nil + || connection.customVerificationManager?.result == .some(.pendingResult) + ) connection.customVerificationManager?.result = .complete(NIOSSLVerificationResult(result)) connection.parentHandler?.resumeHandshake() } @@ -462,7 +467,6 @@ extension CustomVerifyManager { } } - extension CustomVerifyManager { private enum CallbackType { case `public`(NIOSSLCustomVerificationCallback) @@ -489,7 +493,6 @@ extension CustomVerifyManager { internal typealias InternalCallback = (EventLoopPromise) -> Void } - extension NIOSSLVerificationResult { init(_ result: Result) { switch result { diff --git a/Sources/NIOSSL/SSLCertificate.swift b/Sources/NIOSSL/SSLCertificate.swift index 97efa29f7..262718616 100644 --- a/Sources/NIOSSL/SSLCertificate.swift +++ b/Sources/NIOSSL/SSLCertificate.swift @@ -45,16 +45,18 @@ import struct Glibc.time_t /// bytes or from a file path. public final class NIOSSLCertificate { @usableFromInline - internal let _ref: OpaquePointer/**/ + internal let _ref: OpaquePointer // @inlinable - internal func withUnsafeMutableX509Pointer(_ body: (OpaquePointer) throws -> ResultType) rethrows -> ResultType { - return try body(self._ref) + internal func withUnsafeMutableX509Pointer( + _ body: (OpaquePointer) throws -> ResultType + ) rethrows -> ResultType { + try body(self._ref) } // Internal to this class we can just access the ref directly. private var ref: OpaquePointer { - return self._ref + self._ref } /// The serial number of this certificate, as raw bytes. @@ -101,7 +103,7 @@ public final class NIOSSLCertificate { /// /// - SeeAlso: `NIOSSLCertificate.init(bytes:format:)` @available(*, deprecated, renamed: "NIOSSLCertificate.init(bytes:format:)") - public convenience init(buffer: [Int8], format: NIOSSLSerializationFormats) throws { + public convenience init(buffer: [Int8], format: NIOSSLSerializationFormats) throws { try self.init(bytes: buffer.map(UInt8.init), format: format) } @@ -174,7 +176,7 @@ public final class NIOSSLCertificate { /// In general, however, this function should be avoided in favour of one of the convenience /// initializers, which ensure that the lifetime of the `X509` object is better-managed. static func fromUnsafePointer(takingOwnership pointer: OpaquePointer) -> NIOSSLCertificate { - return NIOSSLCertificate(withOwnedReference: pointer) + NIOSSLCertificate(withOwnedReference: pointer) } /// Get a collection of the alternative names in the certificate. @@ -182,12 +184,12 @@ public final class NIOSSLCertificate { let sanExtension = CNIOBoringSSL_X509_get_ext_d2i(self.ref, NID_subject_alt_name, nil, nil) return _SubjectAlternativeNames(nameStack: sanExtension.map(OpaquePointer.init)) } - + /// Extracts the SHA1 hash of the subject name before it has been truncated. /// /// - returns: Numeric hash of the subject name. internal func getSubjectNameHash() -> UInt32 { - return CNIOBoringSSL_X509_subject_name_hash(self.ref) + CNIOBoringSSL_X509_subject_name_hash(self.ref) } /// Returns the commonName field in the Subject of this certificate. @@ -216,7 +218,11 @@ public final class NIOSSLCertificate { } // This is very unlikely, but it could happen. - guard let nameData = CNIOBoringSSL_X509_NAME_ENTRY_get_data(CNIOBoringSSL_X509_NAME_get_entry(subjectName, lastIndex)) else { + guard + let nameData = CNIOBoringSSL_X509_NAME_ENTRY_get_data( + CNIOBoringSSL_X509_NAME_get_entry(subjectName, lastIndex) + ) + else { return nil } @@ -266,7 +272,7 @@ extension NIOSSLCertificate { /// - returns: The DER-encoded bytes for this certificate. /// - throws: If an error occurred while serializing the certificate. public func toDERBytes() throws -> [UInt8] { - return try self.withUnsafeDERCertificateBuffer { Array($0) } + try self.withUnsafeDERCertificateBuffer { Array($0) } } /// Create an array of ``NIOSSLCertificate``s from a buffer of bytes in PEM format. @@ -276,7 +282,7 @@ extension NIOSSLCertificate { /// - SeeAlso: `NIOSSLCertificate.fromPEMBytes(_:)` @available(*, deprecated, renamed: "NIOSSLCertificate.fromPEMBytes(_:)") public class func fromPEMBuffer(_ buffer: [Int8]) throws -> [NIOSSLCertificate] { - return try fromPEMBytes(buffer.map(UInt8.init)) + try fromPEMBytes(buffer.map(UInt8.init)) } /// Create an array of ``NIOSSLCertificate``s from a buffer of bytes in PEM format. @@ -301,7 +307,7 @@ extension NIOSSLCertificate { /// Create an array of ``NIOSSLCertificate``s from a file at a given path in PEM format. /// - /// - Parameter file: The PEM file to read certificates from. + /// - Parameter path: The PEM file to read certificates from. /// - Throws: If an error is encountered while reading certificates. public class func fromPEMFile(_ path: String) throws -> [NIOSSLCertificate] { CNIOBoringSSL_ERR_clear_error() @@ -356,7 +362,9 @@ extension NIOSSLCertificate { let err = CNIOBoringSSL_ERR_peek_error() // If we hit the end of the file then it's not a real error, we just read as much as we could. - if CNIOBoringSSLShims_ERR_GET_LIB(err) == ERR_LIB_PEM && CNIOBoringSSLShims_ERR_GET_REASON(err) == PEM_R_NO_START_LINE { + if CNIOBoringSSLShims_ERR_GET_LIB(err) == ERR_LIB_PEM + && CNIOBoringSSLShims_ERR_GET_REASON(err) == PEM_R_NO_START_LINE + { CNIOBoringSSL_ERR_clear_error() } else { throw NIOSSLError.failedToLoadCertificate @@ -397,12 +405,11 @@ extension NIOSSLCertificate { } extension NIOSSLCertificate: Equatable { - public static func ==(lhs: NIOSSLCertificate, rhs: NIOSSLCertificate) -> Bool { - return CNIOBoringSSL_X509_cmp(lhs.ref, rhs.ref) == 0 + public static func == (lhs: NIOSSLCertificate, rhs: NIOSSLCertificate) -> Bool { + CNIOBoringSSL_X509_cmp(lhs.ref, rhs.ref) == 0 } } - extension NIOSSLCertificate: Hashable { public func hash(into hasher: inout Hasher) { // We just hash the DER bytes of the cert. If we can't get the bytes, this is a fatal error as @@ -413,7 +420,7 @@ extension NIOSSLCertificate: Hashable { } extension NIOSSLCertificate: CustomStringConvertible { - + public var description: String { let serialNumber = self.serialNumber.map { String($0, radix: 16) }.reduce("", +) var desc = "" } - + } extension UnsafePointer where Pointee == ASN1_TIME { diff --git a/Sources/NIOSSL/SSLCertificateExtensions.swift b/Sources/NIOSSL/SSLCertificateExtensions.swift index 394cac53a..18b98ee03 100644 --- a/Sources/NIOSSL/SSLCertificateExtensions.swift +++ b/Sources/NIOSSL/SSLCertificateExtensions.swift @@ -22,31 +22,31 @@ extension NIOSSLCertificate { /// `reference` is optional because `CNIOBoringSSL_X509_get0_extensions` can return`nil` if no extensions are present. /// We therefore need to handle the `nil` case as if this collection is empty. let reference: OpaquePointer? - + init(takeOwnershipOf reference: OpaquePointer?) { self.reference = reference } - + deinit { if let reference = self.reference { CNIOBoringSSL_sk_X509_EXTENSION_free(reference) } } } - + case owned(Deallocator) /// `reference` is optional because `CNIOBoringSSL_X509_get0_extensions` can return`nil` if no extensions are present. /// We therefore need to handle the `nil` case as if this collection is empty. case borrowed(reference: OpaquePointer?, owner: AnyObject) - + init(takeOwnershipOf reference: OpaquePointer?) { self = .owned(.init(takeOwnershipOf: reference)) } - + init(borrowing reference: OpaquePointer?, owner: AnyObject) { self = .borrowed(reference: reference, owner: owner) } - + /// The owner of the memory to which the reference points var owner: AnyObject { switch self { @@ -56,7 +56,7 @@ extension NIOSSLCertificate { return owner } } - + /// All operations accessing `reference` need to be implemented while guaranteeing that we still have a reference to the memory owner. /// Otherwise `reference` could already be freed. This would result in undefined behaviour as we access a dangling pointer. /// This method guarantees that `reference` is valid during execution of `body`. @@ -73,10 +73,10 @@ extension NIOSSLCertificate { } } } - + @usableFromInline internal let stackSize: Int private let storage: Storage - + internal init(takeOwnershipOf reference: OpaquePointer?) { self.storage = .init(takeOwnershipOf: reference) if let reference = reference { @@ -85,7 +85,7 @@ extension NIOSSLCertificate { self.stackSize = 0 } } - + internal init(borrowing reference: OpaquePointer?, owner: AnyObject) { self.storage = .init(borrowing: reference, owner: owner) if let reference = reference { @@ -114,7 +114,7 @@ extension NIOSSLCertificate._Extensions: RandomAccessCollection { return .init(borrowing: value, owner: self.storage.owner) } } - + @inlinable public var startIndex: Int { 0 } @inlinable public var endIndex: Int { self.stackSize } } @@ -125,13 +125,13 @@ extension NIOSSLCertificate { self.owner = owner self._reference = reference } - + /// lifetime automatically managed by `owner` private let _reference: OpaquePointer - + /// only part of this type to keep a strong reference to the underlying storage of `reference` private let owner: AnyObject - + /// All operations accessing `reference` need to be implemented while guaranteeing that we still have a reference to the memory `owner`. /// Otherwise `reference` could already be freed. This would result in undefined behaviour as we access a dangling pointer. /// This method guarantees that `reference` is valid during execution of `body`. @@ -142,19 +142,19 @@ extension NIOSSLCertificate { try body(self._reference) } } - + public var objectIdentifier: NIOSSLObjectIdentifier { withReference { .init(borrowing: CNIOBoringSSL_X509_EXTENSION_get_object($0), owner: self.owner) } } - + public var isCritical: Bool { withReference { CNIOBoringSSL_X509_EXTENSION_get_critical($0) == 1 } } - + public var data: Data { withReference { let data = CNIOBoringSSL_X509_EXTENSION_get_data($0) @@ -177,12 +177,12 @@ extension NIOSSLCertificate._Extension { private let owner: AnyObject // lifetime automatically managed by `owner` @usableFromInline internal let buffer: UnsafeBufferPointer - + internal init(buffer: UnsafeBufferPointer, owner: AnyObject) { self.buffer = buffer self.owner = owner } - + @inlinable public func withUnsafeBufferPointer( _ body: (UnsafeBufferPointer) throws -> Result ) rethrows -> Result { @@ -206,12 +206,12 @@ extension NIOSSLCertificate._Extension.Data: @unchecked Sendable {} extension NIOSSLCertificate._Extension.Data: RandomAccessCollection { @inlinable public var startIndex: Int { self.buffer.startIndex } @inlinable public var endIndex: Int { self.buffer.endIndex } - + @inlinable public subscript(position: Int) -> UInt8 { precondition(self.indices.contains(position), "index \(position) out of bounds") return withUnsafeBufferPointer { $0[position] } } - + @inlinable public func withContiguousStorageIfAvailable( _ body: (UnsafeBufferPointer) throws -> Result ) rethrows -> Result? { diff --git a/Sources/NIOSSL/SSLConnection.swift b/Sources/NIOSSL/SSLConnection.swift index 77f3094a2..fca85a969 100644 --- a/Sources/NIOSSL/SSLConnection.swift +++ b/Sources/NIOSSL/SSLConnection.swift @@ -12,8 +12,8 @@ // //===----------------------------------------------------------------------===// -import NIOCore @_implementationOnly import CNIOBoringSSL +import NIOCore internal let SSL_MAX_RECORD_SIZE = 16 * 1024 @@ -72,7 +72,7 @@ internal final class SSLConnection { self.setRenegotiationSupport(self.parentContext.configuration.renegotiationSupport) } - + deinit { CNIOBoringSSL_SSL_free(ssl) } @@ -90,7 +90,10 @@ internal final class SSLConnection { } func setAllocator(_ allocator: ByteBufferAllocator, maximumPreservedOutboundBufferCapacity: Int) { - self.bio = ByteBufferBIO(allocator: allocator, maximumPreservedOutboundBufferCapacity: maximumPreservedOutboundBufferCapacity) + self.bio = ByteBufferBIO( + allocator: allocator, + maximumPreservedOutboundBufferCapacity: maximumPreservedOutboundBufferCapacity + ) // This weird dance where we pass the *exact same* pointer in to both objects is because, weirdly, // the BoringSSL docs claim that only one reference count will be consumed here. We therefore need to @@ -107,7 +110,7 @@ internal final class SSLConnection { func setServerName(name: String) throws { CNIOBoringSSL_ERR_clear_error() let rc = name.withCString { - return CNIOBoringSSL_SSL_set_tlsext_host_name(ssl, $0) + CNIOBoringSSL_SSL_set_tlsext_host_name(ssl, $0) } guard rc == 1 else { throw BoringSSLError.invalidSNIName(BoringSSLError.buildErrorStack()) @@ -129,7 +132,9 @@ internal final class SSLConnection { CNIOBoringSSL_SSL_set_verify(self.ssl, currentMode) { preverify, storeContext in // To start out, let's grab the certificate we're operating on. guard let certPointer = CNIOBoringSSL_X509_STORE_CTX_get_current_cert(storeContext) else { - preconditionFailure("Can only have verification function invoked with actual certificate: bad store \(String(describing: storeContext))") + preconditionFailure( + "Can only have verification function invoked with actual certificate: bad store \(String(describing: storeContext))" + ) } CNIOBoringSSL_X509_up_ref(certPointer) let cert = NIOSSLCertificate.fromUnsafePointer(takingOwnership: certPointer) @@ -138,7 +143,12 @@ internal final class SSLConnection { let verificationResult = NIOSSLVerificationResult(fromBoringSSLPreverify: preverify) // Now, grab the SSLConnection object. - guard let ssl = CNIOBoringSSL_X509_STORE_CTX_get_ex_data(storeContext, CNIOBoringSSL_SSL_get_ex_data_X509_STORE_CTX_idx()) else { + guard + let ssl = CNIOBoringSSL_X509_STORE_CTX_get_ex_data( + storeContext, + CNIOBoringSSL_SSL_get_ex_data_X509_STORE_CTX_idx() + ) + else { preconditionFailure("Unable to obtain SSL * from X509_STORE_CTX * \(String(describing: storeContext))") } let connection = SSLConnection.loadConnectionFromSSL(OpaquePointer(ssl)) @@ -163,7 +173,9 @@ internal final class SSLConnection { let currentMode = CNIOBoringSSL_SSL_get_verify_mode(self.ssl) CNIOBoringSSL_SSL_set_custom_verify(self.ssl, currentMode) { ssl, outAlert in guard let unwrappedSSL = ssl else { - preconditionFailure("Unexpected null pointer in custom verification callback. ssl: \(String(describing: ssl))") + preconditionFailure( + "Unexpected null pointer in custom verification callback. ssl: \(String(describing: ssl))" + ) } // Ok, this call may be a resumption of a previous negotiation. We need to check if our connection object has a pre-existing verifiation state. @@ -197,9 +209,13 @@ internal final class SSLConnection { throw NIOSSLError.noCertificateToValidate } - guard try validIdentityForService(serverHostname: self.expectedHostname, - socketAddress: address, - leafCertificate: peerCert) else { + guard + try validIdentityForService( + serverHostname: self.expectedHostname, + socketAddress: address, + leafCertificate: peerCert + ) + else { throw NIOSSLExtraError.failedToValidateHostname(expectedName: self.expectedHostname ?? "") } } @@ -214,19 +230,19 @@ internal final class SSLConnection { func doHandshake() -> AsyncOperationResult { CNIOBoringSSL_ERR_clear_error() let rc = CNIOBoringSSL_SSL_do_handshake(ssl) - + if rc == 1 { return .complete(rc) } let result = CNIOBoringSSL_SSL_get_error(ssl, rc) let error = BoringSSLError.fromSSLGetErrorResult(result)! - + switch error { case .wantRead, - .wantWrite, - .wantCertificateVerify, - .wantX509Lookup: + .wantWrite, + .wantCertificateVerify, + .wantX509Lookup: return .incomplete default: return .failed(error) @@ -243,7 +259,7 @@ internal final class SSLConnection { func doShutdown() -> AsyncOperationResult { CNIOBoringSSL_ERR_clear_error() let rc = CNIOBoringSSL_SSL_shutdown(ssl) - + switch rc { case 1: return .complete(rc) @@ -252,17 +268,17 @@ internal final class SSLConnection { default: let result = CNIOBoringSSL_SSL_get_error(ssl, rc) let error = BoringSSLError.fromSSLGetErrorResult(result)! - + switch error { case .wantRead, - .wantWrite: + .wantWrite: return .incomplete default: return .failed(error) } } } - + /// Given some unprocessed data from the remote peer, places it into /// BoringSSL's receive buffer ready for handling by BoringSSL. /// @@ -283,7 +299,7 @@ internal final class SSLConnection { /// Returns `nil` if there is no data to write. Otherwise, returns all of the pending /// data. func getDataForNetwork() -> ByteBuffer? { - return self.bio!.outboundCiphertext() + self.bio!.outboundCiphertext() } /// Attempts to decrypt any application data sent by the remote peer, and fills a buffer @@ -299,23 +315,24 @@ internal final class SSLConnection { // // We require that there is space to write at least one TLS record. var bytesRead: CInt = 0 - let rc = outputBuffer.writeWithUnsafeMutableBytes(minimumWritableBytes: SSL_MAX_RECORD_SIZE) { (pointer) -> Int in + let rc = outputBuffer.writeWithUnsafeMutableBytes(minimumWritableBytes: SSL_MAX_RECORD_SIZE) { + (pointer) -> Int in // We ask for the amount of spare space in the buffer, clamping to CInt.max. let maxReadSize = Int(CInt.max) let readSize = CInt(min(maxReadSize, pointer.count)) bytesRead = CNIOBoringSSL_SSL_read(self.ssl, pointer.baseAddress, readSize) return bytesRead >= 0 ? Int(bytesRead) : 0 } - + if bytesRead > 0 { return .complete(rc) } else { let result = CNIOBoringSSL_SSL_get_error(ssl, CInt(bytesRead)) let error = BoringSSLError.fromSSLGetErrorResult(result)! - + switch error { case .wantRead, - .wantWrite: + .wantWrite: return .incomplete default: return .failed(error) @@ -335,9 +352,9 @@ internal final class SSLConnection { } let writtenBytes = data.withUnsafeReadableBytes { (pointer) -> CInt in - return CNIOBoringSSL_SSL_write(ssl, pointer.baseAddress, CInt(pointer.count)) + CNIOBoringSSL_SSL_write(ssl, pointer.baseAddress, CInt(pointer.count)) } - + if writtenBytes > 0 { // The default behaviour of SSL_write is to only return once *all* of the data has been written, // unless the underlying BIO cannot satisfy the need (in which case WANT_WRITE will be returned). @@ -349,7 +366,7 @@ internal final class SSLConnection { } else { let result = CNIOBoringSSL_SSL_get_error(ssl, writtenBytes) let error = BoringSSLError.fromSSLGetErrorResult(result)! - + switch error { case .wantRead, .wantWrite: return .incomplete @@ -411,20 +428,20 @@ internal final class SSLConnection { /// /// - returns: The unconsumed `ByteBuffer`, if any. func extractUnconsumedData() -> ByteBuffer? { - return self.bio?.evacuateInboundData() + self.bio?.evacuateInboundData() } - + /// Returns an optional `TLSVersion` used on a `Channel` through the `NIOSSLHandler` APIs. func getTLSVersionForConnection() -> TLSVersion? { let uint16Version = CNIOBoringSSL_SSL_version(self.ssl) switch uint16Version { - case TLS1_3_VERSION: + case TLS1_3_VERSION: return .tlsv13 - case TLS1_2_VERSION: + case TLS1_2_VERSION: return .tlsv12 - case TLS1_1_VERSION: + case TLS1_1_VERSION: return .tlsv11 - case TLS1_VERSION: + case TLS1_VERSION: return .tlsv1 default: return nil @@ -432,7 +449,6 @@ internal final class SSLConnection { } } - /// MARK: ConnectionRole extension SSLConnection { internal enum ConnectionRole { @@ -441,7 +457,6 @@ extension SSLConnection { } } - // MARK: Certificate Peer Chain Buffers extension SSLConnection { /// A collection of buffers representing the DER-encoded bytes of the peer certificate chain. @@ -460,7 +475,9 @@ extension SSLConnection { /// bytes synchronously within the block, or they must copy them to a new buffer that they own. /// /// If there are no peer certificates, the body will be called with nil. - func withPeerCertificateChainBuffers(_ body: (PeerCertificateChainBuffers?) throws -> Result) rethrows -> Result { + func withPeerCertificateChainBuffers( + _ body: (PeerCertificateChainBuffers?) throws -> Result + ) rethrows -> Result { guard let stackPointer = CNIOBoringSSL_SSL_get0_peer_certificates(self.ssl) else { return try body(nil) } @@ -470,7 +487,7 @@ extension SSLConnection { /// The certificate chain presented by the peer. func peerCertificateChain() throws -> [NIOSSLCertificate] { - return try self.withPeerCertificateChainBuffers { buffers in + try self.withPeerCertificateChainBuffers { buffers in guard let buffers = buffers else { return [] } @@ -491,32 +508,36 @@ extension SSLConnection.PeerCertificateChainBuffers: RandomAccessCollection { } static func < (lhs: Index, rhs: Index) -> Bool { - return lhs.index < rhs.index + lhs.index < rhs.index } - func advanced(by n: SSLConnection.PeerCertificateChainBuffers.Index.Stride) -> SSLConnection.PeerCertificateChainBuffers.Index { + func advanced( + by n: SSLConnection.PeerCertificateChainBuffers.Index.Stride + ) -> SSLConnection.PeerCertificateChainBuffers.Index { var result = self result.index += n return result } - func distance(to other: SSLConnection.PeerCertificateChainBuffers.Index) -> SSLConnection.PeerCertificateChainBuffers.Index.Stride { - return other.index - self.index + func distance( + to other: SSLConnection.PeerCertificateChainBuffers.Index + ) -> SSLConnection.PeerCertificateChainBuffers.Index.Stride { + other.index - self.index } } typealias Element = UnsafeRawBufferPointer var startIndex: Index { - return Index(0) + Index(0) } var endIndex: Index { - return Index(self.count) + Index(self.count) } var count: Int { - return CNIOBoringSSL_sk_CRYPTO_BUFFER_num(self.basePointer) + CNIOBoringSSL_sk_CRYPTO_BUFFER_num(self.basePointer) } subscript(_ index: Index) -> UnsafeRawBufferPointer { diff --git a/Sources/NIOSSL/SSLContext.swift b/Sources/NIOSSL/SSLContext.swift index f55ba5300..d8abc54fd 100644 --- a/Sources/NIOSSL/SSLContext.swift +++ b/Sources/NIOSSL/SSLContext.swift @@ -12,9 +12,9 @@ // //===----------------------------------------------------------------------===// -import NIOCore @_implementationOnly import CNIOBoringSSL @_implementationOnly import CNIOBoringSSLShims +import NIOCore #if canImport(Darwin) import Darwin.C @@ -45,19 +45,19 @@ internal enum FileSystemObject { return nil } -#if os(Android) && arch(arm) + #if os(Android) && arch(arm) return (statObj.st_mode & UInt32(S_IFDIR)) != 0 ? .directory : .file -#else + #else return (statObj.st_mode & S_IFDIR) != 0 ? .directory : .file -#endif + #endif } } // This bizarre extension to UnsafeBufferPointer is very useful for handling ALPN identifiers. BoringSSL // likes to work with them in wire format, so rather than us decoding them we can just encode ours to // the wire format and then work with them from there. -private extension UnsafeBufferPointer where Element == UInt8 { - func locateAlpnIdentifier(identifier: UnsafeBufferPointer) -> (index: Int, length: Int)? { +extension UnsafeBufferPointer where Element == UInt8 { + fileprivate func locateAlpnIdentifier(identifier: UnsafeBufferPointer) -> (index: Int, length: Int)? { precondition(identifier.count != 0) let targetLength = Int(identifier[0]) @@ -88,12 +88,14 @@ private extension UnsafeBufferPointer where Element == UInt8 { } } -private func alpnCallback(ssl: OpaquePointer?, - out: UnsafeMutablePointer?>?, - outlen: UnsafeMutablePointer?, - in: UnsafePointer?, - inlen: UInt32, - appData: UnsafeMutableRawPointer?) -> CInt { +private func alpnCallback( + ssl: OpaquePointer?, + out: UnsafeMutablePointer?>?, + outlen: UnsafeMutablePointer?, + in: UnsafePointer?, + inlen: UInt32, + appData: UnsafeMutableRawPointer? +) -> CInt { // Perform some soundness checks. We don't want NULL pointers around here. guard let ssl = ssl, let out = out, let outlen = outlen, let `in` = `in` else { return SSL_TLSEXT_ERR_NOACK @@ -115,45 +117,49 @@ private func alpnCallback(ssl: OpaquePointer?, } /// PSK Callback for the server side context. -private func serverPSKCallback(ssl: OpaquePointer?, - identity: UnsafePointer?, - psk: UnsafeMutablePointer?, - max_psk_len: UInt32) -> UInt32 { - +private func serverPSKCallback( + ssl: OpaquePointer?, + identity: UnsafePointer?, + psk: UnsafeMutablePointer?, + max_psk_len: UInt32 +) -> UInt32 { + guard let ssl = ssl else { return 0 } // Initial implementation only supports TLS 1.2 due API support exposed from BoringSSL. // TODO (meaton) add TLS 1.3 support when available. - + let parentSwiftContext = NIOSSLContext.lookupFromRawContext(ssl: ssl) guard let serverCallback = parentSwiftContext.pskServerConfigurationCallback, - let unwrappedIdentity = identity, // Incoming identity - let strIdentity = String(validatingUTF8: unwrappedIdentity), - let outputPSK = psk // Output PSK key. - else { + let unwrappedIdentity = identity, // Incoming identity + let strIdentity = String(validatingUTF8: unwrappedIdentity), + let outputPSK = psk // Output PSK key. + else { return 0 } // Take the hint and the possible identity and pass them down to the callback to get associated PSK from callback var identityResponse: PSKServerIdentityResponse? = nil switch serverCallback { - case .callback(let callback): - // Deprecated callback doesn't accept optional hint value - guard let hint = parentSwiftContext.configuration.pskHint else { return 0 } - identityResponse = try? callback(hint, strIdentity) - case .provider(let provider): - identityResponse = try? provider(PSKServerContext( + case .callback(let callback): + // Deprecated callback doesn't accept optional hint value + guard let hint = parentSwiftContext.configuration.pskHint else { return 0 } + identityResponse = try? callback(hint, strIdentity) + case .provider(let provider): + identityResponse = try? provider( + PSKServerContext( hint: parentSwiftContext.configuration.pskHint, clientIdentity: strIdentity, maxPSKLength: Int(max_psk_len) - )) - } + ) + ) + } guard let identityResponse else { return 0 } - let serverPSK = identityResponse.key // From the callback - + let serverPSK = identityResponse.key // From the callback + // Make sure the key is returned by the callback and it is of proper length, otherwise, fail. if serverPSK.isEmpty || serverPSK.count > max_psk_len { return 0 @@ -165,56 +171,60 @@ private func serverPSKCallback(ssl: OpaquePointer?, } /// PSK Callback for the client side context. -private func clientPSKCallback(ssl: OpaquePointer?, - hint: UnsafePointer?, - identity: UnsafeMutablePointer?, - max_identity_len: UInt32, - psk: UnsafeMutablePointer?, - max_psk_len: UInt32) -> UInt32 { - +private func clientPSKCallback( + ssl: OpaquePointer?, + hint: UnsafePointer?, + identity: UnsafeMutablePointer?, + max_identity_len: UInt32, + psk: UnsafeMutablePointer?, + max_psk_len: UInt32 +) -> UInt32 { + guard let ssl = ssl else { return 0 } - + let parentSwiftContext = NIOSSLContext.lookupFromRawContext(ssl: ssl) guard let clientCallback = parentSwiftContext.pskClientConfigurationCallback, - let unwrappedIdentity = identity, // Output identity that will be later be mapped from client callback - let outputPSK = psk // Output PSK key that will later be mapped from client callback - else { + let unwrappedIdentity = identity, // Output identity that will be later be mapped from client callback + let outputPSK = psk // Output PSK key that will later be mapped from client callback + else { return 0 } - + // If set, build out a hint otherwise fallback to an empty string and pass it into the client callback. let clientHint: String? = hint.flatMap({ String(validatingUTF8: $0) }) // Take the hint and pass it down to the callback to get associated PSK from callback let pskIdentity: PSKClientIdentityResponse? switch clientCallback { - case .callback(let callback): - // Deprecated callback doesn't accept optional hint value - guard let clientHint else { return 0 } - pskIdentity = try? callback(clientHint) - case .provider(let provider): - pskIdentity = try? provider(PSKClientContext( - hint: clientHint, + case .callback(let callback): + // Deprecated callback doesn't accept optional hint value + guard let clientHint else { return 0 } + pskIdentity = try? callback(clientHint) + case .provider(let provider): + pskIdentity = try? provider( + PSKClientContext( + hint: clientHint, maxPSKLength: Int(max_psk_len) - )) + ) + ) } guard let pskIdentity else { return 0 } - - let clientPSK = pskIdentity.key // Key from the callback + + let clientPSK = pskIdentity.key // Key from the callback let clientIdentity = pskIdentity.identity - + // Use max_identity_len so it does not trigger an overrun. if clientIdentity.utf8.isEmpty || clientIdentity.utf8.count > max_identity_len { return 0 } - + // Map the output identity from the one passed back from the callback. // This helps populate the server callback for the key exchange. let _ = clientIdentity.withCString { ptr in memcpy(unwrappedIdentity, ptr, clientIdentity.utf8.count) } - + if clientPSK.isEmpty || clientPSK.count > max_psk_len { return 0 } @@ -226,17 +236,19 @@ private func clientPSKCallback(ssl: OpaquePointer?, private func sslContextCallback(ssl: OpaquePointer?, arg: UnsafeMutableRawPointer?) -> Int32 { guard let ssl = ssl else { - preconditionFailure(""" - SSL_CTX_set_cert_cb was executed with an invalid ssl pointer. - This should not be possible, please file an issue. - """) + preconditionFailure( + """ + SSL_CTX_set_cert_cb was executed with an invalid ssl pointer. + This should not be possible, please file an issue. + """ + ) } let parentSwiftContext = NIOSSLContext.lookupFromRawContext(ssl: ssl) // This is a safe force unwrap as this callback is only register directly after setting the manager var contextManager = parentSwiftContext.customContextManager! - + // Begin loading a new context let result = contextManager.loadContext(ssl: ssl) @@ -295,7 +307,9 @@ public final class NIOSSLContext { callbackManager: CallbackManagerProtocol? ) throws { guard boringSSLIsInitialized else { fatalError("Failed to initialize BoringSSL") } - guard let context = CNIOBoringSSL_SSL_CTX_new(CNIOBoringSSL_TLS_method()) else { fatalError("Failed to create new BoringSSL context") } + guard let context = CNIOBoringSSL_SSL_CTX_new(CNIOBoringSSL_TLS_method()) else { + fatalError("Failed to create new BoringSSL context") + } let minTLSVersion: CInt switch configuration.minimumTLSVersion { @@ -333,11 +347,12 @@ public final class NIOSSLContext { // Curves list. if let curves = configuration.curves { - returnCode = curves + returnCode = + curves .map { $0.rawValue } .withUnsafeBufferPointer { algo in CNIOBoringSSL_SSL_CTX_set1_group_ids(context, algo.baseAddress, algo.count) - } + } if returnCode != 1 { let errorStack = BoringSSLError.buildErrorStack() throw BoringSSLError.unknownError(errorStack) @@ -349,7 +364,7 @@ public final class NIOSSLContext { self.pskClientConfigurationCallback = pskClientConfigurationsCallback CNIOBoringSSL_SSL_CTX_set_psk_client_callback(context, clientPSKCallback) } - + // Set the PSK Server Configuration callback. if let pskServerConfigurationCallback = configuration._pskServerIdentityProvider { self.pskServerConfigurationCallback = pskServerConfigurationCallback @@ -391,28 +406,31 @@ public final class NIOSSLContext { verification: configuration.certificateVerification, trustRoots: configuration.trustRoots, additionalTrustRoots: configuration.additionalTrustRoots, - sendCANames: configuration.sendCANameList) - + sendCANames: configuration.sendCANameList + ) + // Configure verification algorithms if let verifySignatureAlgorithms = configuration.verifySignatureAlgorithms { - returnCode = verifySignatureAlgorithms + returnCode = + verifySignatureAlgorithms .map { $0.rawValue } .withUnsafeBufferPointer { algo in CNIOBoringSSL_SSL_CTX_set_verify_algorithm_prefs(context, algo.baseAddress, algo.count) - } + } if returnCode != 1 { let errorStack = BoringSSLError.buildErrorStack() throw BoringSSLError.unknownError(errorStack) } } - + // Configure signing algorithms if let signingSignatureAlgorithms = configuration.resolvedSigningSignatureAlgorithms { - returnCode = signingSignatureAlgorithms + returnCode = + signingSignatureAlgorithms .map { $0.rawValue } .withUnsafeBufferPointer { algo in CNIOBoringSSL_SSL_CTX_set_signing_algorithm_prefs(context, algo.baseAddress, algo.count) - } + } if returnCode != 1 { let errorStack = BoringSSLError.buildErrorStack() throw BoringSSLError.unknownError(errorStack) @@ -422,8 +440,14 @@ public final class NIOSSLContext { // If we were given a certificate chain to use, load it and its associated private key. Before // we do, set up a passphrase callback if we need to. if let callbackManager = callbackManager { - CNIOBoringSSL_SSL_CTX_set_default_passwd_cb(context, { globalBoringSSLPassphraseCallback(buf: $0, size: $1, rwflag: $2, u: $3) }) - CNIOBoringSSL_SSL_CTX_set_default_passwd_cb_userdata(context, Unmanaged.passUnretained(callbackManager as AnyObject).toOpaque()) + CNIOBoringSSL_SSL_CTX_set_default_passwd_cb( + context, + { globalBoringSSLPassphraseCallback(buf: $0, size: $1, rwflag: $2, u: $3) } + ) + CNIOBoringSSL_SSL_CTX_set_default_passwd_cb_userdata( + context, + Unmanaged.passUnretained(callbackManager as AnyObject).toOpaque() + ) } try NIOSSLContext.useCertificateChain(configuration.certificateChain, context: context) @@ -482,8 +506,10 @@ public final class NIOSSLContext { /// - passphraseCallback: The callback to use to decrypt any private keys used by this /// ``NIOSSLContext``. For more details on this parameter see the documentation for /// ``NIOSSLPassphraseCallback``. - public convenience init(configuration: TLSConfiguration, - passphraseCallback: @escaping NIOSSLPassphraseCallback) throws where T.Element == UInt8 { + public convenience init( + configuration: TLSConfiguration, + passphraseCallback: @escaping NIOSSLPassphraseCallback + ) throws where T.Element == UInt8 { let manager = BoringSSLPassphraseCallbackManager(userCallback: passphraseCallback) try self.init(configuration: configuration, callbackManager: manager) } @@ -501,13 +527,18 @@ public final class NIOSSLContext { #if canImport(Darwin) switch self.configuration.trustRoots { case .some(.default), .none: - conn.setCustomVerificationCallback(CustomVerifyManager(callback: { - do { - conn.performSecurityFrameworkValidation(promise: $0, peerCertificates: try conn.getPeerCertificatesAsSecCertificate()) - } catch { - $0.fail(error) - } - })) + conn.setCustomVerificationCallback( + CustomVerifyManager(callback: { + do { + conn.performSecurityFrameworkValidation( + promise: $0, + peerCertificates: try conn.getPeerCertificatesAsSecCertificate() + ) + } catch { + $0.fail(error) + } + }) + ) case .some(.certificates), .some(.file): break } @@ -516,7 +547,7 @@ public final class NIOSSLContext { return conn } - fileprivate func alpnSelectCallback(offeredProtocols: UnsafeBufferPointer) -> (index: Int, length: Int)? { + fileprivate func alpnSelectCallback(offeredProtocols: UnsafeBufferPointer) -> (index: Int, length: Int)? { for possibility in configuration.encodedApplicationProtocols { let match = possibility.withUnsafeBufferPointer { offeredProtocols.locateAlpnIdentifier(identifier: $0) @@ -548,7 +579,10 @@ extension NIOSSLContext { } extension NIOSSLContext { - fileprivate static func useCertificateChain(_ certificateChain: [NIOSSLCertificateSource], context: OpaquePointer) throws { + fileprivate static func useCertificateChain( + _ certificateChain: [NIOSSLCertificateSource], + context: OpaquePointer + ) throws { var leaf = true for source in certificateChain { switch source { @@ -570,9 +604,9 @@ extension NIOSSLContext { // TODO(cory): This shouldn't be an assert but should instead be actual error handling. // assert(path.isFileURL) let result = path.withCString { (pointer) -> CInt in - return CNIOBoringSSL_SSL_CTX_use_certificate_chain_file(context, pointer) + CNIOBoringSSL_SSL_CTX_use_certificate_chain_file(context, pointer) } - + // TODO(cory): again, some error handling would be good. precondition(result == 1) } @@ -585,7 +619,7 @@ extension NIOSSLContext { throw NIOSSLError.failedToLoadCertificate } } - + private static func addAdditionalChainCertificate(_ cert: NIOSSLCertificate, context: OpaquePointer) throws { let rc = cert.withUnsafeMutableX509Pointer { ref in CNIOBoringSSL_SSL_CTX_add1_chain_cert(context, ref) @@ -621,7 +655,7 @@ extension NIOSSLContext { private static func usePrivateKeyFile(_ path: String, context: OpaquePointer) throws { let pathExtension = path.split(separator: ".").last let fileType: CInt - + switch pathExtension?.lowercased() { case .some("pem"): fileType = SSL_FILETYPE_PEM @@ -630,16 +664,16 @@ extension NIOSSLContext { default: throw NIOSSLExtraError.unknownPrivateKeyFileType(path: path) } - + let result = path.withCString { (pointer) -> CInt in - return CNIOBoringSSL_SSL_CTX_use_PrivateKey_file(context, pointer, fileType) + CNIOBoringSSL_SSL_CTX_use_PrivateKey_file(context, pointer, fileType) } - + guard result == 1 else { throw NIOSSLError.failedToLoadPrivateKey } } - + private static func setAlpnProtocols(_ protocols: [[UInt8]], context: OpaquePointer) throws { // This copy should be done infrequently, so we don't worry too much about it. let protoBuf = protocols.reduce([UInt8](), +) @@ -657,15 +691,23 @@ extension NIOSSLContext { private static func setAlpnCallback(context: OpaquePointer) { // This extra closure here is very silly, but it exists to allow us to avoid writing down the type of the first // argument. Combined with the helper above, the compiler will be able to solve its way to success here. - CNIOBoringSSL_SSL_CTX_set_alpn_select_cb(context, - { alpnCallback(ssl: $0, out: $1, outlen: $2, in: $3, inlen: $4, appData: $5) }, - nil) + CNIOBoringSSL_SSL_CTX_set_alpn_select_cb( + context, + { alpnCallback(ssl: $0, out: $1, outlen: $2, in: $3, inlen: $4, appData: $5) }, + nil + ) } } // Configuring certificate verification extension NIOSSLContext { - private static func configureCertificateValidation(context: OpaquePointer, verification: CertificateVerification, trustRoots: NIOSSLTrustRoots?, additionalTrustRoots: [NIOSSLAdditionalTrustRoots], sendCANames: Bool) throws { + 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: @@ -694,12 +736,12 @@ extension NIOSSLContext { } } try configureTrustRoots(trustRoots: trustRoots ?? .default) - try additionalTrustRoots.forEach { try configureTrustRoots(trustRoots: .init(from: $0)) } + for root in additionalTrustRoots { try configureTrustRoots(trustRoots: .init(from: root)) } default: break } } - + private static func addCACertificateNameToList(context: OpaquePointer, certificate: NIOSSLCertificate) throws { // Adds the CA name extracted from cert to the list of CAs sent to the client when requesting a client certificate. try certificate.withUnsafeMutableX509Pointer { ref in @@ -722,7 +764,7 @@ extension NIOSSLContext { let result = path.withCString { (pointer) -> CInt in let file = !isDirectory ? pointer : nil - let directory = isDirectory ? pointer: nil + let directory = isDirectory ? pointer : nil return CNIOBoringSSL_SSL_CTX_load_verify_locations(context, file, directory) } @@ -797,39 +839,41 @@ extension NIOSSLContext { parentSwiftContext.keyLogManager!.log(linePointer) } } - + /// Takes a path and determines if the file at this path is of c_rehash format . internal static func _isRehashFormat(path: String) throws -> Bool { // Check if the element’s name matches the c_rehash symlink name format. // The links created are of the form HHHHHHHH.D, where each H is a hexadecimal character and D is a single decimal digit. let utf8PathView = path.utf8 let utf8PathSplitView = utf8PathView.split(separator: UInt8(ascii: "/")) - + // Make sure the path is at least 10 units long guard let lastPathComponent = utf8PathSplitView.last, - lastPathComponent.count == 10 else { return false } + lastPathComponent.count == 10 + else { return false } // Split into filename parts HHHHHHHH.D -> [[HHHHHHHH], [D]] let filenameParts = lastPathComponent.split(separator: UInt8(ascii: ".")) - + // Double check that the extension did not fail to cast to an integer. // Make sure that the filename is an 8 character hex based file name. guard filenameParts.count == 2, - let filename = filenameParts.first, - let fileExtension = filenameParts.last, - fileExtension.count == 1, - filename.count == 8, - filename.allSatisfy({ $0.isHexDigit }), - fileExtension.first == UInt8(ascii: "0") else { return false } - + let filename = filenameParts.first, + let fileExtension = filenameParts.last, + fileExtension.count == 1, + filename.count == 8, + filename.allSatisfy({ $0.isHexDigit }), + fileExtension.first == UInt8(ascii: "0") + else { return false } + // Check if the element is a symlink. If it is not, return false. var buffer = stat() let _ = try Posix.lstat(path: path, buf: &buffer) // Check the mode to make sure this is a symlink -#if os(Android) && arch(arm) + #if os(Android) && arch(arm) if (buffer.st_mode & UInt32(S_IFMT)) != UInt32(S_IFLNK) { return false } -#else + #else if (buffer.st_mode & S_IFMT) != S_IFLNK { return false } -#endif + #endif // Return true at this point because the file format is considered to be in rehash format and a symlink. // Rehash format being "%08lx.%d" or HHHHHHHH.D @@ -862,7 +906,9 @@ extension NIOSSLContext { /// /// The pointers are only guaranteed to be valid for the duration of this call. This method aligns with the RandomAccessCollection protocol /// to access UInt16 pointers at a specific index. This pointer is used to safely access id values of the cipher to create a new NIOTLSCipher. - fileprivate func withStackOfCipherSuiteBuffers(_ body: (NIOTLSCipherBuffers?) throws -> Result) rethrows -> Result { + fileprivate func withStackOfCipherSuiteBuffers( + _ body: (NIOTLSCipherBuffers?) throws -> Result + ) rethrows -> Result { guard let stackPointer = CNIOBoringSSL_SSL_CTX_get_ciphers(self.sslContext) else { return try body(nil) } @@ -871,7 +917,7 @@ extension NIOSSLContext { /// Access cipher suites applied to the context internal var cipherSuites: [NIOTLSCipher] { - return self.withStackOfCipherSuiteBuffers { buffers in + self.withStackOfCipherSuiteBuffers { buffers in guard let buffers = buffers else { return [] } @@ -881,7 +927,7 @@ extension NIOSSLContext { } extension NIOSSLContext.NIOTLSCipherBuffers: RandomAccessCollection { - + struct Index: Hashable, Comparable, Strideable { typealias Stride = Int @@ -892,7 +938,7 @@ extension NIOSSLContext.NIOTLSCipherBuffers: RandomAccessCollection { } static func < (lhs: Index, rhs: Index) -> Bool { - return lhs.index < rhs.index + lhs.index < rhs.index } func advanced(by n: NIOSSLContext.NIOTLSCipherBuffers.Index.Stride) -> NIOSSLContext.NIOTLSCipherBuffers.Index { @@ -901,25 +947,27 @@ extension NIOSSLContext.NIOTLSCipherBuffers: RandomAccessCollection { return result } - func distance(to other: NIOSSLContext.NIOTLSCipherBuffers.Index) -> NIOSSLContext.NIOTLSCipherBuffers.Index.Stride { - return other.index - self.index + func distance( + to other: NIOSSLContext.NIOTLSCipherBuffers.Index + ) -> NIOSSLContext.NIOTLSCipherBuffers.Index.Stride { + other.index - self.index } } typealias Element = NIOTLSCipher var startIndex: Index { - return Index(0) + Index(0) } var endIndex: Index { - return Index(self.count) + Index(self.count) } var count: Int { - return CNIOBoringSSL_sk_SSL_CIPHER_num(self.basePointer) + CNIOBoringSSL_sk_SSL_CIPHER_num(self.basePointer) } - + subscript(position: Index) -> NIOTLSCipher { precondition(position < self.endIndex) precondition(position >= self.startIndex) @@ -935,7 +983,7 @@ extension Optional where Wrapped == String { internal func withCString(_ body: (UnsafePointer?) throws -> Result) rethrows -> Result { switch self { case .some(let s): - return try s.withCString({ try body($0 ) }) + return try s.withCString({ try body($0) }) case .none: return try body(nil) } @@ -943,7 +991,7 @@ extension Optional where Wrapped == String { } internal class DirectoryContents: Sequence, IteratorProtocol { - + typealias Element = String let path: String // Used to account between the differences of DIR being defined on Darwin. @@ -953,12 +1001,12 @@ internal class DirectoryContents: Sequence, IteratorProtocol { #else let dir: OpaquePointer #endif - + init(path: String) { self.path = path self.dir = opendir(path)! } - + func next() -> String? { if let dirent: UnsafeMutablePointer = readdir(self.dir) { let name = withUnsafePointer(to: &dirent.pointee.d_name) { (ptr) -> String in @@ -971,7 +1019,7 @@ internal class DirectoryContents: Sequence, IteratorProtocol { } return nil } - + deinit { closedir(dir) } @@ -989,8 +1037,8 @@ extension UTF8.CodeUnit { var isHexDigit: Bool { switch self { case (.asciiZero)...(.asciiNine), - (.asciiLowercaseA)...(.asciiLowercaseF), - (.asciiUppercaseA)...(.asciiUppercaseF): + (.asciiLowercaseA)...(.asciiLowercaseF), + (.asciiUppercaseA)...(.asciiUppercaseF): return true default: return false diff --git a/Sources/NIOSSL/SSLErrors.swift b/Sources/NIOSSL/SSLErrors.swift index ea594bf45..e9b5db986 100644 --- a/Sources/NIOSSL/SSLErrors.swift +++ b/Sources/NIOSSL/SSLErrors.swift @@ -49,7 +49,7 @@ public struct BoringSSLInternalError: Equatable, CustomStringConvertible, Sendab } public var description: String { - return "Error: \(errorCode) \(errorMessage ?? "")" + "Error: \(errorCode) \(errorMessage ?? "")" } init(errorCode: UInt32, filename: String, line: UInt) { @@ -62,15 +62,16 @@ public struct BoringSSLInternalError: Equatable, CustomStringConvertible, Sendab /// Received EOF during the TLS handshake. public static let eofDuringHandshake = Self(syntheticErrorDescription: "EOF during handshake") - + /// Received EOF during additional certificate chain verification. - public static let eofDuringAdditionalCertficiateChainValidation = Self(syntheticErrorDescription: "EOF during addition certificate chain validation") + public static let eofDuringAdditionalCertficiateChainValidation = Self( + syntheticErrorDescription: "EOF during addition certificate chain validation" + ) } /// A representation of BoringSSL's internal error stack: a list of BoringSSL errors. public typealias NIOBoringSSLErrorStack = [BoringSSLInternalError] - /// Errors that can be raised by NIO's BoringSSL wrapper. public enum NIOSSLError: Error { case writeDuringTLSShutdown @@ -113,8 +114,7 @@ public enum BoringSSLError: Error { extension BoringSSLError: Equatable {} - -internal extension BoringSSLError { +extension BoringSSLError { static func fromSSLGetErrorResult(_ result: CInt) -> BoringSSLError? { switch result { case SSL_ERROR_NONE: @@ -145,10 +145,10 @@ internal extension BoringSSLError { return .unknownError(buildErrorStack()) } } - + static func buildErrorStack() -> NIOBoringSSLErrorStack { var errorStack = NIOBoringSSLErrorStack() - + while true { var file: UnsafePointer? = nil var line: CInt = 0 @@ -157,7 +157,7 @@ internal extension BoringSSLError { let fileAsString = String(cString: file!) errorStack.append(BoringSSLInternalError(errorCode: errorCode, filename: fileAsString, line: UInt(line))) } - + return errorStack } } @@ -178,7 +178,6 @@ public enum NIOTLSUnwrappingError: Error { case unflushedWriteOnUnwrap } - /// This structure contains errors added to NIOSSL after the original ``NIOSSLError`` enum was /// shipped. This is an extensible error object that allows us to evolve it going forward. public struct NIOSSLExtraError: Error { @@ -192,7 +191,6 @@ public struct NIOSSLExtraError: Error { } } - extension NIOSSLExtraError { private enum BaseError: Equatable { case failedToValidateHostname @@ -204,13 +202,18 @@ extension NIOSSLExtraError { } } - extension NIOSSLExtraError { /// NIOSSL was unable to validate the hostname presented by the remote peer. - public static let failedToValidateHostname = NIOSSLExtraError(baseError: .failedToValidateHostname, description: nil) + public static let failedToValidateHostname = NIOSSLExtraError( + baseError: .failedToValidateHostname, + description: nil + ) /// The server hostname provided by the user cannot match any names in the certificate due to containing invalid characters. - public static let serverHostnameImpossibleToMatch = NIOSSLExtraError(baseError: .serverHostnameImpossibleToMatch, description: nil) + public static let serverHostnameImpossibleToMatch = NIOSSLExtraError( + baseError: .serverHostnameImpossibleToMatch, + description: nil + ) /// IP addresses may not be used in SNI. public static let cannotUseIPAddressInSNI = NIOSSLExtraError(baseError: .cannotUseIPAddressInSNI, description: nil) @@ -227,7 +230,10 @@ extension NIOSSLExtraError { public static let invalidSNIHostname = NIOSSLExtraError(baseError: .invalidSNIHostname, description: nil) /// The private key file for the TLS configuration has an unknown type. - public static let unknownPrivateKeyFileType = NIOSSLExtraError(baseError: .unknownPrivateKeyFileType, description: nil) + public static let unknownPrivateKeyFileType = NIOSSLExtraError( + baseError: .unknownPrivateKeyFileType, + description: nil + ) /// No forward progress is being made. /// @@ -260,7 +266,6 @@ extension NIOSSLExtraError { } } - extension NIOSSLExtraError: CustomStringConvertible { public var description: String { let formattedDescription = self._description.map { ": " + $0 } ?? "" @@ -269,7 +274,7 @@ extension NIOSSLExtraError: CustomStringConvertible { } extension NIOSSLExtraError: Equatable { - public static func ==(lhs: NIOSSLExtraError, rhs: NIOSSLExtraError) -> Bool { - return lhs.baseError == rhs.baseError + public static func == (lhs: NIOSSLExtraError, rhs: NIOSSLExtraError) -> Bool { + lhs.baseError == rhs.baseError } } diff --git a/Sources/NIOSSL/SSLPKCS12Bundle.swift b/Sources/NIOSSL/SSLPKCS12Bundle.swift index af4859f10..524f9be87 100644 --- a/Sources/NIOSSL/SSLPKCS12Bundle.swift +++ b/Sources/NIOSSL/SSLPKCS12Bundle.swift @@ -14,7 +14,6 @@ @_implementationOnly import CNIOBoringSSL - /// A container for a single PKCS#12 bundle. /// /// PKCS#12 is a specification that defines an archive format for storing multiple @@ -46,8 +45,8 @@ public struct NIOSSLPKCS12Bundle: Hashable { public let privateKey: NIOSSLPrivateKey private init(ref: OpaquePointer, passphrase: Bytes?) throws where Bytes.Element == UInt8 { - var pkey: OpaquePointer?/**/ = nil - var cert: OpaquePointer?/**/ = nil + var pkey: OpaquePointer? = nil // + var cert: OpaquePointer? = nil // var caCerts: OpaquePointer? = nil let rc = try passphrase.withSecureCString { passphrase in @@ -88,7 +87,7 @@ public struct NIOSSLPKCS12Bundle: Hashable { /// - passphrase: The passphrase used for the bundle, as a sequence of UTF-8 bytes. public init(buffer: [UInt8], passphrase: Bytes?) throws where Bytes.Element == UInt8 { guard boringSSLIsInitialized else { fatalError("Failed to initialize BoringSSL") } - + let p12 = buffer.withUnsafeBytes { pointer -> OpaquePointer? in let bio = CNIOBoringSSL_BIO_new_mem_buf(pointer.baseAddress, pointer.count)! defer { @@ -202,8 +201,7 @@ extension Collection where Element == UInt8 { } } - -internal extension Optional where Wrapped: Collection, Wrapped.Element == UInt8 { +extension Optional where Wrapped: Collection, Wrapped.Element == UInt8 { func withSecureCString(_ block: (UnsafePointer?) throws -> T) throws -> T { if let `self` = self { return try self.withSecureCString({ try block($0) }) diff --git a/Sources/NIOSSL/SSLPrivateKey.swift b/Sources/NIOSSL/SSLPrivateKey.swift index 78424b780..093849709 100644 --- a/Sources/NIOSSL/SSLPrivateKey.swift +++ b/Sources/NIOSSL/SSLPrivateKey.swift @@ -24,14 +24,13 @@ /// use. We guarantee that after the ``NIOSSLPassphraseSetter`` closure has been invoked the `Collection` /// you have passed in will no longer be needed by BoringSSL, and so you can safely destroy any memory it /// may be using if you need to. -public typealias NIOSSLPassphraseCallback = (NIOSSLPassphraseSetter) throws -> Void where Bytes.Element == UInt8 - +public typealias NIOSSLPassphraseCallback = (NIOSSLPassphraseSetter) throws -> Void +where Bytes.Element == UInt8 /// An ``NIOSSLPassphraseSetter`` is a closure that you must invoke to provide a passphrase to BoringSSL. /// It will be provided to you when your ``NIOSSLPassphraseCallback`` is invoked. public typealias NIOSSLPassphraseSetter = (Bytes) -> Void where Bytes.Element == UInt8 - /// An internal protocol that exists to let us avoid problems with generic types. /// /// The issue we have here is that we want to allow users to use whatever collection type suits them best to set @@ -51,13 +50,13 @@ internal protocol CallbackManagerProtocol: AnyObject { func invoke(buffer: UnsafeMutableBufferPointer) -> CInt } - /// This class exists primarily to work around the fact that Swift does not let us stuff /// a closure into an `Unmanaged`. Instead, we use this object to keep hold of it. -final class BoringSSLPassphraseCallbackManager: CallbackManagerProtocol where Bytes.Element == UInt8 { +final class BoringSSLPassphraseCallbackManager: CallbackManagerProtocol +where Bytes.Element == UInt8 { private let userCallback: NIOSSLPassphraseCallback - init(userCallback: @escaping NIOSSLPassphraseCallback){ + init(userCallback: @escaping NIOSSLPassphraseCallback) { // We have to type-erase this. self.userCallback = userCallback } @@ -84,24 +83,27 @@ final class BoringSSLPassphraseCallbackManager: CallbackManag } } - /// Our global static BoringSSL passphrase callback. This is used as a thunk to dispatch out to /// the user-provided callback. -func globalBoringSSLPassphraseCallback(buf: UnsafeMutablePointer?, - size: CInt, - rwflag: CInt, - u: UnsafeMutableRawPointer?) -> CInt { +func globalBoringSSLPassphraseCallback( + buf: UnsafeMutablePointer?, + size: CInt, + rwflag: CInt, + u: UnsafeMutableRawPointer? +) -> CInt { guard let buffer = buf, let userData = u else { - preconditionFailure("Invalid pointers passed to passphrase callback, buf: \(String(describing: buf)) u: \(String(describing: u))") + preconditionFailure( + "Invalid pointers passed to passphrase callback, buf: \(String(describing: buf)) u: \(String(describing: u))" + ) } let bufferPointer = UnsafeMutableBufferPointer(start: buffer, count: Int(size)) - guard let cbManager = Unmanaged.fromOpaque(userData).takeUnretainedValue() as? CallbackManagerProtocol else { + guard let cbManager = Unmanaged.fromOpaque(userData).takeUnretainedValue() as? CallbackManagerProtocol + else { preconditionFailure("Failed to pass object that can handle callback") } return cbManager.invoke(buffer: bufferPointer) } - /// A reference to an BoringSSL private key object in the form of an `EVP_PKEY *`. /// /// This thin wrapper class allows us to use ARC to automatically manage @@ -114,14 +116,16 @@ func globalBoringSSLPassphraseCallback(buf: UnsafeMutablePointer?, public final class NIOSSLPrivateKey { @usableFromInline internal enum Representation { - case native(OpaquePointer /* case custom(AnyNIOSSLCustomPrivateKey) } @usableFromInline internal let representation: Representation - internal func withUnsafeMutableEVPPKEYPointer(_ body: (OpaquePointer) throws -> ReturnType) rethrows -> ReturnType { + internal func withUnsafeMutableEVPPKEYPointer( + _ body: (OpaquePointer) throws -> ReturnType + ) rethrows -> ReturnType { guard case .native(let pointer) = self.representation else { preconditionFailure() } @@ -134,7 +138,11 @@ public final class NIOSSLPrivateKey { } /// A delegating initializer for `init(file:format:passphraseCallback)` and `init(file:format:)`. - private convenience init(file: String, format: NIOSSLSerializationFormats, callbackManager: CallbackManagerProtocol?) throws { + private convenience init( + file: String, + format: NIOSSLSerializationFormats, + callbackManager: CallbackManagerProtocol? + ) throws { let fileObject = try Posix.fopen(file: file, mode: "rb") defer { // If fclose fails there is nothing we can do about it. @@ -154,7 +162,12 @@ public final class NIOSSLPrivateKey { // This annoying conditional binding is used to work around the fact that I cannot pass // a variable to a function pointer argument. if let callbackManager = callbackManager { - return CNIOBoringSSL_PEM_read_PrivateKey(fileObject, nil, { globalBoringSSLPassphraseCallback(buf: $0, size: $1, rwflag: $2, u: $3) }, Unmanaged.passUnretained(callbackManager as AnyObject).toOpaque()) + return CNIOBoringSSL_PEM_read_PrivateKey( + fileObject, + nil, + { globalBoringSSLPassphraseCallback(buf: $0, size: $1, rwflag: $2, u: $3) }, + Unmanaged.passUnretained(callbackManager as AnyObject).toOpaque() + ) } else { return CNIOBoringSSL_PEM_read_PrivateKey(fileObject, nil, nil, nil) } @@ -171,7 +184,11 @@ public final class NIOSSLPrivateKey { } /// A delegating initializer for `init(buffer:format:passphraseCallback)` and `init(buffer:format:)`. - private convenience init(bytes: [UInt8], format: NIOSSLSerializationFormats, callbackManager: CallbackManagerProtocol?) throws { + private convenience init( + bytes: [UInt8], + format: NIOSSLSerializationFormats, + callbackManager: CallbackManagerProtocol? + ) throws { let ref = bytes.withUnsafeBytes { (ptr) -> OpaquePointer? in let bio = CNIOBoringSSL_BIO_new_mem_buf(ptr.baseAddress!, ptr.count)! defer { @@ -184,7 +201,12 @@ public final class NIOSSLPrivateKey { if let callbackManager = callbackManager { // This annoying conditional binding is used to work around the fact that I cannot pass // a variable to a function pointer argument. - return CNIOBoringSSL_PEM_read_bio_PrivateKey(bio, nil, { globalBoringSSLPassphraseCallback(buf: $0, size: $1, rwflag: $2, u: $3) }, Unmanaged.passUnretained(callbackManager as AnyObject).toOpaque()) + return CNIOBoringSSL_PEM_read_bio_PrivateKey( + bio, + nil, + { globalBoringSSLPassphraseCallback(buf: $0, size: $1, rwflag: $2, u: $3) }, + Unmanaged.passUnretained(callbackManager as AnyObject).toOpaque() + ) } else { return CNIOBoringSSL_PEM_read_bio_PrivateKey(bio, nil, nil, nil) } @@ -219,7 +241,11 @@ public final class NIOSSLPrivateKey { /// - format: The format of the key to load, either DER or PEM. /// - passphraseCallback: A callback to invoke to obtain the passphrase for /// encrypted keys. - public convenience init(file: String, format: NIOSSLSerializationFormats, passphraseCallback: @escaping NIOSSLPassphraseCallback) throws where T.Element == UInt8 { + public convenience init( + file: String, + format: NIOSSLSerializationFormats, + passphraseCallback: @escaping NIOSSLPassphraseCallback + ) throws where T.Element == UInt8 { let manager = BoringSSLPassphraseCallbackManager(userCallback: passphraseCallback) try self.init(file: file, format: format, callbackManager: manager) } @@ -258,7 +284,11 @@ public final class NIOSSLPrivateKey { /// stdin. /// - SeeAlso: `NIOSSLPrivateKey.init(bytes:format:passphraseCallback:)` @available(*, deprecated, renamed: "NIOSSLPrivateKey.init(bytes:format:passphraseCallback:)") - public convenience init(buffer: [Int8], format: NIOSSLSerializationFormats, passphraseCallback: @escaping NIOSSLPassphraseCallback) throws where T.Element == UInt8 { + public convenience init( + buffer: [Int8], + format: NIOSSLSerializationFormats, + passphraseCallback: @escaping NIOSSLPassphraseCallback + ) throws where T.Element == UInt8 { try self.init(bytes: buffer.map(UInt8.init), format: format, passphraseCallback: passphraseCallback) } @@ -272,7 +302,11 @@ public final class NIOSSLPrivateKey { /// encrypted keys. If not provided, or set to `nil`, the default BoringSSL /// behaviour will be used, which prints a prompt and requests the passphrase from /// stdin. - public convenience init(bytes: [UInt8], format: NIOSSLSerializationFormats, passphraseCallback: @escaping NIOSSLPassphraseCallback) throws where T.Element == UInt8 { + public convenience init( + bytes: [UInt8], + format: NIOSSLSerializationFormats, + passphraseCallback: @escaping NIOSSLPassphraseCallback + ) throws where T.Element == UInt8 { let manager = BoringSSLPassphraseCallbackManager(userCallback: passphraseCallback) try self.init(bytes: bytes, format: format, callbackManager: manager) } @@ -300,7 +334,7 @@ public final class NIOSSLPrivateKey { /// In general, however, this function should be avoided in favour of one of the convenience /// initializers, which ensure that the lifetime of the EVP_PKEY object is better-managed. static internal func fromUnsafePointer(takingOwnership pointer: OpaquePointer) -> NIOSSLPrivateKey { - return NIOSSLPrivateKey(withReference: pointer) + NIOSSLPrivateKey(withReference: pointer) } deinit { @@ -318,7 +352,6 @@ public final class NIOSSLPrivateKey { // It is therefore Sendable. extension NIOSSLPrivateKey: @unchecked Sendable {} - // MARK:- Utilities extension NIOSSLPrivateKey { /// Calls the given body function with a temporary buffer containing the DER-encoded bytes of this @@ -328,7 +361,10 @@ extension NIOSSLPrivateKey { /// The pointer provided to the closure is not valid beyond the lifetime of this method call. /// /// This method is only safe to call on native private keys. - private static func withUnsafeDERBuffer(of ref: OpaquePointer, _ body: (UnsafeRawBufferPointer) throws -> T) throws -> T { + private static func withUnsafeDERBuffer( + of ref: OpaquePointer, + _ body: (UnsafeRawBufferPointer) throws -> T + ) throws -> T { guard let bio = CNIOBoringSSL_BIO_new(CNIOBoringSSL_BIO_s_mem()) else { fatalError("Failed to malloc for a BIO handler") } @@ -366,9 +402,8 @@ extension NIOSSLPrivateKey { } } - extension NIOSSLPrivateKey: Equatable { - public static func ==(lhs: NIOSSLPrivateKey, rhs: NIOSSLPrivateKey) -> Bool { + public static func == (lhs: NIOSSLPrivateKey, rhs: NIOSSLPrivateKey) -> Bool { switch (lhs.representation, rhs.representation) { case (.native, .native): // Annoyingly, EVP_PKEY_cmp does not have a traditional return value pattern. 1 means equal, 0 means non-equal, @@ -389,7 +424,6 @@ extension NIOSSLPrivateKey: Equatable { } } - extension NIOSSLPrivateKey: Hashable { public func hash(into hasher: inout Hasher) { switch self.representation { diff --git a/Sources/NIOSSL/SSLPublicKey.swift b/Sources/NIOSSL/SSLPublicKey.swift index d87578301..86f749cef 100644 --- a/Sources/NIOSSL/SSLPublicKey.swift +++ b/Sources/NIOSSL/SSLPublicKey.swift @@ -21,7 +21,7 @@ /// ``NIOSSLCertificate`` objects to be serialized, so that they can be passed to /// general-purpose cryptography libraries. public final class NIOSSLPublicKey { - private let ref: OpaquePointer /**/ + private let ref: OpaquePointer // fileprivate init(withOwnedReference ref: OpaquePointer) { self.ref = ref @@ -46,7 +46,7 @@ extension NIOSSLPublicKey { /// - pointer: A pointer to an `EVP_PKEY` structure containing the public key. /// - returns: An `NIOSSLPublicKey` wrapping the pointer. internal static func fromInternalPointer(takingOwnership pointer: OpaquePointer) -> NIOSSLPublicKey { - return NIOSSLPublicKey(withOwnedReference: pointer) + NIOSSLPublicKey(withOwnedReference: pointer) } } diff --git a/Sources/NIOSSL/SecurityFrameworkCertificateVerification.swift b/Sources/NIOSSL/SecurityFrameworkCertificateVerification.swift index 0dc794523..b2aed91f2 100644 --- a/Sources/NIOSSL/SecurityFrameworkCertificateVerification.swift +++ b/Sources/NIOSSL/SecurityFrameworkCertificateVerification.swift @@ -11,8 +11,8 @@ // SPDX-License-Identifier: Apache-2.0 // //===----------------------------------------------------------------------===// -import NIOCore @_implementationOnly import CNIOBoringSSL +import NIOCore // We can only use Security.framework to validate TLS certificates on Apple platforms. #if canImport(Darwin) @@ -21,7 +21,10 @@ import Foundation import Security extension SSLConnection { - func performSecurityFrameworkValidation(promise: EventLoopPromise, peerCertificates: [SecCertificate]) { + func performSecurityFrameworkValidation( + promise: EventLoopPromise, + peerCertificates: [SecCertificate] + ) { do { guard case .default = self.parentContext.configuration.trustRoots ?? .default else { preconditionFailure("This callback should only be used if we are using the system-default trust.") @@ -37,19 +40,24 @@ extension SSLConnection { } // If there are additional trust roots then we need to add them to the SecTrust as anchors. - let additionalAnchorCertificates: [SecCertificate] = try self.parentContext.configuration.additionalTrustRoots.flatMap { trustRoots -> [NIOSSLCertificate] in - guard case .certificates(let certs) = trustRoots else { - preconditionFailure("This callback happens on the request path, file-based additional trust roots should be pre-loaded when creating the SSLContext.") - } - return certs - }.map { - guard let secCert = SecCertificateCreateWithData(nil, Data(try $0.toDERBytes()) as CFData) else { - throw NIOSSLError.failedToLoadCertificate + let additionalAnchorCertificates: [SecCertificate] = try self.parentContext.configuration + .additionalTrustRoots.flatMap { trustRoots -> [NIOSSLCertificate] in + guard case .certificates(let certs) = trustRoots else { + preconditionFailure( + "This callback happens on the request path, file-based additional trust roots should be pre-loaded when creating the SSLContext." + ) + } + return certs + }.map { + guard let secCert = SecCertificateCreateWithData(nil, Data(try $0.toDERBytes()) as CFData) else { + throw NIOSSLError.failedToLoadCertificate + } + return secCert } - return secCert - } if !additionalAnchorCertificates.isEmpty { - guard SecTrustSetAnchorCertificates(actualTrust, additionalAnchorCertificates as CFArray) == errSecSuccess else { + guard + SecTrustSetAnchorCertificates(actualTrust, additionalAnchorCertificates as CFArray) == errSecSuccess + else { throw NIOSSLError.failedToLoadCertificate } // To use additional anchors _and_ the built-in ones we must reenable the built-in ones expicitly. diff --git a/Sources/NIOSSL/String+unsafeUninitializedCapacity.swift b/Sources/NIOSSL/String+unsafeUninitializedCapacity.swift index 6e3cfae01..bbec85c07 100644 --- a/Sources/NIOSSL/String+unsafeUninitializedCapacity.swift +++ b/Sources/NIOSSL/String+unsafeUninitializedCapacity.swift @@ -27,7 +27,7 @@ extension String { try self.init(backportUnsafeUninitializedCapacity: capacity, initializingUTF8With: initializer) } } - + private init( backportUnsafeUninitializedCapacity capacity: Int, initializingUTF8With initializer: (_ buffer: UnsafeMutableBufferPointer) throws -> Int @@ -37,10 +37,12 @@ extension String { buffer.deallocate() } - let initializedCount = try initializer(buffer) precondition(initializedCount <= capacity, "Overran buffer in initializer!") - self = String(decoding: UnsafeMutableBufferPointer(start: buffer.baseAddress!, count: initializedCount), as: UTF8.self) + self = String( + decoding: UnsafeMutableBufferPointer(start: buffer.baseAddress!, count: initializedCount), + as: UTF8.self + ) } } diff --git a/Sources/NIOSSL/SubjectAlternativeName.swift b/Sources/NIOSSL/SubjectAlternativeName.swift index 28ad5eee4..8bef30fba 100644 --- a/Sources/NIOSSL/SubjectAlternativeName.swift +++ b/Sources/NIOSSL/SubjectAlternativeName.swift @@ -12,9 +12,9 @@ // //===----------------------------------------------------------------------===// -import NIOCore @_implementationOnly import CNIOBoringSSL @_implementationOnly import CNIOBoringSSLShims +import NIOCore #if canImport(Darwin) import Darwin.C @@ -30,13 +30,13 @@ import Android /// Collection of all Subject Alternative Names from a `NIOSSLCertificate` public struct _SubjectAlternativeNames { - + @usableFromInline internal final class Storage { - + fileprivate let nameStack: OpaquePointer? @usableFromInline internal let stackSize: Int - + internal init(nameStack: OpaquePointer?) { self.nameStack = nameStack if let nameStack = nameStack { @@ -45,12 +45,12 @@ public struct _SubjectAlternativeNames { self.stackSize = 0 } } - + public subscript(position: Int) -> Element { guard let name = CNIOBoringSSLShims_sk_GENERAL_NAME_value(self.nameStack!, position) else { fatalError("Unexpected null pointer when unwrapping SAN value") } - + let contents = UnsafeBufferPointer( start: CNIOBoringSSL_ASN1_STRING_get0_data(name.pointee.d.ia5), count: Int(CNIOBoringSSL_ASN1_STRING_length(name.pointee.d.ia5)) @@ -64,10 +64,9 @@ public struct _SubjectAlternativeNames { } } } - - + @usableFromInline internal var storage: Storage - + internal init(nameStack: OpaquePointer?) { self.storage = .init(nameStack: nameStack) } @@ -77,18 +76,18 @@ public struct _SubjectAlternativeNames { extension _SubjectAlternativeNames: @unchecked Sendable {} extension _SubjectAlternativeNames: RandomAccessCollection { - + @inlinable public subscript(position: Int) -> _SubjectAlternativeName { precondition(self.indices.contains(position), "index \(position) out of bounds") return self.storage[position] } - + @inlinable public var startIndex: Int { 0 } @inlinable public var endIndex: Int { self.storage.stackSize } } public struct _SubjectAlternativeName { - + public struct NameType: Hashable, Sendable { public var rawValue: Int @@ -99,7 +98,7 @@ public struct _SubjectAlternativeName { fileprivate init(_ rawCode: Int32) { self.init(Int(rawCode)) } - + public static let email = Self(GEN_EMAIL) public static let dnsName = Self(GEN_DNS) public static let ipAddress = Self(GEN_IPADD) @@ -111,25 +110,25 @@ public struct _SubjectAlternativeName { private let collection: _SubjectAlternativeNames.Storage // lifetime automatically managed by `collection` @usableFromInline internal let buffer: UnsafeBufferPointer - + internal init(collection: _SubjectAlternativeNames.Storage, buffer: UnsafeBufferPointer) { self.collection = collection self.buffer = buffer } - + @inlinable public func withUnsafeBufferPointer( _ body: (UnsafeBufferPointer) throws -> Result ) rethrows -> Result { try body(self.buffer) } } - + // should be replaced by `swift-nio`s `IPAddress` once https://github.com/apple/swift-nio/issues/1650 is resolved internal enum IPAddress { case ipv4(in_addr) case ipv6(in6_addr) } - + public var nameType: NameType public var contents: Contents } @@ -141,10 +140,10 @@ extension _SubjectAlternativeName: @unchecked Sendable {} extension _SubjectAlternativeName.Contents: @unchecked Sendable {} extension _SubjectAlternativeName.Contents: RandomAccessCollection { - + @inlinable public var startIndex: Int { self.buffer.startIndex } @inlinable public var endIndex: Int { self.buffer.endIndex } - + @inlinable public subscript(position: Int) -> UInt8 { precondition(self.indices.contains(position), "index \(position) out of bounds") return self.buffer[position] @@ -152,7 +151,7 @@ extension _SubjectAlternativeName.Contents: RandomAccessCollection { } extension _SubjectAlternativeName.IPAddress { - + internal init?(_ subjectAlternativeName: _SubjectAlternativeName) { guard subjectAlternativeName.nameType == .ipAddress else { return nil @@ -184,11 +183,11 @@ extension _SubjectAlternativeName.IPAddress { } } +// swift-format-ignore: DontRepeatTypeInStaticProperties extension _SubjectAlternativeName.IPAddress: CustomStringConvertible { - private static let ipv4AddressLength = 16 private static let ipv6AddressLength = 46 - + /// A string representation of the IP address. /// E.g. IPv4: `192.168.0.1` /// E.g. IPv6: `2001:db8::1` @@ -200,24 +199,30 @@ extension _SubjectAlternativeName.IPAddress: CustomStringConvertible { return Self.ipv6ToString(addr) } } - + static private func ipv4ToString(_ address: in_addr) -> String { - + var address = address var dest: [CChar] = Array(repeating: 0, count: Self.ipv4AddressLength) dest.withUnsafeMutableBufferPointer { pointer in let result = inet_ntop(AF_INET, &address, pointer.baseAddress!, socklen_t(pointer.count)) - precondition(result != nil, "The IP address was invalid. This should never happen as we're within the IP address struct.") + precondition( + result != nil, + "The IP address was invalid. This should never happen as we're within the IP address struct." + ) } return String(cString: &dest) } - + static private func ipv6ToString(_ address: in6_addr) -> String { var address = address var dest: [CChar] = Array(repeating: 0, count: Self.ipv6AddressLength) dest.withUnsafeMutableBufferPointer { pointer in let result = inet_ntop(AF_INET6, &address, pointer.baseAddress!, socklen_t(pointer.count)) - precondition(result != nil, "The IP address was invalid. This should never happen as we're within the IP address struct.") + precondition( + result != nil, + "The IP address was invalid. This should never happen as we're within the IP address struct." + ) } return String(cString: &dest) } diff --git a/Sources/NIOSSL/SwiftCrypto/NIOSSLSecureBytes.swift b/Sources/NIOSSL/SwiftCrypto/NIOSSLSecureBytes.swift index add3d053a..6b04d3797 100644 --- a/Sources/NIOSSL/SwiftCrypto/NIOSSLSecureBytes.swift +++ b/Sources/NIOSSL/SwiftCrypto/NIOSSLSecureBytes.swift @@ -33,16 +33,21 @@ public struct NIOSSLSecureBytes { self.backing = NIOSSLSecureBytes.Backing.create(randomBytes: count) } - init (bytes: [UInt8]) { + init(bytes: [UInt8]) { self.backing = Backing.create(bytes: bytes) } /// Allows initializing a SecureBytes object with a closure that will initialize the memory. @usableFromInline - init(unsafeUninitializedCapacity: Int, initializingWith callback: (inout UnsafeMutableRawBufferPointer, inout Int) throws -> Void) rethrows { + init( + unsafeUninitializedCapacity: Int, + initializingWith callback: (inout UnsafeMutableRawBufferPointer, inout Int) throws -> Void + ) rethrows { self.backing = Backing.create(capacity: unsafeUninitializedCapacity) try self.backing._withVeryUnsafeMutableBytes { veryUnsafePointer in // As Array does, we want to truncate the initializing pointer to only have the requested size. - var veryUnsafePointer = UnsafeMutableRawBufferPointer(rebasing: veryUnsafePointer.prefix(unsafeUninitializedCapacity)) + var veryUnsafePointer = UnsafeMutableRawBufferPointer( + rebasing: veryUnsafePointer.prefix(unsafeUninitializedCapacity) + ) var initializedCount = 0 try callback(&veryUnsafePointer, &initializedCount) @@ -78,10 +83,10 @@ extension NIOSSLSecureBytes { newBacking._appendBytes(self.backing, inRange: 0..(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T { - return try self.backing.withUnsafeBytes(body) + try self.backing.withUnsafeBytes(body) } } @@ -100,19 +105,19 @@ extension NIOSSLSecureBytes: Equatable { extension NIOSSLSecureBytes: RandomAccessCollection { @inlinable public var startIndex: Int { 0 } - + @inlinable public var endIndex: Int { self.count } @inlinable public var count: Int { - return self.backing.count + self.backing.count } @inlinable public subscript(_ index: Int) -> UInt8 { get { - return self.backing[offset: index] + self.backing[offset: index] } set { self.backing[offset: index] = newValue @@ -120,14 +125,14 @@ extension NIOSSLSecureBytes: RandomAccessCollection { } } - // MARK: - MutableCollection conformance -extension NIOSSLSecureBytes: MutableCollection { } +extension NIOSSLSecureBytes: MutableCollection {} // MARK: - RangeReplaceableCollection conformance extension NIOSSLSecureBytes: RangeReplaceableCollection { @inlinable - mutating public func replaceSubrange(_ subrange: Range, with newElements: C) where C.Element == UInt8 { + mutating public func replaceSubrange(_ subrange: Range, with newElements: C) + where C.Element == UInt8 { let requiredCapacity = self.backing.count - subrange.count + newElements.count if !isKnownUniquelyReferenced(&self.backing) || requiredCapacity > self.backing.capacity { @@ -167,17 +172,20 @@ extension NIOSSLSecureBytes { @usableFromInline class func create(capacity: Int) -> Backing { let capacity = Int(UInt32(capacity).nextPowerOf2ClampedToMax()) - return Backing.create(minimumCapacity: capacity, makingHeaderWith: { _ in BackingHeader(count: 0, capacity: capacity) }) as! Backing + return Backing.create( + minimumCapacity: capacity, + makingHeaderWith: { _ in BackingHeader(count: 0, capacity: capacity) } + ) as! Backing } @usableFromInline class func create(copying original: Backing) -> Backing { - return Backing.create(bytes: original.withUnsafeBytes { Array($0) }) + Backing.create(bytes: original.withUnsafeBytes { Array($0) }) } @inlinable class func create(bytes: [UInt8]) -> Backing { - return bytes.withUnsafeBytes { bytesPtr in + bytes.withUnsafeBytes { bytesPtr in let backing = Backing.create(capacity: bytesPtr.count) backing._withVeryUnsafeMutableBytes { targetPtr in targetPtr.copyMemory(from: bytesPtr) @@ -211,7 +219,7 @@ extension NIOSSLSecureBytes { @usableFromInline var count: Int { get { - return self.header.count + self.header.count } set { self.header.count = newValue @@ -222,7 +230,7 @@ extension NIOSSLSecureBytes { subscript(offset offset: Int) -> UInt8 { get { // precondition(offset >= 0 && offset < self.count) - return self.withUnsafeMutablePointerToElements { return ($0 + offset).pointee } + self.withUnsafeMutablePointerToElements { ($0 + offset).pointee } } set { // precondition(offset >= 0 && offset < self.count) @@ -234,7 +242,8 @@ extension NIOSSLSecureBytes { extension NIOSSLSecureBytes.Backing { @usableFromInline - func replaceSubrangeFittingWithinCapacity(_ subrange: Range, with newElements: C) where C.Element == UInt8 { + func replaceSubrangeFittingWithinCapacity(_ subrange: Range, with newElements: C) + where C.Element == UInt8 { // This function is called when have a unique reference to the backing storage, and we have enough room to store these bytes without // any problem. We have one pre-existing buffer made up of 4 regions: a prefix set of bytes that are // before the range "subrange", a range of bytes to be replaced (R1), a suffix set of bytes that are after @@ -263,10 +272,14 @@ extension NIOSSLSecureBytes.Backing { } /// Appends the bytes of a collection to this storage, crashing if there is not enough room. - /* private but inlinable */ @inlinable func _appendBytes(_ bytes: C) where C.Element == UInt8 { + @inlinable // private but inlinable + func _appendBytes(_ bytes: C) where C.Element == UInt8 { let byteCount = bytes.count - precondition(self.capacity - self.count - byteCount >= 0, "Insufficient space for byte copying, must have reallocated!") + precondition( + self.capacity - self.count - byteCount >= 0, + "Insufficient space for byte copying, must have reallocated!" + ) let lowerOffset = self.count self._withVeryUnsafeMutableBytes { bytesPtr in @@ -278,10 +291,17 @@ extension NIOSSLSecureBytes.Backing { /// Appends the bytes of a slice of another backing buffer to this storage, crashing if there /// is not enough room. - /* private but inlinable */ @inlinable func _appendBytes(_ backing: NIOSSLSecureBytes.Backing, inRange range: Range) { + @inlinable // private but inlinable + func _appendBytes( + _ backing: NIOSSLSecureBytes.Backing, + inRange range: Range + ) { precondition(range.lowerBound >= 0) precondition(range.upperBound <= backing.capacity) - precondition(self.capacity - self.count - range.count >= 0, "Insufficient space for byte copying, must have reallocated!") + precondition( + self.capacity - self.count - range.count >= 0, + "Insufficient space for byte copying, must have reallocated!" + ) backing.withUnsafeBytes { backingPtr in let ptrSlice = UnsafeRawBufferPointer(rebasing: backingPtr[range]) @@ -298,8 +318,8 @@ extension NIOSSLSecureBytes.Backing { /// Moves the range of bytes identified by the slice by the delta, crashing if the move would /// place the bytes out of the storage. Note that this does not update the count: external code /// must ensure that that happens. - @usableFromInline - /* private but usableFromInline */ func _moveBytes(range: Range, by delta: Int) { + @usableFromInline // private but usableFromInline + func _moveBytes(range: Range, by delta: Int) { // We have to check that the range is within the delta, as is the new location. precondition(range.lowerBound >= 0) precondition(range.upperBound <= self.capacity) @@ -316,8 +336,8 @@ extension NIOSSLSecureBytes.Backing { } // Copies some bytes into the buffer at the appropriate place. Does not update count: external code must do so. - @inlinable - /* private but inlinable */ func _copyBytes(_ bytes: C, at offset: Int) where C.Element == UInt8 { + @inlinable // private but inlinable + func _copyBytes(_ bytes: C, at offset: Int) where C.Element == UInt8 { precondition(offset >= 0) precondition(offset + bytes.count <= self.capacity) @@ -328,13 +348,13 @@ extension NIOSSLSecureBytes.Backing { dest.copyBytes(from: bytes) } } - + @usableFromInline func withUnsafeBytes(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T { let count = self.count return try self.withUnsafeMutablePointerToElements { elementsPtr in - return try body(UnsafeRawBufferPointer(start: elementsPtr, count: count)) + try body(UnsafeRawBufferPointer(start: elementsPtr, count: count)) } } @usableFromInline @@ -342,17 +362,19 @@ extension NIOSSLSecureBytes.Backing { let count = self.count return try self.withUnsafeMutablePointerToElements { elementsPtr in - return try body(UnsafeMutableRawBufferPointer(start: elementsPtr, count: count)) + try body(UnsafeMutableRawBufferPointer(start: elementsPtr, count: count)) } } /// Very unsafe in the sense that this points to uninitialized memory. Used only for implementations within this file. - @inlinable - /* private but inlinable */ func _withVeryUnsafeMutableBytes(_ body: (UnsafeMutableRawBufferPointer) throws -> T) rethrows -> T { + @inlinable // private but inlinable + func _withVeryUnsafeMutableBytes( + _ body: (UnsafeMutableRawBufferPointer) throws -> T + ) rethrows -> T { let capacity = self.capacity return try self.withUnsafeMutablePointerToElements { elementsPtr in - return try body(UnsafeMutableRawBufferPointer(start: elementsPtr, count: capacity)) + try body(UnsafeMutableRawBufferPointer(start: elementsPtr, count: capacity)) } } } diff --git a/Sources/NIOSSL/SwiftCrypto/SafeCompare.swift b/Sources/NIOSSL/SwiftCrypto/SafeCompare.swift index 662e8d571..828d6a902 100644 --- a/Sources/NIOSSL/SwiftCrypto/SafeCompare.swift +++ b/Sources/NIOSSL/SwiftCrypto/SafeCompare.swift @@ -14,7 +14,8 @@ /// A straightforward constant-time comparison function for any two collections of bytes. @inlinable -internal func constantTimeCompare(_ lhs: LHS, _ rhs: RHS) -> Bool where LHS.Element == UInt8, RHS.Element == UInt8 { +internal func constantTimeCompare(_ lhs: LHS, _ rhs: RHS) -> Bool +where LHS.Element == UInt8, RHS.Element == UInt8 { guard lhs.count == rhs.count else { return false } diff --git a/Sources/NIOSSL/TLSConfiguration.swift b/Sources/NIOSSL/TLSConfiguration.swift index a3e0a6969..d0a60c354 100644 --- a/Sources/NIOSSL/TLSConfiguration.swift +++ b/Sources/NIOSSL/TLSConfiguration.swift @@ -25,7 +25,12 @@ public enum TLSVersion: Sendable { /// Places NIOSSL can obtain certificates from. public enum NIOSSLCertificateSource: Hashable, Sendable { - @available(*, deprecated, message: "Use 'NIOSSLCertificate.fromPEMFile(_:)' to load the certificate(s) and use the '.certificate(NIOSSLCertificate)' case to provide them as a source") + @available( + *, + deprecated, + message: + "Use 'NIOSSLCertificate.fromPEMFile(_:)' to load the certificate(s) and use the '.certificate(NIOSSLCertificate)' case to provide them as a source" + ) case file(String) case certificate(NIOSSLCertificate) } @@ -104,27 +109,27 @@ public struct NIOTLSCipher: RawRepresentable, Hashable, Sendable { public var rawValue: UInt16 public typealias RawValue = UInt16 - public static let TLS_RSA_WITH_AES_128_CBC_SHA = NIOTLSCipher(rawValue: 0x2F) - public static let TLS_RSA_WITH_AES_256_CBC_SHA = NIOTLSCipher(rawValue: 0x35) - public static let TLS_PSK_WITH_AES_128_CBC_SHA = NIOTLSCipher(rawValue: 0x8C) - public static let TLS_PSK_WITH_AES_256_CBC_SHA = NIOTLSCipher(rawValue: 0x8D) - public static let TLS_RSA_WITH_AES_128_GCM_SHA256 = NIOTLSCipher(rawValue: 0x9C) - public static let TLS_RSA_WITH_AES_256_GCM_SHA384 = NIOTLSCipher(rawValue: 0x9D) - public static let TLS_AES_128_GCM_SHA256 = NIOTLSCipher(rawValue: 0x1301) - public static let TLS_AES_256_GCM_SHA384 = NIOTLSCipher(rawValue: 0x1302) - public static let TLS_CHACHA20_POLY1305_SHA256 = NIOTLSCipher(rawValue: 0x1303) - public static let TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = NIOTLSCipher(rawValue: 0xC009) - public static let TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = NIOTLSCipher(rawValue: 0xC00A) - public static let TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = NIOTLSCipher(rawValue: 0xC013) - public static let TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = NIOTLSCipher(rawValue: 0xC014) - public static let TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA = NIOTLSCipher(rawValue: 0xC035) - public static let TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA = NIOTLSCipher(rawValue: 0xC036) - public static let TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = NIOTLSCipher(rawValue: 0xC02B) - public static let TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = NIOTLSCipher(rawValue: 0xC02C) - public static let TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = NIOTLSCipher(rawValue: 0xC02F) - public static let TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = NIOTLSCipher(rawValue: 0xC030) - public static let TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = NIOTLSCipher(rawValue: 0xCCA8) - public static let TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = NIOTLSCipher(rawValue: 0xCCA9) + public static let TLS_RSA_WITH_AES_128_CBC_SHA = NIOTLSCipher(rawValue: 0x2F) + public static let TLS_RSA_WITH_AES_256_CBC_SHA = NIOTLSCipher(rawValue: 0x35) + public static let TLS_PSK_WITH_AES_128_CBC_SHA = NIOTLSCipher(rawValue: 0x8C) + public static let TLS_PSK_WITH_AES_256_CBC_SHA = NIOTLSCipher(rawValue: 0x8D) + public static let TLS_RSA_WITH_AES_128_GCM_SHA256 = NIOTLSCipher(rawValue: 0x9C) + public static let TLS_RSA_WITH_AES_256_GCM_SHA384 = NIOTLSCipher(rawValue: 0x9D) + public static let TLS_AES_128_GCM_SHA256 = NIOTLSCipher(rawValue: 0x1301) + public static let TLS_AES_256_GCM_SHA384 = NIOTLSCipher(rawValue: 0x1302) + public static let TLS_CHACHA20_POLY1305_SHA256 = NIOTLSCipher(rawValue: 0x1303) + public static let TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = NIOTLSCipher(rawValue: 0xC009) + public static let TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = NIOTLSCipher(rawValue: 0xC00A) + public static let TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = NIOTLSCipher(rawValue: 0xC013) + public static let TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = NIOTLSCipher(rawValue: 0xC014) + public static let TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA = NIOTLSCipher(rawValue: 0xC035) + public static let TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA = NIOTLSCipher(rawValue: 0xC036) + public static let TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = NIOTLSCipher(rawValue: 0xC02B) + public static let TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = NIOTLSCipher(rawValue: 0xC02C) + public static let TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = NIOTLSCipher(rawValue: 0xC02F) + public static let TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = NIOTLSCipher(rawValue: 0xC030) + public static let TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = NIOTLSCipher(rawValue: 0xCCA8) + public static let TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = NIOTLSCipher(rawValue: 0xCCA9) var standardName: String { let boringSSLCipher = CNIOBoringSSL_SSL_get_cipher_by_value(self.rawValue) @@ -151,8 +156,8 @@ public struct NIOTLSCurve: RawRepresentable, Hashable, Sendable { public static let secp256r1 = NIOTLSCurve(rawValue: 0x17) public static let secp384r1 = NIOTLSCurve(rawValue: 0x18) public static let secp521r1 = NIOTLSCurve(rawValue: 0x19) - public static let x25519 = NIOTLSCurve(rawValue: 0x1D) - public static let x448 = NIOTLSCurve(rawValue: 0x1E) + public static let x25519 = NIOTLSCurve(rawValue: 0x1D) + public static let x448 = NIOTLSCurve(rawValue: 0x1E) } /// Formats NIOSSL supports for serializing keys and certificates. @@ -193,7 +198,7 @@ public enum NIORenegotiationSupport: Sendable { } /// Signature algorithms. The values are defined as in TLS 1.3 -public struct SignatureAlgorithm : RawRepresentable, Hashable, Sendable { +public struct SignatureAlgorithm: RawRepresentable, Hashable, Sendable { public typealias RawValue = UInt16 public var rawValue: UInt16 @@ -216,7 +221,6 @@ public struct SignatureAlgorithm : RawRepresentable, Hashable, Sendable { public static let ed25519 = SignatureAlgorithm(rawValue: 0x0807) } - /// A secure default configuration of cipher suites for TLS 1.2 and earlier. /// /// The goal of this cipher suite string is: @@ -239,7 +243,7 @@ public let defaultCipherSuites = [ "!aNULL", "!eNULL", "!MD5", - ].joined(separator: ":") +].joined(separator: ":") /// Encodes a string to the wire format of an ALPN identifier. These MUST be ASCII, and so /// this routine will crash the program if they aren't, as these are always user-supplied @@ -258,7 +262,7 @@ internal func encodeALPNIdentifier(identifier: String) -> [UInt8] { /// Decodes a string from the wire format of an ALPN identifier. These MUST be correctly /// formatted ALPN identifiers, and so this routine will crash the program if they aren't. internal func decodeALPNIdentifier(identifier: [UInt8]) -> String { - return String(decoding: identifier[1.. Bool { let isKeyLoggerCallbacksEqual = withUnsafeBytes(of: self.keyLogCallback) { callbackPointer1 in - return withUnsafeBytes(of: comparing.keyLogCallback) { callbackPointer2 in - return callbackPointer1.elementsEqual(callbackPointer2) + withUnsafeBytes(of: comparing.keyLogCallback) { callbackPointer2 in + callbackPointer1.elementsEqual(callbackPointer2) } } let isPSKClientProviderEqual = withUnsafeBytes(of: self._pskClientIdentityProvider) { pskClientProvider1 in - return withUnsafeBytes(of: comparing._pskClientIdentityProvider) { pskClientProvider2 in - return pskClientProvider1.elementsEqual(pskClientProvider2) + withUnsafeBytes(of: comparing._pskClientIdentityProvider) { pskClientProvider2 in + pskClientProvider1.elementsEqual(pskClientProvider2) } } let isPSKServerProviderEqual = withUnsafeBytes(of: self._pskServerIdentityProvider) { pskServerProvider1 in - return withUnsafeBytes(of: comparing._pskServerIdentityProvider) { pskServerProvider2 in - return pskServerProvider1.elementsEqual(pskServerProvider2) + withUnsafeBytes(of: comparing._pskServerIdentityProvider) { pskServerProvider2 in + pskServerProvider1.elementsEqual(pskServerProvider2) } } let isSSLContextCallbackEqual = withUnsafeBytes(of: self.sslContextCallback) { sslContextCallback1 in - return withUnsafeBytes(of: comparing.sslContextCallback) { sslContextCallback2 in - return sslContextCallback1.elementsEqual(sslContextCallback2) + withUnsafeBytes(of: comparing.sslContextCallback) { sslContextCallback2 in + sslContextCallback1.elementsEqual(sslContextCallback2) } } - return self.minimumTLSVersion == comparing.minimumTLSVersion && - self.maximumTLSVersion == comparing.maximumTLSVersion && - self.cipherSuites == comparing.cipherSuites && - self.curves == comparing.curves && - self.verifySignatureAlgorithms == comparing.verifySignatureAlgorithms && - self.signingSignatureAlgorithms == comparing.signingSignatureAlgorithms && - self.certificateVerification == comparing.certificateVerification && - self.trustRoots == comparing.trustRoots && - self.additionalTrustRoots == comparing.additionalTrustRoots && - self.certificateChain == comparing.certificateChain && - self.privateKey == comparing.privateKey && - self.encodedApplicationProtocols == comparing.encodedApplicationProtocols && - self.shutdownTimeout == comparing.shutdownTimeout && - isKeyLoggerCallbacksEqual && - self.renegotiationSupport == comparing.renegotiationSupport && - self.sendCANameList == comparing.sendCANameList && - isSSLContextCallbackEqual && - isPSKClientProviderEqual && - isPSKServerProviderEqual && - self.pskHint == comparing.pskHint + return self.minimumTLSVersion == comparing.minimumTLSVersion + && self.maximumTLSVersion == comparing.maximumTLSVersion && self.cipherSuites == comparing.cipherSuites + && self.curves == comparing.curves && self.verifySignatureAlgorithms == comparing.verifySignatureAlgorithms + && self.signingSignatureAlgorithms == comparing.signingSignatureAlgorithms + && self.certificateVerification == comparing.certificateVerification + && self.trustRoots == comparing.trustRoots && self.additionalTrustRoots == comparing.additionalTrustRoots + && self.certificateChain == comparing.certificateChain && self.privateKey == comparing.privateKey + && self.encodedApplicationProtocols == comparing.encodedApplicationProtocols + && self.shutdownTimeout == comparing.shutdownTimeout && isKeyLoggerCallbacksEqual + && self.renegotiationSupport == comparing.renegotiationSupport + && self.sendCANameList == comparing.sendCANameList && isSSLContextCallbackEqual && isPSKClientProviderEqual + && isPSKServerProviderEqual && self.pskHint == comparing.pskHint } /// Returns a best effort hash of this TLS configuration. @@ -554,25 +552,27 @@ extension TLSConfiguration { /// /// For customising fields, modify the returned TLSConfiguration object. public static func makeClientConfiguration() -> TLSConfiguration { - return TLSConfiguration(cipherSuites: defaultCipherSuites, - verifySignatureAlgorithms: nil, - signingSignatureAlgorithms: nil, - minimumTLSVersion: .tlsv1, - maximumTLSVersion: nil, - certificateVerification: .fullVerification, - trustRoots: .default, - certificateChain: [], - privateKey: nil, - applicationProtocols: [], - shutdownTimeout: .seconds(5), - keyLogCallback: nil, - renegotiationSupport: .none, - additionalTrustRoots: [], - sendCANameList: false, - sslContextCallback: nil, - pskClientProvider: nil, - pskServerProvider: nil, - pskHint: nil) + TLSConfiguration( + cipherSuites: defaultCipherSuites, + verifySignatureAlgorithms: nil, + signingSignatureAlgorithms: nil, + minimumTLSVersion: .tlsv1, + maximumTLSVersion: nil, + certificateVerification: .fullVerification, + trustRoots: .default, + certificateChain: [], + privateKey: nil, + applicationProtocols: [], + shutdownTimeout: .seconds(5), + keyLogCallback: nil, + renegotiationSupport: .none, + additionalTrustRoots: [], + sendCANameList: false, + sslContextCallback: nil, + pskClientProvider: nil, + pskServerProvider: nil, + pskHint: nil + ) } /// Create a TLS configuration for use with server-side contexts. @@ -585,24 +585,26 @@ extension TLSConfiguration { certificateChain: [NIOSSLCertificateSource], privateKey: NIOSSLPrivateKeySource ) -> TLSConfiguration { - return TLSConfiguration(cipherSuites: defaultCipherSuites, - verifySignatureAlgorithms: nil, - signingSignatureAlgorithms: nil, - minimumTLSVersion: .tlsv1, - maximumTLSVersion: nil, - certificateVerification: .none, - trustRoots: .default, - certificateChain: certificateChain, - privateKey: privateKey, - applicationProtocols: [], - shutdownTimeout: .seconds(5), - keyLogCallback: nil, - renegotiationSupport: .none, - additionalTrustRoots: [], - sendCANameList: false, - pskClientProvider: nil, - pskServerProvider: nil, - pskHint: nil) + TLSConfiguration( + cipherSuites: defaultCipherSuites, + verifySignatureAlgorithms: nil, + signingSignatureAlgorithms: nil, + minimumTLSVersion: .tlsv1, + maximumTLSVersion: nil, + certificateVerification: .none, + trustRoots: .default, + certificateChain: certificateChain, + privateKey: privateKey, + applicationProtocols: [], + shutdownTimeout: .seconds(5), + keyLogCallback: nil, + renegotiationSupport: .none, + additionalTrustRoots: [], + sendCANameList: false, + pskClientProvider: nil, + pskServerProvider: nil, + pskHint: nil + ) } /// Create a TLS configuration for use with server-side or client-side contexts that uses Pre-Shared Keys for TLS 1.2 and below. @@ -613,24 +615,26 @@ extension TLSConfiguration { /// For customising fields, modify the returned TLSConfiguration object. public static func makePreSharedKeyConfiguration() -> TLSConfiguration { - return TLSConfiguration(cipherSuites: defaultCipherSuites, - verifySignatureAlgorithms: nil, - signingSignatureAlgorithms: nil, - minimumTLSVersion: .tlsv1, - maximumTLSVersion: nil, - certificateVerification: .none, - trustRoots: .default, - certificateChain: [], - privateKey: nil, - applicationProtocols: [], - shutdownTimeout: .seconds(5), - keyLogCallback: nil, - renegotiationSupport: .none, - additionalTrustRoots: [], - sendCANameList: false, - pskClientProvider: nil, - pskServerProvider: nil, - pskHint: nil) + TLSConfiguration( + cipherSuites: defaultCipherSuites, + verifySignatureAlgorithms: nil, + signingSignatureAlgorithms: nil, + minimumTLSVersion: .tlsv1, + maximumTLSVersion: nil, + certificateVerification: .none, + trustRoots: .default, + certificateChain: [], + privateKey: nil, + applicationProtocols: [], + shutdownTimeout: .seconds(5), + keyLogCallback: nil, + renegotiationSupport: .none, + additionalTrustRoots: [], + sendCANameList: false, + pskClientProvider: nil, + pskServerProvider: nil, + pskHint: nil + ) } } @@ -642,33 +646,37 @@ extension TLSConfiguration { /// This provides sensible defaults while requiring that you provide any data that is necessary /// for server-side function. For client use, try ``TLSConfiguration/makeClientConfiguration()`` instead. @available(*, deprecated, renamed: "makeServerConfiguration(certificateChain:privateKey:)") - public static func forServer(certificateChain: [NIOSSLCertificateSource], - privateKey: NIOSSLPrivateKeySource, - cipherSuites: [NIOTLSCipher], - verifySignatureAlgorithms: [SignatureAlgorithm]? = nil, - signingSignatureAlgorithms: [SignatureAlgorithm]? = nil, - minimumTLSVersion: TLSVersion = .tlsv1, - maximumTLSVersion: TLSVersion? = nil, - certificateVerification: CertificateVerification = .none, - trustRoots: NIOSSLTrustRoots = .default, - applicationProtocols: [String] = [], - shutdownTimeout: TimeAmount = .seconds(5), - keyLogCallback: NIOSSLKeyLogCallback? = nil, - additionalTrustRoots: [NIOSSLAdditionalTrustRoots] = []) -> TLSConfiguration { - return TLSConfiguration(cipherSuiteValues: cipherSuites, - verifySignatureAlgorithms: verifySignatureAlgorithms, - signingSignatureAlgorithms: signingSignatureAlgorithms, - minimumTLSVersion: minimumTLSVersion, - maximumTLSVersion: maximumTLSVersion, - certificateVerification: certificateVerification, - trustRoots: trustRoots, - certificateChain: certificateChain, - privateKey: privateKey, - applicationProtocols: applicationProtocols, - shutdownTimeout: shutdownTimeout, - keyLogCallback: keyLogCallback, - renegotiationSupport: .none, // Servers never support renegotiation: there's no point. - additionalTrustRoots: additionalTrustRoots) + public static func forServer( + certificateChain: [NIOSSLCertificateSource], + privateKey: NIOSSLPrivateKeySource, + cipherSuites: [NIOTLSCipher], + verifySignatureAlgorithms: [SignatureAlgorithm]? = nil, + signingSignatureAlgorithms: [SignatureAlgorithm]? = nil, + minimumTLSVersion: TLSVersion = .tlsv1, + maximumTLSVersion: TLSVersion? = nil, + certificateVerification: CertificateVerification = .none, + trustRoots: NIOSSLTrustRoots = .default, + applicationProtocols: [String] = [], + shutdownTimeout: TimeAmount = .seconds(5), + keyLogCallback: NIOSSLKeyLogCallback? = nil, + additionalTrustRoots: [NIOSSLAdditionalTrustRoots] = [] + ) -> TLSConfiguration { + TLSConfiguration( + cipherSuiteValues: cipherSuites, + verifySignatureAlgorithms: verifySignatureAlgorithms, + signingSignatureAlgorithms: signingSignatureAlgorithms, + minimumTLSVersion: minimumTLSVersion, + maximumTLSVersion: maximumTLSVersion, + certificateVerification: certificateVerification, + trustRoots: trustRoots, + certificateChain: certificateChain, + privateKey: privateKey, + applicationProtocols: applicationProtocols, + shutdownTimeout: shutdownTimeout, + keyLogCallback: keyLogCallback, + renegotiationSupport: .none, // Servers never support renegotiation: there's no point. + additionalTrustRoots: additionalTrustRoots + ) } /// Create a TLS configuration for use with server-side contexts. @@ -676,30 +684,34 @@ extension TLSConfiguration { /// This provides sensible defaults while requiring that you provide any data that is necessary /// for server-side function. For client use, try ``TLSConfiguration/makeClientConfiguration()`` instead. @available(*, deprecated, renamed: "makeServerConfiguration(certificateChain:privateKey:)") - public static func forServer(certificateChain: [NIOSSLCertificateSource], - privateKey: NIOSSLPrivateKeySource, - cipherSuites: String = defaultCipherSuites, - minimumTLSVersion: TLSVersion = .tlsv1, - maximumTLSVersion: TLSVersion? = nil, - certificateVerification: CertificateVerification = .none, - trustRoots: NIOSSLTrustRoots = .default, - applicationProtocols: [String] = [], - shutdownTimeout: TimeAmount = .seconds(5), - keyLogCallback: NIOSSLKeyLogCallback? = nil) -> TLSConfiguration { - return TLSConfiguration(cipherSuites: cipherSuites, - verifySignatureAlgorithms: nil, - signingSignatureAlgorithms: nil, - minimumTLSVersion: minimumTLSVersion, - maximumTLSVersion: maximumTLSVersion, - certificateVerification: certificateVerification, - trustRoots: trustRoots, - certificateChain: certificateChain, - privateKey: privateKey, - applicationProtocols: applicationProtocols, - shutdownTimeout: shutdownTimeout, - keyLogCallback: keyLogCallback, - renegotiationSupport: .none, // Servers never support renegotiation: there's no point. - additionalTrustRoots: []) + public static func forServer( + certificateChain: [NIOSSLCertificateSource], + privateKey: NIOSSLPrivateKeySource, + cipherSuites: String = defaultCipherSuites, + minimumTLSVersion: TLSVersion = .tlsv1, + maximumTLSVersion: TLSVersion? = nil, + certificateVerification: CertificateVerification = .none, + trustRoots: NIOSSLTrustRoots = .default, + applicationProtocols: [String] = [], + shutdownTimeout: TimeAmount = .seconds(5), + keyLogCallback: NIOSSLKeyLogCallback? = nil + ) -> TLSConfiguration { + TLSConfiguration( + cipherSuites: cipherSuites, + verifySignatureAlgorithms: nil, + signingSignatureAlgorithms: nil, + minimumTLSVersion: minimumTLSVersion, + maximumTLSVersion: maximumTLSVersion, + certificateVerification: certificateVerification, + trustRoots: trustRoots, + certificateChain: certificateChain, + privateKey: privateKey, + applicationProtocols: applicationProtocols, + shutdownTimeout: shutdownTimeout, + keyLogCallback: keyLogCallback, + renegotiationSupport: .none, // Servers never support renegotiation: there's no point. + additionalTrustRoots: [] + ) } /// Create a TLS configuration for use with server-side contexts. @@ -707,32 +719,36 @@ extension TLSConfiguration { /// This provides sensible defaults while requiring that you provide any data that is necessary /// for server-side function. For client use, try ``TLSConfiguration/makeClientConfiguration()`` instead. @available(*, deprecated, renamed: "makeServerConfiguration(certificateChain:privateKey:)") - public static func forServer(certificateChain: [NIOSSLCertificateSource], - privateKey: NIOSSLPrivateKeySource, - cipherSuites: String = defaultCipherSuites, - verifySignatureAlgorithms: [SignatureAlgorithm]? = nil, - signingSignatureAlgorithms: [SignatureAlgorithm]? = nil, - minimumTLSVersion: TLSVersion = .tlsv1, - maximumTLSVersion: TLSVersion? = nil, - certificateVerification: CertificateVerification = .none, - trustRoots: NIOSSLTrustRoots = .default, - applicationProtocols: [String] = [], - shutdownTimeout: TimeAmount = .seconds(5), - keyLogCallback: NIOSSLKeyLogCallback? = nil) -> TLSConfiguration { - return TLSConfiguration(cipherSuites: cipherSuites, - verifySignatureAlgorithms: verifySignatureAlgorithms, - signingSignatureAlgorithms: signingSignatureAlgorithms, - minimumTLSVersion: minimumTLSVersion, - maximumTLSVersion: maximumTLSVersion, - certificateVerification: certificateVerification, - trustRoots: trustRoots, - certificateChain: certificateChain, - privateKey: privateKey, - applicationProtocols: applicationProtocols, - shutdownTimeout: shutdownTimeout, - keyLogCallback: keyLogCallback, - renegotiationSupport: .none, // Servers never support renegotiation: there's no point. - additionalTrustRoots: []) + public static func forServer( + certificateChain: [NIOSSLCertificateSource], + privateKey: NIOSSLPrivateKeySource, + cipherSuites: String = defaultCipherSuites, + verifySignatureAlgorithms: [SignatureAlgorithm]? = nil, + signingSignatureAlgorithms: [SignatureAlgorithm]? = nil, + minimumTLSVersion: TLSVersion = .tlsv1, + maximumTLSVersion: TLSVersion? = nil, + certificateVerification: CertificateVerification = .none, + trustRoots: NIOSSLTrustRoots = .default, + applicationProtocols: [String] = [], + shutdownTimeout: TimeAmount = .seconds(5), + keyLogCallback: NIOSSLKeyLogCallback? = nil + ) -> TLSConfiguration { + TLSConfiguration( + cipherSuites: cipherSuites, + verifySignatureAlgorithms: verifySignatureAlgorithms, + signingSignatureAlgorithms: signingSignatureAlgorithms, + minimumTLSVersion: minimumTLSVersion, + maximumTLSVersion: maximumTLSVersion, + certificateVerification: certificateVerification, + trustRoots: trustRoots, + certificateChain: certificateChain, + privateKey: privateKey, + applicationProtocols: applicationProtocols, + shutdownTimeout: shutdownTimeout, + keyLogCallback: keyLogCallback, + renegotiationSupport: .none, // Servers never support renegotiation: there's no point. + additionalTrustRoots: [] + ) } /// Create a TLS configuration for use with server-side contexts. @@ -740,33 +756,37 @@ extension TLSConfiguration { /// This provides sensible defaults while requiring that you provide any data that is necessary /// for server-side function. For client use, try ``TLSConfiguration/makeClientConfiguration()`` instead. @available(*, deprecated, renamed: "makeServerConfiguration(certificateChain:privateKey:)") - public static func forServer(certificateChain: [NIOSSLCertificateSource], - privateKey: NIOSSLPrivateKeySource, - cipherSuites: String = defaultCipherSuites, - verifySignatureAlgorithms: [SignatureAlgorithm]? = nil, - signingSignatureAlgorithms: [SignatureAlgorithm]? = nil, - minimumTLSVersion: TLSVersion = .tlsv1, - maximumTLSVersion: TLSVersion? = nil, - certificateVerification: CertificateVerification = .none, - trustRoots: NIOSSLTrustRoots = .default, - applicationProtocols: [String] = [], - shutdownTimeout: TimeAmount = .seconds(5), - keyLogCallback: NIOSSLKeyLogCallback? = nil, - additionalTrustRoots: [NIOSSLAdditionalTrustRoots]) -> TLSConfiguration { - return TLSConfiguration(cipherSuites: cipherSuites, - verifySignatureAlgorithms: verifySignatureAlgorithms, - signingSignatureAlgorithms: signingSignatureAlgorithms, - minimumTLSVersion: minimumTLSVersion, - maximumTLSVersion: maximumTLSVersion, - certificateVerification: certificateVerification, - trustRoots: trustRoots, - certificateChain: certificateChain, - privateKey: privateKey, - applicationProtocols: applicationProtocols, - shutdownTimeout: shutdownTimeout, - keyLogCallback: keyLogCallback, - renegotiationSupport: .none, // Servers never support renegotiation: there's no point. - additionalTrustRoots: additionalTrustRoots) + public static func forServer( + certificateChain: [NIOSSLCertificateSource], + privateKey: NIOSSLPrivateKeySource, + cipherSuites: String = defaultCipherSuites, + verifySignatureAlgorithms: [SignatureAlgorithm]? = nil, + signingSignatureAlgorithms: [SignatureAlgorithm]? = nil, + minimumTLSVersion: TLSVersion = .tlsv1, + maximumTLSVersion: TLSVersion? = nil, + certificateVerification: CertificateVerification = .none, + trustRoots: NIOSSLTrustRoots = .default, + applicationProtocols: [String] = [], + shutdownTimeout: TimeAmount = .seconds(5), + keyLogCallback: NIOSSLKeyLogCallback? = nil, + additionalTrustRoots: [NIOSSLAdditionalTrustRoots] + ) -> TLSConfiguration { + TLSConfiguration( + cipherSuites: cipherSuites, + verifySignatureAlgorithms: verifySignatureAlgorithms, + signingSignatureAlgorithms: signingSignatureAlgorithms, + minimumTLSVersion: minimumTLSVersion, + maximumTLSVersion: maximumTLSVersion, + certificateVerification: certificateVerification, + trustRoots: trustRoots, + certificateChain: certificateChain, + privateKey: privateKey, + applicationProtocols: applicationProtocols, + shutdownTimeout: shutdownTimeout, + keyLogCallback: keyLogCallback, + renegotiationSupport: .none, // Servers never support renegotiation: there's no point. + additionalTrustRoots: additionalTrustRoots + ) } /// Creates a TLS configuration for use with client-side contexts. This allows setting the ``NIOTLSCipher`` property specifically. @@ -774,34 +794,38 @@ extension TLSConfiguration { /// This provides sensible defaults, and can be used without customisation. For server-side /// contexts, you should use ``TLSConfiguration/makeServerConfiguration(certificateChain:privateKey:)`` instead. @available(*, deprecated, renamed: "makeClientConfiguration()") - public static func forClient(cipherSuites: [NIOTLSCipher], - verifySignatureAlgorithms: [SignatureAlgorithm]? = nil, - signingSignatureAlgorithms: [SignatureAlgorithm]? = nil, - minimumTLSVersion: TLSVersion = .tlsv1, - maximumTLSVersion: TLSVersion? = nil, - certificateVerification: CertificateVerification = .fullVerification, - trustRoots: NIOSSLTrustRoots = .default, - certificateChain: [NIOSSLCertificateSource] = [], - privateKey: NIOSSLPrivateKeySource? = nil, - applicationProtocols: [String] = [], - shutdownTimeout: TimeAmount = .seconds(5), - keyLogCallback: NIOSSLKeyLogCallback? = nil, - renegotiationSupport: NIORenegotiationSupport = .none, - additionalTrustRoots: [NIOSSLAdditionalTrustRoots] = []) -> TLSConfiguration { - return TLSConfiguration(cipherSuiteValues: cipherSuites, - verifySignatureAlgorithms: verifySignatureAlgorithms, - signingSignatureAlgorithms: signingSignatureAlgorithms, - minimumTLSVersion: minimumTLSVersion, - maximumTLSVersion: maximumTLSVersion, - certificateVerification: certificateVerification, - trustRoots: trustRoots, - certificateChain: certificateChain, - privateKey: privateKey, - applicationProtocols: applicationProtocols, - shutdownTimeout: shutdownTimeout, - keyLogCallback: keyLogCallback, - renegotiationSupport: renegotiationSupport, - additionalTrustRoots: additionalTrustRoots) + public static func forClient( + cipherSuites: [NIOTLSCipher], + verifySignatureAlgorithms: [SignatureAlgorithm]? = nil, + signingSignatureAlgorithms: [SignatureAlgorithm]? = nil, + minimumTLSVersion: TLSVersion = .tlsv1, + maximumTLSVersion: TLSVersion? = nil, + certificateVerification: CertificateVerification = .fullVerification, + trustRoots: NIOSSLTrustRoots = .default, + certificateChain: [NIOSSLCertificateSource] = [], + privateKey: NIOSSLPrivateKeySource? = nil, + applicationProtocols: [String] = [], + shutdownTimeout: TimeAmount = .seconds(5), + keyLogCallback: NIOSSLKeyLogCallback? = nil, + renegotiationSupport: NIORenegotiationSupport = .none, + additionalTrustRoots: [NIOSSLAdditionalTrustRoots] = [] + ) -> TLSConfiguration { + TLSConfiguration( + cipherSuiteValues: cipherSuites, + verifySignatureAlgorithms: verifySignatureAlgorithms, + signingSignatureAlgorithms: signingSignatureAlgorithms, + minimumTLSVersion: minimumTLSVersion, + maximumTLSVersion: maximumTLSVersion, + certificateVerification: certificateVerification, + trustRoots: trustRoots, + certificateChain: certificateChain, + privateKey: privateKey, + applicationProtocols: applicationProtocols, + shutdownTimeout: shutdownTimeout, + keyLogCallback: keyLogCallback, + renegotiationSupport: renegotiationSupport, + additionalTrustRoots: additionalTrustRoots + ) } /// Creates a TLS configuration for use with client-side contexts. @@ -809,63 +833,70 @@ extension TLSConfiguration { /// This provides sensible defaults, and can be used without customisation. For server-side /// contexts, you should use ``TLSConfiguration/makeServerConfiguration(certificateChain:privateKey:)`` instead. @available(*, deprecated, renamed: "makeClientConfiguration()") - public static func forClient(cipherSuites: String = defaultCipherSuites, - minimumTLSVersion: TLSVersion = .tlsv1, - maximumTLSVersion: TLSVersion? = nil, - certificateVerification: CertificateVerification = .fullVerification, - trustRoots: NIOSSLTrustRoots = .default, - certificateChain: [NIOSSLCertificateSource] = [], - privateKey: NIOSSLPrivateKeySource? = nil, - applicationProtocols: [String] = [], - shutdownTimeout: TimeAmount = .seconds(5), - keyLogCallback: NIOSSLKeyLogCallback? = nil) -> TLSConfiguration { - return TLSConfiguration(cipherSuites: cipherSuites, - verifySignatureAlgorithms: nil, - signingSignatureAlgorithms: nil, - minimumTLSVersion: minimumTLSVersion, - maximumTLSVersion: maximumTLSVersion, - certificateVerification: certificateVerification, - trustRoots: trustRoots, - certificateChain: certificateChain, - privateKey: privateKey, - applicationProtocols: applicationProtocols, - shutdownTimeout: shutdownTimeout, - keyLogCallback: keyLogCallback, - renegotiationSupport: .none, // Default value is here for backward-compatibility. - additionalTrustRoots: []) + public static func forClient( + cipherSuites: String = defaultCipherSuites, + minimumTLSVersion: TLSVersion = .tlsv1, + maximumTLSVersion: TLSVersion? = nil, + certificateVerification: CertificateVerification = .fullVerification, + trustRoots: NIOSSLTrustRoots = .default, + certificateChain: [NIOSSLCertificateSource] = [], + privateKey: NIOSSLPrivateKeySource? = nil, + applicationProtocols: [String] = [], + shutdownTimeout: TimeAmount = .seconds(5), + keyLogCallback: NIOSSLKeyLogCallback? = nil + ) -> TLSConfiguration { + TLSConfiguration( + cipherSuites: cipherSuites, + verifySignatureAlgorithms: nil, + signingSignatureAlgorithms: nil, + minimumTLSVersion: minimumTLSVersion, + maximumTLSVersion: maximumTLSVersion, + certificateVerification: certificateVerification, + trustRoots: trustRoots, + certificateChain: certificateChain, + privateKey: privateKey, + applicationProtocols: applicationProtocols, + shutdownTimeout: shutdownTimeout, + keyLogCallback: keyLogCallback, + renegotiationSupport: .none, // Default value is here for backward-compatibility. + additionalTrustRoots: [] + ) } - /// Creates a TLS configuration for use with client-side contexts. /// /// This provides sensible defaults, and can be used without customisation. For server-side /// contexts, you should use ``TLSConfiguration/makeServerConfiguration(certificateChain:privateKey:)`` instead. @available(*, deprecated, renamed: "makeClientConfiguration()") - public static func forClient(cipherSuites: String = defaultCipherSuites, - minimumTLSVersion: TLSVersion = .tlsv1, - maximumTLSVersion: TLSVersion? = nil, - certificateVerification: CertificateVerification = .fullVerification, - trustRoots: NIOSSLTrustRoots = .default, - certificateChain: [NIOSSLCertificateSource] = [], - privateKey: NIOSSLPrivateKeySource? = nil, - applicationProtocols: [String] = [], - shutdownTimeout: TimeAmount = .seconds(5), - keyLogCallback: NIOSSLKeyLogCallback? = nil, - renegotiationSupport: NIORenegotiationSupport) -> TLSConfiguration { - return TLSConfiguration(cipherSuites: cipherSuites, - verifySignatureAlgorithms: nil, - signingSignatureAlgorithms: nil, - minimumTLSVersion: minimumTLSVersion, - maximumTLSVersion: maximumTLSVersion, - certificateVerification: certificateVerification, - trustRoots: trustRoots, - certificateChain: certificateChain, - privateKey: privateKey, - applicationProtocols: applicationProtocols, - shutdownTimeout: shutdownTimeout, - keyLogCallback: keyLogCallback, - renegotiationSupport: renegotiationSupport, - additionalTrustRoots: []) + public static func forClient( + cipherSuites: String = defaultCipherSuites, + minimumTLSVersion: TLSVersion = .tlsv1, + maximumTLSVersion: TLSVersion? = nil, + certificateVerification: CertificateVerification = .fullVerification, + trustRoots: NIOSSLTrustRoots = .default, + certificateChain: [NIOSSLCertificateSource] = [], + privateKey: NIOSSLPrivateKeySource? = nil, + applicationProtocols: [String] = [], + shutdownTimeout: TimeAmount = .seconds(5), + keyLogCallback: NIOSSLKeyLogCallback? = nil, + renegotiationSupport: NIORenegotiationSupport + ) -> TLSConfiguration { + TLSConfiguration( + cipherSuites: cipherSuites, + verifySignatureAlgorithms: nil, + signingSignatureAlgorithms: nil, + minimumTLSVersion: minimumTLSVersion, + maximumTLSVersion: maximumTLSVersion, + certificateVerification: certificateVerification, + trustRoots: trustRoots, + certificateChain: certificateChain, + privateKey: privateKey, + applicationProtocols: applicationProtocols, + shutdownTimeout: shutdownTimeout, + keyLogCallback: keyLogCallback, + renegotiationSupport: renegotiationSupport, + additionalTrustRoots: [] + ) } /// Creates a TLS configuration for use with client-side contexts. @@ -873,33 +904,37 @@ extension TLSConfiguration { /// This provides sensible defaults, and can be used without customisation. For server-side /// contexts, you should use ``TLSConfiguration/makeServerConfiguration(certificateChain:privateKey:)`` instead. @available(*, deprecated, renamed: "makeClientConfiguration()") - public static func forClient(cipherSuites: String = defaultCipherSuites, - verifySignatureAlgorithms: [SignatureAlgorithm]? = nil, - signingSignatureAlgorithms: [SignatureAlgorithm]? = nil, - minimumTLSVersion: TLSVersion = .tlsv1, - maximumTLSVersion: TLSVersion? = nil, - certificateVerification: CertificateVerification = .fullVerification, - trustRoots: NIOSSLTrustRoots = .default, - certificateChain: [NIOSSLCertificateSource] = [], - privateKey: NIOSSLPrivateKeySource? = nil, - applicationProtocols: [String] = [], - shutdownTimeout: TimeAmount = .seconds(5), - keyLogCallback: NIOSSLKeyLogCallback? = nil, - renegotiationSupport: NIORenegotiationSupport) -> TLSConfiguration { - return TLSConfiguration(cipherSuites: cipherSuites, - verifySignatureAlgorithms: verifySignatureAlgorithms, - signingSignatureAlgorithms: signingSignatureAlgorithms, - minimumTLSVersion: minimumTLSVersion, - maximumTLSVersion: maximumTLSVersion, - certificateVerification: certificateVerification, - trustRoots: trustRoots, - certificateChain: certificateChain, - privateKey: privateKey, - applicationProtocols: applicationProtocols, - shutdownTimeout: shutdownTimeout, - keyLogCallback: keyLogCallback, - renegotiationSupport: renegotiationSupport, - additionalTrustRoots: []) + public static func forClient( + cipherSuites: String = defaultCipherSuites, + verifySignatureAlgorithms: [SignatureAlgorithm]? = nil, + signingSignatureAlgorithms: [SignatureAlgorithm]? = nil, + minimumTLSVersion: TLSVersion = .tlsv1, + maximumTLSVersion: TLSVersion? = nil, + certificateVerification: CertificateVerification = .fullVerification, + trustRoots: NIOSSLTrustRoots = .default, + certificateChain: [NIOSSLCertificateSource] = [], + privateKey: NIOSSLPrivateKeySource? = nil, + applicationProtocols: [String] = [], + shutdownTimeout: TimeAmount = .seconds(5), + keyLogCallback: NIOSSLKeyLogCallback? = nil, + renegotiationSupport: NIORenegotiationSupport + ) -> TLSConfiguration { + TLSConfiguration( + cipherSuites: cipherSuites, + verifySignatureAlgorithms: verifySignatureAlgorithms, + signingSignatureAlgorithms: signingSignatureAlgorithms, + minimumTLSVersion: minimumTLSVersion, + maximumTLSVersion: maximumTLSVersion, + certificateVerification: certificateVerification, + trustRoots: trustRoots, + certificateChain: certificateChain, + privateKey: privateKey, + applicationProtocols: applicationProtocols, + shutdownTimeout: shutdownTimeout, + keyLogCallback: keyLogCallback, + renegotiationSupport: renegotiationSupport, + additionalTrustRoots: [] + ) } /// Creates a TLS configuration for use with client-side contexts. @@ -907,34 +942,38 @@ extension TLSConfiguration { /// This provides sensible defaults, and can be used without customisation. For server-side /// contexts, you should use ``TLSConfiguration/makeServerConfiguration(certificateChain:privateKey:)`` instead. @available(*, deprecated, renamed: "makeClientConfiguration()") - public static func forClient(cipherSuites: String = defaultCipherSuites, - verifySignatureAlgorithms: [SignatureAlgorithm]? = nil, - signingSignatureAlgorithms: [SignatureAlgorithm]? = nil, - minimumTLSVersion: TLSVersion = .tlsv1, - maximumTLSVersion: TLSVersion? = nil, - certificateVerification: CertificateVerification = .fullVerification, - trustRoots: NIOSSLTrustRoots = .default, - certificateChain: [NIOSSLCertificateSource] = [], - privateKey: NIOSSLPrivateKeySource? = nil, - applicationProtocols: [String] = [], - shutdownTimeout: TimeAmount = .seconds(5), - keyLogCallback: NIOSSLKeyLogCallback? = nil, - renegotiationSupport: NIORenegotiationSupport = .none, - additionalTrustRoots: [NIOSSLAdditionalTrustRoots]) -> TLSConfiguration { - return TLSConfiguration(cipherSuites: cipherSuites, - verifySignatureAlgorithms: verifySignatureAlgorithms, - signingSignatureAlgorithms: signingSignatureAlgorithms, - minimumTLSVersion: minimumTLSVersion, - maximumTLSVersion: maximumTLSVersion, - certificateVerification: certificateVerification, - trustRoots: trustRoots, - certificateChain: certificateChain, - privateKey: privateKey, - applicationProtocols: applicationProtocols, - shutdownTimeout: shutdownTimeout, - keyLogCallback: keyLogCallback, - renegotiationSupport: renegotiationSupport, - additionalTrustRoots: additionalTrustRoots) + public static func forClient( + cipherSuites: String = defaultCipherSuites, + verifySignatureAlgorithms: [SignatureAlgorithm]? = nil, + signingSignatureAlgorithms: [SignatureAlgorithm]? = nil, + minimumTLSVersion: TLSVersion = .tlsv1, + maximumTLSVersion: TLSVersion? = nil, + certificateVerification: CertificateVerification = .fullVerification, + trustRoots: NIOSSLTrustRoots = .default, + certificateChain: [NIOSSLCertificateSource] = [], + privateKey: NIOSSLPrivateKeySource? = nil, + applicationProtocols: [String] = [], + shutdownTimeout: TimeAmount = .seconds(5), + keyLogCallback: NIOSSLKeyLogCallback? = nil, + renegotiationSupport: NIORenegotiationSupport = .none, + additionalTrustRoots: [NIOSSLAdditionalTrustRoots] + ) -> TLSConfiguration { + TLSConfiguration( + cipherSuites: cipherSuites, + verifySignatureAlgorithms: verifySignatureAlgorithms, + signingSignatureAlgorithms: signingSignatureAlgorithms, + minimumTLSVersion: minimumTLSVersion, + maximumTLSVersion: maximumTLSVersion, + certificateVerification: certificateVerification, + trustRoots: trustRoots, + certificateChain: certificateChain, + privateKey: privateKey, + applicationProtocols: applicationProtocols, + shutdownTimeout: shutdownTimeout, + keyLogCallback: keyLogCallback, + renegotiationSupport: renegotiationSupport, + additionalTrustRoots: additionalTrustRoots + ) } } diff --git a/Sources/NIOSSL/UniversalBootstrapSupport.swift b/Sources/NIOSSL/UniversalBootstrapSupport.swift index c19155bf3..f47cad9ce 100644 --- a/Sources/NIOSSL/UniversalBootstrapSupport.swift +++ b/Sources/NIOSSL/UniversalBootstrapSupport.swift @@ -36,15 +36,21 @@ public struct NIOSSLClientTLSProvider: let context: NIOSSLContext let serverHostname: String? /// See ``NIOSSLCustomVerificationCallback`` for more documentation - let customVerificationCallback: (@Sendable ([NIOSSLCertificate], EventLoopPromise) -> Void)? + let customVerificationCallback: + (@Sendable ([NIOSSLCertificate], EventLoopPromise) -> Void)? /// See ``_NIOAdditionalPeerCertificateVerificationCallback`` for more documentation - let additionalPeerCertificateVerificationCallback: (@Sendable (NIOSSLCertificate, Channel) -> EventLoopFuture)? + let additionalPeerCertificateVerificationCallback: + (@Sendable (NIOSSLCertificate, Channel) -> EventLoopFuture)? internal init( context: NIOSSLContext, serverHostname: String?, - customVerificationCallback: (@Sendable ([NIOSSLCertificate], EventLoopPromise) -> Void)? = nil, - additionalPeerCertificateVerificationCallback: (@Sendable (NIOSSLCertificate, Channel) -> EventLoopFuture)? = nil + customVerificationCallback: ( + @Sendable ([NIOSSLCertificate], EventLoopPromise) -> Void + )? = nil, + additionalPeerCertificateVerificationCallback: ( + @Sendable (NIOSSLCertificate, Channel) -> EventLoopFuture + )? = nil ) throws { try serverHostname.map { try $0.validateSNIServerName() @@ -69,9 +75,16 @@ public struct NIOSSLClientTLSProvider: public init( context: NIOSSLContext, serverHostname: String?, - customVerificationCallback: (@Sendable ([NIOSSLCertificate], EventLoopPromise) -> Void)? = nil + customVerificationCallback: ( + @Sendable ([NIOSSLCertificate], EventLoopPromise) -> Void + )? = nil ) throws { - try self.init(context: context, serverHostname: serverHostname, customVerificationCallback: customVerificationCallback, additionalPeerCertificateVerificationCallback: nil) + try self.init( + context: context, + serverHostname: serverHostname, + customVerificationCallback: customVerificationCallback, + additionalPeerCertificateVerificationCallback: nil + ) } /// Enable TLS on the bootstrap. This is not a function you will typically call as a user, it is called by @@ -79,7 +92,7 @@ public struct NIOSSLClientTLSProvider: public func enableTLS(_ bootstrap: Bootstrap) -> Bootstrap { // NIOSSLClientHandler.init only throws because of `malloc` error and invalid SNI hostnames. We want to crash // on malloc error and we pre-checked the SNI hostname in `init` so that should be impossible here. - return bootstrap.protocolHandlers { + bootstrap.protocolHandlers { [ try! NIOSSLClientHandler( context: self.context, diff --git a/Sources/NIOSSLHTTP1Client/main.swift b/Sources/NIOSSLHTTP1Client/main.swift index 602aa4f86..ce5b4e038 100644 --- a/Sources/NIOSSLHTTP1Client/main.swift +++ b/Sources/NIOSSLHTTP1Client/main.swift @@ -12,12 +12,12 @@ // //===----------------------------------------------------------------------===// +import Foundation import NIOCore -import NIOPosix import NIOFoundationCompat import NIOHTTP1 +import NIOPosix import NIOSSL -import Foundation private final class HTTPResponseHandler: ChannelInboundHandler { @@ -35,7 +35,9 @@ private final class HTTPResponseHandler: ChannelInboundHandler { let httpResponsePart = unwrapInboundIn(data) switch httpResponsePart { case .head(let httpResponseHeader): - print("\(httpResponseHeader.version) \(httpResponseHeader.status.code) \(httpResponseHeader.status.reasonPhrase)") + print( + "\(httpResponseHeader.version) \(httpResponseHeader.status.code) \(httpResponseHeader.status.reasonPhrase)" + ) for (name, value) in httpResponseHeader.headers { print("\(name): \(value)") } @@ -104,28 +106,32 @@ tlsConfiguration.renegotiationSupport = .once let sslContext = try! NIOSSLContext(configuration: tlsConfiguration) let bootstrap = ClientBootstrap(group: eventLoopGroup) - .channelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1) - .channelInitializer { channel in - let openSslHandler = try! NIOSSLClientHandler(context: sslContext, serverHostname: url.host) - return channel.pipeline.addHandler(openSslHandler).flatMap { - channel.pipeline.addHTTPClientHandlers() - }.flatMap { - channel.pipeline.addHandler(HTTPResponseHandler(promise)) - } + .channelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1) + .channelInitializer { channel in + let openSslHandler = try! NIOSSLClientHandler(context: sslContext, serverHostname: url.host) + return channel.pipeline.addHandler(openSslHandler).flatMap { + channel.pipeline.addHTTPClientHandlers() + }.flatMap { + channel.pipeline.addHandler(HTTPResponseHandler(promise)) } + } func sendRequest(_ channel: Channel) -> EventLoopFuture { - var request = HTTPRequestHead(version: HTTPVersion(major: 1, minor: 1), method: HTTPMethod.GET, uri: url.absoluteString) + var request = HTTPRequestHead( + version: HTTPVersion(major: 1, minor: 1), + method: HTTPMethod.GET, + uri: url.absoluteString + ) request.headers = HTTPHeaders([ ("Host", url.host!), ("User-Agent", "swift-nio"), ("Accept", "application/json"), - ("Connection", "close") + ("Connection", "close"), ]) channel.write(HTTPClientRequestPart.head(request), promise: nil) return channel.writeAndFlush(HTTPClientRequestPart.end(nil)) } bootstrap.connect(host: url.host!, port: url.port ?? 443) - .flatMap { sendRequest($0) } - .cascadeFailure(to: promise) + .flatMap { sendRequest($0) } + .cascadeFailure(to: promise) diff --git a/Sources/NIOSSLPerformanceTester/BenchManyWrites.swift b/Sources/NIOSSLPerformanceTester/BenchManyWrites.swift index ef2447082..24886e525 100644 --- a/Sources/NIOSSLPerformanceTester/BenchManyWrites.swift +++ b/Sources/NIOSSLPerformanceTester/BenchManyWrites.swift @@ -27,10 +27,12 @@ final class BenchManyWrites: Benchmark { init(loopCount: Int, writeSizeInBytes writeSize: Int) throws { self.loopCount = loopCount self.writeSize = writeSize - self.serverContext = try NIOSSLContext(configuration: .makeServerConfiguration( - certificateChain: [.certificate(.forTesting())], - privateKey: .privateKey(.forTesting()) - )) + self.serverContext = try NIOSSLContext( + configuration: .makeServerConfiguration( + certificateChain: [.certificate(.forTesting())], + privateKey: .privateKey(.forTesting()) + ) + ) var clientConfig = TLSConfiguration.makeClientConfiguration() clientConfig.trustRoots = try .certificates([.forTesting()]) @@ -56,7 +58,7 @@ final class BenchManyWrites: Benchmark { } - func tearDown() { } + func tearDown() {} func run() throws -> Int { guard let buffer = self.buffer else { @@ -73,7 +75,7 @@ final class BenchManyWrites: Benchmark { try self.backToBack.interactInMemory() // Pull any data out of the server to avoid ballooning in memory. - while let _ = try self.backToBack.server.readInbound(as: ByteBuffer.self) { } + while let _ = try self.backToBack.server.readInbound(as: ByteBuffer.self) {} } return self.loopCount diff --git a/Sources/NIOSSLPerformanceTester/BenchRepeatedHandshakes.swift b/Sources/NIOSSLPerformanceTester/BenchRepeatedHandshakes.swift index ca8ac7cb3..a13cc1298 100644 --- a/Sources/NIOSSLPerformanceTester/BenchRepeatedHandshakes.swift +++ b/Sources/NIOSSLPerformanceTester/BenchRepeatedHandshakes.swift @@ -24,19 +24,21 @@ final class BenchRepeatedHandshakes: Benchmark { init(loopCount: Int) throws { self.loopCount = loopCount self.dummyAddress = try SocketAddress(ipAddress: "1.2.3.4", port: 5678) - self.serverContext = try NIOSSLContext(configuration: .makeServerConfiguration( - certificateChain: [.certificate(.forTesting())], - privateKey: .privateKey(.forTesting()) - )) + self.serverContext = try NIOSSLContext( + configuration: .makeServerConfiguration( + certificateChain: [.certificate(.forTesting())], + privateKey: .privateKey(.forTesting()) + ) + ) var clientConfig = TLSConfiguration.makeClientConfiguration() clientConfig.trustRoots = try .certificates([.forTesting()]) self.clientContext = try NIOSSLContext(configuration: clientConfig) } - func setUp() { } + func setUp() {} - func tearDown() { } + func tearDown() {} func run() throws -> Int { for _ in 0..(desc: String, benchmark bench: B) throws { bench.tearDown() } try measureAndPrint(desc: desc) { - return try bench.run() + try bench.run() } } diff --git a/Sources/NIOSSLPerformanceTester/main.swift b/Sources/NIOSSLPerformanceTester/main.swift index 1ad1de030..caf31f9b7 100644 --- a/Sources/NIOSSLPerformanceTester/main.swift +++ b/Sources/NIOSSLPerformanceTester/main.swift @@ -12,19 +12,21 @@ // //===----------------------------------------------------------------------===// -import Foundation import Dispatch +import Foundation // MARK: Test Harness var warning: String = "" -assert({ - print("======================================================") - print("= YOU ARE RUNNING NIOPerformanceTester IN DEBUG MODE =") - print("======================================================") - warning = " <<< DEBUG MODE >>>" - return true -}()) +assert( + { + print("======================================================") + print("= YOU ARE RUNNING NIOPerformanceTester IN DEBUG MODE =") + print("======================================================") + warning = " <<< DEBUG MODE >>>" + return true + }() +) public func measure(_ fn: () throws -> Int) rethrows -> [TimeInterval] { func measureOne(_ fn: () throws -> Int) rethrows -> TimeInterval { @@ -34,7 +36,7 @@ public func measure(_ fn: () throws -> Int) rethrows -> [TimeInterval] { return end.timeIntervalSince(start) } - _ = try measureOne(fn) /* pre-heat and throw away */ + _ = try measureOne(fn) // pre-heat and throw away var measurements = Array(repeating: 0.0, count: 10) for i in 0..<10 { measurements[i] = try measureOne(fn) @@ -45,7 +47,7 @@ public func measure(_ fn: () throws -> Int) rethrows -> [TimeInterval] { let limitSet = CommandLine.arguments.dropFirst() -public func measureAndPrint(desc: String, fn: () throws -> Int) rethrows -> Void { +public func measureAndPrint(desc: String, fn: () throws -> Int) rethrows { if limitSet.count == 0 || limitSet.contains(desc) { print("measuring\(warning): \(desc): ", terminator: "") let measurements = try measure(fn) diff --git a/Sources/NIOSSLPerformanceTester/shared.swift b/Sources/NIOSSLPerformanceTester/shared.swift index 3e0879abe..3e46d79b4 100644 --- a/Sources/NIOSSLPerformanceTester/shared.swift +++ b/Sources/NIOSSLPerformanceTester/shared.swift @@ -21,7 +21,6 @@ class BackToBackEmbeddedChannel { private(set) var server: EmbeddedChannel private var loop: EmbeddedEventLoop - init() { self.loop = EmbeddedEventLoop() self.client = EmbeddedChannel(loop: self.loop) @@ -55,39 +54,39 @@ class BackToBackEmbeddedChannel { } } - extension NIOSSLCertificate { static func forTesting() throws -> NIOSSLCertificate { - return try .init(bytes: certificatePemBytes, format: .pem) + try .init(bytes: certificatePemBytes, format: .pem) } } - extension NIOSSLPrivateKey { static func forTesting() throws -> NIOSSLPrivateKey { - return try .init(bytes: keyPemBytes, format: .pem) + try .init(bytes: keyPemBytes, format: .pem) } } - -fileprivate let certificatePemBytes = Array(""" ------BEGIN CERTIFICATE----- -MIIBTzCB9qADAgECAhQkvv72Je/v+B/cgJ53f84O82z6WTAKBggqhkjOPQQDAjAU -MRIwEAYDVQQDDAlsb2NhbGhvc3QwHhcNMTkxMTI3MTAxMjMwWhcNMjkxMTI0MTAx -MjMwWjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwWTATBgcqhkjOPQIBBggqhkjOPQMB -BwNCAAShtZ9TRt7I+7Y0o99XUkrgSYmUmpr4K8CB0IkTCX6b1tXp3Xqs1V5BckTd -qrls+zsm3AfeiNBb9EDdxiX9DdzuoyYwJDAUBgNVHREEDTALgglsb2NhbGhvc3Qw -DAYDVR0TAQH/BAIwADAKBggqhkjOPQQDAgNIADBFAiAKxYON+YTnIHNR0R6SLP8R -R7hjsjV5NDs18XLoeRnA1gIhANwyggmE6NQW/r9l59fexj/ZrjaS3jYOTNCfC1Lo -5NgJ ------END CERTIFICATE----- -""".utf8) - - -fileprivate let keyPemBytes = Array(""" ------BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgCn182hBmYVMAiNPO -+7w05F40SlAqqxgBEYJZOeK47aihRANCAAShtZ9TRt7I+7Y0o99XUkrgSYmUmpr4 -K8CB0IkTCX6b1tXp3Xqs1V5BckTdqrls+zsm3AfeiNBb9EDdxiX9Ddzu ------END PRIVATE KEY----- -""".utf8) +private let certificatePemBytes = Array( + """ + -----BEGIN CERTIFICATE----- + MIIBTzCB9qADAgECAhQkvv72Je/v+B/cgJ53f84O82z6WTAKBggqhkjOPQQDAjAU + MRIwEAYDVQQDDAlsb2NhbGhvc3QwHhcNMTkxMTI3MTAxMjMwWhcNMjkxMTI0MTAx + MjMwWjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwWTATBgcqhkjOPQIBBggqhkjOPQMB + BwNCAAShtZ9TRt7I+7Y0o99XUkrgSYmUmpr4K8CB0IkTCX6b1tXp3Xqs1V5BckTd + qrls+zsm3AfeiNBb9EDdxiX9DdzuoyYwJDAUBgNVHREEDTALgglsb2NhbGhvc3Qw + DAYDVR0TAQH/BAIwADAKBggqhkjOPQQDAgNIADBFAiAKxYON+YTnIHNR0R6SLP8R + R7hjsjV5NDs18XLoeRnA1gIhANwyggmE6NQW/r9l59fexj/ZrjaS3jYOTNCfC1Lo + 5NgJ + -----END CERTIFICATE----- + """.utf8 +) + +private let keyPemBytes = Array( + """ + -----BEGIN PRIVATE KEY----- + MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgCn182hBmYVMAiNPO + +7w05F40SlAqqxgBEYJZOeK47aihRANCAAShtZ9TRt7I+7Y0o99XUkrgSYmUmpr4 + K8CB0IkTCX6b1tXp3Xqs1V5BckTdqrls+zsm3AfeiNBb9EDdxiX9Ddzu + -----END PRIVATE KEY----- + """.utf8 +) diff --git a/Sources/NIOTLSServer/main.swift b/Sources/NIOTLSServer/main.swift index 2d40693a3..05357a9a5 100644 --- a/Sources/NIOTLSServer/main.swift +++ b/Sources/NIOTLSServer/main.swift @@ -12,11 +12,12 @@ // //===----------------------------------------------------------------------===// -import struct Foundation.URL import NIOCore import NIOPosix import NIOSSL +import struct Foundation.URL + private final class EchoHandler: ChannelInboundHandler { public typealias InboundIn = ByteBuffer @@ -31,12 +32,13 @@ private final class EchoHandler: ChannelInboundHandler { let certificateChain = try NIOSSLCertificate.fromPEMFile("cert.pem") let privateKey = try! NIOSSLPrivateKey(file: "key.pem", format: .pem) -let sslContext = try! NIOSSLContext(configuration: TLSConfiguration.makeServerConfiguration( - certificateChain: certificateChain.map { .certificate($0) }, - privateKey: .privateKey(privateKey)) +let sslContext = try! NIOSSLContext( + configuration: TLSConfiguration.makeServerConfiguration( + certificateChain: certificateChain.map { .certificate($0) }, + privateKey: .privateKey(privateKey) + ) ) - let group = MultiThreadedEventLoopGroup(numberOfThreads: 1) let bootstrap = ServerBootstrap(group: group) // Specify backlog and enable SO_REUSEADDR for the server itself @@ -45,7 +47,7 @@ let bootstrap = ServerBootstrap(group: group) // Set the handlers that are applied to the accepted channels. .childChannelInitializer { channel in - return channel.pipeline.addHandler(NIOSSLServerHandler(context: sslContext)).flatMap { + channel.pipeline.addHandler(NIOSSLServerHandler(context: sslContext)).flatMap { channel.pipeline.addHandler(EchoHandler()) } } @@ -66,12 +68,12 @@ let arg2 = arguments.dropFirst().dropFirst().first var host: String = "::1" var port: Int = 4433 switch (arg1, arg1.flatMap { Int($0) }, arg2.flatMap { Int($0) }) { -case (.some(let h), _ , .some(let p)): - /* we got two arguments, let's interpret that as host and port */ +case (.some(let h), _, .some(let p)): + // we got two arguments, let's interpret that as host and port host = h port = p case (_, .some(let p), _): - /* only one argument --> port */ + // only one argument --> port port = p default: () diff --git a/Tests/NIOSSLTests/ByteBufferBIOTest.swift b/Tests/NIOSSLTests/ByteBufferBIOTest.swift index 3939a7449..e627bc032 100644 --- a/Tests/NIOSSLTests/ByteBufferBIOTest.swift +++ b/Tests/NIOSSLTests/ByteBufferBIOTest.swift @@ -12,11 +12,11 @@ // //===----------------------------------------------------------------------===// -import XCTest -import NIOCore @_implementationOnly import CNIOBoringSSL -@testable import NIOSSL +import NIOCore +import XCTest +@testable import NIOSSL final class ByteBufferBIOTest: XCTestCase { override func setUp() { @@ -46,7 +46,11 @@ final class ByteBufferBIOTest: XCTestCase { let rc = CNIOBoringSSL_BIO_write(cBIO, &bytesToWrite, 5) XCTAssertEqual(rc, 5) - guard let extractedBytes = swiftBIO.outboundCiphertext().flatMap({ $0.getBytes(at: $0.readerIndex, length: $0.readableBytes) }) else { + guard + let extractedBytes = swiftBIO.outboundCiphertext().flatMap({ + $0.getBytes(at: $0.readerIndex, length: $0.readableBytes) + }) + else { XCTFail("No received bytes") return } @@ -72,7 +76,11 @@ final class ByteBufferBIOTest: XCTestCase { expectedBytes.append(contentsOf: bytesToWrite) } - guard let extractedBytes = swiftBIO.outboundCiphertext().flatMap({ $0.getBytes(at: $0.readerIndex, length: $0.readableBytes) }) else { + guard + let extractedBytes = swiftBIO.outboundCiphertext().flatMap({ + $0.getBytes(at: $0.readerIndex, length: $0.readableBytes) + }) + else { XCTFail("No received bytes") return } @@ -284,7 +292,9 @@ final class ByteBufferBIOTest: XCTestCase { } XCTAssertEqual(rc, 13) - let extractedString = swiftBIO.outboundCiphertext().flatMap { $0.getString(at: $0.readerIndex, length: $0.readableBytes) } + let extractedString = swiftBIO.outboundCiphertext().flatMap { + $0.getString(at: $0.readerIndex, length: $0.readableBytes) + } XCTAssertEqual(extractedString, stringToWrite) XCTAssertNil(swiftBIO.outboundCiphertext()) } @@ -301,7 +311,7 @@ final class ByteBufferBIOTest: XCTestCase { buffer.writeStaticString("Hello, world!") swiftBIO.receiveFromNetwork(buffer: buffer) - var output = Array(repeating: 0, count: 1024) + var output = [CChar](repeating: 0, count: 1024) output.withUnsafeMutableBufferPointer { pointer in let rc = CNIOBoringSSL_BIO_gets(cBIO, pointer.baseAddress, CInt(pointer.count)) @@ -378,9 +388,8 @@ final class ByteBufferBIOTest: XCTestCase { } } - extension ByteBuffer { func baseAddress() -> UInt { - return self.withVeryUnsafeBytes { return UInt(bitPattern: $0.baseAddress! )} + self.withVeryUnsafeBytes { UInt(bitPattern: $0.baseAddress!) } } } diff --git a/Tests/NIOSSLTests/CertificateVerificationTests.swift b/Tests/NIOSSLTests/CertificateVerificationTests.swift index ddb5e5a1c..79219c143 100644 --- a/Tests/NIOSSLTests/CertificateVerificationTests.swift +++ b/Tests/NIOSSLTests/CertificateVerificationTests.swift @@ -13,14 +13,15 @@ //===----------------------------------------------------------------------===// import XCTest + @testable import NIOSSL final class CertificateVerificationTests: XCTestCase { func testCanFindCAFileOnLinux() { // This test only runs on Linux #if os(Linux) - // A valid Linux system means we can find a CA file. - XCTAssertNotNil(rootCAFilePath) + // A valid Linux system means we can find a CA file. + XCTAssertNotNil(rootCAFilePath) #endif } } diff --git a/Tests/NIOSSLTests/ClientSNITests.swift b/Tests/NIOSSLTests/ClientSNITests.swift index ab99f14f3..2bd7aef81 100644 --- a/Tests/NIOSSLTests/ClientSNITests.swift +++ b/Tests/NIOSSLTests/ClientSNITests.swift @@ -12,12 +12,11 @@ // //===----------------------------------------------------------------------===// -import XCTest import NIOCore import NIOPosix -import NIOTLS import NIOSSL - +import NIOTLS +import XCTest class ClientSNITests: XCTestCase { static var cert: NIOSSLCertificate! @@ -49,21 +48,30 @@ class ClientSNITests: XCTestCase { } let sniPromise: EventLoopPromise = group.next().makePromise() - let sniHandler = ByteToMessageHandler(SNIHandler { - sniPromise.succeed($0) - return group.next().makeSucceededFuture(()) - }) - let serverChannel = try serverTLSChannel(context: context, preHandlers: [sniHandler], postHandlers: [], group: group) + let sniHandler = ByteToMessageHandler( + SNIHandler { + sniPromise.succeed($0) + return group.next().makeSucceededFuture(()) + } + ) + let serverChannel = try serverTLSChannel( + context: context, + preHandlers: [sniHandler], + postHandlers: [], + group: group + ) defer { _ = try? serverChannel.close().wait() } - let clientChannel = try clientTLSChannel(context: context, - preHandlers: [], - postHandlers: [], - group: group, - connectingTo: serverChannel.localAddress!, - serverHostname: sniField) + let clientChannel = try clientTLSChannel( + context: context, + preHandlers: [], + postHandlers: [], + group: group, + connectingTo: serverChannel.localAddress!, + serverHostname: sniField + ) defer { _ = try? clientChannel.close().wait() } @@ -84,22 +92,24 @@ class ClientSNITests: XCTestCase { let context = try configuredSSLContext() let testString = "192.168.0.1" - XCTAssertThrowsError(try NIOSSLClientTLSProvider(context: context, serverHostname: testString)) { error in + XCTAssertThrowsError(try NIOSSLClientTLSProvider(context: context, serverHostname: testString)) + { error in XCTAssertEqual(.cannotUseIPAddressInSNI, error as? NIOSSLExtraError) } - XCTAssertThrowsError(try NIOSSLClientHandler(context: context, serverHostname: testString)){ error in + XCTAssertThrowsError(try NIOSSLClientHandler(context: context, serverHostname: testString)) { error in XCTAssertEqual(.cannotUseIPAddressInSNI, error as? NIOSSLExtraError) } } func testSNIIsRejectedForIPv6Addresses() throws { let context = try configuredSSLContext() - + let testString = "fe80::200:f8ff:fe21:67cf" - XCTAssertThrowsError(try NIOSSLClientTLSProvider(context: context, serverHostname: testString)) { error in + XCTAssertThrowsError(try NIOSSLClientTLSProvider(context: context, serverHostname: testString)) + { error in XCTAssertEqual(.cannotUseIPAddressInSNI, error as? NIOSSLExtraError) } - XCTAssertThrowsError(try NIOSSLClientHandler(context: context, serverHostname: testString)){ error in + XCTAssertThrowsError(try NIOSSLClientHandler(context: context, serverHostname: testString)) { error in XCTAssertEqual(.cannotUseIPAddressInSNI, error as? NIOSSLExtraError) } @@ -109,10 +119,11 @@ class ClientSNITests: XCTestCase { let context = try configuredSSLContext() let testString = "" - XCTAssertThrowsError(try NIOSSLClientTLSProvider(context: context, serverHostname: testString)) { error in + XCTAssertThrowsError(try NIOSSLClientTLSProvider(context: context, serverHostname: testString)) + { error in XCTAssertEqual(.invalidSNIHostname, error as? NIOSSLExtraError) } - XCTAssertThrowsError(try NIOSSLClientHandler(context: context, serverHostname: testString)){ error in + XCTAssertThrowsError(try NIOSSLClientHandler(context: context, serverHostname: testString)) { error in XCTAssertEqual(.invalidSNIHostname, error as? NIOSSLExtraError) } } @@ -121,10 +132,11 @@ class ClientSNITests: XCTestCase { let context = try configuredSSLContext() let testString = String(repeating: "x", count: 256) - XCTAssertThrowsError(try NIOSSLClientTLSProvider(context: context, serverHostname: testString)) { error in + XCTAssertThrowsError(try NIOSSLClientTLSProvider(context: context, serverHostname: testString)) + { error in XCTAssertEqual(.invalidSNIHostname, error as? NIOSSLExtraError) } - XCTAssertThrowsError(try NIOSSLClientHandler(context: context, serverHostname: testString)){ error in + XCTAssertThrowsError(try NIOSSLClientHandler(context: context, serverHostname: testString)) { error in XCTAssertEqual(.invalidSNIHostname, error as? NIOSSLExtraError) } } @@ -133,7 +145,8 @@ class ClientSNITests: XCTestCase { let context = try configuredSSLContext() let testString = String(UnicodeScalar(0)!) - XCTAssertThrowsError(try NIOSSLClientTLSProvider(context: context, serverHostname: testString)) { error in + XCTAssertThrowsError(try NIOSSLClientTLSProvider(context: context, serverHostname: testString)) + { error in XCTAssertEqual(.invalidSNIHostname, error as? NIOSSLExtraError) } XCTAssertThrowsError(try NIOSSLClientHandler(context: context, serverHostname: testString)) { error in @@ -144,7 +157,7 @@ class ClientSNITests: XCTestCase { func testSNIIsNotRejectedForAnyOfTheFirst1000CodeUnits() throws { let context = try configuredSSLContext() - for testString in (1...Int(1000)).compactMap({ UnicodeScalar($0).map({ String($0) })}) { + for testString in (1...Int(1000)).compactMap({ UnicodeScalar($0).map({ String($0) }) }) { XCTAssertNoThrow(try NIOSSLClientHandler(context: context, serverHostname: testString)) XCTAssertNoThrow(try NIOSSLClientTLSProvider(context: context, serverHostname: testString)) } @@ -154,7 +167,7 @@ class ClientSNITests: XCTestCase { let context = try configuredSSLContext() let testString = "😎🥶💥🏴󠁧󠁢󠁥󠁮󠁧󠁿👩‍💻" - XCTAssertLessThanOrEqual(testString.utf8.count, 255) // just to check we didn't make this too large. + XCTAssertLessThanOrEqual(testString.utf8.count, 255) // just to check we didn't make this too large. XCTAssertNoThrow(try NIOSSLClientHandler(context: context, serverHostname: testString)) XCTAssertNoThrow(try NIOSSLClientTLSProvider(context: context, serverHostname: testString)) } diff --git a/Tests/NIOSSLTests/CustomPrivateKeyTests.swift b/Tests/NIOSSLTests/CustomPrivateKeyTests.swift index 8f70fbbf6..2185d10c3 100644 --- a/Tests/NIOSSLTests/CustomPrivateKeyTests.swift +++ b/Tests/NIOSSLTests/CustomPrivateKeyTests.swift @@ -12,19 +12,21 @@ // //===----------------------------------------------------------------------===// +import NIOConcurrencyHelpers +import NIOCore +import NIOEmbedded import XCTest + +@testable import NIOSSL + #if compiler(>=5.1) @_implementationOnly import CNIOBoringSSL #else import CNIOBoringSSL #endif -import NIOCore -import NIOEmbedded -import NIOConcurrencyHelpers -@testable import NIOSSL // This is a helper that lets us work with an EVP_PKEY. -fileprivate final class CustomPKEY { +private final class CustomPKEY { private let ref: OpaquePointer init(from key: NIOSSLPrivateKey) { @@ -57,7 +59,11 @@ fileprivate final class CustomPKEY { CNIOBoringSSL_EVP_MD_CTX_init(hashContext) CNIOBoringSSL_EVP_DigestInit_ex(hashContext, algorithm.md, nil) var rc = data.withUnsafeReadableBytes { bytesPtr in - CNIOBoringSSL_EVP_DigestUpdate(hashContext, bytesPtr.baseAddress?.assumingMemoryBound(to: UInt8.self), bytesPtr.count) + CNIOBoringSSL_EVP_DigestUpdate( + hashContext, + bytesPtr.baseAddress?.assumingMemoryBound(to: UInt8.self), + bytesPtr.count + ) } precondition(rc == 1) @@ -66,7 +72,11 @@ fileprivate final class CustomPKEY { var digestBuffer = ByteBuffer() digestBuffer.writeWithUnsafeMutableBytes(minimumWritableBytes: signatureSize) { outputPtr in var actualSize = CUnsignedInt(outputPtr.count) - CNIOBoringSSL_EVP_DigestFinal_ex(hashContext, outputPtr.baseAddress?.assumingMemoryBound(to: UInt8.self), &actualSize) + CNIOBoringSSL_EVP_DigestFinal_ex( + hashContext, + outputPtr.baseAddress?.assumingMemoryBound(to: UInt8.self), + &actualSize + ) return Int(actualSize) } @@ -88,7 +98,13 @@ fileprivate final class CustomPKEY { // Now we find out the length we need. var signatureLength: Int = 0 rc = digestBuffer.withUnsafeReadableBytes { bytesPtr in - CNIOBoringSSL_EVP_PKEY_sign(ctx, nil, &signatureLength, bytesPtr.baseAddress?.assumingMemoryBound(to: UInt8.self), bytesPtr.count) + CNIOBoringSSL_EVP_PKEY_sign( + ctx, + nil, + &signatureLength, + bytesPtr.baseAddress?.assumingMemoryBound(to: UInt8.self), + bytesPtr.count + ) } precondition(rc == 1) @@ -98,7 +114,13 @@ fileprivate final class CustomPKEY { outputBuffer.writeWithUnsafeMutableBytes(minimumWritableBytes: signatureLength) { outputPtr in precondition(signatureLength <= outputPtr.count) let rc = digestBuffer.withUnsafeReadableBytes { bytesPtr in - CNIOBoringSSL_EVP_PKEY_sign(ctx, outputPtr.baseAddress?.assumingMemoryBound(to: UInt8.self), &signatureLength, bytesPtr.baseAddress?.assumingMemoryBound(to: UInt8.self), bytesPtr.count) + CNIOBoringSSL_EVP_PKEY_sign( + ctx, + outputPtr.baseAddress?.assumingMemoryBound(to: UInt8.self), + &signatureLength, + bytesPtr.baseAddress?.assumingMemoryBound(to: UInt8.self), + bytesPtr.count + ) } precondition(rc == 1) return signatureLength @@ -129,12 +151,12 @@ fileprivate final class CustomPKEY { precondition(rc == 1) return written } - + return output } } -fileprivate final class CustomKeyImmediateResult: NIOSSLCustomPrivateKey, Hashable { +private final class CustomKeyImmediateResult: NIOSSLCustomPrivateKey, Hashable { let backing: CustomPKEY let signatureAlgorithms: [SignatureAlgorithm] let expectedChannel: Channel @@ -162,8 +184,8 @@ fileprivate final class CustomKeyImmediateResult: NIOSSLCustomPrivateKey, Hashab return channel.eventLoop.makeSucceededFuture(self.backing.decrypt(data: data)) } - static func ==(lhs: CustomKeyImmediateResult, rhs: CustomKeyImmediateResult) -> Bool { - return lhs.backing === rhs.backing && lhs.signatureAlgorithms == rhs.signatureAlgorithms + static func == (lhs: CustomKeyImmediateResult, rhs: CustomKeyImmediateResult) -> Bool { + lhs.backing === rhs.backing && lhs.signatureAlgorithms == rhs.signatureAlgorithms } func hash(into hasher: inout Hasher) { @@ -172,7 +194,7 @@ fileprivate final class CustomKeyImmediateResult: NIOSSLCustomPrivateKey, Hashab } } -fileprivate final class CustomKeyDelayedCompletion: NIOSSLCustomPrivateKey, Hashable { +private final class CustomKeyDelayedCompletion: NIOSSLCustomPrivateKey, Hashable { let backing: CustomPKEY let signatureAlgorithms: [SignatureAlgorithm] let expectedChannel: Channel @@ -208,8 +230,8 @@ fileprivate final class CustomKeyDelayedCompletion: NIOSSLCustomPrivateKey, Hash } } - static func ==(lhs: CustomKeyDelayedCompletion, rhs: CustomKeyDelayedCompletion) -> Bool { - return lhs.backing === rhs.backing && lhs.signatureAlgorithms == rhs.signatureAlgorithms + static func == (lhs: CustomKeyDelayedCompletion, rhs: CustomKeyDelayedCompletion) -> Bool { + lhs.backing === rhs.backing && lhs.signatureAlgorithms == rhs.signatureAlgorithms } func hash(into hasher: inout Hasher) { @@ -220,7 +242,9 @@ fileprivate final class CustomKeyDelayedCompletion: NIOSSLCustomPrivateKey, Hash final class CustomPrivateKeyTests: XCTestCase { fileprivate static let customECDSACertAndKey: (certificate: NIOSSLCertificate, key: CustomPKEY) = { - let (cert, originalKey) = generateSelfSignedCert(keygenFunction: { generateECPrivateKey(curveNID: NID_X9_62_prime256v1) }) + let (cert, originalKey) = generateSelfSignedCert(keygenFunction: { + generateECPrivateKey(curveNID: NID_X9_62_prime256v1) + }) let derivedKey = CustomPKEY(from: originalKey) return (certificate: cert, key: derivedKey) }() @@ -245,9 +269,11 @@ final class CustomPrivateKeyTests: XCTestCase { return try! NIOSSLContext(configuration: config) } - private func configuredServerContext(certificate: NIOSSLCertificate, privateKey: NIOSSLPrivateKey) -> NIOSSLContext { + private func configuredServerContext(certificate: NIOSSLCertificate, privateKey: NIOSSLPrivateKey) -> NIOSSLContext + { let config = TLSConfiguration.makeServerConfiguration( - certificateChain: [.certificate(certificate)], privateKey: .privateKey(privateKey) + certificateChain: [.certificate(certificate)], + privateKey: .privateKey(privateKey) ) return try! NIOSSLContext(configuration: config) } @@ -260,14 +286,19 @@ final class CustomPrivateKeyTests: XCTestCase { expectedChannel: b2b.server ) - let clientContext = self.configuredClientContext(trustRoot: CustomPrivateKeyTests.customECDSACertAndKey.certificate) + let clientContext = self.configuredClientContext( + trustRoot: CustomPrivateKeyTests.customECDSACertAndKey.certificate + ) let serverContext = self.configuredServerContext( certificate: CustomPrivateKeyTests.customECDSACertAndKey.certificate, privateKey: NIOSSLPrivateKey(customPrivateKey: happyPathKey) ) XCTAssertNoThrow( try b2b.client.pipeline.syncOperations.addHandlers( - [try NIOSSLClientHandler(context: clientContext, serverHostname: "localhost"), HandshakeCompletedHandler()] + [ + try NIOSSLClientHandler(context: clientContext, serverHostname: "localhost"), + HandshakeCompletedHandler(), + ] ) ) XCTAssertNoThrow( @@ -291,14 +322,19 @@ final class CustomPrivateKeyTests: XCTestCase { expectedChannel: b2b.server ) - let clientContext = self.configuredClientContext(trustRoot: CustomPrivateKeyTests.customRSACertAndKey.certificate) + let clientContext = self.configuredClientContext( + trustRoot: CustomPrivateKeyTests.customRSACertAndKey.certificate + ) let serverContext = self.configuredServerContext( certificate: CustomPrivateKeyTests.customRSACertAndKey.certificate, privateKey: NIOSSLPrivateKey(customPrivateKey: happyPathKey) ) XCTAssertNoThrow( try b2b.client.pipeline.syncOperations.addHandlers( - [try NIOSSLClientHandler(context: clientContext, serverHostname: "localhost"), HandshakeCompletedHandler()] + [ + try NIOSSLClientHandler(context: clientContext, serverHostname: "localhost"), + HandshakeCompletedHandler(), + ] ) ) XCTAssertNoThrow( @@ -336,7 +372,10 @@ final class CustomPrivateKeyTests: XCTestCase { ) XCTAssertNoThrow( try b2b.client.pipeline.syncOperations.addHandlers( - [try NIOSSLClientHandler(context: clientContext, serverHostname: "localhost"), HandshakeCompletedHandler()] + [ + try NIOSSLClientHandler(context: clientContext, serverHostname: "localhost"), + HandshakeCompletedHandler(), + ] ) ) XCTAssertNoThrow( @@ -360,14 +399,19 @@ final class CustomPrivateKeyTests: XCTestCase { expectedChannel: b2b.server ) - let clientContext = self.configuredClientContext(trustRoot: CustomPrivateKeyTests.customECDSACertAndKey.certificate) + let clientContext = self.configuredClientContext( + trustRoot: CustomPrivateKeyTests.customECDSACertAndKey.certificate + ) let serverContext = self.configuredServerContext( certificate: CustomPrivateKeyTests.customECDSACertAndKey.certificate, privateKey: NIOSSLPrivateKey(customPrivateKey: happyPathKey) ) XCTAssertNoThrow( try b2b.client.pipeline.syncOperations.addHandlers( - [try NIOSSLClientHandler(context: clientContext, serverHostname: "localhost"), HandshakeCompletedHandler()] + [ + try NIOSSLClientHandler(context: clientContext, serverHostname: "localhost"), + HandshakeCompletedHandler(), + ] ) ) XCTAssertNoThrow( @@ -402,14 +446,19 @@ final class CustomPrivateKeyTests: XCTestCase { expectedChannel: b2b.server ) - let clientContext = self.configuredClientContext(trustRoot: CustomPrivateKeyTests.customRSACertAndKey.certificate) + let clientContext = self.configuredClientContext( + trustRoot: CustomPrivateKeyTests.customRSACertAndKey.certificate + ) let serverContext = self.configuredServerContext( certificate: CustomPrivateKeyTests.customRSACertAndKey.certificate, privateKey: NIOSSLPrivateKey(customPrivateKey: happyPathKey) ) XCTAssertNoThrow( try b2b.client.pipeline.syncOperations.addHandlers( - [try NIOSSLClientHandler(context: clientContext, serverHostname: "localhost"), HandshakeCompletedHandler()] + [ + try NIOSSLClientHandler(context: clientContext, serverHostname: "localhost"), + HandshakeCompletedHandler(), + ] ) ) XCTAssertNoThrow( @@ -458,7 +507,10 @@ final class CustomPrivateKeyTests: XCTestCase { ) XCTAssertNoThrow( try b2b.client.pipeline.syncOperations.addHandlers( - [try NIOSSLClientHandler(context: clientContext, serverHostname: "localhost"), HandshakeCompletedHandler()] + [ + try NIOSSLClientHandler(context: clientContext, serverHostname: "localhost"), + HandshakeCompletedHandler(), + ] ) ) XCTAssertNoThrow( @@ -495,7 +547,9 @@ final class CustomPrivateKeyTests: XCTestCase { expectedChannel: b2b.server ) - let clientContext = self.configuredClientContext(trustRoot: CustomPrivateKeyTests.customECDSACertAndKey.certificate) + let clientContext = self.configuredClientContext( + trustRoot: CustomPrivateKeyTests.customECDSACertAndKey.certificate + ) let serverContext = self.configuredServerContext( certificate: CustomPrivateKeyTests.customECDSACertAndKey.certificate, privateKey: NIOSSLPrivateKey(customPrivateKey: happyPathKey) @@ -515,7 +569,7 @@ final class CustomPrivateKeyTests: XCTestCase { } func testThrowingCustomErrorsSigning() throws { - struct CustomError: Error { } + struct CustomError: Error {} let b2b = BackToBackEmbeddedChannel() let happyPathKey = CustomKeyDelayedCompletion( @@ -524,7 +578,9 @@ final class CustomPrivateKeyTests: XCTestCase { expectedChannel: b2b.server ) - let clientContext = self.configuredClientContext(trustRoot: CustomPrivateKeyTests.customECDSACertAndKey.certificate) + let clientContext = self.configuredClientContext( + trustRoot: CustomPrivateKeyTests.customECDSACertAndKey.certificate + ) let serverContext = self.configuredServerContext( certificate: CustomPrivateKeyTests.customECDSACertAndKey.certificate, privateKey: NIOSSLPrivateKey(customPrivateKey: happyPathKey) @@ -607,12 +663,14 @@ final class CustomPrivateKeyTests: XCTestCase { XCTAssertEqual(Set([firstKey, secondKey]), Set([firstKey, secondKey, thirdKey])) XCTAssertEqual( Set([NIOSSLPrivateKey(customPrivateKey: firstKey), NIOSSLPrivateKey(customPrivateKey: secondKey)]), - Set([NIOSSLPrivateKey(customPrivateKey: firstKey), NIOSSLPrivateKey(customPrivateKey: secondKey), NIOSSLPrivateKey(customPrivateKey: thirdKey)]) + Set([ + NIOSSLPrivateKey(customPrivateKey: firstKey), NIOSSLPrivateKey(customPrivateKey: secondKey), + NIOSSLPrivateKey(customPrivateKey: thirdKey), + ]) ) } } - extension SignatureAlgorithm { var md: OpaquePointer { switch self { diff --git a/Tests/NIOSSLTests/IdentityVerificationTest.swift b/Tests/NIOSSLTests/IdentityVerificationTest.swift index b69b8a72c..32ec12b40 100644 --- a/Tests/NIOSSLTests/IdentityVerificationTest.swift +++ b/Tests/NIOSSLTests/IdentityVerificationTest.swift @@ -12,8 +12,9 @@ // //===----------------------------------------------------------------------===// -import XCTest import NIOCore +import XCTest + @testable import NIOSSL /// This cert contains the following SAN fields: @@ -31,22 +32,22 @@ import NIOCore /// /// This also contains a commonName of httpbin.org. private let weirdoPEMCert = """ ------BEGIN CERTIFICATE----- -MIICZjCCAgygAwIBAgIURNa5MCGhhy1TUo57ogfm5OvVBr8wCgYIKoZIzj0EAwIw -FjEUMBIGA1UEAwwLaHR0cGJpbi5vcmcwHhcNMjQwNTEzMTI1MjUwWhcNNDAwMTAx -MDAwMDAwWjAWMRQwEgYDVQQDDAtodHRwYmluLm9yZzBZMBMGByqGSM49AgEGCCqG -SM49AwEHA0IABHC44jasAWsWYtYdo+cnLOAEuMQHt1zI5A7td2avNIHEfEXqiizj -t1VPWYR6wbL/X7ZXb7IjED8v5ZeN/yK0jpGjggE2MIIBMjAJBgNVHRMEAjAAMIIB -IwYDVR0RBIIBGjCCARaCFiouV0lMRENBUkQuRVhBTVBMRS5jb22CD0ZPKi5FWEFN -UExFLmNvbYIPKkFSLkVYQU1QTEUuY29tgg9CKlouRVhBTVBMRS5jb22CHFRSQUlM -SU5HLlBFUklPRC5FWEFNUExFLmNvbS6CIlhOLS1TVFJBRS1PUUEuVU5JQ09ERS5F -WEFNUExFLmNvbS6CH1hOLS1YKi1HSUEuVU5JQ09ERS5FWEFNUExFLmNvbS6CHFdF -SVJEV0lMRENBUkQuKi5FWEFNUExFLmNvbS6CFyouKi5ET1VCTEUuRVhBTVBMRS5j -b20ughwqLlhOLS1TVFJBRS1PUUEuRVhBTVBMRS5jb20ughFOVUwATC5FWEFNUExF -LmNvbTAKBggqhkjOPQQDAgNIADBFAiEAoZP9/AT/kI4XV9ComU/3TOBavn2HT4KJ -GLTqsl138zwCIFAGdxsBH3CGfuFNYXOdYZOJ/FIqv7Ev0eGxXvTZ+bcs ------END CERTIFICATE----- -""" + -----BEGIN CERTIFICATE----- + MIICZjCCAgygAwIBAgIURNa5MCGhhy1TUo57ogfm5OvVBr8wCgYIKoZIzj0EAwIw + FjEUMBIGA1UEAwwLaHR0cGJpbi5vcmcwHhcNMjQwNTEzMTI1MjUwWhcNNDAwMTAx + MDAwMDAwWjAWMRQwEgYDVQQDDAtodHRwYmluLm9yZzBZMBMGByqGSM49AgEGCCqG + SM49AwEHA0IABHC44jasAWsWYtYdo+cnLOAEuMQHt1zI5A7td2avNIHEfEXqiizj + t1VPWYR6wbL/X7ZXb7IjED8v5ZeN/yK0jpGjggE2MIIBMjAJBgNVHRMEAjAAMIIB + IwYDVR0RBIIBGjCCARaCFiouV0lMRENBUkQuRVhBTVBMRS5jb22CD0ZPKi5FWEFN + UExFLmNvbYIPKkFSLkVYQU1QTEUuY29tgg9CKlouRVhBTVBMRS5jb22CHFRSQUlM + SU5HLlBFUklPRC5FWEFNUExFLmNvbS6CIlhOLS1TVFJBRS1PUUEuVU5JQ09ERS5F + WEFNUExFLmNvbS6CH1hOLS1YKi1HSUEuVU5JQ09ERS5FWEFNUExFLmNvbS6CHFdF + SVJEV0lMRENBUkQuKi5FWEFNUExFLmNvbS6CFyouKi5ET1VCTEUuRVhBTVBMRS5j + b20ughwqLlhOLS1TVFJBRS1PUUEuRVhBTVBMRS5jb20ughFOVUwATC5FWEFNUExF + LmNvbTAKBggqhkjOPQQDAgNIADBFAiEAoZP9/AT/kI4XV9ComU/3TOBavn2HT4KJ + GLTqsl138zwCIFAGdxsBH3CGfuFNYXOdYZOJ/FIqv7Ev0eGxXvTZ+bcs + -----END CERTIFICATE----- + """ /// Returns whether this system supports resolving IPv6 function. func ipv6Supported() throws -> Bool { @@ -61,69 +62,84 @@ func ipv6Supported() throws -> Bool { class IdentityVerificationTest: XCTestCase { func testCanValidateHostnameInFirstSan() throws { let cert = try NIOSSLCertificate(bytes: .init(multiSanCert.utf8), format: .pem) - let matched = try validIdentityForService(serverHostname: "localhost", - socketAddress: try .init(unixDomainSocketPath: "/path"), - leafCertificate: cert) + let matched = try validIdentityForService( + serverHostname: "localhost", + socketAddress: try .init(unixDomainSocketPath: "/path"), + leafCertificate: cert + ) XCTAssertTrue(matched) } func testCanValidateHostnameInSecondSan() throws { let cert = try NIOSSLCertificate(bytes: .init(multiSanCert.utf8), format: .pem) - let matched = try validIdentityForService(serverHostname: "example.com", - socketAddress: try .init(unixDomainSocketPath: "/path"), - leafCertificate: cert) + let matched = try validIdentityForService( + serverHostname: "example.com", + socketAddress: try .init(unixDomainSocketPath: "/path"), + leafCertificate: cert + ) XCTAssertTrue(matched) } func testIgnoresTrailingPeriod() throws { let cert = try NIOSSLCertificate(bytes: .init(multiSanCert.utf8), format: .pem) - let matched = try validIdentityForService(serverHostname: "example.com.", - socketAddress: try .init(unixDomainSocketPath: "/path"), - leafCertificate: cert) + let matched = try validIdentityForService( + serverHostname: "example.com.", + socketAddress: try .init(unixDomainSocketPath: "/path"), + leafCertificate: cert + ) XCTAssertTrue(matched) } func testLowercasesHostnameForSan() throws { let cert = try NIOSSLCertificate(bytes: .init(multiSanCert.utf8), format: .pem) - let matched = try validIdentityForService(serverHostname: "LoCaLhOsT", - socketAddress: try .init(unixDomainSocketPath: "/path"), - leafCertificate: cert) + let matched = try validIdentityForService( + serverHostname: "LoCaLhOsT", + socketAddress: try .init(unixDomainSocketPath: "/path"), + leafCertificate: cert + ) XCTAssertTrue(matched) } func testRejectsIncorrectHostname() throws { let cert = try NIOSSLCertificate(bytes: .init(multiSanCert.utf8), format: .pem) - let matched = try validIdentityForService(serverHostname: "httpbin.org", - socketAddress: try .init(unixDomainSocketPath: "/path"), - leafCertificate: cert) + let matched = try validIdentityForService( + serverHostname: "httpbin.org", + socketAddress: try .init(unixDomainSocketPath: "/path"), + leafCertificate: cert + ) XCTAssertFalse(matched) } func testAcceptsIpv4Address() throws { let cert = try NIOSSLCertificate(bytes: .init(multiSanCert.utf8), format: .pem) - let matched = try validIdentityForService(serverHostname: nil, - socketAddress: try .makeAddressResolvingHost("192.168.0.1", port: 443), - leafCertificate: cert) + let matched = try validIdentityForService( + serverHostname: nil, + socketAddress: try .makeAddressResolvingHost("192.168.0.1", port: 443), + leafCertificate: cert + ) XCTAssertTrue(matched) } - func testAcceptsIpv6Address() throws { guard try ipv6Supported() else { return } let ipv6Address = try SocketAddress.makeAddressResolvingHost("2001:db8::1", port: 443) let cert = try NIOSSLCertificate(bytes: .init(multiSanCert.utf8), format: .pem) - let matched = try validIdentityForService(serverHostname: nil, - socketAddress: ipv6Address, - leafCertificate: cert) + let matched = try validIdentityForService( + serverHostname: nil, + socketAddress: ipv6Address, + leafCertificate: cert + ) XCTAssertTrue(matched) } func testRejectsIncorrectIpv4Address() throws { let cert = try NIOSSLCertificate(bytes: .init(multiSanCert.utf8), format: .pem) - let matched = try validIdentityForService(serverHostname: nil, - socketAddress: try .makeAddressResolvingHost("192.168.0.2", port: 443), - leafCertificate: cert) + let matched = try validIdentityForService( + serverHostname: nil, + socketAddress: try .makeAddressResolvingHost("192.168.0.2", port: 443), + leafCertificate: cert + ) XCTAssertFalse(matched) } @@ -132,178 +148,234 @@ class IdentityVerificationTest: XCTestCase { let ipv6Address = try SocketAddress.makeAddressResolvingHost("2001:db8::2", port: 443) let cert = try NIOSSLCertificate(bytes: .init(multiSanCert.utf8), format: .pem) - let matched = try validIdentityForService(serverHostname: nil, - socketAddress: ipv6Address, - leafCertificate: cert) + let matched = try validIdentityForService( + serverHostname: nil, + socketAddress: ipv6Address, + leafCertificate: cert + ) XCTAssertFalse(matched) } func testAcceptsWildcards() throws { let cert = try NIOSSLCertificate(bytes: .init(weirdoPEMCert.utf8), format: .pem) - let matched = try validIdentityForService(serverHostname: "this.wildcard.example.com", - socketAddress: try .init(unixDomainSocketPath: "/path"), - leafCertificate: cert) + let matched = try validIdentityForService( + serverHostname: "this.wildcard.example.com", + socketAddress: try .init(unixDomainSocketPath: "/path"), + leafCertificate: cert + ) XCTAssertTrue(matched) } func testAcceptsSuffixWildcard() throws { let cert = try NIOSSLCertificate(bytes: .init(weirdoPEMCert.utf8), format: .pem) - let matched = try validIdentityForService(serverHostname: "foo.example.com", - socketAddress: try .init(unixDomainSocketPath: "/path"), - leafCertificate: cert) + let matched = try validIdentityForService( + serverHostname: "foo.example.com", + socketAddress: try .init(unixDomainSocketPath: "/path"), + leafCertificate: cert + ) XCTAssertTrue(matched) } func testAcceptsPrefixWildcard() throws { let cert = try NIOSSLCertificate(bytes: .init(weirdoPEMCert.utf8), format: .pem) - let matched = try validIdentityForService(serverHostname: "bar.example.com", - socketAddress: try .init(unixDomainSocketPath: "/path"), - leafCertificate: cert) + let matched = try validIdentityForService( + serverHostname: "bar.example.com", + socketAddress: try .init(unixDomainSocketPath: "/path"), + leafCertificate: cert + ) XCTAssertTrue(matched) } func testAcceptsInfixWildcard() throws { let cert = try NIOSSLCertificate(bytes: .init(weirdoPEMCert.utf8), format: .pem) - let matched = try validIdentityForService(serverHostname: "baz.example.com", - socketAddress: try .init(unixDomainSocketPath: "/path"), - leafCertificate: cert) + let matched = try validIdentityForService( + serverHostname: "baz.example.com", + socketAddress: try .init(unixDomainSocketPath: "/path"), + leafCertificate: cert + ) XCTAssertTrue(matched) } func testIgnoresTrailingPeriodInCert() throws { let cert = try NIOSSLCertificate(bytes: .init(weirdoPEMCert.utf8), format: .pem) - let matched = try validIdentityForService(serverHostname: "trailing.period.example.com", - socketAddress: try .init(unixDomainSocketPath: "/path"), - leafCertificate: cert) + let matched = try validIdentityForService( + serverHostname: "trailing.period.example.com", + socketAddress: try .init(unixDomainSocketPath: "/path"), + leafCertificate: cert + ) XCTAssertTrue(matched) } func testRejectsEncodedIDNALabel() throws { let cert = try NIOSSLCertificate(bytes: .init(weirdoPEMCert.utf8), format: .pem) - XCTAssertThrowsError(try validIdentityForService(serverHostname: "straße.unicode.example.com", - socketAddress: try .init(unixDomainSocketPath: "/path"), - leafCertificate: cert)) { error in + XCTAssertThrowsError( + try validIdentityForService( + serverHostname: "straße.unicode.example.com", + socketAddress: try .init(unixDomainSocketPath: "/path"), + leafCertificate: cert + ) + ) { error in XCTAssertEqual(error as? NIOSSLExtraError, .serverHostnameImpossibleToMatch) - XCTAssertEqual(String(describing: error), - "NIOSSLExtraError.serverHostnameImpossibleToMatch: The server hostname straße.unicode.example.com cannot be matched due to containing non-DNS characters") + XCTAssertEqual( + String(describing: error), + "NIOSSLExtraError.serverHostnameImpossibleToMatch: The server hostname straße.unicode.example.com cannot be matched due to containing non-DNS characters" + ) } } func testMatchesUnencodedIDNALabel() throws { let cert = try NIOSSLCertificate(bytes: .init(weirdoPEMCert.utf8), format: .pem) - let matched = try validIdentityForService(serverHostname: "xn--strae-oqa.unicode.example.com", - socketAddress: try .init(unixDomainSocketPath: "/path"), - leafCertificate: cert) + let matched = try validIdentityForService( + serverHostname: "xn--strae-oqa.unicode.example.com", + socketAddress: try .init(unixDomainSocketPath: "/path"), + leafCertificate: cert + ) XCTAssertTrue(matched) } func testDoesNotMatchIDNALabelWithWildcard() throws { let cert = try NIOSSLCertificate(bytes: .init(weirdoPEMCert.utf8), format: .pem) - let matched = try validIdentityForService(serverHostname: "xn--xx-gia.unicode.example.com", - socketAddress: try .init(unixDomainSocketPath: "/path"), - leafCertificate: cert) + let matched = try validIdentityForService( + serverHostname: "xn--xx-gia.unicode.example.com", + socketAddress: try .init(unixDomainSocketPath: "/path"), + leafCertificate: cert + ) XCTAssertFalse(matched) } func testDoesNotMatchNonLeftmostWildcards() throws { let cert = try NIOSSLCertificate(bytes: .init(weirdoPEMCert.utf8), format: .pem) - let matched = try validIdentityForService(serverHostname: "weirdwildcard.nomatch.example.com", - socketAddress: try .init(unixDomainSocketPath: "/path"), - leafCertificate: cert) + let matched = try validIdentityForService( + serverHostname: "weirdwildcard.nomatch.example.com", + socketAddress: try .init(unixDomainSocketPath: "/path"), + leafCertificate: cert + ) XCTAssertFalse(matched) } func testDoesNotMatchMultipleWildcards() throws { let cert = try NIOSSLCertificate(bytes: .init(weirdoPEMCert.utf8), format: .pem) - let matched = try validIdentityForService(serverHostname: "one.two.double.example.com", - socketAddress: try .init(unixDomainSocketPath: "/path"), - leafCertificate: cert) + let matched = try validIdentityForService( + serverHostname: "one.two.double.example.com", + socketAddress: try .init(unixDomainSocketPath: "/path"), + leafCertificate: cert + ) XCTAssertFalse(matched) } func testRejectsWildcardBeforeUnencodedIDNALabel() throws { let cert = try NIOSSLCertificate(bytes: .init(weirdoPEMCert.utf8), format: .pem) - XCTAssertThrowsError(try validIdentityForService(serverHostname: "foo.straße.example.com", - socketAddress: try .init(unixDomainSocketPath: "/path"), - leafCertificate: cert)) { error in + XCTAssertThrowsError( + try validIdentityForService( + serverHostname: "foo.straße.example.com", + socketAddress: try .init(unixDomainSocketPath: "/path"), + leafCertificate: cert + ) + ) { error in XCTAssertEqual(error as? NIOSSLExtraError, .serverHostnameImpossibleToMatch) - XCTAssertEqual(String(describing: error), - "NIOSSLExtraError.serverHostnameImpossibleToMatch: The server hostname foo.straße.example.com cannot be matched due to containing non-DNS characters") + XCTAssertEqual( + String(describing: error), + "NIOSSLExtraError.serverHostnameImpossibleToMatch: The server hostname foo.straße.example.com cannot be matched due to containing non-DNS characters" + ) } } func testMatchesWildcardBeforeEncodedIDNALabel() throws { let cert = try NIOSSLCertificate(bytes: .init(weirdoPEMCert.utf8), format: .pem) - let matched = try validIdentityForService(serverHostname: "foo.xn--strae-oqa.example.com", - socketAddress: try .init(unixDomainSocketPath: "/path"), - leafCertificate: cert) + let matched = try validIdentityForService( + serverHostname: "foo.xn--strae-oqa.example.com", + socketAddress: try .init(unixDomainSocketPath: "/path"), + leafCertificate: cert + ) XCTAssertTrue(matched) } func testDoesNotMatchSANWithEmbeddedNULL() throws { let cert = try NIOSSLCertificate(bytes: .init(weirdoPEMCert.utf8), format: .pem) - XCTAssertThrowsError(try validIdentityForService(serverHostname: "nul\u{0000}l.example.com", - socketAddress: try .init(unixDomainSocketPath: "/path"), - leafCertificate: cert)) { error in + XCTAssertThrowsError( + try validIdentityForService( + serverHostname: "nul\u{0000}l.example.com", + socketAddress: try .init(unixDomainSocketPath: "/path"), + leafCertificate: cert + ) + ) { error in XCTAssertEqual(error as? NIOSSLExtraError, .serverHostnameImpossibleToMatch) - XCTAssertEqual(String(describing: error), - "NIOSSLExtraError.serverHostnameImpossibleToMatch: The server hostname nul\u{0000}l.example.com cannot be matched due to containing non-DNS characters") + XCTAssertEqual( + String(describing: error), + "NIOSSLExtraError.serverHostnameImpossibleToMatch: The server hostname nul\u{0000}l.example.com cannot be matched due to containing non-DNS characters" + ) } } func testFallsBackToCommonName() throws { let cert = try NIOSSLCertificate(bytes: .init(multiCNCert.utf8), format: .pem) - let matched = try validIdentityForService(serverHostname: "localhost", - socketAddress: try .init(unixDomainSocketPath: "/path"), - leafCertificate: cert) + let matched = try validIdentityForService( + serverHostname: "localhost", + socketAddress: try .init(unixDomainSocketPath: "/path"), + leafCertificate: cert + ) XCTAssertTrue(matched) } func testLowercasesForCommonName() throws { let cert = try NIOSSLCertificate(bytes: .init(multiCNCert.utf8), format: .pem) - let matched = try validIdentityForService(serverHostname: "LoCaLhOsT", - socketAddress: try .init(unixDomainSocketPath: "/path"), - leafCertificate: cert) + let matched = try validIdentityForService( + serverHostname: "LoCaLhOsT", + socketAddress: try .init(unixDomainSocketPath: "/path"), + leafCertificate: cert + ) XCTAssertTrue(matched) } func testRejectsUnicodeCommonNameWithUnencodedIDNALabel() throws { let cert = try NIOSSLCertificate(bytes: .init(unicodeCNCert.utf8), format: .pem) - XCTAssertThrowsError(try validIdentityForService(serverHostname: "straße.org", - socketAddress: try .init(unixDomainSocketPath: "/path"), - leafCertificate: cert)) { error in + XCTAssertThrowsError( + try validIdentityForService( + serverHostname: "straße.org", + socketAddress: try .init(unixDomainSocketPath: "/path"), + leafCertificate: cert + ) + ) { error in XCTAssertEqual(error as? NIOSSLExtraError, .serverHostnameImpossibleToMatch) - XCTAssertEqual(String(describing: error), - "NIOSSLExtraError.serverHostnameImpossibleToMatch: The server hostname straße.org cannot be matched due to containing non-DNS characters") + XCTAssertEqual( + String(describing: error), + "NIOSSLExtraError.serverHostnameImpossibleToMatch: The server hostname straße.org cannot be matched due to containing non-DNS characters" + ) } } func testRejectsUnicodeCommonNameWithEncodedIDNALabel() throws { let cert = try NIOSSLCertificate(bytes: .init(unicodeCNCert.utf8), format: .pem) - let matched = try validIdentityForService(serverHostname: "xn--strae-oqa.org", - socketAddress: try .init(unixDomainSocketPath: "/path"), - leafCertificate: cert) + let matched = try validIdentityForService( + serverHostname: "xn--strae-oqa.org", + socketAddress: try .init(unixDomainSocketPath: "/path"), + leafCertificate: cert + ) XCTAssertFalse(matched) } func testHandlesMissingCommonName() throws { let cert = try NIOSSLCertificate(bytes: .init(noCNCert.utf8), format: .pem) - let matched = try validIdentityForService(serverHostname: "localhost", - socketAddress: try .init(unixDomainSocketPath: "/path"), - leafCertificate: cert) + let matched = try validIdentityForService( + serverHostname: "localhost", + socketAddress: try .init(unixDomainSocketPath: "/path"), + leafCertificate: cert + ) XCTAssertFalse(matched) } func testDoesNotFallBackToCNWithSans() throws { let cert = try NIOSSLCertificate(bytes: .init(weirdoPEMCert.utf8), format: .pem) - let matched = try validIdentityForService(serverHostname: "httpbin.org", - socketAddress: try .init(unixDomainSocketPath: "/path"), - leafCertificate: cert) + let matched = try validIdentityForService( + serverHostname: "httpbin.org", + socketAddress: try .init(unixDomainSocketPath: "/path"), + leafCertificate: cert + ) XCTAssertFalse(matched) } } diff --git a/Tests/NIOSSLTests/NIOSSLALPNTest.swift b/Tests/NIOSSLTests/NIOSSLALPNTest.swift index 92c07ccbe..998a460cb 100644 --- a/Tests/NIOSSLTests/NIOSSLALPNTest.swift +++ b/Tests/NIOSSLTests/NIOSSLALPNTest.swift @@ -12,13 +12,12 @@ // //===----------------------------------------------------------------------===// -import XCTest @_implementationOnly import CNIOBoringSSL import NIOCore import NIOPosix -import NIOTLS import NIOSSL - +import NIOTLS +import XCTest class NIOSSLALPNTest: XCTestCase { static var cert: NIOSSLCertificate! @@ -41,9 +40,11 @@ class NIOSSLALPNTest: XCTestCase { return try NIOSSLContext(configuration: config) } - private func assertNegotiatedProtocol(protocol: String?, - serverContext: NIOSSLContext, - clientContext: NIOSSLContext) throws { + private func assertNegotiatedProtocol( + protocol: String?, + serverContext: NIOSSLContext, + clientContext: NIOSSLContext + ) throws { let group = MultiThreadedEventLoopGroup(numberOfThreads: 1) defer { XCTAssertNoThrow(try group.syncShutdownGracefully()) @@ -52,18 +53,22 @@ class NIOSSLALPNTest: XCTestCase { let completionPromise: EventLoopPromise = group.next().makePromise() let serverHandler = EventRecorderHandler() - let serverChannel = try serverTLSChannel(context: serverContext, - handlers: [serverHandler, PromiseOnReadHandler(promise: completionPromise)], - group: group) + let serverChannel = try serverTLSChannel( + context: serverContext, + handlers: [serverHandler, PromiseOnReadHandler(promise: completionPromise)], + group: group + ) defer { XCTAssertNoThrow(try serverChannel.close().wait()) } - let clientChannel = try clientTLSChannel(context: clientContext, - preHandlers: [], - postHandlers: [], - group: group, - connectingTo: serverChannel.localAddress!) + let clientChannel = try clientTLSChannel( + context: clientContext, + preHandlers: [], + postHandlers: [], + group: group, + connectingTo: serverChannel.localAddress! + ) defer { XCTAssertNoThrow(try clientChannel.close().wait()) } @@ -78,7 +83,7 @@ class NIOSSLALPNTest: XCTestCase { .Active, .UserEvent(TLSUserEvent.handshakeCompleted(negotiatedProtocol: `protocol`)), .Read, - .ReadComplete + .ReadComplete, ] XCTAssertEqual(expectedEvents, serverHandler.events) } @@ -96,7 +101,9 @@ class NIOSSLALPNTest: XCTestCase { serverCtx = try assertNoThrowWithValue(configuredSSLContextWithAlpnProtocols(protocols: ["h2", "http/1.1"])) clientCtx = try assertNoThrowWithValue(configuredSSLContextWithAlpnProtocols(protocols: ["http/1.1", "h2"])) - XCTAssertNoThrow(try assertNegotiatedProtocol(protocol: "h2", serverContext: serverCtx, clientContext: clientCtx)) + XCTAssertNoThrow( + try assertNegotiatedProtocol(protocol: "h2", serverContext: serverCtx, clientContext: clientCtx) + ) } func testBasicALPNNegotiationNoOverlap() throws { @@ -104,7 +111,9 @@ class NIOSSLALPNTest: XCTestCase { let clientCtx: NIOSSLContext serverCtx = try assertNoThrowWithValue(configuredSSLContextWithAlpnProtocols(protocols: ["h2", "http/1.1"])) clientCtx = try assertNoThrowWithValue(configuredSSLContextWithAlpnProtocols(protocols: ["spdy/3", "webrtc"])) - XCTAssertNoThrow(try assertNegotiatedProtocol(protocol: nil, serverContext: serverCtx, clientContext: clientCtx)) + XCTAssertNoThrow( + try assertNegotiatedProtocol(protocol: nil, serverContext: serverCtx, clientContext: clientCtx) + ) } func testBasicALPNNegotiationNotOfferedByClient() throws { @@ -112,7 +121,9 @@ class NIOSSLALPNTest: XCTestCase { let clientCtx: NIOSSLContext serverCtx = try assertNoThrowWithValue(configuredSSLContextWithAlpnProtocols(protocols: ["h2", "http/1.1"])) clientCtx = try assertNoThrowWithValue(configuredSSLContextWithAlpnProtocols(protocols: [])) - XCTAssertNoThrow(try assertNegotiatedProtocol(protocol: nil, serverContext: serverCtx, clientContext: clientCtx)) + XCTAssertNoThrow( + try assertNegotiatedProtocol(protocol: nil, serverContext: serverCtx, clientContext: clientCtx) + ) } func testBasicALPNNegotiationNotSupportedByServer() throws { @@ -121,6 +132,8 @@ class NIOSSLALPNTest: XCTestCase { serverCtx = try assertNoThrowWithValue(configuredSSLContextWithAlpnProtocols(protocols: [])) clientCtx = try assertNoThrowWithValue(configuredSSLContextWithAlpnProtocols(protocols: ["h2", "http/1.1"])) - XCTAssertNoThrow(try assertNegotiatedProtocol(protocol: nil, serverContext: serverCtx, clientContext: clientCtx)) + XCTAssertNoThrow( + try assertNegotiatedProtocol(protocol: nil, serverContext: serverCtx, clientContext: clientCtx) + ) } } diff --git a/Tests/NIOSSLTests/NIOSSLIntegrationTest.swift b/Tests/NIOSSLTests/NIOSSLIntegrationTest.swift index 8662cdff0..fa8e0b7a7 100644 --- a/Tests/NIOSSLTests/NIOSSLIntegrationTest.swift +++ b/Tests/NIOSSLTests/NIOSSLIntegrationTest.swift @@ -12,16 +12,22 @@ // //===----------------------------------------------------------------------===// -import XCTest @_implementationOnly import CNIOBoringSSL import NIOConcurrencyHelpers import NIOCore import NIOEmbedded import NIOPosix -@testable import NIOSSL import NIOTLS +import XCTest + +@testable import NIOSSL -public func assertNoThrowWithValue(_ body: @autoclosure () throws -> T, defaultValue: T? = nil, file: StaticString = #filePath, line: UInt = #line) throws -> T { +public func assertNoThrowWithValue( + _ body: @autoclosure () throws -> T, + defaultValue: T? = nil, + file: StaticString = #filePath, + line: UInt = #line +) throws -> T { do { return try body() } catch { @@ -242,15 +248,15 @@ public final class EventRecorderHandler: ChannelInboundHandler wh // require Equatable, so we can't safely record these events and expect // a sensible implementation of Equatable here. - public static func ==(lhs: RecordedEvents, rhs: RecordedEvents) -> Bool { + public static func == (lhs: RecordedEvents, rhs: RecordedEvents) -> Bool { switch (lhs, rhs) { case (.Registered, .Registered), - (.Unregistered, .Unregistered), - (.Active, .Active), - (.Inactive, .Inactive), - (.Read, .Read), - (.ReadComplete, .ReadComplete), - (.WritabilityChanged, .WritabilityChanged): + (.Unregistered, .Unregistered), + (.Active, .Active), + (.Inactive, .Inactive), + (.Read, .Read), + (.ReadComplete, .ReadComplete), + (.WritabilityChanged, .WritabilityChanged): return true case (.UserEvent(let e1), .UserEvent(let e2)): return e1 == e2 @@ -341,66 +347,93 @@ private class WriteDelayHandler: ChannelOutboundHandler { func forceFlush() { let writes = self.writes self.writes = [] - writes.forEach { $0.0.writeAndFlush($0.1, promise: $0.2) } + for write in writes { write.0.writeAndFlush(write.1, promise: write.2) } } } -internal func serverTLSChannel(context: NIOSSLContext, - handlers: [ChannelHandler], - group: EventLoopGroup, - file: StaticString = #filePath, - line: UInt = #line) throws -> Channel { - return try assertNoThrowWithValue(serverTLSChannel(context: context, - preHandlers: [], - postHandlers: handlers, - group: group, - file: file, - line: line), - file: file, line: line) +internal func serverTLSChannel( + context: NIOSSLContext, + handlers: [ChannelHandler], + group: EventLoopGroup, + file: StaticString = #filePath, + line: UInt = #line +) throws -> Channel { + try assertNoThrowWithValue( + serverTLSChannel( + context: context, + preHandlers: [], + postHandlers: handlers, + group: group, + file: file, + line: line + ), + file: file, + line: line + ) } -internal func serverTLSChannel(context: NIOSSLContext, - preHandlers: [ChannelHandler], - postHandlers: [ChannelHandler], - group: EventLoopGroup, - customVerificationCallback: NIOSSLCustomVerificationCallback? = nil, - file: StaticString = #filePath, - line: UInt = #line) throws -> Channel { - return try assertNoThrowWithValue(ServerBootstrap(group: group) - .serverChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1) - .childChannelInitializer { channel in - let results = preHandlers.map { channel.pipeline.addHandler($0) } - return EventLoopFuture.andAllSucceed(results, on: channel.eventLoop).map { - if let verify = customVerificationCallback { - return NIOSSLServerHandler(context: context, customVerificationCallback: verify) - } else { - return NIOSSLServerHandler(context: context) +internal func serverTLSChannel( + context: NIOSSLContext, + preHandlers: [ChannelHandler], + postHandlers: [ChannelHandler], + group: EventLoopGroup, + customVerificationCallback: NIOSSLCustomVerificationCallback? = nil, + file: StaticString = #filePath, + line: UInt = #line +) throws -> Channel { + try assertNoThrowWithValue( + ServerBootstrap(group: group) + .serverChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1) + .childChannelInitializer { channel in + let results = preHandlers.map { channel.pipeline.addHandler($0) } + return EventLoopFuture.andAllSucceed(results, on: channel.eventLoop).map { + if let verify = customVerificationCallback { + return NIOSSLServerHandler(context: context, customVerificationCallback: verify) + } else { + return NIOSSLServerHandler(context: context) + } + }.flatMap { + channel.pipeline.addHandler($0) + }.flatMap { + let results = postHandlers.map { channel.pipeline.addHandler($0) } + return EventLoopFuture.andAllSucceed(results, on: channel.eventLoop) } - }.flatMap { - channel.pipeline.addHandler($0) - }.flatMap { - let results = postHandlers.map { channel.pipeline.addHandler($0) } - return EventLoopFuture.andAllSucceed(results, on: channel.eventLoop) - } - }.bind(host: "127.0.0.1", port: 0).wait(), file: file, line: line) + }.bind(host: "127.0.0.1", port: 0).wait(), + file: file, + line: line + ) } -typealias SendableAdditionalPeerCertificateVerificationCallback = @Sendable (NIOSSLCertificate, Channel) -> EventLoopFuture - -internal func clientTLSChannel(context: NIOSSLContext, - additionalPeerCertificateVerificationCallback: SendableAdditionalPeerCertificateVerificationCallback? = nil, - preHandlers: [ChannelHandler], - postHandlers: [ChannelHandler], - group: EventLoopGroup, - connectingTo: SocketAddress, - serverHostname: String? = nil, - file: StaticString = #filePath, - line: UInt = #line) throws -> Channel { +typealias SendableAdditionalPeerCertificateVerificationCallback = @Sendable (NIOSSLCertificate, Channel) -> + EventLoopFuture + +internal func clientTLSChannel( + context: NIOSSLContext, + additionalPeerCertificateVerificationCallback: SendableAdditionalPeerCertificateVerificationCallback? = nil, + preHandlers: [ChannelHandler], + postHandlers: [ChannelHandler], + group: EventLoopGroup, + connectingTo: SocketAddress, + serverHostname: String? = nil, + file: StaticString = #filePath, + line: UInt = #line +) throws -> Channel { func tlsFactory() -> NIOSSLClientTLSProvider { - return try! .init(context: context, serverHostname: serverHostname, additionalPeerCertificateVerificationCallback: additionalPeerCertificateVerificationCallback) + try! .init( + context: context, + serverHostname: serverHostname, + additionalPeerCertificateVerificationCallback: additionalPeerCertificateVerificationCallback + ) } - return try _clientTLSChannel(context: context, preHandlers: preHandlers, postHandlers: postHandlers, group: group, connectingTo: connectingTo, tlsFactory: tlsFactory) + return try _clientTLSChannel( + context: context, + preHandlers: preHandlers, + postHandlers: postHandlers, + group: group, + connectingTo: connectingTo, + tlsFactory: tlsFactory + ) } @available(*, deprecated, message: "just for testing the deprecated functionality") @@ -412,92 +445,121 @@ private struct DeprecatedTLSProviderForTests Bootstrap { - return bootstrap.protocolHandlers { + bootstrap.protocolHandlers { // NIOSSLClientHandler.init only throws because of `malloc` error and invalid SNI hostnames. We want to crash // on malloc error and we pre-checked the SNI hostname in `init` so that should be impossible here. - return [try! NIOSSLClientHandler(context: self.context, - serverHostname: self.serverHostname, - verificationCallback: self.verificationCallback)] + [ + try! NIOSSLClientHandler( + context: self.context, + serverHostname: self.serverHostname, + verificationCallback: self.verificationCallback + ) + ] } } } - - -@available(*, deprecated, renamed: "clientTLSChannel(context:preHandlers:postHandlers:group:connectingTo:serverHostname:customVerificationCallback:file:line:)") -internal func clientTLSChannel(context: NIOSSLContext, - preHandlers: [ChannelHandler], - postHandlers: [ChannelHandler], - group: EventLoopGroup, - connectingTo: SocketAddress, - serverHostname: String? = nil, - verificationCallback: @escaping NIOSSLVerificationCallback, - file: StaticString = #filePath, - line: UInt = #line) throws -> Channel { +@available( + *, + deprecated, + renamed: + "clientTLSChannel(context:preHandlers:postHandlers:group:connectingTo:serverHostname:customVerificationCallback:file:line:)" +) +internal func clientTLSChannel( + context: NIOSSLContext, + preHandlers: [ChannelHandler], + postHandlers: [ChannelHandler], + group: EventLoopGroup, + connectingTo: SocketAddress, + serverHostname: String? = nil, + verificationCallback: @escaping NIOSSLVerificationCallback, + file: StaticString = #filePath, + line: UInt = #line +) throws -> Channel { func tlsFactory() -> DeprecatedTLSProviderForTests { - return .init(context: context, serverHostname: serverHostname, verificationCallback: verificationCallback) + .init(context: context, serverHostname: serverHostname, verificationCallback: verificationCallback) } - return try _clientTLSChannel(context: context, - preHandlers: preHandlers, - postHandlers: postHandlers, - group: group, connectingTo: connectingTo, - tlsFactory: tlsFactory) + return try _clientTLSChannel( + context: context, + preHandlers: preHandlers, + postHandlers: postHandlers, + group: group, + connectingTo: connectingTo, + tlsFactory: tlsFactory + ) } - -internal func clientTLSChannel(context: NIOSSLContext, - preHandlers: [ChannelHandler], - postHandlers: [ChannelHandler], - group: EventLoopGroup, - connectingTo: SocketAddress, - serverHostname: String? = nil, - customVerificationCallback: @escaping NIOSSLCustomVerificationCallback, - file: StaticString = #filePath, - line: UInt = #line) throws -> Channel { +internal func clientTLSChannel( + context: NIOSSLContext, + preHandlers: [ChannelHandler], + postHandlers: [ChannelHandler], + group: EventLoopGroup, + connectingTo: SocketAddress, + serverHostname: String? = nil, + customVerificationCallback: @escaping NIOSSLCustomVerificationCallback, + file: StaticString = #filePath, + line: UInt = #line +) throws -> Channel { func tlsFactory() -> NIOSSLClientTLSProvider { - return try! .init(context: context, - serverHostname: serverHostname, - customVerificationCallback: customVerificationCallback) + try! .init( + context: context, + serverHostname: serverHostname, + customVerificationCallback: customVerificationCallback + ) } - return try _clientTLSChannel(context: context, - preHandlers: preHandlers, - postHandlers: postHandlers, - group: group, - connectingTo: connectingTo, - tlsFactory: tlsFactory) + return try _clientTLSChannel( + context: context, + preHandlers: preHandlers, + postHandlers: postHandlers, + group: group, + connectingTo: connectingTo, + tlsFactory: tlsFactory + ) } -fileprivate func _clientTLSChannel(context: NIOSSLContext, - preHandlers: [ChannelHandler], - postHandlers: [ChannelHandler], - group: EventLoopGroup, - connectingTo: SocketAddress, - tlsFactory: @escaping () -> TLS, - file: StaticString = #filePath, - line: UInt = #line) throws -> Channel where TLS.Bootstrap == ClientBootstrap { - let bootstrap = NIOClientTCPBootstrap(ClientBootstrap(group: group), - tls: tlsFactory()) - return try assertNoThrowWithValue(bootstrap - .channelInitializer { channel in - channel.pipeline.addHandlers(postHandlers) - } - .enableTLS() - .connect(to: connectingTo) - .flatMap { channel in - channel.pipeline.addHandlers(preHandlers, position: .first).map { - channel - } - } - .wait(), file: file, line: line) +private func _clientTLSChannel( + context: NIOSSLContext, + preHandlers: [ChannelHandler], + postHandlers: [ChannelHandler], + group: EventLoopGroup, + connectingTo: SocketAddress, + tlsFactory: @escaping () -> TLS, + file: StaticString = #filePath, + line: UInt = #line +) throws -> Channel where TLS.Bootstrap == ClientBootstrap { + let bootstrap = NIOClientTCPBootstrap( + ClientBootstrap(group: group), + tls: tlsFactory() + ) + return try assertNoThrowWithValue( + bootstrap + .channelInitializer { channel in + channel.pipeline.addHandlers(postHandlers) + } + .enableTLS() + .connect(to: connectingTo) + .flatMap { channel in + channel.pipeline.addHandlers(preHandlers, position: .first).map { + channel + } + } + .wait(), + file: file, + line: line + ) } struct EventLoopFutureTimeoutError: Error {} @@ -534,14 +596,21 @@ class NIOSSLIntegrationTest: XCTestCase { let (cert, key) = generateSelfSignedCert() NIOSSLIntegrationTest.cert = cert NIOSSLIntegrationTest.key = key - NIOSSLIntegrationTest.encryptedKeyPath = try! keyInFile(key: NIOSSLIntegrationTest.key, passphrase: "thisisagreatpassword") + NIOSSLIntegrationTest.encryptedKeyPath = try! keyInFile( + key: NIOSSLIntegrationTest.key, + passphrase: "thisisagreatpassword" + ) } override class func tearDown() { _ = unlink(NIOSSLIntegrationTest.encryptedKeyPath) } - private func configuredSSLContext(keyLogCallback: NIOSSLKeyLogCallback? = nil, file: StaticString = #filePath, line: UInt = #line) throws -> NIOSSLContext { + private func configuredSSLContext( + keyLogCallback: NIOSSLKeyLogCallback? = nil, + file: StaticString = #filePath, + line: UInt = #line + ) throws -> NIOSSLContext { var config = TLSConfiguration.makeServerConfiguration( certificateChain: [.certificate(NIOSSLIntegrationTest.cert)], privateKey: .privateKey(NIOSSLIntegrationTest.key) @@ -551,16 +620,25 @@ class NIOSSLIntegrationTest: XCTestCase { return try assertNoThrowWithValue(NIOSSLContext(configuration: config), file: file, line: line) } - private func configuredSSLContext(passphraseCallback: @escaping NIOSSLPassphraseCallback, - file: StaticString = #filePath, line: UInt = #line) throws -> NIOSSLContext - where T.Element == UInt8 { - let privateKey = try NIOSSLPrivateKey(file: NIOSSLIntegrationTest.encryptedKeyPath, format: .pem) { closure in closure("thisisagreatpassword".utf8) } + private func configuredSSLContext( + passphraseCallback: @escaping NIOSSLPassphraseCallback, + file: StaticString = #filePath, + line: UInt = #line + ) throws -> NIOSSLContext + where T.Element == UInt8 { + let privateKey = try NIOSSLPrivateKey(file: NIOSSLIntegrationTest.encryptedKeyPath, format: .pem) { closure in + closure("thisisagreatpassword".utf8) + } var config = TLSConfiguration.makeServerConfiguration( certificateChain: [.certificate(NIOSSLIntegrationTest.cert)], privateKey: .privateKey(privateKey) ) config.trustRoots = .certificates([NIOSSLIntegrationTest.cert]) - return try assertNoThrowWithValue(NIOSSLContext(configuration: config, passphraseCallback: passphraseCallback), file: file, line: line) + return try assertNoThrowWithValue( + NIOSSLContext(configuration: config, passphraseCallback: passphraseCallback), + file: file, + line: line + ) } private func configuredClientContext( @@ -569,10 +647,14 @@ class NIOSSLIntegrationTest: XCTestCase { ) throws -> NIOSSLContext { var config = TLSConfiguration.makeClientConfiguration() config.trustRoots = .certificates([NIOSSLIntegrationTest.cert]) - return try assertNoThrowWithValue(NIOSSLContext( - configuration: config, - callbackManager: nil - ), file: file, line: line) + return try assertNoThrowWithValue( + NIOSSLContext( + configuration: config, + callbackManager: nil + ), + file: file, + line: line + ) } static func keyInFile(key: NIOSSLPrivateKey, passphrase: String) throws -> String { @@ -586,7 +668,15 @@ class NIOSSLIntegrationTest: XCTestCase { let rc = withExtendedLifetime(manager) { manager -> CInt in let userData = Unmanaged.passUnretained(manager).toOpaque() return key.withUnsafeMutableEVPPKEYPointer { ref in - return CNIOBoringSSL_PEM_write_bio_PrivateKey(fileBio, ref, CNIOBoringSSL_EVP_aes_256_cbc(), nil, 0, globalBoringSSLPassphraseCallback, userData) + CNIOBoringSSL_PEM_write_bio_PrivateKey( + fileBio, + ref, + CNIOBoringSSL_EVP_aes_256_cbc(), + nil, + 0, + globalBoringSSLPassphraseCallback, + userData + ) } } CNIOBoringSSL_BIO_free(fileBio) @@ -600,7 +690,7 @@ class NIOSSLIntegrationTest: XCTestCase { fatalError("couldn't make temp file") } let tempFile = fileName.withCString { ptr in - return open(ptr, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0o644) + open(ptr, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0o644) } precondition(tempFile > 1, String(cString: strerror(errno))) let fileBio = CNIOBoringSSL_BIO_new_fp(fdopen(tempFile, "w+"), BIO_CLOSE) @@ -624,16 +714,22 @@ class NIOSSLIntegrationTest: XCTestCase { let completionPromise: EventLoopPromise = group.next().makePromise() - let serverChannel: Channel = try serverTLSChannel(context: context, handlers: [SimpleEchoServer()], group: group) + let serverChannel: Channel = try serverTLSChannel( + context: context, + handlers: [SimpleEchoServer()], + group: group + ) defer { XCTAssertNoThrow(try serverChannel.close().wait()) } - let clientChannel = try clientTLSChannel(context: context, - preHandlers: [], - postHandlers: [PromiseOnReadHandler(promise: completionPromise)], - group: group, - connectingTo: serverChannel.localAddress!) + let clientChannel = try clientTLSChannel( + context: context, + preHandlers: [], + postHandlers: [PromiseOnReadHandler(promise: completionPromise)], + group: group, + connectingTo: serverChannel.localAddress! + ) defer { XCTAssertNoThrow(try clientChannel.close().wait()) } @@ -656,18 +752,22 @@ class NIOSSLIntegrationTest: XCTestCase { let readComplete: EventLoopPromise = group.next().makePromise() let serverHandler: EventRecorderHandler = EventRecorderHandler() - let serverChannel = try serverTLSChannel(context: context, - handlers: [serverHandler, PromiseOnReadHandler(promise: readComplete)], - group: group) + let serverChannel = try serverTLSChannel( + context: context, + handlers: [serverHandler, PromiseOnReadHandler(promise: readComplete)], + group: group + ) defer { XCTAssertNoThrow(try serverChannel.close().wait()) } - let clientChannel = try clientTLSChannel(context: context, - preHandlers: [], - postHandlers: [SimpleEchoServer()], - group: group, - connectingTo: serverChannel.localAddress!) + let clientChannel = try clientTLSChannel( + context: context, + preHandlers: [], + postHandlers: [SimpleEchoServer()], + group: group, + connectingTo: serverChannel.localAddress! + ) defer { XCTAssertNoThrow(try clientChannel.close().wait()) } @@ -687,7 +787,7 @@ class NIOSSLIntegrationTest: XCTestCase { .Active, .UserEvent(TLSUserEvent.handshakeCompleted(negotiatedProtocol: nil)), .Read, - .ReadComplete + .ReadComplete, ] XCTAssertEqual(expectedEvents, serverHandler.events) @@ -703,15 +803,19 @@ class NIOSSLIntegrationTest: XCTestCase { let readComplete: EventLoopPromise = group.next().makePromise() let serverHandler: EventRecorderHandler = EventRecorderHandler() - let serverChannel = try serverTLSChannel(context: context, - handlers: [serverHandler, PromiseOnReadHandler(promise: readComplete)], - group: group) + let serverChannel = try serverTLSChannel( + context: context, + handlers: [serverHandler, PromiseOnReadHandler(promise: readComplete)], + group: group + ) - let clientChannel = try clientTLSChannel(context: context, - preHandlers: [], - postHandlers: [SimpleEchoServer()], - group: group, - connectingTo: serverChannel.localAddress!) + let clientChannel = try clientTLSChannel( + context: context, + preHandlers: [], + postHandlers: [SimpleEchoServer()], + group: group, + connectingTo: serverChannel.localAddress! + ) var originalBuffer = clientChannel.allocator.buffer(capacity: 5) originalBuffer.writeString("Hello") @@ -719,9 +823,9 @@ class NIOSSLIntegrationTest: XCTestCase { // Ok, we want to wait for the read to finish, then close the server and client connections. _ = try readComplete.futureResult.flatMap { (_: ByteBuffer) in - return serverChannel.close() - }.flatMap { - return clientChannel.close() + serverChannel.close() + }.flatMap { + clientChannel.close() }.wait() let expectedEvents: [EventRecorderHandler.RecordedEvents] = [ @@ -732,7 +836,7 @@ class NIOSSLIntegrationTest: XCTestCase { .ReadComplete, .UserEvent(TLSUserEvent.shutdownCompleted), .Inactive, - .Unregistered + .Unregistered, ] XCTAssertEqual(expectedEvents, serverHandler.events) @@ -751,12 +855,12 @@ class NIOSSLIntegrationTest: XCTestCase { let preHandlers: [ChannelHandler] = [] let postHandlers = [SimpleEchoServer()] let serverChannel: Channel = try ServerBootstrap(group: group) - .childChannelOption(ChannelOptions.allowRemoteHalfClosure, value: true) // Important! + .childChannelOption(ChannelOptions.allowRemoteHalfClosure, value: true) // Important! .serverChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1) .childChannelInitializer { channel in let results = preHandlers.map { channel.pipeline.addHandler($0) } return EventLoopFuture.andAllSucceed(results, on: channel.eventLoop).map { - return NIOSSLServerHandler(context: context) + NIOSSLServerHandler(context: context) }.flatMap { channel.pipeline.addHandler($0) }.flatMap { @@ -807,15 +911,15 @@ class NIOSSLIntegrationTest: XCTestCase { let preHandlers: [ChannelHandler] = [] let postHandlers: [ChannelHandler] = [ PromiseOnChildChannelInitHandler(promise: childChannelInitPromise), - SimpleEchoServer() + SimpleEchoServer(), ] let serverChannel: Channel = try ServerBootstrap(group: group) - .childChannelOption(ChannelOptions.allowRemoteHalfClosure, value: true) // Important! + .childChannelOption(ChannelOptions.allowRemoteHalfClosure, value: true) // Important! .serverChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1) .childChannelInitializer { channel in let results = preHandlers.map { channel.pipeline.addHandler($0) } return EventLoopFuture.andAllSucceed(results, on: channel.eventLoop).map { - return NIOSSLServerHandler(context: context) + NIOSSLServerHandler(context: context) }.flatMap { channel.pipeline.addHandler($0) }.flatMap { @@ -830,14 +934,17 @@ class NIOSSLIntegrationTest: XCTestCase { } let clientChannelInactivePromise: EventLoopPromise = group.next().makePromise() - let closeInputVerificationHandler = ShutdownVerificationHandler(shutdownEvent: .input, promise: group.next().makePromise()) + let closeInputVerificationHandler = ShutdownVerificationHandler( + shutdownEvent: .input, + promise: group.next().makePromise() + ) let clientChannel = try clientTLSChannel( context: context, preHandlers: [], postHandlers: [ PromiseOnReadHandler(promise: completionPromise), closeInputVerificationHandler, - ChannelInactiveHandler(promise: clientChannelInactivePromise) + ChannelInactiveHandler(promise: clientChannelInactivePromise), ], group: group, connectingTo: serverChannel.localAddress! @@ -879,12 +986,12 @@ class NIOSSLIntegrationTest: XCTestCase { let preHandlers: [ChannelHandler] = [] let postHandlers = [SimpleEchoServer()] let serverChannel: Channel = try ServerBootstrap(group: group) - .childChannelOption(ChannelOptions.allowRemoteHalfClosure, value: true) // Important! + .childChannelOption(ChannelOptions.allowRemoteHalfClosure, value: true) // Important! .serverChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1) .childChannelInitializer { channel in let results = preHandlers.map { channel.pipeline.addHandler($0) } return EventLoopFuture.andAllSucceed(results, on: channel.eventLoop).map { - return NIOSSLServerHandler(context: context) + NIOSSLServerHandler(context: context) }.flatMap { channel.pipeline.addHandler($0) }.flatMap { @@ -934,12 +1041,12 @@ class NIOSSLIntegrationTest: XCTestCase { let preHandlers: [ChannelHandler] = [] let postHandlers = [SimpleEchoServer()] let serverChannel: Channel = try ServerBootstrap(group: group) - .childChannelOption(ChannelOptions.allowRemoteHalfClosure, value: true) // Important! + .childChannelOption(ChannelOptions.allowRemoteHalfClosure, value: true) // Important! .serverChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1) .childChannelInitializer { channel in let results = preHandlers.map { channel.pipeline.addHandler($0) } return EventLoopFuture.andAllSucceed(results, on: channel.eventLoop).map { - return NIOSSLServerHandler(context: context) + NIOSSLServerHandler(context: context) }.flatMap { channel.pipeline.addHandler($0) }.flatMap { @@ -953,11 +1060,13 @@ class NIOSSLIntegrationTest: XCTestCase { XCTAssertNoThrow(try serverChannel.close().wait()) } - let clientChannel = try clientTLSChannel(context: context, - preHandlers: [], - postHandlers: [PromiseOnReadHandler(promise: completionPromise)], - group: group, - connectingTo: serverChannel.localAddress!) + let clientChannel = try clientTLSChannel( + context: context, + preHandlers: [], + postHandlers: [PromiseOnReadHandler(promise: completionPromise)], + group: group, + connectingTo: serverChannel.localAddress! + ) defer { XCTAssertNoThrow(try clientChannel.close().wait()) } @@ -976,7 +1085,9 @@ class NIOSSLIntegrationTest: XCTestCase { // To avoid the risk of the I/O loop actually closing the connection before we're done, we need to hijack the // I/O loop and issue all the closes on that thread. Otherwise, the channel will probably pull off the TLS shutdown // before we get to the third call to close(). - let promises: [EventLoopPromise] = [group.next().makePromise(), group.next().makePromise(), group.next().makePromise()] + let promises: [EventLoopPromise] = [ + group.next().makePromise(), group.next().makePromise(), group.next().makePromise(), + ] group.next().execute { for promise in promises { clientChannel.close(mode: .output, promise: promise) @@ -1010,11 +1121,13 @@ class NIOSSLIntegrationTest: XCTestCase { } } - let clientChannel = try clientTLSChannel(context: context, - preHandlers: [], - postHandlers: [PromiseOnReadHandler(promise: completionPromise)], - group: group, - connectingTo: serverChannel.localAddress!) + let clientChannel = try clientTLSChannel( + context: context, + preHandlers: [], + postHandlers: [PromiseOnReadHandler(promise: completionPromise)], + group: group, + connectingTo: serverChannel.localAddress! + ) defer { XCTAssertNoThrow(try clientChannel.close().wait()) } @@ -1033,7 +1146,9 @@ class NIOSSLIntegrationTest: XCTestCase { // To avoid the risk of the I/O loop actually closing the connection before we're done, we need to hijack the // I/O loop and issue all the closes on that thread. Otherwise, the channel will probably pull off the TLS shutdown // before we get to the third call to close(). - let promises: [EventLoopPromise] = [group.next().makePromise(), group.next().makePromise(), group.next().makePromise()] + let promises: [EventLoopPromise] = [ + group.next().makePromise(), group.next().makePromise(), group.next().makePromise(), + ] group.next().execute { for promise in promises { serverChannel.close(promise: promise) @@ -1065,11 +1180,13 @@ class NIOSSLIntegrationTest: XCTestCase { let writeCounter = WriteCountingHandler() let readPromise: EventLoopPromise = group.next().makePromise() - let clientChannel = try clientTLSChannel(context: context, - preHandlers: [writeCounter], - postHandlers: [PromiseOnReadHandler(promise: readPromise)], - group: group, - connectingTo: serverChannel.localAddress!) + let clientChannel = try clientTLSChannel( + context: context, + preHandlers: [writeCounter], + postHandlers: [PromiseOnReadHandler(promise: readPromise)], + group: group, + connectingTo: serverChannel.localAddress! + ) defer { XCTAssertNoThrow(try clientChannel.close().wait()) } @@ -1091,7 +1208,7 @@ class NIOSSLIntegrationTest: XCTestCase { // Here we're in the I/O loop, so we know that no further channel action will happen // while we dispatch this callback. This is the perfect time to check how many writes // happened. - return writeCounter.writeCount + writeCounter.writeCount }.wait() XCTAssertLessThanOrEqual(writeCount, 3) } @@ -1109,11 +1226,13 @@ class NIOSSLIntegrationTest: XCTestCase { XCTAssertNoThrow(try serverChannel.close().wait()) } - let clientChannel = try clientTLSChannel(context: context, - preHandlers: [], - postHandlers: [], - group: group, - connectingTo: serverChannel.localAddress!) + let clientChannel = try clientTLSChannel( + context: context, + preHandlers: [], + postHandlers: [], + group: group, + connectingTo: serverChannel.localAddress! + ) defer { XCTAssertNoThrow(try clientChannel.close().wait()) } @@ -1121,7 +1240,7 @@ class NIOSSLIntegrationTest: XCTestCase { // We're going to issue a number of small writes. Each of these should be coalesced together // and all their futures (along with the one for the flush) should fire, in order, with nothing // missed. - var firedFutures: Array = [] + var firedFutures: [Int] = [] var writeFutures: [EventLoopFuture<()>] = [] var originalBuffer = clientChannel.allocator.buffer(capacity: 1) originalBuffer.writeString("A") @@ -1140,7 +1259,7 @@ class NIOSSLIntegrationTest: XCTestCase { clientChannel.flush() try EventLoopFuture<()>.andAllSucceed(writeFutures, on: clientChannel.eventLoop).map { XCTAssertEqual(firedFutures, [0, 1, 2, 3, 4]) - }.recover { error in + }.recover { error in XCTFail("Write promised failed: \(error)") }.wait() } @@ -1169,9 +1288,11 @@ class NIOSSLIntegrationTest: XCTestCase { let recorderHandler: EventRecorderHandler = EventRecorderHandler() let channelActiveWaiter = ChannelActiveWaiter(promise: group.next().makePromise()) - let serverChannel = try serverTLSChannel(context: context, - handlers: [recorderHandler, SimpleEchoServer(), channelActiveWaiter], - group: group) + let serverChannel = try serverTLSChannel( + context: context, + handlers: [recorderHandler, SimpleEchoServer(), channelActiveWaiter], + group: group + ) defer { XCTAssertNoThrow(try serverChannel.close().wait()) } @@ -1194,7 +1315,10 @@ class NIOSSLIntegrationTest: XCTestCase { }.wait() // Now, add the TLS handler to the pipeline. - try clientChannel.pipeline.addHandler(NIOSSLClientHandler(context: context, serverHostname: nil), position: .first).wait() + try clientChannel.pipeline.addHandler( + NIOSSLClientHandler(context: context, serverHostname: nil), + position: .first + ).wait() var data = clientChannel.allocator.buffer(capacity: 1) data.writeStaticString("x") try clientChannel.writeAndFlush(data).wait() @@ -1204,7 +1328,10 @@ class NIOSSLIntegrationTest: XCTestCase { // At this point the handshake should be complete. try group.next().submit { - XCTAssertEqual(recorderHandler.events[..<3], [.Registered, .Active, .UserEvent(.handshakeCompleted(negotiatedProtocol: nil))]) + XCTAssertEqual( + recorderHandler.events[..<3], + [.Registered, .Active, .UserEvent(.handshakeCompleted(negotiatedProtocol: nil))] + ) }.wait() } @@ -1217,19 +1344,23 @@ class NIOSSLIntegrationTest: XCTestCase { try? group.syncShutdownGracefully() } - let serverChannel = try serverTLSChannel(context: serverCtx, - handlers: [], - group: group) + let serverChannel = try serverTLSChannel( + context: serverCtx, + handlers: [], + group: group + ) defer { XCTAssertNoThrow(try serverChannel.close().wait()) } let errorHandler = ErrorCatcher() - let clientChannel = try clientTLSChannel(context: clientCtx, - preHandlers: [], - postHandlers: [errorHandler], - group: group, - connectingTo: serverChannel.localAddress!) + let clientChannel = try clientTLSChannel( + context: clientCtx, + preHandlers: [], + postHandlers: [errorHandler], + group: group, + connectingTo: serverChannel.localAddress! + ) var originalBuffer = clientChannel.allocator.buffer(capacity: 5) originalBuffer.writeString("Hello") @@ -1237,9 +1368,9 @@ class NIOSSLIntegrationTest: XCTestCase { let errorsFuture: EventLoopFuture<[NIOSSLExtraError]> = writeFuture.recover { (_: Error) in // We're swallowing errors here, on purpose, because we'll definitely // hit them. - return () + () }.map { - return errorHandler.errors + errorHandler.errors } let actualErrors = try errorsFuture.wait() @@ -1248,7 +1379,10 @@ class NIOSSLIntegrationTest: XCTestCase { let expectedErrors: [NIOSSLExtraError] = [NIOSSLExtraError.failedToValidateHostname] XCTAssertEqual(expectedErrors, actualErrors) - XCTAssertEqual(actualErrors.first.map { String(describing: $0) }, "NIOSSLExtraError.failedToValidateHostname: Couldn't find in certificate from peer") + XCTAssertEqual( + actualErrors.first.map { String(describing: $0) }, + "NIOSSLExtraError.failedToValidateHostname: Couldn't find in certificate from peer" + ) } func testValidatesHostnameOnConnectionSucceeds() throws { @@ -1260,26 +1394,33 @@ class NIOSSLIntegrationTest: XCTestCase { XCTAssertNoThrow(try group.syncShutdownGracefully()) } - let serverChannel = try serverTLSChannel(context: serverCtx, - handlers: [], - group: group) + let serverChannel = try serverTLSChannel( + context: serverCtx, + handlers: [], + group: group + ) defer { XCTAssertNoThrow(try serverChannel.close().wait()) } let eventHandler = EventRecorderHandler() - let clientChannel = try clientTLSChannel(context: clientCtx, - preHandlers: [], - postHandlers: [eventHandler], - group: group, - connectingTo: serverChannel.localAddress!, - serverHostname: "localhost") + let clientChannel = try clientTLSChannel( + context: clientCtx, + preHandlers: [], + postHandlers: [eventHandler], + group: group, + connectingTo: serverChannel.localAddress!, + serverHostname: "localhost" + ) var originalBuffer = clientChannel.allocator.buffer(capacity: 5) originalBuffer.writeString("Hello") let writeFuture = clientChannel.writeAndFlush(originalBuffer) writeFuture.whenComplete { _ in - XCTAssertEqual(eventHandler.events[..<3], [.Registered, .Active, .UserEvent(.handshakeCompleted(negotiatedProtocol: nil))]) + XCTAssertEqual( + eventHandler.events[..<3], + [.Registered, .Active, .UserEvent(.handshakeCompleted(negotiatedProtocol: nil))] + ) } try writeFuture.wait() } @@ -1293,30 +1434,37 @@ class NIOSSLIntegrationTest: XCTestCase { let serverCtx = try configuredSSLContext() let clientCtx = try configuredClientContext() - let serverChannel = try serverTLSChannel(context: serverCtx, - handlers: [], - group: group) + let serverChannel = try serverTLSChannel( + context: serverCtx, + handlers: [], + group: group + ) defer { XCTAssertNoThrow(try serverChannel.close().wait()) } let eventHandler = EventRecorderHandler() - let clientChannel = try clientTLSChannel(context: clientCtx, - additionalPeerCertificateVerificationCallback: { cert, channel in - XCTAssertEqual(cert, Self.cert) - return channel.eventLoop.makeSucceededFuture(()) - }, - preHandlers: [], - postHandlers: [eventHandler], - group: group, - connectingTo: serverChannel.localAddress!, - serverHostname: "localhost") + let clientChannel = try clientTLSChannel( + context: clientCtx, + additionalPeerCertificateVerificationCallback: { cert, channel in + XCTAssertEqual(cert, Self.cert) + return channel.eventLoop.makeSucceededFuture(()) + }, + preHandlers: [], + postHandlers: [eventHandler], + group: group, + connectingTo: serverChannel.localAddress!, + serverHostname: "localhost" + ) var originalBuffer = clientChannel.allocator.buffer(capacity: 5) originalBuffer.writeString("Hello") let writeFuture = clientChannel.writeAndFlush(originalBuffer) writeFuture.whenComplete { _ in - XCTAssertEqual(eventHandler.events[..<3], [.Registered, .Active, .UserEvent(.handshakeCompleted(negotiatedProtocol: nil))]) + XCTAssertEqual( + eventHandler.events[..<3], + [.Registered, .Active, .UserEvent(.handshakeCompleted(negotiatedProtocol: nil))] + ) } try writeFuture.wait() } @@ -1331,9 +1479,11 @@ class NIOSSLIntegrationTest: XCTestCase { let serverCtx = try configuredSSLContext() let clientCtx = try configuredClientContext() - let serverChannel = try serverTLSChannel(context: serverCtx, - handlers: [], - group: group) + let serverChannel = try serverTLSChannel( + context: serverCtx, + handlers: [], + group: group + ) defer { XCTAssertNoThrow(try serverChannel.close().wait()) } @@ -1358,9 +1508,9 @@ class NIOSSLIntegrationTest: XCTestCase { let errorsFuture: EventLoopFuture<[Error]> = writeFuture.recover { (_: Error) in // We're swallowing errors here, on purpose, because we'll definitely // hit them. - return () + () }.map { - return errorHandler.errors + errorHandler.errors } let actualErrors = try errorsFuture.wait() @@ -1380,30 +1530,37 @@ class NIOSSLIntegrationTest: XCTestCase { let serverCtx = try configuredSSLContext() let clientCtx = try configuredClientContext() - let serverChannel = try serverTLSChannel(context: serverCtx, - handlers: [], - group: group) + let serverChannel = try serverTLSChannel( + context: serverCtx, + handlers: [], + group: group + ) defer { XCTAssertNoThrow(try serverChannel.close().wait()) } let eventHandler = EventRecorderHandler() - let clientChannel = try clientTLSChannel(context: clientCtx, - additionalPeerCertificateVerificationCallback: { cert, channel in - XCTAssertEqual(cert, Self.cert) - channel.flush() - return additionalHandshakePromise.futureResult - }, - preHandlers: [], - postHandlers: [eventHandler], - group: group, - connectingTo: serverChannel.localAddress!, - serverHostname: "localhost") + let clientChannel = try clientTLSChannel( + context: clientCtx, + additionalPeerCertificateVerificationCallback: { cert, channel in + XCTAssertEqual(cert, Self.cert) + channel.flush() + return additionalHandshakePromise.futureResult + }, + preHandlers: [], + postHandlers: [eventHandler], + group: group, + connectingTo: serverChannel.localAddress!, + serverHostname: "localhost" + ) let writeFuture = clientChannel.writeAndFlush(ByteBuffer(string: "Hello")) XCTAssertThrowsError(try writeFuture.timeout(after: .milliseconds(100)).wait()) additionalHandshakePromise.succeed(()) writeFuture.whenComplete { _ in - XCTAssertEqual(eventHandler.events[..<3], [.Registered, .Active, .UserEvent(.handshakeCompleted(negotiatedProtocol: nil))]) + XCTAssertEqual( + eventHandler.events[..<3], + [.Registered, .Active, .UserEvent(.handshakeCompleted(negotiatedProtocol: nil))] + ) } try writeFuture.wait() } @@ -1459,7 +1616,7 @@ class NIOSSLIntegrationTest: XCTestCase { } // Now clean up the client channel. We need to also fire the channel inactive here as there is - // no-one left for the client channel to hang up on. + // no-one left for the client channel to end the connection with. _ = clientChannel.close() clientChannel.pipeline.fireChannelInactive() } @@ -1476,7 +1633,10 @@ class NIOSSLIntegrationTest: XCTestCase { return config } defer { - precondition(.some(0) == tempFile.map { unlink($0) }, "couldn't remove temp file \(tempFile.debugDescription)") + precondition( + .some(0) == tempFile.map { unlink($0) }, + "couldn't remove temp file \(tempFile.debugDescription)" + ) } let clientCtx = try assertNoThrowWithValue(NIOSSLContext(configuration: config)) @@ -1486,16 +1646,22 @@ class NIOSSLIntegrationTest: XCTestCase { } let completionPromise: EventLoopPromise = group.next().makePromise() - let serverChannel: Channel = try serverTLSChannel(context: serverCtx, handlers: [SimpleEchoServer()], group: group) + let serverChannel: Channel = try serverTLSChannel( + context: serverCtx, + handlers: [SimpleEchoServer()], + group: group + ) defer { _ = try? serverChannel.close().wait() } - let clientChannel = try clientTLSChannel(context: clientCtx, - preHandlers: [], - postHandlers: [PromiseOnReadHandler(promise: completionPromise)], - group: group, - connectingTo: serverChannel.localAddress!) + let clientChannel = try clientTLSChannel( + context: clientCtx, + preHandlers: [], + postHandlers: [PromiseOnReadHandler(promise: completionPromise)], + group: group, + connectingTo: serverChannel.localAddress! + ) defer { _ = try? clientChannel.close().wait() } @@ -1522,19 +1688,23 @@ class NIOSSLIntegrationTest: XCTestCase { XCTAssertNoThrow(try group.syncShutdownGracefully()) } - let serverChannel = try serverTLSChannel(context: serverCtx, - handlers: [], - group: group) + let serverChannel = try serverTLSChannel( + context: serverCtx, + handlers: [], + group: group + ) defer { XCTAssertNoThrow(try serverChannel.close().wait()) } let errorHandler = ErrorCatcher() - let clientChannel = try clientTLSChannel(context: clientCtx, - preHandlers: [], - postHandlers: [errorHandler], - group: group, - connectingTo: serverChannel.localAddress!) + let clientChannel = try clientTLSChannel( + context: clientCtx, + preHandlers: [], + postHandlers: [errorHandler], + group: group, + connectingTo: serverChannel.localAddress! + ) var originalBuffer = clientChannel.allocator.buffer(capacity: 5) originalBuffer.writeString("Hello") @@ -1542,9 +1712,9 @@ class NIOSSLIntegrationTest: XCTestCase { let errorsFuture: EventLoopFuture<[NIOSSLError]> = writeFuture.recover { (_: Error) in // We're swallowing errors here, on purpose, because we'll definitely // hit them. - return () + () }.map { - return errorHandler.errors + errorHandler.errors } let actualErrors = try errorsFuture.wait() @@ -1583,7 +1753,8 @@ class NIOSSLIntegrationTest: XCTestCase { XCTAssertNoThrow(try serverChannel.throwIfErrorCaught()) - XCTAssertThrowsError(try interactInMemory(clientChannel: clientChannel, serverChannel: serverChannel)) { error in + XCTAssertThrowsError(try interactInMemory(clientChannel: clientChannel, serverChannel: serverChannel)) { + error in XCTAssertEqual(.readInInvalidTLSState, error as? NIOSSLError) } } @@ -1594,12 +1765,15 @@ class NIOSSLIntegrationTest: XCTestCase { let context = try configuredSSLContext() - let completePromise: EventLoopPromise = serverChannel.eventLoop.makePromise() XCTAssertNoThrow(try serverChannel.pipeline.addHandler(NIOSSLServerHandler(context: context)).wait()) - XCTAssertNoThrow(try serverChannel.pipeline.addHandler(ReadRecordingHandler(completePromise: completePromise)).wait()) - XCTAssertNoThrow(try clientChannel.pipeline.addHandler(try NIOSSLClientHandler(context: context, serverHostname: nil)).wait()) + XCTAssertNoThrow( + try serverChannel.pipeline.addHandler(ReadRecordingHandler(completePromise: completePromise)).wait() + ) + XCTAssertNoThrow( + try clientChannel.pipeline.addHandler(try NIOSSLClientHandler(context: context, serverHostname: nil)).wait() + ) let addr = try SocketAddress(unixDomainSocketPath: "/tmp/whatever2") let connectFuture = clientChannel.connect(to: addr) @@ -1637,18 +1811,22 @@ class NIOSSLIntegrationTest: XCTestCase { let completionPromise: EventLoopPromise = group.next().makePromise() - let serverChannel = try serverTLSChannel(context: context, - handlers: [PromiseOnReadHandler(promise: completionPromise)], - group: group) + let serverChannel = try serverTLSChannel( + context: context, + handlers: [PromiseOnReadHandler(promise: completionPromise)], + group: group + ) defer { _ = try? serverChannel.close().wait() } - let clientChannel = try clientTLSChannel(context: context, - preHandlers: [], - postHandlers: [], - group: group, - connectingTo: serverChannel.localAddress!) + let clientChannel = try clientTLSChannel( + context: context, + preHandlers: [], + postHandlers: [], + group: group, + connectingTo: serverChannel.localAddress! + ) defer { _ = try? clientChannel.close().wait() } @@ -1732,16 +1910,22 @@ class NIOSSLIntegrationTest: XCTestCase { let completionPromise: EventLoopPromise = group.next().makePromise() - let serverChannel: Channel = try serverTLSChannel(context: context, handlers: [SimpleEchoServer()], group: group) + let serverChannel: Channel = try serverTLSChannel( + context: context, + handlers: [SimpleEchoServer()], + group: group + ) defer { XCTAssertNoThrow(try serverChannel.close().wait()) } - let clientChannel = try clientTLSChannel(context: context, - preHandlers: [], - postHandlers: [PromiseOnReadHandler(promise: completionPromise)], - group: group, - connectingTo: serverChannel.localAddress!) + let clientChannel = try clientTLSChannel( + context: context, + preHandlers: [], + postHandlers: [PromiseOnReadHandler(promise: completionPromise)], + group: group, + connectingTo: serverChannel.localAddress! + ) defer { XCTAssertNoThrow(try clientChannel.close().wait()) } @@ -1766,8 +1950,12 @@ class NIOSSLIntegrationTest: XCTestCase { let completePromise: EventLoopPromise = serverChannel.eventLoop.makePromise() XCTAssertNoThrow(try serverChannel.pipeline.addHandler(NIOSSLServerHandler(context: context)).wait()) - XCTAssertNoThrow(try serverChannel.pipeline.addHandler(ReadRecordingHandler(completePromise: completePromise)).wait()) - XCTAssertNoThrow(try clientChannel.pipeline.addHandler(try NIOSSLClientHandler(context: context, serverHostname: nil)).wait()) + XCTAssertNoThrow( + try serverChannel.pipeline.addHandler(ReadRecordingHandler(completePromise: completePromise)).wait() + ) + XCTAssertNoThrow( + try clientChannel.pipeline.addHandler(try NIOSSLClientHandler(context: context, serverHostname: nil)).wait() + ) // Connect let addr = try assertNoThrowWithValue(SocketAddress(unixDomainSocketPath: "/tmp/whatever2")) @@ -1814,15 +2002,17 @@ class NIOSSLIntegrationTest: XCTestCase { } let errorHandler = ErrorCatcher() - let clientChannel = try clientTLSChannel(context: try configuredClientContext(), - preHandlers: [], - postHandlers: [errorHandler], - group: group, - connectingTo: serverChannel.localAddress!, - verificationCallback: { preverify, certificate in - XCTAssertEqual(preverify, .certificateVerified) - return .failed - }) + let clientChannel = try clientTLSChannel( + context: try configuredClientContext(), + preHandlers: [], + postHandlers: [errorHandler], + group: group, + connectingTo: serverChannel.localAddress!, + verificationCallback: { preverify, certificate in + XCTAssertEqual(preverify, .certificateVerified) + return .failed + } + ) var originalBuffer = clientChannel.allocator.buffer(capacity: 5) originalBuffer.writeString("Hello") @@ -1830,9 +2020,9 @@ class NIOSSLIntegrationTest: XCTestCase { let errorsFuture: EventLoopFuture<[NIOSSLError]> = writeFuture.recover { (_: Error) in // We're swallowing errors here, on purpose, because we'll definitely // hit them. - return () + () }.map { - return errorHandler.errors + errorHandler.errors } let actualErrors = try errorsFuture.wait() @@ -1859,22 +2049,28 @@ class NIOSSLIntegrationTest: XCTestCase { let completionPromise: EventLoopPromise = group.next().makePromise() - let serverChannel: Channel = try serverTLSChannel(context: context, handlers: [SimpleEchoServer()], group: group) + let serverChannel: Channel = try serverTLSChannel( + context: context, + handlers: [SimpleEchoServer()], + group: group + ) defer { XCTAssertNoThrow(try serverChannel.close().wait()) } var certificates = [NIOSSLCertificate]() - let clientChannel = try clientTLSChannel(context: configuredClientContext(), - preHandlers: [], - postHandlers: [PromiseOnReadHandler(promise: completionPromise)], - group: group, - connectingTo: serverChannel.localAddress!, - serverHostname: "localhost", - verificationCallback: { verify, certificate in - certificates.append(certificate) - return verify - }) + let clientChannel = try clientTLSChannel( + context: configuredClientContext(), + preHandlers: [], + postHandlers: [PromiseOnReadHandler(promise: completionPromise)], + group: group, + connectingTo: serverChannel.localAddress!, + serverHostname: "localhost", + verificationCallback: { verify, certificate in + certificates.append(certificate) + return verify + } + ) defer { XCTAssertNoThrow(try clientChannel.close().wait()) } @@ -1904,14 +2100,16 @@ class NIOSSLIntegrationTest: XCTestCase { let handshakeResultPromise = group.next().makePromise(of: Void.self) let handshakeWatcher = WaitForHandshakeHandler(handshakeResultPromise: handshakeResultPromise) - let clientChannel = try clientTLSChannel(context: try configuredClientContext(), - preHandlers: [], - postHandlers: [handshakeWatcher], - group: group, - connectingTo: serverChannel.localAddress!, - customVerificationCallback: { _, promise in - promise.succeed(.failed) - }) + let clientChannel = try clientTLSChannel( + context: try configuredClientContext(), + preHandlers: [], + postHandlers: [handshakeWatcher], + group: group, + connectingTo: serverChannel.localAddress!, + customVerificationCallback: { _, promise in + promise.succeed(.failed) + } + ) defer { // Ignore errors here, the channel should be closed already by the time this happens. @@ -1940,14 +2138,16 @@ class NIOSSLIntegrationTest: XCTestCase { let handshakeResultPromise = group.next().makePromise(of: Void.self) let handshakeWatcher = WaitForHandshakeHandler(handshakeResultPromise: handshakeResultPromise) - let clientChannel = try clientTLSChannel(context: try configuredClientContext(), - preHandlers: [], - postHandlers: [handshakeWatcher], - group: group, - connectingTo: serverChannel.localAddress!, - customVerificationCallback: { _, promise in - promise.fail(LocalError.kaboom) - }) + let clientChannel = try clientTLSChannel( + context: try configuredClientContext(), + preHandlers: [], + postHandlers: [handshakeWatcher], + group: group, + connectingTo: serverChannel.localAddress!, + customVerificationCallback: { _, promise in + promise.fail(LocalError.kaboom) + } + ) defer { // Ignore errors here, the channel should be closed already by the time this happens. try? clientChannel.close().wait() @@ -1991,7 +2191,8 @@ class NIOSSLIntegrationTest: XCTestCase { customVerificationCallback: { innerCertificates, promise in handshakeCompletePromise = promise handshakeFiredPromise.succeed(()) - }) + } + ) defer { XCTAssertNoThrow(try serverChannel.close().wait()) } @@ -2044,7 +2245,11 @@ class NIOSSLIntegrationTest: XCTestCase { } } - let serverChannel: Channel = try serverTLSChannel(context: context, handlers: [SimpleEchoServer()], group: group) + let serverChannel: Channel = try serverTLSChannel( + context: context, + handlers: [SimpleEchoServer()], + group: group + ) defer { XCTAssertNoThrow(try serverChannel.close().wait()) } @@ -2052,16 +2257,18 @@ class NIOSSLIntegrationTest: XCTestCase { var handshakeCompletePromise: EventLoopPromise? = nil let handshakeFiredPromise: EventLoopPromise = group.next().makePromise() - let clientChannel = try clientTLSChannel(context: configuredClientContext(), - preHandlers: [], - postHandlers: [PromiseOnReadHandler(promise: completionPromise)], - group: group, - connectingTo: serverChannel.localAddress!, - serverHostname: "localhost", - customVerificationCallback: { innerCertificates, promise in - handshakeCompletePromise = promise - handshakeFiredPromise.succeed(()) - }) + let clientChannel = try clientTLSChannel( + context: configuredClientContext(), + preHandlers: [], + postHandlers: [PromiseOnReadHandler(promise: completionPromise)], + group: group, + connectingTo: serverChannel.localAddress!, + serverHostname: "localhost", + customVerificationCallback: { innerCertificates, promise in + handshakeCompletePromise = promise + handshakeFiredPromise.succeed(()) + } + ) defer { XCTAssertNoThrow(try clientChannel.close().wait()) } @@ -2095,22 +2302,28 @@ class NIOSSLIntegrationTest: XCTestCase { let completionPromise: EventLoopPromise = group.next().makePromise() - let serverChannel: Channel = try serverTLSChannel(context: context, handlers: [SimpleEchoServer()], group: group) + let serverChannel: Channel = try serverTLSChannel( + context: context, + handlers: [SimpleEchoServer()], + group: group + ) defer { XCTAssertNoThrow(try serverChannel.close().wait()) } var certificates = [NIOSSLCertificate]() - let clientChannel = try clientTLSChannel(context: configuredClientContext(), - preHandlers: [], - postHandlers: [PromiseOnReadHandler(promise: completionPromise)], - group: group, - connectingTo: serverChannel.localAddress!, - serverHostname: "localhost", - customVerificationCallback: { innerCertificates, promise in - certificates = innerCertificates - promise.succeed(.certificateVerified) - }) + let clientChannel = try clientTLSChannel( + context: configuredClientContext(), + preHandlers: [], + postHandlers: [PromiseOnReadHandler(promise: completionPromise)], + group: group, + connectingTo: serverChannel.localAddress!, + serverHostname: "localhost", + customVerificationCallback: { innerCertificates, promise in + certificates = innerCertificates + promise.succeed(.certificateVerified) + } + ) defer { XCTAssertNoThrow(try clientChannel.close().wait()) } @@ -2149,17 +2362,19 @@ class NIOSSLIntegrationTest: XCTestCase { let handshakeCompletePromise = group.next().makePromise(of: Void.self) let customCallbackCalledPromise = group.next().makePromise(of: Void.self) - let clientChannel = try clientTLSChannel(context: clientContext, - preHandlers: [], - postHandlers: [WaitForHandshakeHandler(handshakeResultPromise: handshakeCompletePromise)], - group: group, - connectingTo: serverChannel.localAddress!, - serverHostname: "localhost", - customVerificationCallback: { _, promise in - // Note that we override certificate verification here. - customCallbackCalledPromise.succeed(()) - promise.succeed(.certificateVerified) - }) + let clientChannel = try clientTLSChannel( + context: clientContext, + preHandlers: [], + postHandlers: [WaitForHandshakeHandler(handshakeResultPromise: handshakeCompletePromise)], + group: group, + connectingTo: serverChannel.localAddress!, + serverHostname: "localhost", + customVerificationCallback: { _, promise in + // Note that we override certificate verification here. + customCallbackCalledPromise.succeed(()) + promise.succeed(.certificateVerified) + } + ) defer { XCTAssertNoThrow(try clientChannel.close().wait()) } @@ -2192,12 +2407,14 @@ class NIOSSLIntegrationTest: XCTestCase { } let handshakeCompletePromise = group.next().makePromise(of: Void.self) - let clientChannel = try clientTLSChannel(context: clientContext, - preHandlers: [], - postHandlers: [WaitForHandshakeHandler(handshakeResultPromise: handshakeCompletePromise)], - group: group, - connectingTo: serverChannel.localAddress!, - serverHostname: "localhost") + let clientChannel = try clientTLSChannel( + context: clientContext, + preHandlers: [], + postHandlers: [WaitForHandshakeHandler(handshakeResultPromise: handshakeCompletePromise)], + group: group, + connectingTo: serverChannel.localAddress!, + serverHostname: "localhost" + ) defer { XCTAssertNoThrow(try clientChannel.close().wait()) } @@ -2222,23 +2439,26 @@ class NIOSSLIntegrationTest: XCTestCase { let handshakeResultPromise = group.next().makePromise(of: Void.self) let handshakeWatcher = WaitForHandshakeHandler(handshakeResultPromise: handshakeResultPromise) - let serverChannel: Channel = try serverTLSChannel(context: context, - preHandlers: [], - postHandlers: [handshakeWatcher], - group: group, - customVerificationCallback: { _, promise in - promise.succeed(.failed) - }) + let serverChannel: Channel = try serverTLSChannel( + context: context, + preHandlers: [], + postHandlers: [handshakeWatcher], + group: group, + customVerificationCallback: { _, promise in + promise.succeed(.failed) + } + ) defer { XCTAssertNoThrow(try serverChannel.close().wait()) } - - let clientChannel = try clientTLSChannel(context: try configuredSSLContext(), - preHandlers: [], - postHandlers: [], - group: group, - connectingTo: serverChannel.localAddress!) + let clientChannel = try clientTLSChannel( + context: try configuredSSLContext(), + preHandlers: [], + postHandlers: [], + group: group, + connectingTo: serverChannel.localAddress! + ) defer { // Ignore errors here, the channel should be closed already by the time this happens. @@ -2261,7 +2481,9 @@ class NIOSSLIntegrationTest: XCTestCase { let context = try assertNoThrowWithValue(configuredSSLContext()) XCTAssertNoThrow(try serverChannel.pipeline.addHandler(NIOSSLServerHandler(context: context)).wait()) - XCTAssertNoThrow(try clientChannel.pipeline.addHandler(NIOSSLClientHandler(context: context, serverHostname: nil)).wait()) + XCTAssertNoThrow( + try clientChannel.pipeline.addHandler(NIOSSLClientHandler(context: context, serverHostname: nil)).wait() + ) let handshakeHandler = HandshakeCompletedHandler() XCTAssertNoThrow(try clientChannel.pipeline.addHandler(handshakeHandler).wait()) @@ -2299,7 +2521,9 @@ class NIOSSLIntegrationTest: XCTestCase { let context = try assertNoThrowWithValue(configuredSSLContext()) XCTAssertNoThrow(try serverChannel.pipeline.addHandler(NIOSSLServerHandler(context: context)).wait()) - XCTAssertNoThrow(try clientChannel.pipeline.addHandler(NIOSSLClientHandler(context: context, serverHostname: nil)).wait()) + XCTAssertNoThrow( + try clientChannel.pipeline.addHandler(NIOSSLClientHandler(context: context, serverHostname: nil)).wait() + ) let handshakeHandler = HandshakeCompletedHandler() XCTAssertNoThrow(try clientChannel.pipeline.addHandler(handshakeHandler).wait()) @@ -2381,7 +2605,10 @@ class NIOSSLIntegrationTest: XCTestCase { let errorString = String(describing: error) let range = NSRange(location: 0, length: errorString.utf16.count) - let regex = try! NSRegularExpression(pattern: "sslError\\(\\[Error\\: 268435703 error\\:100000f7\\:SSL routines\\:OPENSSL_internal\\:WRONG_VERSION_NUMBER at .*\\/[A-Za-z_]+\\.cc\\:[0-9]+\\]\\)") + let regex = try! NSRegularExpression( + pattern: + "sslError\\(\\[Error\\: 268435703 error\\:100000f7\\:SSL routines\\:OPENSSL_internal\\:WRONG_VERSION_NUMBER at .*\\/[A-Za-z_]+\\.cc\\:[0-9]+\\]\\)" + ) XCTAssertNotNil(regex.firstMatch(in: errorString, options: [], range: range)) } (clientChannel.eventLoop as! EmbeddedEventLoop).run() @@ -2422,9 +2649,9 @@ class NIOSSLIntegrationTest: XCTestCase { buffer.writeStaticString("Hello, world!") clientChannel.write(buffer).map { XCTFail("Must not succeed") - }.whenFailure { error in - XCTAssertEqual(error as? ChannelError, .ioOnClosedChannel) - writeCompleted = true + }.whenFailure { error in + XCTAssertEqual(error as? ChannelError, .ioOnClosedChannel) + writeCompleted = true } // We haven't spun the event loop, so the handlers are still in the pipeline. Now attempt to close. @@ -2482,7 +2709,9 @@ class NIOSSLIntegrationTest: XCTestCase { XCTAssertNoThrow(try serverChannel.pipeline.addHandler(NIOSSLServerHandler(context: context)).wait()) XCTAssertNoThrow(try serverChannel.pipeline.addHandler(FlushOnReadHandler()).wait()) - XCTAssertNoThrow(try clientChannel.pipeline.addHandler(try NIOSSLClientHandler(context: context, serverHostname: nil)).wait()) + XCTAssertNoThrow( + try clientChannel.pipeline.addHandler(try NIOSSLClientHandler(context: context, serverHostname: nil)).wait() + ) // Connect let addr = try assertNoThrowWithValue(SocketAddress(unixDomainSocketPath: "/tmp/whatever2")) @@ -2519,8 +2748,12 @@ class NIOSSLIntegrationTest: XCTestCase { let clientLines: UnsafeMutableTransferBox<[ByteBuffer]> = .init([]) let serverLines: UnsafeMutableTransferBox<[ByteBuffer]> = .init([]) - let clientContext = try assertNoThrowWithValue(self.configuredSSLContext(keyLogCallback: { clientLines.wrappedValue.append($0) })) - let serverContext = try assertNoThrowWithValue(self.configuredSSLContext(keyLogCallback: { serverLines.wrappedValue.append($0) })) + let clientContext = try assertNoThrowWithValue( + self.configuredSSLContext(keyLogCallback: { clientLines.wrappedValue.append($0) }) + ) + let serverContext = try assertNoThrowWithValue( + self.configuredSSLContext(keyLogCallback: { serverLines.wrappedValue.append($0) }) + ) let serverChannel = EmbeddedChannel() let clientChannel = EmbeddedChannel() @@ -2531,7 +2764,10 @@ class NIOSSLIntegrationTest: XCTestCase { } // Handshake - XCTAssertNoThrow(try clientChannel.pipeline.addHandler(NIOSSLClientHandler(context: clientContext, serverHostname: nil)).wait()) + XCTAssertNoThrow( + try clientChannel.pipeline.addHandler(NIOSSLClientHandler(context: clientContext, serverHostname: nil)) + .wait() + ) XCTAssertNoThrow(try serverChannel.pipeline.addHandler(NIOSSLServerHandler(context: serverContext)).wait()) let handshakeHandler = HandshakeCompletedHandler() XCTAssertNoThrow(try clientChannel.pipeline.addHandler(handshakeHandler).wait()) @@ -2578,11 +2814,13 @@ class NIOSSLIntegrationTest: XCTestCase { XCTAssertNoThrow(try serverChannel.close().wait()) } - let clientChannel = try clientTLSChannel(context: context, - preHandlers: [], - postHandlers: [], - group: group, - connectingTo: serverChannel.localAddress!) + let clientChannel = try clientTLSChannel( + context: context, + preHandlers: [], + postHandlers: [], + group: group, + connectingTo: serverChannel.localAddress! + ) let closeFutures = (0..<20).map { _ in clientChannel.close() } @@ -2652,9 +2890,13 @@ class NIOSSLIntegrationTest: XCTestCase { let context = try configuredSSLContext() let clientChannelCompletedPromise = clientChannel.eventLoop.makePromise(of: Void.self) - let clientChannelCompletedHandler = WaitForHandshakeHandler(handshakeResultPromise: clientChannelCompletedPromise) + let clientChannelCompletedHandler = WaitForHandshakeHandler( + handshakeResultPromise: clientChannelCompletedPromise + ) let serverChannelCompletedPromise = serverChannel.eventLoop.makePromise(of: Void.self) - let serverChannelCompletedHandler = WaitForHandshakeHandler(handshakeResultPromise: serverChannelCompletedPromise) + let serverChannelCompletedHandler = WaitForHandshakeHandler( + handshakeResultPromise: serverChannelCompletedPromise + ) clientChannelCompletedPromise.futureResult.whenSuccess { // Here we need to immediately (and _recursively_) ask the client channel to shutdown. This should force a CLOSE_NOTIFY @@ -2686,10 +2928,14 @@ class NIOSSLIntegrationTest: XCTestCase { } XCTAssertNoThrow( - try serverChannel.pipeline.syncOperations.addHandlers([NIOSSLServerHandler(context: context), serverChannelCompletedHandler]) + try serverChannel.pipeline.syncOperations.addHandlers([ + NIOSSLServerHandler(context: context), serverChannelCompletedHandler, + ]) ) XCTAssertNoThrow( - try clientChannel.pipeline.syncOperations.addHandlers([try NIOSSLClientHandler(context: context, serverHostname: nil), clientChannelCompletedHandler]) + try clientChannel.pipeline.syncOperations.addHandlers([ + try NIOSSLClientHandler(context: context, serverHostname: nil), clientChannelCompletedHandler, + ]) ) // Do the handshake. @@ -2699,7 +2945,7 @@ class NIOSSLIntegrationTest: XCTestCase { try interactInMemory(clientChannel: clientChannel, serverChannel: serverChannel) try connectFuture.wait() - // We now need to forcibly shutdown the client channel, as otherwise it'll hang waiting for a server that never comes back. + // We now need to forcibly shutdown the client channel, as otherwise it'll wedge waiting for a server that never comes back. clientChannel.pipeline.fireChannelInactive() } @@ -2720,7 +2966,10 @@ class NIOSSLIntegrationTest: XCTestCase { let oldIntermediate = try NIOSSLCertificate(bytes: Array(sampleIntermediateCA.utf8), format: .pem) let newCA = try NIOSSLCertificate(bytes: Array(sampleIntermediateAsRootCA.utf8), format: .pem) let serverCert = try NIOSSLCertificate(bytes: Array(sampleClientOfIntermediateCA.utf8), format: .pem) - let serverKey = try NIOSSLPrivateKey(bytes: Array(sampleKeyForCertificateOfClientOfIntermediateCA.utf8), format: .pem) + let serverKey = try NIOSSLPrivateKey( + bytes: Array(sampleKeyForCertificateOfClientOfIntermediateCA.utf8), + format: .pem + ) var clientConfig = TLSConfiguration.makeClientConfiguration() clientConfig.trustRoots = .certificates([newCA, oldCA]) let serverConfig = TLSConfiguration.makeServerConfiguration( @@ -2738,17 +2987,23 @@ class NIOSSLIntegrationTest: XCTestCase { let completionPromise: EventLoopPromise = group.next().makePromise() - let serverChannel: Channel = try serverTLSChannel(context: serverContext, handlers: [SimpleEchoServer()], group: group) + let serverChannel: Channel = try serverTLSChannel( + context: serverContext, + handlers: [SimpleEchoServer()], + group: group + ) defer { XCTAssertNoThrow(try serverChannel.close().wait()) } - let clientChannel = try clientTLSChannel(context: clientContext, - preHandlers: [], - postHandlers: [PromiseOnReadHandler(promise: completionPromise)], - group: group, - connectingTo: serverChannel.localAddress!, - serverHostname: "localhost") + let clientChannel = try clientTLSChannel( + context: clientContext, + preHandlers: [], + postHandlers: [PromiseOnReadHandler(promise: completionPromise)], + group: group, + connectingTo: serverChannel.localAddress!, + serverHostname: "localhost" + ) defer { XCTAssertNoThrow(try clientChannel.close().wait()) } @@ -2877,7 +3132,8 @@ class NIOSSLIntegrationTest: XCTestCase { } // Subsequent writes should also fail. - XCTAssertThrowsError(try channel.writeOutbound(ByteBuffer(string: "Like a record, baby, right 'round"))) { error in + XCTAssertThrowsError(try channel.writeOutbound(ByteBuffer(string: "Like a record, baby, right 'round"))) { + error in XCTAssertEqual(error as? ChannelError, .ioOnClosedChannel) } } diff --git a/Tests/NIOSSLTests/NIOSSLSecureBytesTests.swift b/Tests/NIOSSLTests/NIOSSLSecureBytesTests.swift index ed9d80aff..e2d88536e 100644 --- a/Tests/NIOSSLTests/NIOSSLSecureBytesTests.swift +++ b/Tests/NIOSSLTests/NIOSSLSecureBytesTests.swift @@ -12,6 +12,7 @@ // //===----------------------------------------------------------------------===// import XCTest + @testable import NIOSSL public enum NIOSSLSecureBytesError: Error { @@ -34,7 +35,7 @@ final class NIOSSLSecureBytesTests: XCTestCase { second.append(Data("wrold".utf8)) XCTAssertNotEqual(first, second) } - + func testSimpleCollection() { let base = NIOSSLSecureBytes(0..<100) XCTAssertEqual(base.count, 100) @@ -60,7 +61,7 @@ final class NIOSSLSecureBytesTests: XCTestCase { XCTAssertEqual(base[aMiddleIndex], 48) XCTAssertEqual(base[aDifferentMiddleIndex], 48 + 5) } - + func testSimpleMutableCollection() { var base = NIOSSLSecureBytes(repeating: 0, count: 5) let offset = base.index(base.startIndex, offsetBy: 2) @@ -151,14 +152,14 @@ final class NIOSSLSecureBytesTests: XCTestCase { func testScaryInitializer() { let base = NIOSSLSecureBytes(unsafeUninitializedCapacity: 5) { (scaryPointer, initializedCapacity) in XCTAssertEqual(scaryPointer.count, 5) - scaryPointer.storeBytes(of: UInt32(0x01020304).bigEndian, as: UInt32.self) + scaryPointer.storeBytes(of: UInt32(0x0102_0304).bigEndian, as: UInt32.self) initializedCapacity = 4 } XCTAssertGreaterThanOrEqual(base.backing.capacity, 8) XCTAssertEqual(Array(base), [1, 2, 3, 4]) - let testThrowingInitialization: () throws -> () = { + let testThrowingInitialization: () throws -> Void = { _ = try NIOSSLSecureBytes(unsafeUninitializedCapacity: 5) { (_, _) in throw NIOSSLSecureBytesError.incorrectKeySize } @@ -212,27 +213,26 @@ final class NIOSSLSecureBytesTests: XCTestCase { XCTAssertEqual(base.count, 22) XCTAssertEqual(Array(copy), [0, 1, 2, 3, 4]) } - + func testEquatable() { var a = NIOSSLSecureBytes() a.append(Data("hello".utf8)) - + var b = NIOSSLSecureBytes() b.append(Data("hello".utf8)) - XCTAssertTrue(a==b) - + XCTAssertTrue(a == b) + var c = NIOSSLSecureBytes() c.append(Data("world".utf8)) - XCTAssertFalse(a==c) + XCTAssertFalse(a == c) } - + func testByteCreation() { let a = NIOSSLSecureBytes(bytes: [0x01, 0x02, 0x03, 0x04]) let b = NIOSSLSecureBytes(bytes: [0x01, 0x02, 0x03, 0x04, 0x05]) let c = NIOSSLSecureBytes(bytes: [0x01, 0x02, 0x03, 0x04]) - XCTAssertTrue(a==c) - XCTAssertFalse(a==b) + XCTAssertTrue(a == c) + XCTAssertFalse(a == b) } - -} +} diff --git a/Tests/NIOSSLTests/NIOSSLTestHelpers.swift b/Tests/NIOSSLTests/NIOSSLTestHelpers.swift index ac8ef96d9..494186e08 100644 --- a/Tests/NIOSSLTests/NIOSSLTestHelpers.swift +++ b/Tests/NIOSSLTests/NIOSSLTestHelpers.swift @@ -12,325 +12,331 @@ // //===----------------------------------------------------------------------===// -import Foundation @_implementationOnly import CNIOBoringSSL +import Foundation import NIOCore import NIOEmbedded + @testable import NIOSSL let samplePemCert = """ ------BEGIN CERTIFICATE----- -MIIGGzCCBAOgAwIBAgIJAJ/X0Fo0ynmEMA0GCSqGSIb3DQEBCwUAMIGjMQswCQYD -VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5z -b2t5bzEuMCwGA1UECgwlU2FuIEZyYW5zb2t5byBJbnN0aXR1dGUgb2YgVGVjaG5v -bG9neTEVMBMGA1UECwwMUm9ib3RpY3MgTGFiMSAwHgYDVQQDDBdyb2JvdHMuc2Fu -ZnJhbnNva3lvLmVkdTAeFw0xNzEwMTYyMTAxMDJaFw00NzEwMDkyMTAxMDJaMIGj -MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2Fu -IEZyYW5zb2t5bzEuMCwGA1UECgwlU2FuIEZyYW5zb2t5byBJbnN0aXR1dGUgb2Yg -VGVjaG5vbG9neTEVMBMGA1UECwwMUm9ib3RpY3MgTGFiMSAwHgYDVQQDDBdyb2Jv -dHMuc2FuZnJhbnNva3lvLmVkdTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC -ggIBAO9rzJOOE8cmsIqAJMCrHDxkBAMgZhMsJ863MnWtVz5JIJK6CKI/Nu26tEzo -kHy3EI9565RwikvauheMsWaTFA4PD/P+s1DtxRCGIcK5x+SoTN7Drn5ZueoJNZRf -TYuN+gwyhprzrZrYjXpvEVPYuSIeUqK5XGrTyFA2uGj9wY3f9IF4rd7JT0ewRb1U -8OcR7xQbXKGjkY4iJE1TyfmIsBZboKaG/aYa9KbnWyTkDssaELWUIKrjwwuPgVgS -vlAYmo12MlsGEzkO9z78jvFmhUOsaEldM8Ua2AhOKW0oSYgauVuro/Ap/o5zn8PD -IDapl9g+5vjN2LucqX2a9utoFvxSKXT4NvfpL9fJvzdBNMM4xpqtHIkV0fkiMbWk -EW2FFlOXKnIJV8wT4a9iduuIDMg8O7oc+gt9pG9MHTWthXm4S29DARTqfZ48bW77 -z8RrEURV03o05b/twuAJSRyyOCUi61yMo3YNytebjY2W3Pxqpq+YmT5qhqBZDLlT -LMptuFdISv6SQgg7JoFHGMWRXUavMj/sn5qZD4pQyZToHJ2Vtg5W/MI1pKwc3oKD -6M3/7Gf35r92V/ox6XT7+fnEsAH8AtQiZJkEbvzJ5lpUihSIaV3a/S+jnk7Lw8Tp -vjtpfjOg+wBblc38Oa9tk2WdXwYDbnvbeL26WmyHwQTUBi1jAgMBAAGjUDBOMB0G -A1UdDgQWBBToPRmTBQEF5F5LcPiUI5qBNPBU+DAfBgNVHSMEGDAWgBToPRmTBQEF -5F5LcPiUI5qBNPBU+DAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4ICAQCY -gxM5lufF2lTB9sH0s1E1VTERv37qoapNP+aw06oZkAD67QOTXFzbsM3JU1diY6rV -Y0g9CLzRO7gZY+kmi1WWnsYiMMSIGjIfsB8S+ot43LME+AJXPVeDZQnoZ6KQ/9r+ -71Umi4AKLoZ9dInyUIM3EHg9pg5B0eEINrh4J+OPGtlC3NMiWxdmIkZwzfXa+64Z -8k5aX5piMTI+9BQSMWw5l7tFT/PISuI8b/Ln4IUBXKA0xkONXVnjPOmS0h7MBoc2 -EipChDKnK+Mtm9GQewOCKdS2nsrCndGkIBnUix4ConUYIoywVzWGMD+9OzKNg76d -O6A7MxdjEdKhf1JDvklxInntDUDTlSFL4iEFELwyRseoTzj8vJE+cL6h6ClasYQ6 -p0EeL3UpICYerfIvPhohftCivCH3k7Q1BSf0fq73cQ55nrFAHrqqYjD7HBeBS9hn -3L6bz9Eo6U9cuxX42k3l1N44BmgcDPin0+CRTirEmahUMb3gmvoSZqQ3Cz86GkIg -7cNJosc9NyevQlU9SX3ptEbv33tZtlB5GwgZ2hiGBTY0C3HaVFjLpQiSS5ygZLgI -/+AKtah7sTHIAtpUH1ZZEgKPl1Hg6J4x/dBkuk3wxPommNHaYaHREXF+fHMhBrSi -yH8agBmmECpa21SVnr7vrL+KSqfuF+GxwjSNsSR4SA== ------END CERTIFICATE----- -""" + -----BEGIN CERTIFICATE----- + MIIGGzCCBAOgAwIBAgIJAJ/X0Fo0ynmEMA0GCSqGSIb3DQEBCwUAMIGjMQswCQYD + VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5z + b2t5bzEuMCwGA1UECgwlU2FuIEZyYW5zb2t5byBJbnN0aXR1dGUgb2YgVGVjaG5v + bG9neTEVMBMGA1UECwwMUm9ib3RpY3MgTGFiMSAwHgYDVQQDDBdyb2JvdHMuc2Fu + ZnJhbnNva3lvLmVkdTAeFw0xNzEwMTYyMTAxMDJaFw00NzEwMDkyMTAxMDJaMIGj + MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2Fu + IEZyYW5zb2t5bzEuMCwGA1UECgwlU2FuIEZyYW5zb2t5byBJbnN0aXR1dGUgb2Yg + VGVjaG5vbG9neTEVMBMGA1UECwwMUm9ib3RpY3MgTGFiMSAwHgYDVQQDDBdyb2Jv + dHMuc2FuZnJhbnNva3lvLmVkdTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC + ggIBAO9rzJOOE8cmsIqAJMCrHDxkBAMgZhMsJ863MnWtVz5JIJK6CKI/Nu26tEzo + kHy3EI9565RwikvauheMsWaTFA4PD/P+s1DtxRCGIcK5x+SoTN7Drn5ZueoJNZRf + TYuN+gwyhprzrZrYjXpvEVPYuSIeUqK5XGrTyFA2uGj9wY3f9IF4rd7JT0ewRb1U + 8OcR7xQbXKGjkY4iJE1TyfmIsBZboKaG/aYa9KbnWyTkDssaELWUIKrjwwuPgVgS + vlAYmo12MlsGEzkO9z78jvFmhUOsaEldM8Ua2AhOKW0oSYgauVuro/Ap/o5zn8PD + IDapl9g+5vjN2LucqX2a9utoFvxSKXT4NvfpL9fJvzdBNMM4xpqtHIkV0fkiMbWk + EW2FFlOXKnIJV8wT4a9iduuIDMg8O7oc+gt9pG9MHTWthXm4S29DARTqfZ48bW77 + z8RrEURV03o05b/twuAJSRyyOCUi61yMo3YNytebjY2W3Pxqpq+YmT5qhqBZDLlT + LMptuFdISv6SQgg7JoFHGMWRXUavMj/sn5qZD4pQyZToHJ2Vtg5W/MI1pKwc3oKD + 6M3/7Gf35r92V/ox6XT7+fnEsAH8AtQiZJkEbvzJ5lpUihSIaV3a/S+jnk7Lw8Tp + vjtpfjOg+wBblc38Oa9tk2WdXwYDbnvbeL26WmyHwQTUBi1jAgMBAAGjUDBOMB0G + A1UdDgQWBBToPRmTBQEF5F5LcPiUI5qBNPBU+DAfBgNVHSMEGDAWgBToPRmTBQEF + 5F5LcPiUI5qBNPBU+DAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4ICAQCY + gxM5lufF2lTB9sH0s1E1VTERv37qoapNP+aw06oZkAD67QOTXFzbsM3JU1diY6rV + Y0g9CLzRO7gZY+kmi1WWnsYiMMSIGjIfsB8S+ot43LME+AJXPVeDZQnoZ6KQ/9r+ + 71Umi4AKLoZ9dInyUIM3EHg9pg5B0eEINrh4J+OPGtlC3NMiWxdmIkZwzfXa+64Z + 8k5aX5piMTI+9BQSMWw5l7tFT/PISuI8b/Ln4IUBXKA0xkONXVnjPOmS0h7MBoc2 + EipChDKnK+Mtm9GQewOCKdS2nsrCndGkIBnUix4ConUYIoywVzWGMD+9OzKNg76d + O6A7MxdjEdKhf1JDvklxInntDUDTlSFL4iEFELwyRseoTzj8vJE+cL6h6ClasYQ6 + p0EeL3UpICYerfIvPhohftCivCH3k7Q1BSf0fq73cQ55nrFAHrqqYjD7HBeBS9hn + 3L6bz9Eo6U9cuxX42k3l1N44BmgcDPin0+CRTirEmahUMb3gmvoSZqQ3Cz86GkIg + 7cNJosc9NyevQlU9SX3ptEbv33tZtlB5GwgZ2hiGBTY0C3HaVFjLpQiSS5ygZLgI + /+AKtah7sTHIAtpUH1ZZEgKPl1Hg6J4x/dBkuk3wxPommNHaYaHREXF+fHMhBrSi + yH8agBmmECpa21SVnr7vrL+KSqfuF+GxwjSNsSR4SA== + -----END CERTIFICATE----- + """ let samplePemKey = """ ------BEGIN RSA PRIVATE KEY----- -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 ------END RSA PRIVATE KEY----- -""" + -----BEGIN RSA PRIVATE KEY----- + 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 + -----END RSA PRIVATE KEY----- + """ let sampleECPemKey = """ ------BEGIN EC PRIVATE KEY----- -MHcCAQEEIMJZj2Qw9NGv83izxbgRr5xRvb0RHymOfl5hDJ/RPI2GoAoGCCqGSM49 -AwEHoUQDQgAEc5zHoemKB93GfO9MA/vLYEiYMtV3UWDIV88M/TP59R0dKIuPS2Dw -EeAoz1vgyHNpgE73eYX8NII6U11Xv8Lmgg== ------END EC PRIVATE KEY----- -""" + -----BEGIN EC PRIVATE KEY----- + MHcCAQEEIMJZj2Qw9NGv83izxbgRr5xRvb0RHymOfl5hDJ/RPI2GoAoGCCqGSM49 + AwEHoUQDQgAEc5zHoemKB93GfO9MA/vLYEiYMtV3UWDIV88M/TP59R0dKIuPS2Dw + EeAoz1vgyHNpgE73eYX8NII6U11Xv8Lmgg== + -----END EC PRIVATE KEY----- + """ let samplePemRSAEncryptedKey = """ ------BEGIN RSA PRIVATE KEY----- -Proc-Type: 4,ENCRYPTED -DEK-Info: AES-256-CBC,701BA8806DAD9F13E63F41109F51B2AD - -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 ------END RSA PRIVATE KEY----- -""" + -----BEGIN RSA PRIVATE KEY----- + Proc-Type: 4,ENCRYPTED + DEK-Info: AES-256-CBC,701BA8806DAD9F13E63F41109F51B2AD + + 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 + -----END RSA PRIVATE KEY----- + """ let samplePKCS8PemPrivateKey = """ ------BEGIN ENCRYPTED PRIVATE KEY----- -MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIShGta1Mpj/QCAggA -MBQGCCqGSIb3DQMHBAjQbLTPjvMqpwSCBMh8omeDIM0ceuoiEhaepFqbst/jUwYh -m1pzLokTph0GS/81vmTDr9U7uI9rHiFbACRRMQBH/cCkZFUN2Jo3pJXA4q3RvGsh -4UIaWiP+SNkzKR54QcuWRzYoQs/YH8VickNp2per3zQ9R0Regx1ZaHSCk3cFRFy3 -4sJtgoquwJYD2vUdQvhwcuF2Syl/VCpaQ0+KtfBqJ+4YLJPQcsL+OKLlaWFY0ivO -2oSVCg3QJrVbS8TDnrIgeL8MNhyVHQbuSyh2MlXKcjiKlJHdHXSlYSINgpUsc/Eg -cTSgod0JXvjbExrtBx2mODwM5hzDkGpdub+TptXinQg3FQjUKhBh/+wrP0HoKBcn -UFE1emd3n1s0MFN28uSN3OcX3833Lt4KAnxF4xaPfWEAk/2yuukiUqKU+K9cEhNX -V1arxKq8RLB7n7o6YFt3xuVgAJYWDk6nyr/0I2LgFj2Jz/C2v+YBFYGUcQUKgHQw -OLzzZnCrPj8JIP2cUqagZrW7JOoMsFCtroJptImaqhsm/4i3tyf2uoUWglZN8DVE -WbNbnAr5KZSl9U1/sNuEesixIWd+RrJC/l0tNmScCvJifL9WrJnccOI83EAkmz/+ -W8UpcPCscAmAdOcjFQl8T37xHGxwVcvh8LyaoacBqQCYiZzO/M6bA2YuBYVpkk4v -DFXMmy2SaHGGhGHDmyn4uuzykGCOn1ZN92eT6PXZCmHz0/QCH6RIGx2cK5frfhUP -icU30GnK1jRv8QFHVx9IZQpHbALRgSNMbtF8EqWmONUIs9wQIQtEMZ2AYwq8gKL2 -9Cwk2SkqO0Y8dbE/lw+iBA37/NO7KiSLB/Mpq0/zX5SfBVcGZAVzGKiyeOW5sKcI -pSOTTv5jLkoEnels2f0jsPM7aMjG+ys6wveL0tDhfKSbtjyC8Zw/eXpK9AHGW8Hr -xM7hwTkQpznyt/NUIDmjrDHg7n6O9sp7KWduP1L9bYC/n5Dj2gnxHj6FFTpMqmm7 -Q6GEj/dttmqvSYeG93heWqoS/j6j45dppoKG/3vU9UWODStcc3y66WJ2ULEY0/CF -IiBd33GJgIKUJlrMGwUSAPxH2wklF3VwWFVXMnLbqpggaWlVxzVnvGjnzoHm3AW6 -hWCMnvsP/pYVBMpaKKdPF6PCW1yQXjTbA67gxpGECoin2Bu/rp+t0GeVmgTcCS9a -Y2Su4cpwCD1ngIrdodWhVVJSObApRdn3SDI2xOZUgZPVT52AtEMPQ3R5eoIOfLI6 -CPC7cYl2JDmMkKGLaSom1zZpCoXtPTkxDAIpaG4ofT6pIDibCSywllL1KeeVw4WX -Cr2b/BS5TZNFyPzdrMaN5og6hNkbyca73SyEADnJtHTQc6mi/Q93al4TI3RYaVpk -KWwIW4kZE/p5pONeZDNNt7dKrgkjaTylNpM9jdnBL3hU5Fxr4I6a6+IBWQC03EwC -o2zT+g6YmVkod050GMv0V60npTpbOpWIamzB+q3GMMkU9NNyw8xH7RkNS78eWLVv -niWQmWlbkzLEf5PT264+c4w9IkE8aUKY2V8Ev2k1FXZcLdfw3G5yVzrjXoAwFUaY -xnOAdO/QLMtD55Kn+jzV6dCXmyZQkBJAMLBF5xEX9DcnXCptZ2Asgvxa4EpO7jzX -v5o= ------END ENCRYPTED PRIVATE KEY----- -""" + -----BEGIN ENCRYPTED PRIVATE KEY----- + MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIShGta1Mpj/QCAggA + MBQGCCqGSIb3DQMHBAjQbLTPjvMqpwSCBMh8omeDIM0ceuoiEhaepFqbst/jUwYh + m1pzLokTph0GS/81vmTDr9U7uI9rHiFbACRRMQBH/cCkZFUN2Jo3pJXA4q3RvGsh + 4UIaWiP+SNkzKR54QcuWRzYoQs/YH8VickNp2per3zQ9R0Regx1ZaHSCk3cFRFy3 + 4sJtgoquwJYD2vUdQvhwcuF2Syl/VCpaQ0+KtfBqJ+4YLJPQcsL+OKLlaWFY0ivO + 2oSVCg3QJrVbS8TDnrIgeL8MNhyVHQbuSyh2MlXKcjiKlJHdHXSlYSINgpUsc/Eg + cTSgod0JXvjbExrtBx2mODwM5hzDkGpdub+TptXinQg3FQjUKhBh/+wrP0HoKBcn + UFE1emd3n1s0MFN28uSN3OcX3833Lt4KAnxF4xaPfWEAk/2yuukiUqKU+K9cEhNX + V1arxKq8RLB7n7o6YFt3xuVgAJYWDk6nyr/0I2LgFj2Jz/C2v+YBFYGUcQUKgHQw + OLzzZnCrPj8JIP2cUqagZrW7JOoMsFCtroJptImaqhsm/4i3tyf2uoUWglZN8DVE + WbNbnAr5KZSl9U1/sNuEesixIWd+RrJC/l0tNmScCvJifL9WrJnccOI83EAkmz/+ + W8UpcPCscAmAdOcjFQl8T37xHGxwVcvh8LyaoacBqQCYiZzO/M6bA2YuBYVpkk4v + DFXMmy2SaHGGhGHDmyn4uuzykGCOn1ZN92eT6PXZCmHz0/QCH6RIGx2cK5frfhUP + icU30GnK1jRv8QFHVx9IZQpHbALRgSNMbtF8EqWmONUIs9wQIQtEMZ2AYwq8gKL2 + 9Cwk2SkqO0Y8dbE/lw+iBA37/NO7KiSLB/Mpq0/zX5SfBVcGZAVzGKiyeOW5sKcI + pSOTTv5jLkoEnels2f0jsPM7aMjG+ys6wveL0tDhfKSbtjyC8Zw/eXpK9AHGW8Hr + xM7hwTkQpznyt/NUIDmjrDHg7n6O9sp7KWduP1L9bYC/n5Dj2gnxHj6FFTpMqmm7 + Q6GEj/dttmqvSYeG93heWqoS/j6j45dppoKG/3vU9UWODStcc3y66WJ2ULEY0/CF + IiBd33GJgIKUJlrMGwUSAPxH2wklF3VwWFVXMnLbqpggaWlVxzVnvGjnzoHm3AW6 + hWCMnvsP/pYVBMpaKKdPF6PCW1yQXjTbA67gxpGECoin2Bu/rp+t0GeVmgTcCS9a + Y2Su4cpwCD1ngIrdodWhVVJSObApRdn3SDI2xOZUgZPVT52AtEMPQ3R5eoIOfLI6 + CPC7cYl2JDmMkKGLaSom1zZpCoXtPTkxDAIpaG4ofT6pIDibCSywllL1KeeVw4WX + Cr2b/BS5TZNFyPzdrMaN5og6hNkbyca73SyEADnJtHTQc6mi/Q93al4TI3RYaVpk + KWwIW4kZE/p5pONeZDNNt7dKrgkjaTylNpM9jdnBL3hU5Fxr4I6a6+IBWQC03EwC + o2zT+g6YmVkod050GMv0V60npTpbOpWIamzB+q3GMMkU9NNyw8xH7RkNS78eWLVv + niWQmWlbkzLEf5PT264+c4w9IkE8aUKY2V8Ev2k1FXZcLdfw3G5yVzrjXoAwFUaY + xnOAdO/QLMtD55Kn+jzV6dCXmyZQkBJAMLBF5xEX9DcnXCptZ2Asgvxa4EpO7jzX + v5o= + -----END ENCRYPTED PRIVATE KEY----- + """ /// A CA that expired a while ago. let sampleExpiredCA = """ ------BEGIN CERTIFICATE----- -MIIC5TCCAc2gAwIBAgIUTSNLkfg8YiYSq+fnrXP25txgCkUwDQYJKoZIhvcNAQEL -BQAwIjEgMB4GA1UEAwwXYmFkQ2VydGlmaWNhdGVBdXRob3JpdHkwHhcNMTkwODA5 -MTk1MTExWhcNMTkxMTE3MTk1MTExWjAiMSAwHgYDVQQDDBdiYWRDZXJ0aWZpY2F0 -ZUF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKqWcbgw -TFX14tKxUMIrla9Y0aLddlnnTDqsxtxJ7dSjE4+OBkVBslCq4WtjgaeubdHkTCtc -GRVeOpXVcEyznGBGW5k/5gCkmaGPe8jI4+caavtXnoTdPU91ukYkZkBXzCgycVS8 -kQxyPwvTDUOfHQ3VqUfc2LMTXQYU3vzyrPzq7XAWgZR9d5lOtB9tpGnxCRP8GOFO -KHa3KroiRxJb2cReJsayJWx713pje5lPKtSKP0iYICR2kYgtP+8Y3wPzcLzPRM9u -6a0olO6PFFWdPNRtivObCr5Y3Cy0P8i2ZSyOO2c6cn0ksLmCe/qrRX9HKx7TrmEu -7Rs+ql6liiyrQ7ECAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B -AQsFAAOCAQEAWSCh35Fk5Td+8uV3oe+K+IPbTrhtNmrwC42sGw/mpQC56zNjlDt9 -jBZVZbu5iAwO/nrtn+JpCSA3ADugjisQKQdELb/ogaCnIu2vY/fjHv7a9/tYoYc2 -i/rtcXIQdhSrniZuVnKG1Keu5qohKIP1ne4TAxADTlzl3Dx7QH/32hUBlJFwYiDQ -JIuZD9LM5Ic9jtrsfTN79tNPM3eHofWUdKyUk9fTrM7/28kSERLJJz/RcXDMP85z -5Y0zZar+qh+9A6kYy/xcaFVOX0bDsuArBA6d/n0skqJN8gylOvdsnpeJRrXxOSSE -dcvafu1dqy0zZdFMSzymwRnprqgdFYC1xw== ------END CERTIFICATE----- -""" + -----BEGIN CERTIFICATE----- + MIIC5TCCAc2gAwIBAgIUTSNLkfg8YiYSq+fnrXP25txgCkUwDQYJKoZIhvcNAQEL + BQAwIjEgMB4GA1UEAwwXYmFkQ2VydGlmaWNhdGVBdXRob3JpdHkwHhcNMTkwODA5 + MTk1MTExWhcNMTkxMTE3MTk1MTExWjAiMSAwHgYDVQQDDBdiYWRDZXJ0aWZpY2F0 + ZUF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKqWcbgw + TFX14tKxUMIrla9Y0aLddlnnTDqsxtxJ7dSjE4+OBkVBslCq4WtjgaeubdHkTCtc + GRVeOpXVcEyznGBGW5k/5gCkmaGPe8jI4+caavtXnoTdPU91ukYkZkBXzCgycVS8 + kQxyPwvTDUOfHQ3VqUfc2LMTXQYU3vzyrPzq7XAWgZR9d5lOtB9tpGnxCRP8GOFO + KHa3KroiRxJb2cReJsayJWx713pje5lPKtSKP0iYICR2kYgtP+8Y3wPzcLzPRM9u + 6a0olO6PFFWdPNRtivObCr5Y3Cy0P8i2ZSyOO2c6cn0ksLmCe/qrRX9HKx7TrmEu + 7Rs+ql6liiyrQ7ECAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B + AQsFAAOCAQEAWSCh35Fk5Td+8uV3oe+K+IPbTrhtNmrwC42sGw/mpQC56zNjlDt9 + jBZVZbu5iAwO/nrtn+JpCSA3ADugjisQKQdELb/ogaCnIu2vY/fjHv7a9/tYoYc2 + i/rtcXIQdhSrniZuVnKG1Keu5qohKIP1ne4TAxADTlzl3Dx7QH/32hUBlJFwYiDQ + JIuZD9LM5Ic9jtrsfTN79tNPM3eHofWUdKyUk9fTrM7/28kSERLJJz/RcXDMP85z + 5Y0zZar+qh+9A6kYy/xcaFVOX0bDsuArBA6d/n0skqJN8gylOvdsnpeJRrXxOSSE + dcvafu1dqy0zZdFMSzymwRnprqgdFYC1xw== + -----END CERTIFICATE----- + """ /// An intermediate signed by the above CA. let sampleIntermediateCA = """ ------BEGIN CERTIFICATE----- -MIIC3DCCAcSgAwIBAgIUDK9fkCTocM8Yu3csdNcm86ahG4IwDQYJKoZIhvcNAQEL -BQAwIjEgMB4GA1UEAwwXYmFkQ2VydGlmaWNhdGVBdXRob3JpdHkwHhcNMTkxMTE2 -MTk1MTExWhcNMzAwNjAyMTk1MTExWjAZMRcwFQYDVQQDDA5pbnRlcm1lZGlhdGVD -QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALdj2KDFRR6Es/RpN+07 -q4IiQMoLVcDu/CoxCJSteNuNShmScfyqG4e6AFDOKxjv2U2NHWmhVbBYN7b9jStf -uZBpvz4/JY4+mVfGASL7mBkcsTLzNG+7rmQ0Oi271KL5WlDmw6DUMIFNvYSy0q9y -MFS5qSYJh4JnXXtdxkGIjDmrWy1hCRzIGCpDZXvNjnhJDphgH3Ss+PR7wTJZXRiJ -uoO4plWWl3JsRIRoyuL7K2CeWrR7CvIEThTF/D2P/7odf+CNz//46lC83b5eKdIA -GD+RECQaA1YFygAbvEln+za5AjnH11Y310zvzAb1gCxGuxNaABNKhYLcDpDL/Mcd -Il0CAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEA -X4D5jVygEJyp6Ub/Yao9miF/vZW0bep00gOzHVJ8i6y1Qjn9ieVyrX9l6V8ZNwQU -wrAkse99WoI94LT8QLWlAlDB7S0IS8IK7gkt+06pSbrhW5GJtEQJjug84DkOVqOm -JSCupM2BEiHVQPYerF+sJ7I/4eENkafVn0zXSL9SEh9fPXBYJKiCYIxKWmGF3KOp -KG5Y1W9sWz5NaatoL1kHFGDeuDWLwXJ8WZuNrtJNBe1iQ8yvuO1STRzjtq2iTDk3 -TCYZoKnV3ui38BJn7libgUsN3lHD4yKdrw5LNeyjrYOZ5oFhe4QBQv0ZA+wUR+h7 -1A4gDvFcIkbYSywqlirBQg== ------END CERTIFICATE----- -""" + -----BEGIN CERTIFICATE----- + MIIC3DCCAcSgAwIBAgIUDK9fkCTocM8Yu3csdNcm86ahG4IwDQYJKoZIhvcNAQEL + BQAwIjEgMB4GA1UEAwwXYmFkQ2VydGlmaWNhdGVBdXRob3JpdHkwHhcNMTkxMTE2 + MTk1MTExWhcNMzAwNjAyMTk1MTExWjAZMRcwFQYDVQQDDA5pbnRlcm1lZGlhdGVD + QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALdj2KDFRR6Es/RpN+07 + q4IiQMoLVcDu/CoxCJSteNuNShmScfyqG4e6AFDOKxjv2U2NHWmhVbBYN7b9jStf + uZBpvz4/JY4+mVfGASL7mBkcsTLzNG+7rmQ0Oi271KL5WlDmw6DUMIFNvYSy0q9y + MFS5qSYJh4JnXXtdxkGIjDmrWy1hCRzIGCpDZXvNjnhJDphgH3Ss+PR7wTJZXRiJ + uoO4plWWl3JsRIRoyuL7K2CeWrR7CvIEThTF/D2P/7odf+CNz//46lC83b5eKdIA + GD+RECQaA1YFygAbvEln+za5AjnH11Y310zvzAb1gCxGuxNaABNKhYLcDpDL/Mcd + Il0CAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEA + X4D5jVygEJyp6Ub/Yao9miF/vZW0bep00gOzHVJ8i6y1Qjn9ieVyrX9l6V8ZNwQU + wrAkse99WoI94LT8QLWlAlDB7S0IS8IK7gkt+06pSbrhW5GJtEQJjug84DkOVqOm + JSCupM2BEiHVQPYerF+sJ7I/4eENkafVn0zXSL9SEh9fPXBYJKiCYIxKWmGF3KOp + KG5Y1W9sWz5NaatoL1kHFGDeuDWLwXJ8WZuNrtJNBe1iQ8yvuO1STRzjtq2iTDk3 + TCYZoKnV3ui38BJn7libgUsN3lHD4yKdrw5LNeyjrYOZ5oFhe4QBQv0ZA+wUR+h7 + 1A4gDvFcIkbYSywqlirBQg== + -----END CERTIFICATE----- + """ /// The intermediate above, self-signed, as a root let sampleIntermediateAsRootCA = """ ------BEGIN CERTIFICATE----- -MIIC0zCCAbugAwIBAgIUDK9fkCTocM8Yu3csdNcm86ahG4IwDQYJKoZIhvcNAQEL -BQAwGTEXMBUGA1UEAwwOaW50ZXJtZWRpYXRlQ0EwHhcNMTkxMTE2MTk1MTExWhcN -MzAwNjAyMTk1MTExWjAZMRcwFQYDVQQDDA5pbnRlcm1lZGlhdGVDQTCCASIwDQYJ -KoZIhvcNAQEBBQADggEPADCCAQoCggEBALdj2KDFRR6Es/RpN+07q4IiQMoLVcDu -/CoxCJSteNuNShmScfyqG4e6AFDOKxjv2U2NHWmhVbBYN7b9jStfuZBpvz4/JY4+ -mVfGASL7mBkcsTLzNG+7rmQ0Oi271KL5WlDmw6DUMIFNvYSy0q9yMFS5qSYJh4Jn -XXtdxkGIjDmrWy1hCRzIGCpDZXvNjnhJDphgH3Ss+PR7wTJZXRiJuoO4plWWl3Js -RIRoyuL7K2CeWrR7CvIEThTF/D2P/7odf+CNz//46lC83b5eKdIAGD+RECQaA1YF -ygAbvEln+za5AjnH11Y310zvzAb1gCxGuxNaABNKhYLcDpDL/McdIl0CAwEAAaMT -MBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAWervzZUKKDEb -O9nXiJckFEBmCOlQuQ6O6+hVyRLAugtPDUyesCUDqoLF2wmMKNRM322gJKaWShaM -ueBrXHIx+ERXKJsgFic8b2m/v+VT16aAVPvQCLmZBpWR2ICqgNTpUzoDXqIZk/9l -ZkJZMaS9kiQmEPeTDH2O8acO9TjqmQbdZa+q6kBWBnNzLPOu5ziEdKrh7rNzikUw -qe0yKxavA5L8l8uWumGC8L6GE7ie7X8oMLwaLXFXt2TG9ZENrVQ0xcLSKTBAF2yL -4lqh2YnpZhntnCtv9Qvx81Asp2+6YfocAe9IKNIA534R2FgoZwt24SokDBhfg49d -2fV7ZO/cqQ== ------END CERTIFICATE----- -""" + -----BEGIN CERTIFICATE----- + MIIC0zCCAbugAwIBAgIUDK9fkCTocM8Yu3csdNcm86ahG4IwDQYJKoZIhvcNAQEL + BQAwGTEXMBUGA1UEAwwOaW50ZXJtZWRpYXRlQ0EwHhcNMTkxMTE2MTk1MTExWhcN + MzAwNjAyMTk1MTExWjAZMRcwFQYDVQQDDA5pbnRlcm1lZGlhdGVDQTCCASIwDQYJ + KoZIhvcNAQEBBQADggEPADCCAQoCggEBALdj2KDFRR6Es/RpN+07q4IiQMoLVcDu + /CoxCJSteNuNShmScfyqG4e6AFDOKxjv2U2NHWmhVbBYN7b9jStfuZBpvz4/JY4+ + mVfGASL7mBkcsTLzNG+7rmQ0Oi271KL5WlDmw6DUMIFNvYSy0q9yMFS5qSYJh4Jn + XXtdxkGIjDmrWy1hCRzIGCpDZXvNjnhJDphgH3Ss+PR7wTJZXRiJuoO4plWWl3Js + RIRoyuL7K2CeWrR7CvIEThTF/D2P/7odf+CNz//46lC83b5eKdIAGD+RECQaA1YF + ygAbvEln+za5AjnH11Y310zvzAb1gCxGuxNaABNKhYLcDpDL/McdIl0CAwEAAaMT + MBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAWervzZUKKDEb + O9nXiJckFEBmCOlQuQ6O6+hVyRLAugtPDUyesCUDqoLF2wmMKNRM322gJKaWShaM + ueBrXHIx+ERXKJsgFic8b2m/v+VT16aAVPvQCLmZBpWR2ICqgNTpUzoDXqIZk/9l + ZkJZMaS9kiQmEPeTDH2O8acO9TjqmQbdZa+q6kBWBnNzLPOu5ziEdKrh7rNzikUw + qe0yKxavA5L8l8uWumGC8L6GE7ie7X8oMLwaLXFXt2TG9ZENrVQ0xcLSKTBAF2yL + 4lqh2YnpZhntnCtv9Qvx81Asp2+6YfocAe9IKNIA534R2FgoZwt24SokDBhfg49d + 2fV7ZO/cqQ== + -----END CERTIFICATE----- + """ /// A client signed by the intermediate. let sampleClientOfIntermediateCA = """ ------BEGIN CERTIFICATE----- -MIIC4TCCAcmgAwIBAgIUFJCxfytdLl/FpvlUqwJbztiALjcwDQYJKoZIhvcNAQEL -BQAwGTEXMBUGA1UEAwwOaW50ZXJtZWRpYXRlQ0EwHhcNMTkxMTE2MTk1MTExWhcN -MzAwNTI4MTk1MTExWjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3 -DQEBAQUAA4IBDwAwggEKAoIBAQDS9XBpPYlP3ToaYKmWaqhXd4lnLSvjReuknE9I -UmvFBoPTyGRU2UNv8N9tFT3xMOX2DrGOn7eVqXBXOvKYRB8+q3CIsh3F/5smdNKQ -PfsL2tFL4d2lvrZ+2GOr2yRtPm9nH0N2wrmJi6GtR1J+x2Uvm7EoHvk3Ujbo77fB -HvFauvwA3GsFT10J+f5buPcNW0rdpo+ASMfMpfBMsr0Ucy1ys9XM/ehCMeWMiX/d -d+fxqmOtl1tGyw4/Bbub5uf/HkiJStbKSCMgs7E4VgVhqFMu6jpeMlADXgDeOKEa -rW+Ds8eb3TkdIlYE2nmwxvdOPeW3AgChkE5RCRYW0aALTwEbAgMBAAGjJjAkMAwG -A1UdEwEB/wQCMAAwFAYDVR0RBA0wC4IJbG9jYWxob3N0MA0GCSqGSIb3DQEBCwUA -A4IBAQBarG3HrdOULNMGfY/UrSoc2qCQoK33SxM43ecFSXsDbPXLOZHp9iQmib1f -uKy2m4VVkxtxYrQ2i7bueqgRt91rM7hHR8+uopj/BdNYFZfIik+VNFoyKJeATYcx -FRjjAAoMpVYdAJXvtckNix8mlAdan5VNL1AsHYum25BjClQEy+kHM1i3bDLOIiDB -dKMwvI/1ZnUgrMFnAvK8U8WxbxVxij8IeloW+YgjOYXqzjCysVh3L7HkI3AOi6yw -eMNi5idG30y1NnTJWTSWzwR4UcoeLFdzMAmAxo5IVJBYnngcLTEkfofGFC9k2ODI -XANkLW5BKAnSmOQUBrExL4yAj5jt ------END CERTIFICATE----- -""" + -----BEGIN CERTIFICATE----- + MIIC4TCCAcmgAwIBAgIUFJCxfytdLl/FpvlUqwJbztiALjcwDQYJKoZIhvcNAQEL + BQAwGTEXMBUGA1UEAwwOaW50ZXJtZWRpYXRlQ0EwHhcNMTkxMTE2MTk1MTExWhcN + MzAwNTI4MTk1MTExWjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3 + DQEBAQUAA4IBDwAwggEKAoIBAQDS9XBpPYlP3ToaYKmWaqhXd4lnLSvjReuknE9I + UmvFBoPTyGRU2UNv8N9tFT3xMOX2DrGOn7eVqXBXOvKYRB8+q3CIsh3F/5smdNKQ + PfsL2tFL4d2lvrZ+2GOr2yRtPm9nH0N2wrmJi6GtR1J+x2Uvm7EoHvk3Ujbo77fB + HvFauvwA3GsFT10J+f5buPcNW0rdpo+ASMfMpfBMsr0Ucy1ys9XM/ehCMeWMiX/d + d+fxqmOtl1tGyw4/Bbub5uf/HkiJStbKSCMgs7E4VgVhqFMu6jpeMlADXgDeOKEa + rW+Ds8eb3TkdIlYE2nmwxvdOPeW3AgChkE5RCRYW0aALTwEbAgMBAAGjJjAkMAwG + A1UdEwEB/wQCMAAwFAYDVR0RBA0wC4IJbG9jYWxob3N0MA0GCSqGSIb3DQEBCwUA + A4IBAQBarG3HrdOULNMGfY/UrSoc2qCQoK33SxM43ecFSXsDbPXLOZHp9iQmib1f + uKy2m4VVkxtxYrQ2i7bueqgRt91rM7hHR8+uopj/BdNYFZfIik+VNFoyKJeATYcx + FRjjAAoMpVYdAJXvtckNix8mlAdan5VNL1AsHYum25BjClQEy+kHM1i3bDLOIiDB + dKMwvI/1ZnUgrMFnAvK8U8WxbxVxij8IeloW+YgjOYXqzjCysVh3L7HkI3AOi6yw + eMNi5idG30y1NnTJWTSWzwR4UcoeLFdzMAmAxo5IVJBYnngcLTEkfofGFC9k2ODI + XANkLW5BKAnSmOQUBrExL4yAj5jt + -----END CERTIFICATE----- + """ /// The key for the above cert. let sampleKeyForCertificateOfClientOfIntermediateCA = """ ------BEGIN PRIVATE KEY----- -MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDS9XBpPYlP3Toa -YKmWaqhXd4lnLSvjReuknE9IUmvFBoPTyGRU2UNv8N9tFT3xMOX2DrGOn7eVqXBX -OvKYRB8+q3CIsh3F/5smdNKQPfsL2tFL4d2lvrZ+2GOr2yRtPm9nH0N2wrmJi6Gt -R1J+x2Uvm7EoHvk3Ujbo77fBHvFauvwA3GsFT10J+f5buPcNW0rdpo+ASMfMpfBM -sr0Ucy1ys9XM/ehCMeWMiX/dd+fxqmOtl1tGyw4/Bbub5uf/HkiJStbKSCMgs7E4 -VgVhqFMu6jpeMlADXgDeOKEarW+Ds8eb3TkdIlYE2nmwxvdOPeW3AgChkE5RCRYW -0aALTwEbAgMBAAECggEBAIzYFxv8XK+4iPFRdggZ35i+EzuSegm8Be6Z+YjUlmUt -y1fbI7lOcOrMy669juR3/CCCgOMzGVPPk1R547vrR10FAxYQrTYjSIetWWO6LeEl -T7U08FGXeapIeIslvTU+iQw1YEprCYqecewJgTdpktHtRaL+wu6/ci+k1G8YZJVo -qPmkSJigrEppm8ciXjvae+89jgUSEUmumI7A+LwiD2qr1GjGMg01TvKJ3jVrU0yq -cGP58zAY/W1DcenJm26bpirE82Wnesosv3hQf2LBMGBMyVp6ErNzITSNN1fUSfyB -231DlGDor9oopfGfk9ApDUUVNXfFUv6ODnCSGBcdUkkCgYEA8snNvwok8IjbXzeG -zdDVUCVLX/o/vrFQg0KmktTArklLe7vAgcbmCp5TbdZKnpHam2KNu6ucgla5ZchV -5vHbAdAhhvZFnYEaDPlpvueVT2jLWZHvsld17vfy7PVpZBwJSa2SQL4aC5sk+Bsn -5LbSE4OL2o0KLQr6+BOAa9soVw8CgYEA3nA6u4Pxdhlf4UGo1fMWFbeXvU6myBs2 -JXiAPEM/9wKiGS3LOseqBzLBAoiWND9J7ynDJ+w5uuezwJP6MZImj+J0kbXEm0vy -3iUBGBQvj1FJLN+wJx1QEzZBa+rslqX7vE+YsByJwfffqonGwXpj94Qxf6HMMDea -fRuHxqAjVTUCgYBsXe7bymdahXuFMH+W9hOARmUyXbx+HR7Wt7Up7JRkNorem5r9 -Ug3zx19tsyxzQp7UpFSm455j/tmZuKW/A0zBrmiImPvRpYI/MEQm1a8rVpcNT7ox -XCBjnYBsi82SxYDPxg11oGR3sbP6mgRgbcmutBSEZFeaa0BB4lJ70cJbuQKBgQDE -a1gBo3ZB8hAvafp7yqby0GbmnKA7zYOXvPuHu16tcR7QmxZ9tjgXGSNEaHYydryD -u14AT+F+gQHCiSkCQutYXQDQdjDBbWRt80EvEQwaQw4Z2QDE2WaPQHaupAj80l8j -nynWQa0HoilYf0cKLFhABfRrnuUeossBtKDFrTzmDQKBgH2uBQ2v0hV3EW7u2wdy -y7V9lkY+GDm51P1GWAH5c0BBZp3iAW1IBNzbUB8wXVJmhYPWO5Mh7wCAnr18HEZz -OjJVhqRxwhY4NEUsyI86Xxb7rV23HAM6laDItQ/bPlR+b7py5GWCH/DRhhZjHuta -yVOAYA18BnJi7O7Cwd6krmQd ------END PRIVATE KEY----- -""" - -let sampleDerCertSPKI = Array(Data(base64Encoded: """ -'MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA72vMk44TxyawioAkwKscPGQEAyBmEywnzrcyda1XPkkgkroIoj827bq0TOiQfLcQj3nrlHCKS9q6F4yxZpMUDg8P8/6zUO3FEIYhwrnH5KhM3sOuflm56gk1lF9Ni436DDKGmvOtmtiNem8RU9i5Ih5SorlcatPIUDa4aP3Bjd/0gXit3slPR7BFvVTw5xHvFBtcoaORjiIkTVPJ+YiwFlugpob9phr0pudbJOQOyxoQtZQgquPDC4+BWBK+UBiajXYyWwYTOQ73PvyO8WaFQ6xoSV0zxRrYCE4pbShJiBq5W6uj8Cn+jnOfw8MgNqmX2D7m+M3Yu5ypfZr262gW/FIpdPg29+kv18m/N0E0wzjGmq0ciRXR+SIxtaQRbYUWU5cqcglXzBPhr2J264gMyDw7uhz6C32kb0wdNa2FebhLb0MBFOp9njxtbvvPxGsRRFXTejTlv+3C4AlJHLI4JSLrXIyjdg3K15uNjZbc/Gqmr5iZPmqGoFkMuVMsym24V0hK/pJCCDsmgUcYxZFdRq8yP+yfmpkPilDJlOgcnZW2Dlb8wjWkrBzegoPozf/sZ/fmv3ZX+jHpdPv5+cSwAfwC1CJkmQRu/MnmWlSKFIhpXdr9L6OeTsvDxOm+O2l+M6D7AFuVzfw5r22TZZ1fBgNue9t4vbpabIfBBNQGLWMCAwEAAQ==' -""", options: .ignoreUnknownCharacters)!) + -----BEGIN PRIVATE KEY----- + MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDS9XBpPYlP3Toa + YKmWaqhXd4lnLSvjReuknE9IUmvFBoPTyGRU2UNv8N9tFT3xMOX2DrGOn7eVqXBX + OvKYRB8+q3CIsh3F/5smdNKQPfsL2tFL4d2lvrZ+2GOr2yRtPm9nH0N2wrmJi6Gt + R1J+x2Uvm7EoHvk3Ujbo77fBHvFauvwA3GsFT10J+f5buPcNW0rdpo+ASMfMpfBM + sr0Ucy1ys9XM/ehCMeWMiX/dd+fxqmOtl1tGyw4/Bbub5uf/HkiJStbKSCMgs7E4 + VgVhqFMu6jpeMlADXgDeOKEarW+Ds8eb3TkdIlYE2nmwxvdOPeW3AgChkE5RCRYW + 0aALTwEbAgMBAAECggEBAIzYFxv8XK+4iPFRdggZ35i+EzuSegm8Be6Z+YjUlmUt + y1fbI7lOcOrMy669juR3/CCCgOMzGVPPk1R547vrR10FAxYQrTYjSIetWWO6LeEl + T7U08FGXeapIeIslvTU+iQw1YEprCYqecewJgTdpktHtRaL+wu6/ci+k1G8YZJVo + qPmkSJigrEppm8ciXjvae+89jgUSEUmumI7A+LwiD2qr1GjGMg01TvKJ3jVrU0yq + cGP58zAY/W1DcenJm26bpirE82Wnesosv3hQf2LBMGBMyVp6ErNzITSNN1fUSfyB + 231DlGDor9oopfGfk9ApDUUVNXfFUv6ODnCSGBcdUkkCgYEA8snNvwok8IjbXzeG + zdDVUCVLX/o/vrFQg0KmktTArklLe7vAgcbmCp5TbdZKnpHam2KNu6ucgla5ZchV + 5vHbAdAhhvZFnYEaDPlpvueVT2jLWZHvsld17vfy7PVpZBwJSa2SQL4aC5sk+Bsn + 5LbSE4OL2o0KLQr6+BOAa9soVw8CgYEA3nA6u4Pxdhlf4UGo1fMWFbeXvU6myBs2 + JXiAPEM/9wKiGS3LOseqBzLBAoiWND9J7ynDJ+w5uuezwJP6MZImj+J0kbXEm0vy + 3iUBGBQvj1FJLN+wJx1QEzZBa+rslqX7vE+YsByJwfffqonGwXpj94Qxf6HMMDea + fRuHxqAjVTUCgYBsXe7bymdahXuFMH+W9hOARmUyXbx+HR7Wt7Up7JRkNorem5r9 + Ug3zx19tsyxzQp7UpFSm455j/tmZuKW/A0zBrmiImPvRpYI/MEQm1a8rVpcNT7ox + XCBjnYBsi82SxYDPxg11oGR3sbP6mgRgbcmutBSEZFeaa0BB4lJ70cJbuQKBgQDE + a1gBo3ZB8hAvafp7yqby0GbmnKA7zYOXvPuHu16tcR7QmxZ9tjgXGSNEaHYydryD + u14AT+F+gQHCiSkCQutYXQDQdjDBbWRt80EvEQwaQw4Z2QDE2WaPQHaupAj80l8j + nynWQa0HoilYf0cKLFhABfRrnuUeossBtKDFrTzmDQKBgH2uBQ2v0hV3EW7u2wdy + y7V9lkY+GDm51P1GWAH5c0BBZp3iAW1IBNzbUB8wXVJmhYPWO5Mh7wCAnr18HEZz + OjJVhqRxwhY4NEUsyI86Xxb7rV23HAM6laDItQ/bPlR+b7py5GWCH/DRhhZjHuta + yVOAYA18BnJi7O7Cwd6krmQd + -----END PRIVATE KEY----- + """ + +let sampleDerCertSPKI = Array( + Data( + base64Encoded: """ + 'MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA72vMk44TxyawioAkwKscPGQEAyBmEywnzrcyda1XPkkgkroIoj827bq0TOiQfLcQj3nrlHCKS9q6F4yxZpMUDg8P8/6zUO3FEIYhwrnH5KhM3sOuflm56gk1lF9Ni436DDKGmvOtmtiNem8RU9i5Ih5SorlcatPIUDa4aP3Bjd/0gXit3slPR7BFvVTw5xHvFBtcoaORjiIkTVPJ+YiwFlugpob9phr0pudbJOQOyxoQtZQgquPDC4+BWBK+UBiajXYyWwYTOQ73PvyO8WaFQ6xoSV0zxRrYCE4pbShJiBq5W6uj8Cn+jnOfw8MgNqmX2D7m+M3Yu5ypfZr262gW/FIpdPg29+kv18m/N0E0wzjGmq0ciRXR+SIxtaQRbYUWU5cqcglXzBPhr2J264gMyDw7uhz6C32kb0wdNa2FebhLb0MBFOp9njxtbvvPxGsRRFXTejTlv+3C4AlJHLI4JSLrXIyjdg3K15uNjZbc/Gqmr5iZPmqGoFkMuVMsym24V0hK/pJCCDsmgUcYxZFdRq8yP+yfmpkPilDJlOgcnZW2Dlb8wjWkrBzegoPozf/sZ/fmv3ZX+jHpdPv5+cSwAfwC1CJkmQRu/MnmWlSKFIhpXdr9L6OeTsvDxOm+O2l+M6D7AFuVzfw5r22TZZ1fBgNue9t4vbpabIfBBNQGLWMCAwEAAQ==' + """, + options: .ignoreUnknownCharacters + )! +) // Custom Root for the certificates below. // For example the following two certificates were issued from customCARoot: @@ -364,149 +370,149 @@ let sampleDerCertSPKI = Array(Data(base64Encoded: """ // // Then, copy the contents of the files into the literal strings below. let customCARoot = """ ------BEGIN CERTIFICATE----- -MIICljCCAX4CCQC4Y0sXrSJWijANBgkqhkiG9w0BAQsFADANMQswCQYDVQQDDAJj -YTAeFw0yNDA4MTMxMzQ4MjhaFw0yNzA2MDMxMzQ4MjhaMA0xCzAJBgNVBAMMAmNh -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxOnWOl7KYoEtoB0cjKnU -kHJg2E7MhKiuCaPBLIodz8XxtC8WGc1DFnHakrphHWs850nWsOew1elBL1pLVFUP -N6KUOgFFNXJ3OY3aD+Naekoefrc6UtljE8S+hlob+98vs1fSaLWIOVCoUiq9CwZN -zwLC3oRxCPdL1+XndhwRl6o/lQq7iNY2/IAKuSbuugBw2LElVTOUmD5LneDRT17G -K8iCzQa9pzrRqMv9+85nhSaETQUrTmnA9xVljp67Hi2AJtiZgEmZXP2/UF5svESz -OfTXQyM/rWSc8wNLMfc5+UOq8uizqymDcbPdSrObFJDHus/UiS9EV+pNo2f8u+r1 -tQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAkqa7MfgsPyWNOd7juFXVIN3JJv2t9 -BcBUKMEsZx7ntLUKDgLsJopPLE2jwmyGxY3mKz9KjOifIvbDa1jyhDgditRgc9LQ -uxwYXYDLTMuDBM7S2LJXgxDLaGuxEq6jeZHl3skXJJbGbfwjtsyvZSYocge7eJ6q -lNeGVZVoTaEIvQzNr5JBIR9gSxHq4ASe8+w/emK4rUjEJ4RA34WkK7dsmqJdqinj -u8cia2rDrffFzy/+Pb8q7CGekX/ky3BSyh4WObJ69zbDLQGEODIhe6WiMC1F7b0u -WzA4SXi/yTa01nbGnQ6+VsqqlyZD4dMtjW34s64XmlyyhJFmsK6a7MuG ------END CERTIFICATE----- -""" + -----BEGIN CERTIFICATE----- + MIICljCCAX4CCQC4Y0sXrSJWijANBgkqhkiG9w0BAQsFADANMQswCQYDVQQDDAJj + YTAeFw0yNDA4MTMxMzQ4MjhaFw0yNzA2MDMxMzQ4MjhaMA0xCzAJBgNVBAMMAmNh + MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxOnWOl7KYoEtoB0cjKnU + kHJg2E7MhKiuCaPBLIodz8XxtC8WGc1DFnHakrphHWs850nWsOew1elBL1pLVFUP + N6KUOgFFNXJ3OY3aD+Naekoefrc6UtljE8S+hlob+98vs1fSaLWIOVCoUiq9CwZN + zwLC3oRxCPdL1+XndhwRl6o/lQq7iNY2/IAKuSbuugBw2LElVTOUmD5LneDRT17G + K8iCzQa9pzrRqMv9+85nhSaETQUrTmnA9xVljp67Hi2AJtiZgEmZXP2/UF5svESz + OfTXQyM/rWSc8wNLMfc5+UOq8uizqymDcbPdSrObFJDHus/UiS9EV+pNo2f8u+r1 + tQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAkqa7MfgsPyWNOd7juFXVIN3JJv2t9 + BcBUKMEsZx7ntLUKDgLsJopPLE2jwmyGxY3mKz9KjOifIvbDa1jyhDgditRgc9LQ + uxwYXYDLTMuDBM7S2LJXgxDLaGuxEq6jeZHl3skXJJbGbfwjtsyvZSYocge7eJ6q + lNeGVZVoTaEIvQzNr5JBIR9gSxHq4ASe8+w/emK4rUjEJ4RA34WkK7dsmqJdqinj + u8cia2rDrffFzy/+Pb8q7CGekX/ky3BSyh4WObJ69zbDLQGEODIhe6WiMC1F7b0u + WzA4SXi/yTa01nbGnQ6+VsqqlyZD4dMtjW34s64XmlyyhJFmsK6a7MuG + -----END CERTIFICATE----- + """ let leafCertificateForTLSIssuedFromCustomCARoot = """ ------BEGIN CERTIFICATE----- -MIICnTCCAYUCCQCFiuzjrL/j7TANBgkqhkiG9w0BAQsFADANMQswCQYDVQQDDAJj -YTAeFw0yNDA4MTMxMzQ4MjhaFw0yNTA4MTMxMzQ4MjhaMBQxEjAQBgNVBAMMCWxv -Y2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOQ0prmO5wtc -NTA2ln55ztxWIE9E6P1N0gqRcg2t9wvIXk+n/xWUuBRawYKQ0SahXRF3rAbsSaEm -CdGdP1kImjLi7nFN+4tII8Ew/JsbLnJPr/UXbMVttJwdaMzDOsWQ9jb8GIqrtw+a -voGlMI/pfipyvviSgSNTbkZHRGQorJSDyj1lANM6d3RvgRfL10QPhDR2TGzQQ/tx -dtYdFmI5cUMyIDiB5FIh21q7ubb7I3L5Jw8tb7YhIYN0kQowU8lp0j0xc1i3XQcM -bK0T/pRsmSmfmIFVxnhzp2tF1eKKmxvXjlBOnLrbxgtZ1QxPFGDrz5U62OU96RUI -kgJshubN8oECAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAbeRxmsGMThKPX5V9+8RN -0e51sNYquLLx0Z5tVPvU21C6dVgNc/513P3oULInUnVLxt7TU5kOlOij6JeuXijz -+NGjzE+jv4R5vcr6Hk3s7nPo/YpIAuck9NZsQOW5qhjyNp2nKoUNa4DUb4ixrvTo -BKtPr+XJDmsVre1scE8kifbTnLjlhfdA85kAN+qLaelzRCxyK8BDyAKRNfyR1JaC -bJDmUKdzZ78CHr6fsRtas5TedEROF3bwGlVuel3t5tBx1X3OsHqu8QOP7n7EZScJ -A+UxN/xGlii6lBYINDWGLBlqKj7dh8pCFjP9Q8d7es53X9iY+Zmypac0dvg5GDnY -DQ== ------END CERTIFICATE----- -""" + -----BEGIN CERTIFICATE----- + MIICnTCCAYUCCQCFiuzjrL/j7TANBgkqhkiG9w0BAQsFADANMQswCQYDVQQDDAJj + YTAeFw0yNDA4MTMxMzQ4MjhaFw0yNTA4MTMxMzQ4MjhaMBQxEjAQBgNVBAMMCWxv + Y2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOQ0prmO5wtc + NTA2ln55ztxWIE9E6P1N0gqRcg2t9wvIXk+n/xWUuBRawYKQ0SahXRF3rAbsSaEm + CdGdP1kImjLi7nFN+4tII8Ew/JsbLnJPr/UXbMVttJwdaMzDOsWQ9jb8GIqrtw+a + voGlMI/pfipyvviSgSNTbkZHRGQorJSDyj1lANM6d3RvgRfL10QPhDR2TGzQQ/tx + dtYdFmI5cUMyIDiB5FIh21q7ubb7I3L5Jw8tb7YhIYN0kQowU8lp0j0xc1i3XQcM + bK0T/pRsmSmfmIFVxnhzp2tF1eKKmxvXjlBOnLrbxgtZ1QxPFGDrz5U62OU96RUI + kgJshubN8oECAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAbeRxmsGMThKPX5V9+8RN + 0e51sNYquLLx0Z5tVPvU21C6dVgNc/513P3oULInUnVLxt7TU5kOlOij6JeuXijz + +NGjzE+jv4R5vcr6Hk3s7nPo/YpIAuck9NZsQOW5qhjyNp2nKoUNa4DUb4ixrvTo + BKtPr+XJDmsVre1scE8kifbTnLjlhfdA85kAN+qLaelzRCxyK8BDyAKRNfyR1JaC + bJDmUKdzZ78CHr6fsRtas5TedEROF3bwGlVuel3t5tBx1X3OsHqu8QOP7n7EZScJ + A+UxN/xGlii6lBYINDWGLBlqKj7dh8pCFjP9Q8d7es53X9iY+Zmypac0dvg5GDnY + DQ== + -----END CERTIFICATE----- + """ let privateKeyForLeafCertificate = """ ------BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDkNKa5jucLXDUw -NpZ+ec7cViBPROj9TdIKkXINrfcLyF5Pp/8VlLgUWsGCkNEmoV0Rd6wG7EmhJgnR -nT9ZCJoy4u5xTfuLSCPBMPybGy5yT6/1F2zFbbScHWjMwzrFkPY2/BiKq7cPmr6B -pTCP6X4qcr74koEjU25GR0RkKKyUg8o9ZQDTOnd0b4EXy9dED4Q0dkxs0EP7cXbW -HRZiOXFDMiA4geRSIdtau7m2+yNy+ScPLW+2ISGDdJEKMFPJadI9MXNYt10HDGyt -E/6UbJkpn5iBVcZ4c6drRdXiipsb145QTpy628YLWdUMTxRg68+VOtjlPekVCJIC -bIbmzfKBAgMBAAECggEARegLGtS32jcI5BgUyfGueLi5dQ77AH2SVkJv2djs0OM0 -YNppvcatDS8wEDskltzfkbZDMGu5sm/gmiG9ghysf+IcgQEOiYAz076Z4znUZJgc -osvmOiR9K0WnEPLNUjAx/G4FZpVropAYw8ZCthMk3wP/lE3s2VF5enXicXw0Qdn5 -QsaA1D+qPsdl/NcEKX4VrVYiQgFTUv7x6LT13Hq6o3CKeIkrg4/6stx8ErHQrAkM -7dzoxvoSb/pB/Ik41gBeQXNeDig0FghyrEeHZnT+DwouF+/yOLjJCLMe2DezSDbq -4jasWm7nbzpEkIJUgqC3ZZhtiQLXqNwErBsgGD/QsQKBgQD14hIsDfvqAlT59/Qi -q8Q9bu0jwy13Ha+mVlDW5kvLWiPIz7Yp63znJP4tKiwn7vqGKQLAnFiLR4qOq7vv -ohT76s9ItWmCLOdtxc461z+UueG+TiqYra7Gthk+3EqUblpUGW912pWxYokcsf8S -FgkjumkycC2XUWgv70+9NcMIZwKBgQDtmGGGpRqp0zLMB9tdeEjWt+tm425mZAcE -rtcHTtTRv38XfCG5UgtYc6weVg4IwOzQp5wWiu4O8ISiizJ5R7R4cn8k9O+rPB7d -sGmtUmo32a2rP0g5kOPD3ssSarMnRY/BD2yPK2pSgLPnf4KYFd/XFBni1Irg8Trp -i6SDQpB81wKBgHEzL2KQ3ZWSlUSv3vnHUoVl+E8qoFfiludhfb4yMFrimO7ukdMi -01InOc3ZSJLp9vSlFNtQH4Of4C5m6hMc78Q7CktTGcwQmEt1ccitKFx0Z3WRzxKT -g4+Abob+LGfBllx5iVMc2yXbU3yehevxsSt9usi51IOBuxG2f2OAyNWpAoGBAIvB -9KwU9kgq+VhWzsx+cqoK6adN5KTJ9e7lQYsE7d6rPAD+fX/bKN1QvU/i4sJ3aVWb -Ig+IjVuwUvSh2IDKkve+sdd1VH1vEeDpYmAXeG991dBDmyJxfei7Zsxggx14p4Sy -o/LbYOFC35AuywzW4SJMqqVozIBgpXy3LYAgaYllAoGAbKdFBQSBaREyDl9Rq/YT -cJId2Ti1Uf4NZ3Rv3ZG2/tU1tCXXPNF+1vWalM/Dxb6wcD38d9qeInth3v4fsi3E -sS7RcKqjaA/qxL/pyjZCTLJq0e6LNJf8lLjeN1ZtG7rVEJ2OKFCGblePdXSakvIU -n+6w7fMhLu0vy1cyUMjICco= ------END PRIVATE KEY----- -""" + -----BEGIN PRIVATE KEY----- + MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDkNKa5jucLXDUw + NpZ+ec7cViBPROj9TdIKkXINrfcLyF5Pp/8VlLgUWsGCkNEmoV0Rd6wG7EmhJgnR + nT9ZCJoy4u5xTfuLSCPBMPybGy5yT6/1F2zFbbScHWjMwzrFkPY2/BiKq7cPmr6B + pTCP6X4qcr74koEjU25GR0RkKKyUg8o9ZQDTOnd0b4EXy9dED4Q0dkxs0EP7cXbW + HRZiOXFDMiA4geRSIdtau7m2+yNy+ScPLW+2ISGDdJEKMFPJadI9MXNYt10HDGyt + E/6UbJkpn5iBVcZ4c6drRdXiipsb145QTpy628YLWdUMTxRg68+VOtjlPekVCJIC + bIbmzfKBAgMBAAECggEARegLGtS32jcI5BgUyfGueLi5dQ77AH2SVkJv2djs0OM0 + YNppvcatDS8wEDskltzfkbZDMGu5sm/gmiG9ghysf+IcgQEOiYAz076Z4znUZJgc + osvmOiR9K0WnEPLNUjAx/G4FZpVropAYw8ZCthMk3wP/lE3s2VF5enXicXw0Qdn5 + QsaA1D+qPsdl/NcEKX4VrVYiQgFTUv7x6LT13Hq6o3CKeIkrg4/6stx8ErHQrAkM + 7dzoxvoSb/pB/Ik41gBeQXNeDig0FghyrEeHZnT+DwouF+/yOLjJCLMe2DezSDbq + 4jasWm7nbzpEkIJUgqC3ZZhtiQLXqNwErBsgGD/QsQKBgQD14hIsDfvqAlT59/Qi + q8Q9bu0jwy13Ha+mVlDW5kvLWiPIz7Yp63znJP4tKiwn7vqGKQLAnFiLR4qOq7vv + ohT76s9ItWmCLOdtxc461z+UueG+TiqYra7Gthk+3EqUblpUGW912pWxYokcsf8S + FgkjumkycC2XUWgv70+9NcMIZwKBgQDtmGGGpRqp0zLMB9tdeEjWt+tm425mZAcE + rtcHTtTRv38XfCG5UgtYc6weVg4IwOzQp5wWiu4O8ISiizJ5R7R4cn8k9O+rPB7d + sGmtUmo32a2rP0g5kOPD3ssSarMnRY/BD2yPK2pSgLPnf4KYFd/XFBni1Irg8Trp + i6SDQpB81wKBgHEzL2KQ3ZWSlUSv3vnHUoVl+E8qoFfiludhfb4yMFrimO7ukdMi + 01InOc3ZSJLp9vSlFNtQH4Of4C5m6hMc78Q7CktTGcwQmEt1ccitKFx0Z3WRzxKT + g4+Abob+LGfBllx5iVMc2yXbU3yehevxsSt9usi51IOBuxG2f2OAyNWpAoGBAIvB + 9KwU9kgq+VhWzsx+cqoK6adN5KTJ9e7lQYsE7d6rPAD+fX/bKN1QvU/i4sJ3aVWb + Ig+IjVuwUvSh2IDKkve+sdd1VH1vEeDpYmAXeG991dBDmyJxfei7Zsxggx14p4Sy + o/LbYOFC35AuywzW4SJMqqVozIBgpXy3LYAgaYllAoGAbKdFBQSBaREyDl9Rq/YT + cJId2Ti1Uf4NZ3Rv3ZG2/tU1tCXXPNF+1vWalM/Dxb6wcD38d9qeInth3v4fsi3E + sS7RcKqjaA/qxL/pyjZCTLJq0e6LNJf8lLjeN1ZtG7rVEJ2OKFCGblePdXSakvIU + n+6w7fMhLu0vy1cyUMjICco= + -----END PRIVATE KEY----- + """ let leafCertificateForClientAuthenticationIssuedFromCustomCARoot = """ ------BEGIN CERTIFICATE----- -MIICuzCCAaOgAwIBAgIJAIWK7OOsv+PuMA0GCSqGSIb3DQEBCwUAMA0xCzAJBgNV -BAMMAmNhMB4XDTI0MDgxMzEzNDgyOFoXDTI1MDgxMzEzNDgyOFowFDESMBAGA1UE -AwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApjBs -Na28P08R3QmX7bTk56RcMgduRa7ZAmblVwuVjbbc5ik41qzqVYnodGLFMdK+dZ5z -YkK8M71C1PTDiH6eLQb/cxRB3WKS6gyEsOnc4JsTVIZ+xT4skyci3dpqynW1Z4H4 -6ChUJ6g7QXFNZ1L0lTjwkmy5FQth5CpQ5z/5ZbL/+2Rb+2vEQo5f+PmmT/rn2f9g -UpapNqH875uwDWJvhjtqt12f3XpJvKxmLX33FDsX3j3wFtFM7aoEb94Q1r+6SQLe -Du6TibqHE5ohplp7ULb1hUy5y1DlQ6vS8aXtwA5ObinLVCmTDHKqkxmn6VlAdeKv -MYMpFMw65eo335CzdwIDAQABoxcwFTATBgNVHSUEDDAKBggrBgEFBQcDAjANBgkq -hkiG9w0BAQsFAAOCAQEAbwppV53MXMOcCpZ7k3uuYiICALmJQLjD6FDv/gp4Q4Fr -2YVsS+lPYpbdVJVmF1CtSZPTnKn8mYSRq19Ypx48PG+S2Xg3+5VcdUVuTFpRMDCn -+XrQV4TBz+ULUmml79vMwjpBZ6vL/Ddm/fV8nmPtQz2/KTuEYkzVZ33NP/ogtUIj -krLDfYaPlVuyzXDth9cRQ/ZIOBh7ACW57cTohwkac5NMQmXrjRktwnGzzQ3neRZV -Isjs54oPSjhBYISOQjEqMgeOq/cflsDVr8jPaYUkIj4Rd278bS5dyjva4ZJiLKEu -HD03fD1RGeVOWJCOhy0cwErutfPKILZx9koomjet/g== ------END CERTIFICATE----- -""" + -----BEGIN CERTIFICATE----- + MIICuzCCAaOgAwIBAgIJAIWK7OOsv+PuMA0GCSqGSIb3DQEBCwUAMA0xCzAJBgNV + BAMMAmNhMB4XDTI0MDgxMzEzNDgyOFoXDTI1MDgxMzEzNDgyOFowFDESMBAGA1UE + AwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApjBs + Na28P08R3QmX7bTk56RcMgduRa7ZAmblVwuVjbbc5ik41qzqVYnodGLFMdK+dZ5z + YkK8M71C1PTDiH6eLQb/cxRB3WKS6gyEsOnc4JsTVIZ+xT4skyci3dpqynW1Z4H4 + 6ChUJ6g7QXFNZ1L0lTjwkmy5FQth5CpQ5z/5ZbL/+2Rb+2vEQo5f+PmmT/rn2f9g + UpapNqH875uwDWJvhjtqt12f3XpJvKxmLX33FDsX3j3wFtFM7aoEb94Q1r+6SQLe + Du6TibqHE5ohplp7ULb1hUy5y1DlQ6vS8aXtwA5ObinLVCmTDHKqkxmn6VlAdeKv + MYMpFMw65eo335CzdwIDAQABoxcwFTATBgNVHSUEDDAKBggrBgEFBQcDAjANBgkq + hkiG9w0BAQsFAAOCAQEAbwppV53MXMOcCpZ7k3uuYiICALmJQLjD6FDv/gp4Q4Fr + 2YVsS+lPYpbdVJVmF1CtSZPTnKn8mYSRq19Ypx48PG+S2Xg3+5VcdUVuTFpRMDCn + +XrQV4TBz+ULUmml79vMwjpBZ6vL/Ddm/fV8nmPtQz2/KTuEYkzVZ33NP/ogtUIj + krLDfYaPlVuyzXDth9cRQ/ZIOBh7ACW57cTohwkac5NMQmXrjRktwnGzzQ3neRZV + Isjs54oPSjhBYISOQjEqMgeOq/cflsDVr8jPaYUkIj4Rd278bS5dyjva4ZJiLKEu + HD03fD1RGeVOWJCOhy0cwErutfPKILZx9koomjet/g== + -----END CERTIFICATE----- + """ let privateKeyForClientAuthentication = """ ------BEGIN PRIVATE KEY----- -MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCmMGw1rbw/TxHd -CZfttOTnpFwyB25FrtkCZuVXC5WNttzmKTjWrOpVieh0YsUx0r51nnNiQrwzvULU -9MOIfp4tBv9zFEHdYpLqDISw6dzgmxNUhn7FPiyTJyLd2mrKdbVngfjoKFQnqDtB -cU1nUvSVOPCSbLkVC2HkKlDnP/llsv/7ZFv7a8RCjl/4+aZP+ufZ/2BSlqk2ofzv -m7ANYm+GO2q3XZ/dekm8rGYtffcUOxfePfAW0UztqgRv3hDWv7pJAt4O7pOJuocT -miGmWntQtvWFTLnLUOVDq9Lxpe3ADk5uKctUKZMMcqqTGafpWUB14q8xgykUzDrl -6jffkLN3AgMBAAECggEAStoYgvzjguhMNXByu5/0UdkXpXjvU/dyysApn9EZ5SBt -0kTS0u5DBY/94R3zj4NKQZPCiIliVzNxfJVZ1IqjF8jFGcIQAHS7kytcQIq0730p -cbK6OoDMduLzs1UDMHlf4WULBRXVAZ+mQM2VfWpBu0xQHsNVgYME7k2Y7u9Dl2gT -7KR3Mc9rBxyaO/0Fdep+0Veju2AOsn2XG/U7skjXdRXgFgfLSu+6IoYj6fzFGwiI -+kRquj+NerOJTrWjzn2q8BH+xtZxda9lqOra5aHY0gHrTtHY9DLFTQTFXETk6fvU -alT+PU8mM0WqbXoxOL1q+Jdn4kOofwqhnYUc3BWLYQKBgQDcJrx9yvUv2dzablI7 -N04wEpoltfM2cl0sJPrTjnVK1Sjtf2dVsTrhdFS6pRRqCoN+qVQpUYFef63U3Doj -xl4bRHcRAiwYONoV4LWROxGuw6ulT/+xZypYix2ojwQ1rt2I+uwOKYVz6rh9U/Zx -ETX8ue5hDOTNKXpeyOeOVTosWQKBgQDBQDX60vdp6IO332jpFbnyLp0WyPC4oQVE -BUUf8E7naUStKXZfqErzN3aKfSY08VC9jjrJtrR8Fj5XRzDwcfiH2L2yOgmuiR7J -e+CpvTMzPJcNqkAlq3Wu+tTPVJ1Nk5GtIW2kTt0NpNv31JRnZzbH1hcqT3cvyV15 -uqxdqVSkTwKBgBwQDAL09iAtY0usuGq3+A2EsYWRFfmgxmO0Kw0Aoc7yMQ9lKCTy -PJE0pQBNvrZttKlWqFXD//utxtjVYcvho2lSZuMSJdDInnQfesWShASFCMI/2lYg -0nMK+LLd2CmHqtGlOqXrgQlvqCjBpS5whTM7+DkCzb+hQ+oFLg8kqg+xAoGAYv9m -58BNWKbxWy+KyeUEZcl1VefIUXzDes4MVElB0pB9ywtzhZtsEd52zolAGl0I1KJZ -AV6kZPDsLL/elT59Z/Ijc3sB3LSH3gWk2K+A3B2M8EYoKGQGnIYIoNGi58vSE9QN -G9/+o++xc+slvzcDvCmzokwlLYjFZwe3JyAIqUcCgYBLxSG8z7kTKCMhXNMRTX3Y -IjCukdcPm7Uh5qQAbNExQHeXaO87BG94XVo4EcsKaI4zi5YrtStJArtdoRAXm/Wc -pIg/+VE2utJEI9qcwSLwOFQwxXmFZvcVATnYDK4oyxL7ibFuD08x3kxnrDBfB3pi -UT+vAVNaHZwttUGp5k/hQA== ------END PRIVATE KEY----- -""" + -----BEGIN PRIVATE KEY----- + MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCmMGw1rbw/TxHd + CZfttOTnpFwyB25FrtkCZuVXC5WNttzmKTjWrOpVieh0YsUx0r51nnNiQrwzvULU + 9MOIfp4tBv9zFEHdYpLqDISw6dzgmxNUhn7FPiyTJyLd2mrKdbVngfjoKFQnqDtB + cU1nUvSVOPCSbLkVC2HkKlDnP/llsv/7ZFv7a8RCjl/4+aZP+ufZ/2BSlqk2ofzv + m7ANYm+GO2q3XZ/dekm8rGYtffcUOxfePfAW0UztqgRv3hDWv7pJAt4O7pOJuocT + miGmWntQtvWFTLnLUOVDq9Lxpe3ADk5uKctUKZMMcqqTGafpWUB14q8xgykUzDrl + 6jffkLN3AgMBAAECggEAStoYgvzjguhMNXByu5/0UdkXpXjvU/dyysApn9EZ5SBt + 0kTS0u5DBY/94R3zj4NKQZPCiIliVzNxfJVZ1IqjF8jFGcIQAHS7kytcQIq0730p + cbK6OoDMduLzs1UDMHlf4WULBRXVAZ+mQM2VfWpBu0xQHsNVgYME7k2Y7u9Dl2gT + 7KR3Mc9rBxyaO/0Fdep+0Veju2AOsn2XG/U7skjXdRXgFgfLSu+6IoYj6fzFGwiI + +kRquj+NerOJTrWjzn2q8BH+xtZxda9lqOra5aHY0gHrTtHY9DLFTQTFXETk6fvU + alT+PU8mM0WqbXoxOL1q+Jdn4kOofwqhnYUc3BWLYQKBgQDcJrx9yvUv2dzablI7 + N04wEpoltfM2cl0sJPrTjnVK1Sjtf2dVsTrhdFS6pRRqCoN+qVQpUYFef63U3Doj + xl4bRHcRAiwYONoV4LWROxGuw6ulT/+xZypYix2ojwQ1rt2I+uwOKYVz6rh9U/Zx + ETX8ue5hDOTNKXpeyOeOVTosWQKBgQDBQDX60vdp6IO332jpFbnyLp0WyPC4oQVE + BUUf8E7naUStKXZfqErzN3aKfSY08VC9jjrJtrR8Fj5XRzDwcfiH2L2yOgmuiR7J + e+CpvTMzPJcNqkAlq3Wu+tTPVJ1Nk5GtIW2kTt0NpNv31JRnZzbH1hcqT3cvyV15 + uqxdqVSkTwKBgBwQDAL09iAtY0usuGq3+A2EsYWRFfmgxmO0Kw0Aoc7yMQ9lKCTy + PJE0pQBNvrZttKlWqFXD//utxtjVYcvho2lSZuMSJdDInnQfesWShASFCMI/2lYg + 0nMK+LLd2CmHqtGlOqXrgQlvqCjBpS5whTM7+DkCzb+hQ+oFLg8kqg+xAoGAYv9m + 58BNWKbxWy+KyeUEZcl1VefIUXzDes4MVElB0pB9ywtzhZtsEd52zolAGl0I1KJZ + AV6kZPDsLL/elT59Z/Ijc3sB3LSH3gWk2K+A3B2M8EYoKGQGnIYIoNGi58vSE9QN + G9/+o++xc+slvzcDvCmzokwlLYjFZwe3JyAIqUcCgYBLxSG8z7kTKCMhXNMRTX3Y + IjCukdcPm7Uh5qQAbNExQHeXaO87BG94XVo4EcsKaI4zi5YrtStJArtdoRAXm/Wc + pIg/+VE2utJEI9qcwSLwOFQwxXmFZvcVATnYDK4oyxL7ibFuD08x3kxnrDBfB3pi + UT+vAVNaHZwttUGp5k/hQA== + -----END PRIVATE KEY----- + """ // This is a root certificate used to setup and test sending CA names to // a client during client authentication. // This certificate is used to test having multiple root certificates in a directory. let secondaryRootCertificateForClientAuthentication = """ ------BEGIN CERTIFICATE----- -MIIC5TCCAc2gAwIBAgIUDxjYloPbo7PQteeQLKW499sRxm0wDQYJKoZIhvcNAQEL -BQAwGjEYMBYGA1UEAwwPU2FtcGxlUHJvamVjdENBMB4XDTIyMDgwOTE4NDQyMloX -DTIzMDgxMTE4NDQyMlowGjEYMBYGA1UEAwwPU2FtcGxlUHJvamVjdENBMIIBIjAN -BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5Q19OwSP4UJo35NZ0rg/+bAbBh+v -n7lilsPwLwhmhkwWZVSTPQr8bk5ceUGJtPups3w0d1oM/t7oC43O38sFwkCYL5nt -Z6YuQfP0ZijDjO6WiQr+gwyaAZt84/Rm1MHYqF1gBCDFQhcba3CTSd4HQzls+uRF -EaWqu4n706e10ed9Se1uAqeufYRdGPijskFNYmw+MgXWFC/WrY/TXRIoIQsj/g8A -jC66Ovriz+nXWYjPBSLdyXY69WVR5v6qksMeuJAYv37nsWL1H9436Q3WhxlLZ3Hl -v3SI13Kk6y7Sp5TYDeomeMi+9aAHOtvZfZcBEw5yLCkJSXGQL3nIpk7oDQIDAQAB -oyMwITAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwICpDANBgkqhkiG9w0B -AQsFAAOCAQEAx+Ajc4SnzSS/1BpK+bVK2y0vH6NmF9Y9xjAi06pAWOtNpXBTH8Qe -QdQbB/00nUDccEcIoEn46WDKwW4ebGKa4sn2BAalM0W2UoPMX0UYtUDPyNkeK8Q+ -MQVOaZX295g9t6sfQ/rbRQRGJHFH7VsRQPGHo/vYG91+ZS6judUUZw7Mcltaay2y -ljU3QeOeO3m553tfw/MwY6UWiSs9jyZumtzxL3WS/LCssxwnknkE5IM2CA8IzBfM -VShvzuAwd3a5ZTju3jD1cK0mwlbEYNw0xj+wjBLqwFuJI/CnQzGSElvQy0v2ygjr -R6S+ZRBlGxAnjKbTEMg53A+0XkGg/Kgexg== ------END CERTIFICATE----- -""" + -----BEGIN CERTIFICATE----- + MIIC5TCCAc2gAwIBAgIUDxjYloPbo7PQteeQLKW499sRxm0wDQYJKoZIhvcNAQEL + BQAwGjEYMBYGA1UEAwwPU2FtcGxlUHJvamVjdENBMB4XDTIyMDgwOTE4NDQyMloX + DTIzMDgxMTE4NDQyMlowGjEYMBYGA1UEAwwPU2FtcGxlUHJvamVjdENBMIIBIjAN + BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5Q19OwSP4UJo35NZ0rg/+bAbBh+v + n7lilsPwLwhmhkwWZVSTPQr8bk5ceUGJtPups3w0d1oM/t7oC43O38sFwkCYL5nt + Z6YuQfP0ZijDjO6WiQr+gwyaAZt84/Rm1MHYqF1gBCDFQhcba3CTSd4HQzls+uRF + EaWqu4n706e10ed9Se1uAqeufYRdGPijskFNYmw+MgXWFC/WrY/TXRIoIQsj/g8A + jC66Ovriz+nXWYjPBSLdyXY69WVR5v6qksMeuJAYv37nsWL1H9436Q3WhxlLZ3Hl + v3SI13Kk6y7Sp5TYDeomeMi+9aAHOtvZfZcBEw5yLCkJSXGQL3nIpk7oDQIDAQAB + oyMwITAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwICpDANBgkqhkiG9w0B + AQsFAAOCAQEAx+Ajc4SnzSS/1BpK+bVK2y0vH6NmF9Y9xjAi06pAWOtNpXBTH8Qe + QdQbB/00nUDccEcIoEn46WDKwW4ebGKa4sn2BAalM0W2UoPMX0UYtUDPyNkeK8Q+ + MQVOaZX295g9t6sfQ/rbRQRGJHFH7VsRQPGHo/vYG91+ZS6judUUZw7Mcltaay2y + ljU3QeOeO3m553tfw/MwY6UWiSs9jyZumtzxL3WS/LCssxwnknkE5IM2CA8IzBfM + VShvzuAwd3a5ZTju3jD1cK0mwlbEYNw0xj+wjBLqwFuJI/CnQzGSElvQy0v2ygjr + R6S+ZRBlGxAnjKbTEMg53A+0XkGg/Kgexg== + -----END CERTIFICATE----- + """ let samplePemCerts = "\(samplePemCert)\n\(samplePemCert)" let sampleDerCert = pemToDer(samplePemCert) @@ -550,7 +556,7 @@ func randomSerialNumber() -> ASN1_INTEGER { var readBytes = Array.init(repeating: UInt8(0), count: bytesToRead) let readCount = readBytes.withUnsafeMutableBytes { - return read(fd, $0.baseAddress, bytesToRead) + read(fd, $0.baseAddress, bytesToRead) } precondition(readCount == bytesToRead) @@ -615,13 +621,15 @@ func addExtension(x509: OpaquePointer, nid: CInt, value: String) { CNIOBoringSSL_X509V3_set_ctx(&extensionContext, x509, x509, nil, nil, 0) let ext = value.withCString { (pointer) in - return CNIOBoringSSL_X509V3_EXT_nconf_nid(nil, &extensionContext, nid, UnsafeMutablePointer(mutating: pointer)) + CNIOBoringSSL_X509V3_EXT_nconf_nid(nil, &extensionContext, nid, UnsafeMutablePointer(mutating: pointer)) }! CNIOBoringSSL_X509_add_ext(x509, ext, -1) CNIOBoringSSL_X509_EXTENSION_free(ext) } -func generateSelfSignedCert(keygenFunction: () -> OpaquePointer = generateRSAPrivateKey) -> (NIOSSLCertificate, NIOSSLPrivateKey) { +func generateSelfSignedCert( + keygenFunction: () -> OpaquePointer = generateRSAPrivateKey +) -> (NIOSSLCertificate, NIOSSLPrivateKey) { let pkey = keygenFunction() let x = CNIOBoringSSL_X509_new()! CNIOBoringSSL_X509_set_version(x, 2) @@ -648,14 +656,17 @@ func generateSelfSignedCert(keygenFunction: () -> OpaquePointer = generateRSAPri let commonName = "localhost" let name = CNIOBoringSSL_X509_get_subject_name(x) commonName.withCString { (pointer: UnsafePointer) -> Void in - pointer.withMemoryRebound(to: UInt8.self, capacity: commonName.lengthOfBytes(using: .utf8)) { (pointer: UnsafePointer) -> Void in - CNIOBoringSSL_X509_NAME_add_entry_by_NID(name, - NID_commonName, - MBSTRING_UTF8, - UnsafeMutablePointer(mutating: pointer), - ossl_ssize_t(commonName.lengthOfBytes(using: .utf8)), - -1, - 0) + pointer.withMemoryRebound(to: UInt8.self, capacity: commonName.lengthOfBytes(using: .utf8)) { + (pointer: UnsafePointer) -> Void in + CNIOBoringSSL_X509_NAME_add_entry_by_NID( + name, + NID_commonName, + MBSTRING_UTF8, + UnsafeMutablePointer(mutating: pointer), + ossl_ssize_t(commonName.lengthOfBytes(using: .utf8)), + -1, + 0 + ) } } CNIOBoringSSL_X509_set_issuer_name(x, name) @@ -667,7 +678,10 @@ func generateSelfSignedCert(keygenFunction: () -> OpaquePointer = generateRSAPri CNIOBoringSSL_X509_sign(x, pkey, CNIOBoringSSL_EVP_sha256()) - return (NIOSSLCertificate.fromUnsafePointer(takingOwnership: x), NIOSSLPrivateKey.fromUnsafePointer(takingOwnership: pkey)) + return ( + NIOSSLCertificate.fromUnsafePointer(takingOwnership: x), + NIOSSLPrivateKey.fromUnsafePointer(takingOwnership: pkey) + ) } final class BackToBackEmbeddedChannel { @@ -675,7 +689,6 @@ final class BackToBackEmbeddedChannel { private(set) var server: EmbeddedChannel private(set) var loop: EmbeddedEventLoop - init() { self.loop = EmbeddedEventLoop() self.client = EmbeddedChannel(loop: self.loop) diff --git a/Tests/NIOSSLTests/ObjectIdentifierTests.swift b/Tests/NIOSSLTests/ObjectIdentifierTests.swift index 4a2338552..efd6b3474 100644 --- a/Tests/NIOSSLTests/ObjectIdentifierTests.swift +++ b/Tests/NIOSSLTests/ObjectIdentifierTests.swift @@ -12,9 +12,10 @@ // //===----------------------------------------------------------------------===// +@_implementationOnly import CNIOBoringSSL import XCTest + @testable import NIOSSL -@_implementationOnly import CNIOBoringSSL private final class OIDMemoryOwner { var reference: OpaquePointer! @@ -40,61 +41,70 @@ final class ObjectIdentifierTests: XCTestCase { ) XCTAssertEqual(NIOSSLObjectIdentifier("1.2"), NIOSSLObjectIdentifier("1.2")) XCTAssertEqual(NIOSSLObjectIdentifier("1.2.3"), NIOSSLObjectIdentifier("1.2.3")) - + XCTAssertNotEqual(NIOSSLObjectIdentifier("1"), NIOSSLObjectIdentifier("1.2")) XCTAssertNotEqual(NIOSSLObjectIdentifier("1.2"), NIOSSLObjectIdentifier("1.2.3")) } - + func testHashable() { - XCTAssertEqual(Set([ - NIOSSLObjectIdentifier("1.1"), - ]), Set([ - NIOSSLObjectIdentifier("1.1"), - ])) - XCTAssertEqual(Set([ - NIOSSLObjectIdentifier("1.1"), - NIOSSLObjectIdentifier("1.2"), - ]), Set([ - NIOSSLObjectIdentifier("1.2"), - NIOSSLObjectIdentifier("1.1"), - ])) + XCTAssertEqual( + Set([ + NIOSSLObjectIdentifier("1.1") + ]), + Set([ + NIOSSLObjectIdentifier("1.1") + ]) + ) + XCTAssertEqual( + Set([ + NIOSSLObjectIdentifier("1.1"), + NIOSSLObjectIdentifier("1.2"), + ]), + Set([ + NIOSSLObjectIdentifier("1.2"), + NIOSSLObjectIdentifier("1.1"), + ]) + ) } - + func testCustomStringConvertible() { XCTAssertEqual(NIOSSLObjectIdentifier("1.1")?.description, "1.1") XCTAssertEqual(NIOSSLObjectIdentifier("1.2")?.description, "1.2") XCTAssertEqual(NIOSSLObjectIdentifier("1.2.3")?.description, "1.2.3") XCTAssertEqual(NIOSSLObjectIdentifier("1.2.3.4")?.description, "1.2.3.4") } - + func testUnowned() { var owner: Optional = OIDMemoryOwner("1.2.3")! weak var weakReferenceToOwner = owner - + var oid: Optional = NIOSSLObjectIdentifier(borrowing: owner!.reference, owner: owner!) XCTAssertEqual(oid?.description, "1.2.3") - + owner = nil XCTAssertNotNil(weakReferenceToOwner, "OID should still have a strong reference to the owner") - + XCTAssertEqual(oid?.description, "1.2.3") - + oid = nil - XCTAssertNil(weakReferenceToOwner, "OID is released and therefore no one should still have a strong reference to the owner") + XCTAssertNil( + weakReferenceToOwner, + "OID is released and therefore no one should still have a strong reference to the owner" + ) } - + func testCopy() { var owner: Optional = OIDMemoryOwner("1.2.3")! weak var weakReferenceToOwner = owner - + let oid: Optional = withExtendedLifetime(owner) { NIOSSLObjectIdentifier(copyOf: $0?.reference) } - + XCTAssertEqual(oid?.description, "1.2.3") owner = nil XCTAssertNil(weakReferenceToOwner, "OID should no longer have a strong reference to the owner") - + XCTAssertEqual(oid?.description, "1.2.3", "copy should still work after the original owner is deallocated") } } diff --git a/Tests/NIOSSLTests/SSLCertificateExtensionsTests.swift b/Tests/NIOSSLTests/SSLCertificateExtensionsTests.swift index cd9cbd000..610a36ab6 100644 --- a/Tests/NIOSSLTests/SSLCertificateExtensionsTests.swift +++ b/Tests/NIOSSLTests/SSLCertificateExtensionsTests.swift @@ -13,25 +13,32 @@ //===----------------------------------------------------------------------===// import XCTest + @testable import NIOSSL final class SSLCertificateExtensionsTests: XCTestCase { func test() throws { let cert = try NIOSSLCertificate(bytes: Array(samplePemCert.utf8), format: .pem) - + XCTAssertEqual(cert._extensions.count, 3) - let basicConstraint = try XCTUnwrap(cert._extensions.first(where: { $0.objectIdentifier == .init("2.5.29.19")! })) - let subjectKeyIdentifier = try XCTUnwrap(cert._extensions.first(where: { $0.objectIdentifier == .init("2.5.29.14")! })) - let authorityKeyIdentifier = try XCTUnwrap(cert._extensions.first(where: { $0.objectIdentifier == .init("2.5.29.35")! })) - + let basicConstraint = try XCTUnwrap( + cert._extensions.first(where: { $0.objectIdentifier == .init("2.5.29.19")! }) + ) + let subjectKeyIdentifier = try XCTUnwrap( + cert._extensions.first(where: { $0.objectIdentifier == .init("2.5.29.14")! }) + ) + let authorityKeyIdentifier = try XCTUnwrap( + cert._extensions.first(where: { $0.objectIdentifier == .init("2.5.29.35")! }) + ) + XCTAssertEqual(basicConstraint.isCritical, false) XCTAssertEqual( Array(basicConstraint.data), [ - 0x30, 0x3, 0x1, 0x1, 0xFF + 0x30, 0x3, 0x1, 0x1, 0xFF, ] ) - + XCTAssertEqual(subjectKeyIdentifier.isCritical, false) XCTAssertEqual( Array(subjectKeyIdentifier.data), @@ -41,7 +48,7 @@ final class SSLCertificateExtensionsTests: XCTestCase { 0x70, 0xF8, 0x94, 0x23, 0x9A, 0x81, 0x34, 0xF0, 0x54, 0xF8, ] ) - + XCTAssertEqual(authorityKeyIdentifier.isCritical, false) XCTAssertEqual( Array(authorityKeyIdentifier.data), @@ -52,25 +59,28 @@ final class SSLCertificateExtensionsTests: XCTestCase { ] ) } - + func testEmptyExtensions() { let extensions = NIOSSLCertificate._Extensions(takeOwnershipOf: nil) XCTAssertEqual(extensions.count, 0) } - + func testUnowned() throws { var owner: Optional = try NIOSSLCertificate(bytes: Array(samplePemCert.utf8), format: .pem) weak var weakReferenceToOwner = owner - + var extensions: Optional = owner!._extensions XCTAssertEqual(extensions.map { Array($0) }?.count, 3) - + owner = nil XCTAssertNotNil(weakReferenceToOwner, "extensions should still have a strong reference to the owner") - + XCTAssertEqual(extensions.map { Array($0) }?.count, 3) - + extensions = nil - XCTAssertNil(weakReferenceToOwner, "extensions are released and therefore no one should still have a strong reference to the owner") + XCTAssertNil( + weakReferenceToOwner, + "extensions are released and therefore no one should still have a strong reference to the owner" + ) } } diff --git a/Tests/NIOSSLTests/SSLCertificateTest.swift b/Tests/NIOSSLTests/SSLCertificateTest.swift index ebf04ddf2..18d3a1a39 100644 --- a/Tests/NIOSSLTests/SSLCertificateTest.swift +++ b/Tests/NIOSSLTests/SSLCertificateTest.swift @@ -13,95 +13,96 @@ //===----------------------------------------------------------------------===// import Foundation -import XCTest import NIOCore +import XCTest + @testable import NIOSSL let multiSanCert = """ ------BEGIN CERTIFICATE----- -MIIDEzCCAfugAwIBAgIURiMaUmhI1Xr0mZ4p+JmI0XjZTaIwDQYJKoZIhvcNAQEL -BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTE3MTAzMDEyMDUwMFoXDTQwMDEw -MTAwMDAwMFowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF -AAOCAQ8AMIIBCgKCAQEA26DcKAxqdWivhS/J3Klf+cEnrT2cDzLhmVRCHuQZXiIr -tqr5401KDbRTVOg8v2qIyd8x4+YbpE47JP3fBrcMey70UK/Er8nu28RY3z7gZLLi -Yf+obHdDFCK5JaCGmM61I0c0vp7aMXsyv7h3vjEzTuBMlKR8p37ftaXSUAe3Qk/D -/fzA3k02E2e3ap0Sapd/wUu/0n/MFyy9HkkeykivAzLaaFhhvp3hATdFYC4FLld8 -OMB60bC2S13CAljpMlpjU/XLLOUbaPgnNUqE1nFqFBoTl6kV6+ii8Dd5ENVvE7pE -SoNoyGLDUkDRJJMNUHAo0zbxyhd7WOtyZ7B4YBbPswIDAQABo10wWzBLBgNVHREE -RDBCgglsb2NhbGhvc3SCC2V4YW1wbGUuY29tgRB1c2VyQGV4YW1wbGUuY29thwTA -qAABhxAgAQ24AAAAAAAAAAAAAAABMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQEL -BQADggEBACYBArIoL9ZzVX3M+WmTD5epmGEffrH7diRJZsfpVXi86brBPrbvpTBx -Fa+ZKxBAchPnWn4rxoWVJmTm4WYqZljek7oQKzidu88rMTbsxHA+/qyVPVlQ898I -hgnW4h3FFapKOFqq5Hj2gKKItFIcGoVY2oLTBFkyfAx0ofromGQp3fh58KlPhC0W -GX1nFCea74mGyq60X86aEWiyecYYj5AEcaDrTnGg3HLGTsD3mh8SUZPAda13rO4+ -RGtGsA1C9Yovlu9a6pWLgephYJ73XYPmRIGgM64fkUbSuvXNJMYbWnzpoCdW6hka -IEaDUul/WnIkn/JZx8n+wgoWtyQa4EA= ------END CERTIFICATE----- -""" + -----BEGIN CERTIFICATE----- + MIIDEzCCAfugAwIBAgIURiMaUmhI1Xr0mZ4p+JmI0XjZTaIwDQYJKoZIhvcNAQEL + BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTE3MTAzMDEyMDUwMFoXDTQwMDEw + MTAwMDAwMFowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF + AAOCAQ8AMIIBCgKCAQEA26DcKAxqdWivhS/J3Klf+cEnrT2cDzLhmVRCHuQZXiIr + tqr5401KDbRTVOg8v2qIyd8x4+YbpE47JP3fBrcMey70UK/Er8nu28RY3z7gZLLi + Yf+obHdDFCK5JaCGmM61I0c0vp7aMXsyv7h3vjEzTuBMlKR8p37ftaXSUAe3Qk/D + /fzA3k02E2e3ap0Sapd/wUu/0n/MFyy9HkkeykivAzLaaFhhvp3hATdFYC4FLld8 + OMB60bC2S13CAljpMlpjU/XLLOUbaPgnNUqE1nFqFBoTl6kV6+ii8Dd5ENVvE7pE + SoNoyGLDUkDRJJMNUHAo0zbxyhd7WOtyZ7B4YBbPswIDAQABo10wWzBLBgNVHREE + RDBCgglsb2NhbGhvc3SCC2V4YW1wbGUuY29tgRB1c2VyQGV4YW1wbGUuY29thwTA + qAABhxAgAQ24AAAAAAAAAAAAAAABMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQEL + BQADggEBACYBArIoL9ZzVX3M+WmTD5epmGEffrH7diRJZsfpVXi86brBPrbvpTBx + Fa+ZKxBAchPnWn4rxoWVJmTm4WYqZljek7oQKzidu88rMTbsxHA+/qyVPVlQ898I + hgnW4h3FFapKOFqq5Hj2gKKItFIcGoVY2oLTBFkyfAx0ofromGQp3fh58KlPhC0W + GX1nFCea74mGyq60X86aEWiyecYYj5AEcaDrTnGg3HLGTsD3mh8SUZPAda13rO4+ + RGtGsA1C9Yovlu9a6pWLgephYJ73XYPmRIGgM64fkUbSuvXNJMYbWnzpoCdW6hka + IEaDUul/WnIkn/JZx8n+wgoWtyQa4EA= + -----END CERTIFICATE----- + """ let multiCNCert = """ ------BEGIN CERTIFICATE----- -MIIDLjCCAhagAwIBAgIUR6eOMdEFZAqorykK6u6rwPGfsh0wDQYJKoZIhvcNAQEL -BQAwSDELMAkGA1UEBhMCVVMxEjAQBgNVBAMMCUlnbm9yZSBtZTERMA8GA1UECAwI -TmVicmFza2ExEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0xNzExMDIxMzM5MjRaFw00 -MDAxMDEwMDAwMDBaMEgxCzAJBgNVBAYTAlVTMRIwEAYDVQQDDAlJZ25vcmUgbWUx -ETAPBgNVBAgMCE5lYnJhc2thMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqG -SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCb/wE6/pF40KmF4bgtrlInWIojsDma08q7 -cK9LpzifjYNTrlTv7+8tR3TRkWwThW4sMGckq9u1Bty9aF50sazBZaLDZYoamuHS -43T7hj4aX++lEq+inlXaNX3WmKkq0y0ANLBsXaLC+8J+xemlXErBsacK1Lz8Yz// -lVOwD85LG6UN87j8L/L5+t922HyGhQRVTvcbmXa05JovMXILXnoUeEvNteZZtLa0 -zcpO+9pN/VwmxVOnQncxTG81FV6Qypx7YFf16QyEDVkXrt7/l6k+I+sAzBHIn28Y -cPq/HfcAbWPU+gMiCLCplDi5NCyL7yyiG7bEjxR0oiWhzZG1abgjAgMBAAGjEDAO -MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggEBAFAknMMePElmNsuzEUWO -m2a6n/cHEaJzDEVLbFifcCUNU2U6o2bgXrJIBjFudISYPjpG+gmnuAwdfu6CA63M -wiuLaLQASz6W12pRqlIriUazDn4JnIHu8wCHj8QkYTV7HunhtGJjX7xT89dRS5Y/ -IJv0Q9J2CZ16d3ETCzWp2Djq1IPggkBrsgKalJmwsiWi8UkH/GeMA+YQ1p8r9Bvp -+Jd1VitqxJFG5tgT68dq1LxlsNb4L1Cm15m8LdhY5BgSO2AG9G4gBbO0ixZJwHbn -TLiPC0Jd3x5tf9qeSv1eWHuhQd9R908EhZdC6rgN8fZfMux2tQxNbIsNPYAQhmsB -/nc= ------END CERTIFICATE----- -""" + -----BEGIN CERTIFICATE----- + MIIDLjCCAhagAwIBAgIUR6eOMdEFZAqorykK6u6rwPGfsh0wDQYJKoZIhvcNAQEL + BQAwSDELMAkGA1UEBhMCVVMxEjAQBgNVBAMMCUlnbm9yZSBtZTERMA8GA1UECAwI + TmVicmFza2ExEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0xNzExMDIxMzM5MjRaFw00 + MDAxMDEwMDAwMDBaMEgxCzAJBgNVBAYTAlVTMRIwEAYDVQQDDAlJZ25vcmUgbWUx + ETAPBgNVBAgMCE5lYnJhc2thMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqG + SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCb/wE6/pF40KmF4bgtrlInWIojsDma08q7 + cK9LpzifjYNTrlTv7+8tR3TRkWwThW4sMGckq9u1Bty9aF50sazBZaLDZYoamuHS + 43T7hj4aX++lEq+inlXaNX3WmKkq0y0ANLBsXaLC+8J+xemlXErBsacK1Lz8Yz// + lVOwD85LG6UN87j8L/L5+t922HyGhQRVTvcbmXa05JovMXILXnoUeEvNteZZtLa0 + zcpO+9pN/VwmxVOnQncxTG81FV6Qypx7YFf16QyEDVkXrt7/l6k+I+sAzBHIn28Y + cPq/HfcAbWPU+gMiCLCplDi5NCyL7yyiG7bEjxR0oiWhzZG1abgjAgMBAAGjEDAO + MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggEBAFAknMMePElmNsuzEUWO + m2a6n/cHEaJzDEVLbFifcCUNU2U6o2bgXrJIBjFudISYPjpG+gmnuAwdfu6CA63M + wiuLaLQASz6W12pRqlIriUazDn4JnIHu8wCHj8QkYTV7HunhtGJjX7xT89dRS5Y/ + IJv0Q9J2CZ16d3ETCzWp2Djq1IPggkBrsgKalJmwsiWi8UkH/GeMA+YQ1p8r9Bvp + +Jd1VitqxJFG5tgT68dq1LxlsNb4L1Cm15m8LdhY5BgSO2AG9G4gBbO0ixZJwHbn + TLiPC0Jd3x5tf9qeSv1eWHuhQd9R908EhZdC6rgN8fZfMux2tQxNbIsNPYAQhmsB + /nc= + -----END CERTIFICATE----- + """ let noCNCert = """ ------BEGIN CERTIFICATE----- -MIIC3jCCAcagAwIBAgIUeB9gFXDDe/kTcsPGlHIZ4M+SpyYwDQYJKoZIhvcNAQEL -BQAwIDELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE5lYnJhc2thMB4XDTE3MTEwMjEz -NDIwMFoXDTQwMDEwMTAwMDAwMFowIDELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE5l -YnJhc2thMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2DqRr+tIXVXz -4VZA5dSJo4pPgC+lNngg8Bpk9pedmOj8GSdvbIkRmXPRqOIw33vurfGVqcYiX3DH -HcVKS6ZF/ylE4dDH7JmGvCYpJTK6+02nkpdz3CzoX8lIRHBSJAJwny/UK20QBhsU -OWm/mD0uCRfgfp9FasKqA56OBFGNYAOTAM33RHuXQNSSfV5FmSmNkWsiM1S+EUgH -PptKQlXUfiSUFBCuyy9iItSg2fOew3C6/dXJ47T4mFi5qD/WKmI3uSNqBKNPcHI8 -EGZX4r8w0Hvq2hV13t+hexaLkS6VeZWb1kTrdgDPnjcl43txePPP7tEGRlZFO+bI -V2j0pGb/iwIDAQABoxAwDjAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IB -AQC27ElJn7TWhr2WcPsdXxGNUpepFgXEsEAVnoiJPI9XqXdOZCFWTUmRXrQICPUn -8HnVfYTFl/WZnTYhf8Ky5RB1W3X0Juo7MGge7mx6D6m8yJVBecQxPasVienTvdDg -UZI2oodxnS7egFwlvFM2ZUmPLVvq0B7VQBSa2Ix3FChNtJ1u5yfHyoDUMRfYl0bF -0B3poAgLDW3FUQ7QoErMvslUJrFxmJXUKKdhg9z6jQTdcmZ6Dr8sFZQkRADbJRzm -AYqSreeyevxdoNwQrpZMAGm61nc7OS8i0Q0JRe3FpGD29BMS0ystlzDeNnUpf+yJ -u9dFQrCkq8MilGSO1L2bZsqY ------END CERTIFICATE----- -""" + -----BEGIN CERTIFICATE----- + MIIC3jCCAcagAwIBAgIUeB9gFXDDe/kTcsPGlHIZ4M+SpyYwDQYJKoZIhvcNAQEL + BQAwIDELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE5lYnJhc2thMB4XDTE3MTEwMjEz + NDIwMFoXDTQwMDEwMTAwMDAwMFowIDELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE5l + YnJhc2thMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2DqRr+tIXVXz + 4VZA5dSJo4pPgC+lNngg8Bpk9pedmOj8GSdvbIkRmXPRqOIw33vurfGVqcYiX3DH + HcVKS6ZF/ylE4dDH7JmGvCYpJTK6+02nkpdz3CzoX8lIRHBSJAJwny/UK20QBhsU + OWm/mD0uCRfgfp9FasKqA56OBFGNYAOTAM33RHuXQNSSfV5FmSmNkWsiM1S+EUgH + PptKQlXUfiSUFBCuyy9iItSg2fOew3C6/dXJ47T4mFi5qD/WKmI3uSNqBKNPcHI8 + EGZX4r8w0Hvq2hV13t+hexaLkS6VeZWb1kTrdgDPnjcl43txePPP7tEGRlZFO+bI + V2j0pGb/iwIDAQABoxAwDjAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IB + AQC27ElJn7TWhr2WcPsdXxGNUpepFgXEsEAVnoiJPI9XqXdOZCFWTUmRXrQICPUn + 8HnVfYTFl/WZnTYhf8Ky5RB1W3X0Juo7MGge7mx6D6m8yJVBecQxPasVienTvdDg + UZI2oodxnS7egFwlvFM2ZUmPLVvq0B7VQBSa2Ix3FChNtJ1u5yfHyoDUMRfYl0bF + 0B3poAgLDW3FUQ7QoErMvslUJrFxmJXUKKdhg9z6jQTdcmZ6Dr8sFZQkRADbJRzm + AYqSreeyevxdoNwQrpZMAGm61nc7OS8i0Q0JRe3FpGD29BMS0ystlzDeNnUpf+yJ + u9dFQrCkq8MilGSO1L2bZsqY + -----END CERTIFICATE----- + """ let unicodeCNCert = """ ------BEGIN CERTIFICATE----- -MIICyjCCAbKgAwIBAgIUeK7KUVK7tcUhxVnkSWEsqHj07TEwDQYJKoZIhvcNAQEL -BQAwFjEUMBIGA1UEAwwLc3RyYcOfZS5vcmcwHhcNMTcxMTAyMTM0NzQxWhcNNDAw -MTAxMDAwMDAwWjAWMRQwEgYDVQQDDAtzdHJhw59lLm9yZzCCASIwDQYJKoZIhvcN -AQEBBQADggEPADCCAQoCggEBAO0Anpw+WpM897YXUNHI4oTr4BUxIcOC2A7LQiQ0 -briNXLIaIN8irwaa4TwCqvjg2B09GGO7EWvi0EX050X0jFFiSDdGhSZGMLL34nfk -/HW14XjTCW+LkYcFAyOD8Kf3nGGLagIdtnPWQ3Atf6rTf5A35K75+penURN226xB -t0vKqtngYTFu0n6B/+Ip6FI/Bq8yyGtPN74yR79KG3WL7mvrEHxv+TnZkb2F6f2j -cJALEJPx8wFug154EnRDOURZMX5gmHRR/Xm9jP1R7Rch+4Ue2Fy38C1a35p0Saap -JDKSmxr2430bQ5S41BTT5Q3N6eBD7f+cqaQyoa0u+qvl+gcCAwEAAaMQMA4wDAYD -VR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAQEAM7x+J+A2UN+RCKEjJUc9rM3S -G9AxfhKO3VN1mrPRs6JG1ED7t/9e2xdjLRRl84Rz9jnaKVTS2sQ8yKYejWGUbXDq -WO6KNlrjzspL3M8EIoi7QNwtRktviCkkxxwhzDfuH9N6ncjq0qod0vxGq0nqxrAo -VJto6NnrshZEQHGF8uipOFPNTDAR0SpzyzXaK59oqSPJ5VrZiQ3p8izVuRE9r1u2 -i5PCcPYi39q101UIxV/WokS0mqHx/XuTYTwhWYd/C49OnM8MLZOUJd8w0VvS0ItY -/wAv4vk0ScS4KmXTJBBGSiBqLdroaM9VKcA1p7TN0vzlut2E/nKmBhgzQJFKZA== ------END CERTIFICATE----- -""" + -----BEGIN CERTIFICATE----- + MIICyjCCAbKgAwIBAgIUeK7KUVK7tcUhxVnkSWEsqHj07TEwDQYJKoZIhvcNAQEL + BQAwFjEUMBIGA1UEAwwLc3RyYcOfZS5vcmcwHhcNMTcxMTAyMTM0NzQxWhcNNDAw + MTAxMDAwMDAwWjAWMRQwEgYDVQQDDAtzdHJhw59lLm9yZzCCASIwDQYJKoZIhvcN + AQEBBQADggEPADCCAQoCggEBAO0Anpw+WpM897YXUNHI4oTr4BUxIcOC2A7LQiQ0 + briNXLIaIN8irwaa4TwCqvjg2B09GGO7EWvi0EX050X0jFFiSDdGhSZGMLL34nfk + /HW14XjTCW+LkYcFAyOD8Kf3nGGLagIdtnPWQ3Atf6rTf5A35K75+penURN226xB + t0vKqtngYTFu0n6B/+Ip6FI/Bq8yyGtPN74yR79KG3WL7mvrEHxv+TnZkb2F6f2j + cJALEJPx8wFug154EnRDOURZMX5gmHRR/Xm9jP1R7Rch+4Ue2Fy38C1a35p0Saap + JDKSmxr2430bQ5S41BTT5Q3N6eBD7f+cqaQyoa0u+qvl+gcCAwEAAaMQMA4wDAYD + VR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAQEAM7x+J+A2UN+RCKEjJUc9rM3S + G9AxfhKO3VN1mrPRs6JG1ED7t/9e2xdjLRRl84Rz9jnaKVTS2sQ8yKYejWGUbXDq + WO6KNlrjzspL3M8EIoi7QNwtRktviCkkxxwhzDfuH9N6ncjq0qod0vxGq0nqxrAo + VJto6NnrshZEQHGF8uipOFPNTDAR0SpzyzXaK59oqSPJ5VrZiQ3p8izVuRE9r1u2 + i5PCcPYi39q101UIxV/WokS0mqHx/XuTYTwhWYd/C49OnM8MLZOUJd8w0VvS0ItY + /wAv4vk0ScS4KmXTJBBGSiBqLdroaM9VKcA1p7TN0vzlut2E/nKmBhgzQJFKZA== + -----END CERTIFICATE----- + """ // created with the following command: // openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes \ @@ -110,37 +111,37 @@ i5PCcPYi39q101UIxV/WokS0mqHx/XuTYTwhWYd/C49OnM8MLZOUJd8w0VvS0ItY // -config <(echo '[req]'; echo 'distinguished_name=req'; // echo '[san]'; echo 'subjectAltName=DNS:localhost,DNS:example.com,email:user@example.com,IP:192.168.0.1,IP:2001:db8::1,URI:http://example.com/path?query=param,URI:http://example.org/') let certWithAllSupportedSANTypes = """ ------BEGIN CERTIFICATE----- -MIIFOzCCAyOgAwIBAgIJALPXfgvEjcDsMA0GCSqGSIb3DQEBCwUAMBYxFDASBgNV -BAMMC2V4YW1wbGUuY29tMB4XDTIyMDMwOTE4MTIxN1oXDTMyMDMwNjE4MTIxN1ow -FjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw -ggIKAoICAQC7Bwqt8H+O3zotsGo4KMjipytzfmYiTOS0Id6HY1zfLVGrOSRTbFAE -BmpPWbu4TzDZpxoNa6oQYqcpMqHTJe6+U/Coz+Xm+fSqWVZPLzcX2iW6igeS5cH5 -2C9sWbzbYJku3qiNc0B0K+sIPQLeUM8sc2UK6rL3Vc6kt/SRRjshZNj6hPRqQNv6 -85ul6yxICOooX6Xy/q0lqJaWaIOk2GZa/Genz/93RbKnLCpynSX0JETcIW8uFIPo -3BeyFcvgThYUq/KvpkkNPqOp7SOfO5rFLi9IRlDNuUF9h4hLZ+qV3NaxQ5mk+8xl -BcNPDNqucNwQ7UKRNEfipmVPE44txMh06VcahcSzc+FKGsQmlNON0WwMfTTRhCPD -Y2JVKZ5BpsgUtrivC4UbNmNJEVQQ9dJBcsALuwhoJo5CL0tkI2Dx/eo6fpwL6KDu -ZE71MZ8BSJ8fW620fGedR+Cr+Jeq5H5eGGaWw55hXRKHbOQgjvIC6LKp9CB4/wNK -jwlWEgae/EiI7iCuSOLj+yGbWvCnUcYdzYxuxZMY1x097dXxWObzJHgHllIT8639 -LqDT7+Xrhqoe0eMxeYwHzE8VMEPPpBeZAGzYO1lXF2lWqzIaPHK2oIeNj8Rskzqd -GFJPSvTZqEUBxgITiz5Ba46G9Cyi4oVom5CIPI+UWBLxDLjUiDbYtQIDAQABo4GL -MIGIMIGFBgNVHREEfjB8gglsb2NhbGhvc3SCC2V4YW1wbGUuY29tgRB1c2VyQGV4 -YW1wbGUuY29thwTAqAABhxAgAQ24AAAAAAAAAAAAAAABhiNodHRwOi8vZXhhbXBs -ZS5jb20vcGF0aD9xdWVyeT1wYXJhbYYTaHR0cDovL2V4YW1wbGUub3JnLzANBgkq -hkiG9w0BAQsFAAOCAgEAJFzzbzD5+YGnX2cXKms9ZSqzdFyzkU1/Glc4gCJJu0ch -GxdqRA1D9eiYtaumtnTwdN/VsJGtHQy87ur+9hawQ7MwA8E45RJoibwT/trCggzK -gjWeor9l1ahwr4eBgmmWDzmdUXd2HcCBRR5iXfU3CLj8BUT2EXx8iFbkHHc5uZGi -19ZfyAaWBV5KkkMjk9FMYAoFCsv/eDjtQzlfJrgKDcAZu7GD7ijYcw2buGeRl9SG -//QKkyAVEnY2Fpn0v+pwOWBunB4EV2bRK+TbSScaU0EC3+AT9Xl62IAqJsdmTOrr -URM7cuo6HVFLhNbAsUZMwd/orLQmKnp+njZOKdcq+J8f3aIUhKBIKg+sYcFVpV1Z -Mpmm/M04hN+EGuZqASJRfIE1CI5PXizVd6sQd1A/zhoy9QtfbVGgxWklYgmy7ycB -wS41t3bU8LLCC3RXflBOBz4y+/7Oe6muRWUAEXt4rgc4Zv391SfIFpwEaNOtFATl -LzVcCAEmtY1Fyp4cOm6GEMjZ0H0buOaCRoYJb3KYZm5L6c58Ahom2GfAdtdoiRcX -7JHZybbOiOTgThxfXxgzABq/HVLC5PNVlAk95SYcoFMjixyDt2S9JD9fnGI3H9CT -kVuVyNH7NBMh6YOuTL1dh55bvDjvgkuzudepsZnpfjgQKE1aZ7dL32Xi000gBM8= ------END CERTIFICATE----- -""" + -----BEGIN CERTIFICATE----- + MIIFOzCCAyOgAwIBAgIJALPXfgvEjcDsMA0GCSqGSIb3DQEBCwUAMBYxFDASBgNV + BAMMC2V4YW1wbGUuY29tMB4XDTIyMDMwOTE4MTIxN1oXDTMyMDMwNjE4MTIxN1ow + FjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw + ggIKAoICAQC7Bwqt8H+O3zotsGo4KMjipytzfmYiTOS0Id6HY1zfLVGrOSRTbFAE + BmpPWbu4TzDZpxoNa6oQYqcpMqHTJe6+U/Coz+Xm+fSqWVZPLzcX2iW6igeS5cH5 + 2C9sWbzbYJku3qiNc0B0K+sIPQLeUM8sc2UK6rL3Vc6kt/SRRjshZNj6hPRqQNv6 + 85ul6yxICOooX6Xy/q0lqJaWaIOk2GZa/Genz/93RbKnLCpynSX0JETcIW8uFIPo + 3BeyFcvgThYUq/KvpkkNPqOp7SOfO5rFLi9IRlDNuUF9h4hLZ+qV3NaxQ5mk+8xl + BcNPDNqucNwQ7UKRNEfipmVPE44txMh06VcahcSzc+FKGsQmlNON0WwMfTTRhCPD + Y2JVKZ5BpsgUtrivC4UbNmNJEVQQ9dJBcsALuwhoJo5CL0tkI2Dx/eo6fpwL6KDu + ZE71MZ8BSJ8fW620fGedR+Cr+Jeq5H5eGGaWw55hXRKHbOQgjvIC6LKp9CB4/wNK + jwlWEgae/EiI7iCuSOLj+yGbWvCnUcYdzYxuxZMY1x097dXxWObzJHgHllIT8639 + LqDT7+Xrhqoe0eMxeYwHzE8VMEPPpBeZAGzYO1lXF2lWqzIaPHK2oIeNj8Rskzqd + GFJPSvTZqEUBxgITiz5Ba46G9Cyi4oVom5CIPI+UWBLxDLjUiDbYtQIDAQABo4GL + MIGIMIGFBgNVHREEfjB8gglsb2NhbGhvc3SCC2V4YW1wbGUuY29tgRB1c2VyQGV4 + YW1wbGUuY29thwTAqAABhxAgAQ24AAAAAAAAAAAAAAABhiNodHRwOi8vZXhhbXBs + ZS5jb20vcGF0aD9xdWVyeT1wYXJhbYYTaHR0cDovL2V4YW1wbGUub3JnLzANBgkq + hkiG9w0BAQsFAAOCAgEAJFzzbzD5+YGnX2cXKms9ZSqzdFyzkU1/Glc4gCJJu0ch + GxdqRA1D9eiYtaumtnTwdN/VsJGtHQy87ur+9hawQ7MwA8E45RJoibwT/trCggzK + gjWeor9l1ahwr4eBgmmWDzmdUXd2HcCBRR5iXfU3CLj8BUT2EXx8iFbkHHc5uZGi + 19ZfyAaWBV5KkkMjk9FMYAoFCsv/eDjtQzlfJrgKDcAZu7GD7ijYcw2buGeRl9SG + //QKkyAVEnY2Fpn0v+pwOWBunB4EV2bRK+TbSScaU0EC3+AT9Xl62IAqJsdmTOrr + URM7cuo6HVFLhNbAsUZMwd/orLQmKnp+njZOKdcq+J8f3aIUhKBIKg+sYcFVpV1Z + Mpmm/M04hN+EGuZqASJRfIE1CI5PXizVd6sQd1A/zhoy9QtfbVGgxWklYgmy7ycB + wS41t3bU8LLCC3RXflBOBz4y+/7Oe6muRWUAEXt4rgc4Zv391SfIFpwEaNOtFATl + LzVcCAEmtY1Fyp4cOm6GEMjZ0H0buOaCRoYJb3KYZm5L6c58Ahom2GfAdtdoiRcX + 7JHZybbOiOTgThxfXxgzABq/HVLC5PNVlAk95SYcoFMjixyDt2S9JD9fnGI3H9CT + kVuVyNH7NBMh6YOuTL1dh55bvDjvgkuzudepsZnpfjgQKE1aZ7dL32Xi000gBM8= + -----END CERTIFICATE----- + """ func makeTemporaryFile(fileExtension: String = "", customPath: String = "") throws -> String { var template = "\(FileManager.default.temporaryDirectory.path)/niotestXXXXXXX\(fileExtension)" @@ -153,7 +154,7 @@ func makeTemporaryFile(fileExtension: String = "", customPath: String = "") thro var templateBytes = template.utf8 + [0] let fd = templateBytes.withUnsafeMutableBufferPointer { ptr in ptr.baseAddress!.withMemoryRebound(to: Int8.self, capacity: ptr.count) { (ptr: UnsafeMutablePointer) in - return mkstemps(ptr, CInt(fileExtension.utf8.count)) + mkstemps(ptr, CInt(fileExtension.utf8.count)) } } close(fd) @@ -161,14 +162,14 @@ func makeTemporaryFile(fileExtension: String = "", customPath: String = "") thro return String(decoding: templateBytes, as: UTF8.self) } -internal func dumpToFile(data: Data, fileExtension: String = "", customPath: String = "") throws -> String { +internal func dumpToFile(data: Data, fileExtension: String = "", customPath: String = "") throws -> String { let filename = try makeTemporaryFile(fileExtension: fileExtension, customPath: customPath) try data.write(to: URL(fileURLWithPath: filename)) return filename } internal func dumpToFile(text: String, fileExtension: String = "") throws -> String { - return try dumpToFile(data: text.data(using: .utf8)!, fileExtension: fileExtension) + try dumpToFile(data: text.data(using: .utf8)!, fileExtension: fileExtension) } class SSLCertificateTest: XCTestCase { @@ -284,15 +285,15 @@ class SSLCertificateTest: XCTestCase { func testLoadingGibberishFromMemoryAsPemFails() throws { let keyBytes: [UInt8] = [1, 2, 3] - - XCTAssertThrowsError(try NIOSSLCertificate(bytes: keyBytes, format: .pem)) {error in + + XCTAssertThrowsError(try NIOSSLCertificate(bytes: keyBytes, format: .pem)) { error in XCTAssertEqual(.failedToLoadCertificate, error as? NIOSSLError) } } func testLoadingGibberishFromPEMBufferFails() throws { let keyBytes: [UInt8] = [1, 2, 3] - XCTAssertThrowsError(try NIOSSLCertificate.fromPEMBytes(keyBytes)) {error in + XCTAssertThrowsError(try NIOSSLCertificate.fromPEMBytes(keyBytes)) { error in XCTAssertEqual(.failedToLoadCertificate, error as? NIOSSLError) } } @@ -300,7 +301,7 @@ class SSLCertificateTest: XCTestCase { func testLoadingGibberishFromMemoryAsDerFails() throws { let keyBytes: [UInt8] = [1, 2, 3] - XCTAssertThrowsError(try NIOSSLCertificate(bytes: keyBytes, format: .der)) {error in + XCTAssertThrowsError(try NIOSSLCertificate(bytes: keyBytes, format: .der)) { error in XCTAssertEqual(.failedToLoadCertificate, error as? NIOSSLError) } } @@ -310,8 +311,8 @@ class SSLCertificateTest: XCTestCase { defer { _ = tempFile.withCString { unlink($0) } } - - XCTAssertThrowsError(try NIOSSLCertificate(file: tempFile, format: .pem)) {error in + + XCTAssertThrowsError(try NIOSSLCertificate(file: tempFile, format: .pem)) { error in XCTAssertEqual(.failedToLoadCertificate, error as? NIOSSLError) } } @@ -322,7 +323,7 @@ class SSLCertificateTest: XCTestCase { _ = tempFile.withCString { unlink($0) } } - XCTAssertThrowsError(try NIOSSLCertificate.fromPEMFile(tempFile)) {error in + XCTAssertThrowsError(try NIOSSLCertificate.fromPEMFile(tempFile)) { error in XCTAssertEqual(.failedToLoadCertificate, error as? NIOSSLError) } } @@ -333,7 +334,7 @@ class SSLCertificateTest: XCTestCase { _ = tempFile.withCString { unlink($0) } } - XCTAssertThrowsError(try NIOSSLCertificate(file: tempFile, format: .der)) {error in + XCTAssertThrowsError(try NIOSSLCertificate(file: tempFile, format: .der)) { error in XCTAssertEqual(.failedToLoadCertificate, error as? NIOSSLError) } } @@ -353,13 +354,13 @@ class SSLCertificateTest: XCTestCase { } func testLoadingNonexistentPEMFile() throws { - XCTAssertThrowsError(try NIOSSLCertificate.fromPEMFile("/nonexistent/path")) {error in + XCTAssertThrowsError(try NIOSSLCertificate.fromPEMFile("/nonexistent/path")) { error in XCTAssertEqual(.failedToLoadCertificate, error as? NIOSSLError) } } func testLoadingNonexistentFileAsDer() throws { - XCTAssertThrowsError(try NIOSSLCertificate(file: "/nonexistent/path", format: .der)) {error in + XCTAssertThrowsError(try NIOSSLCertificate(file: "/nonexistent/path", format: .der)) { error in guard let error = error as? IOError else { return XCTFail("unexpected error \(error)") } @@ -453,17 +454,19 @@ class SSLCertificateTest: XCTestCase { XCTAssertEqual(certBytes, expectedCertBytes) } - + func testPrintingDebugDetailsNoAlternativeNames() throws { - let expectedDebugDescription = "" + let expectedDebugDescription = + "" let cert = try assertNoThrowWithValue(NIOSSLCertificate(bytes: .init(samplePemCert.utf8), format: .pem)) let debugString = String(describing: cert) XCTAssertEqual(debugString, expectedDebugDescription) } - + func testPrintingDebugDetailsWithAlternativeNames() throws { - let expectedDebugDescription = "" + let expectedDebugDescription = + "" let cert = try assertNoThrowWithValue(NIOSSLCertificate(bytes: .init(multiSanCert.utf8), format: .pem)) let debugString = String(describing: cert) diff --git a/Tests/NIOSSLTests/SSLContextTests.swift b/Tests/NIOSSLTests/SSLContextTests.swift index 7994647e8..c0ce89158 100644 --- a/Tests/NIOSSLTests/SSLContextTests.swift +++ b/Tests/NIOSSLTests/SSLContextTests.swift @@ -12,11 +12,12 @@ // //===----------------------------------------------------------------------===// -import XCTest import NIOCore +import NIOEmbedded import NIOPosix import NIOTLS -import NIOEmbedded +import XCTest + @testable import NIOSSL final class SSLContextTest: XCTestCase { @@ -97,22 +98,31 @@ final class SSLContextTest: XCTestCase { let serverContext = try configuredServerSSLContext(eventLoop: group.next()) let sniPromise: EventLoopPromise = group.next().makePromise() - let sniHandler = ByteToMessageHandler(SNIHandler { - sniPromise.succeed($0) - return group.next().makeSucceededFuture(()) - }) + let sniHandler = ByteToMessageHandler( + SNIHandler { + sniPromise.succeed($0) + return group.next().makeSucceededFuture(()) + } + ) - let serverChannel = try serverTLSChannel(context: serverContext, preHandlers: [sniHandler], postHandlers: [], group: group) + let serverChannel = try serverTLSChannel( + context: serverContext, + preHandlers: [sniHandler], + postHandlers: [], + group: group + ) defer { _ = try? serverChannel.close().wait() } - let clientChannel = try clientTLSChannel(context: clientContext, - preHandlers: [], - postHandlers: [handshakeWatcher], - group: group, - connectingTo: serverChannel.localAddress!, - serverHostname: sniField) + let clientChannel = try clientTLSChannel( + context: clientContext, + preHandlers: [], + postHandlers: [handshakeWatcher], + group: group, + connectingTo: serverChannel.localAddress!, + serverHostname: sniField + ) defer { _ = try? clientChannel.close().wait() } @@ -143,27 +153,33 @@ final class SSLContextTest: XCTestCase { let serverContext = try configuredServerSSLContext(eventLoop: group.next(), throwing: expectedError) let sniPromise: EventLoopPromise = group.next().makePromise() - let sniHandler = ByteToMessageHandler(SNIHandler { - sniPromise.succeed($0) - return group.next().makeSucceededFuture(()) - }) + let sniHandler = ByteToMessageHandler( + SNIHandler { + sniPromise.succeed($0) + return group.next().makeSucceededFuture(()) + } + ) let eventHandler = ErrorCatcher() - let serverChannel = try serverTLSChannel(context: serverContext, - preHandlers: [sniHandler], - postHandlers: [eventHandler], - group: group) + let serverChannel = try serverTLSChannel( + context: serverContext, + preHandlers: [sniHandler], + postHandlers: [eventHandler], + group: group + ) defer { _ = try? serverChannel.close().wait() } - let clientChannel = try clientTLSChannel(context: clientContext, - preHandlers: [], - postHandlers: [handshakeWatcher], - group: group, - connectingTo: serverChannel.localAddress!, - serverHostname: sniField) + let clientChannel = try clientTLSChannel( + context: clientContext, + preHandlers: [], + postHandlers: [handshakeWatcher], + group: group, + connectingTo: serverChannel.localAddress!, + serverHostname: sniField + ) defer { _ = try? clientChannel.close().wait() } diff --git a/Tests/NIOSSLTests/SSLPKCS12BundleTest.swift b/Tests/NIOSSLTests/SSLPKCS12BundleTest.swift index 12803f9ca..609b7c3af 100644 --- a/Tests/NIOSSLTests/SSLPKCS12BundleTest.swift +++ b/Tests/NIOSSLTests/SSLPKCS12BundleTest.swift @@ -13,417 +13,424 @@ //===----------------------------------------------------------------------===// import Foundation -import XCTest import NIOCore -@testable import NIOSSL +import XCTest +@testable import NIOSSL /// This is a base64-PKCS12 file that contains only samplePemCert and /// samplePemKey, no extra certs. The passphrase is /// "thisisagreatpassword". let base64EncodedSimpleP12 = """ -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 + """ /// This is a base64-PKCS12 file that contains samplePemCert and /// samplePemKey as the main cert and key, and then extra certs /// multiSanCert, multiCNCert, noCNCert, and unicodeCNCert. The /// passphrase is "thisisagreatpassword". let base64EncodedComplexP12 = """ -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 -qQICCAA= -""" + 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 + qQICCAA= + """ let base64EncodedNoPassP12 = """ -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 + """ var simpleP12: [UInt8] { - return Array(Data(base64Encoded: base64EncodedSimpleP12, options: .ignoreUnknownCharacters)!) + Array(Data(base64Encoded: base64EncodedSimpleP12, options: .ignoreUnknownCharacters)!) } - var complexP12: [UInt8] { - return Array(Data(base64Encoded: base64EncodedComplexP12, options: .ignoreUnknownCharacters)!) + Array(Data(base64Encoded: base64EncodedComplexP12, options: .ignoreUnknownCharacters)!) } - var noPassP12: [UInt8] { - return Array(Data(base64Encoded: base64EncodedNoPassP12, options: .ignoreUnknownCharacters)!) + Array(Data(base64Encoded: base64EncodedNoPassP12, options: .ignoreUnknownCharacters)!) } - class SSLPKCS12BundleTest: XCTestCase { static var simpleFilePath: String! = nil static var complexFilePath: String! = nil static var noPassFilePath: String! = nil override class func setUp() { - SSLPKCS12BundleTest.simpleFilePath = try! dumpToFile(data: Data(base64Encoded: base64EncodedSimpleP12, - options: .ignoreUnknownCharacters)!) - SSLPKCS12BundleTest.complexFilePath = try! dumpToFile(data: Data(base64Encoded: base64EncodedComplexP12, - options: .ignoreUnknownCharacters)!) - SSLPKCS12BundleTest.noPassFilePath = try! dumpToFile(data: Data(base64Encoded: base64EncodedNoPassP12, - options: .ignoreUnknownCharacters)!) + SSLPKCS12BundleTest.simpleFilePath = try! dumpToFile( + data: Data( + base64Encoded: base64EncodedSimpleP12, + options: .ignoreUnknownCharacters + )! + ) + SSLPKCS12BundleTest.complexFilePath = try! dumpToFile( + data: Data( + base64Encoded: base64EncodedComplexP12, + options: .ignoreUnknownCharacters + )! + ) + SSLPKCS12BundleTest.noPassFilePath = try! dumpToFile( + data: Data( + base64Encoded: base64EncodedNoPassP12, + options: .ignoreUnknownCharacters + )! + ) } override class func tearDown() { @@ -464,7 +471,10 @@ class SSLPKCS12BundleTest: XCTestCase { } func testDecodingSimpleP12FromFile() throws { - let p12Bundle = try NIOSSLPKCS12Bundle(file: SSLPKCS12BundleTest.simpleFilePath, passphrase: "thisisagreatpassword".utf8) + let p12Bundle = try NIOSSLPKCS12Bundle( + file: SSLPKCS12BundleTest.simpleFilePath, + passphrase: "thisisagreatpassword".utf8 + ) let expectedKey = try NIOSSLPrivateKey(bytes: .init(samplePemKey.utf8), format: .pem) let expectedCert = try NIOSSLCertificate(bytes: .init(samplePemCert.utf8), format: .pem) @@ -473,7 +483,10 @@ class SSLPKCS12BundleTest: XCTestCase { } func testDecodingComplexP12FromFile() throws { - let p12Bundle = try NIOSSLPKCS12Bundle(file: SSLPKCS12BundleTest.complexFilePath, passphrase: "thisisagreatpassword".utf8) + let p12Bundle = try NIOSSLPKCS12Bundle( + file: SSLPKCS12BundleTest.complexFilePath, + passphrase: "thisisagreatpassword".utf8 + ) let expectedKey = try NIOSSLPrivateKey(bytes: .init(samplePemKey.utf8), format: .pem) let expectedCert = try NIOSSLCertificate(bytes: .init(samplePemCert.utf8), format: .pem) let caOne = try NIOSSLCertificate(bytes: .init(multiSanCert.utf8), format: .pem) @@ -495,11 +508,11 @@ class SSLPKCS12BundleTest: XCTestCase { } func testDecodingNonExistentPKCS12File() throws { - XCTAssertThrowsError(try NIOSSLPKCS12Bundle(file: "/nonexistent/path")){ error in + XCTAssertThrowsError(try NIOSSLPKCS12Bundle(file: "/nonexistent/path")) { error in XCTAssertEqual(ENOENT, (error as? IOError).map { $0.errnoCode }) } } - + func testEquatableAndHashable() throws { let bundle1_a = try NIOSSLPKCS12Bundle(buffer: simpleP12, passphrase: "thisisagreatpassword".utf8) let bundle1_b = try NIOSSLPKCS12Bundle(buffer: simpleP12, passphrase: "thisisagreatpassword".utf8) @@ -507,7 +520,7 @@ class SSLPKCS12BundleTest: XCTestCase { XCTAssertEqual(bundle1_a, bundle1_a) XCTAssertEqual(bundle1_a, bundle1_b) XCTAssertNotEqual(bundle1_a, bundle2) - + let set = Set([bundle1_a, bundle1_b, bundle2]) XCTAssertEqual(set.count, 2) XCTAssertTrue(set.contains(bundle1_a)) @@ -515,4 +528,3 @@ class SSLPKCS12BundleTest: XCTestCase { XCTAssertTrue(set.contains(bundle2)) } } - diff --git a/Tests/NIOSSLTests/SSLPrivateKeyTests.swift b/Tests/NIOSSLTests/SSLPrivateKeyTests.swift index 9dd8d61f0..7ef2dfd4d 100644 --- a/Tests/NIOSSLTests/SSLPrivateKeyTests.swift +++ b/Tests/NIOSSLTests/SSLPrivateKeyTests.swift @@ -13,8 +13,9 @@ //===----------------------------------------------------------------------===// import Foundation -import XCTest import NIOCore +import XCTest + @testable import NIOSSL class SSLPrivateKeyTest: XCTestCase { @@ -25,11 +26,15 @@ class SSLPrivateKeyTest: XCTestCase { static var dynamicallyGeneratedKey: NIOSSLPrivateKey! = nil override class func setUp() { - SSLPrivateKeyTest.pemKeyFilePath = try! dumpToFile(text: samplePemKey, - fileExtension: ".pem") + SSLPrivateKeyTest.pemKeyFilePath = try! dumpToFile( + text: samplePemKey, + fileExtension: ".pem" + ) SSLPrivateKeyTest.derKeyFilePath = try! dumpToFile(data: sampleDerKey) - SSLPrivateKeyTest.passwordPemKeyFilePath = try! dumpToFile(text: samplePemRSAEncryptedKey, - fileExtension: ".pem") + SSLPrivateKeyTest.passwordPemKeyFilePath = try! dumpToFile( + text: samplePemRSAEncryptedKey, + fileExtension: ".pem" + ) SSLPrivateKeyTest.passwordPKCS8PemKeyFilePath = try! dumpToFile(text: samplePKCS8PemPrivateKey) let (_, key) = generateSelfSignedCert() @@ -146,73 +151,109 @@ class SSLPrivateKeyTest: XCTestCase { } func testLoadingNonexistentFileAsPemWithPassphrase() throws { - XCTAssertThrowsError(try NIOSSLPrivateKey(file: "/nonexistent/path", format: .pem) { (_: NIOSSLPassphraseSetter>) in - XCTFail("Should not be called") - }) { error in + XCTAssertThrowsError( + try NIOSSLPrivateKey(file: "/nonexistent/path", format: .pem) { (_: NIOSSLPassphraseSetter<[UInt8]>) in + XCTFail("Should not be called") + } + ) { error in XCTAssertEqual(ENOENT, (error as? IOError).map { $0.errnoCode }) } } func testLoadingNonexistentFileAsDerWithPassphrase() throws { - XCTAssertThrowsError(try NIOSSLPrivateKey(file: "/nonexistent/path", format: .der) { (_: NIOSSLPassphraseSetter>) in - XCTFail("Should not be called") - }) { error in + XCTAssertThrowsError( + try NIOSSLPrivateKey(file: "/nonexistent/path", format: .der) { (_: NIOSSLPassphraseSetter<[UInt8]>) in + XCTFail("Should not be called") + } + ) { error in XCTAssertEqual(ENOENT, (error as? IOError).map { $0.errnoCode }) } } func testLoadingEncryptedRSAKeyFromMemory() throws { - let key1 = try NIOSSLPrivateKey(bytes: .init(samplePemRSAEncryptedKey.utf8), format: .pem) { closure in closure("thisisagreatpassword".utf8) } - let key2 = try NIOSSLPrivateKey(bytes: .init(samplePemRSAEncryptedKey.utf8), format: .pem) { closure in closure("thisisagreatpassword".utf8) } + let key1 = try NIOSSLPrivateKey(bytes: .init(samplePemRSAEncryptedKey.utf8), format: .pem) { closure in + closure("thisisagreatpassword".utf8) + } + let key2 = try NIOSSLPrivateKey(bytes: .init(samplePemRSAEncryptedKey.utf8), format: .pem) { closure in + closure("thisisagreatpassword".utf8) + } XCTAssertEqual(key1, key2) XCTAssertEqual(key1.hashValue, key2.hashValue) } func testLoadingEncryptedRSAPKCS8KeyFromMemory() throws { - let key1 = try NIOSSLPrivateKey(bytes: .init(samplePKCS8PemPrivateKey.utf8), format: .pem) { closure in closure("thisisagreatpassword".utf8) } - let key2 = try NIOSSLPrivateKey(bytes: .init(samplePKCS8PemPrivateKey.utf8), format: .pem) { closure in closure("thisisagreatpassword".utf8) } + let key1 = try NIOSSLPrivateKey(bytes: .init(samplePKCS8PemPrivateKey.utf8), format: .pem) { closure in + closure("thisisagreatpassword".utf8) + } + let key2 = try NIOSSLPrivateKey(bytes: .init(samplePKCS8PemPrivateKey.utf8), format: .pem) { closure in + closure("thisisagreatpassword".utf8) + } XCTAssertEqual(key1, key2) XCTAssertEqual(key1.hashValue, key2.hashValue) } func testLoadingEncryptedRSAKeyFromFile() throws { - let key1 = try NIOSSLPrivateKey(file: SSLPrivateKeyTest.passwordPemKeyFilePath, format: .pem) { closure in closure("thisisagreatpassword".utf8) } - let key2 = try NIOSSLPrivateKey(file: SSLPrivateKeyTest.passwordPemKeyFilePath, format: .pem) { closure in closure("thisisagreatpassword".utf8) } + let key1 = try NIOSSLPrivateKey(file: SSLPrivateKeyTest.passwordPemKeyFilePath, format: .pem) { closure in + closure("thisisagreatpassword".utf8) + } + let key2 = try NIOSSLPrivateKey(file: SSLPrivateKeyTest.passwordPemKeyFilePath, format: .pem) { closure in + closure("thisisagreatpassword".utf8) + } XCTAssertEqual(key1, key2) XCTAssertEqual(key1.hashValue, key2.hashValue) } func testLoadingEncryptedRSAPKCS8KeyFromFile() throws { - let key1 = try NIOSSLPrivateKey(file: SSLPrivateKeyTest.passwordPKCS8PemKeyFilePath, format: .pem) { closure in closure("thisisagreatpassword".utf8) } - let key2 = try NIOSSLPrivateKey(file: SSLPrivateKeyTest.passwordPKCS8PemKeyFilePath, format: .pem) { closure in closure("thisisagreatpassword".utf8) } + let key1 = try NIOSSLPrivateKey(file: SSLPrivateKeyTest.passwordPKCS8PemKeyFilePath, format: .pem) { closure in + closure("thisisagreatpassword".utf8) + } + let key2 = try NIOSSLPrivateKey(file: SSLPrivateKeyTest.passwordPKCS8PemKeyFilePath, format: .pem) { closure in + closure("thisisagreatpassword".utf8) + } XCTAssertEqual(key1, key2) XCTAssertEqual(key1.hashValue, key2.hashValue) } func testWildlyOverlongPassphraseRSAFromMemory() throws { - XCTAssertThrowsError(try NIOSSLPrivateKey(bytes: .init(samplePemRSAEncryptedKey.utf8), format: .pem) { closure in closure(Array(repeating: UInt8(8), count: 1 << 16)) }) { error in + XCTAssertThrowsError( + try NIOSSLPrivateKey(bytes: .init(samplePemRSAEncryptedKey.utf8), format: .pem) { closure in + closure(Array(repeating: UInt8(8), count: 1 << 16)) + } + ) { error in XCTAssertEqual(.failedToLoadPrivateKey, error as? NIOSSLError) } } func testWildlyOverlongPassphrasePKCS8FromMemory() throws { - XCTAssertThrowsError(try NIOSSLPrivateKey(bytes: .init(samplePKCS8PemPrivateKey.utf8), format: .pem) { closure in closure(Array(repeating: UInt8(8), count: 1 << 16)) }) { error in + XCTAssertThrowsError( + try NIOSSLPrivateKey(bytes: .init(samplePKCS8PemPrivateKey.utf8), format: .pem) { closure in + closure(Array(repeating: UInt8(8), count: 1 << 16)) + } + ) { error in XCTAssertEqual(.failedToLoadPrivateKey, error as? NIOSSLError) } } func testWildlyOverlongPassphraseRSAFromFile() throws { - XCTAssertThrowsError(try NIOSSLPrivateKey(bytes: .init(samplePemRSAEncryptedKey.utf8), format: .pem) { closure in closure(Array(repeating: UInt8(8), count: 1 << 16)) }) { error in + XCTAssertThrowsError( + try NIOSSLPrivateKey(bytes: .init(samplePemRSAEncryptedKey.utf8), format: .pem) { closure in + closure(Array(repeating: UInt8(8), count: 1 << 16)) + } + ) { error in XCTAssertEqual(.failedToLoadPrivateKey, error as? NIOSSLError) } } func testWildlyOverlongPassphrasePKCS8FromFile() throws { - XCTAssertThrowsError(try NIOSSLPrivateKey(bytes: .init(samplePKCS8PemPrivateKey.utf8), format: .pem) { closure in closure(Array(repeating: UInt8(8), count: 1 << 16)) }) { error in + XCTAssertThrowsError( + try NIOSSLPrivateKey(bytes: .init(samplePKCS8PemPrivateKey.utf8), format: .pem) { closure in + closure(Array(repeating: UInt8(8), count: 1 << 16)) + } + ) { error in XCTAssertEqual(.failedToLoadPrivateKey, error as? NIOSSLError) } } @@ -222,17 +263,22 @@ class SSLPrivateKeyTest: XCTestCase { case error } - XCTAssertThrowsError(try NIOSSLPrivateKey(bytes: .init(samplePemRSAEncryptedKey.utf8), format: .pem) { (_: NIOSSLPassphraseSetter>) in - throw MyError.error - }) { error in + XCTAssertThrowsError( + try NIOSSLPrivateKey(bytes: .init(samplePemRSAEncryptedKey.utf8), format: .pem) { + (_: NIOSSLPassphraseSetter<[UInt8]>) in + throw MyError.error + } + ) { error in XCTAssertEqual(.failedToLoadPrivateKey, error as? NIOSSLError) } } func testWrongPassword() { - XCTAssertThrowsError(try NIOSSLPrivateKey(bytes: .init(samplePemRSAEncryptedKey.utf8), format: .pem) { - closure in closure("incorrect password".utf8) - }) { error in + XCTAssertThrowsError( + try NIOSSLPrivateKey(bytes: .init(samplePemRSAEncryptedKey.utf8), format: .pem) { + closure in closure("incorrect password".utf8) + } + ) { error in XCTAssertEqual(.failedToLoadPrivateKey, error as? NIOSSLError) } } diff --git a/Tests/NIOSSLTests/SecurityFrameworkVerificationTests.swift b/Tests/NIOSSLTests/SecurityFrameworkVerificationTests.swift index 5d2db773d..f66e29e51 100644 --- a/Tests/NIOSSLTests/SecurityFrameworkVerificationTests.swift +++ b/Tests/NIOSSLTests/SecurityFrameworkVerificationTests.swift @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// import XCTest + @testable import NIOSSL // We can only use Security.framework to validate TLS certificates on Apple platforms. @@ -133,7 +134,10 @@ final class SecurityFrameworkVerificationTests: XCTestCase { let connection = context.createConnection()! connection.setConnectState() - let certificate = SecCertificateCreateWithData(nil, Data(try! Self.anotherSelfSignedCert.toDERBytes()) as CFData)! + let certificate = SecCertificateCreateWithData( + nil, + Data(try! Self.anotherSelfSignedCert.toDERBytes()) as CFData + )! connection.performSecurityFrameworkValidation(promise: p, peerCertificates: [certificate]) let result = try p.futureResult.wait() diff --git a/Tests/NIOSSLTests/TLS13RecordObserver.swift b/Tests/NIOSSLTests/TLS13RecordObserver.swift index 45e749534..92d40ffc1 100644 --- a/Tests/NIOSSLTests/TLS13RecordObserver.swift +++ b/Tests/NIOSSLTests/TLS13RecordObserver.swift @@ -62,7 +62,9 @@ extension TLS13RecordObserver.Record { extension ByteBuffer { fileprivate mutating func readTLS13Record() -> TLS13RecordObserver.Record? { - guard let (contentType, legacyRecordVersion, length) = self.readMultipleIntegers(as: (UInt8, UInt16, UInt16).self) else { + guard + let (contentType, legacyRecordVersion, length) = self.readMultipleIntegers(as: (UInt8, UInt16, UInt16).self) + else { return nil } @@ -70,6 +72,10 @@ extension ByteBuffer { return nil } - return .init(contentType: .init(rawValue: contentType), legacyRecordVersion: legacyRecordVersion, encryptedRecord: encryptedRecord) + return .init( + contentType: .init(rawValue: contentType), + legacyRecordVersion: legacyRecordVersion, + encryptedRecord: encryptedRecord + ) } } diff --git a/Tests/NIOSSLTests/TLSConfigurationTest.swift b/Tests/NIOSSLTests/TLSConfigurationTest.swift index bd103b3f8..089ae4fd4 100644 --- a/Tests/NIOSSLTests/TLSConfigurationTest.swift +++ b/Tests/NIOSSLTests/TLSConfigurationTest.swift @@ -12,13 +12,15 @@ // //===----------------------------------------------------------------------===// -import XCTest @_implementationOnly import CNIOBoringSSL import NIOCore -import NIOPosix import NIOEmbedded -@testable import NIOSSL +import NIOPosix import NIOTLS +import XCTest + +@testable import NIOSSL + #if compiler(>=5.8) @preconcurrency import Dispatch #else @@ -53,7 +55,7 @@ class HandshakeCompletedHandler: ChannelInboundHandler { class WaitForHandshakeHandler: ChannelInboundHandler { public typealias InboundIn = Any public var handshakeResult: EventLoopFuture { - return self.handshakeResultPromise.futureResult + self.handshakeResultPromise.futureResult } private var handshakeResultPromise: EventLoopPromise @@ -95,25 +97,39 @@ class TLSConfigurationTest: XCTestCase { TLSConfigurationTest.key2 = key } - func assertHandshakeError(withClientConfig clientConfig: TLSConfiguration, - andServerConfig serverConfig: TLSConfiguration, - errorTextContains message: String, - file: StaticString = #filePath, - line: UInt = #line) throws { - return try assertHandshakeError(withClientConfig: clientConfig, - andServerConfig: serverConfig, - errorTextContainsAnyOf: [message], - file: file, - line: line) + func assertHandshakeError( + withClientConfig clientConfig: TLSConfiguration, + andServerConfig serverConfig: TLSConfiguration, + errorTextContains message: String, + file: StaticString = #filePath, + line: UInt = #line + ) throws { + try assertHandshakeError( + withClientConfig: clientConfig, + andServerConfig: serverConfig, + errorTextContainsAnyOf: [message], + file: file, + line: line + ) } - func assertHandshakeError(withClientConfig clientConfig: TLSConfiguration, - andServerConfig serverConfig: TLSConfiguration, - errorTextContainsAnyOf messages: [String], - file: StaticString = #filePath, - line: UInt = #line) throws { - let clientContext = try assertNoThrowWithValue(NIOSSLContext(configuration: clientConfig), file: file, line: line) - let serverContext = try assertNoThrowWithValue(NIOSSLContext(configuration: serverConfig), file: file, line: line) + func assertHandshakeError( + withClientConfig clientConfig: TLSConfiguration, + andServerConfig serverConfig: TLSConfiguration, + errorTextContainsAnyOf messages: [String], + file: StaticString = #filePath, + line: UInt = #line + ) throws { + let clientContext = try assertNoThrowWithValue( + NIOSSLContext(configuration: clientConfig), + file: file, + line: line + ) + let serverContext = try assertNoThrowWithValue( + NIOSSLContext(configuration: serverConfig), + file: file, + line: line + ) let group = MultiThreadedEventLoopGroup(numberOfThreads: 1) defer { @@ -122,8 +138,22 @@ class TLSConfigurationTest: XCTestCase { let eventHandler = ErrorCatcher() let handshakeHandler = HandshakeCompletedHandler() - let serverChannel = try assertNoThrowWithValue(serverTLSChannel(context: serverContext, handlers: [], group: group), file: file, line: line) - let clientChannel = try assertNoThrowWithValue(clientTLSChannel(context: clientContext, preHandlers:[], postHandlers: [eventHandler, handshakeHandler], group: group, connectingTo: serverChannel.localAddress!), file: file, line: line) + let serverChannel = try assertNoThrowWithValue( + serverTLSChannel(context: serverContext, handlers: [], group: group), + file: file, + line: line + ) + let clientChannel = try assertNoThrowWithValue( + clientTLSChannel( + context: clientContext, + preHandlers: [], + postHandlers: [eventHandler, handshakeHandler], + group: group, + connectingTo: serverChannel.localAddress! + ), + file: file, + line: line + ) // We expect the channel to be closed fairly swiftly as the handshake should fail. clientChannel.closeFuture.whenComplete { _ in @@ -142,13 +172,23 @@ class TLSConfigurationTest: XCTestCase { try clientChannel.closeFuture.wait() } - func assertPostHandshakeError(withClientConfig clientConfig: TLSConfiguration, - andServerConfig serverConfig: TLSConfiguration, - errorTextContainsAnyOf messages: [String], - file: StaticString = #filePath, - line: UInt = #line) throws { - let clientContext = try assertNoThrowWithValue(NIOSSLContext(configuration: clientConfig), file: file, line: line) - let serverContext = try assertNoThrowWithValue(NIOSSLContext(configuration: serverConfig), file: file, line: line) + func assertPostHandshakeError( + withClientConfig clientConfig: TLSConfiguration, + andServerConfig serverConfig: TLSConfiguration, + errorTextContainsAnyOf messages: [String], + file: StaticString = #filePath, + line: UInt = #line + ) throws { + let clientContext = try assertNoThrowWithValue( + NIOSSLContext(configuration: clientConfig), + file: file, + line: line + ) + let serverContext = try assertNoThrowWithValue( + NIOSSLContext(configuration: serverConfig), + file: file, + line: line + ) let group = MultiThreadedEventLoopGroup(numberOfThreads: 1) defer { @@ -157,8 +197,22 @@ class TLSConfigurationTest: XCTestCase { let eventHandler = ErrorCatcher() let handshakeHandler = HandshakeCompletedHandler() - let serverChannel = try assertNoThrowWithValue(serverTLSChannel(context: serverContext, handlers: [], group: group), file: file, line: line) - let clientChannel = try assertNoThrowWithValue(clientTLSChannel(context: clientContext, preHandlers:[], postHandlers: [eventHandler, handshakeHandler], group: group, connectingTo: serverChannel.localAddress!), file: file, line: line) + let serverChannel = try assertNoThrowWithValue( + serverTLSChannel(context: serverContext, handlers: [], group: group), + file: file, + line: line + ) + let clientChannel = try assertNoThrowWithValue( + clientTLSChannel( + context: clientContext, + preHandlers: [], + postHandlers: [eventHandler, handshakeHandler], + group: group, + connectingTo: serverChannel.localAddress! + ), + file: file, + line: line + ) // We expect the channel to be closed fairly swiftly as the handshake should fail. clientChannel.closeFuture.whenComplete { _ in @@ -182,10 +236,12 @@ class TLSConfigurationTest: XCTestCase { /// /// - NOTE: This function should only be used when you know that there is no custom verification /// callback in use, otherwise it will not be thread-safe. - func assertHandshakeSucceededInMemory(withClientConfig clientConfig: TLSConfiguration, - andServerConfig serverConfig: TLSConfiguration, - file: StaticString = #filePath, - line: UInt = #line) throws { + func assertHandshakeSucceededInMemory( + withClientConfig clientConfig: TLSConfiguration, + andServerConfig serverConfig: TLSConfiguration, + file: StaticString = #filePath, + line: UInt = #line + ) throws { let clientContext = try assertNoThrowWithValue(NIOSSLContext(configuration: clientConfig)) let serverContext = try assertNoThrowWithValue(NIOSSLContext(configuration: serverConfig)) @@ -198,8 +254,17 @@ class TLSConfigurationTest: XCTestCase { _ = try? clientChannel.finish() } - XCTAssertNoThrow(try serverChannel.pipeline.addHandler(NIOSSLServerHandler(context: serverContext)).wait(), file: (file), line: line) - XCTAssertNoThrow(try clientChannel.pipeline.addHandler(NIOSSLClientHandler(context: clientContext, serverHostname: nil)).wait(), file: (file), line: line) + XCTAssertNoThrow( + try serverChannel.pipeline.addHandler(NIOSSLServerHandler(context: serverContext)).wait(), + file: (file), + line: line + ) + XCTAssertNoThrow( + try clientChannel.pipeline.addHandler(NIOSSLClientHandler(context: clientContext, serverHostname: nil)) + .wait(), + file: (file), + line: line + ) let handshakeHandler = HandshakeCompletedHandler() XCTAssertNoThrow(try clientChannel.pipeline.addHandler(handshakeHandler).wait(), file: (file), line: line) @@ -214,12 +279,22 @@ class TLSConfigurationTest: XCTestCase { /// Performs a connection using a real event loop and validates that the handshake was successful. /// /// This function is thread-safe in the presence of custom verification callbacks. - func assertHandshakeSucceededEventLoop(withClientConfig clientConfig: TLSConfiguration, - andServerConfig serverConfig: TLSConfiguration, - file: StaticString = #filePath, - line: UInt = #line) throws { - let clientContext = try assertNoThrowWithValue(NIOSSLContext(configuration: clientConfig), file: file, line: line) - let serverContext = try assertNoThrowWithValue(NIOSSLContext(configuration: serverConfig), file: file, line: line) + func assertHandshakeSucceededEventLoop( + withClientConfig clientConfig: TLSConfiguration, + andServerConfig serverConfig: TLSConfiguration, + file: StaticString = #filePath, + line: UInt = #line + ) throws { + let clientContext = try assertNoThrowWithValue( + NIOSSLContext(configuration: clientConfig), + file: file, + line: line + ) + let serverContext = try assertNoThrowWithValue( + NIOSSLContext(configuration: serverConfig), + file: file, + line: line + ) let group = MultiThreadedEventLoopGroup(numberOfThreads: 1) defer { @@ -231,8 +306,22 @@ class TLSConfigurationTest: XCTestCase { let handshakeResultPromise = group.next().makePromise(of: Void.self) let handshakeWatcher = WaitForHandshakeHandler(handshakeResultPromise: handshakeResultPromise) - let serverChannel = try assertNoThrowWithValue(serverTLSChannel(context: serverContext, handlers: [], group: group), file: file, line: line) - let clientChannel = try assertNoThrowWithValue(clientTLSChannel(context: clientContext, preHandlers:[], postHandlers: [eventHandler, handshakeWatcher, handshakeHandler], group: group, connectingTo: serverChannel.localAddress!), file: file, line: line) + let serverChannel = try assertNoThrowWithValue( + serverTLSChannel(context: serverContext, handlers: [], group: group), + file: file, + line: line + ) + let clientChannel = try assertNoThrowWithValue( + clientTLSChannel( + context: clientContext, + preHandlers: [], + postHandlers: [eventHandler, handshakeWatcher, handshakeHandler], + group: group, + connectingTo: serverChannel.localAddress! + ), + file: file, + line: line + ) handshakeWatcher.handshakeResult.whenComplete { c in _ = clientChannel.close() @@ -245,26 +334,46 @@ class TLSConfigurationTest: XCTestCase { try clientChannel.closeFuture.wait() } - func assertHandshakeSucceeded(withClientConfig clientConfig: TLSConfiguration, - andServerConfig serverConfig: TLSConfiguration, - file: StaticString = #filePath, - line: UInt = #line) throws { + func assertHandshakeSucceeded( + withClientConfig clientConfig: TLSConfiguration, + andServerConfig serverConfig: TLSConfiguration, + file: StaticString = #filePath, + line: UInt = #line + ) throws { // The only use of a custom callback is on Darwin... #if os(Linux) - return try assertHandshakeSucceededInMemory(withClientConfig: clientConfig, andServerConfig: serverConfig, file: file, line: line) + return try assertHandshakeSucceededInMemory( + withClientConfig: clientConfig, + andServerConfig: serverConfig, + file: file, + line: line + ) #else - return try assertHandshakeSucceededEventLoop(withClientConfig: clientConfig, andServerConfig: serverConfig, file: file, line: line) + return try assertHandshakeSucceededEventLoop( + withClientConfig: clientConfig, + andServerConfig: serverConfig, + file: file, + line: line + ) #endif } - func setupTLSLeafandClientIdentitiesFromCustomCARoot() throws -> (leafCert: NIOSSLCertificate, leafKey: NIOSSLPrivateKey , - clientCert: NIOSSLCertificate, clientKey: NIOSSLPrivateKey) { + func setupTLSLeafandClientIdentitiesFromCustomCARoot() throws -> ( + leafCert: NIOSSLCertificate, leafKey: NIOSSLPrivateKey, + clientCert: NIOSSLCertificate, clientKey: NIOSSLPrivateKey + ) { let leaf = try NIOSSLCertificate(bytes: .init(leafCertificateForTLSIssuedFromCustomCARoot.utf8), format: .pem) let leaf_privateKey = try NIOSSLPrivateKey.init(bytes: .init(privateKeyForLeafCertificate.utf8), format: .pem) - let client_cert = try NIOSSLCertificate(bytes: .init(leafCertificateForClientAuthenticationIssuedFromCustomCARoot.utf8), format: .pem) - let client_privateKey = try NIOSSLPrivateKey.init(bytes: .init(privateKeyForClientAuthentication.utf8), format: .pem) + let client_cert = try NIOSSLCertificate( + bytes: .init(leafCertificateForClientAuthenticationIssuedFromCustomCARoot.utf8), + format: .pem + ) + let client_privateKey = try NIOSSLPrivateKey.init( + bytes: .init(privateKeyForClientAuthentication.utf8), + format: .pem + ) return (leaf, leaf_privateKey, client_cert, client_privateKey) } @@ -294,9 +403,11 @@ class TLSConfigurationTest: XCTestCase { ) serverConfig.maximumTLSVersion = .tlsv1 - try assertHandshakeError(withClientConfig: clientConfig, - andServerConfig: serverConfig, - errorTextContains: "ALERT_PROTOCOL_VERSION") + try assertHandshakeError( + withClientConfig: clientConfig, + andServerConfig: serverConfig, + errorTextContains: "ALERT_PROTOCOL_VERSION" + ) } func testNonOverlappingCipherSuitesPreTLS13() throws { @@ -311,7 +422,11 @@ class TLSConfigurationTest: XCTestCase { serverConfig.cipherSuiteValues = [.TLS_RSA_WITH_AES_256_CBC_SHA] serverConfig.maximumTLSVersion = .tlsv12 - try assertHandshakeError(withClientConfig: clientConfig, andServerConfig: serverConfig, errorTextContains: "ALERT_HANDSHAKE_FAILURE") + try assertHandshakeError( + withClientConfig: clientConfig, + andServerConfig: serverConfig, + errorTextContains: "ALERT_HANDSHAKE_FAILURE" + ) } func testCannotVerifySelfSigned() throws { @@ -321,7 +436,11 @@ class TLSConfigurationTest: XCTestCase { privateKey: .privateKey(TLSConfigurationTest.key1) ) - try assertHandshakeError(withClientConfig: clientConfig, andServerConfig: serverConfig, errorTextContains: "CERTIFICATE_VERIFY_FAILED") + try assertHandshakeError( + withClientConfig: clientConfig, + andServerConfig: serverConfig, + errorTextContains: "CERTIFICATE_VERIFY_FAILED" + ) } func testServerCannotValidateClientPreTLS13() throws { @@ -338,7 +457,11 @@ class TLSConfigurationTest: XCTestCase { serverConfig.maximumTLSVersion = .tlsv12 serverConfig.certificateVerification = .noHostnameVerification - try assertHandshakeError(withClientConfig: clientConfig, andServerConfig: serverConfig, errorTextContainsAnyOf: ["ALERT_UNKNOWN_CA", "ALERT_CERTIFICATE_UNKNOWN"]) + try assertHandshakeError( + withClientConfig: clientConfig, + andServerConfig: serverConfig, + errorTextContainsAnyOf: ["ALERT_UNKNOWN_CA", "ALERT_CERTIFICATE_UNKNOWN"] + ) } func testServerCannotValidateClientPostTLS13() throws { @@ -356,7 +479,11 @@ class TLSConfigurationTest: XCTestCase { serverConfig.minimumTLSVersion = .tlsv13 serverConfig.certificateVerification = .noHostnameVerification - try assertPostHandshakeError(withClientConfig: clientConfig, andServerConfig: serverConfig, errorTextContainsAnyOf: ["ALERT_UNKNOWN_CA", "ALERT_CERTIFICATE_UNKNOWN"]) + try assertPostHandshakeError( + withClientConfig: clientConfig, + andServerConfig: serverConfig, + errorTextContainsAnyOf: ["ALERT_UNKNOWN_CA", "ALERT_CERTIFICATE_UNKNOWN"] + ) } func testMutualValidationRequiresClientCertificatePreTLS13() throws { @@ -372,7 +499,11 @@ class TLSConfigurationTest: XCTestCase { serverConfig.certificateVerification = .noHostnameVerification serverConfig.trustRoots = .certificates([TLSConfigurationTest.cert2]) - try assertHandshakeError(withClientConfig: clientConfig, andServerConfig: serverConfig, errorTextContainsAnyOf: ["ALERT_HANDSHAKE_FAILURE"]) + try assertHandshakeError( + withClientConfig: clientConfig, + andServerConfig: serverConfig, + errorTextContainsAnyOf: ["ALERT_HANDSHAKE_FAILURE"] + ) } func testMutualValidationRequiresClientCertificatePostTLS13() throws { @@ -388,7 +519,11 @@ class TLSConfigurationTest: XCTestCase { serverConfig.certificateVerification = .noHostnameVerification serverConfig.trustRoots = .certificates([TLSConfigurationTest.cert2]) - try assertPostHandshakeError(withClientConfig: clientConfig, andServerConfig: serverConfig, errorTextContainsAnyOf: ["CERTIFICATE_REQUIRED"]) + try assertPostHandshakeError( + withClientConfig: clientConfig, + andServerConfig: serverConfig, + errorTextContainsAnyOf: ["CERTIFICATE_REQUIRED"] + ) } func testIncompatibleSignatures() throws { @@ -407,7 +542,11 @@ class TLSConfigurationTest: XCTestCase { serverConfig.minimumTLSVersion = .tlsv13 serverConfig.certificateVerification = .none - try assertHandshakeError(withClientConfig: clientConfig, andServerConfig: serverConfig, errorTextContains: "ALERT_HANDSHAKE_FAILURE") + try assertHandshakeError( + withClientConfig: clientConfig, + andServerConfig: serverConfig, + errorTextContains: "ALERT_HANDSHAKE_FAILURE" + ) } func testCompatibleSignatures() throws { @@ -446,7 +585,6 @@ class TLSConfigurationTest: XCTestCase { try assertHandshakeSucceeded(withClientConfig: clientConfig, andServerConfig: serverConfig) } - func testMutualValidationSuccessNoAdditionalTrustRoots() throws { var clientConfig = TLSConfiguration.makeClientConfiguration() clientConfig.certificateVerification = .noHostnameVerification @@ -455,7 +593,8 @@ class TLSConfigurationTest: XCTestCase { let serverConfig = TLSConfiguration.makeServerConfiguration( certificateChain: [.certificate(TLSConfigurationTest.cert1)], - privateKey: .privateKey(TLSConfigurationTest.key1)) + privateKey: .privateKey(TLSConfigurationTest.key1) + ) try assertHandshakeSucceeded(withClientConfig: clientConfig, andServerConfig: serverConfig) } @@ -545,7 +684,10 @@ class TLSConfigurationTest: XCTestCase { } XCTAssertNoThrow(try serverChannel.pipeline.addHandler(NIOSSLServerHandler(context: serverContext)).wait()) - XCTAssertNoThrow(try clientChannel.pipeline.addHandler(NIOSSLClientHandler(context: clientContext, serverHostname: nil)).wait()) + XCTAssertNoThrow( + try clientChannel.pipeline.addHandler(NIOSSLClientHandler(context: clientContext, serverHostname: nil)) + .wait() + ) let handshakeHandler = HandshakeCompletedHandler() XCTAssertNoThrow(try clientChannel.pipeline.addHandler(handshakeHandler).wait()) @@ -614,7 +756,10 @@ class TLSConfigurationTest: XCTestCase { } XCTAssertNoThrow(try serverChannel.pipeline.addHandler(NIOSSLServerHandler(context: serverContext)).wait()) - XCTAssertNoThrow(try clientChannel.pipeline.addHandler(NIOSSLClientHandler(context: clientContext, serverHostname: nil)).wait()) + XCTAssertNoThrow( + try clientChannel.pipeline.addHandler(NIOSSLClientHandler(context: clientContext, serverHostname: nil)) + .wait() + ) let handshakeHandler = HandshakeCompletedHandler() XCTAssertNoThrow(try clientChannel.pipeline.addHandler(handshakeHandler).wait()) @@ -636,7 +781,11 @@ class TLSConfigurationTest: XCTestCase { let testName = String("\(#function)".dropLast(2)) // Create 2 PEM based certs let rootCAPathOne = try dumpToFile(data: .init(customCARoot.utf8), fileExtension: ".pem", customPath: testName) - let rootCAPathTwo = try dumpToFile(data: .init(secondaryRootCertificateForClientAuthentication.utf8), fileExtension: ".pem", customPath: testName) + let rootCAPathTwo = try dumpToFile( + data: .init(secondaryRootCertificateForClientAuthentication.utf8), + fileExtension: ".pem", + customPath: testName + ) // Create a rehash formatted name of both certificate's subject name that was created above. // Take these rehash certificate names and format a symlink with them below with createSymbolicLink. @@ -651,8 +800,18 @@ class TLSConfigurationTest: XCTestCase { // Create an in-directory symlink the same way that c_rehash would do this. // For example: 7f44456a.0 -> niotestIEOFcMI.pem // NOT: 7f44456a.0 -> /var/folders/my/path/niotestIEOFcMI.pem - XCTAssertNoThrow(try FileManager.default.createSymbolicLink(atPath: rehashSymlinkNameOne, withDestinationPath: rootCAFilenameOne)) - XCTAssertNoThrow(try FileManager.default.createSymbolicLink(atPath: rehashSymlinkNameTwo, withDestinationPath: rootCAFilenameTwo)) + XCTAssertNoThrow( + try FileManager.default.createSymbolicLink( + atPath: rehashSymlinkNameOne, + withDestinationPath: rootCAFilenameOne + ) + ) + XCTAssertNoThrow( + try FileManager.default.createSymbolicLink( + atPath: rehashSymlinkNameTwo, + withDestinationPath: rootCAFilenameTwo + ) + ) defer { // Delete all files that were created for this test. @@ -662,7 +821,7 @@ class TLSConfigurationTest: XCTestCase { XCTAssertNoThrow(try FileManager.default.removeItem(at: URL(string: "file://" + rehashSymlinkNameTwo)!)) // Remove the actual directory also. let removePath = "\(FileManager.default.temporaryDirectory.path)/\(testName)/" - XCTAssertNoThrow(try FileManager.default.removeItem(at: URL(string: "file://" + removePath)!)) + XCTAssertNoThrow(try FileManager.default.removeItem(at: URL(string: "file://" + removePath)!)) } let tempFileDir = FileManager.default.temporaryDirectory.path + "/\(testName)/" @@ -674,7 +833,7 @@ class TLSConfigurationTest: XCTestCase { privateKey: .privateKey(digitalIdentities.leafKey) ) serverConfig.sendCANameList = true - serverConfig.trustRoots = .file(tempFileDir) // Directory path. + serverConfig.trustRoots = .file(tempFileDir) // Directory path. serverConfig.certificateVerification = .fullVerification var serverContext: NIOSSLContext! @@ -717,7 +876,12 @@ class TLSConfigurationTest: XCTestCase { let rootCAURLOne = URL(string: "file://" + rootCAPathOne)! let rootCAFilenameOne = rootCAURLOne.lastPathComponent - XCTAssertNoThrow(try FileManager.default.createSymbolicLink(atPath: rehashSymlinkName, withDestinationPath: rootCAFilenameOne)) + XCTAssertNoThrow( + try FileManager.default.createSymbolicLink( + atPath: rehashSymlinkName, + withDestinationPath: rootCAFilenameOne + ) + ) defer { // Delete all files that were created for this test. @@ -726,7 +890,7 @@ class TLSConfigurationTest: XCTestCase { XCTAssertNoThrow(try FileManager.default.removeItem(at: URL(string: "file://" + newPath)!)) // Remove the actual directory also. let removePath = "\(FileManager.default.temporaryDirectory.path)/\(testName)/" - XCTAssertNoThrow(try FileManager.default.removeItem(at: URL(string: "file://" + removePath)!)) + XCTAssertNoThrow(try FileManager.default.removeItem(at: URL(string: "file://" + removePath)!)) } // Test the success case for the symlink @@ -738,13 +902,16 @@ class TLSConfigurationTest: XCTestCase { var clientConfig = TLSConfiguration.makeClientConfiguration() clientConfig.trustRoots = .file("/thispathbetternotexist/bogus.foo") - XCTAssertThrowsError(try NIOSSLContext(configuration: clientConfig)) {error in + XCTAssertThrowsError(try NIOSSLContext(configuration: clientConfig)) { error in XCTAssertEqual(.noSuchFilesystemObject, error as? NIOSSLError) } } func testComputedApplicationProtocols() throws { - var config = TLSConfiguration.makeServerConfiguration(certificateChain: [], privateKey: .privateKey(TLSConfigurationTest.key1)) + var config = TLSConfiguration.makeServerConfiguration( + certificateChain: [], + privateKey: .privateKey(TLSConfigurationTest.key1) + ) config.applicationProtocols = ["http/1.1"] XCTAssertEqual(config.applicationProtocols, ["http/1.1"]) XCTAssertEqual(config.encodedApplicationProtocols, [[8, 104, 116, 116, 112, 47, 49, 46, 49]]) @@ -792,7 +959,10 @@ class TLSConfigurationTest: XCTestCase { } func testTheSameHashValue() { - var config = TLSConfiguration.makeServerConfiguration(certificateChain: [], privateKey: .privateKey(TLSConfigurationTest.key1)) + var config = TLSConfiguration.makeServerConfiguration( + certificateChain: [], + privateKey: .privateKey(TLSConfigurationTest.key1) + ) config.applicationProtocols = ["http/1.1"] let theSameConfig = config var hasher = Hasher() @@ -804,7 +974,10 @@ class TLSConfigurationTest: XCTestCase { } func testDifferentHashValues() { - var config = TLSConfiguration.makeServerConfiguration(certificateChain: [], privateKey: .privateKey(TLSConfigurationTest.key1)) + var config = TLSConfiguration.makeServerConfiguration( + certificateChain: [], + privateKey: .privateKey(TLSConfigurationTest.key1) + ) config.applicationProtocols = ["http/1.1"] var differentConfig = config differentConfig.privateKey = .privateKey(TLSConfigurationTest.key2) @@ -812,7 +985,10 @@ class TLSConfigurationTest: XCTestCase { } func testDifferentCallbacksNotEqual() { - var config = TLSConfiguration.makeServerConfiguration(certificateChain: [], privateKey: .privateKey(TLSConfigurationTest.key1)) + var config = TLSConfiguration.makeServerConfiguration( + certificateChain: [], + privateKey: .privateKey(TLSConfigurationTest.key1) + ) config.applicationProtocols = ["http/1.1"] config.keyLogCallback = { _ in } var differentConfig = config @@ -821,7 +997,10 @@ class TLSConfigurationTest: XCTestCase { } func testDifferentSSLContextCallbacksNotEqual() throws { - var config = TLSConfiguration.makeServerConfiguration(certificateChain: [], privateKey: .privateKey(TLSConfigurationTest.key1)) + var config = TLSConfiguration.makeServerConfiguration( + certificateChain: [], + privateKey: .privateKey(TLSConfigurationTest.key1) + ) config.applicationProtocols = ["http/1.1"] config.sslContextCallback = { _, _ in } var differentConfig = config @@ -886,7 +1065,11 @@ class TLSConfigurationTest: XCTestCase { serverConfig.cipherSuiteValues = [.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384] serverConfig.maximumTLSVersion = .tlsv12 serverConfig.certificateVerification = .none - try assertHandshakeError(withClientConfig: clientConfig, andServerConfig: serverConfig, errorTextContains: "ALERT_HANDSHAKE_FAILURE") + try assertHandshakeError( + withClientConfig: clientConfig, + andServerConfig: serverConfig, + errorTextContains: "ALERT_HANDSHAKE_FAILURE" + ) } func testCompatibleCipherSuite() throws { @@ -925,7 +1108,11 @@ class TLSConfigurationTest: XCTestCase { serverConfig.cipherSuiteValues = [.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256] serverConfig.maximumTLSVersion = .tlsv12 serverConfig.certificateVerification = .none - try assertHandshakeError(withClientConfig: clientConfig, andServerConfig: serverConfig, errorTextContains: "ALERT_HANDSHAKE_FAILURE") + try assertHandshakeError( + withClientConfig: clientConfig, + andServerConfig: serverConfig, + errorTextContains: "ALERT_HANDSHAKE_FAILURE" + ) } func testDefaultWithRSACipherSuite() throws { @@ -998,7 +1185,7 @@ class TLSConfigurationTest: XCTestCase { serverConfig.cipherSuiteValues = [ .TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, .TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - .TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + .TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, ] serverConfig.maximumTLSVersion = .tlsv12 serverConfig.certificateVerification = .none @@ -1022,7 +1209,7 @@ class TLSConfigurationTest: XCTestCase { .TLS_RSA_WITH_AES_128_CBC_SHA, .TLS_RSA_WITH_AES_256_CBC_SHA, .TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, - .TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + .TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, ] serverConfig.maximumTLSVersion = .tlsv12 serverConfig.certificateVerification = .none @@ -1045,7 +1232,7 @@ class TLSConfigurationTest: XCTestCase { .TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, .TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, .TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - .TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + .TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, ] clientConfig.maximumTLSVersion = .tlsv12 clientConfig.certificateVerification = .noHostnameVerification @@ -1069,7 +1256,7 @@ class TLSConfigurationTest: XCTestCase { clientConfig.cipherSuiteValues = [ .TLS_AES_128_GCM_SHA256, .TLS_AES_256_GCM_SHA384, - .TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + .TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, ] clientConfig.maximumTLSVersion = .tlsv12 clientConfig.certificateVerification = .noHostnameVerification @@ -1083,7 +1270,11 @@ class TLSConfigurationTest: XCTestCase { serverConfig.cipherSuites = "AES256" serverConfig.maximumTLSVersion = .tlsv12 - try assertHandshakeError(withClientConfig: clientConfig, andServerConfig: serverConfig, errorTextContains: "ALERT_HANDSHAKE_FAILURE") + try assertHandshakeError( + withClientConfig: clientConfig, + andServerConfig: serverConfig, + errorTextContains: "ALERT_HANDSHAKE_FAILURE" + ) } func testSettingCiphersWithCipherSuiteValues() { @@ -1091,14 +1282,17 @@ class TLSConfigurationTest: XCTestCase { clientConfig.cipherSuiteValues = [ .TLS_AES_128_GCM_SHA256, .TLS_AES_256_GCM_SHA384, - .TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + .TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, ] clientConfig.maximumTLSVersion = .tlsv12 clientConfig.certificateVerification = .noHostnameVerification clientConfig.trustRoots = .certificates([TLSConfigurationTest.cert1]) clientConfig.renegotiationSupport = .none - XCTAssertEqual(clientConfig.cipherSuites, "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256") + XCTAssertEqual( + clientConfig.cipherSuites, + "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256" + ) } func testSettingCiphersWithCipherSuitesString() { @@ -1111,7 +1305,10 @@ class TLSConfigurationTest: XCTestCase { let assignedCiphers = clientConfig.cipherSuiteValues.map { $0.standardName } let createdCipherSuiteValuesFromString = assignedCiphers.joined(separator: ":") // Note that this includes the PSK values as well. - XCTAssertEqual(createdCipherSuiteValuesFromString, "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA:TLS_RSA_WITH_AES_256_GCM_SHA384:TLS_RSA_WITH_AES_256_CBC_SHA:TLS_PSK_WITH_AES_256_CBC_SHA") + XCTAssertEqual( + createdCipherSuiteValuesFromString, + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA:TLS_RSA_WITH_AES_256_GCM_SHA384:TLS_RSA_WITH_AES_256_CBC_SHA:TLS_PSK_WITH_AES_256_CBC_SHA" + ) } func testDefaultCipherSuiteValues() { @@ -1125,14 +1322,25 @@ class TLSConfigurationTest: XCTestCase { let assignedCiphers = clientConfig.cipherSuiteValues.map { $0.standardName } let defaultCipherSuiteValuesFromString = assignedCiphers.joined(separator: ":") // Note that this includes the PSK values as well. - XCTAssertEqual(defaultCipherSuiteValuesFromString, "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA:TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA:TLS_RSA_WITH_AES_128_GCM_SHA256:TLS_RSA_WITH_AES_256_GCM_SHA384:TLS_RSA_WITH_AES_128_CBC_SHA:TLS_RSA_WITH_AES_256_CBC_SHA") + XCTAssertEqual( + defaultCipherSuiteValuesFromString, + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA:TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA:TLS_RSA_WITH_AES_128_GCM_SHA256:TLS_RSA_WITH_AES_256_GCM_SHA384:TLS_RSA_WITH_AES_128_CBC_SHA:TLS_RSA_WITH_AES_256_CBC_SHA" + ) } - @available(*, deprecated, message: "`TLSConfiguration.pskClientCallback` and `TLSConfiguration.pskClientCallback` are deprecated") + @available( + *, + deprecated, + message: "`TLSConfiguration.pskClientCallback` and `TLSConfiguration.pskClientCallback` are deprecated" + ) func testBestEffortEquatableHashableDifferences() { // If this assertion fails, DON'T JUST CHANGE THE NUMBER HERE! Make sure you've added any appropriate transforms below // so that we're testing these best effort functions. - XCTAssertEqual(MemoryLayout.size, 234, "TLSConfiguration has changed size: you probably need to update this test!") + XCTAssertEqual( + MemoryLayout.size, + 234, + "TLSConfiguration has changed size: you probably need to update this test!" + ) let first = TLSConfiguration.makeClientConfiguration() @@ -1143,21 +1351,24 @@ class TLSConfigurationTest: XCTestCase { return PSKClientIdentityResponse(key: psk, identity: "world") } - let pskServerCallback: NIOPSKServerIdentityCallback = { (hint: String, identity: String) -> PSKServerIdentityResponse in + let pskServerCallback: NIOPSKServerIdentityCallback = { + (hint: String, identity: String) -> PSKServerIdentityResponse in // Evaluate hint and clientIdentity to send back proper PSK. var psk = NIOSSLSecureBytes() psk.append("hello".utf8) return PSKServerIdentityResponse(key: psk) } - let pskClientProvider: NIOPSKClientIdentityProvider = { (context: PSKClientContext) -> PSKClientIdentityResponse in + let pskClientProvider: NIOPSKClientIdentityProvider = { + (context: PSKClientContext) -> PSKClientIdentityResponse in // Evaluate hint and clientIdentity to send back proper PSK. var psk = NIOSSLSecureBytes() psk.append("hello".utf8) return PSKClientIdentityResponse(key: psk, identity: "world") } - let pskServerProvider: NIOPSKServerIdentityProvider = { (context: PSKServerContext) -> PSKServerIdentityResponse in + let pskServerProvider: NIOPSKServerIdentityProvider = { + (context: PSKServerContext) -> PSKServerIdentityResponse in // Evaluate hint and clientIdentity to send back proper PSK. var psk = NIOSSLSecureBytes() psk.append("hello".utf8) @@ -1185,7 +1396,7 @@ class TLSConfigurationTest: XCTestCase { { $0.renegotiationSupport = .always }, { $0.sendCANameList = true }, { $0.pskClientCallback = pskClientCallback }, - { $0.pskServerCallback = pskServerCallback}, + { $0.pskServerCallback = pskServerCallback }, { $0.sslContextCallback = sslContextCallback }, { $0.pskServerCallback = pskServerCallback }, { $0.pskClientProvider = pskClientProvider }, @@ -1196,8 +1407,16 @@ class TLSConfigurationTest: XCTestCase { for (index, transform) in transforms.enumerated() { var transformed = first transform(&transformed) - XCTAssertNotEqual(Wrapper(config: first), Wrapper(config: transformed), "Should have compared not equal in index \(index)") - XCTAssertEqual(Set([Wrapper(config: first), Wrapper(config: transformed)]).count, 2, "Should have hashed non-equal in index \(index)") + XCTAssertNotEqual( + Wrapper(config: first), + Wrapper(config: transformed), + "Should have compared not equal in index \(index)" + ) + XCTAssertEqual( + Set([Wrapper(config: first), Wrapper(config: transformed)]).count, + 2, + "Should have hashed non-equal in index \(index)" + ) } } @@ -1220,7 +1439,10 @@ class TLSConfigurationTest: XCTestCase { let serverContext = try assertNoThrowWithValue(NIOSSLContext(configuration: serverConfig)) XCTAssertNoThrow( try b2b.client.pipeline.syncOperations.addHandlers( - [try NIOSSLClientHandler(context: clientContext, serverHostname: "localhost"), HandshakeCompletedHandler()] + [ + try NIOSSLClientHandler(context: clientContext, serverHostname: "localhost"), + HandshakeCompletedHandler(), + ] ) ) XCTAssertNoThrow( @@ -1242,7 +1464,11 @@ class TLSConfigurationTest: XCTestCase { XCTAssertEqual(channelTLSVersion!, .tlsv11) } - @available(*, deprecated, message: "`TLSConfiguration.pskClientCallback` and `TLSConfiguration.pskClientCallback` are deprecated") + @available( + *, + deprecated, + message: "`TLSConfiguration.pskClientCallback` and `TLSConfiguration.pskClientCallback` are deprecated" + ) func testTLSPSKWithTLS13Deprecated() throws { // The idea here is that adding PSKs with certificates in TLS 1.3 should NOT cause a failure. // Also note that the usage here of PSKs with TLS 1.3 is not supported by BoringSSL at this point. @@ -1254,7 +1480,8 @@ class TLSConfigurationTest: XCTestCase { return PSKClientIdentityResponse(key: psk, identity: "world") } - let pskServerCallback: NIOPSKServerIdentityCallback = { (hint: String, identity: String) -> PSKServerIdentityResponse in + let pskServerCallback: NIOPSKServerIdentityCallback = { + (hint: String, identity: String) -> PSKServerIdentityResponse in // Evaluate hint and clientIdentity to send back proper PSK. XCTAssertEqual(hint, "serverPskHint") XCTAssertEqual(identity, "world") @@ -1283,7 +1510,11 @@ class TLSConfigurationTest: XCTestCase { try assertHandshakeSucceeded(withClientConfig: clientConfig, andServerConfig: serverConfig) } - @available(*, deprecated, message: "`TLSConfiguration.pskClientCallback` and `TLSConfiguration.pskClientCallback` are deprecated") + @available( + *, + deprecated, + message: "`TLSConfiguration.pskClientCallback` and `TLSConfiguration.pskClientCallback` are deprecated" + ) func testTLSPSKWithTLS12Deprecated() throws { // This test ensures that PSK-TLS is supported for TLS 1.2. let pskClientCallback: NIOPSKClientIdentityCallback = { (hint: String) -> PSKClientIdentityResponse in @@ -1294,7 +1525,8 @@ class TLSConfigurationTest: XCTestCase { return PSKClientIdentityResponse(key: psk, identity: "world") } - let pskServerCallback: NIOPSKServerIdentityCallback = { (hint: String, identity: String) -> PSKServerIdentityResponse in + let pskServerCallback: NIOPSKServerIdentityCallback = { + (hint: String, identity: String) -> PSKServerIdentityResponse in // Evaluate hint and clientIdentity to send back proper PSK. XCTAssertEqual(hint, "serverPskHint") XCTAssertEqual(identity, "world") @@ -1318,7 +1550,11 @@ class TLSConfigurationTest: XCTestCase { try assertHandshakeSucceeded(withClientConfig: clientConfig, andServerConfig: serverConfig) } - @available(*, deprecated, message: "`TLSConfiguration.pskClientCallback` and `TLSConfiguration.pskClientCallback` are deprecated") + @available( + *, + deprecated, + message: "`TLSConfiguration.pskClientCallback` and `TLSConfiguration.pskClientCallback` are deprecated" + ) func testTLSPSKWithPinnedCiphersDeprecated() throws { // This test ensures that PSK-TLS is supported with pinned ciphers. let pskClientCallback: NIOPSKClientIdentityCallback = { (hint: String) -> PSKClientIdentityResponse in @@ -1329,7 +1565,8 @@ class TLSConfigurationTest: XCTestCase { return PSKClientIdentityResponse(key: psk, identity: "world") } - let pskServerCallback: NIOPSKServerIdentityCallback = { (hint: String, identity: String) -> PSKServerIdentityResponse in + let pskServerCallback: NIOPSKServerIdentityCallback = { + (hint: String, identity: String) -> PSKServerIdentityResponse in // Evaluate hint and clientIdentity to send back proper PSK. XCTAssertEqual(hint, "serverPskHint") XCTAssertEqual(identity, "world") @@ -1344,24 +1581,32 @@ class TLSConfigurationTest: XCTestCase { clientConfig.maximumTLSVersion = .tlsv12 clientConfig.pskClientCallback = pskClientCallback clientConfig.pskHint = "clientPskHint" - clientConfig.cipherSuiteValues = [.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, - .TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, - .TLS_PSK_WITH_AES_128_CBC_SHA, - .TLS_PSK_WITH_AES_256_CBC_SHA] + clientConfig.cipherSuiteValues = [ + .TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, + .TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, + .TLS_PSK_WITH_AES_128_CBC_SHA, + .TLS_PSK_WITH_AES_256_CBC_SHA, + ] var serverConfig = TLSConfiguration.makePreSharedKeyConfiguration() serverConfig.minimumTLSVersion = .tlsv1 serverConfig.maximumTLSVersion = .tlsv12 serverConfig.pskServerCallback = pskServerCallback serverConfig.pskHint = "serverPskHint" - serverConfig.cipherSuiteValues = [.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, - .TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, - .TLS_PSK_WITH_AES_128_CBC_SHA, - .TLS_PSK_WITH_AES_256_CBC_SHA] + serverConfig.cipherSuiteValues = [ + .TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, + .TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, + .TLS_PSK_WITH_AES_128_CBC_SHA, + .TLS_PSK_WITH_AES_256_CBC_SHA, + ] try assertHandshakeSucceeded(withClientConfig: clientConfig, andServerConfig: serverConfig) } - @available(*, deprecated, message: "`TLSConfiguration.pskClientCallback` and `TLSConfiguration.pskClientCallback` are deprecated") + @available( + *, + deprecated, + message: "`TLSConfiguration.pskClientCallback` and `TLSConfiguration.pskClientCallback` are deprecated" + ) func testTLSPSKFailureDeprecated() throws { // This test ensures that different PSKs used on the client and server fail when passed in. let pskClientCallback: NIOPSKClientIdentityCallback = { (hint: String) -> PSKClientIdentityResponse in @@ -1372,12 +1617,13 @@ class TLSConfigurationTest: XCTestCase { return PSKClientIdentityResponse(key: psk, identity: "world") } - let pskServerCallback: NIOPSKServerIdentityCallback = { (hint: String, identity: String) -> PSKServerIdentityResponse in + let pskServerCallback: NIOPSKServerIdentityCallback = { + (hint: String, identity: String) -> PSKServerIdentityResponse in // Evaluate hint and clientIdentity to send back proper PSK. XCTAssertEqual(hint, "serverPskHint") XCTAssertEqual(identity, "world") var psk = NIOSSLSecureBytes() - psk.append("server".utf8) // Failure + psk.append("server".utf8) // Failure return PSKServerIdentityResponse(key: psk) } @@ -1393,7 +1639,11 @@ class TLSConfigurationTest: XCTestCase { serverConfig.maximumTLSVersion = .tlsv12 serverConfig.pskServerCallback = pskServerCallback serverConfig.pskHint = "serverPskHint" - try assertHandshakeError(withClientConfig: clientConfig, andServerConfig: serverConfig, errorTextContainsAnyOf: ["SSLV3_ALERT_BAD_RECORD_MAC"]) + try assertHandshakeError( + withClientConfig: clientConfig, + andServerConfig: serverConfig, + errorTextContainsAnyOf: ["SSLV3_ALERT_BAD_RECORD_MAC"] + ) } @available(*, deprecated, message: "`.file` NIOSSLPrivateKeySource option deprecated") @@ -1413,7 +1663,8 @@ class TLSConfigurationTest: XCTestCase { func testTLSPSKWithTLS13() throws { // The idea here is that adding PSKs with certificates in TLS 1.3 should NOT cause a failure. // Also note that the usage here of PSKs with TLS 1.3 is not supported by BoringSSL at this point. - let pskClientProvider: NIOPSKClientIdentityProvider = { (context: PSKClientContext) -> PSKClientIdentityResponse in + let pskClientProvider: NIOPSKClientIdentityProvider = { + (context: PSKClientContext) -> PSKClientIdentityResponse in // Evaluate hint and clientIdentity to send back proper PSK. XCTAssertEqual(context.hint, "serverPskHint") var psk = NIOSSLSecureBytes() @@ -1421,7 +1672,8 @@ class TLSConfigurationTest: XCTestCase { return PSKClientIdentityResponse(key: psk, identity: "world") } - let pskServerProvider: NIOPSKServerIdentityProvider = { (context: PSKServerContext) -> PSKServerIdentityResponse in + let pskServerProvider: NIOPSKServerIdentityProvider = { + (context: PSKServerContext) -> PSKServerIdentityResponse in // Evaluate hint and clientIdentity to send back proper PSK. XCTAssertEqual(context.hint, "serverPskHint") XCTAssertEqual(context.clientIdentity, "world") @@ -1452,7 +1704,8 @@ class TLSConfigurationTest: XCTestCase { func testTLSPSKWithTLS12() throws { // This test ensures that PSK-TLS is supported for TLS 1.2. - let pskClientProvider: NIOPSKClientIdentityProvider = { (context: PSKClientContext) -> PSKClientIdentityResponse in + let pskClientProvider: NIOPSKClientIdentityProvider = { + (context: PSKClientContext) -> PSKClientIdentityResponse in // Evaluate hint and clientIdentity to send back proper PSK. XCTAssertEqual(context.hint, "serverPskHint") var psk = NIOSSLSecureBytes() @@ -1460,7 +1713,8 @@ class TLSConfigurationTest: XCTestCase { return PSKClientIdentityResponse(key: psk, identity: "world") } - let pskServerProvider: NIOPSKServerIdentityProvider = { (context: PSKServerContext) -> PSKServerIdentityResponse in + let pskServerProvider: NIOPSKServerIdentityProvider = { + (context: PSKServerContext) -> PSKServerIdentityResponse in // Evaluate hint and clientIdentity to send back proper PSK. XCTAssertEqual(context.hint, "serverPskHint") XCTAssertEqual(context.clientIdentity, "world") @@ -1486,7 +1740,8 @@ class TLSConfigurationTest: XCTestCase { func testTLSPSKWithPinnedCiphers() throws { // This test ensures that PSK-TLS is supported with pinned ciphers. - let pskClientProvider: NIOPSKClientIdentityProvider = { (context: PSKClientContext) -> PSKClientIdentityResponse in + let pskClientProvider: NIOPSKClientIdentityProvider = { + (context: PSKClientContext) -> PSKClientIdentityResponse in // Evaluate hint and clientIdentity to send back proper PSK. XCTAssertEqual(context.hint, "serverPskHint") var psk = NIOSSLSecureBytes() @@ -1494,7 +1749,8 @@ class TLSConfigurationTest: XCTestCase { return PSKClientIdentityResponse(key: psk, identity: "world") } - let pskServerProvider: NIOPSKServerIdentityProvider = { (context: PSKServerContext) -> PSKServerIdentityResponse in + let pskServerProvider: NIOPSKServerIdentityProvider = { + (context: PSKServerContext) -> PSKServerIdentityResponse in // Evaluate hint and clientIdentity to send back proper PSK. XCTAssertEqual(context.hint, "serverPskHint") XCTAssertEqual(context.clientIdentity, "world") @@ -1509,26 +1765,31 @@ class TLSConfigurationTest: XCTestCase { clientConfig.maximumTLSVersion = .tlsv12 clientConfig.pskClientProvider = pskClientProvider clientConfig.pskHint = "clientPskHint" - clientConfig.cipherSuiteValues = [.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, - .TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, - .TLS_PSK_WITH_AES_128_CBC_SHA, - .TLS_PSK_WITH_AES_256_CBC_SHA] + clientConfig.cipherSuiteValues = [ + .TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, + .TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, + .TLS_PSK_WITH_AES_128_CBC_SHA, + .TLS_PSK_WITH_AES_256_CBC_SHA, + ] var serverConfig = TLSConfiguration.makePreSharedKeyConfiguration() serverConfig.minimumTLSVersion = .tlsv1 serverConfig.maximumTLSVersion = .tlsv12 serverConfig.pskServerProvider = pskServerProvider serverConfig.pskHint = "serverPskHint" - serverConfig.cipherSuiteValues = [.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, - .TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, - .TLS_PSK_WITH_AES_128_CBC_SHA, - .TLS_PSK_WITH_AES_256_CBC_SHA] + serverConfig.cipherSuiteValues = [ + .TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, + .TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, + .TLS_PSK_WITH_AES_128_CBC_SHA, + .TLS_PSK_WITH_AES_256_CBC_SHA, + ] try assertHandshakeSucceeded(withClientConfig: clientConfig, andServerConfig: serverConfig) } func testTLSPSKFailure() throws { // This test ensures that different PSKs used on the client and server fail when passed in. - let pskClientProvider: NIOPSKClientIdentityProvider = { (context: PSKClientContext) -> PSKClientIdentityResponse in + let pskClientProvider: NIOPSKClientIdentityProvider = { + (context: PSKClientContext) -> PSKClientIdentityResponse in // Evaluate hint and clientIdentity to send back proper PSK. XCTAssertEqual(context.hint, "serverPskHint") var psk = NIOSSLSecureBytes() @@ -1536,12 +1797,13 @@ class TLSConfigurationTest: XCTestCase { return PSKClientIdentityResponse(key: psk, identity: "world") } - let pskServerProvider: NIOPSKServerIdentityProvider = { (context: PSKServerContext) -> PSKServerIdentityResponse in + let pskServerProvider: NIOPSKServerIdentityProvider = { + (context: PSKServerContext) -> PSKServerIdentityResponse in // Evaluate hint and clientIdentity to send back proper PSK. XCTAssertEqual(context.hint, "serverPskHint") XCTAssertEqual(context.clientIdentity, "world") var psk = NIOSSLSecureBytes() - psk.append("server".utf8) // Failure + psk.append("server".utf8) // Failure return PSKServerIdentityResponse(key: psk) } @@ -1557,13 +1819,18 @@ class TLSConfigurationTest: XCTestCase { serverConfig.maximumTLSVersion = .tlsv12 serverConfig.pskServerProvider = pskServerProvider serverConfig.pskHint = "serverPskHint" - try assertHandshakeError(withClientConfig: clientConfig, andServerConfig: serverConfig, errorTextContainsAnyOf: ["SSLV3_ALERT_BAD_RECORD_MAC"]) + try assertHandshakeError( + withClientConfig: clientConfig, + andServerConfig: serverConfig, + errorTextContainsAnyOf: ["SSLV3_ALERT_BAD_RECORD_MAC"] + ) } func testTLSPSKNoServerHint() throws { let expectation = expectation(description: "pskClientProvider is called") // This test ensures that different PSKs used on the client and server fail when passed in. - let pskClientProvider: NIOPSKClientIdentityProvider = { (context: PSKClientContext) -> PSKClientIdentityResponse in + let pskClientProvider: NIOPSKClientIdentityProvider = { + (context: PSKClientContext) -> PSKClientIdentityResponse in expectation.fulfill() // Ensure server hint is nil XCTAssertEqual(context.hint, nil) @@ -1573,13 +1840,14 @@ class TLSConfigurationTest: XCTestCase { return PSKClientIdentityResponse(key: psk, identity: "world") } - let pskServerProvider: NIOPSKServerIdentityProvider = { (context: PSKServerContext) -> PSKServerIdentityResponse in + let pskServerProvider: NIOPSKServerIdentityProvider = { + (context: PSKServerContext) -> PSKServerIdentityResponse in // Ensure server hint is nil XCTAssertEqual(context.hint, nil) XCTAssertEqual(context.clientIdentity, "world") // Evaluate hint and clientIdentity to send back proper PSK. var psk = NIOSSLSecureBytes() - psk.append("hello".utf8) // Failure + psk.append("hello".utf8) // Failure return PSKServerIdentityResponse(key: psk) } @@ -1602,7 +1870,8 @@ class TLSConfigurationTest: XCTestCase { func testTLSPSKNoClientHint() throws { let expectation = expectation(description: "pskClientProvider is called") // This test ensures that different PSKs used on the client and server fail when passed in. - let pskClientProvider: NIOPSKClientIdentityProvider = { (context: PSKClientContext) -> PSKClientIdentityResponse in + let pskClientProvider: NIOPSKClientIdentityProvider = { + (context: PSKClientContext) -> PSKClientIdentityResponse in expectation.fulfill() // Ensure server hint is nil XCTAssertEqual(context.hint, nil) @@ -1612,13 +1881,14 @@ class TLSConfigurationTest: XCTestCase { return PSKClientIdentityResponse(key: psk, identity: "world") } - let pskServerProvider: NIOPSKServerIdentityProvider = { (context: PSKServerContext) -> PSKServerIdentityResponse in + let pskServerProvider: NIOPSKServerIdentityProvider = { + (context: PSKServerContext) -> PSKServerIdentityResponse in // Ensure server hint is nil XCTAssertEqual(context.hint, nil) XCTAssertEqual(context.clientIdentity, "world") // Evaluate hint and clientIdentity to send back proper PSK. var psk = NIOSSLSecureBytes() - psk.append("hello".utf8) // Failure + psk.append("hello".utf8) // Failure return PSKServerIdentityResponse(key: psk) } @@ -1649,8 +1919,8 @@ extension EmbeddedChannel { struct Wrapper: Hashable { var config: TLSConfiguration - static func ==(lhs: Wrapper, rhs: Wrapper) -> Bool { - return lhs.config.bestEffortEquals(rhs.config) + static func == (lhs: Wrapper, rhs: Wrapper) -> Bool { + lhs.config.bestEffortEquals(rhs.config) } func hash(into hasher: inout Hasher) { diff --git a/Tests/NIOSSLTests/UnsafeTransfer.swift b/Tests/NIOSSLTests/UnsafeTransfer.swift index 3774ace35..3b23627e6 100644 --- a/Tests/NIOSSLTests/UnsafeTransfer.swift +++ b/Tests/NIOSSLTests/UnsafeTransfer.swift @@ -19,7 +19,7 @@ final class UnsafeMutableTransferBox { @usableFromInline var wrappedValue: Wrapped - + @inlinable init(_ wrappedValue: Wrapped) { self.wrappedValue = wrappedValue @@ -27,4 +27,3 @@ final class UnsafeMutableTransferBox { } extension UnsafeMutableTransferBox: @unchecked Sendable {} - diff --git a/Tests/NIOSSLTests/UnwrappingTests.swift b/Tests/NIOSSLTests/UnwrappingTests.swift index 02876a2e1..c29d13484 100644 --- a/Tests/NIOSSLTests/UnwrappingTests.swift +++ b/Tests/NIOSSLTests/UnwrappingTests.swift @@ -12,9 +12,10 @@ // //===----------------------------------------------------------------------===// -import XCTest import NIOCore import NIOEmbedded +import XCTest + @testable import NIOSSL func connectInMemory(client: EmbeddedChannel, server: EmbeddedChannel) throws { @@ -542,9 +543,9 @@ final class UnwrappingTests: XCTestCase { var buffer = clientChannel.allocator.buffer(capacity: 1024) buffer.writeStaticString("GET / HTTP/1.1\r\nHost: localhost\r\nContent-Length: 0\r\n\r\n") - XCTAssertThrowsError(try clientChannel.writeInbound(buffer)) {error in + XCTAssertThrowsError(try clientChannel.writeInbound(buffer)) { error in switch error as? NIOSSLError { - case .some(.shutdownFailed) : + case .some(.shutdownFailed): // Expected break default: diff --git a/docker/Dockerfile b/docker/Dockerfile index 7a118f79a..74d06054a 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -18,9 +18,6 @@ RUN apt-get update && apt-get install -y lsof dnsutils netcat-openbsd net-tools RUN apt-get update && apt-get install -y libssl-dev RUN apt-get update && apt-get install -y execstack -# ruby for soundness -RUN apt-get update && apt-get install -y ruby ruby-dev libsqlite3-dev build-essential - # tools RUN mkdir -p $HOME/.tools RUN echo 'export PATH="$HOME/.tools:$PATH"' >> $HOME/.profile diff --git a/docker/docker-compose.2204.510.yaml b/docker/docker-compose.2204.510.yaml index f6a11bf9c..36a21f982 100644 --- a/docker/docker-compose.2204.510.yaml +++ b/docker/docker-compose.2204.510.yaml @@ -9,15 +9,6 @@ services: ubuntu_version: "jammy" swift_version: "5.10" - unit-tests: - image: swift-nio-ssl:22.04-5.10 - - integration-tests: - image: swift-nio-ssl:22.04-5.10 - - documentation-check: - image: swift-nio-ssl:22.04-5.10 - test: image: swift-nio-ssl:22.04-5.10 environment: @@ -28,8 +19,5 @@ services: performance-test: image: swift-nio-ssl:22.04-5.10 - cxx-interop-build: - image: swift-nio-ssl:22.04-5.10 - shell: image: swift-nio-ssl:22.04-5.10 diff --git a/docker/docker-compose.2204.58.yaml b/docker/docker-compose.2204.58.yaml index c76777d18..35eb494d0 100644 --- a/docker/docker-compose.2204.58.yaml +++ b/docker/docker-compose.2204.58.yaml @@ -9,15 +9,6 @@ services: ubuntu_version: "jammy" swift_version: "5.8" - unit-tests: - image: swift-nio-ssl:22.04-5.8 - - integration-tests: - image: swift-nio-ssl:22.04-5.8 - - documentation-check: - image: swift-nio-ssl:22.04-5.8 - test: image: swift-nio-ssl:22.04-5.8 environment: diff --git a/docker/docker-compose.2204.59.yaml b/docker/docker-compose.2204.59.yaml index 90aaaa222..a9b9472b4 100644 --- a/docker/docker-compose.2204.59.yaml +++ b/docker/docker-compose.2204.59.yaml @@ -9,15 +9,6 @@ services: ubuntu_version: "jammy" swift_version: "5.9" - unit-tests: - image: swift-nio-ssl:22.04-5.9 - - integration-tests: - image: swift-nio-ssl:22.04-5.9 - - documentation-check: - image: swift-nio-ssl:22.04-5.9 - test: image: swift-nio-ssl:22.04-5.9 environment: @@ -28,8 +19,5 @@ services: performance-test: image: swift-nio-ssl:22.04-5.9 - cxx-interop-build: - image: swift-nio-ssl:22.04-5.9 - shell: image: swift-nio-ssl:22.04-5.9 diff --git a/docker/docker-compose.2204.main.yaml b/docker/docker-compose.2204.main.yaml index c87ae16cf..9330020b2 100644 --- a/docker/docker-compose.2204.main.yaml +++ b/docker/docker-compose.2204.main.yaml @@ -8,15 +8,6 @@ services: args: base_image: "swiftlang/swift:nightly-main-jammy" - unit-tests: - image: swift-nio-ssl:22.04-main - - integration-tests: - image: swift-nio-ssl:22.04-main - - documentation-check: - image: swift-nio-ssl:22.04-main - test: image: swift-nio-ssl:22.04-main environment: diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index 1f597bddd..39f8b4de2 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -22,33 +22,13 @@ services: - CAP_NET_RAW - CAP_NET_BIND_SERVICE - soundness: - <<: *common - command: /bin/bash -xcl "./scripts/soundness.sh" - - unit-tests: - <<: *common - command: /bin/bash -xcl "swift test -Xswiftc -warnings-as-errors --enable-test-discovery" - - integration-tests: - <<: *common - command: /bin/bash -xcl "./scripts/integration_tests.sh" - - documentation-check: - <<: *common - command: /bin/bash -xcl "./scripts/check-docs.sh" - test: <<: *common - command: /bin/bash -xcl "swift test -Xswiftc -warnings-as-errors --enable-test-discovery $${SANITIZER_ARG-} $${IMPORT_CHECK_ARG-} && ./scripts/integration_tests.sh" + command: /bin/bash -xcl "./scripts/integration_tests.sh" performance-test: <<: *common command: /bin/bash -xcl "swift build -c release && ./.build/release/NIOSSLPerformanceTester" - - cxx-interop-build: - <<: *common - command: /bin/bash -xcl "./scripts/cxx-interop-compatibility.sh" # util diff --git a/scripts/build-asm.py b/scripts/build-asm.py index e1f66fbee..90f04dd80 100755 --- a/scripts/build-asm.py +++ b/scripts/build-asm.py @@ -13,9 +13,8 @@ ## ##===----------------------------------------------------------------------===## -import contextlib -import subprocess import os +import subprocess # OS_ARCH_COMBOS maps from OS and platform to the OpenSSL assembly "style" for @@ -45,85 +44,85 @@ def FindCMakeFiles(directory): - """Returns list of all CMakeLists.txt files recursively in directory.""" - cmakefiles = [] + """Returns list of all CMakeLists.txt files recursively in directory.""" + cmakefiles = [] - for (path, _, filenames) in os.walk(directory): - for filename in filenames: - if filename == 'CMakeLists.txt': - cmakefiles.append(os.path.join(path, filename)) + for (path, _, filenames) in os.walk(directory): + for filename in filenames: + if filename == 'CMakeLists.txt': + cmakefiles.append(os.path.join(path, filename)) - return cmakefiles + return cmakefiles def ExtractPerlAsmFromCMakeFile(cmakefile): - """Parses the contents of the CMakeLists.txt file passed as an argument and - returns a list of all the perlasm() directives found in the file.""" - perlasms = [] - with open(cmakefile) as f: - for line in f: - line = line.strip() - if not line.startswith('perlasm('): - continue - if not line.endswith(')'): - raise ValueError('Bad perlasm line in %s' % cmakefile) - # Remove "perlasm(" from start and ")" from end - params = line[8:-1].split() - if len(params) < 4: - raise ValueError('Bad perlasm line in %s: %s' % (cmakefile, line)) - perlasms.append({ - 'arch': params[1], - 'output': os.path.join(os.path.dirname(cmakefile), params[2]), - 'input': os.path.join(os.path.dirname(cmakefile), params[3]), - 'extra_args': params[4:] - }) - - return perlasms + """Parses the contents of the CMakeLists.txt file passed as an argument and + returns a list of all the perlasm() directives found in the file.""" + perlasms = [] + with open(cmakefile) as f: + for line in f: + line = line.strip() + if not line.startswith('perlasm('): + continue + if not line.endswith(')'): + raise ValueError('Bad perlasm line in %s' % cmakefile) + # Remove "perlasm(" from start and ")" from end + params = line[8:-1].split() + if len(params) < 4: + raise ValueError('Bad perlasm line in %s: %s' % (cmakefile, line)) + perlasms.append({ + 'arch': params[1], + 'output': os.path.join(os.path.dirname(cmakefile), params[2]), + 'input': os.path.join(os.path.dirname(cmakefile), params[3]), + 'extra_args': params[4:] + }) + + return perlasms def ReadPerlAsmOperations(): - """Returns a list of all perlasm() directives found in CMake config files in - src/.""" - perlasms = [] - cmakefiles = FindCMakeFiles('boringssl') + """Returns a list of all perlasm() directives found in CMake config files in + src/.""" + perlasms = [] + cmakefiles = FindCMakeFiles('boringssl') - for cmakefile in cmakefiles: - perlasms.extend(ExtractPerlAsmFromCMakeFile(cmakefile)) + for cmakefile in cmakefiles: + perlasms.extend(ExtractPerlAsmFromCMakeFile(cmakefile)) - return perlasms + return perlasms def PerlAsm(output_filename, input_filename, perlasm_style, extra_args): - """Runs the a perlasm script and puts the output into output_filename.""" - base_dir = os.path.dirname(output_filename) - if not os.path.isdir(base_dir): - os.makedirs(base_dir) - subprocess.check_call( - ['perl', input_filename, perlasm_style] + extra_args + [output_filename]) + """Runs the a perlasm script and puts the output into output_filename.""" + base_dir = os.path.dirname(output_filename) + if not os.path.isdir(base_dir): + os.makedirs(base_dir) + subprocess.check_call( + ['perl', input_filename, perlasm_style] + extra_args + [output_filename]) + def WriteAsmFiles(perlasms): - """Generates asm files from perlasm directives for each supported OS x - platform combination.""" - asmfiles = {} - - for perlasm in perlasms: - for (osname, arch, perlasm_style, extra_args, asm_ext) in OS_ARCH_COMBOS: - if arch != perlasm['arch']: - continue - key = (osname, arch) - outDir = '%s-%s' % key - - filename = os.path.basename(perlasm['input']) - output = perlasm['output'] - if not output.startswith('boringssl/crypto'): - raise ValueError('output missing crypto: %s' % output) - output = os.path.join(outDir, output[17:]) - output = '%s-%s.%s' % (output, osname, asm_ext) - per_command_extra_args = extra_args + perlasm['extra_args'] - PerlAsm(output, perlasm['input'], perlasm_style, per_command_extra_args) - asmfiles.setdefault(key, []).append(output) - - return asmfiles + """Generates asm files from perlasm directives for each supported OS x + platform combination.""" + asmfiles = {} + + for perlasm in perlasms: + for (osname, arch, perlasm_style, extra_args, asm_ext) in OS_ARCH_COMBOS: + if arch != perlasm['arch']: + continue + key = (osname, arch) + outDir = '%s-%s' % key + + output = perlasm['output'] + if not output.startswith('boringssl/crypto'): + raise ValueError('output missing crypto: %s' % output) + output = os.path.join(outDir, output[17:]) + output = '%s-%s.%s' % (output, osname, asm_ext) + per_command_extra_args = extra_args + perlasm['extra_args'] + PerlAsm(output, perlasm['input'], perlasm_style, per_command_extra_args) + asmfiles.setdefault(key, []).append(output) + + return asmfiles def preprocessor_arch_for_arch(arch): @@ -146,7 +145,7 @@ def preprocessor_platform_for_os(osname): def asm_target(osname, arch, asm): components = asm.split('/') - new_components = ["boringssl/crypto"] + components[1:-1] + [components[-1].replace('.S', '.' + osname + '.' + arch + '.S')] + new_components = ["boringssl/crypto"] + components[1:-1] + [components[-1].replace('.S', '.' + osname + '.' + arch + '.S')] # noqa: E501 return '/'.join(new_components) @@ -154,11 +153,11 @@ def munge_file(pp_arch, pp_platform, source_lines, sink): """ Wraps a single assembly file in appropriate defines. """ - sink.write("#if defined({0}) && defined({1})\n".format(pp_arch, pp_platform).encode()) + sink.write("#if defined({0}) && defined({1})\n".format(pp_arch, pp_platform).encode()) # noqa: E501 for line in source_lines: sink.write(line) - sink.write("#endif // defined({0}) && defined({1})\n".format(pp_arch, pp_platform).encode()) + sink.write("#endif // defined({0}) && defined({1})\n".format(pp_arch, pp_platform).encode()) # noqa: E501 def munge_all_files(osname, arch, asms): @@ -175,7 +174,6 @@ def munge_all_files(osname, arch, asms): munge_file(pp_arch, pp_platform, source, sink) - def main(): # First, we build all the .S files using the helper from boringssl. asm_outputs = WriteAsmFiles(ReadPerlAsmOperations()) @@ -188,15 +186,15 @@ def main(): for ((osname, arch), asm_files) in NON_PERL_FILES.items(): for asm_file in asm_files: - with open(asm_file, 'rb') as f: - lines = f.readlines() + with open(asm_file, 'rb') as f: + lines = f.readlines() - pp_arch = preprocessor_arch_for_arch(arch) - pp_platform = preprocessor_platform_for_os(osname) + pp_arch = preprocessor_arch_for_arch(arch) + pp_platform = preprocessor_platform_for_os(osname) + + with open(asm_file, 'wb') as sink: + munge_file(pp_arch, pp_platform, lines, sink) - with open(asm_file, 'wb') as sink: - munge_file(pp_arch, pp_platform, lines, sink) if __name__ == '__main__': main() - diff --git a/scripts/check-docs.sh b/scripts/check-docs.sh deleted file mode 100755 index 9405b7eb4..000000000 --- a/scripts/check-docs.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -##===----------------------------------------------------------------------===## -## -## This source file is part of the SwiftNIO open source project -## -## Copyright (c) 2023 Apple Inc. and the SwiftNIO project authors -## Licensed under Apache License v2.0 -## -## See LICENSE.txt for license information -## See CONTRIBUTORS.txt for the list of SwiftNIO project authors -## -## SPDX-License-Identifier: Apache-2.0 -## -##===----------------------------------------------------------------------===## - -set -eu - -raw_targets=$(sed -E -n -e 's/^.* - documentation_targets: \[(.*)\].*$/\1/p' .spi.yml) -targets=(${raw_targets//,/ }) - -for target in "${targets[@]}"; do - swift package plugin generate-documentation --target "$target" --warnings-as-errors --analyze --level detailed -done diff --git a/scripts/check_no_api_breakages.sh b/scripts/check_no_api_breakages.sh deleted file mode 100755 index 4e2db709b..000000000 --- a/scripts/check_no_api_breakages.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/bin/bash -##===----------------------------------------------------------------------===## -## -## This source file is part of the SwiftNIO open source project -## -## Copyright (c) 2017-2018 Apple Inc. and the SwiftNIO project authors -## Licensed under Apache License v2.0 -## -## See LICENSE.txt for license information -## See CONTRIBUTORS.txt for the list of SwiftNIO project authors -## -## SPDX-License-Identifier: Apache-2.0 -## -##===----------------------------------------------------------------------===## - -set -eu - -function usage() { - echo >&2 "Usage: $0 REPO-GITHUB-URL NEW-VERSION OLD-VERSIONS..." - echo >&2 - echo >&2 "This script requires a Swift 5.6+ toolchain." - echo >&2 - echo >&2 "Examples:" - echo >&2 - echo >&2 "Check between main and tag 2.1.1 of swift-nio:" - echo >&2 " $0 https://github.com/apple/swift-nio main 2.1.1" - echo >&2 - echo >&2 "Check between HEAD and commit 64cf63d7 using the provided toolchain:" - echo >&2 " xcrun --toolchain org.swift.5120190702a $0 ../some-local-repo HEAD 64cf63d7" -} - -if [[ $# -lt 3 ]]; then - usage - exit 1 -fi - -tmpdir=$(mktemp -d /tmp/.check-api_XXXXXX) -repo_url=$1 -new_tag=$2 -shift 2 - -repodir="$tmpdir/repo" -git clone "$repo_url" "$repodir" -git -C "$repodir" fetch -q origin '+refs/pull/*:refs/remotes/origin/pr/*' -cd "$repodir" -git checkout -q "$new_tag" - -for old_tag in "$@"; do - echo "Checking public API breakages from $old_tag to $new_tag" - - swift package diagnose-api-breaking-changes "$old_tag" -done - -echo done diff --git a/scripts/cxx-interop-compatibility.sh b/scripts/cxx-interop-compatibility.sh deleted file mode 100755 index c0ee923b6..000000000 --- a/scripts/cxx-interop-compatibility.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/bin/bash -##===----------------------------------------------------------------------===## -## -## This source file is part of the SwiftNIO open source project -## -## Copyright (c) 2023 Apple Inc. and the SwiftNIO project authors -## Licensed under Apache License v2.0 -## -## See LICENSE.txt for license information -## See CONTRIBUTORS.txt for the list of SwiftNIO project authors -## -## SPDX-License-Identifier: Apache-2.0 -## -##===----------------------------------------------------------------------===## - -set -eu - -sourcedir=$(pwd) -workingdir=$(mktemp -d) -projectname=$(basename $workingdir) - -cd $workingdir -swift package init - -cat << EOF > Package.swift -// swift-tools-version: 5.9 - -import PackageDescription - -let package = Package( - name: "interop", - products: [ - .library( - name: "interop", - targets: ["interop"] - ), - ], - dependencies: [ - .package(path: "$sourcedir") - ], - targets: [ - .target( - name: "interop", - // Depend on all non-executable products of swift-nio-ssl to make - // sure they're all compatible with cxx interop. - dependencies: [ - .product(name: "NIOSSL", package: "swift-nio-ssl") - ], - swiftSettings: [.interoperabilityMode(.Cxx)] - ) - ] -) -EOF - -cat << EOF > Sources/$projectname/$(echo $projectname | tr . _).swift -import NIOSSL -EOF - -swift build diff --git a/scripts/integration_tests.sh b/scripts/integration_tests.sh index 083c59bf0..496a08dc5 100755 --- a/scripts/integration_tests.sh +++ b/scripts/integration_tests.sh @@ -13,5 +13,7 @@ ## ##===----------------------------------------------------------------------===## +set +ex + mkdir -p .build # for the junit.xml file -./IntegrationTests/run-tests.sh --junit-xml .build/junit-sh-tests.xml -i +./IntegrationTests/run-tests.sh --junit-xml .build/junit-sh-tests.xml -i "$@" diff --git a/scripts/soundness.sh b/scripts/soundness.sh deleted file mode 100755 index 2186a2e47..000000000 --- a/scripts/soundness.sh +++ /dev/null @@ -1,160 +0,0 @@ -#!/bin/bash -##===----------------------------------------------------------------------===## -## -## This source file is part of the SwiftNIO open source project -## -## Copyright (c) 2017-2022 Apple Inc. and the SwiftNIO project authors -## Licensed under Apache License v2.0 -## -## See LICENSE.txt for license information -## See CONTRIBUTORS.txt for the list of SwiftNIO project authors -## -## SPDX-License-Identifier: Apache-2.0 -## -##===----------------------------------------------------------------------===## - -set -eu -here="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -function replace_acceptable_years() { - # this needs to replace all acceptable forms with 'YEARS' - sed -e 's/20[12][78901234]-20[12][8901234]/YEARS/' -e 's/20[12][8901234]/YEARS/' -} - -printf "=> Checking for unacceptable language... " -# This greps for unacceptable terminology. The square bracket[s] are so that -# "git grep" doesn't find the lines that greps :). -# We exclude the vendored BoringSSL copy from this check. -unacceptable_terms=( - -e blacklis[t] - -e whitelis[t] - -e slav[e] - -e sanit[y] -) -if git grep --color=never -i "${unacceptable_terms[@]}" ':(exclude)Sources/CNIOBoring*' ':(exclude)CODE_OF_CONDUCT.md' > /dev/null; then - printf "\033[0;31mUnacceptable language found.\033[0m\n" - git grep -i "${unacceptable_terms[@]}" ':(exclude)Sources/CNIOBoring*' ':(exclude)CODE_OF_CONDUCT.md' - exit 1 -fi -printf "\033[0;32mokay.\033[0m\n" - -# This checks for the umbrella NIO module. -printf "=> Checking for imports of umbrella NIO module... " -if git grep --color=never -i "^[ \t]*import \+NIO[ \t]*$" > /dev/null; then - printf "\033[0;31mUmbrella imports found.\033[0m\n" - git grep -i "^[ \t]*import \+NIO[ \t]*$" - exit 1 -fi -printf "\033[0;32mokay.\033[0m\n" - -printf "=> Checking license headers... " -tmp=$(mktemp /tmp/.swift-nio-soundness_XXXXXX) - -for language in swift-or-c bash dtrace python; do - declare -a matching_files - declare -a exceptions - expections=( ) - matching_files=( -name '*' ) - case "$language" in - swift-or-c) - exceptions=( -path '*Sources/CNIOBoringSSL/*' -o -name 'Package.swift' -o -name 'Package@swift*.swift') - matching_files=( -name '*.swift' -o -name '*.c' -o -name '*.h' ) - cat > "$tmp" <<"EOF" -//===----------------------------------------------------------------------===// -// -// This source file is part of the SwiftNIO open source project -// -// Copyright (c) YEARS Apple Inc. and the SwiftNIO project authors -// Licensed under Apache License v2.0 -// -// See LICENSE.txt for license information -// See CONTRIBUTORS.txt for the list of SwiftNIO project authors -// -// SPDX-License-Identifier: Apache-2.0 -// -//===----------------------------------------------------------------------===// -EOF - ;; - bash) - matching_files=( -name '*.sh' ) - cat > "$tmp" <<"EOF" -#!/bin/bash -##===----------------------------------------------------------------------===## -## -## This source file is part of the SwiftNIO open source project -## -## Copyright (c) YEARS Apple Inc. and the SwiftNIO project authors -## Licensed under Apache License v2.0 -## -## See LICENSE.txt for license information -## See CONTRIBUTORS.txt for the list of SwiftNIO project authors -## -## SPDX-License-Identifier: Apache-2.0 -## -##===----------------------------------------------------------------------===## -EOF - ;; - dtrace) - matching_files=( -name '*.d' ) - cat > "$tmp" <<"EOF" -#!/usr/sbin/dtrace -q -s -/*===----------------------------------------------------------------------===* - * - * This source file is part of the SwiftNIO open source project - * - * Copyright (c) YEARS Apple Inc. and the SwiftNIO project authors - * Licensed under Apache License v2.0 - * - * See LICENSE.txt for license information - * See CONTRIBUTORS.txt for the list of SwiftNIO project authors - * - * SPDX-License-Identifier: Apache-2.0 - * - *===----------------------------------------------------------------------===*/ -EOF - ;; - python) - matching_files=( -name '*.py' ) - cat > "$tmp" <<"EOF" -#!/usr/bin/env python3 -##===----------------------------------------------------------------------===## -## -## This source file is part of the SwiftNIO open source project -## -## Copyright (c) YEARS Apple Inc. and the SwiftNIO project authors -## Licensed under Apache License v2.0 -## -## See LICENSE.txt for license information -## See CONTRIBUTORS.txt for the list of SwiftNIO project authors -## -## SPDX-License-Identifier: Apache-2.0 -## -##===----------------------------------------------------------------------===## -EOF - ;; - *) - echo >&2 "ERROR: unknown language '$language'" - ;; - esac - - expected_lines=$(cat "$tmp" | wc -l) - expected_sha=$(cat "$tmp" | shasum) - - ( - cd "$here/.." - find . \ - \( \! -path './.build/*' -a \ - \! -path './.xcode/*' -a \ - \( "${matching_files[@]}" \) -a \ - \( \! \( "${exceptions[@]}" \) \) \) | while read line; do - if [[ "$(cat "$line" | replace_acceptable_years | head -n $expected_lines | shasum)" != "$expected_sha" ]]; then - printf "\033[0;31mmissing headers in file '$line'!\033[0m\n" - diff -u <(cat "$line" | replace_acceptable_years | head -n $expected_lines) "$tmp" - exit 1 - fi - done - printf "\033[0;32mokay.\033[0m\n" - ) -done - -rm "$tmp" diff --git a/scripts/vendor-boringssl.sh b/scripts/vendor-boringssl.sh index f7c747830..01746510b 100755 --- a/scripts/vendor-boringssl.sh +++ b/scripts/vendor-boringssl.sh @@ -105,9 +105,9 @@ function mangle_symbols { ) # Now cross compile for our targets. - docker run -t -i --rm --privileged -v$(pwd):/src -w/src --platform linux/arm64 swift:5.9-jammy \ + docker run -t -i --rm --privileged -v"$(pwd)":/src -w/src --platform linux/arm64 swift:5.9-jammy \ swift build --product CNIOBoringSSL - docker run -t -i --rm --privileged -v$(pwd):/src -w/src --platform linux/amd64 swift:5.9-jammy \ + docker run -t -i --rm --privileged -v"$(pwd)":/src -w/src --platform linux/amd64 swift:5.9-jammy \ swift build --product CNIOBoringSSL # Now we need to generate symbol mangles for Linux. We can do this in @@ -137,10 +137,10 @@ function mangle_symbols { echo "ADDING symbol mangling" perl -pi -e '$_ .= qq(\n#define BORINGSSL_PREFIX CNIOBoringSSL\n) if /#define OPENSSL_HEADER_BASE_H/' "$DSTROOT/include/openssl/base.h" - for assembly_file in $(find "$DSTROOT" -name "*.S") + while IFS= read -r -d '' assembly_file do $sed -i '1 i #define BORINGSSL_PREFIX CNIOBoringSSL' "$assembly_file" - done + done < <(find "$DSTROOT" -name "*.S" -print0) namespace_inlines "$DSTROOT" } @@ -184,6 +184,7 @@ case "$(uname -s)" in sed=gsed ;; *) + # shellcheck disable=SC2209 sed=sed ;; esac @@ -258,7 +259,7 @@ echo "COPYING boringssl" for pattern in "${PATTERNS[@]}" do for i in $SRCROOT/$pattern; do - path=${i#$SRCROOT} + path=${i#"$SRCROOT"} dest="$DSTROOT$path" dest_dir=$(dirname "$dest") mkdir -p "$dest_dir" @@ -291,6 +292,7 @@ echo "RENAMING header files" rm -rf include/pki # Now change the imports from " to "", apply the same prefix to the 'boringssl_prefix_symbols' headers. + # shellcheck disable=SC2038 find . -name "*.[ch]" -or -name "*.cc" -or -name "*.S" -or -name "*.c.inc" | xargs $sed -i -r -e 's#include ]+/)*)(.+.h)>#include <\1CNIOBoringSSL_\3>#' -e 's+include ]+/)*)(.+.h)"#include "\1CNIOBoringSSL_\3"#' # Okay now we need to rename the headers adding the prefix "CNIOBoringSSL_". @@ -299,6 +301,7 @@ echo "RENAMING header files" for x in **/*.h; do mv -- "$x" "${x%/*}/CNIOBoringSSL_${x##*/}"; done # Finally, make sure we refer to them by their prefixed names, and change any includes from angle brackets to quotation marks. + # shellcheck disable=SC2038 find . -name "*.h" | xargs $sed -i -r -e 's#include "(([^/"]+/)*)(.+.h)"#include "\1CNIOBoringSSL_\3"#' -e 's/include /include "CNIOBoringSSL_\1"/' popd ) @@ -312,6 +315,7 @@ git apply "${HERE}/scripts/patch-3-more-inttypes.patch" echo "PROTECTING against executable stacks" ( cd "$DSTROOT" + # shellcheck disable=SC2038 find . -name "*.S" | xargs $sed -i '$ a #if defined(__linux__) && defined(__ELF__)\n.section .note.GNU-stack,"",%progbits\n#endif\n' )