// // DSignatureDetailsViewController.swift // PDF Reader Pro Edition // // Created by Niehaoyu on 2023/10/10. // import Cocoa class CDSPDFSigntureModel : NSObject { var certificate: CPDFSignatureCertificate! var level: Int = 0 var hide: Int = 0 var count: Int = 0 var isShow: Bool = false } class DSignatureDetailsViewController: NSViewController, NSTableViewDelegate, NSTableViewDataSource, NSTabViewDelegate { @IBOutlet weak var titleLabel: NSTextField! @IBOutlet weak var subTitleLabel: NSTextField! @IBOutlet weak var closeButton: NSButton! @IBOutlet weak var leftScrollView: NSScrollView! @IBOutlet weak var tableView: NSTableView! @IBOutlet weak var tabView: NSTabView! @IBOutlet weak var summaryImageView: NSImageView! @IBOutlet weak var summaryIssuesLabel: NSTextField! @IBOutlet weak var summaryVaildFromLabel: NSTextField! @IBOutlet weak var summaryVaildtoLabel: NSTextField! @IBOutlet weak var summaryUsageLabel: NSTextField! @IBOutlet var summaryUsageTextView: NSTextView! @IBOutlet weak var summaryNameTextField: NSTextField! @IBOutlet weak var summaryIssuesTextField: NSTextField! @IBOutlet weak var summaryVaildFromTextField: NSTextField! @IBOutlet weak var summaryVaildtoTextField: NSTextField! @IBOutlet weak var summaryExportBtn: NSButton! @IBOutlet weak var detailsTableView: NSTableView! @IBOutlet weak var detailsDatasLabel: NSTextField! @IBOutlet var detailsTextView: NSTextView! @IBOutlet weak var trustTitleLabel: NSTextField! @IBOutlet weak var trustSubtitleLabel: NSTextField! @IBOutlet weak var trustDesBox: NSBox! @IBOutlet weak var trustDesTitleLabel: NSTextField! @IBOutlet weak var trustDes1ImageView: NSImageView! @IBOutlet weak var trustDes1Label: NSTextField! @IBOutlet weak var trustDes2ImageView: NSImageView! @IBOutlet weak var trustDes2Label: NSTextField! @IBOutlet weak var trustButton: NSButton! @IBOutlet weak var policiesSubLabel: NSTextField! @IBOutlet weak var legalTitleLabel: NSTextField! @IBOutlet weak var legalSubLabel: NSTextField! var certificates: [CPDFSignatureCertificate] = [] var signer: CPDFSigner! var signature:CPDFSignature! var pdfListView: CPDFView! var isDigitalFile: Bool = false var models: NSMutableArray = NSMutableArray.init() var certDatas: NSMutableArray = NSMutableArray.init() deinit { print("\(self.className) dealloc") } convenience init() { self.init(nibName: "DSignatureDetailsViewController", bundle: nil) } override func viewWillAppear() { super.viewWillAppear() self.view.window?.title = "" self.view.window?.titlebarAppearsTransparent = true self.view.window?.standardWindowButton(.closeButton)?.isHidden = true self.view.window?.standardWindowButton(.miniaturizeButton)?.isHidden = true self.view.window?.standardWindowButton(.zoomButton)?.isHidden = true } override func viewDidLoad() { super.viewDidLoad() // Do view setup here. self.localizedLanguage() self.tableView.delegate = self self.tableView.dataSource = self self.detailsTableView.delegate = self self.detailsTableView.dataSource = self self.tabView.delegate = self; let kMaxDeep = 10 let kShowFlag = (1 << kMaxDeep)-1 if self.certificates.count > 0 { self.models.removeAllObjects() for i in 0...self.certificates.count-1 { let cert = self.certificates[i] let model = CDSPDFSigntureModel.init() model.certificate = cert model.level = i model.hide = kShowFlag model.isShow = true model.count = self.certificates.count - i - 1 self.models.add(model) } } self.tableView.reloadData() self.summaryUsageTextView.backgroundColor = NSColor.clear if (self.models.count > 0) { let set = NSIndexSet.init(index: self.models.count-1) self.tableView.selectRowIndexes(set as IndexSet, byExtendingSelection: true) self.updateCertificateData() } if (self.isDigitalFile) { self.summaryImageView.image = NSImage(named: "ImageNameDSignatureFromFile") } else { self.summaryImageView.image = NSImage(named: "ImageNameDSignatSaveKechain") } } func localizedLanguage () { self.titleLabel.stringValue = NSLocalizedString("Certificate Viewer", comment: "") self.subTitleLabel.stringValue = NSLocalizedString("This dialog allows you to view the details of a certificate and its entire issuance chain. The details correspond to the selected entry. Multiple issuance chains are being displayed because none of the chains were issued by a trust anchor.", comment: "") self.closeButton.title = NSLocalizedString("OK", comment: "") self.trustButton.title = NSLocalizedString("Add to Trusted Certificates...", comment: "") self.summaryIssuesLabel.stringValue = NSLocalizedString("Issued by:", comment: "") self.summaryVaildFromLabel.stringValue = NSLocalizedString("Valid from:", comment: "") self.summaryVaildtoLabel.stringValue = NSLocalizedString("Valid to:", comment: "") self.summaryUsageLabel.stringValue = NSLocalizedString("Intended usage:", comment: "") self.summaryExportBtn.title = NSLocalizedString("Export", comment: "") self.detailsDatasLabel.stringValue = NSLocalizedString("Certificate Data:", comment: "") self.policiesSubLabel.stringValue = NSLocalizedString("Signatures will be valid if the certificate matches this policy restriction. Policy restrictions are provided by your computer administrator or the certificate authority that issued this certificate. Certificates sometimes contain an identifier to indicate the certificate authority's policy for issuing the certificate. An example policy might be one which indicates that the signer was required to be personally present when issued his or her certificate. Only certificates that have been directly trusted can have policy restrictions.", comment: "") self.legalTitleLabel.stringValue = NSLocalizedString("Legal Disclaimer:", comment: "") self.legalSubLabel.stringValue = NSLocalizedString("Validation of a digitally signed document may require certificate-related services provided by independent third-party service vendors. PDF Reader Pro does not provide any warranties of any kind with respect to digitally signed documents, certificates used to create digitally signed documents, and any related services. ", comment: "") self.trustSubtitleLabel.stringValue = NSLocalizedString("Trust Settings", comment: "") self.trustDesTitleLabel.stringValue = NSLocalizedString("This certificate is trusted to:", comment: "") self.trustDes1Label.stringValue = NSLocalizedString("Sign documents or data", comment: "") self.trustDes2Label.stringValue = NSLocalizedString("Certify documents", comment: "") self.tabView.tabViewItem(at: 0).label = NSLocalizedString("Summary", comment: "") self.tabView.tabViewItem(at: 1).label = NSLocalizedString("Details", comment: "") self.tabView.tabViewItem(at: 2).label = NSLocalizedString("Trust", comment: "") self.tabView.tabViewItem(at: 3).label = NSLocalizedString("Policies", comment: "") self.tabView.tabViewItem(at: 4).label = NSLocalizedString("Legal Notice", comment: "") for column in self.detailsTableView.tableColumns { column.headerCell.title = NSLocalizedString(column.headerCell.title, comment: "") } self.titleLabel.textColor = NSColor.labelColor self.subTitleLabel.textColor = NSColor.labelColor self.summaryVaildFromLabel.textColor = NSColor.labelColor self.summaryVaildtoLabel.textColor = NSColor.labelColor self.summaryUsageLabel.textColor = NSColor.labelColor self.summaryIssuesLabel.textColor = NSColor.labelColor self.detailsDatasLabel.textColor = NSColor.labelColor self.legalTitleLabel.textColor = NSColor.labelColor self.legalSubLabel.textColor = NSColor.labelColor self.summaryNameTextField.textColor = NSColor.labelColor self.summaryIssuesTextField.textColor = NSColor.labelColor self.summaryVaildFromTextField.textColor = NSColor.labelColor self.summaryVaildtoTextField.textColor = NSColor.labelColor self.policiesSubLabel.textColor = NSColor.labelColor } func updateCertificateData () { for certificate in self.certificates { certificate.checkIsTrusted() } let row = self.tableView?.selectedRow self.certDatas.removeAllObjects() if row! > -1 && row! < self.models.count { let model = self.models.object(at: row!) as! CDSPDFSigntureModel let cert = model.certificate let keys = ["CN","OU","O", "emailAddress"] var subString = String() for key in keys { let subDic = cert?.subjectDict as? NSDictionary if subDic?.object(forKey: key) != nil { let keyValue = String(format: "%@", cert?.subjectDict[key] as! NSString) if keyValue.isEmpty == false { if subString.isEmpty == false { subString = subString + "\n" + keyValue } else { subString = keyValue } } } } var issuesString = String() for key in keys { let subDic = cert?.issuerDict as? NSDictionary if subDic?.object(forKey: key) != nil { let keyValue = cert?.issuerDict[key] as! String if keyValue.isEmpty == false { if issuesString.isEmpty == false { issuesString = issuesString + "\n" + keyValue } else { issuesString = keyValue } } } } self.summaryNameTextField.stringValue = subString self.summaryIssuesTextField.stringValue = issuesString let dateFormatter = DateFormatter.init() dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss" if cert?.validityStarts != nil { self.summaryVaildFromTextField.stringValue = dateFormatter.string(from: cert!.validityStarts) } else { self.summaryVaildFromTextField.stringValue = "" } if cert?.validityEnds != nil { self.summaryVaildtoTextField.stringValue = dateFormatter.string(from: cert!.validityEnds) } else { self.summaryVaildtoTextField.stringValue = "" } let att = NSMutableArray.init() if (cert?.keyUsage.contains(.encipherOnly) == true) { att.add(NSLocalizedString("Encipher Only", comment: "")) } if (cert?.keyUsage.contains(.crlSignature) == true) { att.add(NSLocalizedString("CRL Signature", comment: "")) } if (cert?.keyUsage.contains(.certificateSignature) == true) { att.add(NSLocalizedString("Certificate Signature", comment: "")) } if (cert?.keyUsage.contains(.keyAgreement) == true) { att.add(NSLocalizedString("Key Agreement", comment: "")) } if (cert?.keyUsage.contains(.dataEncipherment) == true) { att.add(NSLocalizedString("Data Encipherment", comment: "")) } if (cert?.keyUsage.contains(.keyEncipherment) == true) { att.add(NSLocalizedString("Key Encipherment", comment: "")) } if (cert?.keyUsage.contains(.nonRepudiation) == true) { att.add(NSLocalizedString("Non-Repudiation", comment: "")) } if (cert?.keyUsage.contains(.digitalSignature) == true) { att.add(NSLocalizedString("Digital Signature", comment: "")) } if (cert?.keyUsage.contains(.dDecipherOnly) == true) { att.add(NSLocalizedString("Decipher Only", comment: "")) } var usageString = String() for us in att { var usValue = String(format: "%@", us as! String) if usValue.isEmpty == false{ if usageString.isEmpty == true { usageString = NSLocalizedString(usValue, comment: "") } else { usValue = NSLocalizedString(usValue, comment: "") usageString = String(format: "%@,%@", usageString, usValue) } } } self.summaryUsageTextView.string = usageString var dic = NSMutableDictionary.init() dic.setValue(cert?.version, forKey: NSLocalizedString("Version", comment: "")) self.certDatas.add(dic) dic = NSMutableDictionary.init() switch cert?.signatureAlgorithmType { case .RSA_RSA: dic.setValue("RSA_RSA", forKey: NSLocalizedString("Signature algorithm", comment: "")) break case .MD2RSA: dic.setValue("MD2RSA", forKey: NSLocalizedString("Signature algorithm", comment: "")) break case .MD4RSA: dic.setValue("MD4RSA", forKey: NSLocalizedString("Signature algorithm", comment: "")) break case .MD5RSA: break case .SHA1RSA: dic.setValue("SHA1RSA", forKey: NSLocalizedString("Signature algorithm", comment: "")) break case .SHA256RSA: dic.setValue("SHA256RSA", forKey: NSLocalizedString("Signature algorithm", comment: "")) break case .SM3SM2: dic.setValue("SM3SM2", forKey: NSLocalizedString("Signature algorithm", comment: "")) break default: break } self.certDatas.add(dic) dic = NSMutableDictionary.init() dic.setValue(cert?.subject, forKey: NSLocalizedString("Subject", comment: "")) self.certDatas.add(dic) dic = NSMutableDictionary.init() dic.setValue(cert?.issuer, forKey: NSLocalizedString("Issuer", comment: "")) self.certDatas.add(dic) dic = NSMutableDictionary.init() dic.setValue(cert?.serialNumber, forKey: NSLocalizedString("Serial number", comment: "")) self.certDatas.add(dic) if cert?.validityStarts != nil { dic = NSMutableDictionary.init() dic.setValue(dateFormatter.string(from: cert!.validityStarts), forKey: NSLocalizedString("Validity Starts", comment: "")) self.certDatas.add(dic) } if cert?.validityEnds != nil { dic = NSMutableDictionary.init() dic.setValue(dateFormatter.string(from: cert!.validityEnds), forKey: NSLocalizedString("Validity ends", comment: "")) self.certDatas.add(dic) } dic = NSMutableDictionary.init() dic.setValue(NSLocalizedString("<>", comment: ""), forKey: NSLocalizedString("Authority info access", comment: "")) self.certDatas.add(dic) dic = NSMutableDictionary.init() dic.setValue(NSLocalizedString("<>", comment: ""), forKey: NSLocalizedString("Subject key identifier", comment: "")) self.certDatas.add(dic) dic = NSMutableDictionary.init() dic.setValue(usageString, forKey: NSLocalizedString("Key usage", comment: "")) self.certDatas.add(dic) dic = NSMutableDictionary.init() dic.setValue(NSLocalizedString("<>", comment: ""), forKey: NSLocalizedString("Certificate policies", comment: "")) self.certDatas.add(dic) dic = NSMutableDictionary.init() dic.setValue(NSLocalizedString("<>", comment: ""), forKey: NSLocalizedString("Authority key identifier", comment: "")) self.certDatas.add(dic) dic = NSMutableDictionary.init() dic.setValue(NSLocalizedString("<>", comment: ""), forKey: NSLocalizedString("CRL distribution points", comment: "")) self.certDatas.add(dic) dic = NSMutableDictionary.init() dic.setValue(NSLocalizedString("<>", comment: ""), forKey: NSLocalizedString("Basic constraints", comment: "")) self.certDatas.add(dic) dic = NSMutableDictionary.init() dic.setValue(NSLocalizedString("<>", comment: ""), forKey: NSLocalizedString("Public key", comment: "")) self.certDatas.add(dic) dic = NSMutableDictionary.init() dic.setValue(NSLocalizedString("<>", comment: ""), forKey: NSLocalizedString("SHA1 digest of Public key", comment: "")) self.certDatas.add(dic) dic = NSMutableDictionary.init() dic.setValue(cert?.x509Data, forKey: NSLocalizedString("X.509 data", comment: "")) self.certDatas.add(dic) dic = NSMutableDictionary.init() dic.setValue(cert?.sha1Digest, forKey: NSLocalizedString("SHA1 digest", comment: "")) self.certDatas.add(dic) dic = NSMutableDictionary.init() dic.setValue(cert?.md5Digest, forKey: NSLocalizedString("MD5 digest", comment: "")) self.certDatas.add(dic) self.detailsTableView.reloadData() if cert?.isTrusted == false { self.trustTitleLabel.stringValue = NSLocalizedString("This certificate is not trusted.", comment: "") self.trustButton.isEnabled = true self.trustDes1ImageView.image = NSImage(named: "ImageNameSigntureTrustedFailureIcon") self.trustDes2ImageView.image = NSImage(named: "ImageNameSigntureTrustedFailureIcon") } else { self.trustTitleLabel.stringValue = NSLocalizedString("This certificate is trusted because you have the corresponding private key.", comment: "") self.trustButton.isEnabled = false self.trustDes1ImageView.image = NSImage(named: "ImageNameSigntureTrustedIcon") self.trustDes2ImageView.image = NSImage(named: "ImageNameSigntureTrustedIcon") } } } func sizeOfString(_ string: String, _ font: NSFont) -> (CGFloat) { let attributes: [NSAttributedString.Key: Any] = [ .font: font ] let size = (string as NSString).boundingRect(with: NSSize(width: CGFloat(MAXFLOAT), height: font.pointSize+5), options: .usesLineFragmentOrigin, attributes: attributes, context: nil).size return size.width + 10 } //MARK: IBAction @IBAction func actionClose(_ sender: Any) { self.dismiss(self) } @IBAction func exportAction(_ sender: NSButton) { let model = self.models[self.tableView.selectedRow] as! CDSPDFSigntureModel let cert = model.certificate var fileName = cert?.subjectDict["CN"] as! String if fileName.count == 0 { fileName = NSFullUserName() } fileName.append("_CertExchange") let outputSavePanel = NSSavePanel() outputSavePanel.allowedFileTypes = ["cer"] outputSavePanel.nameFieldStringValue = fileName let result = outputSavePanel.runModal() if result == .OK { let filePath = outputSavePanel.url?.path let success = cert?.export(toFilePath: filePath) if success == true { NSWorkspace.shared.selectFile(filePath, inFileViewerRootedAtPath: "") } else { let alert = NSAlert.init() alert.messageText = NSLocalizedString("Export Failure!", comment: "") alert.addButton(withTitle: NSLocalizedString("OK", comment: "")) alert.runModal() } } } @IBAction func buttonItemClick_TrustCer(_ sender: NSButton) { let model = self.models.object(at: self.tableView.selectedRow) as! CDSPDFSigntureModel let cert = model.certificate! let success = cert.addToTrustedCertificates() if success { self.updateCertificateData() if self.signature != nil { NotificationCenter.default.post(name: NSNotification.Name(rawValue: "CSignatureTrustCerDidChangeNotification"), object: nil) self.signature.verifySignature(with: self.pdfListView.document) } let alert = NSAlert.init() alert.messageText = NSLocalizedString("Add to Trusted Certificate Successfully!", comment: "") alert.addButton(withTitle: NSLocalizedString("OK", comment: "")) alert.runModal() } else { let alert = NSAlert.init() alert.messageText = NSLocalizedString("Add to Trusted Certificate Failed!", comment: "") alert.addButton(withTitle: NSLocalizedString("OK", comment: "")) alert.runModal() } } //MARK: NSTableViewDelegate func numberOfRows(in tableView: NSTableView) -> Int { if tableView.isEqual(self.detailsTableView) { return self.certDatas.count } else { return self.models.count } } func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat { return 22.0 } func tableView(_ tableView: NSTableView, rowViewForRow row: Int) -> NSTableRowView? { return NSTableRowView() } func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { if self.detailsTableView.isEqual(tableView) { let dic = self.certDatas.object(at: row) as! NSDictionary let cell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(tableColumn?.identifier.rawValue ?? ""), owner: self) as! NSTableCellView if ((tableColumn?.identifier.rawValue) == "name") { cell.textField?.stringValue = dic.allKeys.first as! String } else if ((tableColumn?.identifier.rawValue) == "value") { // tableColumn?.title = NSLocalizedString("Value:", comment: "") let key = dic.allKeys.first as! String cell.textField?.stringValue = dic.object(forKey: key) as! String } return cell } else { let cellView = DSignDetailTypeACellView() cellView.model = self.models.object(at: row) as! CDSPDFSigntureModel let width = self.sizeOfString(cellView.contendLabel.stringValue, cellView.contendLabel.font!) let max = max(width, tableColumn!.width) tableColumn?.width = max return cellView } } func tableViewSelectionDidChange(_ notification: Notification) { let tableView = notification.object if self.detailsTableView.isEqual(tableView) { let model = self.models.object(at: self.tableView.selectedRow) as! CDSPDFSigntureModel let cert = model.certificate! let dateFormatter = DateFormatter.init() dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss" let selectedRow = self.detailsTableView.selectedRow if selectedRow == 0 { self.detailsTextView.string = cert.version ?? "" } else if selectedRow == 1 { switch cert.signatureAlgorithmType { case .RSA_RSA: self.detailsTextView.string = String(format: "%@(%@)","RSA_RSA",cert.signatureAlgorithmOID) break; case .MD2RSA: self.detailsTextView.string = String(format: "%@(%@)","MD2RSA",cert.signatureAlgorithmOID) break; case .MD4RSA: self.detailsTextView.string = String(format: "%@(%@)", "MD4RSA",cert.signatureAlgorithmOID) break; case .SHA1RSA: self.detailsTextView.string = String(format: "%@(%@)", "SHA1RSA",cert.signatureAlgorithmOID) break; case .SHA256RSA: self.detailsTextView.string = String(format: "%@(%@)", "SHA256RSA",cert.signatureAlgorithmOID) break; case .SM3SM2: self.detailsTextView.string = String(format: "%@(%@)", "SM3SM2",cert.signatureAlgorithmOID) break; default: break } } else if selectedRow == 2 { var string = "" for key in cert.subjectDict.keys { if (string.count == 0) { string = String(format: "%@=%@",key as! String, cert.subjectDict[key] as! String) } else { string = String(format: "%@\n%@=%@",string, (key as! String), cert.subjectDict[key] as! String) } } self.detailsTextView.string = string } else if selectedRow == 3 { var string = "" for key in cert.issuerDict.keys { if (string.count == 0) { string = String(format: "%@=%@",key as! String, cert.issuerDict[key] as! String) } else { string = String(format: "%@\n%@=%@",string, (key as! String), cert.issuerDict[key] as! String) } } self.detailsTextView.string = string } else if selectedRow == 4 { self.detailsTextView.string = cert.serialNumber ?? "" } else if selectedRow == 5 { self.detailsTextView.string = dateFormatter.string(from: cert.validityStarts) } else if selectedRow == 6 { self.detailsTextView.string = dateFormatter.string(from: cert.validityEnds) } else if selectedRow == 7 { var content = "" for infoDic in cert.authorityInfoAccess { let dic: Dictionary = infoDic if content.count == 0 { content = String(format: "%@ = %@", dic["Method"] as! String, (dic["Method"] as! String)) content = content + "\n" let tString = String(format: "URL = %@", (dic["URI"] as! String)) content = content + tString } else { content = content + "\n" content = content + "\n" var tString = String(format: "Method = %@", (dic["Method"] as! String)) content = content + tString content = content + "\n" tString = String(format: "URL = %@",(dic["URI"] as! String)) content = content + tString } } self.detailsTextView.string = content } else if selectedRow == 8 { self.detailsTextView.string = cert.subjectKeyIdentifier.uppercased() } else if selectedRow == 9 { let att = NSMutableArray() if cert.keyUsage.contains(.encipherOnly) == true { att.add(NSLocalizedString("Encipher Only", comment: "")) } else if cert.keyUsage.contains(.crlSignature) == true { att.add(NSLocalizedString("CRL Signature", comment: "")) } else if cert.keyUsage.contains(.certificateSignature) == true { att.add(NSLocalizedString("Certificate Signature", comment: "")) } else if cert.keyUsage.contains(.keyAgreement) == true { att.add(NSLocalizedString("Key Agreement", comment: "")) } else if cert.keyUsage.contains(.dataEncipherment) == true { att.add(NSLocalizedString("Data Encipherment", comment: "")) } else if cert.keyUsage.contains(.keyEncipherment) == true { att.add(NSLocalizedString("Key Encipherment", comment: "")) } else if cert.keyUsage.contains(.nonRepudiation) == true { att.add(NSLocalizedString("Non-Repudiation", comment: "")) } else if cert.keyUsage.contains(.digitalSignature) == true { att.add(NSLocalizedString("Digital Signature", comment: "")) } else if cert.keyUsage.contains(.dDecipherOnly) == true { att.add(NSLocalizedString("Decipher Only", comment: "")) } var usageString = "" for us in att { if usageString.count == 0 { usageString = NSLocalizedString(us as! String, comment: "") } else { usageString = String(format: "%@\n%@",usageString, NSLocalizedString(us as! String, comment: "")) } if usageString.count == 0 { } else { usageString = String(format: "%@\n%@",usageString, NSLocalizedString(us as! String, comment: "")) } } self.detailsTextView.string = usageString } else if selectedRow == 10 { self.detailsTextView.string = cert.certificatePolicies ?? "" } else if selectedRow == 11 { self.detailsTextView.string = cert.authorityKeyIdentifier.uppercased() } else if selectedRow == 12 { var content = "" for tString in cert.crlDistributionPoints { if content.count == 0 { content = tString } else { content = content + "\n" content = content + tString } } self.detailsTextView.string = content } else if selectedRow == 13 { self.detailsTextView.string = cert.basicConstraints.replacingOccurrences(of: ",", with: "\n") } else if selectedRow == 14 { self.detailsTextView.string = cert.publicKey.replacingOccurrences(of: ":", with: " ") } else if selectedRow == 15 { self.detailsTextView.string = cert.subjectKeyIdentifier.uppercased() } else if selectedRow == 16 { self.detailsTextView.string = cert.x509Data.replacingOccurrences(of: ":", with: " ") } else if selectedRow == 17 { self.detailsTextView.string = cert.sha1Digest.replacingOccurrences(of: ":", with: " ") } else if selectedRow == 18 { self.detailsTextView.string = cert.md5Digest.replacingOccurrences(of: ":", with: " ") } } else { self.detailsTextView.string = "" self.updateCertificateData() } } }