1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2015 Nexenta Systems, Inc. All rights reserved. 14 * Copyright 2018, Joyent, Inc. 15 */ 16 17 #include <fcntl.h> 18 #include <strings.h> 19 #include <unistd.h> 20 #include <errno.h> 21 #include <stdio.h> 22 #include <stdlib.h> 23 24 #include "cryptotest.h" 25 26 struct crypto_op { 27 char *in; 28 char *out; 29 char *key; 30 char *param; 31 32 size_t inlen; 33 size_t outlen; 34 size_t keylen; 35 size_t paramlen; 36 size_t updatelen; 37 38 char *mechname; 39 40 /* internal */ 41 crypto_mech_type_t mech; 42 crypto_session_id_t hsession; 43 crypto_func_group_t fg; 44 }; 45 46 static int fd; 47 static const char CRYPTO_DEVICE[] = "/dev/crypto"; 48 49 int 50 kcf_do_ioctl(int opcode, uint_t *arg, char *opstr) 51 { 52 int ret; 53 54 while ((ret = ioctl(fd, opcode, arg)) < 0) { 55 if (errno != EINTR) 56 break; 57 } 58 59 if (ret < 0 || *arg != CRYPTO_SUCCESS) 60 (void) fprintf(stderr, "%s: Error = %d %d 0x%02x\n", 61 (opstr == NULL) ? "ioctl" : opstr, 62 ret, errno, *arg); 63 64 if (ret < 0) 65 return (errno); 66 67 return (*arg); 68 } 69 70 crypto_op_t * 71 cryptotest_init(cryptotest_t *arg, crypto_func_group_t fg) 72 { 73 crypto_op_t *op = malloc(sizeof (*op)); 74 75 if (op == NULL) 76 return (NULL); 77 78 while ((fd = open(CRYPTO_DEVICE, O_RDWR)) < 0) { 79 if (errno != EINTR) 80 return (NULL); 81 } 82 83 op->in = (char *)arg->in; 84 op->out = (char *)arg->out; 85 op->key = (char *)arg->key; 86 op->param = (char *)arg->param; 87 88 op->inlen = arg->inlen; 89 op->outlen = arg->outlen; 90 op->keylen = arg->keylen * 8; /* kcf uses keylen in bits */ 91 op->paramlen = arg->plen; 92 op->updatelen = arg->updatelen; 93 94 op->mechname = arg->mechname; 95 96 op->hsession = CRYPTO_INVALID_SESSION; 97 op->fg = fg; 98 99 if (op->out == NULL) 100 op->outlen = op->inlen; 101 return (op); 102 } 103 104 int 105 cryptotest_close_session(crypto_session_id_t session) 106 { 107 crypto_close_session_t cs; 108 109 cs.cs_session = session; 110 return (kcf_do_ioctl(CRYPTO_CLOSE_SESSION, (uint_t *)&cs, "session")); 111 } 112 113 int 114 cryptotest_close(crypto_op_t *op) 115 { 116 if (op->hsession != CRYPTO_INVALID_SESSION) 117 (void) cryptotest_close_session(op->hsession); 118 free(op); 119 if (fd >= 0) 120 return (close(fd)); 121 return (0); 122 } 123 124 int 125 get_mech_info(crypto_op_t *op) 126 { 127 crypto_get_mechanism_number_t get_number; 128 129 bzero(&get_number, sizeof (get_number)); 130 131 get_number.pn_mechanism_string = op->mechname; 132 get_number.pn_mechanism_len = strlen(op->mechname) + 1; 133 134 if (kcf_do_ioctl(CRYPTO_GET_MECHANISM_NUMBER, 135 (uint_t *)&get_number, "get_mech_info") != CRYPTO_SUCCESS) { 136 (void) fprintf(stderr, "failed to resolve mechanism name %s\n", 137 op->mechname); 138 return (CTEST_NAME_RESOLVE_FAILED); 139 } 140 op->mech = get_number.pn_internal_number; 141 return (CRYPTO_SUCCESS); 142 } 143 144 int 145 get_hsession_by_mech(crypto_op_t *op) 146 { 147 crypto_by_mech_t mech; 148 int rv; 149 150 mech.mech_keylen = op->keylen; 151 mech.mech_type = op->mech; 152 mech.mech_fg = op->fg; 153 154 rv = kcf_do_ioctl(CRYPTO_GET_PROVIDER_BY_MECH, (uint_t *)&mech, 155 "get_hsession_by_mech"); 156 157 if (rv != 0 || mech.rv != CRYPTO_SUCCESS) { 158 (void) fprintf(stderr, 159 "could not find provider for mechanism %llu\n", 160 mech.mech_type); 161 return (CTEST_MECH_NO_PROVIDER); 162 } 163 164 op->hsession = mech.session_id; 165 166 return (CRYPTO_SUCCESS); 167 } 168 169 /* 170 * CRYPTO_MAC_* functions 171 */ 172 int 173 mac_init(crypto_op_t *op) 174 { 175 crypto_mac_init_t init; 176 177 bzero((void *)&init, sizeof (init)); 178 179 init.mi_session = op->hsession; 180 181 init.mi_key.ck_data = op->key; 182 init.mi_key.ck_format = CRYPTO_KEY_RAW; /* must be this */ 183 init.mi_key.ck_length = op->keylen; 184 185 init.mi_mech.cm_type = op->mech; 186 init.mi_mech.cm_param = NULL; 187 init.mi_mech.cm_param_len = 0; 188 189 return (kcf_do_ioctl(CRYPTO_MAC_INIT, (uint_t *)&init, "init")); 190 } 191 192 int 193 mac_single(crypto_op_t *op) 194 { 195 crypto_mac_t mac; 196 197 bzero(&mac, sizeof (mac)); 198 mac.cm_session = op->hsession; 199 mac.cm_datalen = op->inlen; 200 mac.cm_databuf = op->in; 201 mac.cm_maclen = op->outlen; 202 mac.cm_macbuf = op->out; 203 204 return (kcf_do_ioctl(CRYPTO_MAC, (uint_t *)&mac, "single")); 205 } 206 207 int 208 mac_update(crypto_op_t *op, int offset) 209 { 210 crypto_mac_update_t update; 211 212 bzero((void *)&update, sizeof (update)); 213 214 update.mu_session = op->hsession; 215 update.mu_databuf = op->in + offset; 216 update.mu_datalen = op->updatelen; 217 218 return (kcf_do_ioctl(CRYPTO_MAC_UPDATE, (uint_t *)&update, "update")); 219 } 220 221 int 222 mac_final(crypto_op_t *op) 223 { 224 crypto_mac_final_t final; 225 226 bzero((void *)&final, sizeof (final)); 227 228 final.mf_session = op->hsession; 229 final.mf_maclen = op->outlen; 230 final.mf_macbuf = op->out; 231 232 return (kcf_do_ioctl(CRYPTO_MAC_FINAL, (uint_t *)&final, "final")); 233 } 234 235 236 /* 237 * CRYPTO_ENCRYPT_* functions 238 */ 239 240 int 241 encrypt_init(crypto_op_t *op) 242 { 243 crypto_encrypt_init_t init; 244 245 bzero((void *)&init, sizeof (init)); 246 247 init.ei_session = op->hsession; 248 249 init.ei_key.ck_data = op->key; 250 init.ei_key.ck_format = CRYPTO_KEY_RAW; /* must be this */ 251 init.ei_key.ck_length = op->keylen; 252 253 init.ei_mech.cm_type = op->mech; 254 init.ei_mech.cm_param = op->param; 255 init.ei_mech.cm_param_len = op->paramlen; 256 257 return (kcf_do_ioctl(CRYPTO_ENCRYPT_INIT, (uint_t *)&init, "init")); 258 } 259 260 int 261 encrypt_single(crypto_op_t *op) 262 { 263 crypto_encrypt_t encrypt; 264 265 bzero(&encrypt, sizeof (encrypt)); 266 encrypt.ce_session = op->hsession; 267 encrypt.ce_datalen = op->inlen; 268 encrypt.ce_databuf = op->in; 269 encrypt.ce_encrlen = op->outlen; 270 encrypt.ce_encrbuf = op->out; 271 272 return (kcf_do_ioctl(CRYPTO_ENCRYPT, (uint_t *)&encrypt, "single")); 273 } 274 275 int 276 encrypt_update(crypto_op_t *op, int offset, size_t *encrlen) 277 { 278 crypto_encrypt_update_t update; 279 int ret; 280 bzero((void *)&update, sizeof (update)); 281 282 update.eu_session = op->hsession; 283 update.eu_databuf = op->in + offset; 284 update.eu_datalen = op->updatelen; 285 update.eu_encrlen = op->outlen - *encrlen; 286 update.eu_encrbuf = op->out + *encrlen; 287 288 ret = kcf_do_ioctl(CRYPTO_ENCRYPT_UPDATE, (uint_t *)&update, "update"); 289 *encrlen += update.eu_encrlen; 290 return (ret); 291 } 292 293 int 294 encrypt_final(crypto_op_t *op, size_t encrlen) 295 { 296 crypto_encrypt_final_t final; 297 298 bzero((void *)&final, sizeof (final)); 299 300 final.ef_session = op->hsession; 301 final.ef_encrlen = op->outlen - encrlen; 302 final.ef_encrbuf = op->out + encrlen; 303 304 return (kcf_do_ioctl(CRYPTO_ENCRYPT_FINAL, (uint_t *)&final, "final")); 305 } 306 307 /* 308 * CRYPTO_DECRYPT_* functions 309 */ 310 311 int 312 decrypt_init(crypto_op_t *op) 313 { 314 crypto_decrypt_init_t init; 315 316 bzero((void *)&init, sizeof (init)); 317 318 init.di_session = op->hsession; 319 320 init.di_key.ck_data = op->key; 321 init.di_key.ck_format = CRYPTO_KEY_RAW; /* must be this */ 322 init.di_key.ck_length = op->keylen; 323 324 init.di_mech.cm_type = op->mech; 325 init.di_mech.cm_param = op->param; 326 init.di_mech.cm_param_len = op->paramlen; 327 328 return (kcf_do_ioctl(CRYPTO_DECRYPT_INIT, (uint_t *)&init, "init")); 329 } 330 331 int 332 decrypt_single(crypto_op_t *op) 333 { 334 crypto_decrypt_t decrypt; 335 336 bzero(&decrypt, sizeof (decrypt)); 337 decrypt.cd_session = op->hsession; 338 decrypt.cd_datalen = op->outlen; 339 decrypt.cd_databuf = op->out; 340 decrypt.cd_encrlen = op->inlen; 341 decrypt.cd_encrbuf = op->in; 342 343 return (kcf_do_ioctl(CRYPTO_DECRYPT, (uint_t *)&decrypt, "single")); 344 } 345 346 int 347 decrypt_update(crypto_op_t *op, int offset, size_t *encrlen) 348 { 349 crypto_decrypt_update_t update; 350 int ret; 351 352 bzero((void *)&update, sizeof (update)); 353 354 update.du_session = op->hsession; 355 update.du_databuf = op->out + *encrlen; 356 update.du_datalen = op->outlen - *encrlen; 357 update.du_encrlen = op->updatelen; 358 update.du_encrbuf = op->in + offset; 359 360 ret = kcf_do_ioctl(CRYPTO_DECRYPT_UPDATE, (uint_t *)&update, "update"); 361 *encrlen += update.du_datalen; 362 return (ret); 363 } 364 365 int 366 decrypt_final(crypto_op_t *op, size_t encrlen) 367 { 368 crypto_decrypt_final_t final; 369 370 bzero((void *)&final, sizeof (final)); 371 372 final.df_session = op->hsession; 373 final.df_datalen = op->outlen - encrlen; 374 final.df_databuf = op->out + encrlen; 375 376 return (kcf_do_ioctl(CRYPTO_DECRYPT_FINAL, (uint_t *)&final, "final")); 377 } 378 379 int 380 digest_init(crypto_op_t *op) 381 { 382 crypto_digest_init_t init; 383 384 bzero(&init, sizeof (init)); 385 386 init.di_session = op->hsession; 387 388 init.di_mech.cm_type = op->mech; 389 init.di_mech.cm_param = NULL; 390 init.di_mech.cm_param_len = 0; 391 392 return (kcf_do_ioctl(CRYPTO_DIGEST_INIT, (uint_t *)&init, "init")); 393 } 394 395 int 396 digest_single(crypto_op_t *op) 397 { 398 crypto_digest_t digest; 399 400 bzero(&digest, sizeof (digest)); 401 402 digest.cd_session = op->hsession; 403 404 digest.cd_datalen = op->inlen; 405 digest.cd_databuf = op->in; 406 digest.cd_digestlen = op->outlen; 407 digest.cd_digestbuf = op->out; 408 409 return (kcf_do_ioctl(CRYPTO_DIGEST, (uint_t *)&digest, "digest")); 410 } 411 412 int 413 digest_update(crypto_op_t *op, int offset) 414 { 415 crypto_digest_update_t update; 416 417 bzero(&update, sizeof (update)); 418 419 update.du_session = op->hsession; 420 421 update.du_datalen = op->updatelen; 422 update.du_databuf = op->in + offset; 423 424 return (kcf_do_ioctl(CRYPTO_DIGEST_UPDATE, (uint_t *)&update, 425 "update")); 426 } 427 428 int 429 digest_final(crypto_op_t *op) 430 { 431 crypto_digest_final_t final; 432 433 bzero(&final, sizeof (final)); 434 435 final.df_session = op->hsession; 436 437 final.df_digestlen = op->outlen; 438 final.df_digestbuf = op->out; 439 440 return (kcf_do_ioctl(CRYPTO_DIGEST_FINAL, (uint_t *)&final, "final")); 441 }