From: Andre Noll Date: Wed, 27 Dec 2017 20:47:40 +0000 (+0100) Subject: Rename crypt.c -> openssl.c. X-Git-Tag: v0.6.2~5^2~7 X-Git-Url: http://git.tue.mpg.de/?a=commitdiff_plain;h=f1adf8b86e072e22353e0481d96d13f627c364b4;p=paraslash.git Rename crypt.c -> openssl.c. The old name made sense back when we had only one crypto backend. These days paraslash can be compiled against either openssl or gcrypt, so the new name makes it clear that the file is only compiled in if the openssl library was selected as the crypto backend. --- diff --git a/command.c b/command.c index cba2afb4..203fd47b 100644 --- a/command.c +++ b/command.c @@ -876,7 +876,7 @@ static int run_command(struct command_context *cc, struct iovec *iov) * the function if the connection was not authenticated when the timeout * expires. * - * \sa alarm(2), \ref crypt.c, \ref crypt.h. + * \sa alarm(2), \ref openssl.c, \ref crypt.h. */ __noreturn void handle_connect(int fd) { diff --git a/configure.ac b/configure.ac index 499571a7..9493f8e3 100644 --- a/configure.ac +++ b/configure.ac @@ -394,7 +394,7 @@ if test -n "$CRYPTOLIB" && test $HAVE_OSL = yes && test -n "$BISON" && \ version " if test "$CRYPTOLIB" = openssl; then - server_errlist_objs="$server_errlist_objs crypt" + server_errlist_objs="$server_errlist_objs openssl" else server_errlist_objs="$server_errlist_objs gcrypt" fi @@ -432,7 +432,7 @@ if test -n "$CRYPTOLIB"; then version " if test "$CRYPTOLIB" = openssl; then - client_errlist_objs="$client_errlist_objs crypt" + client_errlist_objs="$client_errlist_objs openssl" else client_errlist_objs="$client_errlist_objs gcrypt" fi @@ -488,7 +488,7 @@ if test -n "$CRYPTOLIB"; then sync_filter " if test "$CRYPTOLIB" = openssl; then - audiod_errlist_objs="$audiod_errlist_objs crypt" + audiod_errlist_objs="$audiod_errlist_objs openssl" else audiod_errlist_objs="$audiod_errlist_objs gcrypt" fi diff --git a/crypt.c b/crypt.c deleted file mode 100644 index b8a587cd..00000000 --- a/crypt.c +++ /dev/null @@ -1,296 +0,0 @@ -/* Copyright (C) 2005 Andre Noll , see file COPYING. */ - -/** \file crypt.c Openssl-based encryption/decryption routines. */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "para.h" -#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 { - RSA *rsa; -}; - -void get_random_bytes_or_die(unsigned char *buf, int num) -{ - unsigned long err; - - /* RAND_bytes() returns 1 on success, 0 otherwise. */ - if (RAND_bytes(buf, num) == 1) - return; - err = ERR_get_error(); - PARA_EMERG_LOG("%s\n", ERR_reason_error_string(err)); - exit(EXIT_FAILURE); -} - -/* - * Read 64 bytes from /dev/urandom and add them to the SSL PRNG. Seed the PRNG - * used by random(3) with a random seed obtained from SSL. If /dev/urandom is - * not readable, the function calls exit(). - * - * \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) -{ - int seed, ret = RAND_load_file("/dev/urandom", 64); - - if (ret != 64) { - PARA_EMERG_LOG("could not seed PRNG (ret = %d)\n", ret); - exit(EXIT_FAILURE); - } - get_random_bytes_or_die((unsigned char *)&seed, sizeof(seed)); - srandom(seed); -} - -static int get_private_key(const char *path, RSA **rsa) -{ - EVP_PKEY *pkey; - BIO *bio = BIO_new(BIO_s_file()); - - *rsa = NULL; - if (!bio) - return -E_PRIVATE_KEY; - if (BIO_read_filename(bio, path) <= 0) - goto bio_free; - pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); - if (!pkey) - goto bio_free; - *rsa = EVP_PKEY_get1_RSA(pkey); - EVP_PKEY_free(pkey); -bio_free: - BIO_free(bio); - return *rsa? RSA_size(*rsa) : -E_PRIVATE_KEY; -} - -/* - * The public key loading functions below were inspired by corresponding code - * of openssh-5.2p1, Copyright (c) 1995 Tatu Ylonen , Espoo, - * Finland. However, not much of the original code remains. - */ - -static int read_bignum(const unsigned char *buf, size_t len, BIGNUM **result) -{ - const unsigned char *p = buf, *end = buf + len; - uint32_t bnsize; - BIGNUM *bn; - - if (p + 4 < p) - return -E_BIGNUM; - if (p + 4 > end) - return -E_BIGNUM; - bnsize = read_u32_be(p); - PARA_DEBUG_LOG("bnsize: %u\n", bnsize); - p += 4; - if (p + bnsize < p) - return -E_BIGNUM; - if (p + bnsize > end) - return -E_BIGNUM; - if (bnsize > 8192) - return -E_BIGNUM; - bn = BN_bin2bn(p, bnsize, NULL); - if (!bn) - return -E_BIGNUM; - *result = bn; - return bnsize + 4; -} - -static int read_rsa_bignums(const unsigned char *blob, int blen, RSA **result) -{ - int ret; - RSA *rsa; - BIGNUM *n, *e; - const unsigned char *p = blob, *end = blob + blen; - - rsa = RSA_new(); - if (!rsa) - return -E_BIGNUM; - ret = read_bignum(p, end - p, &e); - if (ret < 0) - goto fail; - p += ret; - ret = read_bignum(p, end - p, &n); - if (ret < 0) - goto fail; -#ifdef HAVE_RSA_SET0_KEY - RSA_set0_key(rsa, n, e, NULL); -#else - rsa->n = n; - rsa->e = e; -#endif - *result = rsa; - return 1; -fail: - RSA_free(rsa); - return ret; -} - -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; - - key = para_malloc(sizeof(*key)); - ret = mmap_full_file(key_file, O_RDONLY, &map, &map_size, NULL); - 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; - ret = RSA_size(key->rsa); -out_unmap: - ret2 = para_munmap(map, map_size); - if (ret >= 0 && ret2 < 0) - ret = ret2; -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); - return ret; -} - -void free_public_key(struct asymmetric_key *key) -{ - if (!key) - return; - RSA_free(key->rsa); - free(key); -} - -int priv_decrypt(const char *key_file, unsigned char *outbuf, - unsigned char *inbuf, int inlen) -{ - struct asymmetric_key *priv; - int ret; - - ret = check_private_key_file(key_file); - if (ret < 0) - return ret; - if (inlen < 0) - return -E_RSA; - priv = para_malloc(sizeof(*priv)); - ret = get_private_key(key_file, &priv->rsa); - if (ret < 0) { - free(priv); - return ret; - } - /* - * RSA is vulnerable to timing attacks. Generate a random blinding - * factor to protect against this kind of attack. - */ - ret = -E_BLINDING; - if (RSA_blinding_on(priv->rsa, NULL) == 0) - goto out; - ret = RSA_private_decrypt(inlen, inbuf, outbuf, priv->rsa, - RSA_PKCS1_OAEP_PADDING); - RSA_blinding_off(priv->rsa); - if (ret <= 0) - ret = -E_DECRYPT; -out: - RSA_free(priv->rsa); - free(priv); - return ret; -} - -int pub_encrypt(struct asymmetric_key *pub, unsigned char *inbuf, - unsigned len, unsigned char *outbuf) -{ - int ret, flen = len; /* RSA_public_encrypt expects a signed int */ - - if (flen < 0) - return -E_ENCRYPT; - ret = RSA_public_encrypt(flen, inbuf, outbuf, pub->rsa, - RSA_PKCS1_OAEP_PADDING); - return ret < 0? -E_ENCRYPT : ret; -} - -struct stream_cipher { - EVP_CIPHER_CTX *aes; -}; - -struct stream_cipher *sc_new(const unsigned char *data, int len) -{ - struct stream_cipher *sc = para_malloc(sizeof(*sc)); - - assert(len >= 2 * AES_CRT128_BLOCK_SIZE); - sc->aes = EVP_CIPHER_CTX_new(); - EVP_EncryptInit_ex(sc->aes, EVP_aes_128_ctr(), NULL, data, - data + AES_CRT128_BLOCK_SIZE); - return sc; -} - -void sc_free(struct stream_cipher *sc) -{ - if (!sc) - return; - EVP_CIPHER_CTX_free(sc->aes); - free(sc); -} - -static void aes_ctr128_crypt(EVP_CIPHER_CTX *ctx, struct iovec *src, - struct iovec *dst) -{ - int ret, inlen = src->iov_len, outlen, tmplen; - - *dst = (typeof(*dst)) { - /* Add one for the terminating zero byte. */ - .iov_base = para_malloc(inlen + 1), - .iov_len = inlen - }; - ret = EVP_EncryptUpdate(ctx, dst->iov_base, &outlen, src->iov_base, inlen); - assert(ret != 0); - ret = EVP_EncryptFinal_ex(ctx, dst->iov_base + outlen, &tmplen); - assert(ret != 0); - outlen += tmplen; - ((char *)dst->iov_base)[outlen] = '\0'; - dst->iov_len = outlen; -} - -void sc_crypt(struct stream_cipher *sc, struct iovec *src, struct iovec *dst) -{ - return aes_ctr128_crypt(sc->aes, src, dst); -} - -void hash_function(const char *data, unsigned long len, unsigned char *hash) -{ - SHA_CTX c; - SHA1_Init(&c); - SHA1_Update(&c, data, len); - SHA1_Final(hash, &c); -} diff --git a/openssl.c b/openssl.c new file mode 100644 index 00000000..f786ce29 --- /dev/null +++ b/openssl.c @@ -0,0 +1,296 @@ +/* Copyright (C) 2005 Andre Noll , see file COPYING. */ + +/** \file openssl.c Openssl-based encryption/decryption routines. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "para.h" +#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 { + RSA *rsa; +}; + +void get_random_bytes_or_die(unsigned char *buf, int num) +{ + unsigned long err; + + /* RAND_bytes() returns 1 on success, 0 otherwise. */ + if (RAND_bytes(buf, num) == 1) + return; + err = ERR_get_error(); + PARA_EMERG_LOG("%s\n", ERR_reason_error_string(err)); + exit(EXIT_FAILURE); +} + +/* + * Read 64 bytes from /dev/urandom and add them to the SSL PRNG. Seed the PRNG + * used by random(3) with a random seed obtained from SSL. If /dev/urandom is + * not readable, the function calls exit(). + * + * \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) +{ + int seed, ret = RAND_load_file("/dev/urandom", 64); + + if (ret != 64) { + PARA_EMERG_LOG("could not seed PRNG (ret = %d)\n", ret); + exit(EXIT_FAILURE); + } + get_random_bytes_or_die((unsigned char *)&seed, sizeof(seed)); + srandom(seed); +} + +static int get_private_key(const char *path, RSA **rsa) +{ + EVP_PKEY *pkey; + BIO *bio = BIO_new(BIO_s_file()); + + *rsa = NULL; + if (!bio) + return -E_PRIVATE_KEY; + if (BIO_read_filename(bio, path) <= 0) + goto bio_free; + pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); + if (!pkey) + goto bio_free; + *rsa = EVP_PKEY_get1_RSA(pkey); + EVP_PKEY_free(pkey); +bio_free: + BIO_free(bio); + return *rsa? RSA_size(*rsa) : -E_PRIVATE_KEY; +} + +/* + * The public key loading functions below were inspired by corresponding code + * of openssh-5.2p1, Copyright (c) 1995 Tatu Ylonen , Espoo, + * Finland. However, not much of the original code remains. + */ + +static int read_bignum(const unsigned char *buf, size_t len, BIGNUM **result) +{ + const unsigned char *p = buf, *end = buf + len; + uint32_t bnsize; + BIGNUM *bn; + + if (p + 4 < p) + return -E_BIGNUM; + if (p + 4 > end) + return -E_BIGNUM; + bnsize = read_u32_be(p); + PARA_DEBUG_LOG("bnsize: %u\n", bnsize); + p += 4; + if (p + bnsize < p) + return -E_BIGNUM; + if (p + bnsize > end) + return -E_BIGNUM; + if (bnsize > 8192) + return -E_BIGNUM; + bn = BN_bin2bn(p, bnsize, NULL); + if (!bn) + return -E_BIGNUM; + *result = bn; + return bnsize + 4; +} + +static int read_rsa_bignums(const unsigned char *blob, int blen, RSA **result) +{ + int ret; + RSA *rsa; + BIGNUM *n, *e; + const unsigned char *p = blob, *end = blob + blen; + + rsa = RSA_new(); + if (!rsa) + return -E_BIGNUM; + ret = read_bignum(p, end - p, &e); + if (ret < 0) + goto fail; + p += ret; + ret = read_bignum(p, end - p, &n); + if (ret < 0) + goto fail; +#ifdef HAVE_RSA_SET0_KEY + RSA_set0_key(rsa, n, e, NULL); +#else + rsa->n = n; + rsa->e = e; +#endif + *result = rsa; + return 1; +fail: + RSA_free(rsa); + return ret; +} + +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; + + key = para_malloc(sizeof(*key)); + ret = mmap_full_file(key_file, O_RDONLY, &map, &map_size, NULL); + 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; + ret = RSA_size(key->rsa); +out_unmap: + ret2 = para_munmap(map, map_size); + if (ret >= 0 && ret2 < 0) + ret = ret2; +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); + return ret; +} + +void free_public_key(struct asymmetric_key *key) +{ + if (!key) + return; + RSA_free(key->rsa); + free(key); +} + +int priv_decrypt(const char *key_file, unsigned char *outbuf, + unsigned char *inbuf, int inlen) +{ + struct asymmetric_key *priv; + int ret; + + ret = check_private_key_file(key_file); + if (ret < 0) + return ret; + if (inlen < 0) + return -E_RSA; + priv = para_malloc(sizeof(*priv)); + ret = get_private_key(key_file, &priv->rsa); + if (ret < 0) { + free(priv); + return ret; + } + /* + * RSA is vulnerable to timing attacks. Generate a random blinding + * factor to protect against this kind of attack. + */ + ret = -E_BLINDING; + if (RSA_blinding_on(priv->rsa, NULL) == 0) + goto out; + ret = RSA_private_decrypt(inlen, inbuf, outbuf, priv->rsa, + RSA_PKCS1_OAEP_PADDING); + RSA_blinding_off(priv->rsa); + if (ret <= 0) + ret = -E_DECRYPT; +out: + RSA_free(priv->rsa); + free(priv); + return ret; +} + +int pub_encrypt(struct asymmetric_key *pub, unsigned char *inbuf, + unsigned len, unsigned char *outbuf) +{ + int ret, flen = len; /* RSA_public_encrypt expects a signed int */ + + if (flen < 0) + return -E_ENCRYPT; + ret = RSA_public_encrypt(flen, inbuf, outbuf, pub->rsa, + RSA_PKCS1_OAEP_PADDING); + return ret < 0? -E_ENCRYPT : ret; +} + +struct stream_cipher { + EVP_CIPHER_CTX *aes; +}; + +struct stream_cipher *sc_new(const unsigned char *data, int len) +{ + struct stream_cipher *sc = para_malloc(sizeof(*sc)); + + assert(len >= 2 * AES_CRT128_BLOCK_SIZE); + sc->aes = EVP_CIPHER_CTX_new(); + EVP_EncryptInit_ex(sc->aes, EVP_aes_128_ctr(), NULL, data, + data + AES_CRT128_BLOCK_SIZE); + return sc; +} + +void sc_free(struct stream_cipher *sc) +{ + if (!sc) + return; + EVP_CIPHER_CTX_free(sc->aes); + free(sc); +} + +static void aes_ctr128_crypt(EVP_CIPHER_CTX *ctx, struct iovec *src, + struct iovec *dst) +{ + int ret, inlen = src->iov_len, outlen, tmplen; + + *dst = (typeof(*dst)) { + /* Add one for the terminating zero byte. */ + .iov_base = para_malloc(inlen + 1), + .iov_len = inlen + }; + ret = EVP_EncryptUpdate(ctx, dst->iov_base, &outlen, src->iov_base, inlen); + assert(ret != 0); + ret = EVP_EncryptFinal_ex(ctx, dst->iov_base + outlen, &tmplen); + assert(ret != 0); + outlen += tmplen; + ((char *)dst->iov_base)[outlen] = '\0'; + dst->iov_len = outlen; +} + +void sc_crypt(struct stream_cipher *sc, struct iovec *src, struct iovec *dst) +{ + return aes_ctr128_crypt(sc->aes, src, dst); +} + +void hash_function(const char *data, unsigned long len, unsigned char *hash) +{ + SHA_CTX c; + SHA1_Init(&c); + SHA1_Update(&c, data, len); + SHA1_Final(hash, &c); +}