You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
101 lines
3.5 KiB
101 lines
3.5 KiB
//////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FoundationSecurity.swift
|
|
// Starscream
|
|
//
|
|
// Created by Dalton Cherry on 3/16/19.
|
|
// Copyright © 2019 Vluxe. All rights reserved.
|
|
//
|
|
// Licensed 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 CommonCrypto
|
|
|
|
public enum FoundationSecurityError: Error {
|
|
case invalidRequest
|
|
}
|
|
|
|
public class FoundationSecurity {
|
|
var allowSelfSigned = false
|
|
|
|
public init(allowSelfSigned: Bool = false) {
|
|
self.allowSelfSigned = allowSelfSigned
|
|
}
|
|
|
|
|
|
}
|
|
|
|
extension FoundationSecurity: CertificatePinning {
|
|
public func evaluateTrust(trust: SecTrust, domain: String?, completion: ((PinningState) -> ())) {
|
|
if allowSelfSigned {
|
|
completion(.success)
|
|
return
|
|
}
|
|
|
|
if let validateDomain = domain {
|
|
SecTrustSetPolicies(trust, SecPolicyCreateSSL(true, validateDomain as NSString?))
|
|
}
|
|
|
|
handleSecurityTrust(trust: trust, completion: completion)
|
|
}
|
|
|
|
private func handleSecurityTrust(trust: SecTrust, completion: ((PinningState) -> ())) {
|
|
if #available(iOS 12.0, OSX 10.14, watchOS 5.0, tvOS 12.0, *) {
|
|
var error: CFError?
|
|
if SecTrustEvaluateWithError(trust, &error) {
|
|
completion(.success)
|
|
} else {
|
|
completion(.failed(error))
|
|
}
|
|
} else {
|
|
handleOldSecurityTrust(trust: trust, completion: completion)
|
|
}
|
|
}
|
|
|
|
private func handleOldSecurityTrust(trust: SecTrust, completion: ((PinningState) -> ())) {
|
|
var result: SecTrustResultType = .unspecified
|
|
SecTrustEvaluate(trust, &result)
|
|
if result == .unspecified || result == .proceed {
|
|
completion(.success)
|
|
} else {
|
|
let e = CFErrorCreate(kCFAllocatorDefault, "FoundationSecurityError" as NSString?, Int(result.rawValue), nil)
|
|
completion(.failed(e))
|
|
}
|
|
}
|
|
}
|
|
|
|
extension FoundationSecurity: HeaderValidator {
|
|
public func validate(headers: [String: String], key: String) -> Error? {
|
|
if let acceptKey = headers[HTTPWSHeader.acceptName] {
|
|
let sha = "\(key)258EAFA5-E914-47DA-95CA-C5AB0DC85B11".sha1Base64()
|
|
if sha != acceptKey {
|
|
return WSError(type: .securityError, message: "accept header doesn't match", code: SecurityErrorCode.acceptFailed.rawValue)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
|
|
private extension String {
|
|
func sha1Base64() -> String {
|
|
let data = self.data(using: .utf8)!
|
|
let pointer = data.withUnsafeBytes { (bytes: UnsafeRawBufferPointer) -> [UInt8] in
|
|
var digest = [UInt8](repeating: 0, count:Int(CC_SHA1_DIGEST_LENGTH))
|
|
CC_SHA1(bytes.baseAddress, CC_LONG(data.count), &digest)
|
|
return digest
|
|
}
|
|
return Data(pointer).base64EncodedString()
|
|
}
|
|
}
|