sl@0: /* sl@0: Copyright (c) 2009-2010 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. sl@0: sl@0: Redistribution and use in source and binary forms, with or without sl@0: modification, are permitted provided that the following conditions are met: sl@0: sl@0: * Redistributions of source code must retain the above copyright notice, this sl@0: list of conditions and the following disclaimer. sl@0: * Redistributions in binary form must reproduce the above copyright notice, sl@0: this list of conditions and the following disclaimer in the documentation sl@0: and/or other materials provided with the distribution. sl@0: * Neither the name of Nokia Corporation nor the names of its contributors sl@0: may be used to endorse or promote products derived from this software sl@0: without specific prior written permission. sl@0: sl@0: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" sl@0: AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE sl@0: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE sl@0: DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE sl@0: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL sl@0: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR sl@0: SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER sl@0: CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, sl@0: OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE sl@0: OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. sl@0: sl@0: Description: sl@0: */ sl@0: sl@0: sl@0: #include "createx509.h" sl@0: sl@0: sl@0: X509* CX509_Initializer::CreateX509L(CX509Certificate* X509Cert) sl@0: { sl@0: X509* ret = X509_new(); sl@0: TBool serail = ETrue; sl@0: sl@0: if(ret != NULL) sl@0: { sl@0: sl@0: //validity sl@0: X509_VAL_free(ret->cert_info->validity); sl@0: ret->cert_info->validity = CreateX509_VAL(X509Cert); sl@0: sl@0: //issuer sl@0: const CX500DistinguishedName& IssName = X509Cert->IssuerName(); sl@0: X509_NAME_free(ret->cert_info->issuer); sl@0: ret->cert_info->issuer = CreateX509_NAMEL(IssName); sl@0: sl@0: //subject sl@0: const CX500DistinguishedName& SubName = X509Cert->SubjectName(); sl@0: X509_NAME_free(ret->cert_info->subject); sl@0: ret->cert_info->subject = CreateX509_NAMEL(SubName); sl@0: // const HBufC * name = SubName.DisplayNameL(); sl@0: sl@0: //signature sl@0: const TPtrC8* sig_alg_ptr = X509Cert->DataElementEncoding(CX509Certificate::EAlgorithmId); sl@0: X509_ALGOR_free(ret->cert_info->signature); sl@0: ret->cert_info->signature = CreateX509_ALGORL(sig_alg_ptr); sl@0: sl@0: //serialnumber sl@0: const TPtrC8 sernum = X509Cert->SerialNumber(); sl@0: ASN1_INTEGER_free(ret->cert_info->serialNumber); sl@0: ret->cert_info->serialNumber = CreateASN1_STRING(sernum.Length(),V_ASN1_INTEGER,(unsigned char *)sernum.Ptr(),0); sl@0: if((sernum.Length()== 1) && sernum[0]==0) sl@0: serail = EFalse; sl@0: sl@0: //version sl@0: sl@0: TInt ver = X509Cert->Version(); sl@0: unsigned char verVal = (unsigned char)(ver-1); sl@0: ASN1_INTEGER_free(ret->cert_info->version); sl@0: if( (verVal) || (!serail))// for X509 V1 certificates, version is null if any serial number present. sl@0: ret->cert_info->version = CreateASN1_STRING(1,V_ASN1_INTEGER,&verVal,0); sl@0: sl@0: sl@0: //issuerUID sl@0: const TPtrC8* issUID_enc = X509Cert->DataElementEncoding(CX509Certificate::EIssuerUID); sl@0: if(issUID_enc) sl@0: ret->cert_info->issuerUID = CreateASN1_STRING(issUID_enc->Length(),V_ASN1_BIT_STRING,(unsigned char *)issUID_enc->Ptr(),0); sl@0: sl@0: sl@0: //subjectUID sl@0: const TPtrC8* subUID_enc = X509Cert->DataElementEncoding(CX509Certificate::ESubjectUID); sl@0: if(subUID_enc) sl@0: ret->cert_info->subjectUID = CreateASN1_STRING(subUID_enc->Length(),V_ASN1_BIT_STRING,(unsigned char *)subUID_enc->Ptr(),0); sl@0: sl@0: //key sl@0: X509_PUBKEY_free(ret->cert_info->key); sl@0: ret->cert_info->key = CreateX509_PUBKEYL(X509Cert); sl@0: sl@0: sl@0: //extension sl@0: sl@0: sl@0: ret->cert_info->extensions = CreateSTACKOF_X509_EXTENSIONL(X509Cert); sl@0: sl@0: sl@0: //name sl@0: ret->name = X509_NAME_oneline(ret->cert_info->subject, NULL, 0); sl@0: sl@0: //sig_alg sl@0: X509_ALGOR_free(ret->sig_alg); sl@0: ret->sig_alg = CreateX509_ALGORL(sig_alg_ptr); sl@0: sl@0: //signature sl@0: const TPtrC8 sig = X509Cert->Signature(); sl@0: ASN1_STRING_free(ret->signature); sl@0: ret->signature = CreateASN1_STRING(sig.Length(), V_ASN1_BIT_STRING, (unsigned char *)sig.Ptr(), ASN1_STRING_FLAG_BITS_LEFT); sl@0: } sl@0: sl@0: return ret; sl@0: } sl@0: sl@0: sl@0: X509_ALGOR* CX509_Initializer::CreateX509_ALGORL(const TPtrC8* ptr) sl@0: { sl@0: X509_ALGOR* ret = X509_ALGOR_new(); sl@0: sl@0: TASN1DecGeneric dec((TDesC8 &)*ptr); sl@0: dec.InitL(); sl@0: sl@0: TASN1DecSequence encSeq; sl@0: CArrayPtrFlat* seq = encSeq.DecodeDERLC(dec); sl@0: sl@0: TASN1DecGeneric& AlgorEncSeq = *(seq->At(0)); sl@0: sl@0: if (dec.LengthDERContent() > AlgorEncSeq.LengthDER()) // can also check for (seq->Count() > 1) alternatively sl@0: { sl@0: // parameter part is present in the encoding. sl@0: TASN1DecGeneric& ParameterEncSeq = *(seq->At(1)); sl@0: sl@0: // if param = 5, ie. ASN1 type NULL, then create a NULL ASN1 STRING sl@0: ret->parameter = ASN1_TYPE_new(); sl@0: ret->parameter->type = (TInt)ParameterEncSeq.Encoding()[0]; sl@0: sl@0: if(ret->parameter->type != V_ASN1_NULL) sl@0: { sl@0: // we have some parameter sl@0: // add code to fill this stuff sl@0: } sl@0: } sl@0: else sl@0: { sl@0: //encoding does not contain parameter at all sl@0: //ret->parameter is anyway NULL when X509_ALGOR is created sl@0: //Not sure if we need to create a NULL ASN1 string or just leave parameter = NULL sl@0: } sl@0: sl@0: sl@0: const TDesC8& algor_data = AlgorEncSeq.GetContentDER(); sl@0: char * ch_algor_data = (char *)algor_data.Ptr(); sl@0: sl@0: ret->algorithm = ASN1_OBJECT_new(); sl@0: ret->algorithm->length = AlgorEncSeq.LengthDERContent(); sl@0: ret->algorithm->data = (unsigned char *)OPENSSL_malloc(ret->algorithm->length); sl@0: if(ret->algorithm->data) sl@0: memcpy(ret->algorithm->data, ch_algor_data, ret->algorithm->length); sl@0: //else log error- cannot malloc sl@0: sl@0: ret->algorithm->flags |= ASN1_OBJECT_FLAG_DYNAMIC_DATA; // so that X509_ALGOR_free() frees all internally allocated data sl@0: sl@0: CleanupStack::PopAndDestroy(); //seq sl@0: sl@0: return ret; sl@0: } sl@0: sl@0: sl@0: sl@0: X509_NAME* CX509_Initializer::CreateX509_NAMEL(const CX500DistinguishedName& DistName) sl@0: { sl@0: X509_NAME* ret = X509_NAME_new(); sl@0: sl@0: CASN1EncSequence * Asn1Seq = DistName.EncodeASN1LC(); sl@0: sl@0: HBufC8* octetData = HBufC8::NewMaxLC(5000); sl@0: TPtr8 oct(octetData->Des()); sl@0: oct.FillZ(); sl@0: oct.SetLength(KMaxNameLength); sl@0: TUint writePos = 0; sl@0: Asn1Seq->WriteDERL(oct, writePos); sl@0: sl@0: TInt len = Fill_X509_NAME_ENTRYL(ret, octetData->Des()); sl@0: sl@0: char *p = (char *)oct.PtrZ(); sl@0: sl@0: ret->bytes->data = (char *)OPENSSL_malloc(len); // no need to free this. BUF_MEM_free will free if not NULL sl@0: if(ret->bytes->data) sl@0: memcpy(ret->bytes->data, p, len); sl@0: //else log error- cannot malloc sl@0: sl@0: ret->bytes->length = len; sl@0: ret->bytes->max = len; sl@0: sl@0: ret->hash = 0; // for now filling zero. Not sure. sl@0: sl@0: CleanupStack::PopAndDestroy(2); // Asn1Seq, octetData sl@0: sl@0: return ret; sl@0: } sl@0: sl@0: sl@0: // return the length of the encoded sequence sl@0: TInt CX509_Initializer::Fill_X509_NAME_ENTRYL(X509_NAME * name, const TDesC8& aBinaryData) sl@0: { sl@0: TInt aPos = 0; sl@0: TASN1DecGeneric dec(aBinaryData.Right(aBinaryData.Length() - aPos)); sl@0: dec.InitL(); sl@0: sl@0: TInt end = aPos + dec.LengthDER(); sl@0: aPos += dec.LengthDERHeader(); sl@0: sl@0: if (dec.Tag() != EASN1Sequence) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: while (aPos < end) sl@0: { sl@0: TASN1DecGeneric rdn(aBinaryData.Right(aBinaryData.Length() - aPos)); sl@0: rdn.InitL(); sl@0: if (rdn.Tag() != EASN1Set) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: TInt rdnEnd = rdn.LengthDER(); sl@0: TInt rdnPos = rdn.LengthDERHeader();//add on header sl@0: while (rdnPos < rdnEnd) sl@0: { sl@0: const TDesC8& TypeValEnc = rdn.Encoding(); sl@0: sl@0: TASN1DecGeneric dec(TypeValEnc.Right(TypeValEnc.Length() - rdnPos)); sl@0: dec.InitL(); sl@0: TInt tvend = rdnPos + dec.LengthDER(); sl@0: rdnPos += dec.LengthDERHeader(); sl@0: sl@0: //first element must be the id sl@0: TASN1DecObjectIdentifier encOID; sl@0: //iType = encOID.DecodeDERL(TypeValEnc, rdnPos); sl@0: TASN1DecGeneric first(TypeValEnc.Right(TypeValEnc.Length() - rdnPos)); sl@0: first.InitL(); sl@0: rdnPos += first.LengthDER(); sl@0: if (first.Tag() != EASN1ObjectIdentifier) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: sl@0: const TDesC8& type = first.GetContentDER(); sl@0: char * ch_type = (char *)type.Ptr(); sl@0: sl@0: //second is the data sl@0: TASN1DecGeneric second(TypeValEnc.Right(TypeValEnc.Length() - rdnPos)); sl@0: second.InitL(); sl@0: rdnPos += second.LengthDER(); sl@0: sl@0: const TDesC8& value = second.GetContentDER(); sl@0: char * ch_value = (char *)value.Ptr(); sl@0: sl@0: X509_NAME_ENTRY* new_entry = CreateX509_NAME_ENTRY(ch_type,first.LengthDERContent(), ch_value, second.LengthDERContent(), second.Tag()); sl@0: sl@0: X509_NAME_add_entry(name, new_entry, -1, 0); sl@0: sl@0: //we can free this, since add_entry makes a copy and adds sl@0: X509_NAME_ENTRY_free(new_entry); sl@0: // sl@0: sl@0: if (rdnPos != tvend) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: sl@0: } sl@0: aPos += rdnEnd; sl@0: } sl@0: if (aPos != end) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: return end; sl@0: } sl@0: sl@0: sl@0: X509_NAME_ENTRY * CX509_Initializer::CreateX509_NAME_ENTRY(char* type, int typeLen, char * value, int valueLen, int stringType) sl@0: { sl@0: X509_NAME_ENTRY * newEntry = X509_NAME_ENTRY_new(); sl@0: sl@0: newEntry->object->length = typeLen; sl@0: newEntry->object->data = (unsigned char *)OPENSSL_malloc(typeLen); sl@0: if(newEntry->object->data) sl@0: memcpy(newEntry->object->data, type, typeLen); sl@0: //else log error- cannot malloc sl@0: sl@0: ASN1_STRING_free(newEntry->value); sl@0: newEntry->value = CreateASN1_STRING(valueLen, stringType, (unsigned char* )value, 0); sl@0: sl@0: newEntry->object->flags |= ASN1_OBJECT_FLAG_DYNAMIC_DATA; // so that X509_NAME_ENTRY_free() frees all internally allocated data sl@0: sl@0: return newEntry; sl@0: sl@0: } sl@0: sl@0: sl@0: X509_VAL * CX509_Initializer::CreateX509_VAL(CX509Certificate* X509Cert) sl@0: { sl@0: X509_VAL * ret = X509_VAL_new(); sl@0: sl@0: const CValidityPeriod& val = X509Cert->ValidityPeriod(); sl@0: sl@0: TBuf8 numBuffer8; sl@0: char* numPtr = (char*)numBuffer8.PtrZ(); sl@0: sl@0: //start date (notBefore) sl@0: TDateTime dt = val.Start().DateTime(); sl@0: sl@0: numBuffer8.AppendNum(dt.Year()); sl@0: if(numBuffer8.Length() > 2) sl@0: numBuffer8.Delete(0, numBuffer8.Length() - 2); sl@0: sl@0: _LIT8(KCertTimeStampFormat, "%02d%02d%02d%02d%02dZ"); sl@0: numBuffer8.AppendFormat(KCertTimeStampFormat,dt.Month()+1,dt.Day()+1,dt.Hour(),dt.Minute(),dt.Second()); //Month and Day - offset from zero, so add 1 sl@0: numPtr[13]='\0'; sl@0: sl@0: ASN1_STRING_free(ret->notBefore); sl@0: ret->notBefore = CreateASN1_STRING(13,V_ASN1_UTCTIME,(unsigned char *)numPtr,0); sl@0: sl@0: //finish date (notAfter) sl@0: dt = val.Finish().DateTime(); sl@0: sl@0: numBuffer8.Zero(); sl@0: numBuffer8.AppendNum(dt.Year()); sl@0: if(numBuffer8.Length() > 2) sl@0: numBuffer8.Delete(0, numBuffer8.Length() - 2); sl@0: sl@0: numBuffer8.AppendFormat(KCertTimeStampFormat,dt.Month()+1,dt.Day()+1,dt.Hour(),dt.Minute(),dt.Second()); //Month and Day - offset from zero, so add 1 sl@0: numPtr[13]='\0'; sl@0: sl@0: ASN1_STRING_free(ret->notAfter); sl@0: ret->notAfter = CreateASN1_STRING(13,V_ASN1_UTCTIME,(unsigned char *)numPtr,0); sl@0: sl@0: return ret; sl@0: sl@0: } sl@0: sl@0: sl@0: sl@0: ASN1_STRING* CX509_Initializer::CreateASN1_STRING(int len, int type, unsigned char* data, long flags) sl@0: { sl@0: ASN1_STRING* ret = ASN1_STRING_new(); sl@0: ret->length = len; sl@0: ret->type = type; sl@0: if(data!=NULL) sl@0: { sl@0: ret->data = (unsigned char *)OPENSSL_malloc(len); sl@0: if(ret->data) sl@0: memcpy(ret->data,data,len); sl@0: //else log error- cannot malloc sl@0: } sl@0: else sl@0: ret->data = NULL; sl@0: sl@0: ret->flags |= flags; sl@0: return ret; sl@0: } sl@0: sl@0: sl@0: sl@0: X509_PUBKEY* CX509_Initializer::CreateX509_PUBKEYL(CX509Certificate* X509Cert) sl@0: { sl@0: X509_PUBKEY* ret = X509_PUBKEY_new(); sl@0: sl@0: //algor sl@0: const TPtrC8* ptr = X509Cert->DataElementEncoding(CX509Certificate::ESubjectPublicKeyInfo); sl@0: sl@0: TInt aPos = 0; sl@0: TASN1DecGeneric dec(ptr->Right(ptr->Length() - aPos)); sl@0: dec.InitL(); sl@0: sl@0: TInt end = aPos + dec.LengthDER(); sl@0: aPos += dec.LengthDERHeader(); sl@0: sl@0: if (dec.Tag() != EASN1Sequence) sl@0: User::Leave(KErrArgument); sl@0: sl@0: if (aPos < end) sl@0: { sl@0: TASN1DecGeneric rdn(ptr->Right(ptr->Length() - aPos)); sl@0: rdn.InitL(); sl@0: TPtrC8 newPtr = rdn.Encoding(); sl@0: sl@0: X509_ALGOR_free(ret->algor); // free the one allocated by X509_PUBKEY_new sl@0: ret->algor = CreateX509_ALGORL(&newPtr); sl@0: } sl@0: sl@0: //public_key sl@0: const CSubjectPublicKeyInfo& pubkey = X509Cert->PublicKey(); sl@0: const TPtrC8 keyDat = pubkey.KeyData(); sl@0: sl@0: ASN1_BIT_STRING_free(ret->public_key); sl@0: ret->public_key = CreateASN1_STRING(keyDat.Size(),V_ASN1_BIT_STRING,(unsigned char*)keyDat.Ptr(),0); sl@0: sl@0: //pkey sl@0: ret->pkey = NULL; // we need not create this. Will be created later. Used to cache the computed data sl@0: sl@0: return ret; sl@0: } sl@0: sl@0: sl@0: sl@0: sl@0: STACK_OF(X509_EXTENSION)* CX509_Initializer::CreateSTACKOF_X509_EXTENSIONL(CX509Certificate* X509Cert) sl@0: { sl@0: //STACK_OF(X509_EXTENSION) * ret = sk_X509_EXTENSION_new_null(); sl@0: STACK_OF(X509_EXTENSION) * ret = NULL; sl@0: sl@0: const TPtrC8* ptr = X509Cert->DataElementEncoding(CX509Certificate::EExtensionList); sl@0: sl@0: const CArrayPtrFlat& extlist = X509Cert->Extensions(); sl@0: sl@0: TASN1DecSequence encSeq; sl@0: TInt pos = 0; sl@0: sl@0: if(ptr != NULL) //There is an extension list sl@0: { sl@0: TASN1DecGeneric dec((TDesC8 &)*ptr); sl@0: ret = sk_X509_EXTENSION_new_null(); sl@0: dec.InitL(); sl@0: sl@0: CArrayPtrFlat* seq = encSeq.DecodeDERLC( dec.GetContentDER(), pos); sl@0: sl@0: TInt count = seq->Count(); // no of extensions in the ext list sl@0: for (TInt i = 0; i < count; i++) sl@0: { sl@0: sl@0: X509_EXTENSION* ext = X509_EXTENSION_new(); sl@0: sl@0: ext->object = ASN1_OBJECT_new(); sl@0: sl@0: TASN1DecGeneric* gen = seq->At(i); sl@0: TASN1DecGeneric oid(seq->At(i)->GetContentDER()); sl@0: oid.InitL(); sl@0: sl@0: const TDesC8& ext_obj_data = oid.GetContentDER(); sl@0: char * ch_ext_obj_data = (char *)ext_obj_data.Ptr(); sl@0: sl@0: ext->object->length = oid.LengthDERContent(); sl@0: ext->object->data = (unsigned char *)OPENSSL_malloc(ext->object->length); sl@0: if(ext->object->data) sl@0: memcpy(ext->object->data, ch_ext_obj_data, ext->object->length); sl@0: //else log error- cannot malloc sl@0: sl@0: ext->object->flags |= ASN1_OBJECT_FLAG_DYNAMIC_DATA; // so that X509_free() frees all internally allocated data sl@0: sl@0: if(extlist.At(i)->Critical()) sl@0: ext->critical = extlist.At(i)->Critical(); sl@0: sl@0: const TPtrC8 data = extlist.At(i)->Data(); sl@0: TASN1DecGeneric value(data); sl@0: value.InitL(); sl@0: sl@0: const TDesC8& ext_value = value.GetContentDER(); sl@0: char * ch_ext_value = (char *)ext_value.Ptr(); sl@0: ASN1_STRING_free(ext->value); sl@0: ext->value = CreateASN1_STRING(value.LengthDERContent(), V_ASN1_OCTET_STRING, (unsigned char *)ch_ext_value, 0); sl@0: sl@0: sk_X509_EXTENSION_push(ret,ext); sl@0: sl@0: } sl@0: sl@0: CleanupStack::PopAndDestroy();// seq sl@0: } sl@0: sl@0: return ret; sl@0: } sl@0: