📄 pkinit.c
字号:
krb5_timestamp sec; int32_t usec; memset(&ap, 0, sizeof(ap)); /* fill in PKAuthenticator */ ret = copy_PrincipalName(req_body->sname, &ap.pkAuthenticator.kdcName); if (ret) { free_AuthPack_Win2k(&ap); krb5_clear_error_string(context); goto out; } ret = copy_Realm(&req_body->realm, &ap.pkAuthenticator.kdcRealm); if (ret) { free_AuthPack_Win2k(&ap); krb5_clear_error_string(context); goto out; } krb5_us_timeofday(context, &sec, &usec); ap.pkAuthenticator.ctime = sec; ap.pkAuthenticator.cusec = usec; ap.pkAuthenticator.nonce = nonce; ASN1_MALLOC_ENCODE(AuthPack_Win2k, buf.data, buf.length, &ap, &size, ret); free_AuthPack_Win2k(&ap); if (ret) { krb5_set_error_string(context, "AuthPack_Win2k: %d", ret); goto out; } if (buf.length != size) krb5_abortx(context, "internal ASN1 encoder error"); oid = oid_id_pkcs7_data(); } else if (ctx->type == COMPAT_IETF) { AuthPack ap; memset(&ap, 0, sizeof(ap)); ret = build_auth_pack(context, nonce, ctx, ctx->dh, req_body, &ap); if (ret) { free_AuthPack(&ap); goto out; } ASN1_MALLOC_ENCODE(AuthPack, buf.data, buf.length, &ap, &size, ret); free_AuthPack(&ap); if (ret) { krb5_set_error_string(context, "AuthPack: %d", ret); goto out; } if (buf.length != size) krb5_abortx(context, "internal ASN1 encoder error"); oid = oid_id_pkauthdata(); } else krb5_abortx(context, "internal pkinit error"); ret = create_signature(context, oid, &buf, ctx->id, ctx->peer, &sd_buf); krb5_data_free(&buf); if (ret) goto out; ret = hx509_cms_wrap_ContentInfo(oid_id_pkcs7_signedData(), &sd_buf, &buf); krb5_data_free(&sd_buf); if (ret) { krb5_set_error_string(context, "ContentInfo wrapping of signedData failed"); goto out; } if (ctx->type == COMPAT_WIN2K) { PA_PK_AS_REQ_Win2k winreq; pa_type = KRB5_PADATA_PK_AS_REQ_WIN; memset(&winreq, 0, sizeof(winreq)); winreq.signed_auth_pack = buf; ASN1_MALLOC_ENCODE(PA_PK_AS_REQ_Win2k, buf.data, buf.length, &winreq, &size, ret); free_PA_PK_AS_REQ_Win2k(&winreq); } else if (ctx->type == COMPAT_IETF) { PA_PK_AS_REQ req; pa_type = KRB5_PADATA_PK_AS_REQ; memset(&req, 0, sizeof(req)); req.signedAuthPack = buf; if (ctx->trustedCertifiers) { req.trustedCertifiers = calloc(1, sizeof(*req.trustedCertifiers)); if (req.trustedCertifiers == NULL) { krb5_set_error_string(context, "malloc: out of memory"); free_PA_PK_AS_REQ(&req); goto out; } ret = build_edi(context, ctx->id->hx509ctx, ctx->id->anchors, req.trustedCertifiers); if (ret) { krb5_set_error_string(context, "pk-init: failed to build trustedCertifiers"); free_PA_PK_AS_REQ(&req); goto out; } } req.kdcPkId = NULL; ASN1_MALLOC_ENCODE(PA_PK_AS_REQ, buf.data, buf.length, &req, &size, ret); free_PA_PK_AS_REQ(&req); } else krb5_abortx(context, "internal pkinit error"); if (ret) { krb5_set_error_string(context, "PA-PK-AS-REQ %d", ret); goto out; } if (buf.length != size) krb5_abortx(context, "Internal ASN1 encoder error"); ret = krb5_padata_add(context, md, pa_type, buf.data, buf.length); if (ret) free(buf.data); if (ret == 0 && ctx->type == COMPAT_WIN2K) krb5_padata_add(context, md, KRB5_PADATA_PK_AS_09_BINDING, NULL, 0);out: free_ContentInfo(&content_info); return ret;}krb5_error_code KRB5_LIB_FUNCTION _krb5_pk_mk_padata(krb5_context context, void *c, const KDC_REQ_BODY *req_body, unsigned nonce, METHOD_DATA *md){ krb5_pk_init_ctx ctx = c; int win2k_compat; win2k_compat = krb5_config_get_bool_default(context, NULL, FALSE, "realms", req_body->realm, "pkinit_win2k", NULL); if (win2k_compat) { ctx->require_binding = krb5_config_get_bool_default(context, NULL, FALSE, "realms", req_body->realm, "pkinit_win2k_require_binding", NULL); ctx->type = COMPAT_WIN2K; } else ctx->type = COMPAT_IETF; ctx->require_eku = krb5_config_get_bool_default(context, NULL, TRUE, "realms", req_body->realm, "pkinit_require_eku", NULL); ctx->require_krbtgt_otherName = krb5_config_get_bool_default(context, NULL, TRUE, "realms", req_body->realm, "pkinit_require_krbtgt_otherName", NULL); ctx->require_hostname_match = krb5_config_get_bool_default(context, NULL, FALSE, "realms", req_body->realm, "pkinit_require_hostname_match", NULL); ctx->trustedCertifiers = krb5_config_get_bool_default(context, NULL, TRUE, "realms", req_body->realm, "pkinit_trustedCertifiers", NULL); return pk_mk_padata(context, ctx, req_body, nonce, md);}krb5_error_code KRB5_LIB_FUNCTION_krb5_pk_verify_sign(krb5_context context, const void *data, size_t length, struct krb5_pk_identity *id, heim_oid *contentType, krb5_data *content, struct krb5_pk_cert **signer){ hx509_certs signer_certs; int ret; *signer = NULL; ret = hx509_cms_verify_signed(id->hx509ctx, id->verify_ctx, data, length, NULL, id->certpool, contentType, content, &signer_certs); if (ret) { _krb5_pk_copy_error(context, id->hx509ctx, ret, "CMS verify signed failed"); return ret; } *signer = calloc(1, sizeof(**signer)); if (*signer == NULL) { krb5_clear_error_string(context); ret = ENOMEM; goto out; } ret = hx509_get_one_cert(id->hx509ctx, signer_certs, &(*signer)->cert); if (ret) { _krb5_pk_copy_error(context, id->hx509ctx, ret, "Failed to get on of the signer certs"); goto out; }out: hx509_certs_free(&signer_certs); if (ret) { if (*signer) { hx509_cert_free((*signer)->cert); free(*signer); *signer = NULL; } } return ret;}static krb5_error_codeget_reply_key_win(krb5_context context, const krb5_data *content, unsigned nonce, krb5_keyblock **key){ ReplyKeyPack_Win2k key_pack; krb5_error_code ret; size_t size; ret = decode_ReplyKeyPack_Win2k(content->data, content->length, &key_pack, &size); if (ret) { krb5_set_error_string(context, "PKINIT decoding reply key failed"); free_ReplyKeyPack_Win2k(&key_pack); return ret; } if (key_pack.nonce != nonce) { krb5_set_error_string(context, "PKINIT enckey nonce is wrong"); free_ReplyKeyPack_Win2k(&key_pack); return KRB5KRB_AP_ERR_MODIFIED; } *key = malloc (sizeof (**key)); if (*key == NULL) { krb5_set_error_string(context, "PKINIT failed allocating reply key"); free_ReplyKeyPack_Win2k(&key_pack); krb5_set_error_string(context, "malloc: out of memory"); return ENOMEM; } ret = copy_EncryptionKey(&key_pack.replyKey, *key); free_ReplyKeyPack_Win2k(&key_pack); if (ret) { krb5_set_error_string(context, "PKINIT failed copying reply key"); free(*key); *key = NULL; } return ret;}static krb5_error_codeget_reply_key(krb5_context context, const krb5_data *content, const krb5_data *req_buffer, krb5_keyblock **key){ ReplyKeyPack key_pack; krb5_error_code ret; size_t size; ret = decode_ReplyKeyPack(content->data, content->length, &key_pack, &size); if (ret) { krb5_set_error_string(context, "PKINIT decoding reply key failed"); free_ReplyKeyPack(&key_pack); return ret; } { krb5_crypto crypto; /* * XXX Verify kp.replyKey is a allowed enctype in the * configuration file */ ret = krb5_crypto_init(context, &key_pack.replyKey, 0, &crypto); if (ret) { free_ReplyKeyPack(&key_pack); return ret; } ret = krb5_verify_checksum(context, crypto, 6, req_buffer->data, req_buffer->length, &key_pack.asChecksum); krb5_crypto_destroy(context, crypto); if (ret) { free_ReplyKeyPack(&key_pack); return ret; } } *key = malloc (sizeof (**key)); if (*key == NULL) { krb5_set_error_string(context, "PKINIT failed allocating reply key"); free_ReplyKeyPack(&key_pack); krb5_set_error_string(context, "malloc: out of memory"); return ENOMEM; } ret = copy_EncryptionKey(&key_pack.replyKey, *key); free_ReplyKeyPack(&key_pack); if (ret) { krb5_set_error_string(context, "PKINIT failed copying reply key"); free(*key); *key = NULL; } return ret;}static krb5_error_codepk_verify_host(krb5_context context, const char *realm, const krb5_krbhst_info *hi, struct krb5_pk_init_ctx_data *ctx, struct krb5_pk_cert *host){ krb5_error_code ret = 0; if (ctx->require_eku) { ret = hx509_cert_check_eku(ctx->id->hx509ctx, host->cert, oid_id_pkkdcekuoid(), 0); if (ret) { krb5_set_error_string(context, "No PK-INIT KDC EKU in kdc certificate"); return ret; } } if (ctx->require_krbtgt_otherName) { hx509_octet_string_list list; int i; ret = hx509_cert_find_subjectAltName_otherName(ctx->id->hx509ctx, host->cert, oid_id_pkinit_san(), &list); if (ret) { krb5_set_error_string(context, "Failed to find the PK-INIT " "subjectAltName in the KDC certificate"); return ret; } for (i = 0; i < list.len; i++) { KRB5PrincipalName r; ret = decode_KRB5PrincipalName(list.val[i].data, list.val[i].length, &r, NULL); if (ret) { krb5_set_error_string(context, "Failed to decode the PK-INIT " "subjectAltName in the KDC certificate"); break; } if (r.principalName.name_string.len != 2 || strcmp(r.principalName.name_string.val[0], KRB5_TGS_NAME) != 0 || strcmp(r.principalName.name_string.val[1], realm) != 0 || strcmp(r.realm, realm) != 0) { krb5_set_error_string(context, "KDC have wrong realm name in " "the certificate"); ret = KRB5_KDC_ERR_INVALID_CERTIFICATE; } free_KRB5PrincipalName(&r); if (ret) break; } hx509_free_octet_string_list(&list); } if (ret) return ret; if (hi) { ret = hx509_verify_hostname(ctx->id->hx509ctx, host->cert, ctx->require_hostname_match, HX509_HN_HOSTNAME, hi->hostname, hi->ai->ai_addr, hi->ai->ai_addrlen); if (ret) krb5_set_error_string(context, "Address mismatch in " "the KDC certificate"); } return ret;}static krb5_error_codepk_rd_pa_reply_enckey(krb5_context context, int type, const heim_octet_string *indata, const heim_oid *dataType, const char *realm, krb5_pk_init_ctx ctx, krb5_enctype etype, const krb5_krbhst_info *hi, unsigned nonce, const krb5_data *req_buffer, PA_DATA *pa, krb5_keyblock **key) { krb5_error_code ret; struct krb5_pk_cert *host = NULL; krb5_data content; heim_oid contentType = { 0, NULL }; if (der_heim_oid_cmp(oid_id_pkcs7_envelopedData(), dataType)) { krb5_set_error_string(context, "PKINIT: Invalid content type"); return EINVAL; } ret = hx509_cms_unenvelope(ctx->id->hx509ctx, ctx->id->certs, HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT, indata->data, indata->length, NULL, &contentType, &content); if (ret) { _krb5_pk_copy_error(context, ctx->id->hx509ctx, ret, "Failed to unenvelope CMS data in PK-INIT reply"); return ret; } der_free_oid(&contentType);#if 0 /* windows LH with interesting CMS packets, leaks memory */ { size_t ph = 1 + der_length_len (length); unsigned char *ptr = malloc(length + ph); size_t l; memcpy(ptr + ph, p, length); ret = der_put_length_and_tag (ptr + ph - 1, ph, length, ASN1_C_UNIV, CONS, UT_Sequence, &l); if (ret) return ret; ptr += ph - l; length += l; p = ptr; }#endif /* win2k uses ContentInfo */ if (type == COMPAT_WIN2K) { heim_oid type; heim_octet_string out; ret = hx509_cms_unwrap_ContentInfo(&content, &type, &out, NULL); if (der_heim_oid_cmp(&type, oid_id_pkcs7_signedData())) { ret = EINVAL; /* XXX */ krb5_set_error_string(context, "PKINIT: Invalid content type"); der_free_oid(&type); der_free_octet_string(&out); goto out; } der_free_oid(&type); krb5_data_free(&content); ret = krb5_data_copy(&content, out.data, out.length); der_free_octet_string(&out); if (ret) { krb5_set_error_string(context, "PKINIT: out of memory"); goto out; } } ret = _krb5_pk_verify_sign(context,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -