杨锴
2024-08-14 909e20941e45f8712c012db602034b47da0bfdb0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
//
//  CryptoSwift
//
//  Copyright (C) Marcin Krzyżanowski <marcin@krzyzanowskim.com>
//  This software is provided 'as-is', without any express or implied warranty.
//
//  In no event will the authors be held liable for any damages arising from the use of this software.
//
//  Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
//  - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
//  - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
//  - This notice may not be removed or altered from any source or binary distribution.
//
//  ASN1 Code inspired by Asn1Parser.swift from SwiftyRSA
 
import Foundation
 
extension ASN1 {
  /// A simple ASN1 parser that will recursively iterate over a root node and return a Node tree.
  /// The root node can be any of the supported nodes described in `Node`. If the parser encounters a sequence
  /// it will recursively parse its children.
  enum Decoder {
 
    enum DecodingError: Error {
      case noType
      case invalidType(value: UInt8)
    }
 
    /// Parses ASN1 data and returns its root node.
    ///
    /// - Parameter data: ASN1 data to parse
    /// - Returns: Root ASN1 Node
    /// - Throws: A DecodingError if anything goes wrong, or if an unknown node was encountered
    static func decode(data: Data) throws -> Node {
      let scanner = ASN1.Scanner(data: data)
      let node = try decodeNode(scanner: scanner)
      return node
    }
 
    /// Parses an ASN1 given an existing scanner.
    /// @warning: this will modify the state (ie: position) of the provided scanner.
    ///
    /// - Parameter scanner: Scanner to use to consume the data
    /// - Returns: Parsed node
    /// - Throws: A DecodingError if anything goes wrong, or if an unknown node was encountered
    private static func decodeNode(scanner: ASN1.Scanner) throws -> Node {
 
      let firstByte = try scanner.consume(length: 1).firstByte
 
      switch firstByte {
        case IDENTIFIERS.SEQUENCE.rawValue:
          let length = try scanner.consumeLength()
          let data = try scanner.consume(length: length)
          let nodes = try decodeSequence(data: data)
          return .sequence(nodes: nodes)
 
        case IDENTIFIERS.INTERGER.rawValue:
          let length = try scanner.consumeLength()
          let data = try scanner.consume(length: length)
          return .integer(data: data)
 
        case IDENTIFIERS.OBJECTID.rawValue:
          let length = try scanner.consumeLength()
          let data = try scanner.consume(length: length)
          return .objectIdentifier(data: data)
 
        case IDENTIFIERS.NULL.rawValue:
          _ = try scanner.consume(length: 1)
          return .null
 
        case IDENTIFIERS.BITSTRING.rawValue:
          let length = try scanner.consumeLength()
 
          // There's an extra byte (0x00) after the bit string length in all the keys I've encountered.
          // I couldn't find a specification that referenced this extra byte, but let's consume it and discard it.
          _ = try scanner.consume(length: 1)
 
          let data = try scanner.consume(length: length - 1)
          return .bitString(data: data)
 
        case IDENTIFIERS.OCTETSTRING.rawValue:
          let length = try scanner.consumeLength()
          let data = try scanner.consume(length: length)
          return .octetString(data: data)
 
        default:
          throw DecodingError.invalidType(value: firstByte)
      }
    }
 
    /// Parses an ASN1 sequence and returns its child nodes
    ///
    /// - Parameter data: ASN1 data
    /// - Returns: A list of ASN1 nodes
    /// - Throws: A DecodingError if anything goes wrong, or if an unknown node was encountered
    private static func decodeSequence(data: Data) throws -> [Node] {
      let scanner = ASN1.Scanner(data: data)
      var nodes: [Node] = []
      while !scanner.isComplete {
        let node = try decodeNode(scanner: scanner)
        nodes.append(node)
      }
      return nodes
    }
  }
}