mirror of https://github.com/shred/acme4j
Move jwkThumbprint() to SignatureUtils, add unit test
parent
ddac0c45d1
commit
c48febda62
|
@ -16,19 +16,13 @@ package org.shredzone.acme4j.challenge;
|
|||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PublicKey;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jose4j.json.JsonUtil;
|
||||
import org.jose4j.jwk.JsonWebKey;
|
||||
import org.jose4j.jwk.JsonWebKey.OutputControlLevel;
|
||||
import org.jose4j.lang.JoseException;
|
||||
import org.shredzone.acme4j.Status;
|
||||
import org.shredzone.acme4j.exception.AcmeProtocolException;
|
||||
|
@ -132,34 +126,6 @@ public class GenericChallenge implements Challenge {
|
|||
return (T) data.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the data map in JSON.
|
||||
*/
|
||||
|
|
|
@ -16,6 +16,7 @@ package org.shredzone.acme4j.challenge;
|
|||
import org.jose4j.base64url.Base64Url;
|
||||
import org.shredzone.acme4j.Registration;
|
||||
import org.shredzone.acme4j.util.ClaimBuilder;
|
||||
import org.shredzone.acme4j.util.SignatureUtils;
|
||||
|
||||
/**
|
||||
* An extension of {@link GenericChallenge} that handles challenges with a {@code token}
|
||||
|
@ -94,7 +95,7 @@ public class GenericTokenChallenge extends GenericChallenge {
|
|||
protected String computeAuthorization(Registration registration) {
|
||||
return getToken()
|
||||
+ '.'
|
||||
+ Base64Url.encode(jwkThumbprint(registration.getKeyPair().getPublic()));
|
||||
+ Base64Url.encode(SignatureUtils.jwkThumbprint(registration.getKeyPair().getPublic()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -13,11 +13,19 @@
|
|||
*/
|
||||
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.JsonWebKey;
|
||||
import org.jose4j.jwk.JsonWebKey.OutputControlLevel;
|
||||
import org.jose4j.jwk.RsaJsonWebKey;
|
||||
import org.jose4j.jws.AlgorithmIdentifiers;
|
||||
import org.jose4j.jws.JsonWebSignature;
|
||||
import org.jose4j.lang.JoseException;
|
||||
import org.shredzone.acme4j.exception.AcmeProtocolException;
|
||||
|
||||
/**
|
||||
* Utility class for signatures.
|
||||
|
@ -67,4 +75,32 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ import org.junit.Test;
|
|||
import org.shredzone.acme4j.Status;
|
||||
import org.shredzone.acme4j.exception.AcmeProtocolException;
|
||||
import org.shredzone.acme4j.util.ClaimBuilder;
|
||||
import org.shredzone.acme4j.util.SignatureUtils;
|
||||
import org.shredzone.acme4j.util.TestUtils;
|
||||
import org.shredzone.acme4j.util.TimestampParser;
|
||||
|
||||
|
@ -115,7 +116,7 @@ public class GenericChallengeTest {
|
|||
assertThat(cb.toString(), is(json.toString()));
|
||||
|
||||
// Make sure the returned thumbprint is correct
|
||||
byte[] thumbprint = GenericChallenge.jwkThumbprint(keypair.getPublic());
|
||||
byte[] thumbprint = SignatureUtils.jwkThumbprint(keypair.getPublic());
|
||||
assertThat(thumbprint, is(Base64Url.decode(TestUtils.THUMBPRINT)));
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ import java.security.KeyPair;
|
|||
import java.security.Security;
|
||||
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.jose4j.base64url.Base64Url;
|
||||
import org.jose4j.jwk.PublicJsonWebKey;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
@ -88,4 +89,17 @@ public class SignatureUtilsTest {
|
|||
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));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue