runtime: The remote certificate is invalid according to the validation procedure

Running a dotnet core 2.2 web api on Ubuntu 18.04 Docker image (mcr.microsoft.com/dotnet/core/aspnet:2.2-bionic). I am using MailKit (https://github.com/jstedfast/MailKit) to send an email and it works fine when I run locally on Windows 10 but fails on Linux:

System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure

Since it works on Windows OK, it seems that there is perhaps an OpenSSL issue, maybe due to 1.0 vs 1.1? MailKit calls into SslStream.AuthenticateAsClient, which is the start of the stack that fails. Since this is an email relay, I need some other way of debugging that rather than just that https works generally (which it does with curl).

I have tried the following to no avail:

  1. Downloaded and updated the root CA stack using update-ca-certificates (no difference)
  2. Used curl from the container itself to access the hello world lets encrypt web site to see if there is a problem with LE specifically (works fine)
  3. Set environment variables for SSL_CERT_DIR (/usr/lib/ssl/certs) and SSL_CERT_FILE (/usr/lib/ssl/cert.pem) after symlinking the downloaded CA file into /usr/lib/ssl (no difference).

Can someone please give me some more debugging tips? Thanks.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 8
  • Comments: 26 (15 by maintainers)

Most upvoted comments

Landed here after finding that this dotnet/aspnetcore issue and its resolutions (not its Stack Overflow thread on dotnet dev-certs https --trust) did not yet work for me on Ubuntu 20.04.

Adding some info here, as it might help with an easy repro. What I did was:

  1. Install Ubuntu 20.04, 64bit
  2. Install dotnet sdk (--version gives 3.1.300)
  3. Clone my repository with IdentityServer4 and ASP.NET Core Web API in one project
  4. Add IdentityModelEventSource.ShowPII = true; // DEV ONLY!! to Configure(...)
  5. Run dotnet dev-certs https --trust
  6. Run it with dotnet run
  7. Open https://localhost:5001 in Firefox

Because the instructions in Stack Overflow did not (yet) work for me somehow (even after sudo update-ca-certificates the verification openssl verify localhost.crt keeps giving me the same error as before), the story continues like this for me:

  1. You get an SSL/TLS warning, via “Advanced” accept “the risk” and continue with the untrusted cert
  2. In my sample app click _“Fetch token for administrator” (this is still fine, the browser cert exception is in place)
  3. Click button “GET /endpoint-specific-security/admin-role-only

Then:

  • Result: the API is called, which via HTTP calls the IdentityServer instance on the same https://localhost:5001 but this fails with:
System.InvalidOperationException: IDX20803: Unable to obtain configuration from: 'https://localhost:5001/.well-known/openid-configuration'.
 ---> System.IO.IOException: IDX20804: Unable to retrieve document from: 'https://localhost:5001/.well-known/openid-configuration'.
 ---> System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
 ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.

To my limited understanding it seems that my API is calling another “server” and is not trusting that server’s SSL certificate. So I presume this is the same problem as OP has, only in their case it is “MailKit” that is running a cert that’s not okay for the calling client (similar to my ‘client’ calling into IDS4)?

I’m adding this information because:

  • either (and most likely) my problem is specific to my case, and for most others @davidsh’s instructions (and this SO answer) in the other thread will be a good workaround
  • or (less likely) my problem is a common one, and the repro above might help track down the issue

I truly hope all this information in my post helps and is not completely off topic. If it is off-topic, then please ignore!


What I did (to no avail) to try and fix the certificate (might be a valid workaround for OP even though it didn’t work for me?):

  1. Create and cd to ~/tmp
  2. Create localhost.conffrom this gist
  3. openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout localhost.key -out localhost.crt -config localhost.conf
  4. openssl pkcs12 -export -out localhost.pfx -inkey localhost.key -in localhost.crt
  5. sudo cp localhost.crt /usr/local/share/ca-certificates
  6. sudo update-ca-certificates (“1 added”)
  7. export ASPNETCORE_Kestrel__Certificates__Default__Password=password
  8. export ASPNETCORE_Kestrel__Certificates__Default__Path=~/tmp/localhost.pfx

Then dotnet run my repository again (it picks up the .pfx because it’ll give an error if the password is wrong), but still get the certificate warnings, both in Mozilla Firefox 76.0.1 and in Google Chrome 83.0.

I’m still gettting following errors targeting netcoreapp3.1 :

unable to get certificate CRL unable to get local issuer certificate Subject: CN=smtp.gmail.com, O=Google LLC, L=Mountain View, S=California, C=US Issuer: CN=GTS CA 1O1, O=Google Trust Services, C=US

Minimal code example for repro with MailKit:

var client = new SmtpClient();
client.Connect("smtp.gmail.com", 587, SecureSocketOptions.StartTls);
client.Authenticate(_options.MailAccountName, _options.MailAccountPassword);
var message = new MimeMessage();
message.From.Add(author);
message.ReplyTo.Add(author);
message.To.Add(recipient);
message.Subject = subject;
message.Body = new TextPart(MimeKit.Text.TextFormat.Plain) { Text = text };
await client.SendAsync(message);

when checking against openssl everything is fine with the certs

openssl s_client -CApath /etc/ssl/certs/ -connect smtp.gmail.com:587 -starttls smtp
CONNECTED(00000003)
depth=2 OU = GlobalSign Root CA - R2, O = GlobalSign, CN = GlobalSign
verify return:1
depth=1 C = US, O = Google Trust Services, CN = GTS CA 1O1
verify return:1
depth=0 C = US, ST = California, L = Mountain View, O = Google LLC, CN = smtp.gmail.com
verify return:1
---
Certificate chain
 0 s:C = US, ST = California, L = Mountain View, O = Google LLC, CN = smtp.gmail.com
   i:C = US, O = Google Trust Services, CN = GTS CA 1O1
 1 s:C = US, O = Google Trust Services, CN = GTS CA 1O1
   i:OU = GlobalSign Root CA - R2, O = GlobalSign, CN = GlobalSign
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIFizCCBHOgAwIBAgIRALAfsBFF7jp2CAAAAAAqsrIwDQYJKoZIhvcNAQELBQAw
QjELMAkGA1UEBhMCVVMxHjAcBgNVBAoTFUdvb2dsZSBUcnVzdCBTZXJ2aWNlczET
MBEGA1UEAxMKR1RTIENBIDFPMTAeFw0yMDAxMjEwODE0NTdaFw0yMDA0MTQwODE0
NTdaMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQH
Ew1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKEwpHb29nbGUgTExDMRcwFQYDVQQDEw5z
bXRwLmdtYWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKg4
68gPXFngWV99XtDhpohHtfmkCFriYf6TJnc8kh0t8VnRjjwoDEt0uEkVyiTkAkjZ
cliqHcKf06h87fGmoA4FtnsKuBWhPeYPU76QR88tSmwDRI1TMcRJjRZmkRAypK+E
H3fHySbudMtdUnm5/G7WoWDtxKp8lAG8L2CHwgmDpgi2n/9TnQ2iZpu+L2SgDbbm
RXdSTo5RhkfDVZ8mVXqT61AFLX62x+0+GzoAh50Ye5145mC1ru7nH89Qno6xf6n+
XhTFmlJNbrORUCD5sHsehkEI4D/e+8O5ndIY7yz9G3uYwGhSm7kUBL5BLtYYH/1H
PyyN2WFiJ064xwcIKNECAwEAAaOCAlQwggJQMA4GA1UdDwEB/wQEAwIFoDATBgNV
HSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTbio0y2MGh
pZVCc2D6W2F1vaVdczAfBgNVHSMEGDAWgBSY0fhuEOvPm+xgnxiQG6DrfQn9KzBk
BggrBgEFBQcBAQRYMFYwJwYIKwYBBQUHMAGGG2h0dHA6Ly9vY3NwLnBraS5nb29n
L2d0czFvMTArBggrBgEFBQcwAoYfaHR0cDovL3BraS5nb29nL2dzcjIvR1RTMU8x
LmNydDAZBgNVHREEEjAQgg5zbXRwLmdtYWlsLmNvbTAhBgNVHSAEGjAYMAgGBmeB
DAECAjAMBgorBgEEAdZ5AgUDMC8GA1UdHwQoMCYwJKAioCCGHmh0dHA6Ly9jcmwu
cGtpLmdvb2cvR1RTMU8xLmNybDCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB2ALIe
BcyLos2KIE6HZvkruYolIGdr2vpw57JJUy3vi5BeAAABb8diMFoAAAQDAEcwRQIg
Z/KVgKafdXDy+ApADniOxmKR/vwjwkGX3vFoSXQSKlkCIQCLumhFIcD0T1QA4auf
2pD2tVXvfQPRdoKihSfgVRCcgQB2AF6nc/nfVsDntTZIfdBJ4DJ6kZoMhKESEoQY
dZaBcUVYAAABb8diMH4AAAQDAEcwRQIhAJjOvO183KgUETiIpAt99NAvZPrY1KOp
xF49fkGWic/pAiBdLafQlkyz25SQvXu8rcz7pFH5x04L4cW4WtTdm6WpBDANBgkq
hkiG9w0BAQsFAAOCAQEAUVjgtKD1pxkisLV9VStkhyqpgd9JJ/l1W92AcF/RZ3Yf
/72ARCDXpfha3IMmVpqfmKUP03Yo7xM3GBHjgPxRtq1K/Hd8xk/ovVZ0ihugCwf2
8FXpEpcbuPm/QBdL9uZg8B+kT3UBsYggN9qrEvXLfODL6HwRHNMN1K5xaJyeQOf8
JZ8HX/JwTQS7iHGLajv9cT3ABUq4En8hy3KdGscV+fPs/qLdmYCDHpTmCYxW7G7q
Q0NKvXY0waiffFy0hxSnhMLoU4n/b4Kiv1AeWb1ZgtO4IY8O5f6wdQIXD/fcEjEr
UDMjAw4Ooy4Szy8gw9eXpot8yaFeGqwqyQML4MF28w==
-----END CERTIFICATE-----
subject=C = US, ST = California, L = Mountain View, O = Google LLC, CN = smtp.gmail.com

issuer=C = US, O = Google Trust Services, CN = GTS CA 1O1

---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: RSA-PSS
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 3271 bytes and written 429 bytes
Verification: OK
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server public key is 2048 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
---
250 SMTPUTF8

help(?)

This issue was ultimately that OpenSSL’s hostname validation routine doesn’t allow underscores.

While underscores are permitted in DNS entries, they’re not legal for hostnames (https://datatracker.ietf.org/doc/html/rfc1034#section-3.5), which is why OpenSSL doesn’t consider it valid.

The CA/Browser forum doubled down on that when they issued a rule that public CAs can’t issue certs that contain underscores in SAN dNSName entries (and had to revoke any there were already so issued): https://cabforum.org/2018/11/12/ballot-sc-12-sunset-of-underscores-in-dnsnames/.