pkiutilities/x509certnameparser/src/X509CertNameParser.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 26 Jan 2010 15:20:08 +0200
changeset 0 164170e6151a
permissions -rw-r--r--
Revision: 201004

/*
* Copyright (c) 2002 Nokia Corporation and/or its subsidiary(-ies). 
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:   Extracts relevant certificate information to be shown to user.
*
*/


// INCLUDE FILES
#include "X509CertNameParser.h"
#include <x509cert.h>       //X509Certificate
#include <x500dn.h>         // CX500DistinguishedName
#include <pkixcertchain.h>  // OIDS for the extensions
#include <escapeutils.h>    // for escape decoding

// CONSTANTS
_LIT (KX509CertParserSpace, " ");

// Max length of array in case of PrimaryAndSecondaryNameL.
const TInt KX509CNPPrimAndSecondNameLengh( 3 ); 

// ============================ MEMBER FUNCTIONS =============================== 
                                                                                                                                                               
// -----------------------------------------------------------------------------
// X509CertNameParser::PrimaryAndSecondaryNameL
//
// -----------------------------------------------------------------------------
EXPORT_C TInt X509CertNameParser::PrimaryAndSecondaryNameL( 
                                      const CX509Certificate& aCertificate,
                                      HBufC*& aPrimaryName, 
                                      HBufC*& aSecondaryName,
                                      const TDesC& aLabel)
    {
    // Get subjectname
    const CX500DistinguishedName& dName = aCertificate.SubjectName();
    // Get subject alternative name
    const CX509CertExtension* extension = 
        aCertificate.Extension( KSubjectAltName );

    CDesCArrayFlat* nameArray = new( ELeave ) CDesCArrayFlat(3);
    CleanupStack::PushL( nameArray );
    // Append label to array
    nameArray->AppendL( aLabel );
    
    // Get PrimaryName and SecondaryName to nameArray if they exists.
    GetNamePartsL( dName, extension, *nameArray, EX509CNPPrimAndSecond );
    
    // Make sure that these are NULL
    aPrimaryName = NULL;
    aSecondaryName = NULL;

    switch ( nameArray->MdcaCount() )
        {
        case 1: //Neither PrimaryName nor SecondaryName found
            {
            aPrimaryName = HBufC::NewLC( KNullDesC.iTypeLength );
            *aPrimaryName = KNullDesC;
            aSecondaryName = HBufC::NewLC( KNullDesC.iTypeLength );
            *aSecondaryName = KNullDesC;
            break;
            }
        case 2: // Only PrimaryName found
            {
            aPrimaryName = HBufC::NewLC(( *nameArray)[1].Length() );
            *aPrimaryName = ( *nameArray )[1];
            aSecondaryName = HBufC::NewLC( KNullDesC.iTypeLength );
            *aSecondaryName = KNullDesC;
            break;
            }
        case 3: // Both found
            {
            aPrimaryName = HBufC::NewLC(( *nameArray)[1].Length() );
            *aPrimaryName = ( *nameArray )[1];
            aSecondaryName = HBufC::NewLC( ( *nameArray )[2].Length() );
            *aSecondaryName = ( *nameArray )[2];
            break;
            }
        default: // Something went wrong.
            {
            aPrimaryName = HBufC::NewLC( KNullDesC.iTypeLength );
            *aPrimaryName = KNullDesC;
            aSecondaryName = HBufC::NewLC( KNullDesC.iTypeLength );
            *aSecondaryName = KNullDesC;
            break;
            }
        }

    if ( aSecondaryName )
        {
        CleanupStack::Pop( aSecondaryName ); // aSecondaryName
        }
    if ( aPrimaryName )
        {
        CleanupStack::Pop( aPrimaryName ); // aPrimaryName
        }
    CleanupStack::PopAndDestroy( nameArray ); //  nameArray
    return KErrNone;
    }

// -----------------------------------------------------------------------------
// X509CertNameParser::SubjectFullNameL
// 
// -----------------------------------------------------------------------------

EXPORT_C TInt X509CertNameParser::SubjectFullNameL(
                                      const CX509Certificate& aCertificate,
                                      HBufC*& aSubjectName,
									  const TDesC& aLabel )
    {
    // Get subjectname
    const CX500DistinguishedName& dName = aCertificate.SubjectName();
    // Get subject alternative name
    const CX509CertExtension* extension = 
        aCertificate.Extension( KSubjectAltName );
    
    return GetFullNameL( dName, extension, aSubjectName, aLabel );
    }

// -----------------------------------------------------------------------------
// X509CertNameParser::IssuerFullNameL
//  
// -----------------------------------------------------------------------------
                                                                                
EXPORT_C TInt X509CertNameParser::IssuerFullNameL( 
                                      const CX509Certificate& aCertificate,
                                      HBufC*& aIssuerName )
    {
    // Get issuerName
    const CX500DistinguishedName& dName = aCertificate.IssuerName();
    // Get issuer alternative name
    const CX509CertExtension* extension = 
        aCertificate.Extension( KIssuerAltName );

    return GetFullNameL( dName, extension, aIssuerName );
    }

// -----------------------------------------------------------------------------
// X509CertNameParser::GetFullNameL
// 
// -----------------------------------------------------------------------------
TInt X509CertNameParser::GetFullNameL( 
                              const CX500DistinguishedName& aDN, 
                              const CX509CertExtension* aExtension,
                              HBufC*& aName,
                              const TDesC& aLabel )
    {
    CDesCArrayFlat* nameArray = new( ELeave ) CDesCArrayFlat(3);
    CleanupStack::PushL( nameArray );
    // Add label to array. It is used for comparing.
    nameArray->AppendL( aLabel );

    // Collect name parts to array
    GetNamePartsL( aDN, aExtension, *nameArray, EX509CNPFullName);
    
    // Count length of the aName.
    TInt length = 0;
    TInt i = 1; // Pass label
    for ( ; i < nameArray->MdcaCount(); i++ )
        { 
        length += (*nameArray)[i].Length();
        length += KX509CNPComma.iTypeLength;
        }
    
    // Add elements of the array to aName.
    // First element is label, so it is passed.
    aName = HBufC::NewLC( length );
    for ( i = 1; i < nameArray->MdcaCount(); i++ )
        {
        if ( i != 1 )
            {
            aName->Des().Append( KX509CNPComma );
            }
        aName->Des().Append( (*nameArray)[i] );   
        }

    CleanupStack::Pop( aName ); 
    CleanupStack::PopAndDestroy( nameArray ); 

    return KErrNone;
    }

// -----------------------------------------------------------------------------
// X509CertNameParser::GetNamePartsL
// 
// -----------------------------------------------------------------------------

