// // X509Certificate.swift // SwiftyRSA // // Created by Stchepinsky Nathan on 24/06/2021. // Copyright © 2021 Scoop. All rights reserved. // import Foundation /// Encoding/Decoding lengths as octets private extension NSInteger { func encodedOctets() -> [CUnsignedChar] { // Short form if self < 128 { return [CUnsignedChar(self)] } // Long form let long = Int(log2(Double(self)) / 8 + 1) var len = self var result: [CUnsignedChar] = [CUnsignedChar(long + 0x80)] for _ in 0..<long { result.insert(CUnsignedChar(len & 0xFF), at: 1) len = len >> 8 } return result } init?(octetBytes: [CUnsignedChar], startIdx: inout NSInteger) { if octetBytes[startIdx] < 128 { // Short form self.init(octetBytes[startIdx]) startIdx += 1 } else { // Long form let octets = NSInteger(octetBytes[startIdx] as UInt8 - 128) if octets > octetBytes.count - startIdx { self.init(0) return nil } var result = UInt64(0) for octet in 1...octets { result = (result << 8) result = result + UInt64(octetBytes[startIdx + octet]) } startIdx += 1 + octets self.init(result) } } } public extension Data { // This code source come from Heimdall project https://github.com/henrinormak/Heimdall published under MIT Licence /// This method prepend the X509 header to a given public key func prependx509Header() -> Data { let result = NSMutableData() let encodingLength: Int = (self.count + 1).encodedOctets().count let OID: [CUnsignedChar] = [0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00] var builder: [CUnsignedChar] = [] // ASN.1 SEQUENCE builder.append(0x30) // Overall size, made of OID + bitstring encoding + actual key let size = OID.count + 2 + encodingLength + self.count let encodedSize = size.encodedOctets() builder.append(contentsOf: encodedSize) result.append(builder, length: builder.count) result.append(OID, length: OID.count) builder.removeAll(keepingCapacity: false) builder.append(0x03) builder.append(contentsOf: (self.count + 1).encodedOctets()) builder.append(0x00) result.append(builder, length: builder.count) // Actual key bytes result.append(self) return result as Data } func hasX509Header() throws -> Bool { let node: Asn1Parser.Node do { node = try Asn1Parser.parse(data: self) } catch { throw SwiftyRSAError.asn1ParsingFailed } // Ensure the raw data is an ASN1 sequence guard case .sequence(let nodes) = node else { return false } // Must contain 2 elements, a sequence and a bit string if nodes.count != 2 { return false } // Ensure the first node is an ASN1 sequence guard case .sequence(let firstNode) = nodes[0] else { return false } // Must contain 2 elements, an object id and NULL if firstNode.count != 2 { return false } guard case .objectIdentifier(_) = firstNode[0] else { return false } guard case .null = firstNode[1] else { return false } // The 2sd child has to be a bit string containing a sequence of 2 int let last = nodes[1] if case .bitString(let secondChildSequence) = last { return try secondChildSequence.isAnHeaderlessKey() } else { return false } } func isAnHeaderlessKey() throws -> Bool { let node: Asn1Parser.Node do { node = try Asn1Parser.parse(data: self) } catch { throw SwiftyRSAError.asn1ParsingFailed } // Ensure the raw data is an ASN1 sequence guard case .sequence(let nodes) = node else { return false } // Detect whether the sequence only has integers, in which case it's a headerless key let onlyHasIntegers = nodes.filter { node -> Bool in if case .integer = node { return false } return true }.isEmpty // Headerless key return onlyHasIntegers } }