/* Define to 1 if you have the `krb5_free_data_contents' function. */
#define HAVE_KRB5_FREE_DATA_CONTENTS 1
/* Define to 1 if you have the `krb5_free_error_string' function. */
-#define HAVE_KRB5_FREE_ERROR_STRING 1
+/* #undef HAVE_KRB5_FREE_ERROR_STRING */
+/* Define to 1 if you have the `krb5_free_error_message' function. */
+#define HAVE_KRB5_FREE_ERROR_MESSAGE 1
/* Define to 1 if you have the `krb5_free_keytab_entry_contents' function. */
/* #undef HAVE_KRB5_FREE_KEYTAB_ENTRY_CONTENTS */
/* Define to 1 if you have the `krb5_free_ktypes' function. */
#define HAVE_KRB5_GET_DEFAULT_IN_TKT_ETYPES 1
/* Define to 1 if you have the `krb5_get_error_string' function. */
#define HAVE_KRB5_GET_ERROR_STRING 1
+/* Define to 1 if you have the `krb5_get_error_message' function. */
+#define HAVE_KRB5_GET_ERROR_MESSAGE 1
/* Define to 1 if you have the `krb5_get_permitted_enctypes' function. */
/* #undef HAVE_KRB5_GET_PERMITTED_ENCTYPES */
/* Define to 1 if you have the `krb5_get_pw_salt' function. */
krb5_principal princ;
krb5_error_code ret;
char *name;
- char **realm;
if (cred->ccache_obtained > obtained) {
return 0;
return ret;
}
- realm = krb5_princ_realm(ccache->smb_krb5_context->krb5_context, princ);
-
cli_credentials_set_principal(cred, name, obtained);
free(name);
gensec_gssapi_state->input_chan_bindings = GSS_C_NO_CHANNEL_BINDINGS;
gensec_gssapi_state->want_flags = 0;
+ if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "delegation_by_kdc_policy", true)) {
+ gensec_gssapi_state->want_flags |= GSS_C_DELEG_POLICY_FLAG;
+ }
if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "mutual", true)) {
gensec_gssapi_state->want_flags |= GSS_C_MUTUAL_FLAG;
}
{
char *ret;
-#if defined(HAVE_KRB5_GET_ERROR_STRING) && defined(HAVE_KRB5_FREE_ERROR_STRING)
- char *context_error = krb5_get_error_string(context);
+#if defined(HAVE_KRB5_GET_ERROR_MESSAGE) && defined(HAVE_KRB5_FREE_ERROR_MESSAGE)
+ const char *context_error = krb5_get_error_message(context, code);
if (context_error) {
ret = talloc_asprintf(mem_ctx, "%s: %s", error_message(code), context_error);
- krb5_free_error_string(context, context_error);
+ krb5_free_error_message(context, context_error);
return ret;
}
#endif
AC_CHECK_FUNC_EXT(krb5_enctypes_compatible_keys, $KRB5_LIBS)
AC_CHECK_FUNC_EXT(krb5_get_error_string, $KRB5_LIBS)
AC_CHECK_FUNC_EXT(krb5_free_error_string, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_get_error_message, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_free_error_message, $KRB5_LIBS)
AC_CHECK_FUNC_EXT(krb5_initlog, $KRB5_LIBS)
AC_CHECK_FUNC_EXT(krb5_addlog_func, $KRB5_LIBS)
AC_CHECK_FUNC_EXT(krb5_set_warn_dest, $KRB5_LIBS)
{
krb5_error_code code = 0;
krb5_creds my_creds;
- krb5_get_init_creds_opt options;
+ krb5_get_init_creds_opt *options;
- krb5_get_init_creds_opt_init(&options);
+ if ((code = krb5_get_init_creds_opt_alloc(ctx, &options))) {
+ return code;
+ }
- krb5_get_init_creds_opt_set_default_flags(ctx, NULL, NULL, &options);
+ krb5_get_init_creds_opt_set_default_flags(ctx, NULL, NULL, options);
if ((code = krb5_get_init_creds_keyblock(ctx, &my_creds, principal, keyblock,
- 0, NULL, &options))) {
+ 0, NULL, options))) {
return code;
}
if ((code = krb5_cc_initialize(ctx, cc, principal))) {
+ krb5_get_init_creds_opt_free(ctx, options);
krb5_free_cred_contents(ctx, &my_creds);
return code;
}
if ((code = krb5_cc_store_cred(ctx, cc, &my_creds))) {
+ krb5_get_init_creds_opt_free(ctx, options);
krb5_free_cred_contents(ctx, &my_creds);
return code;
}
*kdc_time = (time_t) my_creds.times.starttime;
}
+ krb5_get_init_creds_opt_free(ctx, options);
krb5_free_cred_contents(ctx, &my_creds);
return 0;
{
krb5_error_code code = 0;
krb5_creds my_creds;
- krb5_get_init_creds_opt options;
+ krb5_get_init_creds_opt *options;
- krb5_get_init_creds_opt_init(&options);
+ if ((code = krb5_get_init_creds_opt_alloc(ctx, &options))) {
+ return code;
+ }
- krb5_get_init_creds_opt_set_default_flags(ctx, NULL, NULL, &options);
+ krb5_get_init_creds_opt_set_default_flags(ctx, NULL, NULL, options);
if ((code = krb5_get_init_creds_password(ctx, &my_creds, principal, password,
NULL,
- NULL, 0, NULL, &options))) {
+ NULL, 0, NULL, options))) {
return code;
}
if ((code = krb5_cc_initialize(ctx, cc, principal))) {
+ krb5_get_init_creds_opt_free(ctx, options);
krb5_free_cred_contents(ctx, &my_creds);
return code;
}
if ((code = krb5_cc_store_cred(ctx, cc, &my_creds))) {
+ krb5_get_init_creds_opt_free(ctx, options);
krb5_free_cred_contents(ctx, &my_creds);
return code;
}
*kdc_time = (time_t) my_creds.times.starttime;
}
+ krb5_get_init_creds_opt_free(ctx, options);
krb5_free_cred_contents(ctx, &my_creds);
return 0;
krb5_principal client_principal_pac;
int i;
- krb5_clear_error_string(context);
+ krb5_clear_error_message(context);
if (k5ret) {
*k5ret = KRB5_PARSE_MALFORMED;
krb5_error_code ret;
krb5_principal principal;
/* perhaps it's a principal with a realm, so return the right 'domain only' response */
- char **realm;
+ char *realm;
ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, name,
- KRB5_PRINCIPAL_PARSE_MUST_REALM, &principal);
+ KRB5_PRINCIPAL_PARSE_REQUIRE_REALM, &principal);
if (ret) {
info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
return WERR_OK;
}
/* This isn't an allocation assignemnt, so it is free'ed with the krb5_free_principal */
- realm = krb5_princ_realm(smb_krb5_context->krb5_context, principal);
+ realm = krb5_principal_get_realm(smb_krb5_context->krb5_context, principal);
- info1->dns_domain_name = talloc_strdup(mem_ctx, *realm);
+ info1->dns_domain_name = talloc_strdup(mem_ctx, realm);
krb5_free_principal(smb_krb5_context->krb5_context, principal);
W_ERROR_HAVE_NO_MEMORY(info1->dns_domain_name);
const char *result_filter = NULL;
krb5_error_code ret;
krb5_principal principal;
- char **realm;
+ char *realm;
char *unparsed_name_short;
const char *domain_attrs[] = { NULL };
struct ldb_result *domain_res = NULL;
}
ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, name,
- KRB5_PRINCIPAL_PARSE_MUST_REALM, &principal);
+ KRB5_PRINCIPAL_PARSE_REQUIRE_REALM, &principal);
if (ret) {
info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
return WERR_OK;
}
- realm = krb5_princ_realm(smb_krb5_context->krb5_context, principal);
+ realm = krb5_principal_get_realm(smb_krb5_context->krb5_context, principal);
ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res,
samdb_partitions_dn(sam_ctx, mem_ctx),
LDB_SCOPE_ONELEVEL,
domain_attrs,
"(&(&(|(&(dnsRoot=%s)(nETBIOSName=*))(nETBIOSName=%s))(objectclass=crossRef))(ncName=*))",
- ldb_binary_encode_string(mem_ctx, *realm),
- ldb_binary_encode_string(mem_ctx, *realm));
+ ldb_binary_encode_string(mem_ctx, realm),
+ ldb_binary_encode_string(mem_ctx, realm));
if (ldb_ret != LDB_SUCCESS) {
DEBUG(2, ("DsCrackNameUPN domain ref search failed: %s", ldb_errstring(sam_ctx)));
-$Id$
Heimdal is a Kerberos 5 implementation.
s/^\s*//;
s/\s*$//;
s/\s+/ /g;
- if($_ =~ /\)$/){
+ if($_ =~ /\)$/ or $_ =~ /DEPRECATED$/){
if(!/^static/ && !/^PRIVATE/){
- if(/(.*)(__attribute__\s?\(.*\))/) {
- $attr = $2;
+ $attr = "";
+ if(m/(.*)(__attribute__\s?\(.*\))/) {
+ $attr .= " $2";
+ $_ = $1;
+ }
+ if(m/(.*)\s(\w+DEPRECATED)/) {
+ $attr .= " $2";
$_ = $1;
- } else {
- $attr = "";
}
# remove outer ()
s/\s*\(/</;
if ($opt_E) {
$public_h_header .= "#ifndef $opt_E
#if defined(_WIN32)
-#define ${opt_E}_FUNCTION _stdcall __declspec(dllimport)
+#define ${opt_E}_FUNCTION __stdcall __declspec(dllimport)
#define ${opt_E}_VARIABLE __declspec(dllimport)
#else
#define ${opt_E}_FUNCTION
$private_h_header .= "#ifndef $opt_E
#if defined(_WIN32)
-#define ${opt_E}_FUNCTION _stdcall __declspec(dllimport)
+#define ${opt_E}_FUNCTION __stdcall __declspec(dllimport)
#define ${opt_E}_VARIABLE __declspec(dllimport)
#else
#define ${opt_E}_FUNCTION
AC_DEFUN([rk_RESOLV],[
-AC_CHECK_HEADERS([arpa/nameser.h])
+AC_CHECK_HEADERS([arpa/nameser.h dns.h])
AC_CHECK_HEADERS(resolv.h, , , [AC_INCLUDES_DEFAULT
#ifdef HAVE_SYS_TYPES_H
],
[0])
+AC_FIND_FUNC_NO_LIBS(dns_search,,
+[
+#ifdef HAVE_DNS_H
+#include <dns.h>
+#endif
+],
+[0,0,0,0,0,0,0,0])
+
+
AC_FIND_FUNC(dn_expand, resolv,
[
#include <stdio.h>
+++ /dev/null
-/*
- * Copyright (c) 1997-2005 Kungliga Tekniska Högskolan
- * (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$");
-
-#include <krb5-v4compat.h>
-
-/*
- * fetch the server from `t', returning the name in malloced memory in
- * `spn' and the entry itself in `server'
- */
-
-static krb5_error_code
-fetch_server (krb5_context context,
- krb5_kdc_configuration *config,
- const Ticket *t,
- char **spn,
- hdb_entry_ex **server,
- const char *from)
-{
- krb5_error_code ret;
- krb5_principal sprinc;
-
- ret = _krb5_principalname2krb5_principal(context, &sprinc,
- t->sname, t->realm);
- if (ret) {
- kdc_log(context, config, 0, "_krb5_principalname2krb5_principal: %s",
- krb5_get_err_text(context, ret));
- return ret;
- }
- ret = krb5_unparse_name(context, sprinc, spn);
- if (ret) {
- krb5_free_principal(context, sprinc);
- kdc_log(context, config, 0, "krb5_unparse_name: %s",
- krb5_get_err_text(context, ret));
- return ret;
- }
- ret = _kdc_db_fetch(context, config, sprinc, HDB_F_GET_SERVER,
- NULL, server);
- krb5_free_principal(context, sprinc);
- if (ret) {
- kdc_log(context, config, 0,
- "Request to convert ticket from %s for unknown principal %s: %s",
- from, *spn, krb5_get_err_text(context, ret));
- if (ret == HDB_ERR_NOENTRY)
- ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
- return ret;
- }
- return 0;
-}
-
-static krb5_error_code
-log_524 (krb5_context context,
- krb5_kdc_configuration *config,
- const EncTicketPart *et,
- const char *from,
- const char *spn)
-{
- krb5_principal client;
- char *cpn;
- krb5_error_code ret;
-
- ret = _krb5_principalname2krb5_principal(context, &client,
- et->cname, et->crealm);
- if (ret) {
- kdc_log(context, config, 0, "_krb5_principalname2krb5_principal: %s",
- krb5_get_err_text (context, ret));
- return ret;
- }
- ret = krb5_unparse_name(context, client, &cpn);
- if (ret) {
- krb5_free_principal(context, client);
- kdc_log(context, config, 0, "krb5_unparse_name: %s",
- krb5_get_err_text (context, ret));
- return ret;
- }
- kdc_log(context, config, 1, "524-REQ %s from %s for %s", cpn, from, spn);
- free(cpn);
- krb5_free_principal(context, client);
- return 0;
-}
-
-static krb5_error_code
-verify_flags (krb5_context context,
- krb5_kdc_configuration *config,
- const EncTicketPart *et,
- const char *spn)
-{
- if(et->endtime < kdc_time){
- kdc_log(context, config, 0, "Ticket expired (%s)", spn);
- return KRB5KRB_AP_ERR_TKT_EXPIRED;
- }
- if(et->flags.invalid){
- kdc_log(context, config, 0, "Ticket not valid (%s)", spn);
- return KRB5KRB_AP_ERR_TKT_NYV;
- }
- return 0;
-}
-
-/*
- * set the `et->caddr' to the most appropriate address to use, where
- * `addr' is the address the request was received from.
- */
-
-static krb5_error_code
-set_address (krb5_context context,
- krb5_kdc_configuration *config,
- EncTicketPart *et,
- struct sockaddr *addr,
- const char *from)
-{
- krb5_error_code ret;
- krb5_address *v4_addr;
-
- v4_addr = malloc (sizeof(*v4_addr));
- if (v4_addr == NULL)
- return ENOMEM;
-
- ret = krb5_sockaddr2address(context, addr, v4_addr);
- if(ret) {
- free (v4_addr);
- kdc_log(context, config, 0, "Failed to convert address (%s)", from);
- return ret;
- }
-
- if (et->caddr && !krb5_address_search (context, v4_addr, et->caddr)) {
- kdc_log(context, config, 0, "Incorrect network address (%s)", from);
- krb5_free_address(context, v4_addr);
- free (v4_addr);
- return KRB5KRB_AP_ERR_BADADDR;
- }
- if(v4_addr->addr_type == KRB5_ADDRESS_INET) {
- /* we need to collapse the addresses in the ticket to a
- single address; best guess is to use the address the
- connection came from */
-
- if (et->caddr != NULL) {
- free_HostAddresses(et->caddr);
- } else {
- et->caddr = malloc (sizeof (*et->caddr));
- if (et->caddr == NULL) {
- krb5_free_address(context, v4_addr);
- free(v4_addr);
- return ENOMEM;
- }
- }
- et->caddr->val = v4_addr;
- et->caddr->len = 1;
- } else {
- krb5_free_address(context, v4_addr);
- free(v4_addr);
- }
- return 0;
-}
-
-
-static krb5_error_code
-encrypt_v4_ticket(krb5_context context,
- krb5_kdc_configuration *config,
- void *buf,
- size_t len,
- krb5_keyblock *skey,
- EncryptedData *reply)
-{
- krb5_crypto crypto;
- krb5_error_code ret;
- ret = krb5_crypto_init(context, skey, ETYPE_DES_PCBC_NONE, &crypto);
- if (ret) {
- free(buf);
- kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
- krb5_get_err_text(context, ret));
- return ret;
- }
-
- ret = krb5_encrypt_EncryptedData(context,
- crypto,
- KRB5_KU_TICKET,
- buf,
- len,
- 0,
- reply);
- krb5_crypto_destroy(context, crypto);
- if(ret) {
- kdc_log(context, config, 0, "Failed to encrypt data: %s",
- krb5_get_err_text(context, ret));
- return ret;
- }
- return 0;
-}
-
-static krb5_error_code
-encode_524_response(krb5_context context,
- krb5_kdc_configuration *config,
- const char *spn, const EncTicketPart et,
- const Ticket *t, hdb_entry_ex *server,
- EncryptedData *ticket, int *kvno)
-{
- krb5_error_code ret;
- int use_2b;
- size_t len;
-
- use_2b = krb5_config_get_bool(context, NULL, "kdc", "use_2b", spn, NULL);
- if(use_2b) {
- ASN1_MALLOC_ENCODE(EncryptedData,
- ticket->cipher.data, ticket->cipher.length,
- &t->enc_part, &len, ret);
-
- if (ret) {
- kdc_log(context, config, 0,
- "Failed to encode v4 (2b) ticket (%s)", spn);
- return ret;
- }
-
- ticket->etype = 0;
- ticket->kvno = NULL;
- *kvno = 213; /* 2b's use this magic kvno */
- } else {
- unsigned char buf[MAX_KTXT_LEN + 4 * 4];
- Key *skey;
-
- if (!config->enable_v4_cross_realm && strcmp (et.crealm, t->realm) != 0) {
- kdc_log(context, config, 0, "524 cross-realm %s -> %s disabled", et.crealm,
- t->realm);
- return KRB5KDC_ERR_POLICY;
- }
-
- ret = _kdc_encode_v4_ticket(context, config,
- buf + sizeof(buf) - 1, sizeof(buf),
- &et, &t->sname, &len);
- if(ret){
- kdc_log(context, config, 0,
- "Failed to encode v4 ticket (%s)", spn);
- return ret;
- }
- ret = _kdc_get_des_key(context, server, TRUE, FALSE, &skey);
- if(ret){
- kdc_log(context, config, 0,
- "no suitable DES key for server (%s)", spn);
- return ret;
- }
- ret = encrypt_v4_ticket(context, config, buf + sizeof(buf) - len, len,
- &skey->key, ticket);
- if(ret){
- kdc_log(context, config, 0,
- "Failed to encrypt v4 ticket (%s)", spn);
- return ret;
- }
- *kvno = server->entry.kvno;
- }
-
- return 0;
-}
-
-/*
- * process a 5->4 request, based on `t', and received `from, addr',
- * returning the reply in `reply'
- */
-
-krb5_error_code
-_kdc_do_524(krb5_context context,
- krb5_kdc_configuration *config,
- const Ticket *t, krb5_data *reply,
- const char *from, struct sockaddr *addr)
-{
- krb5_error_code ret = 0;
- krb5_crypto crypto;
- hdb_entry_ex *server = NULL;
- Key *skey;
- krb5_data et_data;
- EncTicketPart et;
- EncryptedData ticket;
- krb5_storage *sp;
- char *spn = NULL;
- unsigned char buf[MAX_KTXT_LEN + 4 * 4];
- size_t len;
- int kvno = 0;
-
- if(!config->enable_524) {
- ret = KRB5KDC_ERR_POLICY;
- kdc_log(context, config, 0,
- "Rejected ticket conversion request from %s", from);
- goto out;
- }
-
- ret = fetch_server (context, config, t, &spn, &server, from);
- if (ret) {
- goto out;
- }
-
- ret = hdb_enctype2key(context, &server->entry, t->enc_part.etype, &skey);
- if(ret){
- kdc_log(context, config, 0,
- "No suitable key found for server (%s) from %s", spn, from);
- goto out;
- }
- ret = krb5_crypto_init(context, &skey->key, 0, &crypto);
- if (ret) {
- kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
- krb5_get_err_text(context, ret));
- goto out;
- }
- ret = krb5_decrypt_EncryptedData (context,
- crypto,
- KRB5_KU_TICKET,
- &t->enc_part,
- &et_data);
- krb5_crypto_destroy(context, crypto);
- if(ret){
- kdc_log(context, config, 0,
- "Failed to decrypt ticket from %s for %s", from, spn);
- goto out;
- }
- ret = krb5_decode_EncTicketPart(context, et_data.data, et_data.length,
- &et, &len);
- krb5_data_free(&et_data);
- if(ret){
- kdc_log(context, config, 0,
- "Failed to decode ticket from %s for %s", from, spn);
- goto out;
- }
-
- ret = log_524 (context, config, &et, from, spn);
- if (ret) {
- free_EncTicketPart(&et);
- goto out;
- }
-
- ret = verify_flags (context, config, &et, spn);
- if (ret) {
- free_EncTicketPart(&et);
- goto out;
- }
-
- ret = set_address (context, config, &et, addr, from);
- if (ret) {
- free_EncTicketPart(&et);
- goto out;
- }
-
- ret = encode_524_response(context, config, spn, et, t,
- server, &ticket, &kvno);
- free_EncTicketPart(&et);
-
- out:
- /* make reply */
- memset(buf, 0, sizeof(buf));
- sp = krb5_storage_from_mem(buf, sizeof(buf));
- if (sp) {
- krb5_store_int32(sp, ret);
- if(ret == 0){
- krb5_store_int32(sp, kvno);
- krb5_store_data(sp, ticket.cipher);
- /* Aargh! This is coded as a KTEXT_ST. */
- krb5_storage_seek(sp, MAX_KTXT_LEN - ticket.cipher.length, SEEK_CUR);
- krb5_store_int32(sp, 0); /* mbz */
- free_EncryptedData(&ticket);
- }
- ret = krb5_storage_to_data(sp, reply);
- reply->length = krb5_storage_seek(sp, 0, SEEK_CUR);
- krb5_storage_free(sp);
- } else
- krb5_data_zero(reply);
- if(spn)
- free(spn);
- if(server)
- _kdc_free_ent (context, server);
- return ret;
-}
krb5_config_get_bool_default(context, NULL,
c->enable_v4,
"kdc", "enable-524", NULL);
+#ifdef DIGEST
c->enable_digest =
krb5_config_get_bool_default(context, NULL,
FALSE,
c->enable_digest = 0;
}
}
+#endif
+#ifdef KX509
c->enable_kx509 =
krb5_config_get_bool_default(context, NULL,
FALSE,
c->enable_kx509 = FALSE;
}
}
+#endif
c->check_ticket_addresses =
krb5_config_get_bool_default(context, NULL,
"enable-pkinit",
NULL);
if (c->enable_pkinit) {
- const char *user_id, *anchors, *ocsp_file;
+ const char *user_id, *anchors, *file;
char **pool_list, **revoke_list;
user_id =
krb5_config_get_strings(context, NULL,
"kdc", "pkinit_revoke", NULL);
- ocsp_file =
- krb5_config_get_string(context, NULL,
- "kdc", "pkinit_kdc_ocsp", NULL);
- if (ocsp_file) {
- c->pkinit_kdc_ocsp_file = strdup(ocsp_file);
+ file = krb5_config_get_string(context, NULL,
+ "kdc", "pkinit_kdc_ocsp", NULL);
+ if (file) {
+ c->pkinit_kdc_ocsp_file = strdup(file);
if (c->pkinit_kdc_ocsp_file == NULL)
krb5_errx(context, 1, "out of memory");
}
+ file = krb5_config_get_string(context, NULL,
+ "kdc", "pkinit_kdc_friendly_name", NULL);
+ if (file) {
+ c->pkinit_kdc_friendly_name = strdup(file);
+ if (c->pkinit_kdc_friendly_name == NULL)
+ krb5_errx(context, 1, "out of memory");
+ }
+
+
_kdc_pk_initialize(context, c, user_id, anchors,
pool_list, revoke_list);
#include "kdc_locl.h"
#include <hex.h>
-RCSID("$Id$");
+#ifdef DIGEST
#define MS_CHAP_V2 0x20
#define CHAP_MD5 0x10
krb5_error_code
_kdc_do_digest(krb5_context context,
krb5_kdc_configuration *config,
- const DigestREQ *req, krb5_data *reply,
+ const struct DigestREQ *req, krb5_data *reply,
const char *from, struct sockaddr *addr)
{
krb5_error_code ret = 0;
memset(&ireq, 0, sizeof(ireq));
memset(&r, 0, sizeof(r));
memset(&rep, 0, sizeof(rep));
+ memset(&res, 0, sizeof(res));
kdc_log(context, config, 0, "Digest request from %s", from);
hex_encode(buf.data, buf.length, &r.u.initReply.opaque);
free(buf.data);
+ krb5_data_zero(&buf);
if (r.u.initReply.opaque == NULL) {
krb5_clear_error_message(context);
ret = ENOMEM;
ret = decode_Checksum(buf.data, buf.length, &res, NULL);
free(buf.data);
+ krb5_data_zero(&buf);
if (ret) {
- krb5_set_error_message(context, ret, "Failed to decode digest Checksum");
+ krb5_set_error_message(context, ret,
+ "Failed to decode digest Checksum");
goto out;
}
ret = krb5_verify_checksum(context, crypto,
KRB5_KU_DIGEST_OPAQUE,
buf.data, buf.length, &res);
+ free_Checksum(&res);
+ krb5_data_free(&buf);
krb5_crypto_destroy(context, crypto);
crypto = NULL;
if (ret)
krb5_set_error_message(context, ret, "NTLM storage read flags");
goto out;
}
+ krb5_storage_free(sp);
+ sp = NULL;
krb5_data_free(&buf);
if ((flags & NTLM_NEG_NTLM) == 0) {
free (client_name);
krb5_data_free(&buf);
krb5_data_free(&serverNonce);
+ free_Checksum(&res);
free_DigestREP(&rep);
free_DigestRepInner(&r);
free_DigestReqInner(&ireq);
return ret;
}
+
+#endif /* DIGEST */
#include <parse_units.h>
#include <krb5.h>
#include <krb5_locl.h>
+#ifdef DIGEST
#include <digest_asn1.h>
+#endif
+#ifdef KX509
#include <kx509_asn1.h>
+#endif
#include <hdb.h>
#include <hdb_err.h>
#include <der.h>
+#ifndef NO_NTLM
#include <heimntlm.h>
+#endif
#include <windc_plugin.h>
#undef ALLOC
#include "kdc_locl.h"
-RCSID("$Id$");
+#ifdef KRB4
#include <krb5-v4compat.h>
#include <rx.h>
krb5_storage_free (sp);
return ret;
}
+
+#endif /* KRB4 */
krb5_boolean enable_pkinit;
krb5_boolean pkinit_princ_in_cert;
char *pkinit_kdc_ocsp_file;
+ char *pkinit_kdc_friendly_name;
int pkinit_dh_min_bits;
int pkinit_require_binding;
+ int pkinit_allow_proxy_certs;
krb5_log_facility *logf;
} krb5_kdc_configuration;
+struct krb5_kdc_service {
+ unsigned int flags;
+#define KS_KRB5 1
+#define KS_NO_LENGTH 2
+ krb5_error_code (*process)(krb5_context context,
+ krb5_kdc_configuration *config,
+ krb5_data *req_buffer,
+ krb5_data *reply,
+ const char *from,
+ struct sockaddr *addr,
+ int datagram_reply,
+ int *claim);
+};
+
#include <kdc-protos.h>
#endif
#include "kdc.h"
typedef struct pk_client_params pk_client_params;
+struct DigestREQ;
+struct Kx509Request;
#include <kdc-private.h>
extern sig_atomic_t exit_flag;
extern int enable_http;
+#ifdef SUPPORT_DETACH
+
#define DETACH_IS_DEFAULT FALSE
extern int detach_from_console;
+#endif
extern const struct units _kdc_digestunits[];
+++ /dev/null
-/*
- * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan
- * (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"
-
-#include <krb5-v4compat.h>
-
-RCSID("$Id$");
-
-#ifndef swap32
-static uint32_t
-swap32(uint32_t x)
-{
- return ((x << 24) & 0xff000000) |
- ((x << 8) & 0xff0000) |
- ((x >> 8) & 0xff00) |
- ((x >> 24) & 0xff);
-}
-#endif /* swap32 */
-
-int
-_kdc_maybe_version4(unsigned char *buf, int len)
-{
- return len > 0 && *buf == 4;
-}
-
-static void
-make_err_reply(krb5_context context, krb5_data *reply,
- int code, const char *msg)
-{
- _krb5_krb_cr_err_reply(context, "", "", "",
- kdc_time, code, msg, reply);
-}
-
-struct valid_princ_ctx {
- krb5_kdc_configuration *config;
- unsigned flags;
-};
-
-static krb5_boolean
-valid_princ(krb5_context context,
- void *funcctx,
- krb5_principal princ)
-{
- struct valid_princ_ctx *ctx = funcctx;
- krb5_error_code ret;
- char *s;
- hdb_entry_ex *ent;
-
- ret = krb5_unparse_name(context, princ, &s);
- if (ret)
- return FALSE;
- ret = _kdc_db_fetch(context, ctx->config, princ, ctx->flags, NULL, &ent);
- if (ret) {
- kdc_log(context, ctx->config, 7, "Lookup %s failed: %s", s,
- krb5_get_err_text (context, ret));
- free(s);
- return FALSE;
- }
- kdc_log(context, ctx->config, 7, "Lookup %s succeeded", s);
- free(s);
- _kdc_free_ent(context, ent);
- return TRUE;
-}
-
-krb5_error_code
-_kdc_db_fetch4(krb5_context context,
- krb5_kdc_configuration *config,
- const char *name, const char *instance, const char *realm,
- unsigned flags,
- hdb_entry_ex **ent)
-{
- krb5_principal p;
- krb5_error_code ret;
- struct valid_princ_ctx ctx;
-
- ctx.config = config;
- ctx.flags = flags;
-
- ret = krb5_425_conv_principal_ext2(context, name, instance, realm,
- valid_princ, &ctx, 0, &p);
- if(ret)
- return ret;
- ret = _kdc_db_fetch(context, config, p, flags, NULL, ent);
- krb5_free_principal(context, p);
- return ret;
-}
-
-#define RCHECK(X, L) if(X){make_err_reply(context, reply, KFAILURE, "Packet too short"); goto L;}
-
-/*
- * Process the v4 request in `buf, len' (received from `addr'
- * (with string `from').
- * Return an error code and a reply in `reply'.
- */
-
-krb5_error_code
-_kdc_do_version4(krb5_context context,
- krb5_kdc_configuration *config,
- unsigned char *buf,
- size_t len,
- krb5_data *reply,
- const char *from,
- struct sockaddr_in *addr)
-{
- krb5_storage *sp;
- krb5_error_code ret = EINVAL;
- hdb_entry_ex *client = NULL, *server = NULL;
- Key *ckey, *skey;
- int8_t pvno;
- int8_t msg_type;
- int lsb;
- char *name = NULL, *inst = NULL, *realm = NULL;
- char *sname = NULL, *sinst = NULL;
- int32_t req_time;
- time_t max_life;
- uint8_t life;
- char client_name[256];
- char server_name[256];
-
- if(!config->enable_v4) {
- kdc_log(context, config, 0,
- "Rejected version 4 request from %s", from);
- make_err_reply(context, reply, KRB4ET_KDC_GEN_ERR,
- "Function not enabled");
- return 0;
- }
-
- sp = krb5_storage_from_mem(buf, len);
- RCHECK(krb5_ret_int8(sp, &pvno), out);
- if(pvno != 4){
- kdc_log(context, config, 0,
- "Protocol version mismatch (krb4) (%d)", pvno);
- make_err_reply(context, reply, KRB4ET_KDC_PKT_VER, "protocol mismatch");
- ret = KRB4ET_KDC_PKT_VER;
- goto out;
- }
- RCHECK(krb5_ret_int8(sp, &msg_type), out);
- lsb = msg_type & 1;
- msg_type &= ~1;
- switch(msg_type){
- case AUTH_MSG_KDC_REQUEST: {
- krb5_data ticket, cipher;
- krb5_keyblock session;
-
- krb5_data_zero(&ticket);
- krb5_data_zero(&cipher);
-
- RCHECK(krb5_ret_stringz(sp, &name), out1);
- RCHECK(krb5_ret_stringz(sp, &inst), out1);
- RCHECK(krb5_ret_stringz(sp, &realm), out1);
- RCHECK(krb5_ret_int32(sp, &req_time), out1);
- if(lsb)
- req_time = swap32(req_time);
- RCHECK(krb5_ret_uint8(sp, &life), out1);
- RCHECK(krb5_ret_stringz(sp, &sname), out1);
- RCHECK(krb5_ret_stringz(sp, &sinst), out1);
- snprintf (client_name, sizeof(client_name),
- "%s.%s@%s", name, inst, realm);
- snprintf (server_name, sizeof(server_name),
- "%s.%s@%s", sname, sinst, config->v4_realm);
-
- kdc_log(context, config, 0, "AS-REQ (krb4) %s from %s for %s",
- client_name, from, server_name);
-
- ret = _kdc_db_fetch4(context, config, name, inst, realm,
- HDB_F_GET_CLIENT, &client);
- if(ret) {
- kdc_log(context, config, 0, "Client not found in database: %s: %s",
- client_name, krb5_get_err_text(context, ret));
- make_err_reply(context, reply, KRB4ET_KDC_PR_UNKNOWN,
- "principal unknown");
- goto out1;
- }
- ret = _kdc_db_fetch4(context, config, sname, sinst, config->v4_realm,
- HDB_F_GET_SERVER, &server);
- if(ret){
- kdc_log(context, config, 0, "Server not found in database: %s: %s",
- server_name, krb5_get_err_text(context, ret));
- make_err_reply(context, reply, KRB4ET_KDC_PR_UNKNOWN,
- "principal unknown");
- goto out1;
- }
-
- ret = _kdc_check_flags (context, config,
- client, client_name,
- server, server_name,
- TRUE);
- if (ret) {
- /* good error code? */
- make_err_reply(context, reply, KRB4ET_KDC_NAME_EXP,
- "operation not allowed");
- goto out1;
- }
-
- if (config->enable_v4_per_principal &&
- client->entry.flags.allow_kerberos4 == 0)
- {
- kdc_log(context, config, 0,
- "Per principal Kerberos 4 flag not turned on for %s",
- client_name);
- make_err_reply(context, reply, KRB4ET_KDC_NULL_KEY,
- "allow kerberos4 flag required");
- goto out1;
- }
-
- /*
- * There's no way to do pre-authentication in v4 and thus no
- * good error code to return if preauthentication is required.
- */
-
- if (config->require_preauth
- || client->entry.flags.require_preauth
- || server->entry.flags.require_preauth) {
- kdc_log(context, config, 0,
- "Pre-authentication required for v4-request: "
- "%s for %s",
- client_name, server_name);
- make_err_reply(context, reply, KRB4ET_KDC_NULL_KEY,
- "preauth required");
- goto out1;
- }
-
- ret = _kdc_get_des_key(context, client, FALSE, FALSE, &ckey);
- if(ret){
- kdc_log(context, config, 0, "no suitable DES key for client");
- make_err_reply(context, reply, KRB4ET_KDC_NULL_KEY,
- "no suitable DES key for client");
- goto out1;
- }
-
- ret = _kdc_get_des_key(context, server, TRUE, FALSE, &skey);
- if(ret){
- kdc_log(context, config, 0, "no suitable DES key for server");
- make_err_reply(context, reply, KRB4ET_KDC_NULL_KEY,
- "no suitable DES key for server");
- goto out1;
- }
-
- max_life = _krb5_krb_life_to_time(0, life);
- if(client->entry.max_life)
- max_life = min(max_life, *client->entry.max_life);
- if(server->entry.max_life)
- max_life = min(max_life, *server->entry.max_life);
-
- life = krb_time_to_life(kdc_time, kdc_time + max_life);
-
- ret = krb5_generate_random_keyblock(context,
- ETYPE_DES_PCBC_NONE,
- &session);
- if (ret) {
- make_err_reply(context, reply, KFAILURE,
- "Not enough random i KDC");
- goto out1;
- }
-
- ret = _krb5_krb_create_ticket(context,
- 0,
- name,
- inst,
- config->v4_realm,
- addr->sin_addr.s_addr,
- &session,
- life,
- kdc_time,
- sname,
- sinst,
- &skey->key,
- &ticket);
- if (ret) {
- krb5_free_keyblock_contents(context, &session);
- make_err_reply(context, reply, KFAILURE,
- "failed to create v4 ticket");
- goto out1;
- }
-
- ret = _krb5_krb_create_ciph(context,
- &session,
- sname,
- sinst,
- config->v4_realm,
- life,
- server->entry.kvno % 255,
- &ticket,
- kdc_time,
- &ckey->key,
- &cipher);
- krb5_free_keyblock_contents(context, &session);
- krb5_data_free(&ticket);
- if (ret) {
- make_err_reply(context, reply, KFAILURE,
- "Failed to create v4 cipher");
- goto out1;
- }
-
- ret = _krb5_krb_create_auth_reply(context,
- name,
- inst,
- realm,
- req_time,
- 0,
- client->entry.pw_end ? *client->entry.pw_end : 0,
- client->entry.kvno % 256,
- &cipher,
- reply);
- krb5_data_free(&cipher);
-
- out1:
- break;
- }
- case AUTH_MSG_APPL_REQUEST: {
- struct _krb5_krb_auth_data ad;
- int8_t kvno;
- int8_t ticket_len;
- int8_t req_len;
- krb5_data auth;
- int32_t address;
- size_t pos;
- krb5_principal tgt_princ = NULL;
- hdb_entry_ex *tgt = NULL;
- Key *tkey;
- time_t max_end, actual_end, issue_time;
-
- memset(&ad, 0, sizeof(ad));
- krb5_data_zero(&auth);
-
- RCHECK(krb5_ret_int8(sp, &kvno), out2);
- RCHECK(krb5_ret_stringz(sp, &realm), out2);
-
- ret = krb5_425_conv_principal(context, "krbtgt", realm,
- config->v4_realm,
- &tgt_princ);
- if(ret){
- kdc_log(context, config, 0,
- "Converting krbtgt principal (krb4): %s",
- krb5_get_err_text(context, ret));
- make_err_reply(context, reply, KFAILURE,
- "Failed to convert v4 principal (krbtgt)");
- goto out2;
- }
-
- ret = _kdc_db_fetch(context, config, tgt_princ,
- HDB_F_GET_KRBTGT, NULL, &tgt);
- if(ret){
- char *s;
- s = kdc_log_msg(context, config, 0, "Ticket-granting ticket not "
- "found in database (krb4): krbtgt.%s@%s: %s",
- realm, config->v4_realm,
- krb5_get_err_text(context, ret));
- make_err_reply(context, reply, KFAILURE, s);
- free(s);
- goto out2;
- }
-
- if(tgt->entry.kvno % 256 != kvno){
- kdc_log(context, config, 0,
- "tgs-req (krb4) with old kvno %d (current %d) for "
- "krbtgt.%s@%s", kvno, tgt->entry.kvno % 256,
- realm, config->v4_realm);
- make_err_reply(context, reply, KRB4ET_KDC_AUTH_EXP,
- "old krbtgt kvno used");
- goto out2;
- }
-
- ret = _kdc_get_des_key(context, tgt, TRUE, FALSE, &tkey);
- if(ret){
- kdc_log(context, config, 0,
- "no suitable DES key for krbtgt (krb4)");
- make_err_reply(context, reply, KRB4ET_KDC_NULL_KEY,
- "no suitable DES key for krbtgt");
- goto out2;
- }
-
- RCHECK(krb5_ret_int8(sp, &ticket_len), out2);
- RCHECK(krb5_ret_int8(sp, &req_len), out2);
-
- pos = krb5_storage_seek(sp, ticket_len + req_len, SEEK_CUR);
-
- auth.data = buf;
- auth.length = pos;
-
- if (config->check_ticket_addresses)
- address = addr->sin_addr.s_addr;
- else
- address = 0;
-
- ret = _krb5_krb_rd_req(context, &auth, "krbtgt", realm,
- config->v4_realm,
- address, &tkey->key, &ad);
- if(ret){
- kdc_log(context, config, 0, "krb_rd_req: %d", ret);
- make_err_reply(context, reply, ret, "failed to parse request");
- goto out2;
- }
-
- RCHECK(krb5_ret_int32(sp, &req_time), out2);
- if(lsb)
- req_time = swap32(req_time);
- RCHECK(krb5_ret_uint8(sp, &life), out2);
- RCHECK(krb5_ret_stringz(sp, &sname), out2);
- RCHECK(krb5_ret_stringz(sp, &sinst), out2);
- snprintf (server_name, sizeof(server_name),
- "%s.%s@%s",
- sname, sinst, config->v4_realm);
- snprintf (client_name, sizeof(client_name),
- "%s.%s@%s",
- ad.pname, ad.pinst, ad.prealm);
-
- kdc_log(context, config, 0, "TGS-REQ (krb4) %s from %s for %s",
- client_name, from, server_name);
-
- if(strcmp(ad.prealm, realm)){
- kdc_log(context, config, 0,
- "Can't hop realms (krb4) %s -> %s", realm, ad.prealm);
- make_err_reply(context, reply, KRB4ET_KDC_PR_UNKNOWN,
- "Can't hop realms");
- goto out2;
- }
-
- if (!config->enable_v4_cross_realm && strcmp(realm, config->v4_realm) != 0) {
- kdc_log(context, config, 0,
- "krb4 Cross-realm %s -> %s disabled",
- realm, config->v4_realm);
- make_err_reply(context, reply, KRB4ET_KDC_PR_UNKNOWN,
- "Can't hop realms");
- goto out2;
- }
-
- if(strcmp(sname, "changepw") == 0){
- kdc_log(context, config, 0,
- "Bad request for changepw ticket (krb4)");
- make_err_reply(context, reply, KRB4ET_KDC_PR_UNKNOWN,
- "Can't authorize password change based on TGT");
- goto out2;
- }
-
- ret = _kdc_db_fetch4(context, config, ad.pname, ad.pinst, ad.prealm,
- HDB_F_GET_CLIENT, &client);
- if(ret && ret != HDB_ERR_NOENTRY) {
- char *s;
- s = kdc_log_msg(context, config, 0,
- "Client not found in database: (krb4) %s: %s",
- client_name, krb5_get_err_text(context, ret));
- make_err_reply(context, reply, KRB4ET_KDC_PR_UNKNOWN, s);
- free(s);
- goto out2;
- }
- if (client == NULL && strcmp(ad.prealm, config->v4_realm) == 0) {
- char *s;
- s = kdc_log_msg(context, config, 0,
- "Local client not found in database: (krb4) "
- "%s", client_name);
- make_err_reply(context, reply, KRB4ET_KDC_PR_UNKNOWN, s);
- free(s);
- goto out2;
- }
-
- ret = _kdc_db_fetch4(context, config, sname, sinst, config->v4_realm,
- HDB_F_GET_SERVER, &server);
- if(ret){
- char *s;
- s = kdc_log_msg(context, config, 0,
- "Server not found in database (krb4): %s: %s",
- server_name, krb5_get_err_text(context, ret));
- make_err_reply(context, reply, KRB4ET_KDC_PR_UNKNOWN, s);
- free(s);
- goto out2;
- }
-
- ret = _kdc_check_flags (context, config,
- client, client_name,
- server, server_name,
- FALSE);
- if (ret) {
- make_err_reply(context, reply, KRB4ET_KDC_NAME_EXP,
- "operation not allowed");
- goto out2;
- }
-
- ret = _kdc_get_des_key(context, server, TRUE, FALSE, &skey);
- if(ret){
- kdc_log(context, config, 0,
- "no suitable DES key for server (krb4)");
- make_err_reply(context, reply, KRB4ET_KDC_NULL_KEY,
- "no suitable DES key for server");
- goto out2;
- }
-
- max_end = _krb5_krb_life_to_time(ad.time_sec, ad.life);
- max_end = min(max_end, _krb5_krb_life_to_time(kdc_time, life));
- if(server->entry.max_life)
- max_end = min(max_end, kdc_time + *server->entry.max_life);
- if(client && client->entry.max_life)
- max_end = min(max_end, kdc_time + *client->entry.max_life);
- life = min(life, krb_time_to_life(kdc_time, max_end));
-
- issue_time = kdc_time;
- actual_end = _krb5_krb_life_to_time(issue_time, life);
- while (actual_end > max_end && life > 1) {
- /* move them into the next earlier lifetime bracket */
- life--;
- actual_end = _krb5_krb_life_to_time(issue_time, life);
- }
- if (actual_end > max_end) {
- /* if life <= 1 and it's still too long, backdate the ticket */
- issue_time -= actual_end - max_end;
- }
-
- {
- krb5_data ticket, cipher;
- krb5_keyblock session;
-
- krb5_data_zero(&ticket);
- krb5_data_zero(&cipher);
-
- ret = krb5_generate_random_keyblock(context,
- ETYPE_DES_PCBC_NONE,
- &session);
- if (ret) {
- make_err_reply(context, reply, KFAILURE,
- "Not enough random i KDC");
- goto out2;
- }
-
- ret = _krb5_krb_create_ticket(context,
- 0,
- ad.pname,
- ad.pinst,
- ad.prealm,
- addr->sin_addr.s_addr,
- &session,
- life,
- issue_time,
- sname,
- sinst,
- &skey->key,
- &ticket);
- if (ret) {
- krb5_free_keyblock_contents(context, &session);
- make_err_reply(context, reply, KFAILURE,
- "failed to create v4 ticket");
- goto out2;
- }
-
- ret = _krb5_krb_create_ciph(context,
- &session,
- sname,
- sinst,
- config->v4_realm,
- life,
- server->entry.kvno % 255,
- &ticket,
- issue_time,
- &ad.session,
- &cipher);
- krb5_free_keyblock_contents(context, &session);
- if (ret) {
- make_err_reply(context, reply, KFAILURE,
- "failed to create v4 cipher");
- goto out2;
- }
-
- ret = _krb5_krb_create_auth_reply(context,
- ad.pname,
- ad.pinst,
- ad.prealm,
- req_time,
- 0,
- 0,
- 0,
- &cipher,
- reply);
- krb5_data_free(&cipher);
- }
- out2:
- _krb5_krb_free_auth_data(context, &ad);
- if(tgt_princ)
- krb5_free_principal(context, tgt_princ);
- if(tgt)
- _kdc_free_ent(context, tgt);
- break;
- }
- case AUTH_MSG_ERR_REPLY:
- ret = EINVAL;
- break;
- default:
- kdc_log(context, config, 0, "Unknown message type (krb4): %d from %s",
- msg_type, from);
-
- make_err_reply(context, reply, KFAILURE, "Unknown message type");
- ret = EINVAL;
- }
- out:
- if(name)
- free(name);
- if(inst)
- free(inst);
- if(realm)
- free(realm);
- if(sname)
- free(sname);
- if(sinst)
- free(sinst);
- if(client)
- _kdc_free_ent(context, client);
- if(server)
- _kdc_free_ent(context, server);
- krb5_storage_free(sp);
- return ret;
-}
-
-krb5_error_code
-_kdc_encode_v4_ticket(krb5_context context,
- krb5_kdc_configuration *config,
- void *buf, size_t len, const EncTicketPart *et,
- const PrincipalName *service, size_t *size)
-{
- krb5_storage *sp;
- krb5_error_code ret;
- char name[40], inst[40], realm[40];
- char sname[40], sinst[40];
-
- {
- krb5_principal princ;
- _krb5_principalname2krb5_principal(context,
- &princ,
- *service,
- et->crealm);
- ret = krb5_524_conv_principal(context,
- princ,
- sname,
- sinst,
- realm);
- krb5_free_principal(context, princ);
- if(ret)
- return ret;
-
- _krb5_principalname2krb5_principal(context,
- &princ,
- et->cname,
- et->crealm);
-
- ret = krb5_524_conv_principal(context,
- princ,
- name,
- inst,
- realm);
- krb5_free_principal(context, princ);
- }
- if(ret)
- return ret;
-
- sp = krb5_storage_emem();
-
- krb5_store_int8(sp, 0); /* flags */
- krb5_store_stringz(sp, name);
- krb5_store_stringz(sp, inst);
- krb5_store_stringz(sp, realm);
- {
- unsigned char tmp[4] = { 0, 0, 0, 0 };
- int i;
- if(et->caddr){
- for(i = 0; i < et->caddr->len; i++)
- if(et->caddr->val[i].addr_type == AF_INET &&
- et->caddr->val[i].address.length == 4){
- memcpy(tmp, et->caddr->val[i].address.data, 4);
- break;
- }
- }
- krb5_storage_write(sp, tmp, sizeof(tmp));
- }
-
- if((et->key.keytype != ETYPE_DES_CBC_MD5 &&
- et->key.keytype != ETYPE_DES_CBC_MD4 &&
- et->key.keytype != ETYPE_DES_CBC_CRC) ||
- et->key.keyvalue.length != 8)
- return -1;
- krb5_storage_write(sp, et->key.keyvalue.data, 8);
-
- {
- time_t start = et->starttime ? *et->starttime : et->authtime;
- krb5_store_int8(sp, krb_time_to_life(start, et->endtime));
- krb5_store_int32(sp, start);
- }
-
- krb5_store_stringz(sp, sname);
- krb5_store_stringz(sp, sinst);
-
- {
- krb5_data data;
- krb5_storage_to_data(sp, &data);
- krb5_storage_free(sp);
- *size = (data.length + 7) & ~7; /* pad to 8 bytes */
- if(*size > len)
- return -1;
- memset((unsigned char*)buf - *size + 1, 0, *size);
- memcpy((unsigned char*)buf - *size + 1, data.data, data.length);
- krb5_data_free(&data);
- }
- return 0;
-}
-
-krb5_error_code
-_kdc_get_des_key(krb5_context context,
- hdb_entry_ex *principal, krb5_boolean is_server,
- krb5_boolean prefer_afs_key, Key **ret_key)
-{
- Key *v5_key = NULL, *v4_key = NULL, *afs_key = NULL, *server_key = NULL;
- int i;
- krb5_enctype etypes[] = { ETYPE_DES_CBC_MD5,
- ETYPE_DES_CBC_MD4,
- ETYPE_DES_CBC_CRC };
-
- for(i = 0;
- i < sizeof(etypes)/sizeof(etypes[0])
- && (v5_key == NULL || v4_key == NULL ||
- afs_key == NULL || server_key == NULL);
- ++i) {
- Key *key = NULL;
- while(hdb_next_enctype2key(context, &principal->entry, etypes[i], &key) == 0) {
- if(key->salt == NULL) {
- if(v5_key == NULL)
- v5_key = key;
- } else if(key->salt->type == hdb_pw_salt &&
- key->salt->salt.length == 0) {
- if(v4_key == NULL)
- v4_key = key;
- } else if(key->salt->type == hdb_afs3_salt) {
- if(afs_key == NULL)
- afs_key = key;
- } else if(server_key == NULL)
- server_key = key;
- }
- }
-
- if(prefer_afs_key) {
- if(afs_key)
- *ret_key = afs_key;
- else if(v4_key)
- *ret_key = v4_key;
- else if(v5_key)
- *ret_key = v5_key;
- else if(is_server && server_key)
- *ret_key = server_key;
- else
- return KRB4ET_KDC_NULL_KEY;
- } else {
- if(v4_key)
- *ret_key = v4_key;
- else if(afs_key)
- *ret_key = afs_key;
- else if(v5_key)
- *ret_key = v5_key;
- else if(is_server && server_key)
- *ret_key = server_key;
- else
- return KRB4ET_KDC_NULL_KEY;
- }
-
- if((*ret_key)->key.keyvalue.length == 0)
- return KRB4ET_KDC_NULL_KEY;
- return 0;
-}
-
*/
krb5_boolean
-_kdc_is_weak_expection(krb5_principal principal, krb5_enctype etype)
+_kdc_is_weak_exception(krb5_principal principal, krb5_enctype etype)
{
if (principal->name.name_string.len > 0 &&
strcmp(principal->name.name_string.val[0], "afs") == 0 &&
Key *key = NULL;
if (krb5_enctype_valid(context, etypes[i]) != 0 &&
- !_kdc_is_weak_expection(princ->entry.principal, etypes[i]))
+ !_kdc_is_weak_exception(princ->entry.principal, etypes[i]))
continue;
while (hdb_next_enctype2key(context, &princ->entry, etypes[i], &key) == 0) {
KDC_REP *rep, const EncTicketPart *et, EncKDCRepPart *ek,
krb5_enctype etype,
int skvno, const EncryptionKey *skey,
- int ckvno, const EncryptionKey *ckey,
+ int ckvno, const EncryptionKey *reply_key,
const char **e_text,
krb5_data *reply)
{
*e_text = "KDC internal error";
return KRB5KRB_ERR_GENERIC;
}
- ret = krb5_crypto_init(context, ckey, 0, &crypto);
+ ret = krb5_crypto_init(context, reply_key, 0, &crypto);
if (ret) {
free(buf);
kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
}
}
-static int
-only_older_enctype_p(const KDC_REQ *req)
-{
- int i;
-
- for(i = 0; i < req->req_body.etype.len; i++) {
- if (!older_enctype(req->req_body.etype.val[i]))
- return 0;
- }
- return 1;
-}
-
/*
*
*/
static krb5_error_code
get_pa_etype_info(krb5_context context,
krb5_kdc_configuration *config,
- METHOD_DATA *md, hdb_entry *client,
- ENCTYPE *etypes, unsigned int etypes_len)
+ METHOD_DATA *md, Key *ckey)
{
krb5_error_code ret = 0;
- int i, j;
- unsigned int n = 0;
ETYPE_INFO pa;
unsigned char *buf;
size_t len;
- pa.len = client->keys.len;
- if(pa.len > UINT_MAX/sizeof(*pa.val))
- return ERANGE;
- pa.val = malloc(pa.len * sizeof(*pa.val));
+ pa.len = 1;
+ pa.val = calloc(1, sizeof(pa.val[0]));
if(pa.val == NULL)
return ENOMEM;
- memset(pa.val, 0, pa.len * sizeof(*pa.val));
-
- for(i = 0; i < client->keys.len; i++) {
- for (j = 0; j < n; j++)
- if (pa.val[j].etype == client->keys.val[i].key.keytype)
- goto skip1;
- for(j = 0; j < etypes_len; j++) {
- if(client->keys.val[i].key.keytype == etypes[j]) {
- if (krb5_enctype_valid(context, etypes[j]) != 0)
- continue;
- if (!older_enctype(etypes[j]))
- continue;
- if (n >= pa.len)
- krb5_abortx(context, "internal error: n >= p.len");
- if((ret = make_etype_info_entry(context,
- &pa.val[n++],
- &client->keys.val[i])) != 0) {
- free_ETYPE_INFO(&pa);
- return ret;
- }
- break;
- }
- }
- skip1:;
- }
- for(i = 0; i < client->keys.len; i++) {
- /* already added? */
- for(j = 0; j < etypes_len; j++) {
- if(client->keys.val[i].key.keytype == etypes[j])
- goto skip2;
- }
- if (krb5_enctype_valid(context, client->keys.val[i].key.keytype) != 0)
- continue;
- if (!older_enctype(etypes[j]))
- continue;
- if (n >= pa.len)
- krb5_abortx(context, "internal error: n >= p.len");
- if((ret = make_etype_info_entry(context,
- &pa.val[n++],
- &client->keys.val[i])) != 0) {
- free_ETYPE_INFO(&pa);
- return ret;
- }
- skip2:;
- }
- if(n < pa.len) {
- /* stripped out dups, newer enctypes, and not valid enctypes */
- pa.len = n;
+ ret = make_etype_info_entry(context, &pa.val[0], ckey);
+ if (ret) {
+ free_ETYPE_INFO(&pa);
+ return ret;
}
ASN1_MALLOC_ENCODE(ETYPE_INFO, buf, len, &pa, &len, ret);
static krb5_error_code
get_pa_etype_info2(krb5_context context,
krb5_kdc_configuration *config,
- METHOD_DATA *md, hdb_entry *client,
- ENCTYPE *etypes, unsigned int etypes_len)
+ METHOD_DATA *md, Key *ckey)
{
krb5_error_code ret = 0;
- int i, j;
- unsigned int n = 0;
ETYPE_INFO2 pa;
unsigned char *buf;
size_t len;
- pa.len = client->keys.len;
- if(pa.len > UINT_MAX/sizeof(*pa.val))
- return ERANGE;
- pa.val = malloc(pa.len * sizeof(*pa.val));
+ pa.len = 1;
+ pa.val = calloc(1, sizeof(pa.val[0]));
if(pa.val == NULL)
return ENOMEM;
- memset(pa.val, 0, pa.len * sizeof(*pa.val));
-
- for(i = 0; i < client->keys.len; i++) {
- for (j = 0; j < n; j++)
- if (pa.val[j].etype == client->keys.val[i].key.keytype)
- goto skip1;
- for(j = 0; j < etypes_len; j++) {
- if(client->keys.val[i].key.keytype == etypes[j]) {
- if (krb5_enctype_valid(context, etypes[j]) != 0)
- continue;
- if (n >= pa.len)
- krb5_abortx(context, "internal error: n >= p.len");
- if((ret = make_etype_info2_entry(&pa.val[n++],
- &client->keys.val[i])) != 0) {
- free_ETYPE_INFO2(&pa);
- return ret;
- }
- break;
- }
- }
- skip1:;
- }
- /* send enctypes that the client doesn't know about too */
- for(i = 0; i < client->keys.len; i++) {
- /* already added? */
- for(j = 0; j < etypes_len; j++) {
- if(client->keys.val[i].key.keytype == etypes[j])
- goto skip2;
- }
- if (krb5_enctype_valid(context, client->keys.val[i].key.keytype) != 0)
- continue;
- if (n >= pa.len)
- krb5_abortx(context, "internal error: n >= p.len");
- if((ret = make_etype_info2_entry(&pa.val[n++],
- &client->keys.val[i])) != 0) {
- free_ETYPE_INFO2(&pa);
- return ret;
- }
- skip2:;
- }
- if(n < pa.len) {
- /* stripped out dups, and not valid enctypes */
- pa.len = n;
+ ret = make_etype_info2_entry(&pa.val[0], ckey);
+ if (ret) {
+ free_ETYPE_INFO2(&pa);
+ return ret;
}
ASN1_MALLOC_ENCODE(ETYPE_INFO2, buf, len, &pa, &len, ret);
const KDC_REQ_BODY *b)
{
krb5_error_code ret;
- struct rk_strpool *p = NULL;
+ struct rk_strpool *p;
char *str;
int i;
+ p = rk_strpoolprintf(NULL, "%s", "Client supported enctypes: ");
+
for (i = 0; i < b->etype.len; i++) {
ret = krb5_enctype_to_string(context, b->etype.val[i], &str);
if (ret == 0) {
if (p == NULL)
p = rk_strpoolprintf(p, "no encryption types");
- str = rk_strpoolcollect(p);
- kdc_log(context, config, 0, "Client supported enctypes: %s", str);
- free(str);
-
{
char *cet;
char *set;
if(ret == 0) {
ret = krb5_enctype_to_string(context, setype, &set);
if (ret == 0) {
- kdc_log(context, config, 5, "Using %s/%s", cet, set);
+ p = rk_strpoolprintf(p, ", using %s/%s", cet, set);
free(set);
}
free(cet);
}
if (ret != 0)
- kdc_log(context, config, 5, "Using e-types %d/%d", cetype, setype);
+ p = rk_strpoolprintf(p, ", using enctypes %d/%d",
+ cetype, setype);
}
+ str = rk_strpoolcollect(p);
+ kdc_log(context, config, 0, "%s", str);
+ free(str);
+
{
char fixedstr[128];
unparse_flags(KDCOptions2int(b->kdc_options), asn1_KDCOptions_units(),
fixedstr, sizeof(fixedstr));
if(*fixedstr)
- kdc_log(context, config, 2, "Requested flags: %s", fixedstr);
+ kdc_log(context, config, 0, "Requested flags: %s", fixedstr);
}
}
return TRUE;
}
+krb5_boolean
+_kdc_is_anonymous(krb5_context context, krb5_principal principal)
+{
+ if (principal->name.name_type != KRB5_NT_WELLKNOWN ||
+ principal->name.name_string.len != 2 ||
+ strcmp(principal->name.name_string.val[0], KRB5_WELLKNOWN_NAME) != 0 ||
+ strcmp(principal->name.name_string.val[1], KRB5_ANON_NAME) != 0)
+ return 0;
+ return 1;
+}
+
/*
*
*/
if (ret)
goto out;
}
+
ret = krb5_unparse_name(context, client_princ, &client_name);
}
if (ret) {
kdc_log(context, config, 0, "AS-REQ %s from %s for %s",
client_name, from, server_name);
+ /*
+ *
+ */
+
+ if (_kdc_is_anonymous(context, client_princ)) {
+ if (!b->kdc_options.request_anonymous) {
+ kdc_log(context, config, 0, "Anonymous ticket w/o anonymous flag");
+ ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
+ goto out;
+ }
+ } else if (b->kdc_options.request_anonymous) {
+ kdc_log(context, config, 0,
+ "Request for a anonymous ticket with non "
+ "anonymous client name: %s", client_name);
+ ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
+ goto out;
+ }
+
+ /*
+ *
+ */
+
ret = _kdc_db_fetch(context, config, client_princ,
HDB_F_GET_CLIENT | flags, NULL, &client);
if(ret){
goto out;
}
- ret = _kdc_windc_client_access(context, client, req, &e_data);
- if(ret)
- goto out;
+ memset(&et, 0, sizeof(et));
+ memset(&ek, 0, sizeof(ek));
- ret = _kdc_check_flags(context, config,
- client, client_name,
- server, server_name,
- TRUE);
- if(ret)
+ /*
+ * Find the client key for reply encryption and pa-type salt, Pick
+ * the client key upfront before the other keys because that is
+ * going to affect what enctypes we are going to use in
+ * ETYPE-INFO{,2}.
+ */
+
+ ret = _kdc_find_etype(context, client, b->etype.val, b->etype.len,
+ &ckey, &cetype);
+ if (ret) {
+ kdc_log(context, config, 0,
+ "Client (%s) has no support for etypes", client_name);
goto out;
+ }
- memset(&et, 0, sizeof(et));
- memset(&ek, 0, sizeof(ek));
+ /*
+ * Pre-auth processing
+ */
if(req->padata){
int i;
e_text = "No PKINIT PA found";
i = 0;
- if ((pa = _kdc_find_padata(req, &i, KRB5_PADATA_PK_AS_REQ)))
- ;
+ pa = _kdc_find_padata(req, &i, KRB5_PADATA_PK_AS_REQ);
if (pa == NULL) {
i = 0;
- if((pa = _kdc_find_padata(req, &i, KRB5_PADATA_PK_AS_REQ_WIN)))
- ;
+ pa = _kdc_find_padata(req, &i, KRB5_PADATA_PK_AS_REQ_WIN);
}
if (pa) {
char *client_cert = NULL;
- ret = _kdc_pk_rd_padata(context, config, req, pa, &pkp);
+ ret = _kdc_pk_rd_padata(context, config, req, pa, client, &pkp);
if (ret) {
ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
kdc_log(context, config, 5,
e_text = "PKINIT certificate not allowed to "
"impersonate principal";
_kdc_pk_free_client_param(context, pkp);
-
+
kdc_log(context, config, 0, "%s", e_text);
pkp = NULL;
goto out;
}
+
found_pa = 1;
et.flags.pre_authent = 1;
kdc_log(context, config, 0,
found_pa = 1;
+ if (b->kdc_options.request_anonymous) {
+ ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+ kdc_log(context, config, 0, "ENC-TS doesn't support anon");
+ goto out;
+ }
+
ret = decode_EncryptedData(pa->padata_value.data,
pa->padata_value.length,
&enc_data,
&enc_data,
&ts_data);
krb5_crypto_destroy(context, crypto);
+ /*
+ * Since the user might have several keys with the same
+ * enctype but with diffrent salting, we need to try all
+ * the keys with the same enctype.
+ */
if(ret){
krb5_error_code ret2;
ret2 = krb5_enctype_to_string(context,
goto out;
}
}else if (config->require_preauth
+ || b->kdc_options.request_anonymous /* hack to force anon */
|| client->entry.flags.require_preauth
|| server->entry.flags.require_preauth) {
METHOD_DATA method_data;
method_data.val = NULL;
ret = realloc_method_data(&method_data);
+ if (ret) {
+ free_METHOD_DATA(&method_data);
+ goto out;
+ }
pa = &method_data.val[method_data.len-1];
pa->padata_type = KRB5_PADATA_ENC_TIMESTAMP;
pa->padata_value.length = 0;
#ifdef PKINIT
ret = realloc_method_data(&method_data);
+ if (ret) {
+ free_METHOD_DATA(&method_data);
+ goto out;
+ }
pa = &method_data.val[method_data.len-1];
pa->padata_type = KRB5_PADATA_PK_AS_REQ;
pa->padata_value.length = 0;
pa->padata_value.data = NULL;
ret = realloc_method_data(&method_data);
+ if (ret) {
+ free_METHOD_DATA(&method_data);
+ goto out;
+ }
pa = &method_data.val[method_data.len-1];
pa->padata_type = KRB5_PADATA_PK_AS_REQ_WIN;
pa->padata_value.length = 0;
#endif
/*
- * RFC4120 requires:
- * - If the client only knows about old enctypes, then send
- * both info replies (we send 'info' first in the list).
- * - If the client is 'modern', because it knows about 'new'
- * enctype types, then only send the 'info2' reply.
+ * If there is a client key, send ETYPE_INFO{,2}
*/
-
- /* XXX check ret */
- if (only_older_enctype_p(req))
- ret = get_pa_etype_info(context, config,
- &method_data, &client->entry,
- b->etype.val, b->etype.len);
- /* XXX check ret */
- ret = get_pa_etype_info2(context, config, &method_data,
- &client->entry, b->etype.val, b->etype.len);
-
+ if (ckey) {
+
+ /*
+ * RFC4120 requires:
+ * - If the client only knows about old enctypes, then send
+ * both info replies (we send 'info' first in the list).
+ * - If the client is 'modern', because it knows about 'new'
+ * enctype types, then only send the 'info2' reply.
+ *
+ * Before we send the full list of etype-info data, we pick
+ * the client key we would have used anyway below, just pick
+ * that instead.
+ */
+
+ if (older_enctype(ckey->key.keytype)) {
+ ret = get_pa_etype_info(context, config,
+ &method_data, ckey);
+ if (ret) {
+ free_METHOD_DATA(&method_data);
+ goto out;
+ }
+ }
+ ret = get_pa_etype_info2(context, config,
+ &method_data, ckey);
+ if (ret) {
+ free_METHOD_DATA(&method_data);
+ goto out;
+ }
+ }
ASN1_MALLOC_ENCODE(METHOD_DATA, buf, len, &method_data, &len, ret);
free_METHOD_DATA(&method_data);
}
/*
- * Find the client key (for preauth ENC-TS verification and reply
- * encryption). Then the best encryption type for the KDC and
- * last the best session key that shared between the client and
- * KDC runtime enctypes.
+ * Verify flags after the user been required to prove its identity
+ * with in a preauth mech.
*/
- ret = _kdc_find_etype(context, client, b->etype.val, b->etype.len,
- &ckey, &cetype);
- if (ret) {
- kdc_log(context, config, 0,
- "Client (%s) has no support for etypes", client_name);
+ ret = _kdc_check_flags(context, config,
+ client, client_name,
+ server, server_name,
+ TRUE);
+ if(ret)
goto out;
- }
-
+
+ ret = _kdc_windc_client_access(context, client, req, &e_data);
+ if(ret)
+ goto out;
+
+ /*
+ * Selelct the best encryption type for the KDC with out regard to
+ * the client since the client never needs to read that data.
+ */
+
ret = _kdc_get_preferred_key(context, config,
server, server_name,
&setype, &skey);
rep.pvno = 5;
rep.msg_type = krb_as_rep;
- copy_Realm(&client->entry.principal->realm, &rep.crealm);
- if (f.request_anonymous)
- _kdc_make_anonymous_principalname (&rep.cname);
- else
- _krb5_principal2principalname(&rep.cname,
- client->entry.principal);
+
+ ret = copy_Realm(&client->entry.principal->realm, &rep.crealm);
+ if (ret)
+ goto out;
+ ret = _krb5_principal2principalname(&rep.cname, client->entry.principal);
+ if (ret)
+ goto out;
+
rep.ticket.tkt_vno = 5;
copy_Realm(&server->entry.principal->realm, &rep.ticket.realm);
_krb5_principal2principalname(&rep.ticket.sname,
goto out;
}
- ret = krb5_generate_random_keyblock(context, sessionetype, &et.key);
+ ret = copy_PrincipalName(&rep.cname, &et.cname);
+ if (ret)
+ goto out;
+ ret = copy_Realm(&rep.crealm, &et.crealm);
if (ret)
goto out;
- copy_PrincipalName(&rep.cname, &et.cname);
- copy_Realm(&rep.crealm, &et.crealm);
{
time_t start;
et.transited.tr_type = DOMAIN_X500_COMPRESS;
krb5_data_zero(&et.transited.contents);
- copy_EncryptionKey(&et.key, &ek.key);
-
/* The MIT ASN.1 library (obviously) doesn't tell lengths encoded
* as 0 and as 0x80 (meaning indefinite length) apart, and is thus
* incapable of correctly decoding SEQUENCE OF's of zero length.
rep.padata->len = 0;
rep.padata->val = NULL;
- reply_key = &ckey->key;
#if PKINIT
if (pkp) {
+ e_text = "Failed to build PK-INIT reply";
ret = _kdc_pk_mk_pa_reply(context, config, pkp, client,
- req, req_buffer,
- &reply_key, rep.padata);
+ sessionetype, req, req_buffer,
+ &reply_key, &et.key, rep.padata);
if (ret)
goto out;
ret = _kdc_add_inital_verified_cas(context,
&et);
if (ret)
goto out;
- }
+ } else
#endif
+ if (ckey) {
+ reply_key = &ckey->key;
+ ret = krb5_generate_random_keyblock(context, sessionetype, &et.key);
+ if (ret)
+ goto out;
+ } else {
+ e_text = "Client have no reply key";
+ ret = KRB5KDC_ERR_CLIENT_NOTYET;
+ goto out;
+ }
+
+ ret = copy_EncryptionKey(&et.key, &ek.key);
+ if (ret)
+ goto out;
- set_salt_padata (rep.padata, ckey->salt);
+ if (ckey)
+ set_salt_padata (rep.padata, ckey->salt);
/* Add signing of alias referral */
if (f.canonicalize) {
hdb_entry_ex *krbtgt,
krb5_enctype enctype,
krb5_const_principal server,
- KRB5SignedPathPrincipals *principals,
+ krb5_principals principals,
EncTicketPart *tkt)
{
krb5_error_code ret;
size_t size;
if (server && principals) {
- ret = add_KRB5SignedPathPrincipals(principals, server);
+ ret = add_Principals(principals, server);
if (ret)
return ret;
}
krb5_kdc_configuration *config,
hdb_entry_ex *krbtgt,
EncTicketPart *tkt,
- KRB5SignedPathPrincipals **delegated,
+ krb5_principals *delegated,
int *signedpath)
{
krb5_error_code ret;
return ENOMEM;
}
- ret = copy_KRB5SignedPathPrincipals(*delegated, sp.delegated);
+ ret = copy_Principals(*delegated, sp.delegated);
if (ret) {
free_KRB5SignedPath(&sp);
free(*delegated);
krb5_principal client_principal,
hdb_entry_ex *krbtgt,
krb5_enctype krbtgt_etype,
- KRB5SignedPathPrincipals *spp,
+ krb5_principals spp,
const krb5_data *rspac,
const METHOD_DATA *enc_pa_data,
const char **e_text,
PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) ||
GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
&tgt->transited, &et,
- *krb5_princ_realm(context, client_principal),
- *krb5_princ_realm(context, server->entry.principal),
- *krb5_princ_realm(context, krbtgt->entry.principal));
+ krb5_principal_get_realm(context, client_principal),
+ krb5_principal_get_realm(context, server->entry.principal),
+ krb5_principal_get_realm(context, krbtgt->entry.principal));
if(ret)
goto out;
- copy_Realm(krb5_princ_realm(context, server_principal),
- &rep.ticket.realm);
+ copy_Realm(&server_principal->realm, &rep.ticket.realm);
_krb5_principal2principalname(&rep.ticket.sname, server_principal);
copy_Realm(&tgt_name->realm, &rep.crealm);
/*
}
if (krb5_enctype_valid(context, et.key.keytype) != 0
- && _kdc_is_weak_expection(server->entry.principal, et.key.keytype))
+ && _kdc_is_weak_exception(server->entry.principal, et.key.keytype))
{
krb5_enctype_enable(context, et.key.keytype);
is_weak = 1;
if (server->name.name_string.len == 1)
name = server->name.name_string.val[0];
- if (server->name.name_string.len > 1)
+ else if (server->name.name_string.len > 1)
name = server->name.name_string.val[1];
else
return FALSE;
krb5_keyblock *subkey;
krb5_data ad;
- ret = krb5_auth_con_getremotesubkey(context,
- ac,
- &subkey);
+ ret = krb5_auth_con_getremotesubkey(context, ac, &subkey);
if(ret){
krb5_auth_con_free(context, ac);
kdc_log(context, config, 0, "Failed to get remote subkey: %s",
goto out;
}
ret = krb5_crypto_init(context, subkey, 0, &crypto);
+ krb5_free_keyblock(context, subkey);
if (ret) {
krb5_auth_con_free(context, ac);
kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
goto out;
}
- krb5_free_keyblock(context, subkey);
ALLOC(*auth_data);
if (*auth_data == NULL) {
krb5_auth_con_free(context, ac);
const char *from,
const char **e_text,
AuthorizationData **auth_data,
- const struct sockaddr *from_addr,
- int datagram_reply)
+ const struct sockaddr *from_addr)
{
krb5_error_code ret;
krb5_principal cp = NULL, sp = NULL;
hdb_entry_ex *server = NULL, *client = NULL;
krb5_realm ref_realm = NULL;
EncTicketPart *tgt = &ticket->ticket;
- KRB5SignedPathPrincipals *spp = NULL;
- Key *tkey;
+ krb5_principals spp = NULL;
const EncryptionKey *ekey;
krb5_keyblock sessionkey;
krb5_kvno kvno;
krb5_data rspac;
- int cross_realm = 0;
METHOD_DATA enc_pa_data;
char opt_str[128];
int signedpath = 0;
+ Key *tkey;
+
memset(&sessionkey, 0, sizeof(sessionkey));
memset(&adtkt, 0, sizeof(adtkt));
krb5_data_zero(&rspac);
kdc_log(context, config, 1, "Client not found in database: %s: %s",
cpn, krb5_get_err_text(context, ret));
-
- cross_realm = 1;
}
/*
break;
if(i == b->etype.len) {
kdc_log(context, config, 0,
- "Addition ticket have not matching etypes", spp);
+ "Addition ticket have not matching etypes");
krb5_clear_error_message(context);
- return KRB5KDC_ERR_ETYPE_NOSUPP;
+ ret = KRB5KDC_ERR_ETYPE_NOSUPP;
+ goto out;
}
etype = b->etype.val[i];
kvno = 0;
if(ret) {
kdc_log(context, config, 0,
"Server (%s) has no support for etypes", spn);
- return ret;
+ goto out;
}
ekey = &skey->key;
kvno = server->entry.kvno;
goto out;
}
- /*
- * Validate authoriation data
- */
-
/*
* Check that service is in the same realm as the krbtgt. If it's
* not the same, it's someone that is using a uni-directional trust
goto out;
}
- /* check PAC if there is one */
+ /*
+ * Validate authoriation data
+ */
ret = hdb_enctype2key(context, &krbtgt->entry,
krbtgt_etype, &tkey);
if(ret) {
kdc_log(context, config, 0,
- "Failed to find key for krbtgt PAC check");
+ "Failed to find key for krbtgt PAC check");
goto out;
}
const PA_DATA *sdata;
int i = 0;
- sdata = _kdc_find_padata(req, &i, KRB5_PADATA_S4U2SELF);
+ sdata = _kdc_find_padata(req, &i, KRB5_PADATA_FOR_USER);
if (sdata) {
krb5_crypto crypto;
krb5_data datack;
from,
&e_text,
&auth_data,
- from_addr,
- datagram_reply);
+ from_addr);
if (ret) {
kdc_log(context, config, 0,
"Failed building TGS-REP to %s", from);
#include <rfc2459_asn1.h>
#include <hx509.h>
-RCSID("$Id$");
+#ifdef KX509
/*
*
*/
krb5_error_code
-_kdc_try_kx509_request(void *ptr, size_t len, Kx509Request *req, size_t *size)
+_kdc_try_kx509_request(void *ptr, size_t len, struct Kx509Request *req, size_t *size)
{
if (len < 4)
return -1;
krb5_keyblock *key,
Kx509Response *rep)
{
+ krb5_error_code ret;
HMAC_CTX ctx;
HMAC_CTX_init(&ctx);
- HMAC_Init_ex(&ctx,
- key->keyvalue.data, key->keyvalue.length,
+ HMAC_Init_ex(&ctx, key->keyvalue.data, key->keyvalue.length,
EVP_sha1(), NULL);
- rep->hash->length = HMAC_size(&ctx);
- rep->hash->data = malloc(rep->hash->length);
- if (rep->hash->data == NULL) {
+ ret = krb5_data_alloc(rep->hash, HMAC_size(&ctx));
+ if (ret) {
HMAC_CTX_cleanup(&ctx);
krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
return ENOMEM;
spki.subjectPublicKey.data = key->data;
spki.subjectPublicKey.length = key->length * 8;
- ret = der_copy_oid(oid_id_pkcs1_rsaEncryption(),
+ ret = der_copy_oid(&asn1_oid_id_pkcs1_rsaEncryption,
&spki.algorithm.algorithm);
any.data = "\x05\x00";
krb5_error_code
_kdc_do_kx509(krb5_context context,
krb5_kdc_configuration *config,
- const Kx509Request *req, krb5_data *reply,
+ const struct Kx509Request *req, krb5_data *reply,
const char *from, struct sockaddr *addr)
{
krb5_error_code ret;
if (ret)
goto out;
free_RSAPublicKey(&key);
- if (size != req->pk_key.length)
- ;
+ if (size != req->pk_key.length) {
+ ret = ASN1_EXTRA_DATA;
+ goto out;
+ }
}
ALLOC(rep.certificate);
return 0;
}
+
+#endif /* KX509 */
struct pk_client_params {
enum krb5_pk_type type;
- BIGNUM *dh_public_key;
+ enum { USE_RSA, USE_DH, USE_ECDH } keyex;
+ union {
+ struct {
+ BIGNUM *public_key;
+ DH *key;
+ } dh;
+#ifdef HAVE_OPENSSL
+ struct {
+ EC_KEY *public_key;
+ EC_KEY *key;
+ } ecdh;
+#endif
+ } u;
hx509_cert cert;
unsigned nonce;
- DH *dh;
EncryptionKey reply_key;
char *dh_group_name;
hx509_peer_info peer;
hx509_certs client_anchors;
+ hx509_verify_ctx verify_ctx;
};
struct pk_principal_mapping {
}
void
-_kdc_pk_free_client_param(krb5_context context,
- pk_client_params *client_params)
+_kdc_pk_free_client_param(krb5_context context, pk_client_params *cp)
{
- 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);
+ if (cp == NULL)
+ return;
+ if (cp->cert)
+ hx509_cert_free(cp->cert);
+ if (cp->verify_ctx)
+ hx509_verify_destroy_ctx(cp->verify_ctx);
+ if (cp->keyex == USE_DH) {
+ if (cp->u.dh.key)
+ DH_free(cp->u.dh.key);
+ if (cp->u.dh.public_key)
+ BN_free(cp->u.dh.public_key);
+ }
+#ifdef HAVE_OPENSSL
+ if (cp->keyex == USE_ECDH) {
+ if (cp->u.ecdh.key)
+ EC_KEY_free(cp->u.ecdh.key);
+ if (cp->u.ecdh.public_key)
+ EC_KEY_free(cp->u.ecdh.public_key);
+ }
+#endif
+ krb5_free_keyblock_contents(context, &cp->reply_key);
+ if (cp->dh_group_name)
+ free(cp->dh_group_name);
+ if (cp->peer)
+ hx509_peer_info_free(cp->peer);
+ if (cp->client_anchors)
+ hx509_certs_free(&cp->client_anchors);
+ memset(cp, 0, sizeof(*cp));
+ free(cp);
}
static krb5_error_code
-generate_dh_keyblock(krb5_context context, pk_client_params *client_params,
- krb5_enctype enctype, krb5_keyblock *reply_key)
+generate_dh_keyblock(krb5_context context,
+ pk_client_params *client_params,
+ krb5_enctype enctype)
{
unsigned char *dh_gen_key = NULL;
krb5_keyblock key;
memset(&key, 0, sizeof(key));
- if (!DH_generate_key(client_params->dh)) {
- ret = KRB5KRB_ERR_GENERIC;
- krb5_set_error_message(context, ret, "Can't generate Diffie-Hellman keys");
- goto out;
- }
- if (client_params->dh_public_key == NULL) {
- ret = KRB5KRB_ERR_GENERIC;
- krb5_set_error_message(context, ret, "dh_public_key");
- goto out;
- }
+ if (client_params->keyex == USE_DH) {
- 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;
+ if (client_params->u.dh.public_key == NULL) {
+ ret = KRB5KRB_ERR_GENERIC;
+ krb5_set_error_message(context, ret, "public_key");
+ goto out;
+ }
- dh_gen_key = malloc(size);
- if (dh_gen_key == NULL) {
- ret = ENOMEM;
- krb5_set_error_message(context, ret, "malloc: out of memory");
- goto out;
- }
- memset(dh_gen_key, 0, size - dh_gen_keylen);
+ if (!DH_generate_key(client_params->u.dh.key)) {
+ ret = KRB5KRB_ERR_GENERIC;
+ krb5_set_error_message(context, ret,
+ "Can't generate Diffie-Hellman keys");
+ goto out;
+ }
+
+ dh_gen_keylen = DH_size(client_params->u.dh.key);
+ size = BN_num_bytes(client_params->u.dh.key->p);
+ if (size < dh_gen_keylen)
+ size = dh_gen_keylen;
+
+ dh_gen_key = malloc(size);
+ if (dh_gen_key == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_message(context, ret, "malloc: out of memory");
+ 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->u.dh.public_key,
+ client_params->u.dh.key);
+ if (dh_gen_keylen == -1) {
+ ret = KRB5KRB_ERR_GENERIC;
+ krb5_set_error_message(context, ret,
+ "Can't compute Diffie-Hellman key");
+ goto out;
+ }
+ ret = 0;
+#ifdef HAVE_OPENSSL
+ } else if (client_params->keyex == USE_ECDH) {
+
+ if (client_params->u.ecdh.public_key == NULL) {
+ ret = KRB5KRB_ERR_GENERIC;
+ krb5_set_error_message(context, ret, "public_key");
+ goto out;
+ }
+
+ client_params->u.ecdh.key = EC_KEY_new();
+ if (client_params->u.ecdh.key == NULL) {
+ ret = ENOMEM;
+ goto out;
+ }
+ EC_KEY_set_group(client_params->u.ecdh.key,
+ EC_KEY_get0_group(client_params->u.ecdh.public_key));
- 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) {
+ if (EC_KEY_generate_key(client_params->u.ecdh.key) != 1) {
+ ret = ENOMEM;
+ goto out;
+ }
+
+ size = (EC_GROUP_get_degree(EC_KEY_get0_group(client_params->u.ecdh.key)) + 7) / 8;
+ dh_gen_key = malloc(size);
+ if (dh_gen_key == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_message(context, ret,
+ N_("malloc: out of memory", ""));
+ goto out;
+ }
+
+ dh_gen_keylen = ECDH_compute_key(dh_gen_key, size,
+ EC_KEY_get0_public_key(client_params->u.ecdh.public_key),
+ client_params->u.ecdh.key, NULL);
+ ret = 0;
+#endif /* HAVE_OPENSSL */
+ } else {
ret = KRB5KRB_ERR_GENERIC;
- krb5_set_error_message(context, ret, "Can't compute Diffie-Hellman key");
+ krb5_set_error_message(context, ret,
+ "Diffie-Hellman not selected keys");
goto out;
}
enctype,
dh_gen_key, dh_gen_keylen,
NULL, NULL,
- reply_key);
+ &client_params->reply_key);
out:
if (dh_gen_key)
memset(&dhparam, 0, sizeof(dhparam));
- if (der_heim_oid_cmp(&dh_key_info->algorithm.algorithm, oid_id_dhpublicnumber())) {
- krb5_set_error_message(context, KRB5_BADMSGTYPE,
- "PKINIT invalid oid in clientPublicValue");
- return KRB5_BADMSGTYPE;
+ if ((dh_key_info->subjectPublicKey.length % 8) != 0) {
+ ret = KRB5_BADMSGTYPE;
+ krb5_set_error_message(context, ret,
+ "PKINIT: subjectPublicKey not aligned "
+ "to 8 bit boundary");
+ goto out;
}
if (dh_key_info->algorithm.parameters == NULL) {
goto out;
}
- if ((dh_key_info->subjectPublicKey.length % 8) != 0) {
- ret = KRB5_BADMSGTYPE;
- krb5_set_error_message(context, ret,
- "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);
return ret;
}
- client_params->dh_public_key = integer_to_BN(context,
- "subjectPublicKey",
- &glue);
+ client_params->u.dh.public_key = integer_to_BN(context,
+ "subjectPublicKey",
+ &glue);
der_free_heim_integer(&glue);
- if (client_params->dh_public_key == NULL) {
+ if (client_params->u.dh.public_key == NULL) {
ret = KRB5_BADMSGTYPE;
goto out;
}
}
- client_params->dh = dh;
+ client_params->u.dh.key = dh;
dh = NULL;
ret = 0;
return ret;
}
+#ifdef HAVE_OPENSSL
+
+static krb5_error_code
+get_ecdh_param(krb5_context context,
+ krb5_kdc_configuration *config,
+ SubjectPublicKeyInfo *dh_key_info,
+ pk_client_params *client_params)
+{
+ ECParameters ecp;
+ EC_KEY *public = NULL;
+ krb5_error_code ret;
+ const unsigned char *p;
+ size_t len;
+ int nid;
+
+ if (dh_key_info->algorithm.parameters == NULL) {
+ krb5_set_error_message(context, KRB5_BADMSGTYPE,
+ "PKINIT missing algorithm parameter "
+ "in clientPublicValue");
+ return KRB5_BADMSGTYPE;
+ }
+
+ memset(&ecp, 0, sizeof(ecp));
+
+ ret = decode_ECParameters(dh_key_info->algorithm.parameters->data,
+ dh_key_info->algorithm.parameters->length, &ecp, &len);
+ if (ret)
+ goto out;
+
+ if (ecp.element != choice_ECParameters_namedCurve) {
+ ret = KRB5_BADMSGTYPE;
+ goto out;
+ }
+
+ if (der_heim_oid_cmp(&ecp.u.namedCurve, &asn1_oid_id_ec_group_secp256r1) == 0)
+ nid = NID_X9_62_prime256v1;
+ else {
+ ret = KRB5_BADMSGTYPE;
+ goto out;
+ }
+
+ /* XXX verify group is ok */
+
+ public = EC_KEY_new_by_curve_name(nid);
+
+ p = dh_key_info->subjectPublicKey.data;
+ len = dh_key_info->subjectPublicKey.length / 8;
+ if (o2i_ECPublicKey(&public, &p, len) == NULL) {
+ ret = KRB5_BADMSGTYPE;
+ krb5_set_error_message(context, ret,
+ "PKINIT failed to decode ECDH key");
+ goto out;
+ }
+ client_params->u.ecdh.public_key = public;
+ public = NULL;
+
+ out:
+ if (public)
+ EC_KEY_free(public);
+ free_ECParameters(&ecp);
+ return ret;
+}
+
+#endif /* HAVE_OPENSSL */
+
krb5_error_code
_kdc_pk_rd_padata(krb5_context context,
krb5_kdc_configuration *config,
const KDC_REQ *req,
const PA_DATA *pa,
+ hdb_entry_ex *client,
pk_client_params **ret_params)
{
- pk_client_params *client_params;
+ pk_client_params *cp;
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";
+ hx509_certs trust_anchors;
int have_data = 0;
+ const HDB_Ext_PKINIT_cert *pc;
*ret_params = NULL;
return 0;
}
- hx509_verify_set_time(kdc_identity->verify_ctx, kdc_time);
-
- client_params = calloc(1, sizeof(*client_params));
- if (client_params == NULL) {
+ cp = calloc(1, sizeof(*cp));
+ if (cp == NULL) {
krb5_clear_error_message(context);
ret = ENOMEM;
goto out;
}
+ ret = hx509_certs_init(kdc_identity->hx509ctx,
+ "MEMORY:trust-anchors",
+ 0, NULL, &trust_anchors);
+ if (ret) {
+ krb5_set_error_message(context, ret, "failed to create trust anchors");
+ goto out;
+ }
+
+ ret = hx509_certs_merge(kdc_identity->hx509ctx, trust_anchors,
+ kdc_identity->anchors);
+ if (ret) {
+ hx509_certs_free(&trust_anchors);
+ krb5_set_error_message(context, ret, "failed to create verify context");
+ goto out;
+ }
+
+ /* Add any registered certificates for this client as trust anchors */
+ ret = hdb_entry_get_pkinit_cert(&client->entry, &pc);
+ if (ret == 0 && pc != NULL) {
+ hx509_cert cert;
+ unsigned int i;
+
+ for (i = 0; i < pc->len; i++) {
+ ret = hx509_cert_init_data(kdc_identity->hx509ctx,
+ pc->val[i].cert.data,
+ pc->val[i].cert.length,
+ &cert);
+ if (ret)
+ continue;
+ hx509_certs_add(kdc_identity->hx509ctx, trust_anchors, cert);
+ hx509_cert_free(cert);
+ }
+ }
+
+ ret = hx509_verify_init_ctx(kdc_identity->hx509ctx, &cp->verify_ctx);
+ if (ret) {
+ hx509_certs_free(&trust_anchors);
+ krb5_set_error_message(context, ret, "failed to create verify context");
+ goto out;
+ }
+
+ hx509_verify_set_time(cp->verify_ctx, kdc_time);
+ hx509_verify_attach_anchors(cp->verify_ctx, trust_anchors);
+ hx509_certs_free(&trust_anchors);
+
+ if (config->pkinit_allow_proxy_certs)
+ hx509_verify_set_proxy_certificate(cp->verify_ctx, 1);
+
if (pa->padata_type == KRB5_PADATA_PK_AS_REQ_WIN) {
PA_PK_AS_REQ_Win2k r;
type = "PK-INIT-Win2k";
+ if (req->req_body.kdc_options.request_anonymous) {
+ ret = KRB5_KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED;
+ krb5_set_error_message(context, ret,
+ "Anon not supported in RSA mode");
+ goto out;
+ }
+
ret = decode_PA_PK_AS_REQ_Win2k(pa->padata_value.data,
pa->padata_value.length,
&r,
free_PA_PK_AS_REQ_Win2k(&r);
if (ret) {
krb5_set_error_message(context, ret,
- "Can't decode PK-AS-REQ: %d", ret);
+ "Can't unwrap ContentInfo(win): %d", ret);
goto out;
}
&r,
NULL);
if (ret) {
- krb5_set_error_message(context, ret, "Can't decode PK-AS-REQ: %d", ret);
+ krb5_set_error_message(context, ret,
+ "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;
+ unsigned int i, maxedi;
ret = hx509_certs_init(kdc_identity->hx509ctx,
"MEMORY:client-anchors",
0, NULL,
- &client_params->client_anchors);
+ &cp->client_anchors);
if (ret) {
- krb5_set_error_message(context, ret, "Can't allocate client anchors: %d", ret);
+ krb5_set_error_message(context, ret,
+ "Can't allocate client anchors: %d",
+ ret);
goto out;
}
- for (i = 0; i < edi->len; i++) {
+ /*
+ * If the client sent more then 10 EDI, don't bother
+ * looking more then 10 of performance reasons.
+ */
+ maxedi = edi->len;
+ if (maxedi > 10)
+ maxedi = 10;
+ for (i = 0; i < maxedi; i++) {
IssuerAndSerialNumber iasn;
hx509_query *q;
hx509_cert cert;
}
ret = hx509_query_match_issuer_serial(q, &iasn.issuer, &iasn.serialNumber);
free_IssuerAndSerialNumber(&iasn);
- if (ret)
+ if (ret) {
+ hx509_query_free(kdc_identity->hx509ctx, q);
continue;
+ }
ret = hx509_certs_find(kdc_identity->hx509ctx,
kdc_identity->certs,
if (ret)
continue;
hx509_certs_add(kdc_identity->hx509ctx,
- client_params->client_anchors, cert);
+ cp->client_anchors, cert);
hx509_cert_free(cert);
}
}
goto out;
}
- ret = der_heim_oid_cmp(&contentInfoOid, oid_id_pkcs7_signedData());
+ ret = der_heim_oid_cmp(&contentInfoOid, &asn1_oid_id_pkcs7_signedData);
if (ret != 0) {
ret = KRB5KRB_ERR_GENERIC;
krb5_set_error_message(context, ret,
{
hx509_certs signer_certs;
+ int flags = HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH; /* BTMM */
+
+ if (req->req_body.kdc_options.request_anonymous)
+ flags |= HX509_CMS_VS_ALLOW_ZERO_SIGNER;
ret = hx509_cms_verify_signed(kdc_identity->hx509ctx,
- kdc_identity->verify_ctx,
+ cp->verify_ctx,
+ flags,
signed_content.data,
signed_content.length,
NULL,
goto out;
}
- ret = hx509_get_one_cert(kdc_identity->hx509ctx, signer_certs,
- &client_params->cert);
- hx509_certs_free(&signer_certs);
+ if (signer_certs) {
+ ret = hx509_get_one_cert(kdc_identity->hx509ctx, signer_certs,
+ &cp->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)
+ if (der_heim_oid_cmp(&eContentType, &asn1_oid_id_pkcs7_data) != 0 &&
+ der_heim_oid_cmp(&eContentType, &asn1_oid_id_pkauthdata) != 0)
{
ret = KRB5_BADMSGTYPE;
krb5_set_error_message(context, ret, "got wrong oid for pkauthdata");
&ap,
NULL);
if (ret) {
- krb5_set_error_message(context, ret, "can't decode AuthPack: %d", ret);
+ krb5_set_error_message(context, ret,
+ "Can't decode AuthPack: %d", ret);
goto out;
}
goto out;
}
- client_params->type = PKINIT_WIN2K;
- client_params->nonce = ap.pkAuthenticator.nonce;
+ cp->type = PKINIT_WIN2K;
+ cp->nonce = ap.pkAuthenticator.nonce;
if (ap.clientPublicValue) {
ret = KRB5KRB_ERR_GENERIC;
- krb5_set_error_message(context, ret, "DH not supported for windows");
+ krb5_set_error_message(context, ret,
+ "DH not supported for windows");
goto out;
}
free_AuthPack_Win2k(&ap);
&ap,
NULL);
if (ret) {
- krb5_set_error_message(context, ret, "can't decode AuthPack: %d", ret);
+ krb5_set_error_message(context, ret,
+ "Can't decode AuthPack: %d", ret);
free_AuthPack(&ap);
goto out;
}
+ if (req->req_body.kdc_options.request_anonymous &&
+ ap.clientPublicValue == NULL) {
+ free_AuthPack(&ap);
+ ret = KRB5_KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED;
+ krb5_set_error_message(context, ret,
+ "Anon not supported in RSA mode");
+ goto out;
+ }
+
ret = pk_check_pkauthenticator(context,
&ap.pkAuthenticator,
req);
goto out;
}
- client_params->type = PKINIT_27;
- client_params->nonce = ap.pkAuthenticator.nonce;
+ cp->type = PKINIT_27;
+ cp->nonce = ap.pkAuthenticator.nonce;
if (ap.clientPublicValue) {
- ret = get_dh_param(context, config,
- ap.clientPublicValue, client_params);
+ if (der_heim_oid_cmp(&ap.clientPublicValue->algorithm.algorithm, &asn1_oid_id_dhpublicnumber) == 0) {
+ cp->keyex = USE_DH;
+ ret = get_dh_param(context, config,
+ ap.clientPublicValue, cp);
+#ifdef HAVE_OPENSSL
+ } else if (der_heim_oid_cmp(&ap.clientPublicValue->algorithm.algorithm, &asn1_oid_id_ecPublicKey) == 0) {
+ cp->keyex = USE_ECDH;
+ ret = get_ecdh_param(context, config,
+ ap.clientPublicValue, cp);
+#endif /* HAVE_OPENSSL */
+ } else {
+ ret = KRB5_BADMSGTYPE;
+ krb5_set_error_message(context, ret, "PKINIT unknown DH mechanism");
+ }
if (ret) {
free_AuthPack(&ap);
goto out;
}
- }
+ } else
+ cp->keyex = USE_RSA;
+ ret = hx509_peer_info_alloc(kdc_identity->hx509ctx,
+ &cp->peer);
+ if (ret) {
+ free_AuthPack(&ap);
+ goto out;
+ }
+
if (ap.supportedCMSTypes) {
- ret = hx509_peer_info_alloc(kdc_identity->hx509ctx,
- &client_params->peer);
- if (ret) {
- free_AuthPack(&ap);
- goto out;
- }
ret = hx509_peer_info_set_cms_algs(kdc_identity->hx509ctx,
- client_params->peer,
+ cp->peer,
ap.supportedCMSTypes->val,
ap.supportedCMSTypes->len);
if (ret) {
free_AuthPack(&ap);
goto out;
}
+ } else {
+ /* assume old client */
+ hx509_peer_info_add_cms_alg(kdc_identity->hx509ctx, cp->peer,
+ hx509_crypto_des_rsdi_ede3_cbc());
+ hx509_peer_info_add_cms_alg(kdc_identity->hx509ctx, cp->peer,
+ hx509_signature_rsa_with_sha1());
+ hx509_peer_info_add_cms_alg(kdc_identity->hx509ctx, cp->peer,
+ hx509_signature_sha1());
}
free_AuthPack(&ap);
} else
krb5_data_free(&eContent);
der_free_oid(&eContentType);
der_free_oid(&contentInfoOid);
- if (ret)
- _kdc_pk_free_client_param(context, client_params);
- else
- *ret_params = client_params;
+ if (ret) {
+ _kdc_pk_free_client_param(context, cp);
+ } else
+ *ret_params = cp;
return ret;
}
static krb5_error_code
pk_mk_pa_reply_enckey(krb5_context context,
krb5_kdc_configuration *config,
- pk_client_params *client_params,
+ pk_client_params *cp,
const KDC_REQ *req,
const krb5_data *req_buffer,
krb5_keyblock *reply_key,
- ContentInfo *content_info)
+ ContentInfo *content_info,
+ hx509_cert *kdc_cert)
{
const heim_oid *envelopedAlg = NULL, *sdAlg = NULL, *evAlg = NULL;
krb5_error_code ret;
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 (client_params->type) {
+ switch (cp->type) {
case PKINIT_WIN2K: {
int i = 0;
if (_kdc_find_padata(req, &i, KRB5_PADATA_PK_AS_09_BINDING) == NULL
{
do_win2k = 1;
}
- sdAlg = oid_id_pkcs7_data();
- evAlg = oid_id_pkcs7_data();
- envelopedAlg = oid_id_rsadsi_des_ede3_cbc();
+ 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 = oid_id_pkrkeydata();
- evAlg = oid_id_pkcs7_signedData();
+ sdAlg = &asn1_oid_id_pkrkeydata;
+ evAlg = &asn1_oid_id_pkcs7_signedData;
break;
default:
krb5_abortx(context, "internal pkinit error");
krb5_clear_error_message(context);
goto out;
}
- kp.nonce = client_params->nonce;
+ kp.nonce = cp->nonce;
ASN1_MALLOC_ENCODE(ReplyKeyPack_Win2k,
buf.data, buf.length,
goto out;
hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
- hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE);
+ if (config->pkinit_kdc_friendly_name)
+ hx509_query_match_friendly_name(q, config->pkinit_kdc_friendly_name);
ret = hx509_certs_find(kdc_identity->hx509ctx,
kdc_identity->certs,
buf.length,
NULL,
cert,
- client_params->peer,
- client_params->client_anchors,
+ cp->peer,
+ cp->client_anchors,
kdc_identity->certpool,
&signed_data);
- hx509_cert_free(cert);
+ *kdc_cert = cert;
}
krb5_data_free(&buf);
if (ret)
goto out;
- if (client_params->type == PKINIT_WIN2K) {
- ret = hx509_cms_wrap_ContentInfo(oid_id_pkcs7_signedData(),
+ if (cp->type == PKINIT_WIN2K) {
+ ret = hx509_cms_wrap_ContentInfo(&asn1_oid_id_pkcs7_signedData,
&signed_data,
&buf);
if (ret)
}
ret = hx509_cms_envelope_1(kdc_identity->hx509ctx,
- 0,
- client_params->cert,
+ HX509_CMS_EV_NO_KU_CHECK,
+ cp->cert,
signed_data.data, signed_data.length,
envelopedAlg,
evAlg, &buf);
ret = _krb5_pk_mk_ContentInfo(context,
&buf,
- oid_id_pkcs7_envelopedData(),
+ &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,
- DH *kdc_dh,
- pk_client_params *client_params,
- krb5_keyblock *reply_key,
+ krb5_kdc_configuration *config,
+ pk_client_params *cp,
ContentInfo *content_info,
hx509_cert *kdc_cert)
{
krb5_data signed_data, buf;
ContentInfo contentinfo;
krb5_error_code ret;
+ hx509_cert cert;
+ hx509_query *q;
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);
+ krb5_data_zero(&buf);
*kdc_cert = NULL;
- ret = BN_to_integer(context, kdc_dh->pub_key, &i);
- if (ret)
- return ret;
+ if (cp->keyex == USE_DH) {
+ DH *kdc_dh = cp->u.dh.key;
+ heim_integer i;
- 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;
+ 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);
+#ifdef HAVE_OPENSSL
+ } else if (cp->keyex == USE_ECDH) {
+ unsigned char *p;
+ int len;
+
+ len = i2o_ECPublicKey(cp->u.ecdh.key, NULL);
+ if (len <= 0)
+ abort();
+
+ p = malloc(len);
+ if (p == NULL)
+ abort();
+
+ dh_info.subjectPublicKey.length = len * 8;
+ dh_info.subjectPublicKey.data = p;
+
+ len = i2o_ECPublicKey(cp->u.ecdh.key, &p);
+ if (len <= 0)
+ abort();
+#endif
+ } else
+ krb5_abortx(context, "no keyex selected ?");
- dh_info.nonce = client_params->nonce;
+
+ dh_info.nonce = cp->nonce;
ASN1_MALLOC_ENCODE(KDCDHKeyInfo, buf.data, buf.length, &dh_info, &size,
ret);
* 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;
- }
+ ret = hx509_query_alloc(kdc_identity->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(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,
+ &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,
- oid_id_pkcs7_signedData(),
+ &asn1_oid_id_pkcs7_signedData,
content_info);
if (ret)
goto out;
krb5_error_code
_kdc_pk_mk_pa_reply(krb5_context context,
krb5_kdc_configuration *config,
- pk_client_params *client_params,
+ pk_client_params *cp,
const hdb_entry_ex *client,
+ krb5_enctype sessionetype,
const KDC_REQ *req,
const krb5_data *req_buffer,
krb5_keyblock **reply_key,
+ krb5_keyblock *sessionkey,
METHOD_DATA *md)
{
krb5_error_code ret;
} else
enctype = ETYPE_DES3_CBC_SHA1;
- if (client_params->type == PKINIT_27) {
+ if (cp->type == PKINIT_27) {
PA_PK_AS_REP rep;
const char *type, *other = "";
pa_type = KRB5_PADATA_PK_AS_REP;
- if (client_params->dh == NULL) {
+ if (cp->keyex == USE_RSA) {
ContentInfo info;
type = "enckey";
rep.element = choice_PA_PK_AS_REP_encKeyPack;
ret = krb5_generate_random_keyblock(context, enctype,
- &client_params->reply_key);
+ &cp->reply_key);
if (ret) {
free_PA_PK_AS_REP(&rep);
goto out;
}
ret = pk_mk_pa_reply_enckey(context,
config,
- client_params,
+ cp,
req,
req_buffer,
- &client_params->reply_key,
- &info);
+ &cp->reply_key,
+ &info,
+ &kdc_cert);
if (ret) {
free_PA_PK_AS_REP(&rep);
goto out;
if (rep.u.encKeyPack.length != size)
krb5_abortx(context, "Internal ASN.1 encoder error");
+ ret = krb5_generate_random_keyblock(context, sessionetype,
+ sessionkey);
+ if (ret) {
+ free_PA_PK_AS_REP(&rep);
+ goto out;
+ }
+
} else {
ContentInfo info;
- type = "dh";
- if (client_params->dh_group_name)
- other = client_params->dh_group_name;
+ switch (cp->keyex) {
+ case USE_DH: type = "dh"; break;
+#ifdef HAVE_OPENSSL
+ case USE_ECDH: type = "ecdh"; break;
+#endif
+ default: krb5_abortx(context, "unknown keyex"); break;
+ }
+
+ if (cp->dh_group_name)
+ other = cp->dh_group_name;
rep.element = choice_PA_PK_AS_REP_dhInfo;
- ret = generate_dh_keyblock(context, client_params, enctype,
- &client_params->reply_key);
+ ret = generate_dh_keyblock(context, cp, enctype);
if (ret)
return ret;
- ret = pk_mk_pa_reply_dh(context, client_params->dh,
- client_params,
- &client_params->reply_key,
+ ret = pk_mk_pa_reply_dh(context, config,
+ cp,
&info,
&kdc_cert);
+ if (ret) {
+ free_PA_PK_AS_REP(&rep);
+ krb5_set_error_message(context, ret,
+ "create pa-reply-dh "
+ "failed %d", ret);
+ goto out;
+ }
ASN1_MALLOC_ENCODE(ContentInfo, rep.u.dhInfo.dhSignedData.data,
rep.u.dhInfo.dhSignedData.length, &info, &size,
ret);
free_ContentInfo(&info);
if (ret) {
- krb5_set_error_message(context, ret, "encoding of Key ContentInfo "
+ krb5_set_error_message(context, ret,
+ "encoding of Key ContentInfo "
"failed %d", ret);
free_PA_PK_AS_REP(&rep);
goto out;
if (rep.u.encKeyPack.length != size)
krb5_abortx(context, "Internal ASN.1 encoder error");
- }
- if (ret) {
- free_PA_PK_AS_REP(&rep);
- goto out;
+ /* XXX KRB-FX-CF2 */
+ ret = krb5_generate_random_keyblock(context, sessionetype,
+ sessionkey);
+ if (ret) {
+ free_PA_PK_AS_REP(&rep);
+ goto out;
+ }
+
+ /* XXX Add PA-PKINIT-KX */
+
}
ASN1_MALLOC_ENCODE(PA_PK_AS_REP, buf, len, &rep, &size, ret);
free_PA_PK_AS_REP(&rep);
if (ret) {
- krb5_set_error_message(context, ret, "encode PA-PK-AS-REP failed %d",
- ret);
+ krb5_set_error_message(context, ret,
+ "encode PA-PK-AS-REP failed %d", ret);
goto out;
}
if (len != size)
kdc_log(context, config, 0, "PK-INIT using %s %s", type, other);
- } else if (client_params->type == PKINIT_WIN2K) {
+ } else if (cp->type == PKINIT_WIN2K) {
PA_PK_AS_REP_Win2k rep;
ContentInfo info;
- if (client_params->dh) {
+ if (cp->keyex != USE_RSA) {
ret = KRB5KRB_ERR_GENERIC;
- krb5_set_error_message(context, ret, "Windows PK-INIT doesn't support DH");
+ krb5_set_error_message(context, ret,
+ "Windows PK-INIT doesn't support DH");
goto out;
}
rep.element = choice_PA_PK_AS_REP_encKeyPack;
ret = krb5_generate_random_keyblock(context, enctype,
- &client_params->reply_key);
+ &cp->reply_key);
if (ret) {
free_PA_PK_AS_REP_Win2k(&rep);
goto out;
}
ret = pk_mk_pa_reply_enckey(context,
config,
- client_params,
+ cp,
req,
req_buffer,
- &client_params->reply_key,
- &info);
+ &cp->reply_key,
+ &info,
+ &kdc_cert);
if (ret) {
free_PA_PK_AS_REP_Win2k(&rep);
goto out;
if (len != size)
krb5_abortx(context, "Internal ASN.1 encoder error");
+ ret = krb5_generate_random_keyblock(context, sessionetype,
+ sessionkey);
+ if (ret)
+ goto out;
+
} else
krb5_abortx(context, "PK-INIT internal error");
ret = krb5_padata_add(context, md, pa_type, buf, len);
if (ret) {
- krb5_set_error_message(context, ret, "failed adding PA-PK-AS-REP %d", ret);
+ krb5_set_error_message(context, ret,
+ "Failed adding PA-PK-AS-REP %d", ret);
free(buf);
goto out;
}
hx509_cert_free(kdc_cert);
if (ret == 0)
- *reply_key = &client_params->reply_key;
+ *reply_key = &cp->reply_key;
return ret;
}
ret = hx509_cert_find_subjectAltName_otherName(hx509ctx,
client_cert,
- oid_id_pkinit_san(),
+ &asn1_oid_id_pkinit_san,
&list);
if (ret)
goto out;
ret = hx509_cert_find_subjectAltName_otherName(hx509ctx,
client_cert,
- oid_id_pkinit_ms_san(),
+ &asn1_oid_id_pkinit_ms_san,
&list);
if (ret)
goto out;
_kdc_pk_check_client(krb5_context context,
krb5_kdc_configuration *config,
const hdb_entry_ex *client,
- pk_client_params *client_params,
+ pk_client_params *cp,
char **subject_name)
{
const HDB_Ext_PKINIT_acl *acl;
+ const HDB_Ext_PKINIT_cert *pc;
krb5_error_code ret;
hx509_name name;
int i;
+ if (cp->cert == NULL) {
+
+ *subject_name = strdup("anonymous client client");
+ if (*subject_name == NULL)
+ return ENOMEM;
+ return 0;
+ }
+
ret = hx509_cert_get_base_subject(kdc_identity->hx509ctx,
- client_params->cert,
+ cp->cert,
&name);
if (ret)
return ret;
"Trying to authorize PK-INIT subject DN %s",
*subject_name);
+ ret = hdb_entry_get_pkinit_cert(&client->entry, &pc);
+ if (ret == 0 && pc) {
+ hx509_cert cert;
+ unsigned int i;
+
+ for (i = 0; i < pc->len; i++) {
+ ret = hx509_cert_init_data(kdc_identity->hx509ctx,
+ pc->val[i].cert.data,
+ pc->val[i].cert.length,
+ &cert);
+ if (ret)
+ continue;
+ ret = hx509_cert_cmp(cert, cp->cert);
+ hx509_cert_free(cert);
+ if (ret == 0) {
+ kdc_log(context, config, 5,
+ "Found matching PK-INIT cert in hdb");
+ return 0;
+ }
+ }
+ }
+
+
if (config->pkinit_princ_in_cert) {
ret = match_rfc_san(context, config,
kdc_identity->hx509ctx,
- client_params->cert,
+ cp->cert,
client->entry.principal);
if (ret == 0) {
kdc_log(context, config, 5,
}
ret = match_ms_upn_san(context, config,
kdc_identity->hx509ctx,
- client_params->cert,
+ cp->cert,
client->entry.principal);
if (ret == 0) {
kdc_log(context, config, 5,
krb5_error_code
_kdc_add_inital_verified_cas(krb5_context context,
krb5_kdc_configuration *config,
- pk_client_params *params,
+ pk_client_params *cp,
EncTicketPart *tkt)
{
AD_INITIAL_VERIFIED_CAS cas;
ret = _krb5_pk_load_id(context,
&kdc_identity,
+ 0,
user_id,
anchors,
pool,
}
hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
- hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE);
+ if (config->pkinit_kdc_friendly_name)
+ hx509_query_match_friendly_name(q, config->pkinit_kdc_friendly_name);
ret = hx509_certs_find(kdc_identity->hx509ctx,
kdc_identity->certs,
hx509_query_free(kdc_identity->hx509ctx, q);
if (ret == 0) {
if (hx509_cert_check_eku(kdc_identity->hx509ctx, cert,
- oid_id_pkkdcekuoid(), 0))
- krb5_warnx(context, "WARNING Found KDC certificate "
+ &asn1_oid_id_pkkdcekuoid, 0)) {
+ hx509_name name;
+ char *str;
+ ret = hx509_cert_get_subject(cert, &name);
+ hx509_name_to_string(name, &str);
+ krb5_warnx(context, "WARNING Found KDC certificate (%s)"
"is missing the PK-INIT KDC EKU, this is bad for "
- "interoperability.");
+ "interoperability.", str);
+ hx509_name_free(&name);
+ free(str);
+ }
hx509_cert_free(cert);
} else
krb5_warnx(context, "PKINIT: failed to find a signing "
"certifiate with a public key");
}
- ret = krb5_config_get_bool_default(context,
- NULL,
- FALSE,
- "kdc",
- "pkinit_allow_proxy_certificate",
- NULL);
- _krb5_pk_allow_proxy_certificate(kdc_identity, ret);
+ if (krb5_config_get_bool_default(context,
+ NULL,
+ FALSE,
+ "kdc",
+ "pkinit_allow_proxy_certificate",
+ NULL))
+ config->pkinit_allow_proxy_certs = 1;
file = krb5_config_get_string(context,
NULL,
#include "kdc_locl.h"
-RCSID("$Id$");
-
/*
*
*/
_kdc_now = *tv;
}
+static krb5_error_code
+kdc_as_req(krb5_context context,
+ krb5_kdc_configuration *config,
+ krb5_data *req_buffer,
+ krb5_data *reply,
+ const char *from,
+ struct sockaddr *addr,
+ int datagram_reply,
+ int *claim)
+{
+ krb5_error_code ret;
+ KDC_REQ req;
+ size_t len;
+
+ ret = decode_AS_REQ(req_buffer->data, req_buffer->length, &req, &len);
+ if (ret)
+ return ret;
+
+ *claim = 1;
+
+ ret = _kdc_as_rep(context, config, &req, req_buffer,
+ reply, from, addr, datagram_reply);
+ free_AS_REQ(&req);
+ return ret;
+}
+
+
+static krb5_error_code
+kdc_tgs_req(krb5_context context,
+ krb5_kdc_configuration *config,
+ krb5_data *req_buffer,
+ krb5_data *reply,
+ const char *from,
+ struct sockaddr *addr,
+ int datagram_reply,
+ int *claim)
+{
+ krb5_error_code ret;
+ KDC_REQ req;
+ size_t len;
+
+ ret = decode_TGS_REQ(req_buffer->data, req_buffer->length, &req, &len);
+ if (ret)
+ return ret;
+
+ *claim = 1;
+
+ ret = _kdc_tgs_rep(context, config, &req, reply,
+ from, addr, datagram_reply);
+ free_TGS_REQ(&req);
+ return ret;
+}
+
+#ifdef DIGEST
+
+static krb5_error_code
+kdc_digest(krb5_context context,
+ krb5_kdc_configuration *config,
+ krb5_data *req_buffer,
+ krb5_data *reply,
+ const char *from,
+ struct sockaddr *addr,
+ int datagram_reply,
+ int *claim)
+{
+ DigestREQ digestreq;
+ krb5_error_code ret;
+ size_t len;
+
+ ret = decode_DigestREQ(req_buffer->data, req_buffer->length,
+ &digestreq, &len);
+ if (ret)
+ return ret;
+
+ *claim = 1;
+
+ ret = _kdc_do_digest(context, config, &digestreq, reply, from, addr);
+ free_DigestREQ(&digestreq);
+ return ret;
+}
+
+#endif
+
+#ifdef KX509
+
+static krb5_error_code
+kdc_kx509(krb5_context context,
+ krb5_kdc_configuration *config,
+ krb5_data *req_buffer,
+ krb5_data *reply,
+ const char *from,
+ struct sockaddr *addr,
+ int datagram_reply,
+ int *claim)
+{
+ Kx509Request kx509req;
+ krb5_error_code ret;
+ size_t len;
+
+ ret = _kdc_try_kx509_request(req_buffer->data, req_buffer->length,
+ &kx509req, &len);
+ if (ret)
+ return ret;
+
+ *claim = 1;
+
+ ret = _kdc_do_kx509(context, config, &kx509req, reply, from, addr);
+ free_Kx509Request(&kx509req);
+ return ret;
+}
+
+#endif
+
+
+#ifdef KRB4
+
+static krb5_error_code
+kdc_524(krb5_context context,
+ krb5_kdc_configuration *config,
+ krb5_data *req_buffer,
+ krb5_data *reply,
+ const char *from,
+ struct sockaddr *addr,
+ int datagram_reply,
+ int *claim)
+{
+ krb5_error_code ret;
+ Ticket ticket;
+ size_t len;
+
+ ret = decode_Ticket(req_buffer->data, req_buffer->length, &ticket, &len);
+ if (ret)
+ return ret;
+
+ *claim = 1;
+
+ ret = _kdc_do_524(context, config, &ticket, reply, from, addr);
+ free_Ticket(&ticket);
+ return ret;
+}
+
+static krb5_error_code
+kdc_krb4(krb5_context context,
+ krb5_kdc_configuration *config,
+ krb5_data *req_buffer,
+ krb5_data *reply,
+ const char *from,
+ struct sockaddr *addr,
+ int datagram_reply,
+ int *claim)
+{
+ if (_kdc_maybe_version4(req_buffer->data, req_buffer->length) == 0)
+ return -1;
+
+ *claim = 1;
+
+ return _kdc_do_version4(context, config,
+ req_buffer->data, req_buffer->length,
+ reply, from,
+ (struct sockaddr_in*)addr);
+}
+
+static krb5_error_code
+kdc_kaserver(krb5_context context,
+ krb5_kdc_configuration *config,
+ krb5_data *req_buffer,
+ krb5_data *reply,
+ const char *from,
+ struct sockaddr *addr,
+ int datagram_reply,
+ int *claim)
+{
+ if (config->enable_kaserver == 0)
+ return -1;
+
+ *claim = 1;
+
+ return _kdc_do_kaserver(context, config,
+ req_buffer->data, req_buffer->length,
+ reply, from,
+ (struct sockaddr_in*)addr);
+}
+
+#endif /* KRB4 */
+
+
+static struct krb5_kdc_service services[] = {
+ { KS_KRB5, kdc_as_req },
+ { KS_KRB5, kdc_tgs_req },
+#ifdef DIGEST
+ { 0, kdc_digest },
+#endif
+#ifdef KX509
+ { 0, kdc_kx509 },
+#endif
+#ifdef KRB4
+ { 0, kdc_524 },
+ { KS_NO_LENGTH, kdc_krb4 },
+ { 0, kdc_kaserver },
+#endif
+ { 0, NULL }
+};
+
/*
* handle the request in `buf, len', from `addr' (or `from' as a string),
* sending a reply in `reply'.
struct sockaddr *addr,
int datagram_reply)
{
- KDC_REQ req;
- Ticket ticket;
- DigestREQ digestreq;
- Kx509Request kx509req;
krb5_error_code ret;
- size_t i;
-
- if(decode_AS_REQ(buf, len, &req, &i) == 0){
- krb5_data req_buffer;
+ unsigned int i;
+ krb5_data req_buffer;
+ int claim = 0;
+
+ req_buffer.data = buf;
+ req_buffer.length = len;
- req_buffer.data = buf;
- req_buffer.length = len;
-
- ret = _kdc_as_rep(context, config, &req, &req_buffer,
- reply, from, addr, datagram_reply);
- free_AS_REQ(&req);
- return ret;
- }else if(decode_TGS_REQ(buf, len, &req, &i) == 0){
- ret = _kdc_tgs_rep(context, config, &req, reply, from, addr, datagram_reply);
- free_TGS_REQ(&req);
- return ret;
- }else if(decode_Ticket(buf, len, &ticket, &i) == 0){
- ret = _kdc_do_524(context, config, &ticket, reply, from, addr);
- free_Ticket(&ticket);
- return ret;
- }else if(decode_DigestREQ(buf, len, &digestreq, &i) == 0){
- ret = _kdc_do_digest(context, config, &digestreq, reply, from, addr);
- free_DigestREQ(&digestreq);
- return ret;
- } else if (_kdc_try_kx509_request(buf, len, &kx509req, &i) == 0) {
- ret = _kdc_do_kx509(context, config, &kx509req, reply, from, addr);
- free_Kx509Request(&kx509req);
- return ret;
- } else if(_kdc_maybe_version4(buf, len)){
- *prependlength = FALSE; /* elbitapmoc sdrawkcab XXX */
- ret = _kdc_do_version4(context, config, buf, len, reply, from,
- (struct sockaddr_in*)addr);
- return ret;
- } else if (config->enable_kaserver) {
- ret = _kdc_do_kaserver(context, config, buf, len, reply, from,
- (struct sockaddr_in*)addr);
- return ret;
+ for (i = 0; services[i].process != NULL; i++) {
+ ret = (*services[i].process)(context, config, &req_buffer,
+ reply, from, addr, datagram_reply,
+ &claim);
+ if (claim) {
+ if (services[i].flags & KS_NO_LENGTH)
+ *prependlength = 0;
+ return ret;
+ }
}
-
+
return -1;
}
struct sockaddr *addr,
int datagram_reply)
{
- KDC_REQ req;
krb5_error_code ret;
- size_t i;
+ unsigned int i;
+ krb5_data req_buffer;
+ int claim = 0;
+
+ req_buffer.data = buf;
+ req_buffer.length = len;
- if(decode_AS_REQ(buf, len, &req, &i) == 0){
- krb5_data req_buffer;
-
- req_buffer.data = buf;
- req_buffer.length = len;
-
- ret = _kdc_as_rep(context, config, &req, &req_buffer,
- reply, from, addr, datagram_reply);
- free_AS_REQ(&req);
- return ret;
- }else if(decode_TGS_REQ(buf, len, &req, &i) == 0){
- ret = _kdc_tgs_rep(context, config, &req, reply, from, addr, datagram_reply);
- free_TGS_REQ(&req);
- return ret;
+ for (i = 0; services[i].process != NULL; i++) {
+ if ((services[i].flags & KS_KRB5) == 0)
+ continue;
+ ret = (*services[i].process)(context, config, &req_buffer,
+ reply, from, addr, datagram_reply,
+ &claim);
+ if (claim)
+ return ret;
}
+
return -1;
}
if (ret)
krb5_err (context, 1, ret, "krb5_cc_resolve");
} else {
- ret = krb5_cc_gen_new(context, &krb5_mcc_ops, &id);
+ ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &id);
if (ret)
- krb5_err (context, 1, ret, "krb5_cc_gen_new");
+ krb5_err (context, 1, ret, "krb5_cc_new_unique");
}
if (cred_cache_str == NULL) {
*/
#include "kuser_locl.h"
-RCSID("$Id$");
+#ifndef HEIMDAL_SMALLER
#include "krb5-v4compat.h"
+#endif
+
+struct krb5_dh_moduli;
+struct AlgorithmIdentifier;
+struct _krb5_krb_auth_data;
+#include <krb5-private.h>
+#ifndef NO_NTLM
#include "heimntlm.h"
+#endif
int forwardable_flag = -1;
int proxiable_flag = -1;
char *server_str = NULL;
char *cred_cache = NULL;
char *start_str = NULL;
+static int switch_cache_flags = 1;
struct getarg_strings etype_str;
int use_keytab = 0;
char *keytab_str = NULL;
int fcache_version;
char *password_file = NULL;
char *pk_user_id = NULL;
+int pk_enterprise_flag = 0;
char *pk_x509_anchors = NULL;
int pk_use_enckey = 0;
static int canonicalize_flag = 0;
+static int enterprise_flag = 0;
static int ok_as_delegate_flag = 0;
static int use_referrals_flag = 0;
static int windows_flag = 0;
+#ifndef NO_NTLM
static char *ntlm_domain;
+#endif
static struct getargs args[] = {
{ "canonicalize",0, arg_flag, &canonicalize_flag,
NP_("canonicalize client principal", "") },
+
+ { "enterprise",0, arg_flag, &enterprise_flag,
+ NP_("parse principal as a KRB5-NT-ENTERPRISE name", "") },
#ifdef PKINIT
+ { "pk-enterprise", 0, arg_flag, &pk_enterprise_flag,
+ NP_("use enterprise name from certificate", "") },
+
{ "pk-user", 'C', arg_string, &pk_user_id,
NP_("principal's public/private/certificate identifier", ""), "id" },
{ "pk-use-enckey", 0, arg_flag, &pk_use_enckey,
NP_("Use RSA encrypted reply (instead of DH)", "") },
#endif
+#ifndef NO_NTLM
{ "ntlm-domain", 0, arg_string, &ntlm_domain,
NP_("NTLM domain", ""), "domain" },
+#endif
+
+ { "change-default", 0, arg_negative_flag, &switch_cache_flags,
+ NP_("switch the default cache to the new credentials cache", "") },
{ "ok-as-delegate", 0, arg_flag, &ok_as_delegate_flag,
NP_("honor ok-as-delegate on tickets", "") },
const char *server,
krb5_principal *princ)
{
- krb5_realm *client_realm;
+ krb5_const_realm realm;
if(server)
return krb5_parse_name(context, server, princ);
- client_realm = krb5_princ_realm (context, client);
- return krb5_make_principal(context, princ, *client_realm,
- KRB5_TGS_NAME, *client_realm, NULL);
+ realm = krb5_principal_get_realm(context, client);
+ return krb5_make_principal(context, princ, realm,
+ KRB5_TGS_NAME, realm, NULL);
}
#ifndef HEIMDAL_SMALLER
else if (out)
flags.b.proxiable = out->flags.b.proxiable;
- if (anonymous_flag != -1)
+ if (anonymous_flag)
flags.b.request_anonymous = anonymous_flag;
if(life)
in.times.endtime = time(NULL) + life;
if(get_v4_tgt)
do_524init(context, cache, out, NULL);
#endif
+#ifndef NO_AFS
if(do_afslog && k_hasafs())
krb5_afslog(context, cache, NULL, NULL);
+#endif
}
krb5_free_creds (context, out);
return ret;
}
+#ifndef NO_NTLM
+
static krb5_error_code
store_ntlmkey(krb5_context context, krb5_ccache id,
const char *domain, struct ntlm_buf *buf)
free(name);
return ret;
}
+#endif
static krb5_error_code
get_new_tickets(krb5_context context,
krb5_deltat renew = 0;
char *renewstr = NULL;
krb5_enctype *enctype = NULL;
- struct ntlm_buf ntlmkey;
krb5_ccache tempccache;
-
+#ifndef NO_NTLM
+ struct ntlm_buf ntlmkey;
memset(&ntlmkey, 0, sizeof(ntlmkey));
+#endif
passwd[0] = '\0';
if (password_file) {
krb5_get_init_creds_opt_set_forwardable (opt, forwardable_flag);
if(proxiable_flag != -1)
krb5_get_init_creds_opt_set_proxiable (opt, proxiable_flag);
- if(anonymous_flag != -1)
+ if(anonymous_flag)
krb5_get_init_creds_opt_set_anonymous (opt, anonymous_flag);
if (pac_flag != -1)
krb5_get_init_creds_opt_set_pac_request(context, opt,
pac_flag ? TRUE : FALSE);
if (canonicalize_flag)
krb5_get_init_creds_opt_set_canonicalize(context, opt, TRUE);
- if (pk_user_id) {
+ if (pk_enterprise_flag && windows_flag)
+ krb5_get_init_creds_opt_set_win2k(context, opt, TRUE);
+ if (pk_user_id || anonymous_flag) {
ret = krb5_get_init_creds_opt_set_pkinit(context, opt,
principal,
pk_user_id,
pk_x509_anchors,
NULL,
NULL,
- pk_use_enckey ? 2 : 0,
+ pk_use_enckey ? 2 : 0 |
+ anonymous_flag ? 4 : 0,
krb5_prompter_posix,
NULL,
passwd);
server_str,
opt);
krb5_kt_close(context, kt);
- } else if (pk_user_id) {
+ } else if (pk_user_id || anonymous_flag) {
ret = krb5_get_init_creds_password (context,
&cred,
principal,
opt);
}
krb5_get_init_creds_opt_free(context, opt);
+#ifndef NO_NTLM
if (ntlm_domain && passwd[0])
heim_ntlm_nt_key(passwd, &ntlmkey);
+#endif
memset(passwd, 0, sizeof(passwd));
switch(ret){
if (ret)
krb5_err (context, 1, ret, "krb5_cc_move");
+ if (switch_cache_flags)
+ krb5_cc_switch(context, ccache);
+
+#ifndef NO_NTLM
if (ntlm_domain && ntlmkey.data)
store_ntlmkey(context, ccache, ntlm_domain, &ntlmkey);
+#endif
if (ok_as_delegate_flag || windows_flag || use_referrals_flag) {
unsigned char d = 0;
if(get_v4_tgt || convert_524)
do_524init(ctx->context, ctx->ccache, NULL, server_str);
#endif
+#ifndef NO_AFS
if(do_afslog && k_hasafs())
krb5_afslog(ctx->context, ctx->ccache, NULL, NULL);
+#endif
expire = ticket_lifetime(ctx->context, ctx->ccache, ctx->principal,
server_str) / 2;
argc -= optidx;
argv += optidx;
- if (canonicalize_flag)
+ if (canonicalize_flag || enterprise_flag)
parseflags |= KRB5_PRINCIPAL_PARSE_ENTERPRISE;
- if (argv[0]) {
- ret = krb5_parse_name_flags (context, argv[0], parseflags, &principal);
+ if (pk_enterprise_flag) {
+ ret = _krb5_pk_enterprise_cert(context, pk_user_id,
+ argv[0], &principal);
if (ret)
- krb5_err (context, 1, ret, "krb5_parse_name");
- } else {
- ret = krb5_get_default_principal (context, &principal);
+ krb5_err(context, 1, ret, "krb5_pk_enterprise_certs");
+
+ } else if (anonymous_flag) {
+
+ ret = krb5_make_principal(context, &principal, argv[0],
+ KRB5_WELLKNOWN_NAME, KRB5_ANON_NAME,
+ NULL);
if (ret)
- krb5_err (context, 1, ret, "krb5_get_default_principal");
+ krb5_err(context, 1, ret, "krb5_build_principal");
+ krb5_principal_set_type(context, principal, KRB5_NT_WELLKNOWN);
+
+ } else {
+ if (argv[0]) {
+ ret = krb5_parse_name_flags (context, argv[0], parseflags,
+ &principal);
+ if (ret)
+ krb5_err (context, 1, ret, "krb5_parse_name");
+ } else {
+ ret = krb5_get_default_principal (context, &principal);
+ if (ret)
+ krb5_err (context, 1, ret, "krb5_get_default_principal");
+ }
}
if(fcache_version)
else {
if(argc > 1) {
char s[1024];
- ret = krb5_cc_gen_new(context, &krb5_fcc_ops, &ccache);
+ ret = krb5_cc_new_unique(context, NULL, NULL, &ccache);
if(ret)
krb5_err(context, 1, ret, "creating cred cache");
snprintf(s, sizeof(s), "%s:%s",
if (ret)
krb5_err (context, 1, ret, N_("resolving credentials cache", ""));
+#ifndef NO_AFS
if(argc > 1 && k_hasafs ())
k_setpag();
+#endif
if (lifetime) {
int tmp = parse_time (lifetime, "s");
if(get_v4_tgt || convert_524)
do_524init(context, ccache, NULL, server_str);
#endif
+#ifndef NO_AFS
if(do_afslog && k_hasafs())
krb5_afslog(context, ccache, NULL, NULL);
+#endif
if(argc > 1) {
struct renew_ctx ctx;
time_t timeout;
#ifndef HEIMDAL_SMALLER
_krb5_krb_dest_tkt(context, krb4_cc_name);
#endif
+#ifndef NO_AFS
if(k_hasafs())
k_unlog();
+#endif
} else {
krb5_cc_close (context, ccache);
ret = 0;
#ifndef __KUSER_LOCL_H__
#define __KUSER_LOCL_H__
-#ifdef HAVE_CONFIG_H
#include <config.h>
-#endif
#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_SYS_IOCCOM_H
#include <sys/ioccom.h>
#endif
+#ifndef NO_AFS
#include <kafs.h>
+#endif
#include "crypto-headers.h" /* for UI_UTIL_read_pw_string */
#ifdef HAVE_LOCALE_H
error_code MIN_CONSTRAINT, "ASN.1 too few elements"
error_code MAX_CONSTRAINT, "ASN.1 too many elements"
error_code EXACT_CONSTRAINT, "ASN.1 wrong number of elements"
+error_code INDEF_OVERRUN, "ASN.1 BER indefinte encoding overrun"
+error_code INDEF_UNDERRUN, "ASN.1 BER indefinte encoding underun"
end
&sz);
if (ret)
errx(1, "der_put_length_and_tag: %d", ret);
-
+
if (fwrite(p + sizeof(p) - sz , sz, 1, fout) != 1)
err(1, "fwrite length/tag failed");
offset += sz;
-
+
if (data) {
size_t datalen;
-
+
datalen = strlen(data) / 2;
pdata = emalloc(sz);
-
+
if (hex_decode(data, pdata, datalen) != datalen)
errx(1, "failed to decode data");
-
+
if (fwrite(pdata, datalen, 1, fout) != 1)
err(1, "fwrite data failed");
offset += datalen;
-
+
free(pdata);
}
}
-- Code the tag [2] but it should be primitive since KAKA3 is
-- Workaround: use the INTEGER type directly
-Kaka2 ::= SEQUENCE {
+Kaka2 ::= SEQUENCE {
kaka2-1 [0] INTEGER
}
id-pkcs7-encryptedData OBJECT IDENTIFIER ::= { id-pkcs7 6 }
CMSVersion ::= INTEGER {
- CMSVersion_v0(0),
- CMSVersion_v1(1),
+ CMSVersion_v0(0),
+ CMSVersion_v1(1),
CMSVersion_v2(2),
CMSVersion_v3(3),
CMSVersion_v4(4)
ContentInfo ::= SEQUENCE {
contentType ContentType,
- content [0] EXPLICIT heim_any OPTIONAL -- DEFINED BY contentType
+ content [0] EXPLICIT heim_any OPTIONAL -- DEFINED BY contentType
}
EncapsulatedContentInfo ::= SEQUENCE {
serialNumber CertificateSerialNumber
}
--- RecipientIdentifier is same as SignerIdentifier,
+-- RecipientIdentifier is same as SignerIdentifier,
-- lets glue them togheter and save some bytes and share code for them
CMSIdentifier ::= CHOICE {
--- CMSAttributes are the combined UnsignedAttributes and SignedAttributes
--- to store space and share code
-CMSAttributes ::= SET OF Attribute -- SIZE (1..MAX)
+CMSAttributes ::= SET OF Attribute -- SIZE (1..MAX)
SignatureValue ::= OCTET STRING
SET OF Attribute OPTIONAL,
signatureAlgorithm SignatureAlgorithmIdentifier,
signature SignatureValue,
- unsignedAttrs [1] IMPLICIT -- CMSAttributes --
+ unsignedAttrs [1] IMPLICIT -- CMSAttributes --
SET OF Attribute OPTIONAL
}
--- /dev/null
+--decode-dce-ber
enum {
UT_EndOfContent = 0,
UT_Boolean = 1,
- UT_Integer = 2,
+ UT_Integer = 2,
UT_BitString = 3,
UT_OctetString = 4,
UT_Null = 5,
#include "der_locl.h"
-RCSID("$Id$");
-
-#include <version.h>
-
/*
* All decoding functions take a pointer `p' to first position in
* which to read, from the left, `len' which means the maximum number
return 0;
}
+int
+der_get_octet_string_ber (const unsigned char *p, size_t len,
+ heim_octet_string *data, size_t *size)
+{
+ int e;
+ Der_type type;
+ Der_class class;
+ unsigned int tag, depth = 0;
+ size_t l, datalen, oldlen = len;
+
+ data->length = 0;
+ data->data = NULL;
+
+ while (len) {
+ e = der_get_tag (p, len, &class, &type, &tag, &l);
+ if (e) goto out;
+ if (class != ASN1_C_UNIV) {
+ e = ASN1_BAD_ID;
+ goto out;
+ }
+ if (type == PRIM && tag == UT_EndOfContent) {
+ if (depth == 0)
+ break;
+ depth--;
+ }
+ if (tag != UT_OctetString) {
+ e = ASN1_BAD_ID;
+ goto out;
+ }
+
+ p += l;
+ len -= l;
+ e = der_get_length (p, len, &datalen, &l);
+ if (e) goto out;
+ p += l;
+ len -= l;
+
+ if (datalen > len)
+ return ASN1_OVERRUN;
+
+ if (type == PRIM) {
+ void *ptr;
+
+ ptr = realloc(data->data, data->length + datalen);
+ if (ptr == NULL) {
+ e = ENOMEM;
+ goto out;
+ }
+ data->data = ptr;
+ memcpy(((unsigned char *)data->data) + data->length, p, datalen);
+ data->length += datalen;
+ } else
+ depth++;
+
+ p += datalen;
+ len -= datalen;
+ }
+ if (depth != 0)
+ return ASN1_INDEF_OVERRUN;
+ if(size) *size = oldlen - len;
+ return 0;
+ out:
+ free(data->data);
+ data->data = NULL;
+ data->length = 0;
+ return e;
+}
+
+
int
der_get_heim_integer (const unsigned char *p, size_t len,
heim_integer *data, size_t *size)
++p;
for (n = 2; len > 0; ++n) {
unsigned u = 0, u1;
-
+
do {
--len;
u1 = u * 128 + (*p++ % 128);
der_match_tag (const unsigned char *p, size_t len,
Der_class class, Der_type type,
unsigned int tag, size_t *size)
+{
+ Der_type thistype;
+ int e;
+
+ e = der_match_tag2(p, len, class, &thistype, tag, size);
+ if (e) return e;
+ if (thistype != type) return ASN1_BAD_ID;
+ return 0;
+}
+
+int
+der_match_tag2 (const unsigned char *p, size_t len,
+ Der_class class, Der_type *type,
+ unsigned int tag, size_t *size)
{
size_t l;
Der_class thisclass;
- Der_type thistype;
unsigned int thistag;
int e;
- e = der_get_tag (p, len, &thisclass, &thistype, &thistag, &l);
+ e = der_get_tag (p, len, &thisclass, type, &thistag, &l);
if (e) return e;
- if (class != thisclass || type != thistype)
+ if (class != thisclass)
return ASN1_BAD_ID;
if(tag > thistag)
return ASN1_MISPLACED_FIELD;
int
der_match_tag_and_length (const unsigned char *p, size_t len,
- Der_class class, Der_type type, unsigned int tag,
+ Der_class class, Der_type *type, unsigned int tag,
size_t *length_ret, size_t *size)
{
size_t l, ret = 0;
int e;
- e = der_match_tag (p, len, class, type, tag, &l);
+ e = der_match_tag2 (p, len, class, type, tag, &l);
if (e) return e;
p += l;
len -= l;
ret += l;
e = der_get_length (p, len, length_ret, &l);
if (e) return e;
- p += l;
- len -= l;
- ret += l;
- if(size) *size = ret;
+ if(size) *size = ret + l;
return 0;
}
+
+
/*
* Old versions of DCE was based on a very early beta of the MIT code,
* which used MAVROS for ASN.1 encoding. MAVROS had the interesting
data->data = malloc(len - 1);
if (data->data == NULL && (len - 1) != 0)
return ENOMEM;
- memcpy (data->data, p + 1, len - 1);
- data->length -= p[0];
+ /* copy data is there is data to copy */
+ if (len - 1 != 0) {
+ memcpy (data->data, p + 1, len - 1);
+ data->length -= p[0];
+ }
if(size) *size = len;
return 0;
}
#ifndef __DER_LOCL_H__
#define __DER_LOCL_H__
-#ifdef HAVE_CONFIG_H
+
#include <config.h>
-#endif
+
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
} else {
size_t ret = 0;
unsigned int continuation = 0;
-
+
do {
if (len < 1)
return ASN1_OVERFLOW;
-- qop == auth
-- A2 = Method ":" digest-uri-value
-- qop == auth-int
--- A2 = Method ":" digest-uri-value ":" H(entity-body)
+-- A2 = Method ":" digest-uri-value ":" H(entity-body)
-- request-digest = HEX(KD(HEX(H(A1)),
-- unq(nonce-value) ":" nc-value ":" unq(cnonce-value) ":" unq(qop-value) ":" HEX(H(A2))))
return ASN1_OVERFLOW;
e = der_get_length(p + l, len - l, &length, &len_len);
if (e) return e;
- if (length + len_len + l > len)
- return ASN1_OVERFLOW;
-
+ if (length == ASN1_INDEFINITE) {
+ if (len < len_len + l)
+ return ASN1_OVERFLOW;
+ length = len - (len_len + l);
+ } else {
+ if (len < length + len_len + l)
+ return ASN1_OVERFLOW;
+ }
+
data->data = malloc(length + len_len + l);
if (data->data == NULL)
return ENOMEM;
data->length = length + len_len + l;
memcpy(data->data, p, length + len_len + l);
-
+
if (size)
*size = length + len_len + l;
if (headerbase == NULL)
errx(1, "strdup");
}
+
+ /* public header file */
asprintf(&header, "%s.h", headerbase);
if (header == NULL)
errx(1, "malloc");
- headerfile = fopen (header, "w");
+ asprintf(&fn, "%s.hx", headerbase);
+ if (fn == NULL)
+ errx(1, "malloc");
+ headerfile = fopen (fn, "w");
if (headerfile == NULL)
- err (1, "open %s", header);
+ err (1, "open %s", fn);
+ free(fn);
+
fprintf (headerfile,
"/* Generated from %s */\n"
"/* Do not edit */\n\n",
}
}
-static void
+void
generate_header_of_codefile(const char *name)
{
char *filename;
}
-static void
+void
close_codefile(void)
{
if (codefile == NULL)
struct objid *o, **list;
unsigned int i, len;
- generate_header_of_codefile(s->gen_name);
+ if (!one_code_file)
+ generate_header_of_codefile(s->gen_name);
len = 0;
for (o = s->value->u.objectidentifiervalue; o != NULL; o = o->next)
}
fprintf (headerfile, "} */\n");
- fprintf (headerfile, "const heim_oid *oid_%s(void);\n\n",
+ fprintf (headerfile, "const heim_oid *oid_%s(void);\n",
+ s->gen_name);
+ fprintf (headerfile,
+ "extern const heim_oid asn1_oid_%s;\n\n",
s->gen_name);
+
fprintf (codefile, "static unsigned oid_%s_variable_num[%d] = {",
s->gen_name, len);
for (i = len ; i > 0; i--) {
}
fprintf(codefile, "};\n");
- fprintf (codefile, "static const heim_oid oid_%s_variable = "
+ fprintf (codefile, "const heim_oid asn1_oid_%s = "
"{ %d, oid_%s_variable_num };\n\n",
s->gen_name, len, s->gen_name);
fprintf (codefile, "const heim_oid *oid_%s(void)\n"
"{\n"
- "return &oid_%s_variable;\n"
+ "return &asn1_oid_%s;\n"
"}\n\n",
s->gen_name, s->gen_name);
- close_codefile();
+ free(list);
+
+ if (!one_code_file)
+ close_codefile();
break;
}
fprintf (headerfile, "struct %s {\n", typedefp ? name : "");
ASN1_TAILQ_FOREACH(m, t->members, members) {
char *n;
-
+
asprintf (&n, "%s:1", m->gen_name);
if (n == NULL)
errx(1, "malloc");
void
generate_type (const Symbol *s)
{
- generate_header_of_codefile(s->gen_name);
+ if (!one_code_file)
+ generate_header_of_codefile(s->gen_name);
generate_type_header (s);
generate_type_encode (s);
generate_type_seq (s);
generate_glue (s->type, s->gen_name);
fprintf(headerfile, "\n\n");
- close_codefile();
+
+ if (!one_code_file) {
+ fprintf(codefile, "\n\n");
+ close_codefile();
+ }
}
to, have_ellipsis->gen_name);
used_fail++;
}
- fprintf(codefile, "}\n");
+ fprintf(codefile, "}\n");
}
break;
}
static int
decode_type (const char *name, const Type *t, int optional,
- const char *forwstr, const char *tmpstr)
+ const char *forwstr, const char *tmpstr, const char *dertype)
{
switch (t->type) {
case TType: {
decode_primitive ("enumerated", name, forwstr);
break;
case TOctetString:
+ if (dertype) {
+ fprintf(codefile,
+ "if (%s == CONS) {\n",
+ dertype);
+ decode_primitive("octet_string_ber", name, forwstr);
+ fprintf(codefile,
+ "} else {\n");
+ }
decode_primitive ("octet_string", name, forwstr);
+ if (dertype)
+ fprintf(codefile, "}\n");
if (t->range)
range_check(name, "length", forwstr, t->range);
break;
name, m->gen_name);
if (s == NULL)
errx(1, "malloc");
- decode_type (s, m->type, m->optional, forwstr, m->gen_name);
+ decode_type (s, m->type, m->optional, forwstr, m->gen_name, NULL);
free (s);
}
-
+
break;
}
case TSet: {
"%s = calloc(1, sizeof(*%s));\n"
"if (%s == NULL) { e = ENOMEM; %s; }\n",
s, s, s, forwstr);
- decode_type (s, m->type, 0, forwstr, m->gen_name);
+ decode_type (s, m->type, 0, forwstr, m->gen_name, NULL);
free (s);
fprintf(codefile, "members |= (1 << %d);\n", memno);
asprintf (&sname, "%s_s_of", tmpstr);
if (sname == NULL)
errx(1, "malloc");
- decode_type (n, t->subtype, 0, forwstr, sname);
+ decode_type (n, t->subtype, 0, forwstr, sname, NULL);
fprintf (codefile,
"(%s)->len++;\n"
"len = %s_origlen - ret;\n"
decode_primitive ("general_string", name, forwstr);
break;
case TTag:{
- char *tname;
+ char *tname, *typestring;
+ char *ide = NULL;
+
+ asprintf(&typestring, "%s_type", tmpstr);
fprintf(codefile,
"{\n"
- "size_t %s_datalen, %s_oldlen;\n",
- tmpstr, tmpstr);
- if(dce_fix)
+ "size_t %s_datalen, %s_oldlen;\n"
+ "Der_type %s;\n",
+ tmpstr, tmpstr, typestring);
+ if(support_ber)
fprintf(codefile,
- "int dce_fix;\n");
- fprintf(codefile, "e = der_match_tag_and_length(p, len, %s, %s, %s, "
+ "int is_indefinite;\n");
+
+ fprintf(codefile, "e = der_match_tag_and_length(p, len, %s, &%s, %s, "
"&%s_datalen, &l);\n",
classname(t->tag.tagclass),
- is_primitive_type(t->subtype->type) ? "PRIM" : "CONS",
+ typestring,
valuename(t->tag.tagclass, t->tag.tagvalue),
tmpstr);
+
+ /* XXX hardcode for now */
+ if (support_ber && t->subtype->type == TOctetString) {
+ ide = typestring;
+ } else {
+ fprintf(codefile,
+ "if (e == 0 && %s != %s) { e = ASN1_BAD_ID; }\n",
+ typestring,
+ is_primitive_type(t->subtype->type) ? "PRIM" : "CONS");
+ }
+
if(optional) {
fprintf(codefile,
"if(e) {\n"
"p += l; len -= l; ret += l;\n"
"%s_oldlen = len;\n",
tmpstr);
- if(dce_fix)
+ if(support_ber)
fprintf (codefile,
- "if((dce_fix = _heim_fix_dce(%s_datalen, &len)) < 0)\n"
- "{ e = ASN1_BAD_FORMAT; %s; }\n",
- tmpstr, forwstr);
+ "if((is_indefinite = _heim_fix_dce(%s_datalen, &len)) < 0)\n"
+ "{ e = ASN1_BAD_FORMAT; %s; }\n"
+ "if (is_indefinite) { if (len < 2) { e = ASN1_OVERRUN; %s; } len -= 2; }",
+ tmpstr, forwstr, forwstr);
else
fprintf(codefile,
"if (%s_datalen > len) { e = ASN1_OVERRUN; %s; }\n"
asprintf (&tname, "%s_Tag", tmpstr);
if (tname == NULL)
errx(1, "malloc");
- decode_type (name, t->subtype, 0, forwstr, tname);
- if(dce_fix)
+ decode_type (name, t->subtype, 0, forwstr, tname, ide);
+ if(support_ber)
fprintf(codefile,
- "if(dce_fix){\n"
- "e = der_match_tag_and_length (p, len, "
- "(Der_class)0,(Der_type)0, UT_EndOfContent, "
+ "if(is_indefinite){\n"
+ "len += 2;\n"
+ "e = der_match_tag_and_length(p, len, "
+ "(Der_class)0, &%s, UT_EndOfContent, "
"&%s_datalen, &l);\n"
- "if(e) %s;\np += l; len -= l; ret += l;\n"
- "} else \n", tmpstr, forwstr);
+ "if(e) %s;\n"
+ "p += l; len -= l; ret += l;\n"
+ "if (%s != (Der_type)0) { e = ASN1_BAD_ID; %s; }\n"
+ "} else \n",
+ typestring,
+ tmpstr,
+ forwstr,
+ typestring, forwstr);
fprintf(codefile,
"len = %s_oldlen - %s_datalen;\n",
tmpstr, tmpstr);
fprintf(codefile,
"}\n");
free(tname);
+ free(typestring);
break;
}
case TChoice: {
Der_class cl;
Der_type ty;
unsigned tag;
-
+
if (m->ellipsis) {
have_ellipsis = m;
continue;
name, m->gen_name);
if (s == NULL)
errx(1, "malloc");
- decode_type (s, m->type, m->optional, forwstr, m->gen_name);
+ decode_type (s, m->type, m->optional, forwstr, m->gen_name, NULL);
fprintf(codefile,
"(%s)->element = %s;\n",
name, m->label);
fprintf (codefile, "\n");
fprintf (codefile, "memset(data, 0, sizeof(*data));\n"); /* hack to avoid `unused variable' */
- decode_type ("data", s->type, 0, "goto fail", "Top");
+ decode_type ("data", s->type, 0, "goto fail", "Top", NULL);
if (preserve)
fprintf (codefile,
"data->_save.data = calloc(1, ret);\n"
if (t->members == NULL)
break;
-
+
ASN1_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) {
char *s;
int c;
asprintf (&tname, "%s_tag", tmpstr);
if (tname == NULL)
- errx(1, "malloc");
+ errx(1, "malloc");
c = encode_type (name, t->subtype, tname);
fprintf (codefile,
"e = der_put_length_and_tag (p, len, ret, %s, %s, %s, &l);\n"
if(t->type == TChoice)
fprintf(codefile, "break;\n");
}
-
+
if(t->type == TChoice) {
if (have_ellipsis)
fprintf(codefile,
ASN1_TAILQ_FOREACH(m, t->members, members) {
char *s;
-
+
if (m->ellipsis) {
have_ellipsis = m;
continue;
#ifndef __GEN_LOCL_H__
#define __GEN_LOCL_H__
-#ifdef HAVE_CONFIG_H
#include <config.h>
-#endif
+
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
int preserve_type(const char *);
int seq_type(const char *);
+void generate_header_of_codefile(const char *);
+void close_codefile(void);
+
+
extern FILE *headerfile, *codefile, *logfile;
-extern int dce_fix;
+extern int support_ber;
extern int rfc1510_bitstring;
+extern int one_code_file;
extern int error_flag;
KRB5_NT_X500_PRINCIPAL(6), -- PKINIT
KRB5_NT_SMTP_NAME(7), -- Name in form of SMTP email name
KRB5_NT_ENTERPRISE_PRINCIPAL(10), -- Windows 2000 UPN
+ KRB5_NT_WELLKNOWN(11), -- Wellknown
KRB5_NT_ENT_PRINCIPAL_AND_ID(-130), -- Windows 2000 UPN and SID
KRB5_NT_MS_PRINCIPAL(-128), -- NT 4 style name
KRB5_NT_MS_PRINCIPAL_AND_ID(-129) -- NT style name and SID
KRB5-PADATA-GET-FROM-TYPED-DATA(22),
KRB5-PADATA-SAM-ETYPE-INFO(23),
KRB5-PADATA-SERVER-REFERRAL(25),
+ KRB5-PADATA-ALT-PRINC(24), -- (crawdad@fnal.gov)
+ KRB5-PADATA-SAM-CHALLENGE2(30), -- (kenh@pobox.com)
+ KRB5-PADATA-SAM-RESPONSE2(31), -- (kenh@pobox.com)
+ KRB5-PA-EXTRA-TGT(41), -- Reserved extra TGT
KRB5-PADATA-TD-KRB-PRINCIPAL(102), -- PrincipalName
KRB5-PADATA-PK-TD-TRUSTED-CERTIFIERS(104), -- PKINIT
KRB5-PADATA-PK-TD-CERTIFICATE-INDEX(105), -- PKINIT
KRB5-PADATA-TD-REQ-NONCE(107), -- INTEGER
KRB5-PADATA-TD-REQ-SEQ(108), -- INTEGER
KRB5-PADATA-PA-PAC-REQUEST(128), -- jbrezak@exchange.microsoft.com
- KRB5-PADATA-S4U2SELF(129),
- KRB5-PADATA-EPAC(130), -- EPAK
- KRB5-PADATA-PK-AS-09-BINDING(132), -- client send this to
- -- tell KDC that is supports
+ KRB5-PADATA-FOR-USER(129), -- MS-KILE
+ KRB5-PADATA-FOR-X509-USER(130), -- MS-KILE
+ KRB5-PADATA-FOR-CHECK-DUPS(131), -- MS-KILE
+ KRB5-PADATA-AS-CHECKSUM(132), -- MS-KILE
+ KRB5-PADATA-PK-AS-09-BINDING(132), -- client send this to
+ -- tell KDC that is supports
-- the asCheckSum in the
-- PK-AS-REP
- KRB5-PADATA-CLIENT-CANONICALIZED(133) --
+ KRB5-PADATA-CLIENT-CANONICALIZED(133), -- referals
+ KRB5-PADATA-FX-COOKIE(133), -- krb-wg-preauth-framework
+ KRB5-PADATA-AUTHENTICATION-SET(134), -- krb-wg-preauth-framework
+ KRB5-PADATA-AUTH-SET-SELECTED(135), -- krb-wg-preauth-framework
+ KRB5-PADATA-FX-FAST(136), -- krb-wg-preauth-framework
+ KRB5-PADATA-FX-ERROR(137), -- krb-wg-preauth-framework
+ KRB5-PADATA-ENCRYPTED-CHALLENGE(138), -- krb-wg-preauth-framework
+ KRB5-PADATA-OTP-CHALLENGE(141), -- (gareth.richards@rsa.com)
+ KRB5-PADATA-OTP-REQUEST(142), -- (gareth.richards@rsa.com)
+ KBB5-PADATA-OTP-CONFIRM(143), -- (gareth.richards@rsa.com)
+ KRB5-PADATA-OTP-PIN-CHANGE(144), -- (gareth.richards@rsa.com)
+ KRB5-PADATA-EPAK-AS-REQ(145),
+ KRB5-PADATA-EPAK-AS-REP(146),
+ KRB5-PADATA-PKINIT-KX(147), -- krb-wg-anon
+ KRB5-PADATA-PKU2U-NAME(148), -- zhu-pku2u
+ KRB5-PADATA-SUPPORTED-ETYPES(165) -- MS-KILE
}
AUTHDATA-TYPE ::= INTEGER {
realm[1] Realm
}
+Principals ::= SEQUENCE OF Principal
+
HostAddress ::= SEQUENCE {
addr-type[0] krb5int32,
address[1] OCTET STRING
-- draft-brezak-win2k-krb-authz-01
PA-PAC-REQUEST ::= SEQUENCE {
- include-pac[0] BOOLEAN -- Indicates whether a PAC
+ include-pac[0] BOOLEAN -- Indicates whether a PAC
-- should be included or not
}
auth[3] GeneralString
}
-KRB5SignedPathPrincipals ::= SEQUENCE OF Principal
-
-- never encoded on the wire, just used to checksum over
KRB5SignedPathData ::= SEQUENCE {
encticket[0] EncTicketPart,
- delegated[1] KRB5SignedPathPrincipals OPTIONAL
+ delegated[1] Principals OPTIONAL
}
KRB5SignedPath ::= SEQUENCE {
-- DERcoded KRB5SignedPathData
- &n