diff --git a/kdc/pkinit.c b/kdc/pkinit.c index 76beadf1d..3e2564501 100644 --- a/kdc/pkinit.c +++ b/kdc/pkinit.c @@ -82,6 +82,12 @@ static struct krb5_pk_identity *kdc_identity; static struct pk_principal_mapping principal_mappings; static struct krb5_dh_moduli **moduli; +static struct { + krb5_data data; + time_t expire; + time_t next_update; +} ocsp; + /* * */ @@ -754,7 +760,8 @@ pk_mk_pa_reply_dh(krb5_context context, DH *kdc_dh, pk_client_params *client_params, krb5_keyblock *reply_key, - ContentInfo *content_info) + ContentInfo *content_info, + hx509_cert *kdc_cert) { KDCDHKeyInfo dh_info; krb5_data signed_data, buf; @@ -768,6 +775,8 @@ pk_mk_pa_reply_dh(krb5_context context, 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; @@ -803,8 +812,8 @@ pk_mk_pa_reply_dh(krb5_context context, */ { - hx509_cert cert; hx509_query *q; + hx509_cert cert; ret = hx509_query_alloc(kdc_identity->hx509ctx, &q); if (ret) @@ -830,7 +839,7 @@ pk_mk_pa_reply_dh(krb5_context context, kdc_identity->anchors, kdc_identity->certpool, &signed_data); - hx509_cert_free(cert); + *kdc_cert = cert; } if (ret) goto out; @@ -843,6 +852,11 @@ pk_mk_pa_reply_dh(krb5_context context, 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); @@ -869,6 +883,7 @@ _kdc_pk_mk_pa_reply(krb5_context context, size_t len, size; krb5_enctype enctype; int pa_type; + hx509_cert kdc_cert = NULL; int i; if (!config->enable_pkinit) { @@ -947,7 +962,8 @@ _kdc_pk_mk_pa_reply(krb5_context context, ret = pk_mk_pa_reply_dh(context, client_params->dh, client_params, &client_params->reply_key, - &info); + &info, + &kdc_cert); ASN1_MALLOC_ENCODE(ContentInfo, rep.u.dhInfo.dhSignedData.data, rep.u.dhInfo.dhSignedData.length, &info, &size, @@ -982,48 +998,43 @@ _kdc_pk_mk_pa_reply(krb5_context context, } else if (client_params->type == PKINIT_COMPAT_WIN2K) { PA_PK_AS_REP_Win2k rep; + ContentInfo info; - pa_type = KRB5_PADATA_PK_AS_REP_19; + if (client_params->dh) { + krb5_set_error_string(context, "Windows PK-INIT doesn't support DH"); + ret = KRB5KRB_ERR_GENERIC; + goto out; + } memset(&rep, 0, sizeof(rep)); - if (client_params->dh) { - krb5_set_error_string(context, "DH -27 not implemented"); - ret = KRB5KRB_ERR_GENERIC; - } else { - rep.element = choice_PA_PK_AS_REP_encKeyPack; - ContentInfo info; + pa_type = KRB5_PADATA_PK_AS_REP_19; + rep.element = choice_PA_PK_AS_REP_encKeyPack; - krb5_generate_random_keyblock(context, enctype, - &client_params->reply_key); - ret = pk_mk_pa_reply_enckey(context, - 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_string(context, "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"); - - } + krb5_generate_random_keyblock(context, enctype, + &client_params->reply_key); + ret = pk_mk_pa_reply_enckey(context, + 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_string(context, "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); @@ -1041,11 +1052,88 @@ _kdc_pk_mk_pa_reply(krb5_context context, ret = krb5_padata_add(context, md, pa_type, buf, len); if (ret) { - krb5_set_error_string(context, "failed adding " - "PA-PK-AS-REP-19 %d", ret); + krb5_set_error_string(context, "failed adding PA-PK-AS-REP %d", ret); free(buf); + goto out; } - 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; + + 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 */ + + out_ocsp: + ocsp.next_update = kdc_time + 3600; + 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_string(context, + "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;