![]() |
Fox's Pages | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
UW home
|
Updated: August 13, 2007 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| EZ SSL - easy to use SSL library |
| Summary: | Provides an easy-to-use, SSL protected connection library. |
|---|---|
| Version: | 1.3.1 |
| Download: | UNIX: ezs-1.3.1.tar.gz
Windows: ezs-1.3.1.zip |
You should be able to install with
$ ./configure
$ make
$ make install
Programs using the ezs api must include
#include "ezs.h"
-lezs -lssl -lcrypto -lpthread
I have had success on AIX with CC=cc_r.
The windows distribution contains libraries compiled for threaded debug and non-debug applications (MD, MDd). It is built for version 0.9.8b of OpenSSL for Windows.
Programs using the windows api must include
#include "ezs.h"
The library provides procedure APIs that allow clients and servers to connect, authenticate, and communicate.
When a procedure returns an error indication, you may retrieve the error code or error code and a text description. Individual error codes are maintained for each connection (EZS). A global error code is maintained for 'unconnected' functions.
Local system errors are indicated by a negative error code: the negative of the system's errno.
If all else fails, setting the external variable ezs_debug to one causes the library to print debug output to stderr.
| Description: | Get the last error code | ||
|---|---|---|---|
| Syntax: | int ezs_errno(EZS* E) | ||
| Arguments: |
| ||
| Return: | the error code | ||
| Errors: |
| ||
| Notes: |
|
| Description: | Get the last error code and message | ||||
|---|---|---|---|---|---|
| Syntax: | int *ezs_geterror(EZS* E, char** txt) | ||||
| Arguments: |
| ||||
| Return: | the error code | ||||
| Errors: |
| ||||
| Notes: |
|
SSL requires initialization for its thread mutexes and its random number seed. You should provide a read/write file for the random seed. You can rewrite this file before exiting to update its 'randomness'.
Usual sequence is
ezs_init(name);
ezs_load_rand_file(filename);
at the start of your program, and
ezs_save_rand_file(filename);
at the end.
| Description: | Initializes the openssl and ezs libraries. | ||
|---|---|---|---|
| Syntax: | void *ezs_init(char* name) | ||
| Arguments: |
| ||
| Return: | 1 (always success) | ||
| Errors: |
| ||
| Notes: |
|
| Description: | Adds data from the file to SSL's 'randomness'. | ||
|---|---|---|---|
| Syntax: | void *ezs_load_rand_file(char* filename) | ||
| Arguments: |
| ||
| Return: | 1 | ||
| Errors: |
| ||
| Notes: |
|
| Description: | Writes random data to the file. | ||
|---|---|---|---|
| Syntax: | void *ezs_save_rand_file(char* filename) | ||
| Arguments: |
| ||
| Return: | 1 | ||
| Errors: |
| ||
| Notes: |
|
| Description: | Allocates a new ezs struct, which will identify a particular connection. |
|---|---|
| Syntax: | EZS *ezs_new() |
| Arguments: |
|
| Return: | Pointer to an EZS structure |
| Errors: |
|
| Notes: |
|
| Description: | Frees an ezs struct. | ||
|---|---|---|---|
| Syntax: | void *ezs_free(EZS* E) | ||
| Arguments: |
| ||
| Return: | |||
| Errors: |
| ||
| Notes: |
|
There are several credentials involved in a secure ezs connection:
Generally if a key file is not specified the key is assumed to be in the same file as the certificate.
| Description: | Add a CA to your list of acceptable CAs. | ||
|---|---|---|---|
| Syntax: | int ezs_add_ca(char* ca_file) | ||
| Arguments: |
| ||
| Return: | 1 = success, 0 = error | ||
| Errors: |
| ||
| Notes: |
|
| Description: | Add a CRL to your list of CRLs. | ||
|---|---|---|---|
| Syntax: | int ezs_add_crl(char* crl_file) | ||
| Arguments: |
| ||
| Return: | 1 = success, 0 = error | ||
| Errors: |
| ||
| Notes: |
|
| Description: | Adds a certificate to the list of available certificates for authentication to peers. | ||||||
|---|---|---|---|---|---|---|---|
| Syntax: | int ezs_add_cert(char* crt, char* key, char** cn) | ||||||
| Arguments: |
| ||||||
| Return: | 1 = success, 0 = error | ||||||
| Errors: |
| ||||||
| Notes: |
|
| Description: | Sets the option to verify the server hostname vs. common name. | ||
|---|---|---|---|
| Syntax: | void ezs_set_verify(EZS* E) | ||
| Arguments: |
| ||
| Return: | |||
| Errors: |
| ||
| Notes: |
|
| Description: | Returns the CN of the connected peer's certificate | ||
|---|---|---|---|
| Syntax: | char ezs_get_peer_cn(EZS* E) | ||
| Arguments: |
| ||
| Return: | |||
| Errors: |
| ||
| Notes: |
|
SSL allows the connecting peer to record a session identifier, essentually the private key used for encryption of data, and use that saved identifier to facilitate subsequent sessions. This bypasses the comparitively long public-key negotiation typical of SSL. Session identifier lifetime is normally five minutes.
Sessions on the server each consume about 12K bytes of memory, and can accumulate rapidly on busy servers. The expire after about five minutes and are automatically purged.
| Description: | Set the server's session name or deactivate sessions | ||
|---|---|---|---|
| Syntax: | void ezs_set_session_name(char* name) | ||
| Arguments: |
| ||
| Return: | |||
| Errors: |
| ||
| Notes: |
|
| Description: | Retrieve the session identifier associated with the current connection | ||
|---|---|---|---|
| Syntax: | char *ezs_get_session(EZS* E) | ||
| Arguments: |
| ||
| Return: | A session identifier | ||
| Errors: |
| ||
| Notes: |
|
| Description: | Specifies a session identifier to be used for the next connection. | ||||
|---|---|---|---|---|---|
| Syntax: | int *ezs_set_session(EZS* E, char* session) | ||||
| Arguments: |
| ||||
| Return: | 1 = success, 0 = error | ||||
| Errors: |
| ||||
| Notes: |
|
Connections are not symmetric. Servers generally wait for connection requests from clients. The library provides connection tools to perform both the IP connect, or accept, and the SSL negotiation or just the negotiation step.
| Description: | Sets blocking IO for this connection | ||
|---|---|---|---|
| Syntax: | int *ezs_use_nonblocking_io(EZS* E) | ||
| Arguments: |
| ||
| Return: | |||
| Errors: |
| ||
| Notes: |
|
| Description: | Sets non-blocking IO for this connection | ||
|---|---|---|---|
| Syntax: | int *ezs_use_nonblocking_io(EZS* E) | ||
| Arguments: |
| ||
| Return: | |||
| Errors: |
| ||
| Notes: |
|
| Description: | Sets semi-blocking timeout for this connection | ||||
|---|---|---|---|---|---|
| Syntax: | int *ezs_set_timeout(EZS* E, int timeout) | ||||
| Arguments: |
| ||||
| Return: | |||||
| Errors: |
| ||||
| Notes: |
|
| Description: | Allow connections using v2 protocol | ||
|---|---|---|---|
| Syntax: | void ezs_allow_v2(EZS* E) | ||
| Arguments: |
| ||
| Return: | |||
| Errors: |
| ||
| Notes: |
|
| Description: | Client connect and authenticate to a server | ||||||||
|---|---|---|---|---|---|---|---|---|---|
| Syntax: | int ezs_connect(EZS* E, char* service, char* cn) | ||||||||
| Arguments: |
| ||||||||
| Return: | 1 = success, 0 = error | ||||||||
| Errors: |
| ||||||||
| Notes: |
|
| Description: | Client authenticate to a server over already connected socket | ||||||||
|---|---|---|---|---|---|---|---|---|---|
| Syntax: | int ezs_connect_fd(EZS* E, int fd, char* cn) | ||||||||
| Arguments: |
| ||||||||
| Return: | 1 = success, 0 = error | ||||||||
| Errors: |
| ||||||||
| Notes: |
|
| Description: | Listen on a port for connection requests. | ||||
|---|---|---|---|---|---|
| Syntax: | int ezs_listen(EZS* E, char* port) | ||||
| Arguments: |
| ||||
| Return: | 1 = success, 0 = error | ||||
| Errors: |
| ||||
| Notes: |
|
| Description: | Server accept connection and verify client | ||||||||
|---|---|---|---|---|---|---|---|---|---|
| Syntax: | EZS *ezs_accept(EZS* E, char* cn) | ||||||||
| Arguments: |
| ||||||||
| Return: | An EZS structure, NULL = error | ||||||||
| Errors: |
| ||||||||
| Notes: |
|
| Description: | Server verify connected client | ||||||||
|---|---|---|---|---|---|---|---|---|---|
| Syntax: | int ezs_accept_fd(EZS* E, int fd, char* cn) | ||||||||
| Arguments: |
| ||||||||
| Return: | 1 = success, 0 = error | ||||||||
| Errors: |
| ||||||||
| Notes: |
|
| Description: | Disconnect a connection | ||
|---|---|---|---|
| Syntax: | void ezs_disconnect(EZS* E) | ||
| Arguments: |
| ||
| Return: | |||
| Errors: |
| ||
| Notes: |
|
Blocking reads and writes are 'semi-blocking'. The library will wait timeout seconds for the operation to complete. Non-blocking reads and writes will return immediately.
Regardless of the blocking mode, a read or write may return one of the 'wouldblock' errors.
Because an SSL connection can be renegotiated either of these conditions may be returned for either a read or a write. You can use the ezs_wouldblock procedure to see if the IO operation failed for either reason.
Because the SSL library buffers incoming data, use the ezs_bytes_for_read procedure in addition to a select to see if there are bytes available for read.
| Description: | Read bytes from a peer len bytes. | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| Syntax: | int ezs_read(EZS* E, char* data, int len) | ||||||||||
| Arguments: |
| ||||||||||
| Return: | number of bytes read, 0 = error | ||||||||||
| Errors: |
| ||||||||||
| Notes: |
|
| Description: | Write bytes to a peer | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| Syntax: | int ezs_write(EZS* E, char* data, int len) | ||||||||||
| Arguments: |
| ||||||||||
| Return: | number of bytes written, 0 = error | ||||||||||
| Errors: |
| ||||||||||
| Notes: |
|
| Description: | Get number of bytes available for read | ||
|---|---|---|---|
| Syntax: | int ezs_bytes_for_read(EZS* E) | ||
| Arguments: |
| ||
| Return: | number of bytes buffered and available for a read operation | ||
| Errors: |
| ||
| Notes: |
|
| Description: | Test if the last IO attempt would have blocked | ||
|---|---|---|---|
| Syntax: | int ezs_wouldblock(EZS* E) | ||
| Arguments: |
| ||
| Return: | 1 if the last IO operation returned EZS_ERR_READ_WOULDBLOCK or EZS_ERR_WRITE_WOULDBLOCK, 0 otherwise | ||
| Errors: |
| ||
| Notes: |
|
Some convenience routines are provided to encrypt and decrypt data and to compute MAC hashes. Encryption generally includes an initialization vector (IV) that ensures randomness in the start of a message. The same, random IV must be used for both encryption and decryption.
Keys are any binary strings, and should be at least 32 bytes long.
The default hash algorithm is SHA-1.
Use ezs_set_cipher and ezs_set_hash to select other algorithms.
| Description: | Initialize cryption structures | ||||||||
|---|---|---|---|---|---|---|---|---|---|
| Syntax: | int ezs_crypt_init(EZS* E, char* key, int len, char** iv) | ||||||||
| Arguments: |
| ||||||||
| Return: | 1 | ||||||||
| Errors: |
| ||||||||
| Notes: |
|
| Description: | Encrypt or decrypt data | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Syntax: | int ezs_crypt(EZS* E, int mode, char* out, int out_len, char* in, int in_len) | ||||||||||||
| Arguments: |
| ||||||||||||
| Return: | 1 = success, 0 = error | ||||||||||||
| Errors: |
| ||||||||||||
| Notes: |
|
| Description: | Generate a MAC of some data | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Syntax: | int ezs_hmac(char** mac, int* mac_len, char* data, int data_len, char* key, int key_len) | ||||||||||||
| Arguments: |
| ||||||||||||
| Return: | 1 | ||||||||||||
| Errors: |
| ||||||||||||
| Notes: |
|
| Description: | Convert binary data to printable base64 | ||||||||
|---|---|---|---|---|---|---|---|---|---|
| Syntax: | int ezs_data_to_base64(char** b64, int* b64_len, char* data, int data_len) | ||||||||
| Arguments: |
| ||||||||
| Return: | 1 | ||||||||
| Errors: |
| ||||||||
| Notes: |
|
| Description: | Convert base64 to binary data | ||||||||
|---|---|---|---|---|---|---|---|---|---|
| Syntax: | int ezs_base64_to_data(char** data, int* data_len, char* b64, int b64_len) | ||||||||
| Arguments: |
| ||||||||
| Return: | 1 | ||||||||
| Errors: |
| ||||||||
| Notes: |
|
| Description: | Sets the cipher used by the encryption procedures | ||
|---|---|---|---|
| Syntax: | int ezs_set_cipher(EVP_CIPHER* (*cipher)()) | ||
| Arguments: |
| ||
| Return: | |||
| Errors: |
| ||
| Notes: |
|
| Description: | Sets the hash algorithm used by the encryption and hash procedures | ||
|---|---|---|---|
| Syntax: | int ezs_set_hash(EVP_MD* (*hash)()) | ||
| Arguments: |
| ||
| Return: | |||
| Errors: |
| ||
| Notes: |
|
The EZS library will report both its own version and the versions of openssl it was compiled and linked with. The latter can help detect cases where the library is linked with different and incompatible versions of openssl.
| Description: | Returns ezs and openssl version information. |
|---|---|
| Syntax: | char *ezs_version() |
| Arguments: |
|
| Return: | Version information as a string. |
| Errors: |
|
| Notes: |
|
* =================================================================
* Copyright (c) 2006 The University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* =================================================================
#include "ezs.h"
static char *hw = "Hello, world.";
main()
{
EZS *E;
char *mycn;
int r;
char resp[4096];
/* allocate an ezs struct */
E = ezs_new(NULL);
/* add the CA info */
if (!ezs_add_ca(CA's certificate file)) {
fprintf(stderr, "set ca: %d\n", ezs_errno(E));
exit (1);
}
/* add our cert */
if (!ezs_add_cert(my cert and key file, NULL, &mycn)) {
fprintf(stderr, "set cert: %d\n", ezs_errno(E));
exit (1);
}
/* connect to server */
if (!ezs_connect(E, server host:port, mycn)) {
fprintf(stderr,">> Connect error, err = %d\n",
ezs_errno(E));
exit (1);
}
/* send message */
if ((r=ezs_write(E, hw, strlen(hw)<0) {
fprintf(stderr, ">> write failed, %d\n",
ezs_errno(E));
exit (1);
}
/* read reply */
if ((r=ezs_read(E, resp, 4095))<=0) {
fprintf(stderr, ">> read failed, %d\n",
ezs_errno(E));
exit (1);
}
resp[r] = '\0';
printf("Received: %s\n", resp);
ezs_disconnect(E);
}
#include "ezs.h"
static char *hw = "Hello, world.";
static key = "my key string";
#define UC (unsigned char*)
main()
{
EZS *E;
unsigned char *e_hw;
int e_len;
unsigned char *mac;
int mac_len;
unsigned char *iv = NULL;
char *mac64, *e64;
/* alloc an ezs struct */
ezs_init(NULL);
E = ezs_new(NULL);
/* Initialize */
ezs_crypt_init(E, key, strlen(key), &iv);
/* encrypt */
e_hw = UC malloc(strlen(hw)+EZS_BLOCKSIZE(E));
ezs_crypt(E, EZS_ENCRYPT, e_hw, &e_len, UC hw, strlen(hw));
/* get mac */
ezs_hmac(&mac, &mac_len, e_hw, e_len, UC key, strlen(key));
ezs_data_to_base64(&mac64, NULL, (void*)mac, mac_len);
ezs_data_to_base64(&e64, NULL, (void*)e_hw, e_len);
printf("%s encoded = %s\n", hw, e64);
printf("mac = %s\n", mac64);
}
|
Jim Fox UW Technology Identity and Access Management University of Washington fox@washington.edu |
© 1983-2009, University of Washington