Skip to content

Commit

Permalink
gss_krb5: introduce encryption type framework
Browse files Browse the repository at this point in the history
Add enctype framework and change functions to use the generic
values from it rather than the values hard-coded for des.

Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
Signed-off-by: Steve Dickson <steved@redhat.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
  • Loading branch information
Kevin Coffman authored and Trond Myklebust committed May 14, 2010
1 parent a8cc1cb commit 81d4a43
Show file tree
Hide file tree
Showing 6 changed files with 206 additions and 70 deletions.
25 changes: 24 additions & 1 deletion include/linux/sunrpc/gss_krb5.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* Adapted from MIT Kerberos 5-1.2.1 lib/include/krb5.h,
* lib/gssapi/krb5/gssapiP_krb5.h, and others
*
* Copyright (c) 2000 The Regents of the University of Michigan.
* Copyright (c) 2000-2008 The Regents of the University of Michigan.
* All rights reserved.
*
* Andy Adamson <andros@umich.edu>
Expand Down Expand Up @@ -36,6 +36,7 @@
*
*/

#include <linux/crypto.h>
#include <linux/sunrpc/auth_gss.h>
#include <linux/sunrpc/gss_err.h>
#include <linux/sunrpc/gss_asn1.h>
Expand All @@ -46,9 +47,31 @@
/* Maximum blocksize for the supported crypto algorithms */
#define GSS_KRB5_MAX_BLOCKSIZE (16)

struct gss_krb5_enctype {
const u32 etype; /* encryption (key) type */
const u32 ctype; /* checksum type */
const char *name; /* "friendly" name */
const char *encrypt_name; /* crypto encrypt name */
const char *cksum_name; /* crypto checksum name */
const u16 signalg; /* signing algorithm */
const u16 sealalg; /* sealing algorithm */
const u32 blocksize; /* encryption blocksize */
const u32 cksumlength; /* checksum length */
const u32 keyed_cksum; /* is it a keyed cksum? */
const u32 keybytes; /* raw key len, in bytes */
const u32 keylength; /* final key len, in bytes */
u32 (*encrypt) (struct crypto_blkcipher *tfm,
void *iv, void *in, void *out,
int length); /* encryption function */
u32 (*decrypt) (struct crypto_blkcipher *tfm,
void *iv, void *in, void *out,
int length); /* decryption function */
};

