Skip to content
This repository was archived by the owner on Mar 7, 2026. It is now read-only.

Commit 6e3fb96

Browse files
authored
Refactor certificate generation and error handling
Refactor certificate generation process to ensure proper handling of keys and certificates. Added error handling for key generation and certificate signing, and updated file writing methods to handle empty passwords.
1 parent 55d2a0a commit 6e3fb96

1 file changed

Lines changed: 66 additions & 15 deletions

File tree

Sources/prostore/install/GenerateCert.swift

Lines changed: 66 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import Foundation
22
import OpenSSL
3+
34
enum CertGenError: Error {
45
case keyGenerationFailed(String)
56
case x509CreationFailed(String)
67
case writeFailed(String)
78
case sanCreationFailed(String)
89
}
10+
911
public final class GenerateCert {
1012

1113
public static func createAndSaveCerts(caCN: String = "ProStore",
@@ -17,15 +19,25 @@ public final class GenerateCert {
1719
OPENSSL_init_ssl(UInt64(OPENSSL_INIT_LOAD_SSL_STRINGS | OPENSSL_INIT_LOAD_CRYPTO_STRINGS), nil)
1820
OPENSSL_init_crypto(UInt64(OPENSSL_INIT_LOAD_CONFIG | OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS), nil)
1921

20-
guard let caPkey = try generateRSAKey(bits: rsaBits) else { throw CertGenError.keyGenerationFailed("CA key generation failed") }
22+
guard let caPkey = try generateRSAKey(bits: rsaBits) else {
23+
throw CertGenError.keyGenerationFailed("CA key generation failed")
24+
}
2125

2226
guard let caX509 = try createSelfSignedCertificate(pkey: caPkey, commonName: caCN, days: daysValid, isCA: true) else {
27+
EVP_PKEY_free(caPkey)
2328
throw CertGenError.x509CreationFailed("CA certificate creation failed")
2429
}
2530

26-
guard let serverPkey = try generateRSAKey(bits: rsaBits) else { throw CertGenError.keyGenerationFailed("Server key generation failed") }
31+
guard let serverPkey = try generateRSAKey(bits: rsaBits) else {
32+
EVP_PKEY_free(caPkey)
33+
X509_free(caX509)
34+
throw CertGenError.keyGenerationFailed("Server key generation failed")
35+
}
2736

2837
guard let serverX509 = try createCertificateSignedByCA(serverPKey: serverPkey, caPkey: caPkey, caX509: caX509, commonName: serverCN, days: daysValid) else {
38+
EVP_PKEY_free(caPkey)
39+
X509_free(caX509)
40+
EVP_PKEY_free(serverPkey)
2941
throw CertGenError.x509CreationFailed("Server certificate creation failed")
3042
}
3143

@@ -48,7 +60,8 @@ public final class GenerateCert {
4860
try writePrivateKeyPEM(pkey: serverPkey, to: serverKeyURL.path)
4961
try writeX509PEM(x509: serverX509, to: serverCertURL.path)
5062

51-
try writePKCS12(pkey: serverPkey, cert: serverX509, caCert: caX509, to: localhostP12URL.path, password: nil)
63+
// Try with empty password first, which is what installApp.swift expects
64+
try writePKCS12(pkey: serverPkey, cert: serverX509, caCert: caX509, to: localhostP12URL.path, password: "")
5265

5366
EVP_PKEY_free(caPkey)
5467
X509_free(caX509)
@@ -90,11 +103,14 @@ public final class GenerateCert {
90103

91104
return pkey
92105
}
106+
93107
private static func createSelfSignedCertificate(pkey: OpaquePointer?,
94108
commonName: String,
95109
days: Int32,
96110
isCA: Bool) throws -> OpaquePointer? {
97-
guard let x509 = X509_new() else { throw CertGenError.x509CreationFailed("X509_new failed") }
111+
guard let x509 = X509_new() else {
112+
throw CertGenError.x509CreationFailed("X509_new failed")
113+
}
98114

99115
X509_set_version(x509, 2)
100116

@@ -179,12 +195,15 @@ public final class GenerateCert {
179195

180196
return x509
181197
}
198+
182199
private static func createCertificateSignedByCA(serverPKey: OpaquePointer?,
183200
caPkey: OpaquePointer?,
184201
caX509: OpaquePointer?,
185202
commonName: String,
186203
days: Int32) throws -> OpaquePointer? {
187-
guard let cert = X509_new() else { throw CertGenError.x509CreationFailed("X509_new failed") }
204+
guard let cert = X509_new() else {
205+
throw CertGenError.x509CreationFailed("X509_new failed")
206+
}
188207

189208
X509_set_version(cert, 2)
190209

@@ -272,6 +291,15 @@ public final class GenerateCert {
272291
}
273292
}
274293

294+
// Also add extended key usage for server authentication
295+
if let ext_eku = X509V3_EXT_conf_nid(nil, nil, NID_ext_key_usage, "serverAuth") {
296+
defer { X509_EXTENSION_free(ext_eku) }
297+
if X509_add_ext(cert, ext_eku, -1) != 1 {
298+
X509_free(cert)
299+
throw CertGenError.x509CreationFailed("X509_add_ext for ext_key_usage failed")
300+
}
301+
}
302+
275303
guard let caKey = caPkey else {
276304
X509_free(cert)
277305
throw CertGenError.x509CreationFailed("CA private key missing")
@@ -284,15 +312,20 @@ public final class GenerateCert {
284312

285313
return cert
286314
}
287-
@discardableResult private static func addNameEntry(name: OpaquePointer?, field: String, value: String) -> Int32 {
315+
316+
@discardableResult
317+
private static func addNameEntry(name: OpaquePointer?, field: String, value: String) -> Int32 {
288318
guard let name = name else { return 0 }
289319
return value.withCString { valuePtr in
290320
return X509_NAME_add_entry_by_txt(name, field, MBSTRING_ASC, valuePtr, -1, -1, 0)
291321
}
292322
}
323+
293324
// Simpler version that doesn't use deprecated stack functions
294325
private static func addSubjectAltName_IP_simple(cert: OpaquePointer?, ipString: String) throws {
295-
guard let cert = cert else { throw CertGenError.sanCreationFailed("cert nil") }
326+
guard let cert = cert else {
327+
throw CertGenError.sanCreationFailed("cert nil")
328+
}
296329

297330
// Create SAN string in format "IP:127.0.0.1"
298331
let sanString = "IP:\(ipString)"
@@ -307,28 +340,44 @@ public final class GenerateCert {
307340
throw CertGenError.sanCreationFailed("X509_add_ext failed for SAN")
308341
}
309342
}
343+
310344
private static func writePrivateKeyPEM(pkey: OpaquePointer?, to path: String) throws {
311-
guard let pkey = pkey else { throw CertGenError.writeFailed("pkey nil") }
312-
guard let bio = BIO_new_file(path, "w") else { throw CertGenError.writeFailed("BIO_new_file failed for \(path)") }
345+
guard let pkey = pkey else {
346+
throw CertGenError.writeFailed("pkey nil")
347+
}
348+
guard let bio = BIO_new_file(path, "w") else {
349+
throw CertGenError.writeFailed("BIO_new_file failed for \(path)")
350+
}
313351
defer { BIO_free_all(bio) }
314352

315353
if PEM_write_bio_PrivateKey(bio, pkey, nil, nil, 0, nil, nil) != 1 {
316354
throw CertGenError.writeFailed("PEM_write_bio_PrivateKey failed for \(path)")
317355
}
318356
}
357+
319358
private static func writeX509PEM(x509: OpaquePointer?, to path: String) throws {
320-
guard let x509 = x509 else { throw CertGenError.writeFailed("x509 nil") }
321-
guard let bio = BIO_new_file(path, "w") else { throw CertGenError.writeFailed("BIO_new_file failed for \(path)") }
359+
guard let x509 = x509 else {
360+
throw CertGenError.writeFailed("x509 nil")
361+
}
362+
guard let bio = BIO_new_file(path, "w") else {
363+
throw CertGenError.writeFailed("BIO_new_file failed for \(path)")
364+
}
322365
defer { BIO_free_all(bio) }
323366

324367
if PEM_write_bio_X509(bio, x509) != 1 {
325368
throw CertGenError.writeFailed("PEM_write_bio_X509 failed for \(path)")
326369
}
327370
}
371+
328372
private static func writePKCS12(pkey: OpaquePointer?, cert: OpaquePointer?, caCert: OpaquePointer?, to path: String, password: String?) throws {
329-
guard let pkey = pkey, let cert = cert else { throw CertGenError.writeFailed("pkey or cert nil") }
373+
guard let pkey = pkey, let cert = cert else {
374+
throw CertGenError.writeFailed("pkey or cert nil")
375+
}
376+
377+
// Always use an empty string if password is nil
378+
let passString = password ?? ""
379+
let pass: UnsafePointer<CChar>? = passString.utf8CString.withUnsafeBufferPointer { $0.baseAddress }
330380

331-
let pass: UnsafePointer<CChar>? = password?.utf8CString.withUnsafeBufferPointer { $0.baseAddress } ?? nil
332381
let friendlyName = "localhost"
333382
let name: UnsafePointer<CChar>? = friendlyName.utf8CString.withUnsafeBufferPointer { $0.baseAddress }
334383

@@ -351,11 +400,13 @@ public final class GenerateCert {
351400
}
352401
defer { PKCS12_free(p12) }
353402

354-
guard let bio = BIO_new_file(path, "w") else { throw CertGenError.writeFailed("BIO_new_file failed for \(path)") }
403+
guard let bio = BIO_new_file(path, "wb") else {
404+
throw CertGenError.writeFailed("BIO_new_file failed for \(path)")
405+
}
355406
defer { BIO_free_all(bio) }
356407

357408
if i2d_PKCS12_bio(bio, p12) != 1 {
358409
throw CertGenError.writeFailed("i2d_PKCS12_bio failed for \(path)")
359410
}
360411
}
361-
}
412+
}

0 commit comments

Comments
 (0)