Skip to content

netreconlab/ParseCertificateAuthority

ParseCertificateAuthority

Documentation Tuturiol Build Status CI release codecov License


Send CSR's and retreive certificates to/from ca-server's from your own Swift based client and server apps. Certificatable allows any object to support certificates while ParseCertificatable allows any ParseObject from Parse-Swift. ParseCertificateAuthority helps developers add an extra layer of security to their apps by making it easy to enable certificate pinning, authentication/verification, encrypting/decrypting, and secure device-to-device offline communication with key/certificate exchange.

ParseCertificateAuthority is Designed to Work With ca-server

Adding ParseCertificateAuthority to Your App

Setup a Vapor project by following the directions for installing and setting up your project on macOS or linux.

In your Package.swift file add ParseCertificateAuthority to dependencies:

// swift-tools-version:5.5.2
import PackageDescription

let package = Package(
    name: "YOUR_PROJECT_NAME",
    dependencies: [
        .package(url: "https://github.com/netreconlab/ParseCertificateAuthority", .upToNextMajor(from: "0.1.0")),
    ]
)

Configure ParseCertificateAuthority

import ParseCertificateAuthority

// Innitialize ParseCertificateAuthority
let caConfiguration = try ParseCertificateAuthorityConfiguration(caURLString: "http://certificate-authority:3000", // The url for `ca-server`.
                                                                 caRootCertificatePath: "/ca_certificate", // The root certificate path on `ca-server`.
                                                                 caCertificatesPath: "/certificates/", // The certificates path on `ca-server`.
                                                                 caUsersPath: "/appusers/") // The user path on `ca-server`.
initialize(configuration: caConfiguration)

Choosing an Object or ParseObject Model to Conform to Certificatable or ParseCertificatable

Below is an example of conforming to ParseCertificatable if you are using Parse-Swift. If you are not using Parse-Swift, the process is similar except you conform to Certificatable and use the relevant methods. At least one of your ParseObject models need to conform to ParseCertificatable. A good candidate is a model that already conforms to ParseInstallatiion as this is unique per installation on each device.

// Conform to `ParseCertificatable`. If not using Parse-Swift, conform to `Certificatable` instead.
struct Installation: ParseInstallation, ParseCertificatable {
    var rootCertificate: String?

    var certificate: String?

    var csr: String?
    
    var certificateId: String? {
        installationId
    }
    ...
}

Creating a New Certificate From a CSR

Once you have a CSR from a package like CertificateSigningRequest, you can create an account for the current ParseUser automatically and send the CSR to a ca-server by doing the following:

do {
    let user = User.current // Some user type that conforms to `ParseUser`.
    var installation = Installation.current
    let (certificate, rootCertificate) = try await installation.getCertificates(user)
    if installation.certificate != certificate || installation.rootCertificate != rootCertificate {
        installation.certificate = certificate
        installation.rootCertificate = rootCertificate
        try await installation.save()
        
        // Notify the user their object has been updated with the certificates
    }
} catch {
    // Handle error
}

Requesting a New Certificate Be Generated for an Existing CSR

Creating a new certificate for a CSR can be useful when a certificate has expired. To generage a new certificate, do the following:

do {
    let user = User.current // Some user type that conforms to `ParseUser`.
    var installation = Installation.current
    let (certificate, rootCertificate) = try await installation.requestNewCertificates(user)
    guard let certificate = certificate,
          let rootCertificate = rootCertificate else {
        let error = ParseError(code: .otherCause,
                               message: "Could not get new certificates")
        return
    }
    
    installation.certificate = certificate
    installation.rootCertificate = rootCertificate
    try await installation.save()
       
    // Notify the user their object has been updated with the certificates
} catch {
    // Handle error
}