1 // swiftlint:disable all
2 //
3 //  ASN1Object.swift
4 //
5 //  Copyright © 2017 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 public class ASN1Object: CustomStringConvertible {
28 
29     /// This property contains the DER encoded object
30     public var rawValue: Data?
31 
32     /// This property contains the decoded Swift object whenever is possible
33     public var value: Any?
34 
35     public var identifier: ASN1Identifier?
36 
37     var sub: [ASN1Object]?
38 
39     public internal(set) weak var parent: ASN1Object?
40 
41     public func sub(_ index: Int) -> ASN1Object? {
42         if let sub = self.sub, index >= 0, index < sub.count {
43             return sub[index]
44         }
45         return nil
46     }
47 
48     public func subCount() -> Int {
49         return sub?.count ?? 0
50     }
51 
52     public func findOid(_ oid: OID) -> ASN1Object? {
53         return findOid(oid.rawValue)
54     }
55 
56     public func findOid(_ oid: String) -> ASN1Object? {
57         for child in sub ?? [] {
58             if child.identifier?.tagNumber() == .objectIdentifier {
59                 if child.value as? String == oid {
60                     return child
61                 }
62             } else {
63                 if let result = child.findOid(oid) {
64                     return result
65                 }
66             }
67         }
68         return nil
69     }
70 
71     public var description: String {
72         return printAsn1()
73     }
74 
75     public var asString: String? {
76         if let string = value as? String {
77             return string
78         }
79 
80         for item in sub ?? [] {
81             if let string = item.asString {
82                 return string
83             }
84         }
85 
86         return nil
87     }
88 
89     fileprivate func printAsn1(insets: String = "") -> String {
90         var output = insets
91         output.append(identifier?.description.uppercased() ?? "")
92         output.append(value != nil ? ": \(value!)": "")
93         if identifier?.typeClass() == .universal, identifier?.tagNumber() == .objectIdentifier {
94             if let oidName = OID.description(of: value as? String ?? "") {
95                 output.append(" (\(oidName))")
96             }
97         }
98         output.append(sub != nil && sub!.count > 0 ? " {": "")
99         output.append("\n")
100         for item in sub ?? [] {
101             output.append(item.printAsn1(insets: insets + "    "))
102         }
103         output.append(sub != nil && sub!.count > 0 ? insets + "}\n": "")
104         return output
105     }
106 }
107 // swiftlint:enable all
108