|
1 // Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // App for resigning OCSP responses. |
|
15 // |
|
16 // |
|
17 |
|
18 #include <e32cons.h> |
|
19 #include <f32file.h> |
|
20 #include <asn1dec.h> |
|
21 #include <asn1enc.h> |
|
22 #include <x509cert.h> |
|
23 #include <signed.h> |
|
24 #include <bigint.h> |
|
25 #include <asymmetric.h> |
|
26 #include <hash.h> |
|
27 #include <bacline.h> |
|
28 |
|
29 #include "resign.h" |
|
30 |
|
31 // CertTool command line parameters |
|
32 _LIT(KResign, "-resign"); |
|
33 _LIT(KResignShort, "-r"); |
|
34 |
|
35 _LIT(KCreate, "-create"); |
|
36 _LIT(KCreateShort, "-c"); |
|
37 |
|
38 _LIT(KExtractResponse, "-e"); |
|
39 _LIT(KExtractResponseShort, "-extract"); |
|
40 |
|
41 CResign* CResign::NewLC() |
|
42 { |
|
43 CResign* resign = new(ELeave) CResign(); |
|
44 CleanupStack::PushL(resign); |
|
45 resign->ConstructL(); |
|
46 return resign; |
|
47 } |
|
48 |
|
49 CResign* CResign::NewL() |
|
50 { |
|
51 CResign* resign = CResign::NewLC(); |
|
52 CleanupStack::Pop(resign); |
|
53 return resign; |
|
54 } |
|
55 |
|
56 CResign::CResign() |
|
57 {} |
|
58 |
|
59 void CResign::ConstructL() |
|
60 { |
|
61 User::LeaveIfError(iFs.Connect()); |
|
62 } |
|
63 |
|
64 CResign::~CResign() |
|
65 { |
|
66 delete iArguments; |
|
67 iFs.Close(); |
|
68 } |
|
69 |
|
70 void CResign::ResignL(const TPtrC8& aSignedData, |
|
71 TPtr8& aSignature, |
|
72 RInteger& aModulus, |
|
73 const RInteger& /*aPublicExponent*/, |
|
74 RInteger& aPrivateExponent) |
|
75 { |
|
76 __UHEAP_MARK; |
|
77 // Build message digest |
|
78 CSHA1* hash = CSHA1::NewL(); |
|
79 CleanupStack::PushL(hash); |
|
80 TPtrC8 digest = hash->Final(aSignedData); |
|
81 |
|
82 // Build ASN1 encoding of digestAlgId and digest.. |
|
83 CASN1EncSequence* encAll = CASN1EncSequence::NewLC(); |
|
84 |
|
85 // Build AlgID encoder (for SHA1) |
|
86 CASN1EncSequence* encAlgId = CASN1EncSequence::NewLC(); |
|
87 |
|
88 CASN1EncObjectIdentifier* encObjId = CASN1EncObjectIdentifier::NewLC(KSHA1); |
|
89 encAlgId->AddChildL(encObjId); |
|
90 CleanupStack::Pop(); // encObjId, now owned by endAlgId |
|
91 |
|
92 CASN1EncNull* encNull = CASN1EncNull::NewLC(); |
|
93 encAlgId->AddChildL(encNull); |
|
94 CleanupStack::Pop(); // encNull, now owned by endAlgId |
|
95 |
|
96 encAll->AddChildL(encAlgId); |
|
97 CleanupStack::Pop(); // endAlgId, now owned by encAll |
|
98 |
|
99 CASN1EncOctetString* encDigest = CASN1EncOctetString::NewLC(digest); |
|
100 encAll->AddChildL(encDigest); |
|
101 CleanupStack::Pop(); // encDigest, now owned by encAll |
|
102 |
|
103 HBufC8* digestInfo = HBufC8::NewMaxLC(encAll->LengthDER()); |
|
104 TUint pos = 0; |
|
105 TPtr8 digestInfoPtr = digestInfo->Des(); |
|
106 encAll->WriteDERL(digestInfoPtr, pos); |
|
107 |
|
108 __UHEAP_MARK; |
|
109 |
|
110 CRSAPrivateKeyStandard* rsaPriv = CRSAPrivateKeyStandard::NewLC(aModulus, aPrivateExponent); |
|
111 |
|
112 CRSAPKCS1v15Signer* signer = CRSAPKCS1v15Signer::NewLC(*rsaPriv); |
|
113 |
|
114 const CRSASignature* signature = signer->SignL(digestInfoPtr); |
|
115 |
|
116 HBufC8* theSignature = signature->S().BufferLC(); |
|
117 aSignature.Copy(*theSignature); |
|
118 |
|
119 CleanupStack::PopAndDestroy(4, rsaPriv); |
|
120 |
|
121 __UHEAP_MARKEND; |
|
122 |
|
123 CleanupStack::PopAndDestroy(3, hash); |
|
124 |
|
125 __UHEAP_MARKEND; |
|
126 } |
|
127 |
|
128 void CResign::DecodeDataL(TDes8& aResponse, const TDesC8& aKey) |
|
129 { |
|
130 __UHEAP_MARK; |
|
131 TASN1DecSequence seqDec; |
|
132 TInt pos = 0; |
|
133 |
|
134 // Get the signed data and signature portions of the response |
|
135 CArrayPtr<TASN1DecGeneric>* ocspResponseSeq = seqDec.DecodeDERLC(aResponse, pos, 2, 2); |
|
136 TPtrC8 responseBytes = ocspResponseSeq->At(1)->GetContentDER(); |
|
137 CleanupStack::PopAndDestroy(ocspResponseSeq); |
|
138 |
|
139 pos = 0; |
|
140 CArrayPtr<TASN1DecGeneric>* responseBytesSeq = seqDec.DecodeDERLC(responseBytes, pos, 2, 2); |
|
141 TPtrC8 basicOCSPResponse = responseBytesSeq->At(1)->GetContentDER(); |
|
142 CleanupStack::PopAndDestroy(responseBytesSeq); |
|
143 |
|
144 pos = 0; |
|
145 CArrayPtr<TASN1DecGeneric>* basicOCSPResponseSeq = seqDec.DecodeDERLC(basicOCSPResponse, pos, 3, 4); |
|
146 TPtrC8 responseData = basicOCSPResponseSeq->At(0)->Encoding(); |
|
147 TPtrC8 signatureAlgorithm = basicOCSPResponseSeq->At(1)->Encoding(); |
|
148 TPtrC8 signature = basicOCSPResponseSeq->At(2)->GetContentDER(); |
|
149 CleanupStack::PopAndDestroy(basicOCSPResponseSeq); |
|
150 |
|
151 // Check that it's RSA with SHA1 |
|
152 CX509SigningAlgorithmIdentifier* algId = CX509SigningAlgorithmIdentifier::NewLC(signatureAlgorithm); |
|
153 if (algId->DigestAlgorithm().Algorithm() != ESHA1 |
|
154 || algId->AsymmetricAlgorithm().Algorithm() != ERSA) |
|
155 { |
|
156 User::Leave(KErrNotSupported); |
|
157 } |
|
158 CleanupStack::PopAndDestroy(algId); |
|
159 |
|
160 // Get the modulus and private key portions of the key - only RSA supported |
|
161 |
|
162 // ASN1 .key files have 9 parts: version, modulus, public exponent, private exponent, |
|
163 // prime 1, prime2, exponent 1, exponent 2, coefficient |
|
164 // This is defined in PKCS1 (RFC 2313), the RSAPrivateKey ASN1 data structure |
|
165 pos = 0; |
|
166 CArrayPtr<TASN1DecGeneric>* keySeq = seqDec.DecodeDERLC(aKey, pos, 9, 9); |
|
167 TASN1DecInteger decInt; |
|
168 |
|
169 RInteger modulus = decInt.DecodeDERLongL(*keySeq->At(1)); |
|
170 CleanupStack::PushL(modulus); |
|
171 |
|
172 RInteger publicExponent = decInt.DecodeDERLongL(*keySeq->At(2)); |
|
173 CleanupStack::PushL(publicExponent); |
|
174 |
|
175 RInteger privateExponent = decInt.DecodeDERLongL(*keySeq->At(3)); |
|
176 CleanupStack::PushL(privateExponent); |
|
177 |
|
178 // Cast constness off the signature - and skip the 'number of unused bits' octet |
|
179 TPtr8 sigEdit(CONST_CAST(TUint8*, signature.Ptr() + 1), signature.Length() - 1, signature.Length() - 1); |
|
180 |
|
181 // Pass data on for re-signing |
|
182 ResignL(responseData, sigEdit, modulus, publicExponent, privateExponent); |
|
183 |
|
184 CleanupStack::PopAndDestroy(3, &modulus); // The RIntegers |
|
185 CleanupStack::PopAndDestroy(keySeq); |
|
186 __UHEAP_MARKEND; |
|
187 } |
|
188 |
|
189 void CResign::ProcessCommandLineL() |
|
190 { |
|
191 iArguments = CCommandLineArguments::NewL(); |
|
192 |
|
193 if(iArguments->Count() > 1) |
|
194 { |
|
195 TCommand command = ENone; |
|
196 |
|
197 TPtrC args = iArguments->Arg(1); |
|
198 if ((args.Compare(KResign)==0) || (args.Compare(KResignShort)==0)) |
|
199 { |
|
200 command = EResign; |
|
201 } |
|
202 if ((args.Compare(KCreate)==0) || (args.Compare(KCreateShort)==0)) |
|
203 { |
|
204 command = ECreate; |
|
205 } |
|
206 if ((args.Compare(KExtractResponse)==0) || (args.Compare(KExtractResponseShort)==0)) |
|
207 { |
|
208 command = EExtract; |
|
209 } |
|
210 |
|
211 if(command != ENone) |
|
212 { |
|
213 HandleCommandL(command); |
|
214 } |
|
215 } |
|
216 } |
|
217 |
|
218 void CResign::HandleCommandL(TCommand aCommand) |
|
219 { |
|
220 switch(aCommand) |
|
221 { |
|
222 case EResign: |
|
223 ResignFilesL(); |
|
224 break; |
|
225 |
|
226 case ECreate: |
|
227 CreateDatFileL(); |
|
228 break; |
|
229 |
|
230 case EExtract: |
|
231 ExtractResponseL(); |
|
232 break; |
|
233 } |
|
234 } |
|
235 |
|
236 void CResign::ResignFilesL() |
|
237 { |
|
238 __UHEAP_MARK; |
|
239 |
|
240 TPtrC responseFile(iArguments->Arg(2)); |
|
241 TPtrC keyFile(iArguments->Arg(3)); |
|
242 |
|
243 // Load the key |
|
244 RFile file; |
|
245 User::LeaveIfError(file.Open(iFs, keyFile, EFileRead | EFileShareAny)); |
|
246 CleanupClosePushL(file); |
|
247 |
|
248 TInt keySize; |
|
249 User::LeaveIfError(file.Size(keySize)); |
|
250 HBufC8* keyBuf = HBufC8::NewLC(keySize); |
|
251 TPtr8 key = keyBuf->Des(); |
|
252 |
|
253 User::LeaveIfError(file.Read(key)); |
|
254 |
|
255 // Open the logged response file |
|
256 |
|
257 RFileReadStream readStream; |
|
258 User::LeaveIfError(readStream.Open(iFs, responseFile, EFileRead | EFileShareAny)); |
|
259 CleanupClosePushL(readStream); |
|
260 MStreamBuf* readBuf = readStream.Source(); |
|
261 |
|
262 RFileWriteStream writeStream; |
|
263 User::LeaveIfError(writeStream.Open(iFs, responseFile, EFileWrite | EFileShareAny)); |
|
264 CleanupClosePushL(writeStream); |
|
265 MStreamBuf* writeBuf = writeStream.Sink(); |
|
266 |
|
267 TInt totalResponses = readStream.ReadUint32L(); |
|
268 |
|
269 for (TInt i = 0 ; i < totalResponses ; ++i) |
|
270 { |
|
271 TInt responseSize = readStream.ReadUint32L(); |
|
272 TStreamPos pos = readBuf->TellL(MStreamBuf::ERead); |
|
273 |
|
274 HBufC8* responseBuf = HBufC8::NewLC(responseSize); |
|
275 |
|
276 TPtr8 response = responseBuf->Des(); |
|
277 readStream.ReadL(response); |
|
278 |
|
279 // resigning response |
|
280 DecodeDataL(response, key); |
|
281 |
|
282 writeBuf->SeekL(MStreamBuf::EWrite, pos); |
|
283 writeStream.WriteL(response); |
|
284 |
|
285 CleanupStack::PopAndDestroy(responseBuf); |
|
286 } |
|
287 |
|
288 CleanupStack::PopAndDestroy(4,&file); // close writeStream, readStream, keyBuf and file |
|
289 |
|
290 __UHEAP_MARKEND; |
|
291 } |
|
292 |
|
293 void CResign::CreateDatFileL() |
|
294 { |
|
295 __UHEAP_MARK; |
|
296 |
|
297 |
|
298 // this path will fail if the directories are not already present. |
|
299 _LIT(KDatFile,"c:\\system\\tocsp\\responses\\response.dat"); |
|
300 RFileWriteStream writeStream; |
|
301 User::LeaveIfError(writeStream.Replace(iFs, KDatFile, EFileWrite | EFileShareAny)); |
|
302 CleanupClosePushL(writeStream); |
|
303 |
|
304 TInt fileCount = iArguments->Count(); |
|
305 |
|
306 // total no of responses in this dat file |
|
307 writeStream.WriteInt32L(fileCount-2); |
|
308 RFile file; |
|
309 for(TInt i=2;i<fileCount;i++) |
|
310 { |
|
311 TPtrC responseFile(iArguments->Arg(i)); |
|
312 // Load the response file |
|
313 User::LeaveIfError(file.Open(iFs, responseFile, EFileRead | EFileShareAny)); |
|
314 CleanupClosePushL(file); |
|
315 |
|
316 TInt respSize = 0; |
|
317 User::LeaveIfError(file.Size(respSize)); |
|
318 HBufC8* respBuf = HBufC8::NewLC(respSize); |
|
319 TPtr8 resp = respBuf->Des(); |
|
320 User::LeaveIfError(file.Read(resp)); |
|
321 |
|
322 writeStream.WriteInt32L(respSize); |
|
323 writeStream.WriteL(resp); |
|
324 |
|
325 CleanupStack::PopAndDestroy(2,&file); // respBuf and file |
|
326 } |
|
327 |
|
328 CleanupStack::PopAndDestroy(&writeStream); |
|
329 |
|
330 __UHEAP_MARKEND; |
|
331 } |
|
332 |
|
333 void CResign::ExtractResponseL() |
|
334 { |
|
335 __UHEAP_MARK; |
|
336 |
|
337 TPtrC responseFile(iArguments->Arg(2)); |
|
338 |
|
339 // Load the response file |
|
340 RFileReadStream respFile; |
|
341 User::LeaveIfError(respFile.Open(iFs, responseFile, EFileRead | EFileShareAny)); |
|
342 CleanupClosePushL(respFile); |
|
343 |
|
344 // reading the transaction value. |
|
345 respFile.ReadInt32L(); |
|
346 TInt respSize = respFile.ReadInt32L(); |
|
347 |
|
348 HBufC8* respBuf = HBufC8::NewLC(respSize); |
|
349 TPtr8 resp = respBuf->Des(); |
|
350 |
|
351 respFile.ReadL(resp, respSize); |
|
352 |
|
353 // this path will fail if the directories are not already present. |
|
354 _LIT(KDerFile,"c:\\system\\tocsp\\responses\\response.der"); |
|
355 RFileWriteStream writeStream; |
|
356 User::LeaveIfError(writeStream.Replace(iFs, KDerFile, EFileWrite | EFileShareAny)); |
|
357 CleanupClosePushL(writeStream); |
|
358 writeStream.WriteL(resp); |
|
359 |
|
360 CleanupStack::PopAndDestroy(3,&respFile); // writeStream, respBuf and respFile |
|
361 |
|
362 __UHEAP_MARKEND; |
|
363 |
|
364 } |