IDENTITY AND ACCESS MANAGEMENT
[an error occurred while processing this directive]

EZ-SSL

EZ-SSL library

Summary: Provides an easy-to-use, SSL protected connection library.
Version: 1.4.3
Download: ezs-1.4.3.tar.gz
Git:https://github.com/UWIT-IAM/ezs.git
  • Openssl is the de facto open source standard for secure network communications, but can be difficult to use properly. This library removes some of that complexity, while providing the standard functions needed by clients and servers: connect, read, write.

  • Although not needed for secure communications, convenience routines are provided to encrypt and decrypt data.

  • The library replaces an older, custom crypto connection library used at UW (lsc), and is similar in function.

You should be able to install with

$ ./configure
$ make
$ make install

Programs using the ezs api must include

#include "ezs.h"

and link with at least these libraries (On linux at least you must specify the pthread library)

-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"

and link with one the correct library: ezsMD.lib or ezsMDd.lib.

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.

 ezs_errno

Description: Get the last error code
Syntax:   int ezs_errno(EZS* E)
Arguments:
E: An EZS structure
Return: the error code
Errors:
Notes:
  1. If E is NULL the global error is returned.

 ezs_geterror

Description: Get the last error code and message
Syntax:   int *ezs_geterror(EZS* Echar** txt)
Arguments:
E: An EZS structure
txt:Pointer to a character pointer to receive the error text.
Return: the error code
Errors:
Notes:
  1. If E is NULL the global error is returned.
  2. txt may be NULL. In which case no text is returned.
  3. Caller is responsible for freeing the error text.
  4. The error text includes a description of any SSL errors.
  5. SSL errors are cleared as they are retrieved, so this call may be made only once per error.

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.

 ezs_init

Description: Initializes the openssl and ezs libraries.
Syntax:   void *ezs_init(char* name)
Arguments:
name:session name, may be NULL
Return: 1 (always success)
Errors:
Notes:
  1. This must be called prior to any thread or openssl calls by the program.
  2. The first call to ezs_new will invoke ezs_init with a NULL name if the caller has not already called ezs_init.
  3. Servers can use name to identify SSL sessions. A NULL value deactivates sessions.
  4. The argument is ignored for clients.

 ezs_load_rand_file

Description: Adds data from the file to SSL's 'randomness'.
Syntax:   void *ezs_load_rand_file(char* filename)
Arguments:
filename:read/write file of random data
Return: 1
Errors:
Notes:
  1. This should be called prior to any SSL operation.
  2. You may call this more than once, with different filenames.
  3. This is implemented as a macro

 ezs_save_rand_file

Description: Writes random data to the file.
Syntax:   void *ezs_save_rand_file(char* filename)
Arguments:
filename:read/write file of random data
Return: 1
Errors:
Notes:
  1. This should be called just before your program exits to update the random seed file, but it can be called any time.
  2. This is implemented as a macro

 ezs_new

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:
  1. Initializes the library if ezs_init has not been called.

 ezs_free

Description: Frees an ezs struct.
Syntax:   void *ezs_free(EZS* E)
Arguments:
E: An EZS structure
Return:
Errors:
Notes:

There are several credentials involved in a secure ezs connection:

The authenticating certificate and key consists of a single certificate and key pair that you are using to authenticate to your peer on the connection. Your certificate must have been signed by a CA who is trusted by the peer. Use ezs_add_cert to add certificates and keys to the list of certificates you can use to authenticate to a peer.

Generally if a key file is not specified the key is assumed to be in the same file as the certificate.

A CA certificate is the public certificate of a Certificate Authority (CA) whose signatures you will accept. Use ezs_add_ca to add certificates to the list of acceptable CAs.
A Certificate Revocation List (CRL) identifies certificates that have been revoked by their CA and are no longer valid. Use ezs_add_ca or ezs_add_crl to add to your list of CRLs.

 ezs_add_ca

Description: Add one or more CAs to your list of acceptable CAs.
Syntax:   int ezs_add_ca(char* ca_file)
Arguments:
ca_file: Contains the CA certificates to add (PEM)
Return: 1 = success, 0 = error
Errors:
EZS_ERR_SSL: invalid CA file
Notes:
  1. The certificates will be added to the list of acceptable signers of peer certificates.
  2. Must be PEM format
  3. If the file also contains CRLs they will automatically be added to the CRL list.

 ezs_add_crl

Description: Adds one or more CRLs to your list of CRLs.
Syntax:   int ezs_add_crl(char* crl_file)
Arguments:
crl_file: Contains the CRLs to add
Return: 1 = success, 0 = error
Errors:
EZS_ERR_SSL: invalid CRL file
Notes:
  1. The CRLs will be added to the list of CRLs used to verify certificates.
  2. Must be PEM format
  3. You can use ezs_add_crl at any time to load new CRLs or to refresh existing CRLs. Changes will take effect on the next connect or accept. Existing connections will be unaffected.

 ezs_add_cert

