crypt: Deduplicate get_public_key().
authorAndre Noll <maan@tuebingen.mpg.de>
Thu, 28 Dec 2017 00:41:14 +0000 (01:41 +0100)
committerAndre Noll <maan@tuebingen.mpg.de>
Sun, 25 Feb 2018 23:10:28 +0000 (00:10 +0100)
The openssl and grypt implementations of this function share quite
some code. This patch factors out the common code into the new
decode_ssh_key() helper of crypt_common.c. Both implementations are
changed to call the new helper.

As a side effect of this change, all callers of is_ssh_rsa_key()
and check_ssh_key_header() now reside in crypt_common.c, so we can
make these two functions static and remove their declarations from
crypt_backend.h.

crypt_backend.h
crypt_common.c
gcrypt.c
openssl.c

index ff956ce..175a688 100644 (file)
@@ -7,6 +7,6 @@
 /** AES block size in bytes. */
 #define AES_CRT128_BLOCK_SIZE 16
 
-size_t is_ssh_rsa_key(char *data, size_t size);
-int check_ssh_key_header(const unsigned char *blob, int blen);
+int decode_ssh_key(const char *filename, unsigned char **blob,
+               size_t *decoded_size);
 int check_private_key_file(const char *file);
index 08361b2..235b8b8 100644 (file)
 #include "crypt.h"
 #include "crypt_backend.h"
 #include "portable_io.h"
+#include "fd.h"
+#include "base64.h"
 
 /** If the key begins with this text, we treat it as an ssh key. */
 #define KEY_TYPE_TXT "ssh-rsa"
 
-/**
- * Check if given buffer starts with a ssh rsa key signature.
- *
- * \param data The buffer.
- * \param size Number of data bytes.
+/*
+ * Check if the given buffer starts with an ssh rsa key signature.
  *
- * \return Number of header bytes to be skipped on success, zero if
- * ssh rsa signature was not found.
+ * Returns number of header bytes to be skipped on success, zero if no ssh rsa
+ * signature was found.
  */
-size_t is_ssh_rsa_key(char *data, size_t size)
+static size_t is_ssh_rsa_key(char *data, size_t size)
 {
        char *cp;
 
@@ -42,20 +41,13 @@ size_t is_ssh_rsa_key(char *data, size_t size)
        return cp - data;
 }
 
-/**
- * Sanity checks for the header of an ssh key.
- *
- * \param blob The buffer.
- * \param blen The number of bytes of \a blob.
+/*
+ * Perform some sanity checks on the decoded ssh key.
  *
- * This performs some checks to make sure we really have an ssh key. It also
- * computes the offset in bytes of the start of the key values (modulus,
- * exponent..).
- *
- * \return The number of bytes to skip until the start of the first encoded
- * number (usually 11).
+ * This function returns the size of the header. Usually, the header is 11
+ * bytes long: four bytes for the length field, and the string "ssh-rsa".
  */
-int check_ssh_key_header(const unsigned char *blob, int blen)
+static int check_ssh_key_header(const unsigned char *blob, int blen)
 {
        const unsigned char *p = blob, *end = blob + blen;
        uint32_t rlen;
@@ -76,6 +68,51 @@ int check_ssh_key_header(const unsigned char *blob, int blen)
        return 4 + rlen;
 }
 
+/**
+ * Perform sanity checks and base64-decode an ssh-rsa key.
+ *
+ * \param filename The public key file (usually id_rsa.pub).
+ * \param blob Pointer to base64-decoded blob is returned here.
+ * \param decoded_size The size of the decoded blob.
+ *
+ * The memory pointed at by the returned blob pointer has to be freed by the
+ * caller.
+ *
+ * \return On success, the offset in bytes of the start of the key values
+ * (modulus, exponent..). This is the number of bytes to skip from the blob
+ * until the start of the first encoded number. On failure, a negative error
+ * code is returned.
+ *
+ * \sa \ref uudecode().
+ */
+int decode_ssh_key(const char *filename, unsigned char **blob,
+               size_t *decoded_size)
+{
+       int ret, ret2;
+       void *map;
+       size_t map_size;
+
+       ret = mmap_full_file(filename, O_RDONLY, &map, &map_size, NULL);
+       if (ret < 0)
+               return ret;
+       ret = is_ssh_rsa_key(map, map_size);
+       if (ret == 0) {
+               ret = -E_SSH_PARSE;
+               goto unmap;
+       }
+       ret = uudecode(map + ret, map_size - ret, (char **)blob, decoded_size);
+       if (ret < 0)
+               goto unmap;
+       ret = check_ssh_key_header(*blob, *decoded_size);
+       if (ret < 0)
+               goto unmap;
+unmap:
+       ret2 = para_munmap(map, map_size);
+       if (ret >= 0 && ret2 < 0)
+               ret = ret2;
+       return ret;
+}
+
 /**
  * Check existence and permissions of a private key file.
  *
index 052546d..2398a60 100644 (file)
--- a/gcrypt.c
+++ b/gcrypt.c
@@ -366,27 +366,21 @@ free_blob:
        return ret;
 }
 
-static int get_ssh_public_key(unsigned char *data, int size, gcry_sexp_t *result)
+int get_public_key(const char *key_file, struct asymmetric_key **result)
 {
+       unsigned char *blob, *p, *end;
        int ret;
        gcry_error_t gret;
-       unsigned char *blob = NULL, *p, *end;
        size_t nr_scanned, erroff, decoded_size;
-       gcry_mpi_t e = NULL, n = NULL;
+       gcry_mpi_t e, n;
+       gcry_sexp_t sexp;
+       struct asymmetric_key *key;
 
-       PARA_DEBUG_LOG("decoding %d byte public rsa-ssh key\n", size);
-       ret = uudecode((char *)data, size, (char **)&blob, &decoded_size);
-       if (ret < 0)
-               goto free_blob;
-       end = blob + decoded_size;
-       dump_buffer("decoded key", blob, decoded_size);
-       ret = check_ssh_key_header(blob, decoded_size);
+       ret = decode_ssh_key(key_file, &blob, &decoded_size);
        if (ret < 0)
-               goto free_blob;
+               return ret;
        p = blob + ret;
-       ret = -E_SSH_PARSE;
-       if (p >= end)
-               goto free_blob;
+       end = blob + decoded_size;
        PARA_DEBUG_LOG("scanning modulus and public exponent\n");
        gret = gcry_mpi_scan(&e, GCRYMPI_FMT_SSH, p, end - p, &nr_scanned);
        if (gret) {
@@ -395,8 +389,6 @@ static int get_ssh_public_key(unsigned char *data, int size, gcry_sexp_t *result
                goto free_blob;
        }
        PARA_DEBUG_LOG("scanned e (%zu bytes)\n", nr_scanned);
-//     gcry_mpi_aprint(GCRYMPI_FMT_HEX, &buf, NULL, rsa_e);
-//     PARA_CRIT_LOG("e: %s\n", buf);
        p += nr_scanned;
        if (p >= end)
                goto release_e;
@@ -407,9 +399,7 @@ static int get_ssh_public_key(unsigned char *data, int size, gcry_sexp_t *result
                goto release_e;
        }
        PARA_DEBUG_LOG("scanned n (%zu bytes)\n", nr_scanned);
-//     gcry_mpi_aprint(GCRYMPI_FMT_HEX, &buf, NULL, rsa_n);
-//     PARA_CRIT_LOG("n: %s\n", buf);
-       gret = gcry_sexp_build(result, &erroff, RSA_PUBKEY_SEXP, n, e);
+       gret = gcry_sexp_build(&sexp, &erroff, RSA_PUBKEY_SEXP, n, e);
        if (gret) {
                PARA_ERROR_LOG("offset %zu: %s\n", erroff,
                        gcry_strerror(gcry_err_code(gret)));
@@ -418,6 +408,10 @@ static int get_ssh_public_key(unsigned char *data, int size, gcry_sexp_t *result
        }
        ret = nr_scanned / 32 * 32;
        PARA_INFO_LOG("successfully read %d bit ssh public key\n", ret * 8);
+       key = para_malloc(sizeof(*key));
+       key->num_bytes = ret;
+       key->sexp = sexp;
+       *result = key;
 release_n:
        gcry_mpi_release(n);
 release_e:
@@ -427,42 +421,6 @@ free_blob:
        return ret;
 }
 
-int get_public_key(const char *key_file, struct asymmetric_key **result)
-{
-       int ret, ret2;
-       void *map;
-       size_t map_size;
-       unsigned char *start, *end;
-       gcry_sexp_t sexp;
-       struct asymmetric_key *key;
-
-       ret = mmap_full_file(key_file, O_RDONLY, &map, &map_size, NULL);
-       if (ret < 0)
-               return ret;
-       ret = is_ssh_rsa_key(map, map_size);
-       if (!ret) {
-               para_munmap(map, map_size);
-               return -E_SSH_PARSE;
-       }
-       start = map + ret;
-       end = map + map_size;
-       ret = -E_SSH_PARSE;
-       if (start >= end)
-               goto unmap;
-       ret = get_ssh_public_key(start, end - start, &sexp);
-       if (ret < 0)
-               goto unmap;
-       key = para_malloc(sizeof(*key));
-       key->num_bytes = ret;
-       key->sexp = sexp;
-       *result = key;
-unmap:
-       ret2 = para_munmap(map, map_size);
-       if (ret >= 0 && ret2 < 0)
-               ret = ret2;
-       return ret;
-}
-
 void free_public_key(struct asymmetric_key *key)
 {
        if (!key)
index f786ce2..99b3f7a 100644 (file)
--- a/openssl.c
+++ b/openssl.c
@@ -16,9 +16,7 @@
 #include "error.h"
 #include "string.h"
 #include "crypt.h"
-#include "fd.h"
 #include "crypt_backend.h"
-#include "base64.h"
 #include "portable_io.h"
 
 struct asymmetric_key {
@@ -45,7 +43,7 @@ void get_random_bytes_or_die(unsigned char *buf, int num)
  * \sa RAND_load_file(3), \ref get_random_bytes_or_die(), srandom(3),
  * random(3), \ref para_random().
  */
