2015-09-22 11 views
2

Я пытаюсь проверить токен JWT, проверив его подпись. Но во время проверки я получаю сообщение об ошибкене удалось проверить подпись jwt в Java

java.security.SignatureException: длина подписи не правильно: есть 342, но ожидал 256

. Я предполагаю, что подпись - это зашифрованный sha256 хэш данных. В моем случае данные: base64 (header) + "." + Base64 (body). Вот мой код:

static String certificate = "MIIDBjCCAe4CCQDmPif23IJerzANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMB4XDTE1MDkyMjA3MDkwMFoXDTE2MDkyMTA3MDkwMFowRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALYjKc8pLFkAa45j6w6PHsroe7ijOCfhZmVtMCvZ8lINaP9mR8irOJHpLdJs4vpbxEZMqqLMhKjO7iUmXBmml37QRlJXY6f25essPkTdUmhiIrU/rIrZrCanvegXUHkvf4xvOQ1BTx/p5b1iIq3Wrk5Fox3pMigzqYhk4YuiJho8uabC9zyecmS3zIoRgwx+Vacel/ZW6r6YOlB6mblN9IvasvqWgDalegmMKOIZvwkpo/3mfzcGi5haWZZ3ufUqQjb4B7raJmfyrLnwi6XI9UzzGc04pCfIAsxTb5yM8cJQcJ/5VHF3h21eFJdZKyD2210gSq7/Y8Oda0dDXQchmFcCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAmBm84PfwOe5sGemT9D4ImIYWp/1xrV6b0zeaDZ6Yi7sz9R3VKjfnAxUVOHA7GlMi8xHHdDu7VhVhAWyFCvITdG00K18xJuKap1bwzw3kr70lLQaFahV+zaWKfWAfV34tots3G/hMqdOv0a+I/5t/T7oKPCmm/IfCVKdC1tGbTji+hxVLpaAkn60RFNzLKGFwtSxv9ObxR5Hn88+wV48VAcEnwcUk2DjBi1fW6jnMcNJbVd+/oKBOwj7UK2Lk10Qaeet8KKh5fFKEpgx7D4ITwer0G/Je1NMv1/lfNzpKlTKoBureF5C6B+rJIesQ/dAfg6H/ggxbgVMuo6imIPVvrg=="; 
static String signedData = "Z5MwwjtXdypMQGNwmNNuCVmRcDVT24EgtwoDWalF4icxwz7jyB99Yg3262D7OsERewv4cOfdEz3bbOF-iG7YWXeSC9YZeO1tGapqlc8FRtAergSUZC7BcbFEx75MfSy7qLWYTOfdpJesQ23rOzjF7KdrAMJC_Y0T_r6RuBcZVyfT4P55kICETYyv7bBDXc9V8BJUf-QHDu6DaH7u6PSyeOmdzFInI_LwySnMlr3VahoUfUpJmauU8yHQUnFakJBgrMBe1Au9tS-HxtDVnHmoHQw8xGXsVQnEOa1aPAcVWy0v7hILUSmWNAG3IZ0JwUztQitgtnTTzXDszUxTbJ4YlQ"; 

