main/xmlsecurity/source/xmlsec/mscrypt/securityenvironment_mscryptimpl.cxx
//We return only valid or invalid, as long as the API documentation expresses
//explicitly that all validation steps are carried out even if one or several
//errors occur. See also
//https://wiki.openoffice.org/wiki/Certificate_Path_Validation#Validation_status
We return only valid or invalid, as long as the API documentation expresses
explicitly that all validation steps are carried out even if one or several
errors occur.
We return only valid or invalid as long as the API documentation expresses explicitly that all validation steps are carried out even if one or several errors occur .
sal_Int32 SecurityEnvironment_MSCryptImpl :: verifyCertificate(
    const Reference< ::com::sun::star::security::XCertificate >& aCert,
    const Sequence< Reference< ::com::sun::star::security::XCertificate > >& seqCerts)
    throw( ::com::sun::star::uno::SecurityException, ::com::sun::star::uno::RuntimeException )
{
	sal_Int32 validity = ::com::sun::star::security::CertificateValidity::INVALID;
	PCCERT_CHAIN_CONTEXT pChainContext = NULL;
	PCCERT_CONTEXT pCertContext = NULL;
	const X509Certificate_MSCryptImpl* xcert = NULL;
	Reference< XUnoTunnel > xCertTunnel( aCert, UNO_QUERY ) ;
	if( !xCertTunnel.is() ) {
		throw RuntimeException() ;
	}
    xmlsec_trace("Start verification of certificate: \n %s",
                 OUStringToOString(
                     aCert->getSubjectName(), osl_getThreadTextEncoding()).getStr());
	xcert = ( X509Certificate_MSCryptImpl* )xCertTunnel->getSomething( X509Certificate_MSCryptImpl::getUnoTunnelId() ) ;
	if( xcert == NULL ) {
		throw RuntimeException() ;
	}
	pCertContext = xcert->getMswcryCert() ;
	CERT_ENHKEY_USAGE	enhKeyUsage ;
	CERT_USAGE_MATCH	certUsage ;
	CERT_CHAIN_PARA		chainPara ;
    rtl_zeroMemory(&chainPara, sizeof(CERT_CHAIN_PARA));
	enhKeyUsage.cUsageIdentifier = 0 ;
	enhKeyUsage.rgpszUsageIdentifier = NULL ;
	certUsage.dwType = USAGE_MATCH_TYPE_AND ;
	certUsage.Usage = enhKeyUsage ;
	chainPara.cbSize = sizeof( CERT_CHAIN_PARA ) ;
	chainPara.RequestedUsage = certUsage ;
    HCERTSTORE hCollectionStore = NULL;
    HCERTSTORE hIntermediateCertsStore = NULL;
	BOOL bChain = FALSE;
	if( pCertContext != NULL )
    {
        hIntermediateCertsStore =
            getCertStoreForIntermediatCerts(seqCerts);
        hCollectionStore = CertOpenStore(
			CERT_STORE_PROV_COLLECTION ,
			0 ,
			NULL ,
			0 ,
			NULL
            ) ;
        if (hCollectionStore != NULL)
        {
            CertAddStoreToCollection (
				hCollectionStore ,
				m_hCertStore ,
				CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG ,
				0) ;
            CertAddStoreToCollection (
				hCollectionStore ,
				m_hCertStore ,
				CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG ,
				0) ;
            CertAddStoreToCollection (
                hCollectionStore,
                hIntermediateCertsStore,
                CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG,
                0);
        }
        xmlsec_trace("Verifying cert using revocation information.");
        bChain = CertGetCertificateChain(
            NULL ,
            pCertContext ,
            NULL , 
            hCollectionStore,
            &chainPara ,
            CERT_CHAIN_REVOCATION_CHECK_CHAIN | CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT,
            NULL ,
        	&pChainContext);
        if (bChain && pChainContext->cChain > 0)
        {
            xmlsec_trace("Overall error status (all chains):");
            traceTrustStatus(pChainContext->TrustStatus.dwErrorStatus);
            PCERT_SIMPLE_CHAIN pSimpleChain = pChainContext->rgpChain[0];
            xmlsec_trace("Error status of first chain: ");
            traceTrustStatus(pSimpleChain->TrustStatus.dwErrorStatus);
            DWORD revocationFlags = CERT_TRUST_REVOCATION_STATUS_UNKNOWN |
                CERT_TRUST_IS_OFFLINE_REVOCATION;
            DWORD otherErrorsMask = ~revocationFlags;
            if( !(pSimpleChain->TrustStatus.dwErrorStatus & otherErrorsMask))
            {
                if ( pSimpleChain->TrustStatus.dwErrorStatus & revocationFlags)
                {
                    CertFreeCertificateChain(pChainContext);
                    pChainContext = NULL;
                    xmlsec_trace("Checking again but without requiring revocation information.");
                    bChain = CertGetCertificateChain(
                        NULL ,
                        pCertContext ,
                        NULL , 
                        hCollectionStore,
                        &chainPara ,
                        0,
                        NULL ,
                        &pChainContext);
                    if (bChain
                        && pChainContext->cChain > 0
                        && pChainContext->rgpChain[0]->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR)
                    {
                        xmlsec_trace("Certificate is valid.\n");
                        validity = ::com::sun::star::security::CertificateValidity::VALID;
                    }
                    else
                    {
                        xmlsec_trace("Certificate is invalid.\n");
                    }
                }
                else
                {
                    xmlsec_trace("Certificate is valid.\n");
                    validity = ::com::sun::star::security::CertificateValidity::VALID;
                }
            }
            else
            {
                xmlsec_trace("Certificate is invalid.\n");
                validity = ::com::sun::star::security::CertificateValidity::INVALID ;
            }
        }
        else
        {
            xmlsec_trace("CertGetCertificateChaine failed.\n");
        }
    }
    if (pChainContext)
    {
        CertFreeCertificateChain(pChainContext);
        pChainContext = NULL;
    }
    CertCloseStore(hCollectionStore, CERT_CLOSE_STORE_CHECK_FLAG);
    CertCloseStore(hIntermediateCertsStore, CERT_CLOSE_STORE_CHECK_FLAG);
	return validity ;
}
sal_Int32 SecurityEnvironment_MSCryptImpl :: verifyCertificate ( const Reference < :: com :: sun :: star :: security :: XCertificate > & aCert , const Sequence < Reference < :: com :: sun :: star :: security :: XCertificate > > & seqCerts ) throw ( :: com :: sun :: star :: uno :: SecurityException , :: com :: sun :: star :: uno :: RuntimeException ) { sal_Int32 validity = :: com :: sun :: star :: security :: CertificateValidity :: INVALID ; PCCERT_CHAIN_CONTEXT pChainContext = NULL ; PCCERT_CONTEXT pCertContext = NULL ; const X509Certificate_MSCryptImpl * xcert = NULL ; Reference < XUnoTunnel > xCertTunnel ( aCert , UNO_QUERY ) ; if ( ! xCertTunnel . is ( ) ) { throw RuntimeException ( ) ; } xmlsec_trace ( " \n " , OUStringToOString ( aCert -> getSubjectName ( ) , osl_getThreadTextEncoding ( ) ) . getStr ( ) ) ; xcert = ( X509Certificate_MSCryptImpl * ) xCertTunnel -> getSomething ( X509Certificate_MSCryptImpl :: getUnoTunnelId ( ) ) ; if ( xcert == NULL ) { throw RuntimeException ( ) ; } pCertContext = xcert -> getMswcryCert ( ) ; CERT_ENHKEY_USAGE enhKeyUsage ; CERT_USAGE_MATCH certUsage ; CERT_CHAIN_PARA chainPara ; rtl_zeroMemory ( & chainPara , sizeof ( CERT_CHAIN_PARA ) ) ; enhKeyUsage . cUsageIdentifier = 0 ; enhKeyUsage . rgpszUsageIdentifier = NULL ; certUsage . dwType = USAGE_MATCH_TYPE_AND ; certUsage . Usage = enhKeyUsage ; chainPara . cbSize = sizeof ( CERT_CHAIN_PARA ) ; chainPara . RequestedUsage = certUsage ; HCERTSTORE hCollectionStore = NULL ; HCERTSTORE hIntermediateCertsStore = NULL ; BOOL bChain = FALSE ; if ( pCertContext != NULL ) { hIntermediateCertsStore = getCertStoreForIntermediatCerts ( seqCerts ) ; hCollectionStore = CertOpenStore ( CERT_STORE_PROV_COLLECTION , 0 , NULL , 0 , NULL ) ; if ( hCollectionStore != NULL ) { CertAddStoreToCollection ( hCollectionStore , m_hCertStore , CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG , 0 ) ; CertAddStoreToCollection ( hCollectionStore , m_hCertStore , CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG , 0 ) ; CertAddStoreToCollection ( hCollectionStore , hIntermediateCertsStore , CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG , 0 ) ; } xmlsec_trace ( " " ) ; bChain = CertGetCertificateChain ( NULL , pCertContext , NULL , hCollectionStore , & chainPara , CERT_CHAIN_REVOCATION_CHECK_CHAIN | CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT , NULL , & pChainContext ) ; if ( bChain && pChainContext -> cChain > 0 ) { xmlsec_trace ( " " ) ; traceTrustStatus ( pChainContext -> TrustStatus . dwErrorStatus ) ; PCERT_SIMPLE_CHAIN pSimpleChain = pChainContext -> rgpChain [ 0 ] ; xmlsec_trace ( " " ) ; traceTrustStatus ( pSimpleChain -> TrustStatus . dwErrorStatus ) ; DWORD revocationFlags = CERT_TRUST_REVOCATION_STATUS_UNKNOWN | CERT_TRUST_IS_OFFLINE_REVOCATION ; DWORD otherErrorsMask = ~ revocationFlags ; if ( ! ( pSimpleChain -> TrustStatus . dwErrorStatus & otherErrorsMask ) ) { if ( pSimpleChain -> TrustStatus . dwErrorStatus & revocationFlags ) { CertFreeCertificateChain ( pChainContext ) ; pChainContext = NULL ; xmlsec_trace ( " " ) ; bChain = CertGetCertificateChain ( NULL , pCertContext , NULL , hCollectionStore , & chainPara , 0 , NULL , & pChainContext ) ; if ( bChain && pChainContext -> cChain > 0 && pChainContext -> rgpChain [ 0 ] -> TrustStatus . dwErrorStatus == CERT_TRUST_NO_ERROR ) { xmlsec_trace ( " \n " ) ; validity = :: com :: sun :: star :: security :: CertificateValidity :: VALID ; } else { xmlsec_trace ( " \n " ) ; } } else { xmlsec_trace ( " \n " ) ; validity = :: com :: sun :: star :: security :: CertificateValidity :: VALID ; } } else { xmlsec_trace ( " \n " ) ; validity = :: com :: sun :: star :: security :: CertificateValidity :: INVALID ; } } else { xmlsec_trace ( " \n " ) ; } } if ( pChainContext ) { CertFreeCertificateChain ( pChainContext ) ; pChainContext = NULL ; } CertCloseStore ( hCollectionStore , CERT_CLOSE_STORE_CHECK_FLAG ) ; CertCloseStore ( hIntermediateCertsStore , CERT_CLOSE_STORE_CHECK_FLAG ) ; return validity ; }
We return only valid or invalid, as long as the API documentation expresses
explicitly that all validation steps are carried out even if one or several
errors occur.
We return only valid or invalid as long as the API documentation expresses explicitly that all validation steps are carried out even if one or several errors occur .
//Prepare parameter for CertGetCertificateChain //Merge m_hCertStore and m_hKeyStore and the store of the intermediate //certificates into one store. //CertGetCertificateChain searches by default in MY, CA, ROOT and TRUST //We do not check revocation of the root. In most cases there are none. //Then we would get CERT_TRUST_REVOCATION_STATUS_UNKNOWN //use current system time //highest quality chains come first //CERT_TRUST_REVOCATION_STATUS_UNKNOWN is also set if a certificate //has no AIA(OCSP) or CRLDP extension and there is no CRL locally installed. //No errors except maybe those caused by missing revocation information //Check if there are errors //No revocation information. Because MSDN documentation is not //clear about if all other tests are performed if an error occurs, //we test again, without requiring revocation checking. //use current system time //valid and revocation information available //invalid //Close the additional store, do not destroy the contained certs //Close the temporary store containing the intermediate certificates and make //sure all certificates are deleted.