Description: Adds a certificate to the list of available certificates for authentication to peers.
Syntax:   int ezs_add_cert(char* crtchar* keychar** cn)
Arguments:
crt: Certificate file (PEM)
key: Key file (PEM)
cn: If specified, returns the cert's cn.
Return: 1 = success, 0 = error
Errors:
EZS_ERR_SSL: invalid cert or key
Notes:
  1. If key is NULL the certificate's key will be looked for in the crt file.

 ezs_set_verify

Description: Sets the option to verify the server hostname vs. common name.
Syntax:   void ezs_set_verify(EZS* E)
Arguments:
E: An EZS structure
Return:
Errors:
Notes:
  1. Normally a client or server may choose one of many certificates for any given connection. This option requires that the CN of the certificate match the hostname.
  2. This is implemented as a macro

 ezs_get_peer_cn

Description: Returns the CN of the connected peer's certificate
Syntax:   char ezs_get_peer_cn(EZS* E)
Arguments:
E: An EZS structure
Return:
Errors:
Notes:
  1. The returned value is a pointer into the EZS structure. DO NOT free it.
  2. This is implemented as a macro

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.

Clients can save and reuse a session -- thereby saving negotiating overhead on subsequent connections.

 ezs_set_session_name

Description: Set the server's session name or deactivate sessions
Syntax:   void ezs_set_session_name(char* name)
Arguments:
name: name to use for subsequent accepted connections
Return:
Errors:
Notes:
  1. If name is NULL sessions are deactivated.

 ezs_get_session

Description: Retrieve the session identifier associated with the current connection
Syntax:   char *ezs_get_session(EZS* E)
Arguments:
E: An EZS structure
Return: A session identifier
Errors:
EZS_ERR_NO_CONNECTION: No session exists
Notes:
  1. The session identifier is a null-terminated character string.
  2. ezs_get_session must be called after the connection is opened.

 ezs_set_session

Description: Specifies a session identifier to be used for the next connection.
Syntax:   int *ezs_set_session(EZS* Echar* session)
Arguments:
E: An EZS structure
session: A session identifier.
Return: 1 = success, 0 = error
Errors:
EZS_ERR_SSL: invalid session
Notes:
  1. The session identifier is a null-terminated character string.

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.

 ezs_use_blocking_io

Description: Sets blocking IO for this connection
Syntax:   int *ezs_use_blocking_io(EZS* E)
Arguments:
E: An EZS structure
Return:
Errors:
Notes:
  1. This is the default mode
  2. This is implemented as a macro

 ezs_use_nonblocking_io

Description: Sets non-blocking IO for this connection
Syntax:   int *ezs_use_nonblocking_io(EZS* E)
Arguments:
E: An EZS structure
Return:
Errors:
Notes:
  1. This is implemented as a macro

 ezs_set_timeout

