decoder_test.ha (9814B)
1 // SPDX-License-Identifier: MPL-2.0 2 // (c) Hare authors <https://harelang.org> 3 4 use bufio; 5 use bytes; 6 use errors; 7 use io; 8 use memio; 9 use os; 10 use strings; 11 use time::date; 12 use types; 13 14 15 // XXX: would be nice to just declare this as mem: memio::stream 16 let mem: nullable *memio::stream = null; 17 let rbuf: [os::BUFSZ]u8 = [0...]; 18 19 fn d(i: []u8) decoder = { 20 let buf = memio::fixed(i); 21 let h = match (mem) { 22 case null => 23 let h = alloc(buf); 24 mem = h; 25 yield h; 26 case let m: *memio::stream => 27 *m = buf; 28 yield m; 29 }; 30 return derdecoder(h); 31 }; 32 33 @fini fn freetdec() void = { 34 match (mem) { 35 case null => void; 36 case let m: *memio::stream => 37 free(m); 38 mem = null; 39 }; 40 }; 41 42 @test fn parsetag() void = { 43 assert((next(&d([0x02, 0x01]))!).class == class::UNIVERSAL); 44 assert((next(&d([0x02, 0x01]))!).tagid == 0x02); 45 assert((next(&d([0x1e, 0x01]))!).tagid == 0x1e); 46 assert((next(&d([0x1f, 0x7f, 0x01]))!).tagid == 0x7f); 47 assert((next(&d([0x1f, 0x81, 0x00, 0x01]))!).tagid == 0x80); 48 49 assert((next(&d([0x1f, 0x8f, 0xff, 0xff, 0xff, 0x7f, 0x01]))!).tagid 50 == types::U32_MAX); 51 assert(next(&d([0x1f, 0x90, 0x80, 0x80, 0x80, 0x00, 0x01])) is invalid); 52 }; 53 54 @test fn parselen() void = { 55 assert(dsz(next(&d([0x02, 0x1]))!) == 1); 56 assert(dsz(next(&d([0x02, 0x7f]))!) == 127); 57 assert(dsz(next(&d([0x02, 0x81, 0x80]))!) == 128); 58 59 // must use minimal amount of bytes for length encoding 60 assert(next(&d([0x02, 0x81, 0x01, 0x01])) is invalid); 61 assert(next(&d([0x02, 0x81, 0x7f])) is invalid); 62 assert(next(&d([0x02, 0x82, 0x00, 0xff])) is invalid); 63 64 // indefinite form is not allowed in DER 65 assert(next(&d([0x02, 0x80, 0x01, 0x00, 0x00])) is invalid); 66 }; 67 68 @test fn emptydata() void = { 69 assert(read_bool(&d([])) is badformat); 70 assert(open_set(&d([])) is badformat); 71 }; 72 73 @test fn seq() void = { 74 let dat: [_]u8 = [ 75 0x30, 0x0a, // seq 76 0x01, 0x01, 0xff, // bool true 77 0x30, 0x05, // seq 78 0x30, 0x03, // seq 79 0x01, 0x01, 0x00, // bool false 80 ]; 81 82 let dc = &d(dat); 83 open_seq(dc)!; 84 assert(read_bool(dc)! == true); 85 open_seq(dc)!; 86 open_seq(dc)!; 87 assert(read_bool(dc)! == false); 88 close_seq(dc)!; 89 close_seq(dc)!; 90 close_seq(dc)!; 91 finish(dc)!; 92 93 let dc = &d(dat); 94 open_seq(dc)!; 95 assert(open_seq(dc) is invalid); 96 97 let dc = &d(dat); 98 open_seq(dc)!; 99 assert(close_seq(dc) is badformat); 100 101 let dat: [_]u8 = [ 102 0x30, 0x07, // seq 103 0x0c, 0x05, 0x65, 0x66, 0x67, 0xc3, 0x96, // utf8 string 104 ]; 105 106 let dc = &d(dat); 107 open_seq(dc)!; 108 let r = strreader(dc, utag::UTF8_STRING)!; 109 let s = io::drain(&r)!; 110 defer free(s); 111 assert(bytes::equal([0x65, 0x66, 0x67, 0xc3, 0x96], s)); 112 113 let dc = &d(dat); 114 let buf: [4]u8 = [0...]; 115 open_seq(dc)!; 116 let r = strreader(dc, utag::UTF8_STRING)!; 117 assert(io::read(&r, buf)! == 3); 118 assert(close_seq(dc) is badformat); 119 120 // check unclosed 121 let dc = &d(dat); 122 open_seq(dc)!; 123 assert(finish(dc) is invalid); 124 125 let dc = &d(dat); 126 open_seq(dc)!; 127 let r = strreader(dc, utag::UTF8_STRING)!; 128 let s = io::drain(&r)!; 129 defer free(s); 130 assert(finish(dc) is invalid); 131 }; 132 133 @test fn invalid_seq() void = { 134 let dat: [_]u8 = [ 135 0x30, 0x03, // seq containing data of size 3 136 0x02, 0x03, 0x01, 0x02, 0x03, // int 0x010203 overflows seq 137 ]; 138 139 let dc = &d(dat); 140 open_seq(dc)!; 141 142 let buf: [3]u8 = [0...]; 143 assert(read_int(dc, buf) is invalid); 144 }; 145 146 @test fn read_implicit() void = { 147 let dat: [_]u8 = [ 148 0x30, 0x06, // seq 149 0x85, 0x01, 0xff, // IMPLICIT bool true 150 0x01, 0x01, 0x00, // bool false 151 ]; 152 153 let dc = &d(dat); 154 open_seq(dc)!; 155 expect_implicit(dc, class::CONTEXT, 5)!; 156 assert(read_bool(dc)! == true); 157 assert(read_u16(dc) is badformat); 158 }; 159 160 @test fn read_bool() void = { 161 assert(read_bool(&d([0x01, 0x01, 0xff]))!); 162 assert(read_bool(&d([0x01, 0x01, 0x00]))! == false); 163 assert(read_bool(&d([0x01, 0x02, 0x00, 0x00])) is invalid); 164 // X.690, ch. 11.1 165 assert(read_bool(&d([0x01, 0x01, 0x01])) is invalid); 166 167 // invalid class 168 assert(read_bool(&d([0x81, 0x01, 0x01])) is badformat); 169 // must be primitive 170 assert(read_bool(&d([0x21, 0x01, 0x01])) is invalid); 171 // invalid tag 172 assert(read_bool(&d([0x02, 0x01, 0x01])) is badformat); 173 }; 174 175 @test fn read_null() void = { 176 read_null(&d([0x05, 0x00]))!; 177 read_null(&d([0x05, 0x01, 0x00])) is invalid; 178 read_null(&d([0x85, 0x00])) is invalid; 179 read_null(&d([0x01, 0x00])) is invalid; 180 }; 181 182 @test fn read_int() void = { 183 let buf: [8]u8 = [0...]; 184 185 assert(read_int(&d([0x02, 0x01, 0x01]), buf)! == 1); 186 assert(buf[0] == 0x01); 187 assert(read_int(&d([0x02, 0x01, 0x00]), buf)! == 1); 188 assert(buf[0] == 0x00); 189 assert(read_int(&d([0x02, 0x02, 0x01, 0x02]), buf)! == 2); 190 assert(buf[0] == 0x01); 191 assert(buf[1] == 0x02); 192 193 // must have at least one byte 194 assert(read_int(&d([0x02, 0x00]), buf) is invalid); 195 // non minimal 196 assert(read_int(&d([0x02, 0x02, 0x00, 0x01]), buf) is invalid); 197 assert(read_int(&d([0x02, 0x02, 0xff, 0x81]), buf) is invalid); 198 199 assert(read_u8(&d([0x02, 0x01, 0x00]))! == 0); 200 assert(read_u8(&d([0x02, 0x01, 0x01]))! == 1); 201 assert(read_u8(&d([0x02, 0x01, 0x7f]))! == 0x7f); 202 assert(read_u8(&d([0x02, 0x01, 0x80])) is invalid); 203 assert(read_u8(&d([0x02, 0x01, 0x81])) is invalid); 204 assert(read_u8(&d([0x02, 0x02, 0x00, 0x80]))! == 0x80); 205 assert(read_u8(&d([0x02, 0x02, 0x00, 0xff]))! == 0xff); 206 207 assert(read_u16(&d([0x02, 0x01, 0x00]))! == 0); 208 assert(read_u16(&d([0x02, 0x02, 0x0f, 0xff]))! == 0xfff); 209 assert(read_u16(&d([0x02, 0x03, 0x00, 0xff, 0xff]))! == 0xffff); 210 assert(read_u16(&d([0x02, 0x03, 0x01, 0xff, 0xff])) is invalid); 211 assert(read_u32(&d([0x02, 0x03, 0x00, 0xff, 0xff]))! == 0xffff); 212 213 let maxu64: [_]u8 = [ 214 0x02, 0x09, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 215 ]; 216 assert(read_u64(&d(maxu64))! == 0xffffffffffffffff); 217 maxu64[2] = 0x01; 218 assert(read_u64(&d(maxu64)) is invalid); 219 }; 220 221 @test fn read_bitstr() void = { 222 let buf: [8]u8 = [0...]; 223 let bs = read_bitstr(&d([0x03, 0x01, 0x00]), buf)!; 224 assert(len(bs.0) == 0 && bs.1 == 0); 225 assert(bitstr_isset(bs, 0)! == false); 226 227 let bs = read_bitstr(&d([0x03, 0x02, 0x00, 0xff]), buf)!; 228 assert(bytes::equal(bs.0, [0xff]) && bs.1 == 0); 229 assert(bitstr_isset(bs, 0)!); 230 assert(bitstr_isset(bs, 7)!); 231 232 let bs = read_bitstr(&d([0x03, 0x03, 0x04, 0xab, 0xc0]), buf)!; 233 assert(bytes::equal(bs.0, [0xab, 0xc0]) && bs.1 == 4); 234 assert(bitstr_isset(bs, 0)!); 235 assert(bitstr_isset(bs, 1)! == false); 236 assert(bitstr_isset(bs, 8)!); 237 assert(bitstr_isset(bs, 9)!); 238 assert(!bitstr_isset(bs, 11)!); 239 assert(bitstr_isset(bs, 12) is invalid); 240 241 // unused bits must be zero 242 assert(read_bitstr(&d([0x03, 0x03, 0x04, 0xab, 0xc1]), buf) is invalid); 243 assert(read_bitstr(&d([0x03, 0x03, 0x07, 0xab, 0x40]), buf) is invalid); 244 }; 245 246 let datbuf: [64]u8 = [0...]; 247 248 fn newdatetime(s: str, tag: utag) []u8 = { 249 let datetime = strings::toutf8(s); 250 let datsz = len(datetime): u8; 251 datbuf[..2] = [tag, datsz]; 252 datbuf[2..2 + datsz] = datetime; 253 return datbuf[..2 + datsz]; 254 }; 255 256 @test fn read_utctime() void = { 257 let derdatetime = newdatetime("231030133710Z", utag::UTC_TIME); 258 let dt = read_utctime(&d(derdatetime), 2046)!; 259 260 let fbuf: [24]u8 = [0...]; 261 assert(date::bsformat(fbuf, date::RFC3339, &dt)! 262 == "2023-10-30T13:37:10+0000"); 263 264 let dt = read_utctime(&d(derdatetime), 2020)!; 265 assert(date::bsformat(fbuf, date::RFC3339, &dt)! 266 == "1923-10-30T13:37:10+0000"); 267 268 let derdatetime = newdatetime("2310301337100", utag::UTC_TIME); 269 assert(read_utctime(&d(derdatetime), 2020) is error); 270 271 let derdatetime = newdatetime("231030133710", utag::UTC_TIME); 272 assert(read_utctime(&d(derdatetime), 2020) is error); 273 274 let derdatetime = newdatetime("231030133a10Z", utag::UTC_TIME); 275 assert(read_utctime(&d(derdatetime), 2020) is error); 276 277 let derdatetime = newdatetime("231330133710Z", utag::UTC_TIME); 278 assert(read_utctime(&d(derdatetime), 2020) is error); 279 }; 280 281 @test fn read_gtime() void = { 282 let derdatetime = newdatetime("20231030133710Z", utag::GENERALIZED_TIME); 283 284 let dt = read_gtime(&d(derdatetime))!; 285 286 let fbuf: [32]u8 = [0...]; 287 assert(date::bsformat(fbuf, date::RFC3339, &dt)! 288 == "2023-10-30T13:37:10+0000"); 289 290 let derdatetime = newdatetime("20231030133710.1Z", utag::GENERALIZED_TIME); 291 let dt = read_gtime(&d(derdatetime))!; 292 assert(date::bsformat(fbuf, date::STAMPNANO, &dt)! 293 == "2023-10-30 13:37:10.100000000"); 294 295 // must end with Z 296 let derdatetime = newdatetime("20231030133710", utag::GENERALIZED_TIME); 297 assert(read_gtime(&d(derdatetime)) is error); 298 let derdatetime = newdatetime("202310301337100", utag::GENERALIZED_TIME); 299 assert(read_gtime(&d(derdatetime)) is error); 300 301 // seconds must always be present 302 let derdatetime = newdatetime("202310301337", utag::GENERALIZED_TIME); 303 assert(read_gtime(&d(derdatetime)) is error); 304 let derdatetime = newdatetime("202310301337Z", utag::GENERALIZED_TIME); 305 assert(read_gtime(&d(derdatetime)) is error); 306 307 // fractional seconds must not end with 0. must be ommitted if 0 308 let derdatetime = newdatetime("20231030133710.", utag::GENERALIZED_TIME); 309 assert(read_gtime(&d(derdatetime)) is error); 310 311 let derdatetime = newdatetime("20231030133710.Z", utag::GENERALIZED_TIME); 312 assert(read_gtime(&d(derdatetime)) is error); 313 314 let derdatetime = newdatetime("20231030133710.0", utag::GENERALIZED_TIME); 315 assert(read_gtime(&d(derdatetime)) is error); 316 317 let derdatetime = newdatetime("20231030133710.0Z", utag::GENERALIZED_TIME); 318 assert(read_gtime(&d(derdatetime)) is error); 319 320 let derdatetime = newdatetime("20231030133710.10Z", utag::GENERALIZED_TIME); 321 assert(read_gtime(&d(derdatetime)) is error); 322 323 // TODO midnight is YYYYMMDD000000Z 324 }; 325 326 @test fn read_oid() void = { 327 let db = oiddb { 328 lut = [0x03, 0x2b, 0x65, 0x70, 0x03, 0x55, 0x04, 0x03], 329 index = [0, 4], 330 names = ["ed25519", "id-at-commonName"], 331 }; 332 333 assert(read_oid(&d([0x06, 0x03, 0x55, 0x04, 0x03]), &db)! == 1); 334 assert(stroid(&db, 1) == "id-at-commonName"); 335 336 assert(bytes::equal([0x55, 0x04, 0x03], 337 read_rawoid(&d([0x06, 0x03, 0x55, 0x04, 0x03]))!)); 338 };