6

I was trying to obtain JWT token from Microsoft Azure Active Directory using Certificate credentials for application authentication.

I am struck at figuring out the value of "x5t".

I have tried with

  • SHA-1 fingerprint value available in the public certificate.
  • SHA-1 hash of the public certificate using FVIC.

But i keep getting below error when send the request to MSA login endpoint

{
    "error": "invalid_client",
    "error_description": "AADSTS70002: Error validating credentials. AADSTS50012: Client assertion contains an invalid signature. [Reason - The key was not found., Thumbprint of key used by client: '6F67F76B96F6FBBDF9D3EE1DDF7F9A7B877EE9C75DEDBD3DE9C7FB', Configured keys: [Key0:Start=06/01/2018, End=12/31/2099, Thumbprint=6WGktXA64QmA9TPv;Key1:Start=06/01/2018, End=12/31/2099, Thumbprint=rD9Q10sR6Q6ZkDVw;]]\r\nTrace ID: d9e3e276-e878-4b8a-b08b-10c82a0b0600\r\nCorrelation ID: 48ec889d-2376-45a6-9bf0-01b22b0e0c17\r\nTimestamp: 2018-06-01 09:38:24Z",
    "error_codes": [
        70002,
        50012
    ],
    "timestamp": "2018-06-01 09:38:24Z",
    "trace_id": "d9e3e276-e878-4b8a-b08b-10c82a0b0600",
    "correlation_id": "48ec889d-2376-45a6-9bf0-01b22b0e0c17"
}

How to obtain the value for "x5t" ?

Nancy
  • 26,865
  • 3
  • 18
  • 34
Harinder
  • 116
  • 1
  • 1
  • 11

4 Answers4

16

I found this site and this one invaluable for solving the x5t issue. The easiest way to do it is to manually get the fingerprint:

echo $(openssl x509 -in your.cert.pem -fingerprint -noout) | sed 's/SHA1 Fingerprint=//g' | sed 's/://g' | xxd -r -ps | base64

the value from the above command is the value you put in the x5t field in the JWT. Prior to that I was getting invalid fingerprint error from azure.

If you're using Ruby you can follow this answer to get:

p12 = OpenSSL::PKCS12.new(File.read(CERT_FILE), '')
x509_sha1_thumbprint = Base64.encode64(OpenSSL::Digest::SHA1.new(p12.certificate.to_der).digest).strip
jwt_token = JWT.encode payload, p12.key, 'RS256', { typ: 'JWT', x5t: x509_sha1_thumbprint }
sj26
  • 6,725
  • 2
  • 27
  • 24
codebrane
  • 4,290
  • 2
  • 18
  • 27
  • Thank you for the explanation. On my Mac+Chrome, the _scroll bar_ is kind of annoying when I want to read the (first) command (where you retrieve the fingerprint). I cannot read properly because when I scroll the _scroll bar_ stays. Assuming a lot of Mac+Chrome users encounter the same problem, I'd say editing it somehow (i.e. with a new line after the command) would improve readability. – chriszo111 Jan 14 '19 at 10:44
  • on my Mac+Chrome it scrolls ok – codebrane Jan 14 '19 at 15:44
  • What do you consider „ok“? Because the scroll is fine, it’s the bar that is positioned quite bad :) – chriszo111 Jan 14 '19 at 16:51
  • I used this approach and it worked. You saved me quite some work @codebrane! – Haris Osmanagić May 29 '19 at 16:00
  • There's a slightly simpler way to generate the digest without parsing hex: `OpenSSL::Digest::SHA1.new(p12.certificate.to_der).digest` – sj26 Oct 28 '22 at 20:17
2

The x5t should be the X509 certificate's SHA-1 thumbprint, base64url-encoded:

4.1.7. "x5t" (X.509 Certificate SHA-1 Thumbprint) Header Parameter

The "x5t" (X.509 certificate SHA-1 thumbprint) Header Parameter is a base64url-encoded SHA-1 thumbprint (a.k.a. digest) of the DER encoding of the X.509 certificate [RFC5280] corresponding to the key used to digitally sign the JWS. Note that certificate thumbprints are also sometimes known as certificate fingerprints. Use of this Header Parameter is OPTIONAL.

Source: RFC7515 — https://www.rfc-editor.org/rfc/rfc7515#section-4.1.7

Community
  • 1
  • 1
evilSnobu
  • 24,582
  • 8
  • 41
  • 71
  • 2
    Hi @evilSnobu, Thank for the info. However i am still not able to figure out how Microsoft could get the values published in "x5t" listed [here](https://login.botframework.com/v1/.well-known/keys). If i copy the value of "x5c" at any online X.509 decoder, they doesn't match with the processed value from certificate's hash. – Harinder Jun 04 '18 at 12:32
0

In Powershell 7.x, this goes like this. Important: Do not use the thumbprint from the cert to calculate x5t but instead do it like below,

$CertThumbPrint = '<Thumbprint of your cert with private key, stored in machine/Personal'
$CertificatePath = "cert:\localmachine\my\$CertThumbPrint" #<Add the Certificate Path Including Thumbprint here e.g. cert:\currentuser\my\6C1EE1A11F57F2495B57A567211220E0ADD72DC1 >#
$Cert = Get-Item -Path $CertificatePath

# *** use this (and comment the above line) if you want to load the cert from a pfx file instead of getting it from the machine cert store
#$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2((join-path -path $PSScriptRoot -ChildPath "ExtractContractsFrom-ITSystemMBX.pfx"),"<PFX password>")

$CertificateBase64Hash = [System.Convert]::ToBase64String($cert.GetCertHash())

# Use the CertificateBase64Hash and replace/strip to match web encoding of base64
$x5t = $CertificateBase64Hash -replace '\+','-' -replace '/','_' -replace '='
John Ranger
  • 541
  • 5
  • 18
0

When I used the below command, it was not generating the correct fingerprint because my default fingerprint output was SHA256 and not SHA1.

echo $(openssl x509 -in your.cert.pem -fingerprint -noout) | sed 's/SHA1 Fingerprint=//g' | sed 's/://g' | xxd -r -ps | base64

So I updated the command to output fingerprint specifically in SHA1 as below, and it worked. Same command also worked for .crt file format of certificate:

echo $(openssl x509 -in your.cert.pem -fingerprint -sha1 -noout) | sed 's/SHA1 Fingerprint=//g' | sed 's/://g' | xxd -r -ps | base64

Another way to get the fingerprint for Microsoft Azure is to utilize the thumbprint generated after uploading of the certificate. Use the thumbprint column value to generate it. enter image description here

echo "THUMBRINT COLUMN VALUE" |xxd -r -p| openssl enc -a

OR

echo "THUMBRINT COLUMN VALUE" |xxd -r -p| base64
PRASHANT KUMAR
  • 185
  • 2
  • 3
  • 11