PKCS12.swift 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. //
  2. // PKCS12.swift
  3. // Nextcloud
  4. //
  5. // Created by Milen on 15.05.24.
  6. // Copyright © 2024 Marino Faggiana. All rights reserved.
  7. //
  8. // This program is free software: you can redistribute it and/or modify
  9. // it under the terms of the GNU General Public License as published by
  10. // the Free Software Foundation, either version 3 of the License, or
  11. // (at your option) any later version.
  12. //
  13. // This program is distributed in the hope that it will be useful,
  14. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. // GNU General Public License for more details.
  17. //
  18. // You should have received a copy of the GNU General Public License
  19. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. //
  21. import Foundation
  22. import UIKit
  23. typealias UserCertificate = (data: Data, password: String)
  24. enum PKCS12Error: Error {
  25. case wrongPasswordError(String)
  26. case runtimeError(String)
  27. }
  28. class PKCS12 {
  29. let label: String?
  30. let keyID: NSData?
  31. let trust: SecTrust?
  32. let certChain: [SecTrust]?
  33. let identity: SecIdentity?
  34. /// Creates a PKCS12 instance from a piece of data.
  35. /// - Parameters:
  36. /// - pkcs12Data: the actual data we want to parse.
  37. /// - password: he password required to unlock the PKCS12 data.
  38. public init(pkcs12Data: Data, password: String, onIncorrectPassword: () -> Void) throws {
  39. let importPasswordOption: NSDictionary = [kSecImportExportPassphrase as NSString: password]
  40. var items: CFArray?
  41. let secError: OSStatus = SecPKCS12Import(pkcs12Data as NSData, importPasswordOption, &items)
  42. if secError == errSecAuthFailed {
  43. onIncorrectPassword()
  44. throw PKCS12Error.wrongPasswordError("Wrong password entered")
  45. }
  46. guard let theItemsCFArray = items else { throw PKCS12Error.runtimeError("") }
  47. let theItemsNSArray: NSArray = theItemsCFArray as NSArray
  48. guard let dictArray = theItemsNSArray as? [[String: AnyObject]] else {
  49. throw PKCS12Error.runtimeError("")
  50. }
  51. label = dictArray.element(for: kSecImportItemLabel)
  52. keyID = dictArray.element(for: kSecImportItemKeyID)
  53. trust = dictArray.element(for: kSecImportItemTrust)
  54. certChain = dictArray.element(for: kSecImportItemCertChain)
  55. identity = dictArray.element(for: kSecImportItemIdentity)
  56. }
  57. static func urlCredential(for pkcs12: PKCS12) -> URLCredential? {
  58. guard let identity = pkcs12.identity else {
  59. return nil
  60. }
  61. // In most cases you should pass nil to the certArray parameter. You only need to supply an array of intermediate certificates if the server needs those intermediate certificates to authenticate the client. Typically this isn’t necessary because the server already has a copy of the relevant intermediate certificates.
  62. // See https://developer.apple.com/documentation/foundation/urlcredential/1418121-init
  63. return URLCredential(identity: identity, certificates: nil, persistence: .none)
  64. }
  65. }
  66. private extension Array where Element == [String: AnyObject] {
  67. func element<T>(for key: CFString) -> T? {
  68. for dictElement in self {
  69. if let value = dictElement[key as String] as? T {
  70. return value
  71. }
  72. }
  73. return nil
  74. }
  75. }