1906Sgm89044 /*
2906Sgm89044 * CDDL HEADER START
3906Sgm89044 *
4906Sgm89044 * The contents of this file are subject to the terms of the
5906Sgm89044 * Common Development and Distribution License (the "License").
6906Sgm89044 * You may not use this file except in compliance with the License.
7906Sgm89044 *
8906Sgm89044 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9906Sgm89044 * or http://www.opensolaris.org/os/licensing.
10906Sgm89044 * See the License for the specific language governing permissions
11906Sgm89044 * and limitations under the License.
12906Sgm89044 *
13906Sgm89044 * When distributing Covered Code, include this CDDL HEADER in each
14906Sgm89044 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15906Sgm89044 * If applicable, add the following below this CDDL HEADER, with the
16906Sgm89044 * fields enclosed by brackets "[]" replaced with your own identifying
17906Sgm89044 * information: Portions Copyright [yyyy] [name of copyright owner]
18906Sgm89044 *
19906Sgm89044 * CDDL HEADER END
20906Sgm89044 */
21906Sgm89044
22906Sgm89044 /*
23*5063Sgm89044 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24906Sgm89044 * Use is subject to license terms.
25906Sgm89044 */
26906Sgm89044
27906Sgm89044 #pragma ident "%Z%%M% %I% %E% SMI"
28906Sgm89044
29906Sgm89044 /*
30906Sgm89044 * Deimos - cryptographic acceleration based upon Broadcom 582x.
31906Sgm89044 */
32906Sgm89044
33906Sgm89044 #include <sys/types.h>
34906Sgm89044 #include <sys/ddi.h>
35906Sgm89044 #include <sys/sunddi.h>
36906Sgm89044 #include <sys/kmem.h>
37906Sgm89044 #include <sys/note.h>
38906Sgm89044 #include <sys/crypto/spi.h>
39906Sgm89044 #include <sys/crypto/dca.h>
40906Sgm89044
41906Sgm89044
42906Sgm89044 static void dca_rsaverifydone(dca_request_t *, int);
43906Sgm89044 static void dca_rsadone(dca_request_t *, int);
44906Sgm89044
45906Sgm89044 /* Exported function prototypes */
46906Sgm89044 int dca_rsastart(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
47906Sgm89044 crypto_req_handle_t, int);
48906Sgm89044 int dca_rsainit(crypto_ctx_t *, crypto_mechanism_t *, crypto_key_t *, int);
49906Sgm89044 void dca_rsactxfree(void *);
50906Sgm89044 int dca_rsaatomic(crypto_provider_handle_t, crypto_session_id_t,
51906Sgm89044 crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *,
52906Sgm89044 int, crypto_req_handle_t, int);
53906Sgm89044
54906Sgm89044 /* Local function prototypes */
55906Sgm89044 static int dca_pkcs1_padding(dca_t *dca, caddr_t buf, int flen, int tlen,
56906Sgm89044 int private);
57906Sgm89044 static int dca_pkcs1_unpadding(char *buf, int *tlen, int flen, int mode);
58906Sgm89044 static int dca_x509_padding(caddr_t buf, int flen, int tlen);
59906Sgm89044 static int dca_x509_unpadding(char *buf, int tlen, int flen, int mode);
60906Sgm89044 static int decrypt_error_code(int mode, int decrypt, int verify, int def);
61906Sgm89044
62906Sgm89044
dca_rsastart(crypto_ctx_t * ctx,crypto_data_t * in,crypto_data_t * out,crypto_req_handle_t req,int mode)63906Sgm89044 int dca_rsastart(crypto_ctx_t *ctx, crypto_data_t *in, crypto_data_t *out,
64906Sgm89044 crypto_req_handle_t req, int mode)
65906Sgm89044 {
66906Sgm89044 dca_request_t *reqp = ctx->cc_provider_private;
67906Sgm89044 dca_t *dca = ctx->cc_provider;
68906Sgm89044 caddr_t daddr;
69906Sgm89044 int rv = CRYPTO_QUEUED;
70906Sgm89044 int len;
71906Sgm89044
72906Sgm89044 /* We don't support non-contiguous buffers for RSA */
73906Sgm89044 if (dca_sgcheck(dca, in, DCA_SG_CONTIG) ||
74906Sgm89044 dca_sgcheck(dca, out, DCA_SG_CONTIG)) {
75906Sgm89044 rv = CRYPTO_NOT_SUPPORTED;
76906Sgm89044 goto errout;
77906Sgm89044 }
78906Sgm89044
79906Sgm89044 len = dca_length(in);
80906Sgm89044
81906Sgm89044 /* Extracting the key attributes is now done in dca_rsainit(). */
82906Sgm89044 if (mode == DCA_RSA_ENC || mode == DCA_RSA_SIGN ||
83906Sgm89044 mode == DCA_RSA_SIGNR) {
84906Sgm89044 /*
85906Sgm89044 * Return length needed to store the output.
86906Sgm89044 * For sign, sign-recover, and encrypt, the output buffer
87906Sgm89044 * should not be smaller than modlen since PKCS or X_509
88906Sgm89044 * padding will be applied
89906Sgm89044 */
90906Sgm89044 if (dca_length(out) < reqp->dr_ctx.modlen) {
91906Sgm89044 DBG(dca, DWARN,
92906Sgm89044 "dca_rsastart: output buffer too short (%d < %d)",
93906Sgm89044 dca_length(out), reqp->dr_ctx.modlen);
94906Sgm89044 out->cd_length = reqp->dr_ctx.modlen;
95906Sgm89044 rv = CRYPTO_BUFFER_TOO_SMALL;
96906Sgm89044 goto errout;
97906Sgm89044 }
98906Sgm89044 }
99906Sgm89044 if (out != in && out->cd_length > reqp->dr_ctx.modlen)
100906Sgm89044 out->cd_length = reqp->dr_ctx.modlen;
101906Sgm89044
102906Sgm89044 /* The input length should not be bigger than the modulus */
103906Sgm89044 if (len > reqp->dr_ctx.modlen) {
104906Sgm89044 rv = decrypt_error_code(mode, CRYPTO_ENCRYPTED_DATA_LEN_RANGE,
105906Sgm89044 CRYPTO_SIGNATURE_LEN_RANGE, CRYPTO_DATA_LEN_RANGE);
106906Sgm89044 goto errout;
107906Sgm89044 }
108906Sgm89044
109906Sgm89044 /*
110906Sgm89044 * For decryption, verify, and verifyRecover, the input length should
111906Sgm89044 * not be less than the modulus
112906Sgm89044 */
113906Sgm89044 if (len < reqp->dr_ctx.modlen && (mode == DCA_RSA_DEC ||
114906Sgm89044 mode == DCA_RSA_VRFY || mode == DCA_RSA_VRFYR)) {
115906Sgm89044 rv = decrypt_error_code(mode, CRYPTO_ENCRYPTED_DATA_LEN_RANGE,
116906Sgm89044 CRYPTO_SIGNATURE_LEN_RANGE, CRYPTO_DATA_LEN_RANGE);
117906Sgm89044 goto errout;
118906Sgm89044 }
119906Sgm89044
120906Sgm89044 /*
121906Sgm89044 * For decryption and verifyRecover, the output buffer should not
122906Sgm89044 * be less than the modulus
123906Sgm89044 */
124906Sgm89044 if (out->cd_length < reqp->dr_ctx.modlen && (mode == DCA_RSA_DEC ||
125906Sgm89044 mode == DCA_RSA_VRFYR) &&
126906Sgm89044 reqp->dr_ctx.ctx_cm_type == RSA_X_509_MECH_INFO_TYPE) {
127906Sgm89044 out->cd_length = reqp->dr_ctx.modlen;
128906Sgm89044 rv = CRYPTO_BUFFER_TOO_SMALL;
129906Sgm89044 goto errout;
130906Sgm89044 }
131906Sgm89044
132906Sgm89044 /* For decrypt and verify, the input should not be less than output */
133906Sgm89044 if (out && len < out->cd_length) {
134906Sgm89044 if ((rv = decrypt_error_code(mode,
135906Sgm89044 CRYPTO_ENCRYPTED_DATA_LEN_RANGE,
136906Sgm89044 CRYPTO_SIGNATURE_LEN_RANGE, CRYPTO_SUCCESS)) !=
137906Sgm89044 CRYPTO_SUCCESS)
138906Sgm89044 goto errout;
139906Sgm89044 }
140906Sgm89044
141906Sgm89044 if ((daddr = dca_bufdaddr(in)) == NULL && len > 0) {
142906Sgm89044 rv = CRYPTO_ARGUMENTS_BAD;
143906Sgm89044 goto errout;
144906Sgm89044 }
145906Sgm89044
146906Sgm89044 if (dca_numcmp(daddr, len, (char *)reqp->dr_ctx.mod,
147906Sgm89044 reqp->dr_ctx.modlen) > 0) {
148906Sgm89044 DBG(dca, DWARN,
149906Sgm89044 "dca_rsastart: input larger (numerically) than modulus!");
150906Sgm89044 rv = decrypt_error_code(mode, CRYPTO_ENCRYPTED_DATA_INVALID,
151906Sgm89044 CRYPTO_SIGNATURE_INVALID, CRYPTO_DATA_INVALID);
152906Sgm89044 goto errout;
153906Sgm89044 }
154906Sgm89044
155906Sgm89044 reqp->dr_byte_stat = -1;
156906Sgm89044 reqp->dr_in = in;
157906Sgm89044 reqp->dr_out = out;
158906Sgm89044 reqp->dr_kcf_req = req;
159906Sgm89044 if (mode == DCA_RSA_VRFY)
160906Sgm89044 reqp->dr_callback = dca_rsaverifydone;
161906Sgm89044 else
162906Sgm89044 reqp->dr_callback = dca_rsadone;
163906Sgm89044
164906Sgm89044 dca_reverse(daddr, reqp->dr_ibuf_kaddr, len, reqp->dr_pkt_length);
165906Sgm89044 if (mode == DCA_RSA_ENC || mode == DCA_RSA_SIGN ||
166906Sgm89044 mode == DCA_RSA_SIGNR) {
167906Sgm89044 /*
168906Sgm89044 * Needs to pad appropriately for encrypt, sign, and
169906Sgm89044 * sign_recover
170906Sgm89044 */
171906Sgm89044 if (reqp->dr_ctx.ctx_cm_type == RSA_PKCS_MECH_INFO_TYPE) {
172906Sgm89044 if ((rv = dca_pkcs1_padding(dca, reqp->dr_ibuf_kaddr,
173906Sgm89044 len, reqp->dr_ctx.modlen, reqp->dr_ctx.pqfix)) !=
174906Sgm89044 CRYPTO_QUEUED)
175906Sgm89044 goto errout;
176906Sgm89044 } else if (reqp->dr_ctx.ctx_cm_type ==
177906Sgm89044 RSA_X_509_MECH_INFO_TYPE) {
178906Sgm89044 if ((rv = dca_x509_padding(reqp->dr_ibuf_kaddr,
179906Sgm89044 len, reqp->dr_pkt_length)) != CRYPTO_QUEUED)
180906Sgm89044 goto errout;
181906Sgm89044 }
182906Sgm89044 }
183906Sgm89044 reqp->dr_ctx.mode = mode;
184906Sgm89044
185906Sgm89044 /*
186906Sgm89044 * Since the max RSA input size is 256 bytes (2048 bits), the firstx
187906Sgm89044 * page (at least 4096 bytes) in the pre-mapped buffer is large enough.
188906Sgm89044 * Therefore, we use this first page for RSA.
189906Sgm89044 */
190906Sgm89044 reqp->dr_in_paddr = reqp->dr_ibuf_head.dc_buffer_paddr;
191906Sgm89044 reqp->dr_in_next = 0;
192906Sgm89044 reqp->dr_in_len = reqp->dr_pkt_length;
193906Sgm89044 reqp->dr_out_paddr = reqp->dr_obuf_head.dc_buffer_paddr;
194906Sgm89044 reqp->dr_out_next = 0;
195906Sgm89044 reqp->dr_out_len = reqp->dr_pkt_length;
196906Sgm89044
197906Sgm89044 /* schedule the work by doing a submit */
198906Sgm89044 rv = dca_start(dca, reqp, MCR2, 1);
199906Sgm89044
200906Sgm89044
201906Sgm89044 errout:
202906Sgm89044 if (rv != CRYPTO_QUEUED && rv != CRYPTO_BUFFER_TOO_SMALL)
203906Sgm89044 (void) dca_free_context(ctx);
204906Sgm89044
205906Sgm89044 return (rv);
206906Sgm89044 }
207906Sgm89044
208906Sgm89044 void
dca_rsadone(dca_request_t * reqp,int errno)209906Sgm89044 dca_rsadone(dca_request_t *reqp, int errno)
210906Sgm89044 {
211906Sgm89044 if (errno == CRYPTO_SUCCESS) {
212906Sgm89044 int outsz = reqp->dr_out->cd_length;
213906Sgm89044 caddr_t daddr;
214906Sgm89044
215906Sgm89044 (void) ddi_dma_sync(reqp->dr_obuf_dmah, 0, reqp->dr_out_len,
216906Sgm89044 DDI_DMA_SYNC_FORKERNEL);
217906Sgm89044 if (dca_check_dma_handle(reqp->dr_dca, reqp->dr_obuf_dmah,
218906Sgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) {
219906Sgm89044 reqp->destroy = TRUE;
220906Sgm89044 errno = CRYPTO_DEVICE_ERROR;
221906Sgm89044 goto errout;
222906Sgm89044 }
223906Sgm89044
224906Sgm89044 if (reqp->dr_ctx.mode == DCA_RSA_DEC ||
225906Sgm89044 reqp->dr_ctx.mode == DCA_RSA_VRFY ||
226906Sgm89044 reqp->dr_ctx.mode == DCA_RSA_VRFYR) {
227906Sgm89044 /*
228906Sgm89044 * Needs to unpad appropriately for decrypt, verify,
229906Sgm89044 * and verify_recover
230906Sgm89044 */
231906Sgm89044 if (reqp->dr_ctx.ctx_cm_type ==
232906Sgm89044 RSA_PKCS_MECH_INFO_TYPE) {
233906Sgm89044 errno = dca_pkcs1_unpadding(
234906Sgm89044 reqp->dr_obuf_kaddr, &outsz,
235906Sgm89044 reqp->dr_ctx.modlen, reqp->dr_ctx.mode);
236906Sgm89044
237906Sgm89044 /* check for bad data errors */
238906Sgm89044 if (errno != CRYPTO_SUCCESS &&
239906Sgm89044 errno != CRYPTO_BUFFER_TOO_SMALL) {
240906Sgm89044 goto errout;
241906Sgm89044 }
242906Sgm89044 if (dca_bufdaddr(reqp->dr_out) == NULL) {
243906Sgm89044 errno = CRYPTO_BUFFER_TOO_SMALL;
244906Sgm89044 }
245906Sgm89044 if (errno == CRYPTO_BUFFER_TOO_SMALL) {
246906Sgm89044 reqp->dr_out->cd_length = outsz;
247906Sgm89044 goto errout;
248906Sgm89044 }
249906Sgm89044 /* Reset the output data length */
250906Sgm89044 reqp->dr_out->cd_length = outsz;
251906Sgm89044 } else if (reqp->dr_ctx.ctx_cm_type ==
252906Sgm89044 RSA_X_509_MECH_INFO_TYPE) {
253906Sgm89044 if ((errno = dca_x509_unpadding(
254906Sgm89044 reqp->dr_obuf_kaddr, outsz,
255906Sgm89044 reqp->dr_pkt_length, reqp->dr_ctx.mode)) !=
256906Sgm89044 CRYPTO_SUCCESS)
257906Sgm89044 goto errout;
258906Sgm89044 }
259906Sgm89044 }
260906Sgm89044
261906Sgm89044 if ((daddr = dca_bufdaddr(reqp->dr_out)) == NULL) {
262906Sgm89044 DBG(reqp->dr_dca, DINTR,
263906Sgm89044 "dca_rsadone: reqp->dr_out is bad");
264906Sgm89044 errno = CRYPTO_ARGUMENTS_BAD;
265906Sgm89044 goto errout;
266906Sgm89044 }
267906Sgm89044 /*
268906Sgm89044 * Note that there may be some number of null bytes
269906Sgm89044 * at the end of the source (result), but we don't care
270906Sgm89044 * about them -- they are place holders only and are
271906Sgm89044 * truncated here.
272906Sgm89044 */
273906Sgm89044 dca_reverse(reqp->dr_obuf_kaddr, daddr, outsz, outsz);
274906Sgm89044 }
275906Sgm89044 errout:
276906Sgm89044 ASSERT(reqp->dr_kcf_req != NULL);
277906Sgm89044
278906Sgm89044 /* notify framework that request is completed */
279906Sgm89044 crypto_op_notification(reqp->dr_kcf_req, errno);
280906Sgm89044 DBG(reqp->dr_dca, DINTR,
281906Sgm89044 "dca_rsadone: returning 0x%x to the kef via crypto_op_notification",
282906Sgm89044 errno);
283906Sgm89044
284906Sgm89044 /*
285906Sgm89044 * For non-atomic operations, reqp will be freed in the kCF
286906Sgm89044 * callback function since it may be needed again if
287906Sgm89044 * CRYPTO_BUFFER_TOO_SMALL is returned to kCF
288906Sgm89044 */
289906Sgm89044 if (reqp->dr_ctx.atomic) {
290906Sgm89044 crypto_ctx_t ctx;
291906Sgm89044 ctx.cc_provider_private = reqp;
292906Sgm89044 dca_rsactxfree(&ctx);
293906Sgm89044 }
294906Sgm89044 }
295906Sgm89044
296906Sgm89044 void
dca_rsaverifydone(dca_request_t * reqp,int errno)297906Sgm89044 dca_rsaverifydone(dca_request_t *reqp, int errno)
298906Sgm89044 {
299906Sgm89044 if (errno == CRYPTO_SUCCESS) {
300906Sgm89044 char scratch[RSA_MAX_KEY_LEN];
301906Sgm89044 int outsz = reqp->dr_out->cd_length;
302906Sgm89044 caddr_t daddr;
303906Sgm89044
304906Sgm89044 /*
305906Sgm89044 * ASSUMPTION: the signature length was already
306906Sgm89044 * checked on the way in, and it is a valid length.
307906Sgm89044 */
308906Sgm89044 (void) ddi_dma_sync(reqp->dr_obuf_dmah, 0, outsz,
309906Sgm89044 DDI_DMA_SYNC_FORKERNEL);
310906Sgm89044 if (dca_check_dma_handle(reqp->dr_dca, reqp->dr_obuf_dmah,
311906Sgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) {
312906Sgm89044 reqp->destroy = TRUE;
313906Sgm89044 errno = CRYPTO_DEVICE_ERROR;
314906Sgm89044 goto errout;
315906Sgm89044 }
316906Sgm89044
317906Sgm89044 if (reqp->dr_ctx.mode == DCA_RSA_DEC ||
318906Sgm89044 reqp->dr_ctx.mode == DCA_RSA_VRFY ||
319906Sgm89044 reqp->dr_ctx.mode == DCA_RSA_VRFYR) {
320906Sgm89044 /*
321906Sgm89044 * Needs to unpad appropriately for decrypt, verify,
322906Sgm89044 * and verify_recover
323906Sgm89044 */
324906Sgm89044 if (reqp->dr_ctx.ctx_cm_type ==
325906Sgm89044 RSA_PKCS_MECH_INFO_TYPE) {
326906Sgm89044 errno = dca_pkcs1_unpadding(
327906Sgm89044 reqp->dr_obuf_kaddr, &outsz,
328906Sgm89044 reqp->dr_ctx.modlen, reqp->dr_ctx.mode);
329906Sgm89044
330906Sgm89044 /* check for bad data errors */
331906Sgm89044 if (errno != CRYPTO_SUCCESS &&
332906Sgm89044 errno != CRYPTO_BUFFER_TOO_SMALL) {
333906Sgm89044 goto errout;
334906Sgm89044 }
335906Sgm89044 if (dca_bufdaddr(reqp->dr_out) == NULL) {
336906Sgm89044 errno = CRYPTO_BUFFER_TOO_SMALL;
337906Sgm89044 }
338906Sgm89044 if (errno == CRYPTO_BUFFER_TOO_SMALL) {
339906Sgm89044 reqp->dr_out->cd_length = outsz;
340906Sgm89044 goto errout;
341906Sgm89044 }
342906Sgm89044 /* Reset the output data length */
343906Sgm89044 reqp->dr_out->cd_length = outsz;
344906Sgm89044 } else if (reqp->dr_ctx.ctx_cm_type ==
345906Sgm89044 RSA_X_509_MECH_INFO_TYPE) {
346906Sgm89044 if ((errno = dca_x509_unpadding(
347906Sgm89044 reqp->dr_obuf_kaddr, outsz,
348906Sgm89044 reqp->dr_pkt_length, reqp->dr_ctx.mode)) !=
349906Sgm89044 CRYPTO_SUCCESS)
350906Sgm89044 goto errout;
351906Sgm89044 }
352906Sgm89044 }
353906Sgm89044
354906Sgm89044 dca_reverse(reqp->dr_obuf_kaddr, scratch, outsz, outsz);
355906Sgm89044
356906Sgm89044 if ((daddr = dca_bufdaddr(reqp->dr_out)) == NULL) {
357906Sgm89044 errno = CRYPTO_ARGUMENTS_BAD;
358906Sgm89044 goto errout;
359906Sgm89044 }
360906Sgm89044 if (dca_numcmp(daddr, reqp->dr_out->cd_length, scratch,
361906Sgm89044 outsz) != 0) {
362906Sgm89044 /* VERIFY FAILED */
363906Sgm89044 errno = CRYPTO_SIGNATURE_INVALID;
364906Sgm89044 }
365906Sgm89044 }
366906Sgm89044 errout:
367906Sgm89044 ASSERT(reqp->dr_kcf_req != NULL);
368906Sgm89044
369906Sgm89044 /* notify framework that request is completed */
370906Sgm89044 crypto_op_notification(reqp->dr_kcf_req, errno);
371906Sgm89044 DBG(reqp->dr_dca, DINTR,
372906Sgm89044 "dca_rsaverifydone: rtn 0x%x to the kef via crypto_op_notification",
373906Sgm89044 errno);
374906Sgm89044
375906Sgm89044 /*
376906Sgm89044 * For non-atomic operations, reqp will be freed in the kCF
377906Sgm89044 * callback function since it may be needed again if
378906Sgm89044 * CRYPTO_BUFFER_TOO_SMALL is returned to kCF
379906Sgm89044 */
380906Sgm89044 if (reqp->dr_ctx.atomic) {
381906Sgm89044 crypto_ctx_t ctx;
382906Sgm89044 ctx.cc_provider_private = reqp;
383906Sgm89044 dca_rsactxfree(&ctx);
384906Sgm89044 }
385906Sgm89044 }
386906Sgm89044
387906Sgm89044 /*
388906Sgm89044 * Setup either a public or a private RSA key for subsequent uses
389906Sgm89044 */
390906Sgm89044 int
dca_rsainit(crypto_ctx_t * ctx,crypto_mechanism_t * mechanism,crypto_key_t * key,int kmflag)391906Sgm89044 dca_rsainit(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
392906Sgm89044 crypto_key_t *key, int kmflag)
393906Sgm89044 {
394906Sgm89044 crypto_object_attribute_t *attr;
395906Sgm89044 unsigned expname = 0;
396906Sgm89044 void *attrdata;
397906Sgm89044 int rv;
398906Sgm89044
399906Sgm89044 uchar_t *exp;
400906Sgm89044 uchar_t *p;
401906Sgm89044 uchar_t *q;
402906Sgm89044 uchar_t *dp;
403906Sgm89044 uchar_t *dq;
404906Sgm89044 uchar_t *pinv;
405906Sgm89044
406906Sgm89044 unsigned explen = 0;
407906Sgm89044 unsigned plen = 0;
408906Sgm89044 unsigned qlen = 0;
409906Sgm89044 unsigned dplen = 0;
410906Sgm89044 unsigned dqlen = 0;
411906Sgm89044 unsigned pinvlen = 0;
412906Sgm89044
413906Sgm89044 unsigned modbits, expbits, pbits, qbits;
414906Sgm89044 unsigned modfix, expfix, pqfix = 0;
415906Sgm89044 uint16_t ctxlen;
416906Sgm89044 caddr_t kaddr;
417906Sgm89044 dca_request_t *reqp = NULL;
418906Sgm89044 dca_t *dca = (dca_t *)ctx->cc_provider;
419906Sgm89044
420906Sgm89044 DBG(NULL, DENTRY, "dca_rsainit: start");
421906Sgm89044
422906Sgm89044 if ((reqp = dca_getreq(dca, MCR2, 1)) == NULL) {
423906Sgm89044 DBG(NULL, DWARN,
424906Sgm89044 "dca_rsainit: unable to allocate request for RSA");
425906Sgm89044 rv = CRYPTO_HOST_MEMORY;
426906Sgm89044 goto errout;
427906Sgm89044 }
428906Sgm89044
429906Sgm89044 reqp->dr_ctx.ctx_cm_type = mechanism->cm_type;
430906Sgm89044 ctx->cc_provider_private = reqp;
431906Sgm89044
432906Sgm89044 /*
433906Sgm89044 * Key type can be either RAW, or REFERENCE, or ATTR_LIST (VALUE).
434906Sgm89044 * Only ATTR_LIST is supported on Deimos for RSA.
435906Sgm89044 */
436906Sgm89044 if ((attr = dca_get_key_attr(key)) == NULL) {
437906Sgm89044 DBG(NULL, DWARN, "dca_rsainit: key attributes missing");
438906Sgm89044 rv = CRYPTO_KEY_TYPE_INCONSISTENT;
439906Sgm89044 goto errout;
440906Sgm89044 }
441906Sgm89044
442906Sgm89044 if (dca_find_attribute(attr, key->ck_count, CKA_PUBLIC_EXPONENT))
443906Sgm89044 expname = CKA_PUBLIC_EXPONENT;
444906Sgm89044
445906Sgm89044 /*
446906Sgm89044 * RSA public key has only public exponent. RSA private key must have
447906Sgm89044 * private exponent. However, it may also have public exponent.
448906Sgm89044 * Thus, the existance of a private exponent indicates a private key.
449906Sgm89044 */
450906Sgm89044 if (dca_find_attribute(attr, key->ck_count, CKA_PRIVATE_EXPONENT))
451906Sgm89044 expname = CKA_PRIVATE_EXPONENT;
452906Sgm89044
453906Sgm89044 if (!expname) {
454906Sgm89044 DBG(NULL, DWARN, "dca_rsainit: no exponent in key");
455906Sgm89044 rv = CRYPTO_ARGUMENTS_BAD;
456906Sgm89044 goto errout;
457906Sgm89044 }
458906Sgm89044
459906Sgm89044 /* Modulus */
460906Sgm89044 if ((rv = dca_attr_lookup_uint8_array(attr, key->ck_count, CKA_MODULUS,
461906Sgm89044 &attrdata, &(reqp->dr_ctx.modlen))) != CRYPTO_SUCCESS) {
462906Sgm89044 DBG(NULL, DWARN, "dca_rsainit: failed to retrieve modulus");
463906Sgm89044 goto errout;
464906Sgm89044 }
465906Sgm89044 if ((reqp->dr_ctx.modlen == 0) ||
466906Sgm89044 (reqp->dr_ctx.modlen > RSA_MAX_KEY_LEN)) {
467906Sgm89044 DBG(NULL, DWARN, "dca_rsainit: bad modulus size");
468906Sgm89044 rv = CRYPTO_ARGUMENTS_BAD;
469906Sgm89044 goto errout;
470906Sgm89044 }
471906Sgm89044 if ((reqp->dr_ctx.mod = kmem_alloc(reqp->dr_ctx.modlen, kmflag)) ==
472906Sgm89044 NULL) {
473906Sgm89044 rv = CRYPTO_HOST_MEMORY;
474906Sgm89044 goto errout;
475906Sgm89044 }
476906Sgm89044 bcopy(attrdata, reqp->dr_ctx.mod, reqp->dr_ctx.modlen);
477906Sgm89044
478906Sgm89044 /* Exponent */
479906Sgm89044 if ((rv = dca_attr_lookup_uint8_array(attr, key->ck_count, expname,
480906Sgm89044 (void **) &exp, &explen)) != CRYPTO_SUCCESS) {
481906Sgm89044 DBG(NULL, DWARN, "dca_rsainit: failed to retrieve exponent");
482906Sgm89044 goto errout;
483906Sgm89044 }
484906Sgm89044 if ((explen == 0) || (explen > RSA_MAX_KEY_LEN)) {
485906Sgm89044 DBG(NULL, DWARN, "dca_rsainit: bad exponent size");
486906Sgm89044 rv = CRYPTO_ARGUMENTS_BAD;
487906Sgm89044 goto errout;
488906Sgm89044 }
489906Sgm89044
490906Sgm89044 /* Lookup private attributes */
491906Sgm89044 if (expname == CKA_PRIVATE_EXPONENT) {
492906Sgm89044 /* Prime 1 */
493906Sgm89044 (void) dca_attr_lookup_uint8_array(attr, key->ck_count,
494906Sgm89044 CKA_PRIME_1, (void **)&q, &qlen);
495906Sgm89044
496906Sgm89044 /* Prime 2 */
497906Sgm89044 (void) dca_attr_lookup_uint8_array(attr, key->ck_count,
498906Sgm89044 CKA_PRIME_2, (void **)&p, &plen);
499906Sgm89044
500906Sgm89044 /* Exponent 1 */
501906Sgm89044 (void) dca_attr_lookup_uint8_array(attr, key->ck_count,
502906Sgm89044 CKA_EXPONENT_1, (void **)&dq, &dqlen);
503906Sgm89044
504906Sgm89044 /* Exponent 2 */
505906Sgm89044 (void) dca_attr_lookup_uint8_array(attr, key->ck_count,
506906Sgm89044 CKA_EXPONENT_2, (void **)&dp, &dplen);
507906Sgm89044
508906Sgm89044 /* Coefficient */
509906Sgm89044 (void) dca_attr_lookup_uint8_array(attr, key->ck_count,
510906Sgm89044 CKA_COEFFICIENT, (void **)&pinv, &pinvlen);
511906Sgm89044 }
512906Sgm89044
513906Sgm89044 modbits = dca_bitlen(reqp->dr_ctx.mod, reqp->dr_ctx.modlen);
514906Sgm89044 expbits = dca_bitlen(exp, explen);
515906Sgm89044
516906Sgm89044 if ((modfix = dca_padfull(modbits)) == 0) {
517906Sgm89044 DBG(NULL, DWARN, "dca_rsainit: modulus too long");
518906Sgm89044 rv = CRYPTO_KEY_SIZE_RANGE;
519906Sgm89044 goto errout;
520906Sgm89044 }
521906Sgm89044 expfix = ROUNDUP(explen, sizeof (uint32_t));
522906Sgm89044
523906Sgm89044 if (plen && qlen && dplen && dqlen && pinvlen) {
524906Sgm89044 unsigned pfix, qfix;
525906Sgm89044 qbits = dca_bitlen(q, qlen);
526906Sgm89044 pbits = dca_bitlen(p, plen);
527906Sgm89044 qfix = dca_padhalf(qbits);
528906Sgm89044 pfix = dca_padhalf(pbits);
529906Sgm89044 if (pfix & qfix)
530906Sgm89044 pqfix = max(pfix, qfix);
531906Sgm89044 }
532906Sgm89044
533906Sgm89044 if (pqfix) {
534906Sgm89044 reqp->dr_job_stat = DS_RSAPRIVATE;
535906Sgm89044 reqp->dr_pkt_length = 2 * pqfix;
536906Sgm89044 } else {
537906Sgm89044 reqp->dr_job_stat = DS_RSAPUBLIC;
538906Sgm89044 reqp->dr_pkt_length = modfix;
539906Sgm89044 }
540906Sgm89044
541906Sgm89044 if (pqfix) {
542906Sgm89044 /*
543906Sgm89044 * NOTE: chip's notion of p vs. q is reversed from
544906Sgm89044 * PKCS#11. We use the chip's notion in our variable
545906Sgm89044 * naming.
546906Sgm89044 */
547906Sgm89044 ctxlen = 8 + pqfix * 5;
548906Sgm89044
549906Sgm89044 /* write out the context structure */
550906Sgm89044 PUTCTX16(reqp, CTX_CMD, CMD_RSAPRIVATE);
551906Sgm89044 PUTCTX16(reqp, CTX_LENGTH, ctxlen);
552906Sgm89044 /* exponent and modulus length in bits!!! */
553906Sgm89044 PUTCTX16(reqp, CTX_RSAQLEN, qbits);
554906Sgm89044 PUTCTX16(reqp, CTX_RSAPLEN, pbits);
555906Sgm89044
556906Sgm89044 kaddr = reqp->dr_ctx_kaddr + CTX_RSABIGNUMS;
557906Sgm89044
558906Sgm89044 /* store the bignums */
559906Sgm89044 dca_reverse(p, kaddr, plen, pqfix);
560906Sgm89044 kaddr += pqfix;
561906Sgm89044
562906Sgm89044 dca_reverse(q, kaddr, qlen, pqfix);
563906Sgm89044 kaddr += pqfix;
564906Sgm89044
565906Sgm89044 dca_reverse(dp, kaddr, dplen, pqfix);
566906Sgm89044 kaddr += pqfix;
567906Sgm89044
568906Sgm89044 dca_reverse(dq, kaddr, dqlen, pqfix);
569906Sgm89044 kaddr += pqfix;
570906Sgm89044
571906Sgm89044 dca_reverse(pinv, kaddr, pinvlen, pqfix);
572906Sgm89044 kaddr += pqfix;
573906Sgm89044 } else {
574906Sgm89044 ctxlen = 8 + modfix + expfix;
575906Sgm89044 /* write out the context structure */
576906Sgm89044 PUTCTX16(reqp, CTX_CMD, CMD_RSAPUBLIC);
577906Sgm89044 PUTCTX16(reqp, CTX_LENGTH, (uint16_t)ctxlen);
578906Sgm89044 /* exponent and modulus length in bits!!! */
579906Sgm89044 PUTCTX16(reqp, CTX_RSAEXPLEN, expbits);
580906Sgm89044 PUTCTX16(reqp, CTX_RSAMODLEN, modbits);
581906Sgm89044
582906Sgm89044 kaddr = reqp->dr_ctx_kaddr + CTX_RSABIGNUMS;
583906Sgm89044
584906Sgm89044 /* store the bignums */
585906Sgm89044 dca_reverse(reqp->dr_ctx.mod, kaddr, reqp->dr_ctx.modlen,
586906Sgm89044 modfix);
587906Sgm89044 kaddr += modfix;
588906Sgm89044
589906Sgm89044 dca_reverse(exp, kaddr, explen, expfix);
590906Sgm89044 kaddr += expfix;
591906Sgm89044 }
592906Sgm89044
593906Sgm89044 reqp->dr_ctx.pqfix = pqfix;
594906Sgm89044
595906Sgm89044 errout:
596906Sgm89044 if (rv != CRYPTO_SUCCESS)
597906Sgm89044 dca_rsactxfree(ctx);
598906Sgm89044
599906Sgm89044 return (rv);
600906Sgm89044 }
601906Sgm89044
602906Sgm89044 void
dca_rsactxfree(void * arg)603906Sgm89044 dca_rsactxfree(void *arg)
604906Sgm89044 {
605906Sgm89044 crypto_ctx_t *ctx = (crypto_ctx_t *)arg;
606906Sgm89044 dca_request_t *reqp = ctx->cc_provider_private;
607906Sgm89044
608906Sgm89044 if (reqp == NULL)
609906Sgm89044 return;
610906Sgm89044
611906Sgm89044 if (reqp->dr_ctx.mod)
612906Sgm89044 kmem_free(reqp->dr_ctx.mod, reqp->dr_ctx.modlen);
613906Sgm89044
614906Sgm89044 reqp->dr_ctx.mode = 0;
615906Sgm89044 reqp->dr_ctx.ctx_cm_type = 0;
616906Sgm89044 reqp->dr_ctx.mod = NULL;
617906Sgm89044 reqp->dr_ctx.modlen = 0;
618906Sgm89044 reqp->dr_ctx.pqfix = 0;
619906Sgm89044 reqp->dr_ctx.atomic = 0;
620906Sgm89044
621906Sgm89044 if (reqp->destroy)
622906Sgm89044 dca_destroyreq(reqp);
623906Sgm89044 else
624906Sgm89044 dca_freereq(reqp);
625906Sgm89044
626906Sgm89044 ctx->cc_provider_private = NULL;
627906Sgm89044 }
628906Sgm89044
629906Sgm89044 int
dca_rsaatomic(crypto_provider_handle_t provider,crypto_session_id_t session_id,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_data_t * input,crypto_data_t * output,int kmflag,crypto_req_handle_t req,int mode)630906Sgm89044 dca_rsaatomic(crypto_provider_handle_t provider,
631906Sgm89044 crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
632906Sgm89044 crypto_key_t *key, crypto_data_t *input, crypto_data_t *output,
633906Sgm89044 int kmflag, crypto_req_handle_t req, int mode)
634906Sgm89044 {
635906Sgm89044 crypto_ctx_t ctx; /* on the stack */
636906Sgm89044 int rv;
637906Sgm89044
638906Sgm89044 ctx.cc_provider = provider;
639906Sgm89044 ctx.cc_session = session_id;
640906Sgm89044
641906Sgm89044 rv = dca_rsainit(&ctx, mechanism, key, kmflag);
642906Sgm89044 if (rv != CRYPTO_SUCCESS) {
643906Sgm89044 DBG(NULL, DWARN, "dca_rsaatomic: dca_rsainit() failed");
644906Sgm89044 /* The content of ctx should have been freed already */
645906Sgm89044 return (rv);
646906Sgm89044 }
647906Sgm89044
648906Sgm89044 /*
649906Sgm89044 * Set the atomic flag so that the hardware callback function
650906Sgm89044 * will free the context.
651906Sgm89044 */
652906Sgm89044 ((dca_request_t *)ctx.cc_provider_private)->dr_ctx.atomic = 1;
653906Sgm89044
654*5063Sgm89044 /* check for inplace ops */
655*5063Sgm89044 if (input == output) {
656*5063Sgm89044 ((dca_request_t *)ctx.cc_provider_private)->dr_flags
657*5063Sgm89044 |= DR_INPLACE;
658*5063Sgm89044 }
659*5063Sgm89044
660906Sgm89044 rv = dca_rsastart(&ctx, input, output, req, mode);
661906Sgm89044
662906Sgm89044 /*
663906Sgm89044 * The context will be freed in the hardware callback function if it
664906Sgm89044 * is queued
665906Sgm89044 */
666906Sgm89044 if (rv != CRYPTO_QUEUED)
667906Sgm89044 dca_rsactxfree(&ctx);
668906Sgm89044
669906Sgm89044 return (rv);
670906Sgm89044 }
671906Sgm89044
672906Sgm89044
673906Sgm89044 /*
674906Sgm89044 * For RSA_PKCS padding and unpadding:
675906Sgm89044 * 1. The minimum padding is 11 bytes.
676906Sgm89044 * 2. The first and the last bytes must 0.
677906Sgm89044 * 3. The second byte is 1 for private and 2 for public keys.
678906Sgm89044 * 4. Pad with 0xff for private and non-zero random for public keys.
679906Sgm89044 */
680906Sgm89044 static int
dca_pkcs1_padding(dca_t * dca,caddr_t buf,int flen,int tlen,int private)681906Sgm89044 dca_pkcs1_padding(dca_t *dca, caddr_t buf, int flen, int tlen, int private)
682906Sgm89044 {
683906Sgm89044 int i;
684906Sgm89044
685906Sgm89044 DBG(NULL, DENTRY,
686906Sgm89044 "dca_pkcs1_padding: tlen: %d, flen: %d: private: %d\n",
687906Sgm89044 tlen, flen, private);
688906Sgm89044
689906Sgm89044 if (flen > tlen - 11)
690906Sgm89044 return (CRYPTO_DATA_LEN_RANGE);
691906Sgm89044
692906Sgm89044 if (private) {
693906Sgm89044 /* Padding for private encrypt */
694906Sgm89044 buf[flen] = '\0';
695906Sgm89044 for (i = flen + 1; i < tlen - 2; i++) {
696906Sgm89044 buf[i] = (unsigned char) 0xff;
697906Sgm89044 }
698906Sgm89044 buf[tlen - 2] = 1;
699906Sgm89044 buf[tlen - 1] = 0;
700906Sgm89044 } else {
701906Sgm89044 /* Padding for public encrypt */
702906Sgm89044 buf[flen] = '\0';
703906Sgm89044
704906Sgm89044 if (dca_random_buffer(dca, &buf[flen+1], tlen - flen - 3) !=
705906Sgm89044 CRYPTO_SUCCESS)
706906Sgm89044 return (CRYPTO_RANDOM_NO_RNG);
707906Sgm89044
708906Sgm89044 buf[tlen - 2] = 2;
709906Sgm89044 buf[tlen - 1] = 0;
710906Sgm89044 }
711906Sgm89044
712906Sgm89044 return (CRYPTO_QUEUED);
713906Sgm89044 }
714906Sgm89044
715906Sgm89044 static int
dca_pkcs1_unpadding(char * buf,int * tlen,int flen,int mode)716906Sgm89044 dca_pkcs1_unpadding(char *buf, int *tlen, int flen, int mode)
717906Sgm89044 {
718906Sgm89044 int i;
719906Sgm89044 const unsigned char *p;
720906Sgm89044 unsigned char type;
721906Sgm89044
722906Sgm89044 DBG(NULL, DENTRY, "dca_pkcs1_unpadding: tlen: %d, flen: %d\n",
723906Sgm89044 *tlen, flen);
724906Sgm89044
725906Sgm89044 p = (unsigned char *) buf + (flen-1);
726906Sgm89044 if (*(p--) != 0)
727906Sgm89044 return decrypt_error_code(mode, CRYPTO_ENCRYPTED_DATA_INVALID,
728906Sgm89044 CRYPTO_SIGNATURE_INVALID, CRYPTO_DATA_INVALID);
729906Sgm89044
730906Sgm89044 /* It is ok if the data length is 0 after removing the padding */
731906Sgm89044 type = *(p--);
732906Sgm89044 if (type == 01) {
733906Sgm89044 for (i = flen - 3; i >= 0; i--) {
734906Sgm89044 if (*p != 0xff) {
735906Sgm89044 if (*p == '\0') {
736906Sgm89044 p--;
737906Sgm89044 break;
738906Sgm89044 } else {
739906Sgm89044 return decrypt_error_code(mode,
740906Sgm89044 CRYPTO_ENCRYPTED_DATA_INVALID,
741906Sgm89044 CRYPTO_SIGNATURE_INVALID,
742906Sgm89044 CRYPTO_DATA_INVALID);
743906Sgm89044 }
744906Sgm89044 }
745906Sgm89044 p--;
746906Sgm89044 }
747906Sgm89044 } else if (type == 02) {
748906Sgm89044 for (i = flen - 3; i >= 0; i--) {
749906Sgm89044 if (*p == '\0') {
750906Sgm89044 p--;
751906Sgm89044 break;
752906Sgm89044 }
753906Sgm89044 p--;
754906Sgm89044 }
755906Sgm89044 } else {
756906Sgm89044 return decrypt_error_code(mode, CRYPTO_ENCRYPTED_DATA_INVALID,
757906Sgm89044 CRYPTO_SIGNATURE_INVALID, CRYPTO_DATA_INVALID);
758906Sgm89044 }
759906Sgm89044
760906Sgm89044 /* i < 0 means did not find the end of the padding */
761906Sgm89044 if (i < 0)
762906Sgm89044 return decrypt_error_code(mode, CRYPTO_ENCRYPTED_DATA_INVALID,
763906Sgm89044 CRYPTO_SIGNATURE_INVALID, CRYPTO_DATA_INVALID);
764906Sgm89044
765906Sgm89044 if (i > *tlen) {
766906Sgm89044 *tlen = i;
767906Sgm89044 return (CRYPTO_BUFFER_TOO_SMALL);
768906Sgm89044 }
769906Sgm89044
770906Sgm89044 if (flen - i < 11)
771906Sgm89044 return decrypt_error_code(mode,
772906Sgm89044 CRYPTO_ENCRYPTED_DATA_LEN_RANGE,
773906Sgm89044 CRYPTO_SIGNATURE_LEN_RANGE, CRYPTO_DATA_LEN_RANGE);
774906Sgm89044
775906Sgm89044 /* Return the unpadded length to the caller */
776906Sgm89044 *tlen = i;
777906Sgm89044
778906Sgm89044 return (CRYPTO_SUCCESS);
779906Sgm89044 }
780906Sgm89044
781906Sgm89044 /*
782906Sgm89044 * For RSA_X_509 padding and unpadding, pad all 0s before actual data.
783906Sgm89044 * Note that the data will be in reverse order.
784906Sgm89044 */
785906Sgm89044 static int
dca_x509_padding(caddr_t buf,int flen,int tlen)786906Sgm89044 dca_x509_padding(caddr_t buf, int flen, int tlen)
787906Sgm89044 {
788906Sgm89044 DBG(NULL, DENTRY, "dca_x509_padding: tlen: %d, flen: %d\n",
789906Sgm89044 tlen, flen);
790906Sgm89044
791906Sgm89044 bzero(buf+tlen, tlen - flen);
792906Sgm89044
793906Sgm89044 return (CRYPTO_QUEUED);
794906Sgm89044 }
795906Sgm89044
796906Sgm89044 /* ARGSUSED */
797906Sgm89044 static int
dca_x509_unpadding(char * buf,int tlen,int flen,int mode)798906Sgm89044 dca_x509_unpadding(char *buf, int tlen, int flen, int mode)
799906Sgm89044 {
800906Sgm89044 int i;
801906Sgm89044 const unsigned char *p;
802906Sgm89044
803906Sgm89044 DBG(NULL, DENTRY, "dca_x509_unpadding: tlen: %d, flen: %d\n",
804906Sgm89044 tlen, flen);
805906Sgm89044
806906Sgm89044 p = (unsigned char *) buf + flen;
807906Sgm89044 for (i = tlen; i < flen; i++) {
808906Sgm89044 if (*(--p) != 0)
809906Sgm89044 return (CRYPTO_SIGNATURE_INVALID);
810906Sgm89044 }
811906Sgm89044
812906Sgm89044 return (CRYPTO_SUCCESS);
813906Sgm89044 }
814906Sgm89044
decrypt_error_code(int mode,int decrypt,int verify,int def)815906Sgm89044 static int decrypt_error_code(int mode, int decrypt, int verify, int def)
816906Sgm89044 {
817906Sgm89044 switch (mode) {
818906Sgm89044 case DCA_RSA_DEC:
819906Sgm89044 return (decrypt);
820906Sgm89044 case DCA_RSA_VRFY:
821906Sgm89044 case DCA_RSA_VRFYR:
822906Sgm89044 return (verify);
823906Sgm89044 default:
824906Sgm89044 return (def);
825906Sgm89044 }
826906Sgm89044 }
827