1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 09:27:59 +00:00

Permit configuring RSA signature types in certificates.

As distinct from the type of signature generated by the SSH server
itself from the host key, this lets you exclude (and by default does
exclude) the old "ssh-rsa" SHA-1 signature type from the signature of
the CA on the certificate.
This commit is contained in:
Simon Tatham 2022-05-02 10:18:16 +01:00
parent e34e0220ab
commit dc7ba12253
12 changed files with 215 additions and 47 deletions

View File

@ -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))) {

11
defs.h
View File

@ -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 */

7
ssh.h
View File

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

View File

@ -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);
}

View File

@ -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) {

View File

@ -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);

View File

@ -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):

View File

@ -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'.

View File

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

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}