Exemple #1
0
static krb5_error_code
pk_mk_pa_reply_dh(krb5_context context,
		  krb5_kdc_configuration *config,
      		  pk_client_params *cp,
		  ContentInfo *content_info,
		  hx509_cert *kdc_cert)
{
    KDCDHKeyInfo dh_info;
    krb5_data signed_data, buf;
    ContentInfo contentinfo;
    krb5_error_code ret;
    hx509_cert cert;
    hx509_query *q;
    size_t size = 0;

    memset(&contentinfo, 0, sizeof(contentinfo));
    memset(&dh_info, 0, sizeof(dh_info));
    krb5_data_zero(&signed_data);
    krb5_data_zero(&buf);

    *kdc_cert = NULL;

    if (cp->keyex == USE_DH) {
	DH *kdc_dh = cp->u.dh.key;
	heim_integer i;

	ret = BN_to_integer(context, kdc_dh->pub_key, &i);
	if (ret)
	    return ret;

	ASN1_MALLOC_ENCODE(DHPublicKey, buf.data, buf.length, &i, &size, ret);
	der_free_heim_integer(&i);
	if (ret) {
	    krb5_set_error_message(context, ret, "ASN.1 encoding of "
				   "DHPublicKey failed (%d)", ret);
	    return ret;
	}
	if (buf.length != size)
	    krb5_abortx(context, "Internal ASN.1 encoder error");

	dh_info.subjectPublicKey.length = buf.length * 8;
	dh_info.subjectPublicKey.data = buf.data;
	krb5_data_zero(&buf);
    } else if (cp->keyex == USE_ECDH) {
        unsigned char *p;
        ret = _kdc_serialize_ecdh_key(context, cp->u.ecdh.key, &p,
                                      &dh_info.subjectPublicKey.length);
        dh_info.subjectPublicKey.data = p;
        if (ret)
            goto out;
    } else
	krb5_abortx(context, "no keyex selected ?");


    dh_info.nonce = cp->nonce;

    ASN1_MALLOC_ENCODE(KDCDHKeyInfo, buf.data, buf.length, &dh_info, &size,
		       ret);
    if (ret) {
	krb5_set_error_message(context, ret, "ASN.1 encoding of "
			       "KdcDHKeyInfo failed (%d)", ret);
	goto out;
    }
    if (buf.length != size)
	krb5_abortx(context, "Internal ASN.1 encoder error");

    /*
     * Create the SignedData structure and sign the KdcDHKeyInfo
     * filled in above
     */

    ret = hx509_query_alloc(context->hx509ctx, &q);
    if (ret)
	goto out;

    hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
    if (config->pkinit_kdc_friendly_name)
	hx509_query_match_friendly_name(q, config->pkinit_kdc_friendly_name);

    ret = hx509_certs_find(context->hx509ctx,
			   kdc_identity->certs,
			   q,
			   &cert);
    hx509_query_free(context->hx509ctx, q);
    if (ret)
	goto out;

    ret = hx509_cms_create_signed_1(context->hx509ctx,
				    0,
				    &asn1_oid_id_pkdhkeydata,
				    buf.data,
				    buf.length,
				    NULL,
				    cert,
				    cp->peer,
				    cp->client_anchors,
				    kdc_identity->certpool,
				    &signed_data);
    if (ret) {
	kdc_log(context, config, 0, "Failed signing the DH* reply: %d", ret);
	goto out;
    }
    *kdc_cert = cert;

    ret = _krb5_pk_mk_ContentInfo(context,
				  &signed_data,
				  &asn1_oid_id_pkcs7_signedData,
				  content_info);
    if (ret)
	goto out;

 out:
    if (ret && *kdc_cert) {
	hx509_cert_free(*kdc_cert);
	*kdc_cert = NULL;
    }

    krb5_data_free(&buf);
    krb5_data_free(&signed_data);
    free_KDCDHKeyInfo(&dh_info);

    return ret;
}
Exemple #2
0
krb5_error_code
_kdc_pk_rd_padata(krb5_context context,
		  krb5_kdc_configuration *config,
		  const KDC_REQ *req,
		  const PA_DATA *pa,
		  hdb_entry_ex *client,
		  pk_client_params **ret_params)
{
    pk_client_params *cp;
    krb5_error_code ret;
    heim_oid eContentType = { 0, NULL }, contentInfoOid = { 0, NULL };
    krb5_data eContent = { 0, NULL };
    krb5_data signed_content = { 0, NULL };
    const char *type = "unknown type";
    hx509_certs trust_anchors;
    int have_data = 0;
    const HDB_Ext_PKINIT_cert *pc;

    *ret_params = NULL;

    if (!config->enable_pkinit) {
	kdc_log(context, config, 0, "PK-INIT request but PK-INIT not enabled");
	krb5_clear_error_message(context);
	return 0;
    }

    cp = calloc(1, sizeof(*cp));
    if (cp == NULL) {
	krb5_clear_error_message(context);
	ret = ENOMEM;
	goto out;
    }

    ret = hx509_certs_init(context->hx509ctx,
			   "MEMORY:trust-anchors",
			   0, NULL, &trust_anchors);
    if (ret) {
	krb5_set_error_message(context, ret, "failed to create trust anchors");
	goto out;
    }

    ret = hx509_certs_merge(context->hx509ctx, trust_anchors,
			    kdc_identity->anchors);
    if (ret) {
	hx509_certs_free(&trust_anchors);
	krb5_set_error_message(context, ret, "failed to create verify context");
	goto out;
    }

    /* Add any registered certificates for this client as trust anchors */
    ret = hdb_entry_get_pkinit_cert(&client->entry, &pc);
    if (ret == 0 && pc != NULL) {
	hx509_cert cert;
	unsigned int i;

	for (i = 0; i < pc->len; i++) {
	    cert = hx509_cert_init_data(context->hx509ctx,
					pc->val[i].cert.data,
					pc->val[i].cert.length,
					NULL);
	    if (cert == NULL)
		continue;
	    hx509_certs_add(context->hx509ctx, trust_anchors, cert);
	    hx509_cert_free(cert);
	}
    }

    ret = hx509_verify_init_ctx(context->hx509ctx, &cp->verify_ctx);
    if (ret) {
	hx509_certs_free(&trust_anchors);
	krb5_set_error_message(context, ret, "failed to create verify context");
	goto out;
    }

    hx509_verify_set_time(cp->verify_ctx, kdc_time);
    hx509_verify_attach_anchors(cp->verify_ctx, trust_anchors);
    hx509_certs_free(&trust_anchors);

    if (config->pkinit_allow_proxy_certs)
	hx509_verify_set_proxy_certificate(cp->verify_ctx, 1);

    if (pa->padata_type == KRB5_PADATA_PK_AS_REQ_WIN) {
	PA_PK_AS_REQ_Win2k r;

	type = "PK-INIT-Win2k";

	if (_kdc_is_anon_request(&req->req_body)) {
	    ret = KRB5_KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED;
	    krb5_set_error_message(context, ret,
				   "Anon not supported in RSA mode");
	    goto out;
	}

	ret = decode_PA_PK_AS_REQ_Win2k(pa->padata_value.data,
					pa->padata_value.length,
					&r,
					NULL);
	if (ret) {
	    krb5_set_error_message(context, ret, "Can't decode "
				   "PK-AS-REQ-Win2k: %d", ret);
	    goto out;
	}

	ret = hx509_cms_unwrap_ContentInfo(&r.signed_auth_pack,
					   &contentInfoOid,
					   &signed_content,
					   &have_data);
	free_PA_PK_AS_REQ_Win2k(&r);
	if (ret) {
	    krb5_set_error_message(context, ret,
				   "Can't unwrap ContentInfo(win): %d", ret);
	    goto out;
	}

    } else if (pa->padata_type == KRB5_PADATA_PK_AS_REQ) {
	PA_PK_AS_REQ r;

	type = "PK-INIT-IETF";

	ret = decode_PA_PK_AS_REQ(pa->padata_value.data,
				  pa->padata_value.length,
				  &r,
				  NULL);
	if (ret) {
	    krb5_set_error_message(context, ret,
				   "Can't decode PK-AS-REQ: %d", ret);
	    goto out;
	}

	/* XXX look at r.kdcPkId */
	if (r.trustedCertifiers) {
	    ExternalPrincipalIdentifiers *edi = r.trustedCertifiers;
	    unsigned int i, maxedi;

	    ret = hx509_certs_init(context->hx509ctx,
				   "MEMORY:client-anchors",
				   0, NULL,
				   &cp->client_anchors);
	    if (ret) {
		krb5_set_error_message(context, ret,
				       "Can't allocate client anchors: %d",
				       ret);
		goto out;

	    }
	    /*
	     * If the client sent more then 10 EDI, don't bother
	     * looking more then 10 of performance reasons.
	     */
	    maxedi = edi->len;
	    if (maxedi > 10)
		maxedi = 10;
	    for (i = 0; i < maxedi; i++) {
		IssuerAndSerialNumber iasn;
		hx509_query *q;
		hx509_cert cert;
		size_t size;

		if (edi->val[i].issuerAndSerialNumber == NULL)
		    continue;

		ret = hx509_query_alloc(context->hx509ctx, &q);
		if (ret) {
		    krb5_set_error_message(context, ret,
					  "Failed to allocate hx509_query");
		    goto out;
		}

		ret = decode_IssuerAndSerialNumber(edi->val[i].issuerAndSerialNumber->data,
						   edi->val[i].issuerAndSerialNumber->length,
						   &iasn,
						   &size);
		if (ret) {
		    hx509_query_free(context->hx509ctx, q);
		    continue;
		}
		ret = hx509_query_match_issuer_serial(q, &iasn.issuer, &iasn.serialNumber);
		free_IssuerAndSerialNumber(&iasn);
		if (ret) {
		    hx509_query_free(context->hx509ctx, q);
		    continue;
		}

		ret = hx509_certs_find(context->hx509ctx,
				       kdc_identity->certs,
				       q,
				       &cert);
		hx509_query_free(context->hx509ctx, q);
		if (ret)
		    continue;
		hx509_certs_add(context->hx509ctx,
				cp->client_anchors, cert);
		hx509_cert_free(cert);
	    }
	}

	ret = hx509_cms_unwrap_ContentInfo(&r.signedAuthPack,
					   &contentInfoOid,
					   &signed_content,
					   &have_data);
	free_PA_PK_AS_REQ(&r);
	if (ret) {
	    krb5_set_error_message(context, ret,
				   "Can't unwrap ContentInfo: %d", ret);
	    goto out;
	}

    } else {
	krb5_clear_error_message(context);
	ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
	goto out;
    }

    ret = der_heim_oid_cmp(&contentInfoOid, &asn1_oid_id_pkcs7_signedData);
    if (ret != 0) {
	ret = KRB5KRB_ERR_GENERIC;
	krb5_set_error_message(context, ret,
			       "PK-AS-REQ-Win2k invalid content type oid");
	goto out;
    }

    if (!have_data) {
	ret = KRB5KRB_ERR_GENERIC;
	krb5_set_error_message(context, ret,
			      "PK-AS-REQ-Win2k no signed auth pack");
	goto out;
    }

    {
	hx509_certs signer_certs;
	int flags = HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH; /* BTMM */

	if (_kdc_is_anon_request(&req->req_body))
	    flags |= HX509_CMS_VS_ALLOW_ZERO_SIGNER;

	ret = hx509_cms_verify_signed(context->hx509ctx,
				      cp->verify_ctx,
				      flags,
				      signed_content.data,
				      signed_content.length,
				      NULL,
				      kdc_identity->certpool,
				      &eContentType,
				      &eContent,
				      &signer_certs);
	if (ret) {
	    char *s = hx509_get_error_string(context->hx509ctx, ret);
	    krb5_warnx(context, "PKINIT: failed to verify signature: %s: %d",
		       s, ret);
	    free(s);
	    goto out;
	}

	if (signer_certs) {
	    ret = hx509_get_one_cert(context->hx509ctx, signer_certs,
				     &cp->cert);
	    hx509_certs_free(&signer_certs);
	}
	if (ret)
	    goto out;
    }

    /* Signature is correct, now verify the signed message */
    if (der_heim_oid_cmp(&eContentType, &asn1_oid_id_pkcs7_data) != 0 &&
	der_heim_oid_cmp(&eContentType, &asn1_oid_id_pkauthdata) != 0)
    {
	ret = KRB5_BADMSGTYPE;
	krb5_set_error_message(context, ret, "got wrong oid for pkauthdata");
	goto out;
    }

    if (pa->padata_type == KRB5_PADATA_PK_AS_REQ_WIN) {
	AuthPack_Win2k ap;

	ret = decode_AuthPack_Win2k(eContent.data,
				    eContent.length,
				    &ap,
				    NULL);
	if (ret) {
	    krb5_set_error_message(context, ret,
				   "Can't decode AuthPack: %d", ret);
	    goto out;
	}

	ret = pk_check_pkauthenticator_win2k(context,
					     &ap.pkAuthenticator,
					     req);
	if (ret) {
	    free_AuthPack_Win2k(&ap);
	    goto out;
	}

	cp->type = PKINIT_WIN2K;
	cp->nonce = ap.pkAuthenticator.nonce;

	if (ap.clientPublicValue) {
	    ret = KRB5KRB_ERR_GENERIC;
	    krb5_set_error_message(context, ret,
				   "DH not supported for windows");
	    goto out;
	}
	free_AuthPack_Win2k(&ap);

    } else if (pa->padata_type == KRB5_PADATA_PK_AS_REQ) {
	AuthPack ap;

	ret = decode_AuthPack(eContent.data,
			      eContent.length,
			      &ap,
			      NULL);
	if (ret) {
	    krb5_set_error_message(context, ret,
				   "Can't decode AuthPack: %d", ret);
	    free_AuthPack(&ap);
	    goto out;
	}

	if (_kdc_is_anon_request(&req->req_body) &&
	    ap.clientPublicValue == NULL) {
	    free_AuthPack(&ap);
	    ret = KRB5_KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED;
	    krb5_set_error_message(context, ret,
				   "Anon not supported in RSA mode");
	    goto out;
	}

	ret = pk_check_pkauthenticator(context,
				       &ap.pkAuthenticator,
				       req);
	if (ret) {
	    free_AuthPack(&ap);
	    goto out;
	}

	cp->type = PKINIT_27;
	cp->nonce = ap.pkAuthenticator.nonce;

	if (ap.clientPublicValue) {
	    if (der_heim_oid_cmp(&ap.clientPublicValue->algorithm.algorithm, &asn1_oid_id_dhpublicnumber) == 0) {
		cp->keyex = USE_DH;
		ret = get_dh_param(context, config,
				   ap.clientPublicValue, cp);
	    } else if (der_heim_oid_cmp(&ap.clientPublicValue->algorithm.algorithm, &asn1_oid_id_ecPublicKey) == 0) {
		cp->keyex = USE_ECDH;
                ret = _kdc_get_ecdh_param(context, config,
                                          ap.clientPublicValue,
                                          &cp->u.ecdh.public_key);
	    } else {
		ret = KRB5_BADMSGTYPE;
		krb5_set_error_message(context, ret, "PKINIT unknown DH mechanism");
	    }
	    if (ret) {
		free_AuthPack(&ap);
		goto out;
	    }
	} else
	    cp->keyex = USE_RSA;

	ret = hx509_peer_info_alloc(context->hx509ctx,
					&cp->peer);
	if (ret) {
	    free_AuthPack(&ap);
	    goto out;
	}

	if (ap.supportedCMSTypes) {
	    ret = hx509_peer_info_set_cms_algs(context->hx509ctx,
					       cp->peer,
					       ap.supportedCMSTypes->val,
					       ap.supportedCMSTypes->len);
	    if (ret) {
		free_AuthPack(&ap);
		goto out;
	    }
	} else {
	    /* assume old client */
	    hx509_peer_info_add_cms_alg(context->hx509ctx, cp->peer,
					hx509_crypto_des_rsdi_ede3_cbc());
	    hx509_peer_info_add_cms_alg(context->hx509ctx, cp->peer,
					hx509_signature_rsa_with_sha1());
	    hx509_peer_info_add_cms_alg(context->hx509ctx, cp->peer,
					hx509_signature_sha1());
	}
	free_AuthPack(&ap);
    } else
	krb5_abortx(context, "internal pkinit error");

    kdc_log(context, config, 0, "PK-INIT request of type %s", type);

out:
    if (ret)
	krb5_warn(context, ret, "PKINIT");

    if (signed_content.data)
	free(signed_content.data);
    krb5_data_free(&eContent);
    der_free_oid(&eContentType);
    der_free_oid(&contentInfoOid);
    if (ret) {
        _kdc_pk_free_client_param(context, cp);
    } else
	*ret_params = cp;
    return ret;
}
Exemple #3
0
static krb5_error_code
pk_mk_pa_reply_enckey(krb5_context context,
		      krb5_kdc_configuration *config,
		      pk_client_params *cp,
		      const KDC_REQ *req,
		      const krb5_data *req_buffer,
		      krb5_keyblock *reply_key,
		      ContentInfo *content_info,
		      hx509_cert *kdc_cert)
{
    const heim_oid *envelopedAlg = NULL, *sdAlg = NULL, *evAlg = NULL;
    krb5_error_code ret;
    krb5_data buf, signed_data;
    size_t size = 0;
    int do_win2k = 0;

    krb5_data_zero(&buf);
    krb5_data_zero(&signed_data);

    *kdc_cert = NULL;

    /*
     * If the message client is a win2k-type but it send pa data
     * 09-binding it expects a IETF (checksum) reply so there can be
     * no replay attacks.
     */

    switch (cp->type) {
    case PKINIT_WIN2K: {
	int i = 0;
	if (_kdc_find_padata(req, &i, KRB5_PADATA_PK_AS_09_BINDING) == NULL
	    && config->pkinit_require_binding == 0)
	{
	    do_win2k = 1;
	}
	sdAlg = &asn1_oid_id_pkcs7_data;
	evAlg = &asn1_oid_id_pkcs7_data;
	envelopedAlg = &asn1_oid_id_rsadsi_des_ede3_cbc;
	break;
    }
    case PKINIT_27:
	sdAlg = &asn1_oid_id_pkrkeydata;
	evAlg = &asn1_oid_id_pkcs7_signedData;
	break;
    default:
	krb5_abortx(context, "internal pkinit error");
    }

    if (do_win2k) {
	ReplyKeyPack_Win2k kp;
	memset(&kp, 0, sizeof(kp));

	ret = copy_EncryptionKey(reply_key, &kp.replyKey);
	if (ret) {
	    krb5_clear_error_message(context);
	    goto out;
	}
	kp.nonce = cp->nonce;

	ASN1_MALLOC_ENCODE(ReplyKeyPack_Win2k,
			   buf.data, buf.length,
			   &kp, &size,ret);
	free_ReplyKeyPack_Win2k(&kp);
    } else {
	krb5_crypto ascrypto;
	ReplyKeyPack kp;
	memset(&kp, 0, sizeof(kp));

	ret = copy_EncryptionKey(reply_key, &kp.replyKey);
	if (ret) {
	    krb5_clear_error_message(context);
	    goto out;
	}

	ret = krb5_crypto_init(context, reply_key, 0, &ascrypto);
	if (ret) {
	    krb5_clear_error_message(context);
	    goto out;
	}

	ret = krb5_create_checksum(context, ascrypto, 6, 0,
				   req_buffer->data, req_buffer->length,
				   &kp.asChecksum);
	if (ret) {
	    krb5_clear_error_message(context);
	    goto out;
	}

	ret = krb5_crypto_destroy(context, ascrypto);
	if (ret) {
	    krb5_clear_error_message(context);
	    goto out;
	}
	ASN1_MALLOC_ENCODE(ReplyKeyPack, buf.data, buf.length, &kp, &size,ret);
	free_ReplyKeyPack(&kp);
    }
    if (ret) {
	krb5_set_error_message(context, ret, "ASN.1 encoding of ReplyKeyPack "
			       "failed (%d)", ret);
	goto out;
    }
    if (buf.length != size)
	krb5_abortx(context, "Internal ASN.1 encoder error");

    {
	hx509_query *q;
	hx509_cert cert;

	ret = hx509_query_alloc(context->hx509ctx, &q);
	if (ret)
	    goto out;

	hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
	if (config->pkinit_kdc_friendly_name)
	    hx509_query_match_friendly_name(q, config->pkinit_kdc_friendly_name);

	ret = hx509_certs_find(context->hx509ctx,
			       kdc_identity->certs,
			       q,
			       &cert);
	hx509_query_free(context->hx509ctx, q);
	if (ret)
	    goto out;

	ret = hx509_cms_create_signed_1(context->hx509ctx,
					0,
					sdAlg,
					buf.data,
					buf.length,
					NULL,
					cert,
					cp->peer,
					cp->client_anchors,
					kdc_identity->certpool,
					&signed_data);
	*kdc_cert = cert;
    }

    krb5_data_free(&buf);
    if (ret)
	goto out;

    if (cp->type == PKINIT_WIN2K) {
	ret = hx509_cms_wrap_ContentInfo(&asn1_oid_id_pkcs7_signedData,
					 &signed_data,
					 &buf);
	if (ret)
	    goto out;
	krb5_data_free(&signed_data);
	signed_data = buf;
    }

    ret = hx509_cms_envelope_1(context->hx509ctx,
			       HX509_CMS_EV_NO_KU_CHECK,
			       cp->cert,
			       signed_data.data, signed_data.length,
			       envelopedAlg,
			       evAlg, &buf);
    if (ret)
	goto out;

    ret = _krb5_pk_mk_ContentInfo(context,
				  &buf,
				  &asn1_oid_id_pkcs7_envelopedData,
				  content_info);
out:
    if (ret && *kdc_cert) {
        hx509_cert_free(*kdc_cert);
	*kdc_cert = NULL;
    }

    krb5_data_free(&buf);
    krb5_data_free(&signed_data);
    return ret;
}
Exemple #4
0
krb5_error_code
krb5_kdc_pk_initialize(krb5_context context,
		       krb5_kdc_configuration *config,
		       const char *user_id,
		       const char *anchors,
		       char **pool,
		       char **revoke_list)
{
    const char *file;
    char *fn = NULL;
    krb5_error_code ret;

    file = krb5_config_get_string(context, NULL,
				  "libdefaults", "moduli", NULL);

    ret = _krb5_parse_moduli(context, file, &moduli);
    if (ret)
	krb5_err(context, 1, ret, "PKINIT: failed to load modidi file");

    principal_mappings.len = 0;
    principal_mappings.val = NULL;

    ret = _krb5_pk_load_id(context,
			   &kdc_identity,
			   user_id,
			   anchors,
			   pool,
			   revoke_list,
			   NULL,
			   NULL,
			   NULL);
    if (ret) {
	krb5_warn(context, ret, "PKINIT: ");
	config->enable_pkinit = 0;
	return ret;
    }

    {
	hx509_query *q;
	hx509_cert cert;

	ret = hx509_query_alloc(context->hx509ctx, &q);
	if (ret) {
	    krb5_warnx(context, "PKINIT: out of memory");
	    return ENOMEM;
	}

	hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
	if (config->pkinit_kdc_friendly_name)
	    hx509_query_match_friendly_name(q, config->pkinit_kdc_friendly_name);

	ret = hx509_certs_find(context->hx509ctx,
			       kdc_identity->certs,
			       q,
			       &cert);
	hx509_query_free(context->hx509ctx, q);
	if (ret == 0) {
	    if (hx509_cert_check_eku(context->hx509ctx, cert,
				     &asn1_oid_id_pkkdcekuoid, 0)) {
		hx509_name name;
		char *str;
		ret = hx509_cert_get_subject(cert, &name);
		if (ret == 0) {
		    hx509_name_to_string(name, &str);
		    krb5_warnx(context, "WARNING Found KDC certificate (%s)"
			       "is missing the PK-INIT KDC EKU, this is bad for "
			       "interoperability.", str);
		    hx509_name_free(&name);
		    free(str);
		}
	    }
	    hx509_cert_free(cert);
	} else
	    krb5_warnx(context, "PKINIT: failed to find a signing "
		       "certifiate with a public key");
    }

    if (krb5_config_get_bool_default(context,
				     NULL,
				     FALSE,
				     "kdc",
				     "pkinit_allow_proxy_certificate",
				     NULL))
	config->pkinit_allow_proxy_certs = 1;

    file = krb5_config_get_string(context,
				  NULL,
				  "kdc",
				  "pkinit_mappings_file",
				  NULL);
    if (file == NULL) {
	int aret;

	aret = asprintf(&fn, "%s/pki-mapping", hdb_db_dir(context));
	if (aret == -1) {
	    krb5_warnx(context, "PKINIT: out of memory");
	    return ENOMEM;
	}

	file = fn;
    }

    load_mappings(context, file);
    if (fn)
	free(fn);

    return 0;
}
OM_uint32
_gssiakerb_acquire_cred(OM_uint32 * minor_status,
			const gss_name_t desired_name,
			OM_uint32 time_req,
			const gss_OID_set desired_mechs,
			gss_cred_usage_t cred_usage,
			gss_cred_id_t * output_cred_handle,
			gss_OID_set * actual_mechs,
			OM_uint32 * time_rec)
{
    krb5_principal princ = (krb5_principal)desired_name;
    OM_uint32 major_status, junk;
    krb5_context context;
    krb5_error_code ret;
    gsskrb5_cred handle;
    krb5_data data;
    int iakerb = 0;
    
    GSSAPI_KRB5_INIT(&context);

    *minor_status = 0;
    *output_cred_handle = NULL;
    
    if (cred_usage != GSS_C_INITIATE && cred_usage != GSS_C_BOTH)
	return GSS_S_FAILURE;
    if (princ == NULL)
	return GSS_S_FAILURE;

    handle = calloc(1, sizeof(*handle));
    if (handle == NULL)
        return GSS_S_FAILURE;

    HEIMDAL_MUTEX_init(&handle->cred_id_mutex);

    major_status = _acquire_uuid_name(minor_status, context, princ, &iakerb, handle);
    if (major_status)
	return major_status;
    if (!iakerb)
	return GSS_S_BAD_NAME;

    if ((ret = krb5_cc_get_config(context, handle->ccache, NULL, "password", &data)) == 0) {

	ret = asprintf(&handle->password, "%.*s", (int)data.length, (char *)data.data);
	memset(data.data, 0, data.length);
	krb5_data_free(&data);
	if (ret <= 0 || handle->password == NULL) {
	    _gsskrb5_release_cred(&junk, (gss_cred_id_t *)&handle);
	    *minor_status = ENOMEM;
	    return GSS_S_FAILURE;
	}

#ifdef PKINIT
    } else if ((ret = krb5_cc_get_config(context, handle->ccache, NULL, "certificate-ref", &data)) == 0) {
	hx509_certs certs;
	hx509_query *q;
	
	ret = hx509_certs_init(context->hx509ctx, "KEYCHAIN:", 0, NULL, &certs);
	if (ret) {
	    krb5_data_free(&data);
	    hx509_certs_free(&certs);
	    _gsskrb5_release_cred(&junk, (gss_cred_id_t *)&handle);
	    *minor_status = ret;
	    return GSS_S_FAILURE;
	}

	ret = hx509_query_alloc(context->hx509ctx, &q);
	if (ret) {
	    krb5_data_free(&data);
	    hx509_certs_free(&certs);
	    _gsskrb5_release_cred(&junk, (gss_cred_id_t *)&handle);
	    *minor_status = ret;
	    return GSS_S_FAILURE;
	}
	
	hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
	hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE);
	hx509_query_match_persistent(q, &data);

	ret = _krb5_pk_find_cert(context, 1, certs, q, &handle->cert);
	krb5_data_free(&data);
	hx509_certs_free(&certs);
	hx509_query_free(context->hx509ctx, q);
	if (ret != 0) {
	    _gss_mg_log(1, "gss-krb5: failed to find certificate ref %d", ret);
	    _gsskrb5_release_cred(&junk, (gss_cred_id_t *)&handle);
	    *minor_status = ret;
	    return GSS_S_FAILURE;
	}
#endif
    } else if ((ret = krb5_cc_get_config(context, handle->ccache, NULL, "iakerb", &data)) == 0) {
	handle->cred_flags |= GSS_CF_IAKERB_RESOLVED;
	krb5_data_free(&data);
    } else {
	_gsskrb5_release_cred(&junk, (gss_cred_id_t *)&handle);
	*minor_status = 0;
	return GSS_S_FAILURE;
    }
    
    handle->usage = GSS_C_INITIATE;
    handle->endtime = INT_MAX;
    
    *output_cred_handle = (gss_cred_id_t)handle;
    *minor_status = 0;
    return GSS_S_COMPLETE;
}
OM_uint32
_gsspku2u_acquire_cred(OM_uint32 * minor_status,
		       const gss_name_t desired_name,
		       OM_uint32 time_req,
		       const gss_OID_set desired_mechs,
		       gss_cred_usage_t cred_usage,
		       gss_cred_id_t * output_cred_handle,
		       gss_OID_set * actual_mechs,
		       OM_uint32 * time_rec)
{
    krb5_context context;
    gsskrb5_cred handle;
    hx509_query *q;
    hx509_certs certs = NULL;
    OM_uint32 ret;
    krb5_principal name = (krb5_principal)desired_name;

    /* remove non-options from cred_usage */
    cred_usage = (cred_usage & GSS_C_OPTION_MASK);

    if (cred_usage != GSS_C_ACCEPT && cred_usage != GSS_C_INITIATE && cred_usage != GSS_C_BOTH) {
	*minor_status = GSS_KRB5_S_G_BAD_USAGE;
	return GSS_S_FAILURE;
    }

    GSSAPI_KRB5_INIT(&context);

    *output_cred_handle = NULL;
    if (time_rec)
	*time_rec = GSS_C_INDEFINITE;
    if (actual_mechs)
	*actual_mechs = GSS_C_NO_OID_SET;

    /*
     * We can't acquire credential for specific names that are not
     * PKU2U names, so don't try.
     */

    if (name && !krb5_principal_is_pku2u(context, name)) {
	*minor_status = 0;
	return GSS_S_BAD_NAME;
    }

    handle = calloc(1, sizeof(*handle));
    if (handle == NULL)
	return (GSS_S_FAILURE);

    HEIMDAL_MUTEX_init(&handle->cred_id_mutex);

    handle->usage = cred_usage;

    if ((cred_usage == GSS_C_INITIATE) || (cred_usage == GSS_C_BOTH)) {
	struct search s;

	ret = hx509_certs_init(context->hx509ctx, "KEYCHAIN:", 0, NULL, &certs);
	if (ret) {
	    *minor_status = ret;
	    goto fail;
	}

	ret = hx509_query_alloc(context->hx509ctx, &q);
	if (ret) {
	    *minor_status = ret;
	    goto fail;
	}
	
	hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
	hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE);
	
	if (name) {
	    s.context = context;
	    s.principal = name;
	    hx509_query_match_cmp_func(q, match_pkinit_san, &s);
	}

	ret = _krb5_pk_find_cert(context, 1, certs, q, &handle->cert);
	hx509_query_free(context->hx509ctx, q);
	if (ret) {
	    *minor_status = ret;
	    goto fail;
	}

	if (name)
	    ret = krb5_copy_principal(context, name, &handle->principal);
	else
	    ret = _gsspku2u_principal(context, handle->cert, &handle->principal);
	if (ret) {
	    *minor_status = ret;
	    goto fail;
	}

    }

    if ((cred_usage == GSS_C_ACCEPT) || (cred_usage == GSS_C_BOTH)) {
	ret = get_keytab(context, handle, 1);
	if (ret) {
	    *minor_status = ret;
	    goto fail;
	}
    }
    if (certs)
	hx509_certs_free(&certs);

    *output_cred_handle = (gss_cred_id_t)handle;
    return GSS_S_COMPLETE;

 fail:
    if (certs)
	hx509_certs_free(&certs);
    if (handle->keytab)
	krb5_kt_close(context, handle->keytab);
    HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
    free(handle);

    return GSS_S_FAILURE;
}
Exemple #7
0
static krb5_error_code
pk_mk_pa_reply_dh(krb5_context context,
                  DH *kdc_dh,
      		  pk_client_params *client_params,
                  krb5_keyblock *reply_key,
		  ContentInfo *content_info,
		  hx509_cert *kdc_cert)
{
    KDCDHKeyInfo dh_info;
    krb5_data signed_data, buf;
    ContentInfo contentinfo;
    krb5_error_code ret;
    size_t size;
    heim_integer i;

    memset(&contentinfo, 0, sizeof(contentinfo));
    memset(&dh_info, 0, sizeof(dh_info));
    krb5_data_zero(&buf);
    krb5_data_zero(&signed_data);

    *kdc_cert = NULL;

    ret = BN_to_integer(context, kdc_dh->pub_key, &i);
    if (ret)
	return ret;

    ASN1_MALLOC_ENCODE(DHPublicKey, buf.data, buf.length, &i, &size, ret);
    if (ret) {
	krb5_set_error_message(context, ret, "ASN.1 encoding of "
			       "DHPublicKey failed (%d)", ret);
	return ret;
    }
    if (buf.length != size)
	krb5_abortx(context, "Internal ASN.1 encoder error");

    dh_info.subjectPublicKey.length = buf.length * 8;
    dh_info.subjectPublicKey.data = buf.data;

    dh_info.nonce = client_params->nonce;

    ASN1_MALLOC_ENCODE(KDCDHKeyInfo, buf.data, buf.length, &dh_info, &size,
		       ret);
    if (ret) {
	krb5_set_error_message(context, ret, "ASN.1 encoding of "
			       "KdcDHKeyInfo failed (%d)", ret);
	goto out;
    }
    if (buf.length != size)
	krb5_abortx(context, "Internal ASN.1 encoder error");

    /*
     * Create the SignedData structure and sign the KdcDHKeyInfo
     * filled in above
     */

    {
	hx509_query *q;
	hx509_cert cert;
	
	ret = hx509_query_alloc(kdc_identity->hx509ctx, &q);
	if (ret)
	    goto out;
	
	hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
	hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE);
	
	ret = hx509_certs_find(kdc_identity->hx509ctx,
			       kdc_identity->certs,
			       q,
			       &cert);
	hx509_query_free(kdc_identity->hx509ctx, q);
	if (ret)
	    goto out;
	
	ret = hx509_cms_create_signed_1(kdc_identity->hx509ctx,
					0,
					oid_id_pkdhkeydata(),
					buf.data,
					buf.length,
					NULL,
					cert,
					client_params->peer,
					client_params->client_anchors,
					kdc_identity->certpool,
					&signed_data);
	*kdc_cert = cert;
    }
    if (ret)
	goto out;

    ret = _krb5_pk_mk_ContentInfo(context,
				  &signed_data,
				  oid_id_pkcs7_signedData(),
				  content_info);
    if (ret)
	goto out;

 out:
    if (ret && *kdc_cert) {
	hx509_cert_free(*kdc_cert);
	*kdc_cert = NULL;
    }

    krb5_data_free(&buf);
    krb5_data_free(&signed_data);
    free_KDCDHKeyInfo(&dh_info);

    return ret;
}
Exemple #8
0
krb5_error_code
_kdc_pk_rd_padata(krb5_context context,
		  krb5_kdc_configuration *config,
		  const KDC_REQ *req,
		  const PA_DATA *pa,
		  pk_client_params **ret_params)
{
    pk_client_params *client_params;
    krb5_error_code ret;
    heim_oid eContentType = { 0, NULL }, contentInfoOid = { 0, NULL };
    krb5_data eContent = { 0, NULL };
    krb5_data signed_content = { 0, NULL };
    const char *type = "unknown type";
    int have_data = 0;

    *ret_params = NULL;

    if (!config->enable_pkinit) {
	kdc_log(context, config, 0, "PK-INIT request but PK-INIT not enabled");
	krb5_clear_error_message(context);
	return 0;
    }

    hx509_verify_set_time(kdc_identity->verify_ctx, kdc_time);

    client_params = calloc(1, sizeof(*client_params));
    if (client_params == NULL) {
	krb5_clear_error_message(context);
	ret = ENOMEM;
	goto out;
    }

    if (pa->padata_type == KRB5_PADATA_PK_AS_REQ_WIN) {
	PA_PK_AS_REQ_Win2k r;

	type = "PK-INIT-Win2k";

	ret = decode_PA_PK_AS_REQ_Win2k(pa->padata_value.data,
					pa->padata_value.length,
					&r,
					NULL);
	if (ret) {
	    krb5_set_error_message(context, ret, "Can't decode "
				   "PK-AS-REQ-Win2k: %d", ret);
	    goto out;
	}
	
	ret = hx509_cms_unwrap_ContentInfo(&r.signed_auth_pack,
					   &contentInfoOid,
					   &signed_content,
					   &have_data);
	free_PA_PK_AS_REQ_Win2k(&r);
	if (ret) {
	    krb5_set_error_message(context, ret,
				   "Can't decode PK-AS-REQ: %d", ret);
	    goto out;
	}

    } else if (pa->padata_type == KRB5_PADATA_PK_AS_REQ) {
	PA_PK_AS_REQ r;

	type = "PK-INIT-IETF";

	ret = decode_PA_PK_AS_REQ(pa->padata_value.data,
				  pa->padata_value.length,
				  &r,
				  NULL);
	if (ret) {
	    krb5_set_error_message(context, ret, "Can't decode PK-AS-REQ: %d", ret);
	    goto out;
	}
	
	/* XXX look at r.kdcPkId */
	if (r.trustedCertifiers) {
	    ExternalPrincipalIdentifiers *edi = r.trustedCertifiers;
	    unsigned int i;

	    ret = hx509_certs_init(kdc_identity->hx509ctx,
				   "MEMORY:client-anchors",
				   0, NULL,
				   &client_params->client_anchors);
	    if (ret) {
		krb5_set_error_message(context, ret, "Can't allocate client anchors: %d", ret);
		goto out;

	    }
	    for (i = 0; i < edi->len; i++) {
		IssuerAndSerialNumber iasn;
		hx509_query *q;
		hx509_cert cert;
		size_t size;

		if (edi->val[i].issuerAndSerialNumber == NULL)
		    continue;

		ret = hx509_query_alloc(kdc_identity->hx509ctx, &q);
		if (ret) {
		    krb5_set_error_message(context, ret,
					  "Failed to allocate hx509_query");
		    goto out;
		}
		
		ret = decode_IssuerAndSerialNumber(edi->val[i].issuerAndSerialNumber->data,
						   edi->val[i].issuerAndSerialNumber->length,
						   &iasn,
						   &size);
		if (ret) {
		    hx509_query_free(kdc_identity->hx509ctx, q);
		    continue;
		}
		ret = hx509_query_match_issuer_serial(q, &iasn.issuer, &iasn.serialNumber);
		free_IssuerAndSerialNumber(&iasn);
		if (ret)
		    continue;

		ret = hx509_certs_find(kdc_identity->hx509ctx,
				       kdc_identity->certs,
				       q,
				       &cert);
		hx509_query_free(kdc_identity->hx509ctx, q);
		if (ret)
		    continue;
		hx509_certs_add(kdc_identity->hx509ctx,
				client_params->client_anchors, cert);
		hx509_cert_free(cert);
	    }
	}

	ret = hx509_cms_unwrap_ContentInfo(&r.signedAuthPack,
					   &contentInfoOid,
					   &signed_content,
					   &have_data);
	free_PA_PK_AS_REQ(&r);
	if (ret) {
	    krb5_set_error_message(context, ret,
				   "Can't unwrap ContentInfo: %d", ret);
	    goto out;
	}

    } else {
	krb5_clear_error_message(context);
	ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
	goto out;
    }

    ret = der_heim_oid_cmp(&contentInfoOid, oid_id_pkcs7_signedData());
    if (ret != 0) {
	ret = KRB5KRB_ERR_GENERIC;
	krb5_set_error_message(context, ret,
			       "PK-AS-REQ-Win2k invalid content type oid");
	goto out;
    }
	
    if (!have_data) {
	ret = KRB5KRB_ERR_GENERIC;
	krb5_set_error_message(context, ret,
			      "PK-AS-REQ-Win2k no signed auth pack");
	goto out;
    }

    {
	hx509_certs signer_certs;

	ret = hx509_cms_verify_signed(kdc_identity->hx509ctx,
				      kdc_identity->verify_ctx,
				      signed_content.data,
				      signed_content.length,
				      NULL,
				      kdc_identity->certpool,
				      &eContentType,
				      &eContent,
				      &signer_certs);
	if (ret) {
	    char *s = hx509_get_error_string(kdc_identity->hx509ctx, ret);
	    krb5_warnx(context, "PKINIT: failed to verify signature: %s: %d",
		       s, ret);
	    free(s);
	    goto out;
	}

	ret = hx509_get_one_cert(kdc_identity->hx509ctx, signer_certs,
				 &client_params->cert);
	hx509_certs_free(&signer_certs);
	if (ret)
	    goto out;
    }

    /* Signature is correct, now verify the signed message */
    if (der_heim_oid_cmp(&eContentType, oid_id_pkcs7_data()) != 0 &&
	der_heim_oid_cmp(&eContentType, oid_id_pkauthdata()) != 0)
    {
	ret = KRB5_BADMSGTYPE;
	krb5_set_error_message(context, ret, "got wrong oid for pkauthdata");
	goto out;
    }

    if (pa->padata_type == KRB5_PADATA_PK_AS_REQ_WIN) {
	AuthPack_Win2k ap;

	ret = decode_AuthPack_Win2k(eContent.data,
				    eContent.length,
				    &ap,
				    NULL);
	if (ret) {
	    krb5_set_error_message(context, ret, "can't decode AuthPack: %d", ret);
	    goto out;
	}

	ret = pk_check_pkauthenticator_win2k(context,
					     &ap.pkAuthenticator,
					     req);
	if (ret) {
	    free_AuthPack_Win2k(&ap);
	    goto out;
	}

	client_params->type = PKINIT_WIN2K;
	client_params->nonce = ap.pkAuthenticator.nonce;

	if (ap.clientPublicValue) {
	    ret = KRB5KRB_ERR_GENERIC;
	    krb5_set_error_message(context, ret, "DH not supported for windows");
	    goto out;
	}
	free_AuthPack_Win2k(&ap);

    } else if (pa->padata_type == KRB5_PADATA_PK_AS_REQ) {
	AuthPack ap;

	ret = decode_AuthPack(eContent.data,
			      eContent.length,
			      &ap,
			      NULL);
	if (ret) {
	    krb5_set_error_message(context, ret, "can't decode AuthPack: %d", ret);
	    free_AuthPack(&ap);
	    goto out;
	}

	ret = pk_check_pkauthenticator(context,
				       &ap.pkAuthenticator,
				       req);
	if (ret) {
	    free_AuthPack(&ap);
	    goto out;
	}

	client_params->type = PKINIT_27;
	client_params->nonce = ap.pkAuthenticator.nonce;

	if (ap.clientPublicValue) {
	    ret = get_dh_param(context, config,
			       ap.clientPublicValue, client_params);
	    if (ret) {
		free_AuthPack(&ap);
		goto out;
	    }
	}

	if (ap.supportedCMSTypes) {
	    ret = hx509_peer_info_alloc(kdc_identity->hx509ctx,
					&client_params->peer);
	    if (ret) {
		free_AuthPack(&ap);
		goto out;
	    }
	    ret = hx509_peer_info_set_cms_algs(kdc_identity->hx509ctx,
					       client_params->peer,
					       ap.supportedCMSTypes->val,
					       ap.supportedCMSTypes->len);
	    if (ret) {
		free_AuthPack(&ap);
		goto out;
	    }
	}
	free_AuthPack(&ap);
    } else
	krb5_abortx(context, "internal pkinit error");

    kdc_log(context, config, 0, "PK-INIT request of type %s", type);

out:
    if (ret)
	krb5_warn(context, ret, "PKINIT");

    if (signed_content.data)
	free(signed_content.data);
    krb5_data_free(&eContent);
    der_free_oid(&eContentType);
    der_free_oid(&contentInfoOid);
    if (ret)
	_kdc_pk_free_client_param(context, client_params);
    else
	*ret_params = client_params;
    return ret;
}