+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
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"
(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.
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 *);
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 **);
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
#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
#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
+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.
cksumtype_to_string.o \
cksumtypes.o \
coll_proof_cksum.o \
+ combine_keys.o \
crypto_libinit.o \
default_state.o \
decrypt.o \
$(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) \
$(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 \
$(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 \
--- /dev/null
+/*
+ * 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);
+}
+
+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
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,
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
}
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
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();
}
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();
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); } \
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)
{
(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);
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);
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();
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();
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();
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();
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
*/
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,
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);
(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);
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();
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();
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 */
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();
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();
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();
+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
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"
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"
+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
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;
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)
{
}
}
+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)
{
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)
{
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)
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)
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)
{
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));
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;
/* 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;
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,
pa_enc_timestamp,
PA_REAL,
},
+ {
+ KRB5_PADATA_SAM_CHALLENGE_2,
+ pa_sam_2,
+ PA_REAL,
+ },
{
KRB5_PADATA_SAM_CHALLENGE,
pa_sam,