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 }