struct krb5_ctx {
int initiate; /* 1 = initiating, 0 = accepting */
u32 enctype;
const struct gss_krb5_enctype *gk5e; /* enctype-specific info */
struct crypto_blkcipher *enc;
struct crypto_blkcipher *seq;
s32 endtime;
Expand Down
18 changes: 9 additions & 9 deletions net/sunrpc/auth_gss/gss_krb5_crypto.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* linux/net/sunrpc/gss_krb5_crypto.c
*
* Copyright (c) 2000 The Regents of the University of Michigan.
* Copyright (c) 2000-2008 The Regents of the University of Michigan.
* All rights reserved.
*
* Andy Adamson <andros@umich.edu>
Expand Down Expand Up @@ -58,13 +58,13 @@ krb5_encrypt(
{
u32 ret = -EINVAL;
struct scatterlist sg[1];
u8 local_iv[16] = {0};
u8 local_iv[GSS_KRB5_MAX_BLOCKSIZE] = {0};
struct blkcipher_desc desc = { .tfm = tfm, .info = local_iv };

if (length % crypto_blkcipher_blocksize(tfm) != 0)
goto out;

if (crypto_blkcipher_ivsize(tfm) > 16) {
if (crypto_blkcipher_ivsize(tfm) > GSS_KRB5_MAX_BLOCKSIZE) {
dprintk("RPC: gss_k5encrypt: tfm iv size too large %d\n",
crypto_blkcipher_ivsize(tfm));
goto out;
Expand Down Expand Up @@ -92,13 +92,13 @@ krb5_decrypt(
{
u32 ret = -EINVAL;
struct scatterlist sg[1];
u8 local_iv[16] = {0};
u8 local_iv[GSS_KRB5_MAX_BLOCKSIZE] = {0};
struct blkcipher_desc desc = { .tfm = tfm, .info = local_iv };

if (length % crypto_blkcipher_blocksize(tfm) != 0)
goto out;

if (crypto_blkcipher_ivsize(tfm) > 16) {
if (crypto_blkcipher_ivsize(tfm) > GSS_KRB5_MAX_BLOCKSIZE) {
dprintk("RPC: gss_k5decrypt: tfm iv size too large %d\n",
crypto_blkcipher_ivsize(tfm));
goto out;
Expand Down Expand Up @@ -157,7 +157,7 @@ make_checksum(char *cksumname, char *header, int hdrlen, struct xdr_buf *body,
}

struct encryptor_desc {
u8 iv[8]; /* XXX hard-coded blocksize */
u8 iv[GSS_KRB5_MAX_BLOCKSIZE];
struct blkcipher_desc desc;
int pos;
struct xdr_buf *outbuf;
Expand Down Expand Up @@ -198,7 +198,7 @@ encryptor(struct scatterlist *sg, void *data)
desc->fraglen += sg->length;
desc->pos += sg->length;

fraglen = thislen & 7; /* XXX hardcoded blocksize */
fraglen = thislen & (crypto_blkcipher_blocksize(desc->desc.tfm) - 1);
thislen -= fraglen;

if (thislen == 0)
Expand Down Expand Up @@ -256,7 +256,7 @@ gss_encrypt_xdr_buf(struct crypto_blkcipher *tfm, struct xdr_buf *buf,
}

struct decryptor_desc {
u8 iv[8]; /* XXX hard-coded blocksize */
u8 iv[GSS_KRB5_MAX_BLOCKSIZE];
struct blkcipher_desc desc;
struct scatterlist frags[4];
int fragno;
Expand All @@ -278,7 +278,7 @@ decryptor(struct scatterlist *sg, void *data)
desc->fragno++;
desc->fraglen += sg->length;

fraglen = thislen & 7; /* XXX hardcoded blocksize */
fraglen = thislen & (crypto_blkcipher_blocksize(desc->desc.tfm) - 1);
thislen -= fraglen;

if (thislen == 0)
Expand Down
90 changes: 74 additions & 16 deletions net/sunrpc/auth_gss/gss_krb5_mech.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* linux/net/sunrpc/gss_krb5_mech.c
*
* Copyright (c) 2001 The Regents of the University of Michigan.
* Copyright (c) 2001-2008 The Regents of the University of Michigan.
* All rights reserved.
*
* Andy Adamson <andros@umich.edu>
Expand Down Expand Up @@ -48,6 +48,50 @@
# define RPCDBG_FACILITY RPCDBG_AUTH
#endif

static const struct gss_krb5_enctype supported_gss_krb5_enctypes[] = {
/*
* DES (All DES enctypes are mapped to the same gss functionality)
*/
{
.etype = ENCTYPE_DES_CBC_RAW,
.ctype = CKSUMTYPE_RSA_MD5,
.name = "des-cbc-crc",
.encrypt_name = "cbc(des)",
.cksum_name = "md5",
.encrypt = krb5_encrypt,
.decrypt = krb5_decrypt,
.signalg = SGN_ALG_DES_MAC_MD5,
.sealalg = SEAL_ALG_DES,
.keybytes = 7,
.keylength = 8,
.blocksize = 8,
.cksumlength = 8,
},
};

static const int num_supported_enctypes =
ARRAY_SIZE(supported_gss_krb5_enctypes);

static int
supported_gss_krb5_enctype(int etype)
{
int i;
for (i = 0; i < num_supported_enctypes; i++)
if (supported_gss_krb5_enctypes[i].etype == etype)
return 1;
return 0;
}

static const struct gss_krb5_enctype *
get_gss_krb5_enctype(int etype)
{
int i;
for (i = 0; i < num_supported_enctypes; i++)
if (supported_gss_krb5_enctypes[i].etype == etype)
return &supported_gss_krb5_enctypes[i];
return NULL;
}

static const void *
simple_get_bytes(const void *p, const void *end, void *res, int len)
{
Expand Down Expand Up @@ -78,35 +122,45 @@ simple_get_netobj(const void *p, const void *end, struct xdr_netobj *res)
}

static inline const void *
get_key(const void *p, const void *end, struct crypto_blkcipher **res)
get_key(const void *p, const void *end,
struct krb5_ctx *ctx, struct crypto_blkcipher **res)
{
struct xdr_netobj key;
int alg;
char *alg_name;

p = simple_get_bytes(p, end, &alg, sizeof(alg));
if (IS_ERR(p))
goto out_err;

switch (alg) {
case ENCTYPE_DES_CBC_CRC:
case ENCTYPE_DES_CBC_MD4:
case ENCTYPE_DES_CBC_MD5:
/* Map all these key types to ENCTYPE_DES_CBC_RAW */
alg = ENCTYPE_DES_CBC_RAW;
break;
}

if (!supported_gss_krb5_enctype(alg)) {
printk(KERN_WARNING "gss_kerberos_mech: unsupported "
"encryption key algorithm %d\n", alg);
goto out_err;
}
p = simple_get_netobj(p, end, &key);
if (IS_ERR(p))
goto out_err;

switch (alg) {
case ENCTYPE_DES_CBC_RAW:
alg_name = "cbc(des)";
break;
default:
printk("gss_kerberos_mech: unsupported algorithm %d\n", alg);
goto out_err_free_key;
}
*res = crypto_alloc_blkcipher(alg_name, 0, CRYPTO_ALG_ASYNC);
*res = crypto_alloc_blkcipher(ctx->gk5e->encrypt_name, 0,
CRYPTO_ALG_ASYNC);
if (IS_ERR(*res)) {
printk("gss_kerberos_mech: unable to initialize crypto algorithm %s\n", alg_name);
printk(KERN_WARNING "gss_kerberos_mech: unable to initialize "
"crypto algorithm %s\n", ctx->gk5e->encrypt_name);
*res = NULL;
goto out_err_free_key;
}
if (crypto_blkcipher_setkey(*res, key.data, key.len)) {
printk("gss_kerberos_mech: error setting key for crypto algorithm %s\n", alg_name);
printk(KERN_WARNING "gss_kerberos_mech: error setting key for "
"crypto algorithm %s\n", ctx->gk5e->encrypt_name);
goto out_err_free_tfm;
}

Expand Down Expand Up @@ -134,6 +188,10 @@ gss_import_v1_context(const void *p, const void *end, struct krb5_ctx *ctx)
/* Old format supports only DES! Any other enctype uses new format */
ctx->enctype = ENCTYPE_DES_CBC_RAW;

ctx->gk5e = get_gss_krb5_enctype(ctx->enctype);
if (ctx->gk5e == NULL)
goto out_err;

/* The downcall format was designed before we completely understood
* the uses of the context fields; so it includes some stuff we
* just give some minimal sanity-checking, and some we ignore
Expand Down Expand Up @@ -164,10 +222,10 @@ gss_import_v1_context(const void *p, const void *end, struct krb5_ctx *ctx)
p = simple_get_netobj(p, end, &ctx->mech_used);
if (IS_ERR(p))
goto out_err;
p = get_key(p, end, &ctx->enc);
p = get_key(p, end, ctx, &ctx->enc);
if (IS_ERR(p))
goto out_err_free_mech;
p = get_key(p, end, &ctx->seq);
p = get_key(p, end, ctx, &ctx->seq);
if (IS_ERR(p))
goto out_err_free_key1;
if (p != end) {
Expand Down
49 changes: 30 additions & 19 deletions net/sunrpc/auth_gss/gss_krb5_seal.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*
* Adapted from MIT Kerberos 5-1.2.1 lib/gssapi/krb5/k5seal.c
*
* Copyright (c) 2000 The Regents of the University of Michigan.
* Copyright (c) 2000-2008 The Regents of the University of Michigan.
* All rights reserved.
*
* Andy Adamson <andros@umich.edu>
Expand Down Expand Up @@ -70,36 +70,47 @@

DEFINE_SPINLOCK(krb5_seq_lock);

static char *
setup_token(struct krb5_ctx *ctx, struct xdr_netobj *token)
{
__be16 *ptr, *krb5_hdr;
int body_size = GSS_KRB5_TOK_HDR_LEN + ctx->gk5e->cksumlength;

token->len = g_token_size(&ctx->mech_used, body_size);

ptr = (__be16 *)token->data;
g_make_token_header(&ctx->mech_used, body_size, (unsigned char **)&ptr);

/* ptr now at start of header described in rfc 1964, section 1.2.1: */
krb5_hdr = ptr;
*ptr++ = KG_TOK_MIC_MSG;
*ptr++ = cpu_to_le16(ctx->gk5e->signalg);
*ptr++ = SEAL_ALG_NONE;
*ptr++ = 0xffff;

return (char *)krb5_hdr;
}

static u32
gss_get_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *text,
struct xdr_netobj *token)
{
char cksumdata[16];
struct xdr_netobj md5cksum = {.len = 0, .data = cksumdata};
unsigned char *ptr, *msg_start;
char cksumdata[GSS_KRB5_MAX_CKSUM_LEN];
struct xdr_netobj md5cksum = {.len = sizeof(cksumdata),
.data = cksumdata};
void *ptr;
s32 now;
u32 seq_send;

dprintk("RPC: gss_krb5_seal\n");
dprintk("RPC: %s\n", __func__);
BUG_ON(ctx == NULL);

now = get_seconds();

token->len = g_token_size(&ctx->mech_used, GSS_KRB5_TOK_HDR_LEN + 8);

ptr = token->data;
g_make_token_header(&ctx->mech_used, GSS_KRB5_TOK_HDR_LEN + 8, &ptr);

/* ptr now at header described in rfc 1964, section 1.2.1: */
ptr[0] = (unsigned char) ((KG_TOK_MIC_MSG >> 8) & 0xff);
ptr[1] = (unsigned char) (KG_TOK_MIC_MSG & 0xff);

msg_start = ptr + GSS_KRB5_TOK_HDR_LEN + 8;

*(__be16 *)(ptr + 2) = htons(SGN_ALG_DES_MAC_MD5);
memset(ptr + 4, 0xff, 4);
ptr = setup_token(ctx, token);

if (make_checksum("md5", ptr, 8, text, 0, &md5cksum))
if (make_checksum((char *)ctx->gk5e->cksum_name, ptr, 8,
text, 0, &md5cksum))
return GSS_S_FAILURE;

if (krb5_encrypt(ctx->seq, NULL, md5cksum.data,
Expand Down
15 changes: 9 additions & 6 deletions net/sunrpc/auth_gss/gss_krb5_unseal.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*
* Adapted from MIT Kerberos 5-1.2.1 lib/gssapi/krb5/k5unseal.c
*
* Copyright (c) 2000 The Regents of the University of Michigan.
* Copyright (c) 2000-2008 The Regents of the University of Michigan.
* All rights reserved.
*
* Andy Adamson <andros@umich.edu>
Expand Down Expand Up @@ -76,8 +76,9 @@ gss_verify_mic_v1(struct krb5_ctx *ctx,
{
int signalg;
int sealalg;
char cksumdata[16];
struct xdr_netobj md5cksum = {.len = 0, .data = cksumdata};
char cksumdata[GSS_KRB5_MAX_CKSUM_LEN];
struct xdr_netobj md5cksum = {.len = sizeof(cksumdata),
.data = cksumdata};
s32 now;
int direction;
u32 seqnum;
Expand All @@ -97,7 +98,7 @@ gss_verify_mic_v1(struct krb5_ctx *ctx,
/* XXX sanity-check bodysize?? */

signalg = ptr[2] + (ptr[3] << 8);
if (signalg != SGN_ALG_DES_MAC_MD5)
if (signalg != ctx->gk5e->signalg)
return GSS_S_DEFECTIVE_TOKEN;

sealalg = ptr[4] + (ptr[5] << 8);
Expand All @@ -107,13 +108,15 @@ gss_verify_mic_v1(struct krb5_ctx *ctx,
if ((ptr[6] != 0xff) || (ptr[7] != 0xff))
return GSS_S_DEFECTIVE_TOKEN;

if (make_checksum("md5", ptr, 8, message_buffer, 0, &md5cksum))
if (make_checksum((char *)ctx->gk5e->cksum_name, ptr, 8,
message_buffer, 0, &md5cksum))
return GSS_S_FAILURE;

if (krb5_encrypt(ctx->seq, NULL, md5cksum.data, md5cksum.data, 16))
return GSS_S_FAILURE;

if (memcmp(md5cksum.data + 8, ptr + GSS_KRB5_TOK_HDR_LEN, 8))
if (memcmp(md5cksum.data + 8, ptr + GSS_KRB5_TOK_HDR_LEN,
ctx->gk5e->cksumlength))
return GSS_S_BAD_SIG;

/* it got through unscathed. Make sure the context is unexpired */
Expand Down
Loading

0 comments on commit 81d4a43

Please sign in to comment.