9front - general discussion about 9front
 help / color / mirror / Atom feed
* [9front] obsolete cryptographic algorithms
@ 2022-06-04  7:13 sml
  2022-06-04 14:47 ` ori
  0 siblings, 1 reply; 18+ messages in thread
From: sml @ 2022-06-04  7:13 UTC (permalink / raw)
  To: 9front

Hello everyone, 

I am currently trying to understand the implementation of factotum and I noticed that /sys/src/libsec contains some obsolete cryptographic algorithms like sha-1, md4, md5, dsa and des. 

In section 7.4.3.2 of the fqa the manual change from p9sk1 to dp9ik is described and since then, as far as I understand, it is also the new standard where des has been replaced by aes. 

In the list I keep reading about different cleanups, which I greatly appreciate and I'm wondering whether the deprecated crypto algorithms and protocols can be cleaned out as well, or if there is a specific reason to hold on to them. I think if you use very weak crypto, you can do without it directly.

Many thanks in advance for your responses!

Best regards, 
sml

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [9front] obsolete cryptographic algorithms
  2022-06-04  7:13 [9front] obsolete cryptographic algorithms sml
@ 2022-06-04 14:47 ` ori
  2022-06-04 15:26   ` mkf9
  2022-09-27 20:10   ` Michael Forney
  0 siblings, 2 replies; 18+ messages in thread
From: ori @ 2022-06-04 14:47 UTC (permalink / raw)
  To: 9front

Quoth sml <sml@firstpost.pub>:
> 
> In the list I keep reading about different cleanups, which I greatly appreciate and I'm wondering whether the deprecated crypto algorithms and protocols can be cleaned out as well, or if there is a specific reason to hold on to them. I think if you use very weak crypto, you can do without it directly.

Protocols still use them.

For example, grepping for md5 in /sys/src/cmd/auth,
it's used in:

	- HTTPDIGEST (RFC2517)
	- SecurID RADIUS
	- CRAM digests
	- Secstore MAC

Of these, it seems that the only one we fully control
is the secstore protocol -- patches welcome, though
it may be better to kill secstore entirely.

For the others: what external software implements them,
and what other protocols are supported?

To remove them, someone is going to need to go through
protocol by protocol and implement updates, or show that
they are unused.


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [9front] obsolete cryptographic algorithms
  2022-06-04 14:47 ` ori
@ 2022-06-04 15:26   ` mkf9
  2022-06-04 15:32     ` ori
  2022-09-27 20:10   ` Michael Forney
  1 sibling, 1 reply; 18+ messages in thread
From: mkf9 @ 2022-06-04 15:26 UTC (permalink / raw)
  To: 9front

> it may be better to kill secstore entirely.
> 

do we have alternatives for secstore,
besides auth/aescbc -d < pass > /mnt/factotum/ctl?


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [9front] obsolete cryptographic algorithms
  2022-06-04 15:26   ` mkf9
@ 2022-06-04 15:32     ` ori
  2022-06-04 15:36       ` ori
  0 siblings, 1 reply; 18+ messages in thread
From: ori @ 2022-06-04 15:32 UTC (permalink / raw)
  To: 9front

Quoth mkf9 <mkf9@riseup.net>:
> > it may be better to kill secstore entirely.
> > 
> 
> do we have alternatives for secstore,
> besides auth/aescbc -d < pass > /mnt/factotum/ctl?
> 

stashfs is a start, but the protocol changes, and nobody
has really scrutinized it.

someone would need to touch a keyboard.


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [9front] obsolete cryptographic algorithms
  2022-06-04 15:32     ` ori
@ 2022-06-04 15:36       ` ori
  2022-06-04 16:07         ` Stanley Lieber
  0 siblings, 1 reply; 18+ messages in thread
From: ori @ 2022-06-04 15:36 UTC (permalink / raw)
  To: 9front

Quoth ori@eigenstate.org:
> someone would need to touch a keyboard.

(and not me, I have enough other things that I'd like
to work on; this isn't remotely near the top of my list)


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [9front] obsolete cryptographic algorithms
  2022-06-04 15:36       ` ori
@ 2022-06-04 16:07         ` Stanley Lieber
  2022-06-04 16:12           ` ori
  0 siblings, 1 reply; 18+ messages in thread
From: Stanley Lieber @ 2022-06-04 16:07 UTC (permalink / raw)
  To: 9front

On June 4, 2022 11:36:56 AM EDT, ori@eigenstate.org wrote:
>Quoth ori@eigenstate.org:
>> someone would need to touch a keyboard.
>
>(and not me, I have enough other things that I'd like
>to work on; this isn't remotely near the top of my list)
>
>

maybe we replace secstore before we delete it?

sl

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [9front] obsolete cryptographic algorithms
  2022-06-04 16:07         ` Stanley Lieber
@ 2022-06-04 16:12           ` ori
  0 siblings, 0 replies; 18+ messages in thread
From: ori @ 2022-06-04 16:12 UTC (permalink / raw)
  To: 9front

Quoth Stanley Lieber <sl@stanleylieber.com>:
> On June 4, 2022 11:36:56 AM EDT, ori@eigenstate.org wrote:
> >Quoth ori@eigenstate.org:
> >> someone would need to touch a keyboard.
> >
> >(and not me, I have enough other things that I'd like
> >to work on; this isn't remotely near the top of my list)
> >
> >
> 
> maybe we replace secstore before we delete it?
> 
> sl

to be 100% clear: I'm not proposing any concrete changes.

I'm saying that if you want to delete obsolete algorithms,
secstore is software that would need to change or be
replaced.

patches welcome.


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [9front] obsolete cryptographic algorithms
  2022-06-04 14:47 ` ori
  2022-06-04 15:26   ` mkf9
@ 2022-09-27 20:10   ` Michael Forney
  2022-09-27 20:11     ` hiro
                       ` (2 more replies)
  1 sibling, 3 replies; 18+ messages in thread
From: Michael Forney @ 2022-09-27 20:10 UTC (permalink / raw)
  To: 9front

ori@eigenstate.org wrote:
> Protocols still use them.

What about the ones that aren't used by anything in 9front? I was
poking around libsec a while back and noticed that dsa and elgamal
are completely unused.

Any reason to keep them around? Is there external plan9 software
out there that uses dsa or elgamal from libsec?

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [9front] obsolete cryptographic algorithms
  2022-09-27 20:10   ` Michael Forney
@ 2022-09-27 20:11     ` hiro
  2022-09-27 20:31       ` Michael Forney
  2022-09-27 22:26     ` ori
  2022-10-02 18:23     ` [9front] " magma698hfsp273p9f
  2 siblings, 1 reply; 18+ messages in thread
From: hiro @ 2022-09-27 20:11 UTC (permalink / raw)
  To: 9front

this has been discussed often enough. there might be non-plan9
software that still uses dsa.

On 9/27/22, Michael Forney <mforney@mforney.org> wrote:
> ori@eigenstate.org wrote:
>> Protocols still use them.
>
> What about the ones that aren't used by anything in 9front? I was
> poking around libsec a while back and noticed that dsa and elgamal
> are completely unused.
>
> Any reason to keep them around? Is there external plan9 software
> out there that uses dsa or elgamal from libsec?
>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [9front] obsolete cryptographic algorithms
  2022-09-27 20:11     ` hiro
@ 2022-09-27 20:31       ` Michael Forney
  2022-09-27 21:40         ` hiro
  0 siblings, 1 reply; 18+ messages in thread
From: Michael Forney @ 2022-09-27 20:31 UTC (permalink / raw)
  To: 9front

hiro <23hiro@gmail.com> wrote:
> this has been discussed often enough. there might be non-plan9
> software that still uses dsa.

It seems unlikely that non-plan9 software would be using plan9
libsec.

But maybe I'm misunderstanding you. Can you clarify or provide an
example?

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [9front] obsolete cryptographic algorithms
  2022-09-27 20:31       ` Michael Forney
@ 2022-09-27 21:40         ` hiro
  0 siblings, 0 replies; 18+ messages in thread
From: hiro @ 2022-09-27 21:40 UTC (permalink / raw)
  To: 9front

DSA might be useful to somebody to interoperate with some very old
non-plan9 software.
this is not suckless where stuff gets deleted just so the LOC count
looks pretty.
as long as nothing uses the DSA code, and as long as nobody has to
waste much time maintaining it there's no cost.

On 9/27/22, Michael Forney <mforney@mforney.org> wrote:
> hiro <23hiro@gmail.com> wrote:
>> this has been discussed often enough. there might be non-plan9
>> software that still uses dsa.
>
> It seems unlikely that non-plan9 software would be using plan9
> libsec.
>
> But maybe I'm misunderstanding you. Can you clarify or provide an
> example?
>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [9front] obsolete cryptographic algorithms
  2022-09-27 20:10   ` Michael Forney
  2022-09-27 20:11     ` hiro
@ 2022-09-27 22:26     ` ori
  2022-09-28  6:41       ` hiro
  2022-10-02 18:23     ` [9front] " magma698hfsp273p9f
  2 siblings, 1 reply; 18+ messages in thread
From: ori @ 2022-09-27 22:26 UTC (permalink / raw)
  To: 9front

Quoth Michael Forney <mforney@mforney.org>:
> 
> What about the ones that aren't used by anything in 9front? I was
> poking around libsec a while back and noticed that dsa and elgamal
> are completely unused.
> 
> Any reason to keep them around? Is there external plan9 software
> out there that uses dsa or elgamal from libsec?

I think I'm happy enough to see them gone if we're certain that they're
dead code. If it turns out that there's soemthing that needs them, we can
always bring it back from history -- though I don't know what protocols
force DSA or ElGamal.


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [9front] obsolete cryptographic algorithms
  2022-09-27 22:26     ` ori
@ 2022-09-28  6:41       ` hiro
  2022-09-29  5:01         ` ori
  0 siblings, 1 reply; 18+ messages in thread
From: hiro @ 2022-09-28  6:41 UTC (permalink / raw)
  To: 9front

git history is a shitty way to organise rarely used files.

On 9/28/22, ori@eigenstate.org <ori@eigenstate.org> wrote:
> Quoth Michael Forney <mforney@mforney.org>:
>>
>> What about the ones that aren't used by anything in 9front? I was
>> poking around libsec a while back and noticed that dsa and elgamal
>> are completely unused.
>>
>> Any reason to keep them around? Is there external plan9 software
>> out there that uses dsa or elgamal from libsec?
>
> I think I'm happy enough to see them gone if we're certain that they're
> dead code. If it turns out that there's soemthing that needs them, we can
> always bring it back from history -- though I don't know what protocols
> force DSA or ElGamal.
>
>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [9front] obsolete cryptographic algorithms
  2022-09-28  6:41       ` hiro
@ 2022-09-29  5:01         ` ori
  2022-09-29  6:17           ` unobe
  2022-09-29  8:53           ` hiro
  0 siblings, 2 replies; 18+ messages in thread
From: ori @ 2022-09-29  5:01 UTC (permalink / raw)
  To: 9front

Quoth hiro <23hiro@gmail.com>:
> git history is a shitty way to organise rarely used files.
> 

the belief here is that they're never used.


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [9front] obsolete cryptographic algorithms
  2022-09-29  5:01         ` ori
@ 2022-09-29  6:17           ` unobe
  2022-09-29  6:30             ` unobe
  2022-09-29  8:53           ` hiro
  1 sibling, 1 reply; 18+ messages in thread
From: unobe @ 2022-09-29  6:17 UTC (permalink / raw)
  To: 9front

[-- Attachment #1: Type: text/plain, Size: 725 bytes --]

Quoth ori@eigenstate.org:
> Quoth hiro <23hiro@gmail.com>:
> > git history is a shitty way to organise rarely used files.
> > 
> 
> the belief here is that they're never used.
> 

Please don't remove it.

I have a patch to ssh.c to access rsync.net.  It was never cleaned up,
but it serves my purposes well, until ssh-ed25519 is supported in
9front for key exchange.

The thread where I discussed this was back in June 2020.  The patch
has changed since then (due to changes to ssh.c itself), but it allows
me to use 9front in just one more area of my life without trampolining
through a linux or mac host.

Attached is my current patch that shows using the DSA code in case
anyone else wants to drive fast and take chances.

[-- Attachment #2: ssh-dss.c.patch --]
[-- Type: text/plain, Size: 22473 bytes --]

diff 3a47c8bfbe9298fed2b6dcc5ac19a7af4c96c52f uncommitted
--- a/sys/src/cmd/ssh.c
+++ b/sys/src/cmd/ssh.c
@@ -1,3 +1,14 @@
+/*
+	2020-June (Romano)
+	I think this would be better if refactored into its own subdir with separate files, e.g.:
+	ssh/ssh.h	<-- structs, enums, et c.
+	ssh/debug.c <-- debugging statement stuff, e.g. printKexinitp()
+	ssh/alloc.c <-- kexinitalloc() et c.
+	ssh/kex.c   <-- key exchange and host server algorithm stuff
+	ssh/algs.c  <-- cipher, mac, zip, and lang stuff
+	ssh/ssh.c   <-- main loop
+*/
+
 #include <u.h>
 #include <libc.h>
 #include <mp.h>
@@ -5,6 +16,7 @@
 #include <auth.h>
 #include <authsrv.h>
 
+/* Cf. RFC2450 & RFC8268 */
 enum {
 	MSG_DISCONNECT = 1,
 	MSG_IGNORE,
@@ -47,7 +59,7 @@
 
 
 enum {
-	Overhead = 256,		// enougth for MSG_CHANNEL_DATA header
+	Overhead = 256,		// enough for MSG_CHANNEL_DATA header
 	MaxPacket = 1<<15,
 	WinPackets = 8,		// (1<<15) * 8 = 256K
 };
@@ -76,6 +88,280 @@
 	Rendez;
 } Oneway;
 
+/* BEGIN RFC 4253 name-list agreement structure and implementation */
+struct nameseq {
+	char *val;
+	struct nameseq *next;
+};
+typedef struct nameseq Nameseq;
+
+Nameseq*
+nameseqalloc(void)
+{
+	Nameseq *nameseq;
+
+	nameseq = mallocz(sizeof(*nameseq), 1);
+	if(nameseq == nil)
+		sysfatal("nameseqalloc");
+	return nameseq;
+}
+
+void
+nameseqfree(Nameseq *nameseq)
+{
+	if(nameseq == nil)
+		return;
+	nameseqfree(nameseq->next);
+	free(nameseq);
+}
+
+Nameseq *
+getnameseq(char *c)
+{
+	Nameseq *orderp = nameseqalloc();
+	Nameseq *pp = orderp;
+	char *str = strdup(c);
+	while (str = strtok(str, ",")) {
+		pp->val = str;
+		pp->next = nameseqalloc();
+		pp = pp->next;
+		str = nil;
+	}
+	return orderp;
+}
+
+char *
+nameseqagree(char *c, char *s)
+{
+	Nameseq *cp, *sp, *startsp;
+	char *val = nil;
+
+	if (strlen(c) == 0 && strlen(s) == 0 )
+		return "";
+
+	cp = getnameseq(c);
+	startsp = sp = getnameseq(s);
+	while (cp) {
+		if (cp->val && sp->val && !strcmp(cp->val, sp->val)) {
+			val = strdup(cp->val);
+			break;
+		}
+		if(!(sp = sp->next)) {
+			if(!(cp = cp->next))
+				break;
+			sp = startsp;
+		}
+	}
+
+	nameseqfree(cp);
+	nameseqfree(sp);
+	return val;
+}
+/* END RFC 4253 name-list agreement implementation */
+
+typedef struct algs {
+	char *cipher;
+	char *mac;
+	char *zip;
+	char *lang;
+} Algs;
+typedef Algs *Algsp;
+
+typedef struct kexhost {
+	char *kex;
+	char *host;
+} Kexhost;
+typedef Kexhost *Kexhostp;
+
+typedef struct kexother {
+	uint firstkexpkt;
+	ulong reserved;
+	uchar msg;
+	uchar cookie[16];
+} Kexother;
+typedef Kexother *Kexotherp;
+
+typedef struct kexinit {
+	Kexhostp kh;
+	Algsp ctos;
+	Algsp stoc;
+	Kexotherp ko;
+} Kexinit;
+typedef Kexinit *Kexinitp;
+
+Algsp
+algsalloc(void)
+{
+	Algsp data;
+
+	data = mallocz(sizeof(data), 1);
+	if(data == nil)
+		sysfatal("algsalloc");
+	return data;
+}
+
+Kexhostp
+kexhostalloc(void)
+{
+	Kexhostp data;
+
+	data = mallocz(sizeof(data), 1);
+	if(data == nil)
+		sysfatal("kexhostalloc");
+	return data;
+}
+
+Kexotherp
+kexotheralloc(void)
+{
+	Kexotherp data;
+
+	data = mallocz(sizeof(data), 1);
+	if(data == nil)
+		sysfatal("kexotheralloc");
+	return data;
+}
+
+void
+printKexhostp(char *prefix, Kexhostp data) {
+	fprint(2, "%s 	->%s: %s\n", prefix, "kex", data->kex );
+	fprint(2, "%s 	->%s: %s\n", prefix, "host", data->host );
+}
+
+Kexinitp
+kexinitalloc(void)
+{
+	Kexinitp data;
+
+	data = mallocz(sizeof(data), 1);
+	if(data == nil)
+		sysfatal("kexinitalloc");
+	data->ko = kexotheralloc();
+	data->kh = kexhostalloc();
+	data->ctos = algsalloc();
+	data->stoc = algsalloc();
+	return data;
+}
+
+void
+defKexotherp(Kexotherp kop) {
+	kop->msg = MSG_KEXINIT;
+	kop->firstkexpkt = 0;
+	kop->reserved = 0L;
+	genrandom(kop->cookie, sizeof(kop->cookie));
+}
+
+void
+defKexhostp(Kexhostp khp) {
+	khp->kex = "curve25519-sha256,curve25519-sha256@libssh.org";
+
+	/*
+	ssh-dss is required per RFC4253. OpenSSH has deprecated its use, but
+	does there's no real basis to support that decision for larger modulo.
+	Support it as a secondary algorithm, most likely until ssh-ed25519 is
+	supported.
+	*/
+	khp->host = "ssh-rsa,ssh-dss";
+}
+
+void
+defAlgsp(Algsp algsp) {
+	/*
+	'At some future time, it is expected that another algorithm, one with better
+	strength, will become so prevalent and ubiquitous that the use of
+	"3des-cbc" will be deprecated by another STANDARDS ACTION.' - RFC4253
+	No standards action has yet deprecated it, but have not seen it supported
+	by default in any server.
+	*/
+	algsp->cipher = "chacha20-poly1305@openssh.com";
+	
+	/*
+	hmac-sha1 is a required algorithm by RFC4253, and some servers still check
+	for it; it's effectively ignored since chacha20-poly1305 cipher is AEAD.
+	No RFC has deprecated it, only provided other algorithms to be placed
+	before it (e.g., SHA-2).
+	*/
+	algsp->mac = "hmac-sha1";
+	
+	algsp->zip = "none";
+	algsp->lang = "";
+}
+
+void
+printKexotherp(char *prefix, Kexotherp data) {
+	fprint(2, "%s 	->%s: %uc\n", prefix, "msg", data->msg );
+	fprint(2, "%s 	->%s: %uhd\n", prefix, "cookie", *data->cookie );
+	fprint(2, "%s 	->%s: %ud\n", prefix, "firstkexpkt", data->firstkexpkt );
+	fprint(2, "%s 	->%s: %uld\n", prefix, "reserved", data->reserved );
+}
+
+void
+printAlgsp(char *prefix, Algsp data) {
+	fprint(2, "%s 	->%s: %s\n", prefix, "cipher", data->cipher );
+	fprint(2, "%s 	->%s: %s\n", prefix, "mac", data->mac );
+	fprint(2, "%s 	->%s: %s\n", prefix, "zip", data->zip );
+	fprint(2, "%s 	->%s: %s\n", prefix, "lang", data->lang );
+}
+
+void
+printKexinitp(char *prefix, Kexinitp data) {
+	fprint(2, "%s	%llX:\n", prefix, (vlong)data);
+	fprint(2, "%s ko->\n", prefix);
+	printKexotherp(prefix, data->ko );
+	fprint(2, "%s kh->\n", prefix);
+	printKexhostp(prefix, data->kh );
+	fprint(2, "%s ctos->\n", prefix);
+	printAlgsp(prefix, data->ctos );
+	fprint(2, "%s stoc->\n", prefix);
+	printAlgsp(prefix, data->stoc );
+}
+
+Kexhostp
+khagree(Kexhostp a, Kexhostp b) {
+	Kexhostp c = kexhostalloc();
+	c->kex = nameseqagree(a->kex, b->kex);
+	if(!c->kex)
+		sysfatal("Cannot agree on key exchange algorithm");
+
+	c->host = nameseqagree(a->host, b->host);
+	if(!c->host)
+		sysfatal("Cannot agree on host server algorithm");
+
+	return c;
+}
+
+Algsp
+algsagree(Algsp a, Algsp b, char * cxt) {
+	Algsp c = algsalloc();
+	c->cipher = nameseqagree(a->cipher, b->cipher);
+	if(!c->cipher)
+		sysfatal(smprint("Cannot agree on cipher algorithm for %s", cxt));
+
+	c->mac = nameseqagree(a->mac, b->mac);
+	if(!c->mac)
+		sysfatal(smprint("Cannot agree on mac algorithm for %s", cxt));
+
+	c->zip = nameseqagree(a->zip, b->zip);
+	if(!c->zip)
+		sysfatal(smprint("Cannot agree on zip algorithm for %s", cxt));
+
+	c->lang = nameseqagree(a->lang, b->lang);
+	if(!c->lang)
+		sysfatal(smprint("Cannot agree on lang algorithm for %s", cxt));
+
+	return c;
+}
+
+Kexinitp agreep;
+
+void
+authagree(Kexinitp client, Kexinitp server) {
+	agreep = kexinitalloc();
+	agreep->kh = khagree(client->kh, server->kh);
+	agreep->ctos = algsagree(client->ctos, server->ctos, "ctos");
+	agreep->stoc = algsagree(client->stoc, server->stoc, "stoc");
+}
+
 int nsid;
 uchar sid[256];
 char thumb[2*SHA2_256dlen+1], *thumbfile;
@@ -84,6 +370,7 @@
 char *user, *service, *status, *host, *remote, *cmd;
 
 Oneway recv, send;
+
 void dispatch(void);
 
 void
@@ -163,6 +450,16 @@
 			memmove(p, s, u);
 			p += u;
 			break;
+		/* Why does 's' exist with passing the string length, when it can just be calculated with strlen()? */
+		case 'S':
+			s = va_arg(a, char*);
+			u = strlen(s);
+			if(p+4 > e) goto err;
+			PUT4(p, u), p += 4;
+			if(u > e-p) goto err;
+			memmove(p, s, u);
+			p += u;
+			break;
 		case 'u':
 			u = va_arg(a, int);
 			if(p+4 > e) goto err;
@@ -211,6 +508,14 @@
 			*va_arg(a, int*) = u;
 			p += u;
 			break;
+		/* Why does 's' exist with passing the string length? casting to (char *) is null-terminated and can simply move that way: */
+		case 'S':
+			if(p+4 > e) goto err;
+			u = GET4(p), p += 4;
+			if(u > e-p) goto err;
+			*va_arg(a, char**)= (char*)p;
+			p += u;
+			break;
 		case '[':
 			s = va_arg(a, void*);
 			u = va_arg(a, int);
@@ -280,7 +585,7 @@
 	send.r = send.b;
 	send.w = send.b+n;
 
-if(debug > 1)
+if(debug > 2)
 	fprint(2, "sendpkt: (%d) %.*H\n", send.r[0], (int)(send.w-send.r), send.r);
 
 	if(nsid){
@@ -309,6 +614,26 @@
 	send.seq++;
 }
 
+void
+sendkexinitpkt(Kexinitp data) {
+	sendpkt(
+		"b[SSSSSSSSSSbu",
+		data->ko->msg,
+		data->ko->cookie, sizeof(data->ko->cookie),
+		data->kh->kex,
+		data->kh->host,
+		data->ctos->cipher,
+		data->stoc->cipher,
+		data->ctos->mac,
+		data->stoc->mac,
+		data->ctos->zip,
+		data->stoc->zip,
+		data->ctos->lang,
+		data->stoc->lang,
+		data->ko->firstkexpkt,
+		data->ko->reserved);
+}
+
 int
 readall(int fd, uchar *data, int len)
 {
@@ -366,52 +691,101 @@
 	recv.w = recv.r + n;
 	recv.seq++;
 
-if(debug > 1)
+if(debug > 2)
 	fprint(2, "recvpkt: (%d) %.*H\n", recv.r[0], (int)(recv.w-recv.r), recv.r);
 
 	return recv.r[0];
 }
 
-static char sshrsa[] = "ssh-rsa";
+Kexinitp
+recvkexinit(void) {
 
+	Kexinitp spropp = kexinitalloc();
+	if(unpack(recv.r, recv.w-recv.r, "b[SSSSSSSSSSbu", &(spropp->ko->msg), spropp->ko->cookie, sizeof(spropp->ko->cookie), &(spropp->kh->kex), &(spropp->kh->host), &(spropp->ctos->cipher), &(spropp->stoc->cipher), &(spropp->ctos->mac), &(spropp->stoc->mac), &(spropp->ctos->zip), &(spropp->stoc->zip), &(spropp->ctos->lang), &(spropp->stoc->lang), &(spropp->ko->firstkexpkt), &(spropp->ko->reserved) ) < 0)
+ 		sysfatal("bad MSG_KEXINIT reply");
+
+	if(debug > 1)
+		printKexinitp("server kexinit proposal", spropp);
+
+	return spropp;
+}
+
+typedef struct {
+	RSApub *rsa;
+	DSApub *dsa;
+} Pub;
+
+static Pub *pub;
+ 
 int
-rsapub2ssh(RSApub *rsa, uchar *data, int len)
+dsapub2ssh(uchar *data, int len)
 {
-	return pack(data, len, "smm", sshrsa, sizeof(sshrsa)-1, rsa->ek, rsa->n);
+ 	return pack(data, len, "smmmm", "ssh-dss", sizeof("ssh-dss")-1, pub->dsa->p, pub->dsa->q, pub->dsa->alpha, pub->dsa->key);
 }
 
-RSApub*
-ssh2rsapub(uchar *data, int len)
+void
+ssh2dsapub(uchar *data, int len)
 {
-	RSApub *pub;
 	char *s;
 	int n;
 
-	pub = rsapuballoc();
-	pub->n = mpnew(0);
-	pub->ek = mpnew(0);
-	if(unpack(data, len, "smm", &s, &n, pub->ek, pub->n) < 0
-	|| n != sizeof(sshrsa)-1 || memcmp(s, sshrsa, n) != 0){
-		rsapubfree(pub);
-		return nil;
+	pub->dsa = dsapuballoc();
+	pub->dsa->p = mpnew(0);
+	pub->dsa->q = mpnew(0);
+	pub->dsa->alpha = mpnew(0);
+	pub->dsa->key = mpnew(0);
+	// RFC4253 Section 6.6: alpha is g, key is y
+	if(unpack(data, len, "smmmm", &s, &n, pub->dsa->p, pub->dsa->q, pub->dsa->alpha, pub->dsa->key ) < 0
+	|| n != sizeof("ssh-dss")-1 || memcmp(s, "ssh-dss", n) != 0){
+		dsapubfree(pub->dsa);
 	}
-	return pub;
 }
 
 static char rsasha256[] = "rsa-sha2-256";
 
 int
-rsasig2ssh(RSApub *pub, mpint *S, uchar *data, int len)
+dsasig2ssh(mpint *S, uchar *data, int len)
 {
-	int l = (mpsignif(pub->n)+7)/8;
-	if(4+12+4+l > len)
-		return -1;
-	mptober(S, data+4+12+4, l);
-	return pack(data, len, "ss", rsasha256, sizeof(rsasha256)-1, data+4+12+4, l);
+	DSApriv *dsapriv = dsagen(pub->dsa);
+	DSAsig *dsasig = dsasign(dsapriv, S);
+	mptobe(dsasig->r, data, SHA1dlen, nil);
+	mptobe(dsasig->s, data+SHA1dlen, SHA1dlen, nil);
+	dsasigfree(dsasig);
+	dsaprivfree(dsapriv);
+	return pack(data, len, "ss", "ssh-dss", sizeof("ssh-dss")-1, data, len+2*SHA1dlen);
 }
 
+int
+dsasha1verify(uchar *data, int len, mpint *S)
+{
+	mpint *V;
+	int ret;
+	uchar digest[SHA1dlen];
+
+	sha1(data, len, digest, nil);
+	V = betomp(digest, SHA1dlen, nil);
+	ret = V != nil;
+	if(ret){
+		DSAsig *dsasig = dsasigalloc();
+		dsasig->r = mpnew(0);
+		dsasig->s = mpnew(0);
+		mpright(S, 160, dsasig->r);
+		mptrunc(S, 160, dsasig->s);
+		if(debug > 2) {
+			fmtinstall('B', mpfmt);
+			fprint(2, "V: %B\n", V);
+			fprint(2, "S: %B\n", S);
+			fprint(2, "r:%B; s:%B\n", dsasig->r, dsasig->s);
+		}
+		ret = !dsaverify(pub->dsa, dsasig, V);
+		dsasigfree(dsasig);
+		mpfree(V);
+	}
+	return ret;
+}
+
 mpint*
-ssh2rsasig(uchar *data, int len)
+ssh2sig(uchar *data, int len)
 {
 	mpint *m;
 	char *s;
@@ -419,7 +793,7 @@
 
 	m = mpnew(0);
 	if(unpack(data, len, "sm", &s, &n, m) < 0
-	|| n != sizeof(rsasha256)-1 || memcmp(s, rsasha256, n) != 0){
+	|| n != sizeof(agreep->kh->host)-1 || memcmp(s, agreep->kh->host, n) != 0){
 		mpfree(m);
 		return nil;
 	}
@@ -426,25 +800,58 @@
 	return m;
 }
 
+static char sshrsa[] = "ssh-rsa";
+
+int
+rsapub2ssh(uchar *data, int len)
+{
+	return pack(data, len, "smm", agreep->kh->host, sizeof(agreep->kh->host)-1, pub->rsa->ek, pub->rsa->n);
+}
+
+void
+ssh2rsapub(uchar *data, int len)
+{
+	char *s;
+	int n;
+
+	pub->rsa = rsapuballoc();
+	pub->rsa->n = mpnew(0);
+	pub->rsa->ek = mpnew(0);
+	if(unpack(data, len, "smm", &s, &n, pub->rsa->ek, pub->rsa->n) < 0
+	|| n != sizeof(agreep->kh->host)-1 || memcmp(s, agreep->kh->host, n) != 0){
+		rsapubfree(pub->rsa);
+	}
+}
+
+int
+rsasig2ssh(mpint *S, uchar *data, int len)
+{
+	int l = (mpsignif(pub->rsa->n)+7)/8;
+	if(4+7+4+l > len)
+		return -1;
+	mptober(S, data+4+7+4, l);
+	return pack(data, len, "ss", agreep->kh->host, sizeof(agreep->kh->host)-1, data+4+7+4, l);
+}
+
 mpint*
-pkcs1digest(uchar *data, int len, RSApub *pub)
+pkcs1digest(uchar *data, int len)
 {
 	uchar digest[SHA2_256dlen], buf[256];
 
 	sha2_256(data, len, digest, nil);
-	return pkcs1padbuf(buf, asn1encodedigest(sha2_256, digest, buf, sizeof(buf)), pub->n, 1);
+	return pkcs1padbuf(buf, asn1encodedigest(sha1, digest, buf, sizeof(buf)), pub->rsa->n, 1);
 }
 
 int
-pkcs1verify(uchar *data, int len, RSApub *pub, mpint *S)
+pkcs1verify(uchar *data, int len, mpint *S)
 {
 	mpint *V;
 	int ret;
 
-	V = pkcs1digest(data, len, pub);
+	V = pkcs1digest(data, len);
 	ret = V != nil;
 	if(ret){
-		rsaencrypt(pub, S, S);
+		rsaencrypt(pub->rsa, S, S);
 		ret = mpcmp(V, S) == 0;
 		mpfree(V);
 	}
@@ -488,37 +895,28 @@
 void
 kex(int gotkexinit)
 {
-	static char kexalgs[] = "curve25519-sha256,curve25519-sha256@libssh.org";
-	static char cipheralgs[] = "chacha20-poly1305@openssh.com";
-	static char zipalgs[] = "none";
-	static char macalgs[] = "";
-	static char langs[] = "";
+	Kexinitp cpropp = kexinitalloc();
+	defKexotherp(cpropp->ko);
+	defKexhostp(cpropp->kh);
+	defAlgsp(cpropp->ctos);
+	defAlgsp(cpropp->stoc);
 
-	uchar cookie[16], x[32], yc[32], z[32], k[32+1], h[SHA2_256dlen], *ys, *ks, *sig;
+	if(debug > 1)
+		printKexinitp("client kexinit properties", cpropp);
+
+	uchar x[32], yc[32], z[32], k[32+1], h[SHA2_256dlen], *ys, *ks, *sig;
 	uchar k12[2*ChachaKeylen];
 	int i, nk, nys, nks, nsig;
 	DigestState *ds;
 	mpint *S, *K;
-	RSApub *pub;
 
+	if (pub==nil)
+		pub = mallocz(sizeof(pub), 1);
+
 	ds = hashstr(send.v, strlen(send.v), nil);	
 	ds = hashstr(recv.v, strlen(recv.v), ds);
 
-	genrandom(cookie, sizeof(cookie));
-	sendpkt("b[ssssssssssbu", MSG_KEXINIT,
-		cookie, sizeof(cookie),
-		kexalgs, sizeof(kexalgs)-1,
-		rsasha256, sizeof(rsasha256)-1,
-		cipheralgs, sizeof(cipheralgs)-1,
-		cipheralgs, sizeof(cipheralgs)-1,
-		macalgs, sizeof(macalgs)-1,
-		macalgs, sizeof(macalgs)-1,
-		zipalgs, sizeof(zipalgs)-1,
-		zipalgs, sizeof(zipalgs)-1,
-		langs, sizeof(langs)-1,
-		langs, sizeof(langs)-1,
-		0,
-		0);
+	sendkexinitpkt(cpropp);
 	ds = hashstr(send.r, send.w-send.r, ds);
 
 	if(!gotkexinit){
@@ -532,26 +930,12 @@
 	}
 	ds = hashstr(recv.r, recv.w-recv.r, ds);
 
-	if(debug){
-		char *tab[] = {
-			"kexalgs", "hostalgs",
-			"cipher1", "cipher2",
-			"mac1", "mac2",
-			"zip1", "zip2",
-			"lang1", "lang2",
-			nil,
-		}, **t, *s;
-		uchar *p = recv.r+17;
-		int n;
-		for(t=tab; *t != nil; t++){
-			if(unpack(p, recv.w-p, "s.", &s, &n, &p) < 0)
-				break;
-			fprint(2, "%s: %.*s\n", *t, utfnlen(s, n), s);
-		}
-	}
-
+	Kexinitp spropp = recvkexinit();
+	authagree(cpropp, spropp);
+	if (debug > 1)
+		printKexinitp("agreement", agreep);
 	curve25519_dh_new(x, yc);
-	yc[31] &= ~0x80;
+	yc[31] &= ~0x80; /* curve25519_dh_new does & 0x80, so why reverse? */
 
 	sendpkt("bs", MSG_ECDH_INIT, yc, sizeof(yc));
 Next1:	switch(recvpkt()){
@@ -561,6 +945,8 @@
 	case MSG_KEXINIT:
 		sysfatal("inception");
 	case MSG_ECDH_REPLY:
+
+		/* RFC5656; ys is being set to Q_S */
 		if(unpack(recv.r, recv.w-recv.r, "_sss", &ks, &nks, &ys, &nys, &sig, &nsig) < 0)
 			sysfatal("bad ECDH_REPLY");
 		break;
@@ -567,7 +953,7 @@
 	}
 
 	if(nys != 32)
-		sysfatal("bad server ECDH ephermal public key length");
+		sysfatal("bad server ECDH ephemeral public key length");
 
 	ds = hashstr(ks, nks, ds);
 	ds = hashstr(yc, 32, ds);
@@ -589,18 +975,29 @@
 		if(ok == nil || !okThumbprint(h, sizeof(h), ok)){
 			if(ok != nil) werrstr("unknown host");
 			fprint(2, "%s: %r\n", argv0);
-			fprint(2, "verify hostkey: %s %.*[\n", sshrsa, nks, ks);
+			fprint(2, "verify hostkey: %s %.*[\n", agreep->kh->host, nks, ks);
 			fprint(2, "add thumbprint after verification:\n");
-			fprint(2, "\techo 'ssh sha256=%s server=%s' >> %q\n", thumb, host, thumbfile);
+			fprint(2, "\techo 'ssh sha256=%s server=%s type=%s' >> %q\n", thumb, host, agreep->kh->host, thumbfile);
 			sysfatal("checking hostkey failed: %r");
 		}
 		freeThumbprints(ok);
 	}
 
-	if((pub = ssh2rsapub(ks, nks)) == nil)
-		sysfatal("bad server public key");
-	if((S = ssh2rsasig(sig, nsig)) == nil)
-		sysfatal("bad server signature");
+	// TODO: branch for ed25519
+	if(!strcmp(agreep->kh->host,"ssh-dss")) {
+		ssh2dsapub(ks, nks);
+		if(pub->dsa == nil)
+			sysfatal("bad server dss public key");
+		if((S = ssh2sig(sig, nsig)) == nil)
+			sysfatal("no server dss signature");
+	}
+	else {
+		ssh2rsapub(ks, nks);
+		if(pub->rsa == nil)
+			sysfatal("bad server rsa public key");
+		if((S = ssh2sig(sig, nsig)) == nil)
+			sysfatal("no server rsa signature");
+	}
 
 	if(!curve25519_dh_finish(x, ys, z))
 		sysfatal("unlucky shared key");
@@ -612,10 +1009,17 @@
 
 	ds = hashstr(k, nk, ds);
 	sha2_256(nil, 0, h, ds);
-	if(!pkcs1verify(h, sizeof(h), pub, S))
-		sysfatal("server verification failed");
+	// TODO: branch for ssh-ed25519
+	if(!strcmp(agreep->kh->host,"ssh-dss")){
+		if(!dsasha1verify(h, sizeof(h), S))
+			sysfatal("server dss verification failed");
+	}
+	else {
+		if(!pkcs1verify(h, sizeof(h), S))
+			sysfatal("server rsa verification failed");
+		rsapubfree(pub->rsa);
+	}
 	mpfree(S);
-	rsapubfree(pub);
 
 	sendpkt("b", MSG_NEWKEYS);
 Next2:	switch(recvpkt()){
@@ -708,7 +1112,6 @@
 	char *s;
 	mpint *S;
 	AuthRpc *rpc;
-	RSApub *pub;
 
 	if(!authok(authmeth))
 		return -1;
@@ -720,7 +1123,7 @@
 		return -1;
 	}
 
-	s = "proto=rsa service=ssh role=client";
+	s = !strcmp(agreep->kh->host,"ssh-dss") ? "proto=dsa service=ssh role=client" : "proto=rsa service=ssh role=client";
 	if(auth_rpc(rpc, "start", s, strlen(s)) != ARok){
 		auth_freerpc(rpc);
 		close(afd);
@@ -727,19 +1130,50 @@
 		return -1;
 	}
 
-	pub = rsapuballoc();
-	pub->n = mpnew(0);
-	pub->ek = mpnew(0);
+	// TODO: branch for ssh-ed25519
+	if(!strcmp(agreep->kh->host,"ssh-dss")){
+		pub->dsa = dsapuballoc();
+		pub->dsa->p = mpnew(0);
+		pub->dsa->q = mpnew(0);
+		pub->dsa->alpha = mpnew(0);
+		pub->dsa->key = mpnew(0);
+	}
+	else {
+		pub->rsa = rsapuballoc();
+		pub->rsa->n = mpnew(0);
+		pub->rsa->ek = mpnew(0);
+	}
 
 	while(auth_rpc(rpc, "read", nil, 0) == ARok){
 		s = rpc->arg;
-		if(strtomp(s, &s, 16, pub->n) == nil)
-			break;
-		if(*s++ != ' ')
-			continue;
-		if(strtomp(s, nil, 16, pub->ek) == nil)
-			continue;
-		npk = rsapub2ssh(pub, pk, sizeof(pk));
+		// TODO: branch for ssh-ed25519
+		if(!strcmp(agreep->kh->host,"ssh-dss")){
+			// This seems brittle and dependent upon the order of values set in factotum
+			if(strtomp(s, &s, 16, pub->dsa->p) == nil)
+				break;
+			if(*s++ != ' ')
+				continue;
+			if(strtomp(s, nil, 16, pub->dsa->q) == nil)
+				continue;
+			if(*s++ != ' ')
+				continue;
+			if(strtomp(s, nil, 16, pub->dsa->alpha) == nil)
+				continue;
+			if(*s++ != ' ')
+				continue;
+			if(strtomp(s, nil, 16, pub->dsa->key) == nil)
+				continue;
+			npk = dsapub2ssh(pk, sizeof(pk));
+		}
+		else {
+			if(strtomp(s, &s, 16, pub->rsa->n) == nil)
+				break;
+			if(*s++ != ' ')
+				continue;
+			if(strtomp(s, nil, 16, pub->rsa->ek) == nil)
+				continue;
+			npk = rsapub2ssh(pk, sizeof(pk));
+		}
 
 		sendpkt("bsssbss", MSG_USERAUTH_REQUEST,
 			user, strlen(user),
@@ -746,7 +1180,7 @@
 			service, strlen(service),
 			authmeth, sizeof(authmeth)-1,
 			0,
-			rsasha256, sizeof(rsasha256)-1,
+			agreep->kh->host, sizeof(agreep->kh->host)-1,
 			pk, npk);
 Next1:		switch(recvpkt()){
 		default:
@@ -769,9 +1203,16 @@
 			service, strlen(service),
 			authmeth, sizeof(authmeth)-1,
 			1,
-			rsasha256, sizeof(rsasha256)-1,
+			agreep->kh->host, sizeof(agreep->kh->host)-1,
 			pk, npk);
-		S = pkcs1digest(send.b, n, pub);
+		// TODO branch for ssh-ed25519
+		if (!strcmp(agreep->kh->host,"ssh-dss")){
+			sha1(send.b, n, sig, nil);
+			S = strtomp((char *)sig, nil, 10, nil);
+		}
+		else {
+			S = pkcs1digest(send.b, n);
+		}
 		n = snprint((char*)send.b, sizeof(send.b), "%B", S);
 		mpfree(S);
 
@@ -781,7 +1222,13 @@
 			break;
 
 		S = strtomp(rpc->arg, nil, 16, nil);
-		nsig = rsasig2ssh(pub, S, sig, sizeof(sig));
+		// TODO branch for ssh-ed25519
+		if (!strcmp(agreep->kh->host,"ssh-dss")){
+			nsig = dsasig2ssh(S, sig, sizeof(sig));
+		}
+		else {
+			nsig = rsasig2ssh(S, sig, sizeof(sig));
+		}
 		mpfree(S);
 
 		/* send final userauth request with the signature */
@@ -790,7 +1237,7 @@
 			service, strlen(service),
 			authmeth, sizeof(authmeth)-1,
 			1,
-			rsasha256, sizeof(rsasha256)-1,
+			agreep->kh->host, sizeof(agreep->kh->host)-1,
 			pk, npk,
 			sig, nsig);
 Next2:		switch(recvpkt()){
@@ -804,13 +1251,25 @@
 		case MSG_USERAUTH_SUCCESS:
 			break;
 		}
-		rsapubfree(pub);
+		// TODO: branch for ssh-ed25519
+		if (!strcmp(agreep->kh->host,"ssh-dss")){
+			dsapubfree(pub->dsa);
+		}
+		else {
+			rsapubfree(pub->rsa);
+		}
 		auth_freerpc(rpc);
 		close(afd);
 		return 0;
 	}
 Failed:
-	rsapubfree(pub);
+	// TODO: branch for ssh-ed25519
+	if (!strcmp(agreep->kh->host,"ssh-dss")){
+		dsapubfree(pub->dsa);
+	}
+	else {
+		rsapubfree(pub->rsa);
+	}
 	auth_freerpc(rpc);
 	close(afd);
 	return -1;	
@@ -1171,7 +1630,7 @@
 void
 usage(void)
 {
-	fprint(2, "usage: %s [-dR] [-t thumbfile] [-T tries] [-u user] [-h] [user@]host [-W remote!port] [cmd args...]\n", argv0);
+	fprint(2, "usage: %s [-d] [-R] [-r] [-t thumbfile] [-T tries] [-u user] [-h] [user@]host [-W remote!port] [cmd args...]\n", argv0);
 	exits("usage");
 }
 

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [9front] obsolete cryptographic algorithms
  2022-09-29  6:17           ` unobe
@ 2022-09-29  6:30             ` unobe
  0 siblings, 0 replies; 18+ messages in thread
From: unobe @ 2022-09-29  6:30 UTC (permalink / raw)
  To: 9front

Quoth unobe@cpan.org:
> The thread where I discussed this was back in June 2020.

Here's an archive of that thread if anyone is interested in the short
discussion and doesn't have a local copy:

https://inbox.vuxu.org/9front/8008101F-B2C7-4DB7-BFD9-5BA7E82DBC54@cpan.org/


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [9front] obsolete cryptographic algorithms
  2022-09-29  5:01         ` ori
  2022-09-29  6:17           ` unobe
@ 2022-09-29  8:53           ` hiro
  1 sibling, 0 replies; 18+ messages in thread
From: hiro @ 2022-09-29  8:53 UTC (permalink / raw)
  To: 9front

> the belief here is that they're never used.

that's the thing about old protocols, it doesn't matter whether you
want them not to be used, some shitty gear might come with them
anyway.

what we try to provide here is called interoperability.

unlike linux, programs are limited to safer algorithms by default, so
it looks unused.

the balance to make is between maintainability and interoperability.
removing something is more work than not removing something.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [9front] Re: obsolete cryptographic algorithms
  2022-09-27 20:10   ` Michael Forney
  2022-09-27 20:11     ` hiro
  2022-09-27 22:26     ` ori
@ 2022-10-02 18:23     ` magma698hfsp273p9f
  2 siblings, 0 replies; 18+ messages in thread
From: magma698hfsp273p9f @ 2022-10-02 18:23 UTC (permalink / raw)
  To: 9front

Michael Forney <mforney@mforney.org> writes:

> ori@eigenstate.org wrote:
>> Protocols still use them.
>
> What about the ones that aren't used by anything in 9front? I was
> poking around libsec a while back and noticed that dsa and elgamal
> are completely unused.
>
> Any reason to keep them around? Is there external plan9 software
> out there that uses dsa or elgamal from libsec?

THERE IS REALLY NO SUCH THING AS AN OBSOLETE CRYPTOGRAPHIC ALOGRITHM.
I set that in caps because it demands emphasis.  There are many old
archives, network devices, and other systems which may (and do) employ
older cryptographic technologies.  Removing support from 9front would
remove the ability to read/interact with legacy systems.  I encountered
this problem when some "obsolete" ciphers were removed from the Linux
cryptoapi.  I ended up having to re-implement one of them as a command-
line utility in C, just so I could access data written using a prior
version.  As long as old machines, old software, and old data exists,
there is really no such thing as an obsolete cryptographic alogrithm.

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2022-10-02 22:33 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-04  7:13 [9front] obsolete cryptographic algorithms sml
2022-06-04 14:47 ` ori
2022-06-04 15:26   ` mkf9
2022-06-04 15:32     ` ori
2022-06-04 15:36       ` ori
2022-06-04 16:07         ` Stanley Lieber
2022-06-04 16:12           ` ori
2022-09-27 20:10   ` Michael Forney
2022-09-27 20:11     ` hiro
2022-09-27 20:31       ` Michael Forney
2022-09-27 21:40         ` hiro
2022-09-27 22:26     ` ori
2022-09-28  6:41       ` hiro
2022-09-29  5:01         ` ori
2022-09-29  6:17           ` unobe
2022-09-29  6:30             ` unobe
2022-09-29  8:53           ` hiro
2022-10-02 18:23     ` [9front] " magma698hfsp273p9f

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).