📄 pkinit.c
字号:
/* * Copyright (c) 2003 - 2007 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 "krb5_locl.h"RCSID("$Id: pkinit.c 22673 2008-03-10 15:00:05Z lha $");struct krb5_dh_moduli { char *name; unsigned long bits; heim_integer p; heim_integer g; heim_integer q;};#ifdef PKINIT#include <heim_asn1.h>#include <rfc2459_asn1.h>#include <cms_asn1.h>#include <pkcs8_asn1.h>#include <pkcs9_asn1.h>#include <pkcs12_asn1.h>#include <pkinit_asn1.h>#include <asn1_err.h>#include <der.h>#include <hx509.h>enum { COMPAT_WIN2K = 1, COMPAT_IETF = 2};struct krb5_pk_identity { hx509_context hx509ctx; hx509_verify_ctx verify_ctx; hx509_certs certs; hx509_certs anchors; hx509_certs certpool; hx509_revoke_ctx revokectx;};struct krb5_pk_cert { hx509_cert cert;};struct krb5_pk_init_ctx_data { struct krb5_pk_identity *id; DH *dh; krb5_data *clientDHNonce; struct krb5_dh_moduli **m; hx509_peer_info peer; int type; unsigned int require_binding:1; unsigned int require_eku:1; unsigned int require_krbtgt_otherName:1; unsigned int require_hostname_match:1; unsigned int trustedCertifiers:1;};static void_krb5_pk_copy_error(krb5_context context, hx509_context hx509ctx, int hxret, const char *fmt, ...) __attribute__ ((format (printf, 4, 5)));/* * */void KRB5_LIB_FUNCTION_krb5_pk_cert_free(struct krb5_pk_cert *cert){ if (cert->cert) { hx509_cert_free(cert->cert); } free(cert);}static krb5_error_codeBN_to_integer(krb5_context context, BIGNUM *bn, heim_integer *integer){ integer->length = BN_num_bytes(bn); integer->data = malloc(integer->length); if (integer->data == NULL) { krb5_clear_error_string(context); return ENOMEM; } BN_bn2bin(bn, integer->data); integer->negative = BN_is_negative(bn); return 0;}static BIGNUM *integer_to_BN(krb5_context context, const char *field, const 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;}struct certfind { const char *type; const heim_oid *oid;};/* * Try searchin the key by to use by first looking for for PK-INIT * EKU, then the Microsoft smart card EKU and last, no special EKU at all. */static krb5_error_codefind_cert(krb5_context context, struct krb5_pk_identity *id, hx509_query *q, hx509_cert *cert){ struct certfind cf[3] = { { "PKINIT EKU" }, { "MS EKU" }, { "no" } }; int i, ret; cf[0].oid = oid_id_pkekuoid(); cf[1].oid = oid_id_pkinit_ms_eku(); cf[2].oid = NULL; for (i = 0; i < sizeof(cf)/sizeof(cf[0]); i++) { ret = hx509_query_match_eku(q, cf[i].oid); if (ret) { _krb5_pk_copy_error(context, id->hx509ctx, ret, "Failed setting %s OID", cf[i].type); return ret; } ret = hx509_certs_find(id->hx509ctx, id->certs, q, cert); if (ret == 0) break; _krb5_pk_copy_error(context, id->hx509ctx, ret, "Failed cert for finding %s OID", cf[i].type); } return ret;}static krb5_error_codecreate_signature(krb5_context context, const heim_oid *eContentType, krb5_data *eContent, struct krb5_pk_identity *id, hx509_peer_info peer, krb5_data *sd_data){ hx509_cert cert = NULL; hx509_query *q = NULL; int ret; ret = hx509_query_alloc(id->hx509ctx, &q); if (ret) { _krb5_pk_copy_error(context, id->hx509ctx, ret, "Allocate query to find signing certificate"); return ret; } hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY); hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE); ret = find_cert(context, id, q, &cert); hx509_query_free(id->hx509ctx, q); if (ret) return ret; ret = hx509_cms_create_signed_1(id->hx509ctx, 0, eContentType, eContent->data, eContent->length, NULL, cert, peer, NULL, id->certs, sd_data); hx509_cert_free(cert); if (ret) { _krb5_pk_copy_error(context, id->hx509ctx, ret, "Create CMS signedData"); return ret; } return 0;}static intcert2epi(hx509_context context, void *ctx, hx509_cert c){ ExternalPrincipalIdentifiers *ids = ctx; ExternalPrincipalIdentifier id; hx509_name subject = NULL; void *p; int ret; memset(&id, 0, sizeof(id)); ret = hx509_cert_get_subject(c, &subject); if (ret) return ret; if (hx509_name_is_null_p(subject) != 0) { id.subjectName = calloc(1, sizeof(*id.subjectName)); if (id.subjectName == NULL) { hx509_name_free(&subject); free_ExternalPrincipalIdentifier(&id); return ENOMEM; } ret = hx509_name_binary(subject, id.subjectName); if (ret) { hx509_name_free(&subject); free_ExternalPrincipalIdentifier(&id); return ret; } } hx509_name_free(&subject); id.issuerAndSerialNumber = calloc(1, sizeof(*id.issuerAndSerialNumber)); if (id.issuerAndSerialNumber == NULL) { free_ExternalPrincipalIdentifier(&id); return ENOMEM; } { IssuerAndSerialNumber iasn; hx509_name issuer; size_t size; memset(&iasn, 0, sizeof(iasn)); ret = hx509_cert_get_issuer(c, &issuer); if (ret) { free_ExternalPrincipalIdentifier(&id); return ret; } ret = hx509_name_to_Name(issuer, &iasn.issuer); hx509_name_free(&issuer); if (ret) { free_ExternalPrincipalIdentifier(&id); return ret; } ret = hx509_cert_get_serialnumber(c, &iasn.serialNumber); if (ret) { free_IssuerAndSerialNumber(&iasn); free_ExternalPrincipalIdentifier(&id); return ret; } ASN1_MALLOC_ENCODE(IssuerAndSerialNumber, id.issuerAndSerialNumber->data, id.issuerAndSerialNumber->length, &iasn, &size, ret); free_IssuerAndSerialNumber(&iasn); if (ret) return ret; if (id.issuerAndSerialNumber->length != size) abort(); } id.subjectKeyIdentifier = NULL; p = realloc(ids->val, sizeof(ids->val[0]) * (ids->len + 1)); if (p == NULL) { free_ExternalPrincipalIdentifier(&id); return ENOMEM; } ids->val = p; ids->val[ids->len] = id; ids->len++; return 0;}static krb5_error_codebuild_edi(krb5_context context, hx509_context hx509ctx, hx509_certs certs, ExternalPrincipalIdentifiers *ids){ return hx509_certs_iter(hx509ctx, certs, cert2epi, ids);}static krb5_error_codebuild_auth_pack(krb5_context context, unsigned nonce, krb5_pk_init_ctx ctx, DH *dh, const KDC_REQ_BODY *body, AuthPack *a){ size_t buf_size, len; krb5_error_code ret; void *buf; krb5_timestamp sec; int32_t usec; Checksum checksum; krb5_clear_error_string(context); memset(&checksum, 0, sizeof(checksum)); krb5_us_timeofday(context, &sec, &usec); a->pkAuthenticator.ctime = sec; a->pkAuthenticator.nonce = nonce; ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, body, &len, ret); if (ret) 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) return ret; ALLOC(a->pkAuthenticator.paChecksum, 1); if (a->pkAuthenticator.paChecksum == NULL) { krb5_set_error_string(context, "malloc: out of memory"); return ENOMEM; } ret = krb5_data_copy(a->pkAuthenticator.paChecksum, checksum.checksum.data, checksum.checksum.length); free_Checksum(&checksum); if (ret) return ret; if (dh) { DomainParameters dp; heim_integer dh_pub_key; krb5_data dhbuf; size_t size; if (1 /* support_cached_dh */) { ALLOC(a->clientDHNonce, 1); if (a->clientDHNonce == NULL) { krb5_clear_error_string(context); return ENOMEM; } ret = krb5_data_alloc(a->clientDHNonce, 40); if (a->clientDHNonce == NULL) { krb5_clear_error_string(context); return ENOMEM; } memset(a->clientDHNonce->data, 0, a->clientDHNonce->length); ret = krb5_copy_data(context, a->clientDHNonce, &ctx->clientDHNonce); if (ret) return ret; } ALLOC(a->clientPublicValue, 1); if (a->clientPublicValue == NULL) return ENOMEM; ret = der_copy_oid(oid_id_dhpublicnumber(), &a->clientPublicValue->algorithm.algorithm); if (ret) return ret; memset(&dp, 0, sizeof(dp)); ret = BN_to_integer(context, dh->p, &dp.p); if (ret) { free_DomainParameters(&dp); return ret; } ret = BN_to_integer(context, dh->g, &dp.g); if (ret) { free_DomainParameters(&dp); return ret; } ret = BN_to_integer(context, dh->q, &dp.q); if (ret) { free_DomainParameters(&dp); return ret; } dp.j = NULL; dp.validationParms = NULL; a->clientPublicValue->algorithm.parameters = malloc(sizeof(*a->clientPublicValue->algorithm.parameters)); if (a->clientPublicValue->algorithm.parameters == NULL) { free_DomainParameters(&dp); return ret; } ASN1_MALLOC_ENCODE(DomainParameters, a->clientPublicValue->algorithm.parameters->data, a->clientPublicValue->algorithm.parameters->length, &dp, &size, ret); free_DomainParameters(&dp); if (ret) return ret; if (size != a->clientPublicValue->algorithm.parameters->length) krb5_abortx(context, "Internal ASN1 encoder error"); ret = BN_to_integer(context, dh->pub_key, &dh_pub_key); if (ret) return ret; ASN1_MALLOC_ENCODE(DHPublicKey, dhbuf.data, dhbuf.length, &dh_pub_key, &size, ret); der_free_heim_integer(&dh_pub_key); if (ret) return ret; if (size != dhbuf.length) krb5_abortx(context, "asn1 internal error"); a->clientPublicValue->subjectPublicKey.length = dhbuf.length * 8; a->clientPublicValue->subjectPublicKey.data = dhbuf.data; } { a->supportedCMSTypes = calloc(1, sizeof(*a->supportedCMSTypes)); if (a->supportedCMSTypes == NULL) return ENOMEM; ret = hx509_crypto_available(ctx->id->hx509ctx, HX509_SELECT_ALL, NULL, &a->supportedCMSTypes->val, &a->supportedCMSTypes->len); if (ret) return ret; } return ret;}krb5_error_code KRB5_LIB_FUNCTION_krb5_pk_mk_ContentInfo(krb5_context context, const krb5_data *buf, const heim_oid *oid, struct ContentInfo *content_info){ krb5_error_code ret; ret = der_copy_oid(oid, &content_info->contentType); if (ret) return ret; ALLOC(content_info->content, 1); if (content_info->content == NULL) return ENOMEM; content_info->content->data = malloc(buf->length); if (content_info->content->data == NULL) return ENOMEM; memcpy(content_info->content->data, buf->data, buf->length); content_info->content->length = buf->length; return 0;}static krb5_error_codepk_mk_padata(krb5_context context, krb5_pk_init_ctx ctx, const KDC_REQ_BODY *req_body, unsigned nonce, METHOD_DATA *md){ struct ContentInfo content_info; krb5_error_code ret; const heim_oid *oid; size_t size; krb5_data buf, sd_buf; int pa_type; krb5_data_zero(&buf); krb5_data_zero(&sd_buf); memset(&content_info, 0, sizeof(content_info)); if (ctx->type == COMPAT_WIN2K) { AuthPack_Win2k ap;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -