Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Detection for missing intermediate certificate for leaf cert used by Transport #2030

Open
richfaj opened this issue Mar 7, 2024 · 2 comments
Assignees
Labels
Milestone

Comments

@richfaj
Copy link
Member

richfaj commented Mar 7, 2024

Is your request related to a problem? Please describe.
UntrustedRoot is an error surfaced in Message Tracking Logs/Message Trace when the root certificate is not trusted or less commonly known a missing intermediate certificate during TLS negotiation.

Take the following scenario:
Exchange Online tenant is containing an outbound connector configured to enforce certificate validation. Mail is sent from Exchange Online to On-Premises. During TLS negotiation On-Premises only presents the leaf certificate and does not include any intermediate certs. This can be verified in a network packet capture.

Exchange Online will defer the message and surface the error "UntrustedRoot".

Describe The Request
Disabling downloading of certificates may be one cause to this issue. Can this be detected and surfaced in health checker? Can we detect if exchange is using a certificate that does not have the full chain installed in certificate store?

Additional context
Add any other context or screenshots about the feature request here.

@bill-long
Copy link
Member

Looks like we can take the Thumbprint from Get-ExchangeCertificate and the load the certificate from the store:

$c = Get-ChildItem -Path cert:\LocalMachine\My\48D58B180F99D1FC047654D6B8F2958A736DF465

Note this assumes it's in the My store and not some other place. I guess we would need to check all of them? Anyway once we have the cert we can build the cert chain:

$chain = New-Object System.Security.Cryptography.X509Certificates.X509Chain
$chain.Build($c.RawData)

At this point, $chain.ChainElements has 3 certs - leaf, intermediate, and root. But I'm not sure how this looks on a machine that doesn't have all the certs locally. We probably need to see what this object looks like when the machine is in that state.

@dpaulson45 dpaulson45 added enhancement New feature or request Health Checker P2 labels Mar 7, 2024
@dpaulson45 dpaulson45 added this to the Backlog milestone Mar 7, 2024
@NBIX-Matt-DeWall
Copy link

I could be wildly off topic, but in a related issue I was facing I noticed my "Build" would come back with 2 certs in the chain, rather than the 3 that I knew were in a .pfx file. Adding my findings here, as it may help in the "when the machine is in that state" issue. I came upon this thread which seems somewhat related, so I figured I'd save someone some time of doing the research...

There seems to a bug or 'curious design decision' on how certificate chains are built in Windows. On a fresh machine with no trust to our internal CA, I was trying to import the entire chain from a .pfx file. The entire chain is present in the file.

$pfx = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
$pfx.Import($CertificateFilePath, $CertificatePassword, [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable)

# Try to view chain
$chain = New-Object System.Security.Cryptography.X509Certificates.X509Chain
$chain.Build($pfx) | Out-Null

# Chain elements shows... 2
$chain.ChainElements.count

# I know there are 3 certs in there.  I think build chain fails because the root isn't yet trusted.

# Load the PFX as a collection instead...
$collection = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2Collection
$collection.Import($CertificateFilePath, $CertificatePassword, [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable)

# Collection correctly shows 3!
$collection.count

# If I import just the root (verify your index, mine was cert #3, index 2)
$tempFile = [System.IO.Path]::GetTempFileName()

# Export root (index 2) to file because import-certificate can't handle objects
[System.IO.File]::WriteAllBytes($tempFile, $collection[2].RawData)

Import-Certificate -CertStoreLocation "Cert:\LocalMachine\Root" -FilePath $tempFile
Remove-Item -Path $tempFile

# Now building the chain again.
$chain.Build($pfx) | Out-Null

# Chain elements will show 3!!!
$chain.ChainElements.count

I tried the same experiment with just importing the intermediate. It still showed 2 certificates in the chain. So it's seems your root CA must be in your store at build time.

Anyway, hope this helps...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants