X-Git-Url: http://git.tuebingen.mpg.de/?a=blobdiff_plain;f=gcrypt.c;h=58fa507b6e1f96303998e0f6ba0ae47f90beb493;hb=3699a583f3a7e9514c0f47b8b07f56b050430b67;hp=8d6db3490db95057b32168c3302fd0e2a0ee4e48;hpb=ab98d5b8b03e0e2fdcf010fc8f6a6b0ab8f87564;p=paraslash.git diff --git a/gcrypt.c b/gcrypt.c index 8d6db349..58fa507b 100644 --- a/gcrypt.c +++ b/gcrypt.c @@ -56,7 +56,7 @@ void get_random_bytes_or_die(unsigned char *buf, int num) * 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; @@ -66,10 +66,29 @@ void init_random_seed_or_die(void) 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. */ #define RSA_PUBKEY_SEXP "(public-key (rsa (n %m) (e %m)))" /** S-expression for a private RSA key. */ @@ -87,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; @@ -100,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)) @@ -125,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) @@ -188,11 +205,11 @@ static inline int get_long_form_num_length_bytes(unsigned char c) /* * Returns: Number of bytes scanned. This may differ from the value returned via - * bn_bytes because the latter does not include the ASN.1 prefix and a leading - * zero is not considered as an additional byte for bn_bytes. + * bitsp because the latter does not include the ASN.1 prefix and a leading + * zero is not considered as an additional byte for the number of bits. */ static int read_bignum(unsigned char *start, unsigned char *end, gcry_mpi_t *bn, - int *bn_bytes) + unsigned *bitsp) { int i, bn_size; gcry_error_t gret; @@ -218,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; } @@ -230,8 +247,8 @@ static int read_bignum(unsigned char *start, unsigned char *end, gcry_mpi_t *bn, cp++; bn_size--; } - if (bn_bytes) - *bn_bytes = bn_size; + if (bitsp) + *bitsp = bn_size * 8; cp += bn_size; // unsigned char *buf; // gcry_mpi_aprint(GCRYMPI_FMT_HEX, &buf, NULL, *bn); @@ -239,6 +256,54 @@ static int read_bignum(unsigned char *start, unsigned char *end, gcry_mpi_t *bn, return cp - start; } +struct rsa_params { + gcry_mpi_t n, e, d, p, q, u; +}; + +static int read_pem_rsa_params(unsigned char *start, unsigned char *end, + struct rsa_params *p) +{ + unsigned char *cp = start; + unsigned bits; + int ret; + + ret = read_bignum(cp, end, &p->n, &bits); + if (ret < 0) + return ret; + cp += ret; + ret = read_bignum(cp, end, &p->e, NULL); + if (ret < 0) + goto release_n; + cp += ret; + ret = read_bignum(cp, end, &p->d, NULL); + if (ret < 0) + goto release_e; + cp += ret; + ret = read_bignum(cp, end, &p->p, NULL); + if (ret < 0) + goto release_d; + cp += ret; + ret = read_bignum(cp, end, &p->q, NULL); + if (ret < 0) + goto release_p; + cp += ret; + ret = read_bignum(cp, end, &p->u, NULL); + if (ret < 0) + goto release_q; + return bits; +release_q: + gcry_mpi_release(p->q); +release_p: + gcry_mpi_release(p->p); +release_d: + gcry_mpi_release(p->d); +release_e: + gcry_mpi_release(p->e); +release_n: + gcry_mpi_release(p->n); + return ret; +} + static int find_privkey_bignum_offset(const unsigned char *data, int len) { const unsigned char *p = data, *end = data + len; @@ -271,96 +336,60 @@ 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; + struct rsa_params params; + unsigned char *blob, *end; + int ret; + unsigned bits; 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) goto free_blob; PARA_INFO_LOG("reading RSA params at offset %d\n", ret); - cp = blob + ret; - - ret = read_bignum(cp, end, &n, &n_size); + ret = read_pem_rsa_params(blob + ret, end, ¶ms); if (ret < 0) goto free_blob; - cp += ret; - - ret = read_bignum(cp, end, &e, NULL); - if (ret < 0) - goto release_n; - cp += ret; - - ret = read_bignum(cp, end, &d, NULL); - if (ret < 0) - goto release_e; - cp += ret; - - ret = read_bignum(cp, end, &p, NULL); - if (ret < 0) - goto release_d; - cp += ret; - - ret = read_bignum(cp, end, &q, NULL); - if (ret < 0) - goto release_p; - cp += ret; - ret = read_bignum(cp, end, &u, NULL); - if (ret < 0) - goto release_q; + bits = ret; /* * OpenSSL uses slightly different parameters than gcrypt. To use these * parameters we need to swap the values of p and q and recompute u. */ - if (gcry_mpi_cmp(p, q) > 0) { - gcry_mpi_swap(p, q); - gcry_mpi_invm(u, p, q); + if (gcry_mpi_cmp(params.p, params.q) > 0) { + gcry_mpi_swap(params.p, params.q); + gcry_mpi_invm(params.u, params.p, params.q); } - gret = gcry_sexp_build(&sexp, &erroff, RSA_PRIVKEY_SEXP, - n, e, d, p, q, u); + gret = gcry_sexp_build(&sexp, &erroff, RSA_PRIVKEY_SEXP, params.n, + params.e, params.d, params.p, params.q, params.u); if (gret) { PARA_ERROR_LOG("offset %zu: %s\n", erroff, gcry_strerror(gcry_err_code(gret))); ret = -E_SEXP_BUILD; - goto release_u; + goto free_params; } key = para_malloc(sizeof(*key)); key->sexp = sexp; *result = key; - ret = n_size * 8; + ret = bits; PARA_INFO_LOG("succesfully read %d bit private key\n", ret); -release_u: - gcry_mpi_release(u); -release_q: - gcry_mpi_release(q); -release_p: - gcry_mpi_release(p); -release_d: - gcry_mpi_release(d); -release_e: - gcry_mpi_release(e); -release_n: - gcry_mpi_release(n); +free_params: + gcry_mpi_release(params.n); + gcry_mpi_release(params.e); + gcry_mpi_release(params.d); + gcry_mpi_release(params.u); + gcry_mpi_release(params.p); + gcry_mpi_release(params.q); + free_blob: free(blob); return ret;