aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Hartman <hartmans@mit.edu>2008-12-01 16:41:26 +0000
committerSam Hartman <hartmans@mit.edu>2008-12-01 16:41:26 +0000
commit26df99363f4b42f68c00b2f76470b3ab1c62a354 (patch)
tree666d5ea43d1c2bf9b707c53ccf68472f1c8358d5
parent087199ae03c946635458a9833e2fd4e3d4dcd119 (diff)
downloadkrb5-26df99363f4b42f68c00b2f76470b3ab1c62a354.zip
krb5-26df99363f4b42f68c00b2f76470b3ab1c62a354.tar.gz
krb5-26df99363f4b42f68c00b2f76470b3ab1c62a354.tar.bz2
Some work on checksum code for AEAD
git-svn-id: svn://anonsvn.mit.edu/krb5/branches/mskrb-integ-crypto-iov@21212 dc483132-0cff-0310-8789-dd5450dbe970
-rw-r--r--src/include/k5-int.h21
-rw-r--r--src/include/krb5/krb5.hin1
-rw-r--r--src/lib/crypto/aead.c104
-rw-r--r--src/lib/crypto/aead.h8
-rw-r--r--src/lib/crypto/arcfour/arcfour_aead.c30
-rw-r--r--src/lib/crypto/dk/checksum.c72
-rw-r--r--src/lib/crypto/dk/dk.h6
-rw-r--r--src/lib/crypto/hmac.c40
-rw-r--r--src/lib/crypto/make_checksum_iov.c32
-rw-r--r--src/lib/crypto/verify_checksum_iov.c57
10 files changed, 340 insertions, 31 deletions
diff --git a/src/include/k5-int.h b/src/include/k5-int.h
index 588ba8d..03092bf 100644
--- a/src/include/k5-int.h
+++ b/src/include/k5-int.h
@@ -600,6 +600,21 @@ struct krb5_keyhash_provider {
const krb5_data *input,
const krb5_data *hash,
krb5_boolean *valid);
+
+ krb5_error_code (*hash_iov) (const krb5_keyblock *key,
+ krb5_keyusage keyusage,
+ const krb5_data *ivec,
+ const krb5_crypto_iov *data,
+ size_t num_data,
+ krb5_data *output);
+
+ krb5_error_code (*verify_iov) (const krb5_keyblock *key,
+ krb5_keyusage keyusage,
+ const krb5_data *ivec,
+ const krb5_data *input,
+ const krb5_crypto_iov *data,
+ size_t num_data,
+ krb5_boolean *valid);
};
struct krb5_aead_provider {
@@ -702,6 +717,12 @@ krb5_error_code krb5_hmac
const krb5_keyblock *key, unsigned int icount,
const krb5_data *input, krb5_data *output);
+krb5_error_code krb5_hmac_iov
+(const struct krb5_hash_provider *hash,
+ const krb5_keyblock *key,
+ const krb5_crypto_iov *data, size_t num_data,
+ krb5_data *output);
+
krb5_error_code krb5int_pbkdf2_hmac_sha1 (const krb5_data *, unsigned long,
const krb5_data *,
const krb5_data *);
diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin
index 1c88673..9755dc2 100644
--- a/src/include/krb5/krb5.hin
+++ b/src/include/krb5/krb5.hin
@@ -630,6 +630,7 @@ krb5_error_code KRB5_CALLCONV
krb5_error_code KRB5_CALLCONV
krb5_c_verify_checksum_iov
(krb5_context context,
+ krb5_cksumtype cksumtype,
const krb5_keyblock *key, krb5_keyusage usage,
const krb5_crypto_iov *data, size_t num_data,
krb5_boolean *valid);
diff --git a/src/lib/crypto/aead.c b/src/lib/crypto/aead.c
index 58f1aee..8c1a735 100644
--- a/src/lib/crypto/aead.c
+++ b/src/lib/crypto/aead.c
@@ -25,6 +25,9 @@
*/
#include "k5-int.h"
+#include "etypes.h"
+#include "cksumtypes.h"
+#include "dk.h"
#include "aead.h"
krb5_crypto_iov * KRB5_CALLCONV
@@ -50,3 +53,104 @@ krb5int_c_locate_iov(krb5_crypto_iov *data,
return iov;
}
+static krb5_error_code
+make_unkeyed_checksum_iov(const struct krb5_hash_provider *hash_provider,
+ const krb5_crypto_iov *data,
+ size_t num_data,
+ krb5_data *output)
+{
+ krb5_data *sign_data;
+ size_t num_sign_data;
+ krb5_error_code ret;
+ size_t i, j;
+
+ /* Create a checksum over all the data to be signed */
+ for (i = 0, num_sign_data = 0; i < num_data; i++) {
+ const krb5_crypto_iov *iov = &data[i];
+
+ if (iov->flags == KRB5_CRYPTO_TYPE_DATA ||
+ iov->flags == KRB5_CRYPTO_TYPE_SIGN_ONLY)
+ num_sign_data++;
+ }
+
+ /* XXX cleanup to avoid alloc */
+ sign_data = (krb5_data *)calloc(num_sign_data, sizeof(krb5_data));
+ if (sign_data == NULL)
+ return ENOMEM;
+
+ for (i = 0, j = 0; i < num_data; i++) {
+ const krb5_crypto_iov *iov = &data[i];
+
+ if (iov->flags == KRB5_CRYPTO_TYPE_DATA ||
+ iov->flags == KRB5_CRYPTO_TYPE_SIGN_ONLY) {
+ sign_data[j++] = iov[i].data;
+ }
+ }
+
+ ret = hash_provider->hash(num_sign_data, sign_data, output);
+
+ free(sign_data);
+
+ return ret;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5int_c_make_checksum_iov(const struct krb5_cksumtypes *cksum_type,
+ const krb5_keyblock *key,
+ krb5_keyusage usage,
+ const krb5_crypto_iov *data,
+ size_t num_data,
+ krb5_data *cksum_data)
+{
+ int e1, e2;
+ krb5_error_code ret;
+
+ if (cksum_type->keyhash) {
+ /* check if key is compatible */
+
+ if (cksum_type->keyed_etype) {
+ for (e1=0; e1<krb5_enctypes_length; e1++)
+ if (krb5_enctypes_list[e1].etype ==
+ cksum_type->keyed_etype)
+ break;
+
+ for (e2=0; e2<krb5_enctypes_length; e2++)
+ if (krb5_enctypes_list[e2].etype == key->enctype)
+ break;
+
+ if ((e1 == krb5_enctypes_length) ||
+ (e2 == krb5_enctypes_length) ||
+ (krb5_enctypes_list[e1].enc != krb5_enctypes_list[e2].enc)) {
+ ret = KRB5_BAD_ENCTYPE;
+ goto cleanup;
+ }
+ }
+
+ if (cksum_type->keyhash->hash_iov == NULL) {
+ return KRB5_BAD_ENCTYPE;
+ }
+
+ ret = (*(cksum_type->keyhash->hash_iov))(key, usage, 0,
+ data, num_data, cksum_data);
+ } else if (cksum_type->flags & KRB5_CKSUMFLAG_DERIVE) {
+ ret = krb5_dk_make_checksum_iov(cksum_type->hash,
+ key, usage, data, num_data,
+ cksum_data);
+ } else {
+ ret = make_unkeyed_checksum_iov(cksum_type->hash, data, num_data,
+ cksum_data);
+ }
+
+ if (!ret) {
+ if (cksum_type->trunc_size) {
+ cksum_data->length = cksum_type->trunc_size;
+ }
+ }
+
+cleanup:
+ if (ret) {
+ memset(cksum_data->data, 0, cksum_data->length);
+ }
+
+ return(ret);
+}
diff --git a/src/lib/crypto/aead.h b/src/lib/crypto/aead.h
index 83e4de8..29f97ae 100644
--- a/src/lib/crypto/aead.h
+++ b/src/lib/crypto/aead.h
@@ -33,3 +33,11 @@ krb5int_c_locate_iov(krb5_crypto_iov *data,
size_t num_data,
krb5_cryptotype type);
+krb5_error_code KRB5_CALLCONV
+krb5int_c_make_checksum_iov(const struct krb5_cksumtypes *cksum,
+ const krb5_keyblock *key,
+ krb5_keyusage usage,
+ const krb5_crypto_iov *data,
+ size_t num_data,
+ krb5_data *cksum_data);
+
diff --git a/src/lib/crypto/arcfour/arcfour_aead.c b/src/lib/crypto/arcfour/arcfour_aead.c
index b64e93b..0c51937 100644
--- a/src/lib/crypto/arcfour/arcfour_aead.c
+++ b/src/lib/crypto/arcfour/arcfour_aead.c
@@ -88,13 +88,11 @@ krb5int_arcfour_encrypt_iov(const struct krb5_aead_provider *aead,
{
krb5_error_code ret;
krb5_crypto_iov *header, *trailer, *padding;
- size_t i, j, num_sign_data;
krb5_keyblock k1, k2, k3;
krb5_data d1, d2, d3;
krb5_keyusage ms_usage;
char salt_data[14];
krb5_data salt;
- krb5_data *sign_data = NULL;
d1.length = d2.length = d3.length = 0;
d1.data = d2.data = d3.data = NULL;
@@ -156,32 +154,11 @@ krb5int_arcfour_encrypt_iov(const struct krb5_aead_provider *aead,
if (ret != 0)
goto cleanup;
- /* Create a checksum over all the data to be signed */
- for (i = 0, num_sign_data = 0; i < num_data; i++) {
- krb5_crypto_iov *iov = &data[i];
-
- if (iov->flags == KRB5_CRYPTO_TYPE_DATA ||
- iov->flags == KRB5_CRYPTO_TYPE_SIGN_ONLY)
- num_sign_data++;
- }
- sign_data = (krb5_data *)calloc(num_sign_data, sizeof(krb5_data));
- if (sign_data == NULL)
- goto cleanup;
-
- for (i = 0, j = 0; i < num_data; i++) {
- krb5_crypto_iov *iov = &data[i];
-
- if (iov->flags == KRB5_CRYPTO_TYPE_DATA ||
- iov->flags == KRB5_CRYPTO_TYPE_SIGN_ONLY) {
- sign_data[j++] = iov[i].data;
- }
- }
-
- krb5_hmac(hash, &k2, 1, sign_data, &trailer->data);
+ krb5_hmac_iov(hash, &k2, data, num_data, &trailer->data);
krb5_hmac(hash, &k1, 1, &trailer->data, &d3);
- ret = enc->encrypt_iov(&k3, ivec, data);
+ ret = enc->encrypt_iov(&k3, ivec, data, num_data);
cleanup:
if (d1.data != NULL) {
@@ -196,9 +173,6 @@ cleanup:
memset(d3.data, 0, d3.length);
free(d3.data);
}
- if (sign_data != NULL) {
- free(sign_data);
- }
return ret;
}
diff --git a/src/lib/crypto/dk/checksum.c b/src/lib/crypto/dk/checksum.c
index 2f30cb7..ccef9df 100644
--- a/src/lib/crypto/dk/checksum.c
+++ b/src/lib/crypto/dk/checksum.c
@@ -27,6 +27,7 @@
#include "k5-int.h"
#include "etypes.h"
#include "dk.h"
+#include "aead.h"
#define K5CLENGTH 5 /* 32 bit net byte order integer + one byte seed */
@@ -101,3 +102,74 @@ cleanup:
return(ret);
}
+krb5_error_code
+krb5_dk_make_checksum_iov(const struct krb5_hash_provider *hash,
+ const krb5_keyblock *key, krb5_keyusage usage,
+ const krb5_crypto_iov *data, size_t num_data,
+ krb5_data *output)
+{
+ int i;
+ const struct krb5_enc_provider *enc;
+ size_t blocksize, keybytes, keylength;
+ krb5_error_code ret;
+ unsigned char constantdata[K5CLENGTH];
+ krb5_data datain;
+ unsigned char *kcdata;
+ krb5_keyblock kc;
+ krb5_crypto_iov *checksum;
+
+ for (i=0; i<krb5_enctypes_length; i++) {
+ if (krb5_enctypes_list[i].etype == key->enctype)
+ break;
+ }
+
+ if (i == krb5_enctypes_length)
+ return(KRB5_BAD_ENCTYPE);
+
+ enc = krb5_enctypes_list[i].enc;
+
+ /* allocate and set to-be-derived keys */
+
+ blocksize = enc->block_size;
+ keybytes = enc->keybytes;
+ keylength = enc->keylength;
+
+ /* key->length will be tested in enc->encrypt
+ output->length will be tested in krb5_hmac */
+
+ if ((kcdata = (unsigned char *) malloc(keylength)) == NULL)
+ return(ENOMEM);
+
+ kc.contents = kcdata;
+ kc.length = keylength;
+
+ /* derive the key */
+
+ datain.data = (char *) constantdata;
+ datain.length = K5CLENGTH;
+
+ datain.data[0] = (usage>>24)&0xff;
+ datain.data[1] = (usage>>16)&0xff;
+ datain.data[2] = (usage>>8)&0xff;
+ datain.data[3] = usage&0xff;
+
+ datain.data[4] = (char) 0x99;
+
+ if ((ret = krb5_derive_key(enc, key, &kc, &datain)) != 0)
+ goto cleanup;
+
+ /* hash the data */
+
+ if ((ret = krb5_hmac_iov(hash, &kc, data, num_data, output)) != 0)
+ memset(output->data, 0, output->length);
+
+ /* ret is set correctly by the prior call */
+
+cleanup:
+ memset(kcdata, 0, keylength);
+
+ free(kcdata);
+
+ return(ret);
+}
+
diff --git a/src/lib/crypto/dk/dk.h b/src/lib/crypto/dk/dk.h
index 9e5aab8..a8def7a 100644
--- a/src/lib/crypto/dk/dk.h
+++ b/src/lib/crypto/dk/dk.h
@@ -85,6 +85,12 @@ krb5_error_code krb5_dk_make_checksum
const krb5_data *input, krb5_data *output);
krb5_error_code
+krb5_dk_make_checksum_iov(const struct krb5_hash_provider *hash,
+ const krb5_keyblock *key, krb5_keyusage usage,
+ const krb5_crypto_iov *data, size_t num_data,
+ krb5_data *output);
+
+krb5_error_code
krb5_derive_random(const struct krb5_enc_provider *enc,
const krb5_keyblock *inkey, krb5_data *outrnd,
const krb5_data *in_constant);
diff --git a/src/lib/crypto/hmac.c b/src/lib/crypto/hmac.c
index 3c02726..d3fd968 100644
--- a/src/lib/crypto/hmac.c
+++ b/src/lib/crypto/hmac.c
@@ -125,3 +125,43 @@ cleanup:
return(ret);
}
+
+krb5_error_code
+krb5_hmac_iov(const struct krb5_hash_provider *hash, const krb5_keyblock *key,
+ const krb5_crypto_iov *data, size_t num_data, krb5_data *output)
+{
+ krb5_data *sign_data;
+ size_t num_sign_data;
+ krb5_error_code ret;
+ size_t i, j;
+
+ /* Create a checksum over all the data to be signed */
+ for (i = 0, num_sign_data = 0; i < num_data; i++) {
+ const krb5_crypto_iov *iov = &data[i];
+
+ if (iov->flags == KRB5_CRYPTO_TYPE_DATA ||
+ iov->flags == KRB5_CRYPTO_TYPE_SIGN_ONLY)
+ num_sign_data++;
+ }
+ /* XXX cleanup to avoid alloc */
+ sign_data = (krb5_data *)calloc(num_sign_data, sizeof(krb5_data));
+ if (sign_data == NULL)
+ return ENOMEM;
+
+ for (i = 0, j = 0; i < num_data; i++) {
+ const krb5_crypto_iov *iov = &data[i];
+
+ if (iov->flags == KRB5_CRYPTO_TYPE_DATA ||
+ iov->flags == KRB5_CRYPTO_TYPE_SIGN_ONLY) {
+ sign_data[j++] = iov[i].data;
+ }
+ }
+
+ /* caller must store checksum in iov as it may be TYPE_TRAILER or TYPE_CHECKSUM */
+ ret = krb5_hmac(hash, key, num_sign_data, sign_data, output);
+
+ free(sign_data);
+
+ return ret;
+}
+
diff --git a/src/lib/crypto/make_checksum_iov.c b/src/lib/crypto/make_checksum_iov.c
index 6e52481..0d862c8 100644
--- a/src/lib/crypto/make_checksum_iov.c
+++ b/src/lib/crypto/make_checksum_iov.c
@@ -25,7 +25,8 @@
*/
#include "k5-int.h"
-#include "etypes.h"
+#include "cksumtypes.h"
+#include "aead.h"
krb5_error_code KRB5_CALLCONV
krb5_c_make_checksum_iov(krb5_context context,
@@ -35,4 +36,33 @@ krb5_c_make_checksum_iov(krb5_context context,
krb5_crypto_iov *data,
size_t num_data)
{
+ krb5_error_code ret;
+ size_t cksumlen;
+ krb5_crypto_iov *checksum;
+ size_t i;
+
+ for (i = 0; i < krb5_cksumtypes_length; i++) {
+ if (krb5_cksumtypes_list[i].ctype == cksumtype)
+ break;
+ }
+
+ if (i == krb5_cksumtypes_length)
+ return(KRB5_BAD_ENCTYPE);
+
+ if (krb5_cksumtypes_list[i].keyhash)
+ cksumlen = krb5_cksumtypes_list[i].keyhash->hashsize;
+ else
+ cksumlen = krb5_cksumtypes_list[i].hash->hashsize;
+
+ checksum = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_CHECKSUM);
+ if (checksum == NULL || checksum->data.length < cksumlen)
+ return(KRB5_BAD_MSIZE);
+
+ checksum->data.length = cksumlen;
+
+ ret = krb5int_c_make_checksum_iov(&krb5_cksumtypes_list[i],
+ key, usage, data, num_data,
+ &checksum->data);
+
+ return(ret);
}
diff --git a/src/lib/crypto/verify_checksum_iov.c b/src/lib/crypto/verify_checksum_iov.c
index 82672e8..5627188 100644
--- a/src/lib/crypto/verify_checksum_iov.c
+++ b/src/lib/crypto/verify_checksum_iov.c
@@ -25,15 +25,68 @@
*/
#include "k5-int.h"
-#include "etypes.h"
+#include "cksumtypes.h"
+#include "aead.h"
krb5_error_code KRB5_CALLCONV
krb5_c_verify_checksum_iov(krb5_context context,
+ krb5_cksumtype checksum_type,
const krb5_keyblock *key,
krb5_keyusage usage,
const krb5_crypto_iov *data,
size_t num_data,
krb5_boolean *valid)
{
-}
+ unsigned int i;
+ size_t hashsize;
+ krb5_error_code ret;
+ krb5_data computed;
+ krb5_crypto_iov *checksum;
+
+ for (i=0; i<krb5_cksumtypes_length; i++) {
+ if (krb5_cksumtypes_list[i].ctype == checksum_type)
+ break;
+ }
+
+ if (i == krb5_cksumtypes_length)
+ return(KRB5_BAD_ENCTYPE);
+
+ checksum = krb5int_c_locate_iov((krb5_crypto_iov *)data, num_data, KRB5_CRYPTO_TYPE_CHECKSUM);
+ if (checksum == NULL)
+ return(KRB5_BAD_MSIZE);
+
+ /* if there's actually a verify function, call it */
+
+ if (krb5_cksumtypes_list[i].keyhash &&
+ krb5_cksumtypes_list[i].keyhash->verify_iov)
+ return((*(krb5_cksumtypes_list[i].keyhash->verify_iov))(key, usage, 0,
+ &checksum->data,
+ data, num_data,
+ valid));
+
+ /* otherwise, make the checksum again, and compare */
+ if ((ret = krb5_c_checksum_length(context, checksum_type, &hashsize)))
+ return(ret);
+
+ if (checksum->data.length != hashsize)
+ return(KRB5_BAD_MSIZE);
+
+ computed.data = malloc(hashsize);
+ if (computed.data == NULL) {
+ return(ENOMEM);
+ }
+ computed.length = hashsize;
+
+ if ((ret = krb5int_c_make_checksum_iov(&krb5_cksumtypes_list[i], key, usage,
+ data, num_data, &computed))) {
+ free(computed.data);
+ return(ret);
+ }
+
+ *valid = (memcmp(computed.data, &checksum->data, hashsize) == 0);
+
+ free(computed.data);
+
+ return(0);
+}