Swiftpack.co - Package - IBM-Swift/BlueSSLService

APIDoc Build Status - Master macOS iOS Linux Apache 2 Slack Status

BlueSSLService

SSL/TLS Add-in framework for BlueSocket in Swift using the Swift Package Manager. Works on supported Apple platforms (using Secure Transport) and on Linux (using OpenSSL).

Prerequisites

Swift

  • Swift Open Source swift-4.0.0-RELEASE toolchain (Minimum REQUIRED for latest release)
  • Swift Open Source swift-4.2-RELEASE toolchain (Recommended)
  • Swift toolchain included in Xcode Version 10.0 (10A255) or higher.

macOS

  • macOS 10.11.6 (El Capitan) or higher.
  • Xcode Version 9.0 (9A325) or higher using one of the above toolchains.
  • Xcode Version 10.0 (10A255) or higher using the included toolchain (Recommended).
  • Secure Transport is provided by macOS.

iOS

  • iOS 10.0 or higher
  • Xcode Version 9.0 (9A325) or higher using one of the above toolchains.
  • Xcode Version 10.0 (10A255) or higher using the included toolchain (Recommended).
  • Secure Transport is provided by iOS.

Linux

  • Ubuntu 16.04 (or 16.10 but only tested on 16.04) and 18.04.
  • One of the Swift Open Source toolchain listed above.
  • OpenSSL is provided by the distribution. Note: 1.0.x, 1.1.x and later releases of OpenSSL are supported.
  • The appropriate libssl-dev package is required to be installed when building.

Other Platforms

  • BlueSSLService is NOT supported on watchOS since POSIX/BSD/Darwin sockets are not supported on the actual device although they are supported in the simulator.
  • BlueSSLService should work on tvOS but has NOT been tested.

Note: See Package.swift for details.

Build

To build SSLService from the command line:

% cd <path-to-clone>
% swift build

Testing

To run the supplied unit tests for SSLService from the command line:

% cd <path-to-clone>
% swift build
% swift test

Using BlueSSLService

Before starting

The first you need to do is import both the Socket and SSLService frameworks. This is done by the following:

import Socket
import SSLService

Creating the Configuration

Both clients and server require at a minimum the following configuration items:

  • CA Certficate (either caCertificateFile or caCertificateDirPath)
  • Application certificate (certificateFilePath)
  • Private Key file (keyFilePath)

or

  • Certificate Chain File (chainFilePath)

or, if using self-signed certificates:

  • Application certificate (certificateFilePath)
  • Private Key file (keyFilePath)

or, if running on Linux (for now),

  • A string containing a PEM formatted certificate

or, if running on macOS:

  • Certificate Chain File (chainFilePath) in PKCS12 format

or,

  • No certificate at all.

BlueSSLService provides five ways to create a Configuration supporting the scenarios above. These are:

  • init() - This API allows for the creation of default configuration. This is equivalent to calling the next initializer without changing any parameters.
  • init(withCipherSuite cipherSuite: String? = nil, clientAllowsSelfSignedCertificates: Bool = true) - This API allows for the creation of configuration that does not contain a backing certificate or certificate chain. You can optionally provide a cipherSuite and decide whether to allow, when in client mode, use of self-signed certificates by the server.
  • init(withCACertificatePath caCertificateFilePath: String?, usingCertificateFile certificateFilePath: String?, withKeyFile keyFilePath: String? = nil, usingSelfSignedCerts selfSigned: Bool = true, cipherSuite: String? = nil) - This API allows you to create a configuration using a self contained Certificate Authority (CA) file. The second parameter is the path to the Certificate file to be used by application to establish the connection. The next parameter is the path to the Private Key file used by application corresponding to the Public Key in the Certificate. If you're using self-signed certificates, set the last parameter to true.
  • init(withCACertificateDirectory caCertificateDirPath: String?, usingCertificateFile certificateFilePath: String?, withKeyFile keyFilePath: String? = nil, usingSelfSignedCerts selfSigned: Bool = true, cipherSuite: String? = nil) - This API allows you to create a configuration using a directory of Certificate Authority (CA) files. These CA certificates must be hashed using the Certificate Tool provided by OpenSSL. The following parameters are identical to the previous API.
  • init(withChainFilePath chainFilePath: String? = nil, withPassword password: String? = nil, usingSelfSignedCerts selfSigned: Bool = true, clientAllowsSelfSignedCertificates: Bool = false, cipherSuite: String? = nil) - This API allows you to create a configuration using a single Certificate Chain File (see note 2 below). Add an optional password (if required) using the third parameter. Set the third parameter to true if the certificates you are using are self-signed, otherwise set it to false. If configuring a client and you want that client to be able to connect to servers using self-signed certificates, set the fourth parameter to true.
  • init(withPEMCertificateString certificateString: String, usingSelfSignedCerts selfSigned: Bool = true, cipherSuite: String? = nil) - This API used when supplying a PEM formatted certificate presented as a String. NOTE: At present, this API is only available on Linux.

