Index: libabac/abac.c
===================================================================
--- libabac/abac.c	(revision d2b198c77ec345f4a2f4f7c24f7d28230cb6faad)
+++ libabac/abac.c	(revision afcafea3dca0ade6eafd00ad0fe3f85b0cd05f83)
@@ -343,4 +343,12 @@
 }
 
+/*
+ * Get direct access to the context's keyid mapping.  Used internally.  This
+ * does not make a reference to the map, use abac_keyid_map_dup if that is
+ * required.
+ */
+abac_keyid_map_t *abac_context_get_keyid_map(abac_context_t *ctxt) {
+    return ctxt->keymap;
+}
 
 
Index: libabac/abac.h
===================================================================
--- libabac/abac.h	(revision d2b198c77ec345f4a2f4f7c24f7d28230cb6faad)
+++ libabac/abac.h	(revision afcafea3dca0ade6eafd00ad0fe3f85b0cd05f83)
@@ -54,4 +54,5 @@
 char *abac_context_expand_key(abac_context_t *ctxt, char *s );
 char *abac_context_expand_nickname(abac_context_t *ctxt, char *s );
+abac_keyid_map_t *abac_context_get_keyid_map(abac_context_t *ctxt);
 
 /*
@@ -204,4 +205,5 @@
 // can return 0 if there are no subjects or there's a problem building the cert
 int abac_attribute_bake(abac_attribute_t *attr);
+int abac_attribute_bake_context(abac_attribute_t *attr, abac_context_t *ctxt);
 
 // returns true iff the cert's been baked
Index: libabac/abac.hh
===================================================================
--- libabac/abac.hh	(revision d2b198c77ec345f4a2f4f7c24f7d28230cb6faad)
+++ libabac/abac.hh	(revision afcafea3dca0ade6eafd00ad0fe3f85b0cd05f83)
@@ -65,4 +65,5 @@
             abac_context_t *m_ctx;
 	friend class Role;
+	friend class Attribute;
     };
 
@@ -235,4 +236,9 @@
             }
 
+            bool bake(Context& c) {
+                if (baked()) throw std::logic_error("Cert is already baked");
+                return abac_attribute_bake_context(m_attr, c.m_ctx);
+            }
+
             bool baked() { return abac_attribute_baked(m_attr); }
 
Index: libabac/abac_attribute.c
===================================================================
--- libabac/abac_attribute.c	(revision d2b198c77ec345f4a2f4f7c24f7d28230cb6faad)
+++ libabac/abac_attribute.c	(revision afcafea3dca0ade6eafd00ad0fe3f85b0cd05f83)
@@ -252,8 +252,9 @@
 
 // 0 for fail to bake, 1 is baked okay
-int abac_attribute_bake(abac_attribute_t *attr) {
+int abac_attribute_bake_context(abac_attribute_t *attr, abac_context_t *ctxt) {
     assert(attr);
     assert(attr->head_string);
     assert(attr->tail_strings);
+    abac_keyid_map_t *km = NULL;
 
     abac_chunk_t id_chunk = { NULL, 0 };
@@ -262,9 +263,15 @@
         return 0; 
 
-/* Make an new GENI abac credential with the rt0 rule that expires secs from
- * now.  cert is the PEM encoded X.509 of the issuer's certificate as a string.
- * certlen is the length of cert.  Returns the XML. Caller is responsible for
- * freeing it. */
-    char *attr_cert=make_credential(attr, attr->validity, (char *)id_chunk.ptr, id_chunk.len);
+    if ( ctxt && (km = abac_context_get_keyid_map(ctxt))) {
+	if (attr->keymap) abac_keyid_map_free(attr->keymap);
+	attr->keymap = abac_keyid_map_dup(km);
+    }
+
+    /* Make an new GENI abac credential with the rt0 rule that expires secs
+     * from now.  cert is the PEM encoded X.509 of the issuer's certificate as
+     * a string.  certlen is the length of cert.  Returns the XML. Caller is
+     * responsible for freeing it. */
+    char *attr_cert=make_credential(attr, attr->validity, 
+	    (char *)id_chunk.ptr, id_chunk.len);
 
     if (attr_cert == NULL)
@@ -276,4 +283,8 @@
     /* free(role_string); */
     return 1;
+}
+// 0 for fail to bake, 1 is baked okay
+int abac_attribute_bake(abac_attribute_t *attr) {
+    return abac_attribute_bake_context(attr, NULL);
 }
 
Index: libabac/abac_xml.c
===================================================================
--- libabac/abac_xml.c	(revision d2b198c77ec345f4a2f4f7c24f7d28230cb6faad)
+++ libabac/abac_xml.c	(revision afcafea3dca0ade6eafd00ad0fe3f85b0cd05f83)
@@ -1139,5 +1139,6 @@
 
 /* Template to create a head element in structured XML for RT0 (v1.1).  All
- * heads are a single role element */
+ * heads are a single role element. There aer versions with and without
+ * mnemonics. */
 static char *head_template = 
 "<head>\n"
@@ -1146,6 +1147,13 @@
 "</head>\n";
 
+static char *head_template_w_mnemonic = 
+"<head>\n"
+"   <ABACprincipal><keyid>%s</keyid><mnemonic>%s</mnemonic></ABACprincipal>\n"
+"   <role>%s</role>\n"
+"</head>\n";
+
 /* Templates to create a tail in structured XML  based on how many of
- * principal, role, and linking role are present. */
+ * principal, role, and linking role are present. There are variants with
+ * and without mnomonics. */
 static char *tail_template[] = {
 "<tail>\n"
@@ -1162,4 +1170,98 @@
 "</tail>\n",
 };
+static char *tail_template_w_mnemonic[] = {
+"<tail>\n"
+"   <ABACprincipal><keyid>%s</keyid><mnemonic>%s</mnemonic></ABACprincipal>\n"
+"</tail>\n",
+"<tail>\n"
+"   <ABACprincipal><keyid>%s</keyid><mnemonic>%s</mnemonic></ABACprincipal>\n"
+"   <role>%s</role>\n"
+"</tail>\n",
+"<tail>\n"
+"   <ABACprincipal><keyid>%s</keyid><mnemonic>%s</mnemonic></ABACprincipal>\n"
+"   <role>%s</role>\n"
+"   <linking_role>%s</linking_role>\n"
+"</tail>\n",
+};
+
+/* These three functions are variations on the theme of printing out the XML
+ * representation of tail roles in the XML credential.  They're separated out
+ * to make reading encode_rt0_xml_v11 a little easier.  Each prints the role
+ * (r) into the string tmp, adding mnemonic annotations from km if present.  Sz
+ * is the number of bytes remaining in the overall string, and is always
+ * smaller than the size of tmp.  The only differences are which templates are
+ * used and how many strings are inserted.  The length of the generated string
+ * is returned.
+ */
+static int encode_principal_role(abac_role_t *r, char *tmp,  int sz,
+	abac_keyid_map_t *km) {
+    char *p = minimal_xml_escaping(abac_role_principal(r));
+    char *nick = NULL;
+    int ts = 0;
+
+    if ( km ) 
+	nick = abac_keyid_map_key_to_nickname(km, p);
+
+    if (nick) {
+	ts = snprintf(tmp, sz, tail_template_w_mnemonic[0], p, nick);
+	free(nick);
+	nick = NULL;
+    }
+    else {
+	ts = snprintf(tmp, sz, tail_template[0], p);
+    }
+    free(p);
+    return ts;
+}
+
+static int encode_single_role(abac_role_t *r, char *tmp,  int sz,
+	abac_keyid_map_t *km) {
+    char *p = minimal_xml_escaping(abac_role_principal(r));
+    char *ro = minimal_xml_escaping(abac_role_role_name(r));
+    char *nick = NULL;
+    int ts = 0;
+
+    if ( km ) 
+	nick = abac_keyid_map_key_to_nickname(km, p);
+
+    if (nick) {
+	ts = snprintf(tmp, sz, tail_template_w_mnemonic[0], 
+		p, nick, ro);
+	free(nick);
+	nick = NULL;
+    }
+    else {
+	ts = snprintf(tmp, sz, tail_template[1], p, ro);
+    }
+    free(p);
+    free(ro);
+    return ts;
+}
+
+static int encode_linking_role(abac_role_t *r, char *tmp,  int sz,
+	abac_keyid_map_t *km) {
+    char *p = minimal_xml_escaping(abac_role_principal(r));
+    char *ro = minimal_xml_escaping(abac_role_role_name(r));
+    char *li = minimal_xml_escaping(abac_role_linking_role(r));
+    char *nick = NULL;	    
+    int ts = 0;
+
+    if ( km ) 
+	nick = abac_keyid_map_key_to_nickname(km, p);
+
+    if (nick) {
+	ts = snprintf(tmp, sz, tail_template_w_mnemonic[2], 
+		p, nick, ro, li);
+	free(nick);
+	nick = NULL;
+    }
+    else {
+	ts = snprintf(tmp, sz, tail_template[2], p, ro, li);
+    }
+    free(p);
+    free(ro);
+    free(li);
+    return ts;
+}
 
 /* Convert the given attribute to the RT0 structured XML representation used by
@@ -1167,7 +1269,7 @@
  */
 xmlChar *encode_rt0_xml_v11(abac_attribute_t *a) {
-    int htlen = strlen(head_template);	    /* head template length */
-    int ttlen = strlen(tail_template[2]);   /* length of the longest tail
-					       template */
+    int htlen = strlen(head_template_w_mnemonic);    /* head template length */
+    int ttlen = strlen(tail_template_w_mnemonic[2]); /* length of the longest
+							tail template */
     /* Size of the string we'll need - start with a head template and string */
     int sz = strlen(abac_attribute_get_head(a)) + htlen;
@@ -1177,4 +1279,6 @@
     char *copy = abac_xstrdup(abac_attribute_get_head(a)); /* splitting */
     int npr = 2;	    /* Number of parts in the head role */
+    abac_keyid_map_t *km = (a) ? abac_attribute_get_keyid_map(a) : NULL;
+    char *nick = NULL;	    /* Mnemonic name */
     char *tmp = NULL;	    /* A temporary to build each tail element */
     char *rv = NULL;	    /* The return value */
@@ -1195,6 +1299,15 @@
 	goto fail;
 
+    if ( km ) 
+	nick = abac_keyid_map_key_to_nickname(km, princ_role[0]);
     /* Put the head in */
-    sz -= snprintf(rv, sz, head_template, princ_role[0], princ_role[1]);
+    if ( nick ) {
+	sz -= snprintf(rv, sz, head_template_w_mnemonic, princ_role[0], 
+		nick, princ_role[1]);
+	free(nick);
+	nick = NULL;
+    } else {
+	sz -= snprintf(rv, sz, head_template, princ_role[0], princ_role[1]);
+    }
 
     for ( i = 0 ; i < ntails; i++) {
@@ -1207,29 +1320,12 @@
 	    goto fail;
 
-	if ( abac_role_is_principal(r)) {
-	    char *p = minimal_xml_escaping(abac_role_principal(r));
-
-	    ts = snprintf(tmp, sz, tail_template[0], p);
-	    free(p);
-	} else if (abac_role_is_role(r)) {
-	    char *p = minimal_xml_escaping(abac_role_principal(r));
-	    char *ro = minimal_xml_escaping(abac_role_role_name(r));
-
-	    ts = snprintf(tmp, sz, tail_template[1], p, ro);
-	    free(p);
-	    free(ro);
-	} else if (abac_role_is_linking(r)) {
-	    char *p = minimal_xml_escaping(abac_role_principal(r));
-	    char *ro = minimal_xml_escaping(abac_role_role_name(r));
-	    char *li = minimal_xml_escaping(abac_role_linking_role(r));
-
-	    ts = snprintf(tmp, sz, tail_template[2], p, ro, li);
-	    free(p);
-	    free(ro);
-	    free(li);
-	}
+	if ( abac_role_is_principal(r))
+	    ts = encode_principal_role(r, tmp, sz, km);
+	else if (abac_role_is_role(r))
+	    ts = encode_single_role(r, tmp, sz, km);
+	else if (abac_role_is_linking(r))
+	    ts = encode_linking_role(r, tmp, sz, km);
 
 	free(r);
-
 	if ( ts < 0 ) 
 	    goto fail;
