1 // swiftlint:disable all 2 // 3 // ASN1DistinguishedNames.swift 4 // 5 // Copyright © 2019 Filippo Maguolo. 6 // 7 // Permission is hereby granted, free of charge, to any person obtaining a copy 8 // of this software and associated documentation files (the "Software"), to deal 9 // in the Software without restriction, including without limitation the rights 10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 // copies of the Software, and to permit persons to whom the Software is 12 // furnished to do so, subject to the following conditions: 13 // 14 // The above copyright notice and this permission notice shall be included in all 15 // copies or substantial portions of the Software. 16 // 17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 // SOFTWARE. 24 25 import Foundation 26 27 @available(*, deprecated, message: "Use OID instead") 28 public class ASN1DistinguishedNames { 29 30 public let oid: String 31 public let representation: String 32 33 init(oid: String, representation: String) { 34 self.oid = oid 35 self.representation = representation 36 } 37 38 public static let commonName = ASN1DistinguishedNames(oid: "2.5.4.3", representation: "CN") 39 public static let dnQualifier = ASN1DistinguishedNames(oid: "2.5.4.46", representation: "DNQ") 40 public static let serialNumber = ASN1DistinguishedNames(oid: "2.5.4.5", representation: "SERIALNUMBER") 41 public static let givenName = ASN1DistinguishedNames(oid: "2.5.4.42", representation: "GIVENNAME") 42 public static let surname = ASN1DistinguishedNames(oid: "2.5.4.4", representation: "SURNAME") 43 public static let organizationalUnitName = ASN1DistinguishedNames(oid: "2.5.4.11", representation: "OU") 44 public static let organizationName = ASN1DistinguishedNames(oid: "2.5.4.10", representation: "O") 45 public static let streetAddress = ASN1DistinguishedNames(oid: "2.5.4.9", representation: "STREET") 46 public static let localityName = ASN1DistinguishedNames(oid: "2.5.4.7", representation: "L") 47 public static let stateOrProvinceName = ASN1DistinguishedNames(oid: "2.5.4.8", representation: "ST") 48 public static let countryName = ASN1DistinguishedNames(oid: "2.5.4.6", representation: "C") 49 public static let email = ASN1DistinguishedNames(oid: "1.2.840.113549.1.9.1", representation: "E") 50 } 51 52 public class ASN1DistinguishedNameFormatter { 53 54 public static var separator = ", " 55 56 // Format subject/issuer information in RFC1779 stringnull57 class func string(from block: ASN1Object) -> String? { 58 var result: String? 59 for sub in block.sub ?? [] { 60 if let subOid = sub.sub(0)?.sub(0), subOid.identifier?.tagNumber() == .objectIdentifier, 61 let oidString = subOid.value as? String, let value = sub.sub(0)?.sub(1)?.value as? String { 62 if result == nil { 63 result = "" 64 } else { 65 result?.append(separator) 66 } 67 if let oid = OID(rawValue: oidString) { 68 if let representation = shortRepresentation(oid: oid) { 69 result?.append(representation) 70 } else { 71 result?.append("\(oid)") 72 } 73 } else { 74 result?.append(oidString) 75 } 76 result?.append("=") 77 result?.append(quote(string: value)) 78 } 79 } 80 return result 81 } 82 quotenull83 class func quote(string: String) -> String { 84 let specialChar = ",+=\n<>#;\\" 85 if string.contains(where: { specialChar.contains($0) }) { 86 return "\"" + string + "\"" 87 } else { 88 return string 89 } 90 } 91 shortRepresentationnull92 class func shortRepresentation(oid: OID) -> String? { 93 switch oid { 94 case .commonName: return "CN" 95 case .dnQualifier: return "DNQ" 96 case .serialNumber: return "SERIALNUMBER" 97 case .givenName: return "GIVENNAME" 98 case .surname: return "SURNAME" 99 case .organizationalUnitName: return "OU" 100 case .organizationName: return "O" 101 case .streetAddress: return "STREET" 102 case .localityName: return "L" 103 case .stateOrProvinceName: return "ST" 104 case .countryName: return "C" 105 case .emailAddress: return "E" 106 case .domainComponent: return "DC" 107 case .jurisdictionLocalityName: return "jurisdictionL" 108 case .jurisdictionStateOrProvinceName: return "jurisdictionST" 109 case .jurisdictionCountryName: return "jurisdictionC" 110 default: return nil 111 } 112 } 113 } 114 // swiftlint:enable all 115