Reputation: 2612
I am trying to verify ES512 jwt token using public key which is in string format:
I am trying to imitate a sample written for ES256 which is something like this:
// The code for ES256
public static void VerifyES512Jwt(string token,string publicKey)
{
byte[] publicKeyBytes = Convert.FromBase64String(publicKey);
string[] parts = token.Split('.');
string header = parts[0];
string payload = parts[1];
string signature = parts[2];
var keyType = new byte[] { 0x45, 0x43, 0x53, 0x31 };
var keyLength = new byte[] { 0x20, 0x00, 0x00, 0x00 };
var key = keyType.Concat(keyLength).Concat(publicKeyBytes.Skip(publicKeyBytes.Length - 64)).ToArray();
CngKey cngKey = CngKey.Import(key, CngKeyBlobFormat.EccPublicBlob);
// the purpose is to get ECDsaCng and verify the payload data
ECDsaCng eCDsaCng = new ECDsaCng(cngKey);
bool result = eCDsaCng.VerifyData(payload, signatureBytes);
}
I am trying to use this code for ES512 and got stuck on getting the key
var keyType = new byte[] { 0x45, 0x43, 0x53, 0x31 };
var keyLength = new byte[] { 0x20, 0x00, 0x00, 0x00 };
var key = keyType.Concat(keyLength).Concat(publicKeyBytes.Skip(publicKeyBytes.Length - 64)).ToArray();
when used with the above it gives error in getting key:
CngKey cngKey = CngKey.Import(key, CngKeyBlobFormat.EccPublicBlob);
The public key and token I am using are as follows: public key:
MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBgc4HZz+/fBbC7lmEww0AO3NK9wVZ PDZ0VEnsaUFLEYpTzb90nITtJUcPUbvOsdZIZ1Q8fnbquAYgxXL5UgHMoywAib47 6MkyyYgPk0BXZq3mq4zImTRNuaU9slj9TVJ3ScT3L1bXwVuPJDzpr5GOFpaj+WwM Al8G7CqwoJOsW7Kddns=
Token:
eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzUxMiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE1NjUwOTk2ODgsImV4cCI6MTU5ODE4OTg4NSwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdDozNTg4Iiwic3ViIjoiaHR0cDovL2xvY2FsaG9zdDo1MDM3NiIsImZpcnN0bmFtZSI6IkFydmluZCIsImxhc3RuYW1lIjoiS3VtYXIiLCJFbWFpbCI6ImFydmluZC5rdW1hckBzdHJlYW1hbWcuY29tIiwiSWQiOiIxMDEifQ.AVwAJeY44lKrnywnDs7CdUOu3gli2cGafSJ6iP3zT7lkZpd2QnL0k54aVmPVxAGuN5dDnzbYmMTdRl5u2QE92ccOAHrcf5yA2gsvhhAGuDAAeh6Io4VU7v5TOTvwWGRb-ubgdjUvagA_HSJOyeXvFR16_M_MzGfDnXfg02sj4y9VFjDr
Upvotes: 3
Views: 4900
Reputation: 2612
I generated the key as suggested by @Topaco and used it with JwtSecurityTokenHandler of identity model and it worked. the function which i was trying to use in question did not work for some reasons: The working code is as follows:
public static bool ValidateEcdsa512JwtToken(string token, string publicKey)
{
ECDsa pubKey = LoadPublicKey(publicKey);
var securityTokenHandler = new JwtSecurityTokenHandler();
var validationParameters = new TokenValidationParameters()
{
ValidateAudience = false,
ValidateIssuer = false,
IssuerSigningKey = new ECDsaSecurityKey(pubKey)
};
SecurityToken stoken;
var claims = securityTokenHandler.ValidateToken(token, validationParameters, out stoken);
var verified=claims.Identity.IsAuthenticated;
return verified;
}
private static ECDsa LoadPublicKey(string publicKey)
{
byte[] publicKeyBytes = Convert.FromBase64String(publicKey);
var keyType = new byte[] { 0x45, 0x43, 0x53, 0x35 };
var keyLength = new byte[] { 0x42, 0x00, 0x00, 0x00 };
var key = keyType.Concat(keyLength).Concat(publicKeyBytes.Skip(publicKeyBytes.Length - 132)).ToArray();
CngKey cngKey = CngKey.Import(key, CngKeyBlobFormat.EccPublicBlob);
ECDsaCng eCDsaCng = new ECDsaCng(cngKey);
eCDsaCng.HashAlgorithm = CngAlgorithm.ECDsaP521;
return eCDsaCng;
}
Upvotes: 1
Reputation: 49470
ES512 uses ECDSA with P-521 and SHA-512.
A public key for P-521 (secp521r1, chap. 2.6.1) has a size of 2 x 66 = 132
bytes in uncompressed form (front byte 0x04
). MS specifies the public key for P-521 with the value 0x35534345
.
The key must therefore be generated as follows:
var keyType = new byte[] { 0x45, 0x43, 0x53, 0x35 };
var keyLength = new byte[] { 0x42, 0x00, 0x00, 0x00 };
var key = keyType.Concat(keyLength).Concat(publicKeyBytes.Skip(publicKeyBytes.Length - 132)).ToArray();
The data to be signed are header and payload (both Base64url encoded) including the separator (.
). The signature is also Base64url encoded. The verification must therefore be performed as follows:
byte[] headerPayloadBytes = Encoding.UTF8.GetBytes(header + "." + payload);
byte[] signatureBytes = Base64UrlDecode(signature);
bool verified = eCDsaCng.VerifyData(headerPayloadBytes, signatureBytes, HashAlgorithmName.SHA512);
Base64UrlDecode
accomplishes the Base64url decoding, see e.g. here for implementation details.
Upvotes: 1