|
1 /* |
|
2 Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. |
|
3 |
|
4 Redistribution and use in source and binary forms, with or without |
|
5 modification, are permitted provided that the following conditions are met: |
|
6 |
|
7 * Redistributions of source code must retain the above copyright notice, this |
|
8 list of conditions and the following disclaimer. |
|
9 * Redistributions in binary form must reproduce the above copyright notice, |
|
10 this list of conditions and the following disclaimer in the documentation |
|
11 and/or other materials provided with the distribution. |
|
12 * Neither the name of Nokia Corporation nor the names of its contributors |
|
13 may be used to endorse or promote products derived from this software |
|
14 without specific prior written permission. |
|
15 |
|
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
|
17 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
18 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
|
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE |
|
20 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
|
21 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
|
22 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
|
23 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
|
24 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
25 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
26 |
|
27 Description: |
|
28 */ |
|
29 |
|
30 |
|
31 #include "createx509.h" |
|
32 |
|
33 |
|
34 X509* CX509_Initializer::CreateX509(CX509Certificate* X509Cert) |
|
35 { |
|
36 X509* ret = X509_new(); |
|
37 TBool serail = ETrue; |
|
38 |
|
39 if(ret != NULL) |
|
40 { |
|
41 |
|
42 //validity |
|
43 X509_VAL_free(ret->cert_info->validity); |
|
44 ret->cert_info->validity = CreateX509_VAL(X509Cert); |
|
45 |
|
46 //issuer |
|
47 const CX500DistinguishedName& IssName = X509Cert->IssuerName(); |
|
48 X509_NAME_free(ret->cert_info->issuer); |
|
49 ret->cert_info->issuer = CreateX509_NAME(IssName); |
|
50 |
|
51 //subject |
|
52 const CX500DistinguishedName& SubName = X509Cert->SubjectName(); |
|
53 X509_NAME_free(ret->cert_info->subject); |
|
54 ret->cert_info->subject = CreateX509_NAME(SubName); |
|
55 // const HBufC * name = SubName.DisplayNameL(); |
|
56 |
|
57 //signature |
|
58 const TPtrC8* sig_alg_ptr = X509Cert->DataElementEncoding(CX509Certificate::EAlgorithmId); |
|
59 X509_ALGOR_free(ret->cert_info->signature); |
|
60 ret->cert_info->signature = CreateX509_ALGOR(sig_alg_ptr); |
|
61 |
|
62 //serialnumber |
|
63 const TPtrC8 sernum = X509Cert->SerialNumber(); |
|
64 ASN1_INTEGER_free(ret->cert_info->serialNumber); |
|
65 ret->cert_info->serialNumber = CreateASN1_STRING(sernum.Length(),V_ASN1_INTEGER,(unsigned char *)sernum.Ptr(),0); |
|
66 if((sernum.Length()== 1) && sernum[0]==0) |
|
67 serail = EFalse; |
|
68 |
|
69 //version |
|
70 |
|
71 TInt ver = X509Cert->Version(); |
|
72 unsigned char verVal = (unsigned char)(ver-1); |
|
73 ASN1_INTEGER_free(ret->cert_info->version); |
|
74 if( (verVal) || (!serail))// for X509 V1 certificates, version is null if any serial number present. |
|
75 ret->cert_info->version = CreateASN1_STRING(1,V_ASN1_INTEGER,&verVal,0); |
|
76 |
|
77 |
|
78 //issuerUID |
|
79 const TPtrC8* issUID_enc = X509Cert->DataElementEncoding(CX509Certificate::EIssuerUID); |
|
80 if(issUID_enc) |
|
81 ret->cert_info->issuerUID = CreateASN1_STRING(issUID_enc->Length(),V_ASN1_BIT_STRING,(unsigned char *)issUID_enc->Ptr(),0); |
|
82 |
|
83 |
|
84 //subjectUID |
|
85 const TPtrC8* subUID_enc = X509Cert->DataElementEncoding(CX509Certificate::ESubjectUID); |
|
86 if(subUID_enc) |
|
87 ret->cert_info->subjectUID = CreateASN1_STRING(subUID_enc->Length(),V_ASN1_BIT_STRING,(unsigned char *)subUID_enc->Ptr(),0); |
|
88 |
|
89 //key |
|
90 X509_PUBKEY_free(ret->cert_info->key); |
|
91 ret->cert_info->key = CreateX509_PUBKEY(X509Cert); |
|
92 |
|
93 |
|
94 //extension |
|
95 |
|
96 |
|
97 ret->cert_info->extensions = CreateSTACKOF_X509_EXTENSION(X509Cert); |
|
98 |
|
99 |
|
100 //name |
|
101 ret->name = X509_NAME_oneline(ret->cert_info->subject, NULL, 0); |
|
102 |
|
103 //sig_alg |
|
104 X509_ALGOR_free(ret->sig_alg); |
|
105 ret->sig_alg = CreateX509_ALGOR(sig_alg_ptr); |
|
106 |
|
107 //signature |
|
108 const TPtrC8 sig = X509Cert->Signature(); |
|
109 ASN1_STRING_free(ret->signature); |
|
110 ret->signature = CreateASN1_STRING(sig.Length(), V_ASN1_BIT_STRING, (unsigned char *)sig.Ptr(), ASN1_STRING_FLAG_BITS_LEFT); |
|
111 } |
|
112 |
|
113 return ret; |
|
114 } |
|
115 |
|
116 |
|
117 X509_ALGOR* CX509_Initializer::CreateX509_ALGOR(const TPtrC8* ptr) |
|
118 { |
|
119 X509_ALGOR* ret = X509_ALGOR_new(); |
|
120 |
|
121 TASN1DecGeneric dec((TDesC8 &)*ptr); |
|
122 dec.InitL(); |
|
123 |
|
124 TASN1DecSequence encSeq; |
|
125 CArrayPtrFlat<TASN1DecGeneric>* seq = encSeq.DecodeDERLC(dec); |
|
126 |
|
127 TASN1DecGeneric& AlgorEncSeq = *(seq->At(0)); |
|
128 |
|
129 if (dec.LengthDERContent() > AlgorEncSeq.LengthDER()) // can also check for (seq->Count() > 1) alternatively |
|
130 { |
|
131 // parameter part is present in the encoding. |
|
132 TASN1DecGeneric& ParameterEncSeq = *(seq->At(1)); |
|
133 |
|
134 // if param = 5, ie. ASN1 type NULL, then create a NULL ASN1 STRING |
|
135 ret->parameter = ASN1_TYPE_new(); |
|
136 ret->parameter->type = (TInt)ParameterEncSeq.Encoding()[0]; |
|
137 |
|
138 if(ret->parameter->type != V_ASN1_NULL) |
|
139 { |
|
140 // we have some parameter |
|
141 // add code to fill this stuff |
|
142 } |
|
143 } |
|
144 else |
|
145 { |
|
146 //encoding does not contain parameter at all |
|
147 //ret->parameter is anyway NULL when X509_ALGOR is created |
|
148 //Not sure if we need to create a NULL ASN1 string or just leave parameter = NULL |
|
149 } |
|
150 |
|
151 |
|
152 const TDesC8& algor_data = AlgorEncSeq.GetContentDER(); |
|
153 char * ch_algor_data = (char *)algor_data.Ptr(); |
|
154 |
|
155 ret->algorithm = ASN1_OBJECT_new(); |
|
156 ret->algorithm->length = AlgorEncSeq.LengthDERContent(); |
|
157 ret->algorithm->data = (unsigned char *)OPENSSL_malloc(ret->algorithm->length); |
|
158 if(ret->algorithm->data) |
|
159 memcpy(ret->algorithm->data, ch_algor_data, ret->algorithm->length); |
|
160 //else log error- cannot malloc |
|
161 |
|
162 ret->algorithm->flags |= ASN1_OBJECT_FLAG_DYNAMIC_DATA; // so that X509_ALGOR_free() frees all internally allocated data |
|
163 |
|
164 CleanupStack::PopAndDestroy(); //seq |
|
165 |
|
166 return ret; |
|
167 } |
|
168 |
|
169 |
|
170 |
|
171 X509_NAME* CX509_Initializer::CreateX509_NAME(const CX500DistinguishedName& DistName) |
|
172 { |
|
173 X509_NAME* ret = X509_NAME_new(); |
|
174 |
|
175 CASN1EncSequence * Asn1Seq = DistName.EncodeASN1LC(); |
|
176 |
|
177 HBufC8* octetData = HBufC8::NewMaxLC(5000); |
|
178 TPtr8 oct(octetData->Des()); |
|
179 oct.FillZ(); |
|
180 oct.SetLength(KMaxNameLength); |
|
181 TUint writePos = 0; |
|
182 Asn1Seq->WriteDERL(oct, writePos); |
|
183 |
|
184 TInt len = Fill_X509_NAME_ENTRY(ret, octetData->Des()); |
|
185 |
|
186 char *p = (char *)oct.PtrZ(); |
|
187 |
|
188 ret->bytes->data = (char *)OPENSSL_malloc(len); // no need to free this. BUF_MEM_free will free if not NULL |
|
189 if(ret->bytes->data) |
|
190 memcpy(ret->bytes->data, p, len); |
|
191 //else log error- cannot malloc |
|
192 |
|
193 ret->bytes->length = len; |
|
194 ret->bytes->max = len; |
|
195 |
|
196 ret->hash = 0; // for now filling zero. Not sure. |
|
197 |
|
198 CleanupStack::PopAndDestroy(2); // Asn1Seq, octetData |
|
199 |
|
200 return ret; |
|
201 } |
|
202 |
|
203 |
|
204 // return the length of the encoded sequence |
|
205 TInt CX509_Initializer::Fill_X509_NAME_ENTRY(X509_NAME * name, const TDesC8& aBinaryData) |
|
206 { |
|
207 TInt aPos = 0; |
|
208 TASN1DecGeneric dec(aBinaryData.Right(aBinaryData.Length() - aPos)); |
|
209 dec.InitL(); |
|
210 |
|
211 TInt end = aPos + dec.LengthDER(); |
|
212 aPos += dec.LengthDERHeader(); |
|
213 |
|
214 if (dec.Tag() != EASN1Sequence) |
|
215 { |
|
216 User::Leave(KErrArgument); |
|
217 } |
|
218 while (aPos < end) |
|
219 { |
|
220 TASN1DecGeneric rdn(aBinaryData.Right(aBinaryData.Length() - aPos)); |
|
221 rdn.InitL(); |
|
222 if (rdn.Tag() != EASN1Set) |
|
223 { |
|
224 User::Leave(KErrArgument); |
|
225 } |
|
226 TInt rdnEnd = rdn.LengthDER(); |
|
227 TInt rdnPos = rdn.LengthDERHeader();//add on header |
|
228 while (rdnPos < rdnEnd) |
|
229 { |
|
230 const TDesC8& TypeValEnc = rdn.Encoding(); |
|
231 |
|
232 TASN1DecGeneric dec(TypeValEnc.Right(TypeValEnc.Length() - rdnPos)); |
|
233 dec.InitL(); |
|
234 TInt tvend = rdnPos + dec.LengthDER(); |
|
235 rdnPos += dec.LengthDERHeader(); |
|
236 |
|
237 //first element must be the id |
|
238 TASN1DecObjectIdentifier encOID; |
|
239 //iType = encOID.DecodeDERL(TypeValEnc, rdnPos); |
|
240 TASN1DecGeneric first(TypeValEnc.Right(TypeValEnc.Length() - rdnPos)); |
|
241 first.InitL(); |
|
242 rdnPos += first.LengthDER(); |
|
243 if (first.Tag() != EASN1ObjectIdentifier) |
|
244 { |
|
245 User::Leave(KErrArgument); |
|
246 } |
|
247 |
|
248 const TDesC8& type = first.GetContentDER(); |
|
249 char * ch_type = (char *)type.Ptr(); |
|
250 |
|
251 //second is the data |
|
252 TASN1DecGeneric second(TypeValEnc.Right(TypeValEnc.Length() - rdnPos)); |
|
253 second.InitL(); |
|
254 rdnPos += second.LengthDER(); |
|
255 |
|
256 const TDesC8& value = second.GetContentDER(); |
|
257 char * ch_value = (char *)value.Ptr(); |
|
258 |
|
259 X509_NAME_ENTRY* new_entry = CreateX509_NAME_ENTRY(ch_type,first.LengthDERContent(), ch_value, second.LengthDERContent(), second.Tag()); |
|
260 |
|
261 X509_NAME_add_entry(name, new_entry, -1, 0); |
|
262 |
|
263 //we can free this, since add_entry makes a copy and adds |
|
264 X509_NAME_ENTRY_free(new_entry); |
|
265 // |
|
266 |
|
267 if (rdnPos != tvend) |
|
268 { |
|
269 User::Leave(KErrArgument); |
|
270 } |
|
271 |
|
272 } |
|
273 aPos += rdnEnd; |
|
274 } |
|
275 if (aPos != end) |
|
276 { |
|
277 User::Leave(KErrArgument); |
|
278 } |
|
279 return end; |
|
280 } |
|
281 |
|
282 |
|
283 X509_NAME_ENTRY * CX509_Initializer::CreateX509_NAME_ENTRY(char* type, int typeLen, char * value, int valueLen, int stringType) |
|
284 { |
|
285 X509_NAME_ENTRY * newEntry = X509_NAME_ENTRY_new(); |
|
286 |
|
287 newEntry->object->length = typeLen; |
|
288 newEntry->object->data = (unsigned char *)OPENSSL_malloc(typeLen); |
|
289 if(newEntry->object->data) |
|
290 memcpy(newEntry->object->data, type, typeLen); |
|
291 //else log error- cannot malloc |
|
292 |
|
293 ASN1_STRING_free(newEntry->value); |
|
294 newEntry->value = CreateASN1_STRING(valueLen, stringType, (unsigned char* )value, 0); |
|
295 |
|
296 newEntry->object->flags |= ASN1_OBJECT_FLAG_DYNAMIC_DATA; // so that X509_NAME_ENTRY_free() frees all internally allocated data |
|
297 |
|
298 return newEntry; |
|
299 |
|
300 } |
|
301 |
|
302 |
|
303 X509_VAL * CX509_Initializer::CreateX509_VAL(CX509Certificate* X509Cert) |
|
304 { |
|
305 X509_VAL * ret = X509_VAL_new(); |
|
306 |
|
307 const CValidityPeriod& val = X509Cert->ValidityPeriod(); |
|
308 |
|
309 TBuf8<KCertMaxBuffer> numBuffer8; |
|
310 char* numPtr = (char*)numBuffer8.PtrZ(); |
|
311 |
|
312 //start date (notBefore) |
|
313 TDateTime dt = val.Start().DateTime(); |
|
314 |
|
315 numBuffer8.AppendNum(dt.Year()); |
|
316 if(numBuffer8.Length() > 2) |
|
317 numBuffer8.Delete(0, numBuffer8.Length() - 2); |
|
318 |
|
319 _LIT8(KCertTimeStampFormat, "%02d%02d%02d%02d%02dZ"); |
|
320 numBuffer8.AppendFormat(KCertTimeStampFormat,dt.Month()+1,dt.Day()+1,dt.Hour(),dt.Minute(),dt.Second()); //Month and Day - offset from zero, so add 1 |
|
321 numPtr[13]='\0'; |
|
322 |
|
323 ASN1_STRING_free(ret->notBefore); |
|
324 ret->notBefore = CreateASN1_STRING(13,V_ASN1_UTCTIME,(unsigned char *)numPtr,0); |
|
325 |
|
326 //finish date (notAfter) |
|
327 dt = val.Finish().DateTime(); |
|
328 |
|
329 numBuffer8.Zero(); |
|
330 numBuffer8.AppendNum(dt.Year()); |
|
331 if(numBuffer8.Length() > 2) |
|
332 numBuffer8.Delete(0, numBuffer8.Length() - 2); |
|
333 |
|
334 numBuffer8.AppendFormat(KCertTimeStampFormat,dt.Month()+1,dt.Day()+1,dt.Hour(),dt.Minute(),dt.Second()); //Month and Day - offset from zero, so add 1 |
|
335 numPtr[13]='\0'; |
|
336 |
|
337 ASN1_STRING_free(ret->notAfter); |
|
338 ret->notAfter = CreateASN1_STRING(13,V_ASN1_UTCTIME,(unsigned char *)numPtr,0); |
|
339 |
|
340 return ret; |
|
341 |
|
342 } |
|
343 |
|
344 |
|
345 |
|
346 ASN1_STRING* CX509_Initializer::CreateASN1_STRING(int len, int type, unsigned char* data, long flags) |
|
347 { |
|
348 ASN1_STRING* ret = ASN1_STRING_new(); |
|
349 ret->length = len; |
|
350 ret->type = type; |
|
351 if(data!=NULL) |
|
352 { |
|
353 ret->data = (unsigned char *)OPENSSL_malloc(len); |
|
354 if(ret->data) |
|
355 memcpy(ret->data,data,len); |
|
356 //else log error- cannot malloc |
|
357 } |
|
358 else |
|
359 ret->data = NULL; |
|
360 |
|
361 ret->flags |= flags; |
|
362 return ret; |
|
363 } |
|
364 |
|
365 |
|
366 |
|
367 X509_PUBKEY* CX509_Initializer::CreateX509_PUBKEY(CX509Certificate* X509Cert) |
|
368 { |
|
369 X509_PUBKEY* ret = X509_PUBKEY_new(); |
|
370 |
|
371 //algor |
|
372 const TPtrC8* ptr = X509Cert->DataElementEncoding(CX509Certificate::ESubjectPublicKeyInfo); |
|
373 |
|
374 TInt aPos = 0; |
|
375 TASN1DecGeneric dec(ptr->Right(ptr->Length() - aPos)); |
|
376 dec.InitL(); |
|
377 |
|
378 TInt end = aPos + dec.LengthDER(); |
|
379 aPos += dec.LengthDERHeader(); |
|
380 |
|
381 if (dec.Tag() != EASN1Sequence) |
|
382 User::Leave(KErrArgument); |
|
383 |
|
384 if (aPos < end) |
|
385 { |
|
386 TASN1DecGeneric rdn(ptr->Right(ptr->Length() - aPos)); |
|
387 rdn.InitL(); |
|
388 TPtrC8 newPtr = rdn.Encoding(); |
|
389 |
|
390 X509_ALGOR_free(ret->algor); // free the one allocated by X509_PUBKEY_new |
|
391 ret->algor = CreateX509_ALGOR(&newPtr); |
|
392 } |
|
393 |
|
394 //public_key |
|
395 const CSubjectPublicKeyInfo& pubkey = X509Cert->PublicKey(); |
|
396 const TPtrC8 keyDat = pubkey.KeyData(); |
|
397 |
|
398 ASN1_BIT_STRING_free(ret->public_key); |
|
399 ret->public_key = CreateASN1_STRING(keyDat.Size(),V_ASN1_BIT_STRING,(unsigned char*)keyDat.Ptr(),0); |
|
400 |
|
401 //pkey |
|
402 ret->pkey = NULL; // we need not create this. Will be created later. Used to cache the computed data |
|
403 |
|
404 return ret; |
|
405 } |
|
406 |
|
407 |
|
408 |
|
409 |
|
410 STACK_OF(X509_EXTENSION)* CX509_Initializer::CreateSTACKOF_X509_EXTENSION(CX509Certificate* X509Cert) |
|
411 { |
|
412 //STACK_OF(X509_EXTENSION) * ret = sk_X509_EXTENSION_new_null(); |
|
413 STACK_OF(X509_EXTENSION) * ret = NULL; |
|
414 |
|
415 const TPtrC8* ptr = X509Cert->DataElementEncoding(CX509Certificate::EExtensionList); |
|
416 |
|
417 const CArrayPtrFlat<CX509CertExtension>& extlist = X509Cert->Extensions(); |
|
418 |
|
419 TASN1DecSequence encSeq; |
|
420 TInt pos = 0; |
|
421 |
|
422 if(ptr != NULL) //There is an extension list |
|
423 { |
|
424 TASN1DecGeneric dec((TDesC8 &)*ptr); |
|
425 ret = sk_X509_EXTENSION_new_null(); |
|
426 dec.InitL(); |
|
427 |
|
428 CArrayPtrFlat<TASN1DecGeneric>* seq = encSeq.DecodeDERLC( dec.GetContentDER(), pos); |
|
429 |
|
430 TInt count = seq->Count(); // no of extensions in the ext list |
|
431 for (TInt i = 0; i < count; i++) |
|
432 { |
|
433 |
|
434 X509_EXTENSION* ext = X509_EXTENSION_new(); |
|
435 |
|
436 ext->object = ASN1_OBJECT_new(); |
|
437 |
|
438 TASN1DecGeneric* gen = seq->At(i); |
|
439 TASN1DecGeneric oid(seq->At(i)->GetContentDER()); |
|
440 oid.InitL(); |
|
441 |
|
442 const TDesC8& ext_obj_data = oid.GetContentDER(); |
|
443 char * ch_ext_obj_data = (char *)ext_obj_data.Ptr(); |
|
444 |
|
445 ext->object->length = oid.LengthDERContent(); |
|
446 ext->object->data = (unsigned char *)OPENSSL_malloc(ext->object->length); |
|
447 if(ext->object->data) |
|
448 memcpy(ext->object->data, ch_ext_obj_data, ext->object->length); |
|
449 //else log error- cannot malloc |
|
450 |
|
451 ext->object->flags |= ASN1_OBJECT_FLAG_DYNAMIC_DATA; // so that X509_free() frees all internally allocated data |
|
452 |
|
453 if(extlist.At(i)->Critical()) |
|
454 ext->critical = extlist.At(i)->Critical(); |
|
455 |
|
456 const TPtrC8 data = extlist.At(i)->Data(); |
|
457 TASN1DecGeneric value(data); |
|
458 value.InitL(); |
|
459 |
|
460 const TDesC8& ext_value = value.GetContentDER(); |
|
461 char * ch_ext_value = (char *)ext_value.Ptr(); |
|
462 ASN1_STRING_free(ext->value); |
|
463 ext->value = CreateASN1_STRING(value.LengthDERContent(), V_ASN1_OCTET_STRING, (unsigned char *)ch_ext_value, 0); |
|
464 |
|
465 sk_X509_EXTENSION_push(ret,ext); |
|
466 |
|
467 } |
|
468 |
|
469 CleanupStack::PopAndDestroy();// seq |
|
470 } |
|
471 |
|
472 return ret; |
|
473 } |
|
474 |