Google Cloud Endpoints Invalid JWT signature (.NET Core) [duplicate] - c#

I am using the following code, which I borrowed originally from the jwt-dotnet github page
private static string CreateToken(UserPrincipal principal)
{
/*
* https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims
* http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html
*/
var key = ConfigurationManager.AppSettings["jwt-key"];
var claims = new Dictionary<string, string>()
{
{ClaimTypes.Name, "Rainbow Dash" },
{ClaimTypes.WindowsAccountName, "RDash"}
};
var algorithm = new HMACSHA256Algorithm();
var serializer = new JsonNetSerializer();
var urlEncoder = new JwtBase64UrlEncoder();
var encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
var token = encoder.Encode(claims, key);
return token;
}
The above code generates the following token:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiUmFpbmJvdyBEYXNoIiwiaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93cy8yMDA4LzA2L2lkZW50aXR5L2NsYWltcy93aW5kb3dzYWNjb3VudG5hbWUiOiJSRGFzaCJ9.5WZWDJ0pvTe6QLjVNUeTfZicX_wSsk1dtYvXUbpiOiw
So, I hopped over to jwt.io to test my token. I'm told I have an invalid signature.
How do I give it a valid 'signature'? I don't understand what my JWT is missing.

The tool over JWT.io can verify the digital signature of your token if you give it the secret signing key you used while creating a token:
And from looking at your code it's the value contained in your:
ConfigurationManager.AppSettings["jwt-key"];
Just input the value inside the "secret" text box and if the signature of the token matches the one calculated by JWT.io then you'll get a message saying that the signature is valid.

Related

Correctly handle OCSP requests from C# / Java app (+ BouncyCastle)

I have an application (dotnet core with Bouncy Castle) that generates X509 certificates. Essential part of certificate management is also revoking them. I do support revoking by CRL currently, but there was a requirement from our vendor to implement OCSP as well. And here the problems started to appear.
I've implemented something that looks compatible with the RFC 6960 and with some random Java pieces that are doing something very similar.
However I am stuck with the following error that I could not figure out:
OCSP Request Data:
Version: 1 (0x0)
Requestor List:
Certificate ID:
Hash Algorithm: sha1
Issuer Name Hash: 5ED580C3E05BAB929E3B5FE31AF1FD2D63DA2B66
Issuer Key Hash: 0BA5610F200458E9183155354D0956598285F833
Serial Number: 2D9E89A741BE3BED
Request Extensions:
OCSP Nonce:
0410D596BF4A21EA59007CAD5AE306DCF349
Error querying OCSP responder
27384:error:0D0680A8:asn1 encoding routines:asn1_check_tlen:wrong tag:../openssl-1.1.1c/crypto/asn1/tasn_dec.c:1130:
27384:error:0D06C03A:asn1 encoding routines:asn1_d2i_ex_primitive:nested asn1 error:../openssl-1.1.1c/crypto/asn1/tasn_dec.c:694:
27384:error:0D08303A:asn1 encoding routines:asn1_template_noexp_d2i:nested asn1 error:../openssl-1.1.1c/crypto/asn1/tasn_dec.c:627:Field=responseStatus, Type=OCSP_RESPONSE
The configuration I am following is:
#1 root certificate - used to create all client certificates that can be revoked
#2 ocsp root certificate - generated separately used to sign ocsp responses
I am testing my code using the following command (from the command line):
$ openssl ocsp -issuer certs/root-ocsp.crt -cert client-cert.crt -text -url http://localhost:12345/certificate/ocsp
To be honest I have no more idea what may be wrong... Basing on the error, I suspect that something is wrong with Asn1 signatures, but after checking few options (including rootCert in chain, etc) result is the same all the time.
The crucial part of the code that generates OCSP response looks like this:
public byte[] GenerateOcsp(OcspReq ocspReq, IList<Certificate> certificates)
{
//Should be used at all for OCSP?
var rootCert = _rootCertificateProvider.GetBouncyRootCert("development");
var ocspCert = _rootCertificateProvider.GetBouncyRootCert("ocsp");
var respGen = new BasicOcspRespGenerator(ocspCert.Certificate.GetPublicKey());
var nonceExt = ocspReq.RequestExtensions.GetExtension(OcspObjectIdentifiers.PkixOcspNonce);
if (nonceExt != null)
respGen.SetResponseExtensions(new X509Extensions(new[] { OcspObjectIdentifiers.PkixOcspNonce }, new[] { nonceExt }));
foreach (var req in ocspReq.GetRequestList())
{
var serialNo = req.GetCertID().SerialNumber;
var dbCert = certificates.FirstOrDefault(c => BigInteger.ValueOf(c.SerialNumber).Equals(serialNo));
if (dbCert == null)
{
respGen.AddResponse(req.GetCertID(), new UnknownStatus());
}
else if (dbCert.Revocated)
{
respGen.AddResponse(req.GetCertID(), new RevokedStatus(dbCert.RevocationDate ?? DateTime.Now, 0));
}
else
{
respGen.AddResponse(req.GetCertID(), CertificateStatus.Good);
}
}
var random = new SecureRandom();
var signFactory = new Asn1SignatureFactory("SHA256WithRSA", ocspCert.PrivKey, random);
var ocspResponse = respGen.Generate(signFactory, new[] { ocspCert.Certificate }, DateTime.UtcNow);
return ocspResponse.GetEncoded();
}
Result is returned through the Controller like this:
return new FileContentResult(result, "application/ocsp-response");
Any ideas what may be wrong?
Thanks!
To all future people arriving to this question:
My overall approach in the question was good, the only thing missing was piping a result through an additional response generator.
So instead of returning ocspResponse.GetEncoded() you should do this and you are done:
var builder = new OCSPRespGenerator();
var response = builder.Generate(OCSPRespGenerator.Successful, ocspResponse);
return response.GetEncoded();

