1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-03-22 14:39:24 -05:00

Expose lf_load_keyfile outside sshpubk.c.

I'm about to use it in cmdgen for a minor UI improvement. Also, I
expect it to be useful in the Pageant client code sooner or later.

While I'm here, I've also tweaked its UI a little so that it reports a
more precise error, and provided a version that can read from an
already open stdio stream.
This commit is contained in:
Simon Tatham 2020-02-02 11:27:03 +00:00
parent c25dc9c2fd
commit 5db2f4ca7e
3 changed files with 106 additions and 51 deletions

1
defs.h
View File

@ -64,6 +64,7 @@ typedef struct FontSpec FontSpec;
typedef struct bufchain_tag bufchain; typedef struct bufchain_tag bufchain;
typedef struct strbuf strbuf; typedef struct strbuf strbuf;
typedef struct LoadedFile LoadedFile;
typedef struct RSAKey RSAKey; typedef struct RSAKey RSAKey;

13
ssh.h
View File

@ -1195,6 +1195,19 @@ int rsa1_loadpub_f(const Filename *filename, BinarySink *bs,
const ssh_keyalg *find_pubkey_alg(const char *name); const ssh_keyalg *find_pubkey_alg(const char *name);
const ssh_keyalg *find_pubkey_alg_len(ptrlen name); const ssh_keyalg *find_pubkey_alg_len(ptrlen name);
/*
* A mechanism for loading a key file from disk into a memory buffer
* where it can be picked apart as a BinarySource.
*/
struct LoadedFile {
char *data;
size_t len, max_size;
BinarySource_IMPLEMENTATION;
};
LoadedFile *lf_load_keyfile(const Filename *filename, const char **errptr);
LoadedFile *lf_load_keyfile_fp(FILE *fp, const char **errptr);
void lf_free(LoadedFile *lf);
enum { enum {
SSH_KEYTYPE_UNOPENABLE, SSH_KEYTYPE_UNOPENABLE,
SSH_KEYTYPE_UNKNOWN, SSH_KEYTYPE_UNKNOWN,

143
sshpubk.c
View File

@ -6,6 +6,8 @@
*/ */
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h> #include <stdlib.h>
#include <assert.h> #include <assert.h>
@ -42,36 +44,35 @@ static const ptrlen rsa1_signature =
(x)=='+' ? 62 : \ (x)=='+' ? 62 : \
(x)=='/' ? 63 : 0 ) (x)=='/' ? 63 : 0 )
typedef struct LoadedFile { typedef enum {
char *data; LF_OK, /* file loaded successfully */
size_t len; LF_TOO_BIG, /* file didn't fit in buffer */
BinarySource_IMPLEMENTATION; LF_ERROR, /* error from stdio layer */
} LoadedFile; } LoadFileStatus;
static void lf_free(LoadedFile *lf) static LoadedFile *lf_new(size_t max_size)
{ {
LoadedFile *lf = snew_plus(LoadedFile, max_size);
lf->data = snew_plus_get_aux(lf);
lf->len = 0;
lf->max_size = max_size;
return lf;
}
void lf_free(LoadedFile *lf)
{
smemclr(lf->data, lf->max_size);
smemclr(lf, sizeof(LoadedFile)); smemclr(lf, sizeof(LoadedFile));
sfree(lf); sfree(lf);
} }
static LoadedFile *lf_load(const Filename *filename, size_t max_size, static LoadFileStatus lf_load_fp(LoadedFile *lf, FILE *fp)
bool tolerate_overflow)
{ {
FILE *fp = f_open(filename, "rb", false);
if (!fp)
return NULL;
LoadedFile *lf = snew_plus(LoadedFile, max_size);
lf->data = snew_plus_get_aux(lf);
lf->len = 0; lf->len = 0;
while (lf->len < lf->max_size) {
while (lf->len < max_size) { size_t retd = fread(lf->data + lf->len, 1, lf->max_size - lf->len, fp);
size_t retd = fread(lf->data + lf->len, 1, max_size - lf->len, fp); if (ferror(fp))
if (ferror(fp)) { return LF_ERROR;
lf_free(lf);
fclose(fp);
return NULL;
}
if (retd == 0) if (retd == 0)
break; break;
@ -79,24 +80,70 @@ static LoadedFile *lf_load(const Filename *filename, size_t max_size,
lf->len += retd; lf->len += retd;
} }
if (lf->len == max_size && !tolerate_overflow) { LoadFileStatus status = LF_OK;
if (lf->len == lf->max_size) {
/* The file might be too long to fit in our fixed-size /* The file might be too long to fit in our fixed-size
* structure. Try reading one more byte, to check. */ * structure. Try reading one more byte, to check. */
if (fgetc(fp) != EOF) { if (fgetc(fp) != EOF)
lf_free(lf); status = LF_TOO_BIG;
fclose(fp);
return NULL;
}
} }
fclose(fp);
BinarySource_INIT(lf, lf->data, lf->len); BinarySource_INIT(lf, lf->data, lf->len);
return status;
}
static LoadFileStatus lf_load(LoadedFile *lf, const Filename *filename)
{
FILE *fp = f_open(filename, "rb", false);
if (!fp)
return LF_ERROR;
LoadFileStatus status = lf_load_fp(lf, fp);
fclose(fp);
return status;
}
static inline bool lf_load_keyfile_helper(LoadFileStatus status,
const char **errptr)
{
const char *error;
switch (status) {
case LF_OK:
return true;
case LF_TOO_BIG:
error = "file is too large to be a key file";
break;
case LF_ERROR:
error = strerror(errno);
break;
default:
unreachable("bad status value in lf_load_keyfile_helper");
}
if (errptr)
*errptr = error;
return false;
}
LoadedFile *lf_load_keyfile(const Filename *filename, const char **errptr)
{
LoadedFile *lf = lf_new(MAX_KEY_FILE_SIZE);
if (!lf_load_keyfile_helper(lf_load(lf, filename), errptr)) {
lf_free(lf);
return NULL;
}
return lf; return lf;
} }
static LoadedFile *lf_load_keyfile(const Filename *filename) LoadedFile *lf_load_keyfile_fp(FILE *fp, const char **errptr)
{ {
return lf_load(filename, MAX_KEY_FILE_SIZE, false); LoadedFile *lf = lf_new(MAX_KEY_FILE_SIZE);
if (!lf_load_keyfile_helper(lf_load_fp(lf, fp), errptr)) {
lf_free(lf);
return NULL;
}
return lf;
} }
static int key_type_s(BinarySource *src); static int key_type_s(BinarySource *src);
@ -220,11 +267,9 @@ int rsa1_load_s(BinarySource *src, RSAKey *key,
int rsa1_load_f(const Filename *filename, RSAKey *key, int rsa1_load_f(const Filename *filename, RSAKey *key,
const char *passphrase, const char **errstr) const char *passphrase, const char **errstr)
{ {
LoadedFile *lf = lf_load_keyfile(filename); LoadedFile *lf = lf_load_keyfile(filename, errstr);
if (!lf) { if (!lf)
*errstr = "can't open file";
return false; return false;
}
int toret = rsa1_load_s(BinarySource_UPCAST(lf), key, passphrase, errstr); int toret = rsa1_load_s(BinarySource_UPCAST(lf), key, passphrase, errstr);
lf_free(lf); lf_free(lf);
@ -243,7 +288,7 @@ bool rsa1_encrypted_s(BinarySource *src, char **comment)
bool rsa1_encrypted_f(const Filename *filename, char **comment) bool rsa1_encrypted_f(const Filename *filename, char **comment)
{ {
LoadedFile *lf = lf_load_keyfile(filename); LoadedFile *lf = lf_load_keyfile(filename, NULL);
if (!lf) if (!lf)
return false; /* couldn't even open the file */ return false; /* couldn't even open the file */
@ -342,11 +387,9 @@ int rsa1_loadpub_s(BinarySource *src, BinarySink *bs,
int rsa1_loadpub_f(const Filename *filename, BinarySink *bs, int rsa1_loadpub_f(const Filename *filename, BinarySink *bs,
char **commentptr, const char **errorstr) char **commentptr, const char **errorstr)
{ {
LoadedFile *lf = lf_load_keyfile(filename); LoadedFile *lf = lf_load_keyfile(filename, errorstr);
if (!lf) { if (!lf)
*errorstr = "can't open file";
return 0; return 0;
}
int toret = rsa1_loadpub_s(BinarySource_UPCAST(lf), bs, int toret = rsa1_loadpub_s(BinarySource_UPCAST(lf), bs,
commentptr, errorstr); commentptr, errorstr);
@ -883,11 +926,9 @@ ssh2_userkey *ppk_load_s(BinarySource *src, const char *passphrase,
ssh2_userkey *ppk_load_f(const Filename *filename, const char *passphrase, ssh2_userkey *ppk_load_f(const Filename *filename, const char *passphrase,
const char **errorstr) const char **errorstr)
{ {
LoadedFile *lf = lf_load_keyfile(filename); LoadedFile *lf = lf_load_keyfile(filename, errorstr);
if (!lf) { if (!lf)
*errorstr = "can't open file"; *errorstr = "can't open file";
return NULL;
}
ssh2_userkey *toret = ppk_load_s(BinarySource_UPCAST(lf), ssh2_userkey *toret = ppk_load_s(BinarySource_UPCAST(lf),
passphrase, errorstr); passphrase, errorstr);
@ -1191,11 +1232,9 @@ bool ppk_loadpub_s(BinarySource *src, char **algorithm, BinarySink *bs,
bool ppk_loadpub_f(const Filename *filename, char **algorithm, BinarySink *bs, bool ppk_loadpub_f(const Filename *filename, char **algorithm, BinarySink *bs,
char **commentptr, const char **errorstr) char **commentptr, const char **errorstr)
{ {
LoadedFile *lf = lf_load_keyfile(filename); LoadedFile *lf = lf_load_keyfile(filename, errorstr);
if (!lf) { if (!lf)
*errorstr = "can't open file";
return false; return false;
}
bool toret = ppk_loadpub_s(BinarySource_UPCAST(lf), algorithm, bs, bool toret = ppk_loadpub_s(BinarySource_UPCAST(lf), algorithm, bs,
commentptr, errorstr); commentptr, errorstr);
@ -1253,7 +1292,7 @@ bool ppk_encrypted_s(BinarySource *src, char **commentptr)
bool ppk_encrypted_f(const Filename *filename, char **commentptr) bool ppk_encrypted_f(const Filename *filename, char **commentptr)
{ {
LoadedFile *lf = lf_load_keyfile(filename); LoadedFile *lf = lf_load_keyfile(filename, NULL);
if (!lf) { if (!lf) {
if (commentptr) if (commentptr)
*commentptr = NULL; *commentptr = NULL;
@ -1648,9 +1687,11 @@ static int key_type_s(BinarySource *src)
int key_type(const Filename *filename) int key_type(const Filename *filename)
{ {
LoadedFile *lf = lf_load(filename, 1024, true); LoadedFile *lf = lf_new(1024);
if (!lf) if (lf_load(lf, filename) == LF_ERROR) {
lf_free(lf);
return SSH_KEYTYPE_UNOPENABLE; return SSH_KEYTYPE_UNOPENABLE;
}
int toret = key_type_s(BinarySource_UPCAST(lf)); int toret = key_type_s(BinarySource_UPCAST(lf));
lf_free(lf); lf_free(lf);