|
41 | 41 | import java.util.HashMap;
|
42 | 42 | import java.util.Map;
|
43 | 43 | import java.util.stream.Stream;
|
| 44 | +import lombok.AllArgsConstructor; |
| 45 | +import lombok.NonNull; |
44 | 46 |
|
45 | 47 | final class WebAuthnCodecs {
|
46 | 48 |
|
@@ -209,17 +211,91 @@ private static PublicKey importCoseEcdsaPublicKey(CBORObject cose)
|
209 | 211 | return kFact.generatePublic(new X509EncodedKeySpec(x509Key.getBytes()));
|
210 | 212 | }
|
211 | 213 |
|
212 |
| - private static ByteArray encodeDerLength(final int length) { |
213 |
| - if (length <= 127) { |
214 |
| - return new ByteArray(new byte[] {(byte) length}); |
| 214 | + static ByteArray encodeDerLength(final int length) { |
| 215 | + if (length < 0) { |
| 216 | + throw new IllegalArgumentException("Length is negative: " + length); |
| 217 | + } else if (length <= 0x7f) { |
| 218 | + return new ByteArray(new byte[] {(byte) (length & 0xff)}); |
| 219 | + } else if (length <= 0xff) { |
| 220 | + return new ByteArray(new byte[] {(byte) (0x80 | 0x01), (byte) (length & 0xff)}); |
215 | 221 | } else if (length <= 0xffff) {
|
216 |
| - if (length <= 255) { |
217 |
| - return new ByteArray(new byte[] {-127, (byte) length}); |
| 222 | + return new ByteArray( |
| 223 | + new byte[] {(byte) (0x80 | 0x02), (byte) ((length >> 8) & 0xff), (byte) (length & 0xff)}); |
| 224 | + } else if (length <= 0xffffff) { |
| 225 | + return new ByteArray( |
| 226 | + new byte[] { |
| 227 | + (byte) (0x80 | 0x03), |
| 228 | + (byte) ((length >> 16) & 0xff), |
| 229 | + (byte) ((length >> 8) & 0xff), |
| 230 | + (byte) (length & 0xff) |
| 231 | + }); |
| 232 | + } else { |
| 233 | + return new ByteArray( |
| 234 | + new byte[] { |
| 235 | + (byte) (0x80 | 0x04), |
| 236 | + (byte) ((length >> 24) & 0xff), |
| 237 | + (byte) ((length >> 16) & 0xff), |
| 238 | + (byte) ((length >> 8) & 0xff), |
| 239 | + (byte) (length & 0xff) |
| 240 | + }); |
| 241 | + } |
| 242 | + } |
| 243 | + |
| 244 | + @AllArgsConstructor |
| 245 | + static class ParseDerResult<T> { |
| 246 | + final T result; |
| 247 | + final int nextOffset; |
| 248 | + } |
| 249 | + |
| 250 | + static ParseDerResult<Integer> parseDerLength(@NonNull byte[] der, int offset) { |
| 251 | + final int len = der.length - offset; |
| 252 | + if (len == 0) { |
| 253 | + throw new IllegalArgumentException("Empty input"); |
| 254 | + } else if ((der[offset] & 0x80) == 0) { |
| 255 | + return new ParseDerResult<>(der[offset] & 0xff, offset + 1); |
| 256 | + } else { |
| 257 | + final int longLen = der[offset] & 0x7f; |
| 258 | + if (len >= longLen) { |
| 259 | + switch (longLen) { |
| 260 | + case 0: |
| 261 | + throw new IllegalArgumentException( |
| 262 | + String.format( |
| 263 | + "Empty length encoding at offset %d: %s", offset, new ByteArray(der))); |
| 264 | + case 1: |
| 265 | + return new ParseDerResult<>(der[offset + 1] & 0xff, offset + 2); |
| 266 | + case 2: |
| 267 | + return new ParseDerResult<>( |
| 268 | + ((der[offset + 1] & 0xff) << 8) | (der[offset + 2] & 0xff), offset + 3); |
| 269 | + case 3: |
| 270 | + return new ParseDerResult<>( |
| 271 | + ((der[offset + 1] & 0xff) << 16) |
| 272 | + | ((der[offset + 2] & 0xff) << 8) |
| 273 | + | (der[offset + 3] & 0xff), |
| 274 | + offset + 4); |
| 275 | + case 4: |
| 276 | + if ((der[offset + 1] & 0x80) == 0) { |
| 277 | + return new ParseDerResult<>( |
| 278 | + ((der[offset + 1] & 0xff) << 24) |
| 279 | + | ((der[offset + 2] & 0xff) << 16) |
| 280 | + | ((der[offset + 3] & 0xff) << 8) |
| 281 | + | (der[offset + 4] & 0xff), |
| 282 | + offset + 5); |
| 283 | + } else { |
| 284 | + throw new UnsupportedOperationException( |
| 285 | + String.format( |
| 286 | + "Length out of range of int: 0x%02x%02x%02x%02x", |
| 287 | + der[offset + 1], der[offset + 2], der[offset + 3], der[offset + 4])); |
| 288 | + } |
| 289 | + default: |
| 290 | + throw new UnsupportedOperationException( |
| 291 | + String.format("Length is too long for int: %d octets", longLen)); |
| 292 | + } |
218 | 293 | } else {
|
219 |
| - return new ByteArray(new byte[] {-126, (byte) (length >> 8), (byte) (length & 0x00ff)}); |
| 294 | + throw new IllegalArgumentException( |
| 295 | + String.format( |
| 296 | + "Length encoding needs %d octets but only %s remain at index %d: %s", |
| 297 | + longLen, len - (offset + 1), offset + 1, new ByteArray(der))); |
220 | 298 | }
|
221 |
| - } else { |
222 |
| - throw new UnsupportedOperationException("Too long: " + length); |
223 | 299 | }
|
224 | 300 | }
|
225 | 301 |
|
|
0 commit comments