You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by co...@apache.org on 2021/01/12 08:34:59 UTC
[cxf] branch 3.4.x-fixes updated: CXF-8402 -
JwkUtils::fromECPublicKey returns key coordinates without leading zero
(#739)
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 <co...@users.noreply.github.com>
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-----