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