Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API Long Term Evolution (QUIC, transport agnosticism, etc.) #17939

Open
hlandau opened this issue Mar 22, 2022 · 6 comments
Open

API Long Term Evolution (QUIC, transport agnosticism, etc.) #17939

hlandau opened this issue Mar 22, 2022 · 6 comments
Assignees
Labels
triaged: design The issue/pr deals with a design document

Comments

@hlandau
Copy link
Member

hlandau commented Mar 22, 2022

It is an expressed long term desire of the project to make the usage of TLS, DTLS and, in the future, QUIC as similar as possible in terms of the code which needs to be used by clients consuming libssl.

Our current API designs do not meet this requirement. Switching between TLS and DTLS requires some work from a client and some of the differences between TLS and DTLS are exposed to the application. The current API also tends to expose socket-level concerns to the application (TCP, etc.), which obviously creates issues for supporting QUIC with minimal code changes.

Broadly, if we are to get to this destination, there will need to be a new set of methods for using TLS/DTLS/QUIC which are agnostic, and which are recommended for new applications.

New API Requirements

The requirements for this "preferred set of methods" seems to look something like:

  • Protocol to use (TLS/DTLS/QUIC) should be specified via a string
  • Applications can switch between TLS, DTLS or QUIC with a one-line code change (or, due to use of a string, even just a configuration change)
  • Hides the details of the underlying transport protocol or whether TCP is being used

Demo-Driven Design

I'd like to propose a slightly radical idea for how to approach these tasks (both QUIC API design and a general transport-agnostic API design). Of course I might be barking up the wrong tree here, so feedback is appreciated.

A major concern in the QUIC API design has been to enable applications to make use of QUIC with minimal code changes. This leads to several conclusions:

  • In order to design an MVP API which meets this requirement, we must understand how a varied set of applications consumes libssl.

  • A set of demos should be found, or developed, which demonstrate the full spectrum of existing libssl API usage which we need to support for QUIC (and DTLS under a unified API and so on). This will include blocking applications, non-blocking applications, applications which call SSL_read/SSL_write frequently and applications which don't make any libssl call for hours, applications which want to do their own polling and applications which don't.

  • I propose that the most constructive way to get API designs that meet these requirements actually approved would probably be to express these proposed APIs in terms of diffs to the set of demos proposed above.

    In other words, we adopt a set of model demos for use of libssl as being broadly representative of real-world applications which use libssl, and express a proposed API as a set of (minimal) changes to those demos. Then a concrete API is proposed with the details filled in (function prototypes and their documentation, etc.), but whatever details are filled in must be compatible with the diff of the demo which has been agreed.

    If it turns out that a diff is infeasible to implement, or that there turn out to be reasons why it is highly undesirable to implement, it could be returned to the design stage to agree a new diff, but this is not the expectation.

    You could call this "demo-driven design". As a completely arbitrary example, let's suppose demos/bio/sconnect.c was adopted as a model demo, and agreement is reached that the following diff will drive the API design:

      -ssl_ctx = SSL_CTX_new(TLS_client_method());
      +ssl_ctx = SSL_CTX_new(QUIC_client_method());

    I make no claims that this particular diff is feasible to implement, it is purely a strawman example.

    Note that "diffs" may be expressed as diffs but could also be (or probably will be) expressed as ifdefs.

    It is permissible for some of these demos to be incomplete (not compilable) if they would otherwise be impractically large or if the majority of the code would distract from the use of the libssl API specifically. For example parts unrelated to libssl may simply be elided as .... The demos are intended primarily for human consumption as a way of agreeing on what changes should look like.

  • Since there are different kinds of usage of the libssl API (blocking versus nonblocking, etc.) there will be multiple demos and one diff will be agreed for each demo.

  • This set of agreed diffs then constrains the design space of the actual API which is designed. Essentially, the idea is that since "minimal code changes" is an MVP requirement, we should agree what "minimal code changes" looks like first, rather than designing an API and then trying to figure out how to make it add up to "minimal code changes" later. In short, it means we figure out what shape the hole is we have to fill before we try to fill it.

Two prongs

There are two "prongs" to be pursued in terms of API reform:

  1. Supporting QUIC, at first with minimal code changes.

  2. API reform to enable switching between arbitrary protocols with minimal code changes in future.

The assumption here seems to be that (2), while desired by the project, will require too many changes to application code to qualify as the solution for (1).

However, I don't think this is a foregone conclusion and we may be able to kill two birds with one stone.