JSON Web Token Vulnerability test in C# review

I've attempted to check if the JWT Token Bearer support in WebAPI for .NET Framework 4.5 had the vulnerability as reported by https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/.
So I wrote the following code that takes an existing, valid JWT token, manipulates the header, regenerates the signature using the certificate public key and resend it to the server.
private static string TestSecurityVulnerability(string originalToken)
{
var parts = originalToken.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
var headerPart = Encoding.UTF8.GetString(Convert.FromBase64String(parts.First()));
var payloadPart = Encoding.UTF8.GetString(Convert.FromBase64String(parts.Skip(1).First()));
dynamic headerJson = JsonConvert.DeserializeObject(headerPart);
headerJson["alg"] = "HS256";
headerJson["kid"] = 0;
var tamperedHeaderEncoded = Base64UrlEncode(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(headerJson)));
var cert = Certificate.Load();
var publicKey = cert.PublicKey.EncodedKeyValue.RawData;
var base64PublicKey = Convert.ToBase64String(publicKey); //Not using it but great for verifying if token is "valid"
var sha = new HMACSHA256(publicKey);
var newSigBinary = sha.ComputeHash(Encoding.UTF8.GetBytes(tamperedHeaderEncoded + "." + parts.Skip(1).First()));
var newSigEncoded = Base64UrlEncode(newSigBinary);
return string.Join(".", tamperedHeaderEncoded,
parts.Skip(1).First(),
newSigEncoded);
}
// from JWT spec
private static string Base64UrlEncode(byte[] input)
{
var output = Convert.ToBase64String(input);
output = output.Split('=')[0]; // Remove any trailing '='s
output = output.Replace('+', '-'); // 62nd char of encoding
output = output.Replace('/', '_'); // 63rd char of encoding
return output;
}
As for Certificate.Load(), all it does is look up the certificate that I'm using on IdentityServer to sign the token and it returns with a System.Security.Cryptography.X509Certificates.X509Certificate2 certificate (PFX with public and private key).
I also inspected the value of base64PublicKey to see what the base64'd version is of the public key, to use that as the 256-bit-secret on jwt.io.
My question is, did I do everything correctly? I've checked my solution on https://jwt.io/ and it seems legit from the point of view that I'm signing the JWT correctly but I don't know if I am extracting the certificate correctly.
Would be great just to have a pair of eyes go through this and let me know.
P.S. with my current test the server came back saying "Unauthorized" ;-)

using Jwt-Dotnet to generate a valid token

