Administrator
|
This is an automated email from the ASF dual-hosted git repository.
coheigea pushed a commit to branch 3.4.x-fixes in repository https://gitbox.apache.org/repos/asf/cxf.git The following commit(s) were added to refs/heads/3.4.x-fixes by this push: new f83eca5 CXF-8402 - JwkUtils::fromECPublicKey returns key coordinates without leading zero (#739) f83eca5 is described below commit f83eca59328c185cc92ea7e57ecf005d8e2e0956 Author: Colm O hEigeartaigh <[hidden email]> AuthorDate: Tue Jan 12 08:19:00 2021 +0000 CXF-8402 - JwkUtils::fromECPublicKey returns key coordinates without leading zero (#739) (cherry picked from commit e8b7c0816ebfad5a36606843bd7634d6ff827785) --- .../src/main/appended-resources/META-INF/NOTICE | 3 + .../apache/cxf/rs/security/jose/jwk/JwkUtils.java | 67 +++++++++++++++++++++- .../cxf/rs/security/jose/jwk/JwkUtilsTest.java | 18 ++++++ .../org/apache/cxf/rs/security/jose/jwk/cert.pem | 9 +++ 4 files changed, 95 insertions(+), 2 deletions(-) diff --git a/distribution/src/main/appended-resources/META-INF/NOTICE b/distribution/src/main/appended-resources/META-INF/NOTICE index 8c51d64..9d6104a 100644 --- a/distribution/src/main/appended-resources/META-INF/NOTICE +++ b/distribution/src/main/appended-resources/META-INF/NOTICE @@ -54,4 +54,7 @@ Software Foundation. Additional copyright notices and license terms applicable are present in the licenses directory of this distribution. +This product includes code from the Nimbus JOSE + JWT project, under the Apache +license 2.0 (https://github.com/felx/nimbus-jose-jwt). Copyright 2012-2017, +Connect2id Ltd. diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/JwkUtils.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/JwkUtils.java index d86781a..0f519e3 100644 --- a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/JwkUtils.java +++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/JwkUtils.java @@ -377,12 +377,14 @@ public final class JwkUtils { } public static JsonWebKey fromECPublicKey(ECPublicKey pk, String curve, String kid) { JsonWebKey jwk = prepareECJwk(curve, kid); + int fieldSize = pk.getParams().getCurve().getField().getFieldSize(); jwk.setProperty(JsonWebKey.EC_X_COORDINATE, - Base64UrlUtility.encode(pk.getW().getAffineX().toByteArray())); + encodeCoordinate(fieldSize, pk.getW().getAffineX())); jwk.setProperty(JsonWebKey.EC_Y_COORDINATE, - Base64UrlUtility.encode(pk.getW().getAffineY().toByteArray())); + encodeCoordinate(fieldSize, pk.getW().getAffineY())); return jwk; } + public static JsonWebKey fromECPrivateKey(ECPrivateKey pk, String curve) { return fromECPrivateKey(pk, curve, null); } @@ -603,4 +605,65 @@ public final class JwkUtils { } return parsedKeys; } + + /** + * Returns the Base64URL encoding of the specified elliptic curve 'x', + * 'y' or 'd' coordinate, with leading zero padding up to the specified + * field size in bits. + * Copied and adapted from nimbus-jose-jwt (ECKey#encodeCoordinate) + * + * @param fieldSize The field size in bits. + * @param coordinate The elliptic curve coordinate. Must not be + * {@code null}. + * + * @return The Base64URL-encoded coordinate, with leading zero padding + * up to the curve's field size. + */ + private static String encodeCoordinate(final int fieldSize, final BigInteger coordinate) { + final byte[] notPadded = toIntegerBytes(coordinate); + int bytesToOutput = (fieldSize + 7) / 8; + + if (notPadded.length >= bytesToOutput) { + // Greater-than check to prevent exception on malformed + // key below + return Base64UrlUtility.encode(notPadded); + } + + final byte[] padded = new byte[bytesToOutput]; + System.arraycopy(notPadded, 0, padded, bytesToOutput - notPadded.length, notPadded.length); + return Base64UrlUtility.encode(padded); + } + + /** + * Returns a byte-array representation of a {@code BigInteger} without sign bit. + * Copied from Apache Commons Codec + * + * @param bigInt + * {@code BigInteger} to be converted + * @return a byte array representation of the BigInteger parameter + */ + private static byte[] toIntegerBytes(final BigInteger bigInt) { + + int bitlen = bigInt.bitLength(); + // round bitlen + bitlen = ((bitlen + 7) >> 3) << 3; + final byte[] bigBytes = bigInt.toByteArray(); + + if (((bigInt.bitLength() % 8) != 0) && (((bigInt.bitLength() / 8) + 1) == (bitlen / 8))) { + return bigBytes; + } + // set up params for copying everything but sign bit + int startSrc = 0; + int len = bigBytes.length; + + // if bigInt is exactly byte-aligned, just skip signbit in copy + if ((bigInt.bitLength() % 8) == 0) { + startSrc = 1; + len--; + } + final int startDst = bitlen / 8 - len; // to pad w/ nulls as per spec + final byte[] resizedBytes = new byte[bitlen / 8]; + System.arraycopy(bigBytes, startSrc, resizedBytes, startDst, len); + return resizedBytes; + } } diff --git a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwk/JwkUtilsTest.java b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwk/JwkUtilsTest.java index 2c0bb14..15c5ea3 100644 --- a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwk/JwkUtilsTest.java +++ b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwk/JwkUtilsTest.java @@ -18,11 +18,15 @@ */ package org.apache.cxf.rs.security.jose.jwk; +import java.io.InputStream; import java.math.BigInteger; +import java.security.cert.CertificateFactory; +import java.security.interfaces.ECPublicKey; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.util.Properties; +import org.apache.cxf.common.util.Base64UrlUtility; import org.apache.cxf.rs.security.jose.common.JoseConstants; import org.apache.cxf.rs.security.jose.common.JoseException; import org.apache.cxf.rs.security.jose.common.JoseUtils; @@ -203,4 +207,18 @@ public class JwkUtilsTest { } } + @Test + public void testEcLeadingZeros() throws Exception { + try (InputStream inputStream = this.getClass().getResourceAsStream("cert.pem")) { + ECPublicKey publicKey = (ECPublicKey) CertificateFactory.getInstance("X.509") + .generateCertificate(inputStream).getPublicKey(); + JsonWebKey jwk = JwkUtils.fromECPublicKey(publicKey, "P-256"); + String x = (String)jwk.getProperty(JsonWebKey.EC_X_COORDINATE); + String y = (String)jwk.getProperty(JsonWebKey.EC_Y_COORDINATE); + int xLength = Base64UrlUtility.decode(x).length; + int yLength = Base64UrlUtility.decode(y).length; + assertEquals(xLength, yLength); + } + } + } \ No newline at end of file diff --git a/rt/rs/security/jose-parent/jose/src/test/resources/org/apache/cxf/rs/security/jose/jwk/cert.pem b/rt/rs/security/jose-parent/jose/src/test/resources/org/apache/cxf/rs/security/jose/jwk/cert.pem new file mode 100644 index 0000000..801791d --- /dev/null +++ b/rt/rs/security/jose-parent/jose/src/test/resources/org/apache/cxf/rs/security/jose/jwk/cert.pem @@ -0,0 +1,9 @@ +-----BEGIN CERTIFICATE----- +MIIBPTCB5AIJAJumvtnyaTCYMAoGCCqGSM49BAMCMCcxCzAJBgNVBAMMAnh4MQsw +CQYDVQQKDAJ4eDELMAkGA1UEBhMCWFgwHhcNMjEwMTA3MDgyOTEwWhcNMjIwMTA3 +MDgyOTEwWjAnMQswCQYDVQQDDAJ4eDELMAkGA1UECgwCeHgxCzAJBgNVBAYTAlhY +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAAiurwVih3Bjfd1SUJsZNu4WxzXu +HRyaXMubdTS+m6gtBlLPT5l2c4cgU3YvH0klTvgW4rXxQkU439myx9epDTAKBggq +hkjOPQQDAgNIADBFAiEA+ED92OzKrofQFX/f6bX75CNZox8GH/GPJJT8dJUl6ioC +IFv05HFlcU6+tUK7CKFz/1POx1f2IAySFmSbhH1qF2ua +-----END CERTIFICATE----- |
Free forum by Nabble | Edit this page |