X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=gcrypt.c;h=dbe4900862fef83a552d9c60d9ac21d4c8253d5e;hp=694c0adb8454b73dc0e5b67876fc7a03617b61d0;hb=refs%2Fheads%2Fpu;hpb=6bded356ec89b1344049ff702e6c6babaeccd439 diff --git a/gcrypt.c b/gcrypt.c index 694c0adb..e5f64688 100644 --- a/gcrypt.c +++ b/gcrypt.c @@ -46,6 +46,22 @@ void hash_function(const char *data, unsigned long len, unsigned char *hash) gcry_md_close(handle); } +void hash2_function(const char *data, unsigned long len, unsigned char *hash) +{ + gcry_error_t gret; + gcry_md_hd_t handle; + unsigned char *md; + + gret = gcry_md_open(&handle, GCRY_MD_SHA256, 0); + assert(gret == 0); + gcry_md_write(handle, data, (size_t)len); + gcry_md_final(handle); + md = gcry_md_read(handle, GCRY_MD_SHA256); + assert(md); + memcpy(hash, md, HASH2_SIZE); + gcry_md_close(handle); +} + void get_random_bytes_or_die(unsigned char *buf, int num) { gcry_randomize(buf, (size_t)num, GCRY_STRONG_RANDOM); @@ -98,7 +114,7 @@ void crypt_shutdown(void) struct asymmetric_key { gcry_sexp_t sexp; - int num_bytes; + int bits; }; static const char *gcrypt_strerror(gcry_error_t gret) @@ -106,66 +122,6 @@ 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) -{ - int ret, ret2, i, j; - void *map; - size_t map_size, key_size, blob_size; - unsigned char *blob = NULL; - char *begin, *footer, *key; - - ret = mmap_full_file(key_file, O_RDONLY, &map, &map_size, NULL); - if (ret < 0) - goto out; - ret = -E_KEY_MARKER; - if (strncmp(map, header_str, strlen(header_str))) - goto unmap; - footer = strstr(map, footer_str); - ret = -E_KEY_MARKER; - if (!footer) - goto unmap; - begin = map + strlen(header_str); - /* skip whitespace at the beginning */ - for (; begin < footer; begin++) { - if (para_isspace(*begin)) - continue; - break; - } - ret = -E_KEY_MARKER; - if (begin >= footer) - goto unmap; - - key_size = footer - begin; - key = para_malloc(key_size + 1); - for (i = 0, j = 0; begin + i < footer; i++) { - if (para_isspace(begin[i])) - continue; - key[j++] = begin[i]; - } - key[j] = '\0'; - 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) - ret = ret2; - if (ret < 0) { - free(blob); - blob = NULL; - } -out: - *result = blob; - return ret; -} - /** ASN Types and their code. */ enum asn1_types { /** The next object is an integer. */ @@ -207,11 +163,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) +static int read_pem_bignum(unsigned char *start, unsigned char *end, gcry_mpi_t *bn, + unsigned *bitsp) { int i, bn_size; gcry_error_t gret; @@ -249,8 +205,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); @@ -258,7 +214,55 @@ static int read_bignum(unsigned char *start, unsigned char *end, gcry_mpi_t *bn, return cp - start; } -static int find_privkey_bignum_offset(const unsigned char *data, int len) +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_pem_bignum(cp, end, &p->n, &bits); + if (ret < 0) + return ret; + cp += ret; + ret = read_pem_bignum(cp, end, &p->e, NULL); + if (ret < 0) + goto release_n; + cp += ret; + ret = read_pem_bignum(cp, end, &p->d, NULL); + if (ret < 0) + goto release_e; + cp += ret; + ret = read_pem_bignum(cp, end, &p->p, NULL); + if (ret < 0) + goto release_d; + cp += ret; + ret = read_pem_bignum(cp, end, &p->q, NULL); + if (ret < 0) + goto release_p; + cp += ret; + ret = read_pem_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_pem_bignum_offset(const unsigned char *data, int len) { const unsigned char *p = data, *end = data + len; @@ -290,96 +294,131 @@ 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) +static int read_openssh_bignum(unsigned char *start, unsigned char *end, + gcry_mpi_t *bn, unsigned *bitsp) { - 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; gcry_error_t gret; - size_t erroff; - gcry_sexp_t sexp; - struct asymmetric_key *key; + size_t nscanned; + unsigned bits; - *result = NULL; - ret = decode_key(key_file, PRIVATE_KEY_HEADER, PRIVATE_KEY_FOOTER, - &blob); - 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; + gret = gcry_mpi_scan(bn, GCRYMPI_FMT_SSH, start, end - start, &nscanned); + if (gret) { + PARA_ERROR_LOG("gcry_mpi_scan: %s\n", + gcry_strerror(gcry_err_code(gret))); + return -E_MPI_SCAN; + } + bits = (nscanned - 4 - (start[4] == '\0')) * 8; + if (bitsp) + *bitsp = bits; + PARA_DEBUG_LOG("scanned %u-bit bignum\n", bits); + return nscanned; +} + +static int read_openssh_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, &n, &n_size); + ret = read_openssh_bignum(cp, end, &p->n, &bits); if (ret < 0) - goto free_blob; + return ret; cp += ret; - - ret = read_bignum(cp, end, &e, NULL); + ret = read_openssh_bignum(cp, end, &p->e, NULL); if (ret < 0) goto release_n; cp += ret; - - ret = read_bignum(cp, end, &d, NULL); + ret = read_openssh_bignum(cp, end, &p->d, NULL); if (ret < 0) goto release_e; cp += ret; - - ret = read_bignum(cp, end, &p, NULL); + ret = read_openssh_bignum(cp, end, &p->u, NULL); if (ret < 0) goto release_d; cp += ret; - - ret = read_bignum(cp, end, &q, NULL); + ret = read_openssh_bignum(cp, end, &p->p, NULL); if (ret < 0) - goto release_p; + goto release_u; cp += ret; - ret = read_bignum(cp, end, &u, NULL); + ret = read_openssh_bignum(cp, end, &p->q, NULL); if (ret < 0) - goto release_q; + goto release_p; + return bits; +release_p: + gcry_mpi_release(p->p); +release_u: + gcry_mpi_release(p->u); +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 get_private_key(const char *key_file, struct asymmetric_key **result) +{ + struct rsa_params params; + unsigned char *blob, *end; + unsigned bits; + int ret, key_type; + gcry_error_t gret; + size_t erroff, blob_size; + gcry_sexp_t sexp; + struct asymmetric_key *key; + + *result = NULL; + ret = decode_private_key(key_file, &blob, &blob_size); + if (ret < 0) + return ret; + key_type = ret; + end = blob + blob_size; + if (key_type == PKT_PEM) + ret = find_pem_bignum_offset(blob, blob_size); + else + ret = find_openssh_bignum_offset(blob, blob_size); + if (ret < 0) + goto free_blob; + PARA_INFO_LOG("reading RSA params at offset %d\n", ret); + if (key_type == PKT_PEM) + ret = read_pem_rsa_params(blob + ret, end, ¶ms); + else + ret = read_openssh_rsa_params(blob + ret, end, ¶ms); + if (ret < 0) + goto free_blob; + 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 = alloc(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; @@ -390,34 +429,25 @@ int apc_get_pubkey(const char *key_file, struct asymmetric_key **result) unsigned char *blob, *p, *end; int ret; gcry_error_t gret; - size_t nr_scanned, erroff, decoded_size; + size_t erroff, decoded_size; gcry_mpi_t e, n; gcry_sexp_t sexp; struct asymmetric_key *key; + unsigned bits; - ret = decode_ssh_key(key_file, &blob, &decoded_size); + ret = decode_public_key(key_file, &blob, &decoded_size); if (ret < 0) return ret; p = blob + ret; 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) { - ret = -E_MPI_SCAN; - PARA_CRIT_LOG("%s\n", gcry_strerror(gcry_err_code(gret))); + ret = read_openssh_bignum(p, end, &e, NULL); + if (ret < 0) goto free_blob; - } - PARA_DEBUG_LOG("scanned e (%zu bytes)\n", nr_scanned); - p += nr_scanned; - if (p >= end) - goto release_e; - gret = gcry_mpi_scan(&n, GCRYMPI_FMT_SSH, p, end - p, &nr_scanned); - if (gret) { - ret = -E_MPI_SCAN; - PARA_ERROR_LOG("%s\n", gcry_strerror(gcry_err_code(gret))); + p += ret; + ret = read_openssh_bignum(p, end, &n, &bits); + if (ret < 0) goto release_e; - } - PARA_DEBUG_LOG("scanned n (%zu bytes)\n", nr_scanned); gret = gcry_sexp_build(&sexp, &erroff, RSA_PUBKEY_SEXP, n, e); if (gret) { PARA_ERROR_LOG("offset %zu: %s\n", erroff, @@ -425,12 +455,12 @@ int apc_get_pubkey(const char *key_file, struct asymmetric_key **result) ret = -E_SEXP_BUILD; goto release_n; } - 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; + PARA_INFO_LOG("successfully read %u bit ssh public key\n", bits); + key = alloc(sizeof(*key)); key->sexp = sexp; + key->bits = bits; *result = key; + ret = bits / 8; release_n: gcry_mpi_release(n); release_e: @@ -448,17 +478,20 @@ void apc_free_pubkey(struct asymmetric_key *key) free(key); } -static int decode_rsa(gcry_sexp_t sexp, unsigned char *outbuf, size_t *nbytes) +static int decode_rsa(gcry_sexp_t sexp, unsigned char **outbuf, size_t *nbytes) { const char *p = gcry_sexp_nth_data(sexp, 1, nbytes); - if (!p) + if (!p) { + *outbuf = NULL; return -E_RSA_DECODE; - memcpy(outbuf, p, *nbytes); + } + *outbuf = alloc(*nbytes); + memcpy(*outbuf, p, *nbytes); return 1; } -int apc_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; @@ -468,6 +501,7 @@ int apc_priv_decrypt(const char *key_file, unsigned char *outbuf, gcry_sexp_t in, out, priv_key; size_t nbytes; + *outbuf = NULL; ret = check_private_key_file(key_file); if (ret < 0) return ret; @@ -526,7 +560,7 @@ free_key: } int apc_pub_encrypt(struct asymmetric_key *pub, unsigned char *inbuf, - unsigned len, unsigned char *outbuf) + unsigned len, unsigned char **outbuf) { gcry_error_t gret; gcry_sexp_t pub_key, in, out, out_a; @@ -534,8 +568,7 @@ int apc_pub_encrypt(struct asymmetric_key *pub, unsigned char *inbuf, size_t nbytes; int ret; - PARA_INFO_LOG("encrypting %u byte input with %d-byte key\n", len, pub->num_bytes); - + *outbuf = NULL; /* get pub key */ pub_key = gcry_sexp_find_token(pub->sexp, "public-key", 0); if (!pub_key) @@ -564,14 +597,18 @@ int apc_pub_encrypt(struct asymmetric_key *pub, unsigned char *inbuf, ret = -E_SEXP_FIND; goto out_a_release; } - gret = gcry_mpi_print(GCRYMPI_FMT_USG, outbuf, 512 /* FIXME */, &nbytes, out_mpi); + *outbuf = alloc(pub->bits); + gret = gcry_mpi_print(GCRYMPI_FMT_USG, *outbuf, pub->bits, &nbytes, + out_mpi); if (gret) { + free(*outbuf); + *outbuf = NULL; PARA_ERROR_LOG("%s\n", gcrypt_strerror(gret)); ret = -E_SEXP_ENCRYPT; goto out_mpi_release; } PARA_INFO_LOG("encrypted buffer is %zu bytes\n", nbytes); - dump_buffer("enc buf", outbuf, nbytes); + dump_buffer("enc buf", *outbuf, nbytes); ret = nbytes; out_mpi_release: @@ -594,7 +631,7 @@ struct stream_cipher { struct stream_cipher *sc_new(const unsigned char *data, int len) { gcry_error_t gret; - struct stream_cipher *sc = para_malloc(sizeof(*sc)); + struct stream_cipher *sc = alloc(sizeof(*sc)); assert(len >= 2 * AES_CRT128_BLOCK_SIZE); gret = gcry_cipher_open(&sc->handle, GCRY_CIPHER_AES128,