]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tools/tools/crypto/cryptocheck.c
Upgrade Unbound to 1.6.2. More to follow.
[FreeBSD/FreeBSD.git] / tools / tools / crypto / cryptocheck.c
1 /*-
2  * Copyright (c) 2017 Chelsio Communications, Inc.
3  * All rights reserved.
4  * Written by: John Baldwin <jhb@FreeBSD.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 /*-
28  * Copyright (c) 2004 Sam Leffler, Errno Consulting
29  * All rights reserved.
30  *
31  * Redistribution and use in source and binary forms, with or without
32  * modification, are permitted provided that the following conditions
33  * are met:
34  * 1. Redistributions of source code must retain the above copyright
35  *    notice, this list of conditions and the following disclaimer,
36  *    without modification.
37  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
38  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
39  *    redistribution must be conditioned upon including a substantially
40  *    similar Disclaimer requirement for further binary redistribution.
41  * 3. Neither the names of the above-listed copyright holders nor the names
42  *    of any contributors may be used to endorse or promote products derived
43  *    from this software without specific prior written permission.
44  *
45  * NO WARRANTY
46  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
47  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
48  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
49  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
50  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
51  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
52  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
53  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
54  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
55  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
56  * THE POSSIBILITY OF SUCH DAMAGES.
57  *
58  * $FreeBSD$
59  */
60
61 /*
62  * A different tool for checking hardware crypto support.  Whereas
63  * cryptotest is focused on simple performance numbers, this tool is
64  * focused on correctness.  For each crypto operation, it performs the
65  * operation once in software via OpenSSL and a second time via
66  * OpenCrypto and compares the results.
67  *
68  * cryptocheck [-vz] [-A aad length] [-a algorithm] [-d dev] [size ...]
69  *
70  * Options:
71  *      -v      Verbose.
72  *      -z      Run all algorithms on a variety of buffer sizes.
73  *
74  * Supported algorithms:
75  *      all             Run all tests
76  *      hmac            Run all hmac tests
77  *      blkcipher       Run all block cipher tests
78  *      authenc         Run all authenticated encryption tests
79  *      aead            Run all authenticated encryption with associated data
80  *                      tests
81  *
82  * HMACs:
83  *      sha1            sha1 hmac
84  *      sha256          256-bit sha2 hmac
85  *      sha384          384-bit sha2 hmac
86  *      sha512          512-bit sha2 hmac
87  *      blake2b         Blake2-B
88  *      blake2s         Blake2-S
89  *
90  * Block Ciphers:
91  *      aes-cbc         128-bit aes cbc
92  *      aes-cbc192      192-bit aes cbc
93  *      aes-cbc256      256-bit aes cbc
94  *      aes-ctr         128-bit aes ctr
95  *      aes-ctr192      192-bit aes ctr
96  *      aes-ctr256      256-bit aes ctr
97  *      aes-xts         128-bit aes xts
98  *      aes-xts256      256-bit aes xts
99  *      chacha20
100  *
101  * Authenticated Encryption:
102  *      <block cipher>+<hmac>
103  *
104  * Authenticated Encryption with Associated Data:
105  *      aes-gcm         128-bit aes gcm
106  *      aes-gcm192      192-bit aes gcm
107  *      aes-gcm256      256-bit aes gcm
108  */
109
110 #include <sys/param.h>
111 #include <assert.h>
112 #include <err.h>
113 #include <fcntl.h>
114 #include <libutil.h>
115 #include <stdbool.h>
116 #include <stdio.h>
117 #include <string.h>
118 #include <unistd.h>
119
120 #include <openssl/err.h>
121 #include <openssl/hmac.h>
122
123 #include <crypto/cryptodev.h>
124
125 /* XXX: Temporary hack */
126 #ifndef COP_F_CIPHER_FIRST
127 #define COP_F_CIPHER_FIRST      0x0001  /* Cipher before MAC. */
128 #endif
129
130 struct alg {
131         const char *name;
132         int cipher;
133         int mac;
134         enum { T_HMAC, T_BLKCIPHER, T_AUTHENC, T_GCM } type;
135         const EVP_CIPHER *(*evp_cipher)(void);
136         const EVP_MD *(*evp_md)(void);
137 } algs[] = {
138         { .name = "sha1", .mac = CRYPTO_SHA1_HMAC, .type = T_HMAC,
139           .evp_md = EVP_sha1 },
140         { .name = "sha256", .mac = CRYPTO_SHA2_256_HMAC, .type = T_HMAC,
141           .evp_md = EVP_sha256 },
142         { .name = "sha384", .mac = CRYPTO_SHA2_384_HMAC, .type = T_HMAC,
143           .evp_md = EVP_sha384 },
144         { .name = "sha512", .mac = CRYPTO_SHA2_512_HMAC, .type = T_HMAC,
145           .evp_md = EVP_sha512 },
146         { .name = "blake2b", .mac = CRYPTO_BLAKE2B, .type = T_HMAC,
147           .evp_md = EVP_blake2b512 },
148         { .name = "blake2s", .mac = CRYPTO_BLAKE2S, .type = T_HMAC,
149           .evp_md = EVP_blake2s256 },
150         { .name = "aes-cbc", .cipher = CRYPTO_AES_CBC, .type = T_BLKCIPHER,
151           .evp_cipher = EVP_aes_128_cbc },
152         { .name = "aes-cbc192", .cipher = CRYPTO_AES_CBC, .type = T_BLKCIPHER,
153           .evp_cipher = EVP_aes_192_cbc },
154         { .name = "aes-cbc256", .cipher = CRYPTO_AES_CBC, .type = T_BLKCIPHER,
155           .evp_cipher = EVP_aes_256_cbc },
156         { .name = "aes-ctr", .cipher = CRYPTO_AES_ICM, .type = T_BLKCIPHER,
157           .evp_cipher = EVP_aes_128_ctr },
158         { .name = "aes-ctr192", .cipher = CRYPTO_AES_ICM, .type = T_BLKCIPHER,
159           .evp_cipher = EVP_aes_192_ctr },
160         { .name = "aes-ctr256", .cipher = CRYPTO_AES_ICM, .type = T_BLKCIPHER,
161           .evp_cipher = EVP_aes_256_ctr },
162         { .name = "aes-xts", .cipher = CRYPTO_AES_XTS, .type = T_BLKCIPHER,
163           .evp_cipher = EVP_aes_128_xts },
164         { .name = "aes-xts256", .cipher = CRYPTO_AES_XTS, .type = T_BLKCIPHER,
165           .evp_cipher = EVP_aes_256_xts },
166         { .name = "chacha20", .cipher = CRYPTO_CHACHA20, .type = T_BLKCIPHER,
167           .evp_cipher = EVP_chacha20 },
168         { .name = "aes-gcm", .cipher = CRYPTO_AES_NIST_GCM_16,
169           .mac = CRYPTO_AES_128_NIST_GMAC, .type = T_GCM,
170           .evp_cipher = EVP_aes_128_gcm },
171         { .name = "aes-gcm192", .cipher = CRYPTO_AES_NIST_GCM_16,
172           .mac = CRYPTO_AES_192_NIST_GMAC, .type = T_GCM,
173           .evp_cipher = EVP_aes_192_gcm },
174         { .name = "aes-gcm256", .cipher = CRYPTO_AES_NIST_GCM_16,
175           .mac = CRYPTO_AES_256_NIST_GMAC, .type = T_GCM,
176           .evp_cipher = EVP_aes_256_gcm },
177 };
178
179 static bool verbose;
180 static int crid;
181 static size_t aad_len;
182
183 static void
184 usage(void)
185 {
186         fprintf(stderr,
187             "usage: cryptocheck [-z] [-a algorithm] [-d dev] [size ...]\n");
188         exit(1);
189 }
190
191 static struct alg *
192 find_alg(const char *name)
193 {
194         u_int i;
195
196         for (i = 0; i < nitems(algs); i++)
197                 if (strcasecmp(algs[i].name, name) == 0)
198                         return (&algs[i]);
199         return (NULL);
200 }
201
202 static struct alg *
203 build_authenc(struct alg *cipher, struct alg *hmac)
204 {
205         static struct alg authenc;
206         char *name;
207
208         assert(cipher->type == T_BLKCIPHER);
209         assert(hmac->type == T_HMAC);
210         memset(&authenc, 0, sizeof(authenc));
211         asprintf(&name, "%s+%s", cipher->name, hmac->name);
212         authenc.name = name;
213         authenc.cipher = cipher->cipher;
214         authenc.mac = hmac->mac;
215         authenc.type = T_AUTHENC;
216         authenc.evp_cipher = cipher->evp_cipher;
217         authenc.evp_md = hmac->evp_md;
218         return (&authenc);
219 }
220
221 static struct alg *
222 build_authenc_name(const char *name)
223 {
224         struct alg *cipher, *hmac;
225         const char *hmac_name;
226         char *cp, *cipher_name;
227
228         cp = strchr(name, '+');
229         cipher_name = strndup(name, cp - name);
230         hmac_name = cp + 1;
231         cipher = find_alg(cipher_name);
232         free(cipher_name);
233         if (cipher == NULL)
234                 errx(1, "Invalid cipher %s", cipher_name);
235         hmac = find_alg(hmac_name);
236         if (hmac == NULL)
237                 errx(1, "Invalid hash %s", hmac_name);
238         return (build_authenc(cipher, hmac));
239 }
240
241 static int
242 devcrypto(void)
243 {
244         static int fd = -1;
245
246         if (fd < 0) {
247                 fd = open("/dev/crypto", O_RDWR | O_CLOEXEC, 0);
248                 if (fd < 0)
249                         err(1, "/dev/crypto");
250         }
251         return (fd);
252 }
253
254 static int
255 crlookup(const char *devname)
256 {
257         struct crypt_find_op find;
258
259         if (strncmp(devname, "soft", 4) == 0)
260                 return CRYPTO_FLAG_SOFTWARE;
261
262         find.crid = -1;
263         strlcpy(find.name, devname, sizeof(find.name));
264         if (ioctl(devcrypto(), CIOCFINDDEV, &find) == -1)
265                 err(1, "ioctl(CIOCFINDDEV)");
266         return (find.crid);
267 }
268
269 const char *
270 crfind(int crid)
271 {
272         static struct crypt_find_op find;
273
274         if (crid == CRYPTO_FLAG_SOFTWARE)
275                 return ("soft");
276         else if (crid == CRYPTO_FLAG_HARDWARE)
277                 return ("unknown");
278
279         bzero(&find, sizeof(find));
280         find.crid = crid;
281         if (ioctl(devcrypto(), CRIOFINDDEV, &find) == -1)
282                 err(1, "ioctl(CIOCFINDDEV): crid %d", crid);
283         return (find.name);
284 }
285
286 static int
287 crget(void)
288 {
289         int fd;
290
291         if (ioctl(devcrypto(), CRIOGET, &fd) == -1)
292                 err(1, "ioctl(CRIOGET)");
293         if (fcntl(fd, F_SETFD, 1) == -1)
294                 err(1, "fcntl(F_SETFD) (crget)");
295         return fd;
296 }
297
298 static char
299 rdigit(void)
300 {
301         const char a[] = {
302                 0x10,0x54,0x11,0x48,0x45,0x12,0x4f,0x13,0x49,0x53,0x14,0x41,
303                 0x15,0x16,0x4e,0x55,0x54,0x17,0x18,0x4a,0x4f,0x42,0x19,0x01
304         };
305         return 0x20+a[random()%nitems(a)];
306 }
307
308 static char *
309 alloc_buffer(size_t len)
310 {
311         char *buf;
312         size_t i;
313
314         buf = malloc(len);
315         for (i = 0; i < len; i++)
316                 buf[i] = rdigit();
317         return (buf);
318 }
319
320 static char *
321 generate_iv(size_t len, struct alg *alg)
322 {
323         char *iv;
324
325         iv = alloc_buffer(len);
326         switch (alg->cipher) {
327         case CRYPTO_AES_ICM:
328                 /* Clear the low 32 bits of the IV to hold the counter. */
329                 iv[len - 4] = 0;
330                 iv[len - 3] = 0;
331                 iv[len - 2] = 0;
332                 iv[len - 1] = 0;
333                 break;
334         case CRYPTO_AES_XTS:
335                 /*
336                  * Clear the low 64-bits to only store a 64-bit block
337                  * number.
338                  */
339                 iv[len - 8] = 0;
340                 iv[len - 7] = 0;
341                 iv[len - 6] = 0;
342                 iv[len - 5] = 0;
343                 iv[len - 4] = 0;
344                 iv[len - 3] = 0;
345                 iv[len - 2] = 0;
346                 iv[len - 1] = 0;
347                 break;
348         }
349         return (iv);
350 }
351
352 static bool
353 ocf_hmac(struct alg *alg, const char *buffer, size_t size, const char *key,
354     size_t key_len, char *digest, int *cridp)
355 {
356         struct session2_op sop;
357         struct crypt_op cop;
358         int fd;
359
360         memset(&sop, 0, sizeof(sop));
361         memset(&cop, 0, sizeof(cop));
362         sop.crid = crid;
363         sop.mackeylen = key_len;
364         sop.mackey = (char *)key;
365         sop.mac = alg->mac;
366         fd = crget();
367         if (ioctl(fd, CIOCGSESSION2, &sop) < 0) {
368                 warn("cryptodev %s HMAC not supported for device %s",
369                     alg->name, crfind(crid));
370                 close(fd);
371                 return (false);
372         }
373
374         cop.ses = sop.ses;
375         cop.op = 0;
376         cop.len = size;
377         cop.src = (char *)buffer;
378         cop.dst = NULL;
379         cop.mac = digest;
380         cop.iv = NULL;
381
382         if (ioctl(fd, CIOCCRYPT, &cop) < 0) {
383                 warn("cryptodev %s (%zu) HMAC failed for device %s", alg->name,
384                     size, crfind(crid));
385                 close(fd);
386                 return (false);
387         }
388
389         if (ioctl(fd, CIOCFSESSION, &sop.ses) < 0)
390                 warn("ioctl(CIOCFSESSION)");
391
392         close(fd);
393         *cridp = sop.crid;
394         return (true);
395 }
396
397 static void
398 run_hmac_test(struct alg *alg, size_t size)
399 {
400         const EVP_MD *md;
401         char *key, *buffer;
402         u_int key_len, digest_len;
403         int crid;
404         char control_digest[EVP_MAX_MD_SIZE], test_digest[EVP_MAX_MD_SIZE];
405
406         memset(control_digest, 0x3c, sizeof(control_digest));
407         memset(test_digest, 0x3c, sizeof(test_digest));
408
409         md = alg->evp_md();
410         key_len = EVP_MD_size(md);
411         assert(EVP_MD_size(md) <= sizeof(control_digest));
412
413         key = alloc_buffer(key_len);
414         buffer = alloc_buffer(size);
415
416         /* OpenSSL HMAC. */
417         digest_len = sizeof(control_digest);
418         if (HMAC(md, key, key_len, (u_char *)buffer, size,
419             (u_char *)control_digest, &digest_len) == NULL)
420                 errx(1, "OpenSSL %s (%zu) HMAC failed: %s", alg->name,
421                     size, ERR_error_string(ERR_get_error(), NULL));
422
423         /* cryptodev HMAC. */
424         if (!ocf_hmac(alg, buffer, size, key, key_len, test_digest, &crid))
425                 goto out;
426         if (memcmp(control_digest, test_digest, sizeof(control_digest)) != 0) {
427                 if (memcmp(control_digest, test_digest, EVP_MD_size(md)) == 0)
428                         printf("%s (%zu) mismatch in trailer:\n",
429                             alg->name, size);
430                 else
431                         printf("%s (%zu) mismatch:\n", alg->name, size);
432                 printf("control:\n");
433                 hexdump(control_digest, sizeof(control_digest), NULL, 0);
434                 printf("test (cryptodev device %s):\n", crfind(crid));
435                 hexdump(test_digest, sizeof(test_digest), NULL, 0);
436                 goto out;
437         }
438
439         if (verbose)
440                 printf("%s (%zu) matched (cryptodev device %s)\n",
441                     alg->name, size, crfind(crid));
442
443 out:
444         free(buffer);
445         free(key);
446 }
447
448 static void
449 openssl_cipher(struct alg *alg, const EVP_CIPHER *cipher, const char *key,
450     const char *iv, const char *input, char *output, size_t size, int enc)
451 {
452         EVP_CIPHER_CTX *ctx;
453         int outl, total;
454
455         ctx = EVP_CIPHER_CTX_new();
456         if (ctx == NULL)
457                 errx(1, "OpenSSL %s (%zu) ctx new failed: %s", alg->name,
458                     size, ERR_error_string(ERR_get_error(), NULL));
459         if (EVP_CipherInit_ex(ctx, cipher, NULL, (const u_char *)key,
460             (const u_char *)iv, enc) != 1)
461                 errx(1, "OpenSSL %s (%zu) ctx init failed: %s", alg->name,
462                     size, ERR_error_string(ERR_get_error(), NULL));
463         EVP_CIPHER_CTX_set_padding(ctx, 0);
464         if (EVP_CipherUpdate(ctx, (u_char *)output, &outl,
465             (const u_char *)input, size) != 1)
466                 errx(1, "OpenSSL %s (%zu) cipher update failed: %s", alg->name,
467                     size, ERR_error_string(ERR_get_error(), NULL));
468         total = outl;
469         if (EVP_CipherFinal_ex(ctx, (u_char *)output + outl, &outl) != 1)
470                 errx(1, "OpenSSL %s (%zu) cipher final failed: %s", alg->name,
471                     size, ERR_error_string(ERR_get_error(), NULL));
472         total += outl;
473         if (total != size)
474                 errx(1, "OpenSSL %s (%zu) cipher size mismatch: %d", alg->name,
475                     size, total);
476         EVP_CIPHER_CTX_free(ctx);
477 }
478
479 static bool
480 ocf_cipher(struct alg *alg, const char *key, size_t key_len,
481     const char *iv, const char *input, char *output, size_t size, int enc,
482     int *cridp)
483 {
484         struct session2_op sop;
485         struct crypt_op cop;
486         int fd;
487
488         memset(&sop, 0, sizeof(sop));
489         memset(&cop, 0, sizeof(cop));
490         sop.crid = crid;
491         sop.keylen = key_len;
492         sop.key = (char *)key;
493         sop.cipher = alg->cipher;
494         fd = crget();
495         if (ioctl(fd, CIOCGSESSION2, &sop) < 0) {
496                 warn("cryptodev %s block cipher not supported for device %s",
497                     alg->name, crfind(crid));
498                 close(fd);
499                 return (false);
500         }
501
502         cop.ses = sop.ses;
503         cop.op = enc ? COP_ENCRYPT : COP_DECRYPT;
504         cop.len = size;
505         cop.src = (char *)input;
506         cop.dst = output;
507         cop.mac = NULL;
508         cop.iv = (char *)iv;
509
510         if (ioctl(fd, CIOCCRYPT, &cop) < 0) {
511                 warn("cryptodev %s (%zu) block cipher failed for device %s",
512                     alg->name, size, crfind(crid));
513                 close(fd);
514                 return (false);
515         }
516
517         if (ioctl(fd, CIOCFSESSION, &sop.ses) < 0)
518                 warn("ioctl(CIOCFSESSION)");
519
520         close(fd);
521         *cridp = sop.crid;
522         return (true);
523 }
524
525 static void
526 run_blkcipher_test(struct alg *alg, size_t size)
527 {
528         const EVP_CIPHER *cipher;
529         char *buffer, *cleartext, *ciphertext;
530         char *iv, *key;
531         u_int iv_len, key_len;
532         int crid;
533
534         cipher = alg->evp_cipher();
535         if (size % EVP_CIPHER_block_size(cipher) != 0) {
536                 if (verbose)
537                         printf(
538                             "%s (%zu): invalid buffer size (block size %d)\n",
539                             alg->name, size, EVP_CIPHER_block_size(cipher));
540                 return;
541         }
542
543         key_len = EVP_CIPHER_key_length(cipher);
544         iv_len = EVP_CIPHER_iv_length(cipher);
545
546         key = alloc_buffer(key_len);
547         iv = generate_iv(iv_len, alg);
548         cleartext = alloc_buffer(size);
549         buffer = malloc(size);
550         ciphertext = malloc(size);
551
552         /* OpenSSL cipher. */
553         openssl_cipher(alg, cipher, key, iv, cleartext, ciphertext, size, 1);
554         if (size > 0 && memcmp(cleartext, ciphertext, size) == 0)
555                 errx(1, "OpenSSL %s (%zu): cipher text unchanged", alg->name,
556                     size);
557         openssl_cipher(alg, cipher, key, iv, ciphertext, buffer, size, 0);
558         if (memcmp(cleartext, buffer, size) != 0) {
559                 printf("OpenSSL %s (%zu): cipher mismatch:", alg->name, size);
560                 printf("original:\n");
561                 hexdump(cleartext, size, NULL, 0);
562                 printf("decrypted:\n");
563                 hexdump(buffer, size, NULL, 0);
564                 exit(1);
565         }
566
567         /* OCF encrypt. */
568         if (!ocf_cipher(alg, key, key_len, iv, cleartext, buffer, size, 1,
569             &crid))
570                 goto out;
571         if (memcmp(ciphertext, buffer, size) != 0) {
572                 printf("%s (%zu) encryption mismatch:\n", alg->name, size);
573                 printf("control:\n");
574                 hexdump(ciphertext, size, NULL, 0);
575                 printf("test (cryptodev device %s):\n", crfind(crid));
576                 hexdump(buffer, size, NULL, 0);
577                 goto out;
578         }
579
580         /* OCF decrypt. */
581         if (!ocf_cipher(alg, key, key_len, iv, ciphertext, buffer, size, 0,
582             &crid))
583                 goto out;
584         if (memcmp(cleartext, buffer, size) != 0) {
585                 printf("%s (%zu) decryption mismatch:\n", alg->name, size);
586                 printf("control:\n");
587                 hexdump(cleartext, size, NULL, 0);
588                 printf("test (cryptodev device %s):\n", crfind(crid));
589                 hexdump(buffer, size, NULL, 0);
590                 goto out;
591         }
592
593         if (verbose)
594                 printf("%s (%zu) matched (cryptodev device %s)\n",
595                     alg->name, size, crfind(crid));
596
597 out:
598         free(ciphertext);
599         free(buffer);
600         free(cleartext);
601         free(iv);
602         free(key);
603 }
604
605 static bool
606 ocf_authenc(struct alg *alg, const char *cipher_key, size_t cipher_key_len,
607     const char *iv, size_t iv_len, const char *auth_key, size_t auth_key_len,
608     const char *aad, size_t aad_len, const char *input, char *output,
609     size_t size, char *digest, int enc, int *cridp)
610 {
611         struct session2_op sop;
612         int fd;
613
614         memset(&sop, 0, sizeof(sop));
615         sop.crid = crid;
616         sop.keylen = cipher_key_len;
617         sop.key = (char *)cipher_key;
618         sop.cipher = alg->cipher;
619         sop.mackeylen = auth_key_len;
620         sop.mackey = (char *)auth_key;
621         sop.mac = alg->mac;
622         fd = crget();
623         if (ioctl(fd, CIOCGSESSION2, &sop) < 0) {
624                 warn("cryptodev %s AUTHENC not supported for device %s",
625                     alg->name, crfind(crid));
626                 close(fd);
627                 return (false);
628         }
629
630         if (aad_len != 0) {
631                 struct crypt_aead caead;
632
633                 memset(&caead, 0, sizeof(caead));
634                 caead.ses = sop.ses;
635                 caead.op = enc ? COP_ENCRYPT : COP_DECRYPT;
636                 caead.flags = enc ? COP_F_CIPHER_FIRST : 0;
637                 caead.len = size;
638                 caead.aadlen = aad_len;
639                 caead.ivlen = iv_len;
640                 caead.src = (char *)input;
641                 caead.dst = output;
642                 caead.aad = (char *)aad;
643                 caead.tag = digest;
644                 caead.iv = (char *)iv;
645
646                 if (ioctl(fd, CIOCCRYPTAEAD, &caead) < 0) {
647                         warn("cryptodev %s (%zu) failed for device %s",
648                             alg->name, size, crfind(crid));
649                         close(fd);
650                         return (false);
651                 }
652         } else {
653                 struct crypt_op cop;
654
655                 memset(&cop, 0, sizeof(cop));
656                 cop.ses = sop.ses;
657                 cop.op = enc ? COP_ENCRYPT : COP_DECRYPT;
658                 cop.flags = enc ? COP_F_CIPHER_FIRST : 0;
659                 cop.len = size;
660                 cop.src = (char *)input;
661                 cop.dst = output;
662                 cop.mac = digest;
663                 cop.iv = (char *)iv;
664
665                 if (ioctl(fd, CIOCCRYPT, &cop) < 0) {
666                         warn("cryptodev %s (%zu) AUTHENC failed for device %s",
667                             alg->name, size, crfind(crid));
668                         close(fd);
669                         return (false);
670                 }
671         }
672
673         if (ioctl(fd, CIOCFSESSION, &sop.ses) < 0)
674                 warn("ioctl(CIOCFSESSION)");
675
676         close(fd);
677         *cridp = sop.crid;
678         return (true);
679 }
680
681 static void
682 run_authenc_test(struct alg *alg, size_t size)
683 {
684         const EVP_CIPHER *cipher;
685         const EVP_MD *md;
686         char *aad, *buffer, *cleartext, *ciphertext;
687         char *iv, *auth_key, *cipher_key;
688         u_int iv_len, auth_key_len, cipher_key_len, digest_len;
689         int crid;
690         char control_digest[EVP_MAX_MD_SIZE], test_digest[EVP_MAX_MD_SIZE];
691
692         cipher = alg->evp_cipher();
693         if (size % EVP_CIPHER_block_size(cipher) != 0) {
694                 if (verbose)
695                         printf(
696                             "%s (%zu): invalid buffer size (block size %d)\n",
697                             alg->name, size, EVP_CIPHER_block_size(cipher));
698                 return;
699         }
700
701         memset(control_digest, 0x3c, sizeof(control_digest));
702         memset(test_digest, 0x3c, sizeof(test_digest));
703
704         md = alg->evp_md();
705
706         cipher_key_len = EVP_CIPHER_key_length(cipher);
707         iv_len = EVP_CIPHER_iv_length(cipher);
708         auth_key_len = EVP_MD_size(md);
709
710         cipher_key = alloc_buffer(cipher_key_len);
711         iv = generate_iv(iv_len, alg);
712         auth_key = alloc_buffer(auth_key_len);
713         cleartext = alloc_buffer(aad_len + size);
714         buffer = malloc(aad_len + size);
715         ciphertext = malloc(aad_len + size);
716
717         /* OpenSSL encrypt + HMAC. */
718         if (aad_len != 0)
719                 memcpy(ciphertext, cleartext, aad_len);
720         openssl_cipher(alg, cipher, cipher_key, iv, cleartext + aad_len,
721             ciphertext + aad_len, size, 1);
722         if (size > 0 && memcmp(cleartext + aad_len, ciphertext + aad_len,
723             size) == 0)
724                 errx(1, "OpenSSL %s (%zu): cipher text unchanged", alg->name,
725                     size);
726         digest_len = sizeof(control_digest);
727         if (HMAC(md, auth_key, auth_key_len, (u_char *)ciphertext,
728             aad_len + size, (u_char *)control_digest, &digest_len) == NULL)
729                 errx(1, "OpenSSL %s (%zu) HMAC failed: %s", alg->name,
730                     size, ERR_error_string(ERR_get_error(), NULL));
731
732         /* OCF encrypt + HMAC. */
733         if (!ocf_authenc(alg, cipher_key, cipher_key_len, iv, iv_len, auth_key,
734             auth_key_len, aad_len != 0 ? cleartext : NULL, aad_len,
735             cleartext + aad_len, buffer + aad_len, size, test_digest, 1, &crid))
736                 goto out;
737         if (memcmp(ciphertext + aad_len, buffer + aad_len, size) != 0) {
738                 printf("%s (%zu) encryption mismatch:\n", alg->name, size);
739                 printf("control:\n");
740                 hexdump(ciphertext + aad_len, size, NULL, 0);
741                 printf("test (cryptodev device %s):\n", crfind(crid));
742                 hexdump(buffer + aad_len, size, NULL, 0);
743                 goto out;
744         }
745         if (memcmp(control_digest, test_digest, sizeof(control_digest)) != 0) {
746                 if (memcmp(control_digest, test_digest, EVP_MD_size(md)) == 0)
747                         printf("%s (%zu) enc hash mismatch in trailer:\n",
748                             alg->name, size);
749                 else
750                         printf("%s (%zu) enc hash mismatch:\n", alg->name,
751                             size);
752                 printf("control:\n");
753                 hexdump(control_digest, sizeof(control_digest), NULL, 0);
754                 printf("test (cryptodev device %s):\n", crfind(crid));
755                 hexdump(test_digest, sizeof(test_digest), NULL, 0);
756                 goto out;
757         }
758
759         /* OCF HMAC + decrypt. */
760         memset(test_digest, 0x3c, sizeof(test_digest));
761         if (!ocf_authenc(alg, cipher_key, cipher_key_len, iv, iv_len, auth_key,
762             auth_key_len, aad_len != 0 ? ciphertext : NULL, aad_len,
763             ciphertext + aad_len, buffer + aad_len, size, test_digest, 0,
764             &crid))
765                 goto out;
766         if (memcmp(control_digest, test_digest, sizeof(control_digest)) != 0) {
767                 if (memcmp(control_digest, test_digest, EVP_MD_size(md)) == 0)
768                         printf("%s (%zu) dec hash mismatch in trailer:\n",
769                             alg->name, size);
770                 else
771                         printf("%s (%zu) dec hash mismatch:\n", alg->name,
772                             size);
773                 printf("control:\n");
774                 hexdump(control_digest, sizeof(control_digest), NULL, 0);
775                 printf("test (cryptodev device %s):\n", crfind(crid));
776                 hexdump(test_digest, sizeof(test_digest), NULL, 0);
777                 goto out;
778         }
779         if (memcmp(cleartext + aad_len, buffer + aad_len, size) != 0) {
780                 printf("%s (%zu) decryption mismatch:\n", alg->name, size);
781                 printf("control:\n");
782                 hexdump(cleartext, size, NULL, 0);
783                 printf("test (cryptodev device %s):\n", crfind(crid));
784                 hexdump(buffer, size, NULL, 0);
785                 goto out;
786         }
787
788         if (verbose)
789                 printf("%s (%zu) matched (cryptodev device %s)\n",
790                     alg->name, size, crfind(crid));
791
792 out:
793         free(ciphertext);
794         free(buffer);
795         free(cleartext);
796         free(auth_key);
797         free(iv);
798         free(cipher_key);
799 }
800
801 static void
802 openssl_gcm_encrypt(struct alg *alg, const EVP_CIPHER *cipher, const char *key,
803     const char *iv, const char *aad, size_t aad_len, const char *input,
804     char *output, size_t size, char *tag)
805 {
806         EVP_CIPHER_CTX *ctx;
807         int outl, total;
808
809         ctx = EVP_CIPHER_CTX_new();
810         if (ctx == NULL)
811                 errx(1, "OpenSSL %s (%zu) ctx new failed: %s", alg->name,
812                     size, ERR_error_string(ERR_get_error(), NULL));
813         if (EVP_EncryptInit_ex(ctx, cipher, NULL, (const u_char *)key,
814             (const u_char *)iv) != 1)
815                 errx(1, "OpenSSL %s (%zu) ctx init failed: %s", alg->name,
816                     size, ERR_error_string(ERR_get_error(), NULL));
817         EVP_CIPHER_CTX_set_padding(ctx, 0);
818         if (aad != NULL) {
819                 if (EVP_EncryptUpdate(ctx, NULL, &outl, (const u_char *)aad,
820                     aad_len) != 1)
821                         errx(1, "OpenSSL %s (%zu) aad update failed: %s",
822                             alg->name, size,
823                             ERR_error_string(ERR_get_error(), NULL));
824         }
825         if (EVP_EncryptUpdate(ctx, (u_char *)output, &outl,
826             (const u_char *)input, size) != 1)
827                 errx(1, "OpenSSL %s (%zu) encrypt update failed: %s", alg->name,
828                     size, ERR_error_string(ERR_get_error(), NULL));
829         total = outl;
830         if (EVP_EncryptFinal_ex(ctx, (u_char *)output + outl, &outl) != 1)
831                 errx(1, "OpenSSL %s (%zu) encrypt final failed: %s", alg->name,
832                     size, ERR_error_string(ERR_get_error(), NULL));
833         total += outl;
834         if (total != size)
835                 errx(1, "OpenSSL %s (%zu) encrypt size mismatch: %d", alg->name,
836                     size, total);
837         if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, AES_GMAC_HASH_LEN,
838             tag) != 1)
839                 errx(1, "OpenSSL %s (%zu) get tag failed: %s", alg->name,
840                     size, ERR_error_string(ERR_get_error(), NULL));
841         EVP_CIPHER_CTX_free(ctx);
842 }
843
844 static bool
845 ocf_gcm(struct alg *alg, const char *key, size_t key_len, const char *iv,
846     size_t iv_len, const char *aad, size_t aad_len, const char *input,
847     char *output, size_t size, char *tag, int enc, int *cridp)
848 {
849         struct session2_op sop;
850         struct crypt_aead caead;
851         int fd;
852
853         memset(&sop, 0, sizeof(sop));
854         memset(&caead, 0, sizeof(caead));
855         sop.crid = crid;
856         sop.keylen = key_len;
857         sop.key = (char *)key;
858         sop.cipher = alg->cipher;
859         sop.mackeylen = key_len;
860         sop.mackey = (char *)key;
861         sop.mac = alg->mac;
862         fd = crget();
863         if (ioctl(fd, CIOCGSESSION2, &sop) < 0) {
864                 warn("cryptodev %s not supported for device %s",
865                     alg->name, crfind(crid));
866                 close(fd);
867                 return (false);
868         }
869
870         caead.ses = sop.ses;
871         caead.op = enc ? COP_ENCRYPT : COP_DECRYPT;
872         caead.len = size;
873         caead.aadlen = aad_len;
874         caead.ivlen = iv_len;
875         caead.src = (char *)input;
876         caead.dst = output;
877         caead.aad = (char *)aad;
878         caead.tag = tag;
879         caead.iv = (char *)iv;
880
881         if (ioctl(fd, CIOCCRYPTAEAD, &caead) < 0) {
882                 warn("cryptodev %s (%zu) failed for device %s",
883                     alg->name, size, crfind(crid));
884                 close(fd);
885                 return (false);
886         }
887
888         if (ioctl(fd, CIOCFSESSION, &sop.ses) < 0)
889                 warn("ioctl(CIOCFSESSION)");
890
891         close(fd);
892         *cridp = sop.crid;
893         return (true);
894 }
895
896 #ifdef notused
897 static bool
898 openssl_gcm_decrypt(struct alg *alg, const EVP_CIPHER *cipher, const char *key,
899     const char *iv, const char *aad, size_t aad_len, const char *input,
900     char *output, size_t size, char *tag)
901 {
902         EVP_CIPHER_CTX *ctx;
903         int outl, total;
904         bool valid;
905
906         ctx = EVP_CIPHER_CTX_new();
907         if (ctx == NULL)
908                 errx(1, "OpenSSL %s (%zu) ctx new failed: %s", alg->name,
909                     size, ERR_error_string(ERR_get_error(), NULL));
910         if (EVP_DecryptInit_ex(ctx, cipher, NULL, (const u_char *)key,
911             (const u_char *)iv) != 1)
912                 errx(1, "OpenSSL %s (%zu) ctx init failed: %s", alg->name,
913                     size, ERR_error_string(ERR_get_error(), NULL));
914         EVP_CIPHER_CTX_set_padding(ctx, 0);
915         if (aad != NULL) {
916                 if (EVP_DecryptUpdate(ctx, NULL, &outl, (const u_char *)aad,
917                     aad_len) != 1)
918                         errx(1, "OpenSSL %s (%zu) aad update failed: %s",
919                             alg->name, size,
920                             ERR_error_string(ERR_get_error(), NULL));
921         }
922         if (EVP_DecryptUpdate(ctx, (u_char *)output, &outl,
923             (const u_char *)input, size) != 1)
924                 errx(1, "OpenSSL %s (%zu) decrypt update failed: %s", alg->name,
925                     size, ERR_error_string(ERR_get_error(), NULL));
926         total = outl;
927         if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, AES_GMAC_HASH_LEN,
928             tag) != 1)
929                 errx(1, "OpenSSL %s (%zu) get tag failed: %s", alg->name,
930                     size, ERR_error_string(ERR_get_error(), NULL));
931         valid = (EVP_DecryptFinal_ex(ctx, (u_char *)output + outl, &outl) != 1);
932         total += outl;
933         if (total != size)
934                 errx(1, "OpenSSL %s (%zu) decrypt size mismatch: %d", alg->name,
935                     size, total);
936         EVP_CIPHER_CTX_free(ctx);
937         return (valid);
938 }
939 #endif
940
941 static void
942 run_gcm_test(struct alg *alg, size_t size)
943 {
944         const EVP_CIPHER *cipher;
945         char *aad, *buffer, *cleartext, *ciphertext;
946         char *iv, *key;
947         u_int iv_len, key_len;
948         int crid;
949         char control_tag[AES_GMAC_HASH_LEN], test_tag[AES_GMAC_HASH_LEN];
950
951         cipher = alg->evp_cipher();
952         if (size % EVP_CIPHER_block_size(cipher) != 0) {
953                 if (verbose)
954                         printf(
955                             "%s (%zu): invalid buffer size (block size %d)\n",
956                             alg->name, size, EVP_CIPHER_block_size(cipher));
957                 return;
958         }
959
960         memset(control_tag, 0x3c, sizeof(control_tag));
961         memset(test_tag, 0x3c, sizeof(test_tag));
962
963         key_len = EVP_CIPHER_key_length(cipher);
964         iv_len = EVP_CIPHER_iv_length(cipher);
965
966         key = alloc_buffer(key_len);
967         iv = generate_iv(iv_len, alg);
968         cleartext = alloc_buffer(size);
969         buffer = malloc(size);
970         ciphertext = malloc(size);
971         if (aad_len != 0)
972                 aad = alloc_buffer(aad_len);
973         else
974                 aad = NULL;
975
976         /* OpenSSL encrypt */
977         openssl_gcm_encrypt(alg, cipher, key, iv, aad, aad_len, cleartext,
978             ciphertext, size, control_tag);
979
980         /* OCF encrypt */
981         if (!ocf_gcm(alg, key, key_len, iv, iv_len, aad, aad_len, cleartext,
982             buffer, size, test_tag, 1, &crid))
983                 goto out;
984         if (memcmp(ciphertext, buffer, size) != 0) {
985                 printf("%s (%zu) encryption mismatch:\n", alg->name, size);
986                 printf("control:\n");
987                 hexdump(ciphertext, size, NULL, 0);
988                 printf("test (cryptodev device %s):\n", crfind(crid));
989                 hexdump(buffer, size, NULL, 0);
990                 goto out;
991         }
992         if (memcmp(control_tag, test_tag, sizeof(control_tag)) != 0) {
993                 printf("%s (%zu) enc tag mismatch:\n", alg->name, size);
994                 printf("control:\n");
995                 hexdump(control_tag, sizeof(control_tag), NULL, 0);
996                 printf("test (cryptodev device %s):\n", crfind(crid));
997                 hexdump(test_tag, sizeof(test_tag), NULL, 0);
998                 goto out;
999         }
1000
1001         /* OCF decrypt */
1002         if (!ocf_gcm(alg, key, key_len, iv, iv_len, aad, aad_len, ciphertext,
1003             buffer, size, control_tag, 0, &crid))
1004                 goto out;
1005         if (memcmp(cleartext, buffer, size) != 0) {
1006                 printf("%s (%zu) decryption mismatch:\n", alg->name, size);
1007                 printf("control:\n");
1008                 hexdump(cleartext, size, NULL, 0);
1009                 printf("test (cryptodev device %s):\n", crfind(crid));
1010                 hexdump(buffer, size, NULL, 0);
1011                 goto out;
1012         }
1013
1014         if (verbose)
1015                 printf("%s (%zu) matched (cryptodev device %s)\n",
1016                     alg->name, size, crfind(crid));
1017
1018 out:
1019         free(aad);
1020         free(ciphertext);
1021         free(buffer);
1022         free(cleartext);
1023         free(iv);
1024         free(key);
1025 }
1026
1027 static void
1028 run_test(struct alg *alg, size_t size)
1029 {
1030
1031         switch (alg->type) {
1032         case T_HMAC:
1033                 run_hmac_test(alg, size);
1034                 break;
1035         case T_BLKCIPHER:
1036                 run_blkcipher_test(alg, size);
1037                 break;
1038         case T_AUTHENC:
1039                 run_authenc_test(alg, size);
1040                 break;
1041         case T_GCM:
1042                 run_gcm_test(alg, size);
1043                 break;
1044         }
1045 }
1046
1047 static void
1048 run_test_sizes(struct alg *alg, size_t *sizes, u_int nsizes)
1049 {
1050         u_int i;
1051
1052         for (i = 0; i < nsizes; i++)
1053                 run_test(alg, sizes[i]);
1054 }
1055
1056 static void
1057 run_hmac_tests(size_t *sizes, u_int nsizes)
1058 {
1059         u_int i;
1060
1061         for (i = 0; i < nitems(algs); i++)
1062                 if (algs[i].type == T_HMAC)
1063                         run_test_sizes(&algs[i], sizes, nsizes);
1064 }
1065
1066 static void
1067 run_blkcipher_tests(size_t *sizes, u_int nsizes)
1068 {
1069         u_int i;
1070
1071         for (i = 0; i < nitems(algs); i++)
1072                 if (algs[i].type == T_BLKCIPHER)
1073                         run_test_sizes(&algs[i], sizes, nsizes);
1074 }
1075
1076 static void
1077 run_authenc_tests(size_t *sizes, u_int nsizes)
1078 {
1079         struct alg *authenc, *cipher, *hmac;
1080         u_int i, j;
1081
1082         for (i = 0; i < nitems(algs); i++) {
1083                 cipher = &algs[i];
1084                 if (cipher->type != T_BLKCIPHER)
1085                         continue;
1086                 for (j = 0; j < nitems(algs); j++) {
1087                         hmac = &algs[j];
1088                         if (hmac->type != T_HMAC)
1089                                 continue;
1090                         authenc = build_authenc(cipher, hmac);
1091                         run_test_sizes(authenc, sizes, nsizes);
1092                         free((char *)authenc->name);
1093                 }
1094         }
1095 }
1096
1097 static void
1098 run_aead_tests(size_t *sizes, u_int nsizes)
1099 {
1100         u_int i;
1101
1102         for (i = 0; i < nitems(algs); i++)
1103                 if (algs[i].type == T_GCM)
1104                         run_test_sizes(&algs[i], sizes, nsizes);
1105 }
1106
1107 int
1108 main(int ac, char **av)
1109 {
1110         const char *algname;
1111         struct alg *alg;
1112         size_t sizes[128];
1113         u_int i, nsizes;
1114         bool testall;
1115         int ch;
1116
1117         algname = NULL;
1118         crid = CRYPTO_FLAG_HARDWARE;
1119         testall = false;
1120         verbose = false;
1121         while ((ch = getopt(ac, av, "A:a:d:vz")) != -1)
1122                 switch (ch) {
1123                 case 'A':
1124                         aad_len = atoi(optarg);
1125                         break;
1126                 case 'a':
1127                         algname = optarg;
1128                         break;
1129                 case 'd':
1130                         crid = crlookup(optarg);
1131                         break;
1132                 case 'v':
1133                         verbose = true;
1134                         break;
1135                 case 'z':
1136                         testall = true;
1137                         break;
1138                 default:
1139                         usage();
1140                 }
1141         ac -= optind;
1142         av += optind;
1143         nsizes = 0;
1144         while (ac > 0) {
1145                 char *cp;
1146
1147                 if (nsizes >= nitems(sizes)) {
1148                         warnx("Too many sizes, ignoring extras");
1149                         break;
1150                 }
1151                 sizes[nsizes] = strtol(av[0], &cp, 0);
1152                 if (*cp != '\0')
1153                         errx(1, "Bad size %s", av[0]);
1154                 nsizes++;
1155                 ac--;
1156                 av++;
1157         }
1158
1159         if (algname == NULL)
1160                 errx(1, "Algorithm required");
1161         if (nsizes == 0) {
1162                 sizes[0] = 16;
1163                 nsizes++;
1164                 if (testall) {
1165                         while (sizes[nsizes - 1] * 2 < 240 * 1024) {
1166                                 assert(nsizes < nitems(sizes));
1167                                 sizes[nsizes] = sizes[nsizes - 1] * 2;
1168                                 nsizes++;
1169                         }
1170                         if (sizes[nsizes - 1] < 240 * 1024) {
1171                                 assert(nsizes < nitems(sizes));
1172                                 sizes[nsizes] = 240 * 1024;
1173                                 nsizes++;
1174                         }
1175                 }
1176         }
1177
1178         if (strcasecmp(algname, "hmac") == 0)
1179                 run_hmac_tests(sizes, nsizes);
1180         else if (strcasecmp(algname, "blkcipher") == 0)
1181                 run_blkcipher_tests(sizes, nsizes);
1182         else if (strcasecmp(algname, "authenc") == 0)
1183                 run_authenc_tests(sizes, nsizes);
1184         else if (strcasecmp(algname, "aead") == 0)
1185                 run_aead_tests(sizes, nsizes);
1186         else if (strcasecmp(algname, "all") == 0) {
1187                 run_hmac_tests(sizes, nsizes);
1188                 run_blkcipher_tests(sizes, nsizes);
1189                 run_authenc_tests(sizes, nsizes);
1190                 run_aead_tests(sizes, nsizes);
1191         } else if (strchr(algname, '+') != NULL) {
1192                 alg = build_authenc_name(algname);
1193                 run_test_sizes(alg, sizes, nsizes);
1194         } else {
1195                 alg = find_alg(algname);
1196                 if (alg == NULL)
1197                         errx(1, "Invalid algorithm %s", algname);
1198                 run_test_sizes(alg, sizes, nsizes);
1199         }
1200
1201         return (0);
1202 }