TInt X509CertNameParser::GetNamePartsL( 
                             const CX500DistinguishedName& aDN, 
                             const CX509CertExtension* aExtension, 
                             CDesCArray& aNameArray, 
                             TX509CNPNameType aNameType)
    {
    const CX509AltNameExt* altNameExt = NULL;
    
    if (aExtension)
        {
        altNameExt = CX509AltNameExt::NewLC( aExtension->Data() ); 
        }

    TBool notFound = ETrue; 
    
    // In case of PrimaryAndSecondaryName loop goes through name elements
    // until two of them is found.
    // In case of FullNames loop goes through all supported name element and
    // adds founded names to array.
    for( TInt round = 1; notFound; round++ )
        {
        switch( round )
            {
            case EDNCommonName:
                {
                GetDNPartL( aDN, KX520CommonName, aNameArray );
                break;
                }
            case ECritAltRFC822Name:
                {
                if (aExtension && aExtension->Critical())
                    {
                    GetAltNamePartL( *altNameExt, EX509RFC822Name, aNameArray );
                    }
                break;
                }
            case EDNOrganizationName:
                {
                GetDNPartL( aDN, KX520OrganizationName, aNameArray);    
                break;  
                }
            case EDNOrganizationalUnitName:
                {
                if ( aNameType == EX509CNPPrimAndSecond )
                    {
                    GetDNPartL( aDN, KX520OrganizationalUnitName, aNameArray);    
                    }
                else
                    {
                    GetDNPartAllL( aDN, KX520OrganizationalUnitName, aNameArray);    
                    }
                break;
                }
            case ECritAltURI:
                {
                if (aExtension && aExtension->Critical())
                    {
                    GetAltNamePartL( *altNameExt, EX509URI, aNameArray );
                    }
                break;
                }
            case ECritAltDNSName:
                {
                if (aExtension && aExtension->Critical())
                    {
                    GetAltNamePartL( *altNameExt, EX509DNSName, aNameArray);
                    }
                break;
                }
            case ECritAltDirectoryName:
                {
                if (aExtension && aExtension->Critical())
                    {
                    GetAltNamePartL( *altNameExt, EX509DirectoryName, 
                                     aNameArray );                                   
                    }
                break;
                }
            case ECritAltIPAddress:
                {
                if (aExtension && aExtension->Critical())
                    {
                    GetAltNamePartL( *altNameExt, EX509IPAddress, 
                                     aNameArray );                                   
                    }
                break;
                } 
            case EAltRFC822Name:
                {
                if (aExtension)
                    {
                    GetAltNamePartL( *altNameExt, EX509RFC822Name, 
                                      aNameArray );
                    }
                break;
                }
            case EAltURI:
                {
                if ( aExtension )
                    {
                    GetAltNamePartL( *altNameExt, EX509URI, aNameArray );
                    }
                break;
                }
            case EAltDNSName:
                {
                if ( aExtension )
                    {
                    GetAltNamePartL( *altNameExt, EX509DNSName, aNameArray );
                    }  
                break;
                }
            case EDNCountryName:
                {
                GetDNPartL( aDN, KX520CountryName, aNameArray );
                break;
                }
            case EDNStateOrProvinceName:
                {
                GetDNPartL( aDN, KX520StateOrProvinceName, aNameArray );
                break;
                }
            case EDNLocalityName:
                {
                GetDNPartL( aDN, KX520LocalityName, aNameArray );
                break;
                }
            case EAltDirectoryName:
                {
                if ( aExtension )
                    {
                    GetAltNamePartL( *altNameExt, EX509DirectoryName, 
                                     aNameArray );
                    }
                break;
                }
            case EAltIPAddress:
                {
                if ( aExtension )
                    {
                    GetAltNamePartL( *altNameExt, EX509IPAddress, 
                                     aNameArray );                                   
                    }
                break;
                }    
            default:
                {
                // All the names are gone through.
                notFound = EFalse;
                break;
                }
            } // switch

        if ( notFound ) 
            {
            // If caller is PrimaryAndSecondaryNameL and PrimaryName and
            // SecondaryName have found then end loop.
            if ( aNameType == EX509CNPPrimAndSecond &&  
               ( aNameArray.MdcaCount() >= KX509CNPPrimAndSecondNameLengh ) )
                {
                notFound = EFalse;    
                } // if
            } // if 
        } // for
    
    if ( aExtension )
        {
        CleanupStack::PopAndDestroy(); // altNameExt
        }
    return KErrNone;
    }

// -----------------------------------------------------------------------------
// X509CertNameParser::GetDNPartAllL
// 
// -----------------------------------------------------------------------------

void X509CertNameParser::GetDNPartAllL(
                             const CX500DistinguishedName& aDN, 
                             const TDesC& aSubPartOID, 
                             CDesCArray& aNameArray )
    {
    HBufC* buf = NULL;
    // Count of the name parts of the DN
    TInt count = aDN.Count();

    // This goes through all the nameparts of the DN and appends all the
    // parts, that OID is aSubPartOID, to the array.
	for ( TInt i = 0; i < count; i++ )
		{
		const CX520AttributeTypeAndValue& ava = aDN.Element( i );
		if ( ava.Type() == aSubPartOID )
			{
			TRAPD( error, buf = ava.ValueL() );
            HandleErrorL( error );
            
            if ( buf )
                {
                CleanupStack::PushL( buf );
                CompareAndAddNameL( *buf, aNameArray );
                CleanupStack::PopAndDestroy( buf ); // buf
                buf = NULL; 
                } // if 
            } // if
        } // for
    }

// -----------------------------------------------------------------------------
// X509CertNameParser::GetDNPartL
// 
// -----------------------------------------------------------------------------

void X509CertNameParser::GetDNPartL( 
                             const CX500DistinguishedName& aDN, 
                             const TDesC& aSubPartOID, 
                             CDesCArray& aNameArray )
    {
    HBufC* buf = NULL;
    // Extract one DN part
    TRAPD( error, buf = aDN.ExtractFieldL( aSubPartOID ) );
    HandleErrorL( error );

    // Add to array
    if ( buf )
        {
        CleanupStack::PushL( buf );
        CompareAndAddNameL( *buf, aNameArray );
        CleanupStack::PopAndDestroy( buf );  // buf
        }
    }

// -----------------------------------------------------------------------------
// X509CertNameParser::GetAltNamePartL
// 
// -----------------------------------------------------------------------------

