77
88class ECDSAAlgorithm extends Algorithm {
99
10+ private final int ecNumberSize ;
1011 private final PublicKey publicKey ;
1112
12- ECDSAAlgorithm (String id , String algorithm , PublicKey publicKey ) {
13+ ECDSAAlgorithm (String id , String algorithm , int ecNumberSize , PublicKey publicKey ) {
1314 super (id , algorithm );
1415 if (publicKey == null ) {
1516 throw new IllegalArgumentException ("The PublicKey cannot be null" );
1617 }
18+ this .ecNumberSize = ecNumberSize ;
1719 this .publicKey = publicKey ;
1820 }
1921
@@ -29,6 +31,9 @@ public void verify(String[] jwtParts) throws SignatureVerificationException {
2931 s .initVerify (publicKey );
3032 s .update (content .getBytes ());
3133 byte [] signature = Base64 .decodeBase64 (jwtParts [2 ]);
34+ if (isJOSESignature (signature )) {
35+ signature = JOSEToDER (signature );
36+ }
3237 boolean valid = s .verify (signature );
3338 if (!valid ) {
3439 throw new SignatureVerificationException (this );
@@ -38,4 +43,64 @@ public void verify(String[] jwtParts) throws SignatureVerificationException {
3843 }
3944 }
4045
46+ private boolean isJOSESignature (byte [] signature ) {
47+ //TODO: Check if the signature has JOSE format.
48+ return true ;
49+ }
50+
51+ private byte [] JOSEToDER (byte [] joseSignature ) throws SignatureException {
52+ if (joseSignature .length != ecNumberSize * 2 ) {
53+ throw new SignatureException (String .format ("The signature length was invalid. Expected %d bytes but received %d" , ecNumberSize * 2 , joseSignature .length ));
54+ }
55+
56+ // Retrieve R and S number's length and padding.
57+ int rPadding = countPadding (joseSignature , 0 , ecNumberSize );
58+ int sPadding = countPadding (joseSignature , ecNumberSize , joseSignature .length );
59+ int rLength = ecNumberSize - rPadding ;
60+ int sLength = ecNumberSize - sPadding ;
61+
62+ int length = 2 + rLength + 2 + sLength ;
63+ if (length > 0xFF ) {
64+ throw new SignatureException ("Invalid ECDSA signature format" );
65+ }
66+
67+ byte [] derSignature ;
68+ int offset ;
69+ if (length > 0x7f ) {
70+ derSignature = new byte [3 + length ];
71+ derSignature [1 ] = (byte ) 0x81 ;
72+ offset = 2 ;
73+ } else {
74+ derSignature = new byte [2 + length ];
75+ offset = 1 ;
76+ }
77+
78+ // DER Structure: http://crypto.stackexchange.com/a/1797
79+ // Header with length info
80+ derSignature [0 ] = (byte ) 0x30 ;
81+ derSignature [offset ++] = (byte ) length ;
82+ derSignature [offset ++] = (byte ) 0x02 ;
83+ derSignature [offset ++] = (byte ) rLength ;
84+
85+ // R number
86+ System .arraycopy (joseSignature , 0 , derSignature , offset + (rLength - ecNumberSize ), ecNumberSize );
87+ offset += rLength ;
88+
89+ // S number length
90+ derSignature [offset ++] = (byte ) 0x02 ;
91+ derSignature [offset ++] = (byte ) sLength ;
92+
93+ // S number
94+ System .arraycopy (joseSignature , ecNumberSize , derSignature , offset + (sLength - ecNumberSize ), ecNumberSize );
95+
96+ return derSignature ;
97+ }
98+
99+ private int countPadding (byte [] bytes , int fromIndex , int toIndex ) {
100+ int padding = 0 ;
101+ while (fromIndex + padding < toIndex && bytes [fromIndex + padding ] == 0 ) {
102+ padding ++;
103+ }
104+ return bytes [fromIndex + padding ] > 0x7f ? padding : padding - 1 ;
105+ }
41106}
0 commit comments