mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-25 12:04:47 +00:00
CL: wifi: CC3220: Enterprise auth support PUBLISHED_FROM=ce445eb5b740073c9a3f9811f1acd404ce134f2e
252 lines
7.9 KiB
C
252 lines
7.9 KiB
C
/*
|
|
* Copyright (c) 2014-2018 Cesanta Software Limited
|
|
* All rights reserved
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK
|
|
|
|
#include "common/mg_mem.h"
|
|
|
|
#ifndef MG_SSL_IF_SIMPLELINK_SLFS_PREFIX
|
|
#define MG_SSL_IF_SIMPLELINK_SLFS_PREFIX "SL:"
|
|
#endif
|
|
|
|
#define MG_SSL_IF_SIMPLELINK_SLFS_PREFIX_LEN \
|
|
(sizeof(MG_SSL_IF_SIMPLELINK_SLFS_PREFIX) - 1)
|
|
|
|
struct mg_ssl_if_ctx {
|
|
char *ssl_cert;
|
|
char *ssl_key;
|
|
char *ssl_ca_cert;
|
|
char *ssl_server_name;
|
|
};
|
|
|
|
void mg_ssl_if_init() {
|
|
}
|
|
|
|
enum mg_ssl_if_result mg_ssl_if_conn_init(
|
|
struct mg_connection *nc, const struct mg_ssl_if_conn_params *params,
|
|
const char **err_msg) {
|
|
struct mg_ssl_if_ctx *ctx =
|
|
(struct mg_ssl_if_ctx *) MG_CALLOC(1, sizeof(*ctx));
|
|
if (ctx == NULL) {
|
|
MG_SET_PTRPTR(err_msg, "Out of memory");
|
|
return MG_SSL_ERROR;
|
|
}
|
|
nc->ssl_if_data = ctx;
|
|
|
|
if (params->cert != NULL || params->key != NULL) {
|
|
if (params->cert != NULL && params->key != NULL) {
|
|
ctx->ssl_cert = strdup(params->cert);
|
|
ctx->ssl_key = strdup(params->key);
|
|
} else {
|
|
MG_SET_PTRPTR(err_msg, "Both cert and key are required.");
|
|
return MG_SSL_ERROR;
|
|
}
|
|
}
|
|
if (params->ca_cert != NULL && strcmp(params->ca_cert, "*") != 0) {
|
|
ctx->ssl_ca_cert = strdup(params->ca_cert);
|
|
}
|
|
/* TODO(rojer): cipher_suites. */
|
|
if (params->server_name != NULL) {
|
|
ctx->ssl_server_name = strdup(params->server_name);
|
|
}
|
|
return MG_SSL_OK;
|
|
}
|
|
|
|
enum mg_ssl_if_result mg_ssl_if_conn_accept(struct mg_connection *nc,
|
|
struct mg_connection *lc) {
|
|
/* SimpleLink does everything for us, nothing for us to do. */
|
|
(void) nc;
|
|
(void) lc;
|
|
return MG_SSL_OK;
|
|
}
|
|
|
|
enum mg_ssl_if_result mg_ssl_if_handshake(struct mg_connection *nc) {
|
|
/* SimpleLink has already performed the handshake, nothing to do. */
|
|
return MG_SSL_OK;
|
|
}
|
|
|
|
int mg_ssl_if_read(struct mg_connection *nc, void *buf, size_t len) {
|
|
/* SimpelLink handles TLS, so this is just a pass-through. */
|
|
int n = nc->iface->vtable->tcp_recv(nc, buf, len);
|
|
if (n == 0) nc->flags |= MG_F_WANT_READ;
|
|
return n;
|
|
}
|
|
|
|
int mg_ssl_if_write(struct mg_connection *nc, const void *buf, size_t len) {
|
|
/* SimpelLink handles TLS, so this is just a pass-through. */
|
|
return nc->iface->vtable->tcp_send(nc, buf, len);
|
|
}
|
|
|
|
void mg_ssl_if_conn_close_notify(struct mg_connection *nc) {
|
|
/* Nothing to do */
|
|
(void) nc;
|
|
}
|
|
|
|
void mg_ssl_if_conn_free(struct mg_connection *nc) {
|
|
struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
|
|
if (ctx == NULL) return;
|
|
nc->ssl_if_data = NULL;
|
|
MG_FREE(ctx->ssl_cert);
|
|
MG_FREE(ctx->ssl_key);
|
|
MG_FREE(ctx->ssl_ca_cert);
|
|
MG_FREE(ctx->ssl_server_name);
|
|
memset(ctx, 0, sizeof(*ctx));
|
|
MG_FREE(ctx);
|
|
}
|
|
|
|
bool pem_to_der(const char *pem_file, const char *der_file) {
|
|
bool ret = false;
|
|
FILE *pf = NULL, *df = NULL;
|
|
bool writing = false;
|
|
pf = fopen(pem_file, "r");
|
|
if (pf == NULL) goto clean;
|
|
remove(der_file);
|
|
fs_slfs_set_file_size(der_file + MG_SSL_IF_SIMPLELINK_SLFS_PREFIX_LEN, 2048);
|
|
df = fopen(der_file, "w");
|
|
fs_slfs_unset_file_flags(der_file + MG_SSL_IF_SIMPLELINK_SLFS_PREFIX_LEN);
|
|
if (df == NULL) goto clean;
|
|
while (1) {
|
|
char pem_buf[70];
|
|
char der_buf[48];
|
|
if (!fgets(pem_buf, sizeof(pem_buf), pf)) break;
|
|
if (writing) {
|
|
if (strstr(pem_buf, "-----END ") != NULL) {
|
|
ret = true;
|
|
break;
|
|
}
|
|
int l = 0;
|
|
while (!isspace((unsigned int) pem_buf[l])) l++;
|
|
int der_len = 0;
|
|
cs_base64_decode((const unsigned char *) pem_buf, sizeof(pem_buf),
|
|
der_buf, &der_len);
|
|
if (der_len <= 0) break;
|
|
if (fwrite(der_buf, 1, der_len, df) != der_len) break;
|
|
} else if (strstr(pem_buf, "-----BEGIN ") != NULL) {
|
|
writing = true;
|
|
}
|
|
}
|
|
|
|
clean:
|
|
if (pf != NULL) fclose(pf);
|
|
if (df != NULL) {
|
|
fclose(df);
|
|
if (!ret) remove(der_file);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
#if MG_ENABLE_FILESYSTEM && defined(MG_FS_SLFS)
|
|
/* If the file's extension is .pem, convert it to DER format and put on SLFS. */
|
|
static char *sl_pem2der(const char *pem_file) {
|
|
const char *pem_ext = strstr(pem_file, ".pem");
|
|
if (pem_ext == NULL || *(pem_ext + 4) != '\0') {
|
|
return strdup(pem_file);
|
|
}
|
|
char *der_file = NULL;
|
|
/* DER file must be located on SLFS, add prefix. */
|
|
int l = mg_asprintf(&der_file, 0, MG_SSL_IF_SIMPLELINK_SLFS_PREFIX "%.*s.der",
|
|
(int) (pem_ext - pem_file), pem_file);
|
|
if (der_file == NULL) return NULL;
|
|
bool result = false;
|
|
cs_stat_t st;
|
|
if (mg_stat(der_file, &st) != 0) {
|
|
result = pem_to_der(pem_file, der_file);
|
|
LOG(LL_DEBUG, ("%s -> %s = %d", pem_file, der_file, result));
|
|
} else {
|
|
/* File exists, assume it's already been converted. */
|
|
result = true;
|
|
}
|
|
if (result) {
|
|
/* Strip the SL: prefix we added since NWP does not expect it. */
|
|
memmove(der_file, der_file + MG_SSL_IF_SIMPLELINK_SLFS_PREFIX_LEN,
|
|
l - 2 /* including \0 */);
|
|
} else {
|
|
MG_FREE(der_file);
|
|
der_file = NULL;
|
|
}
|
|
return der_file;
|
|
}
|
|
#else
|
|
static char *sl_pem2der(const char *pem_file) {
|
|
return strdup(pem_file);
|
|
}
|
|
#endif
|
|
|
|
int sl_set_ssl_opts(int sock, struct mg_connection *nc) {
|
|
int err;
|
|
const struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
|
|
DBG(("%p ssl ctx: %p", nc, ctx));
|
|
|
|
if (ctx == NULL) return 0;
|
|
DBG(("%p %s,%s,%s,%s", nc, (ctx->ssl_cert ? ctx->ssl_cert : "-"),
|
|
(ctx->ssl_key ? ctx->ssl_cert : "-"),
|
|
(ctx->ssl_ca_cert ? ctx->ssl_ca_cert : "-"),
|
|
(ctx->ssl_server_name ? ctx->ssl_server_name : "-")));
|
|
if (ctx->ssl_cert != NULL && ctx->ssl_key != NULL) {
|
|
char *ssl_cert = sl_pem2der(ctx->ssl_cert), *ssl_key = NULL;
|
|
if (ssl_cert != NULL) {
|
|
err = sl_SetSockOpt(sock, SL_SOL_SOCKET,
|
|
SL_SO_SECURE_FILES_CERTIFICATE_FILE_NAME, ssl_cert,
|
|
strlen(ssl_cert));
|
|
MG_FREE(ssl_cert);
|
|
LOG(LL_DEBUG, ("CERTIFICATE_FILE_NAME %s -> %d", ssl_cert, err));
|
|
ssl_key = sl_pem2der(ctx->ssl_key);
|
|
if (ssl_key != NULL) {
|
|
err = sl_SetSockOpt(sock, SL_SOL_SOCKET,
|
|
SL_SO_SECURE_FILES_PRIVATE_KEY_FILE_NAME, ssl_key,
|
|
strlen(ssl_key));
|
|
MG_FREE(ssl_key);
|
|
LOG(LL_DEBUG, ("PRIVATE_KEY_FILE_NAME %s -> %d", ssl_key, err));
|
|
} else {
|
|
err = -1;
|
|
}
|
|
} else {
|
|
err = -1;
|
|
}
|
|
if (err != 0) return err;
|
|
}
|
|
if (ctx->ssl_ca_cert != NULL) {
|
|
if (ctx->ssl_ca_cert[0] != '\0') {
|
|
char *ssl_ca_cert = sl_pem2der(ctx->ssl_ca_cert);
|
|
if (ssl_ca_cert != NULL) {
|
|
err =
|
|
sl_SetSockOpt(sock, SL_SOL_SOCKET, SL_SO_SECURE_FILES_CA_FILE_NAME,
|
|
ssl_ca_cert, strlen(ssl_ca_cert));
|
|
LOG(LL_DEBUG, ("CA_FILE_NAME %s -> %d", ssl_ca_cert, err));
|
|
} else {
|
|
err = -1;
|
|
}
|
|
MG_FREE(ssl_ca_cert);
|
|
if (err != 0) return err;
|
|
}
|
|
}
|
|
if (ctx->ssl_server_name != NULL) {
|
|
err = sl_SetSockOpt(sock, SL_SOL_SOCKET,
|
|
SL_SO_SECURE_DOMAIN_NAME_VERIFICATION,
|
|
ctx->ssl_server_name, strlen(ctx->ssl_server_name));
|
|
DBG(("DOMAIN_NAME_VERIFICATION %s -> %d", ctx->ssl_server_name, err));
|
|
/* Domain name verificationw as added in a NWP service pack, older
|
|
* versions return SL_ERROR_BSD_ENOPROTOOPT. There isn't much we can do
|
|
* about it,
|
|
* so we ignore the error. */
|
|
if (err != 0 && err != SL_ERROR_BSD_ENOPROTOOPT) return err;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#endif /* MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK */
|