Skip to content

Commit

Permalink
Merge pull request #384 from JanssenProject/sergey_011_1
Browse files Browse the repository at this point in the history
Unit Tests: fixing the problem: invalid length of ec key attributes (length > 32): issue oxauth.#159
  • Loading branch information
yuriyz committed Dec 20, 2021
2 parents f0d2639 + a138ce8 commit c8bc295
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 43 deletions.
76 changes: 46 additions & 30 deletions model/src/main/java/io/jans/as/model/jwk/Algorithm.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.fasterxml.jackson.annotation.JsonValue;
import io.jans.as.model.crypto.signature.AlgorithmFamily;
import io.jans.as.model.util.StringUtils;
import io.jans.as.model.crypto.signature.RSAKeyFactory;

import java.util.ArrayList;
import java.util.List;
Expand All @@ -21,79 +22,90 @@
* @author Sergey Manoylo
* @version September 13, 2021
*/
@SuppressWarnings("java:S1874")
public enum Algorithm {

// Signature
RS256("RS256", "id_token RS256 Sign Key", "Signature Key: RSA RSASSA-PKCS1-v1_5 using SHA-256", Use.SIGNATURE, AlgorithmFamily.RSA),
RS384("RS384", "id_token RS384 Sign Key", "Signature Key: RSA RSASSA-PKCS1-v1_5 using SHA-384", Use.SIGNATURE, AlgorithmFamily.RSA),
RS512("RS512", "id_token RS512 Sign Key", "Signature Key: RSA RSASSA-PKCS1-v1_5 using SHA-512", Use.SIGNATURE, AlgorithmFamily.RSA),
RS256("RS256", "id_token RS256 Sign Key", "Signature Key: RSA RSASSA-PKCS1-v1_5 using SHA-256", Use.SIGNATURE, AlgorithmFamily.RSA, RSAKeyFactory.DEF_KEYLENGTH),
RS384("RS384", "id_token RS384 Sign Key", "Signature Key: RSA RSASSA-PKCS1-v1_5 using SHA-384", Use.SIGNATURE, AlgorithmFamily.RSA, RSAKeyFactory.DEF_KEYLENGTH),
RS512("RS512", "id_token RS512 Sign Key", "Signature Key: RSA RSASSA-PKCS1-v1_5 using SHA-512", Use.SIGNATURE, AlgorithmFamily.RSA, RSAKeyFactory.DEF_KEYLENGTH),

ES256("ES256", "id_token ES256 Sign Key", "Signature Key: ECDSA using P-256 (secp256r1) and SHA-256", Use.SIGNATURE, AlgorithmFamily.EC),
ES256K("ES256K", "id_token ES256K Sign Key", "Signature Key: ECDSA using secp256k1 and SHA-256", Use.SIGNATURE, AlgorithmFamily.EC),
ES384("ES384", "id_token ES384 Sign Key", "Signature Key: ECDSA using P-384 (secp384r1) and SHA-384", Use.SIGNATURE, AlgorithmFamily.EC),
ES512("ES512", "id_token ES512 Sign Key", "Signature Key: ECDSA using P-521 (secp521r1) and SHA-512", Use.SIGNATURE, AlgorithmFamily.EC),
ES256("ES256", "id_token ES256 Sign Key", "Signature Key: ECDSA using P-256 (secp256r1) and SHA-256", Use.SIGNATURE, AlgorithmFamily.EC, 256),
ES256K("ES256K", "id_token ES256K Sign Key", "Signature Key: ECDSA using secp256k1 and SHA-256", Use.SIGNATURE, AlgorithmFamily.EC, 256),
ES384("ES384", "id_token ES384 Sign Key", "Signature Key: ECDSA using P-384 (secp384r1) and SHA-384", Use.SIGNATURE, AlgorithmFamily.EC, 384),
ES512("ES512", "id_token ES512 Sign Key", "Signature Key: ECDSA using P-521 (secp521r1) and SHA-512", Use.SIGNATURE, AlgorithmFamily.EC, 528),

PS256("PS256", "id_token PS256 Sign Key", "Signature Key: RSASSA-PSS using SHA-256 and MGF1 with SHA-256", Use.SIGNATURE, AlgorithmFamily.RSA),
PS384("PS384", "id_token PS384 Sign Key", "Signature Key: RSASSA-PSS using SHA-384 and MGF1 with SHA-384", Use.SIGNATURE, AlgorithmFamily.RSA),
PS512("PS512", "id_token PS512 Sign Key", "Signature Key: RSASSA-PSS using SHA-512 and MGF1 with SHA-512", Use.SIGNATURE, AlgorithmFamily.RSA),
PS256("PS256", "id_token PS256 Sign Key", "Signature Key: RSASSA-PSS using SHA-256 and MGF1 with SHA-256", Use.SIGNATURE, AlgorithmFamily.RSA, RSAKeyFactory.DEF_KEYLENGTH),
PS384("PS384", "id_token PS384 Sign Key", "Signature Key: RSASSA-PSS using SHA-384 and MGF1 with SHA-384", Use.SIGNATURE, AlgorithmFamily.RSA, RSAKeyFactory.DEF_KEYLENGTH),
PS512("PS512", "id_token PS512 Sign Key", "Signature Key: RSASSA-PSS using SHA-512 and MGF1 with SHA-512", Use.SIGNATURE, AlgorithmFamily.RSA, RSAKeyFactory.DEF_KEYLENGTH),

ED25519("Ed25519", "id_token Ed25519 Sign Key", "Signature Key: EDDSA using Ed25519 with SHA-512", Use.SIGNATURE, AlgorithmFamily.ED),
ED448("Ed448", "id_token Ed448 Sign Key", "Signature Key: EDDSA using Ed448 with SHA-3/SHAKE256", Use.SIGNATURE, AlgorithmFamily.ED),
ED25519("Ed25519", "id_token Ed25519 Sign Key", "Signature Key: EDDSA using Ed25519 with SHA-512", Use.SIGNATURE, AlgorithmFamily.ED, 256),
ED448("Ed448", "id_token Ed448 Sign Key", "Signature Key: EDDSA using Ed448 with SHA-3/SHAKE256", Use.SIGNATURE, AlgorithmFamily.ED, 456),

// Encryption
RSA1_5("RSA1_5", "id_token RSA1_5 Encryption Key", "Encryption Key: RSAES-PKCS1-v1_5",
Use.ENCRYPTION, AlgorithmFamily.RSA),
Use.ENCRYPTION, AlgorithmFamily.RSA, RSAKeyFactory.DEF_KEYLENGTH),
RSA_OAEP("RSA-OAEP", "id_token RSA-OAEP Encryption Key", "Encryption Key: RSAES OAEP using default parameters",
Use.ENCRYPTION, AlgorithmFamily.RSA),
Use.ENCRYPTION, AlgorithmFamily.RSA, RSAKeyFactory.DEF_KEYLENGTH),
RSA_OAEP_256("RSA-OAEP-256", "id_token RSA-OAEP-256 Encryption Key", "Encryption Key: RSAES OAEP using SHA-256 and MGF1 with SHA-256 ",
Use.ENCRYPTION, AlgorithmFamily.RSA),
Use.ENCRYPTION, AlgorithmFamily.RSA, RSAKeyFactory.DEF_KEYLENGTH),

