* ASN.1
@ 2024-05-21 6:36 Jarkko Sakkinen
2024-05-21 14:52 ` ASN.1 Miguel Ojeda
0 siblings, 1 reply; 11+ messages in thread
From: Jarkko Sakkinen @ 2024-05-21 6:36 UTC (permalink / raw)
To: rust-for-linux
Hi,
There's one application where it would make a lot of sense to have the
core implementation in Rust, and make it callable from C. It is encoding
and decoding of ASN.1 (DER).
It is essentially hierarchical binary parsing, i.e. exactly kind of
stuff where it is too easy to shoot yourself into foot with C.
So question is how to approach this? How the holding data structure for
holding the deserialized data should represented so that is is also
directly accessible from C?
Maybe not the sexiest application ever, but it is an actual applications
where Rust might weight a lot, also for the C code base ;-)
I'm interested to help with this too as I consume a lot of DER type of
input data... so I know what it should look like to work at all for the
C code. Or do not know at this poinnt, but can verify the sensibility
at minimum :-)
BR, Jarkko
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: ASN.1
2024-05-21 6:36 ASN.1 Jarkko Sakkinen
@ 2024-05-21 14:52 ` Miguel Ojeda
2024-05-21 15:20 ` ASN.1 Jarkko Sakkinen
0 siblings, 1 reply; 11+ messages in thread
From: Miguel Ojeda @ 2024-05-21 14:52 UTC (permalink / raw)
To: Jarkko Sakkinen; +Cc: rust-for-linux, Daniel Almeida
Hi Jarkko,
On Tue, May 21, 2024 at 8:36 AM Jarkko Sakkinen <jarkko@kernel.org> wrote:
>
> So question is how to approach this? How the holding data structure for
> holding the deserialized data should represented so that is is also
> directly accessible from C?
Daniel (Cc'd) is working on in-kernel Rust codecs and is experimenting
with `cbindgen` support to easily provide an API for C code (of
course, you can do it manually too), so you may want to talk :) He
recently wrote this article on it: https://lwn.net/Articles/970565/
The main issue with a parallel implementation is whether the relevant
maintainers will be OK with keeping both versions alive in the kernel.
As usual, some ideas that may help offsetting the maintenance cost may
be showcasing a security benefit, or a performance improvement, or a
complexity reduction, or an avoidance of unsafe code, etc.
Cheers,
Miguel
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: ASN.1
2024-05-21 14:52 ` ASN.1 Miguel Ojeda
@ 2024-05-21 15:20 ` Jarkko Sakkinen
2024-05-21 18:01 ` ASN.1 Jarkko Sakkinen
0 siblings, 1 reply; 11+ messages in thread
From: Jarkko Sakkinen @ 2024-05-21 15:20 UTC (permalink / raw)
To: Miguel Ojeda; +Cc: rust-for-linux, Daniel Almeida
On Tue May 21, 2024 at 5:52 PM EEST, Miguel Ojeda wrote:
> Hi Jarkko,
>
> On Tue, May 21, 2024 at 8:36 AM Jarkko Sakkinen <jarkko@kernel.org> wrote:
> >
> > So question is how to approach this? How the holding data structure for
> > holding the deserialized data should represented so that is is also
> > directly accessible from C?
>
> Daniel (Cc'd) is working on in-kernel Rust codecs and is experimenting
> with `cbindgen` support to easily provide an API for C code (of
> course, you can do it manually too), so you may want to talk :) He
> recently wrote this article on it: https://lwn.net/Articles/970565/
>
> The main issue with a parallel implementation is whether the relevant
> maintainers will be OK with keeping both versions alive in the kernel.
> As usual, some ideas that may help offsetting the maintenance cost may
> be showcasing a security benefit, or a performance improvement, or a
> complexity reduction, or an avoidance of unsafe code, etc.
For me the main use case would be loading of keys (I co-maintain
keyring).
For keyring the ASN.1 C-API is actually quite good in the sense that
callbacks in parsing and sequential encoding are great at not conserving
memory (actually zero consumption almost). In that sense I'm happy with
it.
It is just hard to modify in the sense that it is very prone to
off-by-one errors and such.
Here's an example of a patch set that I wrote over the weekend for
asymmetric keys:
https://lore.kernel.org/linux-integrity/20240521031645.17008-1-jarkko@kernel.org/
In this case I could imagine loading ASN.1 blob by calling Rust
functions. But yeah more like "immediate mode" API rather than "retained
mode" style ;-)
> Cheers,
> Miguel
BR, Jarkko
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: ASN.1
2024-05-21 15:20 ` ASN.1 Jarkko Sakkinen
@ 2024-05-21 18:01 ` Jarkko Sakkinen
2024-05-21 18:55 ` ASN.1 Jarkko Sakkinen
0 siblings, 1 reply; 11+ messages in thread
From: Jarkko Sakkinen @ 2024-05-21 18:01 UTC (permalink / raw)
To: Jarkko Sakkinen, Miguel Ojeda; +Cc: rust-for-linux, Daniel Almeida
On Tue May 21, 2024 at 6:20 PM EEST, Jarkko Sakkinen wrote:
> On Tue May 21, 2024 at 5:52 PM EEST, Miguel Ojeda wrote:
> In this case I could imagine loading ASN.1 blob by calling Rust
> functions. But yeah more like "immediate mode" API rather than "retained
> mode" style ;-)
Hey, sorry I was mixing things a bit so let me clear this up!
The decoder works as follows. There is a compiler, which generates
bytecode object linked to vmlinux and a header with symbol declaration.
Then there is a asn1_ber_decoder(), which runs the bytecode through a
trivial interpreter with e.g. a key blob as parameter.
And this part is great and it does not really get in the way. All of
kernel uses it to parse ber/der/cer blobs in, and it is somewhat stable,
and super well tested. For decoder the value of Rust is not that great.
Encoder (asn1_encoder.c) is just a set of basic functions, like one
function per tagged type to serialize that type. Most valuable asset
would be to replicate this set in Rust with better defined contraints
etc.
Sorry for longish explanation, just wanted to clear up this story :-)
I.e encoder is higher value asset than the decoder as far as I'm
concerned, despite being much more trivial to implement.
BR, Jarkko
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: ASN.1
2024-05-21 18:01 ` ASN.1 Jarkko Sakkinen
@ 2024-05-21 18:55 ` Jarkko Sakkinen
2024-05-22 12:04 ` ASN.1 Alex Gaynor
0 siblings, 1 reply; 11+ messages in thread
From: Jarkko Sakkinen @ 2024-05-21 18:55 UTC (permalink / raw)
To: Jarkko Sakkinen, Miguel Ojeda; +Cc: rust-for-linux, Daniel Almeida
On Tue May 21, 2024 at 9:01 PM EEST, Jarkko Sakkinen wrote:
> On Tue May 21, 2024 at 6:20 PM EEST, Jarkko Sakkinen wrote:
> > On Tue May 21, 2024 at 5:52 PM EEST, Miguel Ojeda wrote:
> > In this case I could imagine loading ASN.1 blob by calling Rust
> > functions. But yeah more like "immediate mode" API rather than "retained
> > mode" style ;-)
>
> Hey, sorry I was mixing things a bit so let me clear this up!
>
> The decoder works as follows. There is a compiler, which generates
> bytecode object linked to vmlinux and a header with symbol declaration.
> Then there is a asn1_ber_decoder(), which runs the bytecode through a
> trivial interpreter with e.g. a key blob as parameter.
>
> And this part is great and it does not really get in the way. All of
> kernel uses it to parse ber/der/cer blobs in, and it is somewhat stable,
> and super well tested. For decoder the value of Rust is not that great.
>
> Encoder (asn1_encoder.c) is just a set of basic functions, like one
> function per tagged type to serialize that type. Most valuable asset
> would be to replicate this set in Rust with better defined contraints
> etc.
>
> Sorry for longish explanation, just wanted to clear up this story :-)
> I.e encoder is higher value asset than the decoder as far as I'm
> concerned, despite being much more trivial to implement.
For the patch set I'm working on I do have good solution. I only need to
encode this:
RsaPubKey ::= SEQUENCE {
n INTEGER ({ rsa_get_n }),
e INTEGER ({ rsa_get_e })
}
And nice thing is that e is always 65537 and length of e is always 3
i.e. {3} serialized so it is serialized as
static const u8 EXPONENT[5] = {0x02, 1, 0x01, 0x01, 0x01};
Sequence and n can be expressed along the lines of
/* Last two bytes are filled with 16-bit big-endian length: */
u8 sequence[] = {0x30, 0x82, 0x00, 0x00};
u8 n_head[] = {0x02, 0x82, 0x00, 0x00};
So I just copy stuff in order:
1. sequence
2. n_head
3. n (contents)
4. e
And this is along the line what I'm actually going to do because it is
stable for the use case. However, it would be nice that instead of such
sudoku there would be super stable Rust functions to take care of
writing these. This particular use case is sorted and I'll be fine, but
these pop up from time to time in different situations.
The problem with encoders I found for Rust from crates.io is that they
are like too bounded to the type system of Rust by implementing
conversion traits (From, Into etc.) available. Instead of this approach
for it might be more feasible to have dummy functions with no mangling
in the symbols like encode_sequence, encode_integer etc. You can always
use these dummy global functions to implement those fancy traits and
provide bridge for C at the same time and direct as possible access to
the actual functionality.
I think this is simple but very nice and usable pattern for bridging
from C to Rust provided services.
BR, Jarkko
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: ASN.1
2024-05-21 18:55 ` ASN.1 Jarkko Sakkinen
@ 2024-05-22 12:04 ` Alex Gaynor
2024-05-22 12:56 ` ASN.1 Jarkko Sakkinen
0 siblings, 1 reply; 11+ messages in thread
From: Alex Gaynor @ 2024-05-22 12:04 UTC (permalink / raw)
To: Jarkko Sakkinen; +Cc: Miguel Ojeda, rust-for-linux, Daniel Almeida
Hi Jarkko,
I'm one of the maintainers of https://crates.io/crates/asn1/. Based on
that experience, if you want to implement a DER encoder in Rust, I
think it'd make more sense to write the type-code in Rust, and then
expose symbols to C like `encode_rsa_pub_key`. This should be simpler,
but also more efficient (fewer allocations).
For what it's worth, rust-asn1 is _intended_ to be usable from the
kernel/embedded targets. It's no_std. It currently relies on alloc,
but I'd be happy to accept PRs to make it work with the kernel's
approach to fallible allocation (it currently does support fallible
allocation, but using the reserve APIs).
Alex
On Tue, May 21, 2024 at 2:55 PM Jarkko Sakkinen <jarkko@kernel.org> wrote:
>
> On Tue May 21, 2024 at 9:01 PM EEST, Jarkko Sakkinen wrote:
> > On Tue May 21, 2024 at 6:20 PM EEST, Jarkko Sakkinen wrote:
> > > On Tue May 21, 2024 at 5:52 PM EEST, Miguel Ojeda wrote:
> > > In this case I could imagine loading ASN.1 blob by calling Rust
> > > functions. But yeah more like "immediate mode" API rather than "retained
> > > mode" style ;-)
> >
> > Hey, sorry I was mixing things a bit so let me clear this up!
> >
> > The decoder works as follows. There is a compiler, which generates
> > bytecode object linked to vmlinux and a header with symbol declaration.
> > Then there is a asn1_ber_decoder(), which runs the bytecode through a
> > trivial interpreter with e.g. a key blob as parameter.
> >
> > And this part is great and it does not really get in the way. All of
> > kernel uses it to parse ber/der/cer blobs in, and it is somewhat stable,
> > and super well tested. For decoder the value of Rust is not that great.
> >
> > Encoder (asn1_encoder.c) is just a set of basic functions, like one
> > function per tagged type to serialize that type. Most valuable asset
> > would be to replicate this set in Rust with better defined contraints
> > etc.
> >
> > Sorry for longish explanation, just wanted to clear up this story :-)
> > I.e encoder is higher value asset than the decoder as far as I'm
> > concerned, despite being much more trivial to implement.
>
> For the patch set I'm working on I do have good solution. I only need to
> encode this:
>
> RsaPubKey ::= SEQUENCE {
> n INTEGER ({ rsa_get_n }),
> e INTEGER ({ rsa_get_e })
> }
>
> And nice thing is that e is always 65537 and length of e is always 3
> i.e. {3} serialized so it is serialized as
>
> static const u8 EXPONENT[5] = {0x02, 1, 0x01, 0x01, 0x01};
>
> Sequence and n can be expressed along the lines of
>
> /* Last two bytes are filled with 16-bit big-endian length: */
> u8 sequence[] = {0x30, 0x82, 0x00, 0x00};
> u8 n_head[] = {0x02, 0x82, 0x00, 0x00};
>
> So I just copy stuff in order:
>
> 1. sequence
> 2. n_head
> 3. n (contents)
> 4. e
>
> And this is along the line what I'm actually going to do because it is
> stable for the use case. However, it would be nice that instead of such
> sudoku there would be super stable Rust functions to take care of
> writing these. This particular use case is sorted and I'll be fine, but
> these pop up from time to time in different situations.
>
> The problem with encoders I found for Rust from crates.io is that they
> are like too bounded to the type system of Rust by implementing
> conversion traits (From, Into etc.) available. Instead of this approach
> for it might be more feasible to have dummy functions with no mangling
> in the symbols like encode_sequence, encode_integer etc. You can always
> use these dummy global functions to implement those fancy traits and
> provide bridge for C at the same time and direct as possible access to
> the actual functionality.
>
> I think this is simple but very nice and usable pattern for bridging
> from C to Rust provided services.
>
> BR, Jarkko
>
--
All that is necessary for evil to succeed is for good people to do nothing.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: ASN.1
2024-05-22 12:04 ` ASN.1 Alex Gaynor
@ 2024-05-22 12:56 ` Jarkko Sakkinen
2024-05-22 13:49 ` ASN.1 Jarkko Sakkinen
0 siblings, 1 reply; 11+ messages in thread
From: Jarkko Sakkinen @ 2024-05-22 12:56 UTC (permalink / raw)
To: Alex Gaynor; +Cc: Miguel Ojeda, rust-for-linux, Daniel Almeida
On Wed May 22, 2024 at 3:04 PM EEST, Alex Gaynor wrote:
> Hi Jarkko,
>
> I'm one of the maintainers of https://crates.io/crates/asn1/. Based on
> that experience, if you want to implement a DER encoder in Rust, I
> think it'd make more sense to write the type-code in Rust, and then
> expose symbols to C like `encode_rsa_pub_key`. This should be simpler,
> but also more efficient (fewer allocations).
>
> For what it's worth, rust-asn1 is _intended_ to be usable from the
> kernel/embedded targets. It's no_std. It currently relies on alloc,
> but I'd be happy to accept PRs to make it work with the kernel's
> approach to fallible allocation (it currently does support fallible
> allocation, but using the reserve APIs).
>
> Alex
Right, I need to experiment with that just in user space first.
It seemed like most "productized" crate from all that I found.
Yeah, and it is true that also crate could be as rusty as hell,
and then just make bridge shim that hides all that ;-) That is
probably better way around.
Thanks for the response!
BR, Jarkko
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: ASN.1
2024-05-22 12:56 ` ASN.1 Jarkko Sakkinen
@ 2024-05-22 13:49 ` Jarkko Sakkinen
2024-05-23 7:00 ` ASN.1 Jarkko Sakkinen
0 siblings, 1 reply; 11+ messages in thread
From: Jarkko Sakkinen @ 2024-05-22 13:49 UTC (permalink / raw)
To: Jarkko Sakkinen, Alex Gaynor; +Cc: Miguel Ojeda, rust-for-linux, Daniel Almeida
On Wed May 22, 2024 at 3:56 PM EEST, Jarkko Sakkinen wrote:
> On Wed May 22, 2024 at 3:04 PM EEST, Alex Gaynor wrote:
> > Hi Jarkko,
> >
> > I'm one of the maintainers of https://crates.io/crates/asn1/. Based on
> > that experience, if you want to implement a DER encoder in Rust, I
> > think it'd make more sense to write the type-code in Rust, and then
> > expose symbols to C like `encode_rsa_pub_key`. This should be simpler,
> > but also more efficient (fewer allocations).
> >
> > For what it's worth, rust-asn1 is _intended_ to be usable from the
> > kernel/embedded targets. It's no_std. It currently relies on alloc,
> > but I'd be happy to accept PRs to make it work with the kernel's
> > approach to fallible allocation (it currently does support fallible
> > allocation, but using the reserve APIs).
> >
> > Alex
>
> Right, I need to experiment with that just in user space first.
>
> It seemed like most "productized" crate from all that I found.
>
> Yeah, and it is true that also crate could be as rusty as hell,
> and then just make bridge shim that hides all that ;-) That is
> probably better way around.
>
> Thanks for the response!
If we want to considering getting your code to land to the kernel I
would start with the decoder as it already delivers, as an
*experimental* feature. Then when it is landed it would not be
as huge stretch to move forward with the encoder.
Basically how Rust ASN.1 could work out for kernel is pretty trivial to
describe:
1. Add a new Kconfig flag: e.g. CONFIG_ASN1_RUST. This flag could be a
subflag of CONFIG_ASN1 and by default obviously disabled.
2. Import asn1 code to kernel and make it build as part of vmlinux.
3. Implement a shim for C with zero or at least minimal changes to the
developer experience. I.e. you can drop your asn1 file to the subsystem
directory and some small tweaks to Makefile and you are set.
4. Update MAINTAINERS. I think this should have own entry and probably
you would be the best possible person to have M-entry. I could add
myself R-entry (reviewer) because I'm the end customer :-)
If we would get this far and get this to also mainline then it would
be also a huge step towards encoding as then it would be just adding
another feature without infrastructural madness involved ;-)
BR, Jarkko
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: ASN.1
2024-05-22 13:49 ` ASN.1 Jarkko Sakkinen
@ 2024-05-23 7:00 ` Jarkko Sakkinen
2024-05-23 7:03 ` ASN.1 Jarkko Sakkinen
2024-05-23 15:44 ` ASN.1 Jarkko Sakkinen
0 siblings, 2 replies; 11+ messages in thread
From: Jarkko Sakkinen @ 2024-05-23 7:00 UTC (permalink / raw)
To: Jarkko Sakkinen, Alex Gaynor; +Cc: Miguel Ojeda, rust-for-linux, Daniel Almeida
On Wed May 22, 2024 at 4:49 PM EEST, Jarkko Sakkinen wrote:
> If we want to considering getting your code to land to the kernel I
> would start with the decoder as it already delivers, as an
> *experimental* feature. Then when it is landed it would not be
> as huge stretch to move forward with the encoder.
About the encoder. It is relatively new and has only caller, and I'm not
sure if we care about it that much.
In my case I just did:
static int tpm2_key_rsa_encode(const struct tpm2_key_rsa *key, u8 *buf)
{
int pub_len = key->pub_len;
const u8 *pub = key->pub;
u8 *start = &buf[4];
u8 *work = &buf[4];
u32 seq_len;
work[0] = 0x02; /* INTEGER */
work[1] = 0x82; /* u16 */
work[2] = pub_len >> 8;
work[3] = pub_len & 0xff;
work = &work[4];
memcpy(work, pub, pub_len);
work = &work[pub_len];
work[0] = 0x02; /* INTEGER */
work[1] = 3; /* < 128 */
work[2] = 1; /* 65537 */
work[3] = 0;
work[4] = 1;
work = &work[5];
memset(work, 0, 8);
seq_len = work - start;
buf[0] = 0x30; /* SEQUENCE */
buf[1] = 0x82; /* u16 */
buf[2] = seq_len >> 8;
buf[3] = seq_len & 0xff;
return seq_len + 4;
}
Not the prettiest looking but it does the job and is actually easy
to verify :-) Decoder is on the other hand old and mature and makes
more sense both in implementation and architecture.
Looking back it was my mistake to let that encoder into the mainline,
I did not use it because it did not make sense to me, or at least
less sense than above, which practically never changes and is easy
to also later verify and fix, despite being somewhat archaic.
Given this if we want to work on ASN1_RUST experimental feature, I
can create a patch that open codes the call site in trusted_tpm2.c
and thus ASN1_ENCODER can be droper entirely. It is not a priority
but could be part of the patch set, or Git branch, which adds
ASN1_RUST.
So what I might do to move forward is early next month to start
with such patch and create asn1rust branch to my tree at:
https://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd.git
And then start looking at the crate and perhaps post here a more
refined suggestion how to move forward.
Early next month because I have a conference demo to do (actually
in Rust but not kernel related) by the end of the month.
The reason I'm concerned about the topic is that keyring has literally
billions of users dependent on it (mostly without knowing but it is used
practically in any Linux installation) and I know that Rust side needs
ASN.1 eventually, so I want to make sure that the integration path works
for us.
So let's now pretend that encoder did not exist and focus only on
decoder :-)
Sounds like a plan?
BR, Jarkko
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: ASN.1
2024-05-23 7:00 ` ASN.1 Jarkko Sakkinen
@ 2024-05-23 7:03 ` Jarkko Sakkinen
2024-05-23 15:44 ` ASN.1 Jarkko Sakkinen
1 sibling, 0 replies; 11+ messages in thread
From: Jarkko Sakkinen @ 2024-05-23 7:03 UTC (permalink / raw)
To: Jarkko Sakkinen, Jarkko Sakkinen, Alex Gaynor
Cc: Miguel Ojeda, rust-for-linux, Daniel Almeida
On Thu May 23, 2024 at 10:00 AM EEST, Jarkko Sakkinen wrote:
> On Wed May 22, 2024 at 4:49 PM EEST, Jarkko Sakkinen wrote:
> > If we want to considering getting your code to land to the kernel I
> > would start with the decoder as it already delivers, as an
> > *experimental* feature. Then when it is landed it would not be
> > as huge stretch to move forward with the encoder.
>
> About the encoder. It is relatively new and has only caller, and I'm not
*only single caller.
BR, Jarkko
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: ASN.1
2024-05-23 7:00 ` ASN.1 Jarkko Sakkinen
2024-05-23 7:03 ` ASN.1 Jarkko Sakkinen
@ 2024-05-23 15:44 ` Jarkko Sakkinen
1 sibling, 0 replies; 11+ messages in thread
From: Jarkko Sakkinen @ 2024-05-23 15:44 UTC (permalink / raw)
To: Jarkko Sakkinen, Jarkko Sakkinen, Alex Gaynor
Cc: Miguel Ojeda, rust-for-linux, Daniel Almeida
On Thu May 23, 2024 at 10:00 AM EEST, Jarkko Sakkinen wrote:
> On Wed May 22, 2024 at 4:49 PM EEST, Jarkko Sakkinen wrote:
> Given this if we want to work on ASN1_RUST experimental feature, I
> can create a patch that open codes the call site in trusted_tpm2.c
> and thus ASN1_ENCODER can be droper entirely. It is not a priority
> but could be part of the patch set, or Git branch, which adds
> ASN1_RUST.
Not necessarily entirely, that was an overkill statement, but
mostly have only dynamic stuff in it and improve the C API to
be good match of whatever done in encoding side on Rust. I.e.
no regrets for picking it but it needs to mature, and I think
this rust opt-in would also do good for C implementation.
Just writing the notes so that I recall all this some weeks
from now ;-)
BR, Jarkko
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2024-05-23 15:44 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-05-21 6:36 ASN.1 Jarkko Sakkinen
2024-05-21 14:52 ` ASN.1 Miguel Ojeda
2024-05-21 15:20 ` ASN.1 Jarkko Sakkinen
2024-05-21 18:01 ` ASN.1 Jarkko Sakkinen
2024-05-21 18:55 ` ASN.1 Jarkko Sakkinen
2024-05-22 12:04 ` ASN.1 Alex Gaynor
2024-05-22 12:56 ` ASN.1 Jarkko Sakkinen
2024-05-22 13:49 ` ASN.1 Jarkko Sakkinen
2024-05-23 7:00 ` ASN.1 Jarkko Sakkinen
2024-05-23 7:03 ` ASN.1 Jarkko Sakkinen
2024-05-23 15:44 ` ASN.1 Jarkko Sakkinen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox