krb5_{encrypt,decrypt}_iov_ivec for derived crypto.
git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@23647 ec53bebd-3082-4978-b11e-865c3cabbd6b
This commit is contained in:
@@ -3204,16 +3204,6 @@ decrypt_internal_special(krb5_context context,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct krb5_crypto_iov {
|
|
||||||
unsigned int flags;
|
|
||||||
#define KRB5_CRYPTO_TYPE_EMPTY 0 /* ignored */
|
|
||||||
#define KRB5_CRYPTO_TYPE_SIGNATURE 1 /* OUT krb5_crypto_length_signature */
|
|
||||||
#define KRB5_CRYPTO_TYPE_DATA 2 /* IN and OUT */
|
|
||||||
#define KRB5_CRYPTO_TYPE_SIGN_ONLY 3 /* IN */
|
|
||||||
#define KRB5_CRYPTO_TYPE_PADDING 4 /* OUT krb5_crypto_length_padding */
|
|
||||||
krb5_data data;
|
|
||||||
} krb5_crypto_iov;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inline encrypt a kerberos message
|
* Inline encrypt a kerberos message
|
||||||
*
|
*
|
||||||
@@ -3229,38 +3219,361 @@ typedef struct krb5_crypto_iov {
|
|||||||
*
|
*
|
||||||
* Kerberos encrypted data look like this:
|
* Kerberos encrypted data look like this:
|
||||||
*
|
*
|
||||||
* 1. KRB5_CRYPTO_TYPE_SIGNATURE
|
* 1. KRB5_CRYPTO_TYPE_HEADER
|
||||||
* 2. array KRB5_CRYPTO_TYPE_DATA and KRB5_CRYPTO_TYPE_SIGN_ONLY in
|
* 2. array KRB5_CRYPTO_TYPE_DATA and KRB5_CRYPTO_TYPE_SIGN_ONLY in
|
||||||
* any order, however the receiver have to aware of the
|
* any order, however the receiver have to aware of the
|
||||||
* order. KRB5_CRYPTO_TYPE_SIGN_ONLY is commonly used headers and
|
* order. KRB5_CRYPTO_TYPE_SIGN_ONLY is commonly used headers and
|
||||||
* trailers.
|
* trailers.
|
||||||
* 3. KRB5_CRYPTO_TYPE_PADDING (0 for cfx and rc4, 8 for des types)
|
* 3. KRB5_CRYPTO_TYPE_TRAILER
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static krb5_crypto_iov *
|
||||||
|
find_iv(krb5_crypto_iov *data, int num_data, int type)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < num_data; i++)
|
||||||
|
if (data[i].flags == type)
|
||||||
|
return &data[i];
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
krb5_error_code KRB5_LIB_FUNCTION
|
krb5_error_code KRB5_LIB_FUNCTION
|
||||||
krb5_encrypt_iov_ivec(krb5_context context,
|
krb5_encrypt_iov_ivec(krb5_context context,
|
||||||
krb5_crypto crypto,
|
krb5_crypto crypto,
|
||||||
unsigned usage,
|
unsigned usage,
|
||||||
krb5_crypto_iov **data,
|
krb5_crypto_iov *data,
|
||||||
size_t num_data,
|
size_t num_data,
|
||||||
void *ivec)
|
void *ivec)
|
||||||
{
|
{
|
||||||
|
size_t headersz, trailersz, len;
|
||||||
|
size_t i, sz, block_sz, pad_sz;
|
||||||
|
Checksum cksum;
|
||||||
|
unsigned char *p, *q;
|
||||||
|
krb5_error_code ret;
|
||||||
|
struct key_data *dkey;
|
||||||
|
const struct encryption_type *et = crypto->et;
|
||||||
|
krb5_crypto_iov *tiv, *piv, *hiv;
|
||||||
|
|
||||||
|
if(!derived_crypto(context, crypto)) {
|
||||||
krb5_clear_error_string(context);
|
krb5_clear_error_string(context);
|
||||||
return KRB5_CRYPTO_INTERNAL;
|
return KRB5_CRYPTO_INTERNAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
headersz = et->confoundersize;
|
||||||
|
trailersz = CHECKSUMSIZE(et->keyed_checksum);
|
||||||
|
|
||||||
|
for (len = 0, i = 0; i < num_data; i++) {
|
||||||
|
if (data[i].flags != KRB5_CRYPTO_TYPE_HEADER &&
|
||||||
|
data[i].flags == KRB5_CRYPTO_TYPE_DATA) {
|
||||||
|
len += data[i].data.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sz = headersz + len;
|
||||||
|
block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */
|
||||||
|
|
||||||
|
pad_sz = block_sz - sz;
|
||||||
|
trailersz += pad_sz;
|
||||||
|
|
||||||
|
/* header */
|
||||||
|
|
||||||
|
hiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
|
||||||
|
if (hiv == NULL || hiv->data.length != headersz)
|
||||||
|
return KRB5_BAD_MSIZE;
|
||||||
|
|
||||||
|
krb5_generate_random_block(hiv->data.data, hiv->data.length);
|
||||||
|
|
||||||
|
/* padding */
|
||||||
|
|
||||||
|
piv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_PADDING);
|
||||||
|
/* its ok to have no TYPE_PADDING if there is no padding */
|
||||||
|
if (piv == NULL && pad_sz != 0)
|
||||||
|
return KRB5_BAD_MSIZE;
|
||||||
|
if (piv) {
|
||||||
|
if (piv->data.length < pad_sz)
|
||||||
|
return KRB5_BAD_MSIZE;
|
||||||
|
piv->data.length = pad_sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* trailer */
|
||||||
|
|
||||||
|
tiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_TRAILER);
|
||||||
|
if (tiv == NULL || tiv->data.length != trailersz)
|
||||||
|
return KRB5_BAD_MSIZE;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXX replace with EVP_Sign? at least make create_checksum an iov
|
||||||
|
* function.
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (len = 0, i = 0; i < num_data; i++) {
|
||||||
|
if (data[i].flags != KRB5_CRYPTO_TYPE_HEADER &&
|
||||||
|
data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
|
||||||
|
data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
|
||||||
|
continue;
|
||||||
|
len += data[i].data.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = q = malloc(len);
|
||||||
|
|
||||||
|
for (i = 0; i < num_data; i++) {
|
||||||
|
if (data[i].flags != KRB5_CRYPTO_TYPE_HEADER &&
|
||||||
|
data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
|
||||||
|
data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
|
||||||
|
continue;
|
||||||
|
memcpy(q, data[i].data.data, data[i].data.length);
|
||||||
|
q += data[i].data.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = create_checksum(context,
|
||||||
|
et->keyed_checksum,
|
||||||
|
crypto,
|
||||||
|
INTEGRITY_USAGE(usage),
|
||||||
|
p,
|
||||||
|
len,
|
||||||
|
&cksum);
|
||||||
|
free(p);
|
||||||
|
if(ret == 0 && cksum.checksum.length != trailersz) {
|
||||||
|
free_Checksum (&cksum);
|
||||||
|
krb5_clear_error_string (context);
|
||||||
|
ret = KRB5_CRYPTO_INTERNAL;
|
||||||
|
}
|
||||||
|
if(ret)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* save cksum at end */
|
||||||
|
memcpy(tiv->data.data, cksum.checksum.data, cksum.checksum.length);
|
||||||
|
free_Checksum (&cksum);
|
||||||
|
|
||||||
|
/* now encrypt data */
|
||||||
|
|
||||||
|
ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
|
||||||
|
if(ret)
|
||||||
|
goto fail;
|
||||||
|
ret = _key_schedule(context, dkey);
|
||||||
|
if(ret)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* XXX replace with EVP_Cipher */
|
||||||
|
|
||||||
|
for (len = 0, i = 0; i < num_data; i++) {
|
||||||
|
if (data[i].flags != KRB5_CRYPTO_TYPE_HEADER &&
|
||||||
|
data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
|
||||||
|
data[i].flags != KRB5_CRYPTO_TYPE_PADDING)
|
||||||
|
continue;
|
||||||
|
len += data[i].data.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = q = malloc(len);
|
||||||
|
|
||||||
|
for (i = 0; i < num_data; i++) {
|
||||||
|
if (data[i].flags != KRB5_CRYPTO_TYPE_HEADER &&
|
||||||
|
data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
|
||||||
|
data[i].flags != KRB5_CRYPTO_TYPE_PADDING)
|
||||||
|
continue;
|
||||||
|
memcpy(q, data[i].data.data, data[i].data.length);
|
||||||
|
q += data[i].data.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
|
||||||
|
if(ret) {
|
||||||
|
free(p);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
ret = _key_schedule(context, dkey);
|
||||||
|
if(ret) {
|
||||||
|
free(p);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = (*et->encrypt)(context, dkey, p, len, 1, usage, ivec);
|
||||||
|
if (ret) {
|
||||||
|
free(p);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now copy data back to buffers */
|
||||||
|
for (q = p, i = 0; i < num_data; i++) {
|
||||||
|
if (data[i].flags != KRB5_CRYPTO_TYPE_HEADER &&
|
||||||
|
data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
|
||||||
|
data[i].flags != KRB5_CRYPTO_TYPE_PADDING)
|
||||||
|
continue;
|
||||||
|
memcpy(data[i].data.data, q, data[i].data.length);
|
||||||
|
q += data[i].data.length;
|
||||||
|
len -= data[i].data.length;
|
||||||
|
}
|
||||||
|
if (len)
|
||||||
|
krb5_abortx(context, "crypto: failed to get padsize right");
|
||||||
|
free(p);
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
krb5_error_code KRB5_LIB_FUNCTION
|
krb5_error_code KRB5_LIB_FUNCTION
|
||||||
krb5_crypto_length_signature(krb5_crypto crypto, size_t len)
|
krb5_decrypt_iov_ivec(krb5_context context,
|
||||||
|
krb5_crypto crypto,
|
||||||
|
unsigned usage,
|
||||||
|
krb5_crypto_iov *data,
|
||||||
|
size_t num_data,
|
||||||
|
void *ivec)
|
||||||
{
|
{
|
||||||
|
size_t headersz, trailersz, len;
|
||||||
|
size_t i, sz, block_sz, pad_sz;
|
||||||
|
Checksum cksum;
|
||||||
|
unsigned char *p, *q;
|
||||||
|
krb5_error_code ret;
|
||||||
|
struct key_data *dkey;
|
||||||
|
struct encryption_type *et = crypto->et;
|
||||||
|
krb5_crypto_iov *tiv, *hiv;
|
||||||
|
|
||||||
|
if(!derived_crypto(context, crypto)) {
|
||||||
krb5_clear_error_string(context);
|
krb5_clear_error_string(context);
|
||||||
return KRB5_CRYPTO_INTERNAL;
|
return KRB5_CRYPTO_INTERNAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
headersz = et->confoundersize;
|
||||||
|
trailersz = CHECKSUMSIZE(et->keyed_checksum);
|
||||||
|
|
||||||
|
for (len = 0, i = 0; i < num_data; i++)
|
||||||
|
if (data[i].flags == KRB5_CRYPTO_TYPE_DATA)
|
||||||
|
len += data[i].data.length;
|
||||||
|
|
||||||
|
sz = headersz + len;
|
||||||
|
block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */
|
||||||
|
|
||||||
|
pad_sz = block_sz - sz;
|
||||||
|
trailersz += pad_sz;
|
||||||
|
|
||||||
|
/* header */
|
||||||
|
|
||||||
|
hiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
|
||||||
|
if (hiv == NULL || hiv->data.length < headersz)
|
||||||
|
return KRB5_BAD_MSIZE;
|
||||||
|
hiv->data.length = headersz;
|
||||||
|
|
||||||
|
/* trailer */
|
||||||
|
|
||||||
|
tiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_TRAILER);
|
||||||
|
if (tiv == NULL || tiv->data.length < trailersz)
|
||||||
|
return KRB5_BAD_MSIZE;
|
||||||
|
tiv->data.length = trailersz;
|
||||||
|
|
||||||
|
/* body */
|
||||||
|
|
||||||
|
/* XXX replace with EVP_Cipher */
|
||||||
|
|
||||||
|
for (len = 0, i = 0; i < num_data; i++) {
|
||||||
|
if (data[i].flags != KRB5_CRYPTO_TYPE_HEADER &&
|
||||||
|
data[i].flags != KRB5_CRYPTO_TYPE_DATA)
|
||||||
|
continue;
|
||||||
|
len += data[i].data.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = q = malloc(len);
|
||||||
|
if (p == NULL)
|
||||||
|
return ENOMEM;
|
||||||
|
|
||||||
|
for (i = 0; i < num_data; i++) {
|
||||||
|
if (data[i].flags != KRB5_CRYPTO_TYPE_HEADER &&
|
||||||
|
data[i].flags != KRB5_CRYPTO_TYPE_DATA)
|
||||||
|
continue;
|
||||||
|
memcpy(q, data[i].data.data, data[i].data.length);
|
||||||
|
q += data[i].data.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
|
||||||
|
if(ret) {
|
||||||
|
free(p);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
ret = _key_schedule(context, dkey);
|
||||||
|
if(ret) {
|
||||||
|
free(p);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = (*et->encrypt)(context, dkey, p, len, 0, usage, ivec);
|
||||||
|
if (ret) {
|
||||||
|
free(p);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* XXX now copy data back to buffers */
|
||||||
|
for (q = p, i = 0; i < num_data; i++) {
|
||||||
|
if (data[i].flags != KRB5_CRYPTO_TYPE_HEADER &&
|
||||||
|
data[i].flags != KRB5_CRYPTO_TYPE_DATA)
|
||||||
|
continue;
|
||||||
|
if (len < data[i].data.length)
|
||||||
|
data[i].data.length = len;
|
||||||
|
memcpy(data[i].data.data, q, data[i].data.length);
|
||||||
|
q += data[i].data.length;
|
||||||
|
len -= data[i].data.length;
|
||||||
|
}
|
||||||
|
free(p);
|
||||||
|
if (len)
|
||||||
|
krb5_abortx(context, "data still in the buffer");
|
||||||
|
|
||||||
|
for (len = 0, i = 0; i < num_data; i++) {
|
||||||
|
if (data[i].flags != KRB5_CRYPTO_TYPE_HEADER &&
|
||||||
|
data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
|
||||||
|
data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
|
||||||
|
continue;
|
||||||
|
len += data[i].data.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = q = malloc(len);
|
||||||
|
|
||||||
|
for (i = 0; i < num_data; i++) {
|
||||||
|
if (data[i].flags != KRB5_CRYPTO_TYPE_HEADER &&
|
||||||
|
data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
|
||||||
|
data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
|
||||||
|
continue;
|
||||||
|
memcpy(q, data[i].data.data, data[i].data.length);
|
||||||
|
q += data[i].data.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
cksum.checksum.data = tiv->data.data;
|
||||||
|
cksum.checksum.length = tiv->data.length;
|
||||||
|
cksum.cksumtype = CHECKSUMTYPE(et->keyed_checksum);
|
||||||
|
|
||||||
|
ret = verify_checksum(context,
|
||||||
|
crypto,
|
||||||
|
INTEGRITY_USAGE(usage),
|
||||||
|
p,
|
||||||
|
len,
|
||||||
|
&cksum);
|
||||||
|
free(p);
|
||||||
|
if(ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
krb5_error_code KRB5_LIB_FUNCTION
|
|
||||||
krb5_crypto_length_padding(krb5_crypto crypto, size_t len)
|
size_t KRB5_LIB_FUNCTION
|
||||||
|
krb5_crypto_length(krb5_context context,
|
||||||
|
krb5_crypto crypto,
|
||||||
|
size_t len,
|
||||||
|
int type)
|
||||||
{
|
{
|
||||||
krb5_clear_error_string(context);
|
if (!derived_crypto(context, crypto))
|
||||||
return KRB5_CRYPTO_INTERNAL;
|
return (size_t)-1;
|
||||||
|
switch(type) {
|
||||||
|
case KRB5_CRYPTO_TYPE_EMPTY:
|
||||||
|
return 0;
|
||||||
|
case KRB5_CRYPTO_TYPE_HEADER:
|
||||||
|
return crypto->et->blocksize;
|
||||||
|
case KRB5_CRYPTO_TYPE_PADDING:
|
||||||
|
if (crypto->et->padsize > 1)
|
||||||
|
return crypto->et->padsize;
|
||||||
|
return 0;
|
||||||
|
case KRB5_CRYPTO_TYPE_TRAILER:
|
||||||
|
return CHECKSUMSIZE(crypto->et->keyed_checksum);
|
||||||
|
}
|
||||||
|
return (size_t)-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
krb5_error_code KRB5_LIB_FUNCTION
|
krb5_error_code KRB5_LIB_FUNCTION
|
||||||
@@ -3277,8 +3590,9 @@ krb5_encrypt_ivec_new(krb5_context context,
|
|||||||
size_t total_len;
|
size_t total_len;
|
||||||
|
|
||||||
total_len =
|
total_len =
|
||||||
krb5_crypto_signature_length(crypto, len) + len +
|
krb5_crypto_length(context, crypto, len, KRB5_CRYPTO_TYPE_HEADER) +
|
||||||
krb5_crypto_padding_length(crypto, len);
|
len +
|
||||||
|
krb5_crypto_length(context, crypto, len, KRB5_CRYPTO_TYPE_TRAILER);
|
||||||
|
|
||||||
ret = krb5_data_alloc(result, total_len);
|
ret = krb5_data_alloc(result, total_len);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
@@ -3286,21 +3600,21 @@ krb5_encrypt_ivec_new(krb5_context context,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
iov[0].flags = KRB5_CRYPTO_TYPE_SIGNATURE;
|
iov[0].flags = KRB5_CRYPTO_TYPE_HEADER;
|
||||||
iov[0].data.length = krb5_crypto_length_signature(crypto, len);
|
iov[0].data.length = krb5_crypto_length(context, crypto, len, iov[0].flags);
|
||||||
iov[0].data.data = result->data;
|
iov[0].data.data = result->data;
|
||||||
|
|
||||||
iov[1].flags = KRB5_CRYPTO_TYPE_DATA;
|
iov[1].flags = KRB5_CRYPTO_TYPE_DATA;
|
||||||
iov[1].data.length = len;
|
iov[1].data.length = len;
|
||||||
iov[1].data.data = ((char *)result->data) + iov[0].data.length;
|
iov[1].data.data = ((char *)result->data) + iov[0].data.length;
|
||||||
memcpy(iov[0].data.data, data);
|
memcpy(iov[0].data.data, data, len);
|
||||||
|
|
||||||
iov[2].flags = KRB5_CRYPTO_TYPE_PADDING;
|
iov[2].flags = KRB5_CRYPTO_TYPE_TRAILER;
|
||||||
iov[2].data.length = krb5_crypto_length_padding(crypto, len);
|
iov[2].data.length = krb5_crypto_length(context, crypto, len, iov[2].flags);
|
||||||
iov[2].data.data = ((char *)result->data) + iov[0].data.length + len;
|
iov[2].data.data = ((char *)result->data) + iov[0].data.length + len;
|
||||||
|
|
||||||
ret = krb5_encrypt_iov_ivec(context, crypto, usage,
|
ret = krb5_encrypt_iov_ivec(context, crypto, usage,
|
||||||
&iov, sizeof(iov)/sizeof(iov[0]), ivec);
|
iov, sizeof(iov)/sizeof(iov[0]), ivec);
|
||||||
if (ret)
|
if (ret)
|
||||||
krb5_data_free(result);
|
krb5_data_free(result);
|
||||||
return ret;
|
return ret;
|
||||||
|
Reference in New Issue
Block a user