I am using the following code, which I borrowed originally from the jwt-dotnet github page
private static string CreateToken(UserPrincipal principal)
{
/*
* https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims
* http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html
*/
var key = ConfigurationManager.AppSettings["jwt-key"];
var claims = new Dictionary<string, string>()
{
{ClaimTypes.Name, "Rainbow Dash" },
{ClaimTypes.WindowsAccountName, "RDash"}
};
var algorithm = new HMACSHA256Algorithm();
var serializer = new JsonNetSerializer();
var urlEncoder = new JwtBase64UrlEncoder();
var encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
var token = encoder.Encode(claims, key);
return token;
}
The above code generates the following token:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiUmFpbmJvdyBEYXNoIiwiaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93cy8yMDA4LzA2L2lkZW50aXR5L2NsYWltcy93aW5kb3dzYWNjb3VudG5hbWUiOiJSRGFzaCJ9.5WZWDJ0pvTe6QLjVNUeTfZicX_wSsk1dtYvXUbpiOiw
So, I hopped over to jwt.io to test my token. I'm told I have an invalid signature.
How do I give it a valid 'signature'? I don't understand what my JWT is missing.
The tool over JWT.io can verify the digital signature of your token if you give it the secret signing key you used while creating a token:
And from looking at your code it's the value contained in your:
ConfigurationManager.AppSettings["jwt-key"];
Just input the value inside the "secret" text box and if the signature of the token matches the one calculated by JWT.io then you'll get a message saying that the signature is valid.

Azure Media Service - generate new AES encryption token for playback

I am working on open source community project Azure Media Services Upload and Play Videos in MVC since 2015. I was not using any delivery encryption earlier, so I started working on AES.
In all the source code/samples by Azure Media Services Team, i noticed test token was being generated just after uploading the content and this works well in my case too. But, how do I generate test token next time onward for playback?
What I understood is that, we need token each time player requests playback. Technically, player creates a request to key service provider and received updated token.
So to get updated token, I tried couple of ways n not able to fix this, i see error "A ContentKey (Id = '...', Type = 'EnvelopeEncryption') which contains the same type already links to this asset".
This looks like a valid error message because key of type EnvelopeEncryption was already added and associated with asset after uploading content, and upon requesting again this pops-up.
The code given below is copied from here.
public ActionResult Index()
{
var model = new List<VideoViewModel>();
var videos = db.Videos.OrderByDescending(o => o.Id).ToList();
foreach (var video in videos)
{
var viewModel = new VideoViewModel();
viewModel.Id = video.Id;
viewModel.EncodedAssetId = video.EncodedAssetId;
viewModel.IsEncrypted = video.IsEncrypted;
viewModel.LocatorUri = video.LocatorUri;
// If encrypted content, then get token to play
if (video.IsEncrypted)
{
IAsset asset = GetAssetById(video.EncodedAssetId);
IContentKey key = CreateEnvelopeTypeContentKey(asset);
viewModel.Token = GenerateToken(key);
}
model.Add(viewModel);
}
return View(model);
}
Above method calls media service key service provider.
How do I fix this?
You can look into AMS explorer sources
when you creating a restriction policy yo are doing something like this:
//Initilizing ContentKeyAuthorizationPolicyRestriction
ContentKeyAuthorizationPolicyRestriction restriction = new ContentKeyAuthorizationPolicyRestriction
{
Name = "Authorization Policy with Token Restriction",
KeyRestrictionType = (int)ContentKeyRestrictionType.TokenRestricted,
Requirements = TokenRestrictionTemplateSerializer.Serialize(restrictionTemplate)};
restrictions.Add(restriction);
//Saving IContentKeyAuthorizationPolicyOption on server so it can be associated with IContentKeyAuthorizationPolicy
IContentKeyAuthorizationPolicyOption policyOption = objCloudMediaContext.ContentKeyAuthorizationPolicyOptions.Create("myDynamicEncryptionPolicy", ContentKeyDeliveryType.BaselineHttp, restrictions, String.Empty);
policy.Options.Add(policyOption);
//Saving Policy
policy.UpdateAsync();
Key field here is irements = TokenRestrictionTemplateSerializer.Serialize(restriction.Requirements)};
You need to fetch corresponding asset restriction you created first place and desirialize TokenRestriction Template back with
TokenRestrictionTemplate tokenTemplate = TokenRestrictionTemplateSerializer.Deserialize(tokenTemplateString);
Based on what type of key and encryption you use
if (tokenTemplate.PrimaryVerificationKey.GetType() == typeof(SymmetricVerificationKey))
{
InMemorySymmetricSecurityKey tokenSigningKey = new InMemorySymmetricSecurityKey((tokenTemplate.PrimaryVerificationKey as SymmetricVerificationKey).KeyValue);
signingcredentials = new SigningCredentials(tokenSigningKey, SecurityAlgorithms.HmacSha256Signature, SecurityAlgorithms.Sha256Digest);
}
else if (tokenTemplate.PrimaryVerificationKey.GetType() == typeof(X509CertTokenVerificationKey))
{
if (signingcredentials == null)
{
X509Certificate2 cert = DynamicEncryption.GetCertificateFromFile(true).Certificate;
if (cert != null) signingcredentials = new X509SigningCredentials(cert);
}
}
JwtSecurityToken token = new JwtSecurityToken(issuer: tokenTemplate.Issuer, audience: tokenTemplate.Audience, notBefore: DateTime.Now.AddMinutes(-5), expires: DateTime.Now.AddMinutes(Properties.Settings.Default.DefaultTokenDuration), signingCredentials: signingcredentials, claims: myclaims);
JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
string token = handler.WriteToken(token);

