Krb5 ticket support for server-to-server and localauth
authorChaskiel Grundman <cg2v@andrew.cmu.edu>
Sun, 28 Apr 2013 18:27:47 +0000 (14:27 -0400)
committerSimon Wilkinson <sxw@your-file-system.com>
Sat, 13 Jul 2013 10:29:19 +0000 (11:29 +0100)
Create a tkt_MakeTicket5 that creates a native krb5 rxkad token with
a service key supported by the rfc3961 library (session keys must be
provided as DES)

Update GenericAuth to search for rxkad_krb5 keys and call tkt_MakeTicket5
if it finds any.

Change-Id: Ia9543fdcffcbf3ca899a003908662ff3daa8ee07

src/auth/authcon.c
src/libafsrpc/afsrpc.def
src/libafsrpc/libafsrpc.la.sym
src/rxkad/liboafs_rxkad.la.sym
src/rxkad/rxkad_prototypes.h
src/rxkad/ticket5.c

index 8976947..fe54bfd 100644 (file)
@@ -19,6 +19,7 @@
 
 #define HC_DEPRECATED
 #include <hcrypto/des.h>
+#include <hcrypto/rand.h>
 
 #include <rx/rxkad.h>
 #include <rx/rx.h>
@@ -98,35 +99,72 @@ GenericAuth(struct afsconf_dir *adir,
            afs_int32 *aindex,
            rxkad_level enclevel)
 {
-    char tbuffer[256];
+#ifdef UKERNEL
+    return QuickAuth(astr, aindex);
+#else
+    int enctype_preflist[]={18, 17, 23, 16, 0};
+    char tbuffer[512];
     struct ktc_encryptionKey key, session;
     struct rx_securityClass *tclass;
     afs_int32 kvno;
     afs_int32 ticketLen;
     afs_int32 code;
+    int use_krb5=0;
+    struct afsconf_typedKey *kobj;
+    struct rx_opaque *keymat;
+    int *et;
 
     /* first, find the right key and kvno to use */
-    code = afsconf_GetLatestKey(adir, &kvno, &key);
-    if (code) {
-       return QuickAuth(astr, aindex);
+
+    et = enctype_preflist;
+    while(*et != 0) {
+       code = afsconf_GetLatestKeyByTypes(adir, afsconf_rxkad_krb5, *et,
+                                          &kobj);
+       if (code == 0) {
+           afsconf_keyType tktype;
+           int tenctype;
+           afsconf_typedKey_values(kobj, &tktype, &kvno, &tenctype, &keymat);
+           RAND_add(keymat->val, keymat->len, 0.0);
+           use_krb5 = 1;
+           break;
+       }
+       et++;
     }
 
-    /* next create random session key, using key for seed to good random */
-    DES_init_random_number_generator((DES_cblock *) &key);
+    if (use_krb5 == 0) {
+       code = afsconf_GetLatestKey(adir, &kvno, &key);
+       if (code) {
+           return QuickAuth(astr, aindex);
+       }
+       /* next create random session key, using key for seed to good random */
+       DES_init_random_number_generator((DES_cblock *) &key);
+    }
     code = DES_new_random_key((DES_cblock *) &session);
     if (code) {
+       if (use_krb5)
+           afsconf_typedKey_put(&kobj);
        return QuickAuth(astr, aindex);
     }
 
-    /* now create the actual ticket */
-    ticketLen = sizeof(tbuffer);
-    memset(tbuffer, '\0', sizeof(tbuffer));
-    code =
-       tkt_MakeTicket(tbuffer, &ticketLen, &key, AUTH_SUPERUSER, "", "", 0,
-                      0xffffffff, &session, 0, "afs", "");
-    /* parms were buffer, ticketlen, key to seal ticket with, principal
-     * name, instance and cell, start time, end time, session key to seal
-     * in ticket, inet host, server name and server instance */
+    if (use_krb5) {
+       ticketLen = sizeof(tbuffer);
+       memset(tbuffer, '\0', sizeof(tbuffer));
+       code =
+           tkt_MakeTicket5(tbuffer, &ticketLen, *et, &kvno, keymat->val,
+                           keymat->len, AUTH_SUPERUSER, "", "", 0, 0x7fffffff,
+                           &session, "afs", "");
+       afsconf_typedKey_put(&kobj);
+    } else {
+       /* now create the actual ticket */
+       ticketLen = sizeof(tbuffer);
+       memset(tbuffer, '\0', sizeof(tbuffer));
+       code =
+           tkt_MakeTicket(tbuffer, &ticketLen, &key, AUTH_SUPERUSER, "", "", 0,
+                          0xffffffff, &session, 0, "afs", "");
+       /* parms were buffer, ticketlen, key to seal ticket with, principal
+        * name, instance and cell, start time, end time, session key to seal
+        * in ticket, inet host, server name and server instance */
+    }
     if (code) {
        return QuickAuth(astr, aindex);
     }
@@ -141,6 +179,7 @@ GenericAuth(struct afsconf_dir *adir,
     *astr = tclass;
     *aindex = RX_SECIDX_KAD;
     return 0;
+#endif
 }
 
 /* build a fake ticket for 'afs' using keys from adir, returning an
index 5d22669..5772ad0 100755 (executable)
@@ -341,6 +341,7 @@ EXPORTS
        rx_GetNetworkError                      @346
         afs_set_com_err_hook                    @347
        rxkad_NewKrb5ServerSecurityObject       @348
+       tkt_MakeTicket5                         @349
 
 ; for performance testing
         rx_TSFPQGlobSize                        @2001 DATA
index b5c0571..d1b9c46 100644 (file)
@@ -165,6 +165,7 @@ time_to_life
 tkt_CheckTimes
 tkt_DecodeTicket
 tkt_MakeTicket
+tkt_MakeTicket5
 xdr_afsUUID
 xdr_afs_int32
 xdr_afs_int64
index acf9f3c..4933f9b 100644 (file)
@@ -7,3 +7,4 @@ rxkad_NewServerSecurityObject
 time_to_life
 tkt_CheckTimes
 tkt_MakeTicket
+tkt_MakeTicket5
index e73f1d1..525b9d9 100644 (file)
@@ -162,5 +162,10 @@ extern int tkt_DecodeTicket5(char *ticket, afs_int32 ticket_len,
                             char *inst, char *cell, struct ktc_encryptionKey *session_key,
                             afs_int32 * host, afs_uint32 * start,
                             afs_uint32 * end, afs_int32 disableDotCheck);
+extern int tkt_MakeTicket5(char *ticket, int *ticketLen, int enctype, int *kvno,
+                          void *key, size_t keylen,
+                          char *name, char *inst, char *cell, afs_uint32 start,
+                          afs_uint32 end, struct ktc_encryptionKey *sessionKey,
+                          char *sname, char *sinst);
 
 #endif
index 5ce4c7a..1dad81a 100644 (file)
@@ -536,3 +536,99 @@ krb5_des_decrypt(struct ktc_encryptionKey *key, int etype, void *in,
 
     return ret;
 }
+
+
+int
+tkt_MakeTicket5(char *ticket, int *ticketLen, int enctype, int *kvno,
+               void *key, size_t keylen,
+               char *name, char *inst, char *cell, afs_uint32 start,
+               afs_uint32 end, struct ktc_encryptionKey *sessionKey,
+               char *sname, char *sinst)
+{
+    EncTicketPart data;
+    EncryptedData encdata;
+    char *buf, *encodebuf;
+    size_t encodelen, allocsiz;
+    heim_general_string carray[2];
+    int code;
+    krb5_context context;
+    krb5_keyblock kb;
+    krb5_crypto cr;
+    krb5_data encrypted;
+    size_t tl;
+
+    memset(&encrypted, 0, sizeof(encrypted));
+    cr = NULL;
+    context = NULL;
+    buf = NULL;
+    memset(&kb, 0, sizeof(kb));
+    memset(&data, 0, sizeof(data));
+
+    data.flags.transited_policy_checked = 1;
+    data.key.keytype=ETYPE_DES_CBC_CRC;
+    data.key.keyvalue.data=sessionKey->data;
+    data.key.keyvalue.length=8;
+    data.crealm=cell;
+    carray[0]=name;
+    carray[1]=inst;
+    data.cname.name_type=KRB5_NT_PRINCIPAL;
+    data.cname.name_string.val=carray;
+    data.cname.name_string.len=inst[0]?2:1;
+    data.authtime=start;
+    data.endtime=end;
+
+    allocsiz = length_EncTicketPart(&data);
+    buf = rxi_Alloc(allocsiz);
+    encodelen = allocsiz;
+    /* encode function wants pointer to end of buffer */
+    encodebuf = buf + allocsiz - 1;
+    code = encode_EncTicketPart(encodebuf, allocsiz, &data, &encodelen);
+
+    if (code)
+       goto cleanup;
+    code = krb5_init_context(&context);
+    if (code)
+       goto cleanup;
+    code = krb5_keyblock_init(context, enctype, key, keylen, &kb);
+    if (code)
+       goto cleanup;
+    code = krb5_crypto_init(context, &kb, enctype, &cr);
+    if (code)
+       goto cleanup;
+    code = krb5_encrypt(context, cr, KRB5_KU_TICKET, buf,
+                       encodelen, &encrypted);
+    if (code)
+       goto cleanup;
+    memset(&encdata, 0, sizeof(encdata));
+    encdata.etype=enctype;
+    encdata.kvno=kvno;
+    encdata.cipher.data=encrypted.data;
+    encdata.cipher.length=encrypted.length;
+
+    if (length_EncryptedData(&encdata) > *ticketLen) {
+       code = RXKADTICKETLEN;
+       goto cleanup;
+    }
+    tl=*ticketLen;
+    code = encode_EncryptedData(ticket + *ticketLen - 1, *ticketLen, &encdata, &tl);
+    if (code == 0) {
+       *kvno=RXKAD_TKT_TYPE_KERBEROS_V5_ENCPART_ONLY;
+       /*
+        * encode function fills in from the end. move data to
+        * beginning of buffer
+        */
+       memmove(ticket, ticket + *ticketLen - tl, tl);
+       *ticketLen=tl;
+    }
+
+cleanup:
+    krb5_data_free(&encrypted);
+    if (cr != NULL)
+       krb5_crypto_destroy(context, cr);
+    krb5_free_keyblock_contents(context, &kb);
+    krb5_free_context(context);
+    rxi_Free(buf, allocsiz);
+    if ((code && 0xFFFFFF00) == ERROR_TABLE_BASE_asn1)
+       return RXKADINCONSISTENCY;
+    return code;
+}