1/*
2 * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Portions Copyright (c) 2010 Apple Inc. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the Institute nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include <config.h>
37
38#include <stdio.h>
39#include <stdlib.h>
40#include <krb5-types.h>
41#include <assert.h>
42
43#include <rsa.h>
44
45#ifdef HAVE_CDSA
46#define NEED_CDSA 1
47
48#include <rfc2459_asn1.h>
49
50#include "common.h"
51
52#include <roken.h>
53
54/*
55 *
56 */
57
58
59static int
60load_key(CSSM_CSP_HANDLE cspHandle, RSA *rsa, int use_public, CSSM_KEY_PTR key, size_t *keysize)
61{
62    CSSM_KEY_SIZE keySize;
63    CSSM_RETURN ret;
64    size_t size;
65
66    memset(key, 0, sizeof(*key));
67
68    if (use_public) {
69	RSAPublicKey k;
70
71	memset(&k, 0, sizeof(k));
72
73	ret = _hc_BN_to_integer(rsa->n, &k.modulus);
74	if (ret == 0)
75	    ret = _hc_BN_to_integer(rsa->e, &k.publicExponent);
76	if (ret) {
77	    free_RSAPublicKey(&k);
78	    return 0;
79	}
80
81	ASN1_MALLOC_ENCODE(RSAPublicKey, key->KeyData.Data, key->KeyData.Length,
82			   &k, &size, ret);
83	free_RSAPublicKey(&k);
84	if (ret)
85	    return 1;
86	if (size != key->KeyData.Length)
87	    abort();
88
89    } else {
90	RSAPrivateKey k;
91
92	memset(&k, 0, sizeof(k));
93
94	k.version = 1;
95	ret = _hc_BN_to_integer(rsa->n, &k.modulus);
96	if (ret == 0)
97	    ret = _hc_BN_to_integer(rsa->e, &k.publicExponent);
98	if (ret == 0)
99	    ret = _hc_BN_to_integer(rsa->d, &k.privateExponent);
100	if (ret == 0)
101	    ret = _hc_BN_to_integer(rsa->p, &k.prime1);
102	if (ret == 0)
103	    ret = _hc_BN_to_integer(rsa->q, &k.prime2);
104	if (ret == 0)
105	    ret = _hc_BN_to_integer(rsa->dmp1, &k.exponent1);
106	if (ret == 0)
107	    ret = _hc_BN_to_integer(rsa->dmq1, &k.exponent2);
108	if (ret == 0)
109	    ret = _hc_BN_to_integer(rsa->iqmp, &k.coefficient);
110	if (ret) {
111	    free_RSAPrivateKey(&k);
112	    return 1;
113	}
114
115	ASN1_MALLOC_ENCODE(RSAPrivateKey, key->KeyData.Data, key->KeyData.Length,
116			   &k, &size, ret);
117	free_RSAPrivateKey(&k);
118	if (ret)
119	    return 1;
120	if (size != key->KeyData.Length)
121	    abort();
122    }
123
124    key->KeyHeader.HeaderVersion = CSSM_KEYHEADER_VERSION;
125    key->KeyHeader.BlobType = CSSM_KEYBLOB_RAW;
126    key->KeyHeader.Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS1;
127    key->KeyHeader.AlgorithmId = CSSM_ALGID_RSA;
128    key->KeyHeader.KeyClass = use_public ?
129	CSSM_KEYCLASS_PUBLIC_KEY :
130	CSSM_KEYCLASS_PRIVATE_KEY;
131    key->KeyHeader.KeyAttr = CSSM_KEYATTR_EXTRACTABLE;
132    key->KeyHeader.KeyUsage = CSSM_KEYUSE_ANY;
133
134    ret = CSSM_QueryKeySizeInBits(cspHandle, 0, key, &keySize);
135    if(ret)
136	return 1;
137
138    key->KeyHeader.LogicalKeySizeInBits = keySize.LogicalKeySizeInBits;
139
140    *keysize = (keySize.LogicalKeySizeInBits + 7) / 8;
141
142    return 0;
143}
144
145static void
146unload_key(CSSM_KEY_PTR key)
147{
148    free(key->KeyData.Data);
149    memset(key, 0, sizeof(*key));
150}
151
152typedef CSSM_RETURN (*op)(CSSM_CC_HANDLE, const CSSM_DATA *,
153			  uint32, CSSM_DATA_PTR, uint32,
154			  CSSM_SIZE *, CSSM_DATA_PTR);
155
156
157static int
158perform_rsa_op(int flen, const unsigned char* from,
159	       unsigned char* to, RSA* rsa, int padding,
160	       CSSM_ENCRYPT_MODE algMode, op func)
161{
162    CSSM_CSP_HANDLE cspHandle = _hc_get_cdsa_csphandle();
163    CSSM_RETURN cret;
164    CSSM_ACCESS_CREDENTIALS creds;
165    CSSM_KEY cssmKey;
166    CSSM_CC_HANDLE handle = 0;
167    CSSM_DATA out, in, rem;
168    int fret = 0;
169    CSSM_SIZE outlen = 0;
170    char remdata[1024];
171    size_t keysize;
172
173    if (padding != RSA_PKCS1_PADDING)
174	return -1;
175
176    memset(&creds, 0, sizeof(creds));
177
178    fret = load_key(cspHandle, rsa, (algMode == CSSM_ALGMODE_PUBLIC_KEY),
179		    &cssmKey, &keysize);
180    if (fret)
181	return -2;
182
183    fret = CSSM_CSP_CreateAsymmetricContext(cspHandle,
184					    CSSM_ALGID_RSA,
185					    &creds,
186					    &cssmKey,
187					    CSSM_PADDING_PKCS1,
188					    &handle);
189    if(fret) abort();
190
191    {
192	CSSM_CONTEXT_ATTRIBUTE attr;
193
194	attr.AttributeType = CSSM_ATTRIBUTE_MODE;
195	attr.AttributeLength = sizeof(attr.Attribute.Uint32);
196	attr.Attribute.Uint32 = algMode;
197
198	fret = CSSM_UpdateContextAttributes(handle, 1, &attr);
199	if (fret) abort();
200    }
201
202    in.Data = (uint8 *)from;
203    in.Length = flen;
204
205    out.Data = (uint8 *)to;
206    out.Length = keysize;
207
208    rem.Data = (uint8 *)remdata;
209    rem.Length = sizeof(remdata);
210
211    cret = func(handle, &in, 1, &out, 1, &outlen, &rem);
212    if(cret) {
213	/* cssmErrorString(cret); */
214	fret = -1;
215    } else
216	fret = outlen;
217
218    if(handle)
219	CSSM_DeleteContext(handle);
220    unload_key(&cssmKey);
221
222    return fret;
223}
224
225/*
226 *
227 */
228
229
230static int
231cdsa_rsa_public_encrypt(int flen, const unsigned char* from,
232			unsigned char* to, RSA* rsa, int padding)
233{
234    return perform_rsa_op(flen, from, to, rsa, padding, CSSM_ALGMODE_PUBLIC_KEY, CSSM_EncryptData);
235}
236
237static int
238cdsa_rsa_public_decrypt(int flen, const unsigned char* from,
239			 unsigned char* to, RSA* rsa, int padding)
240{
241    return perform_rsa_op(flen, from, to, rsa, padding, CSSM_ALGMODE_PUBLIC_KEY, CSSM_DecryptData);
242}
243
244static int
245cdsa_rsa_private_encrypt(int flen, const unsigned char* from,
246			  unsigned char* to, RSA* rsa, int padding)
247{
248    return perform_rsa_op(flen, from, to, rsa, padding, CSSM_ALGMODE_PRIVATE_KEY, CSSM_EncryptData);
249}
250
251static int
252cdsa_rsa_private_decrypt(int flen, const unsigned char* from,
253			  unsigned char* to, RSA* rsa, int padding)
254{
255    return perform_rsa_op(flen, from, to, rsa, padding, CSSM_ALGMODE_PRIVATE_KEY, CSSM_DecryptData);
256}
257
258
259static int
260cdsa_rsa_generate_key(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb)
261{
262    CSSM_CSP_HANDLE cspHandle = _hc_get_cdsa_csphandle();
263    uint32_t pubAttr = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_RETURN_DATA;
264    uint32_t privAttr = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_RETURN_DATA;
265    CSSM_CC_HANDLE handle;
266    CSSM_RETURN ret;
267    size_t len;
268    const unsigned char *p;
269    CSSM_KEY priv_key, pub_key;
270    AlgorithmIdentifier ai;
271
272    memset(&priv_key, 0, sizeof(priv_key));
273    memset(&pub_key, 0, sizeof(pub_key));
274    memset(&ai, 0, sizeof(ai));
275
276    ret = CSSM_CSP_CreateKeyGenContext(cspHandle,
277				       CSSM_ALGID_RSA,
278				       bits,
279				       NULL,
280				       NULL,
281				       NULL,
282				       NULL,
283				       NULL,
284				       &handle);
285    if (ret)
286	return 0;
287
288    {
289	CSSM_CONTEXT_ATTRIBUTE attr;
290
291	attr.AttributeType = CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT;
292	attr.AttributeLength = sizeof(attr.Attribute.Uint32);
293	attr.Attribute.Uint32 = CSSM_KEYBLOB_RAW_FORMAT_PKCS1;
294
295	ret = CSSM_UpdateContextAttributes(handle, 1, &attr);
296	if (ret) abort();
297
298	attr.AttributeType = CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT;
299	ret = CSSM_UpdateContextAttributes(handle, 1, &attr);
300	if (ret) abort();
301    }
302
303    ret = CSSM_GenerateKeyPair(handle,
304			       /* pubkey */
305			       CSSM_KEYUSE_DERIVE,
306			       pubAttr,
307			       &_hc_labelData,
308			       &pub_key,
309			       /* private key */
310			       CSSM_KEYUSE_DERIVE,
311			       privAttr,
312			       &_hc_labelData,
313			       NULL,
314			       &priv_key);
315
316    CSSM_DeleteContext(handle);
317    if (ret)
318	return 0;
319
320    ret = decode_AlgorithmIdentifier(priv_key.KeyData.Data,
321				     priv_key.KeyData.Length, &ai, NULL);
322    if (ret || ai.parameters == NULL) {
323	p = priv_key.KeyData.Data;
324	len = priv_key.KeyData.Length;
325    } else {
326	p = ai.parameters->data;
327	len = ai.parameters->length;
328    }
329
330    ret = (d2i_RSAPrivateKey(rsa, &p, len) == NULL) ? 0 : 1;
331    free_AlgorithmIdentifier(&ai);
332
333    CSSM_FreeKey(cspHandle, NULL, &pub_key, CSSM_FALSE);
334    CSSM_FreeKey(cspHandle, NULL, &priv_key, CSSM_FALSE);
335
336    return ret;
337}
338
339static int
340cdsa_rsa_init(RSA *rsa)
341{
342    return 1;
343}
344
345static int
346cdsa_rsa_finish(RSA *rsa)
347{
348    return 1;
349}
350
351const RSA_METHOD _hc_rsa_cdsa_method = {
352    "hcrypto cdsa RSA",
353    cdsa_rsa_public_encrypt,
354    cdsa_rsa_public_decrypt,
355    cdsa_rsa_private_encrypt,
356    cdsa_rsa_private_decrypt,
357    NULL,
358    NULL,
359    cdsa_rsa_init,
360    cdsa_rsa_finish,
361    0,
362    NULL,
363    NULL,
364    NULL,
365    cdsa_rsa_generate_key
366};
367#endif
368
369const RSA_METHOD *
370RSA_cdsa_method(void)
371{
372#ifdef HAVE_CDSA
373    return &_hc_rsa_cdsa_method;
374#else
375    return NULL;
376#endif
377}
378