pkiutilities/x509certnameparser/src/X509CertNameParser.cpp
changeset 0 164170e6151a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pkiutilities/x509certnameparser/src/X509CertNameParser.cpp	Tue Jan 26 15:20:08 2010 +0200
@@ -0,0 +1,583 @@
+/*
+* 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