// // DER.swift // Swifter // // Copyright © 2016 Damian Kołakowski. All rights reserved. // import Foundation public struct DER { // // Distinguished Encoding Rules (DER) // // https://en.wikipedia.org/wiki/X.690 // public enum DecodeError: Error { case invalidData } public enum DERClass: UInt8 { case universal = 0, application = 1, context = 2, priv = 3 } public static func decode(_ input: [UInt8]) throws -> DEROObject { var iterator = input[0..>) throws -> DEROObject { guard let first = generator.next() else { throw DecodeError.invalidData } let clazz = try parseClass(first) let primitive = try parsePrimitive(first) let tag = try parseTag(first, &generator) let data = try parseContent(&generator) return DEROObject(clazz: clazz, primitive: primitive, tag: tag, data: data) } private static func parsePrimitive(_ first: UInt8) throws -> Bool { return (first & 0x20) == 0 } private static func parseClass(_ first: UInt8) throws -> DERClass { if let cls = DERClass(rawValue: (first & 0xC0) >> 6) { return cls } throw DecodeError.invalidData } private static func parseTag(_ first: UInt8, _ generator: inout IndexingIterator>) throws -> UInt32 { switch first & 0x1F { case let short where short < 0x1F: return UInt32(short) case let long where long == 0x1F: // Arbitrary allow only for UInt32 as max TAG value. var buffer = [UInt8](repeating: 0, count: 4) for i in 0..(OpaquePointer($0.baseAddress!)).pointee.littleEndian } default: throw DecodeError.invalidData } } private static func parseContent(_ generator: inout IndexingIterator>) throws -> [UInt8] { guard let length = generator.next() else { throw DecodeError.invalidData } switch length { case 0..<0x80: var content = [UInt8]() for _ in 0.. 4 { /* Arbitrary allow only for UInt32 max content size. */ throw DecodeError.invalidData } var buffer = [UInt8]() for _ in 0..(OpaquePointer($0.baseAddress!)).pointee.littleEndian } var content = [UInt8]() for _ in 0..