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; }
/* * spkm3_read_token() * * only SPKM_MIC_TOK with md5 intg-alg is supported */ u32 spkm3_read_token(struct spkm3_ctx *ctx, struct xdr_netobj *read_token, /* checksum */ struct xdr_buf *message_buffer, /* signbuf */ int toktype) { s32 code; struct xdr_netobj wire_cksum = {.len =0, .data = NULL}; struct xdr_netobj md5cksum = {.len = 0, .data = NULL}; unsigned char *ptr = (unsigned char *)read_token->data; unsigned char *cksum; int bodysize, md5elen; int mic_hdrlen; u32 ret = GSS_S_DEFECTIVE_TOKEN; dprintk("RPC: spkm3_read_token read_token->len %d\n", read_token->len); if (g_verify_token_header((struct xdr_netobj *) &ctx->mech_used, &bodysize, &ptr, read_token->len)) goto out; /* decode the token */ if (toktype == SPKM_MIC_TOK) { if ((ret = spkm3_verify_mic_token(&ptr, &mic_hdrlen, &cksum))) goto out; if (*cksum++ != 0x03) { dprintk("RPC: spkm3_read_token BAD checksum type\n"); goto out; } md5elen = *cksum++; cksum++; /* move past the zbit */ if(!decode_asn1_bitstring(&wire_cksum, cksum, md5elen - 1, 16)) goto out; /* HARD CODED FOR MD5 */ /* compute the checksum of the message. * ptr + 2 = start of header piece of checksum * mic_hdrlen + 2 = length of header piece of checksum */ ret = GSS_S_DEFECTIVE_TOKEN; code = make_checksum(CKSUMTYPE_RSA_MD5, ptr + 2, mic_hdrlen + 2, message_buffer, 0, &md5cksum); if (code) goto out; dprintk("RPC: spkm3_read_token: digest wire_cksum.len %d:\n", wire_cksum.len); dprintk(" md5cksum.data\n"); print_hexl((u32 *) md5cksum.data, 16, 0); dprintk(" cksum.data:\n"); print_hexl((u32 *) wire_cksum.data, wire_cksum.len, 0); ret = GSS_S_BAD_SIG; code = memcmp(md5cksum.data, wire_cksum.data, wire_cksum.len); if (code) goto out; } else { dprintk("RPC: BAD or UNSUPPORTED SPKM3 token type: %d\n",toktype); goto out; } /* XXX: need to add expiration and sequencing */ ret = GSS_S_COMPLETE; out: kfree(md5cksum.data); kfree(wire_cksum.data); return ret; }
u32 krb5_read_token(struct krb5_ctx *ctx, struct xdr_netobj *read_token, 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; unsigned char *ptr = (unsigned char *)read_token->data; int bodysize; u32 ret = GSS_S_DEFECTIVE_TOKEN; dprintk("RPC: krb5_read_token\n"); if (g_verify_token_header((struct xdr_netobj *) &ctx->mech_used, &bodysize, &ptr, toktype, read_token->len)) goto out; if (toktype == KG_TOK_WRAP_MSG) { message_buffer->len = 0; message_buffer->data = NULL; } /* get the sign and seal algorithms */ signalg = ptr[0] + (ptr[1] << 8); sealalg = ptr[2] + (ptr[3] << 8); /* Sanity checks */ if ((ptr[4] != 0xff) || (ptr[5] != 0xff)) goto out; if (((toktype != KG_TOK_WRAP_MSG) && (sealalg != 0xffff)) || ((toktype == KG_TOK_WRAP_MSG) && (sealalg == 0xffff))) goto out; /* in the current spec, there is only one valid seal algorithm per key type, so a simple comparison is ok */ if ((toktype == KG_TOK_WRAP_MSG) && !(sealalg == ctx->sealalg)) goto out; /* there are several mappings of seal algorithms to sign algorithms, but few enough that we can try them all. */ if ((ctx->sealalg == SEAL_ALG_NONE && signalg > 1) || (ctx->sealalg == SEAL_ALG_1 && signalg != SGN_ALG_3) || (ctx->sealalg == SEAL_ALG_DES3KD && 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"); plain = kmalloc(tmsglen, GFP_KERNEL); ret = GSS_S_FAILURE; if (plain == NULL) goto out; code = krb5_decrypt(ctx->enc, NULL, ptr + 14 + cksum_len, plain, tmsglen); if (code) goto out; plainlen = tmsglen; conflen = crypto_tfm_alg_blocksize(ctx->enc); token.len = tmsglen - conflen - plain[tmsglen - 1]; if (token.len) { token.data = kmalloc(token.len, GFP_KERNEL); if (token.data == NULL) goto out; memcpy(token.data, plain + conflen, token.len); } } 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; } dprintk("RPC krb5_read_token: token.len %d plainlen %d\n", token.len, plainlen); /* compute the checksum of the message */ /* initialize the the cksum */ switch (signalg) { case SGN_ALG_DES_MAC_MD5: checksum_type = CKSUMTYPE_RSA_MD5; break; default: ret = GSS_S_DEFECTIVE_TOKEN; goto out; } 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) 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) goto out; code = krb5_encrypt(ctx->seq, NULL, md5cksum.data, md5cksum.data, 16); if (code) 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) *message_buffer = token; if (qop_state) *qop_state = GSS_C_QOP_DEFAULT; now = jiffies; ret = GSS_S_CONTEXT_EXPIRED; if (now > ctx->endtime) goto out; /* do sequencing checks */ ret = GSS_S_BAD_SIG; if ((code = krb5_get_seq_num(ctx->seq, ptr + 14, ptr + 6, &direction, &seqnum))) goto out; if ((ctx->initiate && direction != 0xff) || (!ctx->initiate && direction != 0)) goto out; 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); } return ret; }