summaryrefslogtreecommitdiffstats
path: root/src/kdc/kdc_preauth.c
diff options
context:
space:
mode:
authorSam Hartman <hartmans@mit.edu>2010-10-01 17:12:26 +0000
committerSam Hartman <hartmans@mit.edu>2010-10-01 17:12:26 +0000
commit97023f5f10fb091225ad131a0b35f1d91cd12b1e (patch)
tree4e37135602650a44898f2c4b684337211644f80b /src/kdc/kdc_preauth.c
parenta9a153eb38d1b1f3ee2b6860de3de4eba48bbbeb (diff)
downloadkrb5-97023f5f10fb091225ad131a0b35f1d91cd12b1e.tar.gz
krb5-97023f5f10fb091225ad131a0b35f1d91cd12b1e.tar.xz
krb5-97023f5f10fb091225ad131a0b35f1d91cd12b1e.zip
Remove support for the old pa-sam-challenge and pa-sam-response
preauth type per discussion on krbdev. The pa-sam-challenge-2 code remains in the client. preauth: remove pa-sam-challenge git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@24403 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/kdc/kdc_preauth.c')
-rw-r--r--src/kdc/kdc_preauth.c725
1 files changed, 0 insertions, 725 deletions
diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c
index 503c2313b8..0c477266b3 100644
--- a/src/kdc/kdc_preauth.c
+++ b/src/kdc/kdc_preauth.c
@@ -202,35 +202,6 @@ return_pw_salt(krb5_context, krb5_pa_data * padata,
void *pa_system_context,
void **pa_request_context);
-/* SAM preauth support */
-static krb5_error_code
-verify_sam_response(krb5_context, krb5_db_entry *client,
- krb5_data *req_pkt,
- krb5_kdc_req *request,
- krb5_enc_tkt_part * enc_tkt_reply, krb5_pa_data *data,
- preauth_get_entry_data_proc get_entry_data,
- void *pa_module_context,
- void **pa_request_context,
- krb5_data **e_data,
- krb5_authdata ***authz_data);
-
-static krb5_error_code
-get_sam_edata(krb5_context, krb5_kdc_req *request,
- krb5_db_entry *client, krb5_db_entry *server,
- preauth_get_entry_data_proc get_entry_data,
- void *pa_module_context,
- krb5_pa_data *data);
-static krb5_error_code
-return_sam_data(krb5_context, krb5_pa_data * padata,
- krb5_db_entry *client,
- krb5_data *req_pkt,
- krb5_kdc_req *request, krb5_kdc_rep *reply,
- krb5_key_data *client_key,
- krb5_keyblock *encrypting_key,
- krb5_pa_data **send_pa,
- preauth_get_entry_data_proc get_entry_data,
- void *pa_module_context,
- void **pa_request_context);
#if APPLE_PKINIT
/* PKINIT preauth support */
@@ -340,28 +311,6 @@ static krb5_preauth_systems static_preauth_systems[] = {
return_pw_salt
},
{
- "sam-response",
- KRB5_PADATA_SAM_RESPONSE,
- 0,
- NULL,
- NULL,
- NULL,
- 0,
- verify_sam_response,
- return_sam_data
- },
- {
- "sam-challenge",
- KRB5_PADATA_SAM_CHALLENGE,
- PA_HARDWARE, /* causes get_preauth_hint_list to use this */
- NULL,
- NULL,
- NULL,
- get_sam_edata,
- 0,
- 0
- },
- {
"pac-request",
KRB5_PADATA_PAC_REQUEST,
PA_PSEUDO,
@@ -1868,681 +1817,7 @@ cleanup:
return retval;
}
-static krb5_error_code
-return_sam_data(krb5_context context, krb5_pa_data *in_padata,
- krb5_db_entry *client, krb5_data *req_pkt, krb5_kdc_req *request,
- krb5_kdc_rep *reply, krb5_key_data *client_key,
- krb5_keyblock *encrypting_key, krb5_pa_data **send_pa,
- preauth_get_entry_data_proc sam_get_entry_data,
- void *pa_system_context,
- void **pa_request_context)
-{
- krb5_error_code retval;
- krb5_data scratch;
- int i;
-
- krb5_sam_response *sr = 0;
- krb5_predicted_sam_response *psr = 0;
-
- if (in_padata->contents == 0)
- return 0;
-
- /*
- * We start by doing the same thing verify_sam_response() does:
- * extract the psr from the padata (which is an sr). Nothing
- * here should generate errors! We've already successfully done
- * all this once.
- */
-
- scratch.data = (char *)in_padata->contents;
- scratch.length = in_padata->length;
-
- if ((retval = decode_krb5_sam_response(&scratch, &sr))) {
- kdc_err(context, retval,
- "return_sam_data(): decode_krb5_sam_response failed");
- goto cleanup;
- }
-
- {
- krb5_enc_data tmpdata;
-
- tmpdata.enctype = ENCTYPE_UNKNOWN;
- tmpdata.ciphertext = sr->sam_track_id;
-
- scratch.length = tmpdata.ciphertext.length;
- if ((scratch.data = (char *) malloc(scratch.length)) == NULL) {
- retval = ENOMEM;
- goto cleanup;
- }
-
- if ((retval = krb5_c_decrypt(context, &psr_key, /* XXX */ 0, 0,
- &tmpdata, &scratch))) {
- kdc_err(context, retval,
- "return_sam_data(): decrypt track_id failed");
- free(scratch.data);
- goto cleanup;
- }
- }
-
- if ((retval = decode_krb5_predicted_sam_response(&scratch, &psr))) {
- kdc_err(context, retval,
- "return_sam_data(): decode_krb5_predicted_sam_response failed");
- free(scratch.data);
- goto cleanup;
- }
-
- /* We could use sr->sam_flags, but it may be absent or altered. */
- if (psr->sam_flags & KRB5_SAM_MUST_PK_ENCRYPT_SAD) {
- kdc_err(context, retval = KRB5KDC_ERR_PREAUTH_FAILED,
- "Unsupported SAM flag must-pk-encrypt-sad");
- goto cleanup;
- }
- if (psr->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD) {
- /* No key munging */
- goto cleanup;
- }
- if (psr->sam_flags & KRB5_SAM_USE_SAD_AS_KEY) {
- /* Use sam_key instead of client key */
- krb5_free_keyblock_contents(context, encrypting_key);
- krb5_copy_keyblock_contents(context, &psr->sam_key, encrypting_key);
- /* XXX Attach a useful pa_data */
- goto cleanup;
- }
-
- /* Otherwise (no flags set), we XOR the keys */
- /* XXX The passwords-04 draft is underspecified here wrt different
- key types. We will do what I hope to get into the -05 draft. */
- {
- krb5_octet *p = encrypting_key->contents;
- krb5_octet *q = psr->sam_key.contents;
- int length = ((encrypting_key->length < psr->sam_key.length)
- ? encrypting_key->length
- : psr->sam_key.length);
-
- for (i = 0; i < length; i++)
- p[i] ^= q[i];
- }
-
- /* Post-mixing key correction */
- switch (encrypting_key->enctype) {
- case ENCTYPE_DES_CBC_CRC:
- case ENCTYPE_DES_CBC_MD4:
- case ENCTYPE_DES_CBC_MD5:
- case ENCTYPE_DES_CBC_RAW:
- mit_des_fixup_key_parity(encrypting_key->contents);
- if (mit_des_is_weak_key(encrypting_key->contents))
- ((krb5_octet *) encrypting_key->contents)[7] ^= 0xf0;
- break;
-
- /* XXX case ENCTYPE_DES3_CBC_MD5: listed in 1510bis-04 draft */
- case ENCTYPE_DES3_CBC_SHA: /* XXX deprecated? */
- case ENCTYPE_DES3_CBC_RAW:
- case ENCTYPE_DES3_CBC_SHA1:
- for (i = 0; i < 3; i++) {
- mit_des_fixup_key_parity(encrypting_key->contents + i * 8);
- if (mit_des_is_weak_key(encrypting_key->contents + i * 8))
- ((krb5_octet *) encrypting_key->contents)[7 + i * 8] ^= 0xf0;
- }
- break;
-
- default:
- kdc_err(context, retval = KRB5KDC_ERR_PREAUTH_FAILED,
- "Unimplemented keytype for SAM key mixing");
- goto cleanup;
- }
-
- /* XXX Attach a useful pa_data */
-cleanup:
- if (sr)
- krb5_free_sam_response(context, sr);
- if (psr)
- krb5_free_predicted_sam_response(context, psr);
-
- return retval;
-}
-
-static struct {
- char* name;
- int sam_type;
-} *sam_ptr, sam_inst_map[] = {
- { "SNK4", PA_SAM_TYPE_DIGI_PATH, },
- { "SECURID", PA_SAM_TYPE_SECURID, },
- { "GRAIL", PA_SAM_TYPE_GRAIL, },
- { 0, 0 },
-};
-
-static krb5_error_code
-get_sam_edata(krb5_context context, krb5_kdc_req *request,
- krb5_db_entry *client, krb5_db_entry *server,
- preauth_get_entry_data_proc sam_get_entry_data,
- void *pa_system_context, krb5_pa_data *pa_data)
-{
- krb5_error_code retval;
- krb5_sam_challenge sc;
- krb5_predicted_sam_response psr;
- krb5_data * scratch;
- krb5_keyblock encrypting_key, *mkey_ptr;
- char response[9];
- char inputblock[8];
- krb5_data predict_response;
-
- memset(&sc, 0, sizeof(sc));
- memset(&psr, 0, sizeof(psr));
-
- /*
- * Given the client name we can figure out what type of preauth
- * they need. The spec is currently for querying the database for
- * names that match the types of preauth used. Later we should
- * make this mapping show up in kdc.conf. In the meantime, we
- * hardcode the following:
- * /SNK4 -- Digital Pathways SNK/4 preauth.
- * /GRAIL -- experimental preauth
- * The first one found is used. See sam_inst_map above.
- *
- * For SNK4 in particular, the key in the database is the key for
- * the device; kadmin needs a special interface for it.
- */
-
- {
- krb5_db_entry *assoc;
- krb5_key_data *assoc_key;
- krb5_principal newp;
- int probeslot;
-
- sc.sam_type = 0;
-
- retval = krb5_copy_principal(kdc_context, request->client, &newp);
- if (retval) {
- kdc_err(kdc_context, retval, "copying client name for preauth probe");
- return retval;
- }
-
- probeslot = krb5_princ_size(context, newp)++;
- krb5_princ_name(kdc_context, newp) =
- realloc(krb5_princ_name(kdc_context, newp),
- krb5_princ_size(context, newp) * sizeof(krb5_data));
-
- for(sam_ptr = sam_inst_map; sam_ptr->name; sam_ptr++) {
- krb5_princ_component(kdc_context,newp,probeslot)->data = sam_ptr->name;
- krb5_princ_component(kdc_context,newp,probeslot)->length =
- strlen(sam_ptr->name);
- retval = krb5_db_get_principal(kdc_context, newp, 0, &assoc);
- if(retval == 0) {
- sc.sam_type = sam_ptr->sam_type;
- break;
- }
- }
-
- krb5_princ_component(kdc_context,newp,probeslot)->data = 0;
- krb5_princ_component(kdc_context,newp,probeslot)->length = 0;
- krb5_princ_size(context, newp)--;
-
- krb5_free_principal(kdc_context, newp);
-
- /* if sc.sam_type is set, it worked */
- if (sc.sam_type) {
- /* so use assoc to get the key out! */
- {
- if ((retval = krb5_dbe_find_mkey(context, master_keylist,
- assoc, &mkey_ptr))) {
- krb5_keylist_node *tmp_mkey_list;
- /* try refreshing the mkey list in case it's been updated */
- if (krb5_db_fetch_mkey_list(context, master_princ,
- &master_keyblock, 0,
- &tmp_mkey_list) == 0) {
- krb5_dbe_free_key_list(context, master_keylist);
- master_keylist = tmp_mkey_list;
- if ((retval = krb5_dbe_find_mkey(context, master_keylist,
- assoc, &mkey_ptr))) {
- return (retval);
- }
- } else {
- return (retval);
- }
- }
-
- /* here's what do_tgs_req does */
- retval = krb5_dbe_find_enctype(kdc_context, assoc,
- ENCTYPE_DES_CBC_RAW,
- KRB5_KDB_SALTTYPE_NORMAL,
- 0, /* Get highest kvno */
- &assoc_key);
- if (retval) {
- char *sname;
- krb5_unparse_name(kdc_context, request->client, &sname);
- kdc_err(kdc_context, retval,
- "snk4 finding the enctype and key <%s>", sname);
- free(sname);
- return retval;
- }
- /* convert server.key into a real key */
- retval = krb5_dbe_decrypt_key_data(kdc_context, mkey_ptr,
- assoc_key, &encrypting_key,
- NULL);
- if (retval) {
- kdc_err(kdc_context, retval,
- "snk4 pulling out key entry");
- return retval;
- }
- /* now we can use encrypting_key... */
- }
- } else {
- /* SAM is not an option - so don't return as hint */
- return KRB5_PREAUTH_BAD_TYPE;
- }
- }
- sc.magic = KV5M_SAM_CHALLENGE;
- psr.sam_flags = sc.sam_flags = KRB5_SAM_USE_SAD_AS_KEY;
-
- /* Replay prevention */
- if ((retval = krb5_copy_principal(context, request->client, &psr.client)))
- return retval;
-#ifdef USE_RCACHE
- if ((retval = krb5_us_timeofday(context, &psr.stime, &psr.susec)))
- return retval;
-#endif /* USE_RCACHE */
-
- switch (sc.sam_type) {
- case PA_SAM_TYPE_GRAIL:
- sc.sam_type_name.data = "Experimental System";
- sc.sam_type_name.length = strlen(sc.sam_type_name.data);
- sc.sam_challenge_label.data = "experimental challenge label";
- sc.sam_challenge_label.length = strlen(sc.sam_challenge_label.data);
- sc.sam_challenge.data = "12345";
- sc.sam_challenge.length = strlen(sc.sam_challenge.data);
-
-#if 0 /* Enable this to test "normal" (no flags set) mode. */
- psr.sam_flags = sc.sam_flags = 0;
-#endif
-
- psr.magic = KV5M_PREDICTED_SAM_RESPONSE;
- /* string2key on sc.sam_challenge goes in here */
- /* eblock is just to set the enctype */
- {
- const krb5_enctype type = ENCTYPE_DES_CBC_MD5;
-
- if ((retval = krb5_c_string_to_key(context, type, &sc.sam_challenge,
- 0 /* salt */, &psr.sam_key)))
- goto cleanup;
-
- if ((retval = encode_krb5_predicted_sam_response(&psr, &scratch)))
- goto cleanup;
-
- {
- size_t enclen;
- krb5_enc_data tmpdata;
-
- if ((retval = krb5_c_encrypt_length(context,
- psr_key.enctype,
- scratch->length, &enclen)))
- goto cleanup;
-
- if ((tmpdata.ciphertext.data = (char *) malloc(enclen)) == NULL) {
- retval = ENOMEM;
- goto cleanup;
- }
- tmpdata.ciphertext.length = enclen;
-
- if ((retval = krb5_c_encrypt(context, &psr_key,
- /* XXX */ 0, 0, scratch, &tmpdata)))
- goto cleanup;
-
- sc.sam_track_id = tmpdata.ciphertext;
- }
- }
-
- sc.sam_response_prompt.data = "response prompt";
- sc.sam_response_prompt.length = strlen(sc.sam_response_prompt.data);
- sc.sam_pk_for_sad.length = 0;
- sc.sam_nonce = 0;
- /* Generate checksum */
- /*krb5_checksum_size(context, ctype)*/
- /*krb5_calculate_checksum(context,ctype,in,in_length,seed,
- seed_length,outcksum) */
- /*krb5_verify_checksum(context,ctype,cksum,in,in_length,seed,
- seed_length) */
-#if 0 /* XXX a) glue appears broken; b) this gives up the SAD */
- sc.sam_cksum.contents = (krb5_octet *)
- malloc(krb5_checksum_size(context, CKSUMTYPE_RSA_MD5_DES));
- if (sc.sam_cksum.contents == NULL) return(ENOMEM);
-
- retval = krb5_calculate_checksum(context, CKSUMTYPE_RSA_MD5_DES,
- sc.sam_challenge.data,
- sc.sam_challenge.length,
- psr.sam_key.contents, /* key */
- psr.sam_key.length, /* key length */
- &sc.sam_cksum);
- if (retval) { free(sc.sam_cksum.contents); return(retval); }
-#endif /* 0 */
-
- retval = encode_krb5_sam_challenge(&sc, &scratch);
- if (retval) goto cleanup;
- pa_data->magic = KV5M_PA_DATA;
- pa_data->pa_type = KRB5_PADATA_SAM_CHALLENGE;
- pa_data->contents = (krb5_octet *)scratch->data;
- pa_data->length = scratch->length;
-
- retval = 0;
- break;
- case PA_SAM_TYPE_DIGI_PATH:
- sc.sam_type_name.data = "Digital Pathways";
- sc.sam_type_name.length = strlen(sc.sam_type_name.data);
-#if 1
- sc.sam_challenge_label.data = "Enter the following on your keypad";
- sc.sam_challenge_label.length = strlen(sc.sam_challenge_label.data);
-#endif
- /* generate digit string, take it mod 1000000 (six digits.) */
- {
- int j;
- krb5_keyblock session_key;
- char outputblock[8];
- int i;
-
- session_key.contents = 0;
-
- memset(inputblock, 0, 8);
-
- retval = krb5_c_make_random_key(kdc_context, ENCTYPE_DES_CBC_CRC,
- &session_key);
-
- if (retval) {
- /* random key failed */
- kdc_err(kdc_context, retval,
- "generating random challenge for preauth");
- return retval;
- }
- /* now session_key has a key which we can pick bits out of */
- /* we need six decimal digits. Grab 6 bytes, div 2, mod 10 each. */
- if (session_key.length != 8) {
- kdc_err(kdc_context, retval = KRB5KDC_ERR_ETYPE_NOSUPP,
- "keytype didn't match code expectations");
- return retval;
- }
- for(i = 0; i<6; i++) {
- inputblock[i] = '0' + ((session_key.contents[i]/2) % 10);
- }
- if (session_key.contents)
- krb5_free_keyblock_contents(kdc_context, &session_key);
-
- /* retval = krb5_finish_key(kdc_context, &eblock); */
- /* now we have inputblock containing the 8 byte input to DES... */
- sc.sam_challenge.data = inputblock;
- sc.sam_challenge.length = 6;
-
- encrypting_key.enctype = ENCTYPE_DES_CBC_RAW;
-
- if (retval)
- kdc_err(kdc_context, retval, "snk4 processing key");
-
- {
- krb5_data plain;
- krb5_enc_data cipher;
-
- plain.length = 8;
- plain.data = inputblock;
-
- /* XXX I know this is enough because of the fixed raw enctype.
- if it's not, the underlying code will return a reasonable
- error, which should never happen */
- cipher.ciphertext.length = 8;
- cipher.ciphertext.data = outputblock;
-
- if ((retval = krb5_c_encrypt(kdc_context, &encrypting_key,
- /* XXX */ 0, 0, &plain, &cipher))) {
- kdc_err(kdc_context, retval,
- "snk4 response generation failed");
- return retval;
- }
- }
-
- /* now output block is the raw bits of the response; convert it
- to display form */
- for (j=0; j<4; j++) {
- char n[2];
- int k;
- n[0] = outputblock[j] & 0xf;
- n[1] = (outputblock[j]>>4) & 0xf;
- for (k=0; k<2; k++) {
- if(n[k] > 9) n[k] = ((n[k]-1)>>2);
- /* This is equivalent to:
- if(n[k]>=0xa && n[k]<=0xc) n[k] = 2;
- if(n[k]>=0xd && n[k]<=0xf) n[k] = 3;
- */
- }
- /* for v4, we keygen: *(j+(char*)&key1) = (n[1]<<4) | n[0]; */
- /* for v5, we just generate a string */
- response[2*j+0] = '0' + n[1];
- response[2*j+1] = '0' + n[0];
- /* and now, response has what we work with. */
- }
- response[8] = 0;
- predict_response.data = response;
- predict_response.length = 8;
-#if 0 /* for debugging, hack the output too! */
- sc.sam_challenge_label.data = response;
- sc.sam_challenge_label.length = strlen(sc.sam_challenge_label.data);
-#endif
- }
-
- psr.magic = KV5M_PREDICTED_SAM_RESPONSE;
- /* string2key on sc.sam_challenge goes in here */
- /* eblock is just to set the enctype */
- {
- retval = krb5_c_string_to_key(context, ENCTYPE_DES_CBC_MD5,
- &predict_response, 0 /* salt */,
- &psr.sam_key);
- if (retval) goto cleanup;
-
- retval = encode_krb5_predicted_sam_response(&psr, &scratch);
- if (retval) goto cleanup;
-
- {
- size_t enclen;
- krb5_enc_data tmpdata;
-
- if ((retval = krb5_c_encrypt_length(context,
- psr_key.enctype,
- scratch->length, &enclen)))
- goto cleanup;
-
- if ((tmpdata.ciphertext.data = (char *) malloc(enclen)) == NULL) {
- retval = ENOMEM;
- goto cleanup;
- }
- tmpdata.ciphertext.length = enclen;
-
- if ((retval = krb5_c_encrypt(context, &psr_key,
- /* XXX */ 0, 0, scratch, &tmpdata)))
- goto cleanup;
-
- sc.sam_track_id = tmpdata.ciphertext;
- }
- if (retval) goto cleanup;
- }
-
- sc.sam_response_prompt.data = "Enter the displayed response";
- sc.sam_response_prompt.length = strlen(sc.sam_response_prompt.data);
- sc.sam_pk_for_sad.length = 0;
- sc.sam_nonce = 0;
- /* Generate checksum */
- /*krb5_checksum_size(context, ctype)*/
- /*krb5_calculate_checksum(context,ctype,in,in_length,seed,
- seed_length,outcksum) */
- /*krb5_verify_checksum(context,ctype,cksum,in,in_length,seed,
- seed_length) */
-#if 0 /* XXX a) glue appears broken; b) this gives up the SAD */
- sc.sam_cksum.contents = (krb5_octet *)
- malloc(krb5_checksum_size(context, CKSUMTYPE_RSA_MD5_DES));
- if (sc.sam_cksum.contents == NULL) return(ENOMEM);
-
- retval = krb5_calculate_checksum(context, CKSUMTYPE_RSA_MD5_DES,
- sc.sam_challenge.data,
- sc.sam_challenge.length,
- psr.sam_key.contents, /* key */
- psr.sam_key.length, /* key length */
- &sc.sam_cksum);
- if (retval) { free(sc.sam_cksum.contents); return(retval); }
-#endif /* 0 */
-
- retval = encode_krb5_sam_challenge(&sc, &scratch);
- if (retval) goto cleanup;
- pa_data->magic = KV5M_PA_DATA;
- pa_data->pa_type = KRB5_PADATA_SAM_CHALLENGE;
- pa_data->contents = (krb5_octet *)scratch->data;
- pa_data->length = scratch->length;
-
- retval = 0;
- break;
- }
-
-cleanup:
- krb5_free_keyblock_contents(context, &encrypting_key);
- return retval;
-}
-
-static krb5_error_code
-verify_sam_response(krb5_context context, krb5_db_entry *client,
- krb5_data *req_pkt,
- krb5_kdc_req *request, krb5_enc_tkt_part *enc_tkt_reply,
- krb5_pa_data *pa,
- preauth_get_entry_data_proc sam_get_entry_data,
- void *pa_system_context,
- void **pa_request_context,
- krb5_data **e_data,
- krb5_authdata ***authz_data)
-{
- krb5_error_code retval;
- krb5_data scratch;
- krb5_sam_response *sr = 0;
- krb5_predicted_sam_response *psr = 0;
- krb5_enc_sam_response_enc *esre = 0;
- krb5_timestamp timenow;
- char *princ_req = 0, *princ_psr = 0;
-
- scratch.data = (char *)pa->contents;
- scratch.length = pa->length;
-
- if ((retval = decode_krb5_sam_response(&scratch, &sr))) {
- scratch.data = 0;
- kdc_err(context, retval, "decode_krb5_sam_response failed");
- goto cleanup;
- }
- /* XXX We can only handle the challenge/response model of SAM.
- See passwords-04, par 4.1, 4.2 */
- {
- krb5_enc_data tmpdata;
-
- tmpdata.enctype = ENCTYPE_UNKNOWN;
- tmpdata.ciphertext = sr->sam_track_id;
-
- scratch.length = tmpdata.ciphertext.length;
- if ((scratch.data = (char *) malloc(scratch.length)) == NULL) {
- retval = ENOMEM;
- goto cleanup;
- }
-
- if ((retval = krb5_c_decrypt(context, &psr_key, /* XXX */ 0, 0,
- &tmpdata, &scratch))) {
- kdc_err(context, retval, "decrypt track_id failed");
- goto cleanup;
- }
- }
-
- if ((retval = decode_krb5_predicted_sam_response(&scratch, &psr))) {
- kdc_err(context, retval,
- "decode_krb5_predicted_sam_response failed -- replay attack?");
- goto cleanup;
- }
-
- /* Replay detection */
- if ((retval = krb5_unparse_name(context, request->client, &princ_req)))
- goto cleanup;
- if ((retval = krb5_unparse_name(context, psr->client, &princ_psr)))
- goto cleanup;
- if (strcmp(princ_req, princ_psr) != 0) {
- kdc_err(context, retval = KRB5KDC_ERR_PREAUTH_FAILED,
- "Principal mismatch in SAM psr! -- replay attack?");
- goto cleanup;
- }
-
- if ((retval = krb5_timeofday(context, &timenow)))
- goto cleanup;
-
-#ifdef USE_RCACHE
- {
- krb5_donot_replay rep;
- extern krb5_deltat rc_lifetime;
- /*
- * Verify this response came back in a timely manner.
- * We do this b/c otherwise very old (expunged from the rcache)
- * psr's would be able to be replayed.
- */
- if (timenow - psr->stime > rc_lifetime) {
- kdc_err(context, retval = KRB5KDC_ERR_PREAUTH_FAILED,
- "SAM psr came back too late! -- replay attack?");
- goto cleanup;
- }
-
- /* Now check the replay cache. */
- rep.client = princ_psr;
- rep.server = "SAM/rc"; /* Should not match any principal name. */
- rep.msghash = NULL;
- rep.ctime = psr->stime;
- rep.cusec = psr->susec;
- retval = krb5_rc_store(kdc_context, kdc_rcache, &rep);
- if (retval) {
- kdc_err(kdc_context, retval, "SAM psr replay attack!");
- goto cleanup;
- }
- }
-#endif /* USE_RCACHE */
-
-
- {
- free(scratch.data);
- scratch.length = sr->sam_enc_nonce_or_ts.ciphertext.length;
- if ((scratch.data = (char *) malloc(scratch.length)) == NULL) {
- retval = ENOMEM;
- goto cleanup;
- }
-
- if ((retval = krb5_c_decrypt(context, &psr->sam_key, /* XXX */ 0,
- 0, &sr->sam_enc_nonce_or_ts, &scratch))) {
- kdc_err(context, retval, "decrypt nonce_or_ts failed");
- goto cleanup;
- }
- }
-
- if ((retval = decode_krb5_enc_sam_response_enc(&scratch, &esre))) {
- kdc_err(context, retval, "decode_krb5_enc_sam_response_enc failed");
- goto cleanup;
- }
-
- if (esre->sam_timestamp != sr->sam_patimestamp) {
- retval = KRB5KDC_ERR_PREAUTH_FAILED;
- goto cleanup;
- }
-
- if (labs(timenow - sr->sam_patimestamp) > context->clockskew) {
- retval = KRB5KRB_AP_ERR_SKEW;
- goto cleanup;
- }
-
- setflag(enc_tkt_reply->flags, TKT_FLG_HW_AUTH);
-
-cleanup:
- if (retval)
- kdc_err(context, retval, "sam verify failure");
- if (scratch.data) free(scratch.data);
- if (sr) free(sr);
- if (psr) free(psr);
- if (esre) free(esre);
- if (princ_psr) free(princ_psr);
- if (princ_req) free(princ_req);
-
- return retval;
-}
#if APPLE_PKINIT
/* PKINIT preauth support */