From: Andre Noll Date: Thu, 28 Dec 2017 00:41:14 +0000 (+0100) Subject: crypt: Deduplicate get_public_key(). X-Git-Tag: v0.6.2~5^2~5 X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=commitdiff_plain;h=5f20d9afde364f9ce51aa7841ebe513028a65e81;hp=93ad956d88ffd117a6f81c5e38d9aaed3ae8b6e9 crypt: Deduplicate get_public_key(). 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. --- diff --git a/crypt_backend.h b/crypt_backend.h index ff956ce3..175a6881 100644 --- a/crypt_backend.h +++ b/crypt_backend.h @@ -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); diff --git a/crypt_common.c b/crypt_common.c index 08361b27..235b8b8d 100644 --- a/crypt_common.c +++ b/crypt_common.c @@ -10,20 +10,19 @@ #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. * diff --git a/gcrypt.c b/gcrypt.c index 052546dd..2398a605 100644 --- 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) diff --git a/openssl.c b/openssl.c index f786ce29..99b3f7a6 100644 --- 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; }