@@ -44,10 +44,7 @@ public void verify(DecodedJWT jwt) throws SignatureVerificationException {
4444 if (publicKey == null ) {
4545 throw new IllegalStateException ("The given Public Key is null." );
4646 }
47- if (!isDERSignature (signatureBytes )) {
48- signatureBytes = JOSEToDER (signatureBytes );
49- }
50- boolean valid = crypto .verifySignatureFor (getDescription (), publicKey , contentBytes , signatureBytes );
47+ boolean valid = crypto .verifySignatureFor (getDescription (), publicKey , contentBytes , JOSEToDER (signatureBytes ));
5148
5249 if (!valid ) {
5350 throw new SignatureVerificationException (this );
@@ -64,7 +61,8 @@ public byte[] sign(byte[] contentBytes) throws SignatureGenerationException {
6461 if (privateKey == null ) {
6562 throw new IllegalStateException ("The given Private Key is null." );
6663 }
67- return crypto .createSignatureFor (getDescription (), privateKey , contentBytes );
64+ byte [] signature = crypto .createSignatureFor (getDescription (), privateKey , contentBytes );
65+ return DERToJOSE (signature );
6866 } catch (NoSuchAlgorithmException | SignatureException | InvalidKeyException | IllegalStateException e ) {
6967 throw new SignatureGenerationException (this , e );
7068 }
@@ -75,15 +73,60 @@ public String getSigningKeyId() {
7573 return keyProvider .getPrivateKeyId ();
7674 }
7775
78- private boolean isDERSignature (byte [] signature ) {
76+ //Visible for testing
77+ byte [] DERToJOSE (byte [] derSignature ) throws SignatureException {
7978 // DER Structure: http://crypto.stackexchange.com/a/1797
80- // Should begin with 0x30 and have exactly the expected length
81- return signature [0 ] == 0x30 && signature .length != ecNumberSize * 2 ;
79+ boolean derEncoded = derSignature [0 ] == 0x30 && derSignature .length != ecNumberSize * 2 ;
80+ if (!derEncoded ) {
81+ throw new SignatureException ("Invalid DER signature format." );
82+ }
83+
84+ final byte [] joseSignature = new byte [ecNumberSize * 2 ];
85+
86+ //Skip 0x30
87+ int offset = 1 ;
88+ if (derSignature [1 ] == (byte ) 0x81 ) {
89+ //Skip sign
90+ offset ++;
91+ }
92+
93+ //Convert to unsigned. Should match DER length - offset
94+ int encodedLength = derSignature [offset ++] & 0xff ;
95+ if (encodedLength != derSignature .length - offset ) {
96+ throw new SignatureException ("Invalid DER signature format." );
97+ }
98+
99+ //Skip 0x02
100+ offset ++;
101+
102+ //Obtain R number length (Includes padding) and skip it
103+ int rLength = derSignature [offset ++];
104+ if (rLength > ecNumberSize + 1 ) {
105+ throw new SignatureException ("Invalid DER signature format." );
106+ }
107+ int rPadding = ecNumberSize - rLength ;
108+ //Retrieve R number
109+ System .arraycopy (derSignature , offset + Math .max (-rPadding , 0 ), joseSignature , Math .max (rPadding , 0 ), rLength + Math .min (rPadding , 0 ));
110+
111+ //Skip R number and 0x02
112+ offset += rLength + 1 ;
113+
114+ //Obtain S number length. (Includes padding)
115+ int sLength = derSignature [offset ++];
116+ if (sLength > ecNumberSize + 1 ) {
117+ throw new SignatureException ("Invalid DER signature format." );
118+ }
119+ int sPadding = ecNumberSize - sLength ;
120+ //Retrieve R number
121+ System .arraycopy (derSignature , offset + Math .max (-sPadding , 0 ), joseSignature , ecNumberSize + Math .max (sPadding , 0 ), sLength + Math .min (sPadding , 0 ));
122+
123+ return joseSignature ;
82124 }
83125
84- private byte [] JOSEToDER (byte [] joseSignature ) throws SignatureException {
126+ //Visible for testing
127+ byte [] JOSEToDER (byte [] joseSignature ) throws SignatureException {
85128 if (joseSignature .length != ecNumberSize * 2 ) {
86- throw new SignatureException (String . format ( "The signature length was invalid. Expected %d bytes but received %d" , ecNumberSize * 2 , joseSignature . length ) );
129+ throw new SignatureException ("Invalid JOSE signature format." );
87130 }
88131
89132 // Retrieve R and S number's length and padding.
@@ -94,10 +137,10 @@ private byte[] JOSEToDER(byte[] joseSignature) throws SignatureException {
94137
95138 int length = 2 + rLength + 2 + sLength ;
96139 if (length > 255 ) {
97- throw new SignatureException ("Invalid ECDSA signature format" );
140+ throw new SignatureException ("Invalid JOSE signature format. " );
98141 }
99142
100- byte [] derSignature ;
143+ final byte [] derSignature ;
101144 int offset ;
102145 if (length > 0x7f ) {
103146 derSignature = new byte [3 + length ];
@@ -109,22 +152,38 @@ private byte[] JOSEToDER(byte[] joseSignature) throws SignatureException {
109152 }
110153
111154 // DER Structure: http://crypto.stackexchange.com/a/1797
112- // Header with length info
155+ // Header with signature length info
113156 derSignature [0 ] = (byte ) 0x30 ;
114- derSignature [offset ++] = (byte ) length ;
157+ derSignature [offset ++] = (byte ) (length & 0xff );
158+
159+ // Header with "min R" number length
115160 derSignature [offset ++] = (byte ) 0x02 ;
116161 derSignature [offset ++] = (byte ) rLength ;
117162
118163 // R number
119- System .arraycopy (joseSignature , 0 , derSignature , offset + (rLength - ecNumberSize ), ecNumberSize );
120- offset += rLength ;
164+ if (rPadding < 0 ) {
165+ //Sign
166+ derSignature [offset ++] = (byte ) 0x00 ;
167+ System .arraycopy (joseSignature , 0 , derSignature , offset , ecNumberSize );
168+ offset += ecNumberSize ;
169+ } else {
170+ int copyLength = Math .min (ecNumberSize , rLength );
171+ System .arraycopy (joseSignature , rPadding , derSignature , offset , copyLength );
172+ offset += copyLength ;
173+ }
121174
122- // S number length
175+ // Header with "min S" number length
123176 derSignature [offset ++] = (byte ) 0x02 ;
124177 derSignature [offset ++] = (byte ) sLength ;
125178
126179 // S number
127- System .arraycopy (joseSignature , ecNumberSize , derSignature , offset + (sLength - ecNumberSize ), ecNumberSize );
180+ if (sPadding < 0 ) {
181+ //Sign
182+ derSignature [offset ++] = (byte ) 0x00 ;
183+ System .arraycopy (joseSignature , ecNumberSize , derSignature , offset , ecNumberSize );
184+ } else {
185+ System .arraycopy (joseSignature , ecNumberSize + sPadding , derSignature , offset , Math .min (ecNumberSize , sLength ));
186+ }
128187
129188 return derSignature ;
130189 }
@@ -134,7 +193,7 @@ private int countPadding(byte[] bytes, int fromIndex, int toIndex) {
134193 while (fromIndex + padding < toIndex && bytes [fromIndex + padding ] == 0 ) {
135194 padding ++;
136195 }
137- return bytes [fromIndex + padding ] > 0x7f ? padding : padding - 1 ;
196+ return ( bytes [fromIndex + padding ] & 0xff ) > 0x7f ? padding - 1 : padding ;
138197 }
139198
140199 //Visible for testing
0 commit comments