Corentin Labbe | a6f37ce | 2018-09-19 10:10:55 +0000 | [diff] [blame] | 1 | /* Heavily copied from libkcapi 2015 - 2017, Stephan Mueller <smueller@chronox.de> */ |
| 2 | #include <errno.h> |
| 3 | #include <linux/cryptouser.h> |
| 4 | #include <linux/netlink.h> |
| 5 | #include <linux/rtnetlink.h> |
| 6 | #include <sys/types.h> |
| 7 | #include <sys/socket.h> |
| 8 | #include <stdlib.h> |
| 9 | #include <stdio.h> |
| 10 | #include <string.h> |
| 11 | #include <time.h> |
| 12 | #include <unistd.h> |
| 13 | |
| 14 | #define CR_RTA(x) ((struct rtattr *)(((char *)(x)) + NLMSG_ALIGN(sizeof(struct crypto_user_alg)))) |
| 15 | |
| 16 | static int get_stat(const char *drivername) |
| 17 | { |
| 18 | struct { |
| 19 | struct nlmsghdr n; |
| 20 | struct crypto_user_alg cru; |
| 21 | } req; |
| 22 | struct sockaddr_nl nl; |
| 23 | int sd = 0, ret; |
| 24 | socklen_t addr_len; |
| 25 | struct iovec iov; |
| 26 | struct msghdr msg; |
| 27 | char buf[4096]; |
| 28 | struct nlmsghdr *res_n = (struct nlmsghdr *)buf; |
| 29 | struct crypto_user_alg *cru_res = NULL; |
| 30 | int res_len = 0; |
| 31 | struct rtattr *tb[CRYPTOCFGA_MAX + 1]; |
| 32 | struct rtattr *rta; |
| 33 | struct nlmsgerr *errmsg; |
| 34 | |
| 35 | memset(&req, 0, sizeof(req)); |
| 36 | memset(&buf, 0, sizeof(buf)); |
| 37 | memset(&msg, 0, sizeof(msg)); |
| 38 | |
| 39 | req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.cru)); |
| 40 | req.n.nlmsg_flags = NLM_F_REQUEST; |
| 41 | req.n.nlmsg_type = CRYPTO_MSG_GETSTAT; |
| 42 | req.n.nlmsg_seq = time(NULL); |
| 43 | |
| 44 | strncpy(req.cru.cru_driver_name, drivername, strlen(drivername)); |
| 45 | |
| 46 | sd = socket(AF_NETLINK, SOCK_RAW, NETLINK_CRYPTO); |
| 47 | if (sd < 0) { |
| 48 | fprintf(stderr, "Netlink error: cannot open netlink socket"); |
| 49 | return -errno; |
| 50 | } |
| 51 | memset(&nl, 0, sizeof(nl)); |
| 52 | nl.nl_family = AF_NETLINK; |
| 53 | if (bind(sd, (struct sockaddr *)&nl, sizeof(nl)) < 0) { |
| 54 | ret = -errno; |
| 55 | fprintf(stderr, "Netlink error: cannot bind netlink socket"); |
| 56 | goto out; |
| 57 | } |
| 58 | |
| 59 | /* sanity check that netlink socket was successfully opened */ |
| 60 | addr_len = sizeof(nl); |
| 61 | if (getsockname(sd, (struct sockaddr *)&nl, &addr_len) < 0) { |
| 62 | ret = -errno; |
| 63 | printf("Netlink error: cannot getsockname"); |
| 64 | goto out; |
| 65 | } |
| 66 | if (addr_len != sizeof(nl)) { |
| 67 | ret = -errno; |
| 68 | printf("Netlink error: wrong address length %d", addr_len); |
| 69 | goto out; |
| 70 | } |
| 71 | if (nl.nl_family != AF_NETLINK) { |
| 72 | ret = -errno; |
| 73 | printf("Netlink error: wrong address family %d", |
| 74 | nl.nl_family); |
| 75 | goto out; |
| 76 | } |
| 77 | |
| 78 | memset(&nl, 0, sizeof(nl)); |
| 79 | nl.nl_family = AF_NETLINK; |
| 80 | iov.iov_base = (void *)&req.n; |
| 81 | iov.iov_len = req.n.nlmsg_len; |
| 82 | msg.msg_name = &nl; |
| 83 | msg.msg_namelen = sizeof(nl); |
| 84 | msg.msg_iov = &iov; |
| 85 | msg.msg_iovlen = 1; |
| 86 | if (sendmsg(sd, &msg, 0) < 0) { |
| 87 | ret = -errno; |
| 88 | printf("Netlink error: sendmsg failed"); |
| 89 | goto out; |
| 90 | } |
| 91 | memset(buf, 0, sizeof(buf)); |
| 92 | iov.iov_base = buf; |
| 93 | while (1) { |
| 94 | iov.iov_len = sizeof(buf); |
| 95 | ret = recvmsg(sd, &msg, 0); |
| 96 | if (ret < 0) { |
| 97 | if (errno == EINTR || errno == EAGAIN) |
| 98 | continue; |
| 99 | ret = -errno; |
| 100 | printf("Netlink error: netlink receive error"); |
| 101 | goto out; |
| 102 | } |
| 103 | if (ret == 0) { |
| 104 | ret = -errno; |
| 105 | printf("Netlink error: no data"); |
| 106 | goto out; |
| 107 | } |
| 108 | if (ret > sizeof(buf)) { |
| 109 | ret = -errno; |
| 110 | printf("Netlink error: received too much data"); |
| 111 | goto out; |
| 112 | } |
| 113 | break; |
| 114 | } |
| 115 | |
| 116 | ret = -EFAULT; |
| 117 | res_len = res_n->nlmsg_len; |
| 118 | if (res_n->nlmsg_type == NLMSG_ERROR) { |
| 119 | errmsg = NLMSG_DATA(res_n); |
| 120 | fprintf(stderr, "Fail with %d\n", errmsg->error); |
| 121 | ret = errmsg->error; |
| 122 | goto out; |
| 123 | } |
| 124 | |
| 125 | if (res_n->nlmsg_type == CRYPTO_MSG_GETSTAT) { |
| 126 | cru_res = NLMSG_DATA(res_n); |
| 127 | res_len -= NLMSG_SPACE(sizeof(*cru_res)); |
| 128 | } |
| 129 | if (res_len < 0) { |
| 130 | printf("Netlink error: nlmsg len %d\n", res_len); |
| 131 | goto out; |
| 132 | } |
| 133 | |
| 134 | if (!cru_res) { |
| 135 | ret = -EFAULT; |
| 136 | printf("Netlink error: no cru_res\n"); |
| 137 | goto out; |
| 138 | } |
| 139 | |
| 140 | rta = CR_RTA(cru_res); |
| 141 | memset(tb, 0, sizeof(struct rtattr *) * (CRYPTOCFGA_MAX + 1)); |
| 142 | while (RTA_OK(rta, res_len)) { |
| 143 | if ((rta->rta_type <= CRYPTOCFGA_MAX) && (!tb[rta->rta_type])) |
| 144 | tb[rta->rta_type] = rta; |
| 145 | rta = RTA_NEXT(rta, res_len); |
| 146 | } |
| 147 | if (res_len) { |
| 148 | printf("Netlink error: unprocessed data %d", |
| 149 | res_len); |
| 150 | goto out; |
| 151 | } |
| 152 | |
| 153 | if (tb[CRYPTOCFGA_STAT_HASH]) { |
| 154 | struct rtattr *rta = tb[CRYPTOCFGA_STAT_HASH]; |
Corentin Labbe | 76d09ea | 2018-11-29 14:42:20 +0000 | [diff] [blame] | 155 | struct crypto_stat_hash *rhash = |
| 156 | (struct crypto_stat_hash *)RTA_DATA(rta); |
| 157 | printf("%s\tHash\n\tHash: %llu bytes: %llu\n\tErrors: %llu\n", |
Corentin Labbe | a6f37ce | 2018-09-19 10:10:55 +0000 | [diff] [blame] | 158 | drivername, |
| 159 | rhash->stat_hash_cnt, rhash->stat_hash_tlen, |
Corentin Labbe | 44f1313 | 2018-11-29 14:42:25 +0000 | [diff] [blame] | 160 | rhash->stat_err_cnt); |
Corentin Labbe | a6f37ce | 2018-09-19 10:10:55 +0000 | [diff] [blame] | 161 | } else if (tb[CRYPTOCFGA_STAT_COMPRESS]) { |
| 162 | struct rtattr *rta = tb[CRYPTOCFGA_STAT_COMPRESS]; |
Corentin Labbe | 76d09ea | 2018-11-29 14:42:20 +0000 | [diff] [blame] | 163 | struct crypto_stat_compress *rblk = |
| 164 | (struct crypto_stat_compress *)RTA_DATA(rta); |
| 165 | printf("%s\tCompress\n\tCompress: %llu bytes: %llu\n\tDecompress: %llu bytes: %llu\n\tErrors: %llu\n", |
Corentin Labbe | a6f37ce | 2018-09-19 10:10:55 +0000 | [diff] [blame] | 166 | drivername, |
| 167 | rblk->stat_compress_cnt, rblk->stat_compress_tlen, |
| 168 | rblk->stat_decompress_cnt, rblk->stat_decompress_tlen, |
Corentin Labbe | 44f1313 | 2018-11-29 14:42:25 +0000 | [diff] [blame] | 169 | rblk->stat_err_cnt); |
Corentin Labbe | a6f37ce | 2018-09-19 10:10:55 +0000 | [diff] [blame] | 170 | } else if (tb[CRYPTOCFGA_STAT_ACOMP]) { |
| 171 | struct rtattr *rta = tb[CRYPTOCFGA_STAT_ACOMP]; |
Corentin Labbe | 76d09ea | 2018-11-29 14:42:20 +0000 | [diff] [blame] | 172 | struct crypto_stat_compress *rcomp = |
| 173 | (struct crypto_stat_compress *)RTA_DATA(rta); |
| 174 | printf("%s\tACompress\n\tCompress: %llu bytes: %llu\n\tDecompress: %llu bytes: %llu\n\tErrors: %llu\n", |
Corentin Labbe | a6f37ce | 2018-09-19 10:10:55 +0000 | [diff] [blame] | 175 | drivername, |
| 176 | rcomp->stat_compress_cnt, rcomp->stat_compress_tlen, |
| 177 | rcomp->stat_decompress_cnt, rcomp->stat_decompress_tlen, |
Corentin Labbe | 44f1313 | 2018-11-29 14:42:25 +0000 | [diff] [blame] | 178 | rcomp->stat_err_cnt); |
Corentin Labbe | a6f37ce | 2018-09-19 10:10:55 +0000 | [diff] [blame] | 179 | } else if (tb[CRYPTOCFGA_STAT_AEAD]) { |
| 180 | struct rtattr *rta = tb[CRYPTOCFGA_STAT_AEAD]; |
Corentin Labbe | 76d09ea | 2018-11-29 14:42:20 +0000 | [diff] [blame] | 181 | struct crypto_stat_aead *raead = |
| 182 | (struct crypto_stat_aead *)RTA_DATA(rta); |
| 183 | printf("%s\tAEAD\n\tEncrypt: %llu bytes: %llu\n\tDecrypt: %llu bytes: %llu\n\tErrors: %llu\n", |
Corentin Labbe | a6f37ce | 2018-09-19 10:10:55 +0000 | [diff] [blame] | 184 | drivername, |
| 185 | raead->stat_encrypt_cnt, raead->stat_encrypt_tlen, |
| 186 | raead->stat_decrypt_cnt, raead->stat_decrypt_tlen, |
Corentin Labbe | 44f1313 | 2018-11-29 14:42:25 +0000 | [diff] [blame] | 187 | raead->stat_err_cnt); |
Corentin Labbe | a6f37ce | 2018-09-19 10:10:55 +0000 | [diff] [blame] | 188 | } else if (tb[CRYPTOCFGA_STAT_BLKCIPHER]) { |
| 189 | struct rtattr *rta = tb[CRYPTOCFGA_STAT_BLKCIPHER]; |
Corentin Labbe | 76d09ea | 2018-11-29 14:42:20 +0000 | [diff] [blame] | 190 | struct crypto_stat_cipher *rblk = |
| 191 | (struct crypto_stat_cipher *)RTA_DATA(rta); |
| 192 | printf("%s\tCipher\n\tEncrypt: %llu bytes: %llu\n\tDecrypt: %llu bytes: %llu\n\tErrors: %llu\n", |
Corentin Labbe | a6f37ce | 2018-09-19 10:10:55 +0000 | [diff] [blame] | 193 | drivername, |
| 194 | rblk->stat_encrypt_cnt, rblk->stat_encrypt_tlen, |
| 195 | rblk->stat_decrypt_cnt, rblk->stat_decrypt_tlen, |
Corentin Labbe | 44f1313 | 2018-11-29 14:42:25 +0000 | [diff] [blame] | 196 | rblk->stat_err_cnt); |
Corentin Labbe | a6f37ce | 2018-09-19 10:10:55 +0000 | [diff] [blame] | 197 | } else if (tb[CRYPTOCFGA_STAT_AKCIPHER]) { |
| 198 | struct rtattr *rta = tb[CRYPTOCFGA_STAT_AKCIPHER]; |
Corentin Labbe | 76d09ea | 2018-11-29 14:42:20 +0000 | [diff] [blame] | 199 | struct crypto_stat_akcipher *rblk = |
| 200 | (struct crypto_stat_akcipher *)RTA_DATA(rta); |
| 201 | printf("%s\tAkcipher\n\tEncrypt: %llu bytes: %llu\n\tDecrypt: %llu bytes: %llu\n\tSign: %llu\n\tVerify: %llu\n\tErrors: %llu\n", |
Corentin Labbe | a6f37ce | 2018-09-19 10:10:55 +0000 | [diff] [blame] | 202 | drivername, |
| 203 | rblk->stat_encrypt_cnt, rblk->stat_encrypt_tlen, |
| 204 | rblk->stat_decrypt_cnt, rblk->stat_decrypt_tlen, |
| 205 | rblk->stat_sign_cnt, rblk->stat_verify_cnt, |
Corentin Labbe | 44f1313 | 2018-11-29 14:42:25 +0000 | [diff] [blame] | 206 | rblk->stat_err_cnt); |
Corentin Labbe | a6f37ce | 2018-09-19 10:10:55 +0000 | [diff] [blame] | 207 | } else if (tb[CRYPTOCFGA_STAT_CIPHER]) { |
| 208 | struct rtattr *rta = tb[CRYPTOCFGA_STAT_CIPHER]; |
Corentin Labbe | 76d09ea | 2018-11-29 14:42:20 +0000 | [diff] [blame] | 209 | struct crypto_stat_cipher *rblk = |
| 210 | (struct crypto_stat_cipher *)RTA_DATA(rta); |
| 211 | printf("%s\tcipher\n\tEncrypt: %llu bytes: %llu\n\tDecrypt: %llu bytes: %llu\n\tErrors: %llu\n", |
Corentin Labbe | a6f37ce | 2018-09-19 10:10:55 +0000 | [diff] [blame] | 212 | drivername, |
| 213 | rblk->stat_encrypt_cnt, rblk->stat_encrypt_tlen, |
| 214 | rblk->stat_decrypt_cnt, rblk->stat_decrypt_tlen, |
Corentin Labbe | 44f1313 | 2018-11-29 14:42:25 +0000 | [diff] [blame] | 215 | rblk->stat_err_cnt); |
Corentin Labbe | a6f37ce | 2018-09-19 10:10:55 +0000 | [diff] [blame] | 216 | } else if (tb[CRYPTOCFGA_STAT_RNG]) { |
| 217 | struct rtattr *rta = tb[CRYPTOCFGA_STAT_RNG]; |
Corentin Labbe | 76d09ea | 2018-11-29 14:42:20 +0000 | [diff] [blame] | 218 | struct crypto_stat_rng *rrng = |
| 219 | (struct crypto_stat_rng *)RTA_DATA(rta); |
| 220 | printf("%s\tRNG\n\tSeed: %llu\n\tGenerate: %llu bytes: %llu\n\tErrors: %llu\n", |
Corentin Labbe | a6f37ce | 2018-09-19 10:10:55 +0000 | [diff] [blame] | 221 | drivername, |
| 222 | rrng->stat_seed_cnt, |
| 223 | rrng->stat_generate_cnt, rrng->stat_generate_tlen, |
Corentin Labbe | 44f1313 | 2018-11-29 14:42:25 +0000 | [diff] [blame] | 224 | rrng->stat_err_cnt); |
Corentin Labbe | a6f37ce | 2018-09-19 10:10:55 +0000 | [diff] [blame] | 225 | } else if (tb[CRYPTOCFGA_STAT_KPP]) { |
| 226 | struct rtattr *rta = tb[CRYPTOCFGA_STAT_KPP]; |
Corentin Labbe | 76d09ea | 2018-11-29 14:42:20 +0000 | [diff] [blame] | 227 | struct crypto_stat_kpp *rkpp = |
| 228 | (struct crypto_stat_kpp *)RTA_DATA(rta); |
| 229 | printf("%s\tKPP\n\tSetsecret: %llu\n\tGenerate public key: %llu\n\tCompute_shared_secret: %llu\n\tErrors: %llu\n", |
Corentin Labbe | a6f37ce | 2018-09-19 10:10:55 +0000 | [diff] [blame] | 230 | drivername, |
| 231 | rkpp->stat_setsecret_cnt, |
| 232 | rkpp->stat_generate_public_key_cnt, |
| 233 | rkpp->stat_compute_shared_secret_cnt, |
Corentin Labbe | 44f1313 | 2018-11-29 14:42:25 +0000 | [diff] [blame] | 234 | rkpp->stat_err_cnt); |
Corentin Labbe | a6f37ce | 2018-09-19 10:10:55 +0000 | [diff] [blame] | 235 | } else { |
| 236 | fprintf(stderr, "%s is of an unknown algorithm\n", drivername); |
| 237 | } |
| 238 | ret = 0; |
| 239 | out: |
| 240 | close(sd); |
| 241 | return ret; |
| 242 | } |
| 243 | |
| 244 | int main(int argc, const char *argv[]) |
| 245 | { |
| 246 | char buf[4096]; |
| 247 | FILE *procfd; |
| 248 | int i, lastspace; |
| 249 | int ret; |
| 250 | |
| 251 | procfd = fopen("/proc/crypto", "r"); |
| 252 | if (!procfd) { |
| 253 | ret = errno; |
| 254 | fprintf(stderr, "Cannot open /proc/crypto %s\n", strerror(errno)); |
| 255 | return ret; |
| 256 | } |
| 257 | if (argc > 1) { |
| 258 | if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) { |
| 259 | printf("Usage: %s [-h|--help] display this help\n", argv[0]); |
| 260 | printf("Usage: %s display all crypto statistics\n", argv[0]); |
| 261 | printf("Usage: %s drivername1 drivername2 ... = display crypto statistics about drivername1 ...\n", argv[0]); |
| 262 | return 0; |
| 263 | } |
| 264 | for (i = 1; i < argc; i++) { |
| 265 | ret = get_stat(argv[i]); |
| 266 | if (ret) { |
| 267 | fprintf(stderr, "Failed with %s\n", strerror(-ret)); |
| 268 | return ret; |
| 269 | } |
| 270 | } |
| 271 | return 0; |
| 272 | } |
| 273 | |
| 274 | while (fgets(buf, sizeof(buf), procfd)) { |
| 275 | if (!strncmp(buf, "driver", 6)) { |
| 276 | lastspace = 0; |
| 277 | i = 0; |
| 278 | while (i < strlen(buf)) { |
| 279 | i++; |
| 280 | if (buf[i] == ' ') |
| 281 | lastspace = i; |
| 282 | } |
| 283 | buf[strlen(buf) - 1] = '\0'; |
| 284 | ret = get_stat(buf + lastspace + 1); |
| 285 | if (ret) { |
| 286 | fprintf(stderr, "Failed with %s\n", strerror(-ret)); |
| 287 | goto out; |
| 288 | } |
| 289 | } |
| 290 | } |
| 291 | out: |
| 292 | fclose(procfd); |
| 293 | return ret; |
| 294 | } |