summaryrefslogtreecommitdiff
path: root/source4/heimdal/kdc
diff options
context:
space:
mode:
Diffstat (limited to 'source4/heimdal/kdc')
-rw-r--r--source4/heimdal/kdc/digest.c542
-rw-r--r--source4/heimdal/kdc/headers.h9
-rw-r--r--source4/heimdal/kdc/kdc-private.h56
-rw-r--r--source4/heimdal/kdc/kdc.h6
-rw-r--r--source4/heimdal/kdc/kdc_locl.h4
-rw-r--r--source4/heimdal/kdc/kerberos5.c273
-rw-r--r--source4/heimdal/kdc/krb5tgs.c338
-rw-r--r--source4/heimdal/kdc/kx509.c370
-rwxr-xr-xsource4/heimdal/kdc/pkinit.c202
-rw-r--r--source4/heimdal/kdc/process.c11
-rw-r--r--source4/heimdal/kdc/windc.c108
-rw-r--r--source4/heimdal/kdc/windc_plugin.h80
12 files changed, 1701 insertions, 298 deletions
diff --git a/source4/heimdal/kdc/digest.c b/source4/heimdal/kdc/digest.c
index a5517fb896..2c012a2ead 100644
--- a/source4/heimdal/kdc/digest.c
+++ b/source4/heimdal/kdc/digest.c
@@ -32,10 +32,112 @@
*/
#include "kdc_locl.h"
-#include <digest_asn1.h>
#include <hex.h>
-RCSID("$Id: digest.c,v 1.7 2006/10/22 20:11:44 lha Exp $");
+RCSID("$Id: digest.c,v 1.19 2006/12/28 17:03:51 lha Exp $");
+
+#define CHAP_MD5 0x10
+#define DIGEST_MD5 0x08
+#define NTLM_V2 0x04
+#define NTLM_V1_SESSION 0x02
+#define NTLM_V1 0x01
+
+const struct units _kdc_digestunits[] = {
+ {"chap-md5", 1U << 4},
+ {"digest-md5", 1U << 3},
+ {"ntlm-v2", 1U << 2},
+ {"ntlm-v1-session", 1U << 1},
+ {"ntlm-v1", 1U << 0},
+ {NULL, 0}
+};
+
+
+static krb5_error_code
+get_digest_key(krb5_context context,
+ krb5_kdc_configuration *config,
+ hdb_entry_ex *server,
+ krb5_crypto *crypto)
+{
+ krb5_error_code ret;
+ krb5_enctype enctype;
+ Key *key;
+
+ ret = _kdc_get_preferred_key(context,
+ config,
+ server,
+ "digest-service",
+ &enctype,
+ &key);
+ if (ret)
+ return ret;
+ return krb5_crypto_init(context, &key->key, 0, crypto);
+}
+
+/*
+ *
+ */
+
+static char *
+get_ntlm_targetname(krb5_context context,
+ hdb_entry_ex *client)
+{
+ char *targetname, *p;
+
+ targetname = strdup(krb5_principal_get_realm(context,
+ client->entry.principal));
+ if (targetname == NULL)
+ return NULL;
+
+ p = strchr(targetname, '.');
+ if (p)
+ *p = '\0';
+
+ strupr(targetname);
+ return targetname;
+}
+
+static krb5_error_code
+fill_targetinfo(krb5_context context,
+ char *targetname,
+ hdb_entry_ex *client,
+ krb5_data *data)
+{
+ struct ntlm_targetinfo ti;
+ krb5_error_code ret;
+ struct ntlm_buf d;
+ krb5_principal p;
+ const char *str;
+
+ memset(&ti, 0, sizeof(ti));
+
+ ti.domainname = targetname;
+ p = client->entry.principal;
+ str = krb5_principal_get_comp_string(context, p, 0);
+ if (str != NULL &&
+ (strcmp("host", str) == 0 ||
+ strcmp("ftp", str) == 0 ||
+ strcmp("imap", str) == 0 ||
+ strcmp("pop", str) == 0 ||
+ strcmp("smtp", str)))
+ {
+ str = krb5_principal_get_comp_string(context, p, 1);
+ ti.dnsservername = rk_UNCONST(str);
+ }
+
+ ret = heim_ntlm_encode_targetinfo(&ti, 1, &d);
+ if (ret)
+ return ret;
+
+ data->data = d.data;
+ data->length = d.length;
+
+ return 0;
+}
+
+
+/*
+ *
+ */
krb5_error_code
_kdc_do_digest(krb5_context context,
@@ -57,11 +159,13 @@ _kdc_do_digest(krb5_context context,
krb5_storage *sp = NULL;
Checksum res;
hdb_entry_ex *server = NULL, *user = NULL;
- char *password = NULL;
+ hdb_entry_ex *client = NULL;
+ char *client_name = NULL, *password = NULL;
krb5_data serverNonce;
if(!config->enable_digest) {
- kdc_log(context, config, 0, "Rejected digest request from %s", from);
+ kdc_log(context, config, 0,
+ "Rejected digest request (disabled) from %s", from);
return KRB5KDC_ERR_POLICY;
}
@@ -125,6 +229,7 @@ _kdc_do_digest(krb5_context context,
krb5_free_principal(context, principal);
goto out;
}
+ krb5_clear_error_string(context);
ret = _kdc_db_fetch(context, config, principal,
HDB_F_GET_SERVER, NULL, &server);
@@ -137,12 +242,17 @@ _kdc_do_digest(krb5_context context,
/* check the client is allowed to do digest auth */
{
krb5_principal principal = NULL;
- hdb_entry_ex *client;
ret = krb5_ticket_get_client(context, ticket, &principal);
if (ret)
goto out;
+ ret = krb5_unparse_name(context, principal, &client_name);
+ if (ret) {
+ krb5_free_principal(context, principal);
+ goto out;
+ }
+
ret = _kdc_db_fetch(context, config, principal,
HDB_F_GET_CLIENT, NULL, &client);
krb5_free_principal(context, principal);
@@ -150,13 +260,15 @@ _kdc_do_digest(krb5_context context,
goto out;
if (client->entry.flags.allow_digest == 0) {
+ kdc_log(context, config, 0,
+ "Client %s tried to use digest "
+ "but is not allowed to",
+ client_name);
krb5_set_error_string(context,
"Client is not permitted to use digest");
ret = KRB5KDC_ERR_POLICY;
- _kdc_free_ent (context, client);
goto out;
}
- _kdc_free_ent (context, client);
}
/* unpack request */
@@ -192,6 +304,9 @@ _kdc_do_digest(krb5_context context,
goto out;
}
+ kdc_log(context, config, 0, "Valid digest request from %s (%s)",
+ client_name, from);
+
/*
* Process the inner request
*/
@@ -289,22 +404,9 @@ _kdc_do_digest(krb5_context context,
goto out;
}
- {
- Key *key;
- krb5_enctype enctype;
-
- ret = _kdc_get_preferred_key(context,
- config,
- server,
- "digest-service",
- &enctype,
- &key);
- if (ret)
- goto out;
- ret = krb5_crypto_init(context, &key->key, 0, &crypto);
- if (ret)
- goto out;
- }
+ ret = get_digest_key(context, config, server, &crypto);
+ if (ret)
+ goto out;
ret = krb5_create_checksum(context,
crypto,
@@ -337,6 +439,9 @@ _kdc_do_digest(krb5_context context,
goto out;
}
+ kdc_log(context, config, 0, "Digest %s init request successful from %s",
+ ireq.u.init.type, from);
+
break;
}
case choice_DigestReqInner_digestRequest: {
@@ -349,7 +454,11 @@ _kdc_do_digest(krb5_context context,
krb5_set_error_string(context, "out of memory");
goto out;
}
- krb5_store_stringz(sp, ireq.u.digestRequest.type);
+ ret = krb5_store_stringz(sp, ireq.u.digestRequest.type);
+ if (ret) {
+ krb5_clear_error_string(context);
+ goto out;
+ }
krb5_store_stringz(sp, ireq.u.digestRequest.serverNonce);
if (ireq.u.digestRequest.identifier) {
@@ -421,22 +530,9 @@ _kdc_do_digest(krb5_context context,
serverNonce.length = ssize;
}
- {
- Key *key;
- krb5_enctype enctype;
-
- ret = _kdc_get_preferred_key(context,
- config,
- server,
- "digest-service",
- &enctype,
- &key);
- if (ret)
- goto out;
- ret = krb5_crypto_init(context, &key->key, 0, &crypto);
- if (ret)
- goto out;
- }
+ ret = get_digest_key(context, config, server, &crypto);
+ if (ret)
+ goto out;
ret = krb5_verify_checksum(context, crypto,
KRB5_KU_DIGEST_OPAQUE,
@@ -493,6 +589,11 @@ _kdc_do_digest(krb5_context context,
unsigned char md[MD5_DIGEST_LENGTH];
char id;
+ if ((config->digests_allowed & CHAP_MD5) == 0) {
+ kdc_log(context, config, 0, "Digest CHAP MD5 not allowed");
+ goto out;
+ }
+
if (ireq.u.digestRequest.identifier == NULL) {
krb5_set_error_string(context, "Identifier missing "
"from CHAP request");
@@ -524,6 +625,11 @@ _kdc_do_digest(krb5_context context,
unsigned char md[MD5_DIGEST_LENGTH];
char *A1, *A2;
+ if ((config->digests_allowed & DIGEST_MD5) == 0) {
+ kdc_log(context, config, 0, "Digest SASL MD5 not allowed");
+ goto out;
+ }
+
if (ireq.u.digestRequest.nonceCount == NULL)
goto out;
if (ireq.u.digestRequest.clientNonce == NULL)
@@ -627,6 +733,358 @@ _kdc_do_digest(krb5_context context,
r.u.error.code = EINVAL;
}
+ kdc_log(context, config, 0, "Digest %s request successful %s",
+ ireq.u.digestRequest.type, from);
+
+ break;
+ }
+ case choice_DigestReqInner_ntlmInit:
+
+ if ((config->digests_allowed & (NTLM_V1|NTLM_V1_SESSION|NTLM_V2)) == 0) {
+ kdc_log(context, config, 0, "NTLM not allowed");
+ goto out;
+ }
+
+
+ r.element = choice_DigestRepInner_ntlmInitReply;
+
+ r.u.ntlmInitReply.flags = NTLM_NEG_UNICODE;
+
+ if ((ireq.u.ntlmInit.flags & NTLM_NEG_UNICODE) == 0) {
+ kdc_log(context, config, 0, "NTLM client have no unicode");
+ goto out;
+ }
+
+ if (ireq.u.ntlmInit.flags & NTLM_NEG_NTLM)
+ r.u.ntlmInitReply.flags |= NTLM_NEG_NTLM;
+ else {
+ kdc_log(context, config, 0, "NTLM client doesn't support NTLM");
+ goto out;
+ }
+
+ r.u.ntlmInitReply.flags |=
+ NTLM_NEG_TARGET_DOMAIN |
+ NTLM_ENC_128;
+
+#define ALL \
+ NTLM_NEG_SIGN| \
+ NTLM_NEG_SEAL| \
+ NTLM_NEG_ALWAYS_SIGN| \
+ NTLM_NEG_NTLM2_SESSION| \
+ NTLM_NEG_KEYEX
+
+ r.u.ntlmInitReply.flags |= (ireq.u.ntlmInit.flags & (ALL));
+
+#undef ALL
+
+ r.u.ntlmInitReply.targetname =
+ get_ntlm_targetname(context, client);
+ if (r.u.ntlmInitReply.targetname == NULL) {
+ krb5_set_error_string(context, "out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+ r.u.ntlmInitReply.challange.data = malloc(8);
+ if (r.u.ntlmInitReply.challange.data == NULL) {
+ krb5_set_error_string(context, "out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+ r.u.ntlmInitReply.challange.length = 8;
+ if (RAND_bytes(r.u.ntlmInitReply.challange.data,
+ r.u.ntlmInitReply.challange.length) != 1)
+ {
+ krb5_set_error_string(context, "out of random error");
+ ret = ENOMEM;
+ goto out;
+ }
+ /* XXX fix targetinfo */
+ ALLOC(r.u.ntlmInitReply.targetinfo);
+ if (r.u.ntlmInitReply.targetinfo == NULL) {
+ krb5_set_error_string(context, "out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+
+ ret = fill_targetinfo(context,
+ r.u.ntlmInitReply.targetname,
+ client,
+ r.u.ntlmInitReply.targetinfo);
+ if (ret) {
+ krb5_set_error_string(context, "out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+
+ /*
+ * Save data encryted in opaque for the second part of the
+ * ntlm authentication
+ */
+ sp = krb5_storage_emem();
+ if (sp == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string(context, "out of memory");
+ goto out;
+ }
+
+ ret = krb5_storage_write(sp, r.u.ntlmInitReply.challange.data, 8);
+ if (ret != 8) {
+ ret = ENOMEM;
+ krb5_set_error_string(context, "storage write challange");
+ goto out;
+ }
+ ret = krb5_store_uint32(sp, r.u.ntlmInitReply.flags);
+ if (ret) {
+ krb5_clear_error_string(context);
+ goto out;
+ }
+
+ ret = krb5_storage_to_data(sp, &buf);
+ if (ret) {
+ krb5_clear_error_string(context);
+ goto out;
+ }
+
+ ret = get_digest_key(context, config, server, &crypto);
+ if (ret)
+ goto out;
+
+ ret = krb5_encrypt(context, crypto, KRB5_KU_DIGEST_OPAQUE,
+ buf.data, buf.length, &r.u.ntlmInitReply.opaque);
+ krb5_data_free(&buf);
+ krb5_crypto_destroy(context, crypto);
+ crypto = NULL;
+ if (ret)
+ goto out;
+
+ kdc_log(context, config, 0, "NTLM init from %s", from);
+
+ break;
+
+ case choice_DigestReqInner_ntlmRequest: {
+ krb5_principal clientprincipal;
+ unsigned char sessionkey[16];
+ unsigned char challange[8];
+ uint32_t flags;
+ Key *key = NULL;
+ int version;
+
+ r.element = choice_DigestRepInner_ntlmResponse;
+ r.u.ntlmResponse.success = 0;
+ r.u.ntlmResponse.flags = 0;
+ r.u.ntlmResponse.sessionkey = NULL;
+ r.u.ntlmResponse.tickets = NULL;
+
+ /* get username */
+ ret = krb5_parse_name(context,
+ ireq.u.ntlmRequest.username,
+ &clientprincipal);
+ if (ret)
+ goto out;
+
+ ret = _kdc_db_fetch(context, config, clientprincipal,
+ HDB_F_GET_CLIENT, NULL, &user);
+ krb5_free_principal(context, clientprincipal);
+ if (ret) {
+ krb5_set_error_string(context, "NTLM user %s not in database",
+ ireq.u.ntlmRequest.username);
+ goto out;
+ }
+
+ ret = get_digest_key(context, config, server, &crypto);
+ if (ret)
+ goto out;
+
+ ret = krb5_decrypt(context, crypto, KRB5_KU_DIGEST_OPAQUE,
+ ireq.u.ntlmRequest.opaque.data,
+ ireq.u.ntlmRequest.opaque.length, &buf);
+ krb5_crypto_destroy(context, crypto);
+ crypto = NULL;
+ if (ret)
+ goto out;
+
+ sp = krb5_storage_from_data(&buf);
+ if (sp == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string(context, "out of memory");
+ goto out;
+ }
+
+ ret = krb5_storage_read(sp, challange, sizeof(challange));
+ if (ret != sizeof(challange)) {
+ krb5_set_error_string(context, "NTLM storage read challange");
+ ret = ENOMEM;
+ goto out;
+ }
+ ret = krb5_ret_uint32(sp, &flags);
+ if (ret) {
+ krb5_set_error_string(context, "NTLM storage read flags");
+ goto out;
+ }
+ krb5_data_free(&buf);
+
+ if ((flags & NTLM_NEG_NTLM) == 0) {
+ ret = EINVAL;
+ krb5_set_error_string(context, "NTLM not negotiated");
+ goto out;
+ }
+
+ ret = hdb_enctype2key(context, &user->entry,
+ ETYPE_ARCFOUR_HMAC_MD5, &key);
+ if (ret) {
+ krb5_set_error_string(context, "NTLM missing arcfour key");
+ goto out;
+ }
+
+ /* check if this is NTLMv2 */
+ if (ireq.u.ntlmRequest.ntlm.length != 24) {
+ struct ntlm_buf infotarget, answer;
+ char *targetname;
+
+ if ((config->digests_allowed & NTLM_V2) == 0) {
+ kdc_log(context, config, 0, "NTLM v2 not allowed");
+ goto out;
+ }
+
+ version = 2;
+
+ targetname = get_ntlm_targetname(context, client);
+ if (targetname == NULL) {
+ krb5_set_error_string(context, "out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+
+ answer.length = ireq.u.ntlmRequest.ntlm.length;
+ answer.data = ireq.u.ntlmRequest.ntlm.data;
+
+ ret = heim_ntlm_verify_ntlm2(key->key.keyvalue.data,
+ key->key.keyvalue.length,
+ ireq.u.ntlmRequest.username,
+ targetname,
+ 0,
+ challange,
+ &answer,
+ &infotarget,
+ sessionkey);
+ free(targetname);
+ if (ret) {
+ krb5_set_error_string(context, "NTLM v2 verify failed");
+ goto out;
+ }
+
+ /* XXX verify infotarget matches client (checksum ?) */
+
+ free(infotarget.data);
+ /* */
+
+ } else {
+ struct ntlm_buf answer;
+
+ version = 1;
+
+ if (flags & NTLM_NEG_NTLM2_SESSION) {
+ char sessionhash[MD5_DIGEST_LENGTH];
+ MD5_CTX md5ctx;
+
+ if ((config->digests_allowed & NTLM_V1_SESSION) == 0) {
+ kdc_log(context, config, 0, "NTLM v1-session not allowed");
+ goto out;
+ }
+
+ if (ireq.u.ntlmRequest.lm.length != 24) {
+ krb5_set_error_string(context, "LM hash have wrong length "
+ "for NTLM session key");
+ ret = EINVAL;
+ goto out;
+ }
+
+ MD5_Init(&md5ctx);
+ MD5_Update(&md5ctx, challange, sizeof(challange));
+ MD5_Update(&md5ctx, ireq.u.ntlmRequest.lm.data, 8);
+ MD5_Final(sessionhash, &md5ctx);
+ memcpy(challange, sessionhash, sizeof(challange));
+ } else {
+ if ((config->digests_allowed & NTLM_V1) == 0) {
+ kdc_log(context, config, 0, "NTLM v1 not allowed");
+ goto out;
+ }
+ }
+
+ ret = heim_ntlm_calculate_ntlm1(key->key.keyvalue.data,
+ key->key.keyvalue.length,
+ challange, &answer);
+ if (ret) {
+ krb5_set_error_string(context, "NTLM missing arcfour key");
+ goto out;
+ }
+
+ if (ireq.u.ntlmRequest.ntlm.length != answer.length ||
+ memcmp(ireq.u.ntlmRequest.ntlm.data, answer.data, answer.length) != 0)
+ {
+ free(answer.data);
+ ret = EINVAL;
+ krb5_set_error_string(context, "NTLM hash mismatch");
+ goto out;
+ }
+ free(answer.data);
+
+ {
+ MD4_CTX ctx;
+
+ MD4_Init(&ctx);
+ MD4_Update(&ctx,
+ key->key.keyvalue.data, key->key.keyvalue.length);
+ MD4_Final(sessionkey, &ctx);
+ }
+ }
+
+ if (ireq.u.ntlmRequest.sessionkey) {
+ unsigned char masterkey[MD4_DIGEST_LENGTH];
+ RC4_KEY rc4;
+ size_t len;
+
+ if ((flags & NTLM_NEG_KEYEX) == 0) {
+ krb5_set_error_string(context,
+ "NTLM client failed to neg key "
+ "exchange but still sent key");
+ goto out;
+ }
+
+ len = ireq.u.ntlmRequest.sessionkey->length;
+ if (len != sizeof(masterkey)){
+ krb5_set_error_string(context,
+ "NTLM master key wrong length: %lu",
+ (unsigned long)len);
+ goto out;
+ }
+
+ RC4_set_key(&rc4, sizeof(sessionkey), sessionkey);
+
+ RC4(&rc4, sizeof(masterkey),
+ ireq.u.ntlmRequest.sessionkey->data,
+ masterkey);
+ memset(&rc4, 0, sizeof(rc4));
+
+ r.u.ntlmResponse.sessionkey =
+ malloc(sizeof(*r.u.ntlmResponse.sessionkey));
+ if (r.u.ntlmResponse.sessionkey == NULL) {
+ krb5_set_error_string(context, "out of memory");
+ goto out;
+ }
+
+ ret = krb5_data_copy(r.u.ntlmResponse.sessionkey,
+ masterkey, sizeof(masterkey));
+ if (ret) {
+ krb5_set_error_string(context, "out of memory");
+ goto out;
+ }
+ }
+
+ r.u.ntlmResponse.success = 1;
+ kdc_log(context, config, 0, "NTLM version %d successful for %s",
+ version, ireq.u.ntlmRequest.username);
+
break;
}
default:
@@ -698,10 +1156,14 @@ out:
_kdc_free_ent (context, user);
if (server)
_kdc_free_ent (context, server);
+ if (client)
+ _kdc_free_ent (context, client);
if (password) {
memset(password, 0, strlen(password));
free (password);
}
+ if (client_name)
+ free (client_name);
krb5_data_free(&buf);
krb5_data_free(&serverNonce);
free_DigestREP(&rep);
diff --git a/source4/heimdal/kdc/headers.h b/source4/heimdal/kdc/headers.h
index 87d713b076..56ddc8090b 100644
--- a/source4/heimdal/kdc/headers.h
+++ b/source4/heimdal/kdc/headers.h
@@ -32,7 +32,7 @@
*/
/*
- * $Id: headers.h,v 1.18 2006/10/17 02:22:17 lha Exp $
+ * $Id: headers.h,v 1.22 2007/01/04 00:15:34 lha Exp $
*/
#ifndef __HEADERS_H__
@@ -72,6 +72,9 @@
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
@@ -89,10 +92,14 @@
#include <krb5.h>
#include <krb5_locl.h>
#include <digest_asn1.h>
+#include <kx509_asn1.h>
#include <hdb.h>
#include <hdb_err.h>
#include <der.h>
+#include <heimntlm.h>
+#include <windc_plugin.h>
+
#undef ALLOC
#define ALLOC(X) ((X) = malloc(sizeof(*(X))))
#undef ALLOC_SEQ
diff --git a/source4/heimdal/kdc/kdc-private.h b/source4/heimdal/kdc/kdc-private.h
index 6d4fd2a29b..d896bd10e9 100644
--- a/source4/heimdal/kdc/kdc-private.h
+++ b/source4/heimdal/kdc/kdc-private.h
@@ -15,6 +15,13 @@ _kdc_add_KRB5SignedPath (
EncTicketPart */*tkt*/);
krb5_error_code
+_kdc_add_inital_verified_cas (
+ krb5_context /*context*/,
+ krb5_kdc_configuration */*config*/,
+ pk_client_params */*params*/,
+ EncTicketPart */*tkt*/);
+
+krb5_error_code
_kdc_as_rep (
krb5_context /*context*/,
krb5_kdc_configuration */*config*/,
@@ -90,6 +97,15 @@ _kdc_do_kaserver (
struct sockaddr_in */*addr*/);
krb5_error_code
+_kdc_do_kx509 (
+ krb5_context /*context*/,
+ krb5_kdc_configuration */*config*/,
+ const Kx509Request */*req*/,
+ krb5_data */*reply*/,
+ const char */*from*/,
+ struct sockaddr */*addr*/);
+
+krb5_error_code
_kdc_do_version4 (
krb5_context /*context*/,
krb5_kdc_configuration */*config*/,
@@ -183,6 +199,20 @@ _kdc_maybe_version4 (
int /*len*/);
krb5_error_code
+_kdc_pac_generate (
+ krb5_context /*context*/,
+ hdb_entry_ex */*client*/,
+ krb5_pac */*pac*/);
+
+krb5_error_code
+_kdc_pac_verify (
+ krb5_context /*context*/,
+ const krb5_principal /*client_principal*/,
+ hdb_entry_ex */*client*/,
+ hdb_entry_ex */*server*/,
+ krb5_pac */*pac*/);
+
+krb5_error_code
_kdc_pk_check_client (
krb5_context /*context*/,
krb5_kdc_configuration */*config*/,
@@ -230,6 +260,30 @@ _kdc_tgs_rep (
KDC_REQ */*req*/,
krb5_data */*data*/,
const char */*from*/,
- struct sockaddr */*from_addr*/);
+ struct sockaddr */*from_addr*/,
+ int /*datagram_reply*/);
+
+krb5_error_code
+_kdc_tkt_add_if_relevant_ad (
+ krb5_context /*context*/,
+ EncTicketPart */*tkt*/,
+ int /*type*/,
+ const krb5_data */*data*/);
+
+krb5_error_code
+_kdc_try_kx509_request (
+ void */*ptr*/,
+ size_t /*len*/,
+ Kx509Request */*req*/,
+ size_t */*size*/);
+
+krb5_error_code
+_kdc_windc_client_access (
+ krb5_context /*context*/,
+ struct hdb_entry_ex */*client*/,
+ KDC_REQ */*req*/);
+
+krb5_error_code
+_kdc_windc_init (krb5_context /*context*/);
#endif /* __kdc_private_h__ */
diff --git a/source4/heimdal/kdc/kdc.h b/source4/heimdal/kdc/kdc.h
index 043b6de47d..ea9eb7125e 100644
--- a/source4/heimdal/kdc/kdc.h
+++ b/source4/heimdal/kdc/kdc.h
@@ -35,7 +35,7 @@
*/
/*
- * $Id: kdc.h,v 1.9 2006/10/09 15:34:07 lha Exp $
+ * $Id: kdc.h,v 1.11 2006/12/28 21:06:56 lha Exp $
*/
#ifndef __KDC_H__
@@ -81,8 +81,12 @@ typedef struct krb5_kdc_configuration {
int pkinit_dh_min_bits;
int enable_digest;
+ int digests_allowed;
+
size_t max_datagram_reply_length;
+ int enable_kx509;
+
} krb5_kdc_configuration;
#include <kdc-protos.h>
diff --git a/source4/heimdal/kdc/kdc_locl.h b/source4/heimdal/kdc/kdc_locl.h
index ca8672c062..ed3010b673 100644
--- a/source4/heimdal/kdc/kdc_locl.h
+++ b/source4/heimdal/kdc/kdc_locl.h
@@ -32,7 +32,7 @@
*/
/*
- * $Id: kdc_locl.h,v 1.74 2005/12/12 12:23:33 lha Exp $
+ * $Id: kdc_locl.h,v 1.76 2006/12/26 17:18:14 lha Exp $
*/
#ifndef __KDC_LOCL_H__
@@ -55,6 +55,8 @@ extern int enable_http;
extern int detach_from_console;
+extern const struct units _kdc_digestunits[];
+
#define _PATH_KDC_CONF HDB_DB_DIR "/kdc.conf"
#define DEFAULT_LOG_DEST "0-1/FILE:" HDB_DB_DIR "/kdc.log"
diff --git a/source4/heimdal/kdc/kerberos5.c b/source4/heimdal/kdc/kerberos5.c
index dd88e2ea50..bf727ee739 100644
--- a/source4/heimdal/kdc/kerberos5.c
+++ b/source4/heimdal/kdc/kerberos5.c
@@ -33,7 +33,7 @@
#include "kdc_locl.h"
-RCSID("$Id: kerberos5.c,v 1.225 2006/11/10 03:36:32 lha Exp $");
+RCSID("$Id: kerberos5.c,v 1.231 2007/01/04 13:27:27 lha Exp $");
#define MAX_TIME ((time_t)((1U << 31) - 1))
@@ -635,6 +635,69 @@ get_pa_etype_info2(krb5_context context,
}
/*
+ *
+ */
+
+static void
+log_as_req(krb5_context context,
+ krb5_kdc_configuration *config,
+ krb5_enctype cetype,
+ krb5_enctype setype,
+ const KDC_REQ_BODY *b)
+{
+ krb5_error_code ret;
+ struct rk_strpool *p = NULL;
+ char *str;
+ int i;
+
+ for (i = 0; i < b->etype.len; i++) {
+ ret = krb5_enctype_to_string(context, b->etype.val[i], &str);
+ if (ret == 0) {
+ p = rk_strpoolprintf(p, "%s", str);
+ free(str);
+ } else
+ p = rk_strpoolprintf(p, "%d", b->etype.val[i]);
+ if (p && i + 1 < b->etype.len)
+ p = rk_strpoolprintf(p, ", ");
+ if (p == NULL) {
+ kdc_log(context, config, 0, "out of memory");
+ return;
+ }
+ }
+ 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;
+
+ ret = krb5_enctype_to_string(context, cetype, &cet);
+ if(ret == 0) {
+ ret = krb5_enctype_to_string(context, setype, &set);
+ if (ret == 0) {
+ kdc_log(context, config, 5, "Using %s/%s", cet, set);
+ free(set);
+ }
+ free(cet);
+ }
+ if (ret != 0)
+ kdc_log(context, config, 5, "Using e-types %d/%d", cetype, setype);
+ }
+
+ {
+ char str[128];
+ unparse_flags(KDCOptions2int(b->kdc_options), asn1_KDCOptions_units(),
+ str, sizeof(str));
+ if(*str)
+ kdc_log(context, config, 2, "Requested flags: %s", str);
+ }
+}
+
+/*
* verify the flags on `client' and `server', returning 0
* if they are OK and generating an error messages and returning
* and error code otherwise.
@@ -798,6 +861,39 @@ _kdc_check_addresses(krb5_context context,
return result;
}
+/*
+ *
+ */
+
+static krb5_boolean
+send_pac_p(krb5_context context, KDC_REQ *req)
+{
+ krb5_error_code ret;
+ PA_PAC_REQUEST pacreq;
+ PA_DATA *pa;
+ int i = 0;
+
+ pa = _kdc_find_padata(req, &i, KRB5_PADATA_PA_PAC_REQUEST);
+ if (pa == NULL)
+ return TRUE;
+
+ ret = decode_PA_PAC_REQUEST(pa->padata_value.data,
+ pa->padata_value.length,
+ &pacreq,
+ NULL);
+ if (ret)
+ return TRUE;
+ i = pacreq.include_pac;
+ free_PA_PAC_REQUEST(&pacreq);
+ if (i == 0)
+ return FALSE;
+ return TRUE;
+}
+
+/*
+ *
+ */
+
krb5_error_code
_kdc_as_rep(krb5_context context,
krb5_kdc_configuration *config,
@@ -882,6 +978,10 @@ _kdc_as_rep(krb5_context context,
goto out;
}
+ ret = _kdc_windc_client_access(context, client, req);
+ if(ret)
+ goto out;
+
ret = _kdc_check_flags(context, config,
client, client_name,
server, server_name,
@@ -889,13 +989,6 @@ _kdc_as_rep(krb5_context context,
if(ret)
goto out;
- if (client->check_client_access) {
- ret = client->check_client_access(context, client,
- b->addresses);
- if(ret)
- goto out;
- }
-
memset(&et, 0, sizeof(et));
memset(&ek, 0, sizeof(ek));
@@ -1224,57 +1317,7 @@ _kdc_as_rep(krb5_context context,
}
}
- {
- struct rk_strpool *p = NULL;
- char *str;
- int i;
-
- for (i = 0; i < b->etype.len; i++) {
- ret = krb5_enctype_to_string(context, b->etype.val[i], &str);
- if (ret == 0) {
- p = rk_strpoolprintf(p, "%s", str);
- free(str);
- } else
- p = rk_strpoolprintf(p, "%d", b->etype.val[i]);
- if (p && i + 1 < b->etype.len)
- p = rk_strpoolprintf(p, ", ");
- if (p == NULL) {
- kdc_log(context, config, 0, "out of memory");
- goto out;
- }
- }
- 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;
-
- ret = krb5_enctype_to_string(context, cetype, &cet);
- if(ret == 0) {
- ret = krb5_enctype_to_string(context, setype, &set);
- if (ret == 0) {
- kdc_log(context, config, 5, "Using %s/%s", cet, set);
- free(set);
- }
- free(cet);
- }
- if (ret != 0)
- kdc_log(context, config, 5, "Using e-types %d/%d", cetype, setype);
- }
-
- {
- char str[128];
- unparse_flags(KDCOptions2int(f), asn1_KDCOptions_units(),
- str, sizeof(str));
- if(*str)
- kdc_log(context, config, 2, "Requested flags: %s", str);
- }
-
+ log_as_req(context, config, cetype, setype, b);
if(f.renew || f.validate || f.proxy || f.forwarded || f.enc_tkt_in_skey
|| (f.request_anonymous && !config->allow_anonymous)) {
@@ -1330,7 +1373,9 @@ _kdc_as_rep(krb5_context context,
goto out;
}
- krb5_generate_random_keyblock(context, sessionetype, &et.key);
+ ret = krb5_generate_random_keyblock(context, sessionetype, &et.key);
+ if (ret)
+ goto out;
copy_PrincipalName(&rep.cname, &et.cname);
copy_Realm(&rep.crealm, &et.crealm);
@@ -1469,6 +1514,12 @@ _kdc_as_rep(krb5_context context,
&reply_key, rep.padata);
if (ret)
goto out;
+ ret = _kdc_add_inital_verified_cas(context,
+ config,
+ pkp,
+ &et);
+ if (ret)
+ goto out;
}
#endif
@@ -1479,16 +1530,37 @@ _kdc_as_rep(krb5_context context,
rep.padata = NULL;
}
- /* Add the PAC, via a HDB abstraction */
- if (client->authz_data_as_req) {
- ret = client->authz_data_as_req(context, client,
- req->padata,
- et.authtime,
- &skey->key,
- &et.key,
- &et.authorization_data);
- if (ret)
- goto out;
+ /* Add the PAC */
+ if (send_pac_p(context, req)) {
+ krb5_pac p = NULL;
+ krb5_data data;
+
+ ret = _kdc_pac_generate(context, client, &p);
+ if (ret) {
+ kdc_log(context, config, 0, "PAC generation failed for -- %s",
+ client_name);
+ goto out;
+ }
+ if (p != NULL) {
+ ret = _krb5_pac_sign(context, p, et.authtime,
+ client->entry.principal,
+ &skey->key, /* Server key */
+ &skey->key, /* FIXME: should be krbtgt key */
+ &data);
+ krb5_pac_free(context, p);
+ if (ret) {
+ kdc_log(context, config, 0, "PAC signing failed for -- %s",
+ client_name);
+ goto out;
+ }
+
+ ret = _kdc_tkt_add_if_relevant_ad(context, &et,
+ KRB5_AUTHDATA_WIN2K_PAC,
+ &data);
+ krb5_data_free(&data);
+ if (ret)
+ goto out;
+ }
}
_kdc_log_timestamp(context, config, "AS-REQ", et.authtime, et.starttime,
@@ -1552,3 +1624,64 @@ out2:
_kdc_free_ent(context, server);
return ret;
}
+
+/*
+ * Add the AuthorizationData `data´ of `type´ to the last element in
+ * the sequence of authorization_data in `tkt´ wrapped in an IF_RELEVANT
+ */
+
+krb5_error_code
+_kdc_tkt_add_if_relevant_ad(krb5_context context,
+ EncTicketPart *tkt,
+ int type,
+ const krb5_data *data)
+{
+ krb5_error_code ret;
+ size_t size;
+
+ if (tkt->authorization_data == NULL) {
+ tkt->authorization_data = calloc(1, sizeof(*tkt->authorization_data));
+ if (tkt->authorization_data == NULL) {
+ krb5_set_error_string(context, "out of memory");
+ return ENOMEM;
+ }
+ }
+
+ /* add the entry to the last element */
+ {
+ AuthorizationData ad = { 0, NULL };
+ AuthorizationDataElement ade;
+
+ ade.ad_type = type;
+ ade.ad_data = *data;
+
+ ret = add_AuthorizationData(&ad, &ade);
+ if (ret) {
+ krb5_set_error_string(context, "add AuthorizationData failed");
+ return ret;
+ }
+
+ ade.ad_type = KRB5_AUTHDATA_IF_RELEVANT;
+
+ ASN1_MALLOC_ENCODE(AuthorizationData,
+ ade.ad_data.data, ade.ad_data.length,
+ &ad, &size, ret);
+ free_AuthorizationData(&ad);
+ if (ret) {
+ krb5_set_error_string(context, "ASN.1 encode of "
+ "AuthorizationData failed");
+ return ret;
+ }
+ if (ade.ad_data.length != size)
+ krb5_abortx(context, "internal asn.1 encoder error");
+
+ ret = add_AuthorizationData(tkt->authorization_data, &ade);
+ der_free_octet_string(&ade.ad_data);
+ if (ret) {
+ krb5_set_error_string(context, "add AuthorizationData failed");
+ return ret;
+ }
+ }
+
+ return 0;
+}
diff --git a/source4/heimdal/kdc/krb5tgs.c b/source4/heimdal/kdc/krb5tgs.c
index dcf29eb6e9..a056839e5f 100644
--- a/source4/heimdal/kdc/krb5tgs.c
+++ b/source4/heimdal/kdc/krb5tgs.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2006 Kungliga Tekniska Högskolan
+ * Copyright (c) 1997-2006 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
@@ -33,7 +33,7 @@
#include "kdc_locl.h"
-RCSID("$Id: krb5tgs.c,v 1.16 2006/10/22 15:54:37 lha Exp $");
+RCSID("$Id: krb5tgs.c,v 1.25 2007/01/04 12:49:45 lha Exp $");
/*
* return the realm of a krbtgt-ticket or NULL
@@ -119,7 +119,7 @@ _kdc_add_KRB5SignedPath(krb5_context context,
if (server && principals) {
ret = add_KRB5SignedPathPrincipals(principals, server);
if (ret)
- goto out;
+ return ret;
}
{
@@ -131,7 +131,7 @@ _kdc_add_KRB5SignedPath(krb5_context context,
ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
&spd, &size, ret);
if (ret)
- goto out;
+ return ret;
if (data.length != size)
krb5_abortx(context, "internal asn.1 encoder error");
}
@@ -159,12 +159,12 @@ _kdc_add_KRB5SignedPath(krb5_context context,
krb5_crypto_destroy(context, crypto);
free(data.data);
if (ret)
- goto out;
+ return ret;
ASN1_MALLOC_ENCODE(KRB5SignedPath, data.data, data.length, &sp, &size, ret);
free_Checksum(&sp.cksum);
if (ret)
- goto out;
+ return ret;
if (data.length != size)
krb5_abortx(context, "internal asn.1 encoder error");
@@ -174,46 +174,11 @@ _kdc_add_KRB5SignedPath(krb5_context context,
* authorization data field.
*/
- if (tkt->authorization_data == NULL) {
- tkt->authorization_data = calloc(1, sizeof(*tkt->authorization_data));
- if (tkt->authorization_data == NULL) {
- ret = ENOMEM;
- goto out;
- }
- }
-
- /* add the entry to the last element */
- {
- AuthorizationData ad = { 0, NULL };
- AuthorizationDataElement ade;
-
- ade.ad_type = KRB5_AUTHDATA_SIGNTICKET;
- ade.ad_data = data;
-
- ret = add_AuthorizationData(&ad, &ade);
- krb5_data_free(&data);
- if (ret)
- return ret;
-
- ASN1_MALLOC_ENCODE(AuthorizationData, data.data, data.length,
- &ad, &size, ret);
- free_AuthorizationData(&ad);
- if (ret)
- return ret;
- if (data.length != size)
- krb5_abortx(context, "internal asn.1 encoder error");
-
- ade.ad_type = KRB5_AUTHDATA_IF_RELEVANT;
- ade.ad_data = data;
-
- ret = add_AuthorizationData(tkt->authorization_data, &ade);
- krb5_data_free(&data);
- if (ret)
- return ret;
- }
+ ret = _kdc_tkt_add_if_relevant_ad(context, tkt,
+ KRB5_AUTHDATA_SIGNTICKET, &data);
+ krb5_data_free(&data);
-out:
- return 0;
+ return ret;
}
static krb5_error_code
@@ -307,6 +272,87 @@ check_KRB5SignedPath(krb5_context context,
return 0;
}
+/*
+ *
+ */
+
+static krb5_error_code
+check_PAC(krb5_context context,
+ krb5_kdc_configuration *config,
+ const krb5_principal client_principal,
+ hdb_entry_ex *client,
+ hdb_entry_ex *server,
+ const EncryptionKey *server_key,
+ const EncryptionKey *krbtgt_key,
+ EncTicketPart *tkt,
+ krb5_data *rspac,
+ int *require_signedpath)
+{
+ AuthorizationData *ad = tkt->authorization_data;
+ unsigned i, j;
+ krb5_error_code ret;
+
+ if (ad == NULL || ad->len == 0)
+ return 0;
+
+ for (i = 0; i < ad->len; i++) {
+ AuthorizationData child;
+
+ if (ad->val[i].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
+ continue;
+
+ ret = decode_AuthorizationData(ad->val[i].ad_data.data,
+ ad->val[i].ad_data.length,
+ &child,
+ NULL);
+ if (ret) {
+ krb5_set_error_string(context, "Failed to decode "
+ "IF_RELEVANT with %d", ret);
+ return ret;
+ }
+ for (j = 0; j < child.len; j++) {
+
+ if (child.val[j].ad_type == KRB5_AUTHDATA_WIN2K_PAC) {
+ krb5_pac pac;
+
+ /* Found PAC */
+ ret = krb5_pac_parse(context,
+ child.val[j].ad_data.data,
+ child.val[j].ad_data.length,
+ &pac);
+ free_AuthorizationData(&child);
+ if (ret)
+ return ret;
+
+ ret = krb5_pac_verify(context, pac, tkt->authtime,
+ client_principal,
+ krbtgt_key, NULL);
+ if (ret) {
+ krb5_pac_free(context, pac);
+ return ret;
+ }
+
+ ret = _kdc_pac_verify(context, client_principal,
+ client, server, &pac);
+ if (ret) {
+ krb5_pac_free(context, pac);
+ return ret;
+ }
+ *require_signedpath = 0;
+
+ ret = _krb5_pac_sign(context, pac, tkt->authtime,
+ client_principal,
+ server_key, krbtgt_key, rspac);
+
+ krb5_pac_free(context, pac);
+
+ return ret;
+ }
+ }
+ free_AuthorizationData(&child);
+ }
+ return 0;
+}
/*
*
@@ -610,9 +656,10 @@ tgs_make_reply(krb5_context context,
KDC_REQ_BODY *b,
krb5_const_principal tgt_name,
const EncTicketPart *tgt,
- const EncTicketPart *adtkt,
+ const EncryptionKey *ekey,
+ const krb5_keyblock *sessionkey,
+ krb5_kvno kvno,
AuthorizationData *auth_data,
- krb5_ticket *tgs_ticket,
hdb_entry_ex *server,
const char *server_name,
hdb_entry_ex *client,
@@ -620,7 +667,7 @@ tgs_make_reply(krb5_context context,
hdb_entry_ex *krbtgt,
krb5_enctype krbtgt_etype,
KRB5SignedPathPrincipals *spp,
- EncryptionKey *tgtkey,
+ const krb5_data *rspac,
const char **e_text,
krb5_data *reply)
{
@@ -629,32 +676,6 @@ tgs_make_reply(krb5_context context,
EncTicketPart et;
KDCOptions f = b->kdc_options;
krb5_error_code ret;
- krb5_enctype etype;
- Key *skey;
- const EncryptionKey *ekey;
- AuthorizationData *new_auth_data = NULL;
-
- if(adtkt) {
- int i;
- ekey = &adtkt->key;
- for(i = 0; i < b->etype.len; i++)
- if (b->etype.val[i] == adtkt->key.keytype)
- break;
- if(i == b->etype.len) {
- krb5_clear_error_string(context);
- return KRB5KDC_ERR_ETYPE_NOSUPP;
- }
- etype = b->etype.val[i];
- }else{
- ret = _kdc_find_etype(context, server, b->etype.val, b->etype.len,
- &skey, &etype);
- if(ret) {
- kdc_log(context, config, 0,
- "Server (%s) has no support for etypes", server_name);
- return ret;
- }
- ekey = &skey->key;
- }
memset(&rep, 0, sizeof(rep));
memset(&et, 0, sizeof(et));
@@ -768,26 +789,47 @@ tgs_make_reply(krb5_context context,
et.flags.anonymous = tgt->flags.anonymous;
et.flags.ok_as_delegate = server->entry.flags.ok_as_delegate;
-
- krb5_generate_random_keyblock(context, etype, &et.key);
-
- if (server->authz_data_tgs_req) {
- ret = server->authz_data_tgs_req(context, server,
- client_principal,
- tgs_ticket->ticket.authorization_data,
- tgs_ticket->ticket.authtime,
- tgtkey,
- ekey,
- &et.key,
- &new_auth_data);
- if (ret) {
- new_auth_data = NULL;
+ if (auth_data) {
+ /* XXX Check enc-authorization-data */
+ et.authorization_data = calloc(1, sizeof(*et.authorization_data));
+ if (et.authorization_data == NULL) {
+ ret = ENOMEM;
+ goto out;
+ }
+ ret = copy_AuthorizationData(auth_data, et.authorization_data);
+ if (ret)
+ goto out;
+
+ /* Filter out type KRB5SignedPath */
+ ret = find_KRB5SignedPath(context, et.authorization_data, NULL);
+ if (ret == 0) {
+ if (et.authorization_data->len == 1) {
+ free_AuthorizationData(et.authorization_data);
+ free(et.authorization_data);
+ et.authorization_data = NULL;
+ } else {
+ AuthorizationData *ad = et.authorization_data;
+ free_AuthorizationDataElement(&ad->val[ad->len - 1]);
+ ad->len--;
}
+ }
}
- /* XXX Check enc-authorization-data */
- et.authorization_data = new_auth_data;
+ if(rspac->length) {
+ /*
+ * No not need to filter out the any PAC from the
+ * auth_data since its signed by the KDC.
+ */
+ ret = _kdc_tkt_add_if_relevant_ad(context, &et,
+ KRB5_AUTHDATA_WIN2K_PAC,
+ rspac);
+ if (ret)
+ goto out;
+ }
+ ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key);
+ if (ret)
+ goto out;
et.crealm = tgt->crealm;
et.cname = tgt_name->name;
@@ -795,6 +837,10 @@ tgs_make_reply(krb5_context context,
/* MIT must have at least one last_req */
ek.last_req.len = 1;
ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
+ if (ek.last_req.val == NULL) {
+ ret = ENOMEM;
+ goto out;
+ }
ek.nonce = b->nonce;
ek.flags = et.flags;
ek.authtime = et.authtime;
@@ -817,7 +863,7 @@ tgs_make_reply(krb5_context context,
krbtgt,
krbtgt_etype,
NULL,
- NULL,
+ spp,
&et);
if (ret)
goto out;
@@ -835,8 +881,8 @@ tgs_make_reply(krb5_context context,
etype list, even if we don't want a session key with
DES3? */
ret = _kdc_encode_reply(context, config,
- &rep, &et, &ek, etype,
- adtkt ? 0 : server->entry.kvno,
+ &rep, &et, &ek, et.key.keytype,
+ kvno,
ekey, 0, &tgt->key, e_text, reply);
out:
free_TGS_REP(&rep);
@@ -973,8 +1019,7 @@ tgs_parse_request(krb5_context context,
const struct sockaddr *from_addr,
time_t **csec,
int **cusec,
- AuthorizationData **auth_data,
- EncryptionKey **tgtkey)
+ AuthorizationData **auth_data)
{
krb5_ap_req ap_req;
krb5_error_code ret;
@@ -1060,8 +1105,6 @@ tgs_parse_request(krb5_context context,
ret = KRB5KRB_AP_ERR_BADKEYVER;
goto out;
}
-
- *tgtkey = &tkey->key;
if (b->kdc_options.validate)
verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
@@ -1201,8 +1244,8 @@ tgs_build_reply(krb5_context context,
const char *from,
const char **e_text,
AuthorizationData *auth_data,
- EncryptionKey *tgtkey,
- const struct sockaddr *from_addr)
+ const struct sockaddr *from_addr,
+ int datagram_reply)
{
krb5_error_code ret;
krb5_principal cp = NULL, sp = NULL;
@@ -1211,6 +1254,10 @@ tgs_build_reply(krb5_context context,
hdb_entry_ex *server = NULL, *client = NULL;
EncTicketPart *tgt = &ticket->ticket;
KRB5SignedPathPrincipals *spp = NULL;
+ const EncryptionKey *ekey;
+ krb5_keyblock sessionkey;
+ krb5_kvno kvno;
+ krb5_data rspac;
PrincipalName *s;
Realm r;
@@ -1219,7 +1266,9 @@ tgs_build_reply(krb5_context context,
char opt_str[128];
int require_signedpath = 0;
+ memset(&sessionkey, 0, sizeof(sessionkey));
memset(&adtkt, 0, sizeof(adtkt));
+ krb5_data_zero(&rspac);
s = b->sname;
r = b->realm;
@@ -1436,7 +1485,7 @@ server_lookup:
ret = krb5_verify_checksum(context,
crypto,
- KRB5_KU_TGS_IMPERSONATE,
+ KRB5_KU_OTHER_CKSUM,
datack.data,
datack.length,
&self.cksum);
@@ -1617,6 +1666,67 @@ server_lookup:
goto out;
}
+ /*
+ * Select enctype, return key and kvno.
+ */
+
+ {
+ krb5_enctype etype;
+
+ if(b->kdc_options.enc_tkt_in_skey) {
+ int i;
+ ekey = &adtkt.key;
+ for(i = 0; i < b->etype.len; i++)
+ if (b->etype.val[i] == adtkt.key.keytype)
+ break;
+ if(i == b->etype.len) {
+ krb5_clear_error_string(context);
+ return KRB5KDC_ERR_ETYPE_NOSUPP;
+ }
+ etype = b->etype.val[i];
+ kvno = 0;
+ } else {
+ Key *skey;
+
+ ret = _kdc_find_etype(context, server, b->etype.val, b->etype.len,
+ &skey, &etype);
+ if(ret) {
+ kdc_log(context, config, 0,
+ "Server (%s) has no support for etypes", spp);
+ return ret;
+ }
+ ekey = &skey->key;
+ kvno = server->entry.kvno;
+ }
+
+ ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
+ if (ret)
+ goto out;
+ }
+
+ /* check PAC if there is one */
+ {
+ Key *tkey;
+
+ ret = hdb_enctype2key(context, &krbtgt->entry,
+ krbtgt_etype, &tkey);
+ if(ret) {
+ kdc_log(context, config, 0,
+ "Failed to find key for krbtgt PAC check");
+ goto out;
+ }
+
+ ret = check_PAC(context, config, client_principal,
+ client, server, ekey, &tkey->key,
+ tgt, &rspac, &require_signedpath);
+ if (ret) {
+ kdc_log(context, config, 0,
+ "check_PAC check failed for %s (%s) from %s with %s",
+ spn, cpn, from, krb5_get_err_text(context, ret));
+ goto out;
+ }
+ }
+
/* also check the krbtgt for signature */
ret = check_KRB5SignedPath(context,
config,
@@ -1640,9 +1750,10 @@ server_lookup:
b,
client_principal,
tgt,
- b->kdc_options.enc_tkt_in_skey ? &adtkt : NULL,
+ ekey,
+ &sessionkey,
+ kvno,
auth_data,
- ticket,
server,
spn,
client,
@@ -1650,7 +1761,7 @@ server_lookup:
krbtgt,
krbtgt_etype,
spp,
- tgtkey,
+ &rspac,
e_text,
reply);
@@ -1658,6 +1769,8 @@ out:
free(spn);
free(cpn);
+ krb5_data_free(&rspac);
+ krb5_free_keyblock_contents(context, &sessionkey);
if(server)
_kdc_free_ent(context, server);
if(client)
@@ -1685,7 +1798,8 @@ _kdc_tgs_rep(krb5_context context,
KDC_REQ *req,
krb5_data *data,
const char *from,
- struct sockaddr *from_addr)
+ struct sockaddr *from_addr,
+ int datagram_reply)
{
AuthorizationData *auth_data = NULL;
krb5_error_code ret;
@@ -1696,8 +1810,6 @@ _kdc_tgs_rep(krb5_context context,
krb5_ticket *ticket = NULL;
const char *e_text = NULL;
krb5_enctype krbtgt_etype = ETYPE_NULL;
- EncryptionKey *tgtkey = NULL;
-
time_t *csec = NULL;
int *cusec = NULL;
@@ -1726,8 +1838,7 @@ _kdc_tgs_rep(krb5_context context,
&e_text,
from, from_addr,
&csec, &cusec,
- &auth_data,
- &tgtkey);
+ &auth_data);
if (ret) {
kdc_log(context, config, 0,
"Failed parsing TGS-REQ from %s", from);
@@ -1745,14 +1856,21 @@ _kdc_tgs_rep(krb5_context context,
from,
&e_text,
auth_data,
- tgtkey,
- from_addr);
+ from_addr,
+ datagram_reply);
if (ret) {
kdc_log(context, config, 0,
"Failed building TGS-REP to %s", from);
goto out;
}
+ /* */
+ if (datagram_reply && data->length > config->max_datagram_reply_length) {
+ krb5_data_free(data);
+ ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
+ e_text = "Reply packet too large";
+ }
+
out:
if(ret && data->data == NULL){
krb5_mk_error(context,
diff --git a/source4/heimdal/kdc/kx509.c b/source4/heimdal/kdc/kx509.c
new file mode 100644
index 0000000000..d817338f73
--- /dev/null
+++ b/source4/heimdal/kdc/kx509.c
@@ -0,0 +1,370 @@
+/*
+ * Copyright (c) 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 <hex.h>
+
+RCSID("$Id: kx509.c,v 1.1 2006/12/28 21:03:53 lha Exp $");
+
+/*
+ *
+ */
+
+krb5_error_code
+_kdc_try_kx509_request(void *ptr, size_t len, Kx509Request *req, size_t *size)
+{
+ if (len < 4)
+ return -1;
+ if (memcmp("\x00\x00\x02\x00", ptr, 4) != 0)
+ return -1;
+ return decode_Kx509Request(((unsigned char *)ptr) + 4, len - 4, req, size);
+}
+
+/*
+ *
+ */
+
+static const char version_2_0[4] = {0 , 0, 2, 0};
+
+static krb5_error_code
+verify_req_hash(krb5_context context,
+ const Kx509Request *req,
+ krb5_keyblock *key)
+{
+ unsigned char digest[SHA_DIGEST_LENGTH];
+ HMAC_CTX ctx;
+
+ if (req->pk_hash.length != sizeof(digest)) {
+ krb5_set_error_string(context, "pk-hash have wrong length: %lu",
+ (unsigned long)req->pk_hash.length);
+ return KRB5KDC_ERR_PREAUTH_FAILED;
+ }
+
+ HMAC_CTX_init(&ctx);
+ HMAC_Init_ex(&ctx,
+ key->keyvalue.data, key->keyvalue.length,
+ EVP_sha1(), NULL);
+ if (sizeof(digest) != HMAC_size(&ctx))
+ krb5_abortx(context, "runtime error, hmac buffer wrong size in kx509");
+ HMAC_Update(&ctx, version_2_0, sizeof(version_2_0));
+ HMAC_Update(&ctx, req->pk_key.data, req->pk_key.length);
+ HMAC_Final(&ctx, digest, 0);
+ HMAC_CTX_cleanup(&ctx);
+
+ if (memcmp(req->pk_hash.data, digest, sizeof(digest)) != 0) {
+ krb5_set_error_string(context, "pk-hash is not correct");
+ return KRB5KDC_ERR_PREAUTH_FAILED;
+ }
+ return 0;
+}
+
+static krb5_error_code
+calculate_reply_hash(krb5_context context,
+ krb5_keyblock *key,
+ Kx509Response *rep)
+{
+ HMAC_CTX ctx;
+
+ HMAC_CTX_init(&ctx);
+
+ 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) {
+ HMAC_CTX_cleanup(&ctx);
+ krb5_set_error_string(context, "out of memory");
+ return ENOMEM;
+ }
+
+ HMAC_Update(&ctx, version_2_0, sizeof(version_2_0));
+ if (rep->error_code) {
+ int32_t t = *rep->error_code;
+ do {
+ unsigned char p = (t & 0xff);
+ HMAC_Update(&ctx, &p, 1);
+ t >>= 8;
+ } while (t);
+ }
+ if (rep->certificate)
+ HMAC_Update(&ctx, rep->certificate->data, rep->certificate->length);
+ if (rep->e_text)
+ HMAC_Update(&ctx, *rep->e_text, strlen(*rep->e_text));
+
+ HMAC_Final(&ctx, rep->hash->data, 0);
+ HMAC_CTX_cleanup(&ctx);
+
+ return 0;
+}
+
+/*
+ * Build a certifate for `principal´ that will expire at `endtime´.
+ */
+
+static krb5_error_code
+build_certificate(krb5_context context,
+ krb5_kdc_configuration *config,
+ const krb5_data *key,
+ time_t endtime,
+ krb5_principal principal,
+ krb5_data *certificate)
+{
+ /* XXX write code here to generate certificates */
+ FILE *in, *out;
+ krb5_error_code ret;
+ const char *program;
+ char *str, *strkey;
+ char tstr[64];
+ pid_t pid;
+
+ snprintf(tstr, sizeof(tstr), "%lu", (unsigned long)endtime);
+
+ ret = base64_encode(key->data, key->length, &strkey);
+ if (ret < 0) {
+ krb5_set_error_string(context, "failed to base64 encode key");
+ return ENOMEM;
+ }
+
+ program = krb5_config_get_string(context,
+ NULL,
+ "kdc",
+ "kx509_cert_program",
+ NULL);
+ if (program == NULL) {
+ free(strkey);
+ krb5_set_error_string(context, "no certificate program configured");
+ return ENOENT;
+ }
+
+ ret = krb5_unparse_name(context, principal, &str);
+ if (ret) {
+ free(strkey);
+ return ret;
+ }
+
+ pid = pipe_execv(&in, &out, NULL, program, str, tstr, NULL);
+ free(str);
+ if (pid <= 0) {
+ free(strkey);
+ krb5_set_error_string(context,
+ "Failed to run the cert program %s",
+ program);
+ return ret;
+ }
+ fprintf(in, "%s\n", strkey);
+ fclose(in);
+ free(strkey);
+
+ {
+ unsigned buf[1024 * 10];
+ size_t len;
+
+ len = fread(buf, 1, sizeof(buf), out);
+ fclose(out);
+ if(len == 0) {
+ krb5_set_error_string(context,
+ "Certificate program returned no data");
+ return KRB5KDC_ERR_PREAUTH_FAILED;
+ }
+ ret = krb5_data_copy(certificate, buf, len);
+ if (ret) {
+ krb5_set_error_string(context, "Failed To copy certificate");
+ return ret;
+ }
+ }
+ kill(pid, SIGKILL);
+ waitpid(pid, NULL, 0);
+ return 0;
+}
+
+/*
+ *
+ */
+
+krb5_error_code
+_kdc_do_kx509(krb5_context context,
+ krb5_kdc_configuration *config,
+ const Kx509Request *req, krb5_data *reply,
+ const char *from, struct sockaddr *addr)
+{
+ krb5_error_code ret;
+ krb5_ticket *ticket = NULL;
+ krb5_flags ap_req_options;
+ krb5_auth_context ac = NULL;
+ krb5_keytab id = NULL;
+ krb5_principal sprincipal = NULL, cprincipal = NULL;
+ char *cname = NULL;
+ Kx509Response rep;
+ size_t size;
+ krb5_keyblock *key = NULL;
+
+ krb5_data_zero(reply);
+ memset(&rep, 0, sizeof(rep));
+
+ if(!config->enable_kx509) {
+ kdc_log(context, config, 0,
+ "Rejected kx509 request (disabled) from %s", from);
+ return KRB5KDC_ERR_POLICY;
+ }
+
+ kdc_log(context, config, 0, "Kx509 request from %s", from);
+
+ ret = krb5_kt_resolve(context, "HDB:", &id);
+ if (ret) {
+ kdc_log(context, config, 0, "Can't open database for digest");
+ goto out;
+ }
+
+ ret = krb5_rd_req(context,
+ &ac,
+ &req->authenticator,
+ NULL,
+ id,
+ &ap_req_options,
+ &ticket);
+ if (ret)
+ goto out;
+
+ ret = krb5_ticket_get_client(context, ticket, &cprincipal);
+ if (ret)
+ goto out;
+
+ ret = krb5_unparse_name(context, cprincipal, &cname);
+ if (ret)
+ goto out;
+
+ /* verify server principal */
+
+ ret = krb5_sname_to_principal(context, NULL, "kca_service",
+ KRB5_NT_UNKNOWN, &sprincipal);
+ if (ret)
+ goto out;
+
+ {
+ krb5_principal principal = NULL;
+
+ ret = krb5_ticket_get_server(context, ticket, &principal);
+ if (ret)
+ goto out;
+
+ ret = krb5_principal_compare(context, sprincipal, principal);
+ krb5_free_principal(context, principal);
+ if (ret != TRUE) {
+ ret = KRB5KDC_ERR_SERVER_NOMATCH;
+ krb5_set_error_string(context,
+ "User %s used wrong Kx509 service principal",
+ cname);
+ goto out;
+ }
+ }
+
+ ret = krb5_auth_con_getkey(context, ac, &key);
+ if (ret || key == NULL) {
+ krb5_set_error_string(context, "Kx509 can't get session key");
+ goto out;
+ }
+
+ ret = verify_req_hash(context, req, key);
+ if (ret)
+ goto out;
+
+ ALLOC(rep.certificate);
+ if (rep.certificate == NULL)
+ goto out;
+ krb5_data_zero(rep.certificate);
+ ALLOC(rep.hash);
+ if (rep.hash == NULL)
+ goto out;
+ krb5_data_zero(rep.hash);
+
+ ret = build_certificate(context, config, &req->pk_key,
+ krb5_ticket_get_endtime(context, ticket),
+ cprincipal, rep.certificate);
+ if (ret)
+ goto out;
+
+ ret = calculate_reply_hash(context, key, &rep);
+ if (ret)
+ goto out;
+
+ /*
+ * Encode reply, [ version | Kx509Response ]
+ */
+
+ {
+ krb5_data data;
+
+ ASN1_MALLOC_ENCODE(Kx509Response, data.data, data.length, &rep,
+ &size, ret);
+ if (ret) {
+ krb5_set_error_string(context, "Failed to encode kx509 reply");
+ goto out;
+ }
+ if (size != data.length)
+ krb5_abortx(context, "ASN1 internal error");
+
+ ret = krb5_data_alloc(reply, data.length + sizeof(version_2_0));
+ if (ret) {
+ free(data.data);
+ goto out;
+ }
+ memcpy(reply->data, version_2_0, sizeof(version_2_0));
+ memcpy(((unsigned char *)reply->data) + sizeof(version_2_0),
+ data.data, data.length);
+ free(data.data);
+ }
+
+ kdc_log(context, config, 0, "Successful Kx509 request for %s", cname);
+
+out:
+ if (ac)
+ krb5_auth_con_free(context, ac);
+ if (ret)
+ krb5_warn(context, ret, "Kx509 request from %s failed", from);
+ if (ticket)
+ krb5_free_ticket(context, ticket);
+ if (id)
+ krb5_kt_close(context, id);
+ if (sprincipal)
+ krb5_free_principal(context, sprincipal);
+ if (cprincipal)
+ krb5_free_principal(context, cprincipal);
+ if (key)
+ krb5_free_keyblock (context, key);
+ if (cname)
+ free(cname);
+ free_Kx509Response(&rep);
+
+ return 0;
+}
diff --git a/source4/heimdal/kdc/pkinit.c b/source4/heimdal/kdc/pkinit.c
index 6657ab7c44..418a38d030 100755
--- a/source4/heimdal/kdc/pkinit.c
+++ b/source4/heimdal/kdc/pkinit.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003 - 2005 Kungliga Tekniska Högskolan
+ * Copyright (c) 2003 - 2006 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
@@ -33,7 +33,7 @@
#include "kdc_locl.h"
-RCSID("$Id: pkinit.c,v 1.74 2006/11/10 03:37:43 lha Exp $");
+RCSID("$Id: pkinit.c,v 1.86 2007/01/04 12:54:09 lha Exp $");
#ifdef PKINIT
@@ -68,6 +68,8 @@ struct pk_client_params {
DH *dh;
EncryptionKey reply_key;
char *dh_group_name;
+ hx509_peer_info peer;
+ hx509_certs client_anchors;
};
struct pk_principal_mapping {
@@ -180,6 +182,10 @@ _kdc_pk_free_client_param(krb5_context context,
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);
}
@@ -302,8 +308,10 @@ get_dh_param(krb5_context context,
ret = _krb5_dh_group_ok(context, config->pkinit_dh_min_bits,
&dhparam.p, &dhparam.g, &dhparam.q, moduli,
&client_params->dh_group_name);
- if (ret)
+ if (ret) {
+ /* XXX send back proposal of better group */
goto out;
+ }
dh = DH_new();
if (dh == NULL) {
@@ -354,64 +362,6 @@ get_dh_param(krb5_context context,
return ret;
}
-#if 0
-/*
- * XXX We only need this function if there are several certs for the
- * KDC to choose from, and right now, we can't handle that so punt for
- * now.
- *
- * If client has sent a list of CA's trusted by him, make sure our
- * CA is in the list.
- *
- */
-
-static void
-verify_trusted_ca(PA_PK_AS_REQ_19 *r)
-{
-
- if (r.trustedCertifiers != NULL) {
- X509_NAME *kdc_issuer;
- X509 *kdc_cert;
-
- kdc_cert = sk_X509_value(kdc_identity->cert, 0);
- kdc_issuer = X509_get_issuer_name(kdc_cert);
-
- /* XXX will work for heirarchical CA's ? */
- /* XXX also serial_number should be compared */
-
- ret = KRB5_KDC_ERR_KDC_NOT_TRUSTED;
- for (i = 0; i < r.trustedCertifiers->len; i++) {
- TrustedCA_19 *ca = &r.trustedCertifiers->val[i];
-
- switch (ca->element) {
- case choice_TrustedCA_19_caName: {
- X509_NAME *name;
- unsigned char *p;
-
- p = ca->u.caName.data;
- name = d2i_X509_NAME(NULL, &p, ca->u.caName.length);
- if (name == NULL) /* XXX should this be a failure instead ? */
- break;
- if (X509_NAME_cmp(name, kdc_issuer) == 0)
- ret = 0;
- X509_NAME_free(name);
- break;
- }
- case choice_TrustedCA_19_issuerAndSerial:
- /* IssuerAndSerialNumber issuerAndSerial */
- break;
- default:
- break;
- }
- if (ret == 0)
- break;
- }
- if (ret)
- goto out;
- }
-}
-#endif /* 0 */
-
krb5_error_code
_kdc_pk_rd_padata(krb5_context context,
krb5_kdc_configuration *config,
@@ -483,7 +433,61 @@ _kdc_pk_rd_padata(krb5_context context,
goto out;
}
- /* XXX look at r.trustedCertifiers and r.kdcPkId */
+ /* XXX look at r.kdcPkId */
+ if (r.trustedCertifiers) {
+ ExternalPrincipalIdentifiers *edi = r.trustedCertifiers;
+ unsigned int i;
+
+ ret = hx509_certs_init(kdc_identity->hx509ctx,
+ "MEMORY:client-anchors",
+ 0, NULL,
+ &client_params->client_anchors);
+ if (ret) {
+ krb5_set_error_string(context, "Can't allocate client anchors: %d", ret);
+ goto out;
+
+ }
+ for (i = 0; i < edi->len; i++) {
+ IssuerAndSerialNumber iasn;
+ hx509_query *q;
+ hx509_cert cert;
+ size_t size;
+
+ if (edi->val[i].issuerAndSerialNumber == NULL)
+ continue;
+
+ ret = hx509_query_alloc(kdc_identity->hx509ctx, &q);
+ if (ret) {
+ krb5_set_error_string(context,
+ "Failed to allocate hx509_query");
+ goto out;
+ }
+
+ ret = decode_IssuerAndSerialNumber(edi->val[i].issuerAndSerialNumber->data,
+ edi->val[i].issuerAndSerialNumber->length,
+ &iasn,
+ &size);
+ if (ret || size != 0) {
+ hx509_query_free(kdc_identity->hx509ctx, q);
+ continue;
+ }
+ ret = hx509_query_match_issuer_serial(q, &iasn.issuer, &iasn.serialNumber);
+ free_IssuerAndSerialNumber(&iasn);
+ if (ret)
+ continue;
+
+ ret = hx509_certs_find(kdc_identity->hx509ctx,
+ kdc_identity->certs,
+ q,
+ &cert);
+ hx509_query_free(kdc_identity->hx509ctx, q);
+ if (ret)
+ continue;
+ hx509_certs_add(kdc_identity->hx509ctx,
+ client_params->client_anchors, cert);
+ hx509_cert_free(cert);
+ }
+ }
ret = hx509_cms_unwrap_ContentInfo(&r.signedAuthPack,
&contentInfoOid,
@@ -611,6 +615,23 @@ _kdc_pk_rd_padata(krb5_context context,
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,
+ ap.supportedCMSTypes->val,
+ ap.supportedCMSTypes->len);
+ if (ret) {
+ free_AuthPack(&ap);
+ goto out;
+ }
+ }
free_AuthPack(&ap);
} else
krb5_abortx(context, "internal pkinit error");
@@ -752,7 +773,8 @@ pk_mk_pa_reply_enckey(krb5_context context,
buf.length,
NULL,
cert,
- kdc_identity->anchors,
+ client_params->peer,
+ client_params->client_anchors,
kdc_identity->certpool,
&signed_data);
hx509_cert_free(cert);
@@ -864,7 +886,8 @@ pk_mk_pa_reply_dh(krb5_context context,
buf.length,
NULL,
cert,
- kdc_identity->anchors,
+ client_params->peer,
+ client_params->client_anchors,
kdc_identity->certpool,
&signed_data);
*kdc_cert = cert;
@@ -948,8 +971,12 @@ _kdc_pk_mk_pa_reply(krb5_context context,
rep.element = choice_PA_PK_AS_REP_encKeyPack;
- krb5_generate_random_keyblock(context, enctype,
- &client_params->reply_key);
+ ret = krb5_generate_random_keyblock(context, enctype,
+ &client_params->reply_key);
+ if (ret) {
+ free_PA_PK_AS_REP(&rep);
+ goto out;
+ }
ret = pk_mk_pa_reply_enckey(context,
client_params,
req,
@@ -1039,8 +1066,12 @@ _kdc_pk_mk_pa_reply(krb5_context context,
pa_type = KRB5_PADATA_PK_AS_REP_19;
rep.element = choice_PA_PK_AS_REP_encKeyPack;
- krb5_generate_random_keyblock(context, enctype,
- &client_params->reply_key);
+ ret = krb5_generate_random_keyblock(context, enctype,
+ &client_params->reply_key);
+ if (ret) {
+ free_PA_PK_AS_REP_Win2k(&rep);
+ goto out;
+ }
ret = pk_mk_pa_reply_enckey(context,
client_params,
req,
@@ -1337,6 +1368,35 @@ add_principal_mapping(krb5_context context,
return 0;
}
+krb5_error_code
+_kdc_add_inital_verified_cas(krb5_context context,
+ krb5_kdc_configuration *config,
+ pk_client_params *params,
+ EncTicketPart *tkt)
+{
+ AD_INITIAL_VERIFIED_CAS cas;
+ krb5_error_code ret;
+ krb5_data data;
+ size_t size;
+
+ memset(&cas, 0, sizeof(cas));
+
+ /* XXX add CAs to cas here */
+
+ ASN1_MALLOC_ENCODE(AD_INITIAL_VERIFIED_CAS, data.data, data.length,
+ &cas, &size, ret);
+ if (ret)
+ return ret;
+ if (data.length != size)
+ krb5_abortx(context, "internal asn.1 encoder error");
+
+ ret = _kdc_tkt_add_if_relevant_ad(context, tkt,
+ ad_initial_verified_cas, &data);
+ krb5_data_free(&data);
+ return ret;
+}
+
+
krb5_error_code
_kdc_pk_initialize(krb5_context context,
@@ -1372,7 +1432,7 @@ _kdc_pk_initialize(krb5_context context,
NULL,
NULL);
if (ret) {
- krb5_warn(context, ret, "PKINIT: failed to load");
+ krb5_warn(context, ret, "PKINIT: ");
config->enable_pkinit = 0;
return ret;
}
@@ -1411,7 +1471,7 @@ _kdc_pk_initialize(krb5_context context,
NULL,
FALSE,
"kdc",
- "pki-allow-proxy-certificate",
+ "pkinit_allow_proxy_certificate",
NULL);
_krb5_pk_allow_proxy_certificate(kdc_identity, ret);
@@ -1419,7 +1479,7 @@ _kdc_pk_initialize(krb5_context context,
NULL,
HDB_DB_DIR "/pki-mapping",
"kdc",
- "pki-mappings-file",
+ "pkinit_mappings_file",
NULL);
f = fopen(file, "r");
if (f == NULL) {
diff --git a/source4/heimdal/kdc/process.c b/source4/heimdal/kdc/process.c
index ed5cb3d651..a64efaa05d 100644
--- a/source4/heimdal/kdc/process.c
+++ b/source4/heimdal/kdc/process.c
@@ -34,7 +34,7 @@
#include "kdc_locl.h"
-RCSID("$Id: process.c,v 1.5 2006/10/09 15:37:39 lha Exp $");
+RCSID("$Id: process.c,v 1.7 2006/12/28 21:09:35 lha Exp $");
/*
* handle the request in `buf, len', from `addr' (or `from' as a string),
@@ -55,6 +55,7 @@ krb5_kdc_process_request(krb5_context context,
KDC_REQ req;
Ticket ticket;
DigestREQ digestreq;
+ Kx509Request kx509req;
krb5_error_code ret;
size_t i;
@@ -70,7 +71,7 @@ krb5_kdc_process_request(krb5_context context,
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);
+ 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){
@@ -81,6 +82,10 @@ krb5_kdc_process_request(krb5_context context,
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 */
_kdc_do_version4(context, config, buf, len, reply, from,
@@ -128,7 +133,7 @@ krb5_kdc_process_krb5_request(krb5_context context,
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);
+ ret = _kdc_tgs_rep(context, config, &req, reply, from, addr, datagram_reply);
free_TGS_REQ(&req);
return ret;
}
diff --git a/source4/heimdal/kdc/windc.c b/source4/heimdal/kdc/windc.c
new file mode 100644
index 0000000000..41e4ad1bbc
--- /dev/null
+++ b/source4/heimdal/kdc/windc.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2007 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: windc.c,v 1.3 2007/01/04 11:10:06 lha Exp $");
+
+static krb5plugin_windc_ftable *windcft;
+static void *windcctx;
+
+/*
+ * Pick the first WINDC module that we find.
+ */
+
+krb5_error_code
+_kdc_windc_init(krb5_context context)
+{
+ struct krb5_plugin *list = NULL, *e;
+ krb5_error_code ret;
+
+ ret = _krb5_plugin_find(context, PLUGIN_TYPE_DATA, "windc", &list);
+ if(ret != 0 || list == NULL)
+ return 0;
+
+ for (e = list; e != NULL; e = _krb5_plugin_get_next(e)) {
+
+ windcft = _krb5_plugin_get_symbol(e);
+ if (windcft->minor_version < KRB5_WINDC_PLUGING_MINOR)
+ continue;
+
+ (*windcft->init)(context, &windcctx);
+ break;
+ }
+ if (e == NULL) {
+ _krb5_plugin_free(list);
+ krb5_set_error_string(context, "Did not find any WINDC plugin");
+ windcft = NULL;
+ return ENOENT;
+ }
+
+ return 0;
+}
+
+
+krb5_error_code
+_kdc_pac_generate(krb5_context context,
+ hdb_entry_ex *client,
+ krb5_pac *pac)
+{
+ *pac = NULL;
+ if (windcft == NULL)
+ return 0;
+ return (windcft->pac_generate)(windcctx, context, client, pac);
+}
+
+krb5_error_code
+_kdc_pac_verify(krb5_context context,
+ const krb5_principal client_principal,
+ hdb_entry_ex *client,
+ hdb_entry_ex *server,
+ krb5_pac *pac)
+{
+ if (windcft == NULL) {
+ krb5_set_error_string(context, "Can't verify WINDC, no function");
+ return EINVAL;
+ }
+ return (windcft->pac_verify)(windcctx, context, client_principal, client, server, pac);
+}
+
+krb5_error_code
+_kdc_windc_client_access(krb5_context context,
+ struct hdb_entry_ex *client,
+ KDC_REQ *req)
+{
+ if (windcft == NULL)
+ return 0;
+ return (windcft->client_access)(windcctx, context, client, req);
+}
diff --git a/source4/heimdal/kdc/windc_plugin.h b/source4/heimdal/kdc/windc_plugin.h
new file mode 100644
index 0000000000..a3b7534480
--- /dev/null
+++ b/source4/heimdal/kdc/windc_plugin.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 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.
+ */
+
+/* $Id: windc_plugin.h,v 1.2 2007/01/04 11:13:51 lha Exp $ */
+
+#ifndef HEIMDAL_KRB5_PAC_PLUGIN_H
+#define HEIMDAL_KRB5_PAC_PLUGIN_H 1
+
+#include <krb5.h>
+
+/*
+ * The PAC generate function should allocate a krb5_pac using
+ * krb5_pac_init and fill in the PAC structure for the principal using
+ * krb5_pac_add_buffer.
+ *
+ * The PAC verify function should verify all components in the PAC
+ * using krb5_pac_get_types and krb5_pac_get_buffer for all types.
+ *
+ * Check client access function check if the client is authorized.
+ */
+
+struct hdb_entry_ex;
+
+typedef krb5_error_code
+(*krb5plugin_windc_pac_generate)(void *, krb5_context,
+ struct hdb_entry_ex *, krb5_pac *);
+
+typedef krb5_error_code
+(*krb5plugin_windc_pac_verify)(void *, krb5_context,
+ const krb5_principal,
+ struct hdb_entry_ex *, struct hdb_entry_ex *, krb5_pac *);
+
+typedef krb5_error_code
+(*krb5plugin_windc_client_access)(
+ void *, krb5_context, struct hdb_entry_ex *, KDC_REQ *);
+
+
+#define KRB5_WINDC_PLUGING_MINOR 2
+
+typedef struct krb5plugin_windc_ftable {
+ int minor_version;
+ krb5_error_code (*init)(krb5_context, void **);
+ void (*fini)(void *);
+ krb5plugin_windc_pac_generate pac_generate;
+ krb5plugin_windc_pac_verify pac_verify;
+ krb5plugin_windc_client_access client_access;
+} krb5plugin_windc_ftable;
+
+#endif /* HEIMDAL_KRB5_PAC_PLUGIN_H */
+