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 */
63int
64pkcs1_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 */
117int
118pkcs1_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