Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
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/. */
5 #include "ckmk.h"
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 );
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 );
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 };
42 typedef enum {
43 CKMK_DECRYPT,
44 CKMK_SIGN
45 } ckmkRSAOpType;
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;
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 }
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 }
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 }
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 }
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;
150 nsslibc_memcpy(&iOperation->mdOperation,
151 proto, sizeof(NSSCKMDCryptoOperation));
152 iOperation->mdOperation.etc = iOperation;
154 return &iOperation->mdOperation;
155 }
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;
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 }
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);
198 return modulus->size;
199 }
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;
232 if (iOperation->buffer) {
233 return iOperation->buffer->size;
234 }
236 cssmInput.Data = input->data;
237 cssmInput.Length = input->size;
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;
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 }
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 }
274 return iOperation->buffer->size;
275 }
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;
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 }
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;
335 cssmInput.Data = input->data;
336 cssmInput.Length = input->size;
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;
352 return CKR_OK;
353 }
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 };
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 };
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 }
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 }
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 }
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 }
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 }
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 };