Anonymous support for Kerberos
authorSam Hartman <hartmans@mit.edu>
Mon, 28 Dec 2009 17:15:30 +0000 (17:15 +0000)
committerSam Hartman <hartmans@mit.edu>
Mon, 28 Dec 2009 17:15:30 +0000 (17:15 +0000)
This ticket implements Project/Anonymous pkinit from k5wiki.  Provides
support for completely anonymous principals and untested client
support for realm-exposed anonymous authentication.

* Introduce kinit -n
* Introduce kadmin -n
* krb5_get_init_creds_opt_set_out_ccache aliases the supplied ccache
* No longer generate ad-initial-verified-cas in pkinit
* Fix pkinit interactions with non-TGT authentication

Merge remote branch 'anonymous' into trunk

Conflicts:
src/lib/krb5/krb/gic_opt.c

ticket: 6607
Tags: enhancement

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@23527 dc483132-0cff-0310-8789-dd5450dbe970

28 files changed:
src/clients/kinit/kinit.c
src/include/k5-int-pkinit.h
src/include/k5-int.h
src/include/krb5/krb5.hin
src/kadmin/cli/kadmin.c
src/kdc/do_as_req.c
src/kdc/do_tgs_req.c
src/kdc/kdc_authdata.c
src/kdc/kdc_preauth.c
src/lib/gssapi/krb5/disp_name.c
src/lib/gssapi/krb5/import_name.c
src/lib/kadm5/admin.h
src/lib/kadm5/clnt/client_init.c
src/lib/kadm5/clnt/libkadm5clnt.exports
src/lib/kadm5/srv/libkadm5srv.exports
src/lib/kadm5/srv/server_init.c
src/lib/krb5/krb/bld_princ.c
src/lib/krb5/krb/chk_trans.c
src/lib/krb5/krb/get_in_tkt.c
src/lib/krb5/krb/gic_opt.c
src/lib/krb5/libkrb5.exports
src/plugins/preauth/fast_factor.h
src/plugins/preauth/pkinit/pkinit_clnt.c
src/plugins/preauth/pkinit/pkinit_crypto.h
src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
src/plugins/preauth/pkinit/pkinit_identity.c
src/plugins/preauth/pkinit/pkinit_lib.c
src/plugins/preauth/pkinit/pkinit_srv.c

index fdfae88286edc64550b6d2b777cd4761bdec5767..79ac654188665d2247e3031df0205a64a8a303e6 100644 (file)
@@ -106,6 +106,7 @@ struct k_opts
 
     int forwardable;
     int proxiable;
+    int anonymous;
     int addresses;
 
     int not_forwardable;
@@ -189,6 +190,7 @@ usage()
             USAGE_BREAK_LONG
             "[-p | -P" USAGE_LONG_PROXIABLE "] "
             USAGE_BREAK_LONG
+            "-n"
             "[-a | -A" USAGE_LONG_ADDRESSES "] "
             USAGE_BREAK_LONG
             "[-C" USAGE_LONG_CANONICALIZE "] "
@@ -214,6 +216,7 @@ usage()
     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");
@@ -282,7 +285,7 @@ parse_options(argc, argv, opts)
     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':
@@ -316,6 +319,9 @@ parse_options(argc, argv, opts)
         case 'P':
             opts->not_proxiable = 1;
             break;
+        case 'n':
+            opts->anonymous = 1;
+            break;
         case 'a':
             opts->addresses = 1;
             break;
@@ -472,44 +478,63 @@ k5_begin(opts, k5)
     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;
+                    }
+                }
             }
         }
     }
@@ -593,6 +618,8 @@ k5_kinit(opts, k5)
         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;
index 77bd260ffb5e74d52f25fdd966960c3976600801..8dcbd5d4f3b6086260834d5901d50080390cdb04 100644 (file)
@@ -283,4 +283,15 @@ decode_krb5_td_dh_parameters(const krb5_data *, krb5_algorithm_identifier ***);
 
 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 */
