[openssl-users] Comments on the recent OpenSSL 3.0.0 specification (Monday 2019-02-11)

Richard Levitte levitte at openssl.org
Fri Feb 15 10:40:49 UTC 2019

Note: these are my personal answers.  I'm sure (and hope) that other
in our team will chip in (and possibly disagree with me)

On Fri, 15 Feb 2019 04:55:38 +0100,
Jakob Bohm wrote:
> These comments are on the version of the specification released on
> Monday 2019-02-11 at https://www.openssl.org/docs/OpenSSL300Design.html
> General notes on this release:
> - The release was not announced on the openssl-users and
>   openssl-announce mailing lists.  A related blog post was
>   announced two days later.


> - The related strategy document is at
>   https://www.openssl.org/docs/OpenSSLStrategicArchitecture.html
>   (This link is broken on the www.openssl.org front page).

Broken link fixed.  It was a typo...

> - The draft does not link to anywhere that the public can
>   inspect archived or version tracked document versions.

Are you asking us to provide a link to the git repo?  Should we do
that in each of our HTML files?  (I'm not trying to be a smartass,
this is something we could actually do, and quite easily for these
documents specifically)

BTW, more direct answer: the underlying documents are written in
markdown, and the repo links are:

- [our own repo]
- [github]

> Non-FIPS architecture issues:
> - The identifiers for predefined parameters and values (such as
>   "fips", "on", "off", "aes-128-cbc" should be binary values that
>   cannot be easily searched in larger program files (by attackers).
>   This rules out both text strings, UUID values and ASN OID values.
>   Something similar to the function ids would be ideal.  Note that
>   to make this effective, the string names of these should not
>   appear in linked binaries.
>   (The context of this is linking libcrypto and/or libssl into
>   closed source binary programs, since open source binaries cannot
>   hide their internal structure anyway).

The trouble with this is that it limits what providers can actually
provide.  I've used the example of someone inventing an algorithm
"BLARGH", with some parameters and properties they define.  How would
they be represented with a binary number?  How would an application
know what number they should ask for?

We've chosen strings to have the flexibility.

> - It should be possible for applications to configure OpenSSL to
>   load provider DLLs and config files from their own directories
>   rather than the global well-known directory (isolation from
>   system wide changes).

I see no issue with that.  The well-known directory would work as a
fallback, the same way we do with ENGINESDIR today.

> - It should be possible for providers (possibly not the FIPS
>   provider) to be linked directly into programs that link
>   statically to libcrypto.  This implies the absence of
>   conflicting identifiers, a public API to pass the address of
>   a |OSSL_provider_init|function, all bundled providers provided
>   as static libraries in static library builds, and a higher
>   level init function that initializes both libcrypto and the
>   default provider.

You may have noticed in the packaging view that the default provider
will be part of libcrypto.  To allow that, we must allow exactly the
construct that you're talking about, and the step to make it possible
for applications to link statically with providers is very small.

(as for "possibly not the FIPS provider", that's exactly right.  That
one *will* be a loadable module and nothing else, and will only be
validated as such...  meaning that noone can stop you from hacking
around and have it linked in statically, but that would make it
invalid re FIPS)

> - Static library forms of the default provider should not
>   force callers to include every algorithm just because they
>   are referenced from the default dispatch tables.  For example,
>   it should be easy to link a static application that uses only
>   AES-256-CBC and SHA-256, and contains little else.  Such limited
>   feature applications would obviously have to forego using the
>   all-inclusive high level init function.

The way to do that would be to divide the default provider into a
number of smaller providers, one for each algorithm, and then leave
you free to link with exactly those you want and none other.  We
haven't really made any explicit plans to do this initially, but I
can't see any reason why it shouldn't be doable.  I can't say if it
will happen in time for 3.0.0, there's already enough to work on and
this is not in the top priorities.

> - For use with engine-like providers (such as hardware providers
>   and the PKCS#11 provider), it should be possible for a provider
>   to provide algorithms like RSA at multiple abstraction levels.
>   For example, some PKCS#11 hardware provides the raw RSA
>   algorithm (bignum in, bignum out) while others provide specific
>   forms such as PKCS#1.5 signature.  There are even some that
>   provide the PKCS#1.5 form with some hashes and the RSA form
>   as a general fallback.

The new design is at that higher level, centered around the EVP API.
The lower level / raw RSA abstraction level isn't there, and we have
not planned for the kind of lower level "default" algorithm support
that ENGINE did.

> - Similarly, some providers will provide both ends of an
>   asymmetric algorithm, while others only provide the private
>   key operation, leaving the public key operation to other
>   providers (selected by core in the general way).

That would mean some key information passing between providers in a
generic form to allow them to store the key data internally as they
see fit.  Otherwise, those two providers will have to share pretty
damn intimate knowledge about each other's internals.

> - The general bignum library should be exposed via an API, either
>   the legacy OpenSSL bignum API or a replacement API with an overlap
>   of at least one major version with both APIs available.

I don't understand...  the BIGNUM library is available in libcrypto
and as far as I know, there are no plans to remove it.  What did I

> - Provider algorithm implementations should carry
>   description/selection parameters indicating limits to access:
>   "key-readable=yes/no", "key-writable=yes/no", "data-internal=yes/no",
>   "data-external=yes/no" and "iv-internal=yes/no".  For example,
>   a smartcard-like provider may have "key-readable=no" and
>   "key-writable=yes" for RSA keys, while another card may have
>   "key-writable=no" (meaning that externally generated keys cannot
>   be imported to the card.  "data-internal" refers to the
>   ability to process (encrypt, hash etc.) data internal to the
>   provider, such as other keys, while "data-external" refers to
>   the ability to process arbitrary application data.

There's nothing stopping the providers to set such properties, and
there's nothing stopping an application from having them in their
method queries.  And finally, there's nothing stopping a provider to
not provide functionality that goes against their properties, either
by simple not providing that specific function, or by having it return
with an error if it finds a call invalid.

> - Variable key length algorithm implementations should carry
>   description/selection parameters indicating maximum and minimum
>   key lengths (Some will refuse to process short keys, others will
>   refuse long keys, some will require the key length to be a
>   multiple of some number).

Are you thinking descriptions that can be displayed back to the user,
or something that's usable programmatically?  Do you have an idea that
doesn't involve inventing a mini language?

> - The current EVP interface abuses the general (re)init operations
>   with omitted arguments as the main interface to update rapidly
>   changing algorithm parameters such as IVs and/or keys.  With the
>   removal of legacy APIs, the need to provide parameter changing
>   as explicit calls in the EVP API and provider has become more
>   obvious.

We have also explicitely said that current code must work as much as
possible.  This means that while we could certainly provide all kinds
of new functions, our priority is to make this work with the current
EVP API as much as humanly possible.

> - A provider property valuable to some callers (and already a known
>   property of some legacy APIs) is to declare that certain simple
>   operations will always succeed, such as passing additional data
>   bytes to a hash/mac (the rare cases of hardware disconnect and/or
>   exceeding the algorithm maximums can be deferred to "finish"
>   operations).  A name for this property of an algorithm
>   implementation could be "nofail=yes", and the list of non-failing
>   operations defined for each type of algorithm should be publicly
>   specified (a nofail hash would have a different list than a
>   no-fail symmetric encryption).

A note here: "provider property" is meaningless in this case.
Properties are tied to each algorithm implementation, as can be seen
in the definition of OSSL_ALGORITHM.  And yes, that could be done.  I
can't say that it *will* be done, and you'll probably have to remind
us later on (via github issue, please).

> - Providers that are really bridges to another multi-provider API
>   (ENGINE, PKCS#11, MS CAPI 1, MS CNG) should be explicitly allowed
>   to load/init separately for each underlying provider.  For example,
>   it would be bad for an application talking to one PKCS#11 module to
>   run, load or block all other PKCS#11 modules on the system.


> - Under normal file system layout conventions, /usr/share/ (and
>   below) is for architecture-independent files such as man pages,
>   trusted root certificates and platform-independent include files.
>   Architecture specific files such as "openssl/providers/foo.so"
>   and opensslconf.h belong in /usr/ or /usr/local/ .

Ah, I see what you're talking about.  Okie, simple example change.
BTW, many other applications use /usr/lib/{appname}/ or
/usr/local/lib/{appname} for this, so I assume that replacing
"/usr/share/openssl/providers/foo.so" with
"/usr/lib/openssl/providers/foo.so" would be a fine enough example.

> FIPS-specific issues:
> - The checksum of the FIPS DLL should be compiled into the FIPS-
>   capable OpenSSL library, since a checksum stored in its own file
>   on the end user system is too easily replaced by attackers.  This
>   also implies that each FIPS DLL version will need its own file name
>   in case different applications are linked to different libcrypto
>   versions (because they were started before an upgrade of the shared
>   libcrypto or because they use their own copy of libcrypto).

I'm not sure how important you think the libcrypto version is.  A goal
of the new internal design is to make providers fairly agnostic to
libcrypto versions and vice versa.

> - If possible, the core or a libcrypto-provided FIPS-wrapper should
>   check the hash of the opensslfips-3.x.x.so DLL before running any
>   of its code (including on-load stubs), secondly, the DLL can
>   recheck itself using its internal implementation of the chosen MAC
>   algorithm, if this is required by the CMVP.  This is to protect the
>   application if a totally unrelated malicious file is dropped in
>   place of the DLL.
> - The document seems to consistently only mentions the
>   shortest/weakest key lengths, such as AES-128.  Hopefully the
>   actual release will have no such limitation.

We could have mentioned something else.  It's just an example.
(I'm surprised you didn't mention that we consistently specified
'-cbc' as well...  I know some folks who raise an eyebrow at that
these days)

> - The well-known slowness of FIPS validations will in practice
>   require the FIPS module compiled from a source change to be
>   released (much) later than the same change in the default
>   provider.  The draft method of submitting FIPS validation
>   updates just before any FIPS-affecting OpenSSL release seems
>   overly optimistic.

It will only mean that the bleeding edge FIPS module source will be in
a "validation pending" for some time, i.e. you'll have to run your
latest libcrypto build with a previous version of the module for a bit
of time.

> - Similarly, due to the slowness of FIPS validation updates,
>   it may often be prudent to provide a root-cause fix in the
>   default provider and a less-effective change in the FIPS
>   provider, possibly involving FIPS-frozen workaround code in
>   libcrypto, either in core or in a separate FIPS-wrapper
>   component.
> - The mechanisms for dealing with cannot-export-the-private-key
>   hardware providers could also be used to let the FIPS provider
>   offer algorithm variants where the crypto officer (application
>   writer/installer) specify that some keys remain inside the
>   FIPS blob, inaccessible to the user role (application code).
>   For example, TLS PFS (EC)DHE keys and CMS per message keys
>   could by default remain inside the provider.  Extending this
>   to TLS session keys and server private key would be a future
>   option.
> - In future versions, it should be possible to combine the
>   bundled FIPS provider with providers for FIPS-validated hardware,
>   such as FIPS validated PIV smart cards for TLS client
>   certificates.

From a building perspective, I see nothing that would stop such
bundles to emerge.  Some bundling code that appears as one provider to
libcrypto, maybe?

> - Support for generating and validating (EC)DH and (EC)DSA
>   group parameters using the FIPS-specified algorithms should
>   be available in addition to the fixed sets of well-known
>   group parameters.  In FIPS 800-56A rev 3, these are the
>   DH primes specified using a SEED value.  Other versions of
>   SP 800-56A, and/or supplemental NIST documents may allow
>   other such group parameters.
> - If permitted by the CMVP rules, allow an option for
>   application provided (additional) entropy input to the RNG
>   from outside the module boundary.
> Enjoy



Richard Levitte         levitte at openssl.org
OpenSSL Project         http://www.openssl.org/~levitte/

More information about the openssl-users mailing list