Coverage report: /home/ellis/comp/core/lib/dat/asn1.lisp
Kind | Covered | All | % |
expression | 0 | 288 | 0.0 |
branch | 0 | 40 | 0.0 |
Key
Not instrumented
Conditionalized out
Executed
Not executed
Both branches taken
One branch taken
Neither branch taken
1
;;; asn1.lisp --- Simple ASN.1 Coding
3
;; Abstract Syntax Notation One
7
;; IDL for definiting data structures - joint standard between ITU-T and ISO
8
;; used to define a large number of protocols.
10
;; For example see the CRY/SSL/X509 package.
13
- https://github.com/digitalbazaar/forge/blob/909e312878838f46ba6d70e90264650b05eb8bde/js/asn1.js
14
- http://www.obj-sys.com/asn1tutorial/node128.html
15
- https://github.com/deadtrickster/ssl_verify_hostname.erl/blob/master/src/ssl_verify_hostname.erl
16
- https://golang.org/src/encoding/asn1/asn1.go?m=text
20
The most common binary encodings for ASN.1 are BER (Basic Encoding Rules)
21
and DER (Distinguished Encoding Rules). DER is just a subset of BER that
22
has stricter requirements for how data must be encoded.
24
Each ASN.1 structure has a tag (a byte identifying the ASN.1 structure type)
25
and a byte array for the value of this ASN1 structure which may be data or a
26
list of ASN.1 structures.
28
Each ASN.1 structure using BER is (Tag-Length-Value):
30
| byte 0 | bytes X | bytes Y |
31
|--------|---------|----------
32
| tag | length | value |
34
ASN.1 allows for tags to be of "High-tag-number form" which allows a tag to
35
be two or more octets, but that is not supported by this class. A tag is
36
only 1 byte. Bits 1-5 give the tag number (ie the data type within a
37
particular 'class'), 6 indicates whether or not the ASN.1 value is
38
constructed from other ASN.1 values, and bits 7 and 8 give the 'class'. If
39
bits 7 and 8 are both zero, the class is UNIVERSAL. If only bit 7 is set,
40
then the class is APPLICATION. If only bit 8 is set, then the class is
41
CONTEXT_SPECIFIC. If both bits 7 and 8 are set, then the class is PRIVATE.
42
The tag numbers for the data types for the class UNIVERSAL are listed below:
44
UNIVERSAL 0 Reserved for use by the encoding rules
45
UNIVERSAL 1 Boolean type
46
UNIVERSAL 2 Integer type
47
UNIVERSAL 3 Bitstring type
48
UNIVERSAL 4 Octetstring type
50
UNIVERSAL 6 Object identifier type
51
UNIVERSAL 7 Object descriptor type
52
UNIVERSAL 8 External type and Instance-of type
54
UNIVERSAL 10 Enumerated type
55
UNIVERSAL 11 Embedded-pdv type
56
UNIVERSAL 12 UTF8String type
57
UNIVERSAL 13 Relative object identifier type
58
UNIVERSAL 14-15 Reserved for future editions
59
UNIVERSAL 16 Sequence and Sequence-of types
60
UNIVERSAL 17 Set and Set-of types
61
UNIVERSAL 18-22, 25-30 Character string types
62
UNIVERSAL 23-24 Time types
64
The length of an ASN.1 structure is specified after the tag identifier.
65
There is a definite form and an indefinite form. The indefinite form may
66
be used if the encoding is constructed and not all immediately available.
67
The indefinite form is encoded using a length byte with only the 8th bit
68
set. The end of the constructed object is marked using end-of-contents
69
octets (two zero bytes).
71
The definite form looks like this:
73
The length may take up 1 or more bytes, it depends on the length of the
74
value of the ASN.1 structure. DER encoding requires that if the ASN.1
75
structure has a value that has a length greater than 127, more than 1 byte
76
will be used to store its length, otherwise just one byte will be used.
79
In the case that the length of the ASN.1 value is less than 127, 1 octet
80
(byte) is used to store the "short form" length. The 8th bit has a value of
81
0 indicating the length is "short form" and not "long form" and bits 7-1
82
give the length of the data. (The 8th bit is the left-most, most significant
83
bit: also known as big endian or network format).
85
In the case that the length of the ASN.1 value is greater than 127, 2 to
86
127 octets (bytes) are used to store the "long form" length. The first
87
byte's 8th bit is set to 1 to indicate the length is "long form." Bits 7-1
88
give the number of additional octets. All following octets are in base 256
89
with the most significant digit first (typical big-endian binary unsigned
90
integer storage). So, for instance, if the length of a value was 257, the
91
first byte would be set to:
93
10000010 = 130 = 0x82.
95
This indicates there are 2 octets (base 256) for the length. The second and
96
third bytes (the octets just mentioned) would store the length in base 256:
98
octet 2: 00000001 = 1 * 256^1 = 256
99
octet 3: 00000001 = 1 * 256^0 = 1
102
The algorithm for converting a js integer value of 257 to base-256 is:
106
bytes[0] = (value >>> 8) & 0xFF; // most significant byte first
107
bytes[1] = value & 0xFF; // least significant byte last
109
On the ASN.1 UNIVERSAL Object Identifier (OID) type:
111
An OID can be written like: "value1.value2.value3...valueN"
113
The DER encoding rules:
115
The first byte has the value 40 * value1 + value2.
116
The following bytes, if any, encode the remaining values. Each value is
117
encoded in base 128, most significant digit first (big endian), with as
118
few digits as possible, and the most significant bit of each byte set
119
to 1 except the last in each value's encoding. For example: Given the
120
OID "1.2.840.113549", its DER encoding is (remember each byte except the
121
last one in each encoding is OR'd with 0x80):
123
byte 1: 40 * 1 + 2 = 42 = 0x2A.
124
bytes 2-3: 128 * 6 + 72 = 840 = 6 72 = 6 72 = 0x0648 = 0x8648
125
bytes 4-6: 16384 * 6 + 128 * 119 + 13 = 6 119 13 = 0x06770D = 0x86F70D
127
The final value is: 0x2A864886F70D.
128
The full OID (including ASN.1 tag and length of 6 bytes) is:
132
(in-package :dat/asn1)
135
(defun copy-to-lisp-vector (src vector count)
136
(declare (octet-vector vector)
138
(optimize (safety 0) (speed 3)))
139
(clone-octets-from-alien src vector count))
141
(defun asn1-string-octet-vector (asn1-string)
142
(let* ((data (asn1-string-data asn1-string))
143
(length (asn1-string-length asn1-string))
144
(vector (io/static:make-static-vector length)))
145
(copy-to-lisp-vector data vector length)
148
(definline asn1-iastring-char-p (byte)
149
(declare (type octet byte)
150
(optimize (speed 3) (safety 0)))
153
(definline asn1-iastring-p (bytes)
154
(declare (octet-vector bytes)
155
(optimize (speed 3) (safety 0)))
156
(every #'asn1-iastring-char-p bytes))
158
(defgeneric decode-asn1-string (self type))
160
(defmethod decode-asn1-string (self (type (eql #.(v-asn1 :ia5string))))
161
(let ((bytes (asn1-string-octet-vector self)))
162
(if (asn1-iastring-p self)
163
(sb-ext:octets-to-string bytes :external-format :ascii)
164
(error 'invalid-asn1-string :type #.(v-asn1 :ia5string)))))
166
(defun asn1-printable-char-p (byte)
167
(declare (type (unsigned-byte 8) byte)
168
(optimize (speed 3) (safety 0)))
171
((and (>= byte #.(char-code #\a))
172
(<= byte #.(char-code #\z)))
175
((and (>= byte #.(char-code #\'))
176
(<= byte #.(char-code #\/)))
179
((and (>= byte #.(char-code #\0))
180
(<= byte #.(char-code #\9)))
183
((and (>= byte #.(char-code #\A))
184
(<= byte #.(char-code #\Z)))
187
((= byte #.(char-code #\ )) t)
188
((= byte #.(char-code #\:)) t)
189
((= byte #.(char-code #\=)) t)
190
((= byte #.(char-code #\?)) t)))
192
(definline asn1-printable-string-p (bytes)
193
(declare (octet-vector bytes)
194
(optimize (speed 3) (safety 0)))
195
(every #'asn1-printable-char-p bytes))
197
(defmethod decode-asn1-string (self (type (eql #.(v-asn1 :printablestring))))
198
(let* ((bytes (asn1-string-octet-vector self)))
199
(if (asn1-printable-string-p bytes)
200
(sb-ext:octets-to-string bytes :external-format :ascii)
201
(error 'invalid-asn1-string :type #.(v-asn1 :printablestring)))))
203
(defmethod decode-asn1-string (self (type (eql #.(v-asn1 :utf8string))))
204
(let* ((data (asn1-string-data self))
205
(length (asn1-string-length self))
206
(vec (make-octets length)))
207
(clone-octets-from-alien data vec length)
208
(sb-ext:octets-to-string vec :external-format :utf-8 :end length)))
211
(defmethod decode-asn1-string (self (type (eql #.(v-asn1 :universalstring))))
212
(let ((len (asn1-string-length self))
213
(data (asn1-string-data self)))
214
(if (= 0 (mod len 4))
215
(let ((vec (make-octets len)))
216
(clone-octets-from-alien data vec len)
217
(sb-ext:octets-to-string vec :external-format :utf32))
218
(error 'invalid-asn1-string :type '+v-asn1-universalstring+))))
220
(definline asn1-teletex-char-p (byte)
221
(declare (octet byte)
222
(optimize (speed 3) (safety 0)))
223
(and (>= byte #x20) (< byte #x80)))
225
(definline asn1-teletex-string-p (bytes)
226
(declare (octet-vector bytes)
227
(optimize (speed 3) (safety 0)))
228
(every #'asn1-teletex-char-p bytes))
230
(defmethod decode-asn1-string (self (type (eql #.(v-asn1 :teletexstring))))
231
(let ((bytes (asn1-string-octet-vector self)))
232
(if (asn1-teletex-string-p bytes)
233
(sb-ext:octets-to-string bytes :external-format :ascii)
234
(error 'invalid-asn1-string :type #.(v-asn1 :teletexstring)))))
236
(defmethod decode-asn1-string (self (type (eql #.(v-asn1 :bmpstring))))
237
(if (= 0 (mod (length self) 2))
238
(let* ((data (asn1-string-data self))
239
(len (asn1-string-length self))
240
(vec (make-octets len)))
241
(clone-octets-from-alien data vec len)
242
(sb-ext:octets-to-string vec :external-format :utf-16/be))
243
(error 'invalid-asn1-string :type (v-asn1 :bmpstring))))
245
(defun try-get-asn1-string-data (asn1-string allowed-types)
246
(let ((type (asn1-string-type asn1-string)))
247
(assert (member (v-asn1 (asn1-string-type asn1-string)) allowed-types) nil "Invalid asn1 string type")
248
(decode-asn1-string asn1-string type)))
250
;; ASN1 Times are represented with ASN1 Strings
251
(defun decode-asn1-time (asn1-time)
252
(when (zerop (asn1-time-check asn1-time))
253
(error "asn1-time is not a syntactically valid ASN1 UTCTime"))
254
(let ((time-string (sb-ext:octets-to-string (asn1-string-octet-vector asn1-time)
255
:external-format :ascii)))
256
(let* ((utctime-p (= 1 (asn1-utctime-check asn1-time)))
257
(year-len (if utctime-p 2 4))
258
(year-part (parse-integer (subseq time-string 0 year-len)))
260
(if (>= year-part 50)
264
(flet ((get-element-after-year (position)
267
(+ position year-len)
268
(+ position year-len 2)))))
269
(let ((month (get-element-after-year 0))
270
(day (get-element-after-year 2))
271
(hour (get-element-after-year 4))
272
(minute (get-element-after-year 6))
273
(second (get-element-after-year 8)))
274
(encode-universal-time second minute hour day month year 0))))))
276
(defmethod deserialize (from (format (eql :asn1)) &key v-asn1)
277
(decode-asn1-string from (if v-asn1 (v-asn1 v-asn1) (asn1-string-type from))))