index f1b48c0afd6984c8acc33ac4119f983211dca377..a70eae9c53d304554a230d4dbcea454e1029f601 100644 (file)
@@ -806,11 +806,6 @@ krb5_error_code krb5_crypto_us_timeofday(krb5_int32 *, krb5_int32 *);
 
 /* 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,
@@ -1532,7 +1527,7 @@ void KRB5_CALLCONV krb5_free_priv_enc_part(krb5_context, krb5_priv_enc_part *);
 /* 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)
@@ -1571,9 +1566,6 @@ encode_krb5_authenticator(const krb5_authenticator *rep, krb5_data **code);
 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);
 
@@ -1659,9 +1651,6 @@ encode_krb5_etype_info(krb5_etype_info_entry *const *, 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 **);
 
index 7f7b56dd86e786882e1c92655d42709b551f011f..470ca4d50658bbf3f5abe51944e1915a2b6c995e 100644 (file)
@@ -261,6 +261,8 @@ typedef krb5_principal_data * krb5_principal;
 #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 */
@@ -293,6 +295,14 @@ typedef const krb5_principal_data *krb5_const_principal;
  */
 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"
  */
@@ -628,7 +638,7 @@ krb5_c_keyed_checksum_types(krb5_context context, krb5_enctype enctype,
 #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
@@ -838,10 +848,9 @@ krb5_verify_checksum(krb5_context context, krb5_cksumtype ctype,
 /* #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 */
@@ -929,9 +938,8 @@ krb5_verify_checksum(krb5_context context, krb5_cksumtype ctype,
 #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 */
@@ -1033,6 +1041,7 @@ krb5_verify_checksum(krb5_context context, krb5_cksumtype ctype,
 #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
@@ -2196,6 +2205,7 @@ typedef struct _krb5_get_init_creds_opt {
 #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
@@ -2229,6 +2239,21 @@ void 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,
index c8cb3fb5897c6cb978e6f907aaf4333e36c8d204..1bcf891ed64edba701315da3034140fedf9d2b16 100644 (file)
@@ -119,7 +119,7 @@ usage()
 {
     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",
@@ -238,7 +238,7 @@ kadmin_startup(int argc, char *argv[])
     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;
@@ -270,7 +270,7 @@ kadmin_startup(int argc, char *argv[])
         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++;
@@ -296,6 +296,9 @@ kadmin_startup(int argc, char *argv[])
         case 'k':
             use_keytab++;
             break;
+        case 'n':
+            use_anonymous++;
+            break;
         case 't':
             keytab_name = optarg;
             break;
@@ -349,7 +352,9 @@ kadmin_startup(int argc, char *argv[])
         }
     }
     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)) {
@@ -487,6 +492,12 @@ kadmin_startup(int argc, char *argv[])
         retval = kadm5_init_with_creds(context, princstr, cc, svcname, &params,
                                        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, &params,
+                                      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",
index 23f1ddcb83808fd367965ee97fab1b9c6dbb35d6..58da726cb14ff51429c215651181a0a117854eb4 100644 (file)
@@ -389,6 +389,24 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
     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.
      */
index 75d4132509033627c0055b70a21ce3381acc8623..4a778f412072df42f9ea86f646ec1847d0e79b2b 100644 (file)
@@ -593,7 +593,8 @@ tgt_again:
     } 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
      */
index 03bfe29c4f420dee7e42fc264bb845224caedf17..88216744309942f72061f96a644d5651bfaf5f06 100644 (file)
@@ -128,6 +128,7 @@ typedef struct _krb5_authdata_systems {
     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;
@@ -143,7 +144,7 @@ static krb5_authdata_systems static_authdata_systems[] = {
         /* 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,
@@ -153,7 +154,7 @@ static krb5_authdata_systems static_authdata_systems[] = {
         /* Propagate TGT authdata */
         "tgt",
         AUTHDATA_SYSTEM_V2,
-        AUTHDATA_FLAG_CRITICAL,
+        AUTHDATA_FLAG_CRITICAL|AUTHDATA_FLAG_ANONYMOUS,
         NULL,
         NULL,
         NULL,
@@ -765,6 +766,9 @@ handle_authdata (krb5_context context,
 
     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:
index 2262c89560a4a5820694fdcba2962a1ca6b6bd2b..d14b18333e340a4a24a1d292dfb5a8005ffb83fd 100644 (file)
@@ -1275,6 +1275,7 @@ return_padata(krb5_context context, krb5_db_entry *client, krb5_data *req_pkt,
     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;
@@ -1308,7 +1309,8 @@ return_padata(krb5_context context, krb5_db_entry *client, krb5_data *req_pkt,
         return retval;
     }
     key_modified = FALSE;
-
+    null_item.contents = NULL;
+    null_item.length = NULL;
     send_pa = send_pa_list;
     *send_pa = 0;
 
@@ -1330,7 +1332,8 @@ return_padata(krb5_context context, krb5_db_entry *client, krb5_data *req_pkt,
             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) {
@@ -1900,7 +1903,7 @@ return_sam_data(krb5_context context, krb5_pa_data *in_padata,
     krb5_sam_response           *sr = 0;
     krb5_predicted_sam_response *psr = 0;
 
-    if (in_padata == 0)
+    if (in_padata->contents == 0)
         return 0;
 
     /*
index ac576f5b460dc768e4e2f4409977945e1d240bd9..79b14f1a933c33351542a52ed85faa7c279343e7 100644 (file)
@@ -34,6 +34,8 @@ krb5_gss_display_name(minor_status, input_name, output_name_buffer,
     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) {
@@ -49,6 +51,11 @@ krb5_gss_display_name(minor_status, input_name, output_name_buffer,
         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,
@@ -72,6 +79,6 @@ krb5_gss_display_name(minor_status, input_name, output_name_buffer,
 
     *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);
 }
index cd2748b561cb422da72088e21bf86a914e1c6b46..cfb75fb221868516dbdc0bf66fbca1b4e05fd4d8 100644 (file)
@@ -154,7 +154,16 @@ krb5_gss_import_name(minor_status, input_name_buffer,
             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;
index 4196a19e29cc91b351cd2660afc0dd722c727342..8fad11177f49942a451b1faa98deb58be861e9cc 100644 (file)
@@ -338,6 +338,13 @@ kadm5_ret_t    kadm5_init(krb5_context context, char *client_name,
                           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,
index 95c4954ef336f901ec2ce412099e7bdba79b52af..82033e9fda9f734f600a30761d6c2719366a1ad3 100644 (file)
@@ -59,7 +59,7 @@
 
 #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,
@@ -129,6 +129,19 @@ kadm5_ret_t kadm5_init_with_password(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,
@@ -343,7 +356,8 @@ static kadm5_ret_t _kadm5_init_any(krb5_context context, char *client_name,
      * 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;
 
@@ -490,7 +504,7 @@ kadm5_get_init_creds(kadm5_server_handle_t handle,
                           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,
@@ -525,7 +539,7 @@ kadm5_gic_iter(kadm5_server_handle_t handle,
     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;
 
@@ -540,29 +554,32 @@ kadm5_gic_iter(kadm5_server_handle_t handle,
     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) {
@@ -572,7 +589,7 @@ kadm5_gic_iter(kadm5_server_handle_t handle,
                 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)
@@ -588,14 +605,10 @@ kadm5_gic_iter(kadm5_server_handle_t handle,
         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;
 }
 
@@ -644,10 +657,13 @@ kadm5_setup_gss(kadm5_server_handle_t handle,
         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;
index 6174847783216bfe38c77b1f51c5ab316011fc76..5e81580b19dd71defc85ab208fe35deb9e60b10b 100644 (file)
@@ -24,6 +24,7 @@ kadm5_get_principal
 kadm5_get_principals
 kadm5_get_privs
 kadm5_init
+kadm5_init_anonymous
 kadm5_init_krb5_context
 kadm5_init_with_creds
 kadm5_init_with_password
index 35745be883a1690b0a39b609205c7256c5090cad..d8d3b22834a7b7af1214a2b17579b96fc10ade59 100644 (file)
@@ -40,6 +40,7 @@ kadm5_get_principal_keys
 kadm5_get_principals
 kadm5_get_privs
 kadm5_init
+kadm5_init_anonymous
 kadm5_init_krb5_context
 kadm5_init_with_creds
 kadm5_init_with_password
index ed71cbf96b4b5792986b18ac2508d137ae4da376..557ef0ad46839ea68aa575bc10b59e8a50cb85d8 100644 (file)
@@ -104,6 +104,19 @@ kadm5_ret_t kadm5_init_with_password(krb5_context context, char *client_name,
                       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,
index ac2c92a9e3ad3821c3ea718d3c014751c3bc003c..8378599d3b355d688f9a84a4dd42bfcd7e54af30 100644 (file)
@@ -187,3 +187,33 @@ krb5_build_principal(krb5_context context,
 
     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;
+}
index 3c014817c4bdb11fbc7df7de2ed83bfaadbe429a..def50885c8ba3eb37e6505b5e4b2b794c9d6c376 100644 (file)
@@ -315,6 +315,7 @@ krb5_check_transited_list (krb5_context ctx, const krb5_data *trans_in,
     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;
@@ -327,6 +328,11 @@ krb5_check_transited_list (krb5_context ctx, const krb5_data *trans_in,
               (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) {
index 06b3c3874a9cf1a17a25f19f37c4ed13a2e6c665..315bdc9439de993dfbeaf4d7677f4aacc91f981d 100644 (file)
@@ -283,6 +283,71 @@ cleanup:
     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,
@@ -304,10 +369,14 @@ verify_as_reply(krb5_context            context,
      * 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;
 
@@ -1394,6 +1463,32 @@ krb5_init_creds_init(krb5_context context,
         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;
@@ -1829,6 +1924,10 @@ init_creds_step_reply(krb5_context context,
                            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);
index d326ac570f7cd67685655d88ba54b70d394b3f2b..c94ee3487586667065de9c18d085727ecaa517af 100644 (file)
@@ -52,6 +52,15 @@ krb5_get_init_creds_opt_set_canonicalize(krb5_get_init_creds_opt *opt, int canon
         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)
 {
@@ -149,8 +158,6 @@ krb5int_gic_opte_private_free(krb5_context context, krb5_gic_opt_ext *opte)
         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;
@@ -504,13 +511,8 @@ krb5_get_init_creds_opt_set_out_ccache(krb5_context context,
                                      "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
index 1c35c459214a3f35ce123800a5f5b0231a8aa249..e7c191b6394f0a590db5bbe9bd4666f9a7a50610 100644 (file)
@@ -109,6 +109,8 @@ krb5_address_compare
 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
@@ -337,6 +339,7 @@ krb5_get_init_creds_opt_get_fast_flags
 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
index 0789c1ad1822621d6e4362ff8ea60af11df30258..52f4fa2e82fafd258593178e8f11a9a4f3278b1f 100644 (file)
@@ -4,7 +4,7 @@
  * 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)
@@ -21,7 +21,7 @@ fast_get_armor_key(krb5_context context, preauth_get_client_data_proc get_data,
     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,
@@ -43,7 +43,7 @@ fast_kdc_get_armor_key(krb5_context context,
 
 
 
-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)
@@ -51,7 +51,7 @@ fast_kdc_replace_reply_key(krb5_context context,
     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)
index ba1e4344fe51bbe5c4f0161980b20979c6224984..8f17f7e4af9b5c023b8478b04448403f3b65120a 100644 (file)
@@ -61,7 +61,8 @@ static krb5_error_code
 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
@@ -139,7 +140,7 @@ pa_pkinit_gen_req(krb5_context context,
     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);
@@ -218,6 +219,7 @@ pkinit_as_req_create(krb5_context context,
                      krb5_int32 cusec,
                      krb5_ui_4 nonce,
                      const krb5_checksum * cksum,
+                     krb5_principal client,
                      krb5_principal server,
                      krb5_data ** as_req)
 {
@@ -344,10 +346,17 @@ pkinit_as_req_create(krb5_context context,
             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,
@@ -640,6 +649,7 @@ pkinit_as_rep_parse(krb5_context context,
                     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;
@@ -677,7 +687,7 @@ pkinit_as_rep_parse(krb5_context context,
                                             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;
         }
@@ -700,8 +710,16 @@ pkinit_as_rep_parse(krb5_context context,
         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;
@@ -850,6 +868,7 @@ pkinit_as_rep_parse(krb5_context context,
 
 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);
index 83d2f1e19d12bc9da1fdb2abad5e34847a3f72c0..dedd8f9456f17e359597cc81ca2854f7bc03c212 100644 (file)
@@ -113,6 +113,16 @@ void pkinit_fini_req_crypto(pkinit_req_crypto_context);
 
 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
@@ -171,8 +181,9 @@ krb5_error_code cms_signeddata_verify
                    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
index 443b0f98cc0231a11bb88efc94e393edaf70be16..887ec06270779f9c8c7479be74736465c46468dd 100644 (file)
@@ -691,6 +691,102 @@ pkinit_identity_set_prompter(pkinit_identity_crypto_context id_cryptoctx,
     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,
@@ -708,7 +804,6 @@ cms_signeddata_create(krb5_context context,
     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;
@@ -726,7 +821,11 @@ cms_signeddata_create(krb5_context context,
     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);
@@ -751,7 +850,7 @@ cms_signeddata_create(krb5_context context,
         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;
@@ -939,26 +1038,8 @@ cms_signeddata_create(krb5_context context,
         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;
@@ -972,6 +1053,7 @@ cms_signeddata_create(krb5_context context,
         pkiDebug("failed to der encode pkcs7\n");
         goto cleanup2;
     }
+    retval = ENOMEM;
     if ((p = *signed_data = malloc(*signed_data_len)) == NULL)
         goto cleanup2;
 
@@ -1038,12 +1120,14 @@ cms_signeddata_verify(krb5_context context,
                       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;
@@ -1063,7 +1147,8 @@ cms_signeddata_verify(krb5_context context,
     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)
@@ -1079,13 +1164,33 @@ cms_signeddata_verify(krb5_context context,
         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()))
@@ -1285,13 +1390,15 @@ cms_signeddata_verify(krb5_context context,
 
     /* 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;
 
@@ -1617,7 +1724,7 @@ cms_envelopeddata_verify(krb5_context context,
                                    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");
@@ -1655,7 +1762,7 @@ crypto_retrieve_X509_sans(krb5_context context,
     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__);
@@ -3220,7 +3327,7 @@ static krb5_error_code
 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;
@@ -3414,7 +3521,7 @@ pkinit_C_Decrypt(pkinit_identity_crypto_context id_cryptoctx,
     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;
 }
@@ -4451,7 +4558,7 @@ X509_NAME_oneline_ex(X509_NAME * a,
 
     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));
         }
@@ -5459,7 +5566,7 @@ pkcs7_dataDecode(krb5_context context,
     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.
index aef0393610bf7a7f847f96f8f50b40be40fc37e0..aecea2c787a3a9a68b86b886b94cffd32aaba974 100644 (file)
@@ -505,65 +505,67 @@ pkinit_identity_initialize(krb5_context context,
     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,
index e665b6cb7a7c353d4a32762d6d7404fe9d36ad0c..a6d7762fbb9ea819f9c4ca31cc24cd79107c4af0 100644 (file)
@@ -424,7 +424,7 @@ pkinit_copy_krb5_octet_data(krb5_octet_data *dst, const krb5_octet_data *src)
 void
 print_buffer(unsigned char *buf, unsigned int len)
 {
-    int i = 0;
+    unsigned  i = 0;
     if (len <= 0)
         return;
 
@@ -437,7 +437,7 @@ void
 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;
index adfcb95930e8ac5945384a6c3d87cb394568bc86..34700ad18b636a7b864c5d483c850f90e0094db1 100644 (file)
@@ -300,7 +300,6 @@ pkinit_server_verify_padata(krb5_context context,
 {
     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;
@@ -311,9 +310,9 @@ pkinit_server_verify_padata(krb5_context context,
     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");
@@ -367,7 +366,7 @@ pkinit_server_verify_padata(krb5_context context,
                                        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:
@@ -389,7 +388,7 @@ pkinit_server_verify_padata(krb5_context context,
                                        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);
@@ -400,28 +399,35 @@ pkinit_server_verify_padata(krb5_context context,
         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
@@ -446,6 +452,11 @@ pkinit_server_verify_padata(krb5_context context,
                 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.
@@ -536,64 +547,11 @@ pkinit_server_verify_padata(krb5_context context,
 
     /* 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;
     }
@@ -634,6 +592,67 @@ cleanup:
 
     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,
@@ -680,6 +699,9 @@ 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;
 
@@ -1037,6 +1059,8 @@ cleanup:
 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;
 }
 
@@ -1044,6 +1068,7 @@ static krb5_preauthtype supported_server_pa_types[] = {
     KRB5_PADATA_PK_AS_REQ,
     KRB5_PADATA_PK_AS_REQ_OLD,
     KRB5_PADATA_PK_AS_REP_OLD,
+    KRB5_PADATA_PKINIT_KX,
     0
 };
 
@@ -1238,7 +1263,7 @@ pkinit_server_plugin_init(krb5_context context, void **blob,
 {
     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();