Programmer Reference : Cryptography : Architectural Overview
Architectural Overview
VA Smalltalk's ST: Cryptographic Support feature contains the following Applications:
OpenSSLCryptoInterfaceApp - High-Level bindings to OpenSSL's cryptographic library.
OpenSSLCryptoInterfaceExamplesApp - Contains numerous code examples showing how to use the various Crypto APIs.
This application contains the bindings to OpenSSL's cryptographic library. For clarity, and consistency with OpenSSL, all sub-applications represent isolated modules. In this context, a module is a cohesive collection of classes and module boundaries strongly reflect the organization seen in the OpenSSL codebase. Organizing it this way facilitates keeping the bindings up to date with new versions of OpenSSL.
Module descriptions are provided later in the chapter. Here we are going to focus on the high-level design decisions used to implement the bindings. This is presented below as a set of design goals. Below each design goal will be a description of choices that were made and, as a result, how the architecture was influenced by it.
Even when brand new functionality is introduced into VA Smalltalk, the reality is that design decisions from existing functionality often influence it. This means that backwards compatibility could be broken if these existing design decisions are not accounted for and maintaining this compatibility is always a primary goal for VA Smalltalk. The cryptographic feature is no exception. VA Smalltalk has been using OpenSSL ever since it began including support for SSL/TLS. In the same way that OpenSSL's SSL/TLS library depends on OpenSSL's cryptographic library...we also introduced the same dependency at the application level. If you load the ST: Socket Communications Interface feature, you will see that the SciSslSocketInterface application lists OpenSSLCryptoInterfaceApp as a prerequisite.
Since the crypto layer was slid underneath the existing SSL/TLS layer, the crypto layer had to deal with established mechanisms in place for dispatching calls to OpenSSL, exception handling and various other details. In a few areas this meant compromising our ideal implementation so that everything would remain compatible. An example of this is the use of error object (i.e. check if the return value is an error object) instead of raising exception. The cryptographic library uses error objects for compatibility reasons.
Separation of Concerns
Some of the decisions made for the cryptographic library were based off existing design decisions made in the SSL/TLS library.
Functions & Constants: All functions and constants in OpenSSL header files are defined as pool variables in OpenSSLCryptoInterfaceApp's pool dictionaries.
Functions resolve to Smalltalk <PlatformFunction>s
Constants resolve to the primitive types found in the OpenSSL header files such as Integers and Strings.
Dispatching Engine: The actual call to one of the defined OpenSSL functions is performed by the OpenSSLCryptoLibraryDispatcher. In addition to performing the function call, the dispatcher also interprets the return value and creates error objects where required.
OSObject: Objects responsible for presenting an API to the caller and delegating functionality requests to the dispatcher object.
Developers are expected to only interact through the API of the various OSObjects. There should not be a need to call upon the dispatcher directly and certainly calling raw PlatformFunctions is discouraged.
The dispatching engine makes calls to OpenSSL using asynchronous callouts. Each Smalltalk process will make the call to OpenSSL from an available native thread in a thread pool. While the Smalltalk process is blocked until a result is available, other Smalltalk processes are allowed to proceed which may also make asynchronous calls. This means that multiple CPUs can be utilized by making calls with OpenSSL using multiple Smalltalk processes.
The OpenSSL libraries internally have shared state that is guarded by locks. However, versions of OpenSSL prior to 1.1.0 do not provide platform-specific lock implementations. VA Smalltalk has implemented the lock implementations as a shared library on all supported platforms. You will see it referenced in the abt.ini file under THREAD_LIB=vasslthreads. When using older versions of OpenSSL with VA Smalltalk, this is how asynchronous calls can be made without worrying about concurrency issues. As of OpenSSL version 1.1.0, thread-safety is provided within OpenSSL internally so VA Smalltalk's custom lock implementations are not used.
The cryptographic bindings use the OSObject framework for state management and APIs. Since OSObjects most often refer to native memory, it is left up to the user to make sure this memory is freed. In other's a lot like developing in C. This means there is potential to forget to free native memory or double-free native memory which can result in crashes. OpenSSL also has internal reference counters for certain "objects" which may or may not be incremented when answered from an API call. This leads to ambiguity that could make it difficult to know if the OSObject should be freed or not.
We specifically wanted to eliminate the issues described above, so the architecture includes a Memory-Ownership concept, a Reference-Counter and a GC Notifier.
Memory-Ownership: Each Crypto OSObject has the concept of memory ownership. This means:
Each OSObject instance maintains a state-variable that specifies if it "owns" the native memory it refers to or not.
Double-frees are eliminated because calling free on a memory-owner the first time will force it to transition into a non-memory owner. Calling free any number of times after this will essentially be a no-op.
If OpenSSL answers static data from API calls, then VA Smalltalk can create a non-memory owner OSObject. Calling free on these OSObjects will always be a no-op.
Reference-Counter: OpenSSL APIs can answer a new instance of data or an existing data that has its reference count incremented. We internally mirror this and keep track of the reference counts so we know how many times to call free (which decrements a positive reference count) before we know the object was truly freed.
GC Notifier: When an OpenSSL OSObject is about to be garbage collected, the notifier is informed and makes sure to call free on the OSObject if it is a memory owner.
This application contains many examples you can run to see how to use the cryptographic library. These examples are annotated with comments providing a step-by-step description of what is going on. These examples are used internally by Instantiations as integration tests, so you will often see that the examples have assertion like checks along the way.
Last modified date: 08/09/2017