/* * Demo on how to use /dev/crypto device for HMAC. * * Placed under public domain. * */ #include #include #include #include #include #include #include #include #include #include #include #include "../ncr.h" #include #define DATA_SIZE 4096 #define ALIGN_NL __attribute__((aligned(NLA_ALIGNTO))) #define ALG_AES_CBC "cbc(aes)" #define ALG_AES_ECB "ecb(aes)" static void randomize_data(uint8_t * data, size_t data_size) { int i; srand(time(0)*getpid()); for (i=0;inla_type = NCR_ATTR_WANTED_ATTRS; attr_p = (uint16_t *)((char *)nla + NLA_HDRLEN); *attr_p++ = NCR_ATTR_ALGORITHM; *attr_p++ = NCR_ATTR_KEY_FLAGS; *attr_p++ = NCR_ATTR_KEY_TYPE; nla->nla_len = (char *)attr_p - (char *)nla; kinfo.f.input_size = (char *)attr_p - (char *)&kinfo; if (ioctl(cfd, NCRIO_KEY_GET_INFO, &kinfo)) { fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); perror("ioctl(NCRIO_KEY_GET_INFO)"); return 1; } got_algo = got_flags = got_type = 0; if (kinfo.f.output_size < (char *)&kinfo.u.first_header - (char *)&kinfo) { fprintf(stderr, "No nlattr returned\n"); return 1; } nla = &kinfo.u.first_header; for (;;) { void *data; if (nla->nla_len > kinfo.f.output_size - ((char *)nla - (char *)&kinfo)) { fprintf(stderr, "Attributes overflow\n"); return 1; } data = (char *)nla + NLA_HDRLEN; switch (nla->nla_type) { case NCR_ATTR_ALGORITHM: if (nla->nla_len < NLA_HDRLEN + 1) { fprintf(stderr, "Attribute too small\n"); return 1; } if (((char *)data)[nla->nla_len - NLA_HDRLEN - 1] != 0) { fprintf(stderr, "NUL missing\n"); return 1; } if (strcmp(data, ALG_AES_CBC) != 0) { fprintf(stderr, "Unexpected algorithm\n"); return 1; } got_algo++; break; case NCR_ATTR_KEY_FLAGS: if (nla->nla_len < NLA_HDRLEN + sizeof(uint32_t)) { fprintf(stderr, "Attribute too small\n"); return 1; } if (*(uint32_t *)data != NCR_KEY_FLAG_EXPORTABLE) { fprintf(stderr, "Unexpected key flags\n"); return 1; } got_flags++; break; case NCR_ATTR_KEY_TYPE: if (nla->nla_len < NLA_HDRLEN + sizeof(uint32_t)) { fprintf(stderr, "Attribute too small\n"); return 1; } if (*(uint32_t *)data != NCR_KEY_TYPE_SECRET) { fprintf(stderr, "Unexpected key type\n"); return 1; } got_type++; break; } if (NLA_ALIGN(nla->nla_len) + NLA_HDRLEN > kinfo.f.output_size - ((char *)nla - (char *)&kinfo)) break; nla = (struct nlattr *)((char *)nla + NLA_ALIGN(nla->nla_len)); } if (got_algo != 1 || got_flags != 1 || got_type != 1) { fprintf(stderr, "Unexpected attrs - %d, %d, %d\n", got_algo, got_flags, got_type); return 1; } if (ioctl(cfd, NCRIO_KEY_DEINIT, &key)) { fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); perror("ioctl(NCRIO_KEY_DEINIT)"); return 1; } /* test 3: generate an unexportable key in kernel space and * try to export it. */ fprintf(stdout, "\tKey protection of non-exportable keys...\n"); key = ioctl(cfd, NCRIO_KEY_INIT); if (key == -1) { fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); perror("ioctl(NCRIO_KEY_INIT)"); return 1; } memset(&kgen.f, 0, sizeof(kgen.f)); kgen.f.input_size = sizeof(kgen); kgen.f.key = key; kgen.algo_head.nla_len = NLA_HDRLEN + sizeof(kgen.algo); kgen.algo_head.nla_type = NCR_ATTR_ALGORITHM; strcpy(kgen.algo, ALG_AES_CBC); kgen.flags_head.nla_len = NLA_HDRLEN + sizeof(kgen.flags); kgen.flags_head.nla_type = NCR_ATTR_KEY_FLAGS; kgen.flags = 0; kgen.bits_head.nla_len = NLA_HDRLEN + sizeof(kgen.flags); kgen.bits_head.nla_type = NCR_ATTR_SECRET_KEY_BITS; kgen.bits = 128; /* 16 bytes */ if (ioctl(cfd, NCRIO_KEY_GENERATE, &kgen)) { perror("ioctl(NCRIO_KEY_GENERATE)"); return 1; } memset(data, 0, sizeof(data)); memset(&kexport, 0, sizeof(kexport)); kexport.key = key; kexport.buffer = data; kexport.buffer_size = sizeof(data); /* try to get the output data - should fail */ if (ioctl(cfd, NCRIO_KEY_EXPORT, &kexport) >= 0) { fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); fprintf(stderr, "Data were exported, but shouldn't be!\n"); return 1; } if (ioctl(cfd, NCRIO_KEY_DEINIT, &key)) { fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); perror("ioctl(NCRIO_KEY_DEINIT)"); return 1; } return 0; } /* Key wrapping */ static int test_ncr_wrap_key(int cfd) { int i, ret; ncr_key_t key, key2; struct __attribute__((packed)) { struct ncr_key_import f; struct nlattr id_head ALIGN_NL; uint8_t id[2] ALIGN_NL; struct nlattr type_head ALIGN_NL; uint32_t type ALIGN_NL; struct nlattr algo_head ALIGN_NL; char algo[sizeof(ALG_AES_CBC)] ALIGN_NL; struct nlattr flags_head ALIGN_NL; uint32_t flags ALIGN_NL; } kimport; struct __attribute__((packed)) { struct ncr_key_wrap f; struct nlattr algo_head ALIGN_NL; char algo[sizeof(NCR_WALG_AES_RFC3394)] ALIGN_NL; } kwrap; struct __attribute__((packed)) { struct ncr_key_unwrap f; struct nlattr wrap_algo_head ALIGN_NL; char wrap_algo[sizeof(NCR_WALG_AES_RFC3394)] ALIGN_NL; struct nlattr algo_head ALIGN_NL; char algo[sizeof(ALG_AES_CBC)] ALIGN_NL; struct nlattr type_head ALIGN_NL; uint32_t type ALIGN_NL; struct nlattr flags_head ALIGN_NL; uint32_t flags ALIGN_NL; } kunwrap; uint8_t data[WRAPPED_KEY_DATA_SIZE]; int data_size; fprintf(stdout, "Tests on Keys:\n"); /* test 1: generate a key in userspace import it * to kernel via data and export it. */ fprintf(stdout, "\tKey Wrap test...\n"); /* convert it to key */ key = ioctl(cfd, NCRIO_KEY_INIT); if (key == -1) { perror("ioctl(NCRIO_KEY_INIT)"); return 1; } memset(&kimport.f, 0, sizeof(kimport.f)); kimport.f.input_size = sizeof(kimport); kimport.f.key = key; kimport.f.data = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"; kimport.f.data_size = 16; kimport.id_head.nla_len = NLA_HDRLEN + sizeof(kimport.id); kimport.id_head.nla_type = NCR_ATTR_KEY_ID; kimport.id[0] = 'a'; kimport.id[1] = 'b'; kimport.type_head.nla_len = NLA_HDRLEN + sizeof(kimport.type); kimport.type_head.nla_type = NCR_ATTR_KEY_TYPE; kimport.type = NCR_KEY_TYPE_SECRET; kimport.algo_head.nla_len = NLA_HDRLEN + sizeof(kimport.algo); kimport.algo_head.nla_type = NCR_ATTR_ALGORITHM; strcpy(kimport.algo, ALG_AES_CBC); kimport.flags_head.nla_len = NLA_HDRLEN + sizeof(kimport.flags); kimport.flags_head.nla_type = NCR_ATTR_KEY_FLAGS; kimport.flags = NCR_KEY_FLAG_EXPORTABLE|NCR_KEY_FLAG_WRAPPING; ret = ioctl(cfd, NCRIO_KEY_IMPORT, &kimport); if (geteuid() == 0 && ret) { fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); perror("ioctl(NCRIO_KEY_IMPORT)"); return 1; } if (geteuid() != 0) { /* cannot test further */ fprintf(stdout, "\t(Wrapping test not completed. Run as root)\n"); return 0; } /* convert it to key */ key2 = ioctl(cfd, NCRIO_KEY_INIT); if (key2 == -1) { perror("ioctl(NCRIO_KEY_INIT)"); return 1; } memset(&kimport.f, 0, sizeof(kimport.f)); kimport.f.input_size = sizeof(kimport); kimport.f.key = key2; #define DKEY "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF" kimport.f.data = DKEY; kimport.f.data_size = 16; kimport.id_head.nla_len = NLA_HDRLEN + sizeof(kimport.id); kimport.id_head.nla_type = NCR_ATTR_KEY_ID; kimport.id[0] = 'b'; kimport.id[1] = 'a'; kimport.type_head.nla_len = NLA_HDRLEN + sizeof(kimport.type); kimport.type_head.nla_type = NCR_ATTR_KEY_TYPE; kimport.type = NCR_KEY_TYPE_SECRET; kimport.algo_head.nla_len = NLA_HDRLEN + sizeof(kimport.algo); kimport.algo_head.nla_type = NCR_ATTR_ALGORITHM; strcpy(kimport.algo, ALG_AES_CBC); kimport.flags_head.nla_len = NLA_HDRLEN + sizeof(kimport.flags); kimport.flags_head.nla_type = NCR_ATTR_KEY_FLAGS; kimport.flags = NCR_KEY_FLAG_EXPORTABLE|NCR_KEY_FLAG_WRAPPABLE; if (ioctl(cfd, NCRIO_KEY_IMPORT, &kimport)) { fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); perror("ioctl(NCRIO_KEY_IMPORT)"); return 1; } /* now try wrapping key2 using key */ memset(&kwrap.f, 0, sizeof(kwrap.f)); kwrap.f.input_size = sizeof(kwrap); kwrap.f.wrapping_key = key; kwrap.f.source_key = key2; kwrap.f.buffer = data; kwrap.f.buffer_size = sizeof(data); kwrap.algo_head.nla_len = NLA_HDRLEN + sizeof(kwrap.algo); kwrap.algo_head.nla_type = NCR_ATTR_WRAPPING_ALGORITHM; strcpy(kwrap.algo, NCR_WALG_AES_RFC3394); data_size = ioctl(cfd, NCRIO_KEY_WRAP, &kwrap); if (data_size < 0) { fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); perror("ioctl(NCRIO_KEY_WRAP)"); return 1; } if (data_size != 24 || memcmp(data, "\x1F\xA6\x8B\x0A\x81\x12\xB4\x47\xAE\xF3\x4B\xD8\xFB\x5A\x7B\x82\x9D\x3E\x86\x23\x71\xD2\xCF\xE5", 24) != 0) { fprintf(stderr, "Wrapped data do not match.\n"); fprintf(stderr, "Data[%d]: ",(int) data_size); for(i=0;i= 0) { fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); /* wrapping shouldn't have been allowed */ return 1; } return 0; } static int test_ncr_store_wrap_key(int cfd) { int i; ncr_key_t key2; struct __attribute__((packed)) { struct ncr_key_import f; struct nlattr id_head ALIGN_NL; uint8_t id[2] ALIGN_NL; struct nlattr type_head ALIGN_NL; uint32_t type ALIGN_NL; struct nlattr algo_head ALIGN_NL; char algo[sizeof(ALG_AES_CBC)] ALIGN_NL; struct nlattr flags_head ALIGN_NL; uint32_t flags ALIGN_NL; } kimport; struct ncr_key_export kexport; struct ncr_key_storage_wrap kwrap; struct ncr_key_storage_unwrap kunwrap; uint8_t data[DATA_SIZE]; int data_size; fprintf(stdout, "Tests on Key storage:\n"); /* test 1: generate a key in userspace import it * to kernel via data and export it. */ fprintf(stdout, "\tKey Storage wrap test...\n"); /* convert it to key */ key2 = ioctl(cfd, NCRIO_KEY_INIT); if (key2 == -1) { perror("ioctl(NCRIO_KEY_INIT)"); return 1; } memset(&kimport.f, 0, sizeof(kimport.f)); kimport.f.input_size = sizeof(kimport); kimport.f.key = key2; #define DKEY "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF" kimport.f.data = DKEY; kimport.f.data_size = 16; kimport.id_head.nla_len = NLA_HDRLEN + sizeof(kimport.id); kimport.id_head.nla_type = NCR_ATTR_KEY_ID; kimport.id[0] = 'b'; kimport.id[1] = 'a'; kimport.type_head.nla_len = NLA_HDRLEN + sizeof(kimport.type); kimport.type_head.nla_type = NCR_ATTR_KEY_TYPE; kimport.type = NCR_KEY_TYPE_SECRET; kimport.algo_head.nla_len = NLA_HDRLEN + sizeof(kimport.algo); kimport.algo_head.nla_type = NCR_ATTR_ALGORITHM; strcpy(kimport.algo, ALG_AES_CBC); kimport.flags_head.nla_len = NLA_HDRLEN + sizeof(kimport.flags); kimport.flags_head.nla_type = NCR_ATTR_KEY_FLAGS; kimport.flags = NCR_KEY_FLAG_EXPORTABLE|NCR_KEY_FLAG_WRAPPABLE; if (ioctl(cfd, NCRIO_KEY_IMPORT, &kimport)) { fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); perror("ioctl(NCRIO_KEY_IMPORT)"); return 1; } /* now try wrapping key2 using key */ memset(&kwrap, 0, sizeof(kwrap)); kwrap.key = key2; kwrap.buffer = data; kwrap.buffer_size = sizeof(data); data_size = ioctl(cfd, NCRIO_KEY_STORAGE_WRAP, &kwrap); if (data_size < 0) { fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); perror("ioctl(NCRIO_KEY_STORAGE_WRAP)"); return 1; } /* test unwrapping */ fprintf(stdout, "\tKey Storage Unwrap test...\n"); /* reset key2 */ if (ioctl(cfd, NCRIO_KEY_DEINIT, &key2)) { fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); perror("ioctl(NCRIO_KEY_DEINIT)"); return 1; } key2 = ioctl(cfd, NCRIO_KEY_INIT); if (key2 == -1) { fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); perror("ioctl(NCRIO_KEY_INIT)"); return 1; } memset(&kunwrap, 0, sizeof(kunwrap)); kunwrap.key = key2; kunwrap.data = data; kunwrap.data_size = data_size; if (ioctl(cfd, NCRIO_KEY_STORAGE_UNWRAP, &kunwrap)) { fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); perror("ioctl(NCRIO_KEY_STORAGE_UNWRAP)"); return 1; } /* now export the unwrapped */ memset(&kexport, 0, sizeof(kexport)); kexport.key = key2; kexport.buffer = data; kexport.buffer_size = sizeof(data); data_size = ioctl(cfd, NCRIO_KEY_EXPORT, &kexport); if (data_size != 16) { fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); perror("ioctl(NCRIO_KEY_EXPORT)"); return 1; } if (memcmp(data, DKEY, 16) != 0) { fprintf(stderr, "Unwrapped data do not match.\n"); fprintf(stderr, "Data[%d]: ", (int) data_size); for(i=0;i