ECDH_ES("ECDH-ES", "id_token ECDH-ES Encryption Key", "Encryption Key: Elliptic Curve Diffie-Hellman Ephemeral Static key agreement using Concat KDF",
Use.ENCRYPTION, AlgorithmFamily.EC),
Use.ENCRYPTION, AlgorithmFamily.EC, 256),
ECDH_ES_PLUS_A128KW("ECDH-ES+A128KW", "id_token ECDH-ES+A128KW Encryption Key", "Encryption Key: ECDH-ES using Concat KDF and CEK wrapped with A128KW",
Use.ENCRYPTION, AlgorithmFamily.EC),
Use.ENCRYPTION, AlgorithmFamily.EC, 256),
ECDH_ES_PLUS_A192KW("ECDH-ES+A192KW", "id_token ECDH-ES+A192KW Encryption Key", "Encryption Key: ECDH-ES using Concat KDF and CEK wrapped with A192KW",
Use.ENCRYPTION, AlgorithmFamily.EC),
Use.ENCRYPTION, AlgorithmFamily.EC, 256),
ECDH_ES_PLUS_A256KW("ECDH-ES+A256KW", "id_token ECDH-ES+A256KW Encryption Key", "Encryption Key: ECDH-ES using Concat KDF and CEK wrapped with A256KW",
Use.ENCRYPTION, AlgorithmFamily.EC),
Use.ENCRYPTION, AlgorithmFamily.EC, 256),

A128KW("A128KW", "id_token A128KW Encryption Key", "Encryption Key: AES Key Wrap with default initial value using 128-bit key",
Use.ENCRYPTION, AlgorithmFamily.AES),
Use.ENCRYPTION, AlgorithmFamily.AES, -1),
A192KW("A192KW", "id_token A192KW Encryption Key", "Encryption Key: AES Key Wrap with default initial value using 192-bit key",
Use.ENCRYPTION, AlgorithmFamily.AES),
Use.ENCRYPTION, AlgorithmFamily.AES, -1),
A256KW("A256KW", "id_token A256KW Encryption Key", "Encryption Key: AES Key Wrap with default initial value using 192-bit key",
Use.ENCRYPTION, AlgorithmFamily.AES),
Use.ENCRYPTION, AlgorithmFamily.AES, -1),

