From 19fcec84d8d7d21e796c7624e521b60d28ee21ed Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 20:45:59 +0200 Subject: Adding upstream version 16.2.11+ds. Signed-off-by: Daniel Baumann --- .../lib/swift/Sources/TSSLSocketTransport.swift | 236 +++++++++++++++++++++ 1 file changed, 236 insertions(+) create mode 100644 src/jaegertracing/thrift/lib/swift/Sources/TSSLSocketTransport.swift (limited to 'src/jaegertracing/thrift/lib/swift/Sources/TSSLSocketTransport.swift') 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? + var writeStream: Unmanaged? + + /* create a socket structure */ + var pin: sockaddr_in = sockaddr_in() + var hp: UnsafeMutablePointer? = 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(OpaquePointer($0)), socklen_t(MemoryLayout.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? = 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 -- cgit v1.2.3