Note 1: All Certificate and Private Key files must be PEM format. If supplying a certificate via a String, it must be PEM formatted.

Note 2: If using a certificate chain file, the certificates must be in PEM format and must be sorted starting with the subject's certificate (actual client or server certificate), followed by intermediate CA certificates if applicable, and ending at the highest level (root) CA.

Note 3: For the first two versions of the API, if your Private key is included in your certificate file, you can omit this parameter and the API will use the same file name as specified for the certificate file.

Note 4: If you desire to customize the cipher suite used, you can do so by specifying the cipherSuite parameter when using one of the above initializers. If not specified, the default value is set to DEFAULT on Linux. On macOS, setting of this parameter is currently not supported and attempting to set it will result in unpredictable results. See the example below.

Note 5: If you're running on macOS, you must use the third form of init for the Configuration and provide a certificate chain file in PKCS12 format, supplying a password if needed.

Example

The following illustrates creating a configuration (on Linux) using the second form of the API above using a self-signed certificate file as the key file and not supplying a certificate chain file. It also illustrates setting the cipher suite to ALL from the default:

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"

...

Note: This example takes advantage of the default parameters available on the SSLService.Configuration.init function. Also, changing of the cipher suite on macOS is currently not supported.

Creating and using the SSLService

The following API is used to create the SSLService:

  • init?(usingConfiguration config: Configuration) throws - This will create an instance of the SSLService using a previously created Configuration.

Once the SSLService is created, it can applied to a previously created Socket instance that's just been created. This needs to be done before using the Socket. The following code snippet illustrates how to do this (again using Linux). Note: Exception handling omitted for brevity.


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)

The example above creates a SSL server socket. Replacing the socket.listen function with a socket.connect would result in an SSL client being created as illustrated below:

// Connect to the server...
try socket.connect(to: "someplace.org", port: 1337)

SSLService handles all the negotiation and setup for the secure transfer of data. The determining factor for whether or not a Socket is setup as a server or client Socket is API which is used to initiate a connection. listen() will cause the Socket to be setup as a server socket. Calling connect() results a client setup.

Extending Connection Verification

SSLService provides a callback mechanism should you need to specify additional verification logic. After creating the instance of SSLService, you can set the instance variable verifyCallback. This instance variable has the following signature:

public var verifyCallback: ((_ service: SSLService) -> (Bool, String?))? = nil

Setting this callback is not required. It defaults to nil unless set. The first parameter passed to your callback is the instance of SSLService that has this callback. This will allow you to access the public members of the SSLService instance in order to do additional verification. Upon completion, your callback should return a tuple. The first value is a Bool indicating the sucess or failure of the routine. The second value is an optional String value used to provide a description in the case where verification failed. In the event of callback failure, an exception will be thrown by the internal verification function. Important Note: To effectively use this callback requires knowledge of the platforms underlying secure transport service, Apple Secure Transport on supported Apple platforms and OpenSSL on Linux.

Skipping Connection Verification

If desired, SSLService can skip the connection verification. To accomplish this, set the property skipVerification to true after creating the SSLService instance. However, if the verifyCallback property (described above) is set, that callback will be called regardless of this setting. The default for property is false. It is NOT recommended that you skip the connection verification in a production environment unless you are providing verification via the verificationCallback.

Community

We love to talk server-side Swift and Kitura. Join our Slack to meet the team!

License

This library is licensed under Apache 2.0. Full license text is available in LICENSE.

Github

link
Stars: 63
Help us keep the lights on

Releases

1.0.36 - Dec 13, 2018

Version 1.0

SSL/TLS Add-in framework for BlueSocket in Swift using the Swift Package Manager. Works on supported Apple platforms (using Secure Transport) and on Linux (using OpenSSL).

Prerequisites

Swift

  • Swift Open Source swift-4.0.0-RELEASE toolchain (Minimum REQUIRED for latest release)
  • Swift Open Source swift-4.2-RELEASE toolchain (Recommended)
  • Swift toolchain included in Version 10.0 (10A255) or higher.

macOS

  • macOS 10.11.6 (El Capitan) or higher.
  • Xcode Version 9.0 (9A325) or higher using one of the above toolchains.
  • Xcode Version 10.0 (10A255) or higher using the included toolchain (Recommended).
  • Secure Transport is provided by macOS.

iOS

  • iOS 10.0 or higher
  • Xcode Version 9.0 (9A325) or higher using one of the above toolchains.
  • Xcode Version 10.0 (10A255) or higher using the included toolchain (Recommended).
  • Secure Transport is provided by iOS.

