예제 #1
0
krb5_error_code KRB5_CALLCONV
krb5_encode_authdata_container(krb5_context context,
			       krb5_authdatatype type,
			       krb5_authdata *const*authdata,
			       krb5_authdata ***container)
{
    krb5_error_code code;
    krb5_data *data;
    krb5_authdata ad_datum;
    krb5_authdata *ad_data[2];

    *container = NULL;

    code = encode_krb5_authdata((krb5_authdata * const *)authdata, &data);
    if (code)
	return code;

    ad_datum.ad_type = type & AD_TYPE_FIELD_TYPE_MASK;
    ad_datum.length = data->length;
    ad_datum.contents = (unsigned char *)data->data;

    ad_data[0] = &ad_datum;
    ad_data[1] = NULL;

    code = krb5_copy_authdata(context, ad_data, container);

    krb5_free_data(context, data);

    return code;
}
예제 #2
0
파일: mk_req_ext.c 프로젝트: Akasurde/krb5
/* RFC 4537 */
static krb5_error_code
make_etype_list(krb5_context context,
                krb5_enctype *desired_etypes,
                krb5_enctype tkt_enctype,
                krb5_authdata ***authdata)
{
    krb5_error_code code;
    krb5_etype_list etypes;
    krb5_data *enc_etype_list;
    krb5_data *ad_if_relevant;
    krb5_authdata *etype_adata[2], etype_adatum, **adata;
    int i;

    etypes.etypes = desired_etypes;

    for (etypes.length = 0;
         etypes.etypes[etypes.length] != ENCTYPE_NULL;
         etypes.length++)
    {
        /*
         * RFC 4537:
         *
         *   If the enctype of the ticket session key is included in the enctype
         *   list sent by the client, it SHOULD be the last on the list;
         */
        if (etypes.length && etypes.etypes[etypes.length - 1] == tkt_enctype)
            break;
    }

    code = encode_krb5_etype_list(&etypes, &enc_etype_list);
    if (code) {
        return code;
    }

    etype_adatum.magic = KV5M_AUTHDATA;
    etype_adatum.ad_type = KRB5_AUTHDATA_ETYPE_NEGOTIATION;
    etype_adatum.length = enc_etype_list->length;
    etype_adatum.contents = (krb5_octet *)enc_etype_list->data;

    etype_adata[0] = &etype_adatum;
    etype_adata[1] = NULL;

    /* Wrap in AD-IF-RELEVANT container */
    code = encode_krb5_authdata(etype_adata, &ad_if_relevant);
    if (code) {
        krb5_free_data(context, enc_etype_list);
        return code;
    }

    krb5_free_data(context, enc_etype_list);

    adata = *authdata;
    if (adata == NULL) {
        adata = (krb5_authdata **)calloc(2, sizeof(krb5_authdata *));
        i = 0;
    } else {
        for (i = 0; adata[i] != NULL; i++)
            ;

        adata = (krb5_authdata **)realloc(*authdata,
                                          (i + 2) * sizeof(krb5_authdata *));
    }
    if (adata == NULL) {
        krb5_free_data(context, ad_if_relevant);
        return ENOMEM;
    }
    *authdata = adata;

    adata[i] = (krb5_authdata *)malloc(sizeof(krb5_authdata));
    if (adata[i] == NULL) {
        krb5_free_data(context, ad_if_relevant);
        return ENOMEM;
    }
    adata[i]->magic = KV5M_AUTHDATA;
    adata[i]->ad_type = KRB5_AUTHDATA_IF_RELEVANT;
    adata[i]->length = ad_if_relevant->length;
    adata[i]->contents = (krb5_octet *)ad_if_relevant->data;
    free(ad_if_relevant); /* contents owned by adata[i] */

    adata[i + 1] = NULL;

    return 0;
}
예제 #3
0
/*
 * Solaris Kerberos
 * Same as krb5_send_tgs plus an extra arg to return the FQDN
 * of the KDC sent the request.
 */
krb5_error_code
krb5_send_tgs2(krb5_context context, krb5_flags kdcoptions,
	      const krb5_ticket_times *timestruct, const krb5_enctype *ktypes,
	      krb5_const_principal sname, krb5_address *const *addrs,
	      krb5_authdata *const *authorization_data,
	      krb5_pa_data *const *padata, const krb5_data *second_ticket,
	    krb5_creds *in_cred, krb5_response *rep, char **hostname_used)
{
    krb5_error_code retval;
    krb5_kdc_req tgsreq;
    krb5_data *scratch, scratch2;
    krb5_ticket *sec_ticket = 0;
    krb5_ticket *sec_ticket_arr[2];
    krb5_timestamp time_now;
    krb5_pa_data **combined_padata;
    krb5_pa_data ap_req_padata;
    int tcp_only = 0, use_master;

    /* 
     * in_creds MUST be a valid credential NOT just a partially filled in
     * place holder for us to get credentials for the caller.
     */
    if (!in_cred->ticket.length)
        return(KRB5_NO_TKT_SUPPLIED);

    memset((char *)&tgsreq, 0, sizeof(tgsreq));

    tgsreq.kdc_options = kdcoptions;
    tgsreq.server = (krb5_principal) sname;

    tgsreq.from = timestruct->starttime;
    tgsreq.till = timestruct->endtime ? timestruct->endtime :
	    in_cred->times.endtime;
    tgsreq.rtime = timestruct->renew_till;
    if ((retval = krb5_timeofday(context, &time_now)))
	return(retval);
    /* XXX we know they are the same size... */
    rep->expected_nonce = tgsreq.nonce = (krb5_int32) time_now;
    rep->request_time = time_now;

    tgsreq.addresses = (krb5_address **) addrs;

    if (authorization_data) {
	/* need to encrypt it in the request */

	if ((retval = encode_krb5_authdata(authorization_data,
					   &scratch)))
	    return(retval);

	if ((retval = krb5_encrypt_helper(context, &in_cred->keyblock,
					  KRB5_KEYUSAGE_TGS_REQ_AD_SESSKEY,
					  scratch,
					  &tgsreq.authorization_data))) {
	    krb5_xfree(tgsreq.authorization_data.ciphertext.data);
	    krb5_free_data(context, scratch);
	    return retval;
	}

	krb5_free_data(context, scratch);
    }

    /* Get the encryption types list */
    if (ktypes) {
	/* Check passed ktypes and make sure they're valid. */
   	for (tgsreq.nktypes = 0; ktypes[tgsreq.nktypes]; tgsreq.nktypes++) {
    	    if (!krb5_c_valid_enctype(ktypes[tgsreq.nktypes]))
		return KRB5_PROG_ETYPE_NOSUPP;
	}
    	tgsreq.ktype = (krb5_enctype *)ktypes;
    } else {
        /* Get the default ktypes */
	/* Solaris Kerberos */
	if ((retval = krb5_get_tgs_ktypes(context, sname, &(tgsreq.ktype))))
		goto send_tgs_error_2;
	for(tgsreq.nktypes = 0; tgsreq.ktype[tgsreq.nktypes]; tgsreq.nktypes++);
    }

    if (second_ticket) {
	if ((retval = decode_krb5_ticket(second_ticket, &sec_ticket)))
	    goto send_tgs_error_1;
	sec_ticket_arr[0] = sec_ticket;
	sec_ticket_arr[1] = 0;
	tgsreq.second_ticket = sec_ticket_arr;
    } else
	tgsreq.second_ticket = 0;

    /* encode the body; then checksum it */
    if ((retval = encode_krb5_kdc_req_body(&tgsreq, &scratch)))
	goto send_tgs_error_2;

    /*
     * Get an ap_req.
     */
    if ((retval = krb5_send_tgs_basic(context, scratch, in_cred, &scratch2))) {
        krb5_free_data(context, scratch);
	goto send_tgs_error_2;
    }
    krb5_free_data(context, scratch);

    ap_req_padata.pa_type = KRB5_PADATA_AP_REQ;
    ap_req_padata.length = scratch2.length;
    ap_req_padata.contents = (krb5_octet *)scratch2.data;

    /* combine in any other supplied padata */
    if (padata) {
	krb5_pa_data * const * counter;
	register unsigned int i = 0;
	for (counter = padata; *counter; counter++, i++);
	combined_padata = malloc((i+2) * sizeof(*combined_padata));
	if (!combined_padata) {
	    krb5_xfree(ap_req_padata.contents);
	    retval = ENOMEM;
	    goto send_tgs_error_2;
	}
	combined_padata[0] = &ap_req_padata;
	for (i = 1, counter = padata; *counter; counter++, i++)
	    combined_padata[i] = (krb5_pa_data *) *counter;
	combined_padata[i] = 0;
    } else {
	combined_padata = (krb5_pa_data **)malloc(2*sizeof(*combined_padata));
	if (!combined_padata) {
	    krb5_xfree(ap_req_padata.contents);
	    retval = ENOMEM;
	    goto send_tgs_error_2;
	}
	combined_padata[0] = &ap_req_padata;
	combined_padata[1] = 0;
    }
    tgsreq.padata = combined_padata;

    /* the TGS_REQ is assembled in tgsreq, so encode it */
    if ((retval = encode_krb5_tgs_req(&tgsreq, &scratch))) {
	krb5_xfree(ap_req_padata.contents);
	krb5_xfree(combined_padata);
	goto send_tgs_error_2;
    }
    krb5_xfree(ap_req_padata.contents);
    krb5_xfree(combined_padata);

    /* now send request & get response from KDC */
send_again:
    use_master = 0;
    retval = krb5_sendto_kdc2(context, scratch, 
			    krb5_princ_realm(context, sname),
			    &rep->response, &use_master, tcp_only,
			    hostname_used);
    if (retval == 0) {
	if (krb5_is_krb_error(&rep->response)) {
	    if (!tcp_only) {
		krb5_error *err_reply;
		retval = decode_krb5_error(&rep->response, &err_reply);
		/* Solaris Kerberos */
		if (retval == 0) {
		    if (err_reply->error == KRB_ERR_RESPONSE_TOO_BIG) {
			tcp_only = 1;
			krb5_free_error(context, err_reply);
			free(rep->response.data);
			rep->response.data = 0;
			goto send_again;
		    }
		    krb5_free_error(context, err_reply);
		}
	    }
	} else if (krb5_is_tgs_rep(&rep->response))
	    rep->message_type = KRB5_TGS_REP;
        else /* XXX: assume it's an error */
	    rep->message_type = KRB5_ERROR;
    }

    krb5_free_data(context, scratch);
    
send_tgs_error_2:;
    if (sec_ticket) 
	krb5_free_ticket(context, sec_ticket);

send_tgs_error_1:;
    if (ktypes == NULL)
	krb5_xfree(tgsreq.ktype);
    if (tgsreq.authorization_data.ciphertext.data) {
	memset(tgsreq.authorization_data.ciphertext.data, 0,
               tgsreq.authorization_data.ciphertext.length); 
	krb5_xfree(tgsreq.authorization_data.ciphertext.data);
    }

    return retval;
}
예제 #4
0
파일: send_tgs.c 프로젝트: Akasurde/krb5
/*
 * Construct a TGS request and return its ASN.1 encoding as well as the
 * timestamp, nonce, and subkey used.  The pacb_fn callback allows the caller
 * to amend the request padata after the nonce and subkey are determined.
 */
