Пример #1
0
static krb5_error_code
pa_data_add_pac_request(krb5_context context,
			krb5_get_init_creds_ctx *ctx,
			METHOD_DATA *md)
{
    size_t len, length;
    krb5_error_code ret;
    PA_PAC_REQUEST req;
    void *buf;

    switch (ctx->req_pac) {
    case KRB5_INIT_CREDS_TRISTATE_UNSET:
	return 0; /* don't bother */
    case KRB5_INIT_CREDS_TRISTATE_TRUE:
	req.include_pac = 1;
	break;
    case KRB5_INIT_CREDS_TRISTATE_FALSE:
	req.include_pac = 0;
    }

    ASN1_MALLOC_ENCODE(PA_PAC_REQUEST, buf, length,
		       &req, &len, ret);
    if (ret)
	return ret;
    if(len != length)
	krb5_abortx(context, "internal error in ASN.1 encoder");

    ret = krb5_padata_add(context, md, KRB5_PADATA_PA_PAC_REQUEST, buf, len);
    if (ret)
	free(buf);

    return 0;
}
Пример #2
0
static krb5_error_code
make_pa_enc_timestamp(krb5_context context, METHOD_DATA *md,
		      krb5_enctype etype, krb5_keyblock *key)
{
    PA_ENC_TS_ENC p;
    unsigned char *buf;
    size_t buf_size;
    size_t len;
    EncryptedData encdata;
    krb5_error_code ret;
    int32_t usec;
    int usec2;
    krb5_crypto crypto;

    krb5_us_timeofday (context, &p.patimestamp, &usec);
    usec2         = usec;
    p.pausec      = &usec2;

    ASN1_MALLOC_ENCODE(PA_ENC_TS_ENC, buf, buf_size, &p, &len, ret);
    if (ret)
	return ret;
    if(buf_size != len)
	krb5_abortx(context, "internal error in ASN.1 encoder");

    ret = krb5_crypto_init(context, key, 0, &crypto);
    if (ret) {
	free(buf);
	return ret;
    }
    ret = krb5_encrypt_EncryptedData(context,
				     crypto,
				     KRB5_KU_PA_ENC_TIMESTAMP,
				     buf,
				     len,
				     0,
				     &encdata);
    free(buf);
    krb5_crypto_destroy(context, crypto);
    if (ret)
	return ret;

    ASN1_MALLOC_ENCODE(EncryptedData, buf, buf_size, &encdata, &len, ret);
    free_EncryptedData(&encdata);
    if (ret)
	return ret;
    if(buf_size != len)
	krb5_abortx(context, "internal error in ASN.1 encoder");

    ret = krb5_padata_add(context, md, KRB5_PADATA_ENC_TIMESTAMP, buf, len);
    if (ret)
	free(buf);
    return ret;
}
Пример #3
0
static krb5_error_code
fast_add_cookie(kdc_request_t r, METHOD_DATA *method_data)
{
    krb5_crypto crypto = NULL;
    KDCFastCookie shell;
    krb5_error_code ret;
    krb5_data data;
    size_t size;

    memset(&shell, 0, sizeof(shell));

    r->fast.expiration = kdc_time + FAST_EXPIRATION_TIME;

    ASN1_MALLOC_ENCODE(KDCFastState, data.data, data.length, 
		       &r->fast, &size, ret);
    if (ret)
	return ret;
    heim_assert(size == data.length, "internal asn1 encoder error");

    ret = get_fastuser_crypto(r, KRB5_ENCTYPE_NULL, &crypto);
    if (ret)
	goto out;

    ret = krb5_encrypt_EncryptedData(r->context, crypto,
				     KRB5_KU_H5L_COOKIE,
				     data.data, data.length, 0,
				     &shell.cookie);
    krb5_crypto_destroy(r->context, crypto);
    if (ret)
	goto out;
    
    free(data.data);

    shell.version = "H5L1";

    ASN1_MALLOC_ENCODE(KDCFastCookie, data.data, data.length, 
		       &shell, &size, ret);
    free_EncryptedData(&shell.cookie);
    if (ret)
	goto out;
    heim_assert(size == data.length, "internal asn1 encoder error");
    
    ret = krb5_padata_add(r->context, method_data,
			  KRB5_PADATA_FX_COOKIE,
			  data.data, data.length);
 out:
    if (ret)
	free(data.data);
    return ret;
}
Пример #4
0
static krb5_error_code
get_cred_kdc(krb5_context context,
	     krb5_ccache id,
	     krb5_kdc_flags flags,
	     krb5_addresses *addresses,
	     krb5_creds *in_creds,
	     krb5_creds *krbtgt,
	     krb5_principal impersonate_principal,
	     Ticket *second_ticket,
	     krb5_creds *out_creds)
{
    TGS_REQ req;
    krb5_data enc;
    krb5_data resp;
    krb5_kdc_rep rep;
    KRB_ERROR error;
    krb5_error_code ret;
    unsigned nonce;
    krb5_keyblock *subkey = NULL;
    size_t len;
    Ticket second_ticket_data;
    METHOD_DATA padata;

    krb5_data_zero(&resp);
    krb5_data_zero(&enc);
    padata.val = NULL;
    padata.len = 0;

    krb5_generate_random_block(&nonce, sizeof(nonce));
    nonce &= 0xffffffff;

    if(flags.b.enc_tkt_in_skey && second_ticket == NULL){
	ret = decode_Ticket(in_creds->second_ticket.data,
			    in_creds->second_ticket.length,
			    &second_ticket_data, &len);
	if(ret)
	    return ret;
	second_ticket = &second_ticket_data;
    }


    if (impersonate_principal) {
	krb5_crypto crypto;
	PA_S4U2Self self;
	krb5_data data;
	void *buf;
	size_t size;

	self.name = impersonate_principal->name;
	self.realm = impersonate_principal->realm;
	self.auth = estrdup("Kerberos");
	
	ret = _krb5_s4u2self_to_checksumdata(context, &self, &data);
	if (ret) {
	    free(self.auth);
	    goto out;
	}

	ret = krb5_crypto_init(context, &krbtgt->session, 0, &crypto);
	if (ret) {
	    free(self.auth);
	    krb5_data_free(&data);
	    goto out;
	}

	ret = krb5_create_checksum(context,
				   crypto,
				   KRB5_KU_OTHER_CKSUM,
				   0,
				   data.data,
				   data.length,
				   &self.cksum);
	krb5_crypto_destroy(context, crypto);
	krb5_data_free(&data);
	if (ret) {
	    free(self.auth);
	    goto out;
	}

	ASN1_MALLOC_ENCODE(PA_S4U2Self, buf, len, &self, &size, ret);
	free(self.auth);
	free_Checksum(&self.cksum);
	if (ret)
	    goto out;
	if (len != size)
	    krb5_abortx(context, "internal asn1 error");
	
	ret = krb5_padata_add(context, &padata, KRB5_PADATA_FOR_USER, buf, len);
	if (ret)
	    goto out;
    }

    ret = init_tgs_req (context,
			id,
			addresses,
			flags,
			second_ticket,
			in_creds,
			krbtgt,
			nonce,
			&padata,
			&subkey,
			&req);
    if (ret)
	goto out;

    ASN1_MALLOC_ENCODE(TGS_REQ, enc.data, enc.length, &req, &len, ret);
    if (ret)
	goto out;
    if(enc.length != len)
	krb5_abortx(context, "internal error in ASN.1 encoder");

    /* don't free addresses */
    req.req_body.addresses = NULL;
    free_TGS_REQ(&req);

    /*
     * Send and receive
     */
    {
	krb5_sendto_ctx stctx;
	ret = krb5_sendto_ctx_alloc(context, &stctx);
	if (ret)
	    return ret;
	krb5_sendto_ctx_set_func(stctx, _krb5_kdc_retry, NULL);

	ret = krb5_sendto_context (context, stctx, &enc,
				   krbtgt->server->name.name_string.val[1],
				   &resp);
	krb5_sendto_ctx_free(context, stctx);
    }
    if(ret)
	goto out;

    memset(&rep, 0, sizeof(rep));
    if(decode_TGS_REP(resp.data, resp.length, &rep.kdc_rep, &len) == 0) {
	unsigned eflags = 0;

	ret = krb5_copy_principal(context,
				  in_creds->client,
				  &out_creds->client);
	if(ret)
	    goto out2;
	ret = krb5_copy_principal(context,
				  in_creds->server,
				  &out_creds->server);
	if(ret)
	    goto out2;
	/* this should go someplace else */
	out_creds->times.endtime = in_creds->times.endtime;

	/* XXX should do better testing */
	if (flags.b.constrained_delegation || impersonate_principal)
	    eflags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH;

	ret = _krb5_extract_ticket(context,
				   &rep,
				   out_creds,
				   &krbtgt->session,
				   NULL,
				   0,
				   &krbtgt->addresses,
				   nonce,
				   eflags,
				   decrypt_tkt_with_subkey,
				   subkey);
    out2:
	krb5_free_kdc_rep(context, &rep);
    } else if(krb5_rd_error(context, &resp, &error) == 0) {
	ret = krb5_error_from_rd_error(context, &error, in_creds);
	krb5_free_error_contents(context, &error);
    } else if(resp.length > 0 && ((char*)resp.data)[0] == 4) {
	ret = KRB5KRB_AP_ERR_V4_REPLY;
	krb5_clear_error_message(context);
    } else {
	ret = KRB5KRB_AP_ERR_MSG_TYPE;
	krb5_clear_error_message(context);
    }

out:
    if (second_ticket == &second_ticket_data)
	free_Ticket(&second_ticket_data);
    free_METHOD_DATA(&padata);
    krb5_data_free(&resp);
    krb5_data_free(&enc);
    if(subkey)
	krb5_free_keyblock(context, subkey);
    return ret;

}
Пример #5
0
krb5_error_code
_krb5_init_tgs_req(krb5_context context,
		   krb5_ccache ccache,
		   krb5_addresses *addresses,
		   krb5_kdc_flags flags,
		   krb5_const_principal impersonate_principal,
		   Ticket *second_ticket,
		   krb5_creds *in_creds,
		   krb5_creds *krbtgt,
		   unsigned nonce,
		   METHOD_DATA *padata,
		   krb5_keyblock **subkey,
		   TGS_REQ *t)
{
    krb5_auth_context ac = NULL;
    krb5_error_code ret = 0;
    
    /* inherit the forwardable/proxyable flags from the krbtgt */
    flags.b.forwardable = krbtgt->flags.b.forwardable;
    flags.b.proxiable = krbtgt->flags.b.proxiable;

    if (ccache->ops->tgt_req) {
	KERB_TGS_REQ_OUT out;
	KERB_TGS_REQ_IN in;
	
	memset(&in, 0, sizeof(in));
	memset(&out, 0, sizeof(out));

	ret = ccache->ops->tgt_req(context, ccache, &in, &out);
	if (ret)
	    return ret;

	free_KERB_TGS_REQ_OUT(&out);
	return 0;
    }


    memset(t, 0, sizeof(*t));

    if (impersonate_principal) {
	krb5_crypto crypto;
	PA_S4U2Self self;
	krb5_data data;
	void *buf;
	size_t size, len;

	self.name = impersonate_principal->name;
	self.realm = impersonate_principal->realm;
	self.auth = rk_UNCONST("Kerberos");
	
	ret = _krb5_s4u2self_to_checksumdata(context, &self, &data);
	if (ret)
	    goto fail;

	ret = krb5_crypto_init(context, &krbtgt->session, 0, &crypto);
	if (ret) {
	    krb5_data_free(&data);
	    goto fail;
	}

	ret = krb5_create_checksum(context,
				   crypto,
				   KRB5_KU_OTHER_CKSUM,
				   0,
				   data.data,
				   data.length,
				   &self.cksum);
	krb5_crypto_destroy(context, crypto);
	krb5_data_free(&data);
	if (ret)
	    goto fail;

	ASN1_MALLOC_ENCODE(PA_S4U2Self, buf, len, &self, &size, ret);
	free_Checksum(&self.cksum);
	if (ret)
	    goto fail;
	if (len != size)
	    krb5_abortx(context, "internal asn1 error");
	
	ret = krb5_padata_add(context, padata, KRB5_PADATA_FOR_USER, buf, len);
	if (ret)
	    goto fail;
    }

    t->pvno = 5;
    t->msg_type = krb_tgs_req;
    if (in_creds->session.keytype) {
	ALLOC_SEQ(&t->req_body.etype, 1);
	if(t->req_body.etype.val == NULL) {
	    ret = ENOMEM;
	    krb5_set_error_message(context, ret,
				   N_("malloc: out of memory", ""));
	    goto fail;
	}
	t->req_body.etype.val[0] = in_creds->session.keytype;
    } else {
	ret = _krb5_init_etype(context,
			       KRB5_PDU_TGS_REQUEST,
			       &t->req_body.etype.len,
			       &t->req_body.etype.val,
			       NULL);
    }
    if (ret)
	goto fail;
    t->req_body.addresses = addresses;
    t->req_body.kdc_options = flags.b;
    ret = copy_Realm(&in_creds->server->realm, &t->req_body.realm);
    if (ret)
	goto fail;
    ALLOC(t->req_body.sname, 1);
    if (t->req_body.sname == NULL) {
	ret = ENOMEM;
	krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
	goto fail;
    }

    /* some versions of some code might require that the client be
       present in TGS-REQs, but this is clearly against the spec */

    ret = copy_PrincipalName(&in_creds->server->name, t->req_body.sname);
    if (ret)
	goto fail;

    /* req_body.till should be NULL if there is no endtime specified,
       but old MIT code (like DCE secd) doesn't like that */
    ALLOC(t->req_body.till, 1);
    if(t->req_body.till == NULL){
	ret = ENOMEM;
	krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
	goto fail;
    }
    *t->req_body.till = in_creds->times.endtime;

    t->req_body.nonce = nonce;
    if(second_ticket){
	ALLOC(t->req_body.additional_tickets, 1);
	if (t->req_body.additional_tickets == NULL) {
	    ret = ENOMEM;
	    krb5_set_error_message(context, ret,
				   N_("malloc: out of memory", ""));
	    goto fail;
	}
	ALLOC_SEQ(t->req_body.additional_tickets, 1);
	if (t->req_body.additional_tickets->val == NULL) {
	    ret = ENOMEM;
	    krb5_set_error_message(context, ret,
				   N_("malloc: out of memory", ""));
	    goto fail;
	}
	ret = copy_Ticket(second_ticket, t->req_body.additional_tickets->val);
	if (ret)
	    goto fail;
    }
    ALLOC(t->padata, 1);
    if (t->padata == NULL) {
	ret = ENOMEM;
	krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
	goto fail;
    }
    ALLOC_SEQ(t->padata, 1 + padata->len);
    if (t->padata->val == NULL) {
	ret = ENOMEM;
	krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
	goto fail;
    }
    {
	size_t i;
	for (i = 0; i < padata->len; i++) {
	    ret = copy_PA_DATA(&padata->val[i], &t->padata->val[i + 1]);
	    if (ret) {
		krb5_set_error_message(context, ret,
				       N_("malloc: out of memory", ""));
		goto fail;
	    }
	}
    }

    ret = krb5_auth_con_init(context, &ac);
    if(ret)
	goto fail;

    ret = krb5_auth_con_generatelocalsubkey(context, ac, &krbtgt->session);
    if (ret)
	goto fail;

    ret = set_auth_data (context, &t->req_body, &in_creds->authdata,
			 ac->local_subkey);
    if (ret)
	goto fail;

    ret = make_pa_tgs_req(context,
			  ac,
			  &t->req_body,
			  &t->padata->val[0],
			  ccache,
			  krbtgt);
    if(ret)
	goto fail;

    ret = krb5_auth_con_getlocalsubkey(context, ac, subkey);
    if (ret)
	goto fail;

fail:
    if (ac)
	krb5_auth_con_free(context, ac);
    if (ret) {
	t->req_body.addresses = NULL;
	free_TGS_REQ (t);
    }
    return ret;
}
Пример #6
0
krb5_error_code
_kdc_pk_mk_pa_reply(krb5_context context,
		    krb5_kdc_configuration *config,
		    pk_client_params *cp,
		    const hdb_entry_ex *client,
		    krb5_enctype sessionetype,
		    const KDC_REQ *req,
		    const krb5_data *req_buffer,
		    krb5_keyblock *reply_key,
		    krb5_keyblock *sessionkey,
		    METHOD_DATA *md)
{
    krb5_error_code ret;
    void *buf = NULL;
    size_t len = 0, size = 0;
    krb5_enctype enctype;
    int pa_type;
    hx509_cert kdc_cert = NULL;
    size_t i;

    if (!config->enable_pkinit) {
	krb5_clear_error_message(context);
	return 0;
    }

    if (req->req_body.etype.len > 0) {
	for (i = 0; i < req->req_body.etype.len; i++)
	    if (krb5_enctype_valid(context, req->req_body.etype.val[i]) == 0)
		break;
	if (req->req_body.etype.len <= i) {
	    ret = KRB5KRB_ERR_GENERIC;
	    krb5_set_error_message(context, ret,
				   "No valid enctype available from client");
	    goto out;
	}
	enctype = req->req_body.etype.val[i];
    } else
	enctype = ETYPE_DES3_CBC_SHA1;

    if (cp->type == PKINIT_27) {
	PA_PK_AS_REP rep;
	const char *type, *other = "";

	memset(&rep, 0, sizeof(rep));

	pa_type = KRB5_PADATA_PK_AS_REP;

	if (cp->keyex == USE_RSA) {
	    ContentInfo info;

	    type = "enckey";

	    rep.element = choice_PA_PK_AS_REP_encKeyPack;

	    ret = krb5_generate_random_keyblock(context, enctype,
						&cp->reply_key);
	    if (ret) {
		free_PA_PK_AS_REP(&rep);
		goto out;
	    }
	    ret = pk_mk_pa_reply_enckey(context,
					config,
					cp,
					req,
					req_buffer,
					&cp->reply_key,
					&info,
					&kdc_cert);
	    if (ret) {
		free_PA_PK_AS_REP(&rep);
		goto out;
	    }
	    ASN1_MALLOC_ENCODE(ContentInfo, rep.u.encKeyPack.data,
			       rep.u.encKeyPack.length, &info, &size,
			       ret);
	    free_ContentInfo(&info);
	    if (ret) {
		krb5_set_error_message(context, ret, "encoding of Key ContentInfo "
				       "failed %d", ret);
		free_PA_PK_AS_REP(&rep);
		goto out;
	    }
	    if (rep.u.encKeyPack.length != size)
		krb5_abortx(context, "Internal ASN.1 encoder error");

	    ret = krb5_generate_random_keyblock(context, sessionetype,
						sessionkey);
	    if (ret) {
		free_PA_PK_AS_REP(&rep);
		goto out;
	    }

	} else {
	    ContentInfo info;

	    switch (cp->keyex) {
	    case USE_DH: type = "dh"; break;
	    case USE_ECDH: type = "ecdh"; break;
	    default: krb5_abortx(context, "unknown keyex"); break;
	    }

	    if (cp->dh_group_name)
		other = cp->dh_group_name;

	    rep.element = choice_PA_PK_AS_REP_dhInfo;

	    ret = generate_dh_keyblock(context, cp, enctype);
	    if (ret)
		return ret;

	    ret = pk_mk_pa_reply_dh(context, config,
				    cp,
				    &info,
				    &kdc_cert);
	    if (ret) {
		free_PA_PK_AS_REP(&rep);
		krb5_set_error_message(context, ret,
				       "create pa-reply-dh "
				       "failed %d", ret);
		goto out;
	    }

	    ASN1_MALLOC_ENCODE(ContentInfo, rep.u.dhInfo.dhSignedData.data,
			       rep.u.dhInfo.dhSignedData.length, &info, &size,
			       ret);
	    free_ContentInfo(&info);
	    if (ret) {
		krb5_set_error_message(context, ret,
				       "encoding of Key ContentInfo "
				       "failed %d", ret);
		free_PA_PK_AS_REP(&rep);
		goto out;
	    }
	    if (rep.u.encKeyPack.length != size)
		krb5_abortx(context, "Internal ASN.1 encoder error");

	    /* generate the session key using the method from RFC6112 */
	    {
		krb5_keyblock kdc_contribution_key;
		krb5_crypto reply_crypto;
		krb5_crypto kdccont_crypto;
		krb5_data p1 = { strlen("PKINIT"), "PKINIT"};
		krb5_data p2 = { strlen("KEYEXCHANGE"), "KEYEXCHANGE"};
		void *kckdata;
		size_t kcklen;
		EncryptedData kx;
		void *kxdata;
		size_t kxlen;

		ret = krb5_generate_random_keyblock(context, sessionetype,
						&kdc_contribution_key);
		if (ret) {
		    free_PA_PK_AS_REP(&rep);
		    goto out;
		}
		ret = krb5_crypto_init(context, &cp->reply_key, enctype, &reply_crypto);
		if (ret) {
		    krb5_free_keyblock_contents(context, &kdc_contribution_key);
		    free_PA_PK_AS_REP(&rep);
		    goto out;
		}
		ret = krb5_crypto_init(context, &kdc_contribution_key, sessionetype, &kdccont_crypto);
		if (ret) {
		    krb5_crypto_destroy(context, reply_crypto);
		    krb5_free_keyblock_contents(context, &kdc_contribution_key);
		    free_PA_PK_AS_REP(&rep);
		    goto out;
		}
		/* KRB-FX-CF2 */
		ret = krb5_crypto_fx_cf2(context, kdccont_crypto, reply_crypto,
					 &p1, &p2, sessionetype, sessionkey);
		krb5_crypto_destroy(context, kdccont_crypto);
		if (ret) {
		    krb5_crypto_destroy(context, reply_crypto);
		    krb5_free_keyblock_contents(context, &kdc_contribution_key);
		    free_PA_PK_AS_REP(&rep);
		    goto out;
		}
		ASN1_MALLOC_ENCODE(EncryptionKey, kckdata, kcklen,
				   &kdc_contribution_key, &size, ret);
		krb5_free_keyblock_contents(context, &kdc_contribution_key);
		if (ret) {
		    krb5_set_error_message(context, ret, "encoding of PKINIT-KX Key failed %d", ret);
		    krb5_crypto_destroy(context, reply_crypto);
		    free_PA_PK_AS_REP(&rep);
		    goto out;
		}
		if (kcklen != size)
		    krb5_abortx(context, "Internal ASN.1 encoder error");
		ret = krb5_encrypt_EncryptedData(context, reply_crypto, KRB5_KU_PA_PKINIT_KX,
					kckdata, kcklen, 0, &kx);
		krb5_crypto_destroy(context, reply_crypto);
		free(kckdata);
		if (ret) {
		    free_PA_PK_AS_REP(&rep);
		    goto out;
		}
		ASN1_MALLOC_ENCODE(EncryptedData, kxdata, kxlen,
				   &kx, &size, ret);
		free_EncryptedData(&kx);
		if (ret) {
		    krb5_set_error_message(context, ret, "encoding of PKINIT-KX failed %d", ret);
		    free_PA_PK_AS_REP(&rep);
		    goto out;
		}
		if (kxlen != size)
		    krb5_abortx(context, "Internal ASN.1 encoder error");
		/* Add PA-PKINIT-KX */
		ret = krb5_padata_add(context, md, KRB5_PADATA_PKINIT_KX, kxdata, kxlen);
		if (ret) {
		    krb5_set_error_message(context, ret,
					   "Failed adding PKINIT-KX %d", ret);
		    free(buf);
		    goto out;
		}
	    }
	}

#define use_btmm_with_enckey 0
	if (use_btmm_with_enckey && rep.element == choice_PA_PK_AS_REP_encKeyPack) {
	    PA_PK_AS_REP_BTMM btmm;
	    heim_any any;

	    any.data = rep.u.encKeyPack.data;
	    any.length = rep.u.encKeyPack.length;

	    btmm.dhSignedData = NULL;
	    btmm.encKeyPack = &any;

	    ASN1_MALLOC_ENCODE(PA_PK_AS_REP_BTMM, buf, len, &btmm, &size, ret);
	} else {
	    ASN1_MALLOC_ENCODE(PA_PK_AS_REP, buf, len, &rep, &size, ret);
	}

	free_PA_PK_AS_REP(&rep);
	if (ret) {
	    krb5_set_error_message(context, ret,
				   "encode PA-PK-AS-REP failed %d", ret);
	    goto out;
	}
	if (len != size)
	    krb5_abortx(context, "Internal ASN.1 encoder error");

	kdc_log(context, config, 0, "PK-INIT using %s %s", type, other);

    } else if (cp->type == PKINIT_WIN2K) {
	PA_PK_AS_REP_Win2k rep;
	ContentInfo info;

	if (cp->keyex != USE_RSA) {
	    ret = KRB5KRB_ERR_GENERIC;
	    krb5_set_error_message(context, ret,
				   "Windows PK-INIT doesn't support DH");
	    goto out;
	}

	memset(&rep, 0, sizeof(rep));

	pa_type = KRB5_PADATA_PK_AS_REP_19;
	rep.element = choice_PA_PK_AS_REP_Win2k_encKeyPack;

	ret = krb5_generate_random_keyblock(context, enctype,
					    &cp->reply_key);
	if (ret) {
	    free_PA_PK_AS_REP_Win2k(&rep);
	    goto out;
	}
	ret = pk_mk_pa_reply_enckey(context,
				    config,
				    cp,
				    req,
				    req_buffer,
				    &cp->reply_key,
				    &info,
				    &kdc_cert);
	if (ret) {
	    free_PA_PK_AS_REP_Win2k(&rep);
	    goto out;
	}
	ASN1_MALLOC_ENCODE(ContentInfo, rep.u.encKeyPack.data,
			   rep.u.encKeyPack.length, &info, &size,
			   ret);
	free_ContentInfo(&info);
	if (ret) {
	    krb5_set_error_message(context, ret, "encoding of Key ContentInfo "
				  "failed %d", ret);
	    free_PA_PK_AS_REP_Win2k(&rep);
	    goto out;
	}
	if (rep.u.encKeyPack.length != size)
	    krb5_abortx(context, "Internal ASN.1 encoder error");

	ASN1_MALLOC_ENCODE(PA_PK_AS_REP_Win2k, buf, len, &rep, &size, ret);
	free_PA_PK_AS_REP_Win2k(&rep);
	if (ret) {
	    krb5_set_error_message(context, ret,
				  "encode PA-PK-AS-REP-Win2k failed %d", ret);
	    goto out;
	}
	if (len != size)
	    krb5_abortx(context, "Internal ASN.1 encoder error");

	ret = krb5_generate_random_keyblock(context, sessionetype,
					    sessionkey);
	if (ret) {
	    free(buf);
	    goto out;
	}

    } else
	krb5_abortx(context, "PK-INIT internal error");


    ret = krb5_padata_add(context, md, pa_type, buf, len);
    if (ret) {
	krb5_set_error_message(context, ret,
			       "Failed adding PA-PK-AS-REP %d", ret);
	free(buf);
	goto out;
    }

    if (config->pkinit_kdc_ocsp_file) {

	if (ocsp.expire == 0 && ocsp.next_update > kdc_time) {
	    struct stat sb;
	    int fd;

	    krb5_data_free(&ocsp.data);

	    ocsp.expire = 0;
	    ocsp.next_update = kdc_time + 60 * 5;

	    fd = open(config->pkinit_kdc_ocsp_file, O_RDONLY);
	    if (fd < 0) {
		kdc_log(context, config, 0,
			"PK-INIT failed to open ocsp data file %d", errno);
		goto out_ocsp;
	    }
	    ret = fstat(fd, &sb);
	    if (ret) {
		ret = errno;
		close(fd);
		kdc_log(context, config, 0,
			"PK-INIT failed to stat ocsp data %d", ret);
		goto out_ocsp;
	    }

	    ret = krb5_data_alloc(&ocsp.data, sb.st_size);
	    if (ret) {
		close(fd);
		kdc_log(context, config, 0,
			"PK-INIT failed to stat ocsp data %d", ret);
		goto out_ocsp;
	    }
	    ocsp.data.length = sb.st_size;
	    ret = read(fd, ocsp.data.data, sb.st_size);
	    close(fd);
	    if (ret != sb.st_size) {
		kdc_log(context, config, 0,
			"PK-INIT failed to read ocsp data %d", errno);
		goto out_ocsp;
	    }

	    ret = hx509_ocsp_verify(context->hx509ctx,
				    kdc_time,
				    kdc_cert,
				    0,
				    ocsp.data.data, ocsp.data.length,
				    &ocsp.expire);
	    if (ret) {
		kdc_log(context, config, 0,
			"PK-INIT failed to verify ocsp data %d", ret);
		krb5_data_free(&ocsp.data);
		ocsp.expire = 0;
	    } else if (ocsp.expire > 180) {
		ocsp.expire -= 180; /* refetch the ocsp before it expire */
		ocsp.next_update = ocsp.expire;
	    } else {
		ocsp.next_update = kdc_time;
	    }
	out_ocsp:
	    ret = 0;
	}

	if (ocsp.expire != 0 && ocsp.expire > kdc_time) {

	    ret = krb5_padata_add(context, md,
				  KRB5_PADATA_PA_PK_OCSP_RESPONSE,
				  ocsp.data.data, ocsp.data.length);
	    if (ret) {
		krb5_set_error_message(context, ret,
				       "Failed adding OCSP response %d", ret);
		goto out;
	    }
	}
    }

out:
    if (kdc_cert)
	hx509_cert_free(kdc_cert);

    if (ret == 0)
	ret = krb5_copy_keyblock_contents(context, &cp->reply_key, reply_key);
    return ret;
}
Пример #7
0
krb5_error_code
_kdc_fast_mk_error(krb5_context context,
		   kdc_request_t r,
		   METHOD_DATA *error_method,
		   krb5_crypto armor_crypto,
		   const KDC_REQ_BODY *req_body,
		   krb5_error_code outer_error,
		   const char *e_text,
		   krb5_principal error_server,
		   const PrincipalName *error_client_name,
		   const Realm *error_client_realm,
		   time_t *csec, int *cusec,
		   krb5_data *error_msg)
{
    krb5_error_code ret;
    krb5_data e_data;
    size_t size;

    krb5_data_zero(&e_data);

    if (armor_crypto) {
	PA_FX_FAST_REPLY fxfastrep;
	KrbFastResponse fastrep;

	memset(&fxfastrep, 0, sizeof(fxfastrep));
	memset(&fastrep, 0, sizeof(fastrep));
	    
	/* first add the KRB-ERROR to the fast errors */

	ret = krb5_mk_error_ext(context,
				outer_error,
				e_text,
				NULL,
				error_server,
				error_client_name,
				error_client_realm,
				NULL,
				NULL,
				&e_data);
	if (ret)
	    return ret;

	ret = krb5_padata_add(context, error_method,
			      KRB5_PADATA_FX_ERROR,
			      e_data.data, e_data.length);
	if (ret) {
	    krb5_data_free(&e_data);
	    return ret;
	}

	if (/* hide_principal */ 0) {
	    error_client_name = NULL;
	    error_client_realm = NULL;
	    error_server = NULL;
	    e_text = NULL;
	}

	if (r)
	    ret = fast_add_cookie(r, error_method);
	else
	    ret = krb5_padata_add(context, error_method,
				  KRB5_PADATA_FX_COOKIE,
				  NULL, 0);
	if (ret) {
	    kdc_log(r->context, r->config, 0, "failed to add fast cookie with: %d", ret);
	    free_METHOD_DATA(error_method);
	    return ret;
	}
	
	ret = _kdc_fast_mk_response(context, armor_crypto,
				    error_method, NULL, NULL, 
				    req_body->nonce, &e_data);
	free_METHOD_DATA(error_method);
	if (ret)
	    return ret;
	
	ret = krb5_padata_add(context, error_method,
			      KRB5_PADATA_FX_FAST,
			      e_data.data, e_data.length);
	if (ret)
	    return ret;
    }

    if (error_method && error_method->len) {
	ASN1_MALLOC_ENCODE(METHOD_DATA, e_data.data, e_data.length, 
			   error_method, &size, ret);
	if (ret)
	    return ret;
	if (e_data.length != size)
	    krb5_abortx(context, "internal asn.1 error");
    }
    
    ret = krb5_mk_error_ext(context,
			    outer_error,
			    e_text,
			    (e_data.length ? &e_data : NULL),
			    error_server,
			    error_client_name,
			    error_client_realm,
			    csec,
			    cusec,
			    error_msg);
    krb5_data_free(&e_data);

    return ret;
}
Пример #8
0
krb5_error_code
_kdc_pk_mk_pa_reply(krb5_context context,
		    krb5_kdc_configuration *config,
		    pk_client_params *client_params,
		    const hdb_entry_ex *client,
		    const KDC_REQ *req,
		    const krb5_data *req_buffer,
		    krb5_keyblock **reply_key,
		    METHOD_DATA *md)
{
    krb5_error_code ret;
    void *buf;
    size_t len, size;
    krb5_enctype enctype;
    int pa_type;
    hx509_cert kdc_cert = NULL;
    int i;

    if (!config->enable_pkinit) {
	krb5_clear_error_message(context);
	return 0;
    }

    if (req->req_body.etype.len > 0) {
	for (i = 0; i < req->req_body.etype.len; i++)
	    if (krb5_enctype_valid(context, req->req_body.etype.val[i]) == 0)
		break;
	if (req->req_body.etype.len <= i) {
	    ret = KRB5KRB_ERR_GENERIC;
	    krb5_set_error_message(context, ret,
				   "No valid enctype available from client");
	    goto out;
	}	
	enctype = req->req_body.etype.val[i];
    } else
	enctype = ETYPE_DES3_CBC_SHA1;

    if (client_params->type == PKINIT_27) {
	PA_PK_AS_REP rep;
	const char *type, *other = "";

	memset(&rep, 0, sizeof(rep));

	pa_type = KRB5_PADATA_PK_AS_REP;

	if (client_params->dh == NULL) {
	    ContentInfo info;

	    type = "enckey";

	    rep.element = choice_PA_PK_AS_REP_encKeyPack;

	    ret = krb5_generate_random_keyblock(context, enctype,
						&client_params->reply_key);
	    if (ret) {
		free_PA_PK_AS_REP(&rep);
		goto out;
	    }
	    ret = pk_mk_pa_reply_enckey(context,
					config,
					client_params,
					req,
					req_buffer,
					&client_params->reply_key,
					&info);
	    if (ret) {
		free_PA_PK_AS_REP(&rep);
		goto out;
	    }
	    ASN1_MALLOC_ENCODE(ContentInfo, rep.u.encKeyPack.data,
			       rep.u.encKeyPack.length, &info, &size,
			       ret);
	    free_ContentInfo(&info);
	    if (ret) {
		krb5_set_error_message(context, ret, "encoding of Key ContentInfo "
				       "failed %d", ret);
		free_PA_PK_AS_REP(&rep);
		goto out;
	    }
	    if (rep.u.encKeyPack.length != size)
		krb5_abortx(context, "Internal ASN.1 encoder error");

	} else {
	    ContentInfo info;

	    type = "dh";
	    if (client_params->dh_group_name)
		other = client_params->dh_group_name;

	    rep.element = choice_PA_PK_AS_REP_dhInfo;

	    ret = generate_dh_keyblock(context, client_params, enctype,
				       &client_params->reply_key);
	    if (ret)
		return ret;

	    ret = pk_mk_pa_reply_dh(context, client_params->dh,
				    client_params,
				    &client_params->reply_key,
				    &info,
				    &kdc_cert);

	    ASN1_MALLOC_ENCODE(ContentInfo, rep.u.dhInfo.dhSignedData.data,
			       rep.u.dhInfo.dhSignedData.length, &info, &size,
			       ret);
	    free_ContentInfo(&info);
	    if (ret) {
		krb5_set_error_message(context, ret, "encoding of Key ContentInfo "
				       "failed %d", ret);
		free_PA_PK_AS_REP(&rep);
		goto out;
	    }
	    if (rep.u.encKeyPack.length != size)
		krb5_abortx(context, "Internal ASN.1 encoder error");

	}
	if (ret) {
	    free_PA_PK_AS_REP(&rep);
	    goto out;
	}

	ASN1_MALLOC_ENCODE(PA_PK_AS_REP, buf, len, &rep, &size, ret);
	free_PA_PK_AS_REP(&rep);
	if (ret) {
	    krb5_set_error_message(context, ret, "encode PA-PK-AS-REP failed %d",
				   ret);
	    goto out;
	}
	if (len != size)
	    krb5_abortx(context, "Internal ASN.1 encoder error");

	kdc_log(context, config, 0, "PK-INIT using %s %s", type, other);

    } else if (client_params->type == PKINIT_WIN2K) {
	PA_PK_AS_REP_Win2k rep;
	ContentInfo info;

	if (client_params->dh) {
	    ret = KRB5KRB_ERR_GENERIC;
	    krb5_set_error_message(context, ret, "Windows PK-INIT doesn't support DH");
	    goto out;
	}

	memset(&rep, 0, sizeof(rep));

	pa_type = KRB5_PADATA_PK_AS_REP_19;
	rep.element = choice_PA_PK_AS_REP_encKeyPack;

	ret = krb5_generate_random_keyblock(context, enctype,
					    &client_params->reply_key);
	if (ret) {
	    free_PA_PK_AS_REP_Win2k(&rep);
	    goto out;
	}
	ret = pk_mk_pa_reply_enckey(context,
				    config,
				    client_params,
				    req,
				    req_buffer,
				    &client_params->reply_key,
				    &info);
	if (ret) {
	    free_PA_PK_AS_REP_Win2k(&rep);
	    goto out;
	}
	ASN1_MALLOC_ENCODE(ContentInfo, rep.u.encKeyPack.data,
			   rep.u.encKeyPack.length, &info, &size,
			   ret);
	free_ContentInfo(&info);
	if (ret) {
	    krb5_set_error_message(context, ret, "encoding of Key ContentInfo "
				  "failed %d", ret);
	    free_PA_PK_AS_REP_Win2k(&rep);
	    goto out;
	}
	if (rep.u.encKeyPack.length != size)
	    krb5_abortx(context, "Internal ASN.1 encoder error");

	ASN1_MALLOC_ENCODE(PA_PK_AS_REP_Win2k, buf, len, &rep, &size, ret);
	free_PA_PK_AS_REP_Win2k(&rep);
	if (ret) {
	    krb5_set_error_message(context, ret,
				  "encode PA-PK-AS-REP-Win2k failed %d", ret);
	    goto out;
	}
	if (len != size)
	    krb5_abortx(context, "Internal ASN.1 encoder error");

    } else
	krb5_abortx(context, "PK-INIT internal error");


    ret = krb5_padata_add(context, md, pa_type, buf, len);
    if (ret) {
	krb5_set_error_message(context, ret, "failed adding PA-PK-AS-REP %d", ret);
	free(buf);
	goto out;
    }

    if (config->pkinit_kdc_ocsp_file) {

	if (ocsp.expire == 0 && ocsp.next_update > kdc_time) {
	    struct stat sb;
	    int fd;

	    krb5_data_free(&ocsp.data);

	    ocsp.expire = 0;
	    ocsp.next_update = kdc_time + 60 * 5;

	    fd = open(config->pkinit_kdc_ocsp_file, O_RDONLY);
	    if (fd < 0) {
		kdc_log(context, config, 0,
			"PK-INIT failed to open ocsp data file %d", errno);
		goto out_ocsp;
	    }
	    ret = fstat(fd, &sb);
	    if (ret) {
		ret = errno;
		close(fd);
		kdc_log(context, config, 0,
			"PK-INIT failed to stat ocsp data %d", ret);
		goto out_ocsp;
	    }
	
	    ret = krb5_data_alloc(&ocsp.data, sb.st_size);
	    if (ret) {
		close(fd);
		kdc_log(context, config, 0,
			"PK-INIT failed to stat ocsp data %d", ret);
		goto out_ocsp;
	    }
	    ocsp.data.length = sb.st_size;
	    ret = read(fd, ocsp.data.data, sb.st_size);
	    close(fd);
	    if (ret != sb.st_size) {
		kdc_log(context, config, 0,
			"PK-INIT failed to read ocsp data %d", errno);
		goto out_ocsp;
	    }

	    ret = hx509_ocsp_verify(kdc_identity->hx509ctx,
				    kdc_time,
				    kdc_cert,
				    0,
				    ocsp.data.data, ocsp.data.length,
				    &ocsp.expire);
	    if (ret) {
		kdc_log(context, config, 0,
			"PK-INIT failed to verify ocsp data %d", ret);
		krb5_data_free(&ocsp.data);
		ocsp.expire = 0;
	    } else if (ocsp.expire > 180) {
		ocsp.expire -= 180; /* refetch the ocsp before it expire */
		ocsp.next_update = ocsp.expire;
	    } else {
		ocsp.next_update = kdc_time;
	    }
	out_ocsp:
	    ret = 0;
	}

	if (ocsp.expire != 0 && ocsp.expire > kdc_time) {

	    ret = krb5_padata_add(context, md,
				  KRB5_PADATA_PA_PK_OCSP_RESPONSE,
				  ocsp.data.data, ocsp.data.length);
	    if (ret) {
		krb5_set_error_message(context, ret,
				       "Failed adding OCSP response %d", ret);
		goto out;
	    }
	}
    }

out:
    if (kdc_cert)
	hx509_cert_free(kdc_cert);

    if (ret == 0)
	*reply_key = &client_params->reply_key;
    return ret;
}