Linux

  • Ubuntu 16.04 (or 16.10 but only tested on 16.04 and 18.04).
  • One of the Swift Open Source toolchain listed above.
  • OpenSSL is provided by the distribution. Note: Only the 1.0.x releases of OpenSSL are currently supported.

Other Platforms

  • BlueSSLService is NOT supported on watchOS since POSIX/BSD/Darwin sockets are not supported on the actual device although they are supported in the simulator.
  • BlueSSLService should work on tvOS but has NOT been tested.

Changes since 1.0.0

  • Require latest version of BlueSocket.
  • Update to Swift 4.1.
  • Support SSL_OP* constants defined as longs. Use CLong to explicitly cast these options where used. PR #52.
  • Update to include Swift 4.2 in CI builds.
  • Added prerequisite that the libssl-dev package is required to be installed when building on Linux.
  • Minor license update.
  • Updates for Xcode 10 to project.
  • Swift 4.2 support. PR #57
  • Make Swift 4.2 the default compiler in project.
  • Rename Swift 4.2 OpenSSL system library target (#59)
  • Revert (#59) back to using OpenSSL module in 4.2 format. PR #60.
  • Update for Swift 4.2 and Xcode 10.
  • Add support for OpenSSL 1.1.x aa well as OpenSSL 1.0.x. PR #61.
  • Added CI support for building with Swift 5. PR #64.
  • Fixed handshake bug that could prevent a connection when BlueSSLService is used on the client side.
  • Added unit tests for cursory (at least for now) testing BlueSSLService.
  • Removed requirement of Swift 4.2 to support OpenSSL 1.1.x. OpenSSL 1.1.x is now supported using Swift 4.0, 4.1 and 4.2.
  • To avoid confusion regarding the availability of SSLService.Configuration APIs on supported platforms, added @available attributes to all the APIs that are only supported on the Linux platform. This will cause compile time errors if the wrong API is used on Apple platforms.

0.12.84 - Oct 10, 2017

This release minimally requires use of the swift-3.1.1-RELEASE toolchain or the swift-4.0.0-RELEASE toolchain which is recommended.

  • Compatible with Xcode 9.0 (9A235) General Release or higher using one of the above toolchains.
  • On Linux this release support OpenSSL 1.0.x only.
  • Corrected some issues with SSL error handling on Linux. PR #42.
  • Added framework target to Xcode project, issue #44.
  • Added Cathage support. #44. #45.
  • Remove build on Xcode 8.3.
  • CI updates.
  • Changes to adapt to Swift 4.1.

0.12.5 - Sep 29, 2016

This release minimally requires use of the swift-3.1.1-RELEASE toolchain or the swift-4.0.0-RELEASE toolchain which is recommended.

  • Compatible with Xcode 9.0 (9A235) General Release or higher using one of the above toolchains.

  • This version supports Apple Secure Transport on Apple Platforms and OpenSSL on Linux.

  • At present on Apple platforms, only PKCS12 files are accepted in the Configuration. You should use the init function described below and further in the README.md.

  • Also, on Apple platforms, changing of the cipherSuite property is not supported. Please use the default.

  • Added new parameter to init function in Configuration that allows optionally specifying a password for the PKCS12 certificate chain file. That signature now looks like this:

    public init(withChainFilePath chainFilePath: String?, withPassword password: String? = nil, usingSelfSignedCerts selfSigned: Bool = true)
    
  • Loosened up the too stringent certificate verification process.

  • Added client support when using Secure Transport on Apple platforms.

  • Added optional connection verification callback feature. See the section Extending Connection Verification in the README.md.

  • Added optional connection verification bypass feature. See the section Skipping Connection Verification in the README.md.

  • Allow use on iOS, tvOS and watchOS as well as macOS.

  • Use version 0.10.24 on master if you wish to use the version that uses OpenSSL on both platforms.

  • This version now merged onto master.

  • Added CI (PR#2).

  • Fixed Kitura issue -> #852

  • A new, defaulted to nil, optional parameter has been added to the end of each of the Configuration init functions. This feature allows the setting of the cipherSuite. If this parameter is set to nil, the default cipherSuite for the platform will be used. Note: Setting the cipher suite on Apple platforms is currently not supported and attempting to do so may result in unpredictable behavior. See the README.md for more information.

  • Added a new Configuration initializer that allows creating a Configuration that does NOT contain a backing certificate or certificate chain.

  • Fixed issue #959 from Kitura.

  • Added support (currently on Linux only) for creating a configuration that is based on PEM formatted certificate passed in as a string. Issue #10. See the README.md for information about the new configuration API. Note: This functionality has had only minimal testing. Use with caution and report any anomalies.

  • Fixed issue #11 by implementing issue #12 alleviating a performance hit when processing the PKCS12 file on macOS.

  • Fix for issue #983 from Kitura. On macOS, the SSLContext must only be used by one thread at a time. Access to use of it must be protected. Introduced a new SSLReadWriteDispatcher struct that allows for sync'ing access to the context when doing reads and writes. This effectively forces reads and write to occur serially.

  • Related to the above fix, apparently on Linux, simultaneous reads and writes are not thread safe. Used the previously introduced SSLReadWriteDispatcher struct that allows for sync'ing access when doing reads and writes. This effectively forces reads and write to occur serially.

  • Also on Linux, added a check to see if the remote connection has gone away prior to issuing a SSL_shutdown() request. This should alleviate the problem of apps receiving a SIGPIPE when attempting to shutdown SSL after the remote has already terminated.

  • Fixed issue #16. Default cipher suite was not being enabled on macOS.

  • More on issue #16. Enabled ECDH ciphers if linking with OpenSSL 1.0.2 or higher.

  • Fixed issue #18 and #19.

  • Merged PR #20.

  • Bug fixes related to rejected PR #21. On Linux, after SSL_read or SSL_write, need to get the last error using SSL_get_error(). The error is NOT in the return code. If returning from SSL_write and the error is SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE, an SSLError.retryNeeded exception is thrown. If we're returning from SSL_read under the same circumstances, we set the errno to EAGAIN and return -1.

  • Add an option to allow clients to connect to servers that are using self-signed certificates. PR #24.

  • The initializer used to create a configuration without a backing certificate should (when being used as a client) allow self-signed certificates. Reference closed PR #25.

  • Added podspec for cocoapod integration. PR #27.

  • Update podspec to include watchOS and tvOS. PR #29

  • Support of Xcode 9 Beta.

  • Fix for problem with using the default Configuration initializer. PR #30

  • Fix for problem when importing PKCS12 that causes index out of bounds and subsequent crash. PR #31

  • Support for ALPN. PR #26. Important Note: Usage of this functionality is dependent on the availability of version 1.0.2 of OpenSSL or higher at build and runtime.

  • Fix for using client certificates (Issue #28) via PR #33.

  • Automatically enabled ECDH ciphers if linking with OpenSSL v1.0.2 or higher. See related issue #16. Previously, this required the setting of a compile time switch. That requirement has been eliminated.

  • Reverted PR #33 to fix issue #36.

  • Changed the default enabled cipher list from "DEFAULT" to "DEFAULT:!DH". This effectively disables DH ciphers which is fine since currently there's no API to allow setup of the required DH keys.

  • Swift 4 Support.

  • Remove support for watchOS. See BlueSocket issue #87 for more information.

0.11.26 - Sep 8, 2016

This release minimally requires use of the swift-3.0-RELEASE toolchain or the swift-DEVELOPMENT-SNAPSHOT-2016-09-27-a toolchain which is recommended.

CAUTION: THIS RELEASE IS STILL STABILIZING. USE AT YOUR OWN RISK.

  • Compatible with Xcode 8 General Release using one of the above toolchains.

  • This version supports Apple Secure Transport on macOS and OpenSSL on Linux.

  • At present on macOS, only PKCS12 files are accepted in the Configuration. You should use the init function described below and further in the README.md.

  • Also, on macOS, changing of the cipherSuite property is not supported. Please use the default.

  • Added new parameter to init function in Configuration that allows optionally specifying a password for the PKCS12 certificate chain file. That signature now looks like this:

    public init(withChainFilePath chainFilePath: String? = nil, withPassword password: String? = nil, usingSelfSignedCerts selfSigned: Bool = true)
    
  • Loosened up the too stringent certificate verification process.

  • Added client support when using Secure Transport on macOS.

  • Added optional connection verification callback feature. See the section Extending Connection Verification in the README.md.

  • Allow use on iOS, tvOS and watchOS as well as macOS.

  • This version is experimental and relatively lightly tested.

  • Use version 0.10.x on master if you wish to use the version that uses OpenSSL on both platforms.

  • This version now merged onto master.

0.10.24 - Aug 19, 2016

This release minimally requires use of the swift-3.0-RELEASE toolchain or the swift-DEVELOPMENT-SNAPSHOT-2016-09-27-a toolchain which is recommended.

  • Compatible with Xcode 8 General Release using one of the above toolchains.
  • Added password property to Configuration.
  • Removed verifyConnection() function from delegate. Now handled internally.
  • Ensured that OpenSSL libraries are only initialized once.
  • Minor change to initialize delegate function of SSLServiceDelegate. SSLService.inititalize(isServer:) became SSLService.initialize(asServer:).
  • Loosened up the too stringent certificate verification process.