Skip to content

Commit

Permalink
JWK signature now follows P1363 pair format (helidon-io#7185)
Browse files Browse the repository at this point in the history
JWK signature now follows P1363 pair format

Signed-off-by: David Kral <david.k.kral@oracle.com>
  • Loading branch information
Verdent authored Jul 14, 2023
1 parent 096217b commit 0696554
Showing 1 changed file with 5 additions and 89 deletions.
94 changes: 5 additions & 89 deletions security/jwt/src/main/java/io/helidon/security/jwt/jwk/JwkEC.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2021 Oracle and/or its affiliates.
* Copyright (c) 2018, 2023 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,9 +16,6 @@

package io.helidon.security.jwt.jwk;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.PrivateKey;
Expand All @@ -32,7 +29,6 @@
import java.security.spec.ECPublicKeySpec;
import java.security.spec.EllipticCurve;
import java.security.spec.InvalidKeySpecException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

Expand Down Expand Up @@ -117,9 +113,9 @@ public class JwkEC extends JwkPki {

static {
// Values obtained from RFC (mapping of algorithms)
ALG_MAP.put(ALG_ES256, "SHA256withECDSA");
ALG_MAP.put(ALG_ES384, "SHA384withECDSA");
ALG_MAP.put(ALG_ES512, "SHA512withECDSA");
ALG_MAP.put(ALG_ES256, "SHA256withECDSAinP1363Format");
ALG_MAP.put(ALG_ES384, "SHA384withECDSAinP1363Format");
ALG_MAP.put(ALG_ES512, "SHA512withECDSAinP1363Format");
ALG_MAP.put(ALG_NONE, ALG_NONE);

// Values obtained from org.bouncycastle.jce.ECNamedCurveTable
Expand Down Expand Up @@ -220,87 +216,7 @@ String signatureAlgorithm() {

@Override
public boolean doVerify(byte[] signedBytes, byte[] signatureToVerify) {
try {
return super.doVerify(signedBytes, signatureToVerify);
} catch (JwtException e) {
if (e.getCause().getMessage().contains("encoding")) {
return changeSignatureEncodingToDER(signedBytes, signatureToVerify);
} else {
throw e;
}
}
}

private boolean changeSignatureEncodingToDER(byte[] signedBytes, byte[] signatureToVerify) {
String alg = signatureAlgorithm();

if (ALG_NONE.equals(alg)) {
return verifyNoneAlg(signatureToVerify);
}

byte[] rBytes = Arrays.copyOfRange(signatureToVerify, 0, 32);
byte[] sBytes = Arrays.copyOfRange(signatureToVerify, 32, 64);

BigInteger r = new BigInteger(1, rBytes);
BigInteger s = new BigInteger(1, sBytes);

byte[] rb = r.toByteArray();
byte[] sb = s.toByteArray();

byte[] signatureDerBytes;
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
int length = 1 + calculateBodyLength(rb.length) + rb.length + 1 + calculateBodyLength(sb.length) + sb.length;
outputStream.write(16 | 32);
writeLength(outputStream, length);
outputStream.write(2);
writeLength(outputStream, rb.length);
outputStream.write(rb);
outputStream.write(2);
writeLength(outputStream, sb.length);
outputStream.write(sb);
signatureDerBytes = outputStream.toByteArray();
} catch (IOException e) {
throw new JwtException("Signature encoding conversion to DER has failed.", e);
}
return super.doVerify(signedBytes, signatureDerBytes);
}

private static int calculateBodyLength(int length) {
int count = 1;

if (length > 127) {
int size = 1;
int val = length;

while ((val >>>= 8) != 0) {
size++;
}

for (int i = (size - 1) * 8; i >= 0; i -= 8) {
count++;
}
}

return count;
}

private void writeLength(OutputStream os, int length) throws IOException {
if (length > 127) {
int size = 1;
int val = length;

while ((val >>>= 8) != 0) {
size++;
}

os.write((byte) (size | 0x80));

for (int i = (size - 1) * 8; i >= 0; i -= 8) {
os.write((byte) (length >> i));
}
} else {
os.write((byte) length);
}
return super.doVerify(signedBytes, signatureToVerify);
}

/**
Expand Down

0 comments on commit 0696554

Please sign in to comment.