hcrypto: Add hcrypto EVP support to the Unix CM
[openafs.git] / tests / auth / keys-t.c
1 /*
2  * Copyright (c) 2010 Your File System Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24
25 /*!
26  * Tests for the afsconf key handling functions
27  */
28
29 #include <afsconfig.h>
30 #include <afs/param.h>
31
32 #include <roken.h>
33
34 #include <afs/cellconfig.h>
35 #include <afs/keys.h>
36 #include <afs/afsutil.h>
37 #include <rx/rxkad.h>
38
39 #include <tap/basic.h>
40
41 static int
42 copy(char *inFile, char *outFile)
43 {
44     int in, out;
45     char *block;
46     size_t len;
47
48     in = open(inFile, O_RDONLY);
49     if (in<0)
50         return EIO;
51
52     out = open(outFile, O_WRONLY | O_CREAT, 0600);
53     if (out<0)
54         return EIO;
55
56     block = malloc(1024);
57     do {
58         len = read(in, block, 1024);
59         if (len > 0)
60             write(out, block, len);
61     } while (len > 0);
62     free(block);
63
64     close(in);
65     close(out);
66
67     if (len == -1)
68         return EIO;
69
70     return 0;
71 }
72
73 int
74 keyMatches(struct afsconf_typedKey *typedKey,
75            afsconf_keyType type, int kvno, int subType,
76            void *keyMaterial, size_t keyLen)
77 {
78     afsconf_keyType keyType;
79     int keyKvno;
80     int keySubType;
81     struct rx_opaque *buffer;
82
83     afsconf_typedKey_values(typedKey, &keyType, &keyKvno, &keySubType,
84                             &buffer);
85
86     return (keyType == type && keyKvno == kvno && keySubType == subType &&
87             buffer->len == keyLen &&
88             memcmp(keyMaterial, buffer->val, buffer->len) == 0);
89 }
90
91
92 int main(int argc, char **argv)
93 {
94     struct afsconf_dir *dir;
95     struct afsconf_keys keys;
96     struct ktc_encryptionKey key;
97     struct rx_opaque *keyMaterial;
98     struct afsconf_typedKey *typedKey;
99     struct afsconf_typedKeyList *typedKeyList;
100
101     char buffer[1024];
102     char *dirEnd;
103     FILE *file;
104     afs_int32 kvno;
105     int code;
106     int i;
107
108     plan(122);
109
110     /* Create a temporary afs configuration directory */
111     snprintf(buffer, sizeof(buffer), "%s/afs_XXXXXX", gettmpdir());
112     mkdtemp(buffer);
113     dirEnd = buffer + strlen(buffer);
114
115     /* Create a CellServDB file */
116     strcpy(dirEnd, "/CellServDB");
117     file = fopen(buffer, "w");
118     fprintf(file, ">example.org # An example cell\n");
119     fprintf(file, "127.0.0.1 #test.example.org\n");
120     fclose(file);
121
122     /* Create a ThisCell file */
123     strcpy(dirEnd, "/ThisCell");
124     file = fopen(buffer, "w");
125     fprintf(file, "example.org\n");
126     fclose(file);
127
128     /* Firstly, copy in a known keyfile. */
129     strcpy(dirEnd, "/KeyFile");
130     code = copy("KeyFile", buffer);
131     if (code)
132         goto out;
133
134     *dirEnd='\0';
135
136     /* Start with a blank configuration directory */
137     dir = afsconf_Open(strdup(buffer));
138     ok(dir != NULL, "Sucessfully re-opened config directory");
139     if (dir == NULL)
140         goto out;
141
142     /* Verify that GetKeys returns the entire set of keys correctly */
143     code = afsconf_GetKeys(dir, &keys);
144     is_int(0, code, "afsconf_GetKeys returns successfully");
145     is_int(3, keys.nkeys, "... and returns the right number of keys");
146     is_int(1, keys.key[0].kvno, " ... first key number is correct");
147     is_int(2, keys.key[1].kvno, " ... second key number is correct");
148     is_int(4, keys.key[2].kvno, " ... third key number is correct");
149     ok(memcmp(keys.key[0].key, "\x01\x02\x04\x08\x10\x20\x40\x80", 8) == 0,
150        " ... first key matches");
151     ok(memcmp(keys.key[1].key, "\x04\x04\x04\x04\x04\x04\x04\x04", 8) == 0,
152        " ... second key matches");
153     ok(memcmp(keys.key[2].key, "\x19\x16\xfe\xe6\xba\x77\x2f\xfd", 8) == 0,
154        " ... third key matches");
155
156     /* Verify that GetLatestKey returns the newest key */
157     code = afsconf_GetLatestKey(dir, &kvno, &key);
158     is_int(0, code, "afsconf_GetLatestKey returns sucessfully");
159     is_int(4, kvno, " ... with correct key number");
160     ok(memcmp(&key, "\x19\x16\xfe\xe6\xba\x77\x2f\xfd", 8) == 0,
161        " ... and correct key");
162
163     /* Verify that random access using GetKey works properly */
164     code = afsconf_GetKey(dir, 2, &key);
165     is_int(0, code, "afsconf_GetKey returns successfully");
166     ok(memcmp(&key, "\x04\x04\x04\x04\x04\x04\x04\x04", 8) == 0,
167        " ... and with correct key");
168
169     /* And that it fails if the key number doesn't exist */
170     code = afsconf_GetKey(dir, 3, &key);
171     is_int(code, AFSCONF_NOTFOUND,
172            "afsconf_GetKey returns not found for missing key");
173
174     /* Check that AddKey can be used to add a new 'newest' key */
175     code = afsconf_AddKey(dir, 5, "\x08\x08\x08\x08\x08\x08\x08\x08", 0);
176     is_int(0, code, "afsconf_AddKey sucessfully adds a new key");
177
178     /* And that we can get it back with GetKeys, GetLatestKey and GetKey */
179     code = afsconf_GetKeys(dir, &keys);
180     is_int(0, code, " ... and GetKeys still works");
181     is_int(4, keys.nkeys, "... and has the correct number of keys");
182     is_int(5, keys.key[3].kvno, " ... and the fourth key has the correct kvno");
183     ok(memcmp(keys.key[3].key, "\x08\x08\x08\x08\x08\x08\x08\x08", 8) == 0,
184        " ... and is the correct key");
185
186     code = afsconf_GetLatestKey(dir, &kvno, &key);
187     is_int(0, code, " ... and GetLatestKey returns successfully");
188     is_int(5, kvno, " ... with the correct key number");
189     ok(memcmp(&key, "\x08\x08\x08\x08\x08\x08\x08\x08", 8) == 0,
190        " ... and the correct key");
191
192     code = afsconf_GetKey(dir, 5, &key);
193     is_int(0, code, " ... and GetKey still works");
194     ok(memcmp(&key, "\x08\x08\x08\x08\x08\x08\x08\x08", 8) == 0,
195        " ... and returns the correct key");
196
197     /* Check that AddKey without the overwrite flag won't overwrite an existing
198      * key */
199     code = afsconf_AddKey(dir, 5, "\x10\x10\x10\x10\x10\x10\x10", 0);
200     is_int(AFSCONF_KEYINUSE, code, "AddKey won't overwrite without being told to");
201
202     /* Check with GetKey that it didn't */
203     code = afsconf_GetKey(dir, 5, &key);
204     is_int(0, code, " ... and GetKey still works");
205     ok(memcmp(&key, "\x08\x08\x08\x08\x08\x08\x08\x08", 8) == 0,
206        " ... and key hasn't been overwritten");
207
208     /* Check that AddKey with the overwrite flag will overwrite an existing key */
209     code = afsconf_AddKey(dir, 5, "\x10\x10\x10\x10\x10\x10\x10\x10", 1);
210     is_int(0, code, "AddKey overwrites when asked");
211
212     /* Use GetKey to check that it did so */
213     code = afsconf_GetKey(dir, 5, &key);
214     is_int(0, code, " ... and GetKey still works");
215     ok(memcmp(&key, "\x10\x10\x10\x10\x10\x10\x10\x10", 8) == 0,
216        " ... and key has been overwritten");
217
218     /* Check that deleting a key that doesn't exist fails */
219     code = afsconf_DeleteKey(dir, 6);
220     is_int(AFSCONF_NOTFOUND, code,
221            "afsconf_DeleteKey returns NOTFOUND if key doesn't exist");
222
223     /* Check that we can delete a key using afsconf_DeleteKey */
224     code = afsconf_DeleteKey(dir, 2);
225     is_int(0, code, "afsconf_DeleteKey can delete a key");
226     code = afsconf_GetKey(dir, 2, &key);
227     is_int(AFSCONF_NOTFOUND, code, " ... and afsconf_GetKey can't find it");
228
229     /* Check that deleting it doesn't leave a hole in what GetKeys returns */
230     code = afsconf_GetKeys(dir, &keys);
231     is_int(0, code, "... and afsconf_GetKeys returns it");
232     is_int(3, keys.nkeys, "... and returns the right number of keys");
233     is_int(1, keys.key[0].kvno, " ... first key number is correct");
234     is_int(4, keys.key[1].kvno, " ... second key number is correct");
235     is_int(5, keys.key[2].kvno, " ... third key number is correct");
236
237     /* Make sure that if we drop the dir structure, and then rebuild it, we
238      * still have the same KeyFile */
239     afsconf_Close(dir);
240
241     *dirEnd='\0';
242     dir = afsconf_Open(strdup(buffer));
243     ok(dir != NULL, "Sucessfully re-opened config directory");
244     if (dir == NULL)
245         goto out;
246
247     code = afsconf_GetKeys(dir, &keys);
248     is_int(0, code, "afsconf_GetKeys still works");
249     is_int(3, keys.nkeys, "... and returns the right number of keys");
250     is_int(1, keys.key[0].kvno, " ... first key number is correct");
251     is_int(4, keys.key[1].kvno, " ... second key number is correct");
252     is_int(5, keys.key[2].kvno, " ... third key number is correct");
253
254     /* Now check that we're limited to 8 keys */
255     for (i=0; i<5; i++) {
256         code = afsconf_AddKey(dir, 10+i, "\x10\x10\x10\x10\x10\x10\x10\x10",
257                               0);
258         is_int(0, code, "Adding %dth key with AddKey works", i+4);
259     }
260     code = afsconf_AddKey(dir, 20, "\x10\x10\x10\x10\x10\x10\x10\x10",0);
261     is_int(AFSCONF_FULL, code, "afsconf_AddKey fails once we've got 8 keys");
262
263     /* Check that the new interface also fails when we've got too many
264      * keys */
265     keyMaterial = rx_opaque_new("\x10\x10\x10\x10\x10\x10\x10\x10", 8);
266     typedKey = afsconf_typedKey_new(afsconf_rxkad, 20, 0, keyMaterial);
267     rx_opaque_free(&keyMaterial);
268     code = afsconf_AddTypedKey(dir, typedKey, 0);
269     afsconf_typedKey_put(&typedKey);
270     is_int(AFSCONF_FULL, code,
271            "afsconf_AddTypedKey fails for rxkad once we've got 8 keys");
272
273     /* Check the new accessors work for rxkad keys */
274     code = afsconf_GetKeyByTypes(dir, afsconf_rxkad, 4, 0, &typedKey);
275     is_int(0, code,
276            "afsconf_GetKeyByTypes works for rxkad");
277     ok(keyMatches(typedKey, afsconf_rxkad, 4, 0,
278                   "\x19\x16\xfe\xe6\xba\x77\x2f\xfd", 8),
279        " ... and returned key matches");
280
281     afsconf_typedKey_put(&typedKey);
282
283     code = afsconf_GetKeysByType(dir, afsconf_rxkad, 4, &typedKeyList);
284     is_int(0, code,
285            "afsconf_GetKeysByType works for rxkad");
286     is_int(1, typedKeyList->nkeys,
287            " ... and returns 1 key, as expected");
288     ok(keyMatches(typedKeyList->keys[0], afsconf_rxkad, 4, 0,
289                   "\x19\x16\xfe\xe6\xba\x77\x2f\xfd", 8),
290        " ... and returned key matches");
291
292     afsconf_PutTypedKeyList(&typedKeyList);
293
294     code = afsconf_GetLatestKeyByTypes(dir, afsconf_rxkad, 0, &typedKey);
295     is_int(0, code,
296            "afsconf_GetLatestKeyByTypes works for rxkad");
297     ok(keyMatches(typedKey, afsconf_rxkad, 14, 0,
298                   "\x10\x10\x10\x10\x10\x10\x10\x10", 8),
299        " ... and returned key matches");
300
301     afsconf_typedKey_put(&typedKey);
302
303     code = afsconf_GetLatestKeysByType(dir, afsconf_rxkad, &typedKeyList);
304     is_int(0, code,
305            "afsconf_GetLatestKeysByType works for rxkad");
306     is_int(1, typedKeyList->nkeys,
307            " ... and returns 1 key, as expected");
308     ok(keyMatches(typedKeyList->keys[0], afsconf_rxkad, 14, 0,
309                  "\x10\x10\x10\x10\x10\x10\x10\x10", 8),
310        " ... and returned key matches");
311     afsconf_PutTypedKeyList(&typedKeyList);
312
313     /* Check that we can't delete a key that doesn't exist */
314     code = afsconf_DeleteKeyByType(dir, afsconf_rxkad, 6);
315     is_int(AFSCONF_NOTFOUND, code,
316            "afsconf_DeleteKeyByType returns NOTFOUND if key doesn't exist");
317     code = afsconf_DeleteKeyBySubType(dir, afsconf_rxkad, 6, 0);
318     is_int(AFSCONF_NOTFOUND, code,
319            "afsconf_DeleteKeyBySubType returns NOTFOUND if key doesn't exist");
320     code = afsconf_DeleteKeyBySubType(dir, afsconf_rxkad, 14, 1);
321     is_int(AFSCONF_NOTFOUND, code,
322            "afsconf_DeleteKeyBySubType doesn't delete with wrong subtype");
323     code = afsconf_GetKeyByTypes(dir, afsconf_rxkad, 14, 0, &typedKey);
324     is_int(0, code, " ... and key is still there!");
325     afsconf_typedKey_put(&typedKey);
326
327     /* Check that we can delete a key that does */
328     code = afsconf_DeleteKeyByType(dir, afsconf_rxkad, 13);
329     is_int(0, code, "afsconf_DeleteKeyByType works");
330     code = afsconf_GetKeysByType(dir, afsconf_rxkad, 13, &typedKeyList);
331     is_int(AFSCONF_NOTFOUND, code, " ... and is really gone");
332
333     code = afsconf_DeleteKeyBySubType(dir, afsconf_rxkad, 14, 0);
334     is_int(0, code, "afsconf_DeleteKeyBySubType works");
335     code = afsconf_GetKeyByTypes(dir, afsconf_rxkad, 14, 0, &typedKey);
336     is_int(AFSCONF_NOTFOUND, code, " ... and is really gone");
337
338     /* Unlink the KeyFile */
339     strcpy(dirEnd, "/KeyFile");
340     unlink(buffer);
341
342     /* Force a rebuild of the directory structure, just in case */
343     afsconf_Close(dir);
344
345     *dirEnd='\0';
346     dir = afsconf_Open(strdup(buffer));
347     ok(dir != NULL, "Sucessfully re-opened config directory");
348     if (dir == NULL)
349         goto out;
350
351     /* Check that all of the various functions work properly if the file
352      * isn't there */
353     code = afsconf_GetKeys(dir, &keys);
354     is_int(0, code, "afsconf_GetKeys works with an empty KeyFile");
355     is_int(0, keys.nkeys, " ... and returns the right number of keys");
356     code = afsconf_GetKey(dir, 1, &key);
357     is_int(AFSCONF_NOTFOUND, code,
358            "afsconf_GetKey returns NOTFOUND with an empty KeyFile");
359     code = afsconf_DeleteKey(dir, 1);
360     is_int(AFSCONF_NOTFOUND, code,
361            "afsconf_DeleteKey returns NOTFOUND with an empty KeyFile");
362     code = afsconf_GetLatestKey(dir, &kvno, &key);
363     is_int(AFSCONF_NOTFOUND, code,
364            "afsconf_GetLatestKey returns NOTFOUND with an empty KeyFile");
365     code = afsconf_GetKeysByType(dir, afsconf_rxkad, 1, &typedKeyList);
366     is_int(AFSCONF_NOTFOUND, code,
367            "afsconf_GetKeysByType returns NOTFOUND with an empty KeyFile");
368     code = afsconf_GetKeyByTypes(dir, afsconf_rxkad, 1, 0, &typedKey);
369     is_int(AFSCONF_NOTFOUND, code,
370            "afsconf_GetKeyByTypes returns NOTFOUND with an empty KeyFile");
371     code = afsconf_GetLatestKeysByType(dir, afsconf_rxkad, &typedKeyList);
372     is_int(AFSCONF_NOTFOUND, code,
373            "afsconf_GetLatestKeysByType returns NOTFOUND with empty KeyFile");
374     code = afsconf_GetLatestKeyByTypes(dir, afsconf_rxkad, 0, &typedKey);
375     is_int(AFSCONF_NOTFOUND, code,
376            "afsconf_GetLatestKeyByTypes returns NOTFOUND with empty KeyFile");
377
378     /* Now try adding a key to an empty file */
379     code = afsconf_AddKey(dir, 1, "\x10\x10\x10\x10\x10\x10\x10\x10", 1);
380     is_int(0, code, "afsconf_AddKey succeeds with an empty KeyFile");
381     code = afsconf_GetLatestKey(dir, &kvno, &key);
382     is_int(0, code, " ... and afsconf_GetLatestKey succeeds");
383     is_int(1, kvno, " ... with correct kvno");
384     ok(memcmp(&key, "\x10\x10\x10\x10\x10\x10\x10\x10", 8) == 0,
385        " ... and key");
386
387     /* And adding a key using the new interface */
388
389     keyMaterial = rx_opaque_new("\x20\x20\x20\x20\x20\x20\x20\x20", 8);
390     typedKey = afsconf_typedKey_new(afsconf_rxkad, 2, 0, keyMaterial);
391     rx_opaque_free(&keyMaterial);
392     code = afsconf_AddTypedKey(dir, typedKey, 0);
393     afsconf_typedKey_put(&typedKey);
394     is_int(0, code, "afsconf_AddTypedKey works");
395     code = afsconf_GetLatestKey(dir, &kvno, &key);
396     is_int(0, code, " ... and afsconf_GetLatestKey succeeds");
397     is_int(2, kvno, " ... with correct kvno");
398     ok(memcmp(&key, "\x20\x20\x20\x20\x20\x20\x20\x20", 8) == 0,
399        " ... and key");
400     code = afsconf_GetLatestKeyByTypes(dir, afsconf_rxkad, 0, &typedKey);
401     is_int(0, code, " ... and so does afsconf_GetLatestKeyByTypes");
402     ok(keyMatches(typedKey, afsconf_rxkad, 2, 0,
403                   "\x20\x20\x20\x20\x20\x20\x20\x20", 8),
404        " ... with correct key");
405     afsconf_typedKey_put(&typedKey);
406
407     /* And that we can't add a key to an existing kvno and type */
408     keyMaterial = rx_opaque_new("\x30\x30\x30\x30\x30\x30\x30\x30", 8);
409     typedKey = afsconf_typedKey_new(afsconf_rxkad, 2, 0, keyMaterial);
410     rx_opaque_free(&keyMaterial);
411     code = afsconf_AddTypedKey(dir, typedKey, 0);
412     afsconf_typedKey_put(&typedKey);
413     is_int(AFSCONF_KEYINUSE, code,
414            "afsconf_AddTypedKey won't overwrite without being told to");
415     code = afsconf_GetKeyByTypes(dir, afsconf_rxkad, 2, 0, &typedKey);
416     is_int(0, code, " ... and key still exists");
417     ok(keyMatches(typedKey, afsconf_rxkad, 2, 0,
418                   "\x20\x20\x20\x20\x20\x20\x20\x20", 8),
419        " ... and hasn't changed");
420     afsconf_typedKey_put(&typedKey);
421
422     /* But we can if we force */
423     keyMaterial = rx_opaque_new("\x30\x30\x30\x30\x30\x30\x30\x30", 8);
424     typedKey = afsconf_typedKey_new(afsconf_rxkad, 2, 0, keyMaterial);
425     rx_opaque_free(&keyMaterial);
426     code = afsconf_AddTypedKey(dir, typedKey, 1);
427     afsconf_typedKey_put(&typedKey);
428     is_int(0, code,  "afsconf_AddTypedKey overwrites when asked");
429     code = afsconf_GetKeyByTypes(dir, afsconf_rxkad, 2, 0, &typedKey);
430     is_int(0, code, " ... and GetKeyByTypes retrieves new key");
431     ok(keyMatches(typedKey, afsconf_rxkad, 2, 0,
432                   "\x30\x30\x30\x30\x30\x30\x30\x30", 8),
433        " ... and it is the new key");
434
435     /* Check that we can't add bad rxkad keys */
436     keyMaterial = rx_opaque_new("\x30\x30\x30\x30\x30\x30\x30", 7);
437     typedKey = afsconf_typedKey_new(afsconf_rxkad, 3, 0, keyMaterial);
438     rx_opaque_free(&keyMaterial);
439     code = afsconf_AddTypedKey(dir, typedKey, 1);
440     afsconf_typedKey_put(&typedKey);
441     is_int(AFSCONF_BADKEY, code,
442            "afsconf_AddTypedKey won't add short rxkad keys");
443     keyMaterial = rx_opaque_new("\x30\x30\x30\x30\x30\x30\x30\x30\x30", 9);
444     typedKey = afsconf_typedKey_new(afsconf_rxkad, 3, 0, keyMaterial);
445     rx_opaque_free(&keyMaterial);
446     code = afsconf_AddTypedKey(dir, typedKey, 1);
447     afsconf_typedKey_put(&typedKey);
448     is_int(AFSCONF_BADKEY, code,
449            "afsconf_AddTypedKey won't add long rxkad keys");
450     keyMaterial = rx_opaque_new("\x30\x30\x30\x30\x30\x30\x30\x30", 8);
451     typedKey = afsconf_typedKey_new(afsconf_rxkad, 3, 1, keyMaterial);
452     rx_opaque_free(&keyMaterial);
453     code = afsconf_AddTypedKey(dir, typedKey, 1);
454     afsconf_typedKey_put(&typedKey);
455     is_int(AFSCONF_BADKEY, code,
456            "afsconf_AddTypedKey won't add rxkad keys with non-zero subtype");
457
458     /* Now, test things with other key types. */
459
460     /* Add a different key type, but with same kvno as rxkad */
461     keyMaterial = rx_opaque_new("\x01", 1);
462     typedKey = afsconf_typedKey_new(1, 2, 0, keyMaterial);
463     code = afsconf_AddTypedKey(dir, typedKey, 0);
464     afsconf_typedKey_put(&typedKey);
465     is_int(0, code,
466            "afsconf_AddTypedKey can add keys with different key type");
467
468     /* Add a different subtype, with same kvno */
469     keyMaterial = rx_opaque_new("\x02\x03", 2);
470     typedKey = afsconf_typedKey_new(1, 2, 1, keyMaterial);
471     code = afsconf_AddTypedKey(dir, typedKey, 0);
472     afsconf_typedKey_put(&typedKey);
473     is_int(0, code,
474            "afsconf_AddTypedKey can add keys with different sub type");
475
476     /* Check the GetKeyByTypes returns one of the keys */
477     code = afsconf_GetKeyByTypes(dir, 1, 2, 1, &typedKey);
478     is_int(0, code, "afsconf_GetKeyByTypes returns");
479     ok(keyMatches(typedKey, 1, 2, 1, "\x02\x03", 2),
480        " ... with the right key");
481
482     /* Check that GetKeysByType returns both of the keys */
483     code = afsconf_GetKeysByType(dir, 1, 2, &typedKeyList);
484     is_int(0, code, "afsconf_GetKeysByType returns");
485     is_int(2, typedKeyList->nkeys, " ... with correct number of keys");
486     ok(keyMatches(typedKeyList->keys[0], 1, 2, 0, "\x01", 1),
487        " ... with the right key in slot 0");
488     ok(keyMatches(typedKeyList->keys[1], 1, 2, 1, "\x02\x03", 2),
489        " ... with the right key in slot 1");
490     afsconf_PutTypedKeyList(&typedKeyList);
491
492     /* Add another key, before these ones, so we can check that
493      * latest really works */
494     keyMaterial = rx_opaque_new("\x03", 1);
495     typedKey = afsconf_typedKey_new(1, 1, 0, keyMaterial);
496     code = afsconf_AddTypedKey(dir, typedKey, 0);
497     afsconf_typedKey_put(&typedKey);
498     is_int(0, code, "afsconf_AddTypedKey worked again");
499
500     /* Check that GetLatestKeyByTypes returns one */
501     code = afsconf_GetLatestKeyByTypes(dir, 1, 1, &typedKey);
502     is_int(0, code, "afsconf_GetLatestKeyByTypes returns");
503     ok(keyMatches(typedKey, 1, 2, 1, "\x02\x03", 2),
504        " ... with the right key");
505
506     /* Check that GetLatestKeysByType returns both */
507     code = afsconf_GetLatestKeysByType(dir, 1, &typedKeyList);
508     is_int(0, code, "afsconf_GetLatestKeysByType returns");
509         is_int(2, typedKeyList->nkeys, " ... with correct number of keys");
510     ok(keyMatches(typedKeyList->keys[0], 1, 2, 0, "\x01", 1),
511        " ... with the right key in slot 0");
512     ok(keyMatches(typedKeyList->keys[1], 1, 2, 1, "\x02\x03", 2),
513        " ... with the right key in slot 1");
514     afsconf_PutTypedKeyList(&typedKeyList);
515
516     /* Check that closing this instance, and reopening, still has all of
517      * the required keys
518      */
519     afsconf_Close(dir);
520
521     *dirEnd='\0';
522     dir = afsconf_Open(strdup(buffer));
523     ok(dir != NULL, "Sucessfully re-opened config directory");
524     if (dir == NULL)
525         goto out;
526
527     /* Check that GetKeysByType returns all of the keys */
528     code = afsconf_GetKeysByType(dir, 1, 1, &typedKeyList);
529     is_int(0, code, "afsconf_GetKeysByType returns after reopening");
530     is_int(1, typedKeyList->nkeys, " ... First kvno has correct number of keys");
531     ok(keyMatches(typedKeyList->keys[0], 1, 1, 0, "\x03", 1),
532        " ... and key material is correct");
533     afsconf_PutTypedKeyList(&typedKeyList);
534
535     code = afsconf_GetKeysByType(dir, 1, 2, &typedKeyList);
536     is_int(0, code, "afsconf_GetKeysByType returns after reopening");
537     is_int(2, typedKeyList->nkeys, " ... with correct number of keys");
538     ok(keyMatches(typedKeyList->keys[0], 1, 2, 0, "\x01", 1),
539        " ... with the right key in slot 0");
540     ok(keyMatches(typedKeyList->keys[1], 1, 2, 1, "\x02\x03", 2),
541        " ... with the right key in slot 1");
542     afsconf_PutTypedKeyList(&typedKeyList);
543
544 out:
545     strcpy(dirEnd, "/KeyFile");
546     unlink(buffer);
547     strcpy(dirEnd, "/CellServDB");
548     unlink(buffer);
549     strcpy(dirEnd, "/ThisCell");
550     unlink(buffer);
551     strcpy(dirEnd, "/UserList");
552     unlink(buffer);
553     *dirEnd='\0';
554     rmdir(buffer);
555
556     return 0;
557 }