From: Sam Hartman Date: Fri, 1 Oct 2010 17:12:26 +0000 (+0000) Subject: Remove support for the old pa-sam-challenge and pa-sam-response X-Git-Tag: krb5-1.9-beta1~58 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=97023f5f10fb091225ad131a0b35f1d91cd12b1e;p=krb5.git 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 --- diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c index 503c2313b..0c477266b 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 */ @@ -339,28 +310,6 @@ static krb5_preauth_systems static_preauth_systems[] = { 0, 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, @@ -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 */ diff --git a/src/lib/krb5/krb/preauth2.c b/src/lib/krb5/krb/preauth2.c index c07fc46da..5d7d2448c 100644 --- a/src/lib/krb5/krb/preauth2.c +++ b/src/lib/krb5/krb/preauth2.c @@ -721,295 +721,6 @@ pa_enc_timestamp(krb5_context context, krb5_kdc_req *request, return(0); } -static char * -sam_challenge_banner(krb5_int32 sam_type) -{ - char *label; - - switch (sam_type) { - case PA_SAM_TYPE_ENIGMA: /* Enigma Logic */ - label = "Challenge for Enigma Logic mechanism"; - break; - case PA_SAM_TYPE_DIGI_PATH: /* Digital Pathways */ - case PA_SAM_TYPE_DIGI_PATH_HEX: /* Digital Pathways */ - label = "Challenge for Digital Pathways mechanism"; - break; - case PA_SAM_TYPE_ACTIVCARD_DEC: /* Digital Pathways */ - case PA_SAM_TYPE_ACTIVCARD_HEX: /* Digital Pathways */ - label = "Challenge for Activcard mechanism"; - break; - case PA_SAM_TYPE_SKEY_K0: /* S/key where KDC has key 0 */ - label = "Challenge for Enhanced S/Key mechanism"; - break; - case PA_SAM_TYPE_SKEY: /* Traditional S/Key */ - label = "Challenge for Traditional S/Key mechanism"; - break; - case PA_SAM_TYPE_SECURID: /* Security Dynamics */ - label = "Challenge for Security Dynamics mechanism"; - break; - case PA_SAM_TYPE_SECURID_PREDICT: /* predictive Security Dynamics */ - label = "Challenge for Security Dynamics mechanism"; - break; - default: - label = "Challenge from authentication server"; - break; - } - - return(label); -} - -/* this macro expands to the int,ptr necessary for "%.*s" in an sprintf */ - -#define SAMDATA(kdata, str, maxsize) \ - (int)((kdata.length)? \ - ((((kdata.length)<=(maxsize))?(kdata.length):strlen(str))): \ - strlen(str)), \ - (kdata.length)? \ - ((((kdata.length)<=(maxsize))?(kdata.data):(str))):(str) - -/* XXX Danger! This code is not in sync with the kerberos-password-02 - draft. This draft cannot be implemented as written. This code is - compatible with earlier versions of mit krb5 and cygnus kerbnet. */ - -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; - - 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_free_sam_challenge(context, 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 == 0) - *etype = ENCTYPE_DES_CBC_CRC; - - if ((ret = (gak_fct)(context, request->client, *etype, prompter, - prompter_data, salt, s2kparams, as_key, - gak_data))) { - krb5_free_sam_challenge(context, sam_challenge); - return(ret); - } - TRACE_PREAUTH_SAM_KEY_GAK(context, as_key); - } - snprintf(name, sizeof(name), "%.*s", - SAMDATA(sam_challenge->sam_type_name, "SAM Authentication", - sizeof(name) - 1)); - - snprintf(banner, sizeof(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); */ - snprintf(prompt, sizeof(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_free_sam_challenge(context, 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_free_sam_challenge(context,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->length == SALT_TYPE_AFS_LENGTH) && (salt->data == NULL)) { - if ((ret = krb5_principal2salt(context, request->client, - &defsalt))) { - krb5_free_sam_challenge(context, 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) - free(defsalt.data); - - if (ret) { - krb5_free_sam_challenge(context, 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 == SALT_TYPE_AFS_LENGTH) && (salt->data == NULL)) { - if (ret = krb5_principal2salt(context, request->client, - &defsalt)) { - krb5_free_sam_challenge(context, 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) - free(defsalt.data); - - if (ret) { - krb5_free_sam_challenge(context, sam_challenge); - return(ret); - } - - enc_sam_response_enc.sam_sad.length = 0; - } else { - /* Eventually, combine SAD with long-term key to get - encryption key. */ - krb5_free_sam_challenge(context, sam_challenge); - 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_free_sam_challenge(context, sam_challenge); - - /* encode the encoded part of the response */ - if ((ret = encode_krb5_enc_sam_response_enc(&enc_sam_response_enc, - &scratch))) - return(ret); - - ret = krb5_encrypt_helper(context, as_key, 0, scratch, - &sam_response.sam_enc_nonce_or_ts); - - 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; - - free(scratch); - - return(0); -} - #if APPLE_PKINIT /* * PKINIT. One function to generate AS-REQ, one to parse AS-REP @@ -1324,6 +1035,51 @@ error_out: } #endif /* APPLE_PKINIT */ +/* this macro expands to the int,ptr necessary for "%.*s" in an sprintf */ + +#define SAMDATA(kdata, str, maxsize) \ + (int)((kdata.length)? \ + ((((kdata.length)<=(maxsize))?(kdata.length):strlen(str))): \ + strlen(str)), \ + (kdata.length)? \ + ((((kdata.length)<=(maxsize))?(kdata.data):(str))):(str) +static char * +sam_challenge_banner(krb5_int32 sam_type) +{ + char *label; + + switch (sam_type) { + case PA_SAM_TYPE_ENIGMA: /* Enigma Logic */ + label = "Challenge for Enigma Logic mechanism"; + break; + case PA_SAM_TYPE_DIGI_PATH: /* Digital Pathways */ + case PA_SAM_TYPE_DIGI_PATH_HEX: /* Digital Pathways */ + label = "Challenge for Digital Pathways mechanism"; + break; + case PA_SAM_TYPE_ACTIVCARD_DEC: /* Digital Pathways */ + case PA_SAM_TYPE_ACTIVCARD_HEX: /* Digital Pathways */ + label = "Challenge for Activcard mechanism"; + break; + case PA_SAM_TYPE_SKEY_K0: /* S/key where KDC has key 0 */ + label = "Challenge for Enhanced S/Key mechanism"; + break; + case PA_SAM_TYPE_SKEY: /* Traditional S/Key */ + label = "Challenge for Traditional S/Key mechanism"; + break; + case PA_SAM_TYPE_SECURID: /* Security Dynamics */ + label = "Challenge for Security Dynamics mechanism"; + break; + case PA_SAM_TYPE_SECURID_PREDICT: /* predictive Security Dynamics */ + label = "Challenge for Security Dynamics mechanism"; + break; + default: + label = "Challenge from authentication server"; + break; + } + + return(label); +} + static krb5_error_code pa_sam_2(krb5_context context, krb5_kdc_req *request, krb5_pa_data *in_padata, krb5_pa_data **out_padata, krb5_data *salt, krb5_data *s2kparams, @@ -1439,7 +1195,7 @@ pa_sam_2(krb5_context context, krb5_kdc_req *request, krb5_pa_data *in_padata, krb5int_set_prompt_types(context, (krb5_prompt_type *)NULL); /* Generate salt used by string_to_key() */ - if ((salt->length == -1) && (salt->data == NULL)) { + if (((int) salt->length == -1) && (salt->data == NULL)) { if ((retval = krb5_principal2salt(context, request->client, &defsalt))) { krb5_free_sam_challenge_2(context, sc2); @@ -1725,11 +1481,6 @@ static const pa_types_t pa_types[] = { pa_sam_2, PA_REAL, }, - { - KRB5_PADATA_SAM_CHALLENGE, - pa_sam, - PA_REAL, - }, { KRB5_PADATA_FX_COOKIE, pa_fx_cookie,