Make Install CA work
This commit is contained in:
parent
eb5032ad6f
commit
cbf356c1e0
|
@ -4,8 +4,8 @@ A description of this package.
|
|||
|
||||
## TODO
|
||||
|
||||
* `install-ca` command
|
||||
* `remove-ca` command
|
||||
* Makefile
|
||||
* Brew formula
|
||||
* README
|
||||
* Filter for os types
|
||||
* `--dry-run` option
|
||||
* `remove` command that removes simulators
|
||||
|
|
|
@ -8,6 +8,7 @@ import SPMUtility
|
|||
class InstallCACommand: Command {
|
||||
private struct Options {
|
||||
var path: String?
|
||||
var dryRun: Bool = false
|
||||
}
|
||||
let name = "install-ca"
|
||||
let overview = "Install a Certificate Authority"
|
||||
|
@ -19,6 +20,14 @@ class InstallCACommand: Command {
|
|||
private var filteringOptions = FilteringOptions()
|
||||
|
||||
func addOptions(to parser: ArgumentParser) {
|
||||
binder.bind(option: parser.add(
|
||||
option: "--dry-run",
|
||||
kind: Bool.self,
|
||||
usage: "Don't actually install any CA"
|
||||
), to: { options, dryRun in
|
||||
options.dryRun = dryRun
|
||||
})
|
||||
|
||||
binder.bind(positional: parser.add(
|
||||
positional: "path",
|
||||
kind: String.self,
|
||||
|
@ -38,11 +47,16 @@ class InstallCACommand: Command {
|
|||
func run() throws {
|
||||
let url = URL(fileURLWithPath: options.path!)
|
||||
let certificate = try Certificate.load(from: url)
|
||||
print(certificate)
|
||||
let certificateName = certificate.subjectSummary ?? "<unknown certificate>"
|
||||
|
||||
print(filteringOptions)
|
||||
for device in try Simctl.flatListDevices().filter(using: filteringOptions) {
|
||||
print(device.name)
|
||||
if options.dryRun {
|
||||
print("Would install \(certificateName) into \(device.name).")
|
||||
} else {
|
||||
print("Installing \(certificateName) into \(device.name).")
|
||||
let trustStore = TrustStore(uuid: device.udid)
|
||||
try trustStore.open().addCertificate(certificate)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,12 +26,14 @@ struct Certificate {
|
|||
}
|
||||
}
|
||||
|
||||
let data: Data
|
||||
private let certificate: SecCertificate
|
||||
|
||||
init(_ data: Data) throws {
|
||||
guard let certificate = SecCertificateCreateWithData(nil, data as CFData) else {
|
||||
throw Error.invalidDERX509
|
||||
}
|
||||
self.data = data
|
||||
self.certificate = certificate
|
||||
}
|
||||
|
||||
|
@ -69,7 +71,7 @@ struct Certificate {
|
|||
}
|
||||
}
|
||||
|
||||
static func load(from url: URL) throws -> SecCertificate {
|
||||
static func load(from url: URL) throws -> Certificate {
|
||||
let data = try Data(contentsOf: url)
|
||||
|
||||
var cfitems: CFArray?
|
||||
|
@ -83,7 +85,8 @@ struct Certificate {
|
|||
guard type == .itemTypeCertificate, let items = cfitems as? [SecCertificate], let item = items.first else {
|
||||
throw Error.notACertficate
|
||||
}
|
||||
return item
|
||||
let certData = SecCertificateCopyData(item) as Data
|
||||
return try Certificate(certData)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -71,8 +71,19 @@ struct TrustStore {
|
|||
}
|
||||
|
||||
func removeCertificate(with sha1: Data) throws {
|
||||
let query: Delete = tsettings.where(sha1Column == sha1.datatypeValue).delete()
|
||||
let query = tsettings.where(sha1Column == sha1.datatypeValue).delete()
|
||||
try connection.run(query)
|
||||
}
|
||||
|
||||
func addCertificate(_ certificate: Certificate) throws {
|
||||
let row = try TrustStoreRow(certificate)
|
||||
let insert = tsettings.insert(
|
||||
subjColumn <- row.subj.datatypeValue,
|
||||
sha1Column <- row.sha1.datatypeValue,
|
||||
tsetColumn <- row.tset?.datatypeValue,
|
||||
dataColumn <- row.data?.datatypeValue
|
||||
)
|
||||
try connection.run(insert)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,15 @@ extension TrustStoreRow {
|
|||
}
|
||||
}
|
||||
|
||||
init(_ certificate: Certificate) throws {
|
||||
let data = certificate.data
|
||||
self.data = data
|
||||
self.sha1 = Digest.sha1(data)
|
||||
self.tset = createTset()
|
||||
self.subj = try subjectContent(from: certificate)
|
||||
assert(isValidTset(self.tset!))
|
||||
}
|
||||
|
||||
func validatedCertificate() throws -> Certificate {
|
||||
guard let tset = tset else {
|
||||
throw Error.noTsetValue
|
||||
|
@ -43,10 +52,9 @@ extension TrustStoreRow {
|
|||
throw Error.noData
|
||||
}
|
||||
let certificate = try Certificate(data)
|
||||
let subjectContent = try certificate.normalizedSubjectContent()
|
||||
let tlv = try DERParser().parse(data: subjectContent)
|
||||
let subject = try subjectContent(from: certificate)
|
||||
|
||||
guard tlv.data == subj else {
|
||||
guard subject == subj else {
|
||||
throw Error.subjectContentDoesNotMatch
|
||||
}
|
||||
|
||||
|
@ -60,6 +68,13 @@ extension TrustStoreRow {
|
|||
|
||||
return certificate
|
||||
}
|
||||
}
|
||||
|
||||
private func subjectContent(from certificate: Certificate) throws -> Data {
|
||||
let subjectContent = try certificate.normalizedSubjectContent()
|
||||
let tlv = try DERParser().parse(data: subjectContent)
|
||||
return tlv.data
|
||||
}
|
||||
|
||||
private func isValidTset(_ data: Data) -> Bool {
|
||||
do {
|
||||
|
@ -69,4 +84,11 @@ extension TrustStoreRow {
|
|||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private func createTset() -> Data {
|
||||
do {
|
||||
return try PropertyListSerialization.data(fromPropertyList: [], format: .xml, options: 0)
|
||||
} catch {
|
||||
fatalError("Should be able to create propertylist")
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue