[cxf] branch CXF-8402 created (now c86dd6e)

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

[cxf] branch CXF-8402 created (now c86dd6e)

coheigea
Administrator
This is an automated email from the ASF dual-hosted git repository.

coheigea pushed a change to branch CXF-8402
in repository https://gitbox.apache.org/repos/asf/cxf.git.


      at c86dd6e  CXF-8402 - JwkUtils::fromECPublicKey returns key coordinates without leading zero

This branch includes the following new commits:

     new c86dd6e  CXF-8402 - JwkUtils::fromECPublicKey returns key coordinates without leading zero

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Reply | Threaded
Open this post in threaded view
|

[cxf] 01/01: CXF-8402 - JwkUtils::fromECPublicKey returns key coordinates without leading zero

coheigea
Administrator
This is an automated email from the ASF dual-hosted git repository.

coheigea pushed a commit to branch CXF-8402
in repository https://gitbox.apache.org/repos/asf/cxf.git

commit c86dd6e98cb5ac1d8c083721950cd2de055ffc80
Author: Colm O hEigeartaigh <[hidden email]>
AuthorDate: Mon Jan 11 10:27:35 2021 +0000

    CXF-8402 - JwkUtils::fromECPublicKey returns key coordinates without leading zero
---
 .../src/main/appended-resources/META-INF/NOTICE    |  3 +
 .../apache/cxf/rs/security/jose/jwk/JwkUtils.java  | 67 +++++++++++++++++++++-
 .../cxf/rs/security/jose/jwk/JwkUtilsTest.java     | 15 +++++
 .../org/apache/cxf/rs/security/jose/jwk/cert.pem   |  9 +++
 4 files changed, 92 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..fa38233 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,7 +18,10 @@
  */
 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;
@@ -203,4 +206,16 @@ 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);
+            assertEquals(x.length(), y.length());
+        }
+    }
+
 }
\ 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-----