Use jose4j's thumbprint calculation

pull/30/head
Richard Körber 2016-07-27 22:55:24 +02:00
parent 31c4d6d133
commit 91c402473f
5 changed files with 15 additions and 89 deletions

View File

@ -290,11 +290,12 @@ public class Registration extends AcmeResource {
String rollover; String rollover;
try { try {
final PublicJsonWebKey oldKeyJwk = PublicJsonWebKey.Factory.newPublicJwk(getSession().getKeyPair().getPublic());
final PublicJsonWebKey newKeyJwk = PublicJsonWebKey.Factory.newPublicJwk(newKeyPair.getPublic());
ClaimBuilder newKeyClaim = new ClaimBuilder(); ClaimBuilder newKeyClaim = new ClaimBuilder();
newKeyClaim.putResource("reg"); newKeyClaim.putResource("reg");
newKeyClaim.putBase64("newKey", SignatureUtils.jwkThumbprint(newKeyPair.getPublic())); newKeyClaim.putBase64("newKey", newKeyJwk.calculateThumbprint("SHA-256"));
final PublicJsonWebKey oldKeyJwk = PublicJsonWebKey.Factory.newPublicJwk(getSession().getKeyPair().getPublic());
JsonWebSignature jws = new JsonWebSignature(); JsonWebSignature jws = new JsonWebSignature();
jws.setPayload(newKeyClaim.toString()); jws.setPayload(newKeyClaim.toString());

View File

@ -16,10 +16,11 @@ package org.shredzone.acme4j.challenge;
import java.security.PublicKey; import java.security.PublicKey;
import org.jose4j.base64url.Base64Url; import org.jose4j.base64url.Base64Url;
import org.jose4j.jwk.PublicJsonWebKey;
import org.jose4j.lang.JoseException;
import org.shredzone.acme4j.Session; import org.shredzone.acme4j.Session;
import org.shredzone.acme4j.exception.AcmeProtocolException; import org.shredzone.acme4j.exception.AcmeProtocolException;
import org.shredzone.acme4j.util.ClaimBuilder; import org.shredzone.acme4j.util.ClaimBuilder;
import org.shredzone.acme4j.util.SignatureUtils;
/** /**
* An extension of {@link Challenge} that handles challenges with a {@code token} and * An extension of {@link Challenge} that handles challenges with a {@code token} and
@ -77,10 +78,15 @@ public class TokenChallenge extends Challenge {
* @return Authorization string * @return Authorization string
*/ */
protected String computeAuthorization() { protected String computeAuthorization() {
PublicKey pk = getSession().getKeyPair().getPublic(); try {
return getToken() PublicKey pk = getSession().getKeyPair().getPublic();
+ '.' PublicJsonWebKey jwk = PublicJsonWebKey.Factory.newPublicJwk(pk);
+ Base64Url.encode(SignatureUtils.jwkThumbprint(pk)); return getToken()
+ '.'
+ Base64Url.encode(jwk.calculateThumbprint("SHA-256"));
} catch (JoseException ex) {
throw new AcmeProtocolException("Cannot compute key thumbprint", ex);
}
} }
@Override @Override

View File

@ -13,19 +13,11 @@
*/ */
package org.shredzone.acme4j.util; package org.shredzone.acme4j.util;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import org.jose4j.jwk.EllipticCurveJsonWebKey; import org.jose4j.jwk.EllipticCurveJsonWebKey;
import org.jose4j.jwk.JsonWebKey; import org.jose4j.jwk.JsonWebKey;
import org.jose4j.jwk.JsonWebKey.OutputControlLevel;
import org.jose4j.jwk.RsaJsonWebKey; import org.jose4j.jwk.RsaJsonWebKey;
import org.jose4j.jws.AlgorithmIdentifiers; import org.jose4j.jws.AlgorithmIdentifiers;
import org.jose4j.jws.JsonWebSignature; import org.jose4j.jws.JsonWebSignature;
import org.jose4j.lang.JoseException;
import org.shredzone.acme4j.exception.AcmeProtocolException;
/** /**
* Utility class for signatures. * Utility class for signatures.
@ -73,32 +65,4 @@ public final class SignatureUtils {
} }
} }
/**
* Computes a JWK Thumbprint. It is frequently used in responses.
*
* @param key
* {@link PublicKey} to create a thumbprint of
* @return Thumbprint, SHA-256 hashed
* @see <a href="https://tools.ietf.org/html/rfc7638">RFC 7638</a>
*/
public static byte[] jwkThumbprint(PublicKey key) {
if (key == null) {
throw new NullPointerException("key must not be null");
}
try {
final JsonWebKey jwk = JsonWebKey.Factory.newJwk(key);
// We need to use ClaimBuilder to bring the keys in lexicographical order.
ClaimBuilder cb = new ClaimBuilder();
cb.putAll(jwk.toParams(OutputControlLevel.PUBLIC_ONLY));
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(cb.toString().getBytes("UTF-8"));
return md.digest();
} catch (JoseException | NoSuchAlgorithmException | UnsupportedEncodingException ex) {
throw new AcmeProtocolException("Cannot compute key thumbprint", ex);
}
}
} }

View File

@ -26,14 +26,10 @@ import java.io.ObjectOutputStream;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.security.KeyPair;
import java.util.Date; import java.util.Date;
import java.util.Map; import java.util.Map;
import org.jose4j.base64url.Base64Url;
import org.jose4j.json.JsonUtil; import org.jose4j.json.JsonUtil;
import org.jose4j.jwk.JsonWebKey;
import org.jose4j.jwk.JsonWebKey.OutputControlLevel;
import org.jose4j.lang.JoseException; import org.jose4j.lang.JoseException;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -43,7 +39,6 @@ import org.shredzone.acme4j.exception.AcmeProtocolException;
import org.shredzone.acme4j.exception.AcmeRetryAfterException; import org.shredzone.acme4j.exception.AcmeRetryAfterException;
import org.shredzone.acme4j.provider.TestableConnectionProvider; import org.shredzone.acme4j.provider.TestableConnectionProvider;
import org.shredzone.acme4j.util.ClaimBuilder; import org.shredzone.acme4j.util.ClaimBuilder;
import org.shredzone.acme4j.util.SignatureUtils;
import org.shredzone.acme4j.util.TestUtils; import org.shredzone.acme4j.util.TestUtils;
import org.shredzone.acme4j.util.TimestampParser; import org.shredzone.acme4j.util.TimestampParser;
@ -140,32 +135,6 @@ public class ChallengeTest {
challenge.unmarshall(TestUtils.getJsonAsMap("dnsChallenge")); challenge.unmarshall(TestUtils.getJsonAsMap("dnsChallenge"));
} }
/**
* Test that the test keypair's thumbprint is correct.
*/
@Test
public void testJwkThumbprint() throws IOException, JoseException {
StringBuilder json = new StringBuilder();
json.append('{');
json.append("\"e\":\"").append(TestUtils.E).append("\",");
json.append("\"kty\":\"").append(TestUtils.KTY).append("\",");
json.append("\"n\":\"").append(TestUtils.N).append("\"");
json.append('}');
KeyPair keypair = TestUtils.createKeyPair();
// Test the JWK raw output. The JSON string must match the assert string
// exactly, as the thumbprint is a digest of that string.
final JsonWebKey jwk = JsonWebKey.Factory.newJwk(keypair.getPublic());
ClaimBuilder cb = new ClaimBuilder();
cb.putAll(jwk.toParams(OutputControlLevel.PUBLIC_ONLY));
assertThat(cb.toString(), is(json.toString()));
// Make sure the returned thumbprint is correct
byte[] thumbprint = SignatureUtils.jwkThumbprint(keypair.getPublic());
assertThat(thumbprint, is(Base64Url.decode(TestUtils.THUMBPRINT)));
}
/** /**
* Test that a challenge can be triggered. * Test that a challenge can be triggered.
*/ */

View File

@ -20,7 +20,6 @@ import java.security.KeyPair;
import java.security.Security; import java.security.Security;
import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.jose4j.base64url.Base64Url;
import org.jose4j.jwk.PublicJsonWebKey; import org.jose4j.jwk.PublicJsonWebKey;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
@ -87,17 +86,4 @@ public class SignatureUtilsTest {
assertThat(type, is("ES512")); assertThat(type, is("ES512"));
} }
/**
* Test if {@link SignatureUtils#jwkThumbprint(java.security.PublicKey)} returns the
* correct thumb print.
*/
@Test
public void testJwkThumbprint() throws Exception {
KeyPair keyPair = TestUtils.createKeyPair();
byte[] thumbprint = SignatureUtils.jwkThumbprint(keyPair.getPublic());
assertThat(Base64Url.encode(thumbprint), is(TestUtils.THUMBPRINT));
}
} }