1 // swiftlint:disable all
2 //
3 //  X509ExtensionClasses.swift
4 //
5 //  Copyright © 2020 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 extension X509Certificate {
28 
29     /// Recognition for Basic Constraint Extension (2.5.29.19)
30     public class BasicConstraintExtension: X509Extension {
31 
32         public var isCA: Bool {
33             return (valueAsBlock?.sub(0)?.sub(0)?.value as? Bool) ?? false
34         }
35 
36         public var pathLenConstraint: UInt64? {
37             guard let data = valueAsBlock?.sub(0)?.sub(1)?.value as? Data else {
38                 return nil
39             }
40             return data.uint64Value
41         }
42     }
43 
44     /// Recognition for Subject Key Identifier Extension (2.5.29.14)
45     public class SubjectKeyIdentifierExtension: X509Extension {
46 
47         public override var value: Any? {
48             guard let rawValue = valueAsBlock?.rawValue else {
49                 return nil
50             }
51             return rawValue.sequenceContent
52         }
53     }
54 
55     // MARK: - Authority Extensions
56 
57     public struct AuthorityInfoAccess {
58         public let method: String
59         public let location: String
60     }
61 
62     /// Recognition for Authority Info Access Extension (1.3.6.1.5.5.7.1.1)
63     public class AuthorityInfoAccessExtension: X509Extension {
64 
65         public var infoAccess: [AuthorityInfoAccess]? {
66             guard let valueAsBlock = valueAsBlock else {
67                 return nil
68             }
69             let subs = valueAsBlock.sub(0)?.sub ?? []
70 
71             return subs.compactMap { sub in
72                 guard var oidData = sub.sub(0)?.rawValue,
73                       let nameBlock = sub.sub(1) else {
74                     return nil
75                 }
76                 if
77                     let oid = ASN1DERDecoder.decodeOid(contentData: &oidData),
78                     let location = generalName(of: nameBlock) {
79                     return AuthorityInfoAccess(method: oid, location: location)
80                 } else {
81                     return nil
82                 }
83             }
84         }
85     }
86 
87     /// Recognition for Authority Key Identifier Extension (2.5.29.35)
88     public class AuthorityKeyIdentifierExtension: X509Extension {
89 
90         /*
91         AuthorityKeyIdentifier ::= SEQUENCE {
92            keyIdentifier             [0] KeyIdentifier           OPTIONAL,
93            authorityCertIssuer       [1] GeneralNames            OPTIONAL,
94            authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL  }
95         */
96 
97         public var keyIdentifier: Data? {
98             guard let sequence = valueAsBlock?.sub(0)?.sub else {
99                 return nil
100             }
101             if let sub = sequence.first(where: { $0.identifier?.tagNumber().rawValue == 0 }) {
102                 return sub.rawValue
103             }
104             return nil
105         }
106 
107         public var certificateIssuer: [String]? {
108             guard let sequence = valueAsBlock?.sub(0)?.sub else {
109                 return nil
110             }
111             if let sub = sequence.first(where: { $0.identifier?.tagNumber().rawValue == 1 }) {
112                 return sub.sub?.compactMap { generalName(of: $0) }
113             }
114             return nil
115         }
116 
117         public var serialNumber: Data? {
118             guard let sequence = valueAsBlock?.sub(0)?.sub else {
119                 return nil
120             }
121             if let sub = sequence.first(where: { $0.identifier?.tagNumber().rawValue == 2 }) {
122                 return sub.rawValue
123             }
124             return nil
125         }
126     }
127 
128     // MARK: - Certificate Policies Extension
129 
130     public struct CertificatePolicyQualifier {
131         public let oid: String
132         public let value: String?
133     }
134     public struct CertificatePolicy {
135         public let oid: String
136         public let qualifiers: [CertificatePolicyQualifier]?
137     }
138 
139     /// Recognition for Certificate Policies Extension (2.5.29.32)
140     public class CertificatePoliciesExtension: X509Extension {
141 
142         public var policies: [CertificatePolicy]? {
143             guard let valueAsBlock = valueAsBlock else {
144                 return nil
145             }
146             let subs = valueAsBlock.sub(0)?.sub ?? []
147 
148             return subs.compactMap { sub in
149                 guard
150                     var data = sub.sub(0)?.rawValue,
151                     let oid = ASN1DERDecoder.decodeOid(contentData: &data) else {
152                     return nil
153                 }
154                 var qualifiers: [CertificatePolicyQualifier]?
155                 if let subQualifiers = sub.sub(1) {
156                     qualifiers = subQualifiers.sub?.compactMap { sub in
157                         if var rawValue = sub.sub(0)?.rawValue, let oid = ASN1DERDecoder.decodeOid(contentData: &rawValue) {
158                             let value = sub.sub(1)?.asString
159                             return CertificatePolicyQualifier(oid: oid, value: value)
160                         } else {
161                             return nil
162                         }
163                     }
164                 }
165                 return CertificatePolicy(oid: oid, qualifiers: qualifiers)
166             }
167         }
168     }
169 
170     // MARK: - CRL Distribution Points
171 
172     public class CRLDistributionPointsExtension: X509Extension {
173 
174         public var crls: [String]? {
175             guard let valueAsBlock = valueAsBlock else {
176                 return nil
177             }
178             let subs = valueAsBlock.sub(0)?.sub ?? []
179             return subs.compactMap { $0.asString }
180         }
181     }
182 }
183 // swiftlint:enable all
184