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