This gives proper error handling which Android's lacks.
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
int fd, err;
#ifdef ANDROID_KEYSTORE
if (!strncmp(fname, "keystore:", 9)) {
- char content[KEYSTORE_MESSAGE_SIZE];
int len;
const char *p = fname + 9;
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;
}
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);
/* 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__ */
#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;
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
#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
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