svn rev #23734: trunk/src/lib/crypto/openssl/enc_provider/
ghudson@MIT.EDU
ghudson at MIT.EDU
Thu Feb 18 13:04:47 EST 2010
http://src.mit.edu/fisheye/changelog/krb5/?cs=23734
Commit By: ghudson
Log Message:
ticket: 6665
subject: Fix cipher state chaining in OpenSSL back end
target_version: 1.8
tags: pullup
Make cipher state chaining work in the OpenSSL back end for des, des3,
and arcfour enc providers. Subtleties:
* DES and DES3 have checks to avoid clobbering ivec with uninitialized
data if there is no data to encrypt.
* Arcfour saves the OpenSSL cipher context across calls. To protect
against a caller improperly copying the state (which happens to work
with other enc providers), a loopback pointer is used, as in GSSAPI.
* EVP_EncryptFinal_ex is unnecessary with stream ciphers and would
interfere with cipher state chaining if it did anything, so just
remove it.
Changed Files:
U trunk/src/lib/crypto/openssl/enc_provider/des.c
U trunk/src/lib/crypto/openssl/enc_provider/des3.c
U trunk/src/lib/crypto/openssl/enc_provider/rc4.c
Modified: trunk/src/lib/crypto/openssl/enc_provider/des.c
===================================================================
--- trunk/src/lib/crypto/openssl/enc_provider/des.c 2010-02-17 20:27:22 UTC (rev 23733)
+++ trunk/src/lib/crypto/openssl/enc_provider/des.c 2010-02-18 18:04:47 UTC (rev 23734)
@@ -60,8 +60,8 @@
#define DES_KEY_BYTES 7
static krb5_error_code
-validate(krb5_key key, const krb5_data *ivec,
- const krb5_crypto_iov *data, size_t num_data)
+validate(krb5_key key, const krb5_data *ivec, const krb5_crypto_iov *data,
+ size_t num_data, krb5_boolean *empty)
{
size_t i, input_length;
@@ -78,6 +78,7 @@
if (ivec && (ivec->length != 8))
return(KRB5_BAD_MSIZE);
+ *empty = (input_length == 0);
return 0;
}
@@ -89,13 +90,13 @@
unsigned char iblock[MIT_DES_BLOCK_LENGTH], oblock[MIT_DES_BLOCK_LENGTH];
struct iov_block_state input_pos, output_pos;
EVP_CIPHER_CTX ciph_ctx;
+ krb5_boolean empty;
IOV_BLOCK_STATE_INIT(&input_pos);
IOV_BLOCK_STATE_INIT(&output_pos);
-
- ret = validate(key, ivec, data, num_data);
- if (ret)
+ ret = validate(key, ivec, data, num_data, &empty);
+ if (ret != 0 || empty)
return ret;
EVP_CIPHER_CTX_init(&ciph_ctx);
@@ -122,6 +123,9 @@
&output_pos);
}
+ if (ivec != NULL)
+ memcpy(ivec->data, oblock, MIT_DES_BLOCK_LENGTH);
+
EVP_CIPHER_CTX_cleanup(&ciph_ctx);
zap(iblock, sizeof(iblock));
@@ -140,12 +144,13 @@
unsigned char iblock[MIT_DES_BLOCK_LENGTH], oblock[MIT_DES_BLOCK_LENGTH];
struct iov_block_state input_pos, output_pos;
EVP_CIPHER_CTX ciph_ctx;
+ krb5_boolean empty;
IOV_BLOCK_STATE_INIT(&input_pos);
IOV_BLOCK_STATE_INIT(&output_pos);
- ret = validate(key, ivec, data, num_data);
- if (ret)
+ ret = validate(key, ivec, data, num_data, &empty);
+ if (ret != 0 || empty)
return ret;
EVP_CIPHER_CTX_init(&ciph_ctx);
@@ -172,6 +177,9 @@
MIT_DES_BLOCK_LENGTH, &output_pos);
}
+ if (ivec != NULL)
+ memcpy(ivec->data, iblock, MIT_DES_BLOCK_LENGTH);
+
EVP_CIPHER_CTX_cleanup(&ciph_ctx);
zap(iblock, sizeof(iblock));
Modified: trunk/src/lib/crypto/openssl/enc_provider/des3.c
===================================================================
--- trunk/src/lib/crypto/openssl/enc_provider/des3.c 2010-02-17 20:27:22 UTC (rev 23733)
+++ trunk/src/lib/crypto/openssl/enc_provider/des3.c 2010-02-18 18:04:47 UTC (rev 23734)
@@ -59,8 +59,8 @@
#define DES_BLOCK_SIZE 8
static krb5_error_code
-validate(krb5_key key, const krb5_data *ivec,
- const krb5_crypto_iov *data, size_t num_data)
+validate(krb5_key key, const krb5_data *ivec, const krb5_crypto_iov *data,
+ size_t num_data, krb5_boolean *empty)
{
size_t i, input_length;
@@ -77,6 +77,7 @@
if (ivec && (ivec->length != 8))
return(KRB5_BAD_MSIZE);
+ *empty = (input_length == 0);
return 0;
}
@@ -88,9 +89,10 @@
unsigned char iblock[MIT_DES_BLOCK_LENGTH], oblock[MIT_DES_BLOCK_LENGTH];
struct iov_block_state input_pos, output_pos;
EVP_CIPHER_CTX ciph_ctx;
+ krb5_boolean empty;
- ret = validate(key, ivec, data, num_data);
- if (ret)
+ ret = validate(key, ivec, data, num_data, &empty);
+ if (ret != 0 || empty)
return ret;
IOV_BLOCK_STATE_INIT(&input_pos);
@@ -121,8 +123,8 @@
oblock, MIT_DES_BLOCK_LENGTH, &output_pos);
}
- /*if (ivec != NULL && ivec->data)
- memcpy(ivec->data, oblock, MIT_DES_BLOCK_LENGTH); */
+ if (ivec != NULL)
+ memcpy(ivec->data, oblock, MIT_DES_BLOCK_LENGTH);
EVP_CIPHER_CTX_cleanup(&ciph_ctx);
@@ -142,9 +144,10 @@
unsigned char iblock[MIT_DES_BLOCK_LENGTH], oblock[MIT_DES_BLOCK_LENGTH];
struct iov_block_state input_pos, output_pos;
EVP_CIPHER_CTX ciph_ctx;
+ krb5_boolean empty;
- ret = validate(key, ivec, data, num_data);
- if (ret)
+ ret = validate(key, ivec, data, num_data, &empty);
+ if (ret != 0 || empty)
return ret;
IOV_BLOCK_STATE_INIT(&input_pos);
@@ -175,8 +178,8 @@
&output_pos);
}
- /*if (ivec != NULL && ivec->data)
- memcpy(ivec->data, oblock, MIT_DES_BLOCK_LENGTH); */
+ if (ivec != NULL)
+ memcpy(ivec->data, iblock, MIT_DES_BLOCK_LENGTH);
EVP_CIPHER_CTX_cleanup(&ciph_ctx);
Modified: trunk/src/lib/crypto/openssl/enc_provider/rc4.c
===================================================================
--- trunk/src/lib/crypto/openssl/enc_provider/rc4.c 2010-02-17 20:27:22 UTC (rev 23733)
+++ trunk/src/lib/crypto/openssl/enc_provider/rc4.c 2010-02-18 18:04:47 UTC (rev 23734)
@@ -40,20 +40,18 @@
#include <rand2key.h>
#include <openssl/evp.h>
-typedef struct
-{
- EVP_CIPHER_CTX evp_ctx;
- unsigned int x;
- unsigned int y;
- unsigned char state[256];
+/*
+ * The loopback field is NULL if ctx is uninitialized (no encrypt or decrypt
+ * operation has taken place), or a pointer to the structure address if ctx is
+ * initialized. If the application copies the state (not a valid operation,
+ * but one which happens to works with some other enc providers), we can detect
+ * it via the loopback field and return a sane error code.
+ */
+struct arcfour_state {
+ struct arcfour_state *loopback;
+ EVP_CIPHER_CTX ctx;
+};
-} ArcfourContext;
-
-typedef struct {
- int initialized;
- ArcfourContext ctx;
-} ArcFourCipherState;
-
#define RC4_KEY_SIZE 16
#define RC4_BLOCK_SIZE 1
@@ -76,59 +74,79 @@
size_t num_data)
{
size_t i;
- int ret = 0, tmp_len = 0;
- unsigned char *tmp_buf = NULL;
+ int ret = 1, tmp_len = 0;
krb5_crypto_iov *iov = NULL;
- EVP_CIPHER_CTX ciph_ctx;
+ EVP_CIPHER_CTX ciph_ctx, *ctx;
+ struct arcfour_state *arcstate;
+ krb5_boolean do_init = TRUE;
-
- EVP_CIPHER_CTX_init(&ciph_ctx);
-
- ret = EVP_EncryptInit_ex(&ciph_ctx, EVP_rc4(), NULL, key->keyblock.contents, NULL);
- if (!ret){
- EVP_CIPHER_CTX_cleanup(&ciph_ctx);
- return KRB5_CRYPTO_INTERNAL;
+ arcstate = (state != NULL) ? (struct arcfour_state *) state->data : NULL;
+ if (arcstate != NULL) {
+ ctx = &arcstate->ctx;
+ if (arcstate->loopback == arcstate)
+ do_init = FALSE;
+ else if (arcstate->loopback != NULL)
+ return KRB5_CRYPTO_INTERNAL;
+ } else {
+ ctx = &ciph_ctx;
}
+ if (do_init) {
+ EVP_CIPHER_CTX_init(ctx);
+ ret = EVP_EncryptInit_ex(ctx, EVP_rc4(), NULL, key->keyblock.contents,
+ NULL);
+ if (!ret)
+ return KRB5_CRYPTO_INTERNAL;
+ }
for (i = 0; i < num_data; i++) {
iov = &data[i];
- if (iov->data.length <= 0) break;
- tmp_len = iov->data.length;
-
if (ENCRYPT_IOV(iov)) {
- tmp_buf=(unsigned char *)iov->data.data;
- ret = EVP_EncryptUpdate(&ciph_ctx,
- tmp_buf, &tmp_len,
- (unsigned char *)iov->data.data, iov->data.length);
- if (!ret) break;
- iov->data.length = tmp_len;
+ ret = EVP_EncryptUpdate(ctx,
+ (unsigned char *) iov->data.data, &tmp_len,
+ (unsigned char *) iov->data.data,
+ iov->data.length);
+ if (!ret)
+ break;
}
}
- if(ret)
- ret = EVP_EncryptFinal_ex(&ciph_ctx, (unsigned char *)tmp_buf, &tmp_len);
- EVP_CIPHER_CTX_cleanup(&ciph_ctx);
+ if (arcstate) /* Context is saved; mark as initialized. */
+ arcstate->loopback = arcstate;
+ else /* Context is not saved; clean it up now. */
+ EVP_CIPHER_CTX_cleanup(ctx);
- if (ret != 1)
+ if (!ret)
return KRB5_CRYPTO_INTERNAL;
- iov->data.length += tmp_len;
-
return 0;
}
static krb5_error_code
k5_arcfour_free_state ( krb5_data *state)
{
- return 0; /* not implemented */
+ struct arcfour_state *arcstate = (struct arcfour_state *) state->data;
+
+ /* Clean up the OpenSSL context if it was initialized. */
+ if (arcstate && arcstate->loopback == arcstate)
+ EVP_CIPHER_CTX_cleanup(&arcstate->ctx);
+ free(arcstate);
+ return 0;
}
static krb5_error_code
k5_arcfour_init_state (const krb5_keyblock *key,
krb5_keyusage keyusage, krb5_data *new_state)
{
- return 0; /* not implemented */
+ struct arcfour_state *arcstate;
+ /* Create a state structure with an uninitialized context. */
+ arcstate = calloc(1, sizeof(*arcstate));
+ if (arcstate == NULL)
+ return ENOMEM;
+ arcstate->loopback = NULL;
+ new_state->data = (char *) arcstate;
+ new_state->length = sizeof(*arcstate);
+ return 0;
}
/* Since the arcfour cipher is identical going forwards and backwards,
@@ -147,6 +165,6 @@
k5_arcfour_docrypt,
NULL,
krb5int_arcfour_make_key,
- k5_arcfour_init_state, /*xxx not implemented */
- k5_arcfour_free_state /*xxx not implemented */
+ k5_arcfour_init_state,
+ k5_arcfour_free_state
};
More information about the cvs-krb5
mailing list