X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=gcrypt.c;h=9b05a9494c23503702f88b27716468942b15d805;hp=1fde479e1be97656bd01002a2071a3d6f1b4b026;hb=686310d4b954efec5d5dcc8b4a143c294bb02739;hpb=8d106ca317a2c42f35a86ba244f843688f6939e6 diff --git a/gcrypt.c b/gcrypt.c index 1fde479e..9b05a949 100644 --- a/gcrypt.c +++ b/gcrypt.c @@ -1,8 +1,4 @@ -/* - * Copyright (C) 2011 Andre Noll - * - * Licensed under the GPL v2. For licencing details see COPYING. - */ +/* Copyright (C) 2011 Andre Noll , see file COPYING. */ /** \file gcrypt.c Libgrcypt-based encryption/decryption routines. */ @@ -56,21 +52,41 @@ void get_random_bytes_or_die(unsigned char *buf, int num) } /* - * This is called at the beginning of every program that uses libgcrypt. We - * don't have to initialize any random seed here, but we must initialize the - * gcrypt library. This task is performed by gcry_check_version() which can - * also check that the gcrypt library version is at least the minimal required - * version. + * This is called at the beginning of every program that uses libgcrypt. The + * call to gcry_check_version() initializes the gcrypt library and checks that + * we have at least the minimal required version. */ -void init_random_seed_or_die(void) +void crypt_init(void) { const char *req_ver = "1.5.0"; + int seed; - if (gcry_check_version(req_ver)) - return; - PARA_EMERG_LOG("fatal: need at least libgcrypt-%s, have: %s\n", - req_ver, gcry_check_version(NULL)); - exit(EXIT_FAILURE); + if (!gcry_check_version(req_ver)) { + PARA_EMERG_LOG("fatal: need at least libgcrypt-%s, have: %s\n", + req_ver, gcry_check_version(NULL)); + exit(EXIT_FAILURE); + } + + /* + * Allocate a pool of secure memory. This also drops privileges where + * needed. + */ + gcry_control(GCRYCTL_INIT_SECMEM, 65536, 0); + + /* Tell Libgcrypt that initialization has completed. */ + gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); + + get_random_bytes_or_die((unsigned char *)&seed, sizeof(seed)); + srandom(seed); +} + +void crypt_shutdown(void) +{ + /* + * WK does not see a way to apply a patch for the sake of Valgrind, so + * as of 2018 libgrypt has no deinitialization routine to free the + * resources on exit. + */ } /** S-expression for the public part of an RSA key. */ @@ -90,12 +106,17 @@ static const char *gcrypt_strerror(gcry_error_t gret) return gcry_strerror(gcry_err_code(gret)); } -static int decode_key(const char *key_file, const char *header_str, - const char *footer_str, unsigned char **result) +/** Private keys start with this header. */ +#define PRIVATE_KEY_HEADER "-----BEGIN RSA PRIVATE KEY-----" +/** Private keys end with this footer. */ +#define PRIVATE_KEY_FOOTER "-----END RSA PRIVATE KEY-----" + +static int decode_key(const char *key_file, unsigned char **result, + size_t *blob_size) { int ret, ret2, i, j; void *map; - size_t map_size, key_size, blob_size; + size_t map_size, key_size; unsigned char *blob = NULL; char *begin, *footer, *key; @@ -103,13 +124,13 @@ static int decode_key(const char *key_file, const char *header_str, if (ret < 0) goto out; ret = -E_KEY_MARKER; - if (strncmp(map, header_str, strlen(header_str))) + if (strncmp(map, PRIVATE_KEY_HEADER, strlen(PRIVATE_KEY_HEADER))) goto unmap; - footer = strstr(map, footer_str); + footer = strstr(map, PRIVATE_KEY_FOOTER); ret = -E_KEY_MARKER; if (!footer) goto unmap; - begin = map + strlen(header_str); + begin = map + strlen(PRIVATE_KEY_HEADER); /* skip whitespace at the beginning */ for (; begin < footer; begin++) { if (para_isspace(*begin)) @@ -128,15 +149,8 @@ static int decode_key(const char *key_file, const char *header_str, key[j++] = begin[i]; } key[j] = '\0'; - ret = base64_decode(key, j, (char **)&blob, &blob_size); + ret = base64_decode(key, j, (char **)&blob, blob_size); free(key); - if (ret < 0) - goto free_unmap; - ret = blob_size; - goto unmap; -free_unmap: - free(blob); - blob = NULL; unmap: ret2 = para_munmap(map, map_size); if (ret >= 0 && ret2 < 0) @@ -221,7 +235,7 @@ static int read_bignum(unsigned char *start, unsigned char *end, gcry_mpi_t *bn, PARA_DEBUG_LOG("bn_size %d (0x%x)\n", bn_size, (unsigned)bn_size); gret = gcry_mpi_scan(bn, GCRYMPI_FMT_STD, cp, bn_size, NULL); if (gret) { - PARA_ERROR_LOG("%s while scanning n\n", + PARA_ERROR_LOG("gcry_mpi_scan: %s\n", gcry_strerror(gcry_err_code(gret))); return-E_MPI_SCAN; } @@ -274,28 +288,21 @@ static int find_privkey_bignum_offset(const unsigned char *data, int len) return p - data; } -/** Private keys start with this header. */ -#define PRIVATE_KEY_HEADER "-----BEGIN RSA PRIVATE KEY-----" -/** Private keys end with this footer. */ -#define PRIVATE_KEY_FOOTER "-----END RSA PRIVATE KEY-----" - static int get_private_key(const char *key_file, struct asymmetric_key **result) { gcry_mpi_t n = NULL, e = NULL, d = NULL, p = NULL, q = NULL, u = NULL; unsigned char *blob, *cp, *end; - int blob_size, ret, n_size; + int ret, n_size; gcry_error_t gret; - size_t erroff; + size_t erroff, blob_size; gcry_sexp_t sexp; struct asymmetric_key *key; *result = NULL; - ret = decode_key(key_file, PRIVATE_KEY_HEADER, PRIVATE_KEY_FOOTER, - &blob); + ret = decode_key(key_file, &blob, &blob_size); if (ret < 0) return ret; - blob_size = ret; end = blob + blob_size; ret = find_privkey_bignum_offset(blob, blob_size); if (ret < 0) @@ -369,27 +376,21 @@ free_blob: return ret; } -static int get_ssh_public_key(unsigned char *data, int size, gcry_sexp_t *result) +int apc_get_pubkey(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); + ret = decode_ssh_key(key_file, &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); - 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) { @@ -398,8 +399,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; @@ -410,17 +409,19 @@ 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))); ret = -E_SEXP_BUILD; goto release_n; } - ret = nr_scanned / 32 * 32; + ret = ROUND_DOWN(nr_scanned, 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: @@ -430,43 +431,7 @@ 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) +void apc_free_pubkey(struct asymmetric_key *key) { if (!key) return; @@ -484,7 +449,7 @@ static int decode_rsa(gcry_sexp_t sexp, unsigned char *outbuf, size_t *nbytes) return 1; } -int priv_decrypt(const char *key_file, unsigned char *outbuf, +int apc_priv_decrypt(const char *key_file, unsigned char *outbuf, unsigned char *inbuf, int inlen) { gcry_error_t gret; @@ -551,7 +516,7 @@ free_key: return ret; } -int pub_encrypt(struct asymmetric_key *pub, unsigned char *inbuf, +int apc_pub_encrypt(struct asymmetric_key *pub, unsigned char *inbuf, unsigned len, unsigned char *outbuf) { gcry_error_t gret;