+1 vote
by (210 points)
edited by

Hello,
we have a problem in one of our clients running Windows 2003 small bussiness server, our windows service is running under local system account.

I've searched this forum and found a code you posted to instruct rebex components to accept all certificates, then save the certificate and do the chain validation using X509Certificate2 class.

This is the code I've used:

if ( args.Length != 4 )
{
    Console.WriteLine( "Uso: TestCertificadoEmail <smtp|pop3> <host> <port> <implicit|explicit>" );
    return;
}

try
{
    CertificateChain certChain = null;

    if ( args[0] == "smtp" )
    {
        // 1. Use Rebex SMTP to download the server certificate into a file
        Smtp client = new Smtp();
        client.Settings.SslAcceptAllCertificates = true;
        client.Connect( args[1], Convert.ToInt32( args[2] ), args[3] == "implicit" ? SslMode.Implicit : SslMode.Explicit );
        certChain = client.TlsSocket.ServerCertificate;
    }
    else if ( args[0] == "pop3" )
    {
        Pop3 client = new Pop3();
        client.Settings.SslAcceptAllCertificates = true;
        client.Connect( args[1], Convert.ToInt32( args[2] ), args[3] == "implicit" ? SslMode.Implicit : SslMode.Explicit );
        certChain = client.TlsSocket.ServerCertificate;
    }
    else
    {
        Console.WriteLine( "Protocolo no soportado" );
        return;
    }

    foreach ( var rebexCert in certChain )
    {
        Console.WriteLine( rebexCert.GetCommonName() );
        rebexCert.Save( "cert.der", CertificateFormat.Base64Der );
        // 2. Validate the certificate (from the file) without using any Rebex code

        X509Certificate2 cert = new X509Certificate2( "cert.der" );

        X509ChainPolicy policy = new X509ChainPolicy();
        policy.RevocationFlag = X509RevocationFlag.ExcludeRoot;
        policy.RevocationMode = X509RevocationMode.Online;

        X509Chain chain = new X509Chain( false );

        try
        {
            chain.ChainPolicy = policy;

            bool valid = chain.Build( cert );
            Console.WriteLine( "Is valid: {0}", valid );
            foreach ( X509ChainStatus s in chain.ChainStatus )
            {
                X509ChainStatusFlags flags = s.Status;

                Console.WriteLine( "Status: {0}", flags );
            }
        }
        finally
        {
            chain.Reset();
        }
    }
    Console.ReadLine();
}
catch ( Exception ex )
{
    Console.WriteLine( ex.Message );
    Console.WriteLine( ex.StackTrace );
}

And this is the result i get when I connect in this machine to pop.gmail.com port 995.

pop.gmail.com
Is valid: False
Status: NotSignatureValid
Status: RevocationStatusUnknown
Status: OfflineRevocation
Google Internet Authority G2
Is valid: False
Status: NotSignatureValid
Status: RevocationStatusUnknown
Status: OfflineRevocation
GeoTrust Global CA
Is valid: True

Of course this has something to do with this particular machine, because the same test run in my developer machine says all the certificates are valid.

What can I do to solve this certificate problem?

Thanks.

Applies to: Rebex Secure Mail

3 Answers

0 votes
by (58.9k points)
selected by
 
Best answer

Hello and thank you for your last outputs of the certutil.exe!

Finally we were able to find the cause of the issue.

The certutil failed with 0x80096004 (-2146869244) error code, which is a known issue with some older Windows systems including Windows Server 2003 that do not support SHA2 hashing algorithms. This is well described in the following blogpost.

In short, the certificate validation at the particular Windows machine fails because the certificates in the chain use the SHA2 hashing algorithms whihc is not supported by your server.

Fortunatelly, Microsoft offers hotfix for the missing SHA2 algorithm problem. So please download the hotfix, install it at your server and then try to validate the certificates one more time. This should make it possible to validate the certificates.

Please let us know whether the issue has been resolved by applying the fix.

by (210 points)
We will talk to to the client and recomend them to upgrade the server to a newer operating system or apply the hotfix.
Meanwhile we have modified our service to set the SslAcceptAllCertificates in this particular client, letting them know that this is insecure.

If they decide to apply the hotfix, I will let you know.
by (58.9k points)
Any news from your client on this issue? It would be good to know if the Microsoft hotfix has helped.
by (210 points)
Yes, the client has decided to stay with the SslAcceptAllCertificates bit set to true, despite our warnings.
We have not installed the hotfix.
0 votes
by (58.9k points)

Hello,

is there any difference if you validate the certificate with .NET classes, but this time using the machine context? E.g in the code above please try to change from:

X509Chain chain = new X509Chain(false);

to

X509Chain chain = new X509Chain(true);

And then let me know whether you are able to validate the certificate on the problematic machine using machine context.

by (210 points)
Hello,

I've tested with machine context and the same result.

pop.gmail.com
Is valid: False
Status: NotSignatureValid
Status: RevocationStatusUnknown
Status: OfflineRevocation
Google Internet Authority G2
Is valid: False
Status: NotSignatureValid
Status: RevocationStatusUnknown
Status: OfflineRevocation
GeoTrust Global CA
Is valid: True
0 votes
by (58.9k points)

Hi,