static String data = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik1uQ19WWmNBVGZNNXBPWWlKSE1iYTlnb0VLWSIsImtpZCI6Ik1uQ19WWmNBVGZNNXBPWWlKSE1iYTlnb0VLWSJ9.eyJhdWQiOiJodHRwczovL2NpdHJpeHAuY29tOjg0NDMvIiwiaXNzIjoiaHR0cHM6Ly9zdHMud2luZG93cy5uZXQvZGQ5YjZhM2UtMjlkMS00MjU0LWE3NDYtZTAyOTQxNDQ0NTE3LyIsImlhdCI6MTQ0MjYyNjA0NSwibmJmIjoxNDQyNjI2MDQ1LCJleHAiOjE0NDI2Mjk5NDUsInZlciI6IjEuMCIsInRpZCI6ImRkOWI2YTNlLTI5ZDEtNDI1NC1hNzQ2LWUwMjk0MTQ0NDUxNyIsIm9pZCI6ImJkZDNmZDAyLTEyMzMtNGMxOC05NTRmLWJkNGFjMWYzOWU5OSIsInVwbiI6InNwQGNpdHJpeHAuY29tIiwic3ViIjoieUFfZTFzMmFOeFdvR3NSNzhfVWNYZkk5dERlYUM0QUozdXFZQXFDdllSbyIsImdpdmVuX25hbWUiOiJzIiwiZmFtaWx5X25hbWUiOiJwIiwibmFtZSI6InNwIiwiYW1yIjpbInB3ZCIsInJzYSJdLCJ1bmlxdWVfbmFtZSI6InNwQGNpdHJpeHAuY29tIiwiYXBwaWQiOiIyOWQ5ZWQ5OC1hNDY5LTQ1MzYtYWRlMi1mOTgxYmMxZDYwNWUiLCJhcHBpZGFjciI6IjAiLCJzY3AiOiJtZG1fZGVsZWdhdGlvbiIsImFjciI6IjEiLCJpcGFkZHIiOiI2My4xMTAuNTEuMTEiLCJkZXZpY2VpZCI6ImQyNzU3NzY0LWFiOTEtNDBiMS05MmM2LTViOWE4MWYxODNiYyJ9"; 

public static void main(String[] args) throws UnsupportedEncodingException { 
    // TODO Auto-generated method stub 
    String certString = "-----BEGIN CERTIFICATE-----\r\n" + certificate + "\r\n-----END CERTIFICATE-----"; 
    Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); 
     CertificateFactory cf; 
     try { 
      cf = CertificateFactory.getInstance("X.509"); 
      InputStream stream = new ByteArrayInputStream(certString.getBytes()); //StandardCharsets.UTF_8 
      java.security.cert.Certificate cert = cf.generateCertificate(stream); 
      PublicKey pk = cert.getPublicKey(); 


      //verifying content with signature and content : 
      Signature sig = Signature.getInstance("SHA256withRSA"); 
      sig.initVerify(pk); 
      sig.update(data.getBytes()); 

      Boolean ret = sig.verify(signedData.getBytes()); 
     } catch (CertificateException | SignatureException | NoSuchAlgorithmException | InvalidKeyException e) { 
      e.printStackTrace(); 
     } 

ответ

2

Сигнатура часть JWT является base64url закодирован (see JWS §7.1), так что вы должны будете правильно декодировать его перед проверкой.

Заменить строку Boolean ret = sig.verify(signedData.getBytes()); с чем-то вроде следующего (с использованием декодера Base64 из Apache Commons Codec),

byte[] signature = org.apache.commons.codec.binary.Base64.decodeBase64(signedData); 
Boolean ret = sig.verify(signature); 

И подпись на этом JWT должен проверить для вас.

Сказав это, я очень рекомендую использовать библиотеку для обработки JWT. Достойная библиотека будет обрабатывать такие вещи для вас и может также предоставить больше возможностей JWT.

Например, следующее, используя jose4j JWT library, может заменить материал из кода в вопросе после получения открытого ключа из сертификата. Это не только проверяет подпись за спецификации, но и подтверждает претензии в JWT, чтобы убедиться, что он все еще в силе, был выпущен к вам, и т.д ..

JwtConsumer jwtConsumer = new JwtConsumerBuilder() 
    .setVerificationKey(pk) 
    .setRequireExpirationTime() 
    .setExpectedAudience("https://citrixp.com:8443/") 
    .setExpectedIssuer("https://sts.windows.net/dd9b6a3e-29d1-4254-a746-e02941444517/") 
    .build(); 

JwtClaims claims = jwtConsumer.processToClaims(data + "." + signedData); 

System.out.println("Subject: " + claims.getSubject()); 
System.out.println("UPN: " + claims.getStringClaimValue("upn")); // or whatever, etc.... 

Это JWT истек еще несколько дней, так что processToClaims выбросит исключение, которое вы хотите. Вы можете добавить .setEvaluationTime(NumericDate.fromSeconds(1442626055)) при построении JwtConsumer, чтобы заставить его работать для данного JWT.

Смежные вопросы