BlueSSLService
Swift 使用 Swift 包管理器为 BlueSocket 提供的 SSL/TLS 插件框架。在支持的 Apple 平台上工作(使用 Secure Transport)以及 Linux(使用 OpenSSL)。
先决条件
Swift
- Swift 开源工具链
swift-5.2-RELEASE
(对于最新版本,**最小要求**) - Swift 开源工具链
swift-5.5-RELEASE
(**推荐**) - 包含在 版本 11.0 或更高版本的 Xcode 中的 Swift 工具链。
BlueSSLService 2.0 版本及以上支持 Swift 5.2+。对于旧版 Swift,请参阅更早版本的 BlueSSLService。
macOS
- macOS 10.14.6(**莫贾韦**)或更高版本。
- 使用上述工具链之一,使用版本 11.0 或更高版本的 Xcode。
- 使用Xcode 12.5或更高版本,并使用包含的工具链(推荐)。
- macOS提供Secure Transport。
iOS
- iOS 10.0或更高版本
- 使用上述工具链之一,使用版本 11.0 或更高版本的 Xcode。
- 使用Xcode 12.5或更高版本,并使用包含的工具链(推荐)。
- iOS提供Secure Transport。
Linux
- Ubuntu 16.04(或16.10,但仅在16.04上进行了测试)和18.04。
- 上述列表中的Swift开源工具链之一。
- 发行版提供OpenSSL。 注意: 支持3.0.x和之后的OpenSSL版本。
- 构建时需要安装相应的libssl-dev软件包。
其他平台
- BlueSSLService在watchOS上不受支持,因为尽管在模拟器中支持POSIX/BSD/Darwin套接字,但它们在实际设备上不受支持。
- BlueSSLService应在tvOS上工作,但尚未进行测试。
注意: 详细信息请见Package.swift
。
构建
要从命令行构建SSLService
% cd <path-to-clone>
% swift build
测试
要从命令行运行提供的<口径 dni`=SSLService`单元测试
% cd <path-to-clone>
% swift build
% swift test
使用BlueSSLService
开始之前
首先您需要导入Socket
和SSLService
框架。这可以通过以下方式完成:
import Socket
import SSLService
创建配置
客户端和服务器至少需要以下配置项:
- CA证书(
caCertificateFile
或caCertificateDirPath
) - 应用证书(
certificateFilePath
) - 私钥文件(
keyFilePath
)
或者
- 证书链文件(
chainFilePath
)
或者,如果您使用自签名证书:
- 应用证书(
certificateFilePath
) - 私钥文件(
keyFilePath
)
或者,若在Linux上运行(目前如此),
- 包含PEM格式证书的字符串
或者,若在macOS上运行
- PKCS12格式的证书链文件(
chainFilePath
)
或者,
- 没有证书。
BlueSSLService 提供了五种创建支持上述情况配置的方法。仅在 Apple 平台上支持最后的版本。在 Linux 上,支持所有版本。这是由于当前 Apple Secure Transport 实现强加的限制。
init()
- 此 API 允许创建默认配置。这等同于调用下一个初始化器而不更改任何参数。init(withCipherSuite cipherSuite: String? = nil, clientAllowsSelfSignedCertificates: Bool = true)
- 此 API 允许创建不包含后置证书或证书链的配置。您可以选择提供cipherSuite
并决定在高客户端模式下,是否允许服务器使用自签名证书。init(withCACertificatePath caCertificateFilePath: String?, usingCertificateFile certificateFilePath: String?, withKeyFile keyFilePath: String? = nil, usingSelfSignedCerts selfSigned: Bool = true, cipherSuite: String? = nil)
- 此 API 允许您使用包含的证书授权(Certificate Authority, CA)
文件创建配置。第二个参数是用于应用建立连接的证书文件路径。下一个参数是用于与证书中的公钥对应的私钥文件的路径。如果您在使用自签名证书,将最后一个参数设置为true。init(withCACertificateDirectory caCertificateDirPath: String?, usingCertificateFile certificateFilePath: String?, withKeyFile keyFilePath: String? = nil, usingSelfSignedCerts selfSigned: Bool = true, cipherSuite: String? = nil)
- 此 API 允许您使用证书授权(Certificate Authority, CA)文件目录创建配置。这些 CA 证书必须是使用 OpenSSL 提供的证书工具散列的。以下参数与前一个 API 相同。init(withPEMCertificateString certificateString: String, usingSelfSignedCerts selfSigned: Bool = true, cipherSuite: String? = nil)
- 在提供以字符串形式表示的PEM格式证书时使用此API。 注意:目前此API仅在Linux上可用。init(withChainFilePath chainFilePath: String? = nil, withPassword password: String? = nil, usingSelfSignedCerts selfSigned: Bool = true, clientAllowsSelfSignedCertificates: Bool = false, cipherSuite: String? = nil)
- 此API允许您使用单个Certificate Chain File
(参看以下第2点)创建配置。使用第三个参数添加可选密码(如果需要)。如果使用的证书是自签名
的,则将第三个参数设置为true,否则设置为false。如果配置客户端并希望该客户端可以使用自签名
证书与服务器连接,则将第四个参数设置为true。
注意1:所有Certificate
和Private Key
文件必须是PEM
格式。如果通过字符串提供证书,则证书必须是PEM格式。
注意2:如果使用证书链文件,证书必须是PEM
格式,并且必须以主题证书(实际客户端或服务器证书)开始排序,然后是如果适用的话中间的CA
证书,最后是最高级别(根)的CA
。
注意3:对于API的第一和第二个版本,如果您的Private key
包含在您的证书文件中,您可以省略此参数,并且API将使用指定给证书文件的相同文件名。
注意4:如果您希望自定义使用的加密套件,可以在使用上述初始化方法之一时指定cipherSuite
参数。如果不指定,Linux上的默认值设置为DEFAULT
。在macOS上,目前不支持设置此参数,尝试设置它会导致结果不可预测。请参见下面的示例。
注意5:如果您正在macOS上运行,则必须使用最后一种形式的init
为Configuration
提供证书链文件,格式为PKCS12
,并在需要时提供password
。
示例
以下示例说明了使用第一种形式的API创建配置(在Linux上)使用自签名证书文件作为密钥文件,并且没有提供证书链文件。它还说明了将加密套件设置为默认值ALL
。
import SSLService
...
let myCertPath = "/opt/myApp/config/myCertificate.pem"
let myKeyPath = "/opt/myApp/config/myKeyFile.pem"
let myConfig = SSLService.Configuration(withCACertificateDirectory: nil, usingCertificateFile: myCertPath, withKeyFile: myKeyFile)
myConfig.cipherSuite = "ALL"
...
注意:此示例利用了SSLService.Configuration.init
函数上的可用default
参数。另外,在macOS上目前不支持更改加密套件。
创建并使用SSLService
以下API用于创建SSLService
init?(usingConfiguration config: Configuration) throws
- 这将使用先前创建的Configuration
创建SSLService
实例。
一旦创建了 SSLService
,它可以应用于刚刚创建的 Socket
实例。这必须在使用 Socket
之前完成。以下代码片段演示了如何实现(再次使用 Linux)。注意:为了简洁,省略了异常处理。
import Socket
import SSLService
...
// Create the configuration...
let myCertPath = "/opt/myApp/config/myCertificate.pem"
let myKeyPath = "/opt/myApp/config/myKeyFile.pem"
let myConfig = SSLService.Configuration(withCACertificateDirectory: nil, usingCertificateFile: myCertPath, withKeyFile: myKeyFile)
// Create the socket...
var socket = try Socket.create()
guard let socket = socket else {
fatalError("Could not create socket.")
}
// Create and attach the SSLService to the socket...
// - Note: if you're going to be using the same
// configuration over and over, it'd be
// better to create it in the beginning
// as `let` constant.
socket.delegate = try SSLService(usingConfiguration: myConfig)
// Start listening...
try socket.listen(on: 1337)
上面的示例创建了一个 SSL 服务器
套接字。将 socket.listen
函数替换为 socket.connect
将导致创建一个如以下所示的 SSL 客户端
。
// Connect to the server...
try socket.connect(to: "someplace.org", port: 1337)
SSLService
处理所有数据安全传输的协商和设置。是否将 Socket
设置为服务器或客户端 Socket
的决定因素是用于发起连接的 API。调用 listen()
将将 Socket
设置为服务器套接字。调用 connect()
将导致客户端设置。
扩展连接验证
SSLService
提供了一种回调机制,以便您可以指定 附加 验证逻辑。创建 SSLService
实例后,您可以设置实例变量 verifyCallback
。此实例变量具有以下签名
public var verifyCallback: ((_ service: SSLService) -> (Bool, String?))? = nil
设置此回调不是必需的。除非设置,否则默认为 nil
。您的回调将接收一个参数,即具有此回调的 SSLService
实例。这将允许您访问 SSLService
实例的公共成员,以便进行附加验证。完成验证后,您的回调应返回一个元组。第一个值是一个 Bool
,指示函数的成功或失败。第二个值是一个可选的 String
值,在验证失败的情况下用于提供描述。在回调失败的情况下,内部验证函数将抛出一个 exception
。重要提示:有效使用此回调需要了解底层安全传输服务,即 支持的苹果平台
上的 Apple Secure Transport
和 Linux
上的 OpenSSL
。
跳过连接验证
如果您需要,SSLService
可以 跳过 连接验证。要完成此操作,请在创建 SSLService
实例后将属性 skipVerification
设置为 true
。但是,如果设置了上面描述的 verifyCallback
属性,则会调用该回调,无论此设置如何。默认值是 false
。在 production
环境中跳过连接验证是 不推荐 的,除非您通过 verificationCallback
提供了验证。
社区
我们喜欢谈论服务器端Swift和Kitura。加入我们的Slack来认识团队!
许可
此库依据Apache 2.0协议授权。完整授权文本可在LICENSE中查看。