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