sq epan/dissectors/pidl/rcg/rcg.cnf
[wireshark-sm.git] / epan / secrets.c
blob935d184a69509c610899915b8f32e189e53523c6
1 /* secrets.c
2 * Secrets management and processing.
3 * Copyright 2018, Peter Wu <peter@lekensteyn.nl>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
12 #include "config.h"
14 #define WS_LOG_DOMAIN LOG_DOMAIN_EPAN
16 #include "secrets.h"
17 #include <wiretap/wtap.h>
18 #include <wsutil/glib-compat.h>
19 #include <wsutil/wslog.h>
21 #include <string.h>
22 #ifdef HAVE_LIBGNUTLS
23 # include <gnutls/gnutls.h>
24 # include <gnutls/abstract.h>
25 # include <gcrypt.h>
26 # include <wsutil/rsa.h>
27 # include <epan/uat.h>
28 # include <wsutil/report_message.h>
29 # include <wsutil/file_util.h>
30 # include <errno.h>
31 #endif /* HAVE_LIBGNUTLS */
33 #ifdef _WIN32
34 #include <windows.h>
35 #endif
37 /** Maps uint32_t secrets_type -> secrets_block_callback_t. */
38 static GHashTable *secrets_callbacks;
40 #ifdef HAVE_LIBGNUTLS
41 /** Maps public key IDs (cert_key_id_t) -> gnutls_privkey_t. */
42 static GHashTable *rsa_privkeys;
44 typedef struct {
45 char *uri; /**< User-supplied PKCS #11 URI for token or RSA private key file. */
46 char *password; /**< User-supplied PKCS #11 PIN or RSA private key file password. */
47 } rsa_privkey_record_t;
49 static uat_t *rsa_privkeys_uat;
50 static rsa_privkey_record_t *uat_rsa_privkeys;
51 static unsigned uat_num_rsa_privkeys;
53 static void register_rsa_uats(void);
54 #endif /* HAVE_LIBGNUTLS */
56 #ifdef HAVE_GNUTLS_PKCS11
57 /** PINs for PKCS #11 keys in rsa_privkeys. Must be cleared after rsa_privkeys. */
58 static GSList *rsa_privkeys_pkcs11_pins;
60 typedef struct {
61 char *library_path; /**< PKCS #11 library path. */
62 } pkcs11_lib_record_t;
64 static uat_t *pkcs11_libs_uat;
65 static pkcs11_lib_record_t *uat_pkcs11_libs;
66 static unsigned uat_num_pkcs11_libs;
67 #endif /* HAVE_GNUTLS_PKCS11 */
69 void
70 secrets_init(void)
72 secrets_callbacks = g_hash_table_new(g_direct_hash, g_direct_equal);
73 #ifdef HAVE_LIBGNUTLS
74 rsa_privkeys = privkey_hash_table_new();
75 register_rsa_uats();
76 #endif /* HAVE_LIBGNUTLS */
79 void
80 secrets_cleanup(void)
82 g_hash_table_destroy(secrets_callbacks);
83 secrets_callbacks = NULL;
84 #ifdef HAVE_LIBGNUTLS
85 g_hash_table_destroy(rsa_privkeys);
86 rsa_privkeys = NULL;
87 #ifdef HAVE_GNUTLS_PKCS11
88 g_slist_free_full(rsa_privkeys_pkcs11_pins, g_free);
89 rsa_privkeys_pkcs11_pins = NULL;
90 #endif /* HAVE_GNUTLS_PKCS11 */
91 #endif /* HAVE_LIBGNUTLS */
94 void
95 secrets_register_type(uint32_t secrets_type, secrets_block_callback_t cb)
97 g_hash_table_insert(secrets_callbacks, GUINT_TO_POINTER(secrets_type), (void *)cb);
100 void
101 secrets_wtap_callback(uint32_t secrets_type, const void *secrets, unsigned size)
103 secrets_block_callback_t cb = (secrets_block_callback_t)g_hash_table_lookup(
104 secrets_callbacks, GUINT_TO_POINTER(secrets_type));
105 if (cb) {
106 cb(secrets, size);
110 #ifdef HAVE_LIBGNUTLS
111 static unsigned
112 key_id_hash(const void *key)
114 const cert_key_id_t *key_id = (const cert_key_id_t *)key;
115 const uint32_t *dw = (const uint32_t *)key_id->key_id;
117 /* The public key' SHA-1 hash (which maps to a private key) has a uniform
118 * distribution, hence simply xor'ing them should be sufficient. */
119 return dw[0] ^ dw[1] ^ dw[2] ^ dw[3] ^ dw[4];
122 static gboolean
123 key_id_equal(const void *a, const void *b)
125 const cert_key_id_t *key_id_a = (const cert_key_id_t *)a;
126 const cert_key_id_t *key_id_b = (const cert_key_id_t *)b;
128 return !memcmp(key_id_a, key_id_b, sizeof(*key_id_a));
131 GHashTable *
132 privkey_hash_table_new(void)
134 return g_hash_table_new_full(key_id_hash, key_id_equal, g_free, (GDestroyNotify)gnutls_privkey_deinit);
137 static void
138 rsa_privkey_add(const cert_key_id_t *key_id, gnutls_privkey_t pkey)
140 void *ht_key = g_memdup2(key_id->key_id, sizeof(cert_key_id_t));
141 const uint32_t *dw = (const uint32_t *)key_id->key_id;
142 g_hash_table_insert(rsa_privkeys, ht_key, pkey);
143 ws_debug("Adding RSA private, Key ID %08x%08x%08x%08x%08x", g_htonl(dw[0]),
144 g_htonl(dw[1]), g_htonl(dw[2]), g_htonl(dw[3]), g_htonl(dw[4]));
147 #ifdef HAVE_GNUTLS_PKCS11
148 /** Provides a fixed PIN to the caller (or failure if the fixed PIN is NULL). */
149 static int
150 set_pin_callback(void *userdata, int attempt _U_,
151 const char *token_url _U_, const char *token_label _U_,
152 unsigned int flags, char *pin, size_t pin_max)
154 const char *fixed_pin = (const char *)userdata;
155 size_t fixed_pin_len = fixed_pin ? strlen(fixed_pin) : 0;
157 /* Fail if the PIN was not provided, wrong or too long. */
158 if (!fixed_pin || (flags & GNUTLS_PIN_WRONG) || fixed_pin_len >= pin_max) {
159 return GNUTLS_E_PKCS11_PIN_ERROR;
162 memcpy(pin, fixed_pin, fixed_pin_len + 1);
163 return 0;
166 static GSList *
167 get_pkcs11_token_uris(void)
169 GSList *tokens = NULL;
171 for (unsigned i = 0; ; i++) {
172 char *uri = NULL;
173 int flags;
174 int ret = gnutls_pkcs11_token_get_url(i, GNUTLS_PKCS11_URL_GENERIC, &uri);
175 if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
176 break;
179 if (ret < 0) {
180 ws_debug("Failed to query token %u: %s\n", i, gnutls_strerror(ret));
181 break;
184 ret = gnutls_pkcs11_token_get_flags(uri, &flags);
185 if (ret < 0) {
186 ws_debug("Failed to query token flags for %s: %s\n", uri, gnutls_strerror(ret));
187 gnutls_free(uri);
188 continue;
191 // The "Trust module" is useless for decryption, so do not return it.
192 if ((flags & GNUTLS_PKCS11_TOKEN_TRUSTED)) {
193 gnutls_free(uri);
194 continue;
197 tokens = g_slist_prepend(tokens, g_strdup(uri));
198 gnutls_free(uri);
201 tokens = g_slist_reverse(tokens);
203 return tokens;
206 static bool
207 verify_pkcs11_token(const char *token_uri, const char *pin, bool *pin_needed, char **error)
209 gnutls_pkcs11_obj_t *list = NULL;
210 unsigned int nlist = 0;
211 int ret;
213 /* Set PIN via a global callback since import_url can prompt for one. */
214 gnutls_pkcs11_set_pin_function(set_pin_callback, (void *)pin);
216 /* This should ask for a PIN if needed. If no PIN is given,
217 * GNUTLS_E_PKCS11_PIN_ERROR (-303) is returned. */
218 ret = gnutls_pkcs11_obj_list_import_url4(&list, &nlist, token_uri,
219 GNUTLS_PKCS11_OBJ_FLAG_PRIVKEY|GNUTLS_PKCS11_OBJ_FLAG_LOGIN);
220 if (ret == 0) {
221 /* Do not care about the objects, we just wanted to know whether the
222 * token and PIN were valid. */
223 for (unsigned i = 0; i < nlist; i++) {
224 gnutls_pkcs11_obj_deinit(list[i]);
226 gnutls_free(list);
229 /* Forget about the PIN. */
230 gnutls_pkcs11_set_pin_function(NULL, NULL);
232 if (pin_needed) {
233 *pin_needed = ret == GNUTLS_E_PKCS11_PIN_ERROR;
235 if (ret != 0) {
236 if (error) {
237 *error = g_strdup(gnutls_strerror(ret));
239 return false;
241 return true;
245 * Load private RSA keys from a PKCS #11 token. Returns zero on success and a
246 * negative error code on failure.
248 static int
249 pkcs11_load_keys_from_token(const char *token_uri, const char *pin, char **err)
251 gnutls_pkcs11_obj_t *list = NULL;
252 unsigned int nlist = 0;
253 int ret;
254 /* An empty/NULL PIN means that none is necessary. */
255 char *fixed_pin = pin && pin[0] ? g_strdup(pin) : NULL;
256 bool pin_in_use = false;
258 /* Set PIN via a global callback since import_url can prompt for one. */
259 gnutls_pkcs11_set_pin_function(set_pin_callback, fixed_pin);
261 /* This might already result in callback for the PIN. */
262 ret = gnutls_pkcs11_obj_list_import_url4(&list, &nlist, token_uri,
263 GNUTLS_PKCS11_OBJ_FLAG_PRIVKEY|GNUTLS_PKCS11_OBJ_FLAG_LOGIN);
264 if (ret < 0) {
265 *err = ws_strdup_printf("Failed to iterate through objects for %s: %s", token_uri, gnutls_strerror(ret));
266 goto cleanup;
269 for (unsigned j = 0; j < nlist; j++) {
270 char *obj_uri = NULL;
271 gnutls_privkey_t privkey = NULL;
272 gnutls_pubkey_t pubkey = NULL;
273 cert_key_id_t key_id;
274 size_t size;
276 if (gnutls_pkcs11_obj_get_type(list[j]) != GNUTLS_PKCS11_OBJ_PRIVKEY) {
277 /* Should not happen since we requested private keys only. */
278 goto cont;
281 ret = gnutls_pkcs11_obj_export_url(list[j], GNUTLS_PKCS11_URL_GENERIC, &obj_uri);
282 if (ret < 0) {
283 /* Should not happen either if the object is valid. */
284 goto cont;
287 ret = gnutls_privkey_init(&privkey);
288 if (ret < 0) {
289 /* Out of memory? */
290 goto cont;
293 /* Set the PIN to be used during decryption. */
294 gnutls_privkey_set_pin_function(privkey, set_pin_callback, fixed_pin);
296 /* Can prompt for PIN. Can also invoke the token function set by
297 * gnutls_pkcs11_set_token_function (if not set, it will just fail
298 * immediately rather than retrying). */
299 ret = gnutls_privkey_import_url(privkey, obj_uri, 0);
300 if (ret < 0) {
301 /* Bad PIN or some other system error? */
302 ws_debug("Failed to import private key %s: %s", obj_uri, gnutls_strerror(ret));
303 goto cont;
306 if (gnutls_privkey_get_pk_algorithm(privkey, NULL) != GNUTLS_PK_RSA) {
307 ws_debug("Skipping private key %s, not RSA.", obj_uri);
308 goto cont;
311 ret = gnutls_pubkey_init(&pubkey);
312 if (ret < 0) {
313 /* Out of memory? */
314 goto cont;
317 /* This requires GnuTLS 3.4.0 and will fail on older versions. */
318 ret = gnutls_pubkey_import_privkey(pubkey, privkey, 0, 0);
319 if (ret < 0) {
320 ws_debug("Failed to import public key %s: %s", obj_uri, gnutls_strerror(ret));
321 goto cont;
324 size = sizeof(key_id);
325 ret = gnutls_pubkey_get_key_id(pubkey, GNUTLS_KEYID_USE_SHA1, key_id.key_id, &size);
326 if (ret < 0 || size != sizeof(key_id)) {
327 ws_debug("Failed to calculate Key ID for %s: %s", obj_uri, gnutls_strerror(ret));
328 goto cont;
331 /* Remember the private key. */
332 rsa_privkey_add(&key_id, privkey);
333 privkey = NULL;
334 pin_in_use = true;
336 cont:
337 gnutls_privkey_deinit(privkey);
338 gnutls_pubkey_deinit(pubkey);
339 gnutls_free(obj_uri);
340 gnutls_pkcs11_obj_deinit(list[j]);
342 gnutls_free(list);
343 if (pin_in_use) {
344 /* Remember PINs such they can be freed later. */
345 rsa_privkeys_pkcs11_pins = g_slist_prepend(rsa_privkeys_pkcs11_pins, fixed_pin);
346 fixed_pin = NULL;
348 ret = 0;
350 cleanup:
351 /* Forget about the PIN. */
352 gnutls_pkcs11_set_pin_function(NULL, NULL);
353 g_free(fixed_pin);
354 return ret;
357 /** Load all libraries specified in a UAT. */
358 static void
359 uat_pkcs11_libs_load_all(void)
361 int ret;
362 GString *err = NULL;
364 for (unsigned i = 0; i < uat_num_pkcs11_libs; i++) {
365 const pkcs11_lib_record_t *rec = &uat_pkcs11_libs[i];
366 const char *libname = rec->library_path;
367 #ifdef _MSC_VER
368 // Work around a bug in p11-kit < 0.23.16 on Windows
369 HMODULE provider_lib = LoadLibraryA(libname);
370 if (! provider_lib || ! GetProcAddress(provider_lib, "C_GetFunctionList")) {
371 ret = GNUTLS_E_PKCS11_LOAD_ERROR;
372 } else {
373 #endif
374 /* Note: should return success for already loaded libraries. */
375 ret = gnutls_pkcs11_add_provider(libname, NULL);
376 #ifdef _MSC_VER
378 if (provider_lib) {
379 FreeLibrary(provider_lib);
381 #endif
382 if (ret) {
383 if (!err) {
384 err = g_string_new("Error loading PKCS #11 libraries:");
386 g_string_append_printf(err, "\n%s: %s", libname, gnutls_strerror(ret));
389 if (err) {
390 report_failure("%s", err->str);
391 g_string_free(err, TRUE);
395 UAT_FILENAME_CB_DEF(pkcs11_libs_uats, library_path, pkcs11_lib_record_t)
397 static void *
398 uat_pkcs11_lib_copy_str_cb(void *dest, const void *source, size_t len _U_)
400 pkcs11_lib_record_t *d = (pkcs11_lib_record_t *)dest;
401 const pkcs11_lib_record_t *s = (const pkcs11_lib_record_t *)source;
402 d->library_path = g_strdup(s->library_path);
403 return dest;
406 static void
407 uat_pkcs11_lib_free_str_cb(void *record)
409 pkcs11_lib_record_t *rec = (pkcs11_lib_record_t *)record;
410 g_free(rec->library_path);
412 #endif /* HAVE_GNUTLS_PKCS11 */
414 UAT_FILENAME_CB_DEF(rsa_privkeys_uats, uri, rsa_privkey_record_t)
415 UAT_CSTRING_CB_DEF(rsa_privkeys_uats, password, rsa_privkey_record_t)
417 static void *
418 uat_rsa_privkey_copy_str_cb(void *dest, const void *source, size_t len _U_)
420 rsa_privkey_record_t *d = (rsa_privkey_record_t *)dest;
421 const rsa_privkey_record_t *s = (const rsa_privkey_record_t *)source;
422 d->uri = g_strdup(s->uri);
423 d->password = g_strdup(s->password);
424 return dest;
427 static void
428 uat_rsa_privkey_free_str_cb(void *record)
430 rsa_privkey_record_t *rec = (rsa_privkey_record_t *)record;
431 g_free(rec->uri);
432 g_free(rec->password);
435 static void
436 load_rsa_keyfile(const char *filename, const char *password, bool save_key, char **err)
438 gnutls_x509_privkey_t x509_priv_key;
439 gnutls_privkey_t privkey = NULL;
440 char *errmsg = NULL;
441 int ret;
442 cert_key_id_t key_id;
443 size_t size = sizeof(key_id);
445 FILE *fp = ws_fopen(filename, "rb");
446 if (!fp) {
447 *err = ws_strdup_printf("Error loading RSA key file %s: %s", filename, g_strerror(errno));
448 return;
451 if (!password || !password[0]) {
452 x509_priv_key = rsa_load_pem_key(fp, &errmsg);
453 } else {
454 /* Assume encrypted PKCS #12 container. */
455 x509_priv_key = rsa_load_pkcs12(fp, password, &errmsg);
457 fclose(fp);
458 if (!x509_priv_key) {
459 *err = ws_strdup_printf("Error loading RSA key file %s: %s", filename, errmsg);
460 g_free(errmsg);
461 return;
464 gnutls_privkey_init(&privkey);
465 ret = gnutls_privkey_import_x509(privkey, x509_priv_key,
466 GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE|GNUTLS_PRIVKEY_IMPORT_COPY);
467 if (ret < 0) {
468 *err = ws_strdup_printf("Error importing private key %s: %s", filename, gnutls_strerror(ret));
469 goto end;
471 ret = gnutls_x509_privkey_get_key_id(x509_priv_key, GNUTLS_KEYID_USE_SHA1, key_id.key_id, &size);
472 if (ret < 0 || size != sizeof(key_id)) {
473 *err = ws_strdup_printf("Error calculating Key ID for %s: %s", filename, gnutls_strerror(ret));
474 goto end;
477 /* Remember the private key. */
478 if (save_key) {
479 rsa_privkey_add(&key_id, privkey);
480 privkey = NULL;
483 end:
484 gnutls_x509_privkey_deinit(x509_priv_key);
485 gnutls_privkey_deinit(privkey);
488 static void
489 uat_rsa_privkeys_post_update(void)
491 /* Clear previous keys. */
492 g_hash_table_remove_all(rsa_privkeys);
493 #ifdef HAVE_GNUTLS_PKCS11
494 g_slist_free_full(rsa_privkeys_pkcs11_pins, g_free);
495 rsa_privkeys_pkcs11_pins = NULL;
496 #endif /* HAVE_GNUTLS_PKCS11 */
497 GString *errors = NULL;
499 for (unsigned i = 0; i < uat_num_rsa_privkeys; i++) {
500 const rsa_privkey_record_t *rec = &uat_rsa_privkeys[i];
501 const char *token_uri = rec->uri;
502 char *err = NULL;
504 if (g_str_has_prefix(token_uri, "pkcs11:")) {
505 #ifdef HAVE_GNUTLS_PKCS11
506 pkcs11_load_keys_from_token(token_uri, rec->password, &err);
507 #endif /* HAVE_GNUTLS_PKCS11 */
508 } else {
509 load_rsa_keyfile(token_uri, rec->password, true, &err);
511 if (err) {
512 if (!errors) {
513 errors = g_string_new("Error processing rsa_privkeys:");
515 g_string_append_c(errors, '\n');
516 g_string_append(errors, err);
517 g_free(err);
520 if (errors) {
521 report_failure("%s", errors->str);
522 g_string_free(errors, TRUE);
526 GSList *
527 secrets_get_available_keys(void)
529 GSList *keys = NULL;
530 #ifdef HAVE_GNUTLS_PKCS11
531 keys = g_slist_concat(keys, get_pkcs11_token_uris());
532 #endif
533 return keys;
536 bool
537 secrets_verify_key(const char *uri, const char *password, bool *need_password, char **error)
539 if (need_password) {
540 *need_password = false;
542 if (error) {
543 *error = NULL;
546 if (g_str_has_prefix(uri, "pkcs11:")) {
547 #ifdef HAVE_GNUTLS_PKCS11
548 return verify_pkcs11_token(uri, password, need_password, error);
549 #else
550 if (error) {
551 *error = g_strdup("PKCS #11 support is not available in this build");
553 return false;
554 #endif
555 } else if (g_file_test(uri, G_FILE_TEST_IS_REGULAR)) {
556 char *err = NULL;
557 load_rsa_keyfile(uri, password, false, &err);
558 if (need_password) {
559 // Assume that failure to load the key is due to password errors.
560 // This might not be correct, but fixing this needs more changes.
561 *need_password = err != NULL;
563 if (err) {
564 if (error) {
565 *error = err;
566 } else {
567 g_free(err);
569 return false;
571 return true;
572 } else {
573 if (error) {
574 *error = g_strdup("Unsupported key URI or path");
576 return false;
581 * Register the UAT definitions such that settings can be loaded from file.
582 * Note: relies on uat_load_all to invoke the post_update_cb in order of
583 * registration below such that libraries are loaded *before* keys are read.
585 static void
586 register_rsa_uats(void)
588 #ifdef HAVE_GNUTLS_PKCS11
589 static uat_field_t uat_pkcs11_libs_fields[] = {
590 UAT_FLD_FILENAME_OTHER(pkcs11_libs_uats, library_path, "Library Path", NULL, "PKCS #11 provider library file"),
591 UAT_END_FIELDS
593 pkcs11_libs_uat = uat_new("PKCS #11 Provider Libraries",
594 sizeof(pkcs11_lib_record_t),
595 "pkcs11_libs", /* filename */
596 false, /* from_profile */
597 &uat_pkcs11_libs, /* data_ptr */
598 &uat_num_pkcs11_libs, /* numitems_ptr */
599 0, /* does not directly affect dissection */
600 NULL, /* Help section (currently a wiki page) */
601 uat_pkcs11_lib_copy_str_cb, /* copy_cb */
602 NULL, /* update_cb */
603 uat_pkcs11_lib_free_str_cb, /* free_cb */
604 uat_pkcs11_libs_load_all, /* post_update_cb */
605 NULL, /* reset_cb */
606 uat_pkcs11_libs_fields);
607 #endif /* HAVE_GNUTLS_PKCS11 */
609 static uat_field_t uat_rsa_privkeys_fields[] = {
610 UAT_FLD_FILENAME_OTHER(rsa_privkeys_uats, uri, "Keyfile or Token URI", NULL, "RSA Key File or PKCS #11 URI for token"),
611 UAT_FLD_FILENAME_OTHER(rsa_privkeys_uats, password, "Password", NULL, "RSA Key File password or PKCS #11 Token PIN"),
612 UAT_END_FIELDS
614 rsa_privkeys_uat = uat_new("RSA Private Keys",
615 sizeof(rsa_privkey_record_t),
616 "rsa_keys", /* filename */
617 false, /* from_profile */
618 &uat_rsa_privkeys, /* data_ptr */
619 &uat_num_rsa_privkeys, /* numitems_ptr */
620 0, /* does not directly affect dissection */
621 NULL, /* Help section (currently a wiki page) */
622 uat_rsa_privkey_copy_str_cb, /* copy_cb */
623 NULL, /* update_cb */
624 uat_rsa_privkey_free_str_cb, /* free_cb */
625 uat_rsa_privkeys_post_update, /* post_update_cb */
626 NULL, /* reset_cb */
627 uat_rsa_privkeys_fields);
631 secrets_rsa_decrypt(const cert_key_id_t *key_id, const uint8_t *encr, int encr_len, uint8_t **out, int *out_len)
633 bool ret;
634 gnutls_datum_t ciphertext = { (unsigned char *)encr, encr_len };
635 gnutls_datum_t plain = { 0 };
637 gnutls_privkey_t pkey = (gnutls_privkey_t)g_hash_table_lookup(rsa_privkeys, key_id->key_id);
638 if (!pkey) {
639 return GNUTLS_E_NO_CERTIFICATE_FOUND;
642 ret = gnutls_privkey_decrypt_data(pkey, 0, &ciphertext, &plain);
643 if (ret == 0) {
644 *out = (uint8_t *)g_memdup2(plain.data, plain.size);
645 *out_len = plain.size;
646 gnutls_free(plain.data);
649 return ret;
651 #endif /* HAVE_LIBGNUTLS */
654 * Editor modelines - https://www.wireshark.org/tools/modelines.html
656 * Local variables:
657 * c-basic-offset: 4
658 * tab-width: 8
659 * indent-tabs-mode: nil
660 * End:
662 * vi: set shiftwidth=4 tabstop=8 expandtab:
663 * :indentSize=4:tabSize=8:noTabs=true: