Client code lacks support for draft-ietf-krb-wg-kerberos-sam-01.txt
authorKen Hornstein <kenh@cmf.nrl.navy.mil>
Thu, 24 Oct 2002 06:49:59 +0000 (06:49 +0000)
committerKen Hornstein <kenh@cmf.nrl.navy.mil>
Thu, 24 Oct 2002 06:49:59 +0000 (06:49 +0000)
This widely-spread commit implements support for the so-called "new"
hardware preauth protocol, defined in the IETF internet-draft
draft-ietf-krb-wg-kerberos-sam-01.txt.  Note that this code is client-side
only.

ticket: new

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

21 files changed:
src/include/ChangeLog
src/include/k5-int.h
src/include/krb5.hin
src/lib/crypto/ChangeLog
src/lib/crypto/Makefile.in
src/lib/crypto/combine_keys.c [new file with mode: 0644]
src/lib/krb5/asn.1/ChangeLog
src/lib/krb5/asn.1/KRB5-asn.py
src/lib/krb5/asn.1/asn1_k_decode.c
src/lib/krb5/asn.1/asn1_k_decode.h
src/lib/krb5/asn.1/asn1_k_encode.c
src/lib/krb5/asn.1/asn1_k_encode.h
src/lib/krb5/asn.1/krb5_decode.c
src/lib/krb5/asn.1/krb5_encode.c
src/lib/krb5/error_tables/ChangeLog
src/lib/krb5/error_tables/krb5_err.et
src/lib/krb5/error_tables/kv5m_err.et
src/lib/krb5/krb/ChangeLog
src/lib/krb5/krb/gic_pwd.c
src/lib/krb5/krb/kfree.c
src/lib/krb5/krb/preauth2.c

index 6aeda6d41ac48c2a8dd74d362f32c632d203d9e4..bf8dbf6b3b0af3a0e0f7d597b34cc4a59a9ff763 100644 (file)
@@ -1,3 +1,8 @@
+2002-10-24  Ken Hornstein  <kenh@cmf.nrl.navy.mil>
+
+       * k5-int.h, krb5.hin: Add new protocols, definitions, and
+       data structures for new hardware preauthentication protocol.
+
 2002-10-23  Ken Hornstein  <kenh@cmf.nrl.navy.mil>
 
        * krb5.hin: Add new LRQ type for password expiration
index 3f9c330c74cd3699c5b955a40a196ab664f0117e..0ee5dd9a8c9d6b690b35ee4496d20f167a8ffe74 100644 (file)
@@ -387,6 +387,39 @@ typedef struct _krb5_sam_response {
        krb5_timestamp  sam_patimestamp;
 } krb5_sam_response;
 
+typedef struct _krb5_sam_challenge_2 {
+       krb5_data       sam_challenge_2_body;
+       krb5_checksum   **sam_cksum;            /* Array of checksums */
+} krb5_sam_challenge_2;
+
+typedef struct _krb5_sam_challenge_2_body {
+       krb5_magic      magic;
+       krb5_int32      sam_type; /* information */
+       krb5_flags      sam_flags; /* KRB5_SAM_* values */
+       krb5_data       sam_type_name;
+       krb5_data       sam_track_id;
+       krb5_data       sam_challenge_label;
+       krb5_data       sam_challenge;
+       krb5_data       sam_response_prompt;
+       krb5_data       sam_pk_for_sad;
+       krb5_int32      sam_nonce;
+       krb5_enctype    sam_etype;
+} krb5_sam_challenge_2_body;
+
+typedef struct _krb5_sam_response_2 {
+       krb5_magic      magic;
+       krb5_int32      sam_type; /* informational */
+       krb5_flags      sam_flags; /* KRB5_SAM_* values */
+       krb5_data       sam_track_id; /* copied */
+       krb5_enc_data   sam_enc_nonce_or_sad; /* krb5_enc_sam_response_enc */
+       krb5_int32      sam_nonce;
+} krb5_sam_response_2;
+
+typedef struct _krb5_enc_sam_response_enc_2 {
+       krb5_magic      magic;
+       krb5_int32      sam_nonce;
+       krb5_data       sam_sad;
+} krb5_enc_sam_response_enc_2;
 
 /*
  * Begin "ext-proto.h"
@@ -648,6 +681,14 @@ krb5_error_code krb5int_default_free_state
 (krb5_data *state);
 
 
+/*
+ * Combine two keys (normally used by the hardware preauth mechanism)
+ */
+krb5_error_code krb5int_c_combine_keys
+(krb5_context context, krb5_keyblock *key1, krb5_keyblock *key2,
+               krb5_keyblock *outkey);
+
+
 /* 
  * These declarations are here, so both krb5 and k5crypto
  * can get to them.
@@ -954,20 +995,36 @@ krb5_error_code krb5_do_preauth
 
 void KRB5_CALLCONV krb5_free_sam_challenge
        (krb5_context, krb5_sam_challenge * );
+void KRB5_CALLCONV krb5_free_sam_challenge_2
+       (krb5_context, krb5_sam_challenge_2 * );
+void KRB5_CALLCONV krb5_free_sam_challenge_2_body
+       (krb5_context, krb5_sam_challenge_2_body *);
 void KRB5_CALLCONV krb5_free_sam_response
        (krb5_context, krb5_sam_response * );
+void KRB5_CALLCONV krb5_free_sam_response_2
+       (krb5_context, krb5_sam_response_2 * );
 void KRB5_CALLCONV krb5_free_predicted_sam_response
        (krb5_context, krb5_predicted_sam_response * );
 void KRB5_CALLCONV krb5_free_enc_sam_response_enc
        (krb5_context, krb5_enc_sam_response_enc * );
+void KRB5_CALLCONV krb5_free_enc_sam_response_enc_2
+       (krb5_context, krb5_enc_sam_response_enc_2 * );
 void KRB5_CALLCONV krb5_free_sam_challenge_contents
        (krb5_context, krb5_sam_challenge * );
+void KRB5_CALLCONV krb5_free_sam_challenge_2_contents
+       (krb5_context, krb5_sam_challenge_2 * );
+void KRB5_CALLCONV krb5_free_sam_challenge_2_body_contents
+       (krb5_context, krb5_sam_challenge_2_body * );
 void KRB5_CALLCONV krb5_free_sam_response_contents
        (krb5_context, krb5_sam_response * );
+void KRB5_CALLCONV krb5_free_sam_response_2_contents
+       (krb5_context, krb5_sam_response_2 *);
 void KRB5_CALLCONV krb5_free_predicted_sam_response_contents
        (krb5_context, krb5_predicted_sam_response * );
 void KRB5_CALLCONV krb5_free_enc_sam_response_enc_contents
        (krb5_context, krb5_enc_sam_response_enc * );
+void KRB5_CALLCONV krb5_free_enc_sam_response_enc_2_contents
+       (krb5_context, krb5_enc_sam_response_enc_2 * );
  
 void KRB5_CALLCONV krb5_free_pa_enc_ts
        (krb5_context, krb5_pa_enc_ts *);
@@ -1243,6 +1300,18 @@ krb5_error_code encode_krb5_enc_sam_response_enc
 krb5_error_code encode_krb5_sam_response
        (const krb5_sam_response * , krb5_data **);
 
+krb5_error_code encode_krb5_sam_challenge_2
+       (const krb5_sam_challenge_2 * , krb5_data **);
+
+krb5_error_code encode_krb5_sam_challenge_2_body
+       (const krb5_sam_challenge_2_body * , krb5_data **);
+
+krb5_error_code encode_krb5_enc_sam_response_enc_2
+       (const krb5_enc_sam_response_enc_2 * , krb5_data **);
+
+krb5_error_code encode_krb5_sam_response_2
+       (const krb5_sam_response_2 * , krb5_data **);
+
 krb5_error_code encode_krb5_predicted_sam_response
        (const krb5_predicted_sam_response * , krb5_data **);
 
@@ -1280,6 +1349,18 @@ krb5_error_code decode_krb5_sam_response
 krb5_error_code decode_krb5_predicted_sam_response
        (const krb5_data *, krb5_predicted_sam_response **);
 
+krb5_error_code decode_krb5_sam_challenge_2
+       (const krb5_data *, krb5_sam_challenge_2 **);
+
+krb5_error_code decode_krb5_sam_challenge_2_body
+       (const krb5_data *, krb5_sam_challenge_2_body **);
+
+krb5_error_code decode_krb5_enc_sam_response_enc_2
+       (const krb5_data *, krb5_enc_sam_response_enc_2 **);
+
+krb5_error_code decode_krb5_sam_response_2
+       (const krb5_data *, krb5_sam_response_2 **);
+
 
 /*************************************************************************
  * Prototypes for krb5_decode.c
index 345660253e3c90ec806b0a694adaa5b13be6d3d5..5b8cb2c609ee5a242b45626be174e909b77e86b0 100644 (file)
@@ -543,6 +543,12 @@ krb5_error_code KRB5_CALLCONV
 #define KRB5_KEYUSAGE_GSS_TOK_WRAP_INTEG       23
 #define KRB5_KEYUSAGE_GSS_TOK_WRAP_PRIV                24
 
+/* Defined in hardware preauth draft */
+
+#define KRB5_KEYUSAGE_PA_SAM_CHALLENGE_CKSUM   25
+#define KRB5_KEYUSAGE_PA_SAM_CHALLENGE_TRACKID 26
+#define KRB5_KEYUSAGE_PA_SAM_RESPONSE          27
+
 krb5_boolean KRB5_CALLCONV krb5_c_valid_enctype
        (krb5_enctype ktype);
 krb5_boolean KRB5_CALLCONV krb5_c_valid_cksumtype
@@ -860,6 +866,8 @@ krb5_error_code krb5_decrypt_data
 #define KRB5_PADATA_ETYPE_INFO         11 /* Etype info for preauth */
 #define KRB5_PADATA_SAM_CHALLENGE      12 /* draft challenge system */
 #define KRB5_PADATA_SAM_RESPONSE       13 /* draft challenge system response */
+#define KRB5_PADATA_SAM_CHALLENGE_2    14 /* draft challenge system, updated */
+#define KRB5_PADATA_SAM_RESPONSE_2     15 /* draft challenge system, updated */
     
 #define        KRB5_SAM_USE_SAD_AS_KEY         0x80000000
 #define        KRB5_SAM_SEND_ENCRYPTED_SAD     0x40000000
index cf91d7b71ba14ffa1631d880cf7608fc1ea92c21..36b03a51cc06565aecfc5bc3a2e67e36c8df45dc 100644 (file)
@@ -1,3 +1,8 @@
+2002-10-24  Ken Hornstein  <kenh@cmf.nrl.navy.mil>
+
+       * Makefile.in, combine_keys.c: New file to implement
+       key-combination algorithm.
+
 2002-10-09  Ken Raeburn  <raeburn@mit.edu>
 
        * pbkdf2.c, t_hmac.c, t_pkcs5.c: New files.
index 3273a82821ad9ec4804213f4be25a119ddcff909..5dc557485698a043341f72f9b46f170c43c5e0b9 100644 (file)
@@ -39,6 +39,7 @@ STLIBOBJS=\
        cksumtype_to_string.o   \
        cksumtypes.o            \
        coll_proof_cksum.o      \
+       combine_keys.o  \
        crypto_libinit.o        \
        default_state.o \
        decrypt.o               \
@@ -69,6 +70,7 @@ OBJS=\
        $(OUTPRE)cksumtype_to_string.$(OBJEXT)  \
        $(OUTPRE)cksumtypes.$(OBJEXT)           \
        $(OUTPRE)coll_proof_cksum.$(OBJEXT)     \
+       $(OUTPRE)combine_keys.$(OBJEXT) \
        $(OUTPRE)crypto_libinit.$(OBJEXT)       \
        $(OUTPRE)default_state.$(OBJEXT) \
        $(OUTPRE)decrypt.$(OBJEXT)              \
@@ -99,6 +101,7 @@ SRCS=\
        $(srcdir)/cksumtype_to_string.c \
        $(srcdir)/cksumtypes.c          \
        $(srcdir)/coll_proof_cksum.c    \
+       $(srcdir)/combine_keys.c        \
        $(srcdir)/crypto_libinit.c      \
        $(srcdir)/default_state.c \
        $(srcdir)/decrypt.c             \
@@ -348,6 +351,12 @@ coll_proof_cksum.so coll_proof_cksum.po $(OUTPRE)coll_proof_cksum.$(OBJEXT): col
   $(COM_ERR_DEPS) $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
   $(SRCTOP)/include/krb5/kdb.h $(BUILDTOP)/include/profile.h \
   cksumtypes.h
+combine_keys.so combine_keys.po $(OUTPRE)combine_keys.$(OBJEXT): combine_keys.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(BUILDTOP)/include/profile.h \
+  etypes.h $(srcdir)/dk/dk.h
 crypto_libinit.so crypto_libinit.po $(OUTPRE)crypto_libinit.$(OBJEXT): crypto_libinit.c \
   crypto_libinit.h
 default_state.so default_state.po $(OUTPRE)default_state.$(OBJEXT): default_state.c $(SRCTOP)/include/k5-int.h \
diff --git a/src/lib/crypto/combine_keys.c b/src/lib/crypto/combine_keys.c
new file mode 100644 (file)
index 0000000..472c07e
--- /dev/null
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c) 2002 Naval Research Laboratory (NRL/CCS)
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the software,
+ * derivative works or modified versions, and any portions thereof.
+ * 
+ * NRL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION AND
+ * DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Key combination function.
+ *
+ * If Key1 and Key2 are two keys to be combined, the algorithm to combine
+ * them is as follows.
+ *
+ * Definitions:
+ *
+ * k-truncate is defined as truncating to the key size the input.
+ *
+ * DR is defined as the generate "random" data from a key
+ * (defined in crypto draft)
+ *
+ * DK is defined as the key derivation function (krb5_derive_key())
+ *
+ * (note: | means "concatenate")
+ *
+ * Combine key algorithm:
+ *
+ * R1 = DR(Key1, n-fold(Key2)) [ Output is length of Key1 ]
+ * R2 = DR(Key2, n-fold(Key1)) [ Output is length of Key2 ]
+ *
+ * rnd = n-fold(R1 | R2) [ Note: output size of nfold must be appropriately
+ *                        sized for random-to-key function ]
+ * tkey = random-to-key(rnd)
+ * Combine-Key(Key1, Key2) = DK(tkey, CombineConstant)
+ *
+ * CombineConstant is defined as the byte string:
+ *
+ * { 0x63 0x6f 0x6d 0x62 0x69 0x6e 0x65 }, which corresponds to the
+ * ASCII encoding of the string "combine"
+ */
+
+#include "k5-int.h"
+#include "etypes.h"
+#include "dk.h"
+
+static krb5_error_code dr
+(const struct krb5_enc_provider *enc, const krb5_keyblock *inkey,
+               unsigned char *outdata, const krb5_data *in_constant);
+
+krb5_error_code KRB5_CALLCONV krb5int_c_combine_keys
+(krb5_context context, krb5_keyblock *key1, krb5_keyblock *key2, krb5_keyblock *outkey)
+{
+    unsigned char *r1, *r2, *combined, *rnd, *output;
+    size_t keybytes, keylength;
+    const struct krb5_enc_provider *enc;
+    krb5_data input, randbits;
+    krb5_keyblock tkey;
+    krb5_error_code ret;
+    int i, myalloc = 0;
+
+    if (key1->length != key2->length || key1->enctype != key2->enctype)
+       return (KRB5_CRYPTO_INTERNAL);
+
+    /*
+     * Find our encryption algorithm
+     */
+
+    for (i = 0; i < krb5_enctypes_length; i++) {
+       if (krb5_enctypes_list[i].etype == key1->enctype)
+           break;
+    }
+
+    if (i == krb5_enctypes_length)
+       return (KRB5_BAD_ENCTYPE);
+
+    enc = krb5_enctypes_list[i].enc;
+
+    (*(enc->keysize))(&keybytes, &keylength);
+
+    /*
+     * Allocate and set up buffers
+     */
+
+    if ((r1 = (unsigned char *) malloc(keybytes)) == NULL)
+       return (ENOMEM);
+
+    if ((r2 = (unsigned char *) malloc(keybytes)) == NULL) {
+       free(r1);
+       return (ENOMEM);
+    }
+
+    if ((rnd = (unsigned char *) malloc(keybytes)) == NULL) {
+       free(r1);
+       free(r2);
+       return (ENOMEM);
+    }
+
+    if ((combined = (unsigned char *) malloc(keybytes * 2)) == NULL) {
+       free(r1);
+       free(r2);
+       free(rnd);
+       return (ENOMEM);
+    }
+
+    if ((output = (unsigned char *) malloc(keylength)) == NULL) {
+       free(r1);
+       free(r2);
+       free(rnd);
+       free(combined);
+       return (ENOMEM);
+    }
+
+    /*
+     * Get R1 and R2 (by running the input keys through the DR algorithm.
+     * Note this is most of derive-key, but not all.
+     */
+
+    input.length = key2->length;
+    input.data = (char *) key2->contents;
+    if ((ret = dr(enc, key1, r1, &input)))
+       goto cleanup;
+
+#if 0
+    {
+       int i;
+       printf("R1 =");
+       for (i = 0; i < keybytes; i++)
+           printf(" %02x", (unsigned char) r1[i]);
+       printf("\n");
+    }
+#endif
+
+    input.length = key1->length;
+    input.data = (char *) key1->contents;
+    if ((ret = dr(enc, key2, r2, &input)))
+       goto cleanup;
+
+#if 0
+    {
+       int i;
+       printf("R2 =");
+       for (i = 0; i < keybytes; i++)
+           printf(" %02x", (unsigned char) r2[i]);
+       printf("\n");
+    }
+#endif
+
+    /*
+     * Concatenate the two keys together, and then run them through
+     * n-fold to reduce them to a length appropriate for the random-to-key
+     * operation.  Note here that krb5_nfold() takes sizes in bits, hence
+     * the multiply by 8.
+     */
+
+    memcpy(combined, r1, keybytes);
+    memcpy(combined + keybytes, r2, keybytes);
+
+    krb5_nfold((keybytes * 2) * 8, combined, keybytes * 8, rnd);
+
+#if 0
+    {
+       int i;
+       printf("rnd =");
+       for (i = 0; i < keybytes; i++)
+           printf(" %02x", (unsigned char) rnd[i]);
+       printf("\n");
+    }
+#endif
+
+    /*
+     * Run the "random" bits through random-to-key to produce a encryption
+     * key.
+     */
+
+    randbits.length = keybytes;
+    randbits.data = (char *) rnd;
+    tkey.length = keylength;
+    tkey.contents = output;
+
+    if ((ret = (*(enc->make_key))(&randbits, &tkey)))
+       goto cleanup;
+
+#if 0
+    {
+       int i;
+       printf("tkey =");
+       for (i = 0; i < tkey.length; i++)
+           printf(" %02x", (unsigned char) tkey.contents[i]);
+       printf("\n");
+    }
+#endif
+
+    /*
+     * Run through derive-key one more time to produce the final key.
+     * Note that the input to derive-key is the ASCII string "combine".
+     */
+
+    input.length = 7; /* Note; change this if string length changes */
+    input.data = "combine";
+
+    /*
+     * Just FYI: _if_ we have space here in the key, then simply use it
+     * without modification.  But if the key is blank (no allocated storage)
+     * then allocate some memory for it.  This allows programs to use one of
+     * the existing keys as the output key, _or_ pass in a blank keyblock
+     * for us to allocate.  It's easier for us to allocate it since we already
+     * know the crypto library internals
+     */
+
+    if (outkey->length == 0 || outkey->contents == NULL) {
+       outkey->contents = (krb5_octet *) malloc(keylength);
+       if (!outkey->contents) {
+           ret = ENOMEM;
+           goto cleanup;
+       }
+       outkey->length = keylength;
+       outkey->enctype = key1->enctype;
+       myalloc = 1;
+    }
+
+    if ((ret = krb5_derive_key(enc, &tkey, outkey, &input))) {
+       if (myalloc) {
+           free(outkey->contents);
+           outkey->contents = NULL;
+       }
+       goto cleanup;
+    }
+
+#if 0
+    {
+       int i;
+       printf("output =");
+       for (i = 0; i < outkey->length; i++)
+           printf(" %02x", (unsigned char) outkey->contents[i]);
+       printf("\n");
+    }
+#endif
+
+    ret = 0;
+
+cleanup:
+    memset(r1, 0, keylength);
+    memset(r2, 0, keylength);
+    memset(rnd, 0, keybytes);
+    memset(combined, 0, keylength * 2);
+    memset(output, 0, keylength);
+
+    free(r1);
+    free(r2);
+    free(rnd);
+    free(combined);
+    free(output);
+
+    return (ret);
+}
+
+/*
+ * Our DR function; mostly taken from derive.c
+ */
+
+static krb5_error_code dr
+(const struct krb5_enc_provider *enc, const krb5_keyblock *inkey, unsigned char *out, const krb5_data *in_constant)
+{
+    size_t blocksize, keybytes, keylength, n;
+    unsigned char *inblockdata, *outblockdata;
+    krb5_data inblock, outblock;
+
+    (*(enc->block_size))(&blocksize);
+    (*(enc->keysize))(&keybytes, &keylength);
+
+    /* allocate and set up buffers */
+
+    if ((inblockdata = (unsigned char *) malloc(blocksize)) == NULL)
+       return(ENOMEM);
+
+    if ((outblockdata = (unsigned char *) malloc(blocksize)) == NULL) {
+       free(inblockdata);
+       return(ENOMEM);
+    }
+
+    inblock.data = (char *) inblockdata;
+    inblock.length = blocksize;
+
+    outblock.data = (char *) outblockdata;
+    outblock.length = blocksize;
+
+    /* initialize the input block */
+
+    if (in_constant->length == inblock.length) {
+       memcpy(inblock.data, in_constant->data, inblock.length);
+    } else {
+       krb5_nfold(in_constant->length*8, (unsigned char *) in_constant->data,
+                  inblock.length*8, (unsigned char *) inblock.data);
+    }
+
+    /* loop encrypting the blocks until enough key bytes are generated */
+
+    n = 0;
+    while (n < keybytes) {
+       (*(enc->encrypt))(inkey, 0, &inblock, &outblock);
+
+       if ((keybytes - n) <= outblock.length) {
+           memcpy(out+n, outblock.data, (keybytes - n));
+           break;
+       }
+
+       memcpy(out+n, outblock.data, outblock.length);
+       memcpy(inblock.data, outblock.data, outblock.length);
+       n += outblock.length;
+    }
+
+    /* clean memory, free resources and exit */
+
+    memset(inblockdata, 0, blocksize);
+    memset(outblockdata, 0, blocksize);
+
+    free(outblockdata);
+    free(inblockdata);
+
+    return(0);
+}
+
index ed71c85b6cc578c2889bf6c5d89cba066c21dff5..577429d7e0c94b87c93b51053916ead032ea384b 100644 (file)
@@ -1,3 +1,10 @@
+2002-10-24  Ken Hornstein  <kenh@cmf.nrl.navy.mil>
+
+       * KRB5-asn.py, asn1_k_decode.c, asn1_k_decode.h, asn1_k_encode.c,
+       asn1_k_encode.h, krb5_decode.c, krb5_encode.c: New functions,
+       prototypes, and ASN.1 definitions for the new hardware
+       preauthentication protocol.
+
 2002-07-02  Sam Hartman  <hartmans@mit.edu>
 
        * asn1_encode.h: Document asn1_encode_enumerated
index 365debcf82777bf2fc97a816adc76f518bb94a8e..867ac677171dcb009fc17f2201bba7e7f0f5801a 100644 (file)
@@ -368,13 +368,32 @@ PA-SAM-CHALLENGE ::= SEQUENCE {
     sam-cksum[9]                Checksum OPTIONAL
 }
 