A128GCMKW("A128GCMKW", "id_token A128GCMKW Encryption Key", "Encryption Key: Key wrapping with AES GCM using 128-bit key",
Use.ENCRYPTION, AlgorithmFamily.AES),
Use.ENCRYPTION, AlgorithmFamily.AES, 128),
A192GCMKW("A192GCMKW", "id_token A192GCMKW Encryption Key", "Encryption Key: Key wrapping with AES GCM using 192-bit key",
Use.ENCRYPTION, AlgorithmFamily.AES),
Use.ENCRYPTION, AlgorithmFamily.AES, 192),
A256GCMKW("A256GCMKW", "id_token A256GCMKW Encryption Key", "Encryption Key: Key wrapping with AES GCM using 256-bit key",
Use.ENCRYPTION, AlgorithmFamily.AES),
Use.ENCRYPTION, AlgorithmFamily.AES, 256),

PBES2_HS256_PLUS_A128KW("PBES2-HS256+A128KW", "id_token PBES2-HS256+A128KW Encryption Key", "Encryption Key: PBES2 with HMAC SHA-256 and A128KW wrapping",
Use.ENCRYPTION, AlgorithmFamily.PASSW),
Use.ENCRYPTION, AlgorithmFamily.PASSW, -1),
PBES2_HS384_PLUS_A192KW("PBES2-HS384+A192KW", "id_token PBES2-HS384+A192KW Encryption Key", "Encryption Key: PBES2 with HMAC SHA-384 and A192KW wrapping",
Use.ENCRYPTION, AlgorithmFamily.PASSW),
Use.ENCRYPTION, AlgorithmFamily.PASSW, -1),
PBES2_HS512_PLUS_A256KW("PBES2-HS512+A256KW", "id_token PBES2-HS512+A256KW Encryption Key", "Encryption Key: PBES2 with HMAC SHA-512 and A256KW wrapping",
Use.ENCRYPTION, AlgorithmFamily.PASSW),
Use.ENCRYPTION, AlgorithmFamily.PASSW, -1),

DIR("dir", "id_token Direct Encryption", "Encryption Key: Direct use of a shared symmetric key as the CEK",
Use.ENCRYPTION, AlgorithmFamily.DIR);
Use.ENCRYPTION, AlgorithmFamily.DIR, -1);

private final String paramName;
private final String outName;
private final String description;
private final Use use;
private final AlgorithmFamily family;
/**
* keyLength
in bits, for some Algorithms - max key Length;
keyLength is defined only for algorithms,
which are used in KeyGenerator,
i.e. where key is generated in the KeyStorage;
can be defined for other (AES: A192KW,...);
*/
private final int keyLength;

Algorithm(final String paramName, final String outName, final String description,
final Use use, final AlgorithmFamily family) {
final Use use, final AlgorithmFamily family, int keyLength) {
this.paramName = paramName;
this.outName = outName;
this.description = description;
this.use = use;
this.family = family;
this.keyLength = keyLength;
}

