📄 pkinit.c
字号:
/* * Copyright (c) 2003 - 2006 Kungliga Tekniska H鰃skolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#include "kdc_locl.h"RCSID("$Id: pkinit.c 22243 2007-12-08 23:39:30Z lha $");#ifdef PKINIT#include <heim_asn1.h>#include <rfc2459_asn1.h>#include <cms_asn1.h>#include <pkinit_asn1.h>#include <hx509.h>#include "crypto-headers.h"/* XXX copied from lib/krb5/pkinit.c */struct krb5_pk_identity { hx509_context hx509ctx; hx509_verify_ctx verify_ctx; hx509_certs certs; hx509_certs anchors; hx509_certs certpool; hx509_revoke_ctx revoke;};enum pkinit_type { PKINIT_COMPAT_WIN2K = 1, PKINIT_COMPAT_27 = 3};struct pk_client_params { enum pkinit_type type; BIGNUM *dh_public_key; hx509_cert cert; unsigned nonce; DH *dh; EncryptionKey reply_key; char *dh_group_name; hx509_peer_info peer; hx509_certs client_anchors;};struct pk_principal_mapping { unsigned int len; struct pk_allowed_princ { krb5_principal principal; char *subject; } *val;};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;/* * */static krb5_error_codepk_check_pkauthenticator_win2k(krb5_context context, PKAuthenticator_Win2k *a, const KDC_REQ *req){ krb5_timestamp now; krb5_timeofday (context, &now); /* XXX cusec */ if (a->ctime == 0 || abs(a->ctime - now) > context->max_skew) { krb5_clear_error_string(context); return KRB5KRB_AP_ERR_SKEW; } return 0;}static krb5_error_codepk_check_pkauthenticator(krb5_context context, PKAuthenticator *a, const KDC_REQ *req){ u_char *buf = NULL; size_t buf_size; krb5_error_code ret; size_t len; krb5_timestamp now; Checksum checksum; krb5_timeofday (context, &now); /* XXX cusec */ if (a->ctime == 0 || abs(a->ctime - now) > context->max_skew) { krb5_clear_error_string(context); return KRB5KRB_AP_ERR_SKEW; } ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, &req->req_body, &len, ret); if (ret) { krb5_clear_error_string(context); return ret; } if (buf_size != len) krb5_abortx(context, "Internal error in ASN.1 encoder"); ret = krb5_create_checksum(context, NULL, 0, CKSUMTYPE_SHA1, buf, len, &checksum); free(buf); if (ret) { krb5_clear_error_string(context); return ret; } if (a->paChecksum == NULL) { krb5_clear_error_string(context); ret = KRB5_KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED; goto out; } if (der_heim_octet_string_cmp(a->paChecksum, &checksum.checksum) != 0) { krb5_clear_error_string(context); ret = KRB5KRB_ERR_GENERIC; }out: free_Checksum(&checksum); return ret;}void_kdc_pk_free_client_param(krb5_context context, pk_client_params *client_params){ if (client_params->cert) hx509_cert_free(client_params->cert); if (client_params->dh) DH_free(client_params->dh); if (client_params->dh_public_key) BN_free(client_params->dh_public_key); krb5_free_keyblock_contents(context, &client_params->reply_key); if (client_params->dh_group_name) free(client_params->dh_group_name); if (client_params->peer) hx509_peer_info_free(client_params->peer); if (client_params->client_anchors) hx509_certs_free(&client_params->client_anchors); memset(client_params, 0, sizeof(*client_params)); free(client_params);}static krb5_error_codegenerate_dh_keyblock(krb5_context context, pk_client_params *client_params, krb5_enctype enctype, krb5_keyblock *reply_key){ unsigned char *dh_gen_key = NULL; krb5_keyblock key; krb5_error_code ret; size_t dh_gen_keylen, size; memset(&key, 0, sizeof(key)); if (!DH_generate_key(client_params->dh)) { krb5_set_error_string(context, "Can't generate Diffie-Hellman keys"); ret = KRB5KRB_ERR_GENERIC; goto out; } if (client_params->dh_public_key == NULL) { krb5_set_error_string(context, "dh_public_key"); ret = KRB5KRB_ERR_GENERIC; goto out; } dh_gen_keylen = DH_size(client_params->dh); size = BN_num_bytes(client_params->dh->p); if (size < dh_gen_keylen) size = dh_gen_keylen; dh_gen_key = malloc(size); if (dh_gen_key == NULL) { krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; goto out; } memset(dh_gen_key, 0, size - dh_gen_keylen); dh_gen_keylen = DH_compute_key(dh_gen_key + (size - dh_gen_keylen), client_params->dh_public_key, client_params->dh); if (dh_gen_keylen == -1) { krb5_set_error_string(context, "Can't compute Diffie-Hellman key"); ret = KRB5KRB_ERR_GENERIC; goto out; } ret = _krb5_pk_octetstring2key(context, enctype, dh_gen_key, dh_gen_keylen, NULL, NULL, reply_key); out: if (dh_gen_key) free(dh_gen_key); if (key.keyvalue.data) krb5_free_keyblock_contents(context, &key); return ret;}static BIGNUM *integer_to_BN(krb5_context context, const char *field, heim_integer *f){ BIGNUM *bn; bn = BN_bin2bn((const unsigned char *)f->data, f->length, NULL); if (bn == NULL) { krb5_set_error_string(context, "PKINIT: parsing BN failed %s", field); return NULL; } BN_set_negative(bn, f->negative); return bn;}static krb5_error_codeget_dh_param(krb5_context context, krb5_kdc_configuration *config, SubjectPublicKeyInfo *dh_key_info, pk_client_params *client_params){ DomainParameters dhparam; DH *dh = NULL; krb5_error_code ret; memset(&dhparam, 0, sizeof(dhparam)); if (der_heim_oid_cmp(&dh_key_info->algorithm.algorithm, oid_id_dhpublicnumber())) { krb5_set_error_string(context, "PKINIT invalid oid in clientPublicValue"); return KRB5_BADMSGTYPE; } if (dh_key_info->algorithm.parameters == NULL) { krb5_set_error_string(context, "PKINIT missing algorithm parameter " "in clientPublicValue"); return KRB5_BADMSGTYPE; } ret = decode_DomainParameters(dh_key_info->algorithm.parameters->data, dh_key_info->algorithm.parameters->length, &dhparam, NULL); if (ret) { krb5_set_error_string(context, "Can't decode algorithm " "parameters in clientPublicValue"); goto out; } if ((dh_key_info->subjectPublicKey.length % 8) != 0) { ret = KRB5_BADMSGTYPE; krb5_set_error_string(context, "PKINIT: subjectPublicKey not aligned " "to 8 bit boundary"); goto out; } ret = _krb5_dh_group_ok(context, config->pkinit_dh_min_bits, &dhparam.p, &dhparam.g, &dhparam.q, moduli, &client_params->dh_group_name); if (ret) { /* XXX send back proposal of better group */ goto out; } dh = DH_new(); if (dh == NULL) { krb5_set_error_string(context, "Cannot create DH structure"); ret = ENOMEM; goto out; } ret = KRB5_BADMSGTYPE; dh->p = integer_to_BN(context, "DH prime", &dhparam.p); if (dh->p == NULL) goto out; dh->g = integer_to_BN(context, "DH base", &dhparam.g); if (dh->g == NULL) goto out; dh->q = integer_to_BN(context, "DH p-1 factor", &dhparam.q); if (dh->g == NULL) goto out; { heim_integer glue; size_t size; ret = decode_DHPublicKey(dh_key_info->subjectPublicKey.data, dh_key_info->subjectPublicKey.length / 8, &glue, &size); if (ret) { krb5_clear_error_string(context); return ret; } client_params->dh_public_key = integer_to_BN(context, "subjectPublicKey", &glue); der_free_heim_integer(&glue); if (client_params->dh_public_key == NULL) goto out; } client_params->dh = dh; dh = NULL; ret = 0; out: if (dh) DH_free(dh); free_DomainParameters(&dhparam); return ret;}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_string(context); return 0; } hx509_verify_set_time(kdc_identity->verify_ctx, _kdc_now.tv_sec); client_params = calloc(1, sizeof(*client_params)); if (client_params == NULL) { krb5_clear_error_string(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_string(context, "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_string(context, "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_string(context, "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_string(context, "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_string(context, "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_string(context, "Can't unwrap ContentInfo: %d", ret); goto out; } } else { krb5_clear_error_string(context); ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP; goto out; } ret = der_heim_oid_cmp(&contentInfoOid, oid_id_pkcs7_signedData()); if (ret != 0) { krb5_set_error_string(context, "PK-AS-REQ-Win2k invalid content " "type oid"); ret = KRB5KRB_ERR_GENERIC; goto out; } if (!have_data) { krb5_set_error_string(context, "PK-AS-REQ-Win2k no signed auth pack"); ret = KRB5KRB_ERR_GENERIC; 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) { krb5_set_error_string(context, "got wrong oid for pkauthdata"); ret = KRB5_BADMSGTYPE; goto out; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -