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); /* */ 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 krb5_error_code make_seal_token_v1_iov(krb5_context context, krb5_gss_ctx_id_rec *ctx, int conf_req_flag, int *conf_state, gss_iov_buffer_desc *iov, int iov_count, int toktype) { krb5_error_code code = 0; gss_iov_buffer_t header; gss_iov_buffer_t padding; gss_iov_buffer_t trailer; krb5_checksum md5cksum; krb5_checksum cksum; size_t k5_headerlen = 0, k5_trailerlen = 0; size_t data_length = 0, assoc_data_length = 0; size_t tmsglen = 0, tlen; unsigned char *ptr; krb5_keyusage sign_usage = KG_USAGE_SIGN; assert(toktype == KG_TOK_WRAP_MSG); md5cksum.length = cksum.length = 0; md5cksum.contents = cksum.contents = NULL; header = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER); if (header == NULL) return EINVAL; padding = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING); if (padding == NULL && (ctx->gss_flags & GSS_C_DCE_STYLE) == 0) return EINVAL; trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER); if (trailer != NULL) trailer->buffer.length = 0; /* Determine confounder length */ if (toktype == KG_TOK_WRAP_MSG || conf_req_flag) k5_headerlen = kg_confounder_size(context, ctx->enc); /* Check padding length */ if (toktype == KG_TOK_WRAP_MSG) { size_t k5_padlen = (ctx->sealalg == SEAL_ALG_MICROSOFT_RC4) ? 1 : 8; size_t gss_padlen; size_t conf_data_length; kg_iov_msglen(iov, iov_count, &data_length, &assoc_data_length); conf_data_length = k5_headerlen + data_length - assoc_data_length; if (k5_padlen == 1) gss_padlen = 1; /* one byte to indicate one byte of padding */ else gss_padlen = k5_padlen - (conf_data_length % k5_padlen); if (ctx->gss_flags & GSS_C_DCE_STYLE) { /* DCE will pad the actual data itself; padding buffer optional and will be zeroed */ gss_padlen = 0; if (conf_data_length % k5_padlen) code = KRB5_BAD_MSIZE; } else if (padding->type & GSS_IOV_BUFFER_FLAG_ALLOCATE) { code = kg_allocate_iov(padding, gss_padlen); } else if (padding->buffer.length < gss_padlen) { code = KRB5_BAD_MSIZE; } if (code != 0) goto cleanup; /* Initialize padding buffer to pad itself */ if (padding != NULL) { padding->buffer.length = gss_padlen; memset(padding->buffer.value, (int)gss_padlen, gss_padlen); } if (ctx->gss_flags & GSS_C_DCE_STYLE) tmsglen = k5_headerlen; /* confounder length */ else tmsglen = conf_data_length + padding->buffer.length + assoc_data_length; } /* Determine token size */ tlen = g_token_size(ctx->mech_used, 14 + ctx->cksum_size + tmsglen); k5_headerlen += tlen - tmsglen; if (header->type & GSS_IOV_BUFFER_FLAG_ALLOCATE) code = kg_allocate_iov(header, k5_headerlen); else if (header->buffer.length < k5_headerlen) code = KRB5_BAD_MSIZE; if (code != 0) goto cleanup; header->buffer.length = k5_headerlen; ptr = (unsigned char *)header->buffer.value; g_make_token_header(ctx->mech_used, 14 + ctx->cksum_size + tmsglen, &ptr, toktype); /* 0..1 SIGN_ALG */ store_16_le(ctx->signalg, &ptr[0]); /* 2..3 SEAL_ALG or Filler */ if (toktype == KG_TOK_WRAP_MSG && conf_req_flag) { store_16_le(ctx->sealalg, &ptr[2]); } else { /* No seal */ ptr[2] = 0xFF; ptr[3] = 0xFF; } /* 4..5 Filler */ ptr[4] = 0xFF; ptr[5] = 0xFF; /* pad the plaintext, encrypt if needed, and stick it in the token */ /* initialize the checksum */ switch (ctx->signalg) { case SGN_ALG_DES_MAC_MD5: case SGN_ALG_MD2_5: md5cksum.checksum_type = CKSUMTYPE_RSA_MD5; break; case SGN_ALG_HMAC_SHA1_DES3_KD: md5cksum.checksum_type = CKSUMTYPE_HMAC_SHA1_DES3; break; case SGN_ALG_HMAC_MD5: md5cksum.checksum_type = CKSUMTYPE_HMAC_MD5_ARCFOUR; if (toktype != KG_TOK_WRAP_MSG) sign_usage = 15; break; default: case SGN_ALG_DES_MAC: abort (); } code = krb5_c_checksum_length(context, md5cksum.checksum_type, &k5_trailerlen); if (code != 0) goto cleanup; md5cksum.length = k5_trailerlen; if (k5_headerlen != 0) { code = kg_make_confounder(context, ctx->enc, ptr + 14 + ctx->cksum_size); if (code != 0) goto cleanup; } /* compute the checksum */ code = kg_make_checksum_iov_v1(context, md5cksum.checksum_type, ctx->cksum_size, ctx->seq, ctx->enc, sign_usage, iov, iov_count, toktype, &md5cksum); if (code != 0) goto cleanup; switch (ctx->signalg) { case SGN_ALG_DES_MAC_MD5: case SGN_ALG_3: code = kg_encrypt(context, ctx->seq, KG_USAGE_SEAL, (g_OID_equal(ctx->mech_used, gss_mech_krb5_old) ? ctx->seq->contents : NULL), md5cksum.contents, md5cksum.contents, 16); if (code != 0) goto cleanup; cksum.length = ctx->cksum_size; cksum.contents = md5cksum.contents + 16 - cksum.length; memcpy(ptr + 14, cksum.contents, cksum.length); break; case SGN_ALG_HMAC_SHA1_DES3_KD: assert(md5cksum.length == ctx->cksum_size); memcpy(ptr + 14, md5cksum.contents, md5cksum.length); break; case SGN_ALG_HMAC_MD5: memcpy(ptr + 14, md5cksum.contents, ctx->cksum_size); break; } /* create the seq_num */ code = kg_make_seq_num(context, ctx->seq, ctx->initiate ? 0 : 0xFF, (OM_uint32)ctx->seq_send, ptr + 14, ptr + 6); if (code != 0) goto cleanup; if (conf_req_flag) { if (ctx->sealalg == SEAL_ALG_MICROSOFT_RC4) { unsigned char bigend_seqnum[4]; krb5_keyblock *enc_key; size_t i; store_32_be(ctx->seq_send, bigend_seqnum); code = krb5_copy_keyblock(context, ctx->enc, &enc_key); if (code != 0) goto cleanup; assert(enc_key->length == 16); for (i = 0; i < enc_key->length; i++) ((char *)enc_key->contents)[i] ^= 0xF0; code = kg_arcfour_docrypt_iov(context, enc_key, 0, bigend_seqnum, 4, iov, iov_count); krb5_free_keyblock(context, enc_key); } else { code = kg_encrypt_iov(context, ctx->proto, ((ctx->gss_flags & GSS_C_DCE_STYLE) != 0), 0 /*EC*/, 0 /*RRC*/, ctx->enc, KG_USAGE_SEAL, NULL, iov, iov_count); } if (code != 0) goto cleanup; } ctx->seq_send++; ctx->seq_send &= 0xFFFFFFFFL; code = 0; if (conf_state != NULL) *conf_state = conf_req_flag; cleanup: if (code != 0) kg_release_iov(iov, iov_count); krb5_free_checksum_contents(context, &md5cksum); return code; }
OM_uint32 kg_seal_iov_length(OM_uint32 *minor_status, gss_ctx_id_t context_handle, int conf_req_flag, gss_qop_t qop_req, int *conf_state, gss_iov_buffer_desc *iov, int iov_count) { krb5_gss_ctx_id_rec *ctx; gss_iov_buffer_t header, trailer, padding; size_t data_length, assoc_data_length; size_t gss_headerlen, gss_padlen, gss_trailerlen; unsigned int k5_headerlen = 0, k5_trailerlen = 0, k5_padlen = 0; krb5_error_code code; krb5_context context; int dce_style; if (qop_req != GSS_C_QOP_DEFAULT) { *minor_status = (OM_uint32)G_UNKNOWN_QOP; return GSS_S_FAILURE; } if (!kg_validate_ctx_id(context_handle)) { *minor_status = (OM_uint32)G_VALIDATE_FAILED; return GSS_S_NO_CONTEXT; } ctx = (krb5_gss_ctx_id_rec *)context_handle; if (!ctx->established) { *minor_status = KG_CTX_INCOMPLETE; return GSS_S_NO_CONTEXT; } header = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER); if (header == NULL) { *minor_status = EINVAL; return GSS_S_FAILURE; } INIT_IOV_DATA(header); trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER); if (trailer != NULL) { INIT_IOV_DATA(trailer); } dce_style = ((ctx->gss_flags & GSS_C_DCE_STYLE) != 0); /* For CFX, EC is used instead of padding, and is placed in header or trailer */ padding = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING); if (padding == NULL) { if (conf_req_flag && ctx->proto == 0 && !dce_style) { *minor_status = EINVAL; return GSS_S_FAILURE; } } else { INIT_IOV_DATA(padding); } kg_iov_msglen(iov, iov_count, &data_length, &assoc_data_length); if (conf_req_flag && kg_integ_only_iov(iov, iov_count)) conf_req_flag = FALSE; context = ctx->k5_context; gss_headerlen = gss_padlen = gss_trailerlen = 0; if (ctx->proto == 1) { krb5_enctype enctype; size_t ec; if (ctx->have_acceptor_subkey) enctype = ctx->acceptor_subkey->enctype; else enctype = ctx->subkey->enctype; code = krb5_c_crypto_length(context, enctype, conf_req_flag ? KRB5_CRYPTO_TYPE_TRAILER : KRB5_CRYPTO_TYPE_CHECKSUM, &k5_trailerlen); if (code != 0) { *minor_status = code; return GSS_S_FAILURE; } if (conf_req_flag) { code = krb5_c_crypto_length(context, enctype, KRB5_CRYPTO_TYPE_HEADER, &k5_headerlen); if (code != 0) { *minor_status = code; return GSS_S_FAILURE; } } gss_headerlen = 16; /* Header */ if (conf_req_flag) { gss_headerlen += k5_headerlen; /* Kerb-Header */ gss_trailerlen = 16 /* E(Header) */ + k5_trailerlen; /* Kerb-Trailer */ code = krb5_c_padding_length(context, enctype, data_length - assoc_data_length + 16 /* E(Header) */, &k5_padlen); if (code != 0) { *minor_status = code; return GSS_S_FAILURE; } if (k5_padlen == 0 && dce_style) { /* Windows rejects AEAD tokens with non-zero EC */ code = krb5_c_block_size(context, enctype, &ec); if (code != 0) { *minor_status = code; return GSS_S_FAILURE; } } else ec = k5_padlen; gss_trailerlen += ec; } else { gss_trailerlen = k5_trailerlen; /* Kerb-Checksum */ } } else if (!dce_style) { k5_padlen = (ctx->sealalg == SEAL_ALG_MICROSOFT_RC4) ? 1 : 8; if (k5_padlen == 1) gss_padlen = 1; else gss_padlen = k5_padlen - ((data_length - assoc_data_length) % k5_padlen); } data_length += gss_padlen; if (ctx->proto == 0) { /* Header | Checksum | Confounder | Data | Pad */ size_t data_size; k5_headerlen = kg_confounder_size(context, ctx->enc); data_size = 14 /* Header */ + ctx->cksum_size + k5_headerlen; if (!dce_style) data_size += data_length; gss_headerlen = g_token_size(ctx->mech_used, data_size); /* g_token_size() will include data_size as well as the overhead, so * subtract data_length just to get the overhead (ie. token size) */ if (!dce_style) gss_headerlen -= data_length; } if (minor_status != NULL) *minor_status = 0; if (trailer == NULL) gss_headerlen += gss_trailerlen; else trailer->buffer.length = gss_trailerlen; assert(gss_padlen == 0 || padding != NULL); if (padding != NULL) padding->buffer.length = gss_padlen; header->buffer.length = gss_headerlen; if (conf_state != NULL) *conf_state = conf_req_flag; return GSS_S_COMPLETE; }
u32 spkm3_make_token(struct spkm3_ctx *ctx, struct xdr_buf * text, struct xdr_netobj * token, int toktype) { s32 checksum_type; char tokhdrbuf[25]; char cksumdata[16]; struct xdr_netobj md5cksum = {.len = 0, .data = cksumdata}; struct xdr_netobj mic_hdr = {.len = 0, .data = tokhdrbuf}; int tokenlen = 0; unsigned char *ptr; s32 now; int ctxelen = 0, ctxzbit = 0; int md5elen = 0, md5zbit = 0; now = jiffies; if (ctx->ctx_id.len != 16) { dprintk("RPC: spkm3_make_token BAD ctx_id.len %d\n", ctx->ctx_id.len); goto out_err; } if (!g_OID_equal(&ctx->intg_alg, &hmac_md5_oid)) { dprintk("RPC: gss_spkm3_seal: unsupported I-ALG " "algorithm. only support hmac-md5 I-ALG.\n"); goto out_err; } else checksum_type = CKSUMTYPE_HMAC_MD5; if (!g_OID_equal(&ctx->conf_alg, &cast5_cbc_oid)) { dprintk("RPC: gss_spkm3_seal: unsupported C-ALG " "algorithm\n"); goto out_err; } if (toktype == SPKM_MIC_TOK) { /* Calculate checksum over the mic-header */ asn1_bitstring_len(&ctx->ctx_id, &ctxelen, &ctxzbit); spkm3_mic_header(&mic_hdr.data, &mic_hdr.len, ctx->ctx_id.data, ctxelen, ctxzbit); if (make_spkm3_checksum(checksum_type, &ctx->derived_integ_key, (char *)mic_hdr.data, mic_hdr.len, text, 0, &md5cksum)) goto out_err; asn1_bitstring_len(&md5cksum, &md5elen, &md5zbit); tokenlen = 10 + ctxelen + 1 + md5elen + 1; /* Create token header using generic routines */ token->len = g_token_size(&ctx->mech_used, tokenlen); ptr = token->data; g_make_token_header(&ctx->mech_used, tokenlen, &ptr); spkm3_make_mic_token(&ptr, tokenlen, &mic_hdr, &md5cksum, md5elen, md5zbit); } else if (toktype == SPKM_WRAP_TOK) { /* Not Supported */ dprintk("RPC: gss_spkm3_seal: SPKM_WRAP_TOK " "not supported\n"); goto out_err; } /* XXX need to implement sequence numbers, and ctx->expired */ return GSS_S_COMPLETE; out_err: token->data = NULL; token->len = 0; return GSS_S_FAILURE; } static int spkm3_checksummer(struct scatterlist *sg, void *data) { struct hash_desc *desc = data; return crypto_hash_update(desc, sg, sg->length); } /* checksum the plaintext data and hdrlen bytes of the token header */ s32 make_spkm3_checksum(s32 cksumtype, struct xdr_netobj *key, char *header, unsigned int hdrlen, struct xdr_buf *body, unsigned int body_offset, struct xdr_netobj *cksum) { char *cksumname; struct hash_desc desc; /* XXX add to ctx? */ struct scatterlist sg[1]; int err; switch (cksumtype) { case CKSUMTYPE_HMAC_MD5: cksumname = "hmac(md5)"; break; default: dprintk("RPC: spkm3_make_checksum:" " unsupported checksum %d", cksumtype); return GSS_S_FAILURE; } if (key->data == NULL || key->len <= 0) return GSS_S_FAILURE; desc.tfm = crypto_alloc_hash(cksumname, 0, CRYPTO_ALG_ASYNC); if (IS_ERR(desc.tfm)) return GSS_S_FAILURE; cksum->len = crypto_hash_digestsize(desc.tfm); desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; err = crypto_hash_setkey(desc.tfm, key->data, key->len); if (err) goto out; err = crypto_hash_init(&desc); if (err) goto out; sg_set_buf(sg, header, hdrlen); crypto_hash_update(&desc, sg, sg->length); xdr_process_buf(body, body_offset, body->len - body_offset, spkm3_checksummer, &desc); crypto_hash_final(&desc, cksum->data); out: crypto_free_hash(desc.tfm); return err ? GSS_S_FAILURE : 0; }
/* * Create a token from IAKERB-HEADER and KRB-KDC-REQ/REP */ static krb5_error_code iakerb_make_token(iakerb_ctx_id_t ctx, krb5_data *realm, krb5_data *cookie, krb5_data *request, int initialContextToken, gss_buffer_t token) { krb5_error_code code; krb5_iakerb_header iah; krb5_data *data = NULL; char *p; unsigned int tokenSize; unsigned char *q; token->value = NULL; token->length = 0; /* * Assemble the IAKERB-HEADER from the realm and cookie */ memset(&iah, 0, sizeof(iah)); iah.target_realm = *realm; iah.cookie = cookie; code = encode_krb5_iakerb_header(&iah, &data); if (code != 0) goto cleanup; /* * Concatenate Kerberos request. */ p = realloc(data->data, data->length + request->length); if (p == NULL) { code = ENOMEM; goto cleanup; } data->data = p; if (request->length > 0) memcpy(data->data + data->length, request->data, request->length); data->length += request->length; if (initialContextToken) tokenSize = g_token_size(gss_mech_iakerb, data->length); else tokenSize = 2 + data->length; token->value = q = gssalloc_malloc(tokenSize); if (q == NULL) { code = ENOMEM; goto cleanup; } token->length = tokenSize; if (initialContextToken) { g_make_token_header(gss_mech_iakerb, data->length, &q, IAKERB_TOK_PROXY); } else { store_16_be(IAKERB_TOK_PROXY, q); q += 2; } memcpy(q, data->data, data->length); q += data->length; assert(q == (unsigned char *)token->value + token->length); cleanup: krb5_free_data(ctx->k5c, data); return code; }
static krb5_error_code make_seal_token_v1 (krb5_context context, krb5_keyblock *enc, krb5_keyblock *seq, gssint_uint64 *seqnum, int direction, gss_buffer_t text, gss_buffer_t token, int signalg, size_t cksum_size, int sealalg, int do_encrypt, int toktype, int bigend, gss_OID oid) { krb5_error_code code; size_t sumlen; char *data_ptr; krb5_data plaind; krb5_checksum md5cksum; krb5_checksum cksum; /* msglen contains the message length * we are signing/encrypting. tmsglen * contains the length of the message * we plan to write out to the token. * tlen is the length of the token * including header. */ unsigned int conflen=0, tmsglen, tlen, msglen; unsigned char *t, *ptr; unsigned char *plain; unsigned char pad; krb5_keyusage sign_usage = KG_USAGE_SIGN; assert((!do_encrypt) || (toktype == KG_TOK_SEAL_MSG)); /* create the token buffer */ /* Do we need confounder? */ if (do_encrypt || (!bigend && (toktype == KG_TOK_SEAL_MSG))) conflen = kg_confounder_size(context, enc); else conflen = 0; if (toktype == KG_TOK_SEAL_MSG) { switch (sealalg) { case SEAL_ALG_MICROSOFT_RC4: msglen = conflen + text->length+1; pad = 1; break; default: /* XXX knows that des block size is 8 */ msglen = (conflen+text->length+8)&(~7); pad = 8-(text->length%8); } tmsglen = msglen; } else { tmsglen = 0; msglen = text->length; pad = 0; } tlen = g_token_size((gss_OID) oid, 14+cksum_size+tmsglen); if ((t = (unsigned char *) xmalloc(tlen)) == NULL) return(ENOMEM); /*** fill in the token */ ptr = t; g_make_token_header(oid, 14+cksum_size+tmsglen, &ptr, toktype); /* 0..1 SIGN_ALG */ store_16_le(signalg, &ptr[0]); /* 2..3 SEAL_ALG or Filler */ if ((toktype == KG_TOK_SEAL_MSG) && do_encrypt) { store_16_le(sealalg, &ptr[2]); } else { /* No seal */ ptr[2] = 0xff; ptr[3] = 0xff; } /* 4..5 Filler */ ptr[4] = 0xff; ptr[5] = 0xff; /* pad the plaintext, encrypt if needed, and stick it in the token */ /* initialize the the cksum */ switch (signalg) { case SGN_ALG_DES_MAC_MD5: case SGN_ALG_MD2_5: md5cksum.checksum_type = CKSUMTYPE_RSA_MD5; break; case SGN_ALG_HMAC_SHA1_DES3_KD: md5cksum.checksum_type = CKSUMTYPE_HMAC_SHA1_DES3; break; case SGN_ALG_HMAC_MD5: md5cksum.checksum_type = CKSUMTYPE_HMAC_MD5_ARCFOUR; if (toktype != KG_TOK_SEAL_MSG) sign_usage = 15; break; default: case SGN_ALG_DES_MAC: abort (); } code = krb5_c_checksum_length(context, md5cksum.checksum_type, &sumlen); if (code) { xfree(t); return(code); } md5cksum.length = sumlen; if ((plain = (unsigned char *) xmalloc(msglen ? msglen : 1)) == NULL) { xfree(t); return(ENOMEM); } if (conflen) { if ((code = kg_make_confounder(context, enc, plain))) { xfree(plain); xfree(t); return(code); } } memcpy(plain+conflen, text->value, text->length); if (pad) memset(plain+conflen+text->length, pad, pad); /* compute the checksum */ /* 8 = head of token body as specified by mech spec */ if (! (data_ptr = (char *) xmalloc(8 + (bigend ? text->length : msglen)))) { xfree(plain); xfree(t); return(ENOMEM); } (void) memcpy(data_ptr, ptr-2, 8); if (bigend) (void) memcpy(data_ptr+8, text->value, text->length); else (void) memcpy(data_ptr+8, plain, msglen); plaind.length = 8 + (bigend ? text->length : msglen); plaind.data = data_ptr; code = krb5_c_make_checksum(context, md5cksum.checksum_type, seq, sign_usage, &plaind, &md5cksum); xfree(data_ptr); if (code) { xfree(plain); xfree(t); return(code); } switch(signalg) { case SGN_ALG_DES_MAC_MD5: case 3: if ((code = kg_encrypt(context, seq, KG_USAGE_SEAL, (g_OID_equal(oid, gss_mech_krb5_old) ? seq->contents : NULL), md5cksum.contents, md5cksum.contents, 16))) { krb5_free_checksum_contents(context, &md5cksum); xfree (plain); xfree(t); return code; } cksum.length = cksum_size; cksum.contents = md5cksum.contents + 16 - cksum.length; memcpy(ptr+14, cksum.contents, cksum.length); break; case SGN_ALG_HMAC_SHA1_DES3_KD: /* * Using key derivation, the call to krb5_c_make_checksum * already dealt with encrypting. */ if (md5cksum.length != cksum_size) abort (); memcpy (ptr+14, md5cksum.contents, md5cksum.length); break; case SGN_ALG_HMAC_MD5: memcpy (ptr+14, md5cksum.contents, cksum_size); break; } krb5_free_checksum_contents(context, &md5cksum); /* create the seq_num */ if ((code = kg_make_seq_num(context, seq, direction?0:0xff, (krb5_ui_4)*seqnum, ptr+14, ptr+6))) { xfree (plain); xfree(t); return(code); } if (do_encrypt) { switch(sealalg) { case SEAL_ALG_MICROSOFT_RC4: { unsigned char bigend_seqnum[4]; krb5_keyblock *enc_key; int i; store_32_be(*seqnum, bigend_seqnum); code = krb5_copy_keyblock (context, enc, &enc_key); if (code) { xfree(plain); xfree(t); return(code); } assert (enc_key->length == 16); for (i = 0; i <= 15; i++) ((char *) enc_key->contents)[i] ^=0xf0; code = kg_arcfour_docrypt (enc_key, 0, bigend_seqnum, 4, plain, tmsglen, ptr+14+cksum_size); krb5_free_keyblock (context, enc_key); if (code) { xfree(plain); xfree(t); return(code); } } break; default: if ((code = kg_encrypt(context, enc, KG_USAGE_SEAL, NULL, (krb5_pointer) plain, (krb5_pointer) (ptr+cksum_size+14), tmsglen))) { xfree(plain); xfree(t); return(code); } } }else { if (tmsglen) memcpy(ptr+14+cksum_size, plain, tmsglen); } xfree(plain); /* that's it. return the token */ (*seqnum)++; *seqnum &= 0xffffffffL; token->length = tlen; token->value = (void *) t; return(0); }
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; }