41
41
import java .util .Arrays ;
42
42
import java .util .HashMap ;
43
43
import java .util .Map ;
44
- import lombok .AllArgsConstructor ;
45
- import lombok .NonNull ;
46
44
47
45
final class WebAuthnCodecs {
48
46
@@ -197,168 +195,23 @@ private static PublicKey importCoseEcdsaPublicKey(CBORObject cose)
197
195
}
198
196
199
197
final byte [] algId =
200
- encodeDerSequence (
201
- encodeDerObjectId (EC_PUBLIC_KEY_OID .getBytes ()), encodeDerObjectId (curveOid ));
198
+ BinaryUtil .encodeDerSequence (
199
+ BinaryUtil .encodeDerObjectId (EC_PUBLIC_KEY_OID .getBytes ()),
200
+ BinaryUtil .encodeDerObjectId (curveOid ));
202
201
203
202
final byte [] rawKey =
204
- encodeDerBitStringWithZeroUnused (
203
+ BinaryUtil . encodeDerBitStringWithZeroUnused (
205
204
BinaryUtil .concat (
206
205
new byte [] {0x04 }, // Raw EC public key with x and y
207
206
x ,
208
207
y ));
209
208
210
- final byte [] x509Key = encodeDerSequence (algId , rawKey );
209
+ final byte [] x509Key = BinaryUtil . encodeDerSequence (algId , rawKey );
211
210
212
211
KeyFactory kFact = KeyFactory .getInstance ("EC" );
213
212
return kFact .generatePublic (new X509EncodedKeySpec (x509Key ));
214
213
}
215
214
216
- static byte [] encodeDerLength (final int length ) {
217
- if (length < 0 ) {
218
- throw new IllegalArgumentException ("Length is negative: " + length );
219
- } else if (length <= 0x7f ) {
220
- return new byte [] {(byte ) (length & 0xff )};
221
- } else if (length <= 0xff ) {
222
- return new byte [] {(byte ) (0x80 | 0x01 ), (byte ) (length & 0xff )};
223
- } else if (length <= 0xffff ) {
224
- return new byte [] {
225
- (byte ) (0x80 | 0x02 ), (byte ) ((length >> 8 ) & 0xff ), (byte ) (length & 0xff )
226
- };
227
- } else if (length <= 0xffffff ) {
228
- return new byte [] {
229
- (byte ) (0x80 | 0x03 ),
230
- (byte ) ((length >> 16 ) & 0xff ),
231
- (byte ) ((length >> 8 ) & 0xff ),
232
- (byte ) (length & 0xff )
233
- };
234
- } else {
235
- return new byte [] {
236
- (byte ) (0x80 | 0x04 ),
237
- (byte ) ((length >> 24 ) & 0xff ),
238
- (byte ) ((length >> 16 ) & 0xff ),
239
- (byte ) ((length >> 8 ) & 0xff ),
240
- (byte ) (length & 0xff )
241
- };
242
- }
243
- }
244
-
245
- @ AllArgsConstructor
246
- static class ParseDerResult <T > {
247
- final T result ;
248
- final int nextOffset ;
249
- }
250
-
251
- static ParseDerResult <Integer > parseDerLength (@ NonNull byte [] der , int offset ) {
252
- final int len = der .length - offset ;
253
- if (len == 0 ) {
254
- throw new IllegalArgumentException ("Empty input" );
255
- } else if ((der [offset ] & 0x80 ) == 0 ) {
256
- return new ParseDerResult <>(der [offset ] & 0xff , offset + 1 );
257
- } else {
258
- final int longLen = der [offset ] & 0x7f ;
259
- if (len >= longLen ) {
260
- switch (longLen ) {
261
- case 0 :
262
- throw new IllegalArgumentException (
263
- String .format (
264
- "Empty length encoding at offset %d: 0x%s" , offset , BinaryUtil .toHex (der )));
265
- case 1 :
266
- return new ParseDerResult <>(der [offset + 1 ] & 0xff , offset + 2 );
267
- case 2 :
268
- return new ParseDerResult <>(
269
- ((der [offset + 1 ] & 0xff ) << 8 ) | (der [offset + 2 ] & 0xff ), offset + 3 );
270
- case 3 :
271
- return new ParseDerResult <>(
272
- ((der [offset + 1 ] & 0xff ) << 16 )
273
- | ((der [offset + 2 ] & 0xff ) << 8 )
274
- | (der [offset + 3 ] & 0xff ),
275
- offset + 4 );
276
- case 4 :
277
- if ((der [offset + 1 ] & 0x80 ) == 0 ) {
278
- return new ParseDerResult <>(
279
- ((der [offset + 1 ] & 0xff ) << 24 )
280
- | ((der [offset + 2 ] & 0xff ) << 16 )
281
- | ((der [offset + 3 ] & 0xff ) << 8 )
282
- | (der [offset + 4 ] & 0xff ),
283
- offset + 5 );
284
- } else {
285
- throw new UnsupportedOperationException (
286
- String .format (
287
- "Length out of range of int: 0x%02x%02x%02x%02x" ,
288
- der [offset + 1 ], der [offset + 2 ], der [offset + 3 ], der [offset + 4 ]));
289
- }
290
- default :
291
- throw new UnsupportedOperationException (
292
- String .format ("Length is too long for int: %d octets" , longLen ));
293
- }
294
- } else {
295
- throw new IllegalArgumentException (
296
- String .format (
297
- "Length encoding needs %d octets but only %s remain at index %d: 0x%s" ,
298
- longLen , len - (offset + 1 ), offset + 1 , BinaryUtil .toHex (der )));
299
- }
300
- }
301
- }
302
-
303
- private static ParseDerResult <byte []> parseDerTagged (
304
- @ NonNull byte [] der , int offset , byte expectTag ) {
305
- final int len = der .length - offset ;
306
- if (len == 0 ) {
307
- throw new IllegalArgumentException (
308
- String .format ("Empty input at offset %d: 0x%s" , offset , BinaryUtil .toHex (der )));
309
- } else {
310
- final byte tag = der [offset ];
311
- if (tag == expectTag ) {
312
- final ParseDerResult <Integer > contentLen = parseDerLength (der , offset + 1 );
313
- final int contentEnd = contentLen .nextOffset + contentLen .result ;
314
- return new ParseDerResult <>(
315
- Arrays .copyOfRange (der , contentLen .nextOffset , contentEnd ), contentEnd );
316
- } else {
317
- throw new IllegalArgumentException (
318
- String .format (
319
- "Incorrect tag: 0x%02x (expected 0x%02x) at offset %d: 0x%s" ,
320
- tag , expectTag , offset , BinaryUtil .toHex (der )));
321
- }
322
- }
323
- }
324
-
325
- /** Parse a SEQUENCE and return a copy of the content octets. */
326
- static ParseDerResult <byte []> parseDerSequence (@ NonNull byte [] der , int offset ) {
327
- return parseDerTagged (der , offset , (byte ) 0x30 );
328
- }
329
-
330
- /**
331
- * Parse an explicitly tagged value of class "context-specific" (bits 8-7 are 0b10), in
332
- * "constructed" encoding (bit 6 is 1), with a prescribed tag value, and return a copy of the
333
- * content octets.
334
- */
335
- static ParseDerResult <byte []> parseDerExplicitlyTaggedContextSpecificConstructed (
336
- @ NonNull byte [] der , int offset , byte tagNumber ) {
337
- if (tagNumber <= 30 && tagNumber >= 0 ) {
338
- return parseDerTagged (der , offset , (byte ) ((tagNumber & 0x1f ) | 0xa0 ));
339
- } else {
340
- throw new UnsupportedOperationException (
341
- String .format ("Tag number out of range: %d (expected 0 to 30, inclusive)" , tagNumber ));
342
- }
343
- }
344
-
345
- private static byte [] encodeDerObjectId (@ NonNull byte [] oid ) {
346
- byte [] result = new byte [2 + oid .length ];
347
- result [0 ] = 0x06 ;
348
- result [1 ] = (byte ) oid .length ;
349
- return BinaryUtil .copyInto (oid , result , 2 );
350
- }
351
-
352
- private static byte [] encodeDerBitStringWithZeroUnused (@ NonNull byte [] content ) {
353
- return BinaryUtil .concat (
354
- new byte [] {0x03 }, encodeDerLength (1 + content .length ), new byte [] {0 }, content );
355
- }
356
-
357
- static byte [] encodeDerSequence (final byte []... items ) {
358
- byte [] content = BinaryUtil .concat (items );
359
- return BinaryUtil .concat (new byte [] {0x30 }, encodeDerLength (content .length ), content );
360
- }
361
-
362
215
private static PublicKey importCoseEdDsaPublicKey (CBORObject cose )
363
216
throws InvalidKeySpecException , NoSuchAlgorithmException {
364
217
final int curveId = cose .get (CBORObject .FromObject (-1 )).AsInt32 ();
@@ -374,7 +227,8 @@ private static PublicKey importCoseEd25519PublicKey(CBORObject cose)
374
227
throws InvalidKeySpecException , NoSuchAlgorithmException {
375
228
final byte [] rawKey = cose .get (CBORObject .FromObject (-2 )).GetByteString ();
376
229
final byte [] x509Key =
377
- encodeDerSequence (ED25519_ALG_ID .getBytes (), encodeDerBitStringWithZeroUnused (rawKey ));
230
+ BinaryUtil .encodeDerSequence (
231
+ ED25519_ALG_ID .getBytes (), BinaryUtil .encodeDerBitStringWithZeroUnused (rawKey ));
378
232
379
233
KeyFactory kFact = KeyFactory .getInstance ("EdDSA" );
380
234
return kFact .generatePublic (new X509EncodedKeySpec (x509Key ));
0 commit comments