mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-04-13 09:59:31 +00:00
crypto/krb5: Implement the Kerberos5 rfc3961 get_mic and verify_mic
Add functions that sign and verify a message according to rfc3961 sec 5.4, using Kc to generate a checksum and insert it into the MIC field in the skbuff in the sign phase then checksum the data and compare it to the MIC in the verify phase. Signed-off-by: David Howells <dhowells@redhat.com> cc: Herbert Xu <herbert@gondor.apana.org.au> cc: "David S. Miller" <davem@davemloft.net> cc: Chuck Lever <chuck.lever@oracle.com> cc: Marc Dionne <marc.dionne@auristor.com> cc: Eric Dumazet <edumazet@google.com> cc: Jakub Kicinski <kuba@kernel.org> cc: Paolo Abeni <pabeni@redhat.com> cc: Simon Horman <horms@kernel.org> cc: linux-afs@lists.infradead.org cc: linux-nfs@vger.kernel.org cc: linux-crypto@vger.kernel.org cc: netdev@vger.kernel.org
This commit is contained in:
parent
00244da40f
commit
348f5669d1
2 changed files with 140 additions and 0 deletions
|
@ -169,3 +169,13 @@ int krb5_aead_decrypt(const struct krb5_enctype *krb5,
|
|||
struct crypto_aead *aead,
|
||||
struct scatterlist *sg, unsigned int nr_sg,
|
||||
size_t *_offset, size_t *_len);
|
||||
ssize_t rfc3961_get_mic(const struct krb5_enctype *krb5,
|
||||
struct crypto_shash *shash,
|
||||
const struct krb5_buffer *metadata,
|
||||
struct scatterlist *sg, unsigned int nr_sg, size_t sg_len,
|
||||
size_t data_offset, size_t data_len);
|
||||
int rfc3961_verify_mic(const struct krb5_enctype *krb5,
|
||||
struct crypto_shash *shash,
|
||||
const struct krb5_buffer *metadata,
|
||||
struct scatterlist *sg, unsigned int nr_sg,
|
||||
size_t *_offset, size_t *_len);
|
||||
|
|
|
@ -653,6 +653,134 @@ error:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate a checksum over some metadata and part of an skbuff and insert the
|
||||
* MIC into the skbuff immediately prior to the data.
|
||||
*/
|
||||
ssize_t rfc3961_get_mic(const struct krb5_enctype *krb5,
|
||||
struct crypto_shash *shash,
|
||||
const struct krb5_buffer *metadata,
|
||||
struct scatterlist *sg, unsigned int nr_sg, size_t sg_len,
|
||||
size_t data_offset, size_t data_len)
|
||||
{
|
||||
struct shash_desc *desc;
|
||||
ssize_t ret, done;
|
||||
size_t bsize;
|
||||
void *buffer, *digest;
|
||||
|
||||
if (WARN_ON(data_offset != krb5->cksum_len))
|
||||
return -EMSGSIZE;
|
||||
|
||||
bsize = krb5_shash_size(shash) +
|
||||
krb5_digest_size(shash);
|
||||
buffer = kzalloc(bsize, GFP_NOFS);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Calculate the MIC with key Kc and store it into the skb */
|
||||
desc = buffer;
|
||||
desc->tfm = shash;
|
||||
ret = crypto_shash_init(desc);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
if (metadata) {
|
||||
ret = crypto_shash_update(desc, metadata->data, metadata->len);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = crypto_shash_update_sg(desc, sg, data_offset, data_len);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
digest = buffer + krb5_shash_size(shash);
|
||||
ret = crypto_shash_final(desc, digest);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
ret = -EFAULT;
|
||||
done = sg_pcopy_from_buffer(sg, nr_sg, digest, krb5->cksum_len,
|
||||
data_offset - krb5->cksum_len);
|
||||
if (done != krb5->cksum_len)
|
||||
goto error;
|
||||
|
||||
ret = krb5->cksum_len + data_len;
|
||||
|
||||
error:
|
||||
kfree_sensitive(buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the MIC on a region of an skbuff. The offset and length are updated
|
||||
* to reflect the actual content of the secure region.
|
||||
*/
|
||||
int rfc3961_verify_mic(const struct krb5_enctype *krb5,
|
||||
struct crypto_shash *shash,
|
||||
const struct krb5_buffer *metadata,
|
||||
struct scatterlist *sg, unsigned int nr_sg,
|
||||
size_t *_offset, size_t *_len)
|
||||
{
|
||||
struct shash_desc *desc;
|
||||
ssize_t done;
|
||||
size_t bsize, data_offset, data_len, offset = *_offset, len = *_len;
|
||||
void *buffer = NULL;
|
||||
int ret;
|
||||
u8 *cksum, *cksum2;
|
||||
|
||||
if (len < krb5->cksum_len)
|
||||
return -EPROTO;
|
||||
data_offset = offset + krb5->cksum_len;
|
||||
data_len = len - krb5->cksum_len;
|
||||
|
||||
bsize = krb5_shash_size(shash) +
|
||||
krb5_digest_size(shash) * 2;
|
||||
buffer = kzalloc(bsize, GFP_NOFS);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
cksum = buffer +
|
||||
krb5_shash_size(shash);
|
||||
cksum2 = buffer +
|
||||
krb5_shash_size(shash) +
|
||||
krb5_digest_size(shash);
|
||||
|
||||
/* Calculate the MIC */
|
||||
desc = buffer;
|
||||
desc->tfm = shash;
|
||||
ret = crypto_shash_init(desc);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
if (metadata) {
|
||||
ret = crypto_shash_update(desc, metadata->data, metadata->len);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
crypto_shash_update_sg(desc, sg, data_offset, data_len);
|
||||
crypto_shash_final(desc, cksum);
|
||||
|
||||
ret = -EFAULT;
|
||||
done = sg_pcopy_to_buffer(sg, nr_sg, cksum2, krb5->cksum_len, offset);
|
||||
if (done != krb5->cksum_len)
|
||||
goto error;
|
||||
|
||||
if (memcmp(cksum, cksum2, krb5->cksum_len) != 0) {
|
||||
ret = -EBADMSG;
|
||||
goto error;
|
||||
}
|
||||
|
||||
*_offset += krb5->cksum_len;
|
||||
*_len -= krb5->cksum_len;
|
||||
ret = 0;
|
||||
|
||||
error:
|
||||
kfree_sensitive(buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
const struct krb5_crypto_profile rfc3961_simplified_profile = {
|
||||
.calc_PRF = rfc3961_calc_PRF,
|
||||
.calc_Kc = rfc3961_calc_DK,
|
||||
|
@ -664,4 +792,6 @@ const struct krb5_crypto_profile rfc3961_simplified_profile = {
|
|||
.load_checksum_key = rfc3961_load_checksum_key,
|
||||
.encrypt = krb5_aead_encrypt,
|
||||
.decrypt = krb5_aead_decrypt,
|
||||
.get_mic = rfc3961_get_mic,
|
||||
.verify_mic = rfc3961_verify_mic,
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue