As a diversion, I tried to compiling an SSL library for the Newton. I settled on CyaSSL, because it is designed for constrained devices. For example, you can define macros that conditionally compile for devices that have NO_FILESYSTEM or NO_DEV_RANDOM. That sounds a lot like the Newton.
Building
I got surprisingly far in compiling the library. First you need to edit settings.h and add a section defining the compilation for the Newton, then pass this definition using “-D NEWTON” to the compiler:
#ifdef NEWTON
#define USER_MATH_LIB
#define BIG_ENDIAN_ORDER
#define SINGLE_THREADED
#define NO_DEV_RANDOM
#define NO_FILESYSTEM
#define NO_STDIO_FILESYSTEM
#define CYASSL_USER_IO
#define NO_WRITEV
#define SIZEOF_LONG 4
#define SIZEOF_LONG_LONG 4
#endif
One issue is that the Newton doesn’t seem to support an 8-byte integer data type. There is one configuration in settings.h where they #undef SIZE_OF_LONG_LONG. (I assume this is if you don’t have a long long datatype) When I try this, it throws an #error, so I set both SIZEOF_LONG and SIZEOF_LONG_LONG to 4 and everything seems to compile. (Note: There is a Int64 datatype in the C++ headers, but its just a struct with two longs.)
Next you need to define a GenerateSeed() function in random.c. I just passed rand() from the CLibrary back. The Newton doesn’t have a /dev/random or a good source of entropy that I know of. I just wanted to get things to compile. Randomness is important for encryption. In practice, a better source of entropy might be needed.
int GenerateSeed(OS_Seed* os, byte* output, word32 sz)
{
return rand();
}
Next you’ll find a odd casting error in internal.c in GetHandShakeHeader:
File “:src:internal.c”; Line 3136 # Error: <function argument>: implicit cast of pointer loses ‘const’ qualifier
The c24to32 is an inline function, and the const qualifier was getting lost for a reason I don’t understand. I manually inlined the function in the one spot where there was a problem.
In internal.h there is a buffer structure that throws the following error:
File “:cyassl:internal.h”; Line 930 # Error: ‘buffer::buffer’ must be a function
File “:cyassl:internal.h”; Line 931 # Fatal error: Failure of internal consistency check
odd ctor type in struct ‘buffer’
The issue appears to be that the compiler does not like the struct being named the same as one of the members. I add an underscore to the struct name. This doesn’t really affect anything else because its in a typedef and future code uses the type:
typedef struct buffer_ {
word32 length;
byte* buffer;
} buffer;
Next, you need to modify dh.c to use <fp.h> for the pow() and log() functions rather than math.h (which doesn’t exist in the Newton C++ Toolkit) There is a place in dh.c for you to place this code, and a macro (USER_MATH_LIB) in the settings.h file that conditionally compiles it in.
#ifndef USER_MATH_LIB
#include <math.h>
#define XPOW(x,y) pow((x),(y))
#define XLOG(x) log((x))
#else
#include <fp.h>
#define XPOW(x,y) pow((x),(y))
#define XLOG(x) log((x))
#endif
Finally, you need to compile the c files. I snagged a list of the c files out of the make file (am__src_libcyassl_la_SOURCES_DIST) and made my own little makefile to call ARMCpp using the mpw tool. (mosrun would work too, but I already had an mpw makefile from another project.) I took Demos.cp and Demos.exp from the NCT example code and modified them to call a few of the CyaSSL initialization functions. (Otherwise the linker won’t link in any of the CyaSSL stuff, since its not used anywhere) I tried to link with ARMLink…
…And… it links! I was surprised, because I expected there to be some random assembly file or something with symbols that I missed. The .sym file is around 386kB. Seems like a reasonable size.
Things go wrong: Static globals
The next step in using C/C++ code in a Newton app is to make the .ntkc package using the AIFtoNTK tool… and this is where things go wrong:
### AIFtoNTK – error – the file ‘CyaSSL.sym’ has a R/W global variables which is NOT supported in Newton packages.
# You can use ‘const’ global variables & ‘*const’ pointers.
Per the “NCT Programmer’s Reference”:
Any global data that you reference in your C++ functions must be read-only data. You must reference this data with a constant pointer to constant data […]
You sometimes need to allocate memory for use in your C++ code that is like global data. Since you cannot use non-constant global data in your C++ code, you need to utilize a coordinated effort between your NewtonScript and C++ code to achieve this.
CyaSSL is pretty light on the static globals variables, but there are some sprinkled throughout. Here are some that I found using a simple grep:
- sniffer.c has a bunch, but I think this can be excluded
- ssl.c has a mutex and a global random number generator object, and some related counters
- io.c has errno as a global variable
- des3.c has a few buffers and bytes, and a mutex
- ecc.c has a cache of some sort.
- memory.c uses globals to hold the malloc, free, and realloc functions. These can be changed to static globals and #ifndef out the inside of CyaSSL_SetAllocators, since it won’t be necessary.
- there may be others that I didn’t find.
Not all of these get linked in, they all might not not need to be fixed. This is more retrofitting then I care to tackle. I’m guessing that we’d need to MakeBinary() on the NewtonScript side and access these binaries using the NCT functions for accessing NewtonScript objects.
Newton Globals
I put together a little stub function that simulates a global variable by storing a pointer in a NewtonScript frame and passing that information back and forth between the C++ code. The prototype looks something like this:
void* NewtonGlobal(RefArg sym, long size);
You give the global a unique name and pass it as a symbol. If the symbol does not exist, a memory block of the given size is created, the pointer is stored in the NewtonScript frame and returned. If it does exist already, then the pointer is retrieved and returned.
With this a very ugly preprocessor macro can be used to remove the static global:
static SessionRow SessionCache[SESSION_ROWS];
becomes
#define SessionCache ((SessionRow*)NewtonGlobal(SYM(SessionCache),sizeof(SessionRow)*SESSION_ROWS))
Ugly, but it should work. I am able to compile, link, and package the CyaSSL library as a .ntkc file. My “test” file tries and calls a few of the CyaSSL function so that the linker will find them in the dependency tree… but in practice there may be more static globals to tackle.
Other considerations
Besides the globals issue, there needs to be some glue code that allows NewtonScript to call CyaSSL and pass data back and forth. NIE doesn’t support the traditional concept of a “socket”. On the plus side, CyaSSL has an abstracted I/O architecture. You can define functions for input and output instead of the default socket implementation.
Also, its quite likely that there are many more compiling & linking issues hidden. When the library is used in practice, there will be more parts of the library in the dependency tree, and we may find new errors or static globals.
An Exercise for the Reader
I think that CyaSSL is a good choice for the Newton. If you’re interested in learning more about CyaSSL, here are some good starting points:
I don’t know how many places these global variables might pop up in the CyaSSL code. Also I’m not an expert on NewtonScript/NIE Endpoints and what well designed “glue” might look like. Could it be done? Probably. It is more work than I want to tackle with this little digression.
While I may dabble with this a little more, I don’t think I’ll see it through to completion. I invite someone else to pick up the ball run with it. You can find me on NewtonTalk if you have any questions about what I have tried up till this point. I’m happy to help out, but given the weird encryption export laws in the USA, I don’t want to post any code directly.