Index: libabac/abac.c
===================================================================
--- libabac/abac.c	(revision b7e77dfa7e38d121dc6bbbab89456e4af6479d04)
+++ libabac/abac.c	(revision d2b198c77ec345f4a2f4f7c24f7d28230cb6faad)
@@ -75,5 +75,5 @@
     );
 
-    dup->keymap = abac_keyid_map_dup(ctx->keymap);
+    dup->keymap = abac_keyid_map_clone(ctx->keymap);
     return dup;
 }
@@ -122,5 +122,5 @@
     assert(ctx != NULL); assert(filename != NULL);
 
-    ret = abac_verifier_load_attribute_cert_file(ctx->id_certs, filename, cred_list);
+    ret = abac_verifier_load_attribute_cert_file(ctx->id_certs, filename, cred_list, ctx->keymap);
 
     if (ret == ABAC_CERT_SUCCESS) {
@@ -148,5 +148,5 @@
     assert(ctx != NULL);
 
-    ret = abac_verifier_load_attribute_cert_chunk(ctx->id_certs, cert_chunk, cred_list);
+    ret = abac_verifier_load_attribute_cert_chunk(ctx->id_certs, cert_chunk, cred_list, ctx->keymap);
     if (ret == ABAC_CERT_SUCCESS) {
         int size = abac_list_size(cred_list);
@@ -325,4 +325,24 @@
 }
 
+/*
+ * Add a nickname to the context.  The keyid must be known to the context.  If
+ * the nickname is in use, it is disambiguated.  Call abac_context_expand_key
+ * to see the assigned name if that is required.  Existing nickname for keyid
+ * is overwritten.  Returns true if the change was successful.
+ */
+int abac_context_set_nickname(abac_context_t *ctxt, char *key, char*nick) {
+    char *p = NULL;
+
+    if ( !ctxt->keymap) return 0;
+    /* Make sure we know the key.  Free the returned nickname */
+    if ( !(p = abac_keyid_map_key_to_nickname(ctxt->keymap, key))) return 0;
+    else free(p);
+
+    abac_keyid_map_remove_keyid(ctxt->keymap, key);
+    return abac_keyid_map_add_nickname(ctxt->keymap, key, nick);
+}
+
+
+
 /**
  * A NULL-terminated array of all the principals in the context.
Index: libabac/abac.h
===================================================================
--- libabac/abac.h	(revision b7e77dfa7e38d121dc6bbbab89456e4af6479d04)
+++ libabac/abac.h	(revision d2b198c77ec345f4a2f4f7c24f7d28230cb6faad)
@@ -250,4 +250,5 @@
 // get the validity period of the attribute cert
 int abac_attribute_validity(abac_attribute_t *attr, struct tm *not_before, struct tm *not_after);
+abac_keyid_map_t *abac_attribute_get_keyid_map(abac_attribute_t *);
 
 // return the principal from an attribute's role string
@@ -263,4 +264,5 @@
 abac_keyid_map_t *abac_keyid_map_new();
 abac_keyid_map_t *abac_keyid_map_dup(abac_keyid_map_t *);
+abac_keyid_map_t *abac_keyid_map_clone(abac_keyid_map_t *);
 void abac_keyid_map_free(abac_keyid_map_t *m); 
 char *abac_keyid_map_key_to_nickname(abac_keyid_map_t *m, char *key);
@@ -268,4 +270,6 @@
 int abac_keyid_map_remove_keyid(abac_keyid_map_t *m, char *key); 
 int abac_keyid_map_add_nickname(abac_keyid_map_t *m, char *key, char *nick);
+void abac_keyid_map_merge(abac_keyid_map_t *d, abac_keyid_map_t *s, 
+	int overwrite);
 char *abac_keyid_map_expand_key(abac_keyid_map_t *m, char *s); 
 char *abac_keyid_map_expand_nickname(abac_keyid_map_t *m, char *s);
Index: libabac/abac_attribute.c
===================================================================
--- libabac/abac_attribute.c	(revision b7e77dfa7e38d121dc6bbbab89456e4af6479d04)
+++ libabac/abac_attribute.c	(revision d2b198c77ec345f4a2f4f7c24f7d28230cb6faad)
@@ -37,4 +37,5 @@
     char **tail_strings;
     char *output_format;
+    abac_keyid_map_t *keymap;
 
     abac_chunk_t cert; // the XML chunk
@@ -100,4 +101,5 @@
     attr->ntails = 0;
     attr->tail_strings = NULL;
+    attr->keymap = NULL;
 
     attr->output_format = abac_xstrdup(DEFAULT_OUTPUT_FORMAT);
@@ -294,10 +296,10 @@
 
 
-static abac_attribute_t *_load_attr(abac_list_t *id_certs,char *rstring, char *xml)
+static abac_attribute_t *_load_attr(abac_list_t *id_certs,char *rstring, char *xml, abac_keyid_map_t *km)
 {
     /* make a copy of rle_string */
     char *role_string=abac_xstrdup(rstring);
 
-if(debug) fprintf(stderr,"loading -> %s \n", role_string);
+    if(debug) fprintf(stderr,"loading -> %s \n", role_string);
 
     char *head_tail[2];
@@ -320,4 +322,9 @@
     attr->tail_strings = NULL;
 
+    /* If there is a keymap, make a reference to it. */
+    if ( km ) attr->keymap = abac_keyid_map_dup(km);
+    else attr->keymap = NULL;
+
+
     attr->head_string = abac_xstrdup(head_tail[0]);
     do {
@@ -344,6 +351,7 @@
     char *xml=NULL;
     char *rt0=NULL;
-
-    char **rt0s=read_credential((void *)id_certs,filename, &xml);
+    abac_keyid_map_t *km = abac_keyid_map_new();
+
+    char **rt0s=read_credential((void *)id_certs,filename, &xml, km);
     if(rt0s == NULL) return alist;
     if(xml == NULL || strlen(xml)==0) return alist;
@@ -355,5 +363,5 @@
         rt0 = rt0s[i]; 
         if(rt0 == NULL) break;
-        attr=_load_attr(id_certs,rt0, xml);
+        attr=_load_attr(id_certs,rt0, xml, km);
         if(attr)
             abac_list_add(alist, attr);
@@ -361,4 +369,5 @@
         i++;
     } while (rt0s[i] !=NULL);
+    abac_keyid_map_free(km);
 
     free(rt0s);
@@ -373,7 +382,9 @@
     abac_list_t *alist=abac_list_new();
     char *xml=(char *)chunk.ptr;
+    abac_keyid_map_t *km = abac_keyid_map_new();
+
     if(chunk.len==0) return alist;
 
-    char **rt0s=get_rt0_from_xml((void *) id_certs,xml);
+    char **rt0s=get_rt0_from_xml((void *) id_certs, xml, km);
     char *rt0=NULL;
     if(rt0s==NULL) return alist;
@@ -384,5 +395,5 @@
         rt0 = rt0s[i]; 
         if(rt0 == NULL) break;
-        attr=_load_attr(id_certs,rt0, xml);
+        attr=_load_attr(id_certs,rt0, xml, km);
         if(attr)
             abac_list_add(alist, attr);
@@ -390,4 +401,5 @@
         i++;
     } while (rt0s[i] !=NULL);
+    abac_keyid_map_free(km);
 
     free(rt0s);
@@ -421,4 +433,12 @@
 
     return ABAC_SUCCESS;
+}
+
+/* return a copy of the local name mappings, if any.  The returned value is not
+ * reference counted, so callers will need to call abac_keyid_map_dup on it if
+ * they need to keep a copy of the pointer.
+ */
+abac_keyid_map_t *abac_attribute_get_keyid_map(abac_attribute_t *attr) {
+    return attr->keymap;
 }
 
@@ -441,4 +461,6 @@
     if ( attr->output_format ) 
 	free(attr->output_format);
+
+    if ( attr->keymap ) abac_keyid_map_free(attr->keymap);
 
 /* XXX this can not be free as if it is a char string
Index: libabac/abac_keyid_map.c
===================================================================
--- libabac/abac_keyid_map.c	(revision b7e77dfa7e38d121dc6bbbab89456e4af6479d04)
+++ libabac/abac_keyid_map.c	(revision d2b198c77ec345f4a2f4f7c24f7d28230cb6faad)
@@ -15,4 +15,5 @@
     abac_keyid_mapping_t *keys;
     abac_keyid_mapping_t *nicknames;
+    int refcount;
 };
 
@@ -39,8 +40,10 @@
     m->keys = NULL;
     m->nicknames = NULL;
+    m->refcount = 1;
     return m;
 }
 
-abac_keyid_map_t *abac_keyid_map_dup(abac_keyid_map_t *old) {
+/* Make a new, independent copy of the old keymap. */
+abac_keyid_map_t *abac_keyid_map_clone(abac_keyid_map_t *old) {
     abac_keyid_map_t *m = abac_xmalloc(sizeof(abac_keyid_map_t));
     abac_keyid_mapping_t *me = NULL;
@@ -48,4 +51,5 @@
     m->keys = NULL;
     m->nicknames = NULL;
+    m->refcount = 1;
 
     for ( me = old->keys; me ; me = me->hh.next) 
@@ -55,6 +59,15 @@
 }
 
+/* Add a reference to old and return it. */
+abac_keyid_map_t *abac_keyid_map_dup(abac_keyid_map_t *old) {
+    old->refcount ++;
+    return old;
+}
+
 void abac_keyid_map_free(abac_keyid_map_t *m) {
     abac_keyid_mapping_t *me = NULL;
+
+    if ( --m->refcount > 0) return;
+
     while ( (me = m->keys) ) {
 	HASH_DEL(m->keys, me);
@@ -129,4 +142,23 @@
     free(name);
     return 1;
+}
+
+void abac_keyid_map_merge(abac_keyid_map_t *dest, abac_keyid_map_t *src, 
+	int overwrite) {
+    abac_keyid_mapping_t *me = NULL;
+    if ( !dest || !src ) return;
+
+    for (me = src->keys; me; me = me->hh.next) {
+	char *n = abac_keyid_map_key_to_nickname(dest, me->key);
+	if ( n ) {
+	    free(n);
+	    if ( overwrite) {
+		abac_keyid_map_remove_keyid(dest,me->key);
+		abac_keyid_map_add_nickname(dest, me->key, me->value);
+	    }
+	} else {
+	    abac_keyid_map_add_nickname(dest, me->key, me->value);
+	}
+    }
 }
 
Index: libabac/abac_verifier.c
===================================================================
--- libabac/abac_verifier.c	(revision b7e77dfa7e38d121dc6bbbab89456e4af6479d04)
+++ libabac/abac_verifier.c	(revision d2b198c77ec345f4a2f4f7c24f7d28230cb6faad)
@@ -201,8 +201,10 @@
  * authority.
  */
-static int _load_attribute_cert(abac_list_t *id_certs,abac_attribute_t *cert, abac_credential_t **cred_ret) {
+static int _load_attribute_cert(abac_list_t *id_certs,abac_attribute_t *cert, 
+	abac_credential_t **cred_ret, abac_keyid_map_t *km) {
     abac_role_t *head_role = NULL;
     abac_role_t *tail_role = NULL;
     abac_id_cert_t *issuer=NULL;
+    abac_keyid_map_t *local_names = NULL;
     int ret;
 
@@ -256,4 +258,7 @@
         goto error;
     }
+
+    if ( (local_names = abac_attribute_get_keyid_map(cert)) && km ) 
+	abac_keyid_map_merge(km, local_names, 1);
     
     // at this point we know we have a good attribute cert
@@ -276,5 +281,6 @@
 }
 
-static int _load_attribute_certs(abac_list_t *id_certs,abac_list_t *attr_list, abac_list_t *cred_list) {
+static int _load_attribute_certs(abac_list_t *id_certs,abac_list_t *attr_list, 
+	abac_list_t *cred_list, abac_keyid_map_t *km) {
 
     int sz=abac_list_size(attr_list);
@@ -283,5 +289,5 @@
     if(sz) { 
         abac_list_foreach(attr_list, attr,
-            int ret=_load_attribute_cert(id_certs, attr, &cred_ret);
+            int ret=_load_attribute_cert(id_certs, attr, &cred_ret, km);
             if(ret==ABAC_CERT_SUCCESS) {
                 abac_list_add(cred_list, cred_ret);
@@ -295,5 +301,5 @@
  * Load an attribute cert from a file.
  */
-int abac_verifier_load_attribute_cert_file(abac_list_t *id_certs,char *filename, abac_list_t *cred_list) {
+int abac_verifier_load_attribute_cert_file(abac_list_t *id_certs,char *filename, abac_list_t *cred_list, abac_keyid_map_t *km) {
 
     // load the cert
@@ -303,5 +309,5 @@
         return ABAC_CERT_INVALID;
 
-    int ret=_load_attribute_certs(id_certs,attr_list, cred_list);
+    int ret=_load_attribute_certs(id_certs,attr_list, cred_list, km);
 
     if(ret) return ABAC_CERT_SUCCESS;
@@ -312,5 +318,5 @@
  * Load an attribute cert from a chunk.
  */
-int abac_verifier_load_attribute_cert_chunk(abac_list_t *id_certs,abac_chunk_t chunk, abac_list_t *cred_list) {
+int abac_verifier_load_attribute_cert_chunk(abac_list_t *id_certs,abac_chunk_t chunk, abac_list_t *cred_list, abac_keyid_map_t *km) {
 
     // load the cert
@@ -320,5 +326,5 @@
         return ABAC_CERT_INVALID;
 
-    int ret=_load_attribute_certs(id_certs,attr_list,cred_list);
+    int ret=_load_attribute_certs(id_certs,attr_list,cred_list, km);
 
     if(ret) return ABAC_CERT_SUCCESS;
Index: libabac/abac_verifier.h
===================================================================
--- libabac/abac_verifier.h	(revision b7e77dfa7e38d121dc6bbbab89456e4af6479d04)
+++ libabac/abac_verifier.h	(revision d2b198c77ec345f4a2f4f7c24f7d28230cb6faad)
@@ -11,6 +11,6 @@
 int abac_verifier_load_id_file(abac_list_t*,char *filename, abac_keyid_mapping_t *);
 int abac_verifier_load_id_chunk(abac_list_t *,abac_chunk_t chunk, abac_keyid_mapping_t *);
-int abac_verifier_load_attribute_cert_file(abac_list_t *,char *filename, abac_list_t *clist);
-int abac_verifier_load_attribute_cert_chunk(abac_list_t *,abac_chunk_t chunk, abac_list_t  *clist);
+int abac_verifier_load_attribute_cert_file(abac_list_t *,char *filename, abac_list_t *clist, abac_keyid_map_t *km);
+int abac_verifier_load_attribute_cert_chunk(abac_list_t *,abac_chunk_t chunk, abac_list_t  *clist, abac_keyid_map_t *km);
 
 void abac_id_cert_insert_cert(abac_list_t *, abac_id_cert_t *id_cert);
Index: libabac/abac_xml.c
===================================================================
--- libabac/abac_xml.c	(revision b7e77dfa7e38d121dc6bbbab89456e4af6479d04)
+++ libabac/abac_xml.c	(revision d2b198c77ec345f4a2f4f7c24f7d28230cb6faad)
@@ -153,6 +153,6 @@
 xmlChar *encode_rt0_xml_v10(abac_attribute_t *);
 xmlChar *encode_rt0_xml_v11(abac_attribute_t *);
-xmlChar **parse_rt0_xml_v10(xmlNodePtr);
-xmlChar **parse_rt0_xml_v11(xmlNodePtr);
+xmlChar **parse_rt0_xml_v10(xmlNodePtr, abac_keyid_map_t *);
+xmlChar **parse_rt0_xml_v11(xmlNodePtr, abac_keyid_map_t *);
 
 /* Structure that specializes XML parsing */
@@ -163,5 +163,5 @@
     xmlChar *(*rt0_to_xml)(abac_attribute_t *);
     /* Convert an rt0 element into a list of RT0 strings */
-    xmlChar **(*xml_to_rt0)(xmlNodePtr);
+    xmlChar **(*xml_to_rt0)(xmlNodePtr, abac_keyid_map_t *);
     /* The overall template to generate this version of credential */
     char *out_template;
@@ -590,5 +590,6 @@
  * return value is an array of strings, zero-terminated (like argv) that holds
  * the RT0 strings.  It is NULL on failure. */
-static xmlChar **parse_privilege(xmlDocPtr doc, void *ctxt_id_certs) {
+static xmlChar **parse_privilege(xmlDocPtr doc, void *ctxt_id_certs, 
+	abac_keyid_map_t *km) {
     xmlNodePtr root = NULL;	/* XML root node */
     xmlNodePtr node = NULL;	/* XML scratch node */
@@ -737,5 +738,5 @@
  * has no structure.
  */
-xmlChar **parse_rt0_xml_v10(xmlNodePtr n) {
+xmlChar **parse_rt0_xml_v10(xmlNodePtr n, abac_keyid_map_t *km) {
     xmlChar *txt;
     xmlChar **rv = NULL;
@@ -816,11 +817,26 @@
  * </tail>
  * becomes P.r1.r2.
+ * In addition, if there is a mnemonic in the ABACPrincipal field, add it to
+ * the keyid_map (if there is a map).
  */
-static xmlChar *term_copy(xmlNodePtr n, xmlChar *dest) {
+static xmlChar *term_copy(xmlNodePtr n, xmlChar *dest, abac_keyid_map_t *km) {
     xmlNodePtr p = get_direct_child(n, "ABACprincipal");
+    xmlNodePtr k = NULL;
+    xmlNodePtr m = NULL;
+    char *ks = NULL;
+    char *ms = NULL;
 
     if ( !p ) return NULL;
-    if ( !(p = get_direct_child(p, "keyid"))) return NULL;
-    if ( !(dest = role_copy(get_element_content(p), dest))) return NULL;
+    if ( !(k = get_direct_child(p, "keyid"))) return NULL;
+    if ( !(ks = get_element_content(k))) return NULL;
+    if ( !(dest = role_copy(ks, dest))) return NULL;
+    /* If there's a mnemonic string, add the mapping from keyid to mnemonic to
+     * the keymap */
+    if ( (m = get_direct_child(p, "mnemonic"))) {
+	if ( (ms = get_element_content(m))) {
+	    abac_keyid_map_remove_keyid(km, ks);
+	    abac_keyid_map_add_nickname(km, ks, ms);
+	}
+    }
     if ( (p = get_direct_child(n, "linking_role"))) {
 	*dest++ = '.';
@@ -870,5 +886,5 @@
  * Converts to A.r<-B.r1.r2 & C.r2
  */
-xmlChar **parse_rt0_xml_v11(xmlNodePtr n) {
+xmlChar **parse_rt0_xml_v11(xmlNodePtr n, abac_keyid_map_t *km) {
     int len = 3;    /* Length of the RT0 string we're building. Initially 3 for
 		       the <- and end-of-string */
@@ -909,5 +925,5 @@
     d = rv[0];
     if ( !( c = get_direct_child(n, "head"))) goto fail;
-    if ( !(d = term_copy(c, d))) goto fail;
+    if ( !(d = term_copy(c, d, km))) goto fail;
     d = append_and_move(d, "<-", 2);
     tails = 0;
@@ -919,5 +935,5 @@
 	    if ( tails++) 
 		d = append_and_move(d, " & ", 3);
-	    if ( !(d = term_copy(c, d))) goto fail;
+	    if ( !(d = term_copy(c, d, km))) goto fail;
 	}
     }
@@ -939,5 +955,5 @@
  * which the new certificate is added.
  */
-xmlChar **parse_abac(xmlDocPtr doc, void *ctxt_id_certs) {
+xmlChar **parse_abac(xmlDocPtr doc, void *ctxt_id_certs, abac_keyid_map_t *km) {
     xmlNodePtr root = NULL;	/* XML root node */
     xmlNodePtr node = NULL;	/* XML credential node */
@@ -991,5 +1007,5 @@
 
     /* read the RT0 and return it */
-    if ( !(rv = proc->xml_to_rt0(rt0)) ) goto fail;
+    if ( !(rv = proc->xml_to_rt0(rt0, km)) ) goto fail;
     ncred=1;
 
@@ -1020,5 +1036,5 @@
  * the ABAC context. */
 char **read_credential(void *ctxt_id_certs, char *infile, 
-	char **in_xml) {
+	char **in_xml, abac_keyid_map_t *km) {
     xmlChar **xml = (xmlChar **) in_xml;    /* Cast */
     xmlDocPtr doc = xmlParseFile(infile);   /* Parse the document */
@@ -1042,7 +1058,7 @@
     /* Demux on type */
     if ( !strcmp((char *) text, "privilege")) {
-	rv = parse_privilege(doc, ctxt_id_certs);
+	rv = parse_privilege(doc, ctxt_id_certs, km);
     } else if ( !strcmp((char *) text, "abac")) {
-	rv = parse_abac(doc, ctxt_id_certs);
+	rv = parse_abac(doc, ctxt_id_certs, km);
     } else { 
 	goto fail;
@@ -1469,5 +1485,5 @@
 
 /* parse xml structure and extract the attribute rules */
-char **get_rt0_from_xml(void *ctxt_id_certs,char *xml) {
+char **get_rt0_from_xml(void *ctxt_id_certs,char *xml, abac_keyid_map_t *km) {
     xmlDocPtr doc=xmlParseMemory(xml,strlen(xml));
     xmlNodePtr node = NULL;                 /* XML scratch node */
@@ -1490,7 +1506,7 @@
     /* Demux on type */
     if ( !strcmp((char *) text, "privilege")) {
-        rv = parse_privilege(doc,ctxt_id_certs);
+        rv = parse_privilege(doc, ctxt_id_certs, km);
     } else if ( !strcmp((char *) text, "abac")) {
-        rv = parse_abac(doc, ctxt_id_certs);
+        rv = parse_abac(doc, ctxt_id_certs, km);
     } else {
         goto fail;
Index: libabac/abac_xml.h
===================================================================
--- libabac/abac_xml.h	(revision b7e77dfa7e38d121dc6bbbab89456e4af6479d04)
+++ libabac/abac_xml.h	(revision d2b198c77ec345f4a2f4f7c24f7d28230cb6faad)
@@ -10,7 +10,9 @@
 extern int init_xmlsec();
 extern int deinit_xmlsec();
-extern char **read_credential(void *id_certs, char *infile, char **xml);
+extern char **read_credential(void *id_certs, char *infile, char **xml,
+	abac_keyid_map_t *);
 
-extern char **get_rt0_from_xml(void *id_certs,char *xml);
+extern char **get_rt0_from_xml(void *id_certs,char *xml,
+	abac_keyid_map_t *);
 extern char *get_keyid_from_xml(char *xml);
 extern long get_validity_from_xml(char *xml);