The X509ChainStatusFlags.RevocationStatusUnknown means that "It is not possible to determine whether the certificate has been revoked. This can be due to the certificate revocation list (CRL) being offline or unavailable". (See http://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509chainstatusflags.aspx)
The error itself actually comes from Windows CryptoAPI's CertGetCertificateChain function (see http://msdn.microsoft.com/en-us/library/windows/desktop/aa376078%28v=vs.85%29.aspx and http://msdn.microsoft.com/en-us/library/windows/desktop/aa377590%28v=vs.85%29.aspx) for more information.

This means that in order to determine what is wrong with certificate validation on your machine, you will have to look deeper – it doesn't seem to be related to Rebex code.

Please download and save Gmail's certificate, using the following code for example:

using System;
using Rebex.Net;
using Rebex.Security.Certificates;
using System.Security.Cryptography.X509Certificates;
... 

// 1. Use Rebex POP3 to download the server certificate into a file
Pop3 client = new Pop3();
client.Settings.SslAcceptAllCertificates = true;
client.Connect("your-pop3-server", SslMode.Implicit);
client.TlsSocket.ServerCertificate[0].Save("certificate.der", CertificateFormat.Base64Der);

Then run the following command line utility on the gmail.der file (at the machine that fails to validate the certificate):
certutil -verify -urlfetch certificate.der
And check its output (send us a copy if possible) – there might be something useful there.

by (210 points)
Under the windows service, see that I included a "whoami" command in the batch to verify I was under the nt authority\system account.
by (148k points)
Actually, when you run `certutil` after running your test code, it only checks the last certificate in the chain because your code overwrites "cert.der" in the foreach loop. The last certificate in the chain happens to be "GeoTrust Global CA" (issued by "Equifax Secure Certificate Authority"), which is actually reported as valid by your code as well (so it's not really any surprise that `certutil` considers them valid as well).

Please try running `certutil` on one of the two certificates that are NOT reported as valid by your code as well. These are the first and second certificates in the chain. This should finally make it possible to determine the cause of the validation issues. Thanks!
by (210 points)
Oops, you're right.

Here is the output for the 2 first certificates in the chain:

Cert 1:

Emisor:
    CN=Google Internet Authority G2
    O=Google Inc
    C=US
Asunto:
    CN=pop.gmail.com
    O=Google Inc
    L=Mountain View
    S=California
    C=US
Nº. de serie de cert.: 4ab74e106987e48d

dwFlags = CA_VERIFY_FLAGS_DUMP_CHAIN (0x40000000)
ChainFlags = CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT (0x40000000)
HCCE_LOCAL_MACHINE
CERT_CHAIN_POLICY_BASE
-------- CERT_CHAIN_CONTEXT --------
ChainContext.dwErrorStatus = CERT_TRUST_IS_NOT_SIGNATURE_VALID (0x8)
ChainContext.dwErrorStatus = CERT_TRUST_REVOCATION_STATUS_UNKNOWN (0x40)
ChainContext.dwErrorStatus = CERT_TRUST_IS_OFFLINE_REVOCATION (0x1000000)
SimpleChain.dwErrorStatus = CERT_TRUST_IS_NOT_SIGNATURE_VALID (0x8)
SimpleChain.dwErrorStatus = CERT_TRUST_REVOCATION_STATUS_UNKNOWN (0x40)
SimpleChain.dwErrorStatus = CERT_TRUST_IS_OFFLINE_REVOCATION (0x1000000)

CertContext[0][0]: dwInfoStatus=2 dwErrorStatus=1000048
  Issuer: CN=Google Internet Authority G2, O=Google Inc, C=US
  Subject: CN=pop.gmail.com, O=Google Inc, L=Mountain View, S=California, C=US
  Serial: 4ab74e106987e48d
  f9 81 fc 97 8c 00 53 89 4f fb 06 00 4e fc 4a 09 8a fd ba 18
  Element.dwInfoStatus = CERT_TRUST_HAS_KEY_MATCH_ISSUER (0x2)
  Element.dwErrorStatus = CERT_TRUST_IS_NOT_SIGNATURE_VALID (0x8)
  Element.dwErrorStatus = CERT_TRUST_REVOCATION_STATUS_UNKNOWN (0x40)
  Element.dwErrorStatus = CERT_TRUST_IS_OFFLINE_REVOCATION (0x1000000)
  ----------------  Certificado AIA  ----------------
  Emisor incorrecto "Certificado (0)" Tiempo: 0
    [0.0] http://pki.google.com/GIAG2.crt

  ----------------  Certificado CDP  ----------------
  Comprobado "CRL de base (869)" Tiempo: 0
    [0.0] http://pki.google.com/GIAG2.crl

  --------------------------------
  Issuance[0] = 1.3.6.1.4.1.11129.2.5.1
  Application[0] = 1.3.6.1.5.5.7.3.1 Autenticación del servidor
  Application[1] = 1.3.6.1.5.5.7.3.2 Autenticación del cliente

CertContext[0][1]: dwInfoStatus=2 dwErrorStatus=1000048
  Issuer: CN=GeoTrust Global CA, O=GeoTrust Inc., C=US
  Subject: CN=Google Internet Authority G2, O=Google Inc, C=US
  Serial: 023a83
  17 8f 7e 93 a7 4e d7 3d 88 c2 90 42 22 0b 9a e6 e4 b3 71 cd
  Element.dwInfoStatus = CERT_TRUST_HAS_KEY_MATCH_ISSUER (0x2)
  Element.dwErrorStatus = CERT_TRUST_IS_NOT_SIGNATURE_VALID (0x8)
  Element.dwErrorStatus = CERT_TRUST_REVOCATION_STATUS_UNKNOWN (0x40)
  Element.dwErrorStatus = CERT_TRUST_IS_OFFLINE_REVOCATION (0x1000000)
  ----------------  Certificado AIA  ----------------
  No hay direcciones URL "Ninguno" Tiempo: 0
  ----------------  Certificado CDP  ----------------
  Comprobado "CRL de base" Tiempo: 0
    [0.0] http://g.symcb.com/crls/gtglobal.crl

  --------------------------------
  Issuance[0] = 1.3.6.1.4.1.11129.2.5.1
  Application[0] = 1.3.6.1.5.5.7.3.1 Autenticación del servidor
  Application[1] = 1.3.6.1.5.5.7.3.2 Autenticación del cliente
  Application[2] = 1.3.6.1.5.5.7.3.4 Correo seguro
  Application[3] = 1.3.6.1.5.5.7.3.3 Firma de código
  Application[4] = 1.3.6.1.5.5.7.3.8 Impresión de fecha

CertContext[0][2]: dwInfoStatus=10a dwErrorStatus=0
  Issuer: CN=GeoTrust Global CA, O=GeoTrust Inc., C=US
  Subject: CN=GeoTrust Global CA, O=GeoTrust Inc., C=US
  Serial: 023456
  de 28 f4 a4 ff e5 b9 2f a3 c5 03 d1 a3 49 a7 f9 96 2a 82 12
  Element.dwInfoStatus = CERT_TRUST_HAS_KEY_MATCH_ISSUER (0x2)
  Element.dwInfoStatus = CERT_TRUST_IS_SELF_SIGNED (0x8)
  Element.dwInfoStatus = CERT_TRUST_HAS_PREFERRED_ISSUER (0x100)
  ----------------  Certificado AIA  ----------------
  No hay direcciones URL "Ninguno" Tiempo: 0
  ----------------  Certificado CDP  ----------------
  No hay direcciones URL "Ninguno" Tiempo: 0
  --------------------------------
  Application[0] = 1.3.6.1.5.5.7.3.1 Autenticación del servidor
  Application[1] = 1.3.6.1.5.5.7.3.2 Autenticación del cliente
  Application[2] = 1.3.6.1.5.5.7.3.4 Correo seguro
  Application[3] = 1.3.6.1.5.5.7.3.3 Firma de código
  Application[4] = 1.3.6.1.5.5.7.3.8 Impresión de fecha

Exclude leaf cert:
  e3 37 31 29 35 60 64 1d 69 7b f5 b0 35 6a 8e 4b 4d f7 56 90
Full chain:
  cd e3 7b 52 c8 12 d4 48 78 c5 78 ce ff 0a 8e 7f b0 5c a6 6e
  Issuer: CN=Google Internet Authority G2, O=Google Inc, C=US
  Subject: CN=pop.gmail.com, O=Google Inc, L=Mountain View, S=California, C=US
  Serial: 4ab74e106987e48d
  f9 81 fc 97 8c 00 53 89 4f fb 06 00 4e fc 4a 09 8a fd ba 18
No se puede comprobar la firma del certificado. 0x80096004 (-2146869244)
------------------------------------
CertUtil: -verify error del comando: 0x80096004 (-2146869244)
CertUtil: No se puede comprobar la firma del certificado.
by (210 points)
Cert 2:

Emisor:
    CN=GeoTrust Global CA
    O=GeoTrust Inc.
    C=US
Asunto:
    CN=Google Internet Authority G2
    O=Google Inc
    C=US
Nº. de serie de cert.: 023a83

dwFlags = CA_VERIFY_FLAGS_DUMP_CHAIN (0x40000000)
ChainFlags = CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT (0x40000000)
HCCE_LOCAL_MACHINE
CERT_CHAIN_POLICY_BASE
-------- CERT_CHAIN_CONTEXT --------
ChainContext.dwErrorStatus = CERT_TRUST_IS_NOT_SIGNATURE_VALID (0x8)
ChainContext.dwErrorStatus = CERT_TRUST_REVOCATION_STATUS_UNKNOWN (0x40)
ChainContext.dwErrorStatus = CERT_TRUST_IS_OFFLINE_REVOCATION (0x1000000)
SimpleChain.dwErrorStatus = CERT_TRUST_IS_NOT_SIGNATURE_VALID (0x8)
SimpleChain.dwErrorStatus = CERT_TRUST_REVOCATION_STATUS_UNKNOWN (0x40)
SimpleChain.dwErrorStatus = CERT_TRUST_IS_OFFLINE_REVOCATION (0x1000000)

CertContext[0][0]: dwInfoStatus=2 dwErrorStatus=1000048
  Issuer: CN=GeoTrust Global CA, O=GeoTrust Inc., C=US
  Subject: CN=Google Internet Authority G2, O=Google Inc, C=US
  Serial: 023a83
  17 8f 7e 93 a7 4e d7 3d 88 c2 90 42 22 0b 9a e6 e4 b3 71 cd
  Element.dwInfoStatus = CERT_TRUST_HAS_KEY_MATCH_ISSUER (0x2)
  Element.dwErrorStatus = CERT_TRUST_IS_NOT_SIGNATURE_VALID (0x8)
  Element.dwErrorStatus = CERT_TRUST_REVOCATION_STATUS_UNKNOWN (0x40)
  Element.dwErrorStatus = CERT_TRUST_IS_OFFLINE_REVOCATION (0x1000000)
  ----------------  Certificado AIA  ----------------
  No hay direcciones URL "Ninguno" Tiempo: 0
  ----------------  Certificado CDP  ----------------
  Comprobado "CRL de base" Tiempo: 0
    [0.0] http://g.symcb.com/crls/gtglobal.crl

  --------------------------------
  Issuance[0] = 1.3.6.1.4.1.11129.2.5.1
  Application[0] = 1.3.6.1.5.5.7.3.1 Autenticación del servidor
  Application[1] = 1.3.6.1.5.5.7.3.2 Autenticación del cliente
  Application[2] = 1.3.6.1.5.5.7.3.4 Correo seguro
  Application[3] = 1.3.6.1.5.5.7.3.3 Firma de código
  Application[4] = 1.3.6.1.5.5.7.3.8 Impresión de fecha

CertContext[0][1]: dwInfoStatus=10a dwErrorStatus=0
  Issuer: CN=GeoTrust Global CA, O=GeoTrust Inc., C=US
  Subject: CN=GeoTrust Global CA, O=GeoTrust Inc., C=US
  Serial: 023456
  de 28 f4 a4 ff e5 b9 2f a3 c5 03 d1 a3 49 a7 f9 96 2a 82 12
  Element.dwInfoStatus = CERT_TRUST_HAS_KEY_MATCH_ISSUER (0x2)
  Element.dwInfoStatus = CERT_TRUST_IS_SELF_SIGNED (0x8)
  Element.dwInfoStatus = CERT_TRUST_HAS_PREFERRED_ISSUER (0x100)
  ----------------  Certificado AIA  ----------------
  No hay direcciones URL "Ninguno" Tiempo: 0
  ----------------  Certificado CDP  ----------------
  No hay direcciones URL "Ninguno" Tiempo: 0
  --------------------------------
  Application[0] = 1.3.6.1.5.5.7.3.1 Autenticación del servidor
  Application[1] = 1.3.6.1.5.5.7.3.2 Autenticación del cliente
  Application[2] = 1.3.6.1.5.5.7.3.4 Correo seguro
  Application[3] = 1.3.6.1.5.5.7.3.3 Firma de código
  Application[4] = 1.3.6.1.5.5.7.3.8 Impresión de fecha

Exclude leaf cert:
  17 8f 7e 93 a7 4e d7 3d 88 c2 90 42 22 0b 9a e6 e4 b3 71 cd
Full chain:
  8d 7b 72 70 27 be 34 54 82 fc 05 02 5d 3f 41 c6 24 02 0d c4
  Issuer: CN=GeoTrust Global CA, O=GeoTrust Inc., C=US
  Subject: CN=Google Internet Authority G2, O=Google Inc, C=US
  Serial: 023a83
  17 8f 7e 93 a7 4e d7 3d 88 c2 90 42 22 0b 9a e6 e4 b3 71 cd
No se puede comprobar la firma del certificado. 0x80096004 (-2146869244)
------------------------------------
CertUtil: -verify error del comando: 0x80096004 (-2146869244)
CertUtil: No se puede comprobar la firma del certificado.
...