Skip to content

Latest commit

 

History

History
182 lines (128 loc) · 5.36 KB

README.md

File metadata and controls

182 lines (128 loc) · 5.36 KB

Transport Layer Security (TLS/SSL) for Swift

Transport Layer Security (TLS) is the successor to Secure Socket Layer 3.0 (SSL). SSL 3.0 was deprecated in June 2015. https://tools.ietf.org/html/rfc7568

Swift Build Status

A Swift wrapper for Transport Layer Security (TLS/SSL) using OpenSSL.

  • Swifty Interface
  • Client and Server
  • Tested

Examples

The examples below assume you already have a socket library and you want to add TLS. If you do not already have a socket library, check out Socks by Honza Dvorsky.

There is an add-on for Socks called SecretSocks that includes this TLS library and provides a convenient makeSecret() method for all Socks' sockets.

If you are using a different socket library, no need to worry. You only need access to the socket's file descriptor to use this package.

import TLS

let socket: MyUnsecureSocket

// Create an unsecure socket
// and grab its file descriptor.
// ...

let descriptor: Int32 = socket.mySocketDescriptor

Now that you have the descriptor, let's add TLS.

Client

This adds a Transport Security Layer for interacting with a server from a client. No certificates are required to be a client.

let context = try TLS.Context(mode: .client, certificates: .none)
let secureSocket = try TLS.Socket(context: context, descriptor: descriptor)

try secureSocket.connect()

Here a context is created. You should hold on to this context if you intend to create multiple sockets. Your socket descriptor is then used with the context to create an TLS.Socket.

The call to connect() creates the connection to the server to start sending and receiving data. This should be called after the unsecure socket has called its version of connect().

Server

This adds a Transport Security Layer for interacting with a client from a server. Setting up a server requires certificates.

let context = try TLS.Context(mode: .server, certificates: .files(
    certificateFile: "./Certs/cert.pem",
    privateKeyFile: "./Certs/key.pem",
    signature: .selfSigned
))

let secureSocket = try TLS.Socket(context: context, descriptor: descriptor)

try secureSocket.accept()

Here a context is created. You should hold on to this context if you intend to create multiple sockets. Your socket descriptor is then used with the context to create an TLS.Socket.

The call to accept() accepts the connection and performs the TLS handshake with the client. This should be called after the unsecure socket has called its version of accept().

Sending / Receiving

You can now send and receive data through the new secure socket.

try secureSocket.send([0x00, 0x01, 0x02])
let data = try secureSocket.receive(max: 3)

Certificates

The Certificates enum lets you supply the appropriate certificates for your TLS-enabled server.

public enum Certificates {
    case none
    case files(certificateFile: String, privateKeyFile: String, signature: Certificate.Signature)
    case chain(chainFile: String, signature: Certificate.Signature)
}

public enum Certificate.Signature {
    case selfSigned
    case signedFile(caCertificateFile: String)
    case signedDirectory(caCertificateDirectory: String)
}

Verification

You can verify the certificates presented by the peer manually.

try socket.verifyConnection()

Errors

The Error enum comprises all errors that can be thrown from this module. The String in all of the cases is a readable error message from OpenSSL.

public enum Error: ErrorProtocol {
    case methodCreation
    case contextCreation
    case loadCACertificate(String)
    case useCertificate(String)
    case usePrivateKey(String)
    case checkPrivateKey(String)
    case useChain(String)
    case socketCreation(String)
    case file(String)
    case accept(SocketError, String)
    case connect(SocketError, String)
    case send(SocketError, String)
    case receive(SocketError, String)
    case invalidPeerCertificate(PeerCertificateError)
}

Some cases of the Error enum contain SocketErrors inside.

public enum SocketError: Int32, ErrorProtocol {
    case none
    case zeroReturn
    case wantRead
    case wantWrite
    case wantConnect
    case wantAccept
    case wantX509Lookup
    case syscall
    case ssl
    case unknown
}

One case of the Error enum contains PeerCertificateErrors inside. This is thrown by verifyConnection().

public enum PeerCertificateError {
    case notPresented
    case noIssuerCertificate
    case invalid
}

Building

macOS

brew install openssl
brew link --force openssl

Linux

sudo apt-get install libssl-dev

Travis

Travis builds Swift TLS on both Ubuntu 14.04 and macOS 10.11. Check out the .travis.yml file to see how this package is built and compiled during testing.

Vapor

This wrapper was created to power Vapor, an Web Framework for Swift.

Author

Created by Tanner Nelson.