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

CA config box: fully validate the CA public key.

Now we check that we can actually make an ssh_key out of it, and
moreover, that the key is of a sensible kind (i.e. not a certificate
in turn). If that's not true, we report something about the problem in
a new CTRL_TEXT below the public key input box. If the key _is_ valid,
that same text control is used to show its type, length and
fingerprint.

On Windows, I've widened the dialog box a little to make fingerprints
fit sensibly in it.
This commit is contained in:
Simon Tatham 2022-05-05 20:26:05 +01:00
parent cd094b28a3
commit 4b0e54c22a
3 changed files with 89 additions and 36 deletions

View File

@ -17,6 +17,7 @@ struct ca_state {
dlgcontrol *ca_name_edit;
dlgcontrol *ca_reclist;
dlgcontrol *ca_pubkey_edit;
dlgcontrol *ca_pubkey_info;
dlgcontrol *ca_wclist;
dlgcontrol *ca_wc_edit;
dlgcontrol *rsa_type_checkboxes[NRSATYPES];
@ -24,6 +25,7 @@ struct ca_state {
tree234 *ca_names; /* stores plain 'char *' */
tree234 *host_wcs; /* stores plain 'char *' */
ca_options opts;
strbuf *ca_pubkey_blob;
};
static int ca_name_compare(void *av, void *bv)
@ -95,6 +97,78 @@ static void set_from_hca(struct ca_state *st, host_ca *hca)
st->opts = hca->opts; /* structure copy */
}
static void ca_refresh_pubkey_info(struct ca_state *st, dlgparam *dp)
{
char *text = NULL;
ssh_key *key = NULL;
strbuf *blob = strbuf_new();
ptrlen data = ptrlen_from_asciz(st->pubkey);
if (st->ca_pubkey_blob)
strbuf_free(st->ca_pubkey_blob);
st->ca_pubkey_blob = NULL;
if (!data.len) {
text = dupstr(" ");
goto out;
}
/*
* See if we have a plain base64-encoded public key blob.
*/
if (base64_valid(data)) {
base64_decode_bs(BinarySink_UPCAST(blob), data);
} else {
/*
* Otherwise, try to decode as if it was a public key _file_.
*/
BinarySource src[1];
BinarySource_BARE_INIT_PL(src, data);
const char *error;
if (!ppk_loadpub_s(src, NULL, BinarySink_UPCAST(blob), NULL, &error)) {
text = dupprintf("Cannot decode key: %s", error);
goto out;
}
}
ptrlen alg_name = pubkey_blob_to_alg_name(ptrlen_from_strbuf(blob));
if (!alg_name.len) {
text = dupstr("Invalid key (no key type)");
goto out;
}
const ssh_keyalg *alg = find_pubkey_alg_len(alg_name);
if (!alg) {
text = dupprintf("Unrecognised key type '%.*s'",
PTRLEN_PRINTF(alg_name));
goto out;
}
if (alg->is_certificate) {
text = dupprintf("CA key may not be a certificate (type is '%.*s')",
PTRLEN_PRINTF(alg_name));
goto out;
}
key = ssh_key_new_pub(alg, ptrlen_from_strbuf(blob));
if (!key) {
text = dupprintf("Invalid '%.*s' key data", PTRLEN_PRINTF(alg_name));
goto out;
}
text = ssh2_fingerprint(key, SSH_FPTYPE_DEFAULT);
st->ca_pubkey_blob = blob;
blob = NULL; /* prevent free */
out:
dlg_text_set(st->ca_pubkey_info, dp, text);
if (key)
ssh_key_free(key);
sfree(text);
if (blob)
strbuf_free(blob);
}
static void ca_load_selected_record(struct ca_state *st, dlgparam *dp)
{
int i = dlg_listbox_index(st->ca_reclist, dp);
@ -123,6 +197,7 @@ static void ca_load_selected_record(struct ca_state *st, dlgparam *dp)
dlg_refresh(st->ca_wclist, dp);
for (size_t i = 0; i < NRSATYPES; i++)
dlg_refresh(st->rsa_type_checkboxes[i], dp);
ca_refresh_pubkey_info(st, dp);
}
static void ca_ok_handler(dlgcontrol *ctrl, dlgparam *dp,
@ -179,26 +254,6 @@ static void ca_load_handler(dlgcontrol *ctrl, dlgparam *dp,
}
}
static strbuf *decode_pubkey(ptrlen data, const char **error)
{
/*
* See if we have a plain base64-encoded public key blob.
*/
if (base64_valid(data))
return base64_decode_sb(data);
/*
* Otherwise, try to decode as if it was a public key _file_.
*/
BinarySource src[1];
BinarySource_BARE_INIT_PL(src, data);
strbuf *blob = strbuf_new();
if (ppk_loadpub_s(src, NULL, BinarySink_UPCAST(blob), NULL, error))
return blob;
return NULL;
}
static void ca_save_handler(dlgcontrol *ctrl, dlgparam *dp,
void *data, int event)
{
@ -209,22 +264,16 @@ static void ca_save_handler(dlgcontrol *ctrl, dlgparam *dp,
return;
}
strbuf *pubkey;
{
const char *error;
pubkey = decode_pubkey(ptrlen_from_asciz(st->pubkey), &error);
if (!pubkey) {
char *msg = dupprintf("CA public key invalid: %s", error);
dlg_error_msg(dp, msg);
sfree(msg);
return;
}
if (!st->ca_pubkey_blob) {
dlg_error_msg(dp, "No valid CA public key entered");
return;
}
host_ca *hca = snew(host_ca);
memset(hca, 0, sizeof(*hca));
hca->name = dupstr(st->name);
hca->ca_public_key = pubkey;
hca->ca_public_key = strbuf_dup(ptrlen_from_strbuf(
st->ca_pubkey_blob));
hca->n_hostname_wildcards = count234(st->host_wcs);
hca->hostname_wildcards = snewn(hca->n_hostname_wildcards, char *);
for (size_t i = 0; i < hca->n_hostname_wildcards; i++)
@ -280,6 +329,7 @@ static void ca_pubkey_edit_handler(dlgcontrol *ctrl, dlgparam *dp,
} else if (event == EVENT_VALCHANGE) {
sfree(st->pubkey);
st->pubkey = dlg_editbox_get(ctrl, dp);
ca_refresh_pubkey_info(st, dp);
}
}
@ -451,8 +501,7 @@ void setup_ca_config_box(struct controlbox *b)
ca_delete_handler, P(st));
c->column = 1;
/* Box containing the details of a specific CA record */
s = ctrl_getset(b, "Main", "details", "Details of a host CA record");
s = ctrl_getset(b, "Main", "pubkey", "Public key for this CA record");
ctrl_columns(s, 2, 75, 25);
c = ctrl_editbox(s, "Public key of certification authority", 'k', 100,
@ -466,6 +515,10 @@ void setup_ca_config_box(struct controlbox *b)
c->align_next_to = st->ca_pubkey_edit;
c->column = 1;
ctrl_columns(s, 1, 100);
st->ca_pubkey_info = c = ctrl_text(s, " ", HELPCTX(no_help));
c->text.wrap = false;
s = ctrl_getset(b, "Main", "options", "What this CA is trusted to do");
c = ctrl_listbox(s, "Hostname patterns this key is trusted to certify",
NO_SHORTCUT, HELPCTX(no_help), ca_wclist_handler, P(st));

View File

@ -1186,8 +1186,8 @@ static INT_PTR CAConfigProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam,
centre_window(hwnd);
pds_create_controls(pds, 0, IDCX_PANELBASE, 3, 3, 13, "Main");
pds_create_controls(pds, 0, IDCX_STDBASE, 3, 3, 235, "");
pds_create_controls(pds, 0, IDCX_PANELBASE, 3, 3, 3, "Main");
pds_create_controls(pds, 0, IDCX_STDBASE, 3, 3, 243, "");
dlg_refresh(NULL, pds->dp); /* and set up control values */
pds_initdialog_finish(pds);

View File

@ -131,7 +131,7 @@ BEGIN
END
/* Accelerators used: aco */
IDD_CA_CONFIG DIALOG DISCARDABLE 0, 0, 300, 252
IDD_CA_CONFIG DIALOG DISCARDABLE 0, 0, 350, 260
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "PuTTY trusted host certification authorities"
FONT 8, "MS Shell Dlg"