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 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Deimos - cryptographic acceleration based upon Broadcom 582x. 31 */ 32 33 #include <sys/types.h> 34 #include <sys/ddi.h> 35 #include <sys/sunddi.h> 36 #include <sys/kmem.h> 37 #include <sys/crypto/common.h> 38 #include <sys/crypto/spi.h> 39 #include <sys/crypto/ioctl.h> 40 #include <sys/crypto/dca.h> 41 42 /* 43 * DSA implementation. 44 */ 45 46 static void dca_dsa_sign_done(dca_request_t *, int); 47 static void dca_dsa_verify_done(dca_request_t *, int); 48 49 50 int dca_dsa_sign(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *sig, 51 crypto_req_handle_t req); 52 int dca_dsa_verify(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *sig, 53 crypto_req_handle_t req); 54 int dca_dsainit(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, 55 crypto_key_t *key, int kmflag, int mode); 56 57 58 int 59 dca_dsa_sign(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *sig, 60 crypto_req_handle_t req) 61 { 62 dca_request_t *reqp = ctx->cc_provider_private; 63 dca_t *dca = ctx->cc_provider; 64 int err; 65 int rv = CRYPTO_QUEUED; 66 caddr_t kaddr; 67 size_t buflen; 68 69 buflen = dca_length(data); 70 if (buflen != SHA1LEN) { 71 DBG(dca, DWARN, "dca_dsa_sign: data length != %d", SHA1LEN); 72 rv = CRYPTO_DATA_LEN_RANGE; 73 goto errout; 74 } 75 76 /* Return length needed to store the output. */ 77 if (dca_length(sig) < DSASIGLEN) { 78 DBG(dca, DWARN, 79 "dca_dsa_sign: output buffer too short (%d < %d)", 80 dca_length(sig), DSASIGLEN); 81 sig->cd_length = DSASIGLEN; 82 rv = CRYPTO_BUFFER_TOO_SMALL; 83 goto errout; 84 } 85 86 /* 87 * Don't change the data values of the data crypto_data_t structure 88 * yet. Only reset the sig cd_length to zero before writing to it. 89 */ 90 91 reqp->dr_job_stat = DS_DSASIGN; 92 reqp->dr_byte_stat = -1; 93 reqp->dr_in = data; 94 reqp->dr_out = sig; 95 reqp->dr_callback = dca_dsa_sign_done; 96 97 reqp->dr_kcf_req = req; 98 /* dca_gather() increments cd_offset & dec. cd_length by SHA1LEN. */ 99 err = dca_gather(data, reqp->dr_ibuf_kaddr, SHA1LEN, 1); 100 if (err != CRYPTO_SUCCESS) { 101 DBG(dca, DWARN, "dca_dsa_sign: dca_gather() failed"); 102 rv = err; 103 goto errout; 104 } 105 106 107 /* sync the input buffer */ 108 (void) ddi_dma_sync(reqp->dr_ibuf_dmah, 0, SHA1LEN, 109 DDI_DMA_SYNC_FORDEV); 110 if (dca_check_dma_handle(dca, reqp->dr_ibuf_dmah, 111 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) { 112 reqp->destroy = TRUE; 113 rv = CRYPTO_DEVICE_ERROR; 114 goto errout; 115 } 116 117 reqp->dr_in_paddr = reqp->dr_ibuf_paddr; 118 reqp->dr_in_next = 0; 119 reqp->dr_in_len = SHA1LEN; 120 reqp->dr_pkt_length = buflen; 121 122 /* 123 * The output requires *two* buffers, r followed by s. 124 */ 125 kaddr = reqp->dr_ctx_kaddr + reqp->dr_offset; 126 127 /* r */ 128 reqp->dr_out_paddr = reqp->dr_obuf_paddr; 129 reqp->dr_out_len = DSAPARTLEN; 130 reqp->dr_out_next = reqp->dr_ctx_paddr + reqp->dr_offset; 131 132 /* s */ 133 PUTDESC32(reqp, kaddr, DESC_BUFADDR, 134 reqp->dr_obuf_paddr + DSAPARTLEN); 135 PUTDESC32(reqp, kaddr, DESC_NEXT, 0); 136 PUTDESC16(reqp, kaddr, DESC_RSVD, 0); 137 PUTDESC16(reqp, kaddr, DESC_LENGTH, DSAPARTLEN); 138 139 /* schedule the work by doing a submit */ 140 rv = dca_start(dca, reqp, MCR2, 1); 141 142 errout: 143 144 if (rv != CRYPTO_QUEUED && rv != CRYPTO_BUFFER_TOO_SMALL) 145 (void) dca_free_context(ctx); 146 147 return (rv); 148 } 149 150 static void 151 dca_dsa_sign_done(dca_request_t *reqp, int errno) 152 { 153 if (errno == CRYPTO_SUCCESS) { 154 (void) ddi_dma_sync(reqp->dr_obuf_dmah, 0, DSASIGLEN, 155 DDI_DMA_SYNC_FORKERNEL); 156 if (dca_check_dma_handle(reqp->dr_dca, reqp->dr_obuf_dmah, 157 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) { 158 reqp->destroy = TRUE; 159 errno = CRYPTO_DEVICE_ERROR; 160 goto errout; 161 } 162 /* 163 * Set the sig cd_length to zero so it's ready to take the 164 * signature. Have already confirmed its size is adequate. 165 */ 166 reqp->dr_out->cd_length = 0; 167 errno = dca_scatter(reqp->dr_obuf_kaddr, 168 reqp->dr_out, DSAPARTLEN, 1); 169 if (errno != CRYPTO_SUCCESS) { 170 DBG(reqp->dr_dca, DWARN, 171 "dca_dsa_sign_done: dca_scatter() failed"); 172 goto errout; 173 } 174 errno = dca_scatter(reqp->dr_obuf_kaddr+DSAPARTLEN, 175 reqp->dr_out, DSAPARTLEN, 1); 176 if (errno != CRYPTO_SUCCESS) { 177 DBG(reqp->dr_dca, DWARN, 178 "dca_dsa_sign_done: dca_scatter() failed"); 179 } 180 } 181 errout: 182 ASSERT(reqp->dr_kcf_req != NULL); 183 184 /* notify framework that request is completed */ 185 crypto_op_notification(reqp->dr_kcf_req, errno); 186 DBG(reqp->dr_dca, DINTR, 187 "dca_dsa_sign_done: rtn 0x%x to kef via crypto_op_notification", 188 errno); 189 190 /* 191 * For non-atomic operations, reqp will be freed in the kCF 192 * callback function since it may be needed again if 193 * CRYPTO_BUFFER_TOO_SMALL is returned to kCF 194 */ 195 if (reqp->dr_ctx.atomic) { 196 crypto_ctx_t ctx; 197 ctx.cc_provider_private = reqp; 198 dca_dsactxfree(&ctx); 199 } 200 } 201 202 int 203 dca_dsa_verify(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *sig, 204 crypto_req_handle_t req) 205 { 206 dca_request_t *reqp = ctx->cc_provider_private; 207 dca_t *dca = ctx->cc_provider; 208 int err; 209 int rv = CRYPTO_QUEUED; 210 caddr_t kaddr; 211 212 /* Impossible for verify to be an in-place operation. */ 213 if (sig == NULL) { 214 rv = CRYPTO_ARGUMENTS_BAD; 215 goto errout; 216 } 217 218 if (dca_length(data) != SHA1LEN) { 219 DBG(dca, DWARN, "dca_dsa_verify: input length != %d", SHA1LEN); 220 rv = CRYPTO_DATA_LEN_RANGE; 221 goto errout; 222 } 223 224 if (dca_length(sig) != DSASIGLEN) { 225 DBG(dca, DWARN, "dca_dsa_verify: signature length != %d", 226 DSASIGLEN); 227 rv = CRYPTO_SIGNATURE_LEN_RANGE; 228 goto errout; 229 } 230 231 /* Don't change the data & sig values for verify. */ 232 233 reqp->dr_job_stat = DS_DSAVERIFY; 234 reqp->dr_byte_stat = -1; 235 236 /* 237 * Grab h, r and s. 238 */ 239 err = dca_gather(data, reqp->dr_ibuf_kaddr, SHA1LEN, 1); 240 if (err != CRYPTO_SUCCESS) { 241 DBG(dca, DWARN, 242 "dca_dsa_vrfy: dca_gather() failed for h"); 243 rv = err; 244 goto errout; 245 } 246 err = dca_gather(sig, reqp->dr_ibuf_kaddr+SHA1LEN, DSAPARTLEN, 1); 247 if (err != CRYPTO_SUCCESS) { 248 DBG(dca, DWARN, 249 "dca_dsa_vrfy: dca_gather() failed for r"); 250 rv = err; 251 goto errout; 252 } 253 err = dca_gather(sig, reqp->dr_ibuf_kaddr+SHA1LEN+DSAPARTLEN, 254 DSAPARTLEN, 1); 255 if (err != CRYPTO_SUCCESS) { 256 DBG(dca, DWARN, 257 "dca_dsa_vrfy: dca_gather() failed for s"); 258 rv = err; 259 goto errout; 260 } 261 /* 262 * As dca_gather() increments the cd_offset and decrements 263 * the cd_length as it copies the data rewind the values ready for 264 * the final compare. 265 */ 266 sig->cd_offset -= (DSAPARTLEN * 2); 267 sig->cd_length += (DSAPARTLEN * 2); 268 /* sync the input buffer */ 269 (void) ddi_dma_sync(reqp->dr_ibuf_dmah, 0, SHA1LEN + DSAPARTLEN, 270 DDI_DMA_SYNC_FORDEV); 271 272 if (dca_check_dma_handle(dca, reqp->dr_ibuf_dmah, 273 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) { 274 reqp->destroy = TRUE; 275 rv = CRYPTO_DEVICE_ERROR; 276 goto errout; 277 } 278 279 reqp->dr_in = data; 280 reqp->dr_out = sig; 281 reqp->dr_kcf_req = req; 282 reqp->dr_flags |= DR_SCATTER | DR_GATHER; 283 reqp->dr_callback = dca_dsa_verify_done; 284 285 /* 286 * Input requires three buffers. m, followed by r, followed by s. 287 * In order to deal with things cleanly, we reverse the signature 288 * into the buffer and then fix up the pointers. 289 */ 290 reqp->dr_pkt_length = SHA1LEN; 291 292 reqp->dr_in_paddr = reqp->dr_ibuf_paddr; 293 reqp->dr_in_len = SHA1LEN; 294 reqp->dr_in_next = reqp->dr_ctx_paddr + reqp->dr_offset; 295 296 reqp->dr_out_paddr = reqp->dr_obuf_paddr; 297 reqp->dr_out_len = DSAPARTLEN; 298 reqp->dr_out_next = 0; 299 300 /* setup 1st chain for r */ 301 kaddr = reqp->dr_ctx_kaddr + reqp->dr_offset; 302 PUTDESC32(reqp, kaddr, DESC_BUFADDR, reqp->dr_ibuf_paddr + SHA1LEN); 303 PUTDESC32(reqp, kaddr, DESC_NEXT, 304 reqp->dr_ctx_paddr + reqp->dr_offset + DESC_SIZE); 305 PUTDESC16(reqp, kaddr, DESC_RSVD, 0); 306 PUTDESC16(reqp, kaddr, DESC_LENGTH, DSAPARTLEN); 307 308 /* and 2nd chain for s */ 309 kaddr = reqp->dr_ctx_kaddr + reqp->dr_offset + DESC_SIZE; 310 PUTDESC32(reqp, kaddr, DESC_BUFADDR, reqp->dr_ibuf_paddr + 311 SHA1LEN + DSAPARTLEN); 312 PUTDESC32(reqp, kaddr, DESC_NEXT, 0); 313 PUTDESC16(reqp, kaddr, DESC_RSVD, 0); 314 PUTDESC16(reqp, kaddr, DESC_LENGTH, DSAPARTLEN); 315 316 /* schedule the work by doing a submit */ 317 rv = dca_start(dca, reqp, MCR2, 1); 318 319 errout: 320 if (rv != CRYPTO_QUEUED && rv != CRYPTO_BUFFER_TOO_SMALL) { 321 (void) dca_free_context(ctx); 322 } 323 return (rv); 324 } 325 326 static void 327 dca_dsa_verify_done(dca_request_t *reqp, int errno) 328 { 329 if (errno == CRYPTO_SUCCESS) { 330 int count = DSAPARTLEN; 331 crypto_data_t *sig = reqp->dr_out; 332 caddr_t daddr; 333 334 (void) ddi_dma_sync(reqp->dr_obuf_dmah, 0, count, 335 DDI_DMA_SYNC_FORKERNEL); 336 if (dca_check_dma_handle(reqp->dr_dca, reqp->dr_obuf_dmah, 337 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) { 338 reqp->destroy = TRUE; 339 errno = CRYPTO_DEVICE_ERROR; 340 goto errout; 341 } 342 343 /* Can only handle a contiguous data buffer currently. */ 344 if (dca_sgcheck(reqp->dr_dca, sig, DCA_SG_CONTIG)) { 345 errno = CRYPTO_SIGNATURE_INVALID; 346 goto errout; 347 } 348 349 if ((daddr = dca_bufdaddr(sig)) == NULL) { 350 errno = CRYPTO_ARGUMENTS_BAD; 351 goto errout; 352 } 353 354 if (dca_bcmp_reverse(daddr, reqp->dr_obuf_kaddr, 355 DSAPARTLEN) != 0) { 356 /* VERIFY FAILED */ 357 errno = CRYPTO_SIGNATURE_INVALID; 358 } 359 } 360 errout: 361 ASSERT(reqp->dr_kcf_req != NULL); 362 363 /* notify framework that request is completed */ 364 365 crypto_op_notification(reqp->dr_kcf_req, errno); 366 DBG(reqp->dr_dca, DINTR, 367 "dca_dsa_verify_done: rtn 0x%x to kef via crypto_op_notification", 368 errno); 369 370 /* 371 * For non-atomic operations, reqp will be freed in the kCF 372 * callback function since it may be needed again if 373 * CRYPTO_BUFFER_TOO_SMALL is returned to kCF 374 */ 375 if (reqp->dr_ctx.atomic) { 376 crypto_ctx_t ctx; 377 ctx.cc_provider_private = reqp; 378 dca_dsactxfree(&ctx); 379 } 380 } 381 382 /* ARGSUSED */ 383 int 384 dca_dsainit(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, 385 crypto_key_t *key, int kmflag, int mode) 386 { 387 crypto_object_attribute_t *attr; 388 unsigned plen = 0, qlen = 0, glen = 0, xlen = 0; 389 uchar_t *p, *q, *g, *x; 390 dca_request_t *reqp = NULL; 391 dca_t *dca = (dca_t *)ctx->cc_provider; 392 int rv = CRYPTO_SUCCESS; 393 unsigned pbits, padjlen; 394 uint16_t ctxlen; 395 caddr_t kaddr; 396 397 if ((reqp = dca_getreq(dca, MCR2, 1)) == NULL) { 398 dca_error(dca, 399 "dca_dsainit: unable to allocate request for DSA"); 400 rv = CRYPTO_HOST_MEMORY; 401 goto errout; 402 } 403 404 ctx->cc_provider_private = reqp; 405 reqp->dr_ctx.ctx_cm_type = mechanism->cm_type; 406 407 if ((attr = dca_get_key_attr(key)) == NULL) { 408 DBG(NULL, DWARN, "dca_dsainit: key attributes missing"); 409 rv = CRYPTO_KEY_TYPE_INCONSISTENT; 410 goto errout; 411 } 412 413 /* Prime */ 414 if (dca_attr_lookup_uint8_array(attr, key->ck_count, CKA_PRIME, 415 (void *) &p, &plen)) { 416 DBG(NULL, DWARN, "dca_dsainit: prime key value not present"); 417 rv = CRYPTO_ARGUMENTS_BAD; 418 goto errout; 419 } 420 421 /* Subprime */ 422 if (dca_attr_lookup_uint8_array(attr, key->ck_count, CKA_SUBPRIME, 423 (void *) &q, &qlen)) { 424 DBG(NULL, DWARN, "dca_dsainit: subprime key value not present"); 425 rv = CRYPTO_ARGUMENTS_BAD; 426 goto errout; 427 } 428 429 /* Base */ 430 if (dca_attr_lookup_uint8_array(attr, key->ck_count, CKA_BASE, 431 (void *) &g, &glen)) { 432 DBG(NULL, DWARN, "dca_dsainit: base key value not present"); 433 rv = CRYPTO_ARGUMENTS_BAD; 434 goto errout; 435 } 436 437 /* Value */ 438 if (dca_attr_lookup_uint8_array(attr, key->ck_count, CKA_VALUE, 439 (void *) &x, &xlen)) { 440 DBG(NULL, DWARN, "dca_dsainit: value key not present"); 441 rv = CRYPTO_ARGUMENTS_BAD; 442 goto errout; 443 } 444 445 if (plen == 0 || qlen == 0 || glen == 0 || xlen == 0) { 446 rv = CRYPTO_ARGUMENTS_BAD; 447 goto errout; 448 } 449 450 if (plen > DSA_MAX_KEY_LEN) { 451 /* maximum 1Kbit key */ 452 DBG(NULL, DWARN, "dca_dsainit: maximum 1Kbit key (%d)", plen); 453 rv = CRYPTO_KEY_SIZE_RANGE; 454 goto errout; 455 } 456 457 if (qlen > DSAPARTLEN) { 458 DBG(NULL, DWARN, "dca_dsainit: q is too long (%d)", qlen); 459 rv = CRYPTO_KEY_SIZE_RANGE; 460 goto errout; 461 } 462 463 if (mode == DCA_DSA_SIGN && xlen > DSAPARTLEN) { 464 DBG(NULL, DWARN, 465 "dca_dsainit: private key is too long (%d)", xlen); 466 rv = CRYPTO_KEY_SIZE_RANGE; 467 goto errout; 468 } 469 470 /* 471 * Setup the key partion of the request. 472 */ 473 474 pbits = dca_bitlen(p, plen); 475 padjlen = dca_padfull(pbits); 476 477 /* accounts for leading context words */ 478 if (mode == DCA_DSA_SIGN) { 479 ctxlen = CTX_DSABIGNUMS + DSAPARTLEN + (padjlen * 2) + 480 DSAPARTLEN; 481 PUTCTX16(reqp, CTX_CMD, CMD_DSASIGN); 482 } else { 483 ctxlen = CTX_DSABIGNUMS + DSAPARTLEN + (padjlen * 3); 484 PUTCTX16(reqp, CTX_CMD, CMD_DSAVERIFY); 485 } 486 487 PUTCTX16(reqp, CTX_LENGTH, ctxlen); 488 PUTCTX16(reqp, CTX_DSAMSGTYPE, CTX_DSAMSGTYPE_SHA1); 489 PUTCTX16(reqp, CTX_DSARSVD, 0); 490 if (mode == DCA_DSA_SIGN) 491 PUTCTX16(reqp, CTX_DSARNG, CTX_DSARNG_GEN); 492 else 493 PUTCTX16(reqp, CTX_DSARNG, 0); 494 PUTCTX16(reqp, CTX_DSAPLEN, pbits); 495 496 kaddr = reqp->dr_ctx_kaddr + CTX_DSABIGNUMS; 497 498 /* store the bignums */ 499 dca_reverse(q, kaddr, qlen, DSAPARTLEN); 500 kaddr += DSAPARTLEN; 501 502 dca_reverse(p, kaddr, plen, padjlen); 503 kaddr += padjlen; 504 505 dca_reverse(g, kaddr, glen, padjlen); 506 kaddr += padjlen; 507 508 if (mode == DCA_DSA_SIGN) { 509 dca_reverse(x, kaddr, xlen, DSAPARTLEN); 510 kaddr += DSAPARTLEN; 511 } else { 512 dca_reverse(x, kaddr, xlen, padjlen); 513 kaddr += padjlen; 514 } 515 516 return (CRYPTO_SUCCESS); 517 518 errout: 519 520 dca_dsactxfree(ctx); 521 return (rv); 522 } 523 524 void 525 dca_dsactxfree(void *arg) 526 { 527 crypto_ctx_t *ctx = (crypto_ctx_t *)arg; 528 dca_request_t *reqp = ctx->cc_provider_private; 529 530 if (reqp == NULL) 531 return; 532 533 reqp->dr_ctx.ctx_cm_type = 0; 534 reqp->dr_ctx.atomic = 0; 535 if (reqp->destroy) 536 dca_destroyreq(reqp); 537 else 538 dca_freereq(reqp); 539 540 ctx->cc_provider_private = NULL; 541 } 542 543 int 544 dca_dsaatomic(crypto_provider_handle_t provider, 545 crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 546 crypto_key_t *key, crypto_data_t *data, crypto_data_t *sig, 547 int kmflag, crypto_req_handle_t req, int mode) 548 { 549 crypto_ctx_t ctx; /* on the stack */ 550 int rv; 551 552 ctx.cc_provider = provider; 553 ctx.cc_session = session_id; 554 555 rv = dca_dsainit(&ctx, mechanism, key, kmflag, mode); 556 if (rv != CRYPTO_SUCCESS) { 557 DBG(NULL, DWARN, "dca_dsaatomic: dca_dsainit() failed"); 558 return (rv); 559 } 560 561 /* 562 * Set the atomic flag so that the hardware callback function 563 * will free the context. 564 */ 565 ((dca_request_t *)ctx.cc_provider_private)->dr_ctx.atomic = 1; 566 567 if (mode == DCA_DSA_SIGN) { 568 rv = dca_dsa_sign(&ctx, data, sig, req); 569 } else { 570 ASSERT(mode == DCA_DSA_VRFY); 571 rv = dca_dsa_verify(&ctx, data, sig, req); 572 } 573 574 /* 575 * The context will be freed in the hardware callback function if it 576 * is queued 577 */ 578 if (rv != CRYPTO_QUEUED) 579 dca_dsactxfree(&ctx); 580 581 return (rv); 582 } 583