diff --git a/enzevalos_iphone.xcodeproj/project.pbxproj b/enzevalos_iphone.xcodeproj/project.pbxproj index 5bfacc2b5401ceb4d60b4be6b3c465a68f4e6970..dc98cc1030fdfbabfe5e36cb0aba5c9cef32761f 100644 --- a/enzevalos_iphone.xcodeproj/project.pbxproj +++ b/enzevalos_iphone.xcodeproj/project.pbxproj @@ -769,9 +769,9 @@ 0ECEA101240EA905007DC71E /* SMIME */ = { isa = PBXGroup; children = ( - 0ECA5797240D496800B0F231 /* SMIME.swift */, - A5E303D524110F6400310264 /* c */, 0EF148042422543E00B3C198 /* Certificate.swift */, + A5E303D524110F6400310264 /* c */, + 0ECA5797240D496800B0F231 /* SMIME.swift */, 0EF73F4224237E6500932FA0 /* SMIMEHelpers.swift */, ); name = SMIME; diff --git a/enzevalos_iphone/SMIME.swift b/enzevalos_iphone/SMIME.swift index 6fb937aa549a7ef1573a22e8efac499d7bf4389a..84faaa522ca08cb543cff1f3d9cfbdef4e6c7f63 100644 --- a/enzevalos_iphone/SMIME.swift +++ b/enzevalos_iphone/SMIME.swift @@ -213,6 +213,95 @@ AYIHvW6qRLTsSR6BZZS3pqGXYue7fE0vj4HJ2IEpj05qQ5RXrD57Wg== -----END RSA PRIVATE KEY----- """ + let att_sig_invalid = """ +MIME-Version: 1.0 +Content-Disposition: attachment; filename="smime.p7m" +Content-Type: application/pkcs7-mime; smime-type=signed-data; name="smime.p7m" +Content-Transfer-Encoding: base64 + +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 +AAAA +""" + + let det_sig_invalid = """ +------56F3BC21B2CE83EB9E02E24139D860BC +Hello world whatever the fuckaaDadaDAd +------56F3BC21B2CE83EB9E02E24139D860BC +Content-Type: application/pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +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 +N8GVQGtc+3uaNA== + +------56F3BC21B2CE83EB9E02E24139D860BC-- +""" + let enc_test_key = """ -----BEGIN ENCRYPTED PRIVATE KEY----- @@ -394,7 +483,7 @@ PkfA6mR7rtcyIbHi34tfkCv/qolV3QivMHov0IJpRyNO let fp = addPrivateKey(keyPlusCertPEM: test_key) let cert = certsKeychain[privateKeyKeychain["ownkey"]!]! let key = privateKeyKeychain[privateKeyKeychain["ownkey"]!]! - + /* let (enc, enc_errs) = encryptWithPem(message: test_string, certPems: [test_key_other, cert]) if enc != nil { // the pointers point to memory allocatedi in c that needs to be manually dealocated @@ -425,7 +514,7 @@ PkfA6mR7rtcyIbHi34tfkCv/qolV3QivMHov0IJpRyNO print("subject", certObj.subject ?? "") print("startDate", certObj.startDate ?? "") print("endDate", certObj.endDate ?? "") - + */ let (sig, sigErr) = signWithPem(message: test_string, certAsPem: cert, keyAsPem: key, detached: false) if sig != nil{ // the pointers point to memory allocatedi in c that needs to be manually dealocated @@ -434,6 +523,15 @@ PkfA6mR7rtcyIbHi34tfkCv/qolV3QivMHov0IJpRyNO else{ print("\n SWIFT SIGN1 failed") } + + if sigErr != nil + { + print("sig errors!") + for x in sigErr ?? [] { + print("errorstring: ",getErrorString(errCode: x)) + } + } + let (sig2, sig2Err) = signWithPem(message: test_string, certAsPem: cert, keyAsPem: key, detached: true) if sig2 != nil{ // the pointers point to memory allocatedi in c that needs to be manually dealocated @@ -442,24 +540,40 @@ PkfA6mR7rtcyIbHi34tfkCv/qolV3QivMHov0IJpRyNO else{ print("\n SWIFT SIGN2 failed") } + + if sig2Err != nil + { + print("sig errors!") + for x in sig2Err ?? [] { + print("errorstring: ",getErrorString(errCode: x)) + } + } var CAs : [String] = [] for k in CAKeychain.allKeys() { CAs.append(CAKeychain[k]!) } - let (vertest, certs,verErrs) = verifyWithCApem(message: sig!, pemCAArr: CAs ) + + let (vertest, certs,verErrs) = verifyWithCApem(message: sig!, pemCAArr: [testEvilCA]) if vertest != nil { print("In Verification", vertest!) - print(certs ?? "No certs") - for x in verErrs ?? [] { - print("errorstring: ",getErrorString(errCode: x)) - } } else{ print("Vertest was nil") } + + print(certs ?? "No certs") + + if verErrs != nil + { + print("ver errors!") + for x in verErrs ?? [] { + print("error code: ", x) + print("error string: ",getErrorString(errCode: x)) + } + } /* let (fpTestKey, _, _) = getFingerprintFromPem(pem: test_key) if (fpTestKey != nil) { @@ -473,6 +587,56 @@ PkfA6mR7rtcyIbHi34tfkCv/qolV3QivMHov0IJpRyNO */ } + func testVerification() { + var CAs : [String] = [] + for k in CAKeychain.allKeys() + { + CAs.append(CAKeychain[k]!) + } + + let (vertest, certs,verErrs) = verifyWithCApem(message: att_sig_invalid, pemCAArr: CAs) + if vertest != nil + { + print("Verification attacthed sig", vertest!) + } + else{ + print("Verification attacthed sig") + } + + print(certs ?? "No certs") + + if verErrs != nil + { + print("SWIFT errors!") + for x in verErrs ?? [] { + print("error code: ", x) + print("error string: ", getErrorString(errCode: x)) + print("error reason: ", getErrorReasonString(errCode: x)) + } + } + + let (vertestDet, certsDet, verErrsDet) = verifyWithCApem(message: det_sig_invalid, pemCAArr: CAs) + if vertestDet != nil + { + print("Verification dettached sig", vertestDet!) + } + else{ + print("Verification dettached sig") + } + + print(certsDet ?? "No certs") + + if verErrsDet != nil + { + print("SWIFT errors") + for x in verErrsDet ?? [] { + print("error code: ", x) + print("error string: ", getErrorString(errCode: x)) + print("error reason: ", getErrorReasonString(errCode: x)) + } + } + } + func testCryptoObjectMethods() { } @@ -505,35 +669,16 @@ PkfA6mR7rtcyIbHi34tfkCv/qolV3QivMHov0IJpRyNO } // Note: we ignore the Encryption interface because some things are built with PGP in mind and make no sense in the context of SMIME (signatureIDs for example) - func decrypt(data: Data, fromAddr: String, ownId:String, isMailNew: Bool) -> CryptoObject? { - // NOTE TO SELF: Implement verify with CryptoObject BEFORE decrypt - let (sigState, certsWithFps) = verify(data: data, email: fromAddr, isMailNew: isMailNew)! - + func decrypt(data: Data, fromAddr: String, ownId:String, isMailNew: Bool) throws -> CryptoObject { var outputData: Data = data let text = String(data: data, encoding: .utf8)! - let fp = getOwnKeyFP() + var fp = getOwnKeyFP() let cert = certsKeychain[fp!]! let key = privateKeyKeychain[fp!]! - - let certObjects = certsWithFps.map( { (arg) -> Certificate in - let (_, pem) = arg - return Certificate(pem: pem) - }) - - var addrs : [String:Bool] = [:] - for c in certObjects - { - for e in c.eMails! - { - addrs[e] = true - } - } - - let addresses : [String] = Array(addrs.keys) - + var (decStr, errArr) = decryptWithPem(message: text, certAsPem: cert, keyAsPem: key) - var encState : EncryptionState = EncryptionState.UnableToDecrypt - if decStr != nil{ + var encState = EncryptionState.UnableToDecrypt + if decStr != nil && (errArr == nil || errArr!.count == 0) { encState = EncryptionState.ValidedEncryptedWithCurrentKey } else @@ -543,6 +688,7 @@ PkfA6mR7rtcyIbHi34tfkCv/qolV3QivMHov0IJpRyNO if f != fp{ (decStr, errArr) = decryptWithPem(message: text, certAsPem: certsKeychain[f]!, keyAsPem: privateKeyKeychain[f]!) if decStr != nil{ + fp = f encState = EncryptionState.ValidEncryptedWithOldKey break } @@ -554,11 +700,22 @@ PkfA6mR7rtcyIbHi34tfkCv/qolV3QivMHov0IJpRyNO outputData = decStr!.data(using: .utf8)! } + /** + we have tried to decrypt with our current key and with our older keys and if all of that failed then: + * the email wasn't meant for us and we shouldn't be able to decrypt it anyway + * there is something wrong with the e-mail + */ if (errArr != nil && errArr!.count > 0) { - // TODO: Exception - return nil + throw SMIMEError(message: "Decryption failed!", errorArray: errArr, type: SMIMEError.ErrorType.decryption) } + let (sigState, certsWithFps, sigStr) = verify(data: outputData, email: fromAddr, isMailNew: isMailNew) + + let addresses = getAllEmailsFromPEMs(certs: certsWithFps.map( { (arg) -> String in + let (_, pem) = arg + return pem + })) + return CryptoObject(chiphertext: data, plaintext: String(data: outputData, encoding: .utf8), decryptedData: outputData, sigState: sigState, encState: encState, signKey: fp, encType: CryptoScheme.SMIME, signedAdrs: sigState == SignatureState.ValidSignature ? addresses : []) } @@ -576,8 +733,15 @@ PkfA6mR7rtcyIbHi34tfkCv/qolV3QivMHov0IJpRyNO return CryptoObject(chiphertext: sigText!.data(using: .utf8), plaintext: text, decryptedData: plainData, sigState: SignatureState.ValidSignature, encState: EncryptionState.NoEncryption, signKey: fp, encType: CryptoScheme.SMIME, signedAdrs: [myEmail]) } - // If multiple signatures are present, ALL need to be valid AND have a matching mail address, else the signature is invalid. - func verify(data: Data, email: String, isMailNew: Bool) -> (SignatureState, [(String, String)])? { + /** + Verifies the signature of a signed message. If multiple signatures are present, ALL need to be valid AND have a matching mail address, else the signature is invalid. The exceptions are in part modelled after the way OpenSSL deals with verification + + - returns: + * SignatureState + * An array of (<fingerprint>, <pem>) tuples + * the verified string + */ + func verify(data: Data, email: String, isMailNew: Bool) -> CryptoObject { var CAs : [String] = [] CAKeychain.allKeys().forEach({ (key) in CAs.append(CAKeychain[key]!) @@ -585,55 +749,74 @@ PkfA6mR7rtcyIbHi34tfkCv/qolV3QivMHov0IJpRyNO let text = String(data: data, encoding: .utf8)! let (verStr, certsFPArr, errArr) = verifyWithCApem(message: text, pemCAArr: CAs) - if certsFPArr != nil { - var newCerts: [String] = [] // all certs that came from the email and weren't available before - var mailMatch = true - if certsFPArr?.count == 0 {mailMatch = false} - for item in certsFPArr! { - var mailFound = false - let (fp, cert) = item - let certObj = Certificate(pem: cert) - // check if the email from the parameters matches with one of the emails in each of the certs used to sign the message - for addr in certObj.eMails ?? [] { - if addr == email { - mailFound = true - break - } - } - mailMatch = mailFound && mailMatch - // check if cert is already in the keychain - if let _ = try? certsKeychain.get(fp) { - continue + + if certsFPArr == nil || certsFPArr!.count == 0 { + let errors = errArr! + + for error in errors { + let reason = getErrorReasonString(errCode: error) + print("reason:", reason) + // check reasons to identify different error causes + // string comaprison necessary because doesn't have fixed error codes... + if reason == "no content type" { + return CryptoObject(chiphertext: data, plaintext: text, decryptedData: nil, sigState: .NoSignature, encState: EncryptionState.NoEncryption, signKey: nil, encType: .UNKNOWN, signedAdrs: []) } - newCerts.append(cert) } - let fps = importCerts(certs: newCerts) - // check if the email has no certificate or the certificate is newer than the present one and update accordingly - for fp in fps{ - let cert = Certificate(pem: certsKeychain[fp]!) - for email in cert.eMails ?? [] + return CryptoObject(chiphertext: data, plaintext: text, decryptedData: nil, sigState: .InvalidSignature, encState: EncryptionState.NoEncryption, signKey: nil, encType: .UNKNOWN, signedAdrs: []) + } + + var newCerts: [String] = [] // all certs that came from the email and weren't available before + var mailMatch = true + if certsFPArr?.count == 0 {mailMatch = false} + + for item in certsFPArr! { + var mailFound = false + let (fp, cert) = item + let certObj = Certificate(pem: cert) + // check if the email from the parameters matches with one of the emails in each of the certs used to sign the message + for addr in certObj.eMails ?? [] { + if addr == email { + mailFound = true + break + } + } + mailMatch = mailFound && mailMatch + // check if cert is already in the keychain + if let _ = try? certsKeychain.get(fp) { + continue + } + newCerts.append(cert) + } + + let fps = importCerts(certs: newCerts) + // check if the email has no certificate or the certificate is newer than the present one and update accordingly + for fp in fps{ + let cert = Certificate(pem: certsKeychain[fp]!) + for email in cert.eMails ?? [] + { + if isMailNew || certsKeychain[email] == nil { - if isMailNew || certsKeychain[email] == nil - { - certsKeychain[email] = fp - } + certsKeychain[email] = fp } } - - let sigState = mailMatch ? SignatureState.ValidSignature : SignatureState.InvalidSignature - - return (sigState, certsFPArr!) } - return nil - // TODO: Exception no valid signatures + let sigState = mailMatch ? SignatureState.ValidSignature : SignatureState.InvalidSignature + + let signedAddresses = getAllEmailsFromPEMs(certs: certsFPArr!.map( { (arg) -> String in + let (_, pem) = arg + return pem + })) + + return CryptoObject(chiphertext: data, plaintext: verStr!, decryptedData: nil, sigState: sigState, encState: EncryptionState.NoEncryption, signKey: nil, encType: .SMIME, signedAdrs: signedAddresses) } func encrypt(plainData: Data, ids: [String], ownId: String, encryptForMyId: Bool = true) throws -> CryptoObject { - let text = String(data: plainData, encoding: .utf8) + let plainText = String(data: plainData, encoding: .utf8) + var (sigText, sigErrArr): (String?, [UInt]?) = (nil, nil) var pems: [String] = [] - var ownFp: String? = nil + let ownFp: String? = getOwnKeyFP() // retrieve the certs as pems for each ID (email), certsKeychain stores for each email a fingerprint of the cert of that user and under a fingerprint a cert is stored for id in ids { @@ -641,41 +824,41 @@ PkfA6mR7rtcyIbHi34tfkCv/qolV3QivMHov0IJpRyNO pems.append(certsKeychain[fp]!) } else{ - throw SMIMEError(message: "No cert for email " + id + "!", errorArray: nil, type: SMIMEError.ErrorType.encryption) + throw SMIMEError(message: "No cert for email " + id + "!", errorArray: nil, type: SMIMEError.ErrorType.other) } } // if we want to encrypt with the user's own key, retrieve the key and handle errors if encryptForMyId { - if let fp = getOwnKeyFP() { - ownFp = fp - pems.append(certsKeychain[fp]!) + if ownFp != nil { + pems.append(certsKeychain[ownFp!]!) } else { - throw SMIMEError(message: "Tried to encrypt email with the user's key but no cert for own key present!", errorArray: nil, type: SMIMEError.ErrorType.encryption) + throw SMIMEError(message: "Tried to encrypt email with the user's key but no cert for own key present!", errorArray: nil, type: SMIMEError.ErrorType.other) } } - // do the actual encryption - let (encStr, errArr) = encryptWithPem(message: text!, certPems: pems) - if errArr != nil && errArr!.count > 0 { - throw SMIMEError(message: "Encryption failed!", errorArray: errArr, type: SMIMEError.ErrorType.encryption) - } - // check if the user has a certificate if ownFp != nil { let ownCert = certsKeychain[ownFp!]! let ownPk = privateKeyKeychain[ownFp!]! - let (sigText, sigErrArr) = signWithPem(message: encStr!, certAsPem: ownCert, keyAsPem: ownPk, detached: false) + (sigText, sigErrArr) = signWithPem(message: plainText!, certAsPem: ownCert, keyAsPem: ownPk, detached: false) if sigErrArr != nil && sigErrArr!.count > 0 { - throw SMIMEError(message: "Signing during encryption failed!", errorArray: sigErrArr, type: SMIMEError.ErrorType.encryption) + throw SMIMEError(message: "Signing during encryption failed!", errorArray: sigErrArr, type: SMIMEError.ErrorType.signing) } - - return CryptoObject(chiphertext: sigText!.data(using: .utf8), plaintext: text, decryptedData: plainData, sigState: SignatureState.ValidSignature, encState: EncryptionState.ValidedEncryptedWithCurrentKey, signKey: ownFp, encType: CryptoScheme.SMIME, signedAdrs: [ownId]) + } else { + throw SMIMEError(message: "Tried to sign with user's certificate but none was present!", errorArray: nil, type: SMIMEError.ErrorType.other) + } + + // do the actual encryption + // NOTE: sigText can't be nil b/c we force signing so we either sign successfully or we throw an exception and never reach this code block + let (encStr, errArr) = encryptWithPem(message: sigText!, certPems: pems) + if errArr != nil && errArr!.count > 0 { + throw SMIMEError(message: "Encryption failed!", errorArray: errArr, type: SMIMEError.ErrorType.encryption) } - throw SMIMEError(message: "Tried to sign with user's certificate but none was present!", errorArray: errArr, type: SMIMEError.ErrorType.encryption) + return CryptoObject(chiphertext: encStr!.data(using: .utf8), plaintext: plainText, decryptedData: plainData, sigState: SignatureState.ValidSignature, encState: EncryptionState.ValidedEncryptedWithCurrentKey, signKey: ownFp, encType: CryptoScheme.SMIME, signedAdrs: [ownId]) } } diff --git a/enzevalos_iphone/SMIMEHelpers.swift b/enzevalos_iphone/SMIMEHelpers.swift index 8c832258bd4e5c4fb35745f1fc840700ebb63622..03874305dbedc7ae74039603f2b57d96f9c8506a 100644 --- a/enzevalos_iphone/SMIMEHelpers.swift +++ b/enzevalos_iphone/SMIMEHelpers.swift @@ -8,17 +8,35 @@ import Foundation -struct SMIMEError : Error { +class SMIMEError : Error { enum ErrorType { case fingerPrint case encryption case decryption + case verification case signing + case other + } + + func errorArrayToString() -> [String] { + var strArr: [String] = [] + + for error in self.errorArray ?? [] { + strArr.append(getErrorString(errCode: error)) + } + + return strArr } let message: String? let errorArray: [UInt]? let type: ErrorType + + init(message: String?, errorArray: [UInt]?, type: ErrorType) { + self.message = message + self.errorArray = errorArray + self.type = type + } } func encryptWithPem(message: String,certPems: [String]) -> (String?, [UInt]?) { @@ -68,6 +86,11 @@ func signWithPem(message:String, certAsPem: String, keyAsPem:String, detached:Bo return (sigStr, errArr) } + +/** + when the signature can't be verified with the present certs: verStr = nil, numCerts = 0, error code: 772378724 + when no signature present, there's error reason "no content type" + */ func verifyWithCApem (message:String, pemCAArr: [String]) -> (String?, [(String, String)]?, [UInt]?) { let pemCAArrC = createCStrArr(sarr: pemCAArr) let ver = OpenSSL_verify(message, pemCAArrC, Int32(pemCAArr.count)) @@ -88,10 +111,12 @@ func verifyWithCApem (message:String, pemCAArr: [String]) -> (String?, [(String, let numCerts = Int((result?.num_certs)!) var certFPArr: [(String, String)] = [] - for i in 0...(numCerts-1) { - certFPArr.append( ((fpArr?[i])!, (certArr?[i])!) ) + if (numCerts > 0) { + for i in 0...(numCerts-1) { + certFPArr.append( ((fpArr?[i])!, (certArr?[i])!) ) + } } - + return (verStr, certFPArr, errArr) } @@ -172,6 +197,36 @@ func getErrorString(errCode: UInt) -> String { return "Invalid error code!" } +func getErrorReasonString(errCode: UInt) -> String { + let cStr = get_err_reason_string(errCode); + defer { + cStr?.deallocate() + } + + if (cStr != nil) { + let str = String( cString: cStr!) + return str; + } + return "Invalid error code!" +} + +func getAllEmailsFromPEMs(certs: [String]) -> [String] { + let certObjects = certs.map( { (arg) -> Certificate in + return Certificate(pem: arg) + }) + + var addrs : [String:Bool] = [:] + for c in certObjects + { + for e in c.eMails! + { + addrs[e] = true + } + } + + return Array(addrs.keys) +} + func deallocateResult(res: UnsafeMutablePointer<result>?) { deallocate_result(res) } diff --git a/enzevalos_iphone/SearchHelper.swift b/enzevalos_iphone/SearchHelper.swift index 1c22010eaf79b606636d1aae2daa8d1876998760..95b93c98a0bad23c627c618ca5fa3d5c0fe7c47c 100644 --- a/enzevalos_iphone/SearchHelper.swift +++ b/enzevalos_iphone/SearchHelper.swift @@ -35,7 +35,8 @@ func containsSearchTerms ( content : String?, searchText: String) -> Bool smime.testSMIMEencrypt() // } // smime.testKeychain() - //smime.testKeyEnc() + // smime.testKeyEnc() + // smime.testVerification() var longterms : [String] = [] var terms : [String] = [] diff --git a/enzevalos_iphone/c/general-helpers.c b/enzevalos_iphone/c/general-helpers.c index 5ef36beefd70da443e6a609b9fa3a9050157cd0f..e537ba48d064af03aa2430eb138c075aad5944a9 100644 --- a/enzevalos_iphone/c/general-helpers.c +++ b/enzevalos_iphone/c/general-helpers.c @@ -23,11 +23,22 @@ int get_array_size(array_with_length *arr) { } char *get_err_string(unsigned long err) { - const char *error = ERR_func_error_string(err); - //printf("\nError: %s", error); - char * error_permanent = (char *) malloc(strlen(error)+1); + char * error_permanent = malloc(256); + ERR_error_string_n(err, error_permanent, 256); + // printf("\nError: %s", error_permanent); + /*char * error_permanent = (char *) malloc(strlen(error)+1); error_permanent[strlen(error)]=0; // To Nullterminate the string - memcpy(error_permanent,error,strlen(error)); + memcpy(error_permanent,error,strlen(error));*/ + + return error_permanent; +} + +char *get_err_reason_string(unsigned long err) { + const char * reason_str = ERR_reason_error_string(err); + char * error_permanent = (char *) malloc(strlen(reason_str)+1); + error_permanent[strlen(reason_str)]=0; // To Nullterminate the string + memcpy(error_permanent,reason_str,strlen(reason_str)); + // printf("\nError: %s", error_permanent); return error_permanent; } diff --git a/enzevalos_iphone/c/generic-helpers.h b/enzevalos_iphone/c/generic-helpers.h index 0cce3db5c8ef3db14c25e38cbf220d2d3d8bfc28..3288c0d8f0ba36412ec3b4b841832daac1d3d159 100644 --- a/enzevalos_iphone/c/generic-helpers.h +++ b/enzevalos_iphone/c/generic-helpers.h @@ -45,6 +45,7 @@ struct array_with_length { char * pop_error (result *res); char *get_err_string(unsigned long err); +char *get_err_reason_string(unsigned long err); void bio_to_str(BIO *bio_in, char **out); int get_array_size(array_with_length *arr); diff --git a/enzevalos_iphone/c/smime-helpers.c b/enzevalos_iphone/c/smime-helpers.c index 0d5569e2a5df5b05e4b65e5de66977520d36bd36..62e528307be0a781713b74ac88838ff323e0f78d 100644 --- a/enzevalos_iphone/c/smime-helpers.c +++ b/enzevalos_iphone/c/smime-helpers.c @@ -39,6 +39,7 @@ void OpenSSL_print_ver(void) { printf("%s", OPENSSL_VERSION_TEXT); } +// TODO: move this to general-helpers.c array_with_length *create_list_of_errors() { unsigned long err = 0; linked_list *head = NULL; @@ -49,6 +50,8 @@ array_with_length *create_list_of_errors() { unsigned long * arr = NULL; while ((err = ERR_get_error()) != 0) { + char error[256]; + printf("Error code from collection: %lu\nError string returned: %s\nError string from buf: %s\n", err, ERR_error_string(err, error), error); linked_list * newerr = malloc(sizeof(linked_list)); newerr->content = malloc(sizeof(unsigned long)); memcpy(newerr->content, &err, sizeof(unsigned long));