From 84b145f3783f4740c7aa4e223e39aad51e3dec33 Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Tue, 2 May 2023 23:56:26 +0200 Subject: [PATCH] apc_pub_encrypt: Let the callee allocate the buffer. Change the encryption routine of the apc API to allocate a suitably sized buffer itself. Currently, the caller has to guess the size of the buffer to pass to the function and we reuse our 4k handshake buffer for that. While 4k is is plenty at the moment, that may change, and it's always better to use the exact size if it is readily available. This is the case here because the required buffer size is just the number of bits of the modulus of the key. --- command.c | 15 ++++++++------- crypt.h | 4 ++-- gcrypt.c | 13 ++++++++++--- openssl.c | 13 ++++++++++--- 4 files changed, 30 insertions(+), 15 deletions(-) diff --git a/command.c b/command.c index bddb9cf0..78c9106c 100644 --- a/command.c +++ b/command.c @@ -922,7 +922,8 @@ int handle_connect(int fd) int ret; unsigned char rand_buf[APC_CHALLENGE_SIZE + 2 * SESSION_KEY_LEN]; unsigned char challenge_hash[HASH2_SIZE]; - char *command = NULL, *buf = alloc(HANDSHAKE_BUFSIZE) /* must be on the heap */; + char *command = NULL, *buf = NULL, hsbuf[HANDSHAKE_BUFSIZE]; + unsigned char *crypt_buf; size_t numbytes; struct command_context cc_struct = {.u = NULL}, *cc = &cc_struct; struct iovec iov; @@ -942,16 +943,16 @@ int handle_connect(int fd) if (ret < 0) goto net_err; /* recv auth request line */ - ret = recv_buffer(fd, buf, HANDSHAKE_BUFSIZE); + ret = recv_buffer(fd, hsbuf, HANDSHAKE_BUFSIZE); if (ret < 0) goto net_err; - ret = parse_auth_request(buf, ret, &cc->u, &cf); + ret = parse_auth_request(hsbuf, ret, &cc->u, &cf); if (ret < 0) goto net_err; if (cc->u) { get_random_bytes_or_die(rand_buf, sizeof(rand_buf)); ret = apc_pub_encrypt(cc->u->pubkey, rand_buf, sizeof(rand_buf), - (unsigned char *)buf); + &crypt_buf); if (ret < 0) goto net_err; numbytes = ret; @@ -962,12 +963,12 @@ int handle_connect(int fd) * fail the authentication later. */ numbytes = 256; - get_random_bytes_or_die((unsigned char *)buf, numbytes); + crypt_buf = alloc(numbytes); + get_random_bytes_or_die(crypt_buf, numbytes); } PARA_DEBUG_LOG("sending %d byte challenge + session key (%zu bytes)\n", APC_CHALLENGE_SIZE, numbytes); - ret = send_sb(&cc->scc, buf, numbytes, SBD_CHALLENGE, false); - buf = NULL; + ret = send_sb(&cc->scc, crypt_buf, numbytes, SBD_CHALLENGE, false); if (ret < 0) goto net_err; ret = recv_sb(&cc->scc, SBD_CHALLENGE_RESPONSE, diff --git a/crypt.h b/crypt.h index 5578cd56..65070995 100644 --- a/crypt.h +++ b/crypt.h @@ -20,12 +20,12 @@ struct asymmetric_key; * \param pub: The public key. * \param inbuf The input buffer. * \param len The length of \a inbuf. - * \param outbuf The output buffer. + * \param outbuf The output buffer will be allocated by the callee. * * \return The size of the encrypted data on success, negative on errors. */ int apc_pub_encrypt(struct asymmetric_key *pub, unsigned char *inbuf, - unsigned len, unsigned char *outbuf); + unsigned len, unsigned char **outbuf); /** * Decrypt a buffer using a private key. diff --git a/gcrypt.c b/gcrypt.c index b46f8f95..68f80f27 100644 --- a/gcrypt.c +++ b/gcrypt.c @@ -114,6 +114,7 @@ void crypt_shutdown(void) struct asymmetric_key { gcry_sexp_t sexp; + int bits; }; static const char *gcrypt_strerror(gcry_error_t gret) @@ -457,6 +458,7 @@ int apc_get_pubkey(const char *key_file, struct asymmetric_key **result) 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: @@ -554,7 +556,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; @@ -562,6 +564,7 @@ int apc_pub_encrypt(struct asymmetric_key *pub, unsigned char *inbuf, size_t nbytes; int ret; + *outbuf = NULL; /* get pub key */ pub_key = gcry_sexp_find_token(pub->sexp, "public-key", 0); if (!pub_key) @@ -590,14 +593,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: diff --git a/openssl.c b/openssl.c index 495d83c2..acf1120d 100644 --- a/openssl.c +++ b/openssl.c @@ -310,15 +310,22 @@ out: } int apc_pub_encrypt(struct asymmetric_key *pub, unsigned char *inbuf, - unsigned len, unsigned char *outbuf) + unsigned len, unsigned char **outbuf) { int ret, flen = len; /* RSA_public_encrypt expects a signed int */ + *outbuf = NULL; if (flen < 0) return -E_ENCRYPT; - ret = RSA_public_encrypt(flen, inbuf, outbuf, pub->rsa, + *outbuf = alloc(RSA_size(pub->rsa)); + ret = RSA_public_encrypt(flen, inbuf, *outbuf, pub->rsa, RSA_PKCS1_OAEP_PADDING); - return ret < 0? -E_ENCRYPT : ret; + if (ret < 0) { + free(*outbuf); + *outbuf = NULL; + return -E_ENCRYPT; + } + return ret; } struct stream_cipher { -- 2.39.5