--- these are [0].. [2] in the draft
-SAMFlags ::= BIT STRING {
-    use-sad-as-key(0),
-    send-encrypted-sad(1),
-    must-pk-encrypt-sad(2)
+PA-SAM-CHALLENGE-2 ::= SEQUENCE {
+    sam-body[0]                 PA-SAM-CHALLENGE-2-BODY,
+    sam-cksum[1]                SEQUENCE (1..MAX) OF Checksum,
+    ...
+}
+
+PA-SAM-CHALLENGE-2-BODY ::= SEQUENCE {
+    sam-type[0]                 INTEGER,
+    sam-flags[1]                SAMFlags,
+    sam-type-name[2]            GeneralString OPTIONAL,
+    sam-track-id[3]             GeneralString OPTIONAL,
+    sam-challenge-label[4]      GeneralString OPTIONAL,
+    sam-challenge[5]            GeneralString OPTIONAL,
+    sam-response-prompt[6]      GeneralString OPTIONAL,
+    sam-pk-for-sad[7]           EncryptionKey OPTIONAL,
+    sam-nonce[8]                INTEGER,
+    sam-etype[9]               INTEGER,
+    ...
 }
 
+-- these are [0].. [2] in the draft
+SAMFlags ::= BIT STRING (SIZE (32..MAX))
+    -- use-sad-as-key(0)
+    -- send-encrypted-sad(1)
+    -- must-pk-encrypt-sad(2)
+
 PA-SAM-RESPONSE ::= SEQUENCE {
     sam-type[0]                 INTEGER,
     sam-flags[1]                SAMFlags,
@@ -388,6 +407,16 @@ PA-SAM-RESPONSE ::= SEQUENCE {
     sam-patimestamp[6]          KerberosTime OPTIONAL
 }
 
+PA-SAM-RESPONSE-2 ::= SEQUENCE {
+    sam-type[0]                 INTEGER,
+    sam-flags[1]                SAMFlags,
+    sam-track-id[2]             GeneralString OPTIONAL,
+    sam-enc-nonce-or-sad[3]     EncryptedData,
+                                   -- PA-ENC-SAM-RESPONSE-ENC
+    sam-nonce[4]                INTEGER,
+    ...
+}
+
 PA-ENC-SAM-KEY ::= SEQUENCE {
              sam-key[0]                 EncryptionKey
 }
@@ -398,4 +427,10 @@ PA-ENC-SAM-RESPONSE-ENC ::= SEQUENCE {
      sam-usec[2]                INTEGER OPTIONAL,
      sam-passcode[3]            GeneralString OPTIONAL
 }
+
+PA-ENC-SAM-RESPONSE-ENC-2 ::= SEQUENCE {
+     sam-nonce[0]               INTEGER,
+     sam-sad[1]                 GeneralString OPTIONAL,
+     ...
+}
 END
index 78d7e47258cf958f0898f454ed4f75fe0aaaa151..f075db09425298b610412e008b0a08ac029a9cae 100644 (file)
@@ -734,6 +734,11 @@ asn1_error_code asn1_decode_sequence_of_enctype(asn1buf *buf, int *num, krb5_enc
   cleanup();
 }
 
+asn1_error_code asn1_decode_sequence_of_checksum(asn1buf *buf, krb5_checksum ***val)
+{
+  decode_array_body(krb5_checksum, asn1_decode_checksum);
+}
+
 asn1_error_code asn1_decode_etype_info_entry(asn1buf *buf, krb5_etype_info_entry *val)
 {
   setup();
@@ -807,6 +812,48 @@ asn1_error_code asn1_decode_sam_challenge(asn1buf *buf, krb5_sam_challenge *val)
   }
   cleanup();
 }
+asn1_error_code asn1_decode_sam_challenge_2(asn1buf *buf, krb5_sam_challenge_2 *val)
+{
+  setup();
+  { char *save, *end;
+    begin_structure();
+    if (tagnum != 0) return ASN1_MISSING_FIELD;
+    if (asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED) 
+      return ASN1_BAD_ID;
+    save = subbuf.next;
+    { sequence_of(&subbuf);
+      end_sequence_of(&subbuf);
+    }
+    end = subbuf.next;
+    if ((val->sam_challenge_2_body.data = (char *) malloc(end - save)) == NULL)
+      return ENOMEM;
+    val->sam_challenge_2_body.length = end - save;
+    memcpy(val->sam_challenge_2_body.data, save, end - save);
+    next_tag();
+    get_field(val->sam_cksum, 1, asn1_decode_sequence_of_checksum);
+    end_structure();
+  }
+  cleanup();
+}
+asn1_error_code asn1_decode_sam_challenge_2_body(asn1buf *buf, krb5_sam_challenge_2_body *val)
+{
+  setup();
+  { begin_structure();
+    get_field(val->sam_type,0,asn1_decode_int32);
+    get_field(val->sam_flags,1,asn1_decode_sam_flags);
+    opt_string(val->sam_type_name,2,asn1_decode_charstring);
+    opt_string(val->sam_track_id,3,asn1_decode_charstring);
+    opt_string(val->sam_challenge_label,4,asn1_decode_charstring);
+    opt_string(val->sam_challenge,5,asn1_decode_charstring);
+    opt_string(val->sam_response_prompt,6,asn1_decode_charstring);
+    opt_string(val->sam_pk_for_sad,7,asn1_decode_charstring);
+    get_field(val->sam_nonce,8,asn1_decode_int32);
+    get_field(val->sam_etype, 9, asn1_decode_int32);
+    end_structure();
+    val->magic = KV5M_SAM_CHALLENGE;
+  }
+  cleanup();
+}
 asn1_error_code asn1_decode_enc_sam_key(asn1buf *buf, krb5_sam_key *val)
 {
   setup();
@@ -833,6 +880,18 @@ asn1_error_code asn1_decode_enc_sam_response_enc(asn1buf *buf, krb5_enc_sam_resp
   cleanup();
 }
 
+asn1_error_code asn1_decode_enc_sam_response_enc_2(asn1buf *buf, krb5_enc_sam_response_enc_2 *val)
+{
+  setup();
+  { begin_structure();
+    get_field(val->sam_nonce,0,asn1_decode_int32);
+    opt_string(val->sam_sad,1,asn1_decode_charstring);
+    end_structure();
+    val->magic = KV5M_ENC_SAM_RESPONSE_ENC_2;
+  }
+  cleanup();
+}
+
 #define opt_encfield(fld,tag,fn) \
     if(tagnum == tag){ \
       get_field(fld,tag,fn); } \
@@ -861,6 +920,21 @@ asn1_error_code asn1_decode_sam_response(asn1buf *buf, krb5_sam_response *val)
   cleanup();
 }
 
+asn1_error_code asn1_decode_sam_response_2(asn1buf *buf, krb5_sam_response_2 *val)
+{
+  setup();
+  { begin_structure();
+    get_field(val->sam_type,0,asn1_decode_int32);
+    get_field(val->sam_flags,1,asn1_decode_sam_flags);
+    opt_string(val->sam_track_id,2,asn1_decode_charstring);
+    get_field(val->sam_enc_nonce_or_sad,3,asn1_decode_encrypted_data);
+    get_field(val->sam_nonce,4,asn1_decode_int32);
+    end_structure();
+    val->magic = KV5M_SAM_RESPONSE;
+  }
+  cleanup();
+}
+
 
 asn1_error_code asn1_decode_predicted_sam_response(asn1buf *buf, krb5_predicted_sam_response *val)
 {
index 22b2d2b5e2dabf94241ecb9e7a95a9cd85470db1..8f8b0bcffe98451f81bf52d465688ff2c26a351d 100644 (file)
@@ -143,12 +143,20 @@ asn1_error_code asn1_decode_etype_info_entry
        (asn1buf *buf, krb5_etype_info_entry *val);
 asn1_error_code asn1_decode_sam_challenge
        (asn1buf *buf, krb5_sam_challenge *val);
+asn1_error_code asn1_decode_sam_challenge_2
+       (asn1buf *buf, krb5_sam_challenge_2 *val);
+asn1_error_code asn1_decode_sam_challenge_2_body
+       (asn1buf *buf, krb5_sam_challenge_2_body *val);
 asn1_error_code asn1_decode_enc_sam_key
        (asn1buf *buf, krb5_sam_key *val);
 asn1_error_code asn1_decode_enc_sam_response_enc
        (asn1buf *buf, krb5_enc_sam_response_enc *val);
+asn1_error_code asn1_decode_enc_sam_response_enc_2
+       (asn1buf *buf, krb5_enc_sam_response_enc_2 *val);
 asn1_error_code asn1_decode_sam_response
        (asn1buf *buf, krb5_sam_response *val);
+asn1_error_code asn1_decode_sam_response_2
+       (asn1buf *buf, krb5_sam_response_2 *val);
 asn1_error_code asn1_decode_predicted_sam_response
        (asn1buf *buf, krb5_predicted_sam_response *val);
 
@@ -169,6 +177,9 @@ asn1_error_code asn1_decode_last_req
 asn1_error_code asn1_decode_sequence_of_enctype
        (asn1buf *buf, int *num, krb5_enctype **val);
 
+asn1_error_code asn1_decode_sequence_of_checksum
+       (asn1buf *buf, krb5_checksum ***val);
+
 asn1_error_code asn1_decode_sequence_of_passwdsequence
        (asn1buf *buf, passwd_phrase_element ***val);
 
index 2177b527ebd28438cb9428c239d804f566327608..111695b3ae18c9ec7273689e4d5dfdacac47a17d 100644 (file)
@@ -371,6 +371,24 @@ asn1_error_code asn1_encode_enc_kdc_rep_part(asn1buf *buf, const krb5_enc_kdc_re
   asn1_cleanup();
 }
 
+asn1_error_code asn1_encode_sequence_of_checksum(asn1buf *buf, const krb5_checksum ** val, unsigned int *retlen)
+{
+  asn1_setup();
+  int i;
+
+  if(val == NULL) return ASN1_MISSING_FIELD;
+
+  for (i=0; val[i] != NULL; i++);
+  for (i--; i>=0; i--){
+    retval = asn1_encode_checksum(buf,val[i],&length);
+    if(retval) return retval;
+    sum += length;
+  }
+  asn1_makeseq();
+
+  asn1_cleanup();
+}
+
 asn1_error_code asn1_encode_kdc_req_body(asn1buf *buf, const krb5_kdc_req *rep, unsigned int *retlen)
 {
   asn1_setup();
@@ -782,6 +800,45 @@ asn1_error_code asn1_encode_sam_challenge(asn1buf *buf, const krb5_sam_challenge
   asn1_cleanup();
 }
 
+asn1_error_code asn1_encode_sam_challenge_2(asn1buf *buf, const krb5_sam_challenge_2 *val, unsigned int *retlen)
+{
+  asn1_setup();
+  if ( (!val) || (!val->sam_cksum) || (!val->sam_cksum[0]))
+      return ASN1_MISSING_FIELD;
+
+  asn1_addfield((const krb5_checksum **) val->sam_cksum, 1, asn1_encode_sequence_of_checksum);
+  asn1buf_insert_octetstring(buf, val->sam_challenge_2_body.length,
+                            (unsigned char *)val->sam_challenge_2_body.data);
+  sum += val->sam_challenge_2_body.length;
+  retval = asn1_make_etag(buf, CONTEXT_SPECIFIC, 0,
+                         val->sam_challenge_2_body.length, &length);
+  if(retval) return retval;
+  sum += length;
+
+  asn1_makeseq();
+  asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_sam_challenge_2_body(asn1buf *buf, const krb5_sam_challenge_2_body *val, unsigned int *retlen)
+{
+  asn1_setup();
+
+  asn1_addfield(val->sam_etype, 9, asn1_encode_integer);
+  asn1_addfield(val->sam_nonce,8,asn1_encode_integer);
+  add_optstring(val->sam_pk_for_sad,7,asn1_encode_charstring);
+  add_optstring(val->sam_response_prompt,6,asn1_encode_charstring);
+  add_optstring(val->sam_challenge,5,asn1_encode_charstring);
+  add_optstring(val->sam_challenge_label,4,asn1_encode_charstring);
+  add_optstring(val->sam_track_id,3,asn1_encode_charstring);
+  add_optstring(val->sam_type_name,2,asn1_encode_charstring);
+
+  asn1_addfield(val->sam_flags,1,asn1_encode_sam_flags);
+  asn1_addfield(val->sam_type,0,asn1_encode_integer);
+
+  asn1_makeseq();
+  asn1_cleanup();
+}
+
 asn1_error_code asn1_encode_sam_key(asn1buf *buf, const krb5_sam_key *val, unsigned int *retlen)
 {
   asn1_setup();
@@ -806,6 +863,17 @@ asn1_error_code asn1_encode_enc_sam_response_enc(asn1buf *buf, const krb5_enc_sa
   asn1_cleanup();
 }
 
+asn1_error_code asn1_encode_enc_sam_response_enc_2(asn1buf *buf, const krb5_enc_sam_response_enc_2 *val, unsigned int *retlen)
+{
+  asn1_setup();
+  add_optstring(val->sam_sad,1,asn1_encode_charstring);
+  asn1_addfield(val->sam_nonce,0,asn1_encode_integer);
+
+  asn1_makeseq();
+
+  asn1_cleanup();
+}
+
 asn1_error_code asn1_encode_sam_response(asn1buf *buf, const krb5_sam_response *val, unsigned int *retlen)
 {
   asn1_setup();
@@ -826,6 +894,21 @@ asn1_error_code asn1_encode_sam_response(asn1buf *buf, const krb5_sam_response *
   asn1_cleanup();
 }
 
+asn1_error_code asn1_encode_sam_response_2(asn1buf *buf, const krb5_sam_response_2 *val, unsigned int *retlen)
+{
+  asn1_setup();
+
+  asn1_addfield(val->sam_nonce,4,asn1_encode_integer);
+  asn1_addfield(&(val->sam_enc_nonce_or_sad),3,asn1_encode_encrypted_data);
+  add_optstring(val->sam_track_id,2,asn1_encode_charstring);
+  asn1_addfield(val->sam_flags,1,asn1_encode_sam_flags);
+  asn1_addfield(val->sam_type,0,asn1_encode_integer);
+
+  asn1_makeseq();
+
+  asn1_cleanup();
+}
+
 asn1_error_code asn1_encode_predicted_sam_response(asn1buf *buf, const krb5_predicted_sam_response *val, unsigned int *retlen)
 {
   asn1_setup();
index 6d3633513fb237d0b8a5dd28ddbcb412c14031c0..5914e0981795815b4b1f0fc90560d8c2d4b2ecee 100644 (file)
@@ -69,6 +69,7 @@
     asn1_encode_sequence_of_pa_data
     asn1_encode_sequence_of_ticket
     asn1_encode_sequence_of_enctype
+    asn1_encode_sequence_of_checksum
     asn1_encode_sequence_of_krb_cred_info
 */
 
@@ -184,6 +185,9 @@ asn1_error_code asn1_encode_sequence_of_enctype
                   const int len, const krb5_enctype *val,
                   unsigned int *retlen);
 
+asn1_error_code asn1_encode_sequence_of_checksum
+       (asn1buf *buf, const krb5_checksum **val, unsigned int *retlen);
+
 asn1_error_code asn1_encode_kdc_req
        (int msg_type,
                   asn1buf *buf,
@@ -234,6 +238,13 @@ asn1_error_code asn1_encode_sam_flags
 asn1_error_code asn1_encode_sam_challenge
        (asn1buf *buf, const krb5_sam_challenge * val, unsigned int *retlen);
 
+asn1_error_code asn1_encode_sam_challenge_2
+       (asn1buf *buf, const krb5_sam_challenge_2 * val, unsigned int *retlen);
+
+asn1_error_code asn1_encode_sam_challenge_2_body
+       (asn1buf *buf, const krb5_sam_challenge_2_body * val,
+                  unsigned int *retlen);
+
 asn1_error_code asn1_encode_sam_key
        (asn1buf *buf, const krb5_sam_key *val, unsigned int *retlen);
 
@@ -241,9 +252,16 @@ asn1_error_code asn1_encode_enc_sam_response_enc
        (asn1buf *buf, const krb5_enc_sam_response_enc *val,
                   unsigned int *retlen);
 
+asn1_error_code asn1_encode_enc_sam_response_enc_2
+       (asn1buf *buf, const krb5_enc_sam_response_enc_2 *val,
+                  unsigned int *retlen);
+
 asn1_error_code asn1_encode_sam_response
        (asn1buf *buf, const krb5_sam_response *val, unsigned int *retlen);
 
+asn1_error_code asn1_encode_sam_response_2
+       (asn1buf *buf, const krb5_sam_response_2 *val, unsigned int *retlen);
+
 asn1_error_code asn1_encode_predicted_sam_response
        (asn1buf *buf, const krb5_predicted_sam_response *val, 
                   unsigned int *retlen);
index cb6e8f252ed7fccd965f0b72d81f104760aa98dc..f2d916527c03c1d3d149f97b4ebd9e3d6deabf64 100644 (file)
@@ -761,6 +761,28 @@ krb5_error_code decode_krb5_sam_challenge(const krb5_data *code, krb5_sam_challe
   cleanup(free);
 }
 
+krb5_error_code decode_krb5_sam_challenge_2(const krb5_data *code, krb5_sam_challenge_2 **rep)
+{
+  setup_buf_only();
+  alloc_field(*rep,krb5_sam_challenge_2);
+
+  retval = asn1_decode_sam_challenge_2(&buf,*rep);
+  if(retval) clean_return(retval);
+
+  cleanup(free);
+}
+
+krb5_error_code decode_krb5_sam_challenge_2_body(const krb5_data *code, krb5_sam_challenge_2_body **rep)
+{
+  setup_buf_only();
+  alloc_field(*rep, krb5_sam_challenge_2_body);
+
+  retval = asn1_decode_sam_challenge_2_body(&buf, *rep);
+  if(retval) clean_return(retval);
+
+  cleanup(free);
+}
+
 krb5_error_code decode_krb5_enc_sam_key(const krb5_data *code, krb5_sam_key **rep)
 {
   setup_buf_only();
@@ -783,6 +805,17 @@ krb5_error_code decode_krb5_enc_sam_response_enc(const krb5_data *code, krb5_enc
   cleanup(free);
 }
 
+krb5_error_code decode_krb5_enc_sam_response_enc_2(const krb5_data *code, krb5_enc_sam_response_enc_2 **rep)
+{
+  setup_buf_only();
+  alloc_field(*rep,krb5_enc_sam_response_enc_2);
+
+  retval = asn1_decode_enc_sam_response_enc_2(&buf,*rep);
+  if(retval) clean_return(retval);
+
+  cleanup(free);
+}
+
 krb5_error_code decode_krb5_sam_response(const krb5_data *code, krb5_sam_response **rep)
 {
   setup_buf_only();
@@ -794,6 +827,17 @@ krb5_error_code decode_krb5_sam_response(const krb5_data *code, krb5_sam_respons
   cleanup(free);
 }
 
+krb5_error_code decode_krb5_sam_response_2(const krb5_data *code, krb5_sam_response_2 **rep)
+{
+  setup_buf_only();
+  alloc_field(*rep,krb5_sam_response_2);
+
+  retval = asn1_decode_sam_response_2(&buf,*rep);
+  if(retval) clean_return(retval);
+
+  cleanup(free);
+}
+
 krb5_error_code decode_krb5_predicted_sam_response(const krb5_data *code, krb5_predicted_sam_response **rep)
 {
   setup_buf_only();            /* preallocated */
index 133f98f3a51b45df6409e051e73b18c58b3f37a7..2a4f7bb14089dea251fade673403adcc4a31b350 100644 (file)
@@ -751,6 +751,24 @@ krb5_error_code encode_krb5_sam_challenge(const krb5_sam_challenge *rep, krb5_da
   krb5_cleanup();
 }
 
+krb5_error_code encode_krb5_sam_challenge_2(const krb5_sam_challenge_2 *rep, krb5_data **code)
+{
+  krb5_setup();
+  retval = asn1_encode_sam_challenge_2(buf,rep,&length);
+  if(retval) return retval;
+  sum += length;
+  krb5_cleanup();
+}
+
+krb5_error_code encode_krb5_sam_challenge_2_body(const krb5_sam_challenge_2_body *rep, krb5_data **code)
+{
+  krb5_setup();
+  retval = asn1_encode_sam_challenge_2_body(buf,rep,&length);
+  if(retval) return retval;
+  sum += length;
+  krb5_cleanup();
+}
+
 krb5_error_code encode_krb5_sam_key(const krb5_sam_key *rep, krb5_data **code)
 {
   krb5_setup();
@@ -769,6 +787,15 @@ krb5_error_code encode_krb5_enc_sam_response_enc(const krb5_enc_sam_response_enc
   krb5_cleanup();
 }
 
+krb5_error_code encode_krb5_enc_sam_response_enc_2(const krb5_enc_sam_response_enc_2 *rep, krb5_data **code)
+{
+  krb5_setup();
+  retval = asn1_encode_enc_sam_response_enc_2(buf,rep,&length);
+  if(retval) return retval;
+  sum += length;
+  krb5_cleanup();
+}
+
 krb5_error_code encode_krb5_sam_response(const krb5_sam_response *rep, krb5_data **code)
 {
   krb5_setup();
@@ -778,6 +805,15 @@ krb5_error_code encode_krb5_sam_response(const krb5_sam_response *rep, krb5_data
   krb5_cleanup();
 }
 
+krb5_error_code encode_krb5_sam_response_2(const krb5_sam_response_2 *rep, krb5_data **code)
+{
+  krb5_setup();
+  retval = asn1_encode_sam_response_2(buf,rep,&length);
+  if(retval) return retval;
+  sum += length;
+  krb5_cleanup();
+}
+
 krb5_error_code encode_krb5_predicted_sam_response(const krb5_predicted_sam_response *rep, krb5_data **code)
 {
   krb5_setup();
index 90dfda0a7e27234b5951592acc384c876c8f1ef9..0f90a66e76e2f26f88e764144c4bfb39bbee11d2 100644 (file)
@@ -1,3 +1,11 @@
+2002-10-24  Ken Hornstein  <kenh@cmf.nrl.navy.mil
+
+       * kv5m_err.et: Add magic numbers for new hardware preauth structures.
+
+       * krb5_err.et (KRB5_SAM_INVALID_ETYPE, KRB5_SAM_NO_CHECKSUM,
+       KRB5_SAM_BAD_CHECKSUM): New error codes for the new hardware
+       preauthentication code.
+
 2002-09-02  Ken Raeburn  <raeburn@mit.edu>
 
        * init_ets.c (krb5_init_ets, krb5_free_ets): Use prototype style
index 7fb927944a6823d1bc50397f201c0b2654e0da07..08e5cdd2b3f8806f35b99a4f37ec48ad3c22c7f5 100644 (file)
@@ -310,6 +310,9 @@ error_code KRB5_GET_IN_TKT_LOOP,  "Looping detected inside krb5_get_in_tkt"
 error_code KRB5_CONFIG_NODEFREALM,     "Configuration file does not specify default realm"
 
 error_code KRB5_SAM_UNSUPPORTED,  "Bad SAM flags in obtain_sam_padata"
+error_code KRB5_SAM_INVALID_ETYPE,     "Invalid encryption type in SAM challenge"
+error_code KRB5_SAM_NO_CHECKSUM,       "Missing checksum in SAM challenge"
+error_code KRB5_SAM_BAD_CHECKSUM,      "Bad checksum in SAM challenge"
 error_code KRB5_KT_NAME_TOOLONG,       "Keytab name too long"
 error_code KRB5_KT_KVNONOTFOUND,       "Key version number for principal in key table is incorrect"
 error_code KRB5_APPL_EXPIRED,  "This application has expired"
index eb6bdd870cbc669e2951530c5c5dbbbfb20cab0b..1b79de252a132102aa2fddc16a07e63706194e46 100644 (file)
@@ -76,9 +76,12 @@ error_code KV5M_RCACHE,              "Bad magic number for krb5_rcache structure"
 error_code KV5M_CCACHE,                "Bad magic number for krb5_ccache structure"
 error_code KV5M_PREAUTH_OPS,   "Bad magic number for krb5_preauth_ops"
 error_code KV5M_SAM_CHALLENGE, "Bad magic number for krb5_sam_challenge"
+error_code KV5M_SAM_CHALLENGE_2,       "Bad magic number for krb5_sam_challenge_2"
 error_code KV5M_SAM_KEY,       "Bad magic number for krb5_sam_key"
 error_code KV5M_ENC_SAM_RESPONSE_ENC,  "Bad magic number for krb5_enc_sam_response_enc"
+error_code KV5M_ENC_SAM_RESPONSE_ENC_2,        "Bad magic number for krb5_enc_sam_response_enc"
 error_code KV5M_SAM_RESPONSE,  "Bad magic number for krb5_sam_response"
+error_code KV5M_SAM_RESPONSE_2,        "Bad magic number for krb5_sam_response 2"
 error_code KV5M_PREDICTED_SAM_RESPONSE,        "Bad magic number for krb5_predicted_sam_response"
 error_code KV5M_PASSWD_PHRASE_ELEMENT, "Bad magic number for passwd_phrase_element"
 error_code KV5M_GSS_OID,       "Bad magic number for GSSAPI OID"
index a651f24972efd63f5b111815c40a7d0769a4269f..4665b65252f5a68c36e1c6294b5e6e90c8feff3d 100644 (file)
@@ -1,3 +1,14 @@
+2002-10-24  Ken Hornstein  <kenh@cmf.nrl.navy.mil>
+
+       * gic_pwd.c (krb5_get_init_creds_password): Exit out of the loop
+       when preauth fails.
+
+       * kfree.c: Add various free functions for new preauth
+       data structures.
+
+       * preauth2.c (pa_sam): Fix up support for "old" hardware preauth.
+       Also implement new hardware preauth in pa_sam2().
+
 2002-10-23  Ken Hornstein  <kenh@cmf.nrl.navy.mil>
 
        * gic_pwd.c (krb5_get_init_creds_password): Fix bug in previous
index 287ee7b7bc3b99dd4f943278b82ed3a71a291ddd..7bc4d5a46dc07af5363a1d396511bcecfce4d3a9 100644 (file)
@@ -130,9 +130,10 @@ krb5_get_init_creds_password(krb5_context context, krb5_creds *creds, krb5_princ
       goto cleanup;
 
    /* If all the kdc's are unavailable, or if the error was due to a
-      user interrupt, fail */
+      user interrupt, or preauth errored out, fail */
 
    if ((ret == KRB5_KDC_UNREACH) ||
+       (ret == KRB5_PREAUTH_FAILED) ||
        (ret == KRB5_LIBOS_PWDINTR) ||
           (ret == KRB5_REALM_CANT_RESOLVE))
       goto cleanup;
index 60a3c61821242651850e53f0b66d6ca8f886bcf2..46d485d32085e4a026ae01bd33e3826a1f889e2f 100644 (file)
@@ -513,6 +513,15 @@ krb5_free_sam_challenge(krb5_context ctx, krb5_sam_challenge *sc)
     krb5_xfree(sc);
 }
 
+void KRB5_CALLCONV
+krb5_free_sam_challenge_2(krb5_context ctx, krb5_sam_challenge_2 *sc2)
+{
+    if (!sc2)
+       return;
+    krb5_free_sam_challenge_2_contents(ctx, sc2);
+    krb5_xfree(sc2);
+}
+
 void KRB5_CALLCONV
 krb5_free_sam_challenge_contents(krb5_context ctx, krb5_sam_challenge *sc)
 {
@@ -536,6 +545,57 @@ krb5_free_sam_challenge_contents(krb5_context ctx, krb5_sam_challenge *sc)
     }
 }
 
+void KRB5_CALLCONV
+krb5_free_sam_challenge_2_contents(krb5_context ctx,
+                                  krb5_sam_challenge_2 *sc2)
+{
+    krb5_checksum **cksump;
+
+    if (!sc2)
+       return;
+    if (sc2->sam_challenge_2_body.data)
+       krb5_free_data_contents(ctx, &sc2->sam_challenge_2_body);
+    if (sc2->sam_cksum) {
+       cksump = sc2->sam_cksum;
+       while (*cksump) {
+           krb5_free_checksum(ctx, *cksump);
+           cksump++;
+       }
+       krb5_xfree(sc2->sam_cksum);
+       sc2->sam_cksum = 0;
+    }
+}
+
+void KRB5_CALLCONV
+krb5_free_sam_challenge_2_body(krb5_context ctx,
+                              krb5_sam_challenge_2_body *sc2)
+{
+    if (!sc2)
+       return;
+    krb5_free_sam_challenge_2_body_contents(ctx, sc2);
+    krb5_xfree(sc2);
+}
+
+void KRB5_CALLCONV
+krb5_free_sam_challenge_2_body_contents(krb5_context ctx,
+                                       krb5_sam_challenge_2_body *sc2)
+{
+    if (!sc2)
+       return;
+    if (sc2->sam_type_name.data) 
+       krb5_free_data_contents(ctx, &sc2->sam_type_name);
+    if (sc2->sam_track_id.data)
+       krb5_free_data_contents(ctx, &sc2->sam_track_id);
+    if (sc2->sam_challenge_label.data)
+       krb5_free_data_contents(ctx, &sc2->sam_challenge_label);
+    if (sc2->sam_challenge.data)
+       krb5_free_data_contents(ctx, &sc2->sam_challenge);
+    if (sc2->sam_response_prompt.data)
+       krb5_free_data_contents(ctx, &sc2->sam_response_prompt);
+    if (sc2->sam_pk_for_sad.data)
+       krb5_free_data_contents(ctx, &sc2->sam_pk_for_sad);
+}
+
 void KRB5_CALLCONV
 krb5_free_sam_response(krb5_context ctx, krb5_sam_response *sr)
 {
@@ -545,6 +605,15 @@ krb5_free_sam_response(krb5_context ctx, krb5_sam_response *sr)
     krb5_xfree(sr);
 }
 
+void KRB5_CALLCONV
+krb5_free_sam_response_2(krb5_context ctx, krb5_sam_response_2 *sr2)
+{
+    if (!sr2)
+       return;
+    krb5_free_sam_response_2_contents(ctx, sr2);
+    krb5_xfree(sr2);
+}
+
 void KRB5_CALLCONV
 krb5_free_sam_response_contents(krb5_context ctx, krb5_sam_response *sr)
 {
@@ -558,6 +627,17 @@ krb5_free_sam_response_contents(krb5_context ctx, krb5_sam_response *sr)
        krb5_free_data_contents(ctx, &sr->sam_enc_nonce_or_ts.ciphertext);
 }
 
+void KRB5_CALLCONV
+krb5_free_sam_response_2_contents(krb5_context ctx, krb5_sam_response_2 *sr2)
+{
+    if (!sr2)
+       return;
+    if (sr2->sam_track_id.data)
+       krb5_free_data_contents(ctx, &sr2->sam_track_id);
+    if (sr2->sam_enc_nonce_or_sad.ciphertext.data)
+       krb5_free_data_contents(ctx, &sr2->sam_enc_nonce_or_sad.ciphertext);
+}
+
 void KRB5_CALLCONV
 krb5_free_predicted_sam_response(krb5_context ctx,
                                 krb5_predicted_sam_response *psr)
@@ -594,6 +674,16 @@ krb5_free_enc_sam_response_enc(krb5_context ctx,
     krb5_xfree(esre);
 }
 
+void KRB5_CALLCONV 
+krb5_free_enc_sam_response_enc_2(krb5_context ctx,
+                                krb5_enc_sam_response_enc_2 *esre2)
+{
+    if (!esre2)
+       return;
+    krb5_free_enc_sam_response_enc_2_contents(ctx, esre2);
+    krb5_xfree(esre2);
+}
+
 void KRB5_CALLCONV
 krb5_free_enc_sam_response_enc_contents(krb5_context ctx,
                               krb5_enc_sam_response_enc *esre)
@@ -604,6 +694,16 @@ krb5_free_enc_sam_response_enc_contents(krb5_context ctx,
        krb5_free_data_contents(ctx, &esre->sam_sad);
 }
 
+void KRB5_CALLCONV
+krb5_free_enc_sam_response_enc_2_contents(krb5_context ctx,
+                                         krb5_enc_sam_response_enc_2 *esre2)
+{
+    if (!esre2)
+       return;
+    if (esre2->sam_sad.data)
+       krb5_free_data_contents(ctx, &esre2->sam_sad);
+}
+
 void KRB5_CALLCONV
 krb5_free_pa_enc_ts(krb5_context ctx, krb5_pa_enc_ts *pa_enc_ts)
 {
index 9ee5cdfc5453ec39731eb9f387734da8f8f1ea29..1e07c18c2efa6ba10fe98f3eb35b68f31b1516b4 100644 (file)
@@ -268,6 +268,24 @@ krb5_error_code pa_sam(krb5_context context,
        return(KRB5_SAM_UNSUPPORTED);
     }
 
+    /* If we need the password from the user (USE_SAD_AS_KEY not set), */
+    /* then get it here.  Exception for "old" KDCs with CryptoCard     */
+    /* support which uses the USE_SAD_AS_KEY flag, but still needs pwd */ 
+
+    if (!(sam_challenge->sam_flags & KRB5_SAM_USE_SAD_AS_KEY) ||
+       (sam_challenge->sam_type == PA_SAM_TYPE_CRYPTOCARD)) {
+
+       /* etype has either been set by caller or by KRB5_PADATA_ETYPE_INFO */
+       /* message from the KDC.  If it is not set, pick an enctype that we */
+       /* think the KDC will have for us.                                  */
+
+       if (etype && *etype == 0)
+          *etype = ENCTYPE_DES_CBC_CRC;
+
+       if (ret = (gak_fct)(context, request->client, *etype, prompter,
+                       prompter_data, salt, as_key, gak_data))
+          return(ret);
+    }
     sprintf(name, "%.*s",
            SAMDATA(sam_challenge->sam_type_name, "SAM Authentication",
                    sizeof(name) - 1));
@@ -288,7 +306,7 @@ krb5_error_code pa_sam(krb5_context context,
     response_data.length = sizeof(response);
 
     kprompt.prompt = prompt;
-    kprompt.hidden = sam_challenge->sam_challenge.length?0:1;
+    kprompt.hidden = 1;
     kprompt.reply = &response_data;
     prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
 
@@ -317,6 +335,11 @@ krb5_error_code pa_sam(krb5_context context,
     /* XXX What if more than one flag is set?  */
     if (sam_challenge->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD) {
 
+       /* Most of this should be taken care of before we get here.  We */
+       /* will need the user's password and as_key to encrypt the SAD  */
+       /* and we want to preserve ordering of user prompts (first      */
+       /* password, then SAM data) so that user's won't be confused.   */
+
        if (as_key->length) {
            krb5_free_keyblock_contents(context, as_key);
            as_key->length = 0;
@@ -443,6 +466,332 @@ krb5_error_code pa_sam(krb5_context context,
     return(0);
 }
 
+static
+krb5_error_code pa_sam_2(krb5_context context,
+                               krb5_kdc_req *request,
+                               krb5_pa_data *in_padata,
+                               krb5_pa_data **out_padata,
+                               krb5_data *salt,
+                               krb5_enctype *etype,
+                               krb5_keyblock *as_key,
+                               krb5_prompter_fct prompter,
+                               void *prompter_data,
+                               krb5_gic_get_as_key_fct gak_fct,
+                               void *gak_data) {
+
+   krb5_error_code retval;
+   krb5_sam_challenge_2 *sc2 = NULL;
+   krb5_sam_challenge_2_body *sc2b = NULL;
+   krb5_data tmp_data;
+   krb5_data response_data;
+   char name[100], banner[100], prompt[100], response[100];
+   krb5_prompt kprompt;
+   krb5_prompt_type prompt_type;
+   krb5_data defsalt;
+   krb5_checksum **cksum;
+   krb5_data *scratch = NULL;
+   krb5_boolean valid_cksum = 0;
+   krb5_enc_sam_response_enc_2 enc_sam_response_enc_2;
+   krb5_sam_response_2 sr2;
+   krb5_pa_data *sam_padata;
+
+   if (prompter == NULL)
+       return KRB5_LIBOS_CANTREADPWD;
+
+   tmp_data.length = in_padata->length;
+   tmp_data.data = (char *)in_padata->contents;
+
+   if (retval = decode_krb5_sam_challenge_2(&tmp_data, &sc2))
+       return(retval);
+
+   retval = decode_krb5_sam_challenge_2_body(&sc2->sam_challenge_2_body, &sc2b);
+
+   if (retval)
+       return(retval);
+
+   if (!sc2->sam_cksum || ! *sc2->sam_cksum) {
+       krb5_free_sam_challenge_2(context, sc2);
+       krb5_free_sam_challenge_2_body(context, sc2b);
+       return(KRB5_SAM_NO_CHECKSUM);
+   }
+
+   if (sc2b->sam_flags & KRB5_SAM_MUST_PK_ENCRYPT_SAD) {
+       krb5_free_sam_challenge_2(context, sc2);
+       krb5_free_sam_challenge_2_body(context, sc2b);
+       return(KRB5_SAM_UNSUPPORTED);
+   }
+
+   if (!valid_enctype(sc2b->sam_etype)) {
+       krb5_free_sam_challenge_2(context, sc2);
+       krb5_free_sam_challenge_2_body(context, sc2b);
+       return(KRB5_SAM_INVALID_ETYPE);
+   }
+
+   /* All of the above error checks are KDC-specific, that is, they    */
+   /* assume a failure in the KDC reply.  By returning anything other  */
+   /* than KRB5_KDC_UNREACH, KRB5_PREAUTH_FAILED,              */
+   /* KRB5_LIBOS_PWDINTR, or KRB5_REALM_CANT_RESOLVE, the client will  */
+   /* most likely go on to try the AS_REQ against master KDC           */
+
+   if (!(sc2b->sam_flags & KRB5_SAM_USE_SAD_AS_KEY)) {
+       /* We will need the password to obtain the key used for */
+       /* the checksum, and encryption of the sam_response.    */
+       /* Go ahead and get it now, preserving the ordering of  */
+       /* prompts for the user.                                */
+
+       retval = (gak_fct)(context, request->client,
+                       sc2b->sam_etype, prompter,
+                       prompter_data, salt, as_key, gak_data);
+       if (retval) {
+          krb5_free_sam_challenge_2(context, sc2);
+          krb5_free_sam_challenge_2_body(context, sc2b);
+          return(retval);
+       }
+   }
+
+   sprintf(name, "%.*s",
+       SAMDATA(sc2b->sam_type_name, "SAM Authentication",
+       sizeof(name) - 1));
+
+   sprintf(banner, "%.*s",
+       SAMDATA(sc2b->sam_challenge_label,
+       sam_challenge_banner(sc2b->sam_type),
+       sizeof(banner)-1));
+
+   sprintf(prompt, "%s%.*s%s%.*s",
+       sc2b->sam_challenge.length?"Challenge is [":"",
+       SAMDATA(sc2b->sam_challenge, "", 20),
+       sc2b->sam_challenge.length?"], ":"",
+       SAMDATA(sc2b->sam_response_prompt, "passcode", 55));
+
+   response_data.data = response;
+   response_data.length = sizeof(response);
+   kprompt.prompt = prompt;
+   kprompt.hidden = 1;
+   kprompt.reply = &response_data;
+
+   prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
+   krb5int_set_prompt_types(context, &prompt_type);
+
+   if (retval = ((*prompter)(context, prompter_data, name,
+                               banner, 1, &kprompt))) {
+       krb5_free_sam_challenge_2(context, sc2);
+       krb5_free_sam_challenge_2_body(context, sc2b);
+       krb5int_set_prompt_types(context, 0);
+       return(retval);
+   }
+
+   krb5int_set_prompt_types(context, (krb5_prompt_type *)NULL);
+
+   /* Generate salt used by string_to_key() */
+   if ((salt->length == -1) && (salt->data == NULL)) {
+       if (retval = krb5_principal2salt(context, request->client, &defsalt)) {
+          krb5_free_sam_challenge_2(context, sc2);
+          krb5_free_sam_challenge_2_body(context, sc2b);
+          return(retval);
+       }
+       salt = &defsalt;
+   } else {
+       defsalt.length = 0;
+   }
+
+   /* Get encryption key to be used for checksum and sam_response */
+   if (!(sc2b->sam_flags & KRB5_SAM_USE_SAD_AS_KEY)) {
+       /* as_key = string_to_key(password) */
+       int i;
+
+       if (as_key->length) {
+          krb5_free_keyblock_contents(context, as_key);
+          as_key->length = 0;
+       }
+
+       /* generate a key using the supplied password */
+       retval = krb5_c_string_to_key(context, sc2b->sam_etype,
+                                   (krb5_data *)gak_data, salt, as_key);
+
+       if (retval) {
+          krb5_free_sam_challenge_2(context, sc2);
+          krb5_free_sam_challenge_2_body(context, sc2b);
+          if (defsalt.length) krb5_xfree(defsalt.data);
+          return(retval);
+       }
+
+       if (!(sc2b->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD)) {
+          /* as_key = combine_key (as_key, string_to_key(SAD)) */
+          krb5_keyblock tmp_kb;
+
+          retval = krb5_c_string_to_key(context, sc2b->sam_etype,
+                               &response_data, salt, &tmp_kb);
+
+          if (retval) {
+               krb5_free_sam_challenge_2(context, sc2);
+               krb5_free_sam_challenge_2_body(context, sc2b);
+               if (defsalt.length) krb5_xfree(defsalt.data);
+               return(retval);
+          }
+
+          /* This should be a call to the crypto library some day */
+          /* key types should already match the sam_etype */
+          retval = krb5int_c_combine_keys(context, as_key, &tmp_kb, as_key);
+
+          if (retval) {
+               krb5_free_sam_challenge_2(context, sc2);
+               krb5_free_sam_challenge_2_body(context, sc2b);
+               if (defsalt.length) krb5_xfree(defsalt.data);
+               return(retval);
+          }
+          krb5_free_keyblock_contents(context, &tmp_kb);
+       }
+
+       if (defsalt.length)
+          krb5_xfree(defsalt.data);
+
+   } else {
+       /* as_key = string_to_key(SAD) */
+
+       if (as_key->length) {
+          krb5_free_keyblock_contents(context, as_key);
+          as_key->length = 0;
+       }
+
+       /* generate a key using the supplied password */
+       retval = krb5_c_string_to_key(context, sc2b->sam_etype,
+                               &response_data, salt, as_key);
+
+       if (defsalt.length)
+          krb5_xfree(defsalt.data);
+
+       if (retval) {
+          krb5_free_sam_challenge_2(context, sc2);
+          krb5_free_sam_challenge_2_body(context, sc2b);
+          return(retval);
+       }
+   }
+
+   /* Now we have a key, verify the checksum on the sam_challenge */
+
+   cksum = sc2->sam_cksum;
+   
+   while (*cksum) {
+       /* Check this cksum */
+       retval = krb5_c_verify_checksum(context, as_key,
+                       KRB5_KEYUSAGE_PA_SAM_CHALLENGE_CKSUM,
+                       &sc2->sam_challenge_2_body,
+                       *cksum, &valid_cksum);
+       if (retval) {
+          krb5_free_data(context, scratch);
+          krb5_free_sam_challenge_2(context, sc2);
+          krb5_free_sam_challenge_2_body(context, sc2b);
+          return(retval);
+       }
+       if (valid_cksum)
+          break;
+       cksum++;
+   }
+
+   if (!valid_cksum) {
+
+       /* If KRB5_SAM_SEND_ENCRYPTED_SAD is set, then password is only */
+       /* source for checksum key.  Therefore, a bad checksum means a  */
+       /* bad password.  Don't give that direct feedback to someone    */
+       /* trying to brute-force passwords.                             */
+
+       if (!(sc2b->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD))
+       krb5_free_sam_challenge_2(context, sc2);
+       krb5_free_sam_challenge_2_body(context, sc2b);
+       /*
+        * Note: We return AP_ERR_BAD_INTEGRITY so upper-level applications
+        * can interpret that as "password incorrect", which is probably
+        * the best error we can return in this situation.
+        */
+       return(KRB5KRB_AP_ERR_BAD_INTEGRITY);
+   }
+   /* fill in enc_sam_response_enc_2 */
+   enc_sam_response_enc_2.magic = KV5M_ENC_SAM_RESPONSE_ENC_2;
+   enc_sam_response_enc_2.sam_nonce = sc2b->sam_nonce;
+   if (sc2b->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD) {
+       enc_sam_response_enc_2.sam_sad = response_data;
+   } else {
+       enc_sam_response_enc_2.sam_sad.data = NULL;
+       enc_sam_response_enc_2.sam_sad.length = 0;
+   }
+
+   /* encode and encrypt enc_sam_response_enc_2 with as_key */
+   retval = encode_krb5_enc_sam_response_enc_2(&enc_sam_response_enc_2,
+               &scratch);
+   if (retval) {
+       krb5_free_sam_challenge_2(context, sc2);
+       krb5_free_sam_challenge_2_body(context, sc2b);
+       return(retval);
+   }
+
+   /* Fill in sam_response_2 */
+   memset(&sr2, 0, sizeof(sr2));
+   sr2.sam_type = sc2b->sam_type;
+   sr2.sam_flags = sc2b->sam_flags;
+   sr2.sam_track_id = sc2b->sam_track_id;
+   sr2.sam_nonce = sc2b->sam_nonce;
+
+   /* Now take care of sr2.sam_enc_nonce_or_sad by encrypting encoded  */
+   /* enc_sam_response_enc_2 from above */
+
+   retval = krb5_c_encrypt_length(context, as_key->enctype, scratch->length,
+               (unsigned int *) &sr2.sam_enc_nonce_or_sad.ciphertext.length);
+   if (retval) {
+       krb5_free_sam_challenge_2(context, sc2);
+       krb5_free_sam_challenge_2_body(context, sc2b);
+       return(retval);
+   }
+
+   sr2.sam_enc_nonce_or_sad.ciphertext.data =
+       (char *)malloc(sr2.sam_enc_nonce_or_sad.ciphertext.length);
+
+   if (!sr2.sam_enc_nonce_or_sad.ciphertext.data) {
+       krb5_free_sam_challenge_2(context, sc2);
+       krb5_free_sam_challenge_2_body(context, sc2b);
+       return(ENOMEM);
+   }
+
+   retval = krb5_c_encrypt(context, as_key, KRB5_KEYUSAGE_PA_SAM_RESPONSE,
+               NULL, scratch, &sr2.sam_enc_nonce_or_sad);
+   if (retval) {
+       krb5_free_sam_challenge_2(context, sc2);
+       krb5_free_sam_challenge_2_body(context, sc2b);
+       krb5_free_data(context, scratch);
+       krb5_free_data_contents(context, &sr2.sam_enc_nonce_or_sad.ciphertext);
+       return(retval);
+   }
+   krb5_free_data(context, scratch);
+   scratch = NULL;
+
+   /* Encode the sam_response_2 */
+   retval = encode_krb5_sam_response_2(&sr2, &scratch);
+   krb5_free_sam_challenge_2(context, sc2);
+   krb5_free_sam_challenge_2_body(context, sc2b);
+   krb5_free_data_contents(context, &sr2.sam_enc_nonce_or_sad.ciphertext);
+
+   if (retval) {
+       return (retval);
+   }
+
+   /* Almost there, just need to make padata !  */
+   sam_padata = malloc(sizeof(krb5_pa_data));
+   if (sam_padata == NULL) {
+       krb5_free_data(context, scratch);
+       return(ENOMEM);
+   }
+
+   sam_padata->magic = KV5M_PA_DATA;
+   sam_padata->pa_type = KRB5_PADATA_SAM_RESPONSE_2;
+   sam_padata->length = scratch->length;
+   sam_padata->contents = (krb5_octet *) scratch->data;
+
+   *out_padata = sam_padata;
+
+   return(0);
+}
+
 static pa_types_t pa_types[] = {
     {
        KRB5_PADATA_PW_SALT,
@@ -459,6 +808,11 @@ static pa_types_t pa_types[] = {
        pa_enc_timestamp,
        PA_REAL,
     },
+    {
+       KRB5_PADATA_SAM_CHALLENGE_2,
+       pa_sam_2,
+       PA_REAL,
+    },
     {
        KRB5_PADATA_SAM_CHALLENGE,
        pa_sam,