|
1 /* |
|
2 * Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of the License "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include "CCreateKey.h" |
|
20 #include "tokenserverdebug.h" |
|
21 #include <bigint.h> |
|
22 |
|
23 // Wrapper class because we differ from crypto on what a DH key is |
|
24 class CSimpleDHKey : public CBase |
|
25 { |
|
26 public: |
|
27 static CSimpleDHKey* NewL(TInt aSize); |
|
28 ~CSimpleDHKey(); |
|
29 public: |
|
30 inline RInteger& DHKey() {return (iKey);}; |
|
31 private: |
|
32 CSimpleDHKey() {}; |
|
33 void ConstructL(TInt aSize); |
|
34 private: |
|
35 RInteger iKey; |
|
36 }; |
|
37 |
|
38 CSimpleDHKey* CSimpleDHKey::NewL(TInt aSize) |
|
39 { |
|
40 CSimpleDHKey* me = new (ELeave) CSimpleDHKey(); |
|
41 CleanupStack::PushL(me); |
|
42 me->ConstructL(aSize); |
|
43 CleanupStack::Pop(me); |
|
44 return (me); |
|
45 } |
|
46 |
|
47 void CSimpleDHKey::ConstructL(TInt aSize) |
|
48 { |
|
49 iKey = RInteger::NewRandomL(aSize - 1); |
|
50 } |
|
51 |
|
52 CSimpleDHKey::~CSimpleDHKey() |
|
53 { |
|
54 iKey.Close(); |
|
55 } |
|
56 |
|
57 CKeyCreator::CKeyCreator() |
|
58 : CActive(EPriorityStandard), iAction(EIdle) |
|
59 { |
|
60 CActiveScheduler::Add(this); |
|
61 } |
|
62 |
|
63 |
|
64 CKeyCreator::~CKeyCreator() |
|
65 { |
|
66 Cancel(); |
|
67 |
|
68 iCreatorThread.LogonCancel(iStatus); |
|
69 iCreatorThread.Close(); |
|
70 |
|
71 delete iCreateData; |
|
72 } |
|
73 |
|
74 // Spin a thread to create an appropriate key, if successful, left on CleanupStack |
|
75 void CKeyCreator::DoCreateKeyAsyncL(CKeyInfo::EKeyAlgorithm aAlgorithm, TInt aSize, TRequestStatus& aStatus) |
|
76 { |
|
77 if ( (aSize <= 0) || |
|
78 (aAlgorithm==CKeyInfo::EInvalidAlgorithm) || |
|
79 ((aAlgorithm!=CKeyInfo::ERSA) && (aAlgorithm!=CKeyInfo::EDSA) && (aAlgorithm!=CKeyInfo::EDH)) ) |
|
80 User::Leave(KErrArgument); |
|
81 |
|
82 iClientStatus = &aStatus; |
|
83 *iClientStatus = KRequestPending; |
|
84 |
|
85 iCreateData = new (ELeave) CKeyCreatorData(aAlgorithm, aSize); |
|
86 |
|
87 // OK, ready to start the async operation...do it in RunL |
|
88 iAction = EReadyToCreateKey; |
|
89 iStatus = KRequestPending; |
|
90 SetActive(); |
|
91 TRequestStatus* stat = &iStatus; |
|
92 User::RequestComplete(stat, KErrNone); |
|
93 } |
|
94 |
|
95 // HERE'S THE THREAD TO CREATE THE KEY |
|
96 // Code cannot leave in here, but not as many traps as it looks |
|
97 /*static*/ TInt CKeyCreator::CreatorThreadEntryPoint(TAny* aParameters) |
|
98 { |
|
99 CTrapCleanup* cleanup = CTrapCleanup::New(); |
|
100 if (!cleanup) |
|
101 User::Exit(KErrNoMemory); |
|
102 |
|
103 #ifdef _DEBUG |
|
104 TokenServerDebug::PauseOOMTest(); |
|
105 #endif |
|
106 |
|
107 ASSERT(aParameters); |
|
108 TInt result = KErrNone; |
|
109 CKeyCreatorData* createData = static_cast<CKeyCreatorData*>(aParameters); |
|
110 switch (createData->iKeyAlgorithm) |
|
111 { |
|
112 case(CKeyInfo::ERSA): |
|
113 {// Currently, CRT signing is not supported, in case the key is to be used |
|
114 // for such, create a standard (private) key as part of the pair |
|
115 TRAP(result, createData->iKey.iRSAKey = CRSAKeyPair::NewL(createData->iSize)); |
|
116 } |
|
117 break; |
|
118 case (CKeyInfo::EDSA): |
|
119 { |
|
120 TRAP(result, createData->iKey.iDSAKey = CDSAKeyPair::NewL(createData->iSize)); |
|
121 } |
|
122 break; |
|
123 case (CKeyInfo::EDH): |
|
124 {// Generate a number that's less than N. The snag is that |
|
125 // we don't know what N is. We do know that it'll be of a |
|
126 // particular size, so we can safely generate any number |
|
127 // with less than iSize digits |
|
128 TRAP(result, createData->iKey.iDHKey = CSimpleDHKey::NewL(createData->iSize)); |
|
129 } |
|
130 break; |
|
131 default: |
|
132 ASSERT(EFalse); |
|
133 result = KErrArgument; |
|
134 } |
|
135 |
|
136 #ifdef _DEBUG |
|
137 TokenServerDebug::ResumeOOMTest(); |
|
138 #endif |
|
139 delete cleanup; |
|
140 User::Exit(result); |
|
141 return (KErrNone); |
|
142 } |
|
143 |
|
144 CRSAKeyPair* CKeyCreator::GetCreatedRSAKey() |
|
145 {// Check algorithm is as expected, return NULL if no key or wrong type |
|
146 if ( (!iCreateData) || (CKeyInfo::ERSA!=iCreateData->iKeyAlgorithm) ) |
|
147 return (NULL); |
|
148 else |
|
149 return (iCreateData->iKey.iRSAKey); |
|
150 } |
|
151 |
|
152 CDSAKeyPair* CKeyCreator::GetCreatedDSAKey() |
|
153 {// Check algorithm is as expected, return NULL if no key or wrong type |
|
154 if ( (!iCreateData) || (CKeyInfo::EDSA!=iCreateData->iKeyAlgorithm) ) |
|
155 return (NULL); |
|
156 else |
|
157 return (iCreateData->iKey.iDSAKey); |
|
158 } |
|
159 |
|
160 void CKeyCreator::GetCreatedDHKey(RInteger& aDHKey) |
|
161 { |
|
162 ASSERT(iCreateData); |
|
163 ASSERT(CKeyInfo::EDH==iCreateData->iKeyAlgorithm); |
|
164 aDHKey = iCreateData->iKey.iDHKey->DHKey(); |
|
165 } |
|
166 |
|
167 void CKeyCreator::DoCancel() |
|
168 {// Only do the cancel if in the middle of creating a key. Kill the thread. |
|
169 if (iAction!=EIdle) |
|
170 { |
|
171 TExitType exitType = iCreatorThread.ExitType(); |
|
172 if (EExitPending==exitType) // Still alive, so kill it |
|
173 iCreatorThread.Kill(KErrCancel); |
|
174 |
|
175 iAction = EIdle; |
|
176 } |
|
177 |
|
178 ASSERT(iClientStatus); |
|
179 User::RequestComplete(iClientStatus, KErrCancel); |
|
180 } |
|
181 |
|
182 void CKeyCreator::RunL() |
|
183 { |
|
184 ASSERT(iClientStatus); |
|
185 |
|
186 switch (iAction) |
|
187 { |
|
188 case (EReadyToCreateKey): |
|
189 { // Spin off the thread and pass it the parameter data, then stand by |
|
190 // INC118634 |
|
191 // To be safe, we should use anonymous threads because naming a thread means anybody could have opened a handle on the thread, |
|
192 // most likely system applications which want to know about panicing threads. So next thread creation will fail with KErrAlreadyExist(-11). |
|
193 User::LeaveIfError(iCreatorThread.Create(KNullDesC, CreatorThreadEntryPoint, KDefaultStackSize, NULL, (TAny*)iCreateData)); |
|
194 iStatus = KRequestPending; |
|
195 iCreatorThread.Logon(iStatus); |
|
196 iAction = ECreatedKey; |
|
197 SetActive(); |
|
198 iCreatorThread.Resume(); |
|
199 } |
|
200 break; |
|
201 case (ECreatedKey): |
|
202 {// Notify the caller |
|
203 ASSERT(iClientStatus); |
|
204 // May be OOM creating logon, in which case we should kill thread |
|
205 if (iStatus.Int() == KErrNoMemory) |
|
206 { |
|
207 TExitType exitType = iCreatorThread.ExitType(); |
|
208 if (EExitPending==exitType) // Still alive, so kill it |
|
209 iCreatorThread.Kill(KErrNone); |
|
210 } |
|
211 |
|
212 User::RequestComplete(iClientStatus, iStatus.Int()); |
|
213 iAction = EIdle; |
|
214 } |
|
215 break; |
|
216 default: |
|
217 ASSERT(EFalse); |
|
218 } |
|
219 } |
|
220 |
|
221 TInt CKeyCreator::RunError(TInt anError) |
|
222 { |
|
223 if (iClientStatus) |
|
224 User::RequestComplete(iClientStatus, anError); |
|
225 |
|
226 return (KErrNone); |
|
227 } |
|
228 |
|
229 |
|
230 |
|
231 CKeyCreator::CKeyCreatorData::CKeyCreatorData(CKeyInfo::EKeyAlgorithm aAlgorithm, TInt aSize) |
|
232 : iSize(aSize), iKeyAlgorithm(aAlgorithm) |
|
233 {} |
|
234 |
|
235 CKeyCreator::CKeyCreatorData::~CKeyCreatorData() |
|
236 { |
|
237 if (iKeyAlgorithm==CKeyInfo::ERSA) |
|
238 delete iKey.iRSAKey; |
|
239 else if (iKeyAlgorithm==CKeyInfo::EDSA) |
|
240 delete iKey.iDSAKey; |
|
241 else if (iKeyAlgorithm==CKeyInfo::EDH) |
|
242 delete iKey.iDHKey; |
|
243 } |