From: Trond Myklebust RPCSEC_GSS: Miscellaneous cleanups of the krb5 code required for the integrity checksumming. --- include/linux/sunrpc/gss_krb5.h | 20 +---- net/sunrpc/auth_gss/gss_krb5_crypto.c | 44 +++++------ net/sunrpc/auth_gss/gss_krb5_mech.c | 28 +++---- net/sunrpc/auth_gss/gss_krb5_seal.c | 43 ++-------- net/sunrpc/auth_gss/gss_krb5_unseal.c | 134 ++++++++-------------------------- 5 files changed, 84 insertions(+), 185 deletions(-) diff -puN include/linux/sunrpc/gss_krb5.h~nfs-11-krb5_cleanup include/linux/sunrpc/gss_krb5.h --- 25/include/linux/sunrpc/gss_krb5.h~nfs-11-krb5_cleanup 2004-01-09 22:16:14.000000000 -0800 +++ 25-akpm/include/linux/sunrpc/gss_krb5.h 2004-01-09 22:16:14.000000000 -0800 @@ -50,7 +50,6 @@ struct krb5_ctx { struct crypto_tfm *seq; s32 endtime; u32 seq_send; - u32 seq_recv; struct xdr_netobj mech_used; }; @@ -73,7 +72,7 @@ enum seal_alg { SEAL_ALG_DES3KD = 0x0002 }; -#define RSA_MD5_CKSUM_LENGTH 16 +#define KRB5_CKSUM_LENGTH 8 #define CKSUMTYPE_CRC32 0x0001 #define CKSUMTYPE_RSA_MD4 0x0002 @@ -100,16 +99,6 @@ enum seal_alg { #define KG_EMPTY_CCACHE (39756044L) #define KG_NO_CTYPES (39756045L) -#define KV5M_PRINCIPAL (-1760647423L) -#define KV5M_KEYBLOCK (-1760647421L) -#define KV5M_CHECKSUM (-1760647420L) -#define KV5M_ADDRESS (-1760647390L) -#define KV5M_AUTHENTICATOR (-1760647410L) -#define KV5M_AUTH_CONTEXT (-1760647383L) -#define KV5M_AUTHDATA (-1760647414L) -#define KV5M_GSS_OID (-1760647372L) -#define KV5M_GSS_QUEUE (-1760647371L) - /* per Kerberos v5 protocol spec crypto types from the wire. * these get mapped to linux kernel crypto routines. */ @@ -126,14 +115,13 @@ enum seal_alg { #define ENCTYPE_UNKNOWN 0x01ff s32 -krb5_make_checksum(s32 cksumtype, - struct xdr_netobj *input, +krb5_make_checksum(s32 cksumtype, char *header, char *body, int body_len, struct xdr_netobj *cksum); u32 krb5_make_token(struct krb5_ctx *context_handle, int qop_req, - struct xdr_netobj * input_message_buffer, - struct xdr_netobj * output_message_buffer, int toktype); + struct xdr_netobj *input_message_buffer, + struct xdr_netobj *output_message_buffer, int toktype); u32 krb5_read_token(struct krb5_ctx *context_handle, diff -puN net/sunrpc/auth_gss/gss_krb5_crypto.c~nfs-11-krb5_cleanup net/sunrpc/auth_gss/gss_krb5_crypto.c --- 25/net/sunrpc/auth_gss/gss_krb5_crypto.c~nfs-11-krb5_cleanup 2004-01-09 22:16:14.000000000 -0800 +++ 25-akpm/net/sunrpc/auth_gss/gss_krb5_crypto.c 2004-01-09 22:16:14.000000000 -0800 @@ -122,14 +122,23 @@ out: return(ret); } +void +buf_to_sg(struct scatterlist *sg, char *ptr, int len) { + sg->page = virt_to_page(ptr); + sg->offset = offset_in_page(ptr); + sg->length = len; +} + +/* checksum the plaintext data and the first 8 bytes of the krb5 token header, + * as specified by the rfc: */ s32 -krb5_make_checksum(s32 cksumtype, struct xdr_netobj *input, +krb5_make_checksum(s32 cksumtype, char *header, char *body, int body_len, struct xdr_netobj *cksum) { - s32 ret = -EINVAL; - struct scatterlist sg[1]; - char *cksumname; - struct crypto_tfm *tfm; + char *cksumname; + struct crypto_tfm *tfm = NULL; /* XXX add to ctx? */ + struct scatterlist sg[2]; + u32 code = GSS_S_FAILURE; switch (cksumtype) { case CKSUMTYPE_RSA_MD5: @@ -143,24 +152,17 @@ krb5_make_checksum(s32 cksumtype, struct if (!(tfm = crypto_alloc_tfm(cksumname, 0))) goto out; cksum->len = crypto_tfm_alg_digestsize(tfm); + if ((cksum->data = kmalloc(cksum->len, GFP_KERNEL)) == NULL) + goto out; - if ((cksum->data = kmalloc(cksum->len, GFP_KERNEL)) == NULL) { - ret = -ENOMEM; - goto out_free_tfm; - } - sg[0].page = virt_to_page(input->data); - sg[0].offset = offset_in_page(input->data); - sg[0].length = input->len; - + buf_to_sg(&sg[0], header, 8); + buf_to_sg(&sg[1], body, body_len); crypto_digest_init(tfm); - crypto_digest_update(tfm, sg, 1); + crypto_digest_update(tfm, sg, 2); crypto_digest_final(tfm, cksum->data); - - ret = 0; - -out_free_tfm: - crypto_free_tfm(tfm); + code = 0; out: - dprintk("RPC: gss_k5cksum: returning %d\n", ret); - return (ret); + if (tfm) + crypto_free_tfm(tfm); + return code; } diff -puN net/sunrpc/auth_gss/gss_krb5_mech.c~nfs-11-krb5_cleanup net/sunrpc/auth_gss/gss_krb5_mech.c --- 25/net/sunrpc/auth_gss/gss_krb5_mech.c~nfs-11-krb5_cleanup 2004-01-09 22:16:14.000000000 -0800 +++ 25-akpm/net/sunrpc/auth_gss/gss_krb5_mech.c 2004-01-09 22:16:14.000000000 -0800 @@ -98,7 +98,7 @@ get_key(char **p, char *end, struct cryp alg_mode = CRYPTO_TFM_MODE_CBC; break; default: - dprintk("RPC: get_key: unsupported algorithm %d", alg); + dprintk("RPC: get_key: unsupported algorithm %d\n", alg); goto out_err_free_key; } if (!(*res = crypto_alloc_tfm(alg_name, alg_mode))) @@ -168,7 +168,7 @@ out_err: return GSS_S_FAILURE; } -void +static void gss_delete_sec_context_kerberos(void *internal_ctx) { struct krb5_ctx *kctx = internal_ctx; @@ -181,16 +181,16 @@ gss_delete_sec_context_kerberos(void *in kfree(kctx); } -u32 +static u32 gss_verify_mic_kerberos(struct gss_ctx *ctx, - struct xdr_netobj *signbuf, - struct xdr_netobj *checksum, - u32 *qstate) { + struct xdr_netobj *message, + struct xdr_netobj *mic_token, + u32 *qstate) { u32 maj_stat = 0; int qop_state; struct krb5_ctx *kctx = ctx->internal_ctx_id; - maj_stat = krb5_read_token(kctx, checksum, signbuf, &qop_state, + maj_stat = krb5_read_token(kctx, mic_token, message, &qop_state, KG_TOK_MIC_MSG); if (!maj_stat && qop_state) *qstate = qop_state; @@ -199,21 +199,17 @@ gss_verify_mic_kerberos(struct gss_ctx return maj_stat; } -u32 +static u32 gss_get_mic_kerberos(struct gss_ctx *ctx, u32 qop, - struct xdr_netobj *message_buffer, - struct xdr_netobj *message_token) { + struct xdr_netobj *message, + struct xdr_netobj *mic_token) { u32 err = 0; struct krb5_ctx *kctx = ctx->internal_ctx_id; - if (!message_buffer->data) return GSS_S_FAILURE; - - dprintk("RPC: gss_get_mic_kerberos:" - " message_buffer->len %d\n",message_buffer->len); + if (!message->data) return GSS_S_FAILURE; - err = krb5_make_token(kctx, qop, message_buffer, - message_token, KG_TOK_MIC_MSG); + err = krb5_make_token(kctx, qop, message, mic_token, KG_TOK_MIC_MSG); dprintk("RPC: gss_get_mic_kerberos returning %d\n",err); diff -puN net/sunrpc/auth_gss/gss_krb5_seal.c~nfs-11-krb5_cleanup net/sunrpc/auth_gss/gss_krb5_seal.c --- 25/net/sunrpc/auth_gss/gss_krb5_seal.c~nfs-11-krb5_cleanup 2004-01-09 22:16:14.000000000 -0800 +++ 25-akpm/net/sunrpc/auth_gss/gss_krb5_seal.c 2004-01-09 22:16:14.000000000 -0800 @@ -63,14 +63,13 @@ #include #include #include +#include #include #ifdef RPC_DEBUG # define RPCDBG_FACILITY RPCDBG_AUTH #endif -#define CKSUM_SIZE 8 - static inline int gss_krb5_padding(int blocksize, int length) { /* Most of the code is block-size independent but in practice we @@ -79,29 +78,6 @@ gss_krb5_padding(int blocksize, int leng return 8 - (length & 7); } -/* checksum the plaintext data and the first 8 bytes of the krb5 token header, - * as specified by the rfc: */ -static u32 -compute_checksum(s32 checksum_type, char *header, char *body, int body_len, - struct xdr_netobj *md5cksum) { - char *data_ptr; - struct xdr_netobj plaind; - u32 code = GSS_S_FAILURE; - - if (!(data_ptr = kmalloc(8 + body_len, GFP_KERNEL))) - goto out; - memcpy(data_ptr, header, 8); - memcpy(data_ptr + 8, body, body_len); - plaind.len = 8 + body_len; - plaind.data = data_ptr; - code = krb5_make_checksum(checksum_type, &plaind, md5cksum); - kfree(data_ptr); - code = 0; - -out: - return code; -} - u32 krb5_make_token(struct krb5_ctx *ctx, int qop_req, struct xdr_netobj * text, struct xdr_netobj * token, @@ -113,10 +89,12 @@ krb5_make_token(struct krb5_ctx *ctx, in unsigned char *ptr, *krb5_hdr, *msg_start; s32 now; - dprintk("RPC: gss_krb5_seal"); + dprintk("RPC: gss_krb5_seal\n"); now = jiffies; + token->data = NULL; + if (qop_req != 0) goto out_err; @@ -167,8 +145,8 @@ krb5_make_token(struct krb5_ctx *ctx, in memset(msg_start + blocksize + text->len, pad, pad); - if (compute_checksum(checksum_type, krb5_hdr, msg_start, - tmsglen, &md5cksum)) + if (krb5_make_checksum(checksum_type, krb5_hdr, msg_start, + tmsglen, &md5cksum)) goto out_err; if (krb5_encrypt(ctx->enc, NULL, msg_start, msg_start, @@ -176,8 +154,8 @@ krb5_make_token(struct krb5_ctx *ctx, in goto out_err; } else { /* Sign only. */ - if (compute_checksum(checksum_type, krb5_hdr, text->data, - text->len, &md5cksum)) + if (krb5_make_checksum(checksum_type, krb5_hdr, text->data, + text->len, &md5cksum)) goto out_err; } @@ -187,10 +165,11 @@ krb5_make_token(struct krb5_ctx *ctx, in md5cksum.data, md5cksum.len)) goto out_err; memcpy(krb5_hdr + 16, - md5cksum.data + md5cksum.len - CKSUM_SIZE, CKSUM_SIZE); + md5cksum.data + md5cksum.len - KRB5_CKSUM_LENGTH, + KRB5_CKSUM_LENGTH); dprintk("make_seal_token: cksum data: \n"); - print_hexl((u32 *) (krb5_hdr + 16), CKSUM_SIZE, 0); + print_hexl((u32 *) (krb5_hdr + 16), KRB5_CKSUM_LENGTH, 0); break; default: BUG(); diff -puN net/sunrpc/auth_gss/gss_krb5_unseal.c~nfs-11-krb5_cleanup net/sunrpc/auth_gss/gss_krb5_unseal.c --- 25/net/sunrpc/auth_gss/gss_krb5_unseal.c~nfs-11-krb5_cleanup 2004-01-09 22:16:14.000000000 -0800 +++ 25-akpm/net/sunrpc/auth_gss/gss_krb5_unseal.c 2004-01-09 22:16:14.000000000 -0800 @@ -68,7 +68,12 @@ #endif -/* message_buffer is an input if MIC and an output if WRAP. */ +/* message_buffer is an input if toktype is MIC and an output if it is WRAP: + * If toktype is MIC: read_token is a mic token, and message_buffer is the + * data that the mic was supposedly taken over. + * If toktype is WRAP: read_token is a wrap token, and message_buffer is used + * to return the decrypted data. + */ u32 krb5_read_token(struct krb5_ctx *ctx, @@ -76,20 +81,13 @@ krb5_read_token(struct krb5_ctx *ctx, struct xdr_netobj *message_buffer, int *qop_state, int toktype) { - s32 code; - int tmsglen = 0; - int conflen = 0; int signalg; int sealalg; struct xdr_netobj token = {.len = 0, .data = NULL}; s32 checksum_type; - struct xdr_netobj cksum; struct xdr_netobj md5cksum = {.len = 0, .data = NULL}; - struct xdr_netobj plaind; - char *data_ptr; s32 now; unsigned char *plain = NULL; - int cksum_len = 0; int plainlen = 0; int direction; s32 seqnum; @@ -97,10 +95,9 @@ krb5_read_token(struct krb5_ctx *ctx, int bodysize; u32 ret = GSS_S_DEFECTIVE_TOKEN; - dprintk("RPC: krb5_read_token\n"); + dprintk("RPC: krb5_read_token\n"); - if (g_verify_token_header((struct xdr_netobj *) &ctx->mech_used, - &bodysize, &ptr, toktype, + if (g_verify_token_header(&ctx->mech_used, &bodysize, &ptr, toktype, read_token->len)) goto out; @@ -138,40 +135,22 @@ krb5_read_token(struct krb5_ctx *ctx, signalg != SGN_ALG_HMAC_SHA1_DES3_KD)) goto out; - /* starting with a single alg */ - switch (signalg) { - case SGN_ALG_DES_MAC_MD5: - cksum_len = 8; - break; - default: - goto out; - } - - if (toktype == KG_TOK_WRAP_MSG) - tmsglen = bodysize - (14 + cksum_len); - - /* get the token parameters */ - - /* decode the message, if WRAP */ - if (toktype == KG_TOK_WRAP_MSG) { - dprintk("RPC: krb5_read_token KG_TOK_WRAP_MSG\n"); + int conflen = crypto_tfm_alg_blocksize(ctx->enc); + int padlen; - plain = kmalloc(tmsglen, GFP_KERNEL); - ret = GSS_S_FAILURE; - if (plain == NULL) - goto out; + plainlen = bodysize - (14 + KRB5_CKSUM_LENGTH); + plain = ptr + 14 + KRB5_CKSUM_LENGTH; - code = krb5_decrypt(ctx->enc, NULL, - ptr + 14 + cksum_len, plain, - tmsglen); - if (code) + ret = krb5_decrypt(ctx->enc, NULL, plain, plain, plainlen); + if (ret) goto out; - plainlen = tmsglen; - - conflen = crypto_tfm_alg_blocksize(ctx->enc); - token.len = tmsglen - conflen - plain[tmsglen - 1]; + ret = GSS_S_FAILURE; + padlen = plain[plainlen -1]; + if ((padlen < 1) || (padlen > 8)) + goto out; + token.len = plainlen - conflen - padlen; if (token.len) { token.data = kmalloc(token.len, GFP_KERNEL); @@ -181,15 +160,13 @@ krb5_read_token(struct krb5_ctx *ctx, } } else if (toktype == KG_TOK_MIC_MSG) { - dprintk("RPC: krb5_read_token KG_TOK_MIC_MSG\n"); token = *message_buffer; plain = token.data; plainlen = token.len; } else { - token.len = 0; - token.data = NULL; - plain = token.data; - plainlen = token.len; + printk("RPC: bad toktype in krb5_read_token"); + ret = GSS_S_FAILURE; + goto out; } dprintk("RPC krb5_read_token: token.len %d plainlen %d\n", token.len, @@ -209,67 +186,26 @@ krb5_read_token(struct krb5_ctx *ctx, switch (signalg) { case SGN_ALG_DES_MAC_MD5: - dprintk("RPC krb5_read_token SGN_ALG_DES_MAC_MD5\n"); - /* compute the checksum of the message. - * 8 = bytes of token body to be checksummed according to spec - */ - - data_ptr = kmalloc(8 + plainlen, GFP_KERNEL); - ret = GSS_S_FAILURE; - if (!data_ptr) + ret = krb5_make_checksum(checksum_type, ptr - 2, plain, + plainlen, &md5cksum); + if (ret) goto out; - memcpy(data_ptr, ptr - 2, 8); - memcpy(data_ptr + 8, plain, plainlen); - - plaind.len = 8 + plainlen; - plaind.data = data_ptr; - - code = krb5_make_checksum(checksum_type, - &plaind, &md5cksum); - - kfree(data_ptr); - - if (code) + ret = krb5_encrypt(ctx->seq, NULL, md5cksum.data, + md5cksum.data, 16); + if (ret) goto out; - code = krb5_encrypt(ctx->seq, NULL, md5cksum.data, - md5cksum.data, 16); - if (code) + if (memcmp(md5cksum.data + 8, ptr + 14, 8)) { + ret = GSS_S_BAD_SIG; goto out; - - if (signalg == 0) - cksum.len = 8; - else - cksum.len = 16; - cksum.data = md5cksum.data + 16 - cksum.len; - - dprintk - ("RPC: krb5_read_token: memcmp digest cksum.len %d:\n", - cksum.len); - dprintk(" md5cksum.data\n"); - print_hexl((u32 *) md5cksum.data, 16, 0); - dprintk(" cksum.data:\n"); - print_hexl((u32 *) cksum.data, cksum.len, 0); - { - u32 *p; - - (u8 *) p = ptr + 14; - dprintk(" ptr+14:\n"); - print_hexl(p, cksum.len, 0); } - - code = memcmp(cksum.data, ptr + 14, cksum.len); break; default: ret = GSS_S_DEFECTIVE_TOKEN; goto out; } - ret = GSS_S_BAD_SIG; - if (code) - goto out; - /* it got through unscathed. Make sure the context is unexpired */ if (toktype == KG_TOK_WRAP_MSG) @@ -287,8 +223,8 @@ krb5_read_token(struct krb5_ctx *ctx, /* do sequencing checks */ ret = GSS_S_BAD_SIG; - if ((code = krb5_get_seq_num(ctx->seq, ptr + 14, ptr + 6, &direction, - &seqnum))) + if ((ret = krb5_get_seq_num(ctx->seq, ptr + 14, ptr + 6, &direction, + &seqnum))) goto out; if ((ctx->initiate && direction != 0xff) || @@ -298,9 +234,7 @@ krb5_read_token(struct krb5_ctx *ctx, ret = GSS_S_COMPLETE; out: if (md5cksum.data) kfree(md5cksum.data); - if (toktype == KG_TOK_WRAP_MSG) { - if (plain) kfree(plain); - if (ret && token.data) kfree(token.data); - } + if ((toktype == KG_TOK_WRAP_MSG) && ret && token.data) + kfree(token.data); return ret; } _