Подписать пользовательский токен формата JWT, используя метод SignAsyn c из azure, и выполнить проверку в автономном режиме - PullRequest
0 голосов
/ 05 марта 2020
 var byteData = Encoding.Unicode.GetBytes( encodedSerializedHeader + "." + encodedPayload);
            var hasher = new SHA256CryptoServiceProvider();
            var digest = hasher.ComputeHash(byteData);



           var  signature = await keyVaultClient.SignAsync("https://offline-token-api.vault.azure.net/keys/offlinetokenprime256v1cert/3e99b8ce5dkkk3d4fb8bc6a645e7c6aa5de",
                     SecurityAlgorithms.EcdsaSha256, digest);
var encodedSignature = Base64UrlEncoder.Encode(signature.Result);

Now to fetch the public key for verification i am using following:- 

 var secret = keyVaultClient.GetSecretAsync(vaultAddress, "offlinetokenprime256v1cert").GetAwaiter().GetResult();
  X509Certificate2Collection exportedCertCollection = new X509Certificate2Collection();
            exportedCertCollection.Import(Convert.FromBase64String(secret.Value));

            X509Certificate2 certFromSecret = exportedCertCollection.Cast<X509Certificate2>().Single(s => s.HasPrivateKey);
            var publickeybyte = certFromSecret.GetPublicKey();
            var publicekeybyte = certFromSecret.GetPublicKeyString();
            var privatek = certFromSecret.GetECDsaPrivateKey();
            var publicECDsa = LoadPublicKey(FromHexString(publicekeybyte));
            var pubpri = certFromSecret.GetECDsaPublicKey();

            var privateECDsa = LoadPrivateKey(FromHexString(privateKey));
            var publiccECDsa = LoadPublicKey(FromHexString(publicKey));


for offline verification -

var securityToken = new JwtSecurityToken(token);
                var securityTokenHandler = new JwtSecurityTokenHandler();
                IdentityModelEventSource.ShowPII = true;
              var validationParameters = new TokenValidationParameters()
                {
                    ValidIssuer = securityToken.Issuer,
                    ValidAudience = securityToken.Audiences.First(),
                    IssuerSigningKey = new ECDsaSecurityKey(eCDsa)
                };

                SecurityToken stoken;
                var claims = securityTokenHandler.ValidateToken(token, validationParameters, out stoken);
                return true;

Но я получаю сообщение об ошибке, это не работает, у кого-то есть другое решение для того же? Я хочу подписать свой токен без извлечения секретного ключа из хранилища и хочу подписать информацию, заключенную в токене jwt. Любой способ подписать токен с помощью signasyn c и проверить в автономном режиме?

1 Ответ

0 голосов
/ 06 марта 2020

Насколько я знаю, пользователи не могут получить закрытые ключи от ключа хранилища ключей Azure. Только ключ publi c может быть восстановлен.

Вот образец, который я использовал для подписи и проверки:

    KeyVaultClient kvc = new KeyVaultClient(AuthenticationCallback);

    var key = kvc.GetKeyAsync(baseUrl, "ECDSA").GetAwaiter().GetResult();
    var parameters = key.Key.ToECDsa().ExportParameters(false);

    var pubKeyX = parameters.Q.X;
    var pubKeyY = parameters.Q.Y;

    // You can store X and Y, so that you may not need to get them from Azure Key Vault again
    // Use X and Y to create ECDsa instance
    var ecdsa = ECDsa.Create(new System.Security.Cryptography.ECParameters
    {
        Curve = ECCurve.NamedCurves.nistP256,
        Q = new ECPoint
        {
            X = pubKeyX,
            Y = pubKeyY
        }
    });

    // Generate JWT 
    var now = DateTime.UtcNow;

    var claims = new List<Claim>()
    {
        new Claim(JwtRegisteredClaimNames.Sub, "jack"),
        new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
        new Claim(JwtRegisteredClaimNames.Email, "jack@hanxia.onmicrosoft.com", ClaimValueTypes.String)
    };

    var jwt = new JwtSecurityToken(
        issuer: "aaa",
        audience: "bbb",
        claims: claims,
        notBefore: now,
        expires: now.AddHours(1)
    );

    var header = Base64UrlEncoder.Encode(JsonConvert.SerializeObject(new Dictionary<string, string>()
    {
        { JwtHeaderParameterNames.Alg, "ES256" },
        { JwtHeaderParameterNames.Kid, key.KeyIdentifier.ToString() },
        { JwtHeaderParameterNames.Typ, "JWT" }
    }));

    // Sign
    var byteData = Encoding.UTF8.GetBytes($"{header}.{jwt.EncodedPayload}");
    var hasher = new SHA256CryptoServiceProvider();
    var digest = hasher.ComputeHash(byteData);
    var result = kvc.SignAsync(key.KeyIdentifier.ToString(), "ES256", digest).GetAwaiter().GetResult().Result;

    var signature = Base64UrlEncoder.Encode(result);

    // Verify
    var tokenHandler = new JwtSecurityTokenHandler();
    var claimsPrincipal = tokenHandler.ValidateToken($"{header}.{jwt.EncodedPayload}.{signature}", new TokenValidationParameters
    {
        ValidIssuer = "aaa",
        ValidAudience = "bbb",
        IssuerSigningKey = new ECDsaSecurityKey(ecdsa)
    }, out var parsedToken);
...