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.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
25 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
34 #include <sys/strsun.h>
35 #include <sys/types.h>
36 #include <modes/modes.h>
37 #include <sys/crypto/common.h>
38 #include <sys/crypto/impl.h>
41 * Initialize by setting iov_or_mp to point to the current iovec or mp,
42 * and by setting current_offset to an offset within the current iovec or mp.
45 crypto_init_ptrs(crypto_data_t
*out
, void **iov_or_mp
, offset_t
*current_offset
)
49 switch (out
->cd_format
) {
51 *current_offset
= out
->cd_offset
;
54 case CRYPTO_DATA_UIO
: {
55 uio_t
*uiop
= out
->cd_uio
;
58 offset
= out
->cd_offset
;
59 for (vec_idx
= 0; vec_idx
< uiop
->uio_iovcnt
&&
60 offset
>= uiop
->uio_iov
[vec_idx
].iov_len
;
61 offset
-= uiop
->uio_iov
[vec_idx
++].iov_len
)
64 *current_offset
= offset
;
65 *iov_or_mp
= (void *)vec_idx
;
69 case CRYPTO_DATA_MBLK
: {
72 offset
= out
->cd_offset
;
73 for (mp
= out
->cd_mp
; mp
!= NULL
&& offset
>= MBLKL(mp
);
74 offset
-= MBLKL(mp
), mp
= mp
->b_cont
)
77 *current_offset
= offset
;
86 * Get pointers for where in the output to copy a block of encrypted or
87 * decrypted data. The iov_or_mp argument stores a pointer to the current
88 * iovec or mp, and offset stores an offset into the current iovec or mp.
91 crypto_get_ptrs(crypto_data_t
*out
, void **iov_or_mp
, offset_t
*current_offset
,
92 uint8_t **out_data_1
, size_t *out_data_1_len
, uint8_t **out_data_2
,
97 switch (out
->cd_format
) {
98 case CRYPTO_DATA_RAW
: {
101 offset
= *current_offset
;
103 if ((offset
+ amt
) <= iov
->iov_len
) {
105 *out_data_1
= (uint8_t *)iov
->iov_base
+ offset
;
106 *out_data_1_len
= amt
;
108 *current_offset
= offset
+ amt
;
113 case CRYPTO_DATA_UIO
: {
114 uio_t
*uio
= out
->cd_uio
;
120 offset
= *current_offset
;
121 vec_idx
= (uintptr_t)(*iov_or_mp
);
122 iov
= &uio
->uio_iov
[vec_idx
];
123 p
= (uint8_t *)iov
->iov_base
+ offset
;
126 if (offset
+ amt
<= iov
->iov_len
) {
127 /* can fit one block into this iov */
128 *out_data_1_len
= amt
;
130 *current_offset
= offset
+ amt
;
132 /* one block spans two iovecs */
133 *out_data_1_len
= iov
->iov_len
- offset
;
134 if (vec_idx
== uio
->uio_iovcnt
)
137 iov
= &uio
->uio_iov
[vec_idx
];
138 *out_data_2
= (uint8_t *)iov
->iov_base
;
139 *current_offset
= amt
- *out_data_1_len
;
141 *iov_or_mp
= (void *)vec_idx
;
145 case CRYPTO_DATA_MBLK
: {
149 offset
= *current_offset
;
150 mp
= (mblk_t
*)*iov_or_mp
;
151 p
= mp
->b_rptr
+ offset
;
153 if ((p
+ amt
) <= mp
->b_wptr
) {
154 /* can fit one block into this mblk */
155 *out_data_1_len
= amt
;
157 *current_offset
= offset
+ amt
;
159 /* one block spans two mblks */
160 *out_data_1_len
= _PTRDIFF(mp
->b_wptr
, p
);
161 if ((mp
= mp
->b_cont
) == NULL
)
163 *out_data_2
= mp
->b_rptr
;
164 *current_offset
= (amt
- *out_data_1_len
);
173 crypto_free_mode_ctx(void *ctx
)
175 common_ctx_t
*common_ctx
= (common_ctx_t
*)ctx
;
177 switch (common_ctx
->cc_flags
& (ECB_MODE
|CBC_MODE
|CMAC_MODE
|CTR_MODE
|
178 CCM_MODE
|GCM_MODE
|GMAC_MODE
)) {
181 kmem_free(common_ctx
, sizeof (ecb_ctx_t
));
190 kmem_free(common_ctx
, sizeof (cbc_ctx_t
));
198 kmem_free(common_ctx
, sizeof (ctr_ctx_t
));
206 if (((ccm_ctx_t
*)ctx
)->ccm_pt_buf
!= NULL
)
207 kmem_free(((ccm_ctx_t
*)ctx
)->ccm_pt_buf
,
208 ((ccm_ctx_t
*)ctx
)->ccm_data_len
);
210 kmem_free(ctx
, sizeof (ccm_ctx_t
));
212 if (((ccm_ctx_t
*)ctx
)->ccm_pt_buf
!= NULL
)
213 free(((ccm_ctx_t
*)ctx
)->ccm_pt_buf
);
221 if (((gcm_ctx_t
*)ctx
)->gcm_pt_buf
!= NULL
)
222 kmem_free(((gcm_ctx_t
*)ctx
)->gcm_pt_buf
,
223 ((gcm_ctx_t
*)ctx
)->gcm_pt_buf_len
);
225 kmem_free(ctx
, sizeof (gcm_ctx_t
));
227 if (((gcm_ctx_t
*)ctx
)->gcm_pt_buf
!= NULL
)
228 free(((gcm_ctx_t
*)ctx
)->gcm_pt_buf
);
235 * Utility routine to apply the command, 'cmd', to the
236 * data in the uio structure.
239 crypto_uio_data(crypto_data_t
*data
, uchar_t
*buf
, int len
, cmd_type_t cmd
,
240 void *digest_ctx
, void (*update
)())
242 uio_t
*uiop
= data
->cd_uio
;
243 off_t offset
= data
->cd_offset
;
250 ASSERT3U(data
->cd_format
, ==, CRYPTO_DATA_UIO
);
252 assert(data
->cd_format
== CRYPTO_DATA_UIO
);
254 if (uiop
->uio_segflg
!= UIO_SYSSPACE
) {
255 return (CRYPTO_ARGUMENTS_BAD
);
259 * Jump to the first iovec containing data to be
262 for (vec_idx
= 0; vec_idx
< uiop
->uio_iovcnt
&&
263 offset
>= uiop
->uio_iov
[vec_idx
].iov_len
;
264 offset
-= uiop
->uio_iov
[vec_idx
++].iov_len
)
267 if (vec_idx
== uiop
->uio_iovcnt
) {
269 * The caller specified an offset that is larger than
270 * the total size of the buffers it provided.
272 return (CRYPTO_DATA_LEN_RANGE
);
275 while (vec_idx
< uiop
->uio_iovcnt
&& length
> 0) {
276 cur_len
= MIN(uiop
->uio_iov
[vec_idx
].iov_len
-
279 datap
= (uchar_t
*)(uiop
->uio_iov
[vec_idx
].iov_base
+
283 bcopy(datap
, buf
, cur_len
);
287 bcopy(buf
, datap
, cur_len
);
290 case COMPARE_TO_DATA
:
291 if (bcmp(datap
, buf
, cur_len
))
292 return (CRYPTO_SIGNATURE_INVALID
);
295 case MD5_DIGEST_DATA
:
296 case SHA1_DIGEST_DATA
:
297 case SHA2_DIGEST_DATA
:
299 update(digest_ctx
, datap
, cur_len
);
308 if (vec_idx
== uiop
->uio_iovcnt
&& length
> 0) {
310 * The end of the specified iovec's was reached but
311 * the length requested could not be processed.
315 data
->cd_length
= len
;
316 return (CRYPTO_BUFFER_TOO_SMALL
);
318 return (CRYPTO_DATA_LEN_RANGE
);
322 return (CRYPTO_SUCCESS
);
326 * Utility routine to apply the command, 'cmd', to the
327 * data in the mblk structure.
330 crypto_mblk_data(crypto_data_t
*data
, uchar_t
*buf
, int len
, cmd_type_t cmd
,
331 void *digest_ctx
, void (*update
)())
333 off_t offset
= data
->cd_offset
;
340 ASSERT3U(data
->cd_format
, ==, CRYPTO_DATA_MBLK
);
342 assert(data
->cd_format
== CRYPTO_DATA_MBLK
);
345 * Jump to the first mblk_t containing data to be processed.
347 for (mp
= data
->cd_mp
; mp
!= NULL
&& offset
>= MBLKL(mp
);
348 offset
-= MBLKL(mp
), mp
= mp
->b_cont
)
352 * The caller specified an offset that is larger
353 * than the total size of the buffers it provided.
355 return (CRYPTO_DATA_LEN_RANGE
);
359 * Now do the processing on the mblk chain.
361 while (mp
!= NULL
&& length
> 0) {
362 cur_len
= MIN(MBLKL(mp
) - offset
, length
);
364 datap
= (uchar_t
*)(mp
->b_rptr
+ offset
);
367 bcopy(datap
, buf
, cur_len
);
371 bcopy(buf
, datap
, cur_len
);
374 case COMPARE_TO_DATA
:
375 if (bcmp(datap
, buf
, cur_len
))
376 return (CRYPTO_SIGNATURE_INVALID
);
379 case MD5_DIGEST_DATA
:
380 case SHA1_DIGEST_DATA
:
381 case SHA2_DIGEST_DATA
:
383 update(digest_ctx
, datap
, cur_len
);
392 if (mp
== NULL
&& length
> 0) {
394 * The end of the mblk was reached but the length
395 * requested could not be processed.
399 data
->cd_length
= len
;
400 return (CRYPTO_BUFFER_TOO_SMALL
);
402 return (CRYPTO_DATA_LEN_RANGE
);
406 return (CRYPTO_SUCCESS
);
410 * Utility routine to copy a buffer to a crypto_data structure.
413 crypto_put_output_data(uchar_t
*buf
, crypto_data_t
*output
, int len
)
415 switch (output
->cd_format
) {
416 case CRYPTO_DATA_RAW
:
417 if (MAXOFF_T
- output
->cd_offset
< (off_t
)len
) {
418 return (CRYPTO_ARGUMENTS_BAD
);
420 if (output
->cd_raw
.iov_len
< len
+ output
->cd_offset
) {
421 output
->cd_length
= len
;
422 return (CRYPTO_BUFFER_TOO_SMALL
);
424 bcopy(buf
, (uchar_t
*)(output
->cd_raw
.iov_base
+
425 output
->cd_offset
), len
);
428 case CRYPTO_DATA_UIO
:
429 return (crypto_uio_data(output
, buf
, len
,
430 COPY_TO_DATA
, NULL
, NULL
));
432 case CRYPTO_DATA_MBLK
:
433 return (crypto_mblk_data(output
, buf
, len
,
434 COPY_TO_DATA
, NULL
, NULL
));
437 return (CRYPTO_ARGUMENTS_BAD
);
440 return (CRYPTO_SUCCESS
);