void X509CertNameParser::GetAltNamePartL( 
                             const CX509AltNameExt& aAltName, 
                             const TGNType& aSubPartType, 
                             CDesCArray& aNameArray )
    {
    // Get all parts of the alternative name to the array
    const CArrayPtrFlat<CX509GeneralName>& subParts = aAltName.AltName();
    TInt count = subParts.Count();
    CX509DomainName* domainName = NULL;
    TInt error = KErrNone;  

    // This goes through all the nameparts of the DN and appends all the
    // parts, that OID is aSubPartOID, to the array.
    for (TInt i = 0; count > i; i++)
        {
        if ( subParts[i]->Tag() == aSubPartType )
            {
            TPtrC8 data = subParts[i]->Data(); 
            switch ( aSubPartType )
                {
                case EX509RFC822Name:
                    {
                    TRAP( error, domainName = CX509RFC822Name::NewL( data ) );
                    CleanupStack::PushL( domainName );
                    AddAltNameToArrayL( error, domainName, aNameArray );
                    CleanupStack::PopAndDestroy( domainName );     
                    break;
                    }
                case EX509DNSName:
                case EX509DirectoryName:
                    {
                    TRAP( error, domainName = CX509DNSName::NewL( data ) );
                    CleanupStack::PushL( domainName );
                    AddAltNameToArrayL( error, domainName, aNameArray );
                    CleanupStack::PopAndDestroy( domainName );
                    break;
                    }
                case EX509URI:
                    {
                    CX509IPBasedURI* uri = NULL;
                    HBufC* decodedUri = NULL;
                    TRAP( error, uri = CX509IPBasedURI::NewL( data ) );
                    
                    if ( error == KErrNone )
                        {
                        CleanupStack::PushL( uri );
                        TRAP( error, decodedUri = EscapeUtils::
                            EscapeDecodeL( uri->Name() ) );
                        CleanupStack::PopAndDestroy(); //uri
                        }
                    
                    HandleErrorL( error );
                    if ( error == KErrNone )
                        {
                        CleanupStack::PushL( decodedUri );
                        CompareAndAddNameL( *decodedUri, aNameArray );
                        CleanupStack::PopAndDestroy(); // decodedUri
                        }
                    break;
                    }
                case EX509IPAddress:
                    {
                    // Not supported
                    break;
                    }
                default:
                    {
                    break;
                    }
                } // switch
            } // if 
        } // for
    }

// -----------------------------------------------------------------------------
// X509CertNameParser::AddAltNameToArrayL
// 
// -----------------------------------------------------------------------------

TInt X509CertNameParser::AddAltNameToArrayL( 
                            TInt aError, 
                            CX509DomainName* aDomainName, 
                            CDesCArray& aNameArray )
    {
    TInt error = HandleErrorL( aError );
    
    if ( error == KErrNone )
        {
        const TPtrC name = aDomainName->Name();
        CompareAndAddNameL( name, aNameArray );
        }

    return error;
    }

// -----------------------------------------------------------------------------
// X509CertNameParser::AddToBufLD
// 
// -----------------------------------------------------------------------------

void X509CertNameParser::AddToBufLD( const TDesC& aName, HBufC*& aBuf )
    {
    if (!aBuf)
        {
        aBuf = HBufC::NewL( aName.Length() );
        aBuf->Des().Append( aName );
        }
    else
        {
        HBufC* helpBuf = HBufC::NewL( aName.Length() + aBuf->Length() + 1);
        helpBuf->Des().Append( *aBuf );
        helpBuf->Des().Append( KX509CertParserSpace );
        helpBuf->Des().Append( aName );
        CleanupStack::PopAndDestroy( aBuf ); // aBuf
        aBuf = helpBuf;
        }
    }

// -----------------------------------------------------------------------------
// X509CertNameParser::CompareAndAddNameL
// 
// -----------------------------------------------------------------------------

void X509CertNameParser::CompareAndAddNameL( const TDesC& aProposal, 
                                             CDesCArray& aNameArray )
    {
    TInt pos = 0; // This is needed only for calling Find().
    // Append to array, if aProposal don't already exist in the array.
    if ( aNameArray.Find( aProposal, pos, ECmpNormal ) )
        {
        aNameArray.AppendL( aProposal );
        }
    }



// -----------------------------------------------------------------------------
// X509CertNameParser::HandleErrorL
// 
// -----------------------------------------------------------------------------

TInt X509CertNameParser::HandleErrorL( TInt aError )
    {    
    if ( !( aError == KErrNone || aError == KErrArgument || aError == KErrNotSupported ) )
        {
        User::Leave( aError );
        }       
    return aError;
    }
    
//  End of File