|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 #include "ckmk.h" |
|
6 |
|
7 /* Sigh, For all the talk about 'ease of use', apple has hidden the interfaces |
|
8 * needed to be able to truly use CSSM. These came from their modification |
|
9 * to NSS's S/MIME code. The following two functions currently are not |
|
10 * part of the SecKey.h interface. |
|
11 */ |
|
12 OSStatus |
|
13 SecKeyGetCredentials |
|
14 ( |
|
15 SecKeyRef keyRef, |
|
16 CSSM_ACL_AUTHORIZATION_TAG authTag, |
|
17 int type, |
|
18 const CSSM_ACCESS_CREDENTIALS **creds |
|
19 ); |
|
20 |
|
21 /* this function could be implemented using 'SecKeychainItemCopyKeychain' and |
|
22 * 'SecKeychainGetCSPHandle' */ |
|
23 OSStatus |
|
24 SecKeyGetCSPHandle |
|
25 ( |
|
26 SecKeyRef keyRef, |
|
27 CSSM_CSP_HANDLE *cspHandle |
|
28 ); |
|
29 |
|
30 |
|
31 typedef struct ckmkInternalCryptoOperationRSAPrivStr |
|
32 ckmkInternalCryptoOperationRSAPriv; |
|
33 struct ckmkInternalCryptoOperationRSAPrivStr |
|
34 { |
|
35 NSSCKMDCryptoOperation mdOperation; |
|
36 NSSCKMDMechanism *mdMechanism; |
|
37 ckmkInternalObject *iKey; |
|
38 NSSItem *buffer; |
|
39 CSSM_CC_HANDLE cssmContext; |
|
40 }; |
|
41 |
|
42 typedef enum { |
|
43 CKMK_DECRYPT, |
|
44 CKMK_SIGN |
|
45 } ckmkRSAOpType; |
|
46 |
|
47 /* |
|
48 * ckmk_mdCryptoOperationRSAPriv_Create |
|
49 */ |
|
50 static NSSCKMDCryptoOperation * |
|
51 ckmk_mdCryptoOperationRSAPriv_Create |
|
52 ( |
|
53 const NSSCKMDCryptoOperation *proto, |
|
54 NSSCKMDMechanism *mdMechanism, |
|
55 NSSCKMDObject *mdKey, |
|
56 ckmkRSAOpType type, |
|
57 CK_RV *pError |
|
58 ) |
|
59 { |
|
60 ckmkInternalObject *iKey = (ckmkInternalObject *)mdKey->etc; |
|
61 const NSSItem *classItem = nss_ckmk_FetchAttribute(iKey, CKA_CLASS, pError); |
|
62 const NSSItem *keyType = nss_ckmk_FetchAttribute(iKey, CKA_KEY_TYPE, pError); |
|
63 ckmkInternalCryptoOperationRSAPriv *iOperation; |
|
64 SecKeyRef privateKey; |
|
65 OSStatus macErr; |
|
66 CSSM_RETURN cssmErr; |
|
67 const CSSM_KEY *cssmKey; |
|
68 CSSM_CSP_HANDLE cspHandle; |
|
69 const CSSM_ACCESS_CREDENTIALS *creds = NULL; |
|
70 CSSM_CC_HANDLE cssmContext; |
|
71 CSSM_ACL_AUTHORIZATION_TAG authType; |
|
72 |
|
73 /* make sure we have the right objects */ |
|
74 if (((const NSSItem *)NULL == classItem) || |
|
75 (sizeof(CK_OBJECT_CLASS) != classItem->size) || |
|
76 (CKO_PRIVATE_KEY != *(CK_OBJECT_CLASS *)classItem->data) || |
|
77 ((const NSSItem *)NULL == keyType) || |
|
78 (sizeof(CK_KEY_TYPE) != keyType->size) || |
|
79 (CKK_RSA != *(CK_KEY_TYPE *)keyType->data)) { |
|
80 *pError = CKR_KEY_TYPE_INCONSISTENT; |
|
81 return (NSSCKMDCryptoOperation *)NULL; |
|
82 } |
|
83 |
|
84 privateKey = (SecKeyRef) iKey->u.item.itemRef; |
|
85 macErr = SecKeyGetCSSMKey(privateKey, &cssmKey); |
|
86 if (noErr != macErr) { |
|
87 CKMK_MACERR("Getting CSSM Key", macErr); |
|
88 *pError = CKR_KEY_HANDLE_INVALID; |
|
89 return (NSSCKMDCryptoOperation *)NULL; |
|
90 } |
|
91 macErr = SecKeyGetCSPHandle(privateKey, &cspHandle); |
|
92 if (noErr != macErr) { |
|
93 CKMK_MACERR("Getting CSP for Key", macErr); |
|
94 *pError = CKR_KEY_HANDLE_INVALID; |
|
95 return (NSSCKMDCryptoOperation *)NULL; |
|
96 } |
|
97 switch (type) { |
|
98 case CKMK_DECRYPT: |
|
99 authType = CSSM_ACL_AUTHORIZATION_DECRYPT; |
|
100 break; |
|
101 case CKMK_SIGN: |
|
102 authType = CSSM_ACL_AUTHORIZATION_SIGN; |
|
103 break; |
|
104 default: |
|
105 *pError = CKR_GENERAL_ERROR; |
|
106 #ifdef DEBUG |
|
107 fprintf(stderr,"RSAPriv_Create: bad type = %d\n", type); |
|
108 #endif |
|
109 return (NSSCKMDCryptoOperation *)NULL; |
|
110 } |
|
111 |
|
112 macErr = SecKeyGetCredentials(privateKey, authType, 0, &creds); |
|
113 if (noErr != macErr) { |
|
114 CKMK_MACERR("Getting Credentials for Key", macErr); |
|
115 *pError = CKR_KEY_HANDLE_INVALID; |
|
116 return (NSSCKMDCryptoOperation *)NULL; |
|
117 } |
|
118 |
|
119 switch (type) { |
|
120 case CKMK_DECRYPT: |
|
121 cssmErr = CSSM_CSP_CreateAsymmetricContext(cspHandle, CSSM_ALGID_RSA, |
|
122 creds, cssmKey, CSSM_PADDING_PKCS1, &cssmContext); |
|
123 break; |
|
124 case CKMK_SIGN: |
|
125 cssmErr = CSSM_CSP_CreateSignatureContext(cspHandle, CSSM_ALGID_RSA, |
|
126 creds, cssmKey, &cssmContext); |
|
127 break; |
|
128 default: |
|
129 *pError = CKR_GENERAL_ERROR; |
|
130 #ifdef DEBUG |
|
131 fprintf(stderr,"RSAPriv_Create: bad type = %d\n", type); |
|
132 #endif |
|
133 return (NSSCKMDCryptoOperation *)NULL; |
|
134 } |
|
135 if (noErr != cssmErr) { |
|
136 CKMK_MACERR("Getting Context for Key", cssmErr); |
|
137 *pError = CKR_GENERAL_ERROR; |
|
138 return (NSSCKMDCryptoOperation *)NULL; |
|
139 } |
|
140 |
|
141 iOperation = nss_ZNEW(NULL, ckmkInternalCryptoOperationRSAPriv); |
|
142 if ((ckmkInternalCryptoOperationRSAPriv *)NULL == iOperation) { |
|
143 *pError = CKR_HOST_MEMORY; |
|
144 return (NSSCKMDCryptoOperation *)NULL; |
|
145 } |
|
146 iOperation->mdMechanism = mdMechanism; |
|
147 iOperation->iKey = iKey; |
|
148 iOperation->cssmContext = cssmContext; |
|
149 |
|
150 nsslibc_memcpy(&iOperation->mdOperation, |
|
151 proto, sizeof(NSSCKMDCryptoOperation)); |
|
152 iOperation->mdOperation.etc = iOperation; |
|
153 |
|
154 return &iOperation->mdOperation; |
|
155 } |
|
156 |
|
157 static void |
|
158 ckmk_mdCryptoOperationRSAPriv_Destroy |
|
159 ( |
|
160 NSSCKMDCryptoOperation *mdOperation, |
|
161 NSSCKFWCryptoOperation *fwOperation, |
|
162 NSSCKMDInstance *mdInstance, |
|
163 NSSCKFWInstance *fwInstance |
|
164 ) |
|
165 { |
|
166 ckmkInternalCryptoOperationRSAPriv *iOperation = |
|
167 (ckmkInternalCryptoOperationRSAPriv *)mdOperation->etc; |
|
168 |
|
169 if (iOperation->buffer) { |
|
170 nssItem_Destroy(iOperation->buffer); |
|
171 } |
|
172 if (iOperation->cssmContext) { |
|
173 CSSM_DeleteContext(iOperation->cssmContext); |
|
174 } |
|
175 nss_ZFreeIf(iOperation); |
|
176 return; |
|
177 } |
|
178 |
|
179 static CK_ULONG |
|
180 ckmk_mdCryptoOperationRSA_GetFinalLength |
|
181 ( |
|
182 NSSCKMDCryptoOperation *mdOperation, |
|
183 NSSCKFWCryptoOperation *fwOperation, |
|
184 NSSCKMDSession *mdSession, |
|
185 NSSCKFWSession *fwSession, |
|
186 NSSCKMDToken *mdToken, |
|
187 NSSCKFWToken *fwToken, |
|
188 NSSCKMDInstance *mdInstance, |
|
189 NSSCKFWInstance *fwInstance, |
|
190 CK_RV *pError |
|
191 ) |
|
192 { |
|
193 ckmkInternalCryptoOperationRSAPriv *iOperation = |
|
194 (ckmkInternalCryptoOperationRSAPriv *)mdOperation->etc; |
|
195 const NSSItem *modulus = |
|
196 nss_ckmk_FetchAttribute(iOperation->iKey, CKA_MODULUS, pError); |
|
197 |
|
198 return modulus->size; |
|
199 } |
|
200 |
|
201 |
|
202 /* |
|
203 * ckmk_mdCryptoOperationRSADecrypt_GetOperationLength |
|
204 * we won't know the length until we actually decrypt the |
|
205 * input block. Since we go to all the work to decrypt the |
|
206 * the block, we'll save if for when the block is asked for |
|
207 */ |
|
208 static CK_ULONG |
|
209 ckmk_mdCryptoOperationRSADecrypt_GetOperationLength |
|
210 ( |
|
211 NSSCKMDCryptoOperation *mdOperation, |
|
212 NSSCKFWCryptoOperation *fwOperation, |
|
213 NSSCKMDSession *mdSession, |
|
214 NSSCKFWSession *fwSession, |
|
215 NSSCKMDToken *mdToken, |
|
216 NSSCKFWToken *fwToken, |
|
217 NSSCKMDInstance *mdInstance, |
|
218 NSSCKFWInstance *fwInstance, |
|
219 const NSSItem *input, |
|
220 CK_RV *pError |
|
221 ) |
|
222 { |
|
223 ckmkInternalCryptoOperationRSAPriv *iOperation = |
|
224 (ckmkInternalCryptoOperationRSAPriv *)mdOperation->etc; |
|
225 CSSM_DATA cssmInput; |
|
226 CSSM_DATA cssmOutput = { 0, NULL }; |
|
227 PRUint32 bytesDecrypted; |
|
228 CSSM_DATA remainder = { 0, NULL }; |
|
229 NSSItem output; |
|
230 CSSM_RETURN cssmErr; |
|
231 |
|
232 if (iOperation->buffer) { |
|
233 return iOperation->buffer->size; |
|
234 } |
|
235 |
|
236 cssmInput.Data = input->data; |
|
237 cssmInput.Length = input->size; |
|
238 |
|
239 cssmErr = CSSM_DecryptData(iOperation->cssmContext, |
|
240 &cssmInput, 1, &cssmOutput, 1, |
|
241 &bytesDecrypted, &remainder); |
|
242 if (CSSM_OK != cssmErr) { |
|
243 CKMK_MACERR("Decrypt Failed", cssmErr); |
|
244 *pError = CKR_DATA_INVALID; |
|
245 return 0; |
|
246 } |
|
247 /* we didn't suppy any buffers, so it should all be in remainder */ |
|
248 output.data = nss_ZNEWARRAY(NULL, char, bytesDecrypted + remainder.Length); |
|
249 if (NULL == output.data) { |
|
250 free(cssmOutput.Data); |
|
251 free(remainder.Data); |
|
252 *pError = CKR_HOST_MEMORY; |
|
253 return 0; |
|
254 } |
|
255 output.size = bytesDecrypted + remainder.Length; |
|
256 |
|
257 if (0 != bytesDecrypted) { |
|
258 nsslibc_memcpy(output.data, cssmOutput.Data, bytesDecrypted); |
|
259 free(cssmOutput.Data); |
|
260 } |
|
261 if (0 != remainder.Length) { |
|
262 nsslibc_memcpy(((char *)output.data)+bytesDecrypted, |
|
263 remainder.Data, remainder.Length); |
|
264 free(remainder.Data); |
|
265 } |
|
266 |
|
267 iOperation->buffer = nssItem_Duplicate(&output, NULL, NULL); |
|
268 nss_ZFreeIf(output.data); |
|
269 if ((NSSItem *) NULL == iOperation->buffer) { |
|
270 *pError = CKR_HOST_MEMORY; |
|
271 return 0; |
|
272 } |
|
273 |
|
274 return iOperation->buffer->size; |
|
275 } |
|
276 |
|
277 /* |
|
278 * ckmk_mdCryptoOperationRSADecrypt_UpdateFinal |
|
279 * |
|
280 * NOTE: ckmk_mdCryptoOperationRSADecrypt_GetOperationLength is presumed to |
|
281 * have been called previously. |
|
282 */ |
|
283 static CK_RV |
|
284 ckmk_mdCryptoOperationRSADecrypt_UpdateFinal |
|
285 ( |
|
286 NSSCKMDCryptoOperation *mdOperation, |
|
287 NSSCKFWCryptoOperation *fwOperation, |
|
288 NSSCKMDSession *mdSession, |
|
289 NSSCKFWSession *fwSession, |
|
290 NSSCKMDToken *mdToken, |
|
291 NSSCKFWToken *fwToken, |
|
292 NSSCKMDInstance *mdInstance, |
|
293 NSSCKFWInstance *fwInstance, |
|
294 const NSSItem *input, |
|
295 NSSItem *output |
|
296 ) |
|
297 { |
|
298 ckmkInternalCryptoOperationRSAPriv *iOperation = |
|
299 (ckmkInternalCryptoOperationRSAPriv *)mdOperation->etc; |
|
300 NSSItem *buffer = iOperation->buffer; |
|
301 |
|
302 if ((NSSItem *)NULL == buffer) { |
|
303 return CKR_GENERAL_ERROR; |
|
304 } |
|
305 nsslibc_memcpy(output->data, buffer->data, buffer->size); |
|
306 output->size = buffer->size; |
|
307 return CKR_OK; |
|
308 } |
|
309 |
|
310 /* |
|
311 * ckmk_mdCryptoOperationRSASign_UpdateFinal |
|
312 * |
|
313 */ |
|
314 static CK_RV |
|
315 ckmk_mdCryptoOperationRSASign_UpdateFinal |
|
316 ( |
|
317 NSSCKMDCryptoOperation *mdOperation, |
|
318 NSSCKFWCryptoOperation *fwOperation, |
|
319 NSSCKMDSession *mdSession, |
|
320 NSSCKFWSession *fwSession, |
|
321 NSSCKMDToken *mdToken, |
|
322 NSSCKFWToken *fwToken, |
|
323 NSSCKMDInstance *mdInstance, |
|
324 NSSCKFWInstance *fwInstance, |
|
325 const NSSItem *input, |
|
326 NSSItem *output |
|
327 ) |
|
328 { |
|
329 ckmkInternalCryptoOperationRSAPriv *iOperation = |
|
330 (ckmkInternalCryptoOperationRSAPriv *)mdOperation->etc; |
|
331 CSSM_DATA cssmInput; |
|
332 CSSM_DATA cssmOutput = { 0, NULL }; |
|
333 CSSM_RETURN cssmErr; |
|
334 |
|
335 cssmInput.Data = input->data; |
|
336 cssmInput.Length = input->size; |
|
337 |
|
338 cssmErr = CSSM_SignData(iOperation->cssmContext, &cssmInput, 1, |
|
339 CSSM_ALGID_NONE, &cssmOutput); |
|
340 if (CSSM_OK != cssmErr) { |
|
341 CKMK_MACERR("Signed Failed", cssmErr); |
|
342 return CKR_FUNCTION_FAILED; |
|
343 } |
|
344 if (cssmOutput.Length > output->size) { |
|
345 free(cssmOutput.Data); |
|
346 return CKR_BUFFER_TOO_SMALL; |
|
347 } |
|
348 nsslibc_memcpy(output->data, cssmOutput.Data, cssmOutput.Length); |
|
349 free(cssmOutput.Data); |
|
350 output->size = cssmOutput.Length; |
|
351 |
|
352 return CKR_OK; |
|
353 } |
|
354 |
|
355 |
|
356 NSS_IMPLEMENT_DATA const NSSCKMDCryptoOperation |
|
357 ckmk_mdCryptoOperationRSADecrypt_proto = { |
|
358 NULL, /* etc */ |
|
359 ckmk_mdCryptoOperationRSAPriv_Destroy, |
|
360 NULL, /* GetFinalLengh - not needed for one shot Decrypt/Encrypt */ |
|
361 ckmk_mdCryptoOperationRSADecrypt_GetOperationLength, |
|
362 NULL, /* Final - not needed for one shot operation */ |
|
363 NULL, /* Update - not needed for one shot operation */ |
|
364 NULL, /* DigetUpdate - not needed for one shot operation */ |
|
365 ckmk_mdCryptoOperationRSADecrypt_UpdateFinal, |
|
366 NULL, /* UpdateCombo - not needed for one shot operation */ |
|
367 NULL, /* DigetKey - not needed for one shot operation */ |
|
368 (void *)NULL /* null terminator */ |
|
369 }; |
|
370 |
|
371 NSS_IMPLEMENT_DATA const NSSCKMDCryptoOperation |
|
372 ckmk_mdCryptoOperationRSASign_proto = { |
|
373 NULL, /* etc */ |
|
374 ckmk_mdCryptoOperationRSAPriv_Destroy, |
|
375 ckmk_mdCryptoOperationRSA_GetFinalLength, |
|
376 NULL, /* GetOperationLengh - not needed for one shot Sign/Verify */ |
|
377 NULL, /* Final - not needed for one shot operation */ |
|
378 NULL, /* Update - not needed for one shot operation */ |
|
379 NULL, /* DigetUpdate - not needed for one shot operation */ |
|
380 ckmk_mdCryptoOperationRSASign_UpdateFinal, |
|
381 NULL, /* UpdateCombo - not needed for one shot operation */ |
|
382 NULL, /* DigetKey - not needed for one shot operation */ |
|
383 (void *)NULL /* null terminator */ |
|
384 }; |
|
385 |
|
386 /********** NSSCKMDMechansim functions ***********************/ |
|
387 /* |
|
388 * ckmk_mdMechanismRSA_Destroy |
|
389 */ |
|
390 static void |
|
391 ckmk_mdMechanismRSA_Destroy |
|
392 ( |
|
393 NSSCKMDMechanism *mdMechanism, |
|
394 NSSCKFWMechanism *fwMechanism, |
|
395 NSSCKMDInstance *mdInstance, |
|
396 NSSCKFWInstance *fwInstance |
|
397 ) |
|
398 { |
|
399 nss_ZFreeIf(fwMechanism); |
|
400 } |
|
401 |
|
402 /* |
|
403 * ckmk_mdMechanismRSA_GetMinKeySize |
|
404 */ |
|
405 static CK_ULONG |
|
406 ckmk_mdMechanismRSA_GetMinKeySize |
|
407 ( |
|
408 NSSCKMDMechanism *mdMechanism, |
|
409 NSSCKFWMechanism *fwMechanism, |
|
410 NSSCKMDToken *mdToken, |
|
411 NSSCKFWToken *fwToken, |
|
412 NSSCKMDInstance *mdInstance, |
|
413 NSSCKFWInstance *fwInstance, |
|
414 CK_RV *pError |
|
415 ) |
|
416 { |
|
417 return 384; |
|
418 } |
|
419 |
|
420 /* |
|
421 * ckmk_mdMechanismRSA_GetMaxKeySize |
|
422 */ |
|
423 static CK_ULONG |
|
424 ckmk_mdMechanismRSA_GetMaxKeySize |
|
425 ( |
|
426 NSSCKMDMechanism *mdMechanism, |
|
427 NSSCKFWMechanism *fwMechanism, |
|
428 NSSCKMDToken *mdToken, |
|
429 NSSCKFWToken *fwToken, |
|
430 NSSCKMDInstance *mdInstance, |
|
431 NSSCKFWInstance *fwInstance, |
|
432 CK_RV *pError |
|
433 ) |
|
434 { |
|
435 return 16384; |
|
436 } |
|
437 |
|
438 /* |
|
439 * ckmk_mdMechanismRSA_DecryptInit |
|
440 */ |
|
441 static NSSCKMDCryptoOperation * |
|
442 ckmk_mdMechanismRSA_DecryptInit |
|
443 ( |
|
444 NSSCKMDMechanism *mdMechanism, |
|
445 NSSCKFWMechanism *fwMechanism, |
|
446 CK_MECHANISM *pMechanism, |
|
447 NSSCKMDSession *mdSession, |
|
448 NSSCKFWSession *fwSession, |
|
449 NSSCKMDToken *mdToken, |
|
450 NSSCKFWToken *fwToken, |
|
451 NSSCKMDInstance *mdInstance, |
|
452 NSSCKFWInstance *fwInstance, |
|
453 NSSCKMDObject *mdKey, |
|
454 NSSCKFWObject *fwKey, |
|
455 CK_RV *pError |
|
456 ) |
|
457 { |
|
458 return ckmk_mdCryptoOperationRSAPriv_Create( |
|
459 &ckmk_mdCryptoOperationRSADecrypt_proto, |
|
460 mdMechanism, mdKey, CKMK_DECRYPT, pError); |
|
461 } |
|
462 |
|
463 /* |
|
464 * ckmk_mdMechanismRSA_SignInit |
|
465 */ |
|
466 static NSSCKMDCryptoOperation * |
|
467 ckmk_mdMechanismRSA_SignInit |
|
468 ( |
|
469 NSSCKMDMechanism *mdMechanism, |
|
470 NSSCKFWMechanism *fwMechanism, |
|
471 CK_MECHANISM *pMechanism, |
|
472 NSSCKMDSession *mdSession, |
|
473 NSSCKFWSession *fwSession, |
|
474 NSSCKMDToken *mdToken, |
|
475 NSSCKFWToken *fwToken, |
|
476 NSSCKMDInstance *mdInstance, |
|
477 NSSCKFWInstance *fwInstance, |
|
478 NSSCKMDObject *mdKey, |
|
479 NSSCKFWObject *fwKey, |
|
480 CK_RV *pError |
|
481 ) |
|
482 { |
|
483 return ckmk_mdCryptoOperationRSAPriv_Create( |
|
484 &ckmk_mdCryptoOperationRSASign_proto, |
|
485 mdMechanism, mdKey, CKMK_SIGN, pError); |
|
486 } |
|
487 |
|
488 |
|
489 NSS_IMPLEMENT_DATA const NSSCKMDMechanism |
|
490 nss_ckmk_mdMechanismRSA = { |
|
491 (void *)NULL, /* etc */ |
|
492 ckmk_mdMechanismRSA_Destroy, |
|
493 ckmk_mdMechanismRSA_GetMinKeySize, |
|
494 ckmk_mdMechanismRSA_GetMaxKeySize, |
|
495 NULL, /* GetInHardware - default false */ |
|
496 NULL, /* EncryptInit - default errs */ |
|
497 ckmk_mdMechanismRSA_DecryptInit, |
|
498 NULL, /* DigestInit - default errs*/ |
|
499 ckmk_mdMechanismRSA_SignInit, |
|
500 NULL, /* VerifyInit - default errs */ |
|
501 ckmk_mdMechanismRSA_SignInit, /* SignRecoverInit */ |
|
502 NULL, /* VerifyRecoverInit - default errs */ |
|
503 NULL, /* GenerateKey - default errs */ |
|
504 NULL, /* GenerateKeyPair - default errs */ |
|
505 NULL, /* GetWrapKeyLength - default errs */ |
|
506 NULL, /* WrapKey - default errs */ |
|
507 NULL, /* UnwrapKey - default errs */ |
|
508 NULL, /* DeriveKey - default errs */ |
|
509 (void *)NULL /* null terminator */ |
|
510 }; |