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  */
  15 
  16 #include <fcntl.h>
  17 #include <strings.h>
  18 #include <unistd.h>
  19 #include <errno.h>
  20 #include <stdio.h>
  21 #include <stdlib.h>
  22 
  23 #include "cryptotest.h"
  24 
  25 struct crypto_op {
  26         char *in;
  27         char *out;
  28         char *key;
  29         char *param;
  30 
  31         size_t inlen;
  32         size_t outlen;
  33         size_t keylen;
  34         size_t paramlen;
  35         size_t updatelen;
  36 
  37         char *mechname;
  38 
  39         /* internal */
  40         crypto_mech_type_t mech;
  41         crypto_session_id_t hsession;
  42         crypto_func_group_t fg;
  43 };
  44 
  45 static int fd;
  46 static const char CRYPTO_DEVICE[] = "/dev/crypto";
  47 
  48 int
  49 kcf_do_ioctl(int opcode, uint_t *arg, char *opstr)
  50 {
  51         int ret;
  52 
  53         while ((ret = ioctl(fd, opcode, arg)) < 0) {
  54                 if (errno != EINTR)
  55                         break;
  56         }
  57 
  58         if (ret < 0 || *arg != CRYPTO_SUCCESS)
  59                 (void) fprintf(stderr, "%s: Error = %d %d 0x%02x\n",
  60                     (opstr == NULL) ? "ioctl" : opstr,
  61                     ret, errno, *arg);
  62 
  63         if (ret < 0)
  64                 return (errno);
  65 
  66         return (*arg);
  67 }
  68 
  69 crypto_op_t *
  70 cryptotest_init(cryptotest_t *arg, crypto_func_group_t fg)
  71 {
  72         crypto_op_t *op = malloc(sizeof (*op));
  73 
  74         if (op == NULL)
  75                 return (NULL);
  76 
  77         while ((fd = open(CRYPTO_DEVICE, O_RDWR)) < 0) {
  78                 if (errno != EINTR)
  79                         return (NULL);
  80         }
  81 
  82         op->in = (char *)arg->in;
  83         op->out = (char *)arg->out;
  84         op->key = (char *)arg->key;
  85         op->param = (char *)arg->param;
  86 
  87         op->inlen = arg->inlen;
  88         op->outlen = arg->outlen;
  89         op->keylen = arg->keylen * 8; /* kcf uses keylen in bits */
  90         op->paramlen = arg->plen;
  91         op->updatelen = arg->updatelen;
  92 
  93         op->mechname = arg->mechname;
  94 
  95         op->hsession = CRYPTO_INVALID_SESSION;
  96         op->fg = fg;
  97 
  98         if (op->out == NULL)
  99                 op->outlen = op->inlen;
 100         return (op);
 101 }
 102 
 103 int
 104 cryptotest_close_session(crypto_session_id_t session)
 105 {
 106         crypto_close_session_t cs;
 107 
 108         cs.cs_session = session;
 109         return (kcf_do_ioctl(CRYPTO_CLOSE_SESSION, (uint_t *)&cs, "session"));
 110 }
 111 
 112 int
 113 cryptotest_close(crypto_op_t *op)
 114 {
 115         if (op->hsession != CRYPTO_INVALID_SESSION)
 116                 (void) cryptotest_close_session(op->hsession);
 117         free(op);
 118         if (fd >= 0)
 119                 return (close(fd));
 120         return (0);
 121 }
 122 
 123 int
 124 get_mech_info(crypto_op_t *op)
 125 {
 126         crypto_get_mechanism_number_t get_number;
 127 
 128         bzero(&get_number, sizeof (get_number));
 129 
 130         get_number.pn_mechanism_string = op->mechname;
 131         get_number.pn_mechanism_len = strlen(op->mechname) + 1;
 132 
 133         if (kcf_do_ioctl(CRYPTO_GET_MECHANISM_NUMBER,
 134             (uint_t *)&get_number, "get_mech_info") != CRYPTO_SUCCESS) {
 135                 (void) fprintf(stderr, "failed to resolve mechanism name %s\n",
 136                     op->mechname);
 137                 (void) cryptotest_close(op);
 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                 (void) cryptotest_close(op);
 162                 return (CTEST_MECH_NO_PROVIDER);
 163         }
 164 
 165         op->hsession = mech.session_id;
 166 
 167         return (CRYPTO_SUCCESS);
 168 }
 169 
 170 /*
 171  * CRYPTO_MAC_* functions
 172  */
 173 int
 174 mac_init(crypto_op_t *op)
 175 {
 176         crypto_mac_init_t init;
 177 
 178         bzero((void *)&init, sizeof (init));
 179 
 180         init.mi_session = op->hsession;
 181 
 182         init.mi_key.ck_data = op->key;
 183         init.mi_key.ck_format = CRYPTO_KEY_RAW; /* must be this */
 184         init.mi_key.ck_length = op->keylen;
 185 
 186         init.mi_mech.cm_type = op->mech;
 187         init.mi_mech.cm_param = NULL;
 188         init.mi_mech.cm_param_len = 0;
 189 
 190         return (kcf_do_ioctl(CRYPTO_MAC_INIT, (uint_t *)&init, "init"));
 191 }
 192 
 193 int
 194 mac_single(crypto_op_t *op)
 195 {
 196         crypto_mac_t mac;
 197 
 198         bzero(&mac, sizeof (mac));
 199         mac.cm_session = op->hsession;
 200         mac.cm_datalen = op->inlen;
 201         mac.cm_databuf = op->in;
 202         mac.cm_maclen = op->outlen;
 203         mac.cm_macbuf = op->out;
 204 
 205         return (kcf_do_ioctl(CRYPTO_MAC, (uint_t *)&mac, "single"));
 206 }
 207 
 208 int
 209 mac_update(crypto_op_t *op, int offset)
 210 {
 211         crypto_mac_update_t update;
 212 
 213         bzero((void *)&update, sizeof (update));
 214 
 215         update.mu_session = op->hsession;
 216         update.mu_databuf = op->in + offset;
 217         update.mu_datalen = op->updatelen;
 218 
 219         return (kcf_do_ioctl(CRYPTO_MAC_UPDATE, (uint_t *)&update, "update"));
 220 }
 221 
 222 int
 223 mac_final(crypto_op_t *op)
 224 {
 225         crypto_mac_final_t final;
 226 
 227         bzero((void *)&final, sizeof (final));
 228 
 229         final.mf_session = op->hsession;
 230         final.mf_maclen = op->outlen;
 231         final.mf_macbuf = op->out;
 232 
 233         return (kcf_do_ioctl(CRYPTO_MAC_FINAL, (uint_t *)&final, "final"));
 234 }
 235 
 236 
 237 /*
 238  * CRYPTO_ENCRYPT_* functions
 239  */
 240 
 241 int
 242 encrypt_init(crypto_op_t *op)
 243 {
 244         crypto_encrypt_init_t init;
 245 
 246         bzero((void *)&init, sizeof (init));
 247 
 248         init.ei_session = op->hsession;
 249 
 250         init.ei_key.ck_data = op->key;
 251         init.ei_key.ck_format = CRYPTO_KEY_RAW; /* must be this */
 252         init.ei_key.ck_length = op->keylen;
 253 
 254         init.ei_mech.cm_type = op->mech;
 255         init.ei_mech.cm_param = op->param;
 256         init.ei_mech.cm_param_len = op->paramlen;
 257 
 258         return (kcf_do_ioctl(CRYPTO_ENCRYPT_INIT, (uint_t *)&init, "init"));
 259 }
 260 
 261 int
 262 encrypt_single(crypto_op_t *op)
 263 {
 264         crypto_encrypt_t encrypt;
 265 
 266         bzero(&encrypt, sizeof (encrypt));
 267         encrypt.ce_session = op->hsession;
 268         encrypt.ce_datalen = op->inlen;
 269         encrypt.ce_databuf = op->in;
 270         encrypt.ce_encrlen = op->outlen;
 271         encrypt.ce_encrbuf = op->out;
 272 
 273         return (kcf_do_ioctl(CRYPTO_ENCRYPT, (uint_t *)&encrypt, "single"));
 274 }
 275 
 276 int
 277 encrypt_update(crypto_op_t *op, int offset, size_t *encrlen)
 278 {
 279         crypto_encrypt_update_t update;
 280         int ret;
 281         bzero((void *)&update, sizeof (update));
 282 
 283         update.eu_session = op->hsession;
 284         update.eu_databuf = op->in + offset;
 285         update.eu_datalen = op->updatelen;
 286         update.eu_encrlen = op->outlen - *encrlen;
 287         update.eu_encrbuf = op->out + *encrlen;
 288 
 289         ret = kcf_do_ioctl(CRYPTO_ENCRYPT_UPDATE, (uint_t *)&update, "update");
 290         *encrlen += update.eu_encrlen;
 291         return (ret);
 292 }
 293 
 294 int
 295 encrypt_final(crypto_op_t *op, size_t encrlen)
 296 {
 297         crypto_encrypt_final_t final;
 298 
 299         bzero((void *)&final, sizeof (final));
 300 
 301         final.ef_session = op->hsession;
 302         final.ef_encrlen = op->outlen - encrlen;
 303         final.ef_encrbuf = op->out + encrlen;
 304 
 305         return (kcf_do_ioctl(CRYPTO_ENCRYPT_FINAL, (uint_t *)&final, "final"));
 306 }
 307 
 308 /*
 309  * CRYPTO_DECRYPT_* functions
 310  */
 311 
 312 int
 313 decrypt_init(crypto_op_t *op)
 314 {
 315         crypto_decrypt_init_t init;
 316 
 317         bzero((void *)&init, sizeof (init));
 318 
 319         init.di_session = op->hsession;
 320 
 321         init.di_key.ck_data = op->key;
 322         init.di_key.ck_format = CRYPTO_KEY_RAW; /* must be this */
 323         init.di_key.ck_length = op->keylen;
 324 
 325         init.di_mech.cm_type = op->mech;
 326         init.di_mech.cm_param = op->param;
 327         init.di_mech.cm_param_len = op->paramlen;
 328 
 329         return (kcf_do_ioctl(CRYPTO_DECRYPT_INIT, (uint_t *)&init, "init"));
 330 }
 331 
 332 int
 333 decrypt_single(crypto_op_t *op)
 334 {
 335         crypto_decrypt_t decrypt;
 336 
 337         bzero(&decrypt, sizeof (decrypt));
 338         decrypt.cd_session = op->hsession;
 339         decrypt.cd_datalen = op->outlen;
 340         decrypt.cd_databuf = op->out;
 341         decrypt.cd_encrlen = op->inlen;
 342         decrypt.cd_encrbuf = op->in;
 343 
 344         return (kcf_do_ioctl(CRYPTO_DECRYPT, (uint_t *)&decrypt, "single"));
 345 }
 346 
 347 int
 348 decrypt_update(crypto_op_t *op, int offset, size_t *encrlen)
 349 {
 350         crypto_decrypt_update_t update;
 351         int ret;
 352 
 353         bzero((void *)&update, sizeof (update));
 354 
 355         update.du_session = op->hsession;
 356         update.du_databuf = op->out + *encrlen;
 357         update.du_datalen = op->outlen - *encrlen;
 358         update.du_encrlen = op->updatelen;
 359         update.du_encrbuf = op->in + offset;
 360 
 361         ret = kcf_do_ioctl(CRYPTO_DECRYPT_UPDATE, (uint_t *)&update, "update");
 362         *encrlen += update.du_datalen;
 363         return (ret);
 364 }
 365 
 366 int
 367 decrypt_final(crypto_op_t *op, size_t encrlen)
 368 {
 369         crypto_decrypt_final_t final;
 370 
 371         bzero((void *)&final, sizeof (final));
 372 
 373         final.df_session = op->hsession;
 374         final.df_datalen = op->outlen - encrlen;
 375         final.df_databuf = op->out + encrlen;
 376 
 377         return (kcf_do_ioctl(CRYPTO_DECRYPT_FINAL, (uint_t *)&final, "final"));
 378 }