Hi Martin,
> We reviewed the full text and found no other changes to be made for now.
> We are working in splitting the PR into two, so the refactoring for
> class Provider and bug fixes can make their way first.
I think this is a good plan. Do you plan to decouple the refactoring
from the JEP and propose it under a different issue? I think that would
make the most sense as long as the refactoring has no direct
dependencies on the JEP.
> Any other comments about the JEP?
We have been very busy with JDK 24 deliverables. Let's sync up again on
the JEP after RDP1.
--Sean
On 11/26/24 5:52 PM, Martin Balao wrote:
Hello Sean,
We've made the following adjustments to the JEP [1]:
1) Paragraphs starting with "When a security provider is installed..."
and "The filter applies to services..." replaced with paragraphs
starting with "The filter applies to services..." and "Each service is
evaluated by...". The purpose of this change was to better describe the
multi-layer filtering strategy. We fixed a minor error in the description.
2) In Non-Goals, we clarified that characters are reserved in the syntax
(i.e. ":" and ",") with the purpose of extending the filter in the
future to provide more granularity in services selection: "(...) With
that said, extensions to this proposal may be explored in the future and
characters such as `:` and `,` will be reserved in the filter syntax for
this purpose.".
3) Sub-section "Filtering at the ::getInstance API level only" added to
the Alternatives discussion.
4) Sub-section "Leveraging on the existing
java.security.Provider::configure API to configure security providers"
added to the Alternatives discussion.
We reviewed the full text and found no other changes to be made for now.
We are working in splitting the PR into two, so the refactoring for
class Provider and bug fixes can make their way first.
Any other comments about the JEP?
Thanks,
Martin.-
--
[1] - https://bugs.openjdk.org/browse/JDK-8325511
On 10/18/24 14:55, Martin Balao wrote:
Hello Sean,
On 9/19/24 12:00, Sean Mullan wrote:
Hi Martin,
Our team at Oracle has done another review of the proposed feature
and we have some questions that we would like to discuss below.
This is a significant effort that would add some valuable features to
the Security Provider mechanism. However, this is also modifying an
important core function used by all JCA/JCE APIs to locate
implementations, so we want to make sure we spend the time to review
all aspects of the proposal thoroughly.
Thanks for reviewing our proposal. We totally understand and are happy
to have such a thorough review. It is in the best interest of the
whole community and us to get this right.
- The current implementation introduces behavior changes in the
Provider API which we believe would need to be specified in the
specification. For example, if an application registers a service
that is restricted by the filter using the Provider API, then that
service won't be returned by methods such as Provider.getServices().
This is a behavior change in the API. I don't think it could be
specified as an implementation note, since it changes the specified
behavior of these methods.
Adding specification changes will make any backport much more
difficult, if that was one of your goals.
We agree that our proposal affects the behavior of
Provider::getService(s) APIs and that a specification change is
required. We are aware of this extra complexity but, in the interest
of having the best solution possible for the long term, are willing to
have the discussion. Our expectation is to have the Filter included in
JDK 25 and have no plans for backports to earlier releases. With that
said, if it takes longer to integrate the Filter into JDK main line,
we will still be interested in a backport to JDK 25.
- Did you consider implementing the filtering mechanism at a higher
layer, in the getInstance methods? This could possibly avoid the
specification concerns above, as the behavior could potentially be
added as implementation notes in the getInstance methods, similar to
the implementation note for the jdk.security.provider.preferred
Security property.
Yes, we considered that option. We just noticed that it is not in the
Alternatives segment of the JEP. We will add it in the coming days.
Being ::getInstance a public API and the Filter altering its behavior
in terms of what is returned, we'd rather handle this alternative as a
specification change as well. In any case, the main reason why we
opted for filtering at the Service level is to handle any service type
in a uniform and consistent way, including service types defined by
3rd-party applications/libraries/providers. Having taken
the ::getInstance path, we would have had to either not support 3rd-
party service types or create a new public API in the Filter to query
whether a service is allowed or denied. This approach would have
opened the door for flaws or inconsistencies in how 3rd-party
implementations handle Filter decisions. Besides this, we thought that
obtaining a service instance with Provider::getService(s) that cannot
be obtained and used by ::getInstance could introduce some confusion.
This would have had an impact not only programmatically but in -
XshowSettings:security:providers.
- The syntax doesn't currently support key size constraints, or
algorithm constraints that are not specified in algorithm names, such
as the parameters used with the RSASSA-PSS algorithm. How would you
add support for these in the future?
We reserved the colon (:) and comma (,) characters in the syntax for
this purpose. As these characters must be escaped, we can extend the
syntax in the future to allow further constraints (e.g. key size,
algorithm constraints) in a backward-compatible way.
We added the following reference in the JEP:
"In addition, identifying services with a granularity finer than an
algorithm name or alias (e.g. based on key size or other algorithm
parameters) is not under the scope at this time. With that said,
extensions to this proposal may be explored in the future and
characters will be reserved in the filter syntax for this purpose."
We also mentioned the full list of reserved characters:
"The following characters, when part of one of the listed levels, must
be escaped by prepending a '\' character: '!', '*', ' ' (white space),
'.', ';', '\', ':' and ','."
We did not connect the two references by matching the concept of finer
granularity with the reserved characters for that purpose. We can add
a loose connection. However, we prefer not to prescribe the exact
syntax now as it is a non-goal and would require further analysis and
to explore implementations.
One thing to consider here is that the use of one of the reserved
characters (e.g. ':') can open the door for an extension of the syntax
with new reserved tokens and characters. For example:
SunJCE.Cipher.AES : keySize > 128. In this case, '>' does not need to
be reserved for the provider name, service type or algorithm. For the
algorithm constraint, 'keySize' and '>' are assigned a specific meaning.
- Does the filtering work for providers that are not registered, and
just passed into the getInstance methods?
Yes, it does. For most providers, filtering occurs when they invoke
Provider::putService/put APIs. In very rare cases, a Provider may not
invoke Provider::putService/put APIs and still return a Service
overriding Provider::getService(s). In that situation, we filter when
Service::newInstance is invoked. In theory, it is possible that a
Service subclass overrides Service::newInstance. In such extreme
circumstances, we filter at the ::getInstance level. The last case
will not apply to 3rd-party service types, but should be extremely
unlikely.
- Did you consider implementing this as a Provider.configure option?
There are pros/cons to doing that, but given that the configure
method is designed to configure providers, we think it should be
considered and described in the Alternatives section.
We did not consider Provider::configure. We will add it to the
Alternatives section if you deem it important. I personally see more
cons than pros but if someone has a different opinion and wants to
advocate for it, we're happy to have a discussion.
- Would early initialization of the filter inadvertently triggered
by a cryptographic operation (for example, when verifying a signed
JAR on the classpath) cause subsequent settings of the filter by an
application at runtime to be ignored? If so, this is something that
could easily go undetected, as the filter could be silently ignored
and thus restrictions not enforced as expected - it may be worth
considering throwing an exception if you can detect that the property
has already been set and processed. The logging and debugging
mechanisms are helpful but I view them as being more useful when
testing the filter or later debugging of issues.
Our understanding is that in such an event the Filter would be
initialized when the ClassLoader does JAR verification. If this is the
case, programmatically defining a Filter in the signed JAR should not
work. @Francisco will create a proof-of-concept to confirm this
hypothesis in the coming days.
We agree that throwing an exception in such a case would be ideal.
However, this type of change —as we see it— involves a specification
change in System::setProperty/Security::setProperty as that's the only
interface to set a Filter value programmatically. We are open to
having this discussion.
Another alternative would be to reserve the property in
System::setProperty/Security::setProperty and throw an exception
irrespective of the Filter status. We think that setting the Filter
programmatically should not be recommended for general use. However,
this would prevent advanced users that know how things are initialized
from benefiting.
- Does the additional searching for Cipher transformations cause
significant performance issues?
We don't think so. When providers register the full "alg/mode/padding"
as algorithm name, transformation queries against the filter are done
at registration time (Provider::putService/put invocation) and cached
in the Service instance. It's true that queries may be done at run
time to explore different transformation combinations
(e.g. ::getInstance of "alg/mode/padding" may explore services that
registered "alg/mode", "alg//padding" and "alg" as algorithm name).
However, these transformation queries are cached per Service instance
after the Filter decision is made. In the worst case —extremely
unlikely—, a provider may register 4 services relevant for the
transformation (e.g. alg/mode/padding, alg/mode, alg//padding and alg)
and the Filter blocks the transformation —if the Filter allows the
transformation, the first service will be used and the others won't be
queried because it is a lazy mechanism—. This case would require 3
queries against the filter —the "alg/mode/padding" decision is read
from the Service's cache— when they are not in the transformations
cache. The reason why the transformation cache is per service and not
per provider is because we include service aliases as part of the query.
Regards,
Martin and Francisco.-