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; }
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; }
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; }