1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-10 09:58:01 +00:00
Commit Graph

152 Commits

Author SHA1 Message Date
Simon Tatham
89da2ddf56 Giant const-correctness patch of doom!
Having found a lot of unfixed constness issues in recent development,
I thought perhaps it was time to get proactive, so I compiled the
whole codebase with -Wwrite-strings. That turned up a huge load of
const problems, which I've fixed in this commit: the Unix build now
goes cleanly through with -Wwrite-strings, and the Windows build is as
close as I could get it (there are some lingering issues due to
occasional Windows API functions like AcquireCredentialsHandle not
having the right constness).

Notable fallout beyond the purely mechanical changing of types:
 - the stuff saved by cmdline_save_param() is now explicitly
   dupstr()ed, and freed in cmdline_run_saved.
 - I couldn't make both string arguments to cmdline_process_param()
   const, because it intentionally writes to one of them in the case
   where it's the argument to -pw (in the vain hope of being at least
   slightly friendly to 'ps'), so elsewhere I had to temporarily
   dupstr() something for the sake of passing it to that function
 - I had to invent a silly parallel version of const_cmp() so I could
   pass const string literals in to lookup functions.
 - stripslashes() in pscp.c and psftp.c has the annoying strchr nature
2015-05-15 12:47:44 +01:00
Simon Tatham
7db526c730 Clean up elliptic curve selection and naming.
The ec_name_to_curve and ec_curve_to_name functions shouldn't really
have had to exist at all: whenever any part of the PuTTY codebase
starts using sshecc.c, it's starting from an ssh_signkey or ssh_kex
pointer already found by some other means. So if we make sure not to
lose that pointer, we should never need to do any string-based lookups
to find the curve we want, and conversely, when we need to know the
name of our curve or our algorithm, we should be able to look it up as
a straightforward const char * starting from the algorithm pointer.

This commit cleans things up so that that is indeed what happens. The
ssh_signkey and ssh_kex structures defined in sshecc.c now have
'extra' fields containing pointers to all the necessary stuff;
ec_name_to_curve and ec_curve_to_name have been completely removed;
struct ec_curve has a string field giving the curve's name (but only
for those curves which _have_ a name exposed in the wire protocol,
i.e. the three NIST ones); struct ec_key keeps a pointer to the
ssh_signkey it started from, and uses that to remember the algorithm
name rather than reconstructing it from the curve. And I think I've
got rid of all the ad-hockery scattered around the code that switches
on curve->fieldBits or manually constructs curve names using stuff
like sprintf("nistp%d"); the only remaining switch on fieldBits
(necessary because that's the UI for choosing a curve in PuTTYgen) is
at least centralised into one place in sshecc.c.

One user-visible result is that the format of ed25519 host keys in the
registry has changed: there's now no curve name prefix on them,
because I think it's not really right to make up a name to use. So any
early adopters who've been using snapshot PuTTY in the last week will
be inconvenienced; sorry about that.
2015-05-15 10:15:35 +01:00
Simon Tatham
1293334ebf Provide an 'extra' pointer in ssh_signkey and ssh_kex.
This gives families of public key and kex functions (by which I mean
those sharing a set of methods) a place to store parameters that allow
the methods to vary depending on which exact algorithm is in use.

The ssh_kex structure already had a set of parameters specific to
Diffie-Hellman key exchange; I've moved those into sshdh.c and made
them part of the 'extra' structure for that family only, so that
unrelated kex methods don't have to faff about saying NULL,NULL,0,0.
(This required me to write an extra accessor function for ssh.c to ask
whether a DH method was group-exchange style or fixed-group style, but
that doesn't seem too silly.)
2015-05-15 10:12:08 +01:00
Simon Tatham
870ad6ab07 Pass the ssh_signkey structure itself to public key methods.
Not all of them, but the ones that don't get a 'void *key' parameter.
This means I can share methods between multiple ssh_signkey
structures, and still give those methods an easy way to find out which
public key method they're dealing with, by loading parameters from a
larger structure in which the ssh_signkey is the first element.

(In OO terms, I'm arranging that all static methods of my public key
classes get a pointer to the class vtable, to make up for not having a
pointer to the class instance.)

I haven't actually done anything with the new facility in this commit,
but it will shortly allow me to clean up the constant lookups by curve
name in the ECDSA code.
2015-05-15 10:12:07 +01:00
Simon Tatham
a5fc95b715 Const-correctness of name fields in struct ssh_*.
All the name strings in ssh_cipher, ssh_mac, ssh_hash, ssh_signkey
point to compile-time string literals, hence should obviously be const
char *.

Most of these const-correctness patches are just a mechanical job of
adding a 'const' in the one place you need it right now, and then
chasing the implications through the code adding further consts until
it compiles. But this one has actually shown up a bug: the 'algorithm'
output parameter in ssh2_userkey_loadpub was sometimes returning a
pointer to a string literal, and sometimes a pointer to dynamically
allocated memory, so callers were forced to either sometimes leak
memory or sometimes free a bad thing. Now it's consistently
dynamically allocated, and should be freed everywhere too.
2015-05-15 10:12:06 +01:00
Simon Tatham
79fe96155a Const-correctness in struct ssh_hash.
The 'bytes' function should take a const void * as input, not a void *.
2015-05-15 10:12:05 +01:00
Simon Tatham
8682246d33 Centralise SSH-2 key fingerprinting into sshpubk.c.
There were ad-hoc functions for fingerprinting a bare key blob in both
cmdgen.c and pageant.c, not quite doing the same thing. Also, every
SSH-2 public key algorithm in the code base included a dedicated
fingerprint() method, which is completely pointless since SSH-2 key
fingerprints are computed in an algorithm-independent way (just hash
the standard-format public key blob), so each of those methods was
just duplicating the work of the public_blob() method with a less
general output mechanism.

Now sshpubk.c centrally provides an ssh2_fingerprint_blob() function
that does all the real work, plus an ssh2_fingerprint() function that
wraps it and deals with calling public_blob() to get something to
fingerprint. And the fingerprint() method has been completely removed
from ssh_signkey and all its implementations, and good riddance.
2015-05-12 14:56:38 +01:00
Simon Tatham
eef0235a0f Centralise public-key output code into sshpubk.c.
There was a fair amount of duplication between Windows and Unix
PuTTYgen, and some confusion over writing things to FILE * and
formatting them internally into strings. I think all the public-key
output code now lives in sshpubk.c, and there's only one copy of the
code to generate each format.
2015-05-12 14:56:38 +01:00
Simon Tatham
f274b56a57 Const-correctness in the base64 functions. 2015-05-12 14:56:38 +01:00
Simon Tatham
3935cc3af1 Support loading public-key-only files in Unix PuTTYgen.
The rsakey_pubblob() and ssh2_userkey_loadpub() functions, which
expected to be given a private key file and load only the unencrypted
public half, now also cope with any of the public-only formats I know
about (SSH-1 only has one, whereas SSH-2 has the RFC 4716 format and
OpenSSH's one-line format) and return an appropriate public key blob
from each of those too.

cmdgen now supports this functionality, by permitting public key files
to be loaded and used by any operation that doesn't need the private
key: so you can convert back and forth between the SSH-2 public
formats, or list the file's fingerprint.
2015-05-12 12:19:57 +01:00
Simon Tatham
9971da40c3 Utility function: bignum_from_decimal. 2015-05-12 12:14:45 +01:00
Simon Tatham
8c4ce6d8c6 Const-correctness in key-loading functions.
The passphrase parameter should be a const char *.
2015-05-11 15:49:09 +01:00
Simon Tatham
90af5bed04 Sort out the mess with OpenSSH key file formats.
When I implemented reading and writing of the new format a couple of
weeks ago, I kept them strictly separate in the UI, so you have to ask
for the format you want when exporting. But in fact this is silly,
because not every key type can be saved in both formats, and OpenSSH
itself has the policy of using the old format for key types it can
handle, unless specifically asked to use the new one.

So I've now arranged that the key file format enum has three values
for OpenSSH: PEM, NEW and AUTO. Files being loaded are identified as
either PEM or NEW, which describe the two physical file formats. But
exporting UIs present either AUTO or NEW, where AUTO is the virtual
format meaning 'save in the old format if possible, otherwise the new
one'.
2015-05-10 13:11:43 +01:00
Chris Staite
76a4b576e5 Support public keys using the "ssh-ed25519" method.
This introduces a third system of elliptic curve representation and
arithmetic, namely Edwards form.
2015-05-09 15:14:35 +01:00
Chris Staite
541abf9258 Support ECDH key exchange using the 'curve25519' curve.
This is the kex protocol id "curve25519-sha256@libssh.org", so called
because it's over the prime field of order 2^255 - 19.

Arithmetic in this curve is done using the Montgomery representation,
rather than the Weierstrass representation. So 'struct ec_curve' has
grown a discriminant field and a union of subtypes.
2015-05-09 15:07:14 +01:00
Chris Staite
7d6bf4a6ca Provide a little-endian version of bignum_from_bytes(). 2015-05-09 15:02:50 +01:00
Simon Tatham
1f4dc6faa7 Remove the list of key algorithms in pageant.c.
The only reason those couldn't be replaced with a call to the
centralised find_pubkey_alg is because that function takes a zero-
terminated string and instead we had a (length,pointer) string. Easily
fixed; there's now a find_pubkey_alg_len(), and we call that.

This also fixes a string-matching bug in which the sense of memcmp was
reversed by mistake for ECDSA keys!
2015-05-07 19:59:07 +01:00
Simon Tatham
a53e4e2cb6 Const-correctness in x11_setup_display.
The 'display' parameter should have been a const char *. No call sites
affected.
2015-05-05 20:16:18 +01:00
Simon Tatham
bcfcb169ef Const-correctness in public-key functions.
Several of the functions in ssh2_signkey, and one or two SSH-1 key
functions too, were still taking assorted non-const buffer parameters
that had never been properly constified. Sort them all out.
2015-05-05 20:16:17 +01:00
Simon Tatham
6b30316922 Use find_pubkey_alg in openssh_read_new().
This is better than listing all the algorithm names in yet another
place that will then need updating when a new key format is added.
However, that also means I need to find a new place to put the
'npieces' value I was previously setting up differently per key type;
since that's a fundamental property of the key format, I've moved it
to a constant field in the ssh_signkey structure, and filled that
field in for all the existing key types with the values from the
replaced code in openssh_read_new().
2015-05-02 15:11:41 +01:00
Simon Tatham
79bbf37c9e Separate key-type enum values for old and new OpenSSH keys.
It's all very well for these two different formats to share a type
code as long as we're only loading them and not saving, but as soon as
we need to save one or the other, we'll need different type codes
after all.

This commit introduces the openssh_new_write() function, but for the
moment, it always returns failure.
2015-04-28 19:48:43 +01:00
Simon Tatham
d637528181 Implementation of OpenSSH's bcrypt.
This isn't the same as the standard bcrypt; it's OpenSSH's
modification that they use for their new-style key format.

In order to implement this, I've broken up blowfish_setkey() into two
subfunctions, and provided one of them with an extra optional salt
parameter, which is NULL in ordinary Blowfish but used by bcrypt.
Also, I've exposed some of sshblowf.c's internal machinery for the new
sshbcrypt.c to use.
2015-04-27 20:48:29 +01:00
Simon Tatham
a8658edb17 Paste error in comment.
SSH2_MSG_KEX_DH_GEX_REQUEST_OLD and SSH2_MSG_KEX_DH_GEX_REQUEST were
correctly _defined_ as different numbers, but the comments to the
right containing the hex representations of their values were
accidentally the same.
2015-04-27 06:54:21 +01:00
Simon Tatham
183a9ee98b Support OpenSSH encrypt-then-MAC protocol extension.
This causes the initial length field of the SSH-2 binary packet to be
unencrypted (with the knock-on effect that now the packet length not
including MAC must be congruent to 4 rather than 0 mod the cipher
block size), and then the MAC is applied over the unencrypted length
field and encrypted ciphertext (prefixed by the sequence number as
usual). At the cost of exposing some information about the packet
lengths to an attacker (but rarely anything they couldn't have
inferred from the TCP headers anyway), this closes down any
possibility of a MITM using the client as a decryption oracle, unless
they can _first_ fake a correct MAC.

ETM mode is enabled by means of selecting a different MAC identifier,
all the current ones of which are constructed by appending
"-etm@openssh.com" to the name of a MAC that already existed.

We currently prefer the original SSH-2 binary packet protocol (i.e. we
list all the ETM-mode MACs last in our KEXINIT), on the grounds that
it's better tested and more analysed, so at the moment the new mode is
only activated if a server refuses to speak anything else.
2015-04-26 23:30:32 +01:00
Simon Tatham
62a1bce7cb Support RFC 4419.
PuTTY now uses the updated version of Diffie-Hellman group exchange,
except for a few old OpenSSH versions which Darren Tucker reports only
support the old version.

FIXME: this needs further work because the Bugs config panel has now
overflowed.
2015-04-25 10:54:18 +01:00
Simon Tatham
808e414130 Merge branch 'pre-0.64' 2015-02-28 07:57:58 +00:00
Simon Tatham
174476813f Enforce acceptable range for Diffie-Hellman server value.
Florent Daigniere of Matta points out that RFC 4253 actually
_requires_ us to refuse to accept out-of-range values, though it isn't
completely clear to me why this should be a MUST on the receiving end.

Matta considers this to be a security vulnerability, on the grounds
that if a server should accidentally send an obviously useless value
such as 1 then we will fail to reject it and agree a key that an
eavesdropper could also figure out. Their id for this vulnerability is
MATTA-2015-002.
2015-02-28 07:57:35 +00:00
Simon Tatham
bb09a3936e Fix some rogue // comments.
That's what you get for changing things at the last minute...
2014-11-03 18:41:56 +00:00
Chris Staite
2bf8688355 Elliptic-curve cryptography support.
This provides support for ECDSA public keys, for both hosts and users,
and also ECDH key exchange. Supported curves are currently just the
three NIST curves required by RFC 5656.
2014-11-02 18:16:54 +00:00
Chris Staite
7d1c30cd50 Some extra bignum functions: modsub, lshift, random_in_range. 2014-11-02 18:16:54 +00:00
Chris Staite
66970c4258 Provide SHA-384 and SHA-512 as hashes usable in SSH KEX.
SHA-384 was previously not implemented at all, but is a trivial
adjustment to SHA-512 (different starting constants, and truncate the
output hash). Both are now exposed as 'ssh_hash' structures so that
key exchange methods can ask for them.
2014-11-02 18:16:54 +00:00
Simon Tatham
a2b64dca47 Factor out the DSA deterministic k generator.
It's now a separate function, which you call with an identifying
string to be hashed into the generation of x. The idea is that other
DSA-like signature algorithms can reuse the same function, with a
different id string.

As a minor refinement, we now also never return k=1.
2014-11-02 18:16:54 +00:00
Simon Tatham
bb78583ad2 Implement connection sharing between instances of PuTTY.
The basic strategy is described at the top of the new source file
sshshare.c. In very brief: an 'upstream' PuTTY opens a Unix-domain
socket or Windows named pipe, and listens for connections from other
PuTTYs wanting to run sessions on the same server. The protocol spoken
down that socket/pipe is essentially the bare ssh-connection protocol,
using a trivial binary packet protocol with no encryption, and the
upstream has to do some fiddly transformations that I've been
referring to as 'channel-number NAT' to avoid resource clashes between
the sessions it's managing.

This is quite different from OpenSSH's approach of using the Unix-
domain socket as a means of passing file descriptors around; the main
reason for that is that fd-passing is Unix-specific but this system
has to work on Windows too. However, there are additional advantages,
such as making it easy for each downstream PuTTY to run its own
independent set of port and X11 forwardings (though the method for
making the latter work is quite painful).

Sharing is off by default, but configuration is intended to be very
easy in the normal case - just tick one box in the SSH config panel
and everything else happens automatically.

[originally from svn r10083]
2013-11-17 14:05:41 +00:00
Simon Tatham
e5a3e28eec Get rid of the error-return mechanism from x11_init.
Now that it doesn't actually make a network connection because that's
deferred until after the X authorisation exchange, there's no point in
having it return an error message and write the real output through a
pointer argument. Instead, we can just have it return xconn directly
and simplify the call sites.

[originally from svn r10081]
2013-11-17 14:05:23 +00:00
Simon Tatham
94e8f97d3f Refactor the construction of X protocol greetings.
I've moved it out into a separate function, preparatory to calling it
from somewhere completely different in changes to come. Also, we now
retain the peer address sent from the SSH server in string form,
rather than translating it immediately into a numeric IP address, so
that its original form will be available later to pass on elsewhere.

[originally from svn r10080]
2013-11-17 14:05:17 +00:00
Simon Tatham
cc4fbe33bc Prepare to have multiple X11 auth cookies valid at once.
Rather than the top-level component of X forwarding being an
X11Display structure which owns some auth data, it's now a collection
of X11FakeAuth structures, each of which owns a display. The idea is
that when we receive an X connection, we wait to see which of our
available auth cookies it matches, and then connect to whatever X
display that auth cookie identifies. At present the tree will only
have one thing in it; this is all groundwork for later changes.

[originally from svn r10079]
2013-11-17 14:05:10 +00:00
Simon Tatham
01085358e4 Decouple X socket opening from x11_init().
Now we wait to open the socket to the X server until we've seen the
authorisation data. This prepares us to do something else with the
channel if we see different auth data, which will come up in
connection sharing.

[originally from svn r10078]
2013-11-17 14:05:04 +00:00
Simon Tatham
961503e449 Add missing 'const' in the des_*_xdmauth functions.
[originally from svn r10077]
2013-11-17 14:05:01 +00:00
Simon Tatham
9cbcd17651 Refactor ssh.c's APIs to x11fwd.c and portfwd.c.
The most important change is that, where previously ssh.c held the
Socket pointer for each X11 and port forwarding, and the support
modules would find their internal state structure by calling
sk_get_private_ptr on that Socket, it's now the other way round. ssh.c
now directly holds the internal state structure pointer for each
forwarding, and when the support module needs the Socket it looks it
up in a field of that. This will come in handy when I decouple socket
creation from logical forwarding setup, so that X forwardings can
delay actually opening a connection to an X server until they look at
the authentication data and see which server it has to be.

However, while I'm here, I've also taken the opportunity to clean up a
few other points, notably error message handling, and also the fact
that the same kind of state structure was used for both
connection-type and listening-type port forwardings. Now there are
separate PortForwarding and PortListener structure types, which seems
far more sensible.

[originally from svn r10074]
2013-11-17 14:04:41 +00:00
Simon Tatham
0bc76b8252 Move SSH protocol enumerations out into ssh.h.
This permits packet type codes and other magic numbers to be accessed
from modules other than ssh.c.

[originally from svn r10064]
2013-11-17 14:03:29 +00:00
Simon Tatham
8e7b0d0e4b Pass an error message through to sshfwd_unclean_close.
We have access to one at every call site, so there's really no reason
not to send it through to ssh.c to be logged.

[originally from svn r10038]
2013-09-08 07:14:56 +00:00
Simon Tatham
808df44e54 Add an assortment of missing consts I've just noticed.
[originally from svn r9972]
2013-07-27 18:35:48 +00:00
Ben Harris
8f3cc4a9bf Add support for HMAC-SHA-256 as an SSH-2 MAC algorithm ("hmac-sha2-256")
as specified in RFC 6668.  This is not so much because I think it's 
necessary, but because scrypt uses HMAC-SHA-256 and once we've got it we 
may as well use it.

Code very closely derived from the HMAC-SHA-1 code.

Tested against OpenSSH 5.9p1 Debian-5ubuntu1.

[originally from svn r9759]
2013-02-20 23:30:55 +00:00
Simon Tatham
9604c2b367 Generate keys more carefully, so that when the user asks for an n-bit
key they always get an n-bit number instead of n-1. The latter was
perfectly harmless but kept confusing users.

[originally from svn r9421]
2012-03-04 00:24:49 +00:00
Simon Tatham
49927f6c4d Introduce a function sshfwd_unclean_close(), supplied by ssh.c to
subsidiary network modules like portfwd.c. To be called when the
subsidiary module experiences a socket error: it sends an emergency
CHANNEL_CLOSE (not just outgoing CHANNEL_EOF), and immediately deletes
the local side of the channel. (I've invented a new channel type in
ssh.c called CHAN_ZOMBIE, for channels whose original local side has
already been thrown away and they're just hanging around waiting to
receive the acknowledging CHANNEL_CLOSE.)

As a result of this and the last few commits, I can now run a port
forwarding session in which a local socket error occurs on a forwarded
port, and PuTTY now handles it apparently correctly, closing both the
SSH channel and the local socket and then actually recognising that
it's OK to terminate when all _other_ channels have been closed.
Previously the channel corresponding to the duff connection would
linger around (because of net_pending_errors never being called), and
keep being selected on (hence chewing CPU), and inhibit program
termination at the end of the session (because not all channels were
closed).

[originally from svn r9364]
2011-12-08 19:15:58 +00:00
Simon Tatham
947962e0b9 Revamp of EOF handling in all network connections, pipes and other
data channels. Should comprehensively fix 'half-closed', in principle,
though it's a big and complicated change and so there's a good chance
I've made at least one mistake somewhere.

All connections should now be rigorous about propagating end-of-file
(or end-of-data-stream, or socket shutdown, or whatever) independently
in both directions, except in frontends with no mechanism for sending
explicit EOF (e.g. interactive terminal windows) or backends which are
basically always used for interactive sessions so it's unlikely that
an application would be depending on independent EOF (telnet, rlogin).

EOF should now never accidentally be sent while there's still buffered
data to go out before it. (May help fix 'portfwd-corrupt', and also I
noticed recently that the ssh main session channel can accidentally
have MSG_EOF sent before the output bufchain is clear, leading to
embarrassment when it subsequently does send the output).

[originally from svn r9279]
2011-09-13 11:44:03 +00:00
Simon Tatham
a1f3b7a358 Post-release destabilisation! Completely remove the struct type
'Config' in putty.h, which stores all PuTTY's settings and includes an
arbitrary length limit on every single one of those settings which is
stored in string form. In place of it is 'Conf', an opaque data type
everywhere outside the new file conf.c, which stores a list of (key,
value) pairs in which every key contains an integer identifying a
configuration setting, and for some of those integers the key also
contains extra parts (so that, for instance, CONF_environmt is a
string-to-string mapping). Everywhere that a Config was previously
used, a Conf is now; everywhere there was a Config structure copy,
conf_copy() is called; every lookup, adjustment, load and save
operation on a Config has been rewritten; and there's a mechanism for
serialising a Conf into a binary blob and back for use with Duplicate
Session.

User-visible effects of this change _should_ be minimal, though I
don't doubt I've introduced one or two bugs here and there which will
eventually be found. The _intended_ visible effects of this change are
that all arbitrary limits on configuration strings and lists (e.g.
limit on number of port forwardings) should now disappear; that list
boxes in the configuration will now be displayed in a sorted order
rather than the arbitrary order in which they were added to the list
(since the underlying data structure is now a sorted tree234 rather
than an ad-hoc comma-separated string); and one more specific change,
which is that local and dynamic port forwardings on the same port
number are now mutually exclusive in the configuration (putting 'D' in
the key rather than the value was a mistake in the first place).

One other reorganisation as a result of this is that I've moved all
the dialog.c standard handlers (dlg_stdeditbox_handler and friends)
out into config.c, because I can't really justify calling them generic
any more. When they took a pointer to an arbitrary structure type and
the offset of a field within that structure, they were independent of
whether that structure was a Config or something completely different,
but now they really do expect to talk to a Conf, which can _only_ be
used for PuTTY configuration, so I've renamed them all things like
conf_editbox_handler and moved them out of the nominally independent
dialog-box management module into the PuTTY-specific config.c.

[originally from svn r9214]
2011-07-14 18:52:21 +00:00
Jacob Nevins
74c5f7dda9 Implement zlib@openssh.com, using the rekey-after-userauth method suggested in
the wishlist entry.

[originally from svn r9120]
[this svn revision also touched putty-website,putty-wishlist]
2011-03-04 22:34:47 +00:00
Simon Tatham
fa85085640 Implement the Chinese Remainder Theorem optimisation for speeding up
RSA private key operations by making use of the fact that we know the
factors of the modulus.

[originally from svn r9095]
2011-02-18 08:25:39 +00:00
Simon Tatham
99fffd6ed3 Patch from Alejandro Sedeno, somewhat modified by me, which
reorganises the GSSAPI support so that it handles alternative
implementations of the GSS-API. In particular, this means PuTTY can
now talk to MIT Kerberos for Windows instead of being limited to
SSPI. I don't know for sure whether further tweaking will be needed
(to the UI, most likely, or to automatic selection of credentials),
but testing reports suggest it's now at least worth committing to
trunk to get it more widely tested.

[originally from svn r8952]
2010-05-19 18:22:17 +00:00