List certificates

This commit is contained in:
Simon Kågedal Reimer 2019-05-11 18:12:17 +02:00
parent a0e2298e69
commit 9082c86d02
3 changed files with 99 additions and 1 deletions

View File

@ -34,7 +34,11 @@ struct ListDevicesCommand: Command {
print(" - \(device.name)")
let trustStore = TrustStore(uuid: device.udid)
if trustStore.exists {
print(" - Trust store exists at \(trustStore.path)")
if let store = try? trustStore.open(), store.isValid() {
try? store.listCertificates()
} else {
print(" - Invalid trust store exists at \(trustStore.path)")
}
}
}
}

View File

@ -0,0 +1,52 @@
//
// Copyright © 2019 Simon Kågedal Reimer. See LICENSE.
//
import Foundation
import Security
enum SecurityError: LocalizedError {
case invalidDERX509
case unknown
var errorDescription: String? {
switch self {
case .invalidDERX509:
return "Given data was not a valid DER encoded X.509 certificate"
case .unknown:
return "Operation completed with an unknown error from the Security framework"
}
}
}
extension SecCertificate {
static func read(data: Data) throws -> SecCertificate {
guard let certificate = SecCertificateCreateWithData(nil, data as CFData) else {
throw SecurityError.invalidDERX509
}
return certificate
}
var subjectSummary: String? {
return SecCertificateCopySubjectSummary(self) as String?
}
func normalizedSubjectSequence() throws -> Data {
var error: Unmanaged<CFError>?
guard let data = SecCertificateCopyNormalizedSubjectContent(self, &error) else {
guard let error = error else {
throw SecurityError.unknown
}
throw error.takeRetainedValue()
}
return data as Data
}
func printInfo() {
if let summary = subjectSummary {
print(summary)
} else {
print("<unknown certificate>")
}
}
}

View File

@ -14,4 +14,46 @@ struct TrustStore {
var exists: Bool {
return localFileSystem.exists(path)
}
func open() throws -> Connection {
return try Connection(openingPath: path.pathString)
}
class Connection {
private let connection: SQLite.Connection
private let sqliteMaster = Table("sqlite_master")
private let tsettings = Table("tsettings")
private let dataColumn = Expression<Blob?>("data")
fileprivate init(openingPath path: String) throws {
connection = try SQLite.Connection(path)
}
func isValid() -> Bool {
do {
guard let count = try connection.scalar(
"SELECT count(*) FROM sqlite_master WHERE type='table' AND name='tsettings'"
) as? Int64 else {
return false
}
return count > 0
} catch {
return false
}
}
func listCertificates() throws {
for certificate in try connection.prepare(tsettings) {
guard let blob = certificate[dataColumn] else {
print("Couldn't get data blob from row...")
continue
}
let data = Data(blob.bytes)
let cert = try SecCertificate.read(data: data)
cert.printInfo()
let count = blob.bytes.count
print(" - \(count) bytes")
}
}
}
}