前提・実現したいこと
SafetynetのJWT検証をするためにこちらのSampleを試しているのですが、JwtSecurityTokenに埋め込まれたX509セキュリティキーを取得する箇所でNullReferenceExceptionエラーが出ます
c#
1keys = (token.Header["x5c"] as JArray)
なぜキャストが失敗するのかがわかりません.
Microsoft.IdentityModel.Json.Linq.Jarrray」タイプのオブジェクトを「Newtonsoft.Json.Linq.Jarrray」タイプにキャストしたいです.
検証する対象のJWTはjwt.ioにて確認したところ特に問題はないと思います.
HEADER:ALGORITHM & TOKEN TYPE
{
"alg": "RS256",
"x5c": [ "文字列1",
"文字列2",
"文字列3"
]
}
コード側でtoken.Header["x5c"].ToString()としてみると上記と同じ
[ "文字列1",
"文字列2",
"文字列3"
]
がとれます.
発生している問題・エラーメッセージ
エラーメッセージ { "errorType": "NullReferenceException", "errorMessage": "Object reference not set to an instance of an object.", "stackTrace": [ "at AWSLambdaSafetyNetVerify.OfflineVerify.GetEmbeddedKeys(JwtSecurityToken token) in D:\Myfolder\Documents\SafetyNetCsharpLambda\VisualStudioProject\AWSLambdaSafetyNetVerify\OfflineVerify.cs:line 172", "at AWSLambdaSafetyNetVerify.OfflineVerify.ParseAndVerify(String signedAttestationStatement) in D:\Myfolder\Documents\SafetyNetCsharpLambda\VisualStudioProject\AWSLambdaSafetyNetVerify\OfflineVerify.cs:line 57", "at AWSLambdaSafetyNetVerify.Function.SafetyNetAnalysisSignature(String jwt) in D:\Myfolder\Documents\SafetyNetCsharpLambda\VisualStudioProject\AWSLambdaSafetyNetVerify\Function.cs:line 119", "at AWSLambdaSafetyNetVerify.Function.MyMethod(Object input) in D:\Myfolder\Documents\SafetyNetCsharpLambda\VisualStudioProject\AWSLambdaSafetyNetVerify\Function.cs:line 54", "at lambda_method(Closure , Stream , Stream , LambdaContextInternal )" ]
該当のソースコード
c#
1using Microsoft.IdentityModel.Tokens; 2using Newtonsoft.Json.Linq; 3using System; 4using System.Collections.Generic; 5using System.IdentityModel.Tokens.Jwt; 6using System.Linq; 7using System.Security.Cryptography; 8using System.Security.Cryptography.X509Certificates; 9 10namespace SafetyNetCheck 11{ 12 /// <summary> 13 /// Sample code to verify the device attestation offline. 14 /// </summary> 15 public static class OfflineVerify 16 { 17 /// <summary> 18 /// Parses and verifies a SafetyNet attestation statement. 19 /// </summary> 20 /// <param name="signedAttestationStatement">A string containing the 21 /// JWT attestation statement.</param> 22 /// <returns>A parsed attestation statement. null if the statement is 23 /// invalid.</returns> 24 public static AttestationStatement ParseAndVerify( 25 string signedAttestationStatement) 26 { 27 // First parse the token and get the embedded keys. 28 JwtSecurityToken token; 29 try 30 { 31 token = new JwtSecurityToken(signedAttestationStatement); 32 } 33 catch (ArgumentException) 34 { 35 // The token is not in a valid JWS format. 36 return null; 37 } 38 39 // We just want to validate the authenticity of the certificate. 40 var validationParameters = new TokenValidationParameters 41 { 42 ValidateIssuer = false, 43 ValidateAudience = false, 44 ValidateLifetime = false, 45 ValidateIssuerSigningKey = true, 46 IssuerSigningKeys = GetEmbeddedKeys(token) 47 }; 48 49 // Perform the validation 50 var tokenHandler = new JwtSecurityTokenHandler(); 51 SecurityToken validatedToken; 52 try 53 { 54 tokenHandler.ValidateToken( 55 signedAttestationStatement, 56 validationParameters, 57 out validatedToken); 58 } 59 catch (ArgumentException) 60 { 61 // Signature validation failed. 62 return null; 63 } 64 65 // Verify the hostname 66 if (!(validatedToken.SigningKey is X509SecurityKey)) 67 { 68 // The signing key is invalid. 69 return null; 70 } 71 if (!VerifyHostname( 72 "attest.android.com", 73 validatedToken.SigningKey as X509SecurityKey)) 74 { 75 // The certificate isn't issued for the hostname 76 // attest.android.com. 77 return null; 78 } 79 80 // Parse and use the data JSON. 81 Dictionary<string, string> claimsDictionary = token.Claims 82 .ToDictionary(x => x.Type, x => x.Value); 83 84 return new AttestationStatement(claimsDictionary); 85 } 86 87 /// <summary> 88 /// Verifes an X509Security key, and checks that it is issued for a 89 /// given hostname. 90 /// </summary> 91 /// <param name="hostname">The hostname to check to.</param> 92 /// <param name="securityKey">The security key to verify.</param> 93 /// <returns>true if securityKey is valid and is issued to the given 94 /// hostname.</returns> 95 private static bool VerifyHostname( 96 string hostname, 97 X509SecurityKey securityKey) 98 { 99 string commonName; 100 try 101 { 102 // Verify the certificate with Verify(). Alternatively, you 103 // could use the commented code below instead of Verify(), to 104 // get more details of why a particular verification failed. 105 // 106 // var chain = new X509Chain(); 107 // var chainBuilt = chain.Build(securityKey.Certificate); 108 // if (!chainBuilt) 109 // { 110 // string s; // One could use a StringBuilder instead. 111 // foreach (X509ChainStatus chainStatus in 112 // chain.ChainStatus) 113 // { 114 // s += string.Format( 115 // "Chain error: {0} {1}\n", 116 // chainStatus.Status, 117 // chainStatus.StatusInformation); 118 // } 119 // } 120 if (!securityKey.Certificate.Verify()) 121 { 122 return false; 123 } 124 125 commonName = securityKey.Certificate.GetNameInfo( 126 X509NameType.DnsName, false); 127 } 128 catch (CryptographicException) 129 { 130 return false; 131 } 132 return (commonName == hostname); 133 } 134 135 /// <summary> 136 /// Retrieves the X509 security keys embedded in a JwtSecurityToken. 137 /// </summary> 138 /// <param name="token">The token where the keys are to be retrieved 139 /// from.</param> 140 /// <returns>The embedded security keys. null if there are no keys in 141 /// the security token.</returns> 142 /// <exception cref="KeyNotFoundException">Thrown when the JWT data 143 /// does not contain a valid signature 144 /// header "x5c".</exception> 145 /// <exception cref="CryptographicException">Thrwon when the JWT data 146 /// does not contain valid signing 147 /// keys.</exception> 148 private static X509SecurityKey[] GetEmbeddedKeys( 149 JwtSecurityToken token) 150 { 151 // The certificates are embedded in the "x5c" part of the header. 152 // We extract them, parse them, and then create X509 keys out of 153 // them. 154 X509SecurityKey[] keys = null; 155 keys = (token.Header["x5c"] as JArray) //<=========ここでエラー. キャストできない為 nullになる 156 .Values<string>() 157 .Select(x => new X509SecurityKey( 158 new X509Certificate2(Convert.FromBase64String(x)))) 159 .ToArray(); 160 return keys; 161 } 162 } 163} 164
補足情報(FW/ツールのバージョンなど)
Windows10 64bit
Microsoft Visual Studio Community 2019 Version 16.10.4
Newtonsoft.Json 13.0.1
System.IdentityModel.Tokens.Jwt 6.12.0
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/08/14 12:40