-void init_random_seed_or_die(void)
+void crypt_init(void)
 {
        int seed, ret = RAND_load_file("/dev/urandom", 64);
 
@@ -141,47 +139,28 @@ fail:
 
 int get_public_key(const char *key_file, struct asymmetric_key **result)
 {
-       struct asymmetric_key *key = NULL;
-       void *map = NULL;
-       unsigned char *blob = NULL;
-       size_t map_size, encoded_size, decoded_size;
-       int ret, ret2;
-       char *cp;
+       unsigned char *blob;
+       size_t decoded_size;
+       int ret;
+       struct asymmetric_key *key = para_malloc(sizeof(*key));
 
-       key = para_malloc(sizeof(*key));
-       ret = mmap_full_file(key_file, O_RDONLY, &map, &map_size, NULL);
+       ret = decode_ssh_key(key_file, &blob, &decoded_size);
        if (ret < 0)
                goto out;
-       ret = is_ssh_rsa_key(map, map_size);
-       if (!ret) {
-               ret = -E_SSH_PARSE;
-               goto out_unmap;
-       }
-       cp = map + ret;
-       encoded_size = map_size - ret;
-       PARA_INFO_LOG("decoding public rsa-ssh key %s\n", key_file);
-       ret = uudecode(cp, encoded_size, (char **)&blob, &decoded_size);
-       if (ret < 0)
-               goto out_unmap;
-       ret = check_ssh_key_header(blob, decoded_size);
-       if (ret < 0)
-               goto out_unmap;
        ret = read_rsa_bignums(blob + ret, decoded_size - ret, &key->rsa);
        if (ret < 0)
-               goto out_unmap;
+               goto free_blob;
        ret = RSA_size(key->rsa);
-out_unmap:
-       ret2 = para_munmap(map, map_size);
-       if (ret >= 0 && ret2 < 0)
-               ret = ret2;
+       assert(ret > 0);
+       *result = key;
+free_blob:
+       free(blob);
 out:
        if (ret < 0) {
                free(key);
                *result = NULL;
-               PARA_ERROR_LOG("key %s: %s\n", key_file, para_strerror(-ret));
-       } else
-               *result = key;
-       free(blob);
+               PARA_ERROR_LOG("can not load key %s\n", key_file);
+       }
        return ret;
 }