JwtHeader.SigningKeyIdentifier creates incorrect X509ThumbprintKeyIdentifierClause

I am trying to validate a JWT token. The code is within an OWIN OAuth handler, however I have taken the various pieces out into a small console application and it would appear to be a problem with how the JwtHeader method SigningKeyIdentifier creates a X509ThumbprintKeyIdentifierClause object.
My JWT has a header value of x5t = [base64urlencodedvalue], and I have confirmed that when this string is decoded it is indeed the thumbprint for my certificate. However, in the SigningKeyIdentifier class the following code seems to create a incorrect clause, e.g. the hash of the clause doesnt match the certificate.
identifier.Add(new X509ThumbprintKeyIdentifierClause(Base64UrlEncoder.DecodeBytes(this.GetStandardClaim("x5t"))));
Below is a snippet of the console app that tries to demostrate the issue:
// http://kjur.github.io/jsjws/tool_b64udec.html
const string X5T = "NmJmOGUxMzZlYjM2ZDRhNTZlYTA1YzdhZTRiOWE0NWI2M2JmOTc1ZA"; // value inside the JWT (x5t)
const string thumbPrint = "6bf8e136eb36d4a56ea05c7ae4b9a45b63bf975d"; // correct thumbprint of certificate
string thumbPrintBase64 = Base64UrlEncoder.Encode(thumbPrint); // <--- value in x5t of JWT
// finds correct certificate
var cert1 = X509CertificateHelper.FindByThumbprint(StoreName.My, StoreLocation.LocalMachine, thumbPrint).First();
var certHash = cert1.GetCertHash();
string hexa = BitConverter.ToString(certHash).Replace("-", string.Empty);
Console.WriteLine(hexa.ToLowerInvariant());
// TokenValidationParameters.IssuerSigningKey
var clause1 = new X509ThumbprintKeyIdentifierClause(cert1);
string hex1 = BitConverter.ToString(clause1.GetX509Thumbprint()).Replace("-", string.Empty);
Console.WriteLine(clause1.ToString());
Console.WriteLine(hex1.ToLowerInvariant());
// this is how JwtHeader.SigningKeyIdentifier method creates SecurityKeyIdentifier
var hash = Base64UrlEncoder.DecodeBytes(thumbPrintBase64);
var clause2 = new X509ThumbprintKeyIdentifierClause(hash); // <----- broken
string hexb = BitConverter.ToString(hash).Replace("-", string.Empty);
Console.WriteLine(hexb.ToLowerInvariant());
Console.WriteLine(clause2.ToString());
string hex2 = BitConverter.ToString(clause2.GetX509Thumbprint()).Replace("-", string.Empty);
Console.WriteLine(hex2.ToLowerInvariant());
// clause1 and clause2 should be the same, but they arent!?
The problem seems to be that the various consructors for X509ThumbprintKeyIdentifierClause end up with different hash values which when compared later dont match.
In my OWIN project one piece creates a X509ThumbprintKeyIdentifierClause from a certificate (TokenValidationParameters.IssuerSigningKey). e.g.
IssuerSigningKey = new X509SecurityKey(X509CertificateHelper.FindByThumbprint(StoreName.My, StoreLocation.LocalMachine, thumbPrint).First()),
and the IssuerSigningKeyResolver method called to match the JWT with the issue certificate using the thumbnail from the x5t field.
identifier.Add(new X509ThumbprintKeyIdentifierClause(Base64UrlEncoder.DecodeBytes(this.GetStandardClaim("x5t"))));
but they dont match.
What am I missing? Something feels wrong with the encoding/decoding of the thumbnail.
We had a great discussion about this in GitHub, should have posted here before.
https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/100
The input that is encoded and creates the x5t is not the 'thumbprint', which are encoded octets. but the octets from the certhash.
The JwtHeader creates the clause as:
ski.Add(new X509ThumbprintKeyIdentifierClause(Base64UrlEncoder.DecodeBytes(GetStandardClaim(JwtHeaderParameterNames.X5t))));
Not:
var hash = Base64UrlEncoder.DecodeBytes(thumbPrintBase64);

Categories

Resources