Skip to content

Instantly share code, notes, and snippets.

@ateska
Created February 18, 2019 22:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ateska/82d08b543820fd1ed990b90943ac13f8 to your computer and use it in GitHub Desktop.
Save ateska/82d08b543820fd1ed990b90943ac13f8 to your computer and use it in GitHub Desktop.
//
// mini_asn1_der.swift
// miniasn1
//
// Created by Ales Teska on 18.2.19.
// Copyright © 2019 TeskaLabs. All rights reserved.
//
import Foundation
func asn1_int_to_bytes(x: UInt) -> [UInt8] {
var l = x
var d:[UInt8] = []
while (l > 0) {
d.append(UInt8(l & 0xFF))
l = l >> 8
}
return d
}
func asn1_il(tag: UInt8, length: UInt) -> [UInt8] {
if (length < 128) {
return [tag, UInt8(length)]
}
let d = asn1_int_to_bytes(x:length)
return [tag, 0x80 | UInt8(d.count)] + d
}
func asn1_SEQUENCE(elements: [[UInt8]?], implicit_tagging: Bool = true) -> [UInt8] {
var d:[UInt8] = []
var n: UInt8 = 0
for e:[UInt8]? in elements {
guard (e != nil) else {
n += 1
continue
}
var identifier: UInt8 = e![0]
if implicit_tagging {
let e0 = e![0]
if (((e0 & 0x1F) == 0x10) || ((e0 & 0x1F) == 0x11) || (e0 == 0xA0)) {
// the element is constructed
identifier = 0xA0
} else {
// the element is primitive
identifier = 0x80
}
}
else {
identifier = e![0]
}
d.append(identifier + n)
d += e![1..<e!.count]
n += 1
}
return asn1_il(tag:0x30, length:UInt(d.count)) + d
}
func asn1_SEQUENCE_OF(elements: [[UInt8]?], implicit_tagging: Bool = true) -> [UInt8] {
return asn1_SEQUENCE(elements: elements, implicit_tagging: false)
}
func asn1_INTEGER(value: UInt) -> [UInt8] {
// TODO: Support for negative numbers
if (value == 0) {
return asn1_il(tag: 0x02, length: 1) + [0]
}
var b = asn1_int_to_bytes(x: value)
if (b[0] & 0x80 == 0x80){
b.insert(0, at: 0)
}
return asn1_il(tag: 0x02, length: UInt(b.count)) + b
}
func asn1_OCTEC_STRING(value: Data) -> [UInt8] {
return asn1_il(tag:0x04, length:UInt(value.count)) + value
}
func asn1_IA5STRING(value: String) -> [UInt8] {
let b = value.data(using: .ascii)!
return asn1_il(tag:0x16, length:UInt(b.count)) + b
}
func asn1_BITSTRING(value: Data) -> [UInt8] {
return asn1_il(tag:0x03, length:UInt(value.count)+1) + [0] + value
}
func asn1_UTF8String(value: String) -> [UInt8] {
let b = value.data(using: .utf8)!
return asn1_il(tag:12, length:UInt(b.count)) + b
}
func asn1_UTCTime(value: Date) -> [UInt8] {
let formatter = DateFormatter()
formatter.dateFormat = "yyMMddHHmmSS"
let s = formatter.string(from: value) + "Z"
let b = s.data(using: .ascii)!
return asn1_il(tag: 23, length: UInt(b.count)) + b
}
func asn1_variable_length_quantity(value: Int) -> [UInt8] {
// Break it up in groups of 7 bits starting from the lowest significant bit
// For all the other groups of 7 bits than lowest one, set the MSB to 1
var v = value
var m: UInt8 = 0x00
var output: [UInt8] = []
while (v >= 0x80) {
output.insert(UInt8(v & 0x7f) | m | m, at:0)
v = v >> 7
m = 0x80
}
output.insert(UInt8(v) | m, at:0)
return output
}
func asn1_OBJECT_IDENTIFIER(value:String) -> [UInt8] {
let a: [Int] = value.split(separator: ".").map { Int($0)! }
var oid: [UInt8] = [UInt8(a[0]*40 + a[1])] // First two items are coded by a1*40+a2
// A rest is Variable-length_quantity
for n in a[2..<a.count] {
oid += asn1_variable_length_quantity(value:n)
}
return asn1_il(tag: 0x06, length: UInt(oid.count)) + oid
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment