/*
 *  Copyright (c) 1996-2007 Digi International Inc., All Rights Reserved
 *
 *  This software contains proprietary and confidential information of Digi
 *  International Inc.  By accepting transfer of this copy, Recipient agrees
 *  to retain this software in confidence, to prevent disclosure to others,
 *  and to make no use of this software other than that for which it was
 *  delivered.  This is an unpublished copyrighted work of Digi International
 *  Inc.  Except as permitted by federal law, 17 USC 117, copying is strictly
 *  prohibited.
 *
 *  Restricted Rights Legend
 *
 *  Use, duplication, or disclosure by the Government is subject to
 *  restrictions set forth in sub-paragraph (c)(1)(ii) of The Rights in
 *  Technical Data and Computer Software clause at DFARS 252.227-7031 or
 *  subparagraphs (c)(1) and (2) of the Commercial Computer Software -
 *  Restricted Rights at 48 CFR 52.227-19, as applicable.
 *
 *  Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343
 *
 *  Routines to retrieve certificates and load them into WPA.
 *
 *  Note: This is a NET+OS specific file.
 */
#include <stdio.h>
#include <stdlib.h>
#include "sysAccess.h"
#include "bsp_api.h"
#include "narmapi.h"
#include "fservapi.h"
#include "wln_api.h"
#include "wpa_api.h"
#include "Npttypes.h"
#include "nastatus.h"
#include "netos_certs.h"

static int readKeyFromFile(char *fpath, char *buf, int buflen);

extern int wpa_convert_cert_to_binary(char *data, 
                                  size_t data_size, 
                                  unsigned char **out, 
                                  int is_key, 
                                  char *password);

/*ad*
 * 
 * The NET+OS WPA driver supports the Extensible Authentication Protocol (EAP).
 * This section describes how to use EAP-TLS in NET+OS to provide strong security
 * and describes the use of X.509 certificates.
 *
 * NET+OS uses EAP-TLS to connect to a WPA-enabled access point. The access 
 * point, in turn, is configured to authenticate off of a 
 * radius server such as FreeRADIUS 1.0.1.
 *
 * To use EAP-TLS the authentication type and encryption should be set as
 * follows:
 * <list type="unordered">
 *      <item>Authentication type = WPA Enterprise (802.1x)</item>
 *      <item>Encryption type = TKIP</item>
 * </list>
 *
 * In NET+OS certicates by default are stored in the file system, this can
 * be modified by changing the routine @link NaLoadWpaCertificates. Four files
 * are required to be in the FLASH0/certs directory.
 *
 * <list type="unordered">
 *      <item>client_cert.pem This is the signed client certificate in X.509 
 *            PEM format.</item>
 *      <item>client_key.pem  This is the client key in X.509 PEM format.</item>
 *      <item>cacert.pem      Trusted root certificate.</item>
 *      <item>password.txt    Password for private key if encrypted.</item>
 * </list>
 *
 * These certificates can be generated using the openssl command line utlitity.
 * A tutorial on how to do this can be found here: @url http://www.linuxjournal.com/article/8095
 *
 * These certificates must be in the NET+OS file system. The define
 * @link BSP_INCLUDE_FILESYSTEM_FOR_CLIBRARY must be set to TRUE in bsp_fs.h 
 * This change creates a RAM and 
 * Flash file system volume by default and allows using the C library file I/O 
 * API functions to access the file system services.
 *
 * If you do not wish to use the file system you will need to modify the routine
 * @link NaLoadWpaCertificates.
 *
 * During the initialization of NET+OS the routine wireless_init calls the routine
 * @link NaLoadWpaCertificates which reads the certificates from the file system and
 * converts them to an unencrypted binary format and loads them in the WPA driver.
 * If the files do not exist the driver will continue to initialize.  The files 
 * can be loaded into flash using the FTP server in the naftpsvr_fs example.
 *
 * @category BSP:Device_Drivers:wireless:WPA_Certificates
 * @location src/bsp/devices/common/mwifimac/netos_certs.c
 * @since 7.5
 * @overview    WPA Certificates 
 * @include 	"netos_certs.h"
 * @library     bsp	
 * @platform 	connectwiem,connectwime,connectcorewi9c_a,connectwisp,connectcorewi9p9215_a
 * @external
 * @see @link NaLoadWpaCertificates 
 * @see @link BSP_INCLUDE_FILESYSTEM_FOR_CLIBRARY
*ad*/

#define WPA_NUM_TRUSTED_CERTS 8

/* Null terminated array of trusted certificates. */
static struct  wpa_cert trusted[WPA_NUM_TRUSTED_CERTS];