krb5_error_code
k5_make_tgs_req(krb5_context context,
                struct krb5int_fast_request_state *fast_state,
                krb5_creds *tgt, krb5_flags kdcoptions,
                krb5_address *const *addrs, krb5_pa_data **in_padata,
                krb5_creds *desired, k5_pacb_fn pacb_fn, void *pacb_data,
                krb5_data *req_asn1_out, krb5_timestamp *timestamp_out,
                krb5_int32 *nonce_out, krb5_keyblock **subkey_out)
{
    krb5_error_code ret;
    krb5_kdc_req req;
    krb5_data *authdata_asn1 = NULL, *req_body_asn1 = NULL;
    krb5_data *ap_req_asn1 = NULL, *tgs_req_asn1 = NULL;
    krb5_ticket *sec_ticket = NULL;
    krb5_ticket *sec_ticket_arr[2];
    krb5_timestamp time_now;
    krb5_pa_data **padata = NULL, *pa;
    krb5_keyblock *subkey = NULL;
    krb5_enc_data authdata_enc;
    krb5_enctype enctypes[2], *defenctypes = NULL;
    size_t count, i;

    *req_asn1_out = empty_data();
    *timestamp_out = 0;
    *nonce_out = 0;
    *subkey_out = NULL;
    memset(&req, 0, sizeof(req));
    memset(&authdata_enc, 0, sizeof(authdata_enc));

    /* tgt's client principal must match the desired client principal. */
    if (!krb5_principal_compare(context, tgt->client, desired->client))
        return KRB5_PRINC_NOMATCH;

    /* tgt must be an actual credential, not a template. */
    if (!tgt->ticket.length)
        return KRB5_NO_TKT_SUPPLIED;

    req.kdc_options = kdcoptions;
    req.server = desired->server;
    req.from = desired->times.starttime;
    req.till = desired->times.endtime ? desired->times.endtime :
        tgt->times.endtime;
    req.rtime = desired->times.renew_till;
    ret = krb5_timeofday(context, &time_now);
    if (ret)
        return ret;
    *nonce_out = req.nonce = (krb5_int32)time_now;
    *timestamp_out = time_now;

    req.addresses = (krb5_address **)addrs;

    /* Generate subkey. */
    ret = krb5_generate_subkey(context, &tgt->keyblock, &subkey);
    if (ret)
        return ret;
    TRACE_SEND_TGS_SUBKEY(context, subkey);

    ret = krb5int_fast_tgs_armor(context, fast_state, subkey, &tgt->keyblock,
                                 NULL, NULL);
    if (ret)
        goto cleanup;

    if (desired->authdata != NULL) {
        ret = encode_krb5_authdata(desired->authdata, &authdata_asn1);
        if (ret)
            goto cleanup;
        ret = krb5_encrypt_helper(context, subkey,
                                  KRB5_KEYUSAGE_TGS_REQ_AD_SUBKEY,
                                  authdata_asn1, &authdata_enc);
        if (ret)
            goto cleanup;
        req.authorization_data = authdata_enc;
    }

    if (desired->keyblock.enctype != ENCTYPE_NULL) {
        if (!krb5_c_valid_enctype(desired->keyblock.enctype)) {
            ret = KRB5_PROG_ETYPE_NOSUPP;
            goto cleanup;
        }
        enctypes[0] = desired->keyblock.enctype;
        enctypes[1] = ENCTYPE_NULL;
        req.ktype = enctypes;
        req.nktypes = 1;
    } else {
        /* Get the default TGS enctypes. */
        ret = krb5_get_tgs_ktypes(context, desired->server, &defenctypes);
        if (ret)
            goto cleanup;
        for (count = 0; defenctypes[count]; count++);
        req.ktype = defenctypes;
        req.nktypes = count;
    }
    TRACE_SEND_TGS_ETYPES(context, req.ktype);

    if (kdcoptions & (KDC_OPT_ENC_TKT_IN_SKEY | KDC_OPT_CNAME_IN_ADDL_TKT)) {
        if (desired->second_ticket.length == 0) {
            ret = KRB5_NO_2ND_TKT;
            goto cleanup;
        }
        ret = decode_krb5_ticket(&desired->second_ticket, &sec_ticket);
        if (ret)
            goto cleanup;
        sec_ticket_arr[0] = sec_ticket;
        sec_ticket_arr[1] = NULL;
        req.second_ticket = sec_ticket_arr;
    }

    /* Encode the request body. */
    ret = krb5int_fast_prep_req_body(context, fast_state, &req,
                                     &req_body_asn1);
    if (ret)
        goto cleanup;

    ret = tgs_construct_ap_req(context, req_body_asn1, tgt, subkey,
                               &ap_req_asn1);
    if (ret)
        goto cleanup;

    for (count = 0; in_padata != NULL && in_padata[count] != NULL; count++);

    /* Construct a padata array for the request, beginning with the ap-req. */
    padata = k5calloc(count + 2, sizeof(krb5_pa_data *), &ret);
    if (padata == NULL)
        goto cleanup;
    padata[0] = k5alloc(sizeof(krb5_pa_data), &ret);
    if (padata[0] == NULL)
        goto cleanup;
    padata[0]->pa_type = KRB5_PADATA_AP_REQ;
    padata[0]->contents = k5memdup(ap_req_asn1->data, ap_req_asn1->length,
                                   &ret);
    if (padata[0] == NULL)
        goto cleanup;
    padata[0]->length = ap_req_asn1->length;

    /* Append copies of any other supplied padata. */
    for (i = 0; in_padata != NULL && in_padata[i] != NULL; i++) {
        pa = k5alloc(sizeof(krb5_pa_data), &ret);
        if (pa == NULL)
            goto cleanup;
        pa->pa_type = in_padata[i]->pa_type;
        pa->length = in_padata[i]->length;
        pa->contents = k5memdup(in_padata[i]->contents, in_padata[i]->length,
                                &ret);
        if (pa->contents == NULL)
            goto cleanup;
        padata[i + 1] = pa;
    }
    req.padata = padata;

    if (pacb_fn != NULL) {
        ret = (*pacb_fn)(context, subkey, &req, pacb_data);
        if (ret)
            goto cleanup;
    }

    /* Encode the TGS-REQ.  Discard the krb5_data container. */
    ret = krb5int_fast_prep_req(context, fast_state, &req, ap_req_asn1,
                                encode_krb5_tgs_req, &tgs_req_asn1);
    if (ret)
        goto cleanup;
    *req_asn1_out = *tgs_req_asn1;
    free(tgs_req_asn1);
    tgs_req_asn1 = NULL;

    *subkey_out = subkey;
    subkey = NULL;

cleanup:
    krb5_free_data(context, authdata_asn1);
    krb5_free_data(context, req_body_asn1);
    krb5_free_data(context, ap_req_asn1);
    krb5_free_pa_data(context, req.padata);
    krb5_free_ticket(context, sec_ticket);
    krb5_free_data_contents(context, &authdata_enc.ciphertext);
    krb5_free_keyblock(context, subkey);
    free(defenctypes);
    return ret;
}
예제 #5
0
파일: cammac.c 프로젝트: INNOAUS/krb5
/*
 * Create a CAMMAC for contents, using enc_tkt and the first key from krbtgt
 * for the KDC verifier.  Set *cammac_out to a single-element authdata list
 * containing the CAMMAC inside an IF-RELEVANT container.
 */
krb5_error_code
cammac_create(krb5_context context, krb5_enc_tkt_part *enc_tkt,
              krb5_keyblock *server_key, krb5_db_entry *krbtgt,
              krb5_authdata **contents, krb5_authdata ***cammac_out)
{
    krb5_error_code ret;
    krb5_data *der_authdata = NULL, *der_enctkt = NULL, *der_cammac = NULL;
    krb5_authdata ad, *list[2];
    krb5_cammac cammac;
    krb5_verifier_mac kdc_verifier, svc_verifier;
    krb5_key_data *kd;
    krb5_keyblock tgtkey;
    krb5_checksum kdc_cksum, svc_cksum;

    *cammac_out = NULL;
    memset(&tgtkey, 0, sizeof(tgtkey));
    memset(&kdc_cksum, 0, sizeof(kdc_cksum));
    memset(&svc_cksum, 0, sizeof(svc_cksum));

    /* Fetch the first krbtgt key for the KDC verifier. */
    ret = krb5_dbe_find_enctype(context, krbtgt, -1, -1, 0, &kd);
    if (ret)
        goto cleanup;
    ret = krb5_dbe_decrypt_key_data(context, NULL, kd, &tgtkey, NULL);
    if (ret)
        goto cleanup;

    /* Checksum the reply with contents as authdata for the KDC verifier. */
    ret = encode_kdcver_encpart(enc_tkt, contents, &der_enctkt);
    if (ret)
        goto cleanup;
    ret = krb5_c_make_checksum(context, 0, &tgtkey, KRB5_KEYUSAGE_CAMMAC,
                               der_enctkt, &kdc_cksum);
    if (ret)
        goto cleanup;
    kdc_verifier.princ = NULL;
    kdc_verifier.kvno = kd->key_data_kvno;
    kdc_verifier.enctype = ENCTYPE_NULL;
    kdc_verifier.checksum = kdc_cksum;

    /* Encode the authdata and checksum it for the service verifier. */
    ret = encode_krb5_authdata(contents, &der_authdata);
    if (ret)
        goto cleanup;
    ret = krb5_c_make_checksum(context, 0, server_key, KRB5_KEYUSAGE_CAMMAC,
                               der_authdata, &svc_cksum);
    if (ret)
        goto cleanup;
    svc_verifier.princ = NULL;
    svc_verifier.kvno = 0;
    svc_verifier.enctype = ENCTYPE_NULL;
    svc_verifier.checksum = svc_cksum;

    cammac.elements = contents;
    cammac.kdc_verifier = &kdc_verifier;
    cammac.svc_verifier = &svc_verifier;
    cammac.other_verifiers = NULL;

    ret = encode_krb5_cammac(&cammac, &der_cammac);
    if (ret)
        goto cleanup;

    /* Wrap the encoded CAMMAC in an IF-RELEVANT container and return it as a
     * single-element authdata list. */
    ad.ad_type = KRB5_AUTHDATA_CAMMAC;
    ad.length = der_cammac->length;
    ad.contents = (uint8_t *)der_cammac->data;
    list[0] = &ad;
    list[1] = NULL;
    ret = krb5_encode_authdata_container(context, KRB5_AUTHDATA_IF_RELEVANT,
                                         list, cammac_out);

cleanup:
    krb5_free_data(context, der_enctkt);
    krb5_free_data(context, der_authdata);
    krb5_free_data(context, der_cammac);
    krb5_free_keyblock_contents(context, &tgtkey);
    krb5_free_checksum_contents(context, &kdc_cksum);
    krb5_free_checksum_contents(context, &svc_cksum);
    return ret;
}