Index: creddy/attribute.c
===================================================================
--- creddy/attribute.c	(revision 01044ac029c7064233cd45db748ff1f22568be13)
+++ creddy/attribute.c	(revision 980a7b6c556281c8ae33130f5b4b5c91fcadf24d)
@@ -7,4 +7,5 @@
 
 #define ROLE_SEPARATOR " <- "
+#define INTERSECTION_SEP " & "
 #define SHA1_LENGTH 40
 
@@ -86,8 +87,7 @@
 }
 
-
 void attribute_main(options_t *opts) {
-    char *subject_id = NULL;
     struct cb_opts c_opts = { 1, 0, 3, "Key password:" };
+    int i, role_len = 1;
 
     if (
@@ -99,64 +99,76 @@
         usage(opts);
 
-    // make sure we have exactly one of --subject-cert / --subject-id
-    if (opts->subject_cert == NULL && opts->subject_id == NULL)
+    if (!clean_name(opts->role)) {
+        printf("bad role name %s\n", opts->role);
         usage(opts);
-    if (opts->subject_cert && opts->subject_id) {
-        printf("Need exactly one of --subject-cert / --subject-id");
-        usage(opts);
-    }
-
-    // if we have an ID, make sure it's SHA1 and lowercase
-    if (opts->subject_id) {
-        int i;
-        subject_id = opts->subject_id;
-
-        // hex chars (also convert to lowercase)
-        for (i = 0; subject_id[i]; ++i) {
-            subject_id[i] = tolower(subject_id[i]);
-            if (!isxdigit(subject_id[i])) {
-                printf("Invalid subject ID: must be SHA1\n");
+    }
+
+    role_len += SHA1_LENGTH + 1 + strlen(opts->role);
+    role_len += strlen(ROLE_SEPARATOR);
+
+    for (i = 0; i < opts->num_subjects; ++i) {
+        subject_t *cur = &opts->subjects[i];
+
+        // if we have an ID, make sure it's SHA1 and lowercase
+        if (cur->id) {
+            int j;
+            char *subject_id = cur->id;
+
+            // hex chars (also convert to lowercase)
+            for (j = 0; subject_id[j]; ++j) {
+                subject_id[j] = tolower(subject_id[j]);
+                if (!isxdigit(subject_id[j])) {
+                    printf("Invalid subject ID %s: must be SHA1\n", subject_id);
+                    usage(opts);
+                }
+            }
+
+            // correct length
+            if (j != SHA1_LENGTH) {
+                printf("Invalid subject ID %s: must be SHA1 (wrong length)\n", subject_id);
                 usage(opts);
             }
         }
 
-        // correct length
-        if (i != SHA1_LENGTH) {
-            printf("Invalid subject ID: must be SHA1 (too long)\n");
-            usage(opts);
-        }
-    }
-
-    if (!clean_name(opts->role)) {
-        printf("bad role name\n");
-        usage(opts);
-    }
-
-    // verify the subject role name if present
-    if (opts->subject_role) {
-        char *role = opts->subject_role;
-        char *start[3];
-        int name_parts = 0, i;
-
-        start[name_parts++] = role;
-
-        for (i = 0; role[i] != '\0'; ++i)
-            if (role[i] == '.') {
-                if (name_parts == 3) {
-                    printf("bad subject role name (too many dots)\n");
+        // otherwise we have a cert
+        else {
+            certificate_t *subject = cert_from_file(cur->cert);
+            cur->id = cert_keyid(subject);
+            DESTROY_IF(subject);
+        }
+
+        role_len += SHA1_LENGTH;
+
+        // verify the subject role name if present
+        if (cur->role) {
+            char *role = cur->role;
+            char *start[3];
+            int name_parts = 0, j;
+
+            start[name_parts++] = role;
+
+            for (j = 0; role[j] != '\0'; ++j)
+                if (role[j] == '.') {
+                    if (name_parts == 3) {
+                        printf("bad subject role name (too many dots)\n");
+                        usage(opts);
+                    }
+                    start[name_parts++] = &role[j+1];
+                    role[j] = 0;
+                }
+
+            for (j = 0; j < name_parts; ++j)
+                if (!clean_name(start[j])) {
+                    printf("bad subject role name\n");
                     usage(opts);
                 }
-                start[name_parts++] = &role[i+1];
-                role[i] = 0;
-            }
-
-        for (i = 0; i < name_parts; ++i)
-            if (!clean_name(start[i])) {
-                printf("bad subject role name\n");
-                usage(opts);
-            }
-
-        for (i = 1; i < name_parts; ++i)
-            *(start[i]-1) = '.'; // replace the dot
+
+            for (j = 1; j < name_parts; ++j)
+                *(start[j]-1) = '.'; // replace the dot
+
+            role_len += strlen(cur->role) + 1;
+        }
+
+        role_len += sizeof(INTERSECTION_SEP) - 1;
     }
 
@@ -182,33 +194,26 @@
     char *issuer_id = cert_keyid(issuer);
 
-    // subject keyid from cert if it wasn't passed in
-    if (opts->subject_cert) {
-        certificate_t *subject = cert_from_file(opts->subject_cert);
-        subject_id = cert_keyid(subject);
-        DESTROY_IF(subject);
-    }
-
     // build the role encoding
-    int role_encoding_len = 1; // for nul terminator
-    role_encoding_len += strlen(issuer_id) + 1 + strlen(opts->role);
-    role_encoding_len += sizeof(ROLE_SEPARATOR) - 1;
-    role_encoding_len += strlen(subject_id);
-    if (opts->subject_role)
-        role_encoding_len += 1 + strlen(opts->subject_role);
-
-    char *role_encoding = xmalloc(role_encoding_len);
+    char *role_encoding = xmalloc(role_len);
     role_encoding[0] = '\0';
 
-    sprintf(role_encoding, "%s.%s" ROLE_SEPARATOR "%s", issuer_id, opts->role, subject_id);
-    if (opts->subject_role) {
-        strcat(role_encoding, ".");
-        strcat(role_encoding, opts->subject_role);
+    // role
+    sprintf(role_encoding, "%s.%s" ROLE_SEPARATOR, issuer_id, opts->role);
+
+    // subject(s)
+    for (i = 0; i < opts->num_subjects; ++i) {
+        subject_t *cur = &opts->subjects[i];
+
+        strcat(role_encoding, cur->id);
+        if (cur->role) {
+            strcat(role_encoding, ".");
+            strcat(role_encoding, cur->role);
+        }
+
+        if (i < opts->num_subjects - 1)
+            strcat(role_encoding, INTERSECTION_SEP);
     }
 
     free(issuer_id);
-
-    // if opts->subject_id, the memory will be freed in main
-    if (opts->subject_cert)
-        free(subject_id);
 
     // create attribute cert
