更新了登录
This commit is contained in:
220
Pods/SwiftyRSA/Source/Asn1Parser.swift
generated
Normal file
220
Pods/SwiftyRSA/Source/Asn1Parser.swift
generated
Normal file
@@ -0,0 +1,220 @@
|
||||
//
|
||||
// Asn1Parser.swift
|
||||
// SwiftyRSA
|
||||
//
|
||||
// Created by Lois Di Qual on 5/9/17.
|
||||
// Copyright © 2017 Scoop. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// Simple data scanner that consumes bytes from a raw data and keeps an updated position.
|
||||
private class Scanner {
|
||||
|
||||
enum ScannerError: Error {
|
||||
case outOfBounds
|
||||
}
|
||||
|
||||
let data: Data
|
||||
var index: Int = 0
|
||||
|
||||
/// Returns whether there is no more data to consume
|
||||
var isComplete: Bool {
|
||||
return index >= data.count
|
||||
}
|
||||
|
||||
/// Creates a scanner with provided data
|
||||
///
|
||||
/// - Parameter data: Data to consume
|
||||
init(data: Data) {
|
||||
self.data = data
|
||||
}
|
||||
|
||||
/// Consumes data of provided length and returns it
|
||||
///
|
||||
/// - Parameter length: length of the data to consume
|
||||
/// - Returns: data consumed
|
||||
/// - Throws: ScannerError.outOfBounds error if asked to consume too many bytes
|
||||
func consume(length: Int) throws -> Data {
|
||||
|
||||
guard length > 0 else {
|
||||
return Data()
|
||||
}
|
||||
|
||||
guard index + length <= data.count else {
|
||||
throw ScannerError.outOfBounds
|
||||
}
|
||||
|
||||
let subdata = data.subdata(in: index..<index + length)
|
||||
index += length
|
||||
return subdata
|
||||
}
|
||||
|
||||
/// Consumes a primitive, definite ASN1 length and returns its value.
|
||||
///
|
||||
/// See http://luca.ntop.org/Teaching/Appunti/asn1.html,
|
||||
///
|
||||
/// - Short form. One octet. Bit 8 has value "0" and bits 7-1 give the length.
|
||||
/// - Long form. Two to 127 octets. Bit 8 of first octet has value "1" and
|
||||
/// bits 7-1 give the number of additional length octets.
|
||||
/// Second and following octets give the length, base 256, most significant digit first.
|
||||
///
|
||||
/// - Returns: Length that was consumed
|
||||
/// - Throws: ScannerError.outOfBounds error if asked to consume too many bytes
|
||||
func consumeLength() throws -> Int {
|
||||
|
||||
let lengthByte = try consume(length: 1).firstByte
|
||||
|
||||
// If the first byte's value is less than 0x80, it directly contains the length
|
||||
// so we can return it
|
||||
guard lengthByte >= 0x80 else {
|
||||
return Int(lengthByte)
|
||||
}
|
||||
|
||||
// If the first byte's value is more than 0x80, it indicates how many following bytes
|
||||
// will describe the length. For instance, 0x85 indicates that 0x85 - 0x80 = 0x05 = 5
|
||||
// bytes will describe the length, so we need to read the 5 next bytes and get their integer
|
||||
// value to determine the length.
|
||||
let nextByteCount = lengthByte - 0x80
|
||||
let length = try consume(length: Int(nextByteCount))
|
||||
|
||||
return length.integer
|
||||
}
|
||||
}
|
||||
|
||||
private extension Data {
|
||||
|
||||
/// Returns the first byte of the current data
|
||||
var firstByte: UInt8 {
|
||||
var byte: UInt8 = 0
|
||||
copyBytes(to: &byte, count: MemoryLayout<UInt8>.size)
|
||||
return byte
|
||||
}
|
||||
|
||||
/// Returns the integer value of the current data.
|
||||
/// @warning: this only supports data up to 4 bytes, as we can only extract 32-bit integers.
|
||||
var integer: Int {
|
||||
|
||||
guard count > 0 else {
|
||||
return 0
|
||||
}
|
||||
|
||||
var int: UInt32 = 0
|
||||
var offset: Int32 = Int32(count - 1)
|
||||
forEach { byte in
|
||||
let byte32 = UInt32(byte)
|
||||
let shifted = byte32 << (UInt32(offset) * 8)
|
||||
int = int | shifted
|
||||
offset -= 1
|
||||
}
|
||||
|
||||
return Int(int)
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 Asn1Parser {
|
||||
|
||||
/// An ASN1 node
|
||||
enum Node {
|
||||
case sequence(nodes: [Node])
|
||||
case integer(data: Data)
|
||||
case objectIdentifier(data: Data)
|
||||
case null
|
||||
case bitString(data: Data)
|
||||
case octetString(data: Data)
|
||||
}
|
||||
|
||||
enum ParserError: 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 ParserError if anything goes wrong, or if an unknown node was encountered
|
||||
static func parse(data: Data) throws -> Node {
|
||||
let scanner = Scanner(data: data)
|
||||
let node = try parseNode(scanner: scanner)
|
||||
return node
|
||||
}
|
||||
|
||||
/// Parses an ASN1 given an existing scanne.
|
||||
/// @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 ParserError if anything goes wrong, or if an unknown node was encountered
|
||||
private static func parseNode(scanner: Scanner) throws -> Node {
|
||||
|
||||
let firstByte = try scanner.consume(length: 1).firstByte
|
||||
|
||||
// Sequence
|
||||
if firstByte == 0x30 {
|
||||
let length = try scanner.consumeLength()
|
||||
let data = try scanner.consume(length: length)
|
||||
let nodes = try parseSequence(data: data)
|
||||
return .sequence(nodes: nodes)
|
||||
}
|
||||
|
||||
// Integer
|
||||
if firstByte == 0x02 {
|
||||
let length = try scanner.consumeLength()
|
||||
let data = try scanner.consume(length: length)
|
||||
return .integer(data: data)
|
||||
}
|
||||
|
||||
// Object identifier
|
||||
if firstByte == 0x06 {
|
||||
let length = try scanner.consumeLength()
|
||||
let data = try scanner.consume(length: length)
|
||||
return .objectIdentifier(data: data)
|
||||
}
|
||||
|
||||
// Null
|
||||
if firstByte == 0x05 {
|
||||
_ = try scanner.consume(length: 1)
|
||||
return .null
|
||||
}
|
||||
|
||||
// Bit String
|
||||
if firstByte == 0x03 {
|
||||
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)
|
||||
}
|
||||
|
||||
// Octet String
|
||||
if firstByte == 0x04 {
|
||||
let length = try scanner.consumeLength()
|
||||
let data = try scanner.consume(length: length)
|
||||
return .octetString(data: data)
|
||||
}
|
||||
|
||||
throw ParserError.invalidType(value: firstByte)
|
||||
}
|
||||
|
||||
/// Parses an ASN1 sequence and returns its child nodes
|
||||
///
|
||||
/// - Parameter data: ASN1 data
|
||||
/// - Returns: A list of ASN1 nodes
|
||||
/// - Throws: A ParserError if anything goes wrong, or if an unknown node was encountered
|
||||
private static func parseSequence(data: Data) throws -> [Node] {
|
||||
let scanner = Scanner(data: data)
|
||||
var nodes: [Node] = []
|
||||
while !scanner.isComplete {
|
||||
let node = try parseNode(scanner: scanner)
|
||||
nodes.append(node)
|
||||
}
|
||||
return nodes
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user