@@ -51,8 +51,14 @@ public final class GenerateCert {
5151 rsaBits: Int32 = 2048 ,
5252 daysValid: Int32 = 36500 ) async throws -> [ URL ] {
5353 Logger . shared. log ( " Initializing OpenSSL... " )
54- _ = OpenSSL_add_all_algorithms ( )
55- ERR_load_crypto_strings ( )
54+
55+ // Remove deprecated calls
56+ // _ = OpenSSL_add_all_algorithms() // Deprecated in OpenSSL 3.x
57+ // ERR_load_crypto_strings() // Deprecated in OpenSSL 3.x
58+
59+ // For OpenSSL 3.x, use explicit initialization
60+ OPENSSL_init_ssl ( OPENSSL_INIT_LOAD_SSL_STRINGS | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, nil )
61+ OPENSSL_init_crypto ( OPENSSL_INIT_LOAD_CONFIG | OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS, nil )
5662
5763 Logger . shared. log ( " Generating CA key... " )
5864 guard let caPkey = try generateRSAKey ( bits: rsaBits) else { throw CertGenError . keyGenerationFailed ( " CA key generation failed " ) }
@@ -110,107 +116,208 @@ public final class GenerateCert {
110116 return url
111117 }
112118
113- private static func generateRSAKey( bits: Int32 ) throws -> UnsafeMutablePointer < EVP_PKEY > ? {
119+ private static func generateRSAKey( bits: Int32 ) throws -> OpaquePointer ? {
114120 guard let rsa = RSA_new ( ) else { throw CertGenError . keyGenerationFailed ( " RSA_new failed " ) }
115121 guard let bn = BN_new ( ) else { RSA_free ( rsa) ; throw CertGenError . keyGenerationFailed ( " BN_new failed " ) }
116- if BN_set_word ( bn, UInt ( 65537 ) ) != 1 { BN_free ( bn) ; RSA_free ( rsa) ; throw CertGenError . keyGenerationFailed ( " BN_set_word failed " ) }
117- if RSA_generate_key_ex ( rsa, bits, bn, nil ) != 1 { BN_free ( bn) ; RSA_free ( rsa) ; throw CertGenError . keyGenerationFailed ( " RSA_generate_key_ex failed " ) }
118- BN_free ( bn)
119- guard let pkey = EVP_PKEY_new ( ) else { RSA_free ( rsa) ; throw CertGenError . keyGenerationFailed ( " EVP_PKEY_new failed " ) }
120- if EVP_PKEY_assign_RSA ( pkey, rsa) != 1 { EVP_PKEY_free ( pkey) ; RSA_free ( rsa) ; throw CertGenError . keyGenerationFailed ( " EVP_PKEY_assign_RSA failed " ) }
122+
123+ defer { BN_free ( bn) }
124+
125+ if BN_set_word ( bn, UInt ( 65537 ) ) != 1 {
126+ RSA_free ( rsa)
127+ throw CertGenError . keyGenerationFailed ( " BN_set_word failed " )
128+ }
129+
130+ if RSA_generate_key_ex ( rsa, bits, bn, nil ) != 1 {
131+ RSA_free ( rsa)
132+ throw CertGenError . keyGenerationFailed ( " RSA_generate_key_ex failed " )
133+ }
134+
135+ guard let pkey = EVP_PKEY_new ( ) else {
136+ RSA_free ( rsa)
137+ throw CertGenError . keyGenerationFailed ( " EVP_PKEY_new failed " )
138+ }
139+
140+ // Use EVP_PKEY_assign_RSA for OpenSSL 1.x compatibility
141+ // For OpenSSL 3.x, this should still work with the right headers
142+ if EVP_PKEY_assign ( pkey, EVP_PKEY_RSA, rsa) != 1 {
143+ EVP_PKEY_free ( pkey)
144+ RSA_free ( rsa)
145+ throw CertGenError . keyGenerationFailed ( " EVP_PKEY_assign failed " )
146+ }
147+
121148 return pkey
122149 }
123150
124- private static func createSelfSignedCertificate( pkey: UnsafeMutablePointer < EVP_PKEY > ? ,
151+ private static func createSelfSignedCertificate( pkey: OpaquePointer ? ,
125152 commonName: String ,
126153 days: Int32 ,
127- isCA: Bool ) throws -> UnsafeMutablePointer < X509 > ? {
154+ isCA: Bool ) throws -> OpaquePointer ? {
128155 guard let x509 = X509_new ( ) else { throw CertGenError . x509CreationFailed ( " X509_new failed " ) }
156+
157+ defer {
158+ if let x509 = x509 {
159+ // Only free if error occurs
160+ }
161+ }
162+
129163 X509_set_version ( x509, 2 )
130- if let serial = ASN1_INTEGER_new ( ) { ASN1_INTEGER_set ( serial, 1 ) ; X509_set_serialNumber ( x509, serial) ; ASN1_INTEGER_free ( serial) }
164+
165+ if let serial = ASN1_INTEGER_new ( ) {
166+ ASN1_INTEGER_set ( serial, 1 )
167+ X509_set_serialNumber ( x509, serial)
168+ ASN1_INTEGER_free ( serial)
169+ }
170+
131171 X509_gmtime_adj ( X509_get_notBefore ( x509) , 0 )
132172 X509_gmtime_adj ( X509_get_notAfter ( x509) , Int64 ( days) * 24 * 3600 )
133173 X509_set_pubkey ( x509, pkey)
134- guard let name = X509_get_subject_name ( x509) else { X509_free ( x509) ; throw CertGenError . x509CreationFailed ( " X509_get_subject_name nil " ) }
174+
175+ guard let name = X509_get_subject_name ( x509) else {
176+ X509_free ( x509)
177+ throw CertGenError . x509CreationFailed ( " X509_get_subject_name nil " )
178+ }
179+
135180 _ = addNameEntry ( name: name, field: " C " , value: " AU " )
136181 _ = addNameEntry ( name: name, field: " ST " , value: " NSW " )
137182 _ = addNameEntry ( name: name, field: " L " , value: " Sydney " )
138183 _ = addNameEntry ( name: name, field: " O " , value: " MyCompany " )
139184 _ = addNameEntry ( name: name, field: " OU " , value: " Dev " )
140185 _ = addNameEntry ( name: name, field: " CN " , value: commonName)
186+
141187 X509_set_issuer_name ( x509, name)
188+
142189 if isCA {
143- if let ext = X509V3_EXT_conf_nid ( nil , nil , NID_basic_constraints, " CA:TRUE " ) { X509_add_ext ( x509, ext, - 1 ) ; X509_EXTENSION_free ( ext) }
144- if let ext2 = X509V3_EXT_conf_nid ( nil , nil , NID_key_usage, " keyCertSign,cRLSign " ) { X509_add_ext ( x509, ext2, - 1 ) ; X509_EXTENSION_free ( ext2) }
190+ if let ext = X509V3_EXT_conf_nid ( nil , nil , NID_basic_constraints, " CA:TRUE " ) {
191+ X509_add_ext ( x509, ext, - 1 )
192+ X509_EXTENSION_free ( ext)
193+ }
194+ if let ext2 = X509V3_EXT_conf_nid ( nil , nil , NID_key_usage, " keyCertSign,cRLSign " ) {
195+ X509_add_ext ( x509, ext2, - 1 )
196+ X509_EXTENSION_free ( ext2)
197+ }
198+ }
199+
200+ if X509_sign ( x509, pkey, EVP_sha256 ( ) ) == 0 {
201+ X509_free ( x509)
202+ throw CertGenError . x509CreationFailed ( " X509_sign failed " )
145203 }
146- if X509_sign ( x509 , pkey , EVP_sha256 ( ) ) == 0 { X509_free ( x509 ) ; throw CertGenError . x509CreationFailed ( " X509_sign failed " ) }
204+
147205 return x509
148206 }
149207
150- private static func createCertificateSignedByCA( serverPKey: UnsafeMutablePointer < EVP_PKEY > ? ,
151- caPkey: UnsafeMutablePointer < EVP_PKEY > ? ,
152- caX509: UnsafeMutablePointer < X509 > ? ,
208+ private static func createCertificateSignedByCA( serverPKey: OpaquePointer ? ,
209+ caPkey: OpaquePointer ? ,
210+ caX509: OpaquePointer ? ,
153211 commonName: String ,
154- days: Int32 ) throws -> UnsafeMutablePointer < X509 > ? {
212+ days: Int32 ) throws -> OpaquePointer ? {
155213 guard let cert = X509_new ( ) else { throw CertGenError . x509CreationFailed ( " X509_new failed " ) }
214+
215+ defer {
216+ if let cert = cert {
217+ // Only free if error occurs
218+ }
219+ }
220+
156221 X509_set_version ( cert, 2 )
157- if let serial = ASN1_INTEGER_new ( ) { ASN1_INTEGER_set ( serial, Int ( time ( nil ) & 0xffffffff ) ) ; X509_set_serialNumber ( cert, serial) ; ASN1_INTEGER_free ( serial) }
222+
223+ if let serial = ASN1_INTEGER_new ( ) {
224+ ASN1_INTEGER_set ( serial, Int ( time ( nil ) & 0xffffffff ) )
225+ X509_set_serialNumber ( cert, serial)
226+ ASN1_INTEGER_free ( serial)
227+ }
228+
158229 X509_gmtime_adj ( X509_get_notBefore ( cert) , 0 )
159230 X509_gmtime_adj ( X509_get_notAfter ( cert) , Int64 ( days) * 24 * 3600 )
160231 X509_set_pubkey ( cert, serverPKey)
161- guard let subj = X509_get_subject_name ( cert) else { X509_free ( cert) ; throw CertGenError . x509CreationFailed ( " X509_get_subject_name nil " ) }
232+
233+ guard let subj = X509_get_subject_name ( cert) else {
234+ X509_free ( cert)
235+ throw CertGenError . x509CreationFailed ( " X509_get_subject_name nil " )
236+ }
237+
162238 _ = addNameEntry ( name: subj, field: " C " , value: " AU " )
163239 _ = addNameEntry ( name: subj, field: " ST " , value: " NSW " )
164240 _ = addNameEntry ( name: subj, field: " L " , value: " Sydney " )
165241 _ = addNameEntry ( name: subj, field: " O " , value: " MyCompany " )
166242 _ = addNameEntry ( name: subj, field: " OU " , value: " Dev " )
167243 _ = addNameEntry ( name: subj, field: " CN " , value: commonName)
168- if let ca = caX509 { if let caSubject = X509_get_subject_name ( ca) { X509_set_issuer_name ( cert, caSubject) } }
169- do { try addSubjectAltName_IP ( cert: cert, ipString: " 127.0.0.1 " ) } catch { Logger . shared. log ( " Warning: SAN add failed: \( error) " ) }
170- if let ext_bc = X509V3_EXT_conf_nid ( nil , nil , NID_basic_constraints, " CA:FALSE " ) { X509_add_ext ( cert, ext_bc, - 1 ) ; X509_EXTENSION_free ( ext_bc) }
171- if let ext_ku = X509V3_EXT_conf_nid ( nil , nil , NID_key_usage, " digitalSignature,keyEncipherment " ) { X509_add_ext ( cert, ext_ku, - 1 ) ; X509_EXTENSION_free ( ext_ku) }
172- guard let caKey = caPkey else { X509_free ( cert) ; throw CertGenError . x509CreationFailed ( " CA private key missing " ) }
173- if X509_sign ( cert, caKey, EVP_sha256 ( ) ) == 0 { X509_free ( cert) ; throw CertGenError . x509CreationFailed ( " X509_sign with CA key failed " ) }
244+
245+ if let ca = caX509 {
246+ if let caSubject = X509_get_subject_name ( ca) {
247+ X509_set_issuer_name ( cert, caSubject)
248+ }
249+ }
250+
251+ // Use the simpler method for SAN
252+ do { try addSubjectAltName_IP_simple ( cert: cert, ipString: " 127.0.0.1 " ) } catch {
253+ Logger . shared. log ( " Warning: SAN add failed: \( error) " )
254+ }
255+
256+ if let ext_bc = X509V3_EXT_conf_nid ( nil , nil , NID_basic_constraints, " CA:FALSE " ) {
257+ X509_add_ext ( cert, ext_bc, - 1 )
258+ X509_EXTENSION_free ( ext_bc)
259+ }
260+
261+ if let ext_ku = X509V3_EXT_conf_nid ( nil , nil , NID_key_usage, " digitalSignature,keyEncipherment " ) {
262+ X509_add_ext ( cert, ext_ku, - 1 )
263+ X509_EXTENSION_free ( ext_ku)
264+ }
265+
266+ guard let caKey = caPkey else {
267+ X509_free ( cert)
268+ throw CertGenError . x509CreationFailed ( " CA private key missing " )
269+ }
270+
271+ if X509_sign ( cert, caKey, EVP_sha256 ( ) ) == 0 {
272+ X509_free ( cert)
273+ throw CertGenError . x509CreationFailed ( " X509_sign with CA key failed " )
274+ }
275+
174276 return cert
175277 }
176278
177- @discardableResult private static func addNameEntry( name: UnsafeMutablePointer < X509_NAME > ? , field: String , value: String ) -> Int32 {
279+ @discardableResult private static func addNameEntry( name: OpaquePointer ? , field: String , value: String ) -> Int32 {
178280 guard let name = name else { return 0 }
179- return X509_NAME_add_entry_by_txt ( name, field, MBSTRING_ASC, value. withCString { UnsafeRawPointer ( $0) } , - 1 , - 1 , 0 )
281+ return value. withCString { valuePtr in
282+ return X509_NAME_add_entry_by_txt ( name, field, MBSTRING_ASC, valuePtr, - 1 , - 1 , 0 )
283+ }
180284 }
181285
182- private static func addSubjectAltName_IP( cert: UnsafeMutablePointer < X509 > ? , ipString: String ) throws {
286+ // Simpler version that doesn't use deprecated stack functions
287+ private static func addSubjectAltName_IP_simple( cert: OpaquePointer ? , ipString: String ) throws {
183288 guard let cert = cert else { throw CertGenError . sanCreationFailed ( " cert nil " ) }
184- var ipaddr = in_addr ( )
185- guard inet_pton ( AF_INET, ipString, & ipaddr) == 1 else { throw CertGenError . sanCreationFailed ( " inet_pton failed " ) }
186- guard let gen = GENERAL_NAME_new ( ) else { throw CertGenError . sanCreationFailed ( " GENERAL_NAME_new failed " ) }
187- guard let ipOctet = ASN1_OCTET_STRING_new ( ) else { GENERAL_NAME_free ( gen) ; throw CertGenError . sanCreationFailed ( " ASN1_OCTET_STRING_new failed " ) }
188- var rawIP = ipaddr. s_addr
189- withUnsafePointer ( to: & rawIP) { ptr in
190- let p = UnsafeRawPointer ( ptr)
191- ASN1_OCTET_STRING_set ( ipOctet, p. assumingMemoryBound ( to: UInt8 . self) , 4 )
192- }
193- GENERAL_NAME_set0_value ( gen, GEN_IPADD, ipOctet)
194- guard let stack = sk_GENERAL_NAME_new_null ( ) else { GENERAL_NAME_free ( gen) ; throw CertGenError . sanCreationFailed ( " sk_GENERAL_NAME_new_null failed " ) }
195- sk_GENERAL_NAME_push ( stack, gen)
196- if X509_add1_ext_i2d ( cert, NID_subject_alt_name, stack, 0 , X509V3_ADD_REPLACE) != 1 {
197- sk_GENERAL_NAME_pop_free ( stack, { GENERAL_NAME_free ( UnsafeMutablePointer ( mutating: $0) ) } )
198- throw CertGenError . sanCreationFailed ( " X509_add1_ext_i2d failed " )
199- }
200- sk_GENERAL_NAME_pop_free ( stack, { GENERAL_NAME_free ( UnsafeMutablePointer ( mutating: $0) ) } )
289+
290+ // Create SAN string in format "IP:127.0.0.1"
291+ let sanString = " IP: \( ipString) "
292+
293+ guard let ext = X509V3_EXT_conf_nid ( nil , nil , NID_subject_alt_name, sanString) else {
294+ throw CertGenError . sanCreationFailed ( " X509V3_EXT_conf_nid failed for SAN " )
295+ }
296+
297+ defer { X509_EXTENSION_free ( ext) }
298+
299+ if X509_add_ext ( cert, ext, - 1 ) != 1 {
300+ throw CertGenError . sanCreationFailed ( " X509_add_ext failed for SAN " )
301+ }
201302 }
202303
203- private static func writePrivateKeyPEM( pkey: UnsafeMutablePointer < EVP_PKEY > ? , to path: String ) throws {
304+ private static func writePrivateKeyPEM( pkey: OpaquePointer ? , to path: String ) throws {
204305 guard let pkey = pkey else { throw CertGenError . writeFailed ( " pkey nil " ) }
205306 guard let bio = BIO_new_file ( path, " w " ) else { throw CertGenError . writeFailed ( " BIO_new_file failed for \( path) " ) }
206307 defer { BIO_free_all ( bio) }
207- if PEM_write_bio_PrivateKey ( bio, pkey, nil , nil , 0 , nil , nil ) != 1 { throw CertGenError . writeFailed ( " PEM_write_bio_PrivateKey failed for \( path) " ) }
308+
309+ if PEM_write_bio_PrivateKey ( bio, pkey, nil , nil , 0 , nil , nil ) != 1 {
310+ throw CertGenError . writeFailed ( " PEM_write_bio_PrivateKey failed for \( path) " )
311+ }
208312 }
209313
210- private static func writeX509PEM( x509: UnsafeMutablePointer < X509 > ? , to path: String ) throws {
314+ private static func writeX509PEM( x509: OpaquePointer ? , to path: String ) throws {
211315 guard let x509 = x509 else { throw CertGenError . writeFailed ( " x509 nil " ) }
212316 guard let bio = BIO_new_file ( path, " w " ) else { throw CertGenError . writeFailed ( " BIO_new_file failed for \( path) " ) }
213317 defer { BIO_free_all ( bio) }
214- if PEM_write_bio_X509 ( bio, x509) != 1 { throw CertGenError . writeFailed ( " PEM_write_bio_X509 failed for \( path) " ) }
318+
319+ if PEM_write_bio_X509 ( bio, x509) != 1 {
320+ throw CertGenError . writeFailed ( " PEM_write_bio_X509 failed for \( path) " )
321+ }
215322 }
216323}
0 commit comments