As such, the plan of action looks something like this:

  • A set of demos with diffs for supporting QUIC with minimal code changes
    • Classic synchronous/blocking demo plus diff to switch to QUIC
    • Classic asynchronous/non-blocking demo plus diff to switch to QUIC
    • Classic asynchronous/non-blocking with application-driven polling demo plus diff to switch to QUIC
  • A set of demos with diffs for switching to a reformed API
    • Classic synchronous/blocking demo plus diff to switch to reformed API
    • Classic asynchronous/non-blocking demo plus diff to switch to reformed API
    • Classic asynchronous/non-blocking with application-driven polling demo plus diff to switch to reformed API

If the diffs for the latter end up being small enough that they can qualify as minimal change to application code, these two prongs may be able to become one.

Current actions

Currently I'm going to work on the initial demos matching the above description (classic synchronous/blocking demo, classic asynchronous/non-blocking demo, classic asynchronous/non-blocking with application-driven polling demo). The scope of this may change as I develop a fuller understanding of the spectrum of how different applications use libssl.

My guess is that once this is done, an ideal course of action would be something like:

  • Develop the demos.

  • Get OTC agreement in principle that the demos are reflective of a broad spectrum of OpenSSL client applications, and that the demos therefore constitute "model demos" as a basis for demo-driven API design.

    The demos are adopted as the "model demos".

  • Diffs to the model demos are proposed and brainstormed.

  • Get OTC agreement that some set of diffs to the adopted model demos should be adopted as the diffs to use as a basis for API design.

    The diffs are adopted as the model for API design.

  • Design APIs which reflect the diffs. In other words, the demos with the diffs applied should be able to work without further changes to the code (when the APIs are eventually implemented).

  • Implementation, etc.

@mattcaswell @t-j-h Let me know your thoughts.

@hlandau hlandau added the triaged: design The issue/pr deals with a design document label Mar 22, 2022
@hlandau hlandau self-assigned this Mar 22, 2022
@mattcaswell
Copy link
Member

I think it is helpful in any case (regardless of QUIC) to have good demos for how to use libssl. It would also be helpful to know we have an agreed baseline set of apps to work with, i.e. if we can these apps (demos) to work with the agreed changes then we are "done". So I am broadly ok with the approach. I hope that doesn't mean starting again with the current QUIC API Design proposal. I think what we have so far is a good starting point and needs iterating over to add missing pieces or amend as required what we've already got.

One thing I'm slightly worried about...the primary purpose of demos should be education and documentation targeted at application developers seeking to learn our APIs. By taking this approach we are going away from that....having ifdefs in a demo doesn't aid readability. Should these actually be tests that are runnable as part of the test suite?

@hlandau
Copy link
Member Author

hlandau commented Mar 22, 2022

I don't think the idea is to have these published under demos/ for people to consume as tutorial material, nor to have them as tests. They're essentially reference points for the collaborative process of development and discussion, much like the existing QUIC API and record layer design proposals.

@t-j-h
Copy link
Member

t-j-h commented Mar 22, 2022

Working from a well defined set of targets of representative applications is the right approach IMHO and effectively part of the challenge we have had in our OTC discussions is that we don't all have the various API usage patterns in mind at all times when discussing the changes required.

The set of demos we have should compile as part of the normal build process so they don't rot.

Using a derivative of that set of demos when discussing API change impact makes a lot of sense to me and doesn't mean we should turn the demos into ifdef spaghetti - but we do need to see the impacts of proposed APIs in concrete terms when discussing the approaches we are going to use. Seeing the diffs help with that process.

@paulidale
Copy link
Contributor

Protocol to use (TLS/DTLS/QUIC) should be specified via a string

Leads me to thinking of fetchable provider based protocols.

@paulidale
Copy link
Contributor

paulidale commented Mar 23, 2022

I suspect that a QUIC BIO would meet the MVP requirements. A lot of simple applications use the SSL BIO and satisfying them by changing the creation call ought to be enough. We are currently aiming a lot high than this mark.

We naturally need to be cognisant of more complicated applications requiring more but we don't need that for MVP.

@hlandau
Copy link
Member Author

hlandau commented Mar 25, 2022

I've posted my first draft of the demos here:

https://github.com/hlandau/openssl-ddd

These were developed based on analysis of a wide range of open source codebases using libssl to establish real-world usage patterns.

Feedback welcomed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
triaged: design The issue/pr deals with a design document
Projects
None yet
Development

No branches or pull requests

4 participants