|
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 * This file implements the Symkey wrapper and the PKCS context |
|
6 * Interfaces. |
|
7 */ |
|
8 |
|
9 #include "seccomon.h" |
|
10 #include "secmod.h" |
|
11 #include "nssilock.h" |
|
12 #include "secmodi.h" |
|
13 #include "secmodti.h" |
|
14 #include "pkcs11.h" |
|
15 #include "pk11func.h" |
|
16 #include "secitem.h" |
|
17 #include "key.h" |
|
18 #include "secasn1.h" |
|
19 #include "sechash.h" |
|
20 #include "cert.h" |
|
21 #include "secerr.h" |
|
22 |
|
23 /* |
|
24 * find an RSA public key on a card |
|
25 */ |
|
26 static CK_OBJECT_HANDLE |
|
27 pk11_FindRSAPubKey(PK11SlotInfo *slot) |
|
28 { |
|
29 CK_KEY_TYPE key_type = CKK_RSA; |
|
30 CK_OBJECT_CLASS class_type = CKO_PUBLIC_KEY; |
|
31 CK_ATTRIBUTE theTemplate[2]; |
|
32 int template_count = sizeof(theTemplate)/sizeof(theTemplate[0]); |
|
33 CK_ATTRIBUTE *attrs = theTemplate; |
|
34 |
|
35 PK11_SETATTRS(attrs,CKA_CLASS,&class_type,sizeof(class_type)); attrs++; |
|
36 PK11_SETATTRS(attrs,CKA_KEY_TYPE,&key_type,sizeof(key_type)); attrs++; |
|
37 template_count = attrs - theTemplate; |
|
38 PR_ASSERT(template_count <= sizeof(theTemplate)/sizeof(CK_ATTRIBUTE)); |
|
39 |
|
40 return pk11_FindObjectByTemplate(slot,theTemplate,template_count); |
|
41 } |
|
42 |
|
43 PK11SymKey * |
|
44 pk11_KeyExchange(PK11SlotInfo *slot,CK_MECHANISM_TYPE type, |
|
45 CK_ATTRIBUTE_TYPE operation, CK_FLAGS flags, |
|
46 PRBool isPerm, PK11SymKey *symKey) |
|
47 { |
|
48 PK11SymKey *newSymKey = NULL; |
|
49 SECStatus rv; |
|
50 /* performance improvement can go here --- use a generated key at startup |
|
51 * to generate a per token wrapping key. If it exists, use it, otherwise |
|
52 * do a full key exchange. */ |
|
53 |
|
54 /* find a common Key Exchange algorithm */ |
|
55 /* RSA */ |
|
56 if (PK11_DoesMechanism(symKey->slot, CKM_RSA_PKCS) && |
|
57 PK11_DoesMechanism(slot,CKM_RSA_PKCS)) { |
|
58 CK_OBJECT_HANDLE pubKeyHandle = CK_INVALID_HANDLE; |
|
59 CK_OBJECT_HANDLE privKeyHandle = CK_INVALID_HANDLE; |
|
60 SECKEYPublicKey *pubKey = NULL; |
|
61 SECKEYPrivateKey *privKey = NULL; |
|
62 SECItem wrapData; |
|
63 unsigned int symKeyLength = PK11_GetKeyLength(symKey); |
|
64 |
|
65 wrapData.data = NULL; |
|
66 |
|
67 /* find RSA Public Key on target */ |
|
68 pubKeyHandle = pk11_FindRSAPubKey(slot); |
|
69 if (pubKeyHandle != CK_INVALID_HANDLE) { |
|
70 privKeyHandle = PK11_MatchItem(slot,pubKeyHandle,CKO_PRIVATE_KEY); |
|
71 } |
|
72 |
|
73 /* if no key exists, generate a key pair */ |
|
74 if (privKeyHandle == CK_INVALID_HANDLE) { |
|
75 PK11RSAGenParams rsaParams; |
|
76 |
|
77 if (symKeyLength > 53) /* bytes */ { |
|
78 /* we'd have to generate an RSA key pair > 512 bits long, |
|
79 ** and that's too costly. Don't even try. |
|
80 */ |
|
81 PORT_SetError( SEC_ERROR_CANNOT_MOVE_SENSITIVE_KEY ); |
|
82 goto rsa_failed; |
|
83 } |
|
84 rsaParams.keySizeInBits = |
|
85 (symKeyLength > 21 || symKeyLength == 0) ? 512 : 256; |
|
86 rsaParams.pe = 0x10001; |
|
87 privKey = PK11_GenerateKeyPair(slot,CKM_RSA_PKCS_KEY_PAIR_GEN, |
|
88 &rsaParams, &pubKey,PR_FALSE,PR_TRUE,symKey->cx); |
|
89 } else { |
|
90 /* if keys exist, build SECKEY data structures for them */ |
|
91 privKey = PK11_MakePrivKey(slot,nullKey, PR_TRUE, privKeyHandle, |
|
92 symKey->cx); |
|
93 if (privKey != NULL) { |
|
94 pubKey = PK11_ExtractPublicKey(slot, rsaKey, pubKeyHandle); |
|
95 if (pubKey && pubKey->pkcs11Slot) { |
|
96 PK11_FreeSlot(pubKey->pkcs11Slot); |
|
97 pubKey->pkcs11Slot = NULL; |
|
98 pubKey->pkcs11ID = CK_INVALID_HANDLE; |
|
99 } |
|
100 } |
|
101 } |
|
102 if (privKey == NULL) goto rsa_failed; |
|
103 if (pubKey == NULL) goto rsa_failed; |
|
104 |
|
105 wrapData.len = SECKEY_PublicKeyStrength(pubKey); |
|
106 if (!wrapData.len) goto rsa_failed; |
|
107 wrapData.data = PORT_Alloc(wrapData.len); |
|
108 if (wrapData.data == NULL) goto rsa_failed; |
|
109 |
|
110 /* now wrap the keys in and out */ |
|
111 rv = PK11_PubWrapSymKey(CKM_RSA_PKCS, pubKey, symKey, &wrapData); |
|
112 if (rv == SECSuccess) { |
|
113 newSymKey = PK11_PubUnwrapSymKeyWithFlagsPerm(privKey, |
|
114 &wrapData,type,operation,symKeyLength,flags,isPerm); |
|
115 /* make sure we wound up where we wanted to be! */ |
|
116 if (newSymKey && newSymKey->slot != slot) { |
|
117 PK11_FreeSymKey(newSymKey); |
|
118 newSymKey = NULL; |
|
119 } |
|
120 } |
|
121 rsa_failed: |
|
122 if (wrapData.data != NULL) PORT_Free(wrapData.data); |
|
123 if (privKey != NULL) SECKEY_DestroyPrivateKey(privKey); |
|
124 if (pubKey != NULL) SECKEY_DestroyPublicKey(pubKey); |
|
125 |
|
126 return newSymKey; |
|
127 } |
|
128 PORT_SetError( SEC_ERROR_NO_MODULE ); |
|
129 return NULL; |
|
130 } |
|
131 |