X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=gcrypt.c;h=1ae7cfb0deb4fb591dc97bcb5491b7cc54ec920a;hp=ea1e7710d01c53f5fd300444970806715ad14241;hb=d9f54f439c98aed8b974f55acd468bdae424683f;hpb=466c9b7ef6663bcda1aeadf324f74187816da32a diff --git a/gcrypt.c b/gcrypt.c index ea1e7710..1ae7cfb0 100644 --- a/gcrypt.c +++ b/gcrypt.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2012 Andre Noll + * Copyright (C) 2011 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -15,6 +15,7 @@ #include "crypt.h" #include "crypt_backend.h" #include "fd.h" +#include "base64.h" //#define GCRYPT_DEBUG 1 @@ -26,7 +27,7 @@ static void dump_buffer(const char *msg, unsigned char *buf, int len) { int i; - fprintf(stderr, "%s (%u bytes): ", msg, len); + fprintf(stderr, "%s (%d bytes): ", msg, len); for (i = 0; i < len; i++) fprintf(stderr, "%02x ", buf[i]); fprintf(stderr, "\n"); @@ -87,7 +88,7 @@ void init_random_seed_or_die(void) } /** S-expression for the public part of an RSA key. */ -#define RSA_PUBKEY_SEXP "(public-key (rsa (n %m) (e %m)))" +#define RSA_PUBKEY_SEXP "(public-key (rsa (n %m) (e %m)))" /** S-expression for a private RSA key. */ #define RSA_PRIVKEY_SEXP "(private-key (rsa (n %m) (e %m) (d %m) (p %m) (q %m) (u %m)))" @@ -97,7 +98,7 @@ static void mgf1(unsigned char *seed, size_t seed_len, unsigned result_len, { gcry_error_t gret; gcry_md_hd_t handle; - size_t n;; + size_t n; unsigned char *md; unsigned char octet_string[4], *rp = result, *end = rp + result_len; @@ -212,7 +213,7 @@ static int decode_key(const char *key_file, const char *header_str, ret = mmap_full_file(key_file, O_RDONLY, &map, &map_size, NULL); if (ret < 0) - return ret; + goto out; ret = -E_KEY_MARKER; if (strncmp(map, header_str, strlen(header_str))) goto unmap; @@ -239,13 +240,11 @@ static int decode_key(const char *key_file, const char *header_str, key[j++] = begin[i]; } key[j] = '\0'; - //PARA_CRIT_LOG("key: %s\n", key); - blob_size = key_size * 2; - blob = para_malloc(blob_size); - ret = base64_decode(key, 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); @@ -258,6 +257,7 @@ unmap: free(blob); blob = NULL; } +out: *result = blob; return ret; } @@ -275,14 +275,14 @@ enum asn1_types { /* bit 6 has value 0 */ static inline bool is_primitive(unsigned char c) { - return ((c & (1<<6)) == 0); + return (c & (1<<6)) == 0; } static inline bool is_primitive_integer(unsigned char c) { if (!is_primitive(c)) return false; - return ((c & 0x1f) == ASN1_TYPE_INTEGER); + return (c & 0x1f) == ASN1_TYPE_INTEGER; } /* Bit 8 is zero (and bits 7-1 give the length) */ @@ -301,64 +301,6 @@ static inline int get_long_form_num_length_bytes(unsigned char c) return c & 0x7f; } -static int find_pubkey_bignum_offset(const unsigned char *data, int len) -{ - const unsigned char *p = data, *end = data + len; - - /* the whole thing istarts with one sequence */ - if (*p != ASN1_TYPE_SEQUENCE) - return -E_ASN1_PARSE; - p++; - if (p >= end) - return -E_ASN1_PARSE; - if (is_short_form(*p)) - p++; - else - p += 1 + get_long_form_num_length_bytes(*p); - if (p >= end) - return -E_ASN1_PARSE; - /* another sequence containing the object id, skip it */ - if (*p != ASN1_TYPE_SEQUENCE) - return -E_ASN1_PARSE; - p++; - if (p >= end) - return -E_ASN1_PARSE; - if (!is_short_form(*p)) - return -E_ASN1_PARSE; - p += 1 + get_short_form_length(*p); - if (p >= end) - return -E_ASN1_PARSE; - /* all numbers are wrapped in a bit string object that follows */ - if (*p != ASN1_TYPE_BIT_STRING) - return -E_ASN1_PARSE; - p++; - if (p >= end) - return -E_ASN1_PARSE; - if (is_short_form(*p)) - p++; - else - p += 1 + get_long_form_num_length_bytes(*p); - p++; /* skip number of unused bits in the bit string */ - if (p >= end) - return -E_ASN1_PARSE; - - /* next, we have a sequence of two integers (n and e) */ - if (*p != ASN1_TYPE_SEQUENCE) - return -E_ASN1_PARSE; - p++; - if (p >= end) - return -E_ASN1_PARSE; - if (is_short_form(*p)) - p++; - else - p += 1 + get_long_form_num_length_bytes(*p); - if (p >= end) - return -E_ASN1_PARSE; - if (*p != ASN1_TYPE_INTEGER) - return -E_ASN1_PARSE; - return p - data; -} - /* * 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 @@ -388,7 +330,7 @@ static int read_bignum(unsigned char *start, unsigned char *end, gcry_mpi_t *bn, for (i = 0; i < num_bytes; i++, cp++) bn_size = (bn_size << 8) + *cp; } - PARA_DEBUG_LOG("bn_size %d (0x%x)\n", bn_size, bn_size); + 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", @@ -429,7 +371,7 @@ static int find_privkey_bignum_offset(const unsigned char *data, int len) if (p >= end) return -E_ASN1_PARSE; - /* Skip next integer */ + /* skip next integer */ if (*p != ASN1_TYPE_INTEGER) return -E_ASN1_PARSE; p++; @@ -460,6 +402,7 @@ static int get_private_key(const char *key_file, struct asymmetric_key **result) gcry_sexp_t sexp; struct asymmetric_key *key; + *result = NULL; ret = decode_key(key_file, PRIVATE_KEY_HEADER, PRIVATE_KEY_FOOTER, &blob); if (ret < 0) @@ -538,64 +481,6 @@ free_blob: return ret; } -/** Public keys start with this header. */ -#define PUBLIC_KEY_HEADER "-----BEGIN PUBLIC KEY-----" -/** Public keys end with this footer. */ -#define PUBLIC_KEY_FOOTER "-----END PUBLIC KEY-----" - -static int get_asn_public_key(const char *key_file, struct asymmetric_key **result) -{ - gcry_mpi_t n = NULL, e = 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; - - ret = decode_key(key_file, PUBLIC_KEY_HEADER, PUBLIC_KEY_FOOTER, - &blob); - if (ret < 0) - return ret; - blob_size = ret; - end = blob + blob_size; - ret = find_pubkey_bignum_offset(blob, blob_size); - if (ret < 0) - goto free_blob; - PARA_DEBUG_LOG("decoding public RSA params at offset %d\n", ret); - cp = blob + ret; - - ret = read_bignum(cp, end, &n, &n_size); - if (ret < 0) - goto free_blob; - cp += ret; - - ret = read_bignum(cp, end, &e, NULL); - if (ret < 0) - goto release_n; - - 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_e; - } - key = para_malloc(sizeof(*key)); - key->sexp = sexp; - *result = key; - ret = n_size; - PARA_INFO_LOG("successfully read %u bit asn public key\n", n_size * 8); - -release_e: - gcry_mpi_release(e); -release_n: - gcry_mpi_release(n); -free_blob: - free(blob); - return ret; -} - static int get_ssh_public_key(unsigned char *data, int size, gcry_sexp_t *result) { int ret; @@ -604,14 +489,10 @@ static int get_ssh_public_key(unsigned char *data, int size, gcry_sexp_t *result size_t nr_scanned, erroff, decoded_size; gcry_mpi_t e = NULL, n = NULL; - PARA_DEBUG_LOG("decoding %d byte public rsa-ssh key\n", size); - if (size > INT_MAX / 4) - return -ERRNO_TO_PARA_ERROR(EOVERFLOW); - blob = para_malloc(2 * size); - ret = uudecode((char *)data, blob, 2 * size); + 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; - decoded_size = ret; end = blob + decoded_size; dump_buffer("decoded key", blob, decoded_size); ret = check_ssh_key_header(blob, decoded_size); @@ -651,7 +532,7 @@ static int get_ssh_public_key(unsigned char *data, int size, gcry_sexp_t *result goto release_n; } ret = nr_scanned / 32 * 32; - PARA_INFO_LOG("successfully read %u bit ssh public key\n", ret * 8); + PARA_INFO_LOG("successfully read %d bit ssh public key\n", ret * 8); release_n: gcry_mpi_release(n); release_e: @@ -661,8 +542,7 @@ free_blob: return ret; } -int get_asymmetric_key(const char *key_file, int private, - struct asymmetric_key **result) +int get_public_key(const char *key_file, struct asymmetric_key **result) { int ret, ret2; void *map; @@ -671,17 +551,13 @@ int get_asymmetric_key(const char *key_file, int private, gcry_sexp_t sexp; struct asymmetric_key *key; - if (private) - return get_private_key(key_file, result); 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) { - ret = para_munmap(map, map_size); - if (ret < 0) - return ret; - return get_asn_public_key(key_file, result); + para_munmap(map, map_size); + return -E_SSH_PARSE; } start = map + ret; end = map + map_size; @@ -702,7 +578,7 @@ unmap: return ret; } -void free_asymmetric_key(struct asymmetric_key *key) +void free_public_key(struct asymmetric_key *key) { if (!key) return; @@ -758,13 +634,13 @@ static int decode_rsa(gcry_sexp_t sexp, int key_size, unsigned char *outbuf, PARA_DEBUG_LOG("decrypted buffer before unpad (%d bytes):\n", key_size); - dump_buffer("non-unpadded decrypted buffer", oaep_buf, key_size);; + dump_buffer("non-unpadded decrypted buffer", oaep_buf, key_size); ret = unpad_oaep(oaep_buf, key_size, outbuf, nbytes); if (ret < 0) goto out_mpi_release; PARA_DEBUG_LOG("decrypted buffer after unpad (%zu bytes):\n", *nbytes); - dump_buffer("unpadded decrypted buffer", outbuf, *nbytes);; + dump_buffer("unpadded decrypted buffer", outbuf, *nbytes); ret = 1; out_mpi_release: gcry_mpi_release(out_mpi); @@ -781,6 +657,9 @@ int priv_decrypt(const char *key_file, unsigned char *outbuf, gcry_sexp_t in, out, priv_key; size_t nbytes; + ret = check_private_key_file(key_file); + if (ret < 0) + return ret; PARA_INFO_LOG("decrypting %d byte input\n", inlen); /* key_file -> asymmetric key priv */ ret = get_private_key(key_file, &priv); @@ -831,7 +710,8 @@ in_mpi_release: key_release: gcry_sexp_release(priv_key); free_key: - free_asymmetric_key(priv); + gcry_sexp_release(priv->sexp); + free(priv); return ret; } @@ -912,11 +792,25 @@ struct stream_cipher { gcry_cipher_hd_t handle; }; -struct stream_cipher *sc_new(const unsigned char *data, int len) +struct stream_cipher *sc_new(const unsigned char *data, int len, + bool use_aes) { gcry_error_t gret; - struct stream_cipher *sc = para_malloc(sizeof(*sc)); + + if (use_aes) { + assert(len >= 2 * AES_CRT128_BLOCK_SIZE); + gret = gcry_cipher_open(&sc->handle, GCRY_CIPHER_AES128, + GCRY_CIPHER_MODE_CTR, 0); + assert(gret == 0); + gret = gcry_cipher_setkey(sc->handle, data, + AES_CRT128_BLOCK_SIZE); + assert(gret == 0); + gret = gcry_cipher_setctr(sc->handle, + data + AES_CRT128_BLOCK_SIZE, AES_CRT128_BLOCK_SIZE); + assert(gret == 0); + return sc; + } gret = gcry_cipher_open(&sc->handle, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0); if (gret) { @@ -937,35 +831,14 @@ void sc_free(struct stream_cipher *sc) free(sc); } -int sc_send_bin_buffer(struct stream_cipher_context *scc, char *buf, - size_t size) -{ - gcry_error_t gret; - int ret; - unsigned char *tmp = para_malloc(size); - - assert(size); - gret = gcry_cipher_encrypt(scc->send->handle, tmp, size, - (unsigned char *)buf, size); - assert(gret == 0); - ret = xwrite(scc->fd, (char *)tmp, size); - free(tmp); - return ret; -} - -int sc_recv_bin_buffer(struct stream_cipher_context *scc, char *buf, - size_t size) +void sc_crypt(struct stream_cipher *sc, struct iovec *src, struct iovec *dst) { + gcry_cipher_hd_t handle = sc->handle; gcry_error_t gret; - ssize_t ret = recv(scc->fd, buf, size, 0); - if (ret < 0) - ret = -ERRNO_TO_PARA_ERROR(errno); - if (ret <= 0) - return ret; /* perform in-place encryption */ - gret = gcry_cipher_encrypt(scc->recv->handle, (unsigned char *)buf, ret, + *dst = *src; + gret = gcry_cipher_encrypt(handle, src->iov_base, src->iov_len, NULL, 0); assert(gret == 0); - return ret; }