Support ENUMERATED in client DER library

This commit is contained in:
Camden Dixie O'Brien 2025-02-28 00:03:47 +00:00
parent 38ef12fa02
commit 90a6eb3ab4
4 changed files with 110 additions and 57 deletions

View File

@ -6,6 +6,7 @@ namespace StudySystemClient.Der {
}
private const uint BASE_HEADER_SIZE = 2;
private const uint8 MAX_INT64_BYTES = 8;
public static Datum decode(uint8[] bytes, out uint? size = null)
throws DecodeError {
@ -61,6 +62,8 @@ namespace StudySystemClient.Der {
return new Sequence.from_content(content);
case Null.TYPE:
return new Null.from_content(content);
case Enumerated.TYPE:
return new Enumerated.from_content(content);
default:
throw new DecodeError.UNKNOWN_TYPE("Unsupported type: %02x",
type);
@ -135,7 +138,6 @@ namespace StudySystemClient.Der {
public class Integer : Datum {
internal const uint8 TYPE = 0x02;
private const uint8 MAX_BYTES = 8;
public int64 value { get; private set; }
@ -150,59 +152,6 @@ namespace StudySystemClient.Der {
content = bytes;
value = decode_int64(content);
}
private static uint64 twos_complement(uint64 x) {
return ~x + 1;
}
private static int min_bits(bool negative, uint64 x) {
int n = 0;
if (negative) {
while ((x >> (n + 8) & 0xff) != 0xff)
n += 8;
} else {
while (x >> (n + 8) > 0)
n += 8;
}
return n;
}
private static uint8[] encode_int64(int64 val) {
var negative = val < 0;
var uval = negative ? twos_complement(val.abs()) : val;
var shift = min_bits(negative, uval);
var buffer = new ByteArray();
for (; shift >= 0; shift -= 8)
buffer.append({(uint8)(uval >> shift)});
if (!negative && (buffer.data[0] & 0x80) != 0)
buffer.prepend({0x00});
return buffer.data;
}
private static int64 decode_int64(uint8[] bytes) throws DecodeError {
if (bytes.length > MAX_BYTES) {
throw new DecodeError.INVALID_CONTENT(
"int64 too small for %u bytes", bytes.length);
}
var negative = (bytes[0] & 0x80) != 0;
var val = decode_start_val(negative, bytes.length);
foreach (var byte in bytes)
val = val << 8 | byte;
return negative ? -(int64)twos_complement(val) : (int64)val;
}
private static uint64 decode_start_val(bool negative, uint length)
{
if (!negative)
return 0;
var val = 0;
for (uint i = 0; i < MAX_BYTES - length; ++i)
val = val << 8 | 0xff;
return val;
}
}
public class Utf8String : Datum {
@ -307,4 +256,75 @@ namespace StudySystemClient.Der {
content = bytes;
}
}
public class Enumerated : Datum {
internal const uint8 TYPE = 0x0a;
public int64 value { get; private set; }
public Enumerated(int64 val) {
type = TYPE;
content = encode_int64(val);
value = val;
}
internal Enumerated.from_content(uint8[] bytes) throws DecodeError {
type = TYPE;
content = bytes;
value = decode_int64(content);
}
}
private static uint64 twos_complement(uint64 x) {
return ~x + 1;
}
private static int min_bits(bool negative, uint64 x) {
int n = 0;
if (negative) {
while ((x >> (n + 8) & 0xff) != 0xff)
n += 8;
} else {
while (x >> (n + 8) > 0)
n += 8;
}
return n;
}
private static uint8[] encode_int64(int64 val) {
var negative = val < 0;
var uval = negative ? twos_complement(val.abs()) : val;
var shift = min_bits(negative, uval);
var buffer = new ByteArray();
for (; shift >= 0; shift -= 8)
buffer.append({(uint8)(uval >> shift)});
if (!negative && (buffer.data[0] & 0x80) != 0)
buffer.prepend({0x00});
return buffer.data;
}
private static int64 decode_int64(uint8[] bytes) throws DecodeError {
if (bytes.length > MAX_INT64_BYTES) {
throw new DecodeError.INVALID_CONTENT(
"int64 too small for %u bytes", bytes.length);
}
var negative = (bytes[0] & 0x80) != 0;
var val = decode_start_val(negative, bytes.length);
foreach (var byte in bytes)
val = val << 8 | byte;
return negative ? -(int64)twos_complement(val) : (int64)val;
}
private static uint64 decode_start_val(bool negative, uint length)
{
if (!negative)
return 0;
var val = 0;
for (uint i = 0; i < MAX_INT64_BYTES - length; ++i)
val = val << 8 | 0xff;
return val;
}
}

View File

@ -14,7 +14,9 @@ namespace StudySystemClient {
css_provider,
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
new MainWindow(this, new Connection(Config.CERT_DIR));
var connection = new Connection(Config.CERT_DIR);
var main_window = new MainWindow(this, connection);
main_window.present();
} catch (Error e) {
stderr.printf("Failed to initialize: %s\n", e.message);
return;

View File

@ -18,8 +18,6 @@ namespace StudySystemClient {
var activities_view = new ActivitiesView();
set_child(activities_view);
present();
}
}
}

View File

@ -98,6 +98,32 @@ static void test_utf8string_value(string expected, Datum datum) {
}
}
static void test_decode_enumerated(uint8[] bytes, int64 expected) {
Datum datum;
try {
datum = decode(bytes);
} catch (DecodeError err) {
Test.message("Decoding failed: %s", err.message);
Test.fail();
return;
}
test_enumerated_value(expected, datum);
}
static void test_enumerated_value(int64 expected, Datum datum) {
var enumerated = datum as Enumerated;
if (enumerated == null) {
Test.message("Bytes were not decoded as an ENUMERATED");
Test.fail();
return;
}
if (enumerated.value != expected) {
Test.message(@"Expected $expected got $(enumerated.value)");
Test.fail();
return;
}
}
void main(string[] args) {
Test.init(ref args);
@ -184,6 +210,10 @@ void main(string[] args) {
test_encode(new Der.Null(), { 0x05, 0x00 });
});
Test.add_func("/encode/enumerated/42", () => {
test_encode(new Enumerated(42), {0x0a, 0x01, 0x2a});
});
/*
* Decoding
*/
@ -310,6 +340,9 @@ void main(string[] args) {
}
});
Test.add_func("/decode/enumerated/42", () => {
test_decode_enumerated({0x0a, 0x01, 0x2a}, 42);
});
Test.run();
}