1
2/*
3 * Licensed Materials - Property of IBM
4 *
5 * trousers - An open source TCG Software Stack
6 *
7 * (C) Copyright International Business Machines Corp. 2004-2006
8 *
9 */
10
11/*
12 * rsa.c - openssl TSS crypto routines
13 *
14 * Kent Yoder <shpedoikal@gmail.com>
15 *
16 */
17
18#include <string.h>
19
20#include <openssl/evp.h>
21#include <openssl/err.h>
22#include <openssl/sha.h>
23#include <openssl/rsa.h>
24
25#include "trousers/tss.h"
26#include "trousers/trousers.h"
27#include "trousers_types.h"
28#include "spi_utils.h"
29#include "tsplog.h"
30
31#ifdef TSS_DEBUG
32#define DEBUG_print_openssl_errors() \
33	do { \
34		ERR_load_crypto_strings(); \
35		ERR_print_errors_fp(stderr); \
36	} while (0)
37#else
38#define DEBUG_print_openssl_errors()
39#endif
40
41#if OPENSSL_VERSION_NUMBER < 0x10100001L
42static int
43RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
44{
45	if (n != NULL) {
46		BN_free(r->n);
47		r->n = n;
48	}
49	if (e != NULL) {
50		BN_free(r->e);
51		r->e = e;
52	}
53	if (d != NULL) {
54		BN_free(r->d);
55		r->d = d;
56	}
57	return 1;
58}
59#endif
60
61/*
62 * Hopefully this will make the code clearer since
63 * OpenSSL returns 1 on success
64 */
65#define EVP_SUCCESS 1
66
67/* XXX int set to unsigned int values */
68int
69Trspi_RSA_Encrypt(unsigned char *dataToEncrypt, /* in */
70		unsigned int dataToEncryptLen,  /* in */
71		unsigned char *encryptedData,   /* out */
72		unsigned int *encryptedDataLen, /* out */
73		unsigned char *publicKey,
74		unsigned int keysize)
75{
76	int rv;
77	unsigned char exp[] = { 0x01, 0x00, 0x01 }; /* 65537 hex */
78	unsigned char oaepPad[] = "TCPA";
79	int oaepPadLen = 4;
80	RSA *rsa = RSA_new();
81	BYTE encodedData[256];
82	int encodedDataLen;
83	BIGNUM *rsa_n = NULL, *rsa_e = NULL;
84
85	if (rsa == NULL) {
86		rv = TSPERR(TSS_E_OUTOFMEMORY);
87		goto err;
88	}
89
90	/* set the public key value in the OpenSSL object */
91	rsa_n = BN_bin2bn(publicKey, keysize, NULL);
92	/* set the public exponent */
93	rsa_e = BN_bin2bn(exp, sizeof(exp), NULL);
94
95	if (rsa_n == NULL || rsa_e == NULL) {
96		rv = TSPERR(TSS_E_OUTOFMEMORY);
97		BN_free(rsa_n);
98		BN_free(rsa_e);
99		goto err;
100	}
101	if (!RSA_set0_key(rsa, rsa_n, rsa_e, NULL)) {
102		rv = TSPERR(TSS_E_FAIL);
103		BN_free(rsa_n);
104		BN_free(rsa_e);
105		goto err;
106	}
107
108	/* padding constraint for PKCS#1 OAEP padding */
109	if ((int)dataToEncryptLen >= (RSA_size(rsa) - ((2 * SHA_DIGEST_LENGTH) + 1))) {
110		rv = TSPERR(TSS_E_INTERNAL_ERROR);
111		goto err;
112	}
113
114	encodedDataLen = MIN(RSA_size(rsa), 256);
115
116	/* perform our OAEP padding here with custom padding parameter */
117	rv = RSA_padding_add_PKCS1_OAEP(encodedData, encodedDataLen, dataToEncrypt,
118			dataToEncryptLen, oaepPad, oaepPadLen);
119	if (rv != EVP_SUCCESS) {
120		rv = TSPERR(TSS_E_INTERNAL_ERROR);
121		goto err;
122	}
123
124	/* call OpenSSL with no additional padding */
125	rv = RSA_public_encrypt(encodedDataLen, encodedData,
126				encryptedData, rsa, RSA_NO_PADDING);
127	if (rv == -1) {
128		rv = TSPERR(TSS_E_INTERNAL_ERROR);
129		goto err;
130	}
131
132	/* RSA_public_encrypt returns the size of the encrypted data */
133	*encryptedDataLen = rv;
134	rv = TSS_SUCCESS;
135	goto out;
136
137err:
138	DEBUG_print_openssl_errors();
139out:
140	if (rsa)
141		RSA_free(rsa);
142        return rv;
143}
144
145TSS_RESULT
146Trspi_Verify(UINT32 HashType, BYTE *pHash, UINT32 iHashLength,
147	     unsigned char *pModulus, int iKeyLength,
148	     BYTE *pSignature, UINT32 sig_len)
149{
150	int rv, nid;
151	unsigned char exp[] = { 0x01, 0x00, 0x01 }; /* The default public exponent for the TPM */
152	unsigned char buf[256];
153	RSA *rsa = RSA_new();
154	BIGNUM *rsa_n = NULL, *rsa_e = NULL;
155
156	if (rsa == NULL) {
157		rv = TSPERR(TSS_E_OUTOFMEMORY);
158		goto err;
159	}
160
161	/* We assume we're verifying data from a TPM, so there are only
162	 * two options, SHA1 data and PKCSv1.5 encoded signature data.
163	 */
164	switch (HashType) {
165		case TSS_HASH_SHA1:
166			nid = NID_sha1;
167			break;
168		case TSS_HASH_OTHER:
169			nid = NID_undef;
170			break;
171		default:
172			rv = TSPERR(TSS_E_BAD_PARAMETER);
173			goto out;
174			break;
175	}
176
177	/* set the public key value in the OpenSSL object */
178	rsa_n = BN_bin2bn(pModulus, iKeyLength, NULL);
179	/* set the public exponent */
180	rsa_e = BN_bin2bn(exp, sizeof(exp), NULL);
181
182	if (rsa_n == NULL || rsa_e == NULL) {
183		rv = TSPERR(TSS_E_OUTOFMEMORY);
184		BN_free(rsa_n);
185		BN_free(rsa_e);
186		goto err;
187	}
188	if (!RSA_set0_key(rsa, rsa_n, rsa_e, NULL)) {
189		rv = TSPERR(TSS_E_FAIL);
190		BN_free(rsa_n);
191		BN_free(rsa_e);
192		goto err;
193	}
194
195	/* if we don't know the structure of the data we're verifying, do a public decrypt
196	 * and compare manually. If we know we're looking for a SHA1 hash, allow OpenSSL
197	 * to do the work for us.
198	 */
199	if (nid == NID_undef) {
200		rv = RSA_public_decrypt(sig_len, pSignature, buf, rsa, RSA_PKCS1_PADDING);
201		if ((UINT32)rv != iHashLength) {
202			rv = TSPERR(TSS_E_FAIL);
203			goto out;
204		} else if (memcmp(pHash, buf, iHashLength)) {
205			rv = TSPERR(TSS_E_FAIL);
206			goto out;
207		}
208	} else {
209		if ((rv = RSA_verify(nid, pHash, iHashLength, pSignature, sig_len, rsa)) == 0) {
210			rv = TSPERR(TSS_E_FAIL);
211			goto out;
212		}
213	}
214
215	rv = TSS_SUCCESS;
216	goto out;
217
218err:
219	DEBUG_print_openssl_errors();
220out:
221	if (rsa)
222		RSA_free(rsa);
223        return rv;
224}
225
226int
227Trspi_RSA_Public_Encrypt(unsigned char *in, unsigned int inlen,
228			 unsigned char *out, unsigned int *outlen,
229			 unsigned char *pubkey, unsigned int pubsize,
230			 unsigned int e, int padding)
231{
232	int rv, e_size = 3;
233	unsigned char exp[] = { 0x01, 0x00, 0x01 };
234	RSA *rsa = RSA_new();
235	BIGNUM *rsa_n = NULL, *rsa_e = NULL;
236
237	if (rsa == NULL) {
238		rv = TSPERR(TSS_E_OUTOFMEMORY);
239		goto err;
240	}
241
242	switch (e) {
243		case 0:
244			/* fall through */
245		case 65537:
246			break;
247		case 17:
248			exp[0] = 17;
249			e_size = 1;
250			break;
251		case 3:
252			exp[0] = 3;
253			e_size = 1;
254			break;
255		default:
256			rv = TSPERR(TSS_E_INTERNAL_ERROR);
257			goto out;
258			break;
259	}
260
261	switch (padding) {
262		case TR_RSA_PKCS1_OAEP_PADDING:
263			padding = RSA_PKCS1_OAEP_PADDING;
264			break;
265		case TR_RSA_PKCS1_PADDING:
266			padding = RSA_PKCS1_PADDING;
267			break;
268		case TR_RSA_NO_PADDING:
269			padding = RSA_NO_PADDING;
270			break;
271		default:
272			rv = TSPERR(TSS_E_INTERNAL_ERROR);
273			goto out;
274			break;
275	}
276
277	/* set the public key value in the OpenSSL object */
278	rsa_n = BN_bin2bn(pubkey, pubsize, NULL);
279	/* set the public exponent */
280	rsa_e = BN_bin2bn(exp, e_size, NULL);
281
282	if (rsa_n == NULL || rsa_e == NULL) {
283		rv = TSPERR(TSS_E_OUTOFMEMORY);
284                BN_free(rsa_n);
285                BN_free(rsa_e);
286                goto err;
287        }
288        if (!RSA_set0_key(rsa, rsa_n, rsa_e, NULL)) {
289                rv = TSPERR(TSS_E_FAIL);
290                BN_free(rsa_n);
291                BN_free(rsa_e);
292		goto err;
293	}
294
295	rv = RSA_public_encrypt(inlen, in, out, rsa, padding);
296	if (rv == -1) {
297		rv = TSPERR(TSS_E_INTERNAL_ERROR);
298		goto err;
299	}
300
301	/* RSA_public_encrypt returns the size of the encrypted data */
302	*outlen = rv;
303	rv = TSS_SUCCESS;
304	goto out;
305
306err:
307	DEBUG_print_openssl_errors();
308out:
309	if (rsa)
310		RSA_free(rsa);
311        return rv;
312}
313