int forwardable;
int proxiable;
+ int anonymous;
int addresses;
int not_forwardable;
USAGE_BREAK_LONG
"[-p | -P" USAGE_LONG_PROXIABLE "] "
USAGE_BREAK_LONG
+ "-n"
"[-a | -A" USAGE_LONG_ADDRESSES "] "
USAGE_BREAK_LONG
"[-C" USAGE_LONG_CANONICALIZE "] "
fprintf(stderr, "\t-F not forwardable\n");
fprintf(stderr, "\t-p proxiable\n");
fprintf(stderr, "\t-P not proxiable\n");
+ fprintf(stderr, "\t -n anonymous\n");
fprintf(stderr, "\t-a include addresses\n");
fprintf(stderr, "\t-A do not include addresses\n");
fprintf(stderr, "\t-v validate\n");
int errflg = 0;
int i;
- while ((i = GETOPT(argc, argv, "r:fpFP54aAVl:s:c:kt:T:RS:vX:CE"))
+ while ((i = GETOPT(argc, argv, "r:fpFPn54aAVl:s:c:kt:T:RS:vX:CE"))
!= -1) {
switch (i) {
case 'V':
case 'P':
opts->not_proxiable = 1;
break;
+ case 'n':
+ opts->anonymous = 1;
+ break;
case 'a':
opts->addresses = 1;
break;
else
{
/* No principal name specified */
- if (opts->action == INIT_KT) {
- /* Use the default host/service name */
- code = krb5_sname_to_principal(k5->ctx, NULL, NULL,
- KRB5_NT_SRV_HST, &k5->me);
+ if (opts->anonymous) {
+ char *defrealm;
+ code = krb5_get_default_realm(k5->ctx, &defrealm);
if (code) {
- com_err(progname, code,
- "when creating default server principal name");
+ com_err(progname, code, "while getting default realm");
return 0;
}
- if (k5->me->realm.data[0] == 0) {
- code = krb5_unparse_name(k5->ctx, k5->me, &k5->name);
- if (code == 0)
- com_err(progname, KRB5_ERR_HOST_REALM_UNKNOWN,
- "(principal %s)", k5->name);
- else
- com_err(progname, KRB5_ERR_HOST_REALM_UNKNOWN,
- "for local services");
+ code = krb5_build_principal_ext(k5->ctx, &k5->me,
+ strlen(defrealm), defrealm,
+ strlen(KRB5_WELLKNOWN_NAMESTR), KRB5_WELLKNOWN_NAMESTR,
+ strlen(KRB5_ANONYMOUS_PRINCSTR), KRB5_ANONYMOUS_PRINCSTR,
+ 0);
+ krb5_free_default_realm( k5->ctx, defrealm);
+ if (code) {
+ com_err(progname, code, "while building principal");
return 0;
}
} else {
- /* Get default principal from cache if one exists */
- code = krb5_cc_get_principal(k5->ctx, k5->cc,
- &k5->me);
- if (code)
- {
- char *name = get_name_from_os();
- if (!name)
- {
- fprintf(stderr, "Unable to identify user\n");
+ if (opts->action == INIT_KT) {
+ /* Use the default host/service name */
+ code = krb5_sname_to_principal(k5->ctx, NULL, NULL,
+ KRB5_NT_SRV_HST, &k5->me);
+ if (code) {
+ com_err(progname, code,
+ "when creating default server principal name");
return 0;
}
- if ((code = krb5_parse_name_flags(k5->ctx, name,
- flags, &k5->me)))
- {
- com_err(progname, code, "when parsing name %s",
- name);
+ if (k5->me->realm.data[0] == 0) {
+ code = krb5_unparse_name(k5->ctx, k5->me, &k5->name);
+ if (code == 0)
+ com_err(progname, KRB5_ERR_HOST_REALM_UNKNOWN,
+ "(principal %s)", k5->name);
+ else
+ com_err(progname, KRB5_ERR_HOST_REALM_UNKNOWN,
+ "for local services");
return 0;
}
+ } else {
+ /* Get default principal from cache if one exists */
+ code = krb5_cc_get_principal(k5->ctx, k5->cc,
+ &k5->me);
+ if (code)
+ {
+ char *name = get_name_from_os();
+ if (!name)
+ {
+ fprintf(stderr, "Unable to identify user\n");
+ return 0;
+ }
+ if ((code = krb5_parse_name_flags(k5->ctx, name,
+ flags, &k5->me)))
+ {
+ com_err(progname, code, "when parsing name %s",
+ name);
+ return 0;
+ }
+ }
}
}
}
krb5_get_init_creds_opt_set_proxiable(options, 0);
if (opts->canonicalize)
krb5_get_init_creds_opt_set_canonicalize(options, 1);
+ if (opts->anonymous)
+ krb5_get_init_creds_opt_set_anonymous(options, 1);
if (opts->addresses)
{
krb5_address **addresses = NULL;
void krb5_free_typed_data(krb5_context, krb5_typed_data **);
+krb5_error_code
+encode_krb5_enc_data(const krb5_enc_data *, krb5_data **);
+
+krb5_error_code
+encode_krb5_encryption_key(const krb5_keyblock *rep, krb5_data **code);
+
+krb5_error_code
+krb5_encrypt_helper(krb5_context context, const krb5_keyblock *key,
+ krb5_keyusage keyusage, const krb5_data *plain,
+ krb5_enc_data *cipher);
+
#endif /* _KRB5_INT_PKINIT_H */
/* this helper fct is in libkrb5, but it makes sense declared here. */
-krb5_error_code
-krb5_encrypt_helper(krb5_context context, const krb5_keyblock *key,
- krb5_keyusage keyusage, const krb5_data *plain,
- krb5_enc_data *cipher);
-
krb5_error_code
krb5_encrypt_keyhelper(krb5_context context, krb5_key key,
krb5_keyusage keyusage, const krb5_data *plain,
/* allow either constructed or primitive encoding, so check for bit 6
set or reset */
#define krb5int_is_app_tag(dat,tag) \
- ((dat) && (dat)->length && \
+ ((dat != NULL) && (dat)->length && \
((((dat)->data[0] & ~0x20) == ((tag) | 0x40))))
#define krb5_is_krb_ticket(dat) krb5int_is_app_tag(dat, 1)
#define krb5_is_krb_authenticator(dat) krb5int_is_app_tag(dat, 2)
krb5_error_code
encode_krb5_ticket(const krb5_ticket *rep, krb5_data **code);
-krb5_error_code
-encode_krb5_encryption_key(const krb5_keyblock *rep, krb5_data **code);
-
krb5_error_code
encode_krb5_enc_tkt_part(const krb5_enc_tkt_part *rep, krb5_data **code);
krb5_error_code
encode_krb5_etype_info2(krb5_etype_info_entry *const *, krb5_data **code);
-krb5_error_code
-encode_krb5_enc_data(const krb5_enc_data *, krb5_data **);
-
krb5_error_code
encode_krb5_pa_enc_ts(const krb5_pa_enc_ts *, krb5_data **);
#define KRB5_NT_SMTP_NAME 7
/* Windows 2000 UPN */
#define KRB5_NT_ENTERPRISE_PRINCIPAL 10
+#define KRB5_NT_WELLKNOWN 11
+#define KRB5_WELLKNOWN_NAMESTR "WELLKNOWN" /*first component of NT_WELLKNOWN principals*/
/* Windows 2000 UPN and SID */
#define KRB5_NT_MS_PRINCIPAL -128
/* NT 4 style name */
*/
krb5_boolean KRB5_CALLCONV krb5_is_referral_realm(const krb5_data *);
+/*Both these functions return constant storage that must not be freed*/
+
+const krb5_data *KRB5_CALLCONV
+krb5_anonymous_realm(void);
+krb5_const_principal KRB5_CALLCONV
+krb5_anonymous_principal(void);
+#define KRB5_ANONYMOUS_REALMSTR "WELLKNOWN:ANONYMOUS"
+#define KRB5_ANONYMOUS_PRINCSTR "ANONYMOUS" /*wellknown name type*/
/*
* end "base-defs.h"
*/
#define KRB5_KEYUSAGE_PA_S4U_X509_USER_REPLY 27 /* XXX note conflict with above */
#define KRB5_KEYUSAGE_AD_SIGNEDPATH -21
-
+#define KRB5_KEYUSAGE_PA_PKINIT_KX 44
/* define in draft-ietf-krb-wg-preauth-framework*/
#define KRB5_KEYUSAGE_FAST_REQ_CHKSUM 50
#define KRB5_KEYUSAGE_FAST_ENC 51
/* #define KDC_OPT_RESERVED 0x00100000 */
/* #define KDC_OPT_RESERVED 0x00080000 */
/* #define KDC_OPT_RESERVED 0x00040000 */
-#define KDC_OPT_REQUEST_ANONYMOUS 0x00020000
#define KDC_OPT_CNAME_IN_ADDL_TKT 0x00020000
#define KDC_OPT_CANONICALIZE 0x00010000
-/* #define KDC_OPT_RESERVED 0x00008000 */
+#define KDC_OPT_REQUEST_ANONYMOUS 0x00008000
/* #define KDC_OPT_RESERVED 0x00004000 */
/* #define KDC_OPT_RESERVED 0x00002000 */
/* #define KDC_OPT_RESERVED 0x00001000 */
#define TKT_FLG_HW_AUTH 0x00100000
#define TKT_FLG_TRANSIT_POLICY_CHECKED 0x00080000
#define TKT_FLG_OK_AS_DELEGATE 0x00040000
-#define TKT_FLG_ANONYMOUS 0x00020000
#define TKT_FLG_ENC_PA_REP 0x00010000
-/* #define TKT_FLG_RESERVED 0x00008000 */
+#define TKT_FLG_ANONYMOUS 0x00008000
/* #define TKT_FLG_RESERVED 0x00004000 */
/* #define TKT_FLG_RESERVED 0x00002000 */
/* #define TKT_FLG_RESERVED 0x00001000 */
#define KRB5_PADATA_FX_FAST 136
#define KRB5_PADATA_FX_ERROR 137
#define KRB5_PADATA_ENCRYPTED_CHALLENGE 138
+#define KRB5_PADATA_PKINIT_KX 147
#define KRB5_ENCPADATA_REQ_ENC_PA_REP 149
#define KRB5_SAM_USE_SAD_AS_KEY 0x80000000
#define KRB5_GET_INIT_CREDS_OPT_SALT 0x0080
#define KRB5_GET_INIT_CREDS_OPT_CHG_PWD_PRMPT 0x0100
#define KRB5_GET_INIT_CREDS_OPT_CANONICALIZE 0x0200
+#define KRB5_GET_INIT_CREDS_OPT_ANONYMOUS 0x0400
krb5_error_code KRB5_CALLCONV
krb5_get_init_creds_opt_set_canonicalize(krb5_get_init_creds_opt *opt,
int canonicalize);
+/**
+ * Request anonymous credentials from the KDC. If the client name looks like
+ * "@REALM" (an empty principal name), then fully anonymous credentials are
+ * requested. If the client name looks like "name@REALM," then credentials
+ * tied to a specific realm are requested.
+ *
+ * Credentials tied to a specific realm are not supported in this version.
+ *
+ * Note that anonymous credentials are only a request; clients must verify that
+ * credentials are anonymous if that is a requirement.
+ */
+void KRB5_CALLCONV
+krb5_get_init_creds_opt_set_anonymous(krb5_get_init_creds_opt *opt,
+ int anonymous);
+
void KRB5_CALLCONV
krb5_get_init_creds_opt_set_etype_list(krb5_get_init_creds_opt *opt,
krb5_enctype *etype_list,
{
fprintf(stderr,
"Usage: %s [-r realm] [-p principal] [-q query] [clnt|local args]\n"
- "\tclnt args: [-s admin_server[:port]] [[-c ccache]|[-k [-t keytab]]]\n"
+ "\tclnt args: [-s admin_server[:port]] [[-c ccache]|[-k [-t keytab]]]|[-n]\n"
"\tlocal args: [-x db_args]* [-d dbname] [-e \"enc:salt ...\"] [-m]\n"
"where,\n\t[-x db_args]* - any number of database specific arguments.\n"
"\t\t\tLook at each database documentation for supported arguments\n",
char *princstr = NULL, *keytab_name = NULL, *query = NULL;
char *password = NULL;
char *luser, *canon, *cp;
- int optchar, freeprinc = 0, use_keytab = 0;
+ int optchar, freeprinc = 0, use_keytab = 0, use_anonymous = 0;
struct passwd *pw;
kadm5_ret_t retval;
krb5_ccache cc;
exit(1);
}
- while ((optchar = getopt(argc, argv, "x:r:p:kq:w:d:s:mc:t:e:ON")) != EOF) {
+ while ((optchar = getopt(argc, argv, "x:r:p:knq:w:d:s:mc:t:e:ON")) != EOF) {
switch (optchar) {
case 'x':
db_args_size++;
case 'k':
use_keytab++;
break;
+ case 'n':
+ use_anonymous++;
+ break;
case 't':
keytab_name = optarg;
break;
}
}
if ((ccache_name && use_keytab) ||
- (keytab_name && !use_keytab))
+ (keytab_name && !use_keytab)
+ || (ccache_name && use_anonymous)
+ || (use_anonymous &&use_keytab))
usage();
if (def_realm == NULL && krb5_get_default_realm(context, &def_realm)) {
retval = kadm5_init_with_creds(context, princstr, cc, svcname, ¶ms,
KADM5_STRUCT_VERSION,
KADM5_API_VERSION_3, db_args, &handle);
+ } else if ( use_anonymous) {
+ printf("Authenticating as principal %s with password; anonymous requested.\n",
+ princstr);
+ retval = kadm5_init_anonymous(context, princstr, svcname, ¶ms,
+ KADM5_STRUCT_VERSION,
+ KADM5_API_VERSION_3, db_args, &handle);
} else if (use_keytab) {
if (keytab_name)
printf("Authenticating as principal %s with keytab %s.\n",
enc_tkt_reply.caddrs = request->addresses;
enc_tkt_reply.authorization_data = 0;
+ /* If anonymous requests are being used, adjust the realm of the client principal*/
+ if (isflagset(request->kdc_options, KDC_OPT_REQUEST_ANONYMOUS)) {
+ if (!krb5_principal_compare_any_realm(kdc_context, request->client,
+ krb5_anonymous_principal())) {
+ errcode = KRB5KDC_ERR_BADOPTION;
+ status = "Anonymous requested but anonymous principal not used.";
+ goto errout;
+ }
+ setflag(enc_tkt_reply.flags, TKT_FLG_ANONYMOUS);
+ krb5_free_principal(kdc_context, request->client);
+ errcode = krb5_copy_principal(kdc_context, krb5_anonymous_principal(),
+ &request->client);
+ if (errcode) {
+ status = "Copying anonymous principal";
+ goto errout;
+ }
+ enc_tkt_reply.client = request->client;
+ }
/*
* Check the preauthentication if it is there.
*/
} else {
enc_tkt_reply.times.renew_till = 0;
}
-
+ if (isflagset(header_enc_tkt->flags, TKT_FLG_ANONYMOUS))
+ setflag(enc_tkt_reply.flags, TKT_FLG_ANONYMOUS);
/*
* Set authtime to be the same as header or evidence ticket's
*/
int type;
#define AUTHDATA_FLAG_CRITICAL 0x1
#define AUTHDATA_FLAG_PRE_PLUGIN 0x2
+#define AUTHDATA_FLAG_ANONYMOUS 0x4 /*Use this plugin even for anonymous tickets*/
int flags;
void *plugin_context;
init_proc init;
/* Propagate client-submitted authdata */
"tgs_req",
AUTHDATA_SYSTEM_V2,
- AUTHDATA_FLAG_CRITICAL | AUTHDATA_FLAG_PRE_PLUGIN,
+ AUTHDATA_FLAG_CRITICAL | AUTHDATA_FLAG_PRE_PLUGIN|AUTHDATA_FLAG_ANONYMOUS,
NULL,
NULL,
NULL,
/* Propagate TGT authdata */
"tgt",
AUTHDATA_SYSTEM_V2,
- AUTHDATA_FLAG_CRITICAL,
+ AUTHDATA_FLAG_CRITICAL|AUTHDATA_FLAG_ANONYMOUS,
NULL,
NULL,
NULL,
for (i = 0; i < n_authdata_systems; i++) {
const krb5_authdata_systems *asys = &authdata_systems[i];
+ if (isflagset(enc_tkt_reply->flags, TKT_FLG_ANONYMOUS) &&
+ !isflagset(asys->flags, AUTHDATA_FLAG_ANONYMOUS))
+ continue;
switch (asys->type) {
case AUTHDATA_SYSTEM_V0:
krb5_pa_data ** send_pa_list;
krb5_pa_data ** send_pa;
krb5_pa_data * pa = 0;
+ krb5_pa_data null_item;
krb5_preauth_systems * ap;
int * pa_order;
int * pa_type;
return retval;
}
key_modified = FALSE;
-
+ null_item.contents = NULL;
+ null_item.length = NULL;
send_pa = send_pa_list;
*send_pa = 0;
continue;
if (find_pa_context(ap, *padata_context, &pa_context))
continue;
- pa = 0;
+ pa = &null_item;
+ null_item.pa_type = ap->type;
if (request->padata) {
for (padata = request->padata; *padata; padata++) {
if ((*padata)->pa_type == ap->type) {
krb5_sam_response *sr = 0;
krb5_predicted_sam_response *psr = 0;
- if (in_padata == 0)
+ if (in_padata->contents == 0)
return 0;
/*
krb5_context context;
krb5_error_code code;
char *str;
+ krb5_gss_name_t k5name = (krb5_gss_name_t) input_name;
+ gss_OID nametype = (gss_OID) gss_nt_krb5_name;
code = krb5_gss_init_context(&context);
if (code) {
krb5_free_context(context);
return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME);
}
+ if (krb5_princ_type(context, k5name->princ) == KRB5_NT_WELLKNOWN) {
+ if (krb5_principal_compare(context, k5name->princ,
+ krb5_anonymous_principal()))
+ nametype = GSS_C_NT_ANONYMOUS;
+ }
if ((code = krb5_unparse_name(context,
((krb5_gss_name_t) input_name)->princ,
*minor_status = 0;
if (output_name_type)
- *output_name_type = (gss_OID) gss_nt_krb5_name;
+ *output_name_type = (gss_OID) nametype;
return(GSS_S_COMPLETE);
}
krb5_free_context(context);
return(GSS_S_FAILURE);
}
- } else {
+ } else if ((input_name_type != NULL) &&
+ g_OID_equal(input_name_type, GSS_C_NT_ANONYMOUS)) {
+ code = krb5_copy_principal(context, krb5_anonymous_principal(), &princ);
+ if (code != 0) {
+ krb5_free_context(context);
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+ }
+ else {
#ifndef NO_PASSWORD
uid_t uid;
struct passwd pwx;
krb5_ui_4 api_version,
char **db_args,
void **server_handle);
+kadm5_ret_t kadm5_init_anonymous(krb5_context context, char *client_name,
+ char *service_name,
+ kadm5_config_params *params,
+ krb5_ui_4 struct_version,
+ krb5_ui_4 api_version,
+ char **db_args,
+ void **server_handle);
kadm5_ret_t kadm5_init_with_password(krb5_context context,
char *client_name,
char *pass,
#define ADM_CCACHE "/tmp/ovsec_adm.XXXXXX"
-enum init_type { INIT_PASS, INIT_SKEY, INIT_CREDS };
+enum init_type { INIT_PASS, INIT_SKEY, INIT_CREDS , INIT_ANONYMOUS};
static kadm5_ret_t _kadm5_init_any(krb5_context context,
char *client_name,
api_version, db_args, server_handle);
}
+kadm5_ret_t kadm5_init_anonymous(krb5_context context, char *client_name,
+ char *service_name,
+ kadm5_config_params *params,
+ krb5_ui_4 struct_version,
+ krb5_ui_4 api_version,
+ char **db_args,
+ void **server_handle)
+{
+ return _kadm5_init_any(context, client_name, INIT_ANONYMOUS, NULL, NULL,
+ service_name, params, struct_version,
+ api_version, db_args, server_handle);
+}
+
kadm5_ret_t kadm5_init(krb5_context context, char *client_name, char *pass,
char *service_name,
kadm5_config_params *params,
* The RPC connection is open; establish the GSS-API
* authentication context.
*/
- code = kadm5_setup_gss(handle, params_in, client_name, full_svcname);
+ code = kadm5_setup_gss(handle, params_in, (init_type == INIT_CREDS)?client_name:NULL,
+ full_svcname);
if (code)
goto error;
full_svcname, full_svcname_len);
if ((code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
|| code == KRB5_CC_NOTFOUND) && svcname_in == NULL) {
- /* Retry with old host-independent service princpal. */
+ /* Retry with old host-independent service principal. */
code = kadm5_gic_iter(handle, init_type, ccache,
client, pass,
KADM5_ADMIN_SERVICE, realm,
kadm5_ret_t code;
krb5_context ctx;
krb5_keytab kt;
- krb5_get_init_creds_opt opt;
+ krb5_get_init_creds_opt *opt = NULL;
krb5_creds mcreds, outcreds;
int n;
if (realm) {
n = snprintf(full_svcname, full_svcname_len, "%s@%s",
svcname, realm);
- if (n < 0 || n >= full_svcname_len)
+ if (n < 0 || n >= (int) full_svcname_len)
goto error;
} else {
/* krb5_princ_realm(client) is not null terminated */
n = snprintf(full_svcname, full_svcname_len, "%s@%.*s",
svcname, krb5_princ_realm(ctx, client)->length,
krb5_princ_realm(ctx, client)->data);
- if (n < 0 || n >= full_svcname_len)
+ if (n < 0 || n >= (int) full_svcname_len)
goto error;
}
/* Credentials for kadmin don't need to be forwardable or proxiable. */
if (init_type != INIT_CREDS) {
- krb5_get_init_creds_opt_init(&opt);
- krb5_get_init_creds_opt_set_forwardable(&opt, 0);
- krb5_get_init_creds_opt_set_proxiable(&opt, 0);
+ code = krb5_get_init_creds_opt_alloc(ctx, &opt);
+ krb5_get_init_creds_opt_set_forwardable(opt, 0);
+ krb5_get_init_creds_opt_set_proxiable(opt, 0);
+ krb5_get_init_creds_opt_set_out_ccache(ctx, opt, ccache);
+ if (init_type == INIT_ANONYMOUS)
+ krb5_get_init_creds_opt_set_anonymous(opt, 1);
}
- if (init_type == INIT_PASS) {
+ if (init_type == INIT_PASS || init_type == INIT_ANONYMOUS) {
code = krb5_get_init_creds_password(ctx, &outcreds, client, pass,
krb5_prompter_posix,
NULL, 0,
- full_svcname, &opt);
+ full_svcname, opt);
if (code)
goto error;
} else if (init_type == INIT_SKEY) {
goto error;
}
code = krb5_get_init_creds_keytab(ctx, &outcreds, client, kt,
- 0, full_svcname, &opt);
+ 0, full_svcname, opt);
if (pass)
krb5_kt_close(ctx, kt);
if (code)
if (code)
goto error;
}
- if (init_type != INIT_CREDS) {
- /* Caller has initialized ccache. */
- code = krb5_cc_store_cred(ctx, ccache, &outcreds);
- if (code)
- goto error;
- }
error:
krb5_free_cred_contents(ctx, &outcreds);
+ if (opt)
+ krb5_get_init_creds_opt_free(ctx, opt);
return code;
}
goto error;
}
- buf.value = client_name;
- buf.length = strlen((char *)buf.value) + 1;
- gssstat = gss_import_name(&minor_stat, &buf,
- (gss_OID) gss_nt_krb5_name, &gss_client);
+ if (client_name) {
+ buf.value = client_name;
+ buf.length = strlen((char *)buf.value) + 1;
+ gssstat = gss_import_name(&minor_stat, &buf,
+ (gss_OID) gss_nt_krb5_name, &gss_client);
+ } else gss_client = GSS_C_NO_NAME;
+
if (gssstat != GSS_S_COMPLETE) {
code = KADM5_GSS_ERROR;
goto error;
kadm5_get_principals
kadm5_get_privs
kadm5_init
+kadm5_init_anonymous
kadm5_init_krb5_context
kadm5_init_with_creds
kadm5_init_with_password
kadm5_get_principals
kadm5_get_privs
kadm5_init
+kadm5_init_anonymous
kadm5_init_krb5_context
kadm5_init_with_creds
kadm5_init_with_password
server_handle);
}
+kadm5_ret_t kadm5_init_anonymous(krb5_context context, char *client_name,
+ char *service_name,
+ kadm5_config_params *params,
+ krb5_ui_4 struct_version,
+ krb5_ui_4 api_version,
+ char **db_args,
+ void **server_handle)
+{
+ return kadm5_init(context, client_name, NULL, service_name, params,
+ struct_version, api_version, db_args,
+ server_handle);
+}
+
kadm5_ret_t kadm5_init_with_creds(krb5_context context,
char *client_name,
krb5_ccache ccache,
return retval;
}
+
+/*Anonymous and well known principals*/
+static const char anon_realm_str[]
+= KRB5_ANONYMOUS_REALMSTR;
+static const krb5_data anon_realm_data = {
+ KV5M_DATA, sizeof(anon_realm_str)-1,
+ (char *) anon_realm_str};
+static const char wellknown_str[] = KRB5_WELLKNOWN_NAMESTR;
+static const char anon_str[] = KRB5_ANONYMOUS_PRINCSTR;
+static const krb5_data anon_princ_data[] = {
+ {KV5M_DATA, sizeof(wellknown_str)-1, (char *) wellknown_str},
+ {KV5M_DATA, sizeof(anon_str)-1, (char *)anon_str}
+};
+
+const krb5_principal_data anon_princ = {
+ KV5M_PRINCIPAL,
+ {KV5M_DATA, sizeof(anon_realm_str)-1, (char *) anon_realm_str},
+ (krb5_data *) anon_princ_data, 2, KRB5_NT_WELLKNOWN
+};
+
+const krb5_data * KRB5_CALLCONV
+krb5_anonymous_realm()
+{
+ return &anon_realm_data;
+}
+krb5_const_principal KRB5_CALLCONV
+krb5_anonymous_principal()
+{
+ return &anon_princ;
+}
krb5_data trans;
struct check_data cdata;
krb5_error_code r;
+ const krb5_data *anonymous;
trans.length = trans_in->length;
trans.data = (char *) trans_in->data;
(int) srealm->length, srealm->data));
if (trans.length == 0)
return 0;
+ anonymous = krb5_anonymous_realm();
+ if (crealm->length == anonymous->length
+ && (memcmp(crealm->data, anonymous->data, anonymous->length) == 0))
+ return 0; /*Nothing to check for anonymous*/
+
r = krb5_walk_realm_tree (ctx, crealm, srealm, &cdata.tgs,
KRB5_REALM_BRANCH_CHAR);
if (r) {
return (retval);
}
+/**
+ * Fully anonymous replies include a pa_pkinit_kx padata type including the KDC
+ * contribution key. This routine confirms that the session key is of the
+ * right form for fully anonymous requests. It is here rather than in the
+ * preauth code because the session key cannot be verified until the AS reply
+ * is decrypted and the preauth code all runs before the AS reply is decrypted.
+ */
+static krb5_error_code
+verify_anonymous( krb5_context context, krb5_kdc_req *request,
+ krb5_kdc_rep *reply, krb5_keyblock *as_key)
+{
+ krb5_error_code ret = 0;
+ krb5_pa_data *pa;
+ krb5_data scratch;
+ krb5_keyblock *kdc_key = NULL, *expected = NULL;
+ krb5_enc_data *enc = NULL;
+ krb5_keyblock *session = reply->enc_part2->session;
+ if (!krb5_principal_compare_any_realm(context, request->client,
+ krb5_anonymous_principal()))
+ return 0; /*Only applies to fully anonymous*/
+ pa = krb5int_find_pa_data(context, reply->padata, KRB5_PADATA_PKINIT_KX);
+ if (pa == NULL)
+ goto verification_error;
+ scratch.length = pa->length;
+ scratch.data = (char *) pa->contents;
+ ret = decode_krb5_enc_data( &scratch, &enc);
+ if (ret)
+ goto cleanup;
+ scratch.data = k5alloc(enc->ciphertext.length, &ret);
+ if (ret)
+ goto cleanup;
+ scratch.length = enc->ciphertext.length;
+ ret = krb5_c_decrypt(context, as_key, KRB5_KEYUSAGE_PA_PKINIT_KX,
+ NULL /*cipherstate*/, enc, &scratch);
+ if (ret) {
+ free( scratch.data);
+ goto cleanup;
+ }
+ ret = decode_krb5_encryption_key( &scratch, &kdc_key);
+ zap(scratch.data, scratch.length);
+ free(scratch.data);
+ if (ret)
+ goto cleanup;
+ ret = krb5_c_fx_cf2_simple( context, kdc_key, "PKINIT",
+ as_key, "KEYEXCHANGE", &expected);
+ if (ret)
+ goto cleanup;
+ if ((expected->enctype != session->enctype)
+ || (expected->length != session->length)
+ || (memcmp(expected->contents, session->contents, expected->length) != 0))
+ goto verification_error;
+cleanup:
+ if (kdc_key)
+ krb5_free_keyblock(context, kdc_key);
+ if (expected)
+ krb5_free_keyblock(context, expected);
+ if (enc)
+ krb5_free_enc_data(context, enc);
+ return ret;
+verification_error:
+ ret = KRB5_KDCREP_MODIFIED;
+ krb5_set_error_message(context, ret, "Reply has wrong form of session key for anonymous request");
+ goto cleanup;
+}
+
static krb5_error_code
verify_as_reply(krb5_context context,
krb5_timestamp time_now,
* principal) and we requested (and received) a TGT.
*/
canon_req = ((request->kdc_options & KDC_OPT_CANONICALIZE) != 0) ||
- (krb5_princ_type(context, request->client) == KRB5_NT_ENTERPRISE_PRINCIPAL);
+ (krb5_princ_type(context, request->client) == KRB5_NT_ENTERPRISE_PRINCIPAL)
+ || (request->kdc_options & KDC_OPT_REQUEST_ANONYMOUS);
if (canon_req) {
canon_ok = IS_TGS_PRINC(context, request->server) &&
IS_TGS_PRINC(context, as_reply->enc_part2->server);
+ if ((!canon_ok ) && (request->kdc_options &KDC_OPT_REQUEST_ANONYMOUS))
+ canon_ok = krb5_principal_compare_any_realm(context, as_reply->client,
+ krb5_anonymous_principal());
} else
canon_ok = 0;
ctx->salt.data = NULL;
}
+ /*Anonymous*/
+ if(opte->flags & KRB5_GET_INIT_CREDS_OPT_ANONYMOUS) {
+ ctx->request->kdc_options |= KDC_OPT_REQUEST_ANONYMOUS;
+ /*Remap @REALM to WELLKNOWN/ANONYMOUS@REALM*/
+ if (client->length == 1 && client->data[0].length ==0) {
+ krb5_principal new_client;
+ code = krb5_build_principal_ext(context, &new_client, client->realm.length,
+ client->realm.data,
+ strlen(KRB5_WELLKNOWN_NAMESTR),
+ KRB5_WELLKNOWN_NAMESTR,
+ strlen(KRB5_ANONYMOUS_PRINCSTR),
+ KRB5_ANONYMOUS_PRINCSTR,
+ 0);
+ if (code)
+ goto cleanup;
+ krb5_free_principal(context, ctx->request->client);
+ ctx->request->client = new_client;
+ krb5_princ_type(context, ctx->request->client) = KRB5_NT_WELLKNOWN;
+ }
+ }
+ /*We will also handle anonymous if the input principal is the anonymous principal*/
+ if (krb5_principal_compare_any_realm(context, ctx->request->client,
+ krb5_anonymous_principal())) {
+ ctx->request->kdc_options |= KDC_OPT_REQUEST_ANONYMOUS;
+ krb5_princ_type(context, ctx->request->client) = KRB5_NT_WELLKNOWN;
+ }
code = restart_init_creds_loop(context, ctx, NULL);
*pctx = ctx;
ctx->request, ctx->reply);
if (code != 0)
goto cleanup;
+ code = verify_anonymous( context, ctx->request, ctx->reply,
+ &encrypting_key);
+ if (code)
+ goto cleanup;
code = stash_as_reply(context, ctx->request_time, ctx->request,
ctx->reply, &ctx->cred, NULL);
opt->flags &= ~(KRB5_GET_INIT_CREDS_OPT_CANONICALIZE);
}
+void KRB5_CALLCONV
+krb5_get_init_creds_opt_set_anonymous (krb5_get_init_creds_opt *opt,
+ int anonymous)
+{
+ if (anonymous)
+ opt->flags |= KRB5_GET_INIT_CREDS_OPT_ANONYMOUS;
+ else opt->flags &= ~KRB5_GET_INIT_CREDS_OPT_ANONYMOUS;
+}
+
void KRB5_CALLCONV
krb5_get_init_creds_opt_set_etype_list(krb5_get_init_creds_opt *opt, krb5_enctype *etype_list, int etype_list_length)
{
free_gic_opt_ext_preauth_data(context, opte);
if (opte->opt_private->fast_ccache_name)
free(opte->opt_private->fast_ccache_name);
- if (opte->opt_private->out_ccache)
- krb5_cc_close(context, opte->opt_private->out_ccache);
free(opte->opt_private);
opte->opt_private = NULL;
return 0;
"krb5_get_init_creds_opt_set_out_ccache");
if (retval)
return retval;
- if (opte->opt_private->out_ccache) {
- krb5_cc_close(context, opte->opt_private->out_ccache);
- opte->opt_private->out_ccache = NULL;
- }
- retval = krb5_cc_resolve(context, krb5_cc_get_name(context, ccache),
- &opte->opt_private->out_ccache);
- return retval;
+ opte->opt_private->out_ccache = ccache;
+ return 0;
}
krb5_error_code KRB5_CALLCONV
krb5_address_order
krb5_address_search
krb5_aname_to_localname
+krb5_anonymous_principal
+krb5_anonymous_realm
krb5_appdefault_boolean
krb5_appdefault_string
krb5_auth_con_free
krb5_get_init_creds_opt_get_pa
krb5_get_init_creds_opt_init
krb5_get_init_creds_opt_set_address_list
+krb5_get_init_creds_opt_set_anonymous
krb5_get_init_creds_opt_set_canonicalize
krb5_get_init_creds_opt_set_change_password_prompt
krb5_get_init_creds_opt_set_etype_list
* Returns success with a null armor_key if FAST is available but not in use.
* Returns failure if the client library does not support FAST.
*/
-static krb5_error_code
+static inline krb5_error_code
fast_get_armor_key(krb5_context context, preauth_get_client_data_proc get_data,
struct _krb5_preauth_client_rock *rock,
krb5_keyblock **armor_key)
return retval;
}
-static krb5_error_code
+static inline krb5_error_code
fast_kdc_get_armor_key(krb5_context context,
preauth_get_entry_data_proc get_entry,
krb5_kdc_req *request,
-static krb5_error_code
+static inline krb5_error_code
fast_kdc_replace_reply_key(krb5_context context,
preauth_get_entry_data_proc get_data,
krb5_kdc_req *request)
return 0;
}
-static krb5_error_code
+static inline krb5_error_code
fast_set_kdc_verified(krb5_context context,
preauth_get_client_data_proc get_data,
struct _krb5_preauth_client_rock *rock)
pkinit_as_req_create(krb5_context context, pkinit_context plgctx,
pkinit_req_context reqctx, krb5_timestamp ctsec,
krb5_int32 cusec, krb5_ui_4 nonce,
- const krb5_checksum *cksum, krb5_principal server,
+ const krb5_checksum *cksum,
+ krb5_principal client, krb5_principal server,
krb5_data **as_req);
static krb5_error_code
nonce = request->nonce;
retval = pkinit_as_req_create(context, plgctx, reqctx, ctsec, cusec,
- nonce, &cksum, request->server, &out_data);
+ nonce, &cksum, request->client, request->server, &out_data);
if (retval || !out_data->length) {
pkiDebug("error %d on pkinit_as_req_create; aborting PKINIT\n",
(int) retval);
krb5_int32 cusec,
krb5_ui_4 nonce,
const krb5_checksum * cksum,
+ krb5_principal client,
krb5_principal server,
krb5_data ** as_req)
{
retval = ENOMEM;
goto cleanup;
}
- retval = cms_signeddata_create(context, plgctx->cryptoctx,
- reqctx->cryptoctx, reqctx->idctx, CMS_SIGN_CLIENT, 1,
- (unsigned char *)coded_auth_pack->data, coded_auth_pack->length,
- &req->signedAuthPack.data, &req->signedAuthPack.length);
+ /*For the new protocol, we support anonymous*/
+ if (krb5_principal_compare_any_realm(context, client,
+ krb5_anonymous_principal()))
+ retval = cms_contentinfo_create(context, plgctx->cryptoctx,
+ reqctx->cryptoctx, reqctx->idctx, CMS_SIGN_CLIENT,
+ (unsigned char *)coded_auth_pack->data, coded_auth_pack->length,
+ &req->signedAuthPack.data, &req->signedAuthPack.length);
+ else retval = cms_signeddata_create(context, plgctx->cryptoctx,
+ reqctx->cryptoctx, reqctx->idctx, CMS_SIGN_CLIENT, 1,
+ (unsigned char *)coded_auth_pack->data, coded_auth_pack->length,
+ &req->signedAuthPack.data, &req->signedAuthPack.length);
#ifdef DEBUG_ASN1
print_buffer_bin((unsigned char *)req->signedAuthPack.data,
req->signedAuthPack.length,
krb5_data *encoded_request)
{
krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
+ krb5_principal kdc_princ = NULL;
krb5_pa_pk_as_rep *kdc_reply = NULL;
krb5_kdc_dh_key_info *kdc_dh = NULL;
krb5_reply_key_pack *key_pack = NULL;
reqctx->opts->require_crl_checking,
kdc_reply->u.dh_Info.dhSignedData.data,
kdc_reply->u.dh_Info.dhSignedData.length,
- &dh_data.data, &dh_data.length, NULL, NULL)) != 0) {
+ &dh_data.data, &dh_data.length, NULL, NULL, NULL)) != 0) {
pkiDebug("failed to verify pkcs7 signed data\n");
goto cleanup;
}
retval = -1;
goto cleanup;
}
-
- retval = verify_kdc_san(context, plgctx, reqctx, request->server,
+ retval = krb5_build_principal_ext(context, &kdc_princ,
+ request->server->realm.length,
+ request->server->realm.data,
+ strlen(KRB5_TGS_NAME), KRB5_TGS_NAME,
+ request->server->realm.length,
+ request->server->realm.data,
+ 0);
+ if (retval)
+ goto cleanup;
+ retval = verify_kdc_san(context, plgctx, reqctx, kdc_princ,
&valid_san, &need_eku_checking);
if (retval)
goto cleanup;
cleanup:
free(dh_data.data);
+ krb5_free_principal(context, kdc_princ);
free(client_key);
free_krb5_kdc_dh_key_info(&kdc_dh);
free_krb5_pa_pk_as_rep(&kdc_reply);
krb5_error_code pkinit_init_identity_crypto(pkinit_identity_crypto_context *);
void pkinit_fini_identity_crypto(pkinit_identity_crypto_context);
+/**Create a pkinit ContentInfo*/
+krb5_error_code cms_contentinfo_create
+ (krb5_context context, /* IN */
+ pkinit_plg_crypto_context plg_cryptoctx, /* IN */
+ pkinit_req_crypto_context req_cryptoctx, /* IN */
+ pkinit_identity_crypto_context id_cryptoctx, /* IN */
+ int cms_msg_type,
+ unsigned char *in_data, unsigned int in_length,
+ unsigned char **out_data, unsigned int *out_data_len);
+
/*
* this function creates a CMS message where eContentType is SignedData
receives required authorization data that
contains the verified certificate chain
(only used by the KDC) */
- unsigned int *authz_data_len); /* OUT
- receives length of authz_data */
+ unsigned int *authz_data_len, /* OUT
+ receives length of authz_data */
+ int *is_signed /*out: is message signed*/);
/*
* this function creates a CMS message where eContentType is EnvelopedData
return 0;
}
+/*helper function for creating pkinit ContentInfo*/
+static krb5_error_code create_contentinfo
+(krb5_context context, pkinit_plg_crypto_context plg_crypto_context,
+ ASN1_OBJECT *oid,
+ unsigned char *data, size_t data_len,
+ PKCS7 **out_p7)
+{
+ krb5_error_code retval = EINVAL;
+ PKCS7 *inner_p7;
+ ASN1_TYPE *pkinit_data = NULL;
+ *out_p7 = NULL;
+ if ((inner_p7 = PKCS7_new()) == NULL)
+ goto cleanup;
+ if ((pkinit_data = ASN1_TYPE_new()) == NULL)
+ goto cleanup;
+ pkinit_data->type = V_ASN1_OCTET_STRING;
+ if ((pkinit_data->value.octet_string = ASN1_OCTET_STRING_new()) == NULL)
+ goto cleanup;
+ if (!ASN1_OCTET_STRING_set(pkinit_data->value.octet_string, (unsigned char *) data,
+ data_len)) {
+ unsigned long err = ERR_peek_error();
+ retval = KRB5KDC_ERR_PREAUTH_FAILED;
+ krb5_set_error_message(context, retval, "%s\n",
+ ERR_error_string(err, NULL));
+ pkiDebug("failed to add pkcs7 data\n");
+ goto cleanup;
+ }
+ if (!PKCS7_set0_type_other(inner_p7, OBJ_obj2nid(oid), pkinit_data))
+ goto cleanup;
+ retval = 0;
+ *out_p7 = inner_p7;
+ inner_p7 = NULL;
+ pkinit_data = NULL;
+cleanup:
+ if (inner_p7)
+ PKCS7_free(inner_p7);
+ if (pkinit_data)
+ ASN1_TYPE_free(pkinit_data);
+ return retval;
+}
+
+krb5_error_code cms_contentinfo_create
+(krb5_context context, /* IN */
+ pkinit_plg_crypto_context plg_cryptoctx, /* IN */
+ pkinit_req_crypto_context req_cryptoctx, /* IN */
+ pkinit_identity_crypto_context id_cryptoctx, /* IN */
+ int cms_msg_type,
+ unsigned char *data, unsigned int data_len,
+ unsigned char **out_data, unsigned int *out_data_len)
+{
+ krb5_error_code retval = ENOMEM;
+ ASN1_OBJECT *oid = NULL;
+ PKCS7 *p7 = NULL;
+ unsigned char *p;
+ /* pick the correct oid for the eContentInfo */
+ oid = pkinit_pkcs7type2oid(plg_cryptoctx, cms_msg_type);
+ if (oid == NULL)
+ goto cleanup;
+ retval = create_contentinfo(context, plg_cryptoctx, oid,
+ data, data_len, &p7);
+ if (retval != 0)
+ goto cleanup;
+ *out_data_len = i2d_PKCS7(p7, NULL);
+ if (!(*out_data_len)) {
+ unsigned long err = ERR_peek_error();
+ retval = KRB5KDC_ERR_PREAUTH_FAILED;
+ krb5_set_error_message(context, retval, "%s\n",
+ ERR_error_string(err, NULL));
+ pkiDebug("failed to der encode pkcs7\n");
+ goto cleanup;
+ }
+ retval = ENOMEM;
+ if ((p = *out_data = malloc(*out_data_len)) == NULL)
+ goto cleanup;
+
+ /* DER encode PKCS7 data */
+ retval = i2d_PKCS7(p7, &p);
+ if (!retval) {
+ unsigned long err = ERR_peek_error();
+ retval = KRB5KDC_ERR_PREAUTH_FAILED;
+ krb5_set_error_message(context, retval, "%s\n",
+ ERR_error_string(err, NULL));
+ pkiDebug("failed to der encode pkcs7\n");
+ goto cleanup;
+ }
+ retval = 0;
+cleanup:
+ if (p7)
+ PKCS7_free(p7);
+ if (oid)
+ ASN1_OBJECT_free(oid);
+ return retval;
+}
+
+
+
krb5_error_code
cms_signeddata_create(krb5_context context,
pkinit_plg_crypto_context plg_cryptoctx,
PKCS7_SIGNED *p7s = NULL;
PKCS7_SIGNER_INFO *p7si = NULL;
unsigned char *p;
- ASN1_TYPE *pkinit_data = NULL;
STACK_OF(X509) * cert_stack = NULL;
ASN1_OCTET_STRING *digest_attr = NULL;
EVP_MD_CTX ctx, ctx2;
X509 *cert = NULL;
ASN1_OBJECT *oid = NULL;
- /* start creating PKCS7 data */
+ if (id_cryptoctx->my_certs == NULL) {
+ krb5_set_error_message(context, EINVAL, "cms_signdata_create called with no certificates");
+ return EINVAL;
+ }
+/* start creating PKCS7 data */
if ((p7 = PKCS7_new()) == NULL)
goto cleanup;
p7->type = OBJ_nid2obj(NID_pkcs7_signed);
X509_STORE_CTX certctx;
STACK_OF(X509) *certstack = NULL;
char buf[DN_BUF_LEN];
- int i = 0, size = 0;
+ unsigned int i = 0, size = 0;
if ((certstore = X509_STORE_new()) == NULL)
goto cleanup;
goto cleanup2;
/* start on adding data to the pkcs7 signed */
- if ((inner_p7 = PKCS7_new()) == NULL)
- goto cleanup2;
- if ((pkinit_data = ASN1_TYPE_new()) == NULL)
- goto cleanup2;
- pkinit_data->type = V_ASN1_OCTET_STRING;
- if ((pkinit_data->value.octet_string = ASN1_OCTET_STRING_new()) == NULL)
- goto cleanup2;
- if (!ASN1_OCTET_STRING_set(pkinit_data->value.octet_string, data,
- (int)data_len)) {
- unsigned long err = ERR_peek_error();
- retval = KRB5KDC_ERR_PREAUTH_FAILED;
- krb5_set_error_message(context, retval, "%s\n",
- ERR_error_string(err, NULL));
- pkiDebug("failed to add pkcs7 data\n");
- goto cleanup2;
- }
-
- if (!PKCS7_set0_type_other(inner_p7, OBJ_obj2nid(oid), pkinit_data))
- goto cleanup2;
-
+ retval = create_contentinfo(context, plg_cryptoctx, oid,
+ data, data_len, &inner_p7);
if (p7s->contents != NULL)
PKCS7_free(p7s->contents);
p7s->contents = inner_p7;
pkiDebug("failed to der encode pkcs7\n");
goto cleanup2;
}
+ retval = ENOMEM;
if ((p = *signed_data = malloc(*signed_data_len)) == NULL)
goto cleanup2;
unsigned char **data,
unsigned int *data_len,
unsigned char **authz_data,
- unsigned int *authz_data_len)
+ unsigned int *authz_data_len,
+ int *is_signed)
{
krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
PKCS7 *p7 = NULL;
BIO *out = NULL;
- int flags = PKCS7_NOVERIFY, i = 0;
+ int flags = PKCS7_NOVERIFY;
+ unsigned int i = 0;
unsigned int vflags = 0, size = 0;
const unsigned char *p = signed_data;
STACK_OF(PKCS7_SIGNER_INFO) *si_sk = NULL;
print_buffer_bin(signed_data, signed_data_len,
"/tmp/client_received_pkcs7_signeddata");
#endif
-
+ if (is_signed)
+ *is_signed = 1;
/* Do this early enough to create the shadow OID for pkcs7-data if needed */
oid = pkinit_pkcs7type2oid(plgctx, cms_msg_type);
if (oid == NULL)
goto cleanup;
}
- /* verify that the received message is PKCS7 SignedData message */
- if (OBJ_obj2nid(p7->type) != NID_pkcs7_signed) {
- pkiDebug("Expected id-signedData PKCS7 msg (received type = %d)\n",
- OBJ_obj2nid(p7->type));
- krb5_set_error_message(context, retval, "wrong oid\n");
- goto cleanup;
- }
+/*Handle the case in pkinit anonymous where we get unsigned data.*/
+ if (is_signed && !OBJ_cmp( p7->type, oid)) {
+ unsigned char *d;
+ *is_signed = 0;
+ if (p7->d.other->type != V_ASN1_OCTET_STRING) {
+ retval = KRB5KDC_ERR_PREAUTH_FAILED;
+ krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED, "Invalid pkinit packet: octet string expected");
+ goto cleanup;
+ }
+ *data_len = ASN1_STRING_length(p7->d.other->value.octet_string);
+ d = malloc(*data_len);
+ if (d == NULL) {
+ retval = ENOMEM;
+ goto cleanup;
+ }
+ memcpy(d, ASN1_STRING_data(p7->d.other->value.octet_string),
+ *data_len);
+ *data = d;
+ goto out;
+ } else /* verify that the received message is PKCS7 SignedData message */
+ if (OBJ_obj2nid(p7->type) != NID_pkcs7_signed) {
+
+ pkiDebug("Expected id-signedData PKCS7 msg (received type = %d)\n",
+ OBJ_obj2nid(p7->type));
+ krb5_set_error_message(context, retval, "wrong oid\n");
+ goto cleanup;
+ }
/* setup to verify X509 certificate used to sign PKCS7 message */
if (!(store = X509_STORE_new()))
/* transfer the data from PKCS7 message into return buffer */
for (size = 0;;) {
+ int remain;
+ retval = ENOMEM;
if ((*data = realloc(*data, size + 1024 * 10)) == NULL)
goto cleanup;
- i = BIO_read(out, &((*data)[size]), 1024 * 10);
- if (i <= 0)
+ remain = BIO_read(out, &((*data)[size]), 1024 * 10);
+ if (remain <= 0)
break;
else
- size += i;
+ size += remain;
}
*data_len = size;
id_cryptoctx, msg_type,
require_crl_checking,
vfy_buf, vfy_buf_len,
- data, data_len, NULL, NULL);
+ data, data_len, NULL, NULL, NULL);
if (!retval)
pkiDebug("PKCS7 Verification Success\n");
krb5_principal *princs = NULL;
krb5_principal *upns = NULL;
unsigned char **dnss = NULL;
- int i, num_found = 0;
+ unsigned int i, num_found = 0;
if (princs_ret == NULL && upn_ret == NULL && dns_ret == NULL) {
pkiDebug("%s: nowhere to return any values!\n", __FUNCTION__);
pkinit_open_session(krb5_context context,
pkinit_identity_crypto_context cctx)
{
- int i, r;
+ CK_ULONG i, r;
unsigned char *cp;
CK_ULONG count = 0;
CK_SLOT_ID_PTR slotlist;
rv = id_cryptoctx->p11->C_Decrypt(id_cryptoctx->session, pEncryptedData,
ulEncryptedDataLen, pData, pulDataLen);
if (rv == CKR_OK) {
- pkiDebug("pData %x *pulDataLen %d\n", (int) pData, (int) *pulDataLen);
+ pkiDebug("pData %x *pulDataLen %d\n", (unsigned int) pData, (int) *pulDataLen);
}
return rv;
}
out = BIO_new(BIO_s_mem ());
if (X509_NAME_print_ex(out, a, 0, flag) > 0) {
- if (buf != NULL && *size > (int) BIO_number_written(out)) {
+ if (buf != NULL && (int)(*size) > BIO_number_written(out)) {
memset(buf, 0, *size);
BIO_read(out, buf, (int) BIO_number_written(out));
}
if (EVP_CIPHER_asn1_to_param(evp_ctx,enc_alg->parameter) < 0)
goto cleanup;
- if (jj != EVP_CIPHER_CTX_key_length(evp_ctx)) {
+ if ((unsigned) jj != EVP_CIPHER_CTX_key_length(evp_ctx)) {
/* Some S/MIME clients don't use the same key
* and effective key length. The key length is
* determined by the size of the decrypted RSA key.
int i;
pkiDebug("%s: %p %p %p\n", __FUNCTION__, context, idopts, id_cryptoctx);
- if (idopts == NULL || id_cryptoctx == NULL)
- goto errout;
-
- /*
- * If identity was specified, use that. (For the kdc, this
- * is specified as pkinit_identity in the kdc.conf. For users,
- * this is specified on the command line via X509_user_identity.)
- * If a user did not specify identity on the command line,
- * then we will try alternatives which may have been specified
- * in the config file.
- */
- if (idopts->identity != NULL) {
- retval = process_option_identity(context, plg_cryptoctx, req_cryptoctx,
- idopts, id_cryptoctx,
- idopts->identity);
- } else if (idopts->identity_alt != NULL) {
- for (i = 0; retval != 0 && idopts->identity_alt[i] != NULL; i++)
- retval = process_option_identity(context, plg_cryptoctx,
- req_cryptoctx, idopts,
- id_cryptoctx,
- idopts->identity_alt[i]);
- } else {
- pkiDebug("%s: no user identity options specified\n", __FUNCTION__);
- goto errout;
- }
- if (retval)
- goto errout;
-
- retval = crypto_load_certs(context, plg_cryptoctx, req_cryptoctx,
- idopts, id_cryptoctx, princ);
- if (retval)
- goto errout;
+ if (!(princ && krb5_principal_compare_any_realm (context, princ, krb5_anonymous_principal()))) {
+ if (idopts == NULL || id_cryptoctx == NULL)
+ goto errout;
- if (do_matching) {
- retval = pkinit_cert_matching(context, plg_cryptoctx, req_cryptoctx,
- id_cryptoctx, princ);
- if (retval) {
- pkiDebug("%s: No matching certificate found\n", __FUNCTION__);
- crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx,
- id_cryptoctx);
+ /*
+ * If identity was specified, use that. (For the kdc, this
+ * is specified as pkinit_identity in the kdc.conf. For users,
+ * this is specified on the command line via X509_user_identity.)
+ * If a user did not specify identity on the command line,
+ * then we will try alternatives which may have been specified
+ * in the config file.
+ */
+ if (idopts->identity != NULL) {
+ retval = process_option_identity(context, plg_cryptoctx, req_cryptoctx,
+ idopts, id_cryptoctx,
+ idopts->identity);
+ } else if (idopts->identity_alt != NULL) {
+ for (i = 0; retval != 0 && idopts->identity_alt[i] != NULL; i++)
+ retval = process_option_identity(context, plg_cryptoctx,
+ req_cryptoctx, idopts,
+ id_cryptoctx,
+ idopts->identity_alt[i]);
+ } else {
+ pkiDebug("%s: no user identity options specified\n", __FUNCTION__);
goto errout;
}
- } else {
- /* Tell crypto code to use the "default" */
- retval = crypto_cert_select_default(context, plg_cryptoctx,
- req_cryptoctx, id_cryptoctx);
- if (retval) {
- pkiDebug("%s: Failed while selecting default certificate\n",
- __FUNCTION__);
- crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx,
- id_cryptoctx);
+ if (retval)
+ goto errout;
+
+ retval = crypto_load_certs(context, plg_cryptoctx, req_cryptoctx,
+ idopts, id_cryptoctx, princ);
+ if (retval)
goto errout;
+
+ if (do_matching) {
+ retval = pkinit_cert_matching(context, plg_cryptoctx, req_cryptoctx,
+ id_cryptoctx, princ);
+ if (retval) {
+ pkiDebug("%s: No matching certificate found\n", __FUNCTION__);
+ crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx,
+ id_cryptoctx);
+ goto errout;
+ }
+ } else {
+ /* Tell crypto code to use the "default" */
+ retval = crypto_cert_select_default(context, plg_cryptoctx,
+ req_cryptoctx, id_cryptoctx);
+ if (retval) {
+ pkiDebug("%s: Failed while selecting default certificate\n",
+ __FUNCTION__);
+ crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx,
+ id_cryptoctx);
+ goto errout;
+ }
}
- }
- retval = crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx,
- id_cryptoctx);
- if (retval)
- goto errout;
+ retval = crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx,
+ id_cryptoctx);
+ if (retval)
+ goto errout;
+ } /*not anonymous principal*/
for (i = 0; idopts->anchors != NULL && idopts->anchors[i] != NULL; i++) {
retval = process_option_ca_crl(context, plg_cryptoctx, req_cryptoctx,
void
print_buffer(unsigned char *buf, unsigned int len)
{
- int i = 0;
+ unsigned i = 0;
if (len <= 0)
return;
print_buffer_bin(unsigned char *buf, unsigned int len, char *filename)
{
FILE *f = NULL;
- int i = 0;
+ unsigned int i = 0;
if (len <= 0 || filename == NULL)
return;
{
krb5_error_code retval = 0;
krb5_octet_data authp_data = {0, 0, NULL}, krb5_authz = {0, 0, NULL};
- krb5_data *encoded_pkinit_authz_data = NULL;
krb5_pa_pk_as_req *reqp = NULL;
krb5_pa_pk_as_req_draft9 *reqp9 = NULL;
krb5_auth_pack *auth_pack = NULL;
krb5_checksum cksum = {0, 0, 0, NULL};
krb5_data *der_req = NULL;
int valid_eku = 0, valid_san = 0;
- krb5_authdata **my_authz_data = NULL, *pkinit_authz_data = NULL;
krb5_kdc_req *tmp_as_req = NULL;
krb5_data k5data;
+ int is_signed = 1;
krb5_keyblock *armor_key;
pkiDebug("pkinit_verify_padata: entered!\n");
plgctx->opts->require_crl_checking,
reqp->signedAuthPack.data, reqp->signedAuthPack.length,
&authp_data.data, &authp_data.length, &krb5_authz.data,
- &krb5_authz.length);
+ &krb5_authz.length, &is_signed);
break;
case KRB5_PADATA_PK_AS_REP_OLD:
case KRB5_PADATA_PK_AS_REQ_OLD:
plgctx->opts->require_crl_checking,
reqp9->signedAuthPack.data, reqp9->signedAuthPack.length,
&authp_data.data, &authp_data.length, &krb5_authz.data,
- &krb5_authz.length);
+ &krb5_authz.length, NULL);
break;
default:
pkiDebug("unrecognized pa_type = %d\n", data->pa_type);
pkiDebug("pkcs7_signeddata_verify failed\n");
goto cleanup;
}
+ if (is_signed) {
- retval = verify_client_san(context, plgctx, reqctx, request->client,
- &valid_san);
- if (retval)
- goto cleanup;
- if (!valid_san) {
- pkiDebug("%s: did not find an acceptable SAN in user certificate\n",
- __FUNCTION__);
- retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
- goto cleanup;
- }
- retval = verify_client_eku(context, plgctx, reqctx, &valid_eku);
- if (retval)
- goto cleanup;
+ retval = verify_client_san(context, plgctx, reqctx, request->client,
+ &valid_san);
+ if (retval)
+ goto cleanup;
+ if (!valid_san) {
+ pkiDebug("%s: did not find an acceptable SAN in user certificate\n",
+ __FUNCTION__);
+ retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
+ goto cleanup;
+ }
+ retval = verify_client_eku(context, plgctx, reqctx, &valid_eku);
+ if (retval)
+ goto cleanup;
- if (!valid_eku) {
- pkiDebug("%s: did not find an acceptable EKU in user certificate\n",
- __FUNCTION__);
- retval = KRB5KDC_ERR_INCONSISTENT_KEY_PURPOSE;
- goto cleanup;
+ if (!valid_eku) {
+ pkiDebug("%s: did not find an acceptable EKU in user certificate\n",
+ __FUNCTION__);
+ retval = KRB5KDC_ERR_INCONSISTENT_KEY_PURPOSE;
+ goto cleanup;
+ }
+ } else { /*!is_signed*/
+ if (!krb5_principal_compare( context, request->client, krb5_anonymous_principal())) {
+ retval = KRB5KDC_ERR_PREAUTH_FAILED;
+ krb5_set_error_message(context, retval, "Pkinit request not signed, but client not anonymous.");
+ goto cleanup;
+ }
}
-
#ifdef DEBUG_ASN1
print_buffer_bin(authp_data.data, authp_data.length, "/tmp/kdc_auth_pack");
#endif
pkiDebug("bad dh parameters\n");
goto cleanup;
}
+ } else if (!is_signed) {
+ /*Anonymous pkinit requires DH*/
+ retval = KRB5KDC_ERR_PREAUTH_FAILED;
+ krb5_set_error_message(context, retval, "Anonymous pkinit without DH public value not supported.");
+ goto cleanup;
}
/*
* The KDC may have modified the request after decoding it.
/* return authorization data to be included in the ticket */
switch ((int)data->pa_type) {
- case KRB5_PADATA_PK_AS_REQ:
- my_authz_data = malloc(2 * sizeof(*my_authz_data));
- if (my_authz_data == NULL) {
- retval = ENOMEM;
- pkiDebug("Couldn't allocate krb5_authdata ptr array\n");
- goto cleanup;
- }
- my_authz_data[1] = NULL;
- my_authz_data[0] = malloc(sizeof(krb5_authdata));
- if (my_authz_data[0] == NULL) {
- retval = ENOMEM;
- pkiDebug("Couldn't allocate krb5_authdata\n");
- free(my_authz_data);
- goto cleanup;
- }
- /* AD-INITIAL-VERIFIED-CAS must be wrapped in AD-IF-RELEVANT */
- my_authz_data[0]->magic = KV5M_AUTHDATA;
- my_authz_data[0]->ad_type = KRB5_AUTHDATA_IF_RELEVANT;
-
- /* create an internal AD-INITIAL-VERIFIED-CAS data */
- pkinit_authz_data = malloc(sizeof(krb5_authdata));
- if (pkinit_authz_data == NULL) {
- retval = ENOMEM;
- pkiDebug("Couldn't allocate krb5_authdata\n");
- free(my_authz_data[0]);
- free(my_authz_data);
- goto cleanup;
- }
- pkinit_authz_data->ad_type = KRB5_AUTHDATA_INITIAL_VERIFIED_CAS;
- /* content of this ad-type contains the certification
- path with which the client certificate was validated
- */
- pkinit_authz_data->contents = krb5_authz.data;
- pkinit_authz_data->length = krb5_authz.length;
- retval = k5int_encode_krb5_authdata_elt(pkinit_authz_data,
- &encoded_pkinit_authz_data);
-#ifdef DEBUG_ASN1
- print_buffer_bin((unsigned char *)encoded_pkinit_authz_data->data,
- encoded_pkinit_authz_data->length,
- "/tmp/kdc_pkinit_authz_data");
-#endif
- free(pkinit_authz_data);
- if (retval) {
- pkiDebug("k5int_encode_krb5_authdata_elt failed\n");
- free(my_authz_data[0]);
- free(my_authz_data);
- goto cleanup;
- }
-
- my_authz_data[0]->contents =
- (krb5_octet *) encoded_pkinit_authz_data->data;
- my_authz_data[0]->length = encoded_pkinit_authz_data->length;
- *authz_data = my_authz_data;
- pkiDebug("Returning %d bytes of authorization data\n",
- krb5_authz.length);
- encoded_pkinit_authz_data->data = NULL; /* Don't free during cleanup*/
- free(encoded_pkinit_authz_data);
- break;
+/*
+ * This code used to generate ad-initial-verified-cas authorization data.
+ * However that has been removed until the ad-kdc-issued discussion can happen
+ * in the working group. Dec 2009
+ */
default:
*authz_data = NULL;
}
return retval;
}
+static krb5_error_code
+return_pkinit_kx( krb5_context context, krb5_kdc_req *request, krb5_kdc_rep *reply,
+ krb5_keyblock *encrypting_key,
+ krb5_pa_data **out_padata)
+{
+ krb5_error_code ret = 0;
+ krb5_keyblock *session = reply->ticket->enc_part2->session;
+ krb5_keyblock *new_session = NULL;
+ krb5_pa_data *pa = NULL;
+ krb5_enc_data enc;
+ krb5_data *scratch = NULL;
+ *out_padata = NULL;
+ enc.ciphertext.data = NULL;
+ if (!krb5_principal_compare(context, request->client,
+ krb5_anonymous_principal()))
+ return 0;
+ /*
+ *The KDC contribution key needs to be a fresh key of an
+ *enctype supported by the client and server. The existing
+ *session key meets these requirements so we use itt.
+ */
+ ret = krb5_c_fx_cf2_simple(context, session, "PKINIT",
+ encrypting_key, "KEYEXCHANGE",
+ &new_session);
+ if (ret)
+ goto cleanup;
+ ret = encode_krb5_encryption_key( session, &scratch);
+ if (ret)
+ goto cleanup;
+ ret = krb5_encrypt_helper( context, encrypting_key, KRB5_KEYUSAGE_PA_PKINIT_KX,
+ scratch, &enc);
+ if (ret)
+ goto cleanup;
+ memset(scratch->data, 0, scratch->length);
+ krb5_free_data(context, scratch);
+ scratch = NULL;
+ ret = encode_krb5_enc_data(&enc, &scratch);
+ if (ret)
+ goto cleanup;
+ pa = malloc(sizeof(krb5_pa_data));
+ if (pa == NULL) {
+ ret = ENOMEM;
+ goto cleanup;
+ }
+ if (ret)
+ goto cleanup;
+ pa->pa_type = KRB5_PADATA_PKINIT_KX;
+ pa->length = scratch->length;
+ pa->contents = (krb5_octet *) scratch->data;
+ *out_padata = pa;
+ scratch->data = NULL;
+ memset(session->contents, 0, session->length);
+ krb5_free_keyblock_contents(context, session);
+ *session = *new_session;
+ new_session->contents = NULL;
+cleanup:
+ krb5_free_data_contents(context, &enc.ciphertext);
+ krb5_free_keyblock(context, new_session);
+ krb5_free_data(context, scratch);
+ return ret;
+}
static krb5_error_code
pkinit_server_return_padata(krb5_context context,
int fixed_keypack = 0;
*send_pa = NULL;
+ if (padata->pa_type == KRB5_PADATA_PKINIT_KX)
+ return return_pkinit_kx(context, request, reply,
+ encrypting_key, send_pa);
if (padata == NULL || padata->length <= 0 || padata->contents == NULL)
return 0;
static int
pkinit_server_get_flags(krb5_context kcontext, krb5_preauthtype patype)
{
+ if (patype == KRB5_PADATA_PKINIT_KX)
+ return PA_PSEUDO;
return PA_SUFFICIENT | PA_REPLACES_KEY;
}
KRB5_PADATA_PK_AS_REQ,
KRB5_PADATA_PK_AS_REQ_OLD,
KRB5_PADATA_PK_AS_REP_OLD,
+ KRB5_PADATA_PKINIT_KX,
0
};
{
krb5_error_code retval = ENOMEM;
pkinit_kdc_context plgctx, *realm_contexts = NULL;
- int i, j;
+ size_t i, j;
size_t numrealms;
retval = pkinit_accessor_init();