summaryrefslogtreecommitdiffstats
path: root/src/jaegertracing/thrift/lib/swift/Sources/TSSLSocketTransport.swift
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/jaegertracing/thrift/lib/swift/Sources/TSSLSocketTransport.swift236
1 files changed, 236 insertions, 0 deletions
diff --git a/src/jaegertracing/thrift/lib/swift/Sources/TSSLSocketTransport.swift b/src/jaegertracing/thrift/lib/swift/Sources/TSSLSocketTransport.swift
new file mode 100644
index 000000000..d350f821e
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/swift/Sources/TSSLSocketTransport.swift
@@ -0,0 +1,236 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+import Foundation
+import CoreFoundation
+
+#if !swift(>=4.2)
+// Swift 3/4 compatibility
+fileprivate extension RunLoopMode {
+ static let `default` = defaultRunLoopMode
+}
+#endif
+
+#if os(Linux)
+public class TSSLSocketTransport {
+ init(hostname: String, port: UInt16) {
+ // FIXME!
+ assert(false, "Security not available in Linux, TSSLSocketTransport Unavilable for now")
+ }
+}
+#else
+let isLittleEndian = Int(OSHostByteOrder()) == OSLittleEndian
+let htons = isLittleEndian ? _OSSwapInt16 : { $0 }
+let htonl = isLittleEndian ? _OSSwapInt32 : { $0 }
+
+public class TSSLSocketTransport: TStreamTransport {
+ var sslHostname: String
+ var sd: Int32 = 0
+
+ public init(hostname: String, port: UInt16) throws {
+ sslHostname = hostname
+ var readStream: Unmanaged<CFReadStream>?
+ var writeStream: Unmanaged<CFWriteStream>?
+
+ /* create a socket structure */
+ var pin: sockaddr_in = sockaddr_in()
+ var hp: UnsafeMutablePointer<hostent>? = nil
+ for i in 0..<10 {
+
+ hp = gethostbyname(hostname.cString(using: String.Encoding.utf8)!)
+ if hp == nil {
+ print("failed to resolve hostname \(hostname)")
+ herror("resolv")
+ if i == 9 {
+ super.init(inputStream: nil, outputStream: nil) // have to init before throwing
+ throw TSSLSocketTransportError(error: .hostanameResolution(hostname: hostname))
+ }
+ Thread.sleep(forTimeInterval: 0.2)
+ } else {
+ break
+ }
+ }
+ pin.sin_family = UInt8(AF_INET)
+ pin.sin_addr = in_addr(s_addr: UInt32((hp?.pointee.h_addr_list.pointee?.pointee)!)) // Is there a better way to get this???
+ pin.sin_port = htons(port)
+
+ /* create the socket */
+ sd = socket(Int32(AF_INET), Int32(SOCK_STREAM), Int32(IPPROTO_TCP))
+ if sd == -1 {
+ super.init(inputStream: nil, outputStream: nil) // have to init before throwing
+ throw TSSLSocketTransportError(error: .socketCreate(port: Int(port)))
+ }
+
+ /* open a connection */
+ // need a non-self ref to sd, otherwise the j complains
+ let sd_local = sd
+ let connectResult = withUnsafePointer(to: &pin) {
+ connect(sd_local, UnsafePointer<sockaddr>(OpaquePointer($0)), socklen_t(MemoryLayout<sockaddr_in>.size))
+ }
+ if connectResult == -1 {
+ super.init(inputStream: nil, outputStream: nil) // have to init before throwing
+ throw TSSLSocketTransportError(error: .connect)
+ }
+
+ CFStreamCreatePairWithSocket(kCFAllocatorDefault, sd, &readStream, &writeStream)
+
+ CFReadStreamSetProperty(readStream?.takeRetainedValue(), .socketNativeHandle, kCFBooleanTrue)
+ CFWriteStreamSetProperty(writeStream?.takeRetainedValue(), .socketNativeHandle, kCFBooleanTrue)
+
+ var inputStream: InputStream? = nil
+ var outputStream: OutputStream? = nil
+ if readStream != nil && writeStream != nil {
+
+ CFReadStreamSetProperty(readStream?.takeRetainedValue(),
+ .socketSecurityLevel,
+ kCFStreamSocketSecurityLevelTLSv1)
+
+ let settings: [String: Bool] = [kCFStreamSSLValidatesCertificateChain as String: true]
+
+ CFReadStreamSetProperty(readStream?.takeRetainedValue(),
+ .SSLSettings,
+ settings as CFTypeRef)
+
+ CFWriteStreamSetProperty(writeStream?.takeRetainedValue(),
+ .SSLSettings,
+ settings as CFTypeRef)
+
+ inputStream = readStream!.takeRetainedValue()
+ inputStream?.schedule(in: .current, forMode: .default)
+ inputStream?.open()
+
+ outputStream = writeStream!.takeRetainedValue()
+ outputStream?.schedule(in: .current, forMode: .default)
+ outputStream?.open()
+
+ readStream?.release()
+ writeStream?.release()
+ }
+
+
+ super.init(inputStream: inputStream, outputStream: outputStream)
+ self.input?.delegate = self
+ self.output?.delegate = self
+ }
+
+ func recoverFromTrustFailure(_ myTrust: SecTrust, lastTrustResult: SecTrustResultType) -> Bool {
+ let trustTime = SecTrustGetVerifyTime(myTrust)
+ let currentTime = CFAbsoluteTimeGetCurrent()
+
+ let timeIncrement = 31536000 // from TSSLSocketTransport.m
+ let newTime = currentTime - Double(timeIncrement)
+
+ if trustTime - newTime != 0 {
+ let newDate = CFDateCreate(nil, newTime)
+ SecTrustSetVerifyDate(myTrust, newDate!)
+
+ var tr = lastTrustResult
+ let success = withUnsafeMutablePointer(to: &tr) { trPtr -> Bool in
+ if SecTrustEvaluate(myTrust, trPtr) != errSecSuccess {
+ return false
+ }
+ return true
+ }
+ if !success { return false }
+ }
+ if lastTrustResult == .proceed || lastTrustResult == .unspecified {
+ return false
+ }
+
+ print("TSSLSocketTransport: Unable to recover certificate trust failure")
+ return true
+ }
+
+ public func isOpen() -> Bool {
+ return sd > 0
+ }
+}
+
+extension TSSLSocketTransport: StreamDelegate {
+ public func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
+
+ switch eventCode {
+ case Stream.Event(): break
+ case Stream.Event.hasBytesAvailable: break
+ case Stream.Event.openCompleted: break
+ case Stream.Event.hasSpaceAvailable:
+ var proceed = false
+ var trustResult: SecTrustResultType = .invalid
+
+ var newPolicies: CFMutableArray?
+
+ repeat {
+ let trust: SecTrust = aStream.property(forKey: .SSLPeerTrust) as! SecTrust
+
+ // Add new policy to current list of policies
+ let policy = SecPolicyCreateSSL(false, sslHostname as CFString?)
+ var ppolicy = policy // mutable for pointer
+ let policies: UnsafeMutablePointer<CFArray?>? = nil
+ if SecTrustCopyPolicies(trust, policies!) != errSecSuccess {
+ break
+ }
+ withUnsafeMutablePointer(to: &ppolicy) { ptr in
+ newPolicies = CFArrayCreateMutableCopy(nil, 0, policies?.pointee)
+ CFArrayAppendValue(newPolicies, ptr)
+ }
+
+ // update trust policies
+ if SecTrustSetPolicies(trust, newPolicies!) != errSecSuccess {
+ break
+ }
+
+ // Evaluate the trust chain
+ let success = withUnsafeMutablePointer(to: &trustResult) { trustPtr -> Bool in
+ if SecTrustEvaluate(trust, trustPtr) != errSecSuccess {
+ return false
+ }
+ return true
+ }
+
+ if !success {
+ break
+ }
+
+
+ switch trustResult {
+ case .proceed: proceed = true
+ case .unspecified: proceed = true
+ case .recoverableTrustFailure:
+ proceed = self.recoverFromTrustFailure(trust, lastTrustResult: trustResult)
+
+ case .deny: break
+ case .fatalTrustFailure: break
+ case .otherError: break
+ case .invalid: break
+ default: break
+ }
+ } while false
+
+ if !proceed {
+ print("TSSLSocketTransport: Cannot trust certificate. Result: \(trustResult)")
+ aStream.close()
+ }
+
+ case Stream.Event.errorOccurred: break
+ case Stream.Event.endEncountered: break
+ default: break
+ }
+ }
+}
+#endif