Commit dd9b0ab3 authored by David Woodhouse's avatar David Woodhouse

Switch from Android's keystore_get() to our own keystore_fetch()

This gives proper error handling which Android's lacks.
Signed-off-by: default avatarDavid Woodhouse <David.Woodhouse@intel.com>
parent 433f6866
......@@ -249,7 +249,6 @@ static int load_datum(struct openconnect_info *vpninfo,
int fd, err;
#ifdef ANDROID_KEYSTORE
if (!strncmp(fname, "keystore:", 9)) {
char content[KEYSTORE_MESSAGE_SIZE];
int len;
const char *p = fname + 9;
......@@ -259,21 +258,13 @@ static int load_datum(struct openconnect_info *vpninfo,
p++;
if (*p == '/')
p++;
len = keystore_get(p, strlen(p), content);
if (len < 0) {
len = keystore_fetch(p, &datum->data);
if (len <= 0) {
vpn_progress(vpninfo, PRG_ERR,
_("Failed to lead item '%s' from keystore\n"),
p);
_("Failed to load item '%s' from keystore: %s\n"),
p, keystore_strerror(len));
return -EINVAL;
}
datum->data = gnutls_malloc(len + 1);
if (!datum->data) {
vpn_progress(vpninfo, PRG_ERR,
_("Failed to allocate memory for keystore item\n"));
return -ENOMEM;
}
datum->data[len] = 0;
memcpy(datum->data, content, len);
datum->size = len;
return 0;
}
......
......@@ -346,6 +346,13 @@ int __attribute__ ((format (printf, 2, 3)))
openconnect_SSL_printf(struct openconnect_info *vpninfo, const char *fmt, ...);
int openconnect_print_err_cb(const char *str, size_t len, void *ptr);
#define openconnect_report_ssl_errors(v) ERR_print_errors_cb(openconnect_print_err_cb, (v))
#ifdef FAKE_ANDROID_KEYSTORE
#define ANDROID_KEYSTORE
#endif
#ifdef ANDROID_KEYSTORE
char *keystore_strerror(int err);
int keystore_fetch(const char *key, unsigned char **result);
#endif
/* ${SSL_LIBRARY}.c */
int openconnect_SSL_gets(struct openconnect_info *vpninfo, char *buf, size_t len);
......@@ -394,27 +401,4 @@ int add_securid_pin(char *token, char *pin);
/* version.c */
extern const char *openconnect_version_str;
#ifdef ANDROID_KEYSTORE
#include <keystore_get.h>
#elif defined (FAKE_ANDROID_KEYSTORE) /* For testing */
#define ANDROID_KEYSTORE
#define KEYSTORE_MESSAGE_SIZE 16384
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
static inline int keystore_get(const char *p, int plen, char *content)
{
int fd = open(p, O_RDONLY);
int len;
if (fd == -1)
return fd;
len = read(fd, content, KEYSTORE_MESSAGE_SIZE);
close(fd);
if (len <= 0)
return -1;
return len;
}
#endif /* FAKE_ANDROID_KEYSTORE */
#endif /* __OPENCONNECT_INTERNAL_H__ */
......@@ -603,7 +603,7 @@ static int reload_pem_cert(struct openconnect_info *vpninfo)
#ifdef ANDROID_KEYSTORE
static BIO *BIO_from_keystore(struct openconnect_info *vpninfo, const char *item)
{
char content[KEYSTORE_MESSAGE_SIZE];
unsigned char *content;
BIO *b;
int len;
const char *p = item + 9;
......@@ -614,24 +614,23 @@ static BIO *BIO_from_keystore(struct openconnect_info *vpninfo, const char *item
p++;
if (*p == '/')
p++;
/* Old versions of keystore_get.h will return the input length
instead of an error, in some circumstances. So check the
content actually changes, too. */
content[0] = 0;
len = keystore_get(p, strlen(p), content);
if (len < 0 || content[0] == 0) {
len = keystore_fetch(p, &content);
if (len < 0) {
vpn_progress(vpninfo, PRG_ERR,
_("Failed to lead item '%s' from keystore\n"),
p);
_("Failed to load item '%s' from keystore: %s\n"),
p, keystore_strerror(len));
return NULL;
}
if (!(b = BIO_new(BIO_s_mem())) || BIO_write(b, content, len) != len) {
vpn_progress(vpninfo, PRG_ERR,
_("Failed to create BIO for keystore item '%s'\n"),
p);
free(content);
BIO_free(b);
return NULL;
}
free(content);
return b;
}
#endif
......
......@@ -24,6 +24,7 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
......@@ -365,3 +366,121 @@ int openconnect_print_err_cb(const char *str, size_t len, void *ptr)
return 0;
}
#endif
#ifdef FAKE_ANDROID_KEYSTORE
char *keystore_strerror(int err)
{
return (char *)strerror(-err);
}
int keystore_fetch(const char *key, unsigned char **result)
{
unsigned char *data;
struct stat st;
int fd;
int ret;
fd = open(key, O_RDONLY);
if (fd < 0)
return -errno;
if (fstat(fd, &st)) {
ret = -errno;
goto out_fd;
}
data = malloc(st.st_size);
if (!data) {
ret = -ENOMEM;
goto out_fd;
}
if (read(fd, data, st.st_size) != st.st_size) {
ret = -EIO;
free(data);
goto out_fd;
}
*result = data;
ret = st.st_size;
out_fd:
close(fd);
return ret;
}
#elif defined (ANDROID_KEYSTORE)
#include <cutils/sockets.h>
#include <keystore.h>
char *keystore_strerror(int err)
{
switch (-err) {
case NO_ERROR: return _("No error");
case LOCKED: return _("Keystore ocked");
case UNINITIALIZED: return _("Keystore uninitialized");
case SYSTEM_ERROR: return _("System error");
case PROTOCOL_ERROR: return _("Protocol error");
case PERMISSION_DENIED: return _("Permission denied");
case KEY_NOT_FOUND: return _("Key not found");
case VALUE_CORRUPTED: return _("Value corrupted");
case UNDEFINED_ACTION: return _("Undefined action");
case WRONG_PASSWORD_0:
case WRONG_PASSWORD_1:
case WRONG_PASSWORD_2:
case WRONG_PASSWORD_3: return _("Wrong password");
default: return _("Unknown error");
}
}
/* Returns length, or a negative errno in its own namespace (handled by its
own strerror function above). The numbers are from Android's keystore.h */
int keystore_fetch(const char *key, unsigned char **result)
{
unsigned char *data, *p;
unsigned char buf[3];
int len, fd, ofs;
int ret = -SYSTEM_ERROR;
fd = socket_local_client("keystore",
ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_STREAM);
if (fd < 0)
return -SYSTEM_ERROR;
len = strlen(key);
buf[0] = 'g';
buf[1] = len >> 8;
buf[2] = len & 0xff;
if (send(fd, buf, 3, 0) != 3 || send(fd, key, len, 0) != len ||
shutdown(fd, SHUT_WR) || recv(fd, buf, 1, 0) != 1)
goto out;
if (buf[0] != NO_ERROR) {
/* Should never be zero */
ret = buf[0] ? -buf[0] : -PROTOCOL_ERROR;
goto out;
}
if (recv(fd, buf, 2, 0) != 2)
goto out;
len = (buf[0] << 8) + buf[1];
data = malloc(len);
if (!data)
goto out;
p = data;
ret = len;
while (len) {
int got = recv(fd, p, len, 0);
if (got <= 0) {
free(data);
ret = -PROTOCOL_ERROR;
goto out;
}
len -= got;
p += got;
}
*result = data;
out:
close(fd);
return ret;
}
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment