1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 /*
  26  * Copyright 2015 by Saso Kiselkov. All rights reserved.
  27  */
  28 
  29 #include <sys/strsun.h>
  30 #include <sys/systm.h>
  31 #include <sys/sysmacros.h>
  32 #include <sys/kmem.h>
  33 #include <sys/md5.h>
  34 #include <sys/sha1.h>
  35 #include <sys/sha2.h>
  36 #include <modes/modes.h>
  37 #include <sys/crypto/common.h>
  38 #include <sys/crypto/impl.h>
  39 
  40 /*
  41  * Utility routine to apply the command, 'cmd', to the
  42  * data in the uio structure.
  43  */
  44 int
  45 crypto_uio_data(crypto_data_t *data, uchar_t *buf, int len, cmd_type_t cmd,
  46     void *digest_ctx, void (*update)())
  47 {
  48         uio_t *uiop = data->cd_uio;
  49         off_t offset = data->cd_offset;
  50         size_t length = len;
  51         uint_t vec_idx;
  52         size_t cur_len;
  53         uchar_t *datap;
  54 
  55         ASSERT(data->cd_format == CRYPTO_DATA_UIO);
  56         if (uiop->uio_segflg != UIO_SYSSPACE) {
  57                 return (CRYPTO_ARGUMENTS_BAD);
  58         }
  59 
  60         /*
  61          * Jump to the first iovec containing data to be
  62          * processed.
  63          */
  64         for (vec_idx = 0; vec_idx < uiop->uio_iovcnt &&
  65             offset >= uiop->uio_iov[vec_idx].iov_len;
  66             offset -= uiop->uio_iov[vec_idx++].iov_len)
  67                 ;
  68 
  69         if (vec_idx == uiop->uio_iovcnt) {
  70                 /*
  71                  * The caller specified an offset that is larger than
  72                  * the total size of the buffers it provided.
  73                  */
  74                 return (CRYPTO_DATA_LEN_RANGE);
  75         }
  76 
  77         while (vec_idx < uiop->uio_iovcnt && length > 0) {
  78                 cur_len = MIN(uiop->uio_iov[vec_idx].iov_len -
  79                     offset, length);
  80 
  81                 datap = (uchar_t *)(uiop->uio_iov[vec_idx].iov_base +
  82                     offset);
  83                 switch (cmd) {
  84                 case COPY_FROM_DATA:
  85                         bcopy(datap, buf, cur_len);
  86                         buf += cur_len;
  87                         break;
  88                 case COPY_TO_DATA:
  89                         bcopy(buf, datap, cur_len);
  90                         buf += cur_len;
  91                         break;
  92                 case COMPARE_TO_DATA:
  93                         if (bcmp(datap, buf, cur_len))
  94                                 return (CRYPTO_SIGNATURE_INVALID);
  95                         buf += cur_len;
  96                         break;
  97                 case MD5_DIGEST_DATA:
  98                 case SHA1_DIGEST_DATA:
  99                 case SHA2_DIGEST_DATA:
 100                 case GHASH_DATA:
 101                         update(digest_ctx, datap, cur_len);
 102                         break;
 103                 }
 104 
 105                 length -= cur_len;
 106                 vec_idx++;
 107                 offset = 0;
 108         }
 109 
 110         if (vec_idx == uiop->uio_iovcnt && length > 0) {
 111                 /*
 112                  * The end of the specified iovec's was reached but
 113                  * the length requested could not be processed.
 114                  */
 115                 switch (cmd) {
 116                 case COPY_TO_DATA:
 117                         data->cd_length = len;
 118                         return (CRYPTO_BUFFER_TOO_SMALL);
 119                 default:
 120                         return (CRYPTO_DATA_LEN_RANGE);
 121                 }
 122         }
 123 
 124         return (CRYPTO_SUCCESS);
 125 }
 126 
 127 /*
 128  * Utility routine to apply the command, 'cmd', to the
 129  * data in the mblk structure.
 130  */
 131 int
 132 crypto_mblk_data(crypto_data_t *data, uchar_t *buf, int len, cmd_type_t cmd,
 133     void *digest_ctx, void (*update)())
 134 {
 135         off_t offset = data->cd_offset;
 136         size_t length = len;
 137         mblk_t *mp;
 138         size_t cur_len;
 139         uchar_t *datap;
 140 
 141         ASSERT(data->cd_format == CRYPTO_DATA_MBLK);
 142         /*
 143          * Jump to the first mblk_t containing data to be processed.
 144          */
 145         for (mp = data->cd_mp; mp != NULL && offset >= MBLKL(mp);
 146             offset -= MBLKL(mp), mp = mp->b_cont)
 147                 ;
 148         if (mp == NULL) {
 149                 /*
 150                  * The caller specified an offset that is larger
 151                  * than the total size of the buffers it provided.
 152                  */
 153                 return (CRYPTO_DATA_LEN_RANGE);
 154         }
 155 
 156         /*
 157          * Now do the processing on the mblk chain.
 158          */
 159         while (mp != NULL && length > 0) {
 160                 cur_len = MIN(MBLKL(mp) - offset, length);
 161 
 162                 datap = (uchar_t *)(mp->b_rptr + offset);
 163                 switch (cmd) {
 164                 case COPY_FROM_DATA:
 165                         bcopy(datap, buf, cur_len);
 166                         buf += cur_len;
 167                         break;
 168                 case COPY_TO_DATA:
 169                         bcopy(buf, datap, cur_len);
 170                         buf += cur_len;
 171                         break;
 172                 case COMPARE_TO_DATA:
 173                         if (bcmp(datap, buf, cur_len))
 174                                 return (CRYPTO_SIGNATURE_INVALID);
 175                         buf += cur_len;
 176                         break;
 177                 case MD5_DIGEST_DATA:
 178                 case SHA1_DIGEST_DATA:
 179                 case SHA2_DIGEST_DATA:
 180                 case GHASH_DATA:
 181                         update(digest_ctx, datap, cur_len);
 182                         break;
 183                 }
 184 
 185                 length -= cur_len;
 186                 offset = 0;
 187                 mp = mp->b_cont;
 188         }
 189 
 190         if (mp == NULL && length > 0) {
 191                 /*
 192                  * The end of the mblk was reached but the length
 193                  * requested could not be processed.
 194                  */
 195                 switch (cmd) {
 196                 case COPY_TO_DATA:
 197                         data->cd_length = len;
 198                         return (CRYPTO_BUFFER_TOO_SMALL);
 199                 default:
 200                         return (CRYPTO_DATA_LEN_RANGE);
 201                 }
 202         }
 203 
 204         return (CRYPTO_SUCCESS);
 205 }
 206 
 207 /*
 208  * Utility routine to copy a buffer to a crypto_data structure.
 209  */
 210 int
 211 crypto_put_output_data(uchar_t *buf, crypto_data_t *output, int len)
 212 {
 213         switch (output->cd_format) {
 214         case CRYPTO_DATA_RAW:
 215                 if (output->cd_raw.iov_len < len) {
 216                         output->cd_length = len;
 217                         return (CRYPTO_BUFFER_TOO_SMALL);
 218                 }
 219                 bcopy(buf, (uchar_t *)(output->cd_raw.iov_base +
 220                     output->cd_offset), len);
 221                 break;
 222 
 223         case CRYPTO_DATA_UIO:
 224                 return (crypto_uio_data(output, buf, len,
 225                     COPY_TO_DATA, NULL, NULL));
 226 
 227         case CRYPTO_DATA_MBLK:
 228                 return (crypto_mblk_data(output, buf, len,
 229                     COPY_TO_DATA, NULL, NULL));
 230 
 231         default:
 232                 return (CRYPTO_ARGUMENTS_BAD);
 233         }
 234 
 235         return (CRYPTO_SUCCESS);
 236 }
 237 
 238 /*
 239  * Utility routine to get data from a crypto_data structure.
 240  *
 241  * '*dptr' contains a pointer to a buffer on return. 'buf'
 242  * is allocated by the caller and is ignored for CRYPTO_DATA_RAW case.
 243  */
 244 int
 245 crypto_get_input_data(crypto_data_t *input, uchar_t **dptr, uchar_t *buf)
 246 {
 247         int rv;
 248 
 249         switch (input->cd_format) {
 250         case CRYPTO_DATA_RAW:
 251                 if (input->cd_raw.iov_len < input->cd_length)
 252                         return (CRYPTO_ARGUMENTS_BAD);
 253                 *dptr = (uchar_t *)(input->cd_raw.iov_base +
 254                     input->cd_offset);
 255                 break;
 256 
 257         case CRYPTO_DATA_UIO:
 258                 if ((rv = crypto_uio_data(input, buf, input->cd_length,
 259                     COPY_FROM_DATA, NULL, NULL)) != CRYPTO_SUCCESS)
 260                         return (rv);
 261                 *dptr = buf;
 262                 break;
 263 
 264         case CRYPTO_DATA_MBLK:
 265                 if ((rv = crypto_mblk_data(input, buf, input->cd_length,
 266                     COPY_FROM_DATA, NULL, NULL)) != CRYPTO_SUCCESS)
 267                         return (rv);
 268                 *dptr = buf;
 269                 break;
 270 
 271         default:
 272                 return (CRYPTO_ARGUMENTS_BAD);
 273         }
 274 
 275         return (CRYPTO_SUCCESS);
 276 }
 277 
 278 int
 279 crypto_copy_key_to_ctx(crypto_key_t *in_key, crypto_key_t **out_key,
 280     size_t *out_size, int kmflag)
 281 {
 282         int i, count;
 283         size_t len;
 284         caddr_t attr_val;
 285         crypto_object_attribute_t *k_attrs = NULL;
 286         crypto_key_t *key;
 287 
 288         ASSERT(in_key->ck_format == CRYPTO_KEY_ATTR_LIST);
 289 
 290         count = in_key->ck_count;
 291         /* figure out how much memory to allocate for everything */
 292         len = sizeof (crypto_key_t) +
 293             count * sizeof (crypto_object_attribute_t);
 294         for (i = 0; i < count; i++) {
 295                 len += roundup(in_key->ck_attrs[i].oa_value_len,
 296                     sizeof (caddr_t));
 297         }
 298 
 299         /* one big allocation for everything */
 300         key = kmem_alloc(len, kmflag);
 301         if (key == NULL)
 302                 return (CRYPTO_HOST_MEMORY);
 303         k_attrs = (crypto_object_attribute_t *)(void *)((caddr_t)key +
 304             sizeof (crypto_key_t));
 305 
 306         attr_val = (caddr_t)k_attrs +
 307             count * sizeof (crypto_object_attribute_t);
 308         for (i = 0; i < count; i++) {
 309                 k_attrs[i].oa_type = in_key->ck_attrs[i].oa_type;
 310                 bcopy(in_key->ck_attrs[i].oa_value, attr_val,
 311                     in_key->ck_attrs[i].oa_value_len);
 312                 k_attrs[i].oa_value = attr_val;
 313                 k_attrs[i].oa_value_len = in_key->ck_attrs[i].oa_value_len;
 314                 attr_val += roundup(k_attrs[i].oa_value_len, sizeof (caddr_t));
 315         }
 316 
 317         key->ck_format = CRYPTO_KEY_ATTR_LIST;
 318         key->ck_count = count;
 319         key->ck_attrs = k_attrs;
 320         *out_key = key;
 321         *out_size = len;                /* save the size to be freed */
 322 
 323         return (CRYPTO_SUCCESS);
 324 }
 325 
 326 int
 327 crypto_digest_data(crypto_data_t *data, void *dctx, uchar_t *digest,
 328     void (*update)(), void (*final)(), uchar_t flag)
 329 {
 330         int rv, dlen;
 331         uchar_t *dptr;
 332 
 333         ASSERT(flag & CRYPTO_DO_MD5 || flag & CRYPTO_DO_SHA1 ||
 334             flag & CRYPTO_DO_SHA2);
 335         if (data == NULL) {
 336                 ASSERT((flag & CRYPTO_DO_UPDATE) == 0);
 337                 goto dofinal;
 338         }
 339 
 340         dlen = data->cd_length;
 341 
 342         if (flag & CRYPTO_DO_UPDATE) {
 343 
 344                 switch (data->cd_format) {
 345                 case CRYPTO_DATA_RAW:
 346                         dptr = (uchar_t *)(data->cd_raw.iov_base +
 347                             data->cd_offset);
 348 
 349                         update(dctx, dptr, dlen);
 350 
 351                 break;
 352 
 353                 case CRYPTO_DATA_UIO:
 354                         if (flag & CRYPTO_DO_MD5)
 355                                 rv = crypto_uio_data(data, NULL, dlen,
 356                                     MD5_DIGEST_DATA, dctx, update);
 357 
 358                         else if (flag & CRYPTO_DO_SHA1)
 359                                 rv = crypto_uio_data(data, NULL, dlen,
 360                                     SHA1_DIGEST_DATA, dctx, update);
 361 
 362                         else
 363                                 rv = crypto_uio_data(data, NULL, dlen,
 364                                     SHA2_DIGEST_DATA, dctx, update);
 365 
 366                         if (rv != CRYPTO_SUCCESS)
 367                                 return (rv);
 368 
 369                         break;
 370 
 371                 case CRYPTO_DATA_MBLK:
 372                         if (flag & CRYPTO_DO_MD5)
 373                                 rv = crypto_mblk_data(data, NULL, dlen,
 374                                     MD5_DIGEST_DATA, dctx, update);
 375 
 376                         else if (flag & CRYPTO_DO_SHA1)
 377                                 rv = crypto_mblk_data(data, NULL, dlen,
 378                                     SHA1_DIGEST_DATA, dctx, update);
 379 
 380                         else
 381                                 rv = crypto_mblk_data(data, NULL, dlen,
 382                                     SHA2_DIGEST_DATA, dctx, update);
 383 
 384                         if (rv != CRYPTO_SUCCESS)
 385                                 return (rv);
 386 
 387                         break;
 388                 }
 389         }
 390 
 391 dofinal:
 392         if (flag & CRYPTO_DO_FINAL) {
 393                 final(digest, dctx);
 394         }
 395 
 396         return (CRYPTO_SUCCESS);
 397 }
 398 
 399 int
 400 crypto_update_iov(void *ctx, crypto_data_t *input, crypto_data_t *output,
 401     int (*cipher)(void *, caddr_t, size_t, crypto_data_t *),
 402     void (*copy_block)(const uint8_t *, uint64_t *))
 403 {
 404         common_ctx_t *common_ctx = ctx;
 405         int rv;
 406 
 407         if (input->cd_miscdata != NULL) {
 408                 copy_block((uint8_t *)input->cd_miscdata,
 409                     &common_ctx->cc_iv[0]);
 410         }
 411 
 412         if (input->cd_raw.iov_len < input->cd_length)
 413                 return (CRYPTO_ARGUMENTS_BAD);
 414 
 415         rv = (cipher)(ctx, input->cd_raw.iov_base + input->cd_offset,
 416             input->cd_length, (input == output) ? NULL : output);
 417 
 418         return (rv);
 419 }
 420 
 421 int
 422 crypto_update_uio(void *ctx, crypto_data_t *input, crypto_data_t *output,
 423     int (*cipher)(void *, caddr_t, size_t, crypto_data_t *),
 424     void (*copy_block)(const uint8_t *, uint64_t *))
 425 {
 426         common_ctx_t *common_ctx = ctx;
 427         uio_t *uiop = input->cd_uio;
 428         off_t offset = input->cd_offset;
 429         size_t length = input->cd_length;
 430         uint_t vec_idx;
 431         size_t cur_len;
 432 
 433         if (input->cd_miscdata != NULL) {
 434                 copy_block((uint8_t *)input->cd_miscdata,
 435                     &common_ctx->cc_iv[0]);
 436         }
 437 
 438         if (input->cd_uio->uio_segflg != UIO_SYSSPACE) {
 439                 return (CRYPTO_ARGUMENTS_BAD);
 440         }
 441 
 442         /*
 443          * Jump to the first iovec containing data to be
 444          * processed.
 445          */
 446         for (vec_idx = 0; vec_idx < uiop->uio_iovcnt &&
 447             offset >= uiop->uio_iov[vec_idx].iov_len;
 448             offset -= uiop->uio_iov[vec_idx++].iov_len)
 449                 ;
 450         if (vec_idx == uiop->uio_iovcnt) {
 451                 /*
 452                  * The caller specified an offset that is larger than the
 453                  * total size of the buffers it provided.
 454                  */
 455                 return (CRYPTO_DATA_LEN_RANGE);
 456         }
 457 
 458         /*
 459          * Now process the iovecs.
 460          */
 461         while (vec_idx < uiop->uio_iovcnt && length > 0) {
 462                 cur_len = MIN(uiop->uio_iov[vec_idx].iov_len -
 463                     offset, length);
 464 
 465                 (cipher)(ctx, uiop->uio_iov[vec_idx].iov_base + offset,
 466                     cur_len, (input == output) ? NULL : output);
 467 
 468                 length -= cur_len;
 469                 vec_idx++;
 470                 offset = 0;
 471         }
 472 
 473         if (vec_idx == uiop->uio_iovcnt && length > 0) {
 474                 /*
 475                  * The end of the specified iovec's was reached but
 476                  * the length requested could not be processed, i.e.
 477                  * The caller requested to digest more data than it provided.
 478                  */
 479 
 480                 return (CRYPTO_DATA_LEN_RANGE);
 481         }
 482 
 483         return (CRYPTO_SUCCESS);
 484 }
 485 
 486 int
 487 crypto_update_mp(void *ctx, crypto_data_t *input, crypto_data_t *output,
 488     int (*cipher)(void *, caddr_t, size_t, crypto_data_t *),
 489     void (*copy_block)(const uint8_t *, uint64_t *))
 490 {
 491         common_ctx_t *common_ctx = ctx;
 492         off_t offset = input->cd_offset;
 493         size_t length = input->cd_length;
 494         mblk_t *mp;
 495         size_t cur_len;
 496 
 497         if (input->cd_miscdata != NULL) {
 498                 copy_block((uint8_t *)input->cd_miscdata,
 499                     &common_ctx->cc_iv[0]);
 500         }
 501 
 502         /*
 503          * Jump to the first mblk_t containing data to be processed.
 504          */
 505         for (mp = input->cd_mp; mp != NULL && offset >= MBLKL(mp);
 506             offset -= MBLKL(mp), mp = mp->b_cont)
 507                 ;
 508         if (mp == NULL) {
 509                 /*
 510                  * The caller specified an offset that is larger than the
 511                  * total size of the buffers it provided.
 512                  */
 513                 return (CRYPTO_DATA_LEN_RANGE);
 514         }
 515 
 516         /*
 517          * Now do the processing on the mblk chain.
 518          */
 519         while (mp != NULL && length > 0) {
 520                 cur_len = MIN(MBLKL(mp) - offset, length);
 521                 (cipher)(ctx, (char *)(mp->b_rptr + offset), cur_len,
 522                     (input == output) ? NULL : output);
 523 
 524                 length -= cur_len;
 525                 offset = 0;
 526                 mp = mp->b_cont;
 527         }
 528 
 529         if (mp == NULL && length > 0) {
 530                 /*
 531                  * The end of the mblk was reached but the length requested
 532                  * could not be processed, i.e. The caller requested
 533                  * to digest more data than it provided.
 534                  */
 535                 return (CRYPTO_DATA_LEN_RANGE);
 536         }
 537 
 538         return (CRYPTO_SUCCESS);
 539 }
 540 
 541 /*
 542  * Utility routine to look up a attribute of type, 'type',
 543  * in the key.
 544  */
 545 int
 546 crypto_get_key_attr(crypto_key_t *key, crypto_attr_type_t type,
 547     uchar_t **value, ssize_t *value_len)
 548 {
 549         int i;
 550 
 551         ASSERT(key->ck_format == CRYPTO_KEY_ATTR_LIST);
 552         for (i = 0; i < key->ck_count; i++) {
 553                 if (key->ck_attrs[i].oa_type == type) {
 554                         *value = (uchar_t *)key->ck_attrs[i].oa_value;
 555                         *value_len = key->ck_attrs[i].oa_value_len;
 556                         return (CRYPTO_SUCCESS);
 557                 }
 558         }
 559 
 560         return (CRYPTO_FAILED);
 561 }