krb5_error_code krb5_encrypt_tkt_part(krb5_context context, const krb5_keyblock *key, krb5_ticket *ticket) { krb5_data *data = 0; int code; size_t enclen; if ((code = encode_krb5_enc_tkt_part(ticket->enc_part2, &data))) goto Done; if ((code = krb5_c_encrypt_length(context, key->enctype, data->length, &enclen))) goto Done; ticket->enc_part.ciphertext.length = enclen; if (!(ticket->enc_part.ciphertext.data = malloc(enclen))) { code = ENOMEM; goto Done; } if ((code = krb5_c_encrypt(context, key, KRB5_KEYUSAGE_KDC_REP_TICKET, 0, data, &ticket->enc_part))) { free(ticket->enc_part.ciphertext.data); ticket->enc_part.ciphertext.data = 0; } Done: if (data) { if (data->data) free(data->data); free(data); } return code; }
krb5_error_code KRB5_CALLCONV krb5_encrypt(krb5_context context, krb5_const_pointer inptr, krb5_pointer outptr, size_t size, krb5_encrypt_block *eblock, krb5_pointer ivec) { krb5_data inputd, ivecd; krb5_enc_data outputd; size_t blocksize, outlen; krb5_error_code ret; if (ivec) { if ((ret = krb5_c_block_size(context, eblock->key->enctype, &blocksize))) return(ret); ivecd.length = blocksize; ivecd.data = ivec; } /* size is the length of the input cleartext data */ inputd.length = size; inputd.data = inptr; /* The size of the output buffer isn't part of the old api. Not too safe. So, we assume here that it's big enough. */ if ((ret = krb5_c_encrypt_length(context, eblock->key->enctype, size, &outlen))) return(ret); outputd.ciphertext.length = outlen; outputd.ciphertext.data = outptr; return(krb5_c_encrypt(context, eblock->key, 0, ivec?&ivecd:0, &inputd, &outputd)); }
krb5_error_code krb5_encrypt_data(krb5_context context, krb5_keyblock *key, krb5_pointer ivec, krb5_data *data, krb5_enc_data *enc_data) { krb5_error_code ret; size_t enclen, blocksize; krb5_data ivecd; if ((ret = krb5_c_encrypt_length(context, key->enctype, data->length, &enclen))) return(ret); if (ivec) { if ((ret = krb5_c_block_size(context, key->enctype, &blocksize))) return(ret); ivecd.length = blocksize; ivecd.data = ivec; } enc_data->magic = KV5M_ENC_DATA; enc_data->kvno = 0; enc_data->enctype = key->enctype; enc_data->ciphertext.length = enclen; if ((enc_data->ciphertext.data = malloc(enclen)) == NULL) return(ENOMEM); if ((ret = krb5_c_encrypt(context, key, 0, ivec?&ivecd:0, data, enc_data))) free(enc_data->ciphertext.data); return(ret); }
static int gp_encrypt_buffer(krb5_context context, krb5_keyblock *key, size_t len, void *buf, octet_string *out) { int ret; krb5_data data_in; krb5_enc_data enc_handle; data_in.length = len; data_in.data = buf; memset(&enc_handle, '\0', sizeof(krb5_enc_data)); ret = krb5_c_encrypt_length(context, GP_CREDS_HANDLE_KEY_ENCTYPE, data_in.length, (size_t *)&enc_handle.ciphertext.length); if (ret) { goto done; } enc_handle.ciphertext.data = malloc(enc_handle.ciphertext.length); if (!enc_handle.ciphertext.data) { ret = ENOMEM; goto done; } ret = krb5_c_encrypt(context, key, KRB5_KEYUSAGE_APP_DATA_ENCRYPT, NULL, &data_in, &enc_handle); if (ret) { ret = EINVAL; goto done; } ret = gp_conv_octet_string(enc_handle.ciphertext.length, enc_handle.ciphertext.data, out); if (ret) { goto done; } done: free(enc_handle.ciphertext.data); return ret; }
static krb5_error_code securid_encrypt_track_data_2(krb5_context context, krb5_db_entry *client, krb5_data *track_data, krb5_data *output) { krb5_error_code retval; size_t olen; krb5_keyblock sam_key; krb5_enc_data tmp_enc_data; output->data = NULL; retval = get_securid_key(context,client, &sam_key); if (retval != 0) return retval; retval = krb5_c_encrypt_length(context, sam_key.enctype, track_data->length, &olen); if (retval != 0) goto cleanup; assert(olen <= 65536); output->length = olen; output->data = k5alloc(output->length, &retval); if (retval) goto cleanup; tmp_enc_data.ciphertext = *output; tmp_enc_data.enctype = sam_key.enctype; tmp_enc_data.kvno = 0; retval = krb5_c_encrypt(context, &sam_key, KRB5_KEYUSAGE_PA_SAM_CHALLENGE_TRACKID, 0, track_data, &tmp_enc_data); cleanup: krb5_free_keyblock_contents(context, &sam_key); if (retval) { output->length = 0; free(output->data); output->data = NULL; return retval; } return 0; }
krb5_error_code gss_krb5int_make_seal_token_v3 (krb5_context context, krb5_gss_ctx_id_rec *ctx, const gss_buffer_desc * message, gss_buffer_t token, int conf_req_flag, int toktype) { size_t bufsize = 16; unsigned char *outbuf = 0; krb5_error_code err; int key_usage; unsigned char acceptor_flag; const gss_buffer_desc *message2 = message; #ifdef CFX_EXERCISE size_t rrc; #endif size_t ec; unsigned short tok_id; krb5_checksum sum; krb5_keyblock *key; ASSERT(toktype != KG_TOK_SEAL_MSG || ctx->enc != 0); ASSERT(ctx->big_endian == 0); acceptor_flag = ctx->initiate ? 0 : FLAG_SENDER_IS_ACCEPTOR; key_usage = (toktype == KG_TOK_WRAP_MSG ? (ctx->initiate ? KG_USAGE_INITIATOR_SEAL : KG_USAGE_ACCEPTOR_SEAL) : (ctx->initiate ? KG_USAGE_INITIATOR_SIGN : KG_USAGE_ACCEPTOR_SIGN)); if (ctx->have_acceptor_subkey) { key = ctx->acceptor_subkey; } else { key = ctx->enc; } #ifdef _KERNEL context->kef_cipher_mt = get_cipher_mech_type(context, key); context->kef_hash_mt = get_hash_mech_type(context, key); if ((err = init_key_kef(context->kef_cipher_mt, key))) { return (GSS_S_FAILURE); } #endif /* _KERNEL */ #ifdef CFX_EXERCISE { static int initialized = 0; if (!initialized) { srand(time(0)); initialized = 1; } } #endif if (toktype == KG_TOK_WRAP_MSG && conf_req_flag) { krb5_data plain; krb5_enc_data cipher; size_t ec_max; size_t tlen; /* 300: Adds some slop. */ if (SIZE_MAX - 300 < message->length) return ENOMEM; ec_max = SIZE_MAX - message->length - 300; if (ec_max > 0xffff) ec_max = 0xffff; /* * EC should really be a multiple (1) of the number of octets that * the cryptosystem would pad by if we didn't have the filler. * * For AES-CTS this will always be 0 and we expect no further * enctypes, so there should be no issue here. */ ec = 0; plain.length = message->length + 16 + ec; plain.data = MALLOC(plain.length); if (plain.data == NULL) return ENOMEM; /* Get size of ciphertext. */ if ((err = krb5_c_encrypt_length(context, ctx->enc->enctype, plain.length, &tlen))) { FREE(plain.data, plain.length); return (err); } bufsize = 16 + tlen; /* Allocate space for header plus encrypted data. */ outbuf = MALLOC(bufsize); if (outbuf == NULL) { FREE(plain.data, plain.length); return ENOMEM; } /* TOK_ID */ store_16_be(0x0504, outbuf); /* flags */ outbuf[2] = (acceptor_flag | (conf_req_flag ? FLAG_WRAP_CONFIDENTIAL : 0) | (ctx->have_acceptor_subkey ? FLAG_ACCEPTOR_SUBKEY : 0)); /* filler */ outbuf[3] = 0xff; /* EC */ store_16_be(ec, outbuf+4); /* RRC */ store_16_be(0, outbuf+6); store_64_be(ctx->seq_send, outbuf+8); (void) memcpy(plain.data, message->value, message->length); (void) memset(plain.data + message->length, 'x', ec); (void) memcpy(plain.data + message->length + ec, outbuf, 16); /* Should really use scatter/gather crypto interfaces */ cipher.ciphertext.data = (char *)outbuf + 16; cipher.ciphertext.length = bufsize - 16; cipher.enctype = key->enctype; err = krb5_c_encrypt(context, key, key_usage, 0, &plain, &cipher); (void) bzero(plain.data, plain.length); FREE(plain.data, plain.length); plain.data = 0; if (err) goto error; /* Now that we know we're returning a valid token.... */ ctx->seq_send++; #ifdef CFX_EXERCISE rrc = rand() & 0xffff; if (rotate_left(outbuf+16, bufsize-16, (bufsize-16) - (rrc % (bufsize - 16)))) store_16_be(rrc, outbuf+6); /* If the rotate fails, don't worry about it. */ #endif } else if (toktype == KG_TOK_WRAP_MSG && !conf_req_flag) { krb5_data plain; /* Here, message is the application-supplied data; message2 is what goes into the output token. They may be the same, or message2 may be empty (for MIC). */ tok_id = 0x0504; wrap_with_checksum: plain.length = message->length + 16; plain.data = MALLOC(message->length + 16); if (plain.data == NULL) return ENOMEM; if (ctx->cksum_size > 0xffff) { FREE(plain.data, plain.length); return EINVAL; } bufsize = 16 + message2->length + ctx->cksum_size; outbuf = MALLOC(bufsize); if (outbuf == NULL) { FREE(plain.data, plain.length); plain.data = 0; err = ENOMEM; goto error; } /* TOK_ID */ store_16_be(tok_id, outbuf); /* flags */ outbuf[2] = (acceptor_flag | (ctx->have_acceptor_subkey ? FLAG_ACCEPTOR_SUBKEY : 0)); /* filler */ outbuf[3] = 0xff; if (toktype == KG_TOK_WRAP_MSG) { /* Use 0 for checksum calculation, substitute checksum length later. */ /* EC */ store_16_be(0, outbuf+4); /* RRC */ store_16_be(0, outbuf+6); } else { /* MIC and DEL store 0xFF in EC and RRC. */ store_16_be(0xffff, outbuf+4); store_16_be(0xffff, outbuf+6); } store_64_be(ctx->seq_send, outbuf+8); (void) memcpy(plain.data, message->value, message->length); (void) memcpy(plain.data + message->length, outbuf, 16); /* Fill in the output token -- data contents, if any, and space for the checksum. */ if (message2->length) (void) memcpy(outbuf + 16, message2->value, message2->length); sum.contents = outbuf + 16 + message2->length; sum.length = ctx->cksum_size; err = krb5_c_make_checksum(context, ctx->cksumtype, key, key_usage, &plain, &sum); bzero(plain.data, plain.length); FREE(plain.data, plain.length); plain.data = 0; if (err) { bzero(outbuf,bufsize); err = KRB5KRB_AP_ERR_BAD_INTEGRITY; goto error; } if (sum.length != ctx->cksum_size) { err = KRB5KRB_AP_ERR_BAD_INTEGRITY; goto error; } (void) memcpy(outbuf + 16 + message2->length, sum.contents, ctx->cksum_size); krb5_free_checksum_contents(context, &sum); sum.contents = 0; /* Now that we know we're actually generating the token... */ ctx->seq_send++; if (toktype == KG_TOK_WRAP_MSG) { #ifdef CFX_EXERCISE rrc = rand() & 0xffff; /* If the rotate fails, don't worry about it. */ if (rotate_left(outbuf+16, bufsize-16, (bufsize-16) - (rrc % (bufsize - 16)))) store_16_be(rrc, outbuf+6); #endif /* Fix up EC field. */ store_16_be(ctx->cksum_size, outbuf+4); } else { store_16_be(0xffff, outbuf+6); } } else if (toktype == KG_TOK_MIC_MSG) { tok_id = 0x0404; message2 = &empty_message; goto wrap_with_checksum; } else if (toktype == KG_TOK_DEL_CTX) { /* * Solaris Kerberos: * No token should be generated for context deletion. Just * return. */ return 0; } else { err = KRB5KRB_AP_ERR_BAD_INTEGRITY; goto error; } token->value = outbuf; token->length = bufsize; return 0; error: FREE(outbuf, bufsize); token->value = NULL; token->length = 0; return err; }
/* * Generate a krb5_key_data set by encrypting keys according to * enctype/salttype preferences */ krb5_error_code ipa_krb5_generate_key_data(krb5_context krbctx, krb5_principal principal, krb5_data pwd, int kvno, krb5_keyblock *kmkey, int num_encsalts, krb5_key_salt_tuple *encsalts, int *_num_keys, krb5_key_data **_keys) { krb5_error_code kerr; krb5_key_data *keys; int num_keys; int i; num_keys = num_encsalts; keys = calloc(num_keys, sizeof(krb5_key_data)); if (!keys) { return ENOMEM; } for (i = 0; i < num_keys; i++) { krb5_keyblock key; krb5_data salt; krb5_octet *ptr; krb5_data plain; krb5_enc_data cipher; krb5_int16 t; size_t len; salt.data = NULL; keys[i].key_data_ver = 2; /* we always have a salt */ keys[i].key_data_kvno = kvno; switch (encsalts[i].ks_salttype) { case KRB5_KDB_SALTTYPE_ONLYREALM: if (!principal->realm.data) { kerr = EINVAL; goto done; } salt.length = principal->realm.length; salt.data = malloc(salt.length); if (!salt.data) { kerr = ENOMEM; goto done; } memcpy(salt.data, principal->realm.data, salt.length); break; case KRB5_KDB_SALTTYPE_NOREALM: kerr = ipa_krb5_principal2salt_norealm(krbctx, principal, &salt); if (kerr) { goto done; } break; case KRB5_KDB_SALTTYPE_NORMAL: kerr = krb5_principal2salt(krbctx, principal, &salt); if (kerr) { goto done; } break; case KRB5_KDB_SALTTYPE_SPECIAL: kerr = ipa_get_random_salt(krbctx, &salt); if (kerr) { goto done; } break; case KRB5_KDB_SALTTYPE_V4: salt.length = 0; break; case KRB5_KDB_SALTTYPE_AFS3: if (!principal->realm.data) { kerr = EINVAL; goto done; } salt.data = strndup((char *)principal->realm.data, principal->realm.length); if (!salt.data) { kerr = ENOMEM; goto done; } salt.length = SALT_TYPE_AFS_LENGTH; /* special value */ break; default: kerr = EINVAL; goto done; } /* need to build the key now to manage the AFS salt.length * special case */ kerr = krb5_c_string_to_key(krbctx, encsalts[i].ks_enctype, &pwd, &salt, &key); if (kerr) { krb5_free_data_contents(krbctx, &salt); goto done; } if (salt.length == SALT_TYPE_AFS_LENGTH) { salt.length = strlen(salt.data); } kerr = krb5_c_encrypt_length(krbctx, kmkey->enctype, key.length, &len); if (kerr) { krb5int_c_free_keyblock_contents(krbctx, &key); krb5_free_data_contents(krbctx, &salt); goto done; } if ((ptr = (krb5_octet *) malloc(2 + len)) == NULL) { kerr = ENOMEM; krb5int_c_free_keyblock_contents(krbctx, &key); krb5_free_data_contents(krbctx, &salt); goto done; } t = htole16(key.length); memcpy(ptr, &t, 2); plain.length = key.length; plain.data = (char *)key.contents; cipher.ciphertext.length = len; cipher.ciphertext.data = (char *)ptr+2; kerr = krb5_c_encrypt(krbctx, kmkey, 0, 0, &plain, &cipher); if (kerr) { krb5int_c_free_keyblock_contents(krbctx, &key); krb5_free_data_contents(krbctx, &salt); free(ptr); goto done; } /* KrbSalt */ keys[i].key_data_type[1] = encsalts[i].ks_salttype; if (salt.length) { keys[i].key_data_length[1] = salt.length; keys[i].key_data_contents[1] = (krb5_octet *)salt.data; } /* EncryptionKey */ keys[i].key_data_type[0] = key.enctype; keys[i].key_data_length[0] = len + 2; keys[i].key_data_contents[0] = malloc(len + 2); if (!keys[i].key_data_contents[0]) { kerr = ENOMEM; krb5int_c_free_keyblock_contents(krbctx, &key); free(ptr); goto done; } memcpy(keys[i].key_data_contents[0], ptr, len + 2); /* make sure we free the memory used now that we are done with it */ krb5int_c_free_keyblock_contents(krbctx, &key); free(ptr); } *_num_keys = num_keys; *_keys = keys; kerr = 0; done: if (kerr) { ipa_krb5_free_key_data(keys, num_keys); } return kerr; }
static krb5_error_code sam2_process(krb5_context context, krb5_clpreauth_moddata moddata, krb5_clpreauth_modreq modreq, krb5_get_init_creds_opt *opt, krb5_clpreauth_callbacks cb, krb5_clpreauth_rock rock, krb5_kdc_req *request, krb5_data *encoded_request_body, krb5_data *encoded_previous_request, krb5_pa_data *padata, krb5_prompter_fct prompter, void *prompter_data, krb5_pa_data ***out_padata) { krb5_error_code retval; krb5_sam_challenge_2 *sc2 = NULL; krb5_sam_challenge_2_body *sc2b = NULL; krb5_data tmp_data; krb5_data response_data; char name[100], banner[100], prompt[100], response[100]; krb5_prompt kprompt; krb5_prompt_type prompt_type; krb5_data defsalt, *salt; krb5_checksum **cksum; krb5_data *scratch = NULL; krb5_boolean valid_cksum = 0; krb5_enc_sam_response_enc_2 enc_sam_response_enc_2; krb5_sam_response_2 sr2; size_t ciph_len; krb5_pa_data **sam_padata; if (prompter == NULL) return KRB5_LIBOS_CANTREADPWD; tmp_data.length = padata->length; tmp_data.data = (char *)padata->contents; if ((retval = decode_krb5_sam_challenge_2(&tmp_data, &sc2))) return(retval); retval = decode_krb5_sam_challenge_2_body(&sc2->sam_challenge_2_body, &sc2b); if (retval) { krb5_free_sam_challenge_2(context, sc2); return(retval); } if (!sc2->sam_cksum || ! *sc2->sam_cksum) { krb5_free_sam_challenge_2(context, sc2); krb5_free_sam_challenge_2_body(context, sc2b); return(KRB5_SAM_NO_CHECKSUM); } if (sc2b->sam_flags & KRB5_SAM_MUST_PK_ENCRYPT_SAD) { krb5_free_sam_challenge_2(context, sc2); krb5_free_sam_challenge_2_body(context, sc2b); return(KRB5_SAM_UNSUPPORTED); } if (!krb5_c_valid_enctype(sc2b->sam_etype)) { krb5_free_sam_challenge_2(context, sc2); krb5_free_sam_challenge_2_body(context, sc2b); return(KRB5_SAM_INVALID_ETYPE); } /* All of the above error checks are KDC-specific, that is, they */ /* assume a failure in the KDC reply. By returning anything other */ /* than KRB5_KDC_UNREACH, KRB5_PREAUTH_FAILED, */ /* KRB5_LIBOS_PWDINTR, or KRB5_REALM_CANT_RESOLVE, the client will */ /* most likely go on to try the AS_REQ against master KDC */ if (!(sc2b->sam_flags & KRB5_SAM_USE_SAD_AS_KEY)) { /* We will need the password to obtain the key used for */ /* the checksum, and encryption of the sam_response. */ /* Go ahead and get it now, preserving the ordering of */ /* prompts for the user. */ retval = (*rock->gak_fct)(context, request->client, sc2b->sam_etype, prompter, prompter_data, rock->salt, rock->s2kparams, rock->as_key, *rock->gak_data); if (retval) { krb5_free_sam_challenge_2(context, sc2); krb5_free_sam_challenge_2_body(context, sc2b); return(retval); } } snprintf(name, sizeof(name), "%.*s", SAMDATA(sc2b->sam_type_name, _("SAM Authentication"), sizeof(name) - 1)); snprintf(banner, sizeof(banner), "%.*s", SAMDATA(sc2b->sam_challenge_label, sam_challenge_banner(sc2b->sam_type), sizeof(banner)-1)); snprintf(prompt, sizeof(prompt), "%s%.*s%s%.*s", sc2b->sam_challenge.length?"Challenge is [":"", SAMDATA(sc2b->sam_challenge, "", 20), sc2b->sam_challenge.length?"], ":"", SAMDATA(sc2b->sam_response_prompt, "passcode", 55)); response_data.data = response; response_data.length = sizeof(response); kprompt.prompt = prompt; kprompt.hidden = 1; kprompt.reply = &response_data; prompt_type = KRB5_PROMPT_TYPE_PREAUTH; krb5int_set_prompt_types(context, &prompt_type); if ((retval = ((*prompter)(context, prompter_data, name, banner, 1, &kprompt)))) { krb5_free_sam_challenge_2(context, sc2); krb5_free_sam_challenge_2_body(context, sc2b); krb5int_set_prompt_types(context, 0); return(retval); } krb5int_set_prompt_types(context, (krb5_prompt_type *)NULL); /* Generate salt used by string_to_key() */ salt = rock->salt; if (((int) salt->length == -1) && (salt->data == NULL)) { if ((retval = krb5_principal2salt(context, request->client, &defsalt))) { krb5_free_sam_challenge_2(context, sc2); krb5_free_sam_challenge_2_body(context, sc2b); return(retval); } salt = &defsalt; } else { defsalt.length = 0; } /* Get encryption key to be used for checksum and sam_response */ if (!(sc2b->sam_flags & KRB5_SAM_USE_SAD_AS_KEY)) { /* as_key = string_to_key(password) */ if (rock->as_key->length) { krb5_free_keyblock_contents(context, rock->as_key); rock->as_key->length = 0; } /* generate a key using the supplied password */ retval = krb5_c_string_to_key(context, sc2b->sam_etype, (krb5_data *)*rock->gak_data, salt, rock->as_key); if (retval) { krb5_free_sam_challenge_2(context, sc2); krb5_free_sam_challenge_2_body(context, sc2b); if (defsalt.length) free(defsalt.data); return(retval); } if (!(sc2b->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD)) { /* as_key = combine_key (as_key, string_to_key(SAD)) */ krb5_keyblock tmp_kb; retval = krb5_c_string_to_key(context, sc2b->sam_etype, &response_data, salt, &tmp_kb); if (retval) { krb5_free_sam_challenge_2(context, sc2); krb5_free_sam_challenge_2_body(context, sc2b); if (defsalt.length) free(defsalt.data); return(retval); } /* This should be a call to the crypto library some day */ /* key types should already match the sam_etype */ retval = krb5int_c_combine_keys(context, rock->as_key, &tmp_kb, rock->as_key); if (retval) { krb5_free_sam_challenge_2(context, sc2); krb5_free_sam_challenge_2_body(context, sc2b); if (defsalt.length) free(defsalt.data); return(retval); } krb5_free_keyblock_contents(context, &tmp_kb); } if (defsalt.length) free(defsalt.data); } else { /* as_key = string_to_key(SAD) */ if (rock->as_key->length) { krb5_free_keyblock_contents(context, rock->as_key); rock->as_key->length = 0; } /* generate a key using the supplied password */ retval = krb5_c_string_to_key(context, sc2b->sam_etype, &response_data, salt, rock->as_key); if (defsalt.length) free(defsalt.data); if (retval) { krb5_free_sam_challenge_2(context, sc2); krb5_free_sam_challenge_2_body(context, sc2b); return(retval); } } /* Now we have a key, verify the checksum on the sam_challenge */ cksum = sc2->sam_cksum; for (; *cksum; cksum++) { if (!krb5_c_is_keyed_cksum((*cksum)->checksum_type)) continue; /* Check this cksum */ retval = krb5_c_verify_checksum(context, rock->as_key, KRB5_KEYUSAGE_PA_SAM_CHALLENGE_CKSUM, &sc2->sam_challenge_2_body, *cksum, &valid_cksum); if (retval) { krb5_free_data(context, scratch); krb5_free_sam_challenge_2(context, sc2); krb5_free_sam_challenge_2_body(context, sc2b); return(retval); } if (valid_cksum) break; } if (!valid_cksum) { krb5_free_sam_challenge_2(context, sc2); krb5_free_sam_challenge_2_body(context, sc2b); /* * Note: We return AP_ERR_BAD_INTEGRITY so upper-level applications * can interpret that as "password incorrect", which is probably * the best error we can return in this situation. */ return(KRB5KRB_AP_ERR_BAD_INTEGRITY); } /* fill in enc_sam_response_enc_2 */ enc_sam_response_enc_2.magic = KV5M_ENC_SAM_RESPONSE_ENC_2; enc_sam_response_enc_2.sam_nonce = sc2b->sam_nonce; if (sc2b->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD) { enc_sam_response_enc_2.sam_sad = response_data; } else { enc_sam_response_enc_2.sam_sad.data = NULL; enc_sam_response_enc_2.sam_sad.length = 0; } /* encode and encrypt enc_sam_response_enc_2 with as_key */ retval = encode_krb5_enc_sam_response_enc_2(&enc_sam_response_enc_2, &scratch); if (retval) { krb5_free_sam_challenge_2(context, sc2); krb5_free_sam_challenge_2_body(context, sc2b); return(retval); } /* Fill in sam_response_2 */ memset(&sr2, 0, sizeof(sr2)); sr2.sam_type = sc2b->sam_type; sr2.sam_flags = sc2b->sam_flags; sr2.sam_track_id = sc2b->sam_track_id; sr2.sam_nonce = sc2b->sam_nonce; /* Now take care of sr2.sam_enc_nonce_or_sad by encrypting encoded */ /* enc_sam_response_enc_2 from above */ retval = krb5_c_encrypt_length(context, rock->as_key->enctype, scratch->length, &ciph_len); if (retval) { krb5_free_sam_challenge_2(context, sc2); krb5_free_sam_challenge_2_body(context, sc2b); krb5_free_data(context, scratch); return(retval); } sr2.sam_enc_nonce_or_sad.ciphertext.length = ciph_len; sr2.sam_enc_nonce_or_sad.ciphertext.data = (char *)malloc(sr2.sam_enc_nonce_or_sad.ciphertext.length); if (!sr2.sam_enc_nonce_or_sad.ciphertext.data) { krb5_free_sam_challenge_2(context, sc2); krb5_free_sam_challenge_2_body(context, sc2b); krb5_free_data(context, scratch); return(ENOMEM); } retval = krb5_c_encrypt(context, rock->as_key, KRB5_KEYUSAGE_PA_SAM_RESPONSE, NULL, scratch, &sr2.sam_enc_nonce_or_sad); if (retval) { krb5_free_sam_challenge_2(context, sc2); krb5_free_sam_challenge_2_body(context, sc2b); krb5_free_data(context, scratch); krb5_free_data_contents(context, &sr2.sam_enc_nonce_or_sad.ciphertext); return(retval); } krb5_free_data(context, scratch); scratch = NULL; /* Encode the sam_response_2 */ retval = encode_krb5_sam_response_2(&sr2, &scratch); krb5_free_sam_challenge_2(context, sc2); krb5_free_sam_challenge_2_body(context, sc2b); krb5_free_data_contents(context, &sr2.sam_enc_nonce_or_sad.ciphertext); if (retval) { return (retval); } /* Almost there, just need to make padata ! */ sam_padata = malloc(2 * sizeof(*sam_padata)); if (sam_padata == NULL) { krb5_free_data(context, scratch); return(ENOMEM); } sam_padata[0] = malloc(sizeof(krb5_pa_data)); if (sam_padata[0] == NULL) { krb5_free_data(context, scratch); free(sam_padata); return(ENOMEM); } sam_padata[0]->magic = KV5M_PA_DATA; sam_padata[0]->pa_type = KRB5_PADATA_SAM_RESPONSE_2; sam_padata[0]->length = scratch->length; sam_padata[0]->contents = (krb5_octet *) scratch->data; free(scratch); sam_padata[1] = NULL; *out_padata = sam_padata; return(0); }
krb5_error_code gss_krb5int_make_seal_token_v3 (krb5_context context, krb5_gss_ctx_id_rec *ctx, const gss_buffer_desc * message, gss_buffer_t token, int conf_req_flag, int toktype) { size_t bufsize = 16; unsigned char *outbuf = 0; krb5_error_code err; int key_usage; unsigned char acceptor_flag; const gss_buffer_desc *message2 = message; #ifdef CFX_EXERCISE size_t rrc; #endif size_t ec; unsigned short tok_id; krb5_checksum sum; krb5_keyblock *key; krb5_cksumtype cksumtype; assert(ctx->big_endian == 0); acceptor_flag = ctx->initiate ? 0 : FLAG_SENDER_IS_ACCEPTOR; key_usage = (toktype == KG_TOK_WRAP_MSG ? (ctx->initiate ? KG_USAGE_INITIATOR_SEAL : KG_USAGE_ACCEPTOR_SEAL) : (ctx->initiate ? KG_USAGE_INITIATOR_SIGN : KG_USAGE_ACCEPTOR_SIGN)); if (ctx->have_acceptor_subkey) { key = ctx->acceptor_subkey; cksumtype = ctx->acceptor_subkey_cksumtype; } else { key = ctx->subkey; cksumtype = ctx->cksumtype; } assert(key != NULL); #ifdef CFX_EXERCISE { static int initialized = 0; if (!initialized) { srand(time(0)); initialized = 1; } } #endif if (toktype == KG_TOK_WRAP_MSG && conf_req_flag) { krb5_data plain; krb5_enc_data cipher; size_t ec_max; /* 300: Adds some slop. */ if (SIZE_MAX - 300 < message->length) return ENOMEM; ec_max = SIZE_MAX - message->length - 300; if (ec_max > 0xffff) ec_max = 0xffff; #ifdef CFX_EXERCISE /* For testing only. For performance, always set ec = 0. */ ec = ec_max & rand(); #else ec = 0; #endif plain.length = message->length + 16 + ec; plain.data = malloc(message->length + 16 + ec); if (plain.data == NULL) return ENOMEM; /* Get size of ciphertext. */ bufsize = 16 + krb5_encrypt_size (plain.length, key->enctype); /* Allocate space for header plus encrypted data. */ outbuf = malloc(bufsize); if (outbuf == NULL) { free(plain.data); return ENOMEM; } /* TOK_ID */ store_16_be(KG2_TOK_WRAP_MSG, outbuf); /* flags */ outbuf[2] = (acceptor_flag | (conf_req_flag ? FLAG_WRAP_CONFIDENTIAL : 0) | (ctx->have_acceptor_subkey ? FLAG_ACCEPTOR_SUBKEY : 0)); /* filler */ outbuf[3] = 0xff; /* EC */ store_16_be(ec, outbuf+4); /* RRC */ store_16_be(0, outbuf+6); store_64_be(ctx->seq_send, outbuf+8); memcpy(plain.data, message->value, message->length); memset(plain.data + message->length, 'x', ec); memcpy(plain.data + message->length + ec, outbuf, 16); cipher.ciphertext.data = (char *)outbuf + 16; cipher.ciphertext.length = bufsize - 16; cipher.enctype = key->enctype; err = krb5_c_encrypt(context, key, key_usage, 0, &plain, &cipher); zap(plain.data, plain.length); free(plain.data); plain.data = 0; if (err) goto error; /* Now that we know we're returning a valid token.... */ ctx->seq_send++; #ifdef CFX_EXERCISE rrc = rand() & 0xffff; if (gss_krb5int_rotate_left(outbuf+16, bufsize-16, (bufsize-16) - (rrc % (bufsize - 16)))) store_16_be(rrc, outbuf+6); /* If the rotate fails, don't worry about it. */ #endif } else if (toktype == KG_TOK_WRAP_MSG && !conf_req_flag) { krb5_data plain; size_t cksumsize; /* Here, message is the application-supplied data; message2 is what goes into the output token. They may be the same, or message2 may be empty (for MIC). */ tok_id = KG2_TOK_WRAP_MSG; wrap_with_checksum: plain.length = message->length + 16; plain.data = malloc(message->length + 16); if (plain.data == NULL) return ENOMEM; err = krb5_c_checksum_length(context, cksumtype, &cksumsize); if (err) goto error; assert(cksumsize <= 0xffff); bufsize = 16 + message2->length + cksumsize; outbuf = malloc(bufsize); if (outbuf == NULL) { free(plain.data); plain.data = 0; err = ENOMEM; goto error; } /* TOK_ID */ store_16_be(tok_id, outbuf); /* flags */ outbuf[2] = (acceptor_flag | (ctx->have_acceptor_subkey ? FLAG_ACCEPTOR_SUBKEY : 0)); /* filler */ outbuf[3] = 0xff; if (toktype == KG_TOK_WRAP_MSG) { /* Use 0 for checksum calculation, substitute checksum length later. */ /* EC */ store_16_be(0, outbuf+4); /* RRC */ store_16_be(0, outbuf+6); } else { /* MIC and DEL store 0xFF in EC and RRC. */ store_16_be(0xffff, outbuf+4); store_16_be(0xffff, outbuf+6); } store_64_be(ctx->seq_send, outbuf+8); memcpy(plain.data, message->value, message->length); memcpy(plain.data + message->length, outbuf, 16); /* Fill in the output token -- data contents, if any, and space for the checksum. */ if (message2->length) memcpy(outbuf + 16, message2->value, message2->length); sum.contents = outbuf + 16 + message2->length; sum.length = cksumsize; err = krb5_c_make_checksum(context, cksumtype, key, key_usage, &plain, &sum); zap(plain.data, plain.length); free(plain.data); plain.data = 0; if (err) { zap(outbuf,bufsize); goto error; } if (sum.length != cksumsize) abort(); memcpy(outbuf + 16 + message2->length, sum.contents, cksumsize); krb5_free_checksum_contents(context, &sum); sum.contents = 0; /* Now that we know we're actually generating the token... */ ctx->seq_send++; if (toktype == KG_TOK_WRAP_MSG) { #ifdef CFX_EXERCISE rrc = rand() & 0xffff; /* If the rotate fails, don't worry about it. */ if (gss_krb5int_rotate_left(outbuf+16, bufsize-16, (bufsize-16) - (rrc % (bufsize - 16)))) store_16_be(rrc, outbuf+6); #endif /* Fix up EC field. */ store_16_be(cksumsize, outbuf+4); } else { store_16_be(0xffff, outbuf+6); } } else if (toktype == KG_TOK_MIC_MSG) { tok_id = KG2_TOK_MIC_MSG; message2 = &empty_message; goto wrap_with_checksum; } else if (toktype == KG_TOK_DEL_CTX) { tok_id = KG2_TOK_DEL_CTX; message = message2 = &empty_message; goto wrap_with_checksum; } else abort(); token->value = outbuf; token->length = bufsize; return 0; error: free(outbuf); token->value = NULL; token->length = 0; return err; }
int main () { krb5_context context = 0; krb5_data in, in2, out, out2, check, check2, state, signdata; krb5_crypto_iov iov[5]; int i, j, pos; unsigned int dummy; size_t len; krb5_enc_data enc_out, enc_out2; krb5_keyblock *keyblock; krb5_key key; memset(iov, 0, sizeof(iov)); in.data = "This is a test.\n"; in.length = strlen (in.data); in2.data = "This is another test.\n"; in2.length = strlen (in2.data); test ("Seeding random number generator", krb5_c_random_seed (context, &in)); /* Set up output buffers. */ out.data = malloc(2048); out2.data = malloc(2048); check.data = malloc(2048); check2.data = malloc(2048); if (out.data == NULL || out2.data == NULL || check.data == NULL || check2.data == NULL) abort(); out.magic = KV5M_DATA; out.length = 2048; out2.magic = KV5M_DATA; out2.length = 2048; check.length = 2048; check2.length = 2048; for (i = 0; interesting_enctypes[i]; i++) { krb5_enctype enctype = interesting_enctypes [i]; printf ("Testing enctype %d\n", enctype); test ("Initializing a keyblock", krb5_init_keyblock (context, enctype, 0, &keyblock)); test ("Generating random keyblock", krb5_c_make_random_key (context, enctype, keyblock)); test ("Creating opaque key from keyblock", krb5_k_create_key (context, keyblock, &key)); enc_out.ciphertext = out; enc_out2.ciphertext = out2; /* We use an intermediate `len' because size_t may be different size than `int' */ krb5_c_encrypt_length (context, keyblock->enctype, in.length, &len); enc_out.ciphertext.length = len; /* Encrypt, decrypt, and see if we got the plaintext back again. */ test ("Encrypting (c)", krb5_c_encrypt (context, keyblock, 7, 0, &in, &enc_out)); display ("Enc output", &enc_out.ciphertext); test ("Decrypting", krb5_c_decrypt (context, keyblock, 7, 0, &enc_out, &check)); test ("Comparing", compare_results (&in, &check)); /* Try again with the opaque-key-using variants. */ memset(out.data, 0, out.length); test ("Encrypting (k)", krb5_k_encrypt (context, key, 7, 0, &in, &enc_out)); display ("Enc output", &enc_out.ciphertext); test ("Decrypting", krb5_k_decrypt (context, key, 7, 0, &enc_out, &check)); test ("Comparing", compare_results (&in, &check)); /* Check if this enctype supports IOV encryption. */ if ( krb5_c_crypto_length(context, keyblock->enctype, KRB5_CRYPTO_TYPE_HEADER, &dummy) == 0 ){ /* Set up iovecs for stream decryption. */ memcpy(out2.data, enc_out.ciphertext.data, enc_out.ciphertext.length); iov[0].flags= KRB5_CRYPTO_TYPE_STREAM; iov[0].data.data = out2.data; iov[0].data.length = enc_out.ciphertext.length; iov[1].flags = KRB5_CRYPTO_TYPE_DATA; /* Decrypt the encrypted data from above and check it. */ test("IOV stream decrypting (c)", krb5_c_decrypt_iov( context, keyblock, 7, 0, iov, 2)); test("Comparing results", compare_results(&in, &iov[1].data)); /* Try again with the opaque-key-using variant. */ memcpy(out2.data, enc_out.ciphertext.data, enc_out.ciphertext.length); test("IOV stream decrypting (k)", krb5_k_decrypt_iov( context, key, 7, 0, iov, 2)); test("Comparing results", compare_results(&in, &iov[1].data)); /* Set up iovecs for AEAD encryption. */ signdata.magic = KV5M_DATA; signdata.data = (char *) "This should be signed"; signdata.length = strlen(signdata.data); iov[0].flags = KRB5_CRYPTO_TYPE_HEADER; iov[1].flags = KRB5_CRYPTO_TYPE_DATA; iov[1].data = in; /*We'll need to copy memory before encrypt*/ iov[2].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; iov[2].data = signdata; iov[3].flags = KRB5_CRYPTO_TYPE_PADDING; iov[4].flags = KRB5_CRYPTO_TYPE_TRAILER; /* "Allocate" data for the iovec buffers from the "out" buffer. */ test("Setting up iov lengths", krb5_c_crypto_length_iov(context, keyblock->enctype, iov, 5)); for (j=0,pos=0; j <= 4; j++ ){ if (iov[j].flags == KRB5_CRYPTO_TYPE_SIGN_ONLY) continue; iov[j].data.data = &out.data[pos]; pos += iov[j].data.length; } assert (iov[1].data.length == in.length); memcpy(iov[1].data.data, in.data, in.length); /* Encrypt and decrypt in place, and check the result. */ test("iov encrypting (c)", krb5_c_encrypt_iov(context, keyblock, 7, 0, iov, 5)); assert(iov[1].data.length == in.length); display("Header", &iov[0].data); display("Data", &iov[1].data); display("Padding", &iov[3].data); display("Trailer", &iov[4].data); test("iov decrypting", krb5_c_decrypt_iov(context, keyblock, 7, 0, iov, 5)); test("Comparing results", compare_results(&in, &iov[1].data)); /* Try again with opaque-key-using variants. */ test("iov encrypting (k)", krb5_k_encrypt_iov(context, key, 7, 0, iov, 5)); assert(iov[1].data.length == in.length); display("Header", &iov[0].data); display("Data", &iov[1].data); display("Padding", &iov[3].data); display("Trailer", &iov[4].data); test("iov decrypting", krb5_k_decrypt_iov(context, key, 7, 0, iov, 5)); test("Comparing results", compare_results(&in, &iov[1].data)); } enc_out.ciphertext.length = out.length; check.length = 2048; test ("init_state", krb5_c_init_state (context, keyblock, 7, &state)); test ("Encrypting with state", krb5_c_encrypt (context, keyblock, 7, &state, &in, &enc_out)); display ("Enc output", &enc_out.ciphertext); test ("Encrypting again with state", krb5_c_encrypt (context, keyblock, 7, &state, &in2, &enc_out2)); display ("Enc output", &enc_out2.ciphertext); test ("free_state", krb5_c_free_state (context, keyblock, &state)); test ("init_state", krb5_c_init_state (context, keyblock, 7, &state)); test ("Decrypting with state", krb5_c_decrypt (context, keyblock, 7, &state, &enc_out, &check)); test ("Decrypting again with state", krb5_c_decrypt (context, keyblock, 7, &state, &enc_out2, &check2)); test ("free_state", krb5_c_free_state (context, keyblock, &state)); test ("Comparing", compare_results (&in, &check)); test ("Comparing", compare_results (&in2, &check2)); krb5_free_keyblock (context, keyblock); krb5_k_free_key (context, key); } /* Test the RC4 decrypt fallback from key usage 9 to 8. */ test ("Initializing an RC4 keyblock", krb5_init_keyblock (context, ENCTYPE_ARCFOUR_HMAC, 0, &keyblock)); test ("Generating random RC4 key", krb5_c_make_random_key (context, ENCTYPE_ARCFOUR_HMAC, keyblock)); enc_out.ciphertext = out; krb5_c_encrypt_length (context, keyblock->enctype, in.length, &len); enc_out.ciphertext.length = len; check.length = 2048; test ("Encrypting with RC4 key usage 8", krb5_c_encrypt (context, keyblock, 8, 0, &in, &enc_out)); display ("Enc output", &enc_out.ciphertext); test ("Decrypting with RC4 key usage 9", krb5_c_decrypt (context, keyblock, 9, 0, &enc_out, &check)); test ("Comparing", compare_results (&in, &check)); krb5_free_keyblock (context, keyblock); free(out.data); free(out2.data); free(check.data); free(check2.data); return 0; }
/* Construct a cookie pa-data item using the cookie values from state, or a * trivial "MIT" cookie if no values are set. */ krb5_error_code kdc_fast_make_cookie(krb5_context context, struct kdc_request_state *state, krb5_db_entry *local_tgt, krb5_const_principal client_princ, krb5_pa_data **cookie_out) { krb5_error_code ret; krb5_secure_cookie cookie; krb5_pa_data **contents = state->out_cookie_padata, *pa; krb5_keyblock *key = NULL; krb5_timestamp now; krb5_enc_data enc; krb5_data *der_cookie = NULL; krb5_kvno kvno; size_t ctlen; *cookie_out = NULL; memset(&enc, 0, sizeof(enc)); /* Make a trivial cookie if there are no contents to marshal or we don't * have a TGT entry to encrypt them. */ if (contents == NULL || *contents == NULL || local_tgt == NULL) return make_padata(KRB5_PADATA_FX_COOKIE, "MIT", 3, cookie_out); ret = get_cookie_key(context, local_tgt, 0, client_princ, &key, &kvno); if (ret) goto cleanup; /* Encode the cookie. */ ret = krb5_timeofday(context, &now); if (ret) goto cleanup; cookie.time = now; cookie.data = contents; ret = encode_krb5_secure_cookie(&cookie, &der_cookie); if (ret) goto cleanup; /* Encrypt the cookie in key. */ ret = krb5_c_encrypt_length(context, key->enctype, der_cookie->length, &ctlen); if (ret) goto cleanup; ret = alloc_data(&enc.ciphertext, ctlen); if (ret) goto cleanup; ret = krb5_c_encrypt(context, key, KRB5_KEYUSAGE_PA_FX_COOKIE, NULL, der_cookie, &enc); if (ret) goto cleanup; /* Construct the cookie pa-data entry. */ ret = alloc_padata(KRB5_PADATA_FX_COOKIE, 8 + enc.ciphertext.length, &pa); memcpy(pa->contents, "MIT1", 4); store_32_be(kvno, pa->contents + 4); memcpy(pa->contents + 8, enc.ciphertext.data, enc.ciphertext.length); *cookie_out = pa; cleanup: krb5_free_keyblock(context, key); if (der_cookie != NULL) { zapfree(der_cookie->data, der_cookie->length); free(der_cookie); } krb5_free_data_contents(context, &enc.ciphertext); return ret; }
/*ARGSUSED*/ static krb5_error_code krb5_mk_priv_basic(krb5_context context, const krb5_data *userdata, const krb5_keyblock *keyblock, krb5_replay_data *replaydata, krb5_address *local_addr, krb5_address *remote_addr, krb5_pointer i_vector, krb5_data *outbuf) { krb5_error_code retval; krb5_priv privmsg; krb5_priv_enc_part privmsg_enc_part; krb5_data *scratch1, *scratch2, ivdata; size_t blocksize, enclen; privmsg.enc_part.kvno = 0; /* XXX allow user-set? */ privmsg.enc_part.enctype = keyblock->enctype; privmsg_enc_part.user_data = *userdata; privmsg_enc_part.s_address = local_addr; privmsg_enc_part.r_address = remote_addr; /* We should check too make sure one exists. */ privmsg_enc_part.timestamp = replaydata->timestamp; privmsg_enc_part.usec = replaydata->usec; privmsg_enc_part.seq_number = replaydata->seq; /* start by encoding to-be-encrypted part of the message */ if ((retval = encode_krb5_enc_priv_part(&privmsg_enc_part, &scratch1))) return retval; /* put together an eblock for this encryption */ if ((retval = krb5_c_encrypt_length(context, keyblock->enctype, scratch1->length, &enclen))) goto clean_scratch; privmsg.enc_part.ciphertext.length = enclen; if (!(privmsg.enc_part.ciphertext.data = malloc(privmsg.enc_part.ciphertext.length))) { retval = ENOMEM; goto clean_scratch; } /* call the encryption routine */ if (i_vector) { if ((retval = krb5_c_block_size(context, keyblock->enctype, &blocksize))) goto clean_encpart; ivdata.length = blocksize; ivdata.data = i_vector; } if ((retval = krb5_c_encrypt(context, keyblock, KRB5_KEYUSAGE_KRB_PRIV_ENCPART, i_vector?&ivdata:0, scratch1, &privmsg.enc_part))) goto clean_encpart; if ((retval = encode_krb5_priv(&privmsg, &scratch2))) goto clean_encpart; *outbuf = *scratch2; krb5_xfree(scratch2); retval = 0; clean_encpart: memset(privmsg.enc_part.ciphertext.data, 0, privmsg.enc_part.ciphertext.length); free(privmsg.enc_part.ciphertext.data); privmsg.enc_part.ciphertext.length = 0; privmsg.enc_part.ciphertext.data = 0; clean_scratch: memset(scratch1->data, 0, scratch1->length); krb5_free_data(context, scratch1); return retval; }
int Condor_Auth_Kerberos :: wrap(char* input, int input_len, char*& output, int& output_len) { krb5_error_code code; krb5_data in_data; krb5_enc_data out_data; int index, tmp; size_t blocksize, encrypted_length; char* encrypted_data = 0; // make a blank initialization vector code = krb5_c_block_size(krb_context_, sessionKey_->enctype, &blocksize); if (code) { // err } // Make the input buffer in_data.data = input; in_data.length = input_len; // Make the output buffer code = krb5_c_encrypt_length(krb_context_, sessionKey_->enctype, input_len, &encrypted_length); if(code) { // err } encrypted_data = (char*)malloc(encrypted_length); if (!encrypted_length) { // err } out_data.ciphertext.data = (char*)encrypted_data; out_data.ciphertext.length = encrypted_length; if ((code = krb5_c_encrypt(krb_context_, sessionKey_, 1024, /* key usage */ 0, &in_data, &out_data)) != 0) { /* 0 = no ivec */ output = 0; output_len = 0; if (out_data.ciphertext.data) { free(out_data.ciphertext.data); } dprintf( D_ALWAYS, "KERBEROS: %s\n", error_message(code) ); return false; } output_len = sizeof(out_data.enctype) + sizeof(out_data.kvno) + sizeof(out_data.ciphertext.length) + out_data.ciphertext.length; output = (char *) malloc(output_len); index = 0; tmp = htonl(out_data.enctype); memcpy(output + index, &tmp, sizeof(out_data.enctype)); index += sizeof(out_data.enctype); tmp = htonl(out_data.kvno); memcpy(output + index, &tmp, sizeof(out_data.kvno)); index += sizeof(out_data.kvno); tmp = htonl(out_data.ciphertext.length); memcpy(output + index, &tmp, sizeof(out_data.ciphertext.length)); index += sizeof(out_data.ciphertext.length); if (out_data.ciphertext.data) { memcpy(output + index, out_data.ciphertext.data, out_data.ciphertext.length); free(out_data.ciphertext.data); } return TRUE; }
int ksm_rgenerate_out_msg(struct snmp_secmod_outgoing_params *parms) { krb5_auth_context auth_context = NULL; krb5_error_code retcode; krb5_ccache cc = NULL; int retval = SNMPERR_SUCCESS; krb5_data outdata, ivector; krb5_keyblock *subkey = NULL; #ifdef MIT_NEW_CRYPTO krb5_data input; krb5_enc_data output; unsigned int numcksumtypes; krb5_cksumtype *cksumtype_array; #else /* MIT_NEW_CRYPTO */ krb5_encrypt_block eblock; #endif /* MIT_NEW_CRYPTO */ size_t blocksize, encrypted_length; unsigned char *encrypted_data = NULL; int zero = 0, i; u_char *cksum_pointer, *endp = *parms->wholeMsg; krb5_cksumtype cksumtype; krb5_checksum pdu_checksum; u_char **wholeMsg = parms->wholeMsg; size_t *offset = parms->wholeMsgOffset, seq_offset; struct ksm_secStateRef *ksm_state = (struct ksm_secStateRef *) parms->secStateRef; int rc; DEBUGMSGTL(("ksm", "Starting KSM processing\n")); outdata.length = 0; outdata.data = NULL; ivector.length = 0; ivector.data = NULL; pdu_checksum.contents = NULL; if (!ksm_state) { /* * If we don't have a ksm_state, then we're a request. Get a * credential cache and build a ap_req. */ retcode = krb5_cc_default(kcontext, &cc); if (retcode) { DEBUGMSGTL(("ksm", "KSM: krb5_cc_default failed: %s\n", error_message(retcode))); snmp_set_detail(error_message(retcode)); retval = SNMPERR_KRB5; goto error; } DEBUGMSGTL(("ksm", "KSM: Set credential cache successfully\n")); /* * This seems odd, since we don't need this until later (or earlier, * depending on how you look at it), but because the most likely * errors are Kerberos at this point, I'll get this now to save * time not encoding the rest of the packet. * * Also, we need the subkey to encrypt the PDU (if required). */ retcode = krb5_mk_req(kcontext, &auth_context, AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY, (char *) service_name, parms->session->peername, NULL, cc, &outdata); if (retcode) { DEBUGMSGTL(("ksm", "KSM: krb5_mk_req failed: %s\n", error_message(retcode))); snmp_set_detail(error_message(retcode)); retval = SNMPERR_KRB5; goto error; } DEBUGMSGTL(("ksm", "KSM: ticket retrieved successfully for \"%s/%s\" " "(may not be actual ticket sname)\n", service_name, parms->session->peername)); } else { /* * Grab the auth_context from our security state reference */ auth_context = ksm_state->auth_context; /* * Bundle up an AP_REP. Note that we do this only when we * have a security state reference (which means we're in an agent * and we're sending a response). */ DEBUGMSGTL(("ksm", "KSM: Starting reply processing.\n")); retcode = krb5_mk_rep(kcontext, auth_context, &outdata); if (retcode) { DEBUGMSGTL(("ksm", "KSM: krb5_mk_rep failed: %s\n", error_message(retcode))); snmp_set_detail(error_message(retcode)); retval = SNMPERR_KRB5; goto error; } DEBUGMSGTL(("ksm", "KSM: Finished with krb5_mk_rep()\n")); } /* * If we have to encrypt the PDU, do that now */ if (parms->secLevel == SNMP_SEC_LEVEL_AUTHPRIV) { DEBUGMSGTL(("ksm", "KSM: Starting PDU encryption.\n")); /* * It's weird - * * If we're on the manager, it's a local subkey (because that's in * our AP_REQ) * * If we're on the agent, it's a remote subkey (because that comes * FROM the received AP_REQ). */ if (ksm_state) retcode = krb5_auth_con_getremotesubkey(kcontext, auth_context, &subkey); else retcode = krb5_auth_con_getlocalsubkey(kcontext, auth_context, &subkey); if (retcode) { DEBUGMSGTL(("ksm", "KSM: krb5_auth_con_getlocalsubkey failed: %s\n", error_message(retcode))); snmp_set_detail(error_message(retcode)); retval = SNMPERR_KRB5; goto error; } /* * Note that here we need to handle different things between the * old and new crypto APIs. First, we need to get the final encrypted * length of the PDU. */ #ifdef MIT_NEW_CRYPTO retcode = krb5_c_encrypt_length(kcontext, subkey->enctype, parms->scopedPduLen, &encrypted_length); if (retcode) { DEBUGMSGTL(("ksm", "Encryption length calculation failed: %s\n", error_message(retcode))); snmp_set_detail(error_message(retcode)); retval = SNMPERR_KRB5; goto error; } #else /* MIT_NEW_CRYPTO */ krb5_use_enctype(kcontext, &eblock, subkey->enctype); retcode = krb5_process_key(kcontext, &eblock, subkey); if (retcode) { DEBUGMSGTL(("ksm", "krb5_process_key failed: %s\n", error_message(retcode))); snmp_set_detail(error_message(retcode)); retval = SNMPERR_KRB5; goto error; } encrypted_length = krb5_encrypt_size(parms->scopedPduLen, eblock.crypto_entry); #endif /* MIT_NEW_CRYPTO */ encrypted_data = malloc(encrypted_length); if (!encrypted_data) { DEBUGMSGTL(("ksm", "KSM: Unable to malloc %d bytes for encrypt " "buffer: %s\n", parms->scopedPduLen, strerror(errno))); retval = SNMPERR_MALLOC; #ifndef MIT_NEW_CRYPTO krb5_finish_key(kcontext, &eblock); #endif /* ! MIT_NEW_CRYPTO */ goto error; } /* * We need to set up a blank initialization vector for the encryption. * Use a block of all zero's (which is dependent on the block size * of the encryption method). */ #ifdef MIT_NEW_CRYPTO retcode = krb5_c_block_size(kcontext, subkey->enctype, &blocksize); if (retcode) { DEBUGMSGTL(("ksm", "Unable to determine crypto block size: %s\n", error_message(retcode))); snmp_set_detail(error_message(retcode)); retval = SNMPERR_KRB5; goto error; } #else /* MIT_NEW_CRYPTO */ blocksize = krb5_enctype_array[subkey->enctype]->system->block_length; #endif /* MIT_NEW_CRYPTO */ ivector.data = malloc(blocksize); if (!ivector.data) { DEBUGMSGTL(("ksm", "Unable to allocate %d bytes for ivector\n", blocksize)); retval = SNMPERR_MALLOC; goto error; } ivector.length = blocksize; memset(ivector.data, 0, blocksize); /* * Finally! Do the encryption! */ #ifdef MIT_NEW_CRYPTO input.data = (char *) parms->scopedPdu; input.length = parms->scopedPduLen; output.ciphertext.data = (char *) encrypted_data; output.ciphertext.length = encrypted_length; retcode = krb5_c_encrypt(kcontext, subkey, KSM_KEY_USAGE_ENCRYPTION, &ivector, &input, &output); #else /* MIT_NEW_CRYPTO */ retcode = krb5_encrypt(kcontext, (krb5_pointer) parms->scopedPdu, (krb5_pointer) encrypted_data, parms->scopedPduLen, &eblock, ivector.data); krb5_finish_key(kcontext, &eblock); #endif /* MIT_NEW_CRYPTO */ if (retcode) { DEBUGMSGTL(("ksm", "KSM: krb5_encrypt failed: %s\n", error_message(retcode))); retval = SNMPERR_KRB5; snmp_set_detail(error_message(retcode)); goto error; } *offset = 0; rc = asn_realloc_rbuild_string(wholeMsg, parms->wholeMsgLen, offset, 1, (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR), encrypted_data, encrypted_length); if (rc == 0) { DEBUGMSGTL(("ksm", "Building encrypted payload failed.\n")); retval = SNMPERR_TOO_LONG; goto error; } DEBUGMSGTL(("ksm", "KSM: Encryption complete.\n")); } else { /* * Plaintext PDU (not encrypted) */ if (*parms->wholeMsgLen < parms->scopedPduLen) { DEBUGMSGTL(("ksm", "Not enough room for plaintext PDU.\n")); retval = SNMPERR_TOO_LONG; goto error; } } /* * Start encoding the msgSecurityParameters * * For now, use 0 for the response hint */ DEBUGMSGTL(("ksm", "KSM: scopedPdu added to payload\n")); seq_offset = *offset; rc = asn_realloc_rbuild_int(wholeMsg, parms->wholeMsgLen, offset, 1, (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER), (long *) &zero, sizeof(zero)); if (rc == 0) { DEBUGMSGTL(("ksm", "Building ksm security parameters failed.\n")); retval = SNMPERR_TOO_LONG; goto error; } rc = asn_realloc_rbuild_string(wholeMsg, parms->wholeMsgLen, offset, 1, (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR), (u_char *) outdata.data, outdata.length); if (rc == 0) { DEBUGMSGTL(("ksm", "Building ksm AP_REQ failed.\n")); retval = SNMPERR_TOO_LONG; goto error; } /* * Now, we need to pick the "right" checksum algorithm. For old * crypto, just pick CKSUMTYPE_RSA_MD5_DES; for new crypto, pick * one of the "approved" ones. */ #ifdef MIT_NEW_CRYPTO retcode = krb5_c_keyed_checksum_types(kcontext, subkey->enctype, &numcksumtypes, &cksumtype_array); if (retcode) { DEBUGMSGTL(("ksm", "Unable to find appropriate keyed checksum: %s\n", error_message(retcode))); snmp_set_detail(error_message(retcode)); retval = SNMPERR_KRB5; goto error; } if (numcksumtypes <= 0) { DEBUGMSGTL(("ksm", "We received a list of zero cksumtypes for this " "enctype (%d)\n", subkey->enctype)); snmp_set_detail("No valid checksum type for this encryption type"); retval = SNMPERR_KRB5; goto error; } /* * It's not clear to me from the API which checksum you're supposed * to support, so I'm taking a guess at the first one */ cksumtype = cksumtype_array[0]; krb5_free_cksumtypes(kcontext, cksumtype_array); DEBUGMSGTL(("ksm", "KSM: Choosing checksum type of %d (subkey type " "of %d)\n", cksumtype, subkey->enctype)); retcode = krb5_c_checksum_length(kcontext, cksumtype, &blocksize); if (retcode) { DEBUGMSGTL(("ksm", "Unable to determine checksum length: %s\n", error_message(retcode))); snmp_set_detail(error_message(retcode)); retval = SNMPERR_KRB5; goto error; } pdu_checksum.length = blocksize; #else /* MIT_NEW_CRYPTO */ if (ksm_state) cksumtype = ksm_state->cksumtype; else cksumtype = CKSUMTYPE_RSA_MD5_DES; if (!is_keyed_cksum(cksumtype)) { DEBUGMSGTL(("ksm", "Checksum type %d is not a keyed checksum\n", cksumtype)); snmp_set_detail("Checksum is not a keyed checksum"); retval = SNMPERR_KRB5; goto error; } if (!is_coll_proof_cksum(cksumtype)) { DEBUGMSGTL(("ksm", "Checksum type %d is not a collision-proof " "checksum\n", cksumtype)); snmp_set_detail("Checksum is not a collision-proof checksum"); retval = SNMPERR_KRB5; goto error; } pdu_checksum.length = krb5_checksum_size(kcontext, cksumtype); pdu_checksum.checksum_type = cksumtype; #endif /* MIT_NEW_CRYPTO */ /* * Note that here, we're just leaving blank space for the checksum; * we remember where that is, and we'll fill it in later. */ *offset += pdu_checksum.length; memset(*wholeMsg + *parms->wholeMsgLen - *offset, 0, pdu_checksum.length); cksum_pointer = *wholeMsg + *parms->wholeMsgLen - *offset; rc = asn_realloc_rbuild_header(wholeMsg, parms->wholeMsgLen, parms->wholeMsgOffset, 1, (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR), pdu_checksum.length); if (rc == 0) { DEBUGMSGTL(("ksm", "Building ksm security parameters failed.\n")); retval = SNMPERR_TOO_LONG; goto error; } rc = asn_realloc_rbuild_int(wholeMsg, parms->wholeMsgLen, parms->wholeMsgOffset, 1, (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR), (long *) &cksumtype, sizeof(cksumtype)); if (rc == 0) { DEBUGMSGTL(("ksm", "Building ksm security parameters failed.\n")); retval = SNMPERR_TOO_LONG; goto error; } rc = asn_realloc_rbuild_sequence(wholeMsg, parms->wholeMsgLen, parms->wholeMsgOffset, 1, (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), *offset - seq_offset); if (rc == 0) { DEBUGMSGTL(("ksm", "Building ksm security parameters failed.\n")); retval = SNMPERR_TOO_LONG; goto error; } rc = asn_realloc_rbuild_header(wholeMsg, parms->wholeMsgLen, parms->wholeMsgOffset, 1, (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR), *offset - seq_offset); if (rc == 0) { DEBUGMSGTL(("ksm", "Building ksm security parameters failed.\n")); retval = SNMPERR_TOO_LONG; goto error; } DEBUGMSGTL(("ksm", "KSM: Security parameter encoding completed\n")); /* * We're done with the KSM security parameters - now we do the global * header and wrap up the whole PDU. */ if (*parms->wholeMsgLen < parms->globalDataLen) { DEBUGMSGTL(("ksm", "Building global data failed.\n")); retval = SNMPERR_TOO_LONG; goto error; } *offset += parms->globalDataLen; memcpy(*wholeMsg + *parms->wholeMsgLen - *offset, parms->globalData, parms->globalDataLen); rc = asn_realloc_rbuild_sequence(wholeMsg, parms->wholeMsgLen, offset, 1, (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), *offset); if (rc == 0) { DEBUGMSGTL(("ksm", "Building master packet sequence.\n")); retval = SNMPERR_TOO_LONG; goto error; } DEBUGMSGTL(("ksm", "KSM: PDU master packet encoding complete.\n")); /* * Now we need to checksum the entire PDU (since it's built). */ pdu_checksum.contents = malloc(pdu_checksum.length); if (!pdu_checksum.contents) { DEBUGMSGTL(("ksm", "Unable to malloc %d bytes for checksum\n", pdu_checksum.length)); retval = SNMPERR_MALLOC; goto error; } /* * If we didn't encrypt the packet, we haven't yet got the subkey. * Get that now. */ if (!subkey) { if (ksm_state) retcode = krb5_auth_con_getremotesubkey(kcontext, auth_context, &subkey); else retcode = krb5_auth_con_getlocalsubkey(kcontext, auth_context, &subkey); if (retcode) { DEBUGMSGTL(("ksm", "krb5_auth_con_getlocalsubkey failed: %s\n", error_message(retcode))); snmp_set_detail(error_message(retcode)); retval = SNMPERR_KRB5; goto error; } } #ifdef MIT_NEW_CRYPTO input.data = (char *) (*wholeMsg + *parms->wholeMsgLen - *offset); input.length = *offset; retcode = krb5_c_make_checksum(kcontext, cksumtype, subkey, KSM_KEY_USAGE_CHECKSUM, &input, &pdu_checksum); #else /* MIT_NEW_CRYPTO */ retcode = krb5_calculate_checksum(kcontext, cksumtype, *wholeMsg + *parms->wholeMsgLen - *offset, *offset, (krb5_pointer) subkey->contents, subkey->length, &pdu_checksum); #endif /* MIT_NEW_CRYPTO */ if (retcode) { DEBUGMSGTL(("ksm", "Calculate checksum failed: %s\n", error_message(retcode))); retval = SNMPERR_KRB5; snmp_set_detail(error_message(retcode)); goto error; } DEBUGMSGTL(("ksm", "KSM: Checksum calculation complete.\n")); memcpy(cksum_pointer, pdu_checksum.contents, pdu_checksum.length); DEBUGMSGTL(("ksm", "KSM: Writing checksum of %d bytes at offset %d\n", pdu_checksum.length, cksum_pointer - (*wholeMsg + 1))); DEBUGMSGTL(("ksm", "KSM: Checksum:")); for (i = 0; i < pdu_checksum.length; i++) DEBUGMSG(("ksm", " %02x", (unsigned int) pdu_checksum.contents[i])); DEBUGMSG(("ksm", "\n")); /* * If we're _not_ called as part of a response (null ksm_state), * then save the auth_context for later using our cache routines. */ if (!ksm_state) { if ((retval = ksm_insert_cache(parms->pdu->msgid, auth_context, (u_char *) parms->secName, parms->secNameLen)) != SNMPERR_SUCCESS) goto error; auth_context = NULL; } DEBUGMSGTL(("ksm", "KSM processing complete!\n")); error: if (pdu_checksum.contents) #ifdef MIT_NEW_CRYPTO krb5_free_checksum_contents(kcontext, &pdu_checksum); #else /* MIT_NEW_CRYPTO */ free(pdu_checksum.contents); #endif /* MIT_NEW_CRYPTO */ if (ivector.data) free(ivector.data); if (subkey) krb5_free_keyblock(kcontext, subkey); if (encrypted_data) free(encrypted_data); if (cc) krb5_cc_close(kcontext, cc); if (auth_context && !ksm_state) krb5_auth_con_free(kcontext, auth_context); return retval; }
/*ARGSUSED*/ static krb5_error_code pa_sam(krb5_context context, krb5_kdc_req *request, krb5_pa_data *in_padata, krb5_pa_data **out_padata, krb5_data *salt, krb5_data *s2kparams, krb5_enctype *etype, krb5_keyblock *as_key, krb5_prompter_fct prompter, void *prompter_data, krb5_gic_get_as_key_fct gak_fct, void *gak_data) { krb5_error_code ret; krb5_data tmpsam; char name[100], banner[100]; char prompt[100], response[100]; krb5_data response_data; krb5_prompt kprompt; krb5_prompt_type prompt_type; krb5_data defsalt; krb5_sam_challenge *sam_challenge = 0; krb5_sam_response sam_response; /* these two get encrypted and stuffed in to sam_response */ krb5_enc_sam_response_enc enc_sam_response_enc; krb5_data * scratch; krb5_pa_data * pa; krb5_enc_data * enc_data; size_t enclen; if (prompter == NULL) return (EIO); tmpsam.length = in_padata->length; tmpsam.data = (char *) in_padata->contents; if ((ret = decode_krb5_sam_challenge(&tmpsam, &sam_challenge))) return(ret); if (sam_challenge->sam_flags & KRB5_SAM_MUST_PK_ENCRYPT_SAD) { krb5_xfree(sam_challenge); return(KRB5_SAM_UNSUPPORTED); } /* If we need the password from the user (USE_SAD_AS_KEY not set), */ /* then get it here. Exception for "old" KDCs with CryptoCard */ /* support which uses the USE_SAD_AS_KEY flag, but still needs pwd */ if (!(sam_challenge->sam_flags & KRB5_SAM_USE_SAD_AS_KEY) || (sam_challenge->sam_type == PA_SAM_TYPE_CRYPTOCARD)) { /* etype has either been set by caller or by KRB5_PADATA_ETYPE_INFO */ /* message from the KDC. If it is not set, pick an enctype that we */ /* think the KDC will have for us. */ if (etype && *etype == 0) *etype = ENCTYPE_DES_CBC_CRC; if ((ret = (gak_fct)(context, request->client, *etype, prompter, prompter_data, salt, s2kparams, as_key, gak_data))) return(ret); } sprintf(name, "%.*s", SAMDATA(sam_challenge->sam_type_name, "SAM Authentication", sizeof(name) - 1)); sprintf(banner, "%.*s", SAMDATA(sam_challenge->sam_challenge_label, sam_challenge_banner(sam_challenge->sam_type), sizeof(banner)-1)); /* sprintf(prompt, "Challenge is [%s], %s: ", challenge, prompt); */ sprintf(prompt, "%s%.*s%s%.*s", sam_challenge->sam_challenge.length?"Challenge is [":"", SAMDATA(sam_challenge->sam_challenge, "", 20), sam_challenge->sam_challenge.length?"], ":"", SAMDATA(sam_challenge->sam_response_prompt, "passcode", 55)); response_data.data = response; response_data.length = sizeof(response); kprompt.prompt = prompt; kprompt.hidden = 1; kprompt.reply = &response_data; prompt_type = KRB5_PROMPT_TYPE_PREAUTH; /* PROMPTER_INVOCATION */ krb5int_set_prompt_types(context, &prompt_type); if ((ret = ((*prompter)(context, prompter_data, name, banner, 1, &kprompt)))) { krb5_xfree(sam_challenge); krb5int_set_prompt_types(context, 0); return(ret); } krb5int_set_prompt_types(context, 0); enc_sam_response_enc.sam_nonce = sam_challenge->sam_nonce; if (sam_challenge->sam_nonce == 0) { if ((ret = krb5_us_timeofday(context, &enc_sam_response_enc.sam_timestamp, &enc_sam_response_enc.sam_usec))) { krb5_xfree(sam_challenge); return(ret); } sam_response.sam_patimestamp = enc_sam_response_enc.sam_timestamp; } /* XXX What if more than one flag is set? */ if (sam_challenge->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD) { /* Most of this should be taken care of before we get here. We */ /* will need the user's password and as_key to encrypt the SAD */ /* and we want to preserve ordering of user prompts (first */ /* password, then SAM data) so that user's won't be confused. */ if (as_key->length) { krb5_free_keyblock_contents(context, as_key); as_key->length = 0; } /* generate a salt using the requested principal */ if ((salt->length == -1) && (salt->data == NULL)) { if ((ret = krb5_principal2salt(context, request->client, &defsalt))) { krb5_xfree(sam_challenge); return(ret); } salt = &defsalt; } else { defsalt.length = 0; } /* generate a key using the supplied password */ ret = krb5_c_string_to_key(context, ENCTYPE_DES_CBC_MD5, (krb5_data *)gak_data, salt, as_key); if (defsalt.length) krb5_xfree(defsalt.data); if (ret) { krb5_xfree(sam_challenge); return(ret); } /* encrypt the passcode with the key from above */ enc_sam_response_enc.sam_sad = response_data; } else if (sam_challenge->sam_flags & KRB5_SAM_USE_SAD_AS_KEY) { /* process the key as password */ if (as_key->length) { krb5_free_keyblock_contents(context, as_key); as_key->length = 0; } #if 0 if ((salt->length == -1) && (salt->data == NULL)) { if (ret = krb5_principal2salt(context, request->client, &defsalt)) { krb5_xfree(sam_challenge); return(ret); } salt = &defsalt; } else { defsalt.length = 0; } #else defsalt.length = 0; salt = NULL; #endif /* XXX As of the passwords-04 draft, no enctype is specified, the server uses ENCTYPE_DES_CBC_MD5. In the future the server should send a PA-SAM-ETYPE-INFO containing the enctype. */ ret = krb5_c_string_to_key(context, ENCTYPE_DES_CBC_MD5, &response_data, salt, as_key); if (defsalt.length) krb5_xfree(defsalt.data); if (ret) { krb5_xfree(sam_challenge); return(ret); } enc_sam_response_enc.sam_sad.length = 0; } else { /* Eventually, combine SAD with long-term key to get encryption key. */ return KRB5_PREAUTH_BAD_TYPE; } /* copy things from the challenge */ sam_response.sam_nonce = sam_challenge->sam_nonce; sam_response.sam_flags = sam_challenge->sam_flags; sam_response.sam_track_id = sam_challenge->sam_track_id; sam_response.sam_type = sam_challenge->sam_type; sam_response.magic = KV5M_SAM_RESPONSE; krb5_xfree(sam_challenge); /* encode the encoded part of the response */ if ((ret = encode_krb5_enc_sam_response_enc(&enc_sam_response_enc, &scratch))) return(ret); /* * Solaris Kerberos: * Using new crypto interface now so we can get rid of the * old modules. */ if ((ret = krb5_c_encrypt_length(context, as_key->enctype, scratch->length, &enclen))) { krb5_free_data(context, scratch); return(ret); } enc_data = &sam_response.sam_enc_nonce_or_ts; enc_data->magic = KV5M_ENC_DATA; enc_data->kvno = 0; enc_data->enctype = as_key->enctype; enc_data->ciphertext.length = enclen; if ((enc_data->ciphertext.data = MALLOC(enclen)) == NULL) { enc_data->ciphertext.length = 0; krb5_free_data(context, scratch); return(ENOMEM); } if ((ret = krb5_c_encrypt(context, as_key, 0, 0, scratch, enc_data))) { FREE(enc_data->ciphertext.data, enclen); enc_data->ciphertext.data = NULL; enc_data->ciphertext.length = 0; } krb5_free_data(context, scratch); if (ret) return(ret); /* sam_enc_key is reserved for future use */ sam_response.sam_enc_key.ciphertext.length = 0; if ((pa = malloc(sizeof(krb5_pa_data))) == NULL) return(ENOMEM); if ((ret = encode_krb5_sam_response(&sam_response, &scratch))) { free(pa); return(ret); } pa->magic = KV5M_PA_DATA; pa->pa_type = KRB5_PADATA_SAM_RESPONSE; pa->length = scratch->length; pa->contents = (krb5_octet *) scratch->data; *out_padata = pa; return(0); }