/*ad*
 * Load WPA certificates on startup.  This routine reads certificates from the 
 * file system, converts the certificates to a binary format and passes them
 * to the WPA driver. If you do not want to use the file system replace the
 * calls to readKeyFromFile with a routine which will fill in the len and
 * buf variables for each corresponding cerificate.
 * This file is in the directory:
 *  src/bsp/devices/common/mwifimac/netos_certs.c
 * 
 * By defualt the files read are:
 * <list type="unordered">
 *      <item>FLASH0/client_cert.pem   - Client certificate</item>
 *      <item>FLASH0/client_key.pem    - Client Key</item>
 *      <item>FLASH0/cacert.pem        - Trusted root certificate</item>
 *      <item>FLASH0/password.txt      - Password for private key if encrypted</item>
 * </list>
 *
 * @external
 * @category BSP:Device_Drivers:wireless:WPA_Certificates
 * @since 7.5
 *
 * @return 0 		successful
 * @return negative error
 * @see @link wpa_set_trusted_certificates 
 * @see @link wpa_set_client_certificate 
*ad*/
NaLoadWpaCertReturnCodes_t NaLoadWpaCertificates(void)
{
    char    *cert_buf, *key_buf;
    int     cert_len, key_len;  
    struct  wpa_cert cert, key;
    char    password_buf[MAX_PASSWORD_LEN], password_len;
    char    *password_ptr;

    if (NABspFilesystemForCLib == 0)
    {
        return CERT_ERR_NO_FS;
    }

    /* Allocate memory to read the certificates into */
    cert_buf = malloc(MAX_SSL_CERTIFICATE_LEN);
    if (cert_buf == (char *)NULL)
        return CERT_ERR_MEMORY;

    key_buf = malloc(MAX_SSL_CERTIFICATE_LEN);
    if (key_buf == (char *)NULL)
    {
        free(cert_buf);
        return CERT_ERR_MEMORY;
    }

    /* Read the password file */
    password_len = readKeyFromFile(PASSWORD_FILEPATH, password_buf, MAX_PASSWORD_LEN);
    if (!password_len)
    {
       /* 
        * No password exists, which is OK: there doesn't have to be a 
        * password.
        */ 
        password_ptr = (char *)NULL;
    }
    else
    {
        /* If there is a linefeed as the last character - get rid of it */
        if (password_buf[password_len-1] == 0x0A)
            password_buf[password_len-1] = 0;

        password_ptr = password_buf;

    } 


    /* Read the client certificate file */
    cert_len = readKeyFromFile(CLNT_CERTICATE_FILEPATH, cert_buf, MAX_SSL_CERTIFICATE_LEN);
    if (!cert_len)
    {
        free(cert_buf);
        free(key_buf);
        return CERT_ERR_OPEN;
    }

    /* Read the client key file */
    key_len = readKeyFromFile(CLNT_KEY_FILEPATH, key_buf, MAX_SSL_KEY_LEN);
    if (!key_len)
    {
        free(cert_buf);
        free(key_buf);
        return CERT_ERR_OPEN;
    }

    /* Convert to the format which is then passed to WPA. */
    cert.length = wpa_convert_cert_to_binary(cert_buf, cert_len, &cert.data, 
                                         0, password_ptr);

    key.length = wpa_convert_cert_to_binary(key_buf, key_len, &key.data, 
                                         1, password_ptr);

    /* Load certificates with WPA */
    if (cert.length > 0 && key.length > 0)
        wpa_set_client_certificate(&cert, &key, NULL);

    /*
     * Below is an example of loading three SA trusted root certificates, 
     * we pass a NULL terminated array into wpa_set_trusted_certificates 
     * NOTE: This array must be statically allocated and is accessed 
     * after this API call. 
     */

    /* Read the CA certificate from data base */
    cert_len = readKeyFromFile(CA_CERTICATE_FILEPATH, cert_buf, MAX_SSL_CERTIFICATE_LEN);
    if (!cert_len)
    {
        free(cert_buf);
        free(key_buf);
        return CERT_ERR_OPEN;
    }

    // Memory is allocated for the certificate by this call
    trusted[0].length = wpa_convert_cert_to_binary(cert_buf, cert_len, 
                                               &trusted[0].data, 
                                               0, password_ptr);
    /* Read the second CA certificate from data base */
    cert_len = readKeyFromFile(CA_CERTICATE_FILEPATH2, cert_buf, MAX_SSL_CERTIFICATE_LEN);
    if (!cert_len)
    {
        free(cert_buf);
        free(key_buf);
        return CERT_ERR_OPEN;
    }

    trusted[1].length = wpa_convert_cert_to_binary(cert_buf, cert_len, 
                                               &trusted[1].data,  
                                               0, password_ptr);
 
    /* Read the second CA certificate from data base */
    cert_len = readKeyFromFile(CA_CERTICATE_FILEPATH3, cert_buf, MAX_SSL_CERTIFICATE_LEN);
    if (!cert_len)
    {
        free(cert_buf);
        free(key_buf);
        return CERT_ERR_OPEN;
    }

    /* Read the third CA certificate from data base */
    trusted[2].length = wpa_convert_cert_to_binary(cert_buf, cert_len, 
                                               &trusted[2].data,  
                                               0, password_ptr);


    /* NULL terminate the array */
    trusted[3].data   = (uint8 *)0;
    trusted[3].length = 0;

    wpa_set_trusted_certificates(trusted, TRUE);

    free(cert_buf);
    free(key_buf);

    return CERT_SUCCESS;
}



/* 
 * This Function reads the specified file to given buffer. Function returns
 * number of bytes read 
 */
static int readKeyFromFile(char *fpath, char *buf, int buflen)
{
    int rlen=0;
    FILE *fp=NULL;

    fp = fopen(fpath, "r");
    if (fp)
    {
        rlen = fread(buf, 1, buflen, fp);
        if ((!rlen) || (rlen == EOF))
        {
            printf("C library fread() returned 0, error %d\n", getErrno());
            rlen = 0;
        }
        if (fclose(fp))
        {
            printf("C library fclose() failed\n");
        }
    } 

    return rlen;
}



