[Cryptography] Apple and OpenSSL

Dennis E. Hamilton dennis.hamilton at acm.org
Mon Apr 21 17:05:43 EDT 2014


    -----Original Message-----
    From: Theodore Ts'o
    Sent: Monday, April 21, 2014 06:27
    Subject: Re: [Cryptography] Apple and OpenSSL

    On Sun, Apr 20, 2014 at 10:39:13PM -0400, Jerry Leichter wrote:
    [ ... ]
    > If you do anything that changes struct A's length, everything 
      referring to B is likely to break.

    You can solve this problem two different ways.  You can either put a
    type and length values at the beginning of each object, so you can
    always dynamically find the end of the structure (this is what
    Microsoft COM did decades ago), or you can use pointers everywhere, so
    struct B doesn't contain struct A, but contains a pointer to struct A.

    The latter is how most systems that use "object orientated principles"
    in C do things.

    [ ... ]

As a long-time fan of Microsoft COM, I'd like to point out something important about how the COM ABI works.  I mention that because the in-process COM mechanism is sufficient for providing the versioning safeguards that are being discussed here with regard to API versioning and object-instance storage structure changes.

First, the common object that is prefixed is the BSTR, a means for delivering a string value in an array.  The downside is that the recipient is entirely responsible for the lifecycle of the received BSTR, and that includes knowing how to release its memory, when the BSTR is delivered via a pointer. 

But the programmatic interface is different.  The programmatic interface delivers methods only, by return of a pointer to a pointer to a transfer vector (known as a PPV) from an offerer of the interface (either the COM counterpart of a class loader or a method that delivers interfaces, possibly to a dynamically constructed object).  

On calling any of those methods via the ABI, the location of the PPV pointer is always the first parameter.  That is how dynamic binding of methods to instances happens.  Only the implementation of the particular interface is designed to know what else can be found at the location of the PV.  Users of interfaces cooperates in the lifecycle of their use of it by managing the lifecycle of each PPV that's been delivered.  The first three methods of every interface are the same as on the IUnknown interface.  They support PPV reservation, release, and request of the PPV for an interface having a given ID.  Reservation and release are with respect to the PPVs, not the object instance behind the interface.  The object instance is responsible for determining when it no longer has PPV reservations and doing the right thing.   =

The important aspect of these interfaces is they are versioned.  On requesting an interface, it is necessary to provide the globally-unique identifier that is specific to the desired interface.  If the interface changes, either syntactically or semantically, the changed interface has a different identifier.  This means that objects can support legacy interfaces as well as new ones and applications will request the one that they are coded to depend on.  If the requested interface is not supported by some object, the request will fail.  This is not fatal -- one can try for different interfaces as a kind of negotiation.

The other aspect of these interfaces is they are only for methods.  No data is exposed and no data structure that supports an object instance is not disclosed.  How methods use the passed-in PV value to find their necessary state and context information is all on the implementation side of the interface.  With the exception of scalar results and the BSTR case, a common way variable material is returned is by returning an interface as a method result.  The identifier of the acceptable interface is usually a parameter to the method.  (There have been structured-data cases as well as the BSTR one, but they can be ignored in this overview.)

(By the way, the JNI interface for native code integrated under the Java Runtime is a flavor of COM interface.)

The isolation of interface from implementation is not perfect, but it is pretty good.  Great care is required to avoid over-releasing a PPV and also use-after-release bugs.  For performance purposes it is important to consider the granularity of interfaces, of course, so that the overhead of the lifecycle management and interface instantiation activities does not swamp the useful work.  A key advantage is that, in general, one does not know whether or not the interface is to an in-process instance or to a stub for a remote (out-of-process) object.

It was a pleasant surprise to discover that, for Windows 8, the use of COM for access to OS objects has been revived and extended, although with .NET and C++ libraries, it is not so obvious.  

 - Dennis




More information about the cryptography mailing list