u32 gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text, struct xdr_netobj *token) { struct krb5_ctx *ctx = gss_ctx->internal_ctx_id; char cksumdata[16]; struct xdr_netobj md5cksum = {.len = 0, .data = cksumdata}; unsigned char *ptr, *krb5_hdr, *msg_start; s32 now; u32 seq_send; dprintk("RPC: gss_krb5_seal\n"); BUG_ON(ctx == NULL); now = get_seconds(); token->len = g_token_size(&ctx->mech_used, 22); ptr = token->data; g_make_token_header(&ctx->mech_used, 22, &ptr); *ptr++ = (unsigned char) ((KG_TOK_MIC_MSG>>8)&0xff); *ptr++ = (unsigned char) (KG_TOK_MIC_MSG&0xff); /* ptr now at byte 2 of header described in rfc 1964, section 1.2.1: */ krb5_hdr = ptr - 2; msg_start = krb5_hdr + 24; *(__be16 *)(krb5_hdr + 2) = htons(SGN_ALG_DES_MAC_MD5); memset(krb5_hdr + 4, 0xff, 4); if (make_checksum("md5", krb5_hdr, 8, text, 0, &md5cksum)) return GSS_S_FAILURE; if (krb5_encrypt(ctx->seq, NULL, md5cksum.data, md5cksum.data, md5cksum.len)) return GSS_S_FAILURE; memcpy(krb5_hdr + 16, md5cksum.data + md5cksum.len - KRB5_CKSUM_LENGTH, KRB5_CKSUM_LENGTH); spin_lock(&krb5_seq_lock); seq_send = ctx->seq_send++; spin_unlock(&krb5_seq_lock); if (krb5_make_seq_num(ctx->seq, ctx->initiate ? 0 : 0xff, ctx->seq_send, krb5_hdr + 16, krb5_hdr + 8)) return GSS_S_FAILURE; return (ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE; }
static u32 gss_get_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *text, struct xdr_netobj *token) { char cksumdata[GSS_KRB5_MAX_CKSUM_LEN]; struct xdr_netobj md5cksum = {.len = sizeof(cksumdata), .data = cksumdata}; void *ptr; s32 now; u32 seq_send; u8 *cksumkey; dprintk("RPC: %s\n", __func__); BUG_ON(ctx == NULL); now = get_seconds(); ptr = setup_token(ctx, token); if (ctx->gk5e->keyed_cksum) cksumkey = ctx->cksum; else cksumkey = NULL; if (make_checksum(ctx, ptr, 8, text, 0, cksumkey, KG_USAGE_SIGN, &md5cksum)) return GSS_S_FAILURE; memcpy(ptr + GSS_KRB5_TOK_HDR_LEN, md5cksum.data, md5cksum.len); spin_lock(&krb5_seq_lock); seq_send = ctx->seq_send++; spin_unlock(&krb5_seq_lock); if (krb5_make_seq_num(ctx, ctx->seq, ctx->initiate ? 0 : 0xff, seq_send, ptr + GSS_KRB5_TOK_HDR_LEN, ptr + 8)) return GSS_S_FAILURE; return (ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE; } static 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; unsigned int cksum_usage; dprintk("RPC: %s\n", __func__); krb5_hdr = setup_token_v2(ctx, token); 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; cksum_usage = KG_USAGE_INITIATOR_SIGN; } else { cksumkey = ctx->acceptor_sign; cksum_usage = KG_USAGE_ACCEPTOR_SIGN; } if (make_checksum_v2(ctx, krb5_hdr, GSS_KRB5_TOK_HDR_LEN, text, 0, cksumkey, cksum_usage, &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 gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text, struct xdr_netobj *token) { struct krb5_ctx *ctx = gss_ctx->internal_ctx_id; switch (ctx->enctype) { default: BUG(); case ENCTYPE_DES_CBC_RAW: case ENCTYPE_DES3_CBC_RAW: case ENCTYPE_ARCFOUR_HMAC: 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); } }
u32 krb5_make_token(struct krb5_ctx *ctx, int qop_req, struct xdr_netobj * text, struct xdr_netobj * token, int toktype) { s32 checksum_type; struct xdr_netobj md5cksum = {.len = 0, .data = NULL}; int blocksize = 0, tmsglen; unsigned char *ptr, *krb5_hdr, *msg_start; s32 now; dprintk("RPC: gss_krb5_seal"); now = jiffies; if (qop_req != 0) goto out_err; switch (ctx->signalg) { case SGN_ALG_DES_MAC_MD5: checksum_type = CKSUMTYPE_RSA_MD5; break; default: dprintk("RPC: gss_krb5_seal: ctx->signalg %d not" " supported\n", ctx->signalg); goto out_err; } if (ctx->sealalg != SEAL_ALG_NONE && ctx->sealalg != SEAL_ALG_DES) { dprintk("RPC: gss_krb5_seal: ctx->sealalg %d not supported\n", ctx->sealalg); goto out_err; } if (toktype == KG_TOK_WRAP_MSG) { blocksize = crypto_tfm_alg_blocksize(ctx->enc); tmsglen = blocksize + text->len + gss_krb5_padding(blocksize, blocksize + text->len); } else { tmsglen = 0; } token->len = g_token_size(&ctx->mech_used, 22 + tmsglen); if ((token->data = kmalloc(token->len, GFP_KERNEL)) == NULL) goto out_err; ptr = token->data; g_make_token_header(&ctx->mech_used, 22 + tmsglen, &ptr, toktype); /* ptr now at byte 2 of header described in rfc 1964, section 1.2.1: */ krb5_hdr = ptr - 2; msg_start = krb5_hdr + 24; *(u16 *)(krb5_hdr + 2) = htons(ctx->signalg); memset(krb5_hdr + 4, 0xff, 4); if (toktype == KG_TOK_WRAP_MSG) *(u16 *)(krb5_hdr + 4) = htons(ctx->sealalg); if (toktype == KG_TOK_WRAP_MSG) { unsigned char pad = gss_krb5_padding(blocksize, text->len); get_random_bytes(msg_start, blocksize); /* "confounder" */ memcpy(msg_start + blocksize, text->data, text->len); memset(msg_start + blocksize + text->len, pad, pad); if (compute_checksum(checksum_type, krb5_hdr, msg_start, tmsglen, &md5cksum)) goto out_err; if (krb5_encrypt(ctx->enc, NULL, msg_start, msg_start, tmsglen)) goto out_err; } else { /* Sign only. */ if (compute_checksum(checksum_type, krb5_hdr, text->data, text->len, &md5cksum)) goto out_err; } switch (ctx->signalg) { case SGN_ALG_DES_MAC_MD5: if (krb5_encrypt(ctx->seq, NULL, md5cksum.data, md5cksum.data, md5cksum.len)) goto out_err; memcpy(krb5_hdr + 16, md5cksum.data + md5cksum.len - CKSUM_SIZE, CKSUM_SIZE); dprintk("make_seal_token: cksum data: \n"); print_hexl((u32 *) (krb5_hdr + 16), CKSUM_SIZE, 0); break; default: BUG(); } kfree(md5cksum.data); if ((krb5_make_seq_num(ctx->seq, ctx->initiate ? 0 : 0xff, ctx->seq_send, krb5_hdr + 16, krb5_hdr + 8))) goto out_err; ctx->seq_send++; return ((ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE); out_err: if (md5cksum.data) kfree(md5cksum.data); if (token->data) kfree(token->data); token->data = 0; token->len = 0; return GSS_S_FAILURE; }