public String getParamName() {
Expand All @@ -116,6 +128,10 @@ public AlgorithmFamily getFamily() {
return family;
}

public int getKeyLength() {
return keyLength;
}

public boolean canGenerateKeys() { // based on currently supported generator, see io.jans.as.model.crypto.AuthCryptoProvider.generateKeyEncryption
return family == AlgorithmFamily.RSA || family == AlgorithmFamily.EC;
}
Expand Down
32 changes: 22 additions & 10 deletions model/src/main/java/io/jans/as/model/util/Base64Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@

/**
* @author Javier Rojas Blum
* @version July 31, 2016
* @author Sergey Manoylo
* @version December 16, 2021
*/
public class Base64Util {

Expand Down Expand Up @@ -58,15 +59,8 @@ public static String removePadding(String base64UrlEncoded) {
return s;
}

public static String base64urlencodeUnsignedBigInt(BigInteger bigInteger) {
byte[] array = bigInteger.toByteArray();
if (array[0] == 0) {
byte[] tmp = new byte[array.length - 1];
System.arraycopy(array, 1, tmp, 0, tmp.length);
array = tmp;
}

return Base64Util.base64urlencode(array);
public static String base64urlencodeUnsignedBigInt(final BigInteger bigInteger) {
return Base64Util.base64urlencode(bigIntegerToUnsignedByteArray(bigInteger));
}

public static byte[] unsignedToBytes(int[] plaintextUnsignedBytes) {
Expand All @@ -78,4 +72,22 @@ public static byte[] unsignedToBytes(int[] plaintextUnsignedBytes) {

return bytes;
}

public static String bytesToHex(byte[] bytes) {
StringBuilder result = new StringBuilder();
for (byte aByte : bytes) {
result.append(String.format("%02x", aByte));
}
return result.toString();
}

public static byte[] bigIntegerToUnsignedByteArray(final BigInteger bigInteger) {
byte[] array = bigInteger.toByteArray();
if (array[0] == 0) {
byte[] tmp = new byte[array.length - 1];
System.arraycopy(array, 1, tmp, 0, tmp.length);
array = tmp;
}
return array;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,30 @@
import io.jans.as.model.crypto.AbstractCryptoProvider;
import io.jans.as.model.crypto.signature.SignatureAlgorithm;
import io.jans.as.model.jwk.Algorithm;
import io.jans.as.model.jwk.JWKParameter;
import io.jans.as.model.util.Base64Util;
import io.jans.as.server.ConfigurableTest;
import io.jans.as.server.model.config.ConfigurationFactory;
import org.json.JSONObject;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import javax.inject.Inject;

import java.security.interfaces.ECPrivateKey;
import java.util.GregorianCalendar;
import java.util.TimeZone;

import static io.jans.eleven.model.GenerateKeyResponseParam.KEY_ID;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;

/**
* @author Javier Rojas Blum
* @version February 12, 2019
* @author Sergey Manoylo
* @version December 16, 2021
*/
public class CryptoProviderTest extends ConfigurableTest {

Expand All @@ -36,8 +43,12 @@ public class CryptoProviderTest extends ConfigurableTest {
@Inject
private AbstractCryptoProvider cryptoProvider;

private final String SIGNING_INPUT = "Signing Input";
private final String SHARED_SECRET = "secret";
private final static int NUM_KEY_GENS = 100;

private final static byte testByte01 = (byte)0x01;

private final static String SIGNING_INPUT = "Signing Input";
private final static String SHARED_SECRET = "secret";

private static Long expirationTime;
private static String hs256Signature;
Expand Down Expand Up @@ -374,4 +385,69 @@ public void testDeleteKeyES512() {
fail(e.getMessage(), e);
}
}

@DataProvider(name = "GenerateKeysDataProvider")
public Object[][] testGenerateKeysDataProvider() {
return new Object[][] {
{ Algorithm.ES256 },
{ Algorithm.ES384 },
{ Algorithm.ES512 },
};
}

@Test(dependsOnMethods = {"testDeleteKeyRS256", "testDeleteKeyRS384", "testDeleteKeyRS512",
"testDeleteKeyES256", "testDeleteKeyES384", "testDeleteKeyES512" },
dataProvider = "GenerateKeysDataProvider")
public void testGenerateKeys(Algorithm algorithm) {
for(int i = 0; i < NUM_KEY_GENS; i++) {
System.out.println("----------------------");
System.out.println("Algorithm: " + algorithm);
try {
JSONObject response = cryptoProvider.generateKey(algorithm, expirationTime);
String keyId = response.optString(JWKParameter.KEY_ID);
ECPrivateKey ecPrivateKey = (ECPrivateKey)cryptoProvider.getPrivateKey(keyId);
cryptoProvider.deleteKey(response.optString(keyId));

byte[] s = Base64Util.bigIntegerToUnsignedByteArray(ecPrivateKey.getS());

System.out.println("s.length = " + s.length);
System.out.println("s (hex) = " + Base64Util.bytesToHex(s));

String keyX = (String)response.get(JWKParameter.X);
String keyY = (String)response.get(JWKParameter.Y);

System.out.println("keyX = " + keyX);
System.out.println("keyY = " + keyY);

byte[] x = Base64Util.base64urldecode(keyX);
byte[] y = Base64Util.base64urldecode(keyY);

System.out.println("x.length = " + x.length);
System.out.println("y.length = " + y.length);

System.out.println("x (hex) = " + Base64Util.bytesToHex(x));
System.out.println("y (hex) = " + Base64Util.bytesToHex(y));

assertTrue(s.length <= algorithm.getKeyLength());
assertTrue(x.length <= algorithm.getKeyLength());
assertTrue(y.length <= algorithm.getKeyLength());

if(algorithm == Algorithm.ES512) {
if(s.length * 8 == algorithm.getKeyLength()) {
assertEquals(s[0], testByte01);
}
if(x.length * 8 == algorithm.getKeyLength()) {
assertEquals(x[0], testByte01);
}
if(y.length * 8 == algorithm.getKeyLength()) {
assertEquals(y[0], testByte01);
}
}

} catch (Exception e) {
fail(e.getMessage(), e);
}
System.out.println("----------------------");
}
}
}

0 comments on commit c8bc295

Please sign in to comment.