diff --git a/crypto/openssh-certs.c b/crypto/openssh-certs.c index 3af2e3b5..78be4f15 100644 --- a/crypto/openssh-certs.c +++ b/crypto/openssh-certs.c @@ -209,7 +209,7 @@ static key_components *opensshcert_components(ssh_key *key); static ssh_key *opensshcert_base_key(ssh_key *key); static bool opensshcert_check_cert( ssh_key *key, bool host, ptrlen principal, uint64_t time, - BinarySink *error); + const ca_options *opts, BinarySink *error); static int opensshcert_pubkey_bits(const ssh_keyalg *self, ptrlen blob); static unsigned opensshcert_supported_flags(const ssh_keyalg *self); static const char *opensshcert_alternate_ssh_id(const ssh_keyalg *self, @@ -716,7 +716,7 @@ static char *opensshcert_invalid(ssh_key *key, unsigned flags) static bool opensshcert_check_cert( ssh_key *key, bool host, ptrlen principal, uint64_t time, - BinarySink *error) + const ca_options *opts, BinarySink *error) { opensshcert_key *ck = container_of(key, opensshcert_key, sshk); bool result = false; @@ -725,9 +725,6 @@ static bool opensshcert_check_cert( BinarySource src[1]; ptrlen signature = ptrlen_from_strbuf(ck->signature); - /* FIXME: here we should check which signature algorithm is - * actually in use, because that might be a reason to reject the - * certificate (e.g. ssh-rsa when we wanted rsa-sha2-*) */ ca_key = opensshcert_ca_pub_key(ck, signature, NULL); if (!ca_key) { @@ -735,6 +732,18 @@ static bool opensshcert_check_cert( goto out; } + /* Check which signature algorithm is actually in use, because + * that might be a reason to reject the certificate (e.g. ssh-rsa + * when we wanted rsa-sha2-*). */ + const ssh_keyalg *sig_alg = ssh_key_alg(ca_key); + if ((sig_alg == &ssh_rsa && !opts->permit_rsa_sha1) || + (sig_alg == &ssh_rsa_sha256 && !opts->permit_rsa_sha256) || + (sig_alg == &ssh_rsa_sha512 && !opts->permit_rsa_sha512)) { + put_fmt(error, "Certificate signature uses '%s' signature type " + "(forbidden by user configuration)", sig_alg->ssh_id); + goto out; + } + opensshcert_signature_preimage(ck, BinarySink_UPCAST(preimage)); if (!ssh_key_verify(ca_key, signature, ptrlen_from_strbuf(preimage))) { diff --git a/defs.h b/defs.h index cd7d0f4d..17bd62e4 100644 --- a/defs.h +++ b/defs.h @@ -177,6 +177,7 @@ typedef struct dlgcontrol dlgcontrol; typedef struct settings_w settings_w; typedef struct settings_r settings_r; typedef struct settings_e settings_e; +typedef struct ca_options ca_options; typedef struct host_ca host_ca; typedef struct host_ca_enum host_ca_enum; @@ -247,4 +248,14 @@ struct unicode_data; #define CAT_INNER(x,y) x ## y #define CAT(x,y) CAT_INNER(x,y) +/* + * Structure shared between ssh.h and storage.h, giving strictness + * options relating to checking of an OpenSSH certificate. It's a bit + * cheaty to put something so specific in here, but more painful to + * put it in putty.h. + */ +struct ca_options { + bool permit_rsa_sha1, permit_rsa_sha256, permit_rsa_sha512; +}; + #endif /* PUTTY_DEFS_H */ diff --git a/ssh.h b/ssh.h index ecb5074c..e628638c 100644 --- a/ssh.h +++ b/ssh.h @@ -848,7 +848,8 @@ struct ssh_keyalg { /* The following methods can be NULL if !is_certificate */ void (*ca_public_blob)(ssh_key *key, BinarySink *); bool (*check_cert)(ssh_key *key, bool host, ptrlen principal, - uint64_t time, BinarySink *error); + uint64_t time, const ca_options *opts, + BinarySink *error); void (*cert_id_string)(ssh_key *key, BinarySink *); /* 'Class methods' that don't deal with an ssh_key at all */ @@ -904,8 +905,8 @@ static inline void ssh_key_cert_id_string(ssh_key *key, BinarySink *bs) { key->vt->cert_id_string(key, bs); } static inline bool ssh_key_check_cert( ssh_key *key, bool host, ptrlen principal, uint64_t time, - BinarySink *error) -{ return key->vt->check_cert(key, host, principal, time, error); } + const ca_options *opts, BinarySink *error) +{ return key->vt->check_cert(key, host, principal, time, opts, error); } static inline int ssh_key_public_bits(const ssh_keyalg *self, ptrlen blob) { return self->pubkey_bits(self, blob); } static inline const ssh_keyalg *ssh_key_alg(ssh_key *key) diff --git a/ssh/ca-config.c b/ssh/ca-config.c index 056622a2..db104542 100644 --- a/ssh/ca-config.c +++ b/ssh/ca-config.c @@ -11,15 +11,19 @@ const bool has_ca_config_box = true; +#define NRSATYPES 3 + struct ca_state { dlgcontrol *ca_name_edit; dlgcontrol *ca_reclist; dlgcontrol *ca_pubkey_edit; dlgcontrol *ca_wclist; dlgcontrol *ca_wc_edit; + dlgcontrol *rsa_type_checkboxes[NRSATYPES]; char *name, *pubkey, *wc; tree234 *ca_names; /* stores plain 'char *' */ tree234 *host_wcs; /* stores plain 'char *' */ + ca_options opts; }; static int ca_name_compare(void *av, void *bv) @@ -68,6 +72,29 @@ static void ca_refresh_name_list(struct ca_state *st) } } +static void set_from_hca(struct ca_state *st, host_ca *hca) +{ + sfree(st->name); + st->name = dupstr(hca->name); + + sfree(st->pubkey); + if (hca->ca_public_key) + st->pubkey = strbuf_to_str( + base64_encode_sb(ptrlen_from_strbuf(hca->ca_public_key), 0)); + else + st->pubkey = dupstr(""); + + clear_string_tree(st->host_wcs); + for (size_t i = 0; i < hca->n_hostname_wildcards; i++) { + char *name = dupstr(hca->hostname_wildcards[i]); + char *added = add234(st->host_wcs, name); + if (added != name) + sfree(name); /* de-duplicate, just in case */ + } + + st->opts = hca->opts; /* structure copy */ +} + static void ca_load_selected_record(struct ca_state *st, dlgparam *dp) { int i = dlg_listbox_index(st->ca_reclist, dp); @@ -88,26 +115,14 @@ static void ca_load_selected_record(struct ca_state *st, dlgparam *dp) return; } - sfree(st->name); - st->name = dupstr(hca->name); - - sfree(st->pubkey); - st->pubkey = strbuf_to_str( - base64_encode_sb(ptrlen_from_strbuf(hca->ca_public_key), 0)); - - clear_string_tree(st->host_wcs); - for (size_t i = 0; i < hca->n_hostname_wildcards; i++) { - char *name = dupstr(hca->hostname_wildcards[i]); - char *added = add234(st->host_wcs, name); - if (added != name) - sfree(name); /* de-duplicate, just in case */ - } - + set_from_hca(st, hca); host_ca_free(hca); dlg_refresh(st->ca_name_edit, dp); dlg_refresh(st->ca_pubkey_edit, dp); dlg_refresh(st->ca_wclist, dp); + for (size_t i = 0; i < NRSATYPES; i++) + dlg_refresh(st->rsa_type_checkboxes[i], dp); } static void ca_ok_handler(dlgcontrol *ctrl, dlgparam *dp, @@ -214,6 +229,8 @@ static void ca_save_handler(dlgcontrol *ctrl, dlgparam *dp, hca->hostname_wildcards = snewn(hca->n_hostname_wildcards, char *); for (size_t i = 0; i < hca->n_hostname_wildcards; i++) hca->hostname_wildcards[i] = dupstr(index234(st->host_wcs, i)); + hca->opts = st->opts; /* structure copy */ + char *error = host_ca_save(hca); host_ca_free(hca); @@ -363,6 +380,20 @@ static void ca_wc_rem_handler(dlgcontrol *ctrl, dlgparam *dp, } } +static void ca_rsa_type_handler(dlgcontrol *ctrl, dlgparam *dp, + void *data, int event) +{ + struct ca_state *st = (struct ca_state *)ctrl->context.p; + size_t offset = ctrl->context2.i; + bool *option = (bool *)((char *)&st->opts + offset); + + if (event == EVENT_REFRESH) { + dlg_checkbox_set(ctrl, dp, *option); + } else if (event == EVENT_VALCHANGE) { + *option = dlg_checkbox_get(ctrl, dp); + } +} + void setup_ca_config_box(struct controlbox *b) { struct controlset *s; @@ -372,12 +403,17 @@ void setup_ca_config_box(struct controlbox *b) struct ca_state *st = (struct ca_state *)ctrl_alloc_with_free( b, sizeof(struct ca_state), ca_state_free); memset(st, 0, sizeof(*st)); - st->name = dupstr(""); - st->pubkey = dupstr(""); st->ca_names = newtree234(ca_name_compare); st->host_wcs = newtree234(ca_name_compare); ca_refresh_name_list(st); + /* Initialise the settings to a default blank host_ca */ + { + host_ca *hca = host_ca_new(); + set_from_hca(st, hca); + host_ca_free(hca); + } + /* Action area, with the Done button in it */ s = ctrl_getset(b, "", "", ""); ctrl_columns(s, 5, 20, 20, 20, 20, 20); @@ -442,4 +478,25 @@ void setup_ca_config_box(struct controlbox *b) c = ctrl_pushbutton(s, "Remove", NO_SHORTCUT, HELPCTX(no_help), ca_wc_rem_handler, P(st)); c->column = 2; + ctrl_columns(s, 1, 100); + + ctrl_columns(s, 4, 44, 18, 18, 18); + c = ctrl_text(s, "Signature types (RSA keys only):", HELPCTX(no_help)); + c->column = 0; + c = ctrl_checkbox(s, "SHA-1", NO_SHORTCUT, HELPCTX(no_help), + ca_rsa_type_handler, P(st)); + c->column = 1; + c->context2 = I(offsetof(ca_options, permit_rsa_sha1)); + st->rsa_type_checkboxes[0] = c; + c = ctrl_checkbox(s, "SHA-256", NO_SHORTCUT, HELPCTX(no_help), + ca_rsa_type_handler, P(st)); + c->column = 2; + c->context2 = I(offsetof(ca_options, permit_rsa_sha256)); + st->rsa_type_checkboxes[1] = c; + c = ctrl_checkbox(s, "SHA-512", NO_SHORTCUT, HELPCTX(no_help), + ca_rsa_type_handler, P(st)); + c->column = 3; + c->context2 = I(offsetof(ca_options, permit_rsa_sha512)); + st->rsa_type_checkboxes[2] = c; + ctrl_columns(s, 1, 100); } diff --git a/ssh/kex2-client.c b/ssh/kex2-client.c index 41e41503..a67f9e13 100644 --- a/ssh/kex2-client.c +++ b/ssh/kex2-client.c @@ -912,6 +912,7 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted) true, /* host certificate */ ptrlen_from_asciz(s->savedhost), time(NULL), + &hca_found->opts, BinarySink_UPCAST(error)); } if (cert_ok) { diff --git a/storage.h b/storage.h index 0487bf7c..f581256e 100644 --- a/storage.h +++ b/storage.h @@ -6,6 +6,8 @@ #ifndef PUTTY_STORAGE_H #define PUTTY_STORAGE_H +#include "defs.h" + /* ---------------------------------------------------------------------- * Functions to save and restore PuTTY sessions. Note that this is * only the low-level code to do the reading and writing. The @@ -103,6 +105,7 @@ struct host_ca { strbuf *ca_public_key; char **hostname_wildcards; size_t n_hostname_wildcards; + ca_options opts; }; host_ca_enum *enum_host_ca_start(void); diff --git a/test/cryptsuite.py b/test/cryptsuite.py index b2548fbc..ff8cf1ed 100755 --- a/test/cryptsuite.py +++ b/test/cryptsuite.py @@ -2560,7 +2560,7 @@ Private-MAC: 5b1f6f4cc43eb0060d2c3e181bc0129343adba2b def testOpenSSHCert(self): def per_base_keytype_tests(alg, run_validation_tests=False, - ca_signflags=None): + run_ca_rsa_tests=False, ca_signflags=None): cert_pub = sign_cert_via_testcrypt( make_signature_preimage( key_to_certify = base_key.public_blob(), @@ -2600,9 +2600,36 @@ Private-MAC: 5b1f6f4cc43eb0060d2c3e181bc0129343adba2b self.assertEqual(certified_key.verify(base_sig, test_string), True) # Check a successful certificate verification - result, err = certified_key.check_cert(False, b'username', 1000) + result, err = certified_key.check_cert( + False, b'username', 1000, '') self.assertEqual(result, True) + # If the key type is RSA, check that the validator rejects + # wrong kinds of CA signature + if run_ca_rsa_tests: + forbid_all = ",".join(["permit_rsa_sha1=false", + "permit_rsa_sha256=false," + "permit_rsa_sha512=false"]) + result, err = certified_key.check_cert( + False, b'username', 1000, forbid_all) + self.assertEqual(result, False) + + algname = ("rsa-sha2-512" if ca_signflags == 4 else + "rsa-sha2-256" if ca_signflags == 2 else + "ssh-rsa") + self.assertEqual(err, ( + "Certificate signature uses '{}' signature type " + "(forbidden by user configuration)".format(algname) + .encode("ASCII"))) + + permitflag = ("permit_rsa_sha512" if ca_signflags == 4 else + "permit_rsa_sha256" if ca_signflags == 2 else + "permit_rsa_sha1") + result, err = certified_key.check_cert( + False, b'username', 1000, "{},{}=true".format( + forbid_all, permitflag)) + self.assertEqual(result, True) + # That's the end of the tests we need to repeat for all # the key types. Now we move on to detailed tests of the # validation, which are independent of key type, so we @@ -2612,16 +2639,19 @@ Private-MAC: 5b1f6f4cc43eb0060d2c3e181bc0129343adba2b # Check cert verification at the other end of the valid # time range - result, err = certified_key.check_cert(False, b'username', 1999) + result, err = certified_key.check_cert( + False, b'username', 1999, '') self.assertEqual(result, True) # Oops, wrong certificate type - result, err = certified_key.check_cert(True, b'username', 1000) + result, err = certified_key.check_cert( + True, b'username', 1000, '') self.assertEqual(result, False) self.assertEqual(err, b'Certificate type is user; expected host') # Oops, wrong username - result, err = certified_key.check_cert(False, b'someoneelse', 1000) + result, err = certified_key.check_cert( + False, b'someoneelse', 1000, '') self.assertEqual(result, False) self.assertEqual(err, b'Certificate\'s username list ["username"] ' b'does not contain expected username "someoneelse"') @@ -2629,10 +2659,12 @@ Private-MAC: 5b1f6f4cc43eb0060d2c3e181bc0129343adba2b # Oops, time is wrong. (But we can't check the full error # message including the translated start/end times, because # those vary with LC_TIME.) - result, err = certified_key.check_cert(False, b'someoneelse', 999) + result, err = certified_key.check_cert( + False, b'someoneelse', 999, '') self.assertEqual(result, False) self.assertEqual(err[:30], b'Certificate is not valid until') - result, err = certified_key.check_cert(False, b'someoneelse', 2000) + result, err = certified_key.check_cert( + False, b'someoneelse', 2000, '') self.assertEqual(result, False) self.assertEqual(err[:22], b'Certificate expired at') @@ -2642,7 +2674,8 @@ Private-MAC: 5b1f6f4cc43eb0060d2c3e181bc0129343adba2b bytelist[username_position] ^= 1 miscertified_key = ssh_key_new_priv(alg + '-cert', bytes(bytelist), base_key.private_blob()) - result, err = miscertified_key.check_cert(False, b'username', 1000) + result, err = miscertified_key.check_cert( + False, b'username', 1000, '') self.assertEqual(result, False) self.assertEqual(err, b"Certificate's signature is invalid") @@ -2659,7 +2692,8 @@ Private-MAC: 5b1f6f4cc43eb0060d2c3e181bc0129343adba2b critical_options = {b'unknown-option': b'yikes!'}), ca_key) certified_key = ssh_key_new_priv(alg + '-cert', cert_pub, base_key.private_blob()) - result, err = certified_key.check_cert(False, b'username', 1000) + result, err = certified_key.check_cert( + False, b'username', 1000, '') self.assertEqual(result, False) self.assertEqual(err, b'Certificate specifies an unsupported ' b'critical option "unknown-option"') @@ -2677,7 +2711,8 @@ Private-MAC: 5b1f6f4cc43eb0060d2c3e181bc0129343adba2b extensions = {b'unknown-ext': b'whatever, dude'}), ca_key) certified_key = ssh_key_new_priv(alg + '-cert', cert_pub, base_key.private_blob()) - result, err = certified_key.check_cert(False, b'username', 1000) + result, err = certified_key.check_cert( + False, b'username', 1000, '') self.assertEqual(result, True) # Now try a host certificate. We don't need to do _all_ the @@ -2703,19 +2738,19 @@ Private-MAC: 5b1f6f4cc43eb0060d2c3e181bc0129343adba2b # Check certificate type result, err = certified_key.check_cert( - True, b'hostname.example.com', 1000) + True, b'hostname.example.com', 1000, '') self.assertEqual(result, True) result, err = certified_key.check_cert( - False, b'hostname.example.com', 1000) + False, b'hostname.example.com', 1000, '') self.assertEqual(result, False) self.assertEqual(err, b'Certificate type is host; expected user') # Check the second hostname and an unknown one result, err = certified_key.check_cert( - True, b'hostname2.example.com', 1000) + True, b'hostname2.example.com', 1000, '') self.assertEqual(result, True) result, err = certified_key.check_cert( - True, b'hostname3.example.com', 1000) + True, b'hostname3.example.com', 1000, '') self.assertEqual(result, False) self.assertEqual(err, b'Certificate\'s hostname list [' b'"hostname.example.com", "hostname2.example.com"] ' @@ -2738,12 +2773,12 @@ Private-MAC: 5b1f6f4cc43eb0060d2c3e181bc0129343adba2b certified_key = ssh_key_new_priv(alg + '-cert', cert_pub, base_key.private_blob()) result, err = certified_key.check_cert( - False, b'username', 1000) + False, b'username', 1000, '') self.assertEqual(result, False) self.assertEqual(err, b'Certificate type is unknown value 12345; ' b'expected user') result, err = certified_key.check_cert( - True, b'hostname.example.com', 1000) + True, b'hostname.example.com', 1000, '') self.assertEqual(result, False) self.assertEqual(err, b'Certificate type is unknown value 12345; ' b'expected host') @@ -2771,9 +2806,9 @@ Private-MAC: 5b1f6f4cc43eb0060d2c3e181bc0129343adba2b # Now switch to an RSA certifying key, and test different RSA # signature subtypes being used to sign the certificate ca_key = ssh_key_new_priv('rsa', b64('AAAAB3NzaC1yc2EAAAADAQABAAAAgQCKHiavhtnAZQLUPtYlzlQmVTHSKq2ChCKZP0cLNtN2YSS0/f4D1hi8W04Qh/JuSXZAdUThTAVjxDmxpiOMNwa/2WDXMuqip47dzZSQxtSdvTfeL9TVC/M1NaOzy8bqFx6pzi37zPATETT4PP1Zt/Pd23ZJYhwjxSyTlqj7529v0w=='), b64('AAAAgCwTZyEIlaCyG28EBm7WI0CAW3/IIsrNxATHjrJjcqQKaB5iF5e90PL66DSaTaEoTFZRlgOXsPiffBHXBO0P+lTyZ2jlq2J2zgeofRH3Yong4BT4xDtqBKtxixgC1MAHmrOnRXjAcDUiLxIGgU0YKSv0uAlgARsUwDsk0GEvK+jBAAAAQQDMi7liRBQ4/Z6a4wDL/rVnIJ9x+2h2UPK9J8U7f97x/THIBtfkbf9O7nDP6onValuSr86tMR24DJZsEXaGPwjDAAAAQQCs3J3D3jNVwwk16oySRSjA5x3tKCEITYMluyXX06cvFew8ldgRCYl1sh8RYAfbBKXhnJD77qIxtVNaF1yl/guxAAAAQFTRdKRUF2wLu/K/Rr34trwKrV6aW0GWyHlLuWvF7FUB85aDmtqYI2BSk92mVCKHBNw2T3cJMabN9JOznjtADiM=')) - per_base_keytype_tests('rsa') - per_base_keytype_tests('rsa', ca_signflags=2) - per_base_keytype_tests('rsa', ca_signflags=4) + per_base_keytype_tests('rsa', run_ca_rsa_tests=True) + per_base_keytype_tests('rsa', run_ca_rsa_tests=True, ca_signflags=2) + per_base_keytype_tests('rsa', run_ca_rsa_tests=True, ca_signflags=4) class standard_test_vectors(MyTestBase): def testAES(self): diff --git a/test/testcrypt-func.h b/test/testcrypt-func.h index 0873c2ea..02b2eb4d 100644 --- a/test/testcrypt-func.h +++ b/test/testcrypt-func.h @@ -309,7 +309,8 @@ FUNC_WRAPPED(void, ssh_key_cert_id_string, ARG(val_key, key), ARG(out_val_string_binarysink, blob)) FUNC_WRAPPED(boolean, ssh_key_check_cert, ARG(val_key, key), ARG(boolean, host), ARG(val_string_ptrlen, principal), - ARG(uint, time), ARG(out_val_string_binarysink, error)) + ARG(uint, time), ARG(val_string_ptrlen, options), + ARG(out_val_string_binarysink, error)) /* * Accessors to retrieve the innards of a 'key_components'. diff --git a/test/testcrypt.c b/test/testcrypt.c index c3c74784..3d845673 100644 --- a/test/testcrypt.c +++ b/test/testcrypt.c @@ -830,13 +830,37 @@ void ssh_key_cert_id_string_wrapper(ssh_key *key, BinarySink *out) } static bool ssh_key_check_cert_wrapper( - ssh_key *key, bool host, ptrlen principal, uint64_t time, + ssh_key *key, bool host, ptrlen principal, uint64_t time, ptrlen optstr, BinarySink *error) { /* Wrap to avoid null-pointer dereference */ if (!key->vt->is_certificate) fatal_error("ssh_key_cert_id_string: needs a certificate"); - return ssh_key_check_cert(key, host, principal, time, error); + + ca_options opts; + opts.permit_rsa_sha1 = true; + opts.permit_rsa_sha256 = true; + opts.permit_rsa_sha512 = true; + + while (optstr.len) { + ptrlen word = ptrlen_get_word(&optstr, ","); + ptrlen key = word, value = PTRLEN_LITERAL(""); + const char *comma = memchr(word.ptr, '=', word.len); + if (comma) { + key.len = comma - (const char *)word.ptr; + value.ptr = comma + 1; + value.len = word.len - key.len - 1; + } + + if (ptrlen_eq_string(key, "permit_rsa_sha1")) + opts.permit_rsa_sha1 = ptrlen_eq_string(value, "true"); + if (ptrlen_eq_string(key, "permit_rsa_sha256")) + opts.permit_rsa_sha256 = ptrlen_eq_string(value, "true"); + if (ptrlen_eq_string(key, "permit_rsa_sha512")) + opts.permit_rsa_sha512 = ptrlen_eq_string(value, "true"); + } + + return ssh_key_check_cert(key, host, principal, time, &opts, error); } bool dh_validate_f_wrapper(dh_ctx *dh, mp_int *f) diff --git a/unix/storage.c b/unix/storage.c index b3a9e8f1..b18c5166 100644 --- a/unix/storage.c +++ b/unix/storage.c @@ -666,6 +666,12 @@ host_ca *host_ca_load(const char *name) hca->n_hostname_wildcards); hca->hostname_wildcards[hca->n_hostname_wildcards++] = dupstr(value); + } else if (!strcmp(line, "PermitRSASHA1")) { + hca->opts.permit_rsa_sha1 = atoi(value); + } else if (!strcmp(line, "PermitRSASHA256")) { + hca->opts.permit_rsa_sha256 = atoi(value); + } else if (!strcmp(line, "PermitRSASHA512")) { + hca->opts.permit_rsa_sha512 = atoi(value); } sfree(line); @@ -691,6 +697,10 @@ char *host_ca_save(host_ca *hca) for (size_t i = 0; i < hca->n_hostname_wildcards; i++) fprintf(fp, "MatchHosts=%s\n", hca->hostname_wildcards[i]); + fprintf(fp, "PermitRSASHA1=%d\n", (int)hca->opts.permit_rsa_sha1); + fprintf(fp, "PermitRSASHA256=%d\n", (int)hca->opts.permit_rsa_sha256); + fprintf(fp, "PermitRSASHA512=%d\n", (int)hca->opts.permit_rsa_sha512); + bool bad = ferror(fp); if (fclose(fp) < 0) bad = true; diff --git a/utils/host_ca_new_free.c b/utils/host_ca_new_free.c index f77c84d8..8ae158ba 100644 --- a/utils/host_ca_new_free.c +++ b/utils/host_ca_new_free.c @@ -6,6 +6,9 @@ host_ca *host_ca_new(void) { host_ca *hca = snew(host_ca); memset(hca, 0, sizeof(*hca)); + hca->opts.permit_rsa_sha1 = false; + hca->opts.permit_rsa_sha256 = true; + hca->opts.permit_rsa_sha512 = true; return hca; } diff --git a/windows/storage.c b/windows/storage.c index c58f6d85..6a48aee6 100644 --- a/windows/storage.c +++ b/windows/storage.c @@ -427,6 +427,8 @@ host_ca *host_ca_load(const char *name) host_ca *hca = host_ca_new(); hca->name = dupstr(name); + DWORD val; + if ((s = get_reg_sz(rkey, "PublicKey")) != NULL) hca->ca_public_key = base64_decode_sb(ptrlen_from_asciz(s)); @@ -445,6 +447,13 @@ host_ca *host_ca_load(const char *name) strbuf_free(sb); } + if (get_reg_dword(rkey, "PermitRSASHA1", &val)) + hca->opts.permit_rsa_sha1 = val; + if (get_reg_dword(rkey, "PermitRSASHA256", &val)) + hca->opts.permit_rsa_sha256 = val; + if (get_reg_dword(rkey, "PermitRSASHA512", &val)) + hca->opts.permit_rsa_sha512 = val; + close_regkey(rkey); return hca; } @@ -476,6 +485,10 @@ char *host_ca_save(host_ca *hca) put_reg_multi_sz(rkey, "MatchHosts", wcs); strbuf_free(wcs); + put_reg_dword(rkey, "PermitRSASHA1", hca->opts.permit_rsa_sha1); + put_reg_dword(rkey, "PermitRSASHA256", hca->opts.permit_rsa_sha256); + put_reg_dword(rkey, "PermitRSASHA512", hca->opts.permit_rsa_sha512); + close_regkey(rkey); return NULL; }