xref: /illumos-gate/usr/src/common/crypto/padding/pkcs1.c (revision 726fad2a65f16c200a03969c29cb5c86c2d427db)
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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 /*
27  * This file contains padding helper routines common to
28  * the PKCS11 soft token code and the kernel crypto code.
29  */
30 
31 #include <sys/types.h>
32 #include "padding.h"
33 
34 #ifdef _KERNEL
35 #include <sys/param.h>
36 #else
37 #include <strings.h>
38 #include <cryptoutil.h>
39 #endif
40 
41 /*
42  * To create a block type "02" encryption block for RSA PKCS encryption
43  * process.
44  *
45  * This is EME-PKCS1-v1_5 encoding as described in RSA PKCS#1.
46  *
47  * The RSA PKCS Padding before encryption is in the following format:
48  * +----+----+--------------------+----+-----------------------------+
49  * |0x00|0x02| 8 bytes or more RN |0x00|       DATA                  |
50  * +----+----+--------------------+----+-----------------------------+
51  *
52  *
53  * To create a block type "01" block for RSA PKCS signature process.
54  *
55  * This EMSA-PKCS1-1_5 encoding as decribed in RSA PKCS#1.
56  *
57  * The RSA PKCS Padding before Signing is in the following format:
58  * +----+----+----------------------+----+-----------------------------+
59  * |0x00|0x01| 8 bytes of more 0xFF |0x00|          DATA               |
60  * +----+----+----------------------+----+-----------------------------+
61  *
62  */
63 int
pkcs1_encode(int method,uint8_t * databuf,size_t datalen,uint8_t * padbuf,size_t padbuflen)64 pkcs1_encode(int method, uint8_t *databuf, size_t datalen, uint8_t *padbuf,
65     size_t padbuflen)
66 {
67 	size_t	padlen;
68 	int	rv;
69 
70 	padlen = padbuflen - datalen;
71 	if (padlen < MIN_PKCS1_PADLEN) {
72 		return (CKR_DATA_LEN_RANGE);
73 	}
74 
75 	rv = 0;
76 
77 	padbuf[0] = 0x00;
78 	padbuf[1] = (method == PKCS1_ENCRYPT) ? 0x02 : 0x01;
79 
80 	if (method == PKCS1_ENCRYPT) {
81 #ifdef _KERNEL
82 		rv = knzero_random_generator(padbuf + 2, padlen - 3);
83 #else
84 		rv = (pkcs11_get_nzero_urandom(padbuf + 2, padlen - 3) < 0) ?
85 		    CKR_DEVICE_ERROR : 0;
86 #endif
87 	} else if (method == PKCS1_SIGN) {
88 #ifdef _KERNEL
89 		kmemset(padbuf + 2, 0xFF, padlen - 3);
90 #else
91 		(void) memset(padbuf + 2, 0xFF, padlen - 3);
92 #endif
93 	}
94 
95 	if (rv != 0) {
96 		return (rv);
97 	}
98 
99 	padbuf[padlen - 1] = 0x00;
100 
101 	bcopy(databuf, padbuf + padlen, datalen);
102 
103 	return (0);
104 }
105 
106 /*
107  * The RSA PKCS Padding in the following format:
108  * +----+----+-------------------------+----+------------------------+
109  * |0x00| BT | 8 bytes or more padding |0x00|       DATA             |
110  * +----+----+-+++++-------------------+----+------------------------+
111  * where BT is block type: 0x02 for encrypt/decrypt, 0x01 for sign/verify
112  *
113  * 'padbuf' points to the recovered message.  Strip off the padding and
114  * validate it as much as possible.  'plen' is changed to hold the actual
115  * data length.
116  */
117 int
pkcs1_decode(int method,uint8_t * padbuf,size_t * plen)118 pkcs1_decode(int method, uint8_t *padbuf, size_t *plen)
119 {
120 	int	rv = ((method == PKCS1_DECRYPT) ? CKR_ENCRYPTED_DATA_INVALID :
121 	    CKR_SIGNATURE_INVALID);
122 	int	i;
123 
124 	/* Check to see if the recovered data is padded is 0x0002 or 0x0001. */
125 	if (padbuf[0] != 0x00 || padbuf[1] != (method == PKCS1_DECRYPT ?
126 	    0x02 : 0x01)) {
127 		return (rv);
128 	}
129 
130 	/* Remove all the random bits up to 0x00 (= NULL char) */
131 	for (i = 2; (*plen - i) > 0; i++) {
132 		if (padbuf[i] == 0x00) {
133 			i++;
134 			if (i < MIN_PKCS1_PADLEN) {
135 				return (rv);
136 			}
137 			*plen -= i;
138 
139 			return (0);
140 		} else if (method == PKCS1_VERIFY && padbuf[i] != 0xFF) {
141 			return (rv);
142 		}
143 	}
144 
145 	return (rv);
146 }
147