gss_krb5: add support for new token formats in rfc4121
This is a step toward support for AES encryption types which are required to use the new token formats defined in rfc4121. Signed-off-by: Kevin Coffman <kwc@citi.umich.edu> [SteveD: Fixed a typo in gss_verify_mic_v2()] Signed-off-by: Steve Dickson <steved@redhat.com> [Trond: Got rid of the TEST_ROTATE/TEST_EXTRA_COUNT crap] Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
parent
c43abaedaf
commit
de9c17eb4a
|
@ -53,6 +53,8 @@
|
||||||
/* Maximum blocksize for the supported crypto algorithms */
|
/* Maximum blocksize for the supported crypto algorithms */
|
||||||
#define GSS_KRB5_MAX_BLOCKSIZE (16)
|
#define GSS_KRB5_MAX_BLOCKSIZE (16)
|
||||||
|
|
||||||
|
struct krb5_ctx;
|
||||||
|
|
||||||
struct gss_krb5_enctype {
|
struct gss_krb5_enctype {
|
||||||
const u32 etype; /* encryption (key) type */
|
const u32 etype; /* encryption (key) type */
|
||||||
const u32 ctype; /* checksum type */
|
const u32 ctype; /* checksum type */
|
||||||
|
@ -75,6 +77,12 @@ struct gss_krb5_enctype {
|
||||||
u32 (*mk_key) (const struct gss_krb5_enctype *gk5e,
|
u32 (*mk_key) (const struct gss_krb5_enctype *gk5e,
|
||||||
struct xdr_netobj *in,
|
struct xdr_netobj *in,
|
||||||
struct xdr_netobj *out); /* complete key generation */
|
struct xdr_netobj *out); /* complete key generation */
|
||||||
|
u32 (*encrypt_v2) (struct krb5_ctx *kctx, u32 offset,
|
||||||
|
struct xdr_buf *buf, int ec,
|
||||||
|
struct page **pages); /* v2 encryption function */
|
||||||
|
u32 (*decrypt_v2) (struct krb5_ctx *kctx, u32 offset,
|
||||||
|
struct xdr_buf *buf, u32 *headskip,
|
||||||
|
u32 *tailskip); /* v2 decryption function */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* krb5_ctx flags definitions */
|
/* krb5_ctx flags definitions */
|
||||||
|
@ -112,6 +120,18 @@ extern spinlock_t krb5_seq_lock;
|
||||||
#define KG_TOK_MIC_MSG 0x0101
|
#define KG_TOK_MIC_MSG 0x0101
|
||||||
#define KG_TOK_WRAP_MSG 0x0201
|
#define KG_TOK_WRAP_MSG 0x0201
|
||||||
|
|
||||||
|
#define KG2_TOK_INITIAL 0x0101
|
||||||
|
#define KG2_TOK_RESPONSE 0x0202
|
||||||
|
#define KG2_TOK_MIC 0x0404
|
||||||
|
#define KG2_TOK_WRAP 0x0504
|
||||||
|
|
||||||
|
#define KG2_TOKEN_FLAG_SENTBYACCEPTOR 0x01
|
||||||
|
#define KG2_TOKEN_FLAG_SEALED 0x02
|
||||||
|
#define KG2_TOKEN_FLAG_ACCEPTORSUBKEY 0x04
|
||||||
|
|
||||||
|
#define KG2_RESP_FLAG_ERROR 0x0001
|
||||||
|
#define KG2_RESP_FLAG_DELEG_OK 0x0002
|
||||||
|
|
||||||
enum sgn_alg {
|
enum sgn_alg {
|
||||||
SGN_ALG_DES_MAC_MD5 = 0x0000,
|
SGN_ALG_DES_MAC_MD5 = 0x0000,
|
||||||
SGN_ALG_MD2_5 = 0x0001,
|
SGN_ALG_MD2_5 = 0x0001,
|
||||||
|
@ -136,6 +156,9 @@ enum seal_alg {
|
||||||
#define CKSUMTYPE_RSA_MD5_DES 0x0008
|
#define CKSUMTYPE_RSA_MD5_DES 0x0008
|
||||||
#define CKSUMTYPE_NIST_SHA 0x0009
|
#define CKSUMTYPE_NIST_SHA 0x0009
|
||||||
#define CKSUMTYPE_HMAC_SHA1_DES3 0x000c
|
#define CKSUMTYPE_HMAC_SHA1_DES3 0x000c
|
||||||
|
#define CKSUMTYPE_HMAC_SHA1_96_AES128 0x000f
|
||||||
|
#define CKSUMTYPE_HMAC_SHA1_96_AES256 0x0010
|
||||||
|
#define CKSUMTYPE_HMAC_MD5_ARCFOUR -138 /* Microsoft md5 hmac cksumtype */
|
||||||
|
|
||||||
/* from gssapi_err_krb5.h */
|
/* from gssapi_err_krb5.h */
|
||||||
#define KG_CCACHE_NOMATCH (39756032L)
|
#define KG_CCACHE_NOMATCH (39756032L)
|
||||||
|
@ -212,6 +235,11 @@ make_checksum(struct krb5_ctx *kctx, char *header, int hdrlen,
|
||||||
struct xdr_buf *body, int body_offset, u8 *cksumkey,
|
struct xdr_buf *body, int body_offset, u8 *cksumkey,
|
||||||
struct xdr_netobj *cksumout);
|
struct xdr_netobj *cksumout);
|
||||||
|
|
||||||
|
u32
|
||||||
|
make_checksum_v2(struct krb5_ctx *, char *header, int hdrlen,
|
||||||
|
struct xdr_buf *body, int body_offset, u8 *key,
|
||||||
|
struct xdr_netobj *cksum);
|
||||||
|
|
||||||
u32 gss_get_mic_kerberos(struct gss_ctx *, struct xdr_buf *,
|
u32 gss_get_mic_kerberos(struct gss_ctx *, struct xdr_buf *,
|
||||||
struct xdr_netobj *);
|
struct xdr_netobj *);
|
||||||
|
|
||||||
|
|
|
@ -197,6 +197,80 @@ out:
|
||||||
return err ? GSS_S_FAILURE : 0;
|
return err ? GSS_S_FAILURE : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* checksum the plaintext data and hdrlen bytes of the token header
|
||||||
|
* Per rfc4121, sec. 4.2.4, the checksum is performed over the data
|
||||||
|
* body then over the first 16 octets of the MIC token
|
||||||
|
* Inclusion of the header data in the calculation of the
|
||||||
|
* checksum is optional.
|
||||||
|
*/
|
||||||
|
u32
|
||||||
|
make_checksum_v2(struct krb5_ctx *kctx, char *header, int hdrlen,
|
||||||
|
struct xdr_buf *body, int body_offset, u8 *cksumkey,
|
||||||
|
struct xdr_netobj *cksumout)
|
||||||
|
{
|
||||||
|
struct hash_desc desc;
|
||||||
|
struct scatterlist sg[1];
|
||||||
|
int err;
|
||||||
|
u8 checksumdata[GSS_KRB5_MAX_CKSUM_LEN];
|
||||||
|
unsigned int checksumlen;
|
||||||
|
|
||||||
|
if (kctx->gk5e->keyed_cksum == 0) {
|
||||||
|
dprintk("%s: expected keyed hash for %s\n",
|
||||||
|
__func__, kctx->gk5e->name);
|
||||||
|
return GSS_S_FAILURE;
|
||||||
|
}
|
||||||
|
if (cksumkey == NULL) {
|
||||||
|
dprintk("%s: no key supplied for %s\n",
|
||||||
|
__func__, kctx->gk5e->name);
|
||||||
|
return GSS_S_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
desc.tfm = crypto_alloc_hash(kctx->gk5e->cksum_name, 0,
|
||||||
|
CRYPTO_ALG_ASYNC);
|
||||||
|
if (IS_ERR(desc.tfm))
|
||||||
|
return GSS_S_FAILURE;
|
||||||
|
checksumlen = crypto_hash_digestsize(desc.tfm);
|
||||||
|
desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
|
||||||
|
|
||||||
|
err = crypto_hash_setkey(desc.tfm, cksumkey, kctx->gk5e->keylength);
|
||||||
|
if (err)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
err = crypto_hash_init(&desc);
|
||||||
|
if (err)
|
||||||
|
goto out;
|
||||||
|
err = xdr_process_buf(body, body_offset, body->len - body_offset,
|
||||||
|
checksummer, &desc);
|
||||||
|
if (err)
|
||||||
|
goto out;
|
||||||
|
if (header != NULL) {
|
||||||
|
sg_init_one(sg, header, hdrlen);
|
||||||
|
err = crypto_hash_update(&desc, sg, hdrlen);
|
||||||
|
if (err)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
err = crypto_hash_final(&desc, checksumdata);
|
||||||
|
if (err)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
cksumout->len = kctx->gk5e->cksumlength;
|
||||||
|
|
||||||
|
switch (kctx->gk5e->ctype) {
|
||||||
|
case CKSUMTYPE_HMAC_SHA1_96_AES128:
|
||||||
|
case CKSUMTYPE_HMAC_SHA1_96_AES256:
|
||||||
|
/* note that this truncates the hash */
|
||||||
|
memcpy(cksumout->data, checksumdata, kctx->gk5e->cksumlength);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BUG();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
crypto_free_hash(desc.tfm);
|
||||||
|
return err ? GSS_S_FAILURE : 0;
|
||||||
|
}
|
||||||
|
|
||||||
struct encryptor_desc {
|
struct encryptor_desc {
|
||||||
u8 iv[GSS_KRB5_MAX_BLOCKSIZE];
|
u8 iv[GSS_KRB5_MAX_BLOCKSIZE];
|
||||||
struct blkcipher_desc desc;
|
struct blkcipher_desc desc;
|
||||||
|
|
|
@ -91,6 +91,33 @@ setup_token(struct krb5_ctx *ctx, struct xdr_netobj *token)
|
||||||
return (char *)krb5_hdr;
|
return (char *)krb5_hdr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
setup_token_v2(struct krb5_ctx *ctx, struct xdr_netobj *token)
|
||||||
|
{
|
||||||
|
__be16 *ptr, *krb5_hdr;
|
||||||
|
u8 *p, flags = 0x00;
|
||||||
|
|
||||||
|
if ((ctx->flags & KRB5_CTX_FLAG_INITIATOR) == 0)
|
||||||
|
flags |= 0x01;
|
||||||
|
if (ctx->flags & KRB5_CTX_FLAG_ACCEPTOR_SUBKEY)
|
||||||
|
flags |= 0x04;
|
||||||
|
|
||||||
|
/* Per rfc 4121, sec 4.2.6.1, there is no header,
|
||||||
|
* just start the token */
|
||||||
|
krb5_hdr = ptr = (__be16 *)token->data;
|
||||||
|
|
||||||
|
*ptr++ = KG2_TOK_MIC;
|
||||||
|
p = (u8 *)ptr;
|
||||||
|
*p++ = flags;
|
||||||
|
*p++ = 0xff;
|
||||||
|
ptr = (__be16 *)p;
|
||||||
|
*ptr++ = 0xffff;
|
||||||
|
*ptr++ = 0xffff;
|
||||||
|
|
||||||
|
token->len = GSS_KRB5_TOK_HDR_LEN + ctx->gk5e->cksumlength;
|
||||||
|
return krb5_hdr;
|
||||||
|
}
|
||||||
|
|
||||||
static u32
|
static u32
|
||||||
gss_get_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *text,
|
gss_get_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *text,
|
||||||
struct xdr_netobj *token)
|
struct xdr_netobj *token)
|
||||||
|
@ -132,6 +159,45 @@ gss_get_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *text,
|
||||||
return (ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE;
|
return (ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32
|
||||||
|
gss_get_mic_v2(struct krb5_ctx *ctx, struct xdr_buf *text,
|
||||||
|
struct xdr_netobj *token)
|
||||||
|
{
|
||||||
|
char cksumdata[GSS_KRB5_MAX_CKSUM_LEN];
|
||||||
|
struct xdr_netobj cksumobj = { .len = sizeof(cksumdata),
|
||||||
|
.data = cksumdata};
|
||||||
|
void *krb5_hdr;
|
||||||
|
s32 now;
|
||||||
|
u64 seq_send;
|
||||||
|
u8 *cksumkey;
|
||||||
|
|
||||||
|
dprintk("RPC: %s\n", __func__);
|
||||||
|
|
||||||
|
krb5_hdr = setup_token_v2(ctx, token);
|
||||||
|
|
||||||
|
/* Set up the sequence number. Now 64-bits in clear
|
||||||
|
* text and w/o direction indicator */
|
||||||
|
spin_lock(&krb5_seq_lock);
|
||||||
|
seq_send = ctx->seq_send64++;
|
||||||
|
spin_unlock(&krb5_seq_lock);
|
||||||
|
*((u64 *)(krb5_hdr + 8)) = cpu_to_be64(seq_send);
|
||||||
|
|
||||||
|
if (ctx->initiate)
|
||||||
|
cksumkey = ctx->initiator_sign;
|
||||||
|
else
|
||||||
|
cksumkey = ctx->acceptor_sign;
|
||||||
|
|
||||||
|
if (make_checksum_v2(ctx, krb5_hdr, GSS_KRB5_TOK_HDR_LEN,
|
||||||
|
text, 0, cksumkey, &cksumobj))
|
||||||
|
return GSS_S_FAILURE;
|
||||||
|
|
||||||
|
memcpy(krb5_hdr + GSS_KRB5_TOK_HDR_LEN, cksumobj.data, cksumobj.len);
|
||||||
|
|
||||||
|
now = get_seconds();
|
||||||
|
|
||||||
|
return (ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE;
|
||||||
|
}
|
||||||
|
|
||||||
u32
|
u32
|
||||||
gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text,
|
gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text,
|
||||||
struct xdr_netobj *token)
|
struct xdr_netobj *token)
|
||||||
|
@ -144,6 +210,9 @@ gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text,
|
||||||
case ENCTYPE_DES_CBC_RAW:
|
case ENCTYPE_DES_CBC_RAW:
|
||||||
case ENCTYPE_DES3_CBC_RAW:
|
case ENCTYPE_DES3_CBC_RAW:
|
||||||
return gss_get_mic_v1(ctx, text, token);
|
return gss_get_mic_v1(ctx, text, token);
|
||||||
|
case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
|
||||||
|
case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
|
||||||
|
return gss_get_mic_v2(ctx, text, token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -141,6 +141,64 @@ gss_verify_mic_v1(struct krb5_ctx *ctx,
|
||||||
return GSS_S_COMPLETE;
|
return GSS_S_COMPLETE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u32
|
||||||
|
gss_verify_mic_v2(struct krb5_ctx *ctx,
|
||||||
|
struct xdr_buf *message_buffer, struct xdr_netobj *read_token)
|
||||||
|
{
|
||||||
|
char cksumdata[GSS_KRB5_MAX_CKSUM_LEN];
|
||||||
|
struct xdr_netobj cksumobj = {.len = sizeof(cksumdata),
|
||||||
|
.data = cksumdata};
|
||||||
|
s32 now;
|
||||||
|
u64 seqnum;
|
||||||
|
u8 *ptr = read_token->data;
|
||||||
|
u8 *cksumkey;
|
||||||
|
u8 flags;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
dprintk("RPC: %s\n", __func__);
|
||||||
|
|
||||||
|
if (be16_to_cpu(*((__be16 *)ptr)) != KG2_TOK_MIC)
|
||||||
|
return GSS_S_DEFECTIVE_TOKEN;
|
||||||
|
|
||||||
|
flags = ptr[2];
|
||||||
|
if ((!ctx->initiate && (flags & KG2_TOKEN_FLAG_SENTBYACCEPTOR)) ||
|
||||||
|
(ctx->initiate && !(flags & KG2_TOKEN_FLAG_SENTBYACCEPTOR)))
|
||||||
|
return GSS_S_BAD_SIG;
|
||||||
|
|
||||||
|
if (flags & KG2_TOKEN_FLAG_SEALED) {
|
||||||
|
dprintk("%s: token has unexpected sealed flag\n", __func__);
|
||||||
|
return GSS_S_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 3; i < 8; i++)
|
||||||
|
if (ptr[i] != 0xff)
|
||||||
|
return GSS_S_DEFECTIVE_TOKEN;
|
||||||
|
|
||||||
|
if (ctx->initiate)
|
||||||
|
cksumkey = ctx->acceptor_sign;
|
||||||
|
else
|
||||||
|
cksumkey = ctx->initiator_sign;
|
||||||
|
|
||||||
|
if (make_checksum_v2(ctx, ptr, GSS_KRB5_TOK_HDR_LEN, message_buffer, 0,
|
||||||
|
cksumkey, &cksumobj))
|
||||||
|
return GSS_S_FAILURE;
|
||||||
|
|
||||||
|
if (memcmp(cksumobj.data, ptr + GSS_KRB5_TOK_HDR_LEN,
|
||||||
|
ctx->gk5e->cksumlength))
|
||||||
|
return GSS_S_BAD_SIG;
|
||||||
|
|
||||||
|
/* it got through unscathed. Make sure the context is unexpired */
|
||||||
|
now = get_seconds();
|
||||||
|
if (now > ctx->endtime)
|
||||||
|
return GSS_S_CONTEXT_EXPIRED;
|
||||||
|
|
||||||
|
/* do sequencing checks */
|
||||||
|
|
||||||
|
seqnum = be64_to_cpup((__be64 *)ptr + 8);
|
||||||
|
|
||||||
|
return GSS_S_COMPLETE;
|
||||||
|
}
|
||||||
|
|
||||||
u32
|
u32
|
||||||
gss_verify_mic_kerberos(struct gss_ctx *gss_ctx,
|
gss_verify_mic_kerberos(struct gss_ctx *gss_ctx,
|
||||||
struct xdr_buf *message_buffer,
|
struct xdr_buf *message_buffer,
|
||||||
|
@ -154,6 +212,9 @@ gss_verify_mic_kerberos(struct gss_ctx *gss_ctx,
|
||||||
case ENCTYPE_DES_CBC_RAW:
|
case ENCTYPE_DES_CBC_RAW:
|
||||||
case ENCTYPE_DES3_CBC_RAW:
|
case ENCTYPE_DES3_CBC_RAW:
|
||||||
return gss_verify_mic_v1(ctx, message_buffer, read_token);
|
return gss_verify_mic_v1(ctx, message_buffer, read_token);
|
||||||
|
case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
|
||||||
|
case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
|
||||||
|
return gss_verify_mic_v2(ctx, message_buffer, read_token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -340,6 +340,174 @@ gss_unwrap_kerberos_v1(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf)
|
||||||
return GSS_S_COMPLETE;
|
return GSS_S_COMPLETE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We cannot currently handle tokens with rotated data. We need a
|
||||||
|
* generalized routine to rotate the data in place. It is anticipated
|
||||||
|
* that we won't encounter rotated data in the general case.
|
||||||
|
*/
|
||||||
|
static u32
|
||||||
|
rotate_left(struct krb5_ctx *kctx, u32 offset, struct xdr_buf *buf, u16 rrc)
|
||||||
|
{
|
||||||
|
unsigned int realrrc = rrc % (buf->len - offset - GSS_KRB5_TOK_HDR_LEN);
|
||||||
|
|
||||||
|
if (realrrc == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
dprintk("%s: cannot process token with rotated data: "
|
||||||
|
"rrc %u, realrrc %u\n", __func__, rrc, realrrc);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32
|
||||||
|
gss_wrap_kerberos_v2(struct krb5_ctx *kctx, u32 offset,
|
||||||
|
struct xdr_buf *buf, struct page **pages)
|
||||||
|
{
|
||||||
|
int blocksize;
|
||||||
|
u8 *ptr, *plainhdr;
|
||||||
|
s32 now;
|
||||||
|
u8 flags = 0x00;
|
||||||
|
__be16 *be16ptr, ec = 0;
|
||||||
|
__be64 *be64ptr;
|
||||||
|
u32 err;
|
||||||
|
|
||||||
|
dprintk("RPC: %s\n", __func__);
|
||||||
|
|
||||||
|
if (kctx->gk5e->encrypt_v2 == NULL)
|
||||||
|
return GSS_S_FAILURE;
|
||||||
|
|
||||||
|
/* make room for gss token header */
|
||||||
|
if (xdr_extend_head(buf, offset, GSS_KRB5_TOK_HDR_LEN))
|
||||||
|
return GSS_S_FAILURE;
|
||||||
|
|
||||||
|
/* construct gss token header */
|
||||||
|
ptr = plainhdr = buf->head[0].iov_base + offset;
|
||||||
|
*ptr++ = (unsigned char) ((KG2_TOK_WRAP>>8) & 0xff);
|
||||||
|
*ptr++ = (unsigned char) (KG2_TOK_WRAP & 0xff);
|
||||||
|
|
||||||
|
if ((kctx->flags & KRB5_CTX_FLAG_INITIATOR) == 0)
|
||||||
|
flags |= KG2_TOKEN_FLAG_SENTBYACCEPTOR;
|
||||||
|
if ((kctx->flags & KRB5_CTX_FLAG_ACCEPTOR_SUBKEY) != 0)
|
||||||
|
flags |= KG2_TOKEN_FLAG_ACCEPTORSUBKEY;
|
||||||
|
/* We always do confidentiality in wrap tokens */
|
||||||
|
flags |= KG2_TOKEN_FLAG_SEALED;
|
||||||
|
|
||||||
|
*ptr++ = flags;
|
||||||
|
*ptr++ = 0xff;
|
||||||
|
be16ptr = (__be16 *)ptr;
|
||||||
|
|
||||||
|
blocksize = crypto_blkcipher_blocksize(kctx->acceptor_enc);
|
||||||
|
*be16ptr++ = cpu_to_be16(ec);
|
||||||
|
/* "inner" token header always uses 0 for RRC */
|
||||||
|
*be16ptr++ = cpu_to_be16(0);
|
||||||
|
|
||||||
|
be64ptr = (__be64 *)be16ptr;
|
||||||
|
spin_lock(&krb5_seq_lock);
|
||||||
|
*be64ptr = cpu_to_be64(kctx->seq_send64++);
|
||||||
|
spin_unlock(&krb5_seq_lock);
|
||||||
|
|
||||||
|
err = (*kctx->gk5e->encrypt_v2)(kctx, offset, buf, ec, pages);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
now = get_seconds();
|
||||||
|
return (kctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32
|
||||||
|
gss_unwrap_kerberos_v2(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf)
|
||||||
|
{
|
||||||
|
s32 now;
|
||||||
|
u64 seqnum;
|
||||||
|
u8 *ptr;
|
||||||
|
u8 flags = 0x00;
|
||||||
|
u16 ec, rrc;
|
||||||
|
int err;
|
||||||
|
u32 headskip, tailskip;
|
||||||
|
u8 decrypted_hdr[GSS_KRB5_TOK_HDR_LEN];
|
||||||
|
unsigned int movelen;
|
||||||
|
|
||||||
|
|
||||||
|
dprintk("RPC: %s\n", __func__);
|
||||||
|
|
||||||
|
if (kctx->gk5e->decrypt_v2 == NULL)
|
||||||
|
return GSS_S_FAILURE;
|
||||||
|
|
||||||
|
ptr = buf->head[0].iov_base + offset;
|
||||||
|
|
||||||
|
if (be16_to_cpu(*((__be16 *)ptr)) != KG2_TOK_WRAP)
|
||||||
|
return GSS_S_DEFECTIVE_TOKEN;
|
||||||
|
|
||||||
|
flags = ptr[2];
|
||||||
|
if ((!kctx->initiate && (flags & KG2_TOKEN_FLAG_SENTBYACCEPTOR)) ||
|
||||||
|
(kctx->initiate && !(flags & KG2_TOKEN_FLAG_SENTBYACCEPTOR)))
|
||||||
|
return GSS_S_BAD_SIG;
|
||||||
|
|
||||||
|
if ((flags & KG2_TOKEN_FLAG_SEALED) == 0) {
|
||||||
|
dprintk("%s: token missing expected sealed flag\n", __func__);
|
||||||
|
return GSS_S_DEFECTIVE_TOKEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ptr[3] != 0xff)
|
||||||
|
return GSS_S_DEFECTIVE_TOKEN;
|
||||||
|
|
||||||
|
ec = be16_to_cpup((__be16 *)(ptr + 4));
|
||||||
|
rrc = be16_to_cpup((__be16 *)(ptr + 6));
|
||||||
|
|
||||||
|
seqnum = be64_to_cpup((__be64 *)(ptr + 8));
|
||||||
|
|
||||||
|
if (rrc != 0) {
|
||||||
|
err = rotate_left(kctx, offset, buf, rrc);
|
||||||
|
if (err)
|
||||||
|
return GSS_S_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = (*kctx->gk5e->decrypt_v2)(kctx, offset, buf,
|
||||||
|
&headskip, &tailskip);
|
||||||
|
if (err)
|
||||||
|
return GSS_S_FAILURE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Retrieve the decrypted gss token header and verify
|
||||||
|
* it against the original
|
||||||
|
*/
|
||||||
|
err = read_bytes_from_xdr_buf(buf,
|
||||||
|
buf->len - GSS_KRB5_TOK_HDR_LEN - tailskip,
|
||||||
|
decrypted_hdr, GSS_KRB5_TOK_HDR_LEN);
|
||||||
|
if (err) {
|
||||||
|
dprintk("%s: error %u getting decrypted_hdr\n", __func__, err);
|
||||||
|
return GSS_S_FAILURE;
|
||||||
|
}
|
||||||
|
if (memcmp(ptr, decrypted_hdr, 6)
|
||||||
|
|| memcmp(ptr + 8, decrypted_hdr + 8, 8)) {
|
||||||
|
dprintk("%s: token hdr, plaintext hdr mismatch!\n", __func__);
|
||||||
|
return GSS_S_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* do sequencing checks */
|
||||||
|
|
||||||
|
/* it got through unscathed. Make sure the context is unexpired */
|
||||||
|
now = get_seconds();
|
||||||
|
if (now > kctx->endtime)
|
||||||
|
return GSS_S_CONTEXT_EXPIRED;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Move the head data back to the right position in xdr_buf.
|
||||||
|
* We ignore any "ec" data since it might be in the head or
|
||||||
|
* the tail, and we really don't need to deal with it.
|
||||||
|
* Note that buf->head[0].iov_len may indicate the available
|
||||||
|
* head buffer space rather than that actually occupied.
|
||||||
|
*/
|
||||||
|
movelen = min_t(unsigned int, buf->head[0].iov_len, buf->len);
|
||||||
|
movelen -= offset + GSS_KRB5_TOK_HDR_LEN + headskip;
|
||||||
|
BUG_ON(offset + GSS_KRB5_TOK_HDR_LEN + headskip + movelen >
|
||||||
|
buf->head[0].iov_len);
|
||||||
|
memmove(ptr, ptr + GSS_KRB5_TOK_HDR_LEN + headskip, movelen);
|
||||||
|
buf->head[0].iov_len -= GSS_KRB5_TOK_HDR_LEN + headskip;
|
||||||
|
buf->len -= GSS_KRB5_TOK_HDR_LEN + headskip;
|
||||||
|
|
||||||
|
return GSS_S_COMPLETE;
|
||||||
|
}
|
||||||
|
|
||||||
u32
|
u32
|
||||||
gss_wrap_kerberos(struct gss_ctx *gctx, int offset,
|
gss_wrap_kerberos(struct gss_ctx *gctx, int offset,
|
||||||
struct xdr_buf *buf, struct page **pages)
|
struct xdr_buf *buf, struct page **pages)
|
||||||
|
@ -352,6 +520,9 @@ gss_wrap_kerberos(struct gss_ctx *gctx, int offset,
|
||||||
case ENCTYPE_DES_CBC_RAW:
|
case ENCTYPE_DES_CBC_RAW:
|
||||||
case ENCTYPE_DES3_CBC_RAW:
|
case ENCTYPE_DES3_CBC_RAW:
|
||||||
return gss_wrap_kerberos_v1(kctx, offset, buf, pages);
|
return gss_wrap_kerberos_v1(kctx, offset, buf, pages);
|
||||||
|
case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
|
||||||
|
case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
|
||||||
|
return gss_wrap_kerberos_v2(kctx, offset, buf, pages);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,6 +537,9 @@ gss_unwrap_kerberos(struct gss_ctx *gctx, int offset, struct xdr_buf *buf)
|
||||||
case ENCTYPE_DES_CBC_RAW:
|
case ENCTYPE_DES_CBC_RAW:
|
||||||
case ENCTYPE_DES3_CBC_RAW:
|
case ENCTYPE_DES3_CBC_RAW:
|
||||||
return gss_unwrap_kerberos_v1(kctx, offset, buf);
|
return gss_unwrap_kerberos_v1(kctx, offset, buf);
|
||||||
|
case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
|
||||||
|
case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
|
||||||
|
return gss_unwrap_kerberos_v2(kctx, offset, buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Reference in New Issue