Development discussion of WireGuard
 help / color / mirror / Atom feed
* How to verify a wireguard public key?
@ 2020-12-24 16:00 Nico Schottelius
  2020-12-24 23:30 ` Jason A. Donenfeld
  2020-12-24 23:42 ` Adam Stiles
  0 siblings, 2 replies; 9+ messages in thread
From: Nico Schottelius @ 2020-12-24 16:00 UTC (permalink / raw)
  To: wireguard


Good morning,

I am currently extending uncloud [0] to support wireguard tunnels and
keys. At the moment it is not entirely clear how to verify that a
certain string is a valid wireguard key.

I first tried checking that it is valid base64, but not all base64
strings are valid wireguard keys.

Then I tried using `echo $key | wg pubkey && echo ok` - which seems to
check the key format, however the intended behaviour here is misused.

Does anyone have a pointer on how to reliably identify wireguard public
keys?

Is the wireguard key always 32 bytes when decoded from base64? Tests
with a number of public keys seems to indicate that.

Best regards,

Nico


[0] https://code.ungleich.ch/uncloud/uncloud

--
Modern, affordable, Swiss Virtual Machines. Visit www.datacenterlight.ch

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

* Re: How to verify a wireguard public key?
  2020-12-24 16:00 How to verify a wireguard public key? Nico Schottelius
@ 2020-12-24 23:30 ` Jason A. Donenfeld
  2020-12-24 23:42 ` Adam Stiles
  1 sibling, 0 replies; 9+ messages in thread
From: Jason A. Donenfeld @ 2020-12-24 23:30 UTC (permalink / raw)
  To: Nico Schottelius; +Cc: wireguard

It's probably wisest to ignore differences between public keys and
private keys and set aside any structure they might have by virtue of
being related to elliptic curves, and instead just regard them as
32-byte strings encoded in base64. Not 31 bytes or 33 bytes, but exactly
32. This matters, because 32 does not divide evenly by .75, so there's a
padding character and the penultimate character does not include the
whole base64 alphabet. 43 base64 chars can represent up to 258bits,
which is more than 256bits. So, you can either validate this with a
base64 parser and checking that it returns exactly 32 bytes, or you can
match against this simple regex:

^[A-Za-z0-9+/]{42}[A|E|I|M|Q|U|Y|c|g|k|o|s|w|4|8|0]=$

You can convince yourself that's correct by running this for a while and
seeing that it never fails:

while true; do [[ $(head -c 32 /dev/urandom | base64) =~ ^[A-Za-z0-9+/]{42}[A|E|I|M|Q|U|Y|c|g|k|o|s|w|4|8|0]=$ ]] || echo "FAILURE"; done

The endings are valid because those are the only ones that don't end in
01, 10, or 11, so that the string doesn't exceed 256 bits. And again we
can have bash bruteforce those for us:

for i in {A..Z} {a..z} {0..9} + /; do a="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA$i="; [[ $(echo $a|base64 -d|base64) == $a ]] && echo -n $i; done; echo
AEIMQUYcgkosw048

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

* Re: How to verify a wireguard public key?
  2020-12-24 16:00 How to verify a wireguard public key? Nico Schottelius
  2020-12-24 23:30 ` Jason A. Donenfeld
@ 2020-12-24 23:42 ` Adam Stiles
  2020-12-25  9:10   ` Nico Schottelius
  2020-12-25 22:16   ` Matthias Urlichs
  1 sibling, 2 replies; 9+ messages in thread
From: Adam Stiles @ 2020-12-24 23:42 UTC (permalink / raw)
  To: Nico Schottelius; +Cc: wireguard

Hi Nico,

WireGuard uses Curve25519 keys. A Curve25519 secret key is a random 32
byte value with a few special bits flipped, and a public key is
calculated from a secret key.

There's some good info here (https://cr.yp.to/ecdh.html), including
this questions and answer:

"How do I validate Curve25519 public keys?"

"Don't. The Curve25519 function was carefully designed to allow all
32-byte strings as Diffie-Hellman public keys."

I just saw Jason's response, and so this is a bit redundant, but the
reference above is a good one.

