|
1 | 1 | /* |
2 | | - * Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved. |
| 2 | + * Copyright (c) 2006, 2026, Oracle and/or its affiliates. All rights reserved. |
3 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 | 4 | * |
5 | 5 | * This code is free software; you can redistribute it and/or modify it |
|
25 | 25 |
|
26 | 26 | package sun.security.provider.certpath; |
27 | 27 |
|
| 28 | +import java.io.FilterInputStream; |
28 | 29 | import java.io.InputStream; |
29 | 30 | import java.io.IOException; |
30 | 31 | import java.net.HttpURLConnection; |
@@ -188,6 +189,16 @@ private static int initializeTimeout(String prop, int def) { |
188 | 189 | return timeoutVal; |
189 | 190 | } |
190 | 191 |
|
| 192 | + /** |
| 193 | + * Maximum size for a CRL downloaded through a URICertStore |
| 194 | + * in bytes. This can be controlled by the com.sun.security.crl.maxSize |
| 195 | + * Security or System property. The System property, if set, overrides |
| 196 | + * the Security property. The default size is 20MiB. |
| 197 | + */ |
| 198 | + private static final long MAX_CRL_DOWNLOAD_SIZE = |
| 199 | + SecurityProperties.getOverridableLongProp( |
| 200 | + "com.sun.security.crl.maxSize", 20971520, debug); |
| 201 | + |
191 | 202 | /** |
192 | 203 | * Enumeration for the allowed schemes we support when following a |
193 | 204 | * URI from an authorityInfoAccess extension on a certificate. |
@@ -228,6 +239,13 @@ static AllowedScheme nameOf(String name) { |
228 | 239 | private static final boolean CA_ISS_ALLOW_ANY; |
229 | 240 |
|
230 | 241 | static { |
| 242 | + // Add a debug message for the configured CRL download limit |
| 243 | + if (debug != null) { |
| 244 | + debug.println("Maximum downloadable CRL size: " + |
| 245 | + MAX_CRL_DOWNLOAD_SIZE + |
| 246 | + ((MAX_CRL_DOWNLOAD_SIZE < 0) ? " (DISABLED)" : "")); |
| 247 | + } |
| 248 | + |
231 | 249 | boolean allowAny = false; |
232 | 250 | try { |
233 | 251 | if (Builder.USE_AIA) { |
@@ -623,7 +641,19 @@ public synchronized Collection<X509CRL> engineGetCRLs(CRLSelector selector) |
623 | 641 | if (debug != null) { |
624 | 642 | debug.println("Downloading new CRL..."); |
625 | 643 | } |
626 | | - crl = (X509CRL) factory.generateCRL(in); |
| 644 | + InputStream crlIn = (MAX_CRL_DOWNLOAD_SIZE > -1) ? |
| 645 | + new SizeLimitedInputStream(in, MAX_CRL_DOWNLOAD_SIZE) : |
| 646 | + in; |
| 647 | + try { |
| 648 | + crl = (X509CRL) factory.generateCRL(crlIn); |
| 649 | + } catch (IllegalArgumentException iae) { |
| 650 | + // IAE should only be thrown when the CRL exceeds a |
| 651 | + // configured maximum length. |
| 652 | + if (debug != null) { |
| 653 | + debug.println("Discarding CRL: " + iae.getMessage()); |
| 654 | + crl = null; |
| 655 | + } |
| 656 | + } |
627 | 657 | } |
628 | 658 | return getMatchingCRLs(crl, selector); |
629 | 659 | } catch (IOException | CRLException e) { |
@@ -816,4 +846,59 @@ boolean matchRule(URI filterRule, URI caIssuer) { |
816 | 846 | return true; |
817 | 847 | } |
818 | 848 | } |
| 849 | + |
| 850 | + /** |
| 851 | + * Stream wrapper used when an InputStream passed into a CertificateFactory |
| 852 | + * needs to be size limited. It will throw IllegalArgumentException when |
| 853 | + * the downloaded resource via the underlying stream exceeds the maximum |
| 854 | + * limit. |
| 855 | + */ |
| 856 | + private static class SizeLimitedInputStream extends FilterInputStream { |
| 857 | + |
| 858 | + private final long maxBytes; |
| 859 | + private long bytesRead = 0; |
| 860 | + |
| 861 | + private SizeLimitedInputStream(InputStream in, long maxBytes) { |
| 862 | + super(in); |
| 863 | + this.maxBytes = maxBytes; |
| 864 | + } |
| 865 | + |
| 866 | + @Override |
| 867 | + public int read() throws IOException { |
| 868 | + if (bytesRead >= maxBytes) { |
| 869 | + // We will use IAE here to differentiate this special case |
| 870 | + // from other IOEs that the underlying input stream might |
| 871 | + // legitimately throw. |
| 872 | + throw new IllegalArgumentException("InputStream exceeded max " + |
| 873 | + "size of " + maxBytes); |
| 874 | + } |
| 875 | + |
| 876 | + int b = super.read(); |
| 877 | + if (b != -1) { |
| 878 | + bytesRead++; |
| 879 | + } |
| 880 | + return b; |
| 881 | + } |
| 882 | + |
| 883 | + @Override |
| 884 | + public int read(byte[] b, int off, int len) throws IOException { |
| 885 | + |
| 886 | + if (bytesRead >= maxBytes) { |
| 887 | + // We will use IAE here to differentiate this special case |
| 888 | + // from other IOEs that the underlying input stream might |
| 889 | + // legitimately throw. |
| 890 | + throw new IllegalArgumentException("InputStream exceeded max " + |
| 891 | + "size of " + maxBytes); |
| 892 | + } |
| 893 | + |
| 894 | + long remaining = maxBytes - bytesRead; |
| 895 | + int toRead = (int) Math.min(len, remaining); |
| 896 | + |
| 897 | + int n = super.read(b, off, toRead); |
| 898 | + if (n != -1) { |
| 899 | + bytesRead += n; |
| 900 | + } |
| 901 | + return n; |
| 902 | + } |
| 903 | + } |
819 | 904 | } |
0 commit comments