Skip to content

Commit

Permalink
Merge pull request #4 from mlink/main
Browse files Browse the repository at this point in the history
Use SecKeychainCopyDomainSearchList to find system keychain
  • Loading branch information
mlink authored Jan 8, 2024
2 parents 415e63f + a7f3e4d commit 4d58a33
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 2 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.1.1] - 2024-01-05
### Changed
- System keychain is located using Security framework API.

## [1.1.0] - 2023-09-14
### Added
- Import and export capability for certificates, keys, and identities.
Expand Down
44 changes: 42 additions & 2 deletions Sources/Haversack/Security/KeychainFile.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,27 @@ public class KeychainFile {
public static let systemRootCertificates = KeychainFile(at: rootCertificatesKeychainPath)

/// The path to the system keychain.
static let systemKeychainPath = "/Library/Keychains/System.keychain"
static let systemKeychainPath = system.path

/// An instance of ``KeychainFile`` that points at the system keychain
public static let system = KeychainFile(at: systemKeychainPath)
public static let system: KeychainFile = {
let legacySystemKeychainPath = "/Library/Keychains/System.keychain"
var searchList: CFArray?
let status = withUnsafeMutablePointer(to: &searchList) {
SecKeychainCopyDomainSearchList(.system, UnsafeMutablePointer($0))
}

guard status == errSecSuccess else {
// attempt to use traditional path, may fail later
return KeychainFile(at: legacySystemKeychainPath)
}

guard let searchList = searchList as? [SecKeychain], let systemKeychain = searchList.first else {
return KeychainFile(at: legacySystemKeychainPath)
}

return KeychainFile(reference: systemKeychain)
}()

/// The full path to the keychain file.
public let path: FilePath
Expand All @@ -55,6 +72,29 @@ public class KeychainFile {
self.passwordProvider = passwordProvider
}

/// Create an instance from an existing keychain reference
/// - Parameters:
/// - reference: A reference to a `SecKeychain`.
init(reference: SecKeychain) {
passwordProvider = nil
self.reference = reference

var pathLength = UInt32(PATH_MAX)
let pathName = UnsafeMutablePointer<CChar>.allocate(capacity: Int(pathLength))
let status = withUnsafeMutablePointer(to: &pathLength) { pathLength in
SecKeychainGetPath(reference, pathLength, pathName)
}

if status == errSecSuccess {
path = FileManager().string(withFileSystemRepresentation: pathName, length: Int(pathLength))
} else {
// should never happen
path = ""
}

pathName.deallocate()
}

/// Try to open and unlock the keychain file, or create the keychain if it does not yet exist.
/// - Throws: A ``HaversackError`` entity
public func attemptToOpenOrCreate() throws {
Expand Down

0 comments on commit 4d58a33

Please sign in to comment.