Best,

Adam


On Thu, Dec 24, 2020 at 3:21 PM Nico Schottelius
<nico.schottelius@ungleich.ch> wrote:
>
>
> Good morning,
>
> I am currently extending uncloud [0] to support wireguard tunnels and
> keys. At the moment it is not entirely clear how to verify that a
> certain string is a valid wireguard key.
>
> I first tried checking that it is valid base64, but not all base64
> strings are valid wireguard keys.
>
> Then I tried using `echo $key | wg pubkey && echo ok` - which seems to
> check the key format, however the intended behaviour here is misused.
>
> Does anyone have a pointer on how to reliably identify wireguard public
> keys?
>
> Is the wireguard key always 32 bytes when decoded from base64? Tests
> with a number of public keys seems to indicate that.
>
> Best regards,
>
> Nico
>
>
> [0] https://code.ungleich.ch/uncloud/uncloud
>
> --
> Modern, affordable, Swiss Virtual Machines. Visit www.datacenterlight.ch

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

* Re: How to verify a wireguard public key?
  2020-12-24 23:42 ` Adam Stiles
@ 2020-12-25  9:10   ` Nico Schottelius
  2020-12-25 23:37     ` Matthias May
  2020-12-25 22:16   ` Matthias Urlichs
  1 sibling, 1 reply; 9+ messages in thread
From: Nico Schottelius @ 2020-12-25  9:10 UTC (permalink / raw)
  To: Adam Stiles; +Cc: Nico Schottelius, wireguard


Good morning Adam and Jason,

thanks for your qualified and fast answers! It's nice to see Dan's
website still referenced in almost 2021 and also that it can be easily
enough verified.

For reference and if anyone ever looks up this thread, I am using
the following code within the Django Rest Framework [0]:

--------------------------------------------------------------------------------
    def validate_wireguard_public_key(self, value):
        msg = _("Supplied key is not a valid wireguard public key")

        """
        Verify wireguard key.
        See https://lists.zx2c4.com/pipermail/wireguard/2020-December/006221.html
        """

        try:
            decoded_key = base64.standard_b64decode(value)
        except Exception as e:
            raise serializers.ValidationError(msg)

        if not len(decoded_key) == 32:
            raise serializers.ValidationError(msg)

        return value
--------------------------------------------------------------------------------

Thanks again and enjoy the quite time over Christmas!

Best regards,

Nico

[0] https://code.ungleich.ch/uncloud/uncloud/-/blob/master/uncloud_net/serializers.py#L37


Adam Stiles <ajstiles@gmail.com> writes:

> Hi Nico,
>
> WireGuard uses Curve25519 keys. A Curve25519 secret key is a random 32
> byte value with a few special bits flipped, and a public key is
> calculated from a secret key.
>
> There's some good info here (https://cr.yp.to/ecdh.html), including
> this questions and answer:
>
> "How do I validate Curve25519 public keys?"
>
> "Don't. The Curve25519 function was carefully designed to allow all
> 32-byte strings as Diffie-Hellman public keys."
>
> I just saw Jason's response, and so this is a bit redundant, but the
> reference above is a good one.
>
> Best,
>
> Adam
>
>
> On Thu, Dec 24, 2020 at 3:21 PM Nico Schottelius
> <nico.schottelius@ungleich.ch> wrote:
>>
>>
>> Good morning,
>>
>> I am currently extending uncloud [0] to support wireguard tunnels and
>> keys. At the moment it is not entirely clear how to verify that a
>> certain string is a valid wireguard key.
>>
>> I first tried checking that it is valid base64, but not all base64
>> strings are valid wireguard keys.
>>
>> Then I tried using `echo $key | wg pubkey && echo ok` - which seems to
>> check the key format, however the intended behaviour here is misused.
>>
>> Does anyone have a pointer on how to reliably identify wireguard public
>> keys?
>>
>> Is the wireguard key always 32 bytes when decoded from base64? Tests
>> with a number of public keys seems to indicate that.
>>
>> Best regards,
>>
>> Nico
>>
>>
>> [0] https://code.ungleich.ch/uncloud/uncloud
>>
>> --
>> Modern, affordable, Swiss Virtual Machines. Visit www.datacenterlight.ch


--
Modern, affordable, Swiss Virtual Machines. Visit www.datacenterlight.ch

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

* Re: How to verify a wireguard public key?
  2020-12-24 23:42 ` Adam Stiles
  2020-12-25  9:10   ` Nico Schottelius
@ 2020-12-25 22:16   ` Matthias Urlichs
  2020-12-26  8:09     ` Nico Schottelius
  1 sibling, 1 reply; 9+ messages in thread
From: Matthias Urlichs @ 2020-12-25 22:16 UTC (permalink / raw)
  To: wireguard


[-- Attachment #1.1: Type: text/plain, Size: 337 bytes --]

On 25.12.20 00:42, Adam Stiles wrote:
> "How do I validate Curve25519 public keys?"

You send a handshake packet to the owner of the corresponding private 
key and observe whether it accepted it.

The question is, why do you think you need a different/additional way of 
verifying the public key?

-- 
-- Matthias Urlichs



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

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

* Re: How to verify a wireguard public key?
  2020-12-25  9:10   ` Nico Schottelius
@ 2020-12-25 23:37     ` Matthias May
  2020-12-25 23:47       ` Jason A. Donenfeld
  0 siblings, 1 reply; 9+ messages in thread
From: Matthias May @ 2020-12-25 23:37 UTC (permalink / raw)
  To: Nico Schottelius, Adam Stiles; +Cc: wireguard

On 25/12/2020 10:10, Nico Schottelius wrote:
> 
> Good morning Adam and Jason,
> 
> thanks for your qualified and fast answers! It's nice to see Dan's
> website still referenced in almost 2021 and also that it can be easily
> enough verified.
> 
> For reference and if anyone ever looks up this thread, I am using
> the following code within the Django Rest Framework [0]:
> 
> --------------------------------------------------------------------------------
>     def validate_wireguard_public_key(self, value):
>         msg = _("Supplied key is not a valid wireguard public key")
> 
>         """
>         Verify wireguard key.
>         See https://urldefense.com/v3/__https://lists.zx2c4.com/pipermail/wireguard/2020-December/006221.html__;!!I9LPvj3b!XDmxiY_v3yY5wQI9GfFvshrCIUcqg4vvKg35qvL0fFajgNHTwr3LcySSqHrNgCByOzQ$ 
>         """
> 
>         try:
>             decoded_key = base64.standard_b64decode(value)
>         except Exception as e:
>             raise serializers.ValidationError(msg)
> 
>         if not len(decoded_key) == 32:
>             raise serializers.ValidationError(msg)
> 
>         return value
> --------------------------------------------------------------------------------
> 
> Thanks again and enjoy the quite time over Christmas!
> 
> Best regards,
> 
> Nico
> 
> [0] https://urldefense.com/v3/__https://code.ungleich.ch/uncloud/uncloud/-/blob/master/uncloud_net/serializers.py*L37__;Iw!!I9LPvj3b!XDmxiY_v3yY5wQI9GfFvshrCIUcqg4vvKg35qvL0fFajgNHTwr3LcySSqHrNb-aKgNg$ 
> 
> 
> Adam Stiles <ajstiles@gmail.com> writes:
> 
>> Hi Nico,
>>
>> WireGuard uses Curve25519 keys. A Curve25519 secret key is a random 32
>> byte value with a few special bits flipped, and a public key is
>> calculated from a secret key.
>>
>> There's some good info here (https://urldefense.com/v3/__https://cr.yp.to/ecdh.html__;!!I9LPvj3b!XDmxiY_v3yY5wQI9GfFvshrCIUcqg4vvKg35qvL0fFajgNHTwr3LcySSqHrNDoxdskk$ ), including
>> this questions and answer:
>>
>> "How do I validate Curve25519 public keys?"
>>
>> "Don't. The Curve25519 function was carefully designed to allow all
>> 32-byte strings as Diffie-Hellman public keys."
>>
>> I just saw Jason's response, and so this is a bit redundant, but the
>> reference above is a good one.
>>
>> Best,
>>
>> Adam
>>
>>
>> On Thu, Dec 24, 2020 at 3:21 PM Nico Schottelius
>> <nico.schottelius@ungleich.ch> wrote:
>>>
>>>
>>> Good morning,
>>>
>>> I am currently extending uncloud [0] to support wireguard tunnels and
>>> keys. At the moment it is not entirely clear how to verify that a
>>> certain string is a valid wireguard key.
>>>
>>> I first tried checking that it is valid base64, but not all base64
>>> strings are valid wireguard keys.
>>>
>>> Then I tried using `echo $key | wg pubkey && echo ok` - which seems to
>>> check the key format, however the intended behaviour here is misused.
>>>
>>> Does anyone have a pointer on how to reliably identify wireguard public
>>> keys?
>>>
>>> Is the wireguard key always 32 bytes when decoded from base64? Tests
>>> with a number of public keys seems to indicate that.
>>>
>>> Best regards,
>>>
>>> Nico
>>>
>>>
>>> [0] https://urldefense.com/v3/__https://code.ungleich.ch/uncloud/uncloud__;!!I9LPvj3b!XDmxiY_v3yY5wQI9GfFvshrCIUcqg4vvKg35qvL0fFajgNHTwr3LcySSqHrNE6JpRjQ$ 
>>>
>>> --
>>> Modern, affordable, Swiss Virtual Machines. Visit https://urldefense.com/v3/__http://www.datacenterlight.ch__;!!I9LPvj3b!XDmxiY_v3yY5wQI9GfFvshrCIUcqg4vvKg35qvL0fFajgNHTwr3LcySSqHrNmbUvisY$ 
> 
> 
> --
> Modern, affordable, Swiss Virtual Machines. Visit https://urldefense.com/v3/__http://www.datacenterlight.ch__;!!I9LPvj3b!XDmxiY_v3yY5wQI9GfFvshrCIUcqg4vvKg35qvL0fFajgNHTwr3LcySSqHrNmbUvisY$ 
> 


Hi
On this topic, i recently implemented a check if a key is valid in cpp with the following rather crude code:

bool isValidWgKey(const string& usage, const string& key)
{
	/* Wireguard keys are BASE64 encoded */
	unsigned int _key_length = 44;
	unsigned int _key_offset = _key_length -1;
	if (key.length() != _key_length) {
		log("Wireguard " + usage + " has wrong length (" + to_string(key.length()) + " instead of 44)!");
		return false;
	}
	size_t found = key.substr(0,_key_offset).find_first_not_of("abcdefghijklmnopqrstuvwxyz"
								   "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/");
	if (found != std::string::npos) {
		log("Wireguard " + usage + " contains invalid character '" + key.substr(found, 1) + "'");
		return false;
	}
	if (key.substr(_key_offset,1) != "=") {
		log("Wireguard " + usage + " ends with invalid character '" +
		    key.substr(found, 1) + "' instead of '='");
		return false;
	}
	return true;
}

Maybe it's useful to someone.

BR
Matthias

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

* Re: How to verify a wireguard public key?
  2020-12-25 23:37     ` Matthias May
@ 2020-12-25 23:47       ` Jason A. Donenfeld
  0 siblings, 0 replies; 9+ messages in thread
From: Jason A. Donenfeld @ 2020-12-25 23:47 UTC (permalink / raw)
  To: Matthias May; +Cc: Nico Schottelius, Adam Stiles, WireGuard mailing list

On Sat, Dec 26, 2020 at 12:38 AM Matthias May <matthias.may@westermo.com> wrote:
>
> On 25/12/2020 10:10, Nico Schottelius wrote:
> >
> > Good morning Adam and Jason,
> >
> > thanks for your qualified and fast answers! It's nice to see Dan's
> > website still referenced in almost 2021 and also that it can be easily
> > enough verified.
> >
> > For reference and if anyone ever looks up this thread, I am using
> > the following code within the Django Rest Framework [0]:
> >
> > --------------------------------------------------------------------------------
> >     def validate_wireguard_public_key(self, value):
> >         msg = _("Supplied key is not a valid wireguard public key")
> >
> >         """
> >         Verify wireguard key.
> >         See https://urldefense.com/v3/__https://lists.zx2c4.com/pipermail/wireguard/2020-December/006221.html__;!!I9LPvj3b!XDmxiY_v3yY5wQI9GfFvshrCIUcqg4vvKg35qvL0fFajgNHTwr3LcySSqHrNgCByOzQ$
> >         """
> >
> >         try:
> >             decoded_key = base64.standard_b64decode(value)
> >         except Exception as e:
> >             raise serializers.ValidationError(msg)
> >
> >         if not len(decoded_key) == 32:
> >             raise serializers.ValidationError(msg)
> >
> >         return value
> > --------------------------------------------------------------------------------
> >
> > Thanks again and enjoy the quite time over Christmas!
> >
> > Best regards,
> >
> > Nico
> >
> > [0] https://urldefense.com/v3/__https://code.ungleich.ch/uncloud/uncloud/-/blob/master/uncloud_net/serializers.py*L37__;Iw!!I9LPvj3b!XDmxiY_v3yY5wQI9GfFvshrCIUcqg4vvKg35qvL0fFajgNHTwr3LcySSqHrNb-aKgNg$
> >
> >
> > Adam Stiles <ajstiles@gmail.com> writes:
> >
> >> Hi Nico,
> >>
> >> WireGuard uses Curve25519 keys. A Curve25519 secret key is a random 32
> >> byte value with a few special bits flipped, and a public key is
> >> calculated from a secret key.
> >>
> >> There's some good info here (https://urldefense.com/v3/__https://cr.yp.to/ecdh.html__;!!I9LPvj3b!XDmxiY_v3yY5wQI9GfFvshrCIUcqg4vvKg35qvL0fFajgNHTwr3LcySSqHrNDoxdskk$ ), including
> >> this questions and answer:
> >>
> >> "How do I validate Curve25519 public keys?"
> >>
> >> "Don't. The Curve25519 function was carefully designed to allow all
> >> 32-byte strings as Diffie-Hellman public keys."
> >>
> >> I just saw Jason's response, and so this is a bit redundant, but the
> >> reference above is a good one.
> >>
> >> Best,
> >>
> >> Adam
> >>
> >>
> >> On Thu, Dec 24, 2020 at 3:21 PM Nico Schottelius
> >> <nico.schottelius@ungleich.ch> wrote:
> >>>
> >>>
> >>> Good morning,
> >>>
> >>> I am currently extending uncloud [0] to support wireguard tunnels and
> >>> keys. At the moment it is not entirely clear how to verify that a
> >>> certain string is a valid wireguard key.
> >>>
> >>> I first tried checking that it is valid base64, but not all base64
> >>> strings are valid wireguard keys.
> >>>
> >>> Then I tried using `echo $key | wg pubkey && echo ok` - which seems to
> >>> check the key format, however the intended behaviour here is misused.
> >>>
> >>> Does anyone have a pointer on how to reliably identify wireguard public
> >>> keys?
> >>>
> >>> Is the wireguard key always 32 bytes when decoded from base64? Tests
> >>> with a number of public keys seems to indicate that.
> >>>
> >>> Best regards,
> >>>
> >>> Nico
> >>>
> >>>
> >>> [0] https://urldefense.com/v3/__https://code.ungleich.ch/uncloud/uncloud__;!!I9LPvj3b!XDmxiY_v3yY5wQI9GfFvshrCIUcqg4vvKg35qvL0fFajgNHTwr3LcySSqHrNE6JpRjQ$
> >>>
> >>> --
> >>> Modern, affordable, Swiss Virtual Machines. Visit https://urldefense.com/v3/__http://www.datacenterlight.ch__;!!I9LPvj3b!XDmxiY_v3yY5wQI9GfFvshrCIUcqg4vvKg35qvL0fFajgNHTwr3LcySSqHrNmbUvisY$
> >
> >
> > --
> > Modern, affordable, Swiss Virtual Machines. Visit https://urldefense.com/v3/__http://www.datacenterlight.ch__;!!I9LPvj3b!XDmxiY_v3yY5wQI9GfFvshrCIUcqg4vvKg35qvL0fFajgNHTwr3LcySSqHrNmbUvisY$
> >
>
>
> Hi
> On this topic, i recently implemented a check if a key is valid in cpp with the following rather crude code:
>
> bool isValidWgKey(const string& usage, const string& key)
> {
>         /* Wireguard keys are BASE64 encoded */
>         unsigned int _key_length = 44;
>         unsigned int _key_offset = _key_length -1;
>         if (key.length() != _key_length) {
>                 log("Wireguard " + usage + " has wrong length (" + to_string(key.length()) + " instead of 44)!");
>                 return false;
>         }
>         size_t found = key.substr(0,_key_offset).find_first_not_of("abcdefghijklmnopqrstuvwxyz"
>                                                                    "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/");
>         if (found != std::string::npos) {
>                 log("Wireguard " + usage + " contains invalid character '" + key.substr(found, 1) + "'");
>                 return false;
>         }
>         if (key.substr(_key_offset,1) != "=") {
>                 log("Wireguard " + usage + " ends with invalid character '" +
>                     key.substr(found, 1) + "' instead of '='");
>                 return false;
>         }
>         return true;
> }

This code is incorrect because it allows keys that are up to 258bits,
instead of being exactly 256bits. See my post a few messages ago about
different rules for the penultimate character.

https://lists.zx2c4.com/pipermail/wireguard/2020-December/006222.html

Jason

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

* Re: How to verify a wireguard public key?
  2020-12-25 22:16   ` Matthias Urlichs
@ 2020-12-26  8:09     ` Nico Schottelius
  2020-12-26  9:03       ` Matthias Urlichs
  0 siblings, 1 reply; 9+ messages in thread
From: Nico Schottelius @ 2020-12-26  8:09 UTC (permalink / raw)
  To: Matthias Urlichs; +Cc: wireguard


Matthias Urlichs <matthias@urlichs.de> writes:

> On 25.12.20 00:42, Adam Stiles wrote:
>> "How do I validate Curve25519 public keys?"
>
> You send a handshake packet to the owner of the corresponding private
> key and observe whether it accepted it.
>
> The question is, why do you think you need a different/additional way
> of verifying the public key?

That answer is easy: if you add an incorrect key to your wgX.conf, wg
setconf will complain and not apply it. And if you are providing
automated VPNs... well, then this is something you do want to prevent.

Cheers,

Nico

--
Modern, affordable, Swiss Virtual Machines. Visit www.datacenterlight.ch

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

* Re: How to verify a wireguard public key?
  2020-12-26  8:09     ` Nico Schottelius
@ 2020-12-26  9:03       ` Matthias Urlichs
  0 siblings, 0 replies; 9+ messages in thread
From: Matthias Urlichs @ 2020-12-26  9:03 UTC (permalink / raw)
  To: Nico Schottelius; +Cc: wireguard


[-- Attachment #1.1: Type: text/plain, Size: 605 bytes --]

On 26.12.20 09:09, Nico Schottelius wrote:
> That answer is easy: if you add an incorrect key to your wgX.conf, wg
> setconf will complain and not apply it. And if you are providing
> automated VPNs... well, then this is something you do want to prevent.

Umm, sure, but then the question is why an incorrect key would be sent 
through your automated VPN deployment in the first place. And if it 
passes the length check but is still corrupted then that's a worse 
failure mode than "wg setconf" complaining, 'cause at least you'd notice 
the latter immediately.

-- 
-- Matthias Urlichs



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

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

end of thread, other threads:[~2020-12-26  9:04 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-12-24 16:00 How to verify a wireguard public key? Nico Schottelius
2020-12-24 23:30 ` Jason A. Donenfeld
2020-12-24 23:42 ` Adam Stiles
2020-12-25  9:10   ` Nico Schottelius
2020-12-25 23:37     ` Matthias May
2020-12-25 23:47       ` Jason A. Donenfeld
2020-12-25 22:16   ` Matthias Urlichs
2020-12-26  8:09     ` Nico Schottelius
2020-12-26  9:03       ` Matthias Urlichs

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).