Description: Sets semi-blocking timeout for this connection
Syntax:   int *ezs_set_timeout(EZS* Eint timeout
Arguments:
E: An EZS structure
timeout: seconds to block before reporting a wouldblock error.
Return:
Errors:
Notes:
  1. This is implemented as a macro

 ezs_allow_v2

Description: Allow connections using SSLv2 protocol
Syntax:   void ezs_allow_v2(EZS* E)
Arguments:
E: An EZS structure
Return:
Errors:
Notes:
  1. By default the library does not allow SSLv2.
  2. This is implemented as a macro

 ezs_allow_v3

Description: Allow connections using v3 protocol
Syntax:   void ezs_allow_v3(EZS* E)
Arguments:
E: An EZS structure
Return:
Errors:
Notes:
  1. By default the library allows SSLv3.
  2. This is implemented as a macro

 ezs_deny_v2

Description: Deny use of the SSLv2 protocol
Syntax:   void ezs_deny_v2(EZS* E)
Arguments:
E: An EZS structure
Return:
Errors:
Notes:
  1. By default the library does not allow SSLv2.
  2. This is implemented as a macro

 ezs_deny_v3

Description: Deny use of the SSLv3 protocol
Syntax:   void ezs_deny_v3(EZS* E)
Arguments:
E: An EZS structure
Return:
Errors:
Notes:
  1. By default the library allows SSLv3.
  2. This is implemented as a macro

 ezs_connect

Description: Client connect and authenticate to a server
Syntax:   int ezs_connect(EZS* Echar* servicechar* cn)
Arguments:
E: An EZS structure
service: The service address: (host:port).
cn: CN of the certificate to use for authentication
Return: 1 = success, 0 = error
Errors:
EZS_ERR_NOCRT: cert (cn) not loaded
EZS_ERR_BADCRT: cert invalid
EZS_ERR_BADKEY: key invalid
EZS_ERR_SSL: connection failure
Notes:
  1. The 'cn' must have been previously loaded with ezs_add_cert.
  2. On success the connection will be open and verified.
  3. You can find the peer's cn with ezs_get_peer_cn.
  4. If you choose not to retry a WOULDBLOCK error you must call ezs_disconnect to close the partially open connection.

 ezs_connect_fd

Description: Client authenticate to a server over already connected socket
Syntax:   int ezs_connect_fd(EZS* Eint fdchar* cn)
Arguments:
E: An EZS structure
fd: The connected file descriptor
cn: CN of the certificate to use for authentication
Return: 1 = success, 0 = error
Errors:
EZS_ERR_NOCRT: cert (cn) not loaded
EZS_ERR_BADCRT: cert invalid
EZS_ERR_BADKEY: key invalid
EZS_ERR_SSL: connection failure
Notes:
  1. You can find the peer's cn with ezs_get_peer_cn.
  2. If you choose not to retry a WOULDBLOCK error you must call ezs_disconnect to close the partially open connection.

 ezs_listen

Description: Listen on a port for connection requests.
Syntax:   int ezs_listen(EZS* Echar* port)
Arguments:
E: An EZS structure
port: Port to listen on
Return: 1 = success, 0 = error
Errors:
EZS_ERR_SSL: listen failure
Notes:
  1. Note that the port is a character string

 ezs_accept

Description: Server accept connection and verify client
Syntax:   EZS *ezs_accept(EZS* Echar* cn)
Arguments:
E: An EZS structure
cn: CN of the certificate to use for authentication
Return: An EZS structure, NULL = error
Errors:
EZS_ERR_NOCRT: cert (cn) not loaded
EZS_ERR_BADCRT: cert invalid
EZS_ERR_BADKEY: key invalid
EZS_ERR_SSL: accept failure
Notes:
  1. On success the connection will be open and verified.
  2. You can find the peer's cn with ezs_get_peer_cn.
  3. If you choose not to retry a WOULDBLOCK error you must call ezs_disconnect to close the partially open connection.

 ezs_accept_fd

Description: Server verify connected client
Syntax:   int ezs_accept_fd(EZS* Eint fdchar* cn)
Arguments:
E: An EZS structure
fd: The connected file descriptor
cn: CN of the certificate to use for authentication
Return: 1 = success, 0 = error
Errors:
EZS_ERR_NOCRT: cert (cn) not loaded
EZS_ERR_BADCRT: cert invalid
EZS_ERR_BADKEY: key invalid
EZS_ERR_SSL: accept failure
Notes:
  1. On success the connection will be open and verified.
  2. You can find the peer's cn with ezs_get_peer_cn.
  3. If you choose not to retry a WOULDBLOCK error you must call ezs_disconnect to close the partially open connection.

 ezs_disconnect

Description: Disconnect a connection
Syntax:   void ezs_disconnect(EZS* E)
Arguments:
E: An EZS structure
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.

 ezs_read

Description: Read bytes from a peer len bytes.
Syntax:   int ezs_read(EZS* Echar* dataint len)
Arguments:
E: An EZS structure
data: Memory location to receive data. Must be at least
len: maximum number of bytes to read
Return: number of bytes read, 0 = error
Errors:
EZS_ERR_NO_CONNECTION: no connection
EZS_ERR_READ_WOULDBLOCK: read blocked (waiting for read)
EZS_ERR_WRITE_WOULDBLOCK: read blocked (waiting for write)
EZS_ERR_READ_EOF: connection closed by peer
EZS_ERR_SSL: SSL error
Notes:
  1. If you choose to retry a blocked read you must supply the exact same data with the retried ezs_read. You may supply a copy of the original data however.
  2. If you choose not to retry a blocked read you must call ezs_disconnect to close the open connection.
  3. You should call ezs_disconnect to close a connection after receiving an end-of-file.

 ezs_write

Description: Write bytes to a peer
Syntax:   int ezs_write(EZS* Echar* dataint len)
Arguments:
E: An EZS structure
data: Pointer to data.
len: number of bytes to write
Return: number of bytes written, 0 = error
Errors:
EZS_ERR_NO_CONNECTION: no connection
EZS_ERR_READ_WOULDBLOCK: write blocked (waiting for read)
EZS_ERR_WRITE_WOULDBLOCK: write blocked (waiting for write)
EZS_ERR_READ_EOF: connection closed by peer
EZS_ERR_SSL: SSL error
Notes:
  1. Success means all the data were written
  2. If you choose to retry a blocked write you must supply the exact same data with the retried ezs_write. You may supply a copy of the original data however.
  3. If you choose not to retry a blocked write you must call ezs_disconnect to close the open connection.
  4. You should call ezs_disconnect to close a connection after receiving an end-of-file.

 ezs_bytes_for_read

Description: Get number of bytes available for read
Syntax:   int ezs_bytes_for_read(EZS* E
Arguments:
E: An EZS structure
Return: number of bytes buffered and available for a read operation
Errors:
Notes:

 ezs_wouldblock

Description: Test if the last IO attempt would have blocked
Syntax:   int ezs_wouldblock(EZS* E
Arguments:
E: An EZS structure
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.

 ezs_crypt_init

Description: Initialize cryption structures
Syntax:   int ezs_crypt_init(EZS* Echar* keyint lenchar** iv)
Arguments:
E: An EZS structure
key: Encryption key
len: length of the key
iv: initialization vector
Return: 1
Errors:
Notes:
  1. If iv is NULL an IV will be computed, used and discarded.
    If iv points to a NULL pointer an IV will be computed, used and a pointer to it returned in iv. If iv points to a non-NULL pointer it is assumed to be a predefined IV and will be used.
  2. The IV used in for encryption must be provided to the decryption step or the first block of decrypted data will be lost.

 ezs_crypt

Description: Encrypt or decrypt data
Syntax:   int ezs_crypt(EZS* Eint modechar* outint out_lenchar* inint in_len)
Arguments:
E: An EZS structure
mode: Either EZS_ENCRYPT or EZS_DECRYPT
out: buffer to receive the crypted text
out_len: length of data stored in the buffer
in: data to encrypt or decrypt
in_len: length of data
Return: 1 = success, 0 = error
Errors:
EZS_ERR_SSL: cryption failure
Notes:
  1. Because of the possibility of block padding, the output buffer's length should be at least in_len + EZS_BLOCKSIZE(E)
  2. You must call ezs_crypt_init prior to ezs_crypt.

 ezs_hmac

Description: Generate a MAC of some data
Syntax:   int ezs_hmac(char** macint* mac_lenchar* dataint data_lenchar* keyint key_len)
Arguments:
data: data for which the MAC will be computed
data_len: length of data
key: key for the MAC
key_len: length of the key
mac: computed MAC
mac_len: length of mac
Return: 1
Errors:
Notes:

 ezs_data_to_base64

Description: Convert binary data to printable base64
Syntax:  int ezs_data_to_base64(char** b64int* b64_lenchar* dataint data_len)
Arguments:
data: input binary data
data_len: length of data
b64: base64 representation of data
b64_len: length of b64 text
Return: 1
Errors:
Notes:

 ezs_base64_to_data

Description: Convert base64 to binary data
Syntax:  int ezs_base64_to_data(char** dataint* data_lenchar* b64int b64_len)
Arguments:
b64: input base64 representation of data
b64_len: length of b64 text
data: output binary data
data_len: length of data
Return: 1
Errors:
Notes:

 ezs_set_cipher

Description: Sets the cipher used by the encryption procedures
Syntax:  int ezs_set_cipher(EVP_CIPHER* (*cipher)())
Arguments:
cipher: any openssl cipher algorithm
Return:
Errors:
Notes:
  1. Ciphers supported by your version of the openssl library may be found in openssl's inlcude file evp.h.
  2. The default cipher is EVP_aes_128_cbc (128 bit AES in CBC mode)

 ezs_set_hash

Description: Sets the hash algorithm used by the encryption and hash procedures
Syntax:  int ezs_set_hash(EVP_MD* (*hash)())
Arguments:
cipher: any openssl hash algorithm
Return:
Errors:
Notes:
  1. Hashes supported by your version of the openssl library may be found in openssl's inlcude file evp.h.
  2. The default is EVP_sha1 (SHA-1)

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.

 ezs_version

Description: Returns ezs and openssl version information.
Syntax:   char *ezs_version()
Arguments:
Return: Version information as a string.
Errors:
Notes:
  1. Caller is responsible for freeing the returned version string.

 * =================================================================
 * 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.
 * =================================================================

 Client

Basic client connect and read loop


 #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);

}


 Crypto

Encrypt and compute a MAC


 #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);
}
  


[an error occurred while processing this directive]
Jim Fox
UW Technology
Identity and Access Management
University of Washington
fox@washington.edu
[an error occurred while processing this directive]
[an error occurred while processing this directive]
[an error occurred while processing this directive]
Fox's Home

© 1983-2017, University of Washington