Add FreeRTOS-Plus directory with new directory structure so it matches the FreeRTOS directory.

This commit is contained in:
Richard Barry 2013-04-18 09:17:05 +00:00
parent 80f7e8cdd4
commit 64a3ab321a
528 changed files with 228252 additions and 0 deletions

View file

@ -0,0 +1,576 @@
/* crl.c
*
* Copyright (C) 2006-2012 Sawtooth Consulting Ltd.
*
* This file is part of CyaSSL.
*
* CyaSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* CyaSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_CRL
#include <cyassl/internal.h>
#include <cyassl/error.h>
#include <dirent.h>
#include <string.h>
/* Initialze CRL members */
int InitCRL(CYASSL_CRL* crl, CYASSL_CERT_MANAGER* cm)
{
CYASSL_ENTER("InitCRL");
crl->cm = cm;
crl->crlList = NULL;
crl->monitors[0].path = NULL;
crl->monitors[1].path = NULL;
#ifdef HAVE_CRL_MONITOR
crl->tid = 0;
#endif
if (InitMutex(&crl->crlLock) != 0)
return BAD_MUTEX_ERROR;
return 0;
}
/* Initialze CRL Entry */
static int InitCRL_Entry(CRL_Entry* crle, DecodedCRL* dcrl)
{
CYASSL_ENTER("InitCRL_Entry");
XMEMCPY(crle->issuerHash, dcrl->issuerHash, SHA_DIGEST_SIZE);
XMEMCPY(crle->crlHash, dcrl->crlHash, MD5_DIGEST_SIZE);
XMEMCPY(crle->lastDate, dcrl->lastDate, MAX_DATE_SIZE);
XMEMCPY(crle->nextDate, dcrl->nextDate, MAX_DATE_SIZE);
crle->lastDateFormat = dcrl->lastDateFormat;
crle->nextDateFormat = dcrl->nextDateFormat;
crle->certs = dcrl->certs; /* take ownsership */
dcrl->certs = NULL;
crle->totalCerts = dcrl->totalCerts;
return 0;
}
/* Free all CRL Entry resources */
static void FreeCRL_Entry(CRL_Entry* crle)
{
RevokedCert* tmp = crle->certs;
CYASSL_ENTER("FreeCRL_Entry");
while(tmp) {
RevokedCert* next = tmp->next;
XFREE(tmp, NULL, DYNAMIC_TYPE_REVOKED);
tmp = next;
}
}
/* Free all CRL resources */
void FreeCRL(CYASSL_CRL* crl)
{
CRL_Entry* tmp = crl->crlList;
CYASSL_ENTER("FreeCRL");
if (crl->monitors[0].path)
XFREE(crl->monitors[0].path, NULL, DYNAMIC_TYPE_CRL_MONITOR);
if (crl->monitors[1].path)
XFREE(crl->monitors[1].path, NULL, DYNAMIC_TYPE_CRL_MONITOR);
while(tmp) {
CRL_Entry* next = tmp->next;
FreeCRL_Entry(tmp);
XFREE(tmp, NULL, DYNAMIC_TYPE_CRL_ENTRY);
tmp = next;
}
#ifdef HAVE_CRL_MONITOR
if (crl->tid != 0) {
CYASSL_MSG("Canceling monitor thread");
pthread_cancel(crl->tid);
}
#endif
FreeMutex(&crl->crlLock);
}
/* Is the cert ok with CRL, return 0 on success */
int CheckCertCRL(CYASSL_CRL* crl, DecodedCert* cert)
{
CRL_Entry* crle;
int foundEntry = 0;
int revoked = 0;
int ret = 0;
CYASSL_ENTER("CheckCertCRL");
if (LockMutex(&crl->crlLock) != 0) {
CYASSL_MSG("LockMutex failed");
return BAD_MUTEX_ERROR;
}
crle = crl->crlList;
while (crle) {
if (XMEMCMP(crle->issuerHash, cert->issuerHash, SHA_DIGEST_SIZE) == 0) {
CYASSL_MSG("Found CRL Entry on list");
CYASSL_MSG("Checking next date validity");
if (!ValidateDate(crle->nextDate, crle->nextDateFormat, AFTER)) {
CYASSL_MSG("CRL next date is no longer valid");
ret = ASN_AFTER_DATE_E;
}
else
foundEntry = 1;
break;
}
crle = crle->next;
}
if (foundEntry) {
RevokedCert* rc = crle->certs;
while (rc) {
if (XMEMCMP(rc->serialNumber, cert->serial, rc->serialSz) == 0) {
CYASSL_MSG("Cert revoked");
revoked = 1;
ret = CRL_CERT_REVOKED;
break;
}
rc = rc->next;
}
}
UnLockMutex(&crl->crlLock);
if (foundEntry == 0) {
CYASSL_MSG("Couldn't find CRL for status check");
ret = CRL_MISSING;
if (crl->cm->cbMissingCRL) {
char url[256];
CYASSL_MSG("Issuing missing CRL callback");
url[0] = '\0';
if (cert->extCrlInfoSz < (int)sizeof(url) -1 ) {
XMEMCPY(url, cert->extCrlInfo, cert->extCrlInfoSz);
url[cert->extCrlInfoSz] = '\0';
}
else {
CYASSL_MSG("CRL url too long");
}
crl->cm->cbMissingCRL(url);
}
}
return ret;
}
/* Add Decoded CRL, 0 on success */
static int AddCRL(CYASSL_CRL* crl, DecodedCRL* dcrl)
{
CRL_Entry* crle;
CYASSL_ENTER("AddCRL");
crle = (CRL_Entry*)XMALLOC(sizeof(CRL_Entry), NULL, DYNAMIC_TYPE_CRL_ENTRY);
if (crle == NULL) {
CYASSL_MSG("alloc CRL Entry failed");
return -1;
}
if (InitCRL_Entry(crle, dcrl) < 0) {
CYASSL_MSG("Init CRL Entry failed");
XFREE(crle, NULL, DYNAMIC_TYPE_CRL_ENTRY);
return -1;
}
if (LockMutex(&crl->crlLock) != 0) {
CYASSL_MSG("LockMutex failed");
FreeCRL_Entry(crle);
XFREE(crle, NULL, DYNAMIC_TYPE_CRL_ENTRY);
return BAD_MUTEX_ERROR;
}
crle->next = crl->crlList;
crl->crlList = crle;
UnLockMutex(&crl->crlLock);
return 0;
}
/* Load CRL File of type, SSL_SUCCESS on ok */
int BufferLoadCRL(CYASSL_CRL* crl, const byte* buff, long sz, int type)
{
int ret = SSL_SUCCESS;
const byte* myBuffer = buff; /* if DER ok, otherwise switch */
buffer der;
DecodedCRL dcrl;
der.buffer = NULL;
CYASSL_ENTER("BufferLoadCRL");
if (crl == NULL || buff == NULL || sz == 0)
return BAD_FUNC_ARG;
if (type == SSL_FILETYPE_PEM) {
int eccKey = 0; /* not used */
EncryptedInfo info;
info.ctx = NULL;
ret = PemToDer(buff, sz, CRL_TYPE, &der, NULL, &info, &eccKey);
if (ret == 0) {
myBuffer = der.buffer;
sz = der.length;
}
else {
CYASSL_MSG("Pem to Der failed");
return -1;
}
}
InitDecodedCRL(&dcrl);
ret = ParseCRL(&dcrl, myBuffer, sz, crl->cm);
if (ret != 0) {
CYASSL_MSG("ParseCRL error");
}
else {
ret = AddCRL(crl, &dcrl);
if (ret != 0) {
CYASSL_MSG("AddCRL error");
}
}
FreeDecodedCRL(&dcrl);
if (der.buffer)
XFREE(der.buffer, NULL, DYNAMIC_TYPE_CRL);
if (ret == 0)
return SSL_SUCCESS; /* convert */
return ret;
}
#ifdef HAVE_CRL_MONITOR
/* read in new CRL entries and save new list */
static int SwapLists(CYASSL_CRL* crl)
{
int ret;
CYASSL_CRL tmp;
CRL_Entry* newList;
if (InitCRL(&tmp, crl->cm) < 0) {
CYASSL_MSG("Init tmp CRL failed");
return -1;
}
if (crl->monitors[0].path) {
ret = LoadCRL(&tmp, crl->monitors[0].path, SSL_FILETYPE_PEM, 0);
if (ret != SSL_SUCCESS) {
CYASSL_MSG("PEM LoadCRL on dir change failed");
FreeCRL(&tmp);
return -1;
}
}
if (crl->monitors[1].path) {
ret = LoadCRL(&tmp, crl->monitors[1].path, SSL_FILETYPE_ASN1, 0);
if (ret != SSL_SUCCESS) {
CYASSL_MSG("DER LoadCRL on dir change failed");
FreeCRL(&tmp);
return -1;
}
}
if (LockMutex(&crl->crlLock) != 0) {
CYASSL_MSG("LockMutex failed");
FreeCRL(&tmp);
return -1;
}
newList = tmp.crlList;
/* swap lists */
tmp.crlList = crl->crlList;
crl->crlList = newList;
UnLockMutex(&crl->crlLock);
FreeCRL(&tmp);
return 0;
}
#ifdef __MACH__
#include <sys/event.h>
#include <sys/time.h>
#include <fcntl.h>
/* OS X monitoring */
static void* DoMonitor(void* arg)
{
int fPEM, fDER, kq;
struct kevent change;
CYASSL_CRL* crl = (CYASSL_CRL*)arg;
CYASSL_ENTER("DoMonitor");
kq = kqueue();
if (kq == -1) {
CYASSL_MSG("kqueue failed");
return NULL;
}
fPEM = -1;
fDER = -1;
if (crl->monitors[0].path) {
fPEM = open(crl->monitors[0].path, O_EVTONLY);
if (fPEM == -1) {
CYASSL_MSG("PEM event dir open failed");
return NULL;
}
}
if (crl->monitors[1].path) {
fDER = open(crl->monitors[1].path, O_EVTONLY);
if (fDER == -1) {
CYASSL_MSG("DER event dir open failed");
return NULL;
}
}
if (fPEM != -1)
EV_SET(&change, fPEM, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_ONESHOT,
NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB, 0, 0);
if (fDER != -1)
EV_SET(&change, fDER, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_ONESHOT,
NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB, 0, 0);
for (;;) {
struct kevent event;
int numEvents = kevent(kq, &change, 1, &event, 1, NULL);
CYASSL_MSG("Got kevent");
if (numEvents == -1) {
CYASSL_MSG("kevent problem, continue");
continue;
}
if (SwapLists(crl) < 0) {
CYASSL_MSG("SwapLists problem, continue");
}
}
return NULL;
}
#elif __linux__
#include <sys/types.h>
#include <sys/inotify.h>
#include <unistd.h>
/* linux monitoring */
static void* DoMonitor(void* arg)
{
int notifyFd;
int wd;
CYASSL_CRL* crl = (CYASSL_CRL*)arg;
CYASSL_ENTER("DoMonitor");
notifyFd = inotify_init();
if (notifyFd < 0) {
CYASSL_MSG("inotify failed");
return NULL;
}
if (crl->monitors[0].path) {
wd = inotify_add_watch(notifyFd, crl->monitors[0].path, IN_CLOSE_WRITE |
IN_DELETE);
if (wd < 0) {
CYASSL_MSG("PEM notify add watch failed");
return NULL;
}
}
if (crl->monitors[1].path) {
wd = inotify_add_watch(notifyFd, crl->monitors[1].path, IN_CLOSE_WRITE |
IN_DELETE);
if (wd < 0) {
CYASSL_MSG("DER notify add watch failed");
return NULL;
}
}
for (;;) {
char buffer[8192];
int length = read(notifyFd, buffer, sizeof(buffer));
CYASSL_MSG("Got notify event");
if (length < 0) {
CYASSL_MSG("notify read problem, continue");
continue;
}
if (SwapLists(crl) < 0) {
CYASSL_MSG("SwapLists problem, continue");
}
}
return NULL;
}
#endif /* MACH or linux */
/* Start Monitoring the CRL path(s) in a thread */
static int StartMonitorCRL(CYASSL_CRL* crl)
{
pthread_attr_t attr;
CYASSL_ENTER("StartMonitorCRL");
if (crl == NULL)
return BAD_FUNC_ARG;
if (crl->tid != 0) {
CYASSL_MSG("Monitor thread already running");
return MONITOR_RUNNING_E;
}
pthread_attr_init(&attr);
if (pthread_create(&crl->tid, &attr, DoMonitor, crl) != 0) {
CYASSL_MSG("Thread creation error");
return THREAD_CREATE_E;
}
return SSL_SUCCESS;
}
#else /* HAVE_CRL_MONITOR */
static int StartMonitorCRL(CYASSL_CRL* crl)
{
CYASSL_ENTER("StartMonitorCRL");
CYASSL_MSG("Not compiled in");
return NOT_COMPILED_IN;
}
#endif /* HAVE_CRL_MONITOR */
/* Load CRL path files of type, SSL_SUCCESS on ok */
int LoadCRL(CYASSL_CRL* crl, const char* path, int type, int monitor)
{
struct dirent* entry;
DIR* dir;
int ret = SSL_SUCCESS;
CYASSL_ENTER("LoadCRL");
if (crl == NULL)
return BAD_FUNC_ARG;
dir = opendir(path);
if (dir == NULL) {
CYASSL_MSG("opendir path crl load failed");
return BAD_PATH_ERROR;
}
while ( (entry = readdir(dir)) != NULL) {
if (entry->d_type & DT_REG) {
char name[MAX_FILENAME_SZ];
if (type == SSL_FILETYPE_PEM) {
if (strstr(entry->d_name, ".pem") == NULL) {
CYASSL_MSG("not .pem file, skipping");
continue;
}
}
else {
if (strstr(entry->d_name, ".der") == NULL &&
strstr(entry->d_name, ".crl") == NULL) {
CYASSL_MSG("not .der or .crl file, skipping");
continue;
}
}
XMEMSET(name, 0, sizeof(name));
XSTRNCPY(name, path, MAX_FILENAME_SZ/2 - 2);
XSTRNCAT(name, "/", 1);
XSTRNCAT(name, entry->d_name, MAX_FILENAME_SZ/2);
if (ProcessFile(NULL, name, type, CRL_TYPE, NULL, 0, crl)
!= SSL_SUCCESS) {
CYASSL_MSG("CRL file load failed, continuing");
}
}
}
if (monitor & CYASSL_CRL_MONITOR) {
CYASSL_MSG("monitor path requested");
if (type == SSL_FILETYPE_PEM) {
crl->monitors[0].path = strdup(path);
crl->monitors[0].type = SSL_FILETYPE_PEM;
if (crl->monitors[0].path == NULL)
ret = MEMORY_E;
} else {
crl->monitors[1].path = strdup(path);
crl->monitors[1].type = SSL_FILETYPE_ASN1;
if (crl->monitors[1].path == NULL)
ret = MEMORY_E;
}
if (monitor & CYASSL_CRL_START_MON) {
CYASSL_MSG("start monitoring requested");
ret = StartMonitorCRL(crl);
}
}
return ret;
}
#endif /* HAVE_CRL */

View file

@ -0,0 +1,85 @@
# vim:ft=automake
# included from Top Level Makefile.am
# All paths should be given relative to the root
lib_LTLIBRARIES+= src/libcyassl.la
src_libcyassl_la_SOURCES = \
src/internal.c \
src/io.c \
src/keys.c \
src/ssl.c \
src/tls.c \
ctaocrypt/src/asn.c \
ctaocrypt/src/coding.c \
ctaocrypt/src/des3.c \
ctaocrypt/src/hmac.c \
ctaocrypt/src/md5.c \
ctaocrypt/src/md4.c \
ctaocrypt/src/random.c \
ctaocrypt/src/rsa.c \
ctaocrypt/src/sha.c \
ctaocrypt/src/aes.c \
ctaocrypt/src/sha256.c \
ctaocrypt/src/dh.c \
ctaocrypt/src/dsa.c \
ctaocrypt/src/arc4.c \
ctaocrypt/src/rabbit.c \
ctaocrypt/src/pwdbased.c \
ctaocrypt/src/logging.c \
ctaocrypt/src/memory.c
src_libcyassl_la_LDFLAGS = ${AM_LDFLAGS} -no-undefined -version-info ${CYASSL_LIBRARY_VERSION}
src_libcyassl_la_LIBADD = $(LIBM)
src_libcyassl_la_CFLAGS = -DBUILDING_CYASSL $(AM_CFLAGS)
src_libcyassl_la_CPPFLAGS = -DBUILDING_CYASSL $(AM_CPPFLAGS)
if BUILD_AESNI
src_libcyassl_la_SOURCES += ctaocrypt/src/aes_asm.s
endif
if BUILD_MD2
src_libcyassl_la_SOURCES += ctaocrypt/src/md2.c
endif
if BUILD_RIPEMD
src_libcyassl_la_SOURCES += ctaocrypt/src/ripemd.c
endif
if BUILD_SHA512
src_libcyassl_la_SOURCES += ctaocrypt/src/sha512.c
endif
if BUILD_SNIFFER
src_libcyassl_la_SOURCES += src/sniffer.c
endif
if BUILD_HC128
src_libcyassl_la_SOURCES += ctaocrypt/src/hc128.c
endif
if BUILD_NOINLINE
src_libcyassl_la_SOURCES += ctaocrypt/src/misc.c
endif
if BUILD_FASTMATH
src_libcyassl_la_SOURCES += ctaocrypt/src/tfm.c
else
src_libcyassl_la_SOURCES += ctaocrypt/src/integer.c
endif
if BUILD_ECC
src_libcyassl_la_SOURCES += ctaocrypt/src/ecc.c
endif
if BUILD_OCSP
src_libcyassl_la_SOURCES += src/ocsp.c
endif
if BUILD_CRL
src_libcyassl_la_SOURCES += src/crl.c
endif
if BUILD_CRL_MONITOR
src_libcyassl_la_CFLAGS += $(PTHREAD_CFLAGS)
src_libcyassl_la_LIBADD += $(PTHREAD_LIBS)
endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,273 @@
/* io.c
*
* Copyright (C) 2006-2012 Sawtooth Consulting Ltd.
*
* This file is part of CyaSSL.
*
* CyaSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* CyaSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef _WIN32_WCE
/* On WinCE winsock2.h must be included before windows.h for socket stuff */
#include <winsock2.h>
#endif
#include <cyassl/internal.h>
/* if user writes own I/O callbacks they can define CYASSL_USER_IO to remove
automatic setting of default I/O functions EmbedSend() and EmbedReceive()
but they'll still need SetCallback xxx() at end of file
*/
#ifndef CYASSL_USER_IO
#ifdef HAVE_LIBZ
#include "zlib.h"
#endif
#ifndef USE_WINDOWS_API
#ifdef CYASSL_LWIP
/* lwIP needs to be configured to use sockets API in this mode */
/* LWIP_SOCKET 1 && LWIP_COMPAT_SOCKETS 1 in lwip/opt.h or in build */
#define LWIP_PROVIDE_ERRNO 1
#include "sockets.h"
#else
#include <sys/types.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#if !(defined(DEVKITPRO) || defined(THREADX))
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#ifdef __PPU
#include <netex/errno.h>
#else
#include <sys/ioctl.h>
#endif
#endif
#ifdef THREADX
#include <socket.h>
#endif
#endif
#endif /* USE_WINDOWS_API */
#ifdef __sun
#include <sys/filio.h>
#endif
#ifdef USE_WINDOWS_API
/* no epipe yet */
#ifndef WSAEPIPE
#define WSAEPIPE -12345
#endif
#define SOCKET_EWOULDBLOCK WSAEWOULDBLOCK
#define SOCKET_EAGAIN WSAEWOULDBLOCK
#define SOCKET_ECONNRESET WSAECONNRESET
#define SOCKET_EINTR WSAEINTR
#define SOCKET_EPIPE WSAEPIPE
#elif defined(__PPU)
#define SOCKET_EWOULDBLOCK SYS_NET_EWOULDBLOCK
#define SOCKET_EAGAIN SYS_NET_EAGAIN
#define SOCKET_ECONNRESET SYS_NET_ECONNRESET
#define SOCKET_EINTR SYS_NET_EINTR
#define SOCKET_EPIPE SYS_NET_EPIPE
#else
#define SOCKET_EWOULDBLOCK EWOULDBLOCK
#define SOCKET_EAGAIN EAGAIN
#define SOCKET_ECONNRESET ECONNRESET
#define SOCKET_EINTR EINTR
#define SOCKET_EPIPE EPIPE
#endif /* USE_WINDOWS_API */
#ifdef DEVKITPRO
/* from network.h */
int net_send(int, const void*, int, unsigned int);
int net_recv(int, void*, int, unsigned int);
#define SEND_FUNCTION net_send
#define RECV_FUNCTION net_recv
#else
#define SEND_FUNCTION send
#define RECV_FUNCTION recv
#endif
static INLINE int LastError(void)
{
#ifdef USE_WINDOWS_API
return WSAGetLastError();
#else
return errno;
#endif
}
/* The receive embedded callback
* return : nb bytes read, or error
*/
int EmbedReceive(char *buf, int sz, void *ctx)
{
int recvd;
int err;
int sd = *(int*)ctx;
recvd = RECV_FUNCTION(sd, (char *)buf, sz, 0);
if (recvd < 0) {
err = LastError();
CYASSL_MSG("Embed Receive error");
if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) {
CYASSL_MSG(" Would block");
return IO_ERR_WANT_READ;
}
else if (err == SOCKET_ECONNRESET) {
CYASSL_MSG(" Connection reset");
return IO_ERR_CONN_RST;
}
else if (err == SOCKET_EINTR) {
CYASSL_MSG(" Socket interrupted");
return IO_ERR_ISR;
}
else {
CYASSL_MSG(" General error");
return IO_ERR_GENERAL;
}
}
else if (recvd == 0) {
CYASSL_MSG("Embed receive connection closed");
return IO_ERR_CONN_CLOSE;
}
return recvd;
}
/* The send embedded callback
* return : nb bytes sent, or error
*/
int EmbedSend(char *buf, int sz, void *ctx)
{
int sd = *(int*)ctx;
int sent;
int len = sz;
int err;
sent = SEND_FUNCTION(sd, &buf[sz - len], len, 0);
if (sent < 0) {
err = LastError();
CYASSL_MSG("Embed Send error");
if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) {
CYASSL_MSG(" Would Block");
return IO_ERR_WANT_WRITE;
}
else if (err == SOCKET_ECONNRESET) {
CYASSL_MSG(" Connection reset");
return IO_ERR_CONN_RST;
}
else if (err == SOCKET_EINTR) {
CYASSL_MSG(" Socket interrupted");
return IO_ERR_ISR;
}
else if (err == SOCKET_EPIPE) {
CYASSL_MSG(" Socket EPIPE");
return IO_ERR_CONN_CLOSE;
}
else {
CYASSL_MSG(" General error");
return IO_ERR_GENERAL;
}
}
return sent;
}
#ifdef CYASSL_DTLS
#include <cyassl/ctaocrypt/sha.h>
/* The DTLS Generate Cookie callback
* return : number of bytes copied into buf, or error
*/
int EmbedGenerateCookie(byte *buf, int sz, void *ctx)
{
CYASSL* ssl = (CYASSL*)ctx;
int sd = ssl->wfd;
struct sockaddr_storage peer;
socklen_t peerSz = sizeof(peer);
byte cookieSrc[sizeof(struct in6_addr) + sizeof(int)];
int cookieSrcSz = 0;
Sha sha;
getpeername(sd, (struct sockaddr*)&peer, &peerSz);
if (peer.ss_family == AF_INET) {
struct sockaddr_in *s = (struct sockaddr_in*)&peer;
cookieSrcSz = sizeof(struct in_addr) + sizeof(s->sin_port);
XMEMCPY(cookieSrc, &s->sin_port, sizeof(s->sin_port));
XMEMCPY(cookieSrc + sizeof(s->sin_port),
&s->sin_addr, sizeof(struct in_addr));
}
else if (peer.ss_family == AF_INET6) {
struct sockaddr_in6 *s = (struct sockaddr_in6*)&peer;
cookieSrcSz = sizeof(struct in6_addr) + sizeof(s->sin6_port);
XMEMCPY(cookieSrc, &s->sin6_port, sizeof(s->sin6_port));
XMEMCPY(cookieSrc + sizeof(s->sin6_port),
&s->sin6_addr, sizeof(struct in6_addr));
}
InitSha(&sha);
ShaUpdate(&sha, cookieSrc, cookieSrcSz);
ShaFinal(&sha, buf);
return SHA_DIGEST_SIZE;
}
#endif /* CYASSL_DTLS */
#endif /* CYASSL_USER_IO */
CYASSL_API void CyaSSL_SetIORecv(CYASSL_CTX *ctx, CallbackIORecv CBIORecv)
{
ctx->CBIORecv = CBIORecv;
}
CYASSL_API void CyaSSL_SetIOSend(CYASSL_CTX *ctx, CallbackIOSend CBIOSend)
{
ctx->CBIOSend = CBIOSend;
}
CYASSL_API void CyaSSL_SetIOReadCtx(CYASSL* ssl, void *rctx)
{
ssl->IOCB_ReadCtx = rctx;
}
CYASSL_API void CyaSSL_SetIOWriteCtx(CYASSL* ssl, void *wctx)
{
ssl->IOCB_WriteCtx = wctx;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,530 @@
/* ocsp.c
*
* Copyright (C) 2006-2012 Sawtooth Consulting Ltd.
*
* This file is part of CyaSSL.
*
* CyaSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* CyaSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_OCSP
#include <cyassl/error.h>
#include <cyassl/ocsp.h>
#include <cyassl/internal.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
CYASSL_API int ocsp_test(unsigned char* buf, int sz);
#define CYASSL_OCSP_ENABLE 0x0001 /* Enable OCSP lookups */
#define CYASSL_OCSP_URL_OVERRIDE 0x0002 /* Use the override URL instead of URL
* in certificate */
typedef struct sockaddr_in SOCKADDR_IN_T;
#define AF_INET_V AF_INET
#define SOCKET_T unsigned int
int CyaSSL_OCSP_Init(CYASSL_OCSP* ocsp)
{
if (ocsp != NULL) {
XMEMSET(ocsp, 0, sizeof(*ocsp));
return 0;
}
return -1;
}
static void FreeOCSP_Entry(OCSP_Entry* ocspe)
{
CertStatus* tmp = ocspe->status;
CYASSL_ENTER("FreeOCSP_Entry");
while (tmp) {
CertStatus* next = tmp->next;
XFREE(tmp, NULL, DYNAMIC_TYPE_OCSP_STATUS);
tmp = next;
}
}
void CyaSSL_OCSP_Cleanup(CYASSL_OCSP* ocsp)
{
OCSP_Entry* tmp = ocsp->ocspList;
ocsp->enabled = 0;
while (tmp) {
OCSP_Entry* next = tmp->next;
FreeOCSP_Entry(tmp);
XFREE(tmp, NULL, DYNAMIC_TYPE_OCSP_ENTRY);
tmp = next;
}
}
static int decode_url(const char* url, int urlSz,
char* outName, char* outPath, int* outPort)
{
if (outName != NULL && outPath != NULL && outPort != NULL)
{
if (url == NULL || urlSz == 0)
{
*outName = 0;
*outPath = 0;
*outPort = 0;
}
else
{
int i, cur;
/* need to break the url down into scheme, address, and port */
/* "http://example.com:8080/" */
if (XSTRNCMP(url, "http://", 7) == 0) {
cur = 7;
} else cur = 0;
i = 0;
while (url[cur] != 0 && url[cur] != ':' && url[cur] != '/') {
outName[i++] = url[cur++];
}
outName[i] = 0;
/* Need to pick out the path after the domain name */
if (cur < urlSz && url[cur] == ':') {
char port[6];
int j;
i = 0;
cur++;
while (cur < urlSz && url[cur] != 0 && url[cur] != '/' &&
i < 6) {
port[i++] = url[cur++];
}
*outPort = 0;
for (j = 0; j < i; j++) {
if (port[j] < '0' || port[j] > '9') return -1;
*outPort = (*outPort * 10) + (port[j] - '0');
}
}
else
*outPort = 80;
if (cur < urlSz && url[cur] == '/') {
i = 0;
while (cur < urlSz && url[cur] != 0 && i < 80) {
outPath[i++] = url[cur++];
}
outPath[i] = 0;
}
else {
outPath[0] = '/';
outPath[1] = 0;
}
}
}
return 0;
}
int CyaSSL_OCSP_set_override_url(CYASSL_OCSP* ocsp, const char* url)
{
if (ocsp != NULL) {
int urlSz = strlen(url);
decode_url(url, urlSz,
ocsp->overrideName, ocsp->overridePath, &ocsp->overridePort);
return 1;
}
return 0;
}
static INLINE void tcp_socket(SOCKET_T* sockfd, SOCKADDR_IN_T* addr,
const char* peer, word16 port)
{
const char* host = peer;
/* peer could be in human readable form */
if (peer != INADDR_ANY && isalpha(peer[0])) {
struct hostent* entry = gethostbyname(peer);
if (entry) {
struct sockaddr_in tmp;
memset(&tmp, 0, sizeof(struct sockaddr_in));
memcpy(&tmp.sin_addr.s_addr, entry->h_addr_list[0],
entry->h_length);
host = inet_ntoa(tmp.sin_addr);
}
else {
CYASSL_MSG("no entry for host");
}
}
*sockfd = socket(AF_INET_V, SOCK_STREAM, 0);
memset(addr, 0, sizeof(SOCKADDR_IN_T));
addr->sin_family = AF_INET_V;
addr->sin_port = htons(port);
if (host == INADDR_ANY)
addr->sin_addr.s_addr = INADDR_ANY;
else
addr->sin_addr.s_addr = inet_addr(host);
}
static INLINE void tcp_connect(SOCKET_T* sockfd, const char* ip, word16 port)
{
SOCKADDR_IN_T addr;
tcp_socket(sockfd, &addr, ip, port);
if (connect(*sockfd, (const struct sockaddr*)&addr, sizeof(addr)) != 0) {
CYASSL_MSG("tcp connect failed");
}
}
static int build_http_request(const char* domainName, const char* path,
int ocspReqSz, byte* buf, int bufSize)
{
return snprintf((char*)buf, bufSize,
"POST %s HTTP/1.1\r\n"
"Host: %s\r\n"
"Content-Length: %d\r\n"
"Content-Type: application/ocsp-request\r\n"
"\r\n",
path, domainName, ocspReqSz);
}
static int decode_http_response(byte* httpBuf, int httpBufSz, byte** dst)
{
int idx = 0;
int stop = 0;
int len = 0;
byte* contentType = NULL;
byte* contentLength = NULL;
char* buf = (char*)httpBuf; /* kludge so I'm not constantly casting */
if (strncasecmp(buf, "HTTP/1", 6) != 0)
return 0;
idx = 9; /* sets to the first byte after "HTTP/1.X ", which should be the
* HTTP result code */
if (strncasecmp(&buf[idx], "200 OK", 6) != 0)
return 0;
idx += 8;
while (idx < httpBufSz && !stop) {
if (buf[idx] == '\r' && buf[idx+1] == '\n') {
stop = 1;
idx += 2;
}
else {
if (contentType == NULL &&
strncasecmp(&buf[idx], "Content-Type:", 13) == 0) {
idx += 13;
if (buf[idx] == ' ') idx++;
if (strncasecmp(&buf[idx], "application/ocsp-response", 25) != 0)
return 0;
idx += 27;
} else if (contentLength == NULL &&
strncasecmp(&buf[idx], "Content-Length:", 15) == 0) {
idx += 15;
if (buf[idx] == ' ') idx++;
while (buf[idx] >= '0' && buf[idx] <= '9' && idx < httpBufSz) {
len = (len * 10) + (buf[idx] - '0');
idx++;
}
idx += 2; /* skip the crlf */
} else {
/* Advance idx past the next \r\n */
char* end = strstr(&buf[idx], "\r\n");
idx = end - buf + 2;
stop = 1;
}
}
}
if (len > 0) {
*dst = (byte*)XMALLOC(len, NULL, DYNAMIC_TYPE_IN_BUFFER);
XMEMCPY(*dst, httpBuf + idx, len);
}
return len;
}
static int InitOCSP_Entry(OCSP_Entry* ocspe, DecodedCert* cert)
{
CYASSL_ENTER("InitOCSP_Entry");
ocspe->next = NULL;
XMEMCPY(ocspe->issuerHash, cert->issuerHash, SHA_DIGEST_SIZE);
XMEMCPY(ocspe->issuerKeyHash, cert->issuerKeyHash, SHA_DIGEST_SIZE);
ocspe->status = NULL;
ocspe->totalStatus = 0;
return 0;
}
static OCSP_Entry* find_ocsp_entry(CYASSL_OCSP* ocsp, DecodedCert* cert)
{
OCSP_Entry* entry = ocsp->ocspList;
while (entry)
{
if (XMEMCMP(entry->issuerHash, cert->issuerHash, SHA_DIGEST_SIZE) == 0
&& XMEMCMP(entry->issuerKeyHash, cert->issuerKeyHash,
SHA_DIGEST_SIZE) == 0)
{
CYASSL_MSG("Found OCSP responder");
break;
}
else
{
entry = entry->next;
}
}
if (entry == NULL)
{
CYASSL_MSG("Add a new OCSP entry");
entry = (OCSP_Entry*)XMALLOC(sizeof(OCSP_Entry),
NULL, DYNAMIC_TYPE_OCSP_ENTRY);
if (entry != NULL)
{
InitOCSP_Entry(entry, cert);
entry->next = ocsp->ocspList;
ocsp->ocspList = entry;
}
}
return entry;
}
static CertStatus* find_cert_status(OCSP_Entry* ocspe, DecodedCert* cert)
{
CertStatus* stat = ocspe->status;
while (stat)
{
if(stat->serialSz == cert->serialSz &&
(XMEMCMP(stat->serial, cert->serial, cert->serialSz) == 0))
{
break;
}
else
{
stat = stat->next;
}
}
if (stat == NULL)
{
stat = (CertStatus*)XMALLOC(sizeof(CertStatus),
NULL, DYNAMIC_TYPE_OCSP_STATUS);
if (stat != NULL)
{
XMEMCPY(stat->serial, cert->serial, cert->serialSz);
stat->serialSz = cert->serialSz;
stat->status = -1;
stat->nextDate[0] = 0;
ocspe->totalStatus++;
stat->next = ocspe->status;
ocspe->status = stat;
}
}
return stat;
}
#define SCRATCH_BUFFER_SIZE 2048
static int http_ocsp_transaction(CYASSL_OCSP* ocsp, DecodedCert* cert,
byte* ocspReqBuf, int ocspReqSz, byte** ocspRespBuf)
{
SOCKET_T sfd = -1;
byte httpBuf[SCRATCH_BUFFER_SIZE];
int httpBufSz = SCRATCH_BUFFER_SIZE;
char domainName[80], path[80];
int port, ocspRespSz;
if (ocsp->useOverrideUrl || cert->extAuthInfo == NULL) {
if (ocsp->overrideName != NULL) {
XMEMCPY(domainName, ocsp->overrideName, 80);
XMEMCPY(path, ocsp->overridePath, 80);
port = ocsp->overridePort;
} else
return OCSP_NEED_URL;
} else {
if (!decode_url((const char*)cert->extAuthInfo, cert->extAuthInfoSz,
domainName, path, &port))
return OCSP_NEED_URL;
}
httpBufSz = build_http_request(domainName, path, ocspReqSz,
httpBuf, httpBufSz);
tcp_connect(&sfd, domainName, port);
if (sfd > 0) {
int written;
written = write(sfd, httpBuf, httpBufSz);
if (written == httpBufSz) {
written = write(sfd, ocspReqBuf, ocspReqSz);
if (written == ocspReqSz) {
httpBufSz = read(sfd, httpBuf, SCRATCH_BUFFER_SIZE);
if (httpBufSz > 0) {
ocspRespSz = decode_http_response(httpBuf, httpBufSz,
ocspRespBuf);
}
}
}
close(sfd);
if (ocspRespSz == 0) {
CYASSL_MSG("HTTP response was not OK, no OCSP response");
return OCSP_LOOKUP_FAIL;
}
} else {
CYASSL_MSG("OCSP Responder connection failed");
return OCSP_LOOKUP_FAIL;
}
return ocspRespSz;
}
static int xstat2err(int stat)
{
switch (stat) {
case CERT_GOOD:
return 0;
break;
case CERT_REVOKED:
return OCSP_CERT_REVOKED;
break;
default:
return OCSP_CERT_UNKNOWN;
break;
}
}
int CyaSSL_OCSP_Lookup_Cert(CYASSL_OCSP* ocsp, DecodedCert* cert)
{
byte ocspReqBuf[SCRATCH_BUFFER_SIZE];
int ocspReqSz = SCRATCH_BUFFER_SIZE;
byte* ocspRespBuf = NULL;
int ocspRespSz;
OcspRequest ocspRequest;
OcspResponse ocspResponse;
int result = 0;
OCSP_Entry* ocspe;
CertStatus* certStatus;
/* If OCSP lookups are disabled, return success. */
if (!ocsp->enabled) {
CYASSL_MSG("OCSP lookup disabled, assuming CERT_GOOD");
return 0;
}
ocspe = find_ocsp_entry(ocsp, cert);
if (ocspe == NULL) {
CYASSL_MSG("alloc OCSP entry failed");
return MEMORY_ERROR;
}
certStatus = find_cert_status(ocspe, cert);
if (certStatus == NULL)
{
CYASSL_MSG("alloc OCSP cert status failed");
return MEMORY_ERROR;
}
if (certStatus->status != -1)
{
if (!ValidateDate(certStatus->thisDate,
certStatus->thisDateFormat, BEFORE) ||
(certStatus->nextDate[0] == 0) ||
!ValidateDate(certStatus->nextDate,
certStatus->nextDateFormat, AFTER))
{
CYASSL_MSG("\tinvalid status date, looking up cert");
certStatus->status = -1;
}
else
{
CYASSL_MSG("\tusing cached status");
result = xstat2err(certStatus->status);
return result;
}
}
InitOcspRequest(&ocspRequest, cert, ocspReqBuf, ocspReqSz);
ocspReqSz = EncodeOcspRequest(&ocspRequest);
result = http_ocsp_transaction(ocsp, cert,
ocspReqBuf, ocspReqSz, &ocspRespBuf);
if (result < 0) return result;
/* If the transaction failed, return that result. */
InitOcspResponse(&ocspResponse, certStatus, ocspRespBuf, ocspRespSz);
OcspResponseDecode(&ocspResponse);
if (ocspResponse.responseStatus != OCSP_SUCCESSFUL) {
CYASSL_MSG("OCSP Responder failure");
result = OCSP_LOOKUP_FAIL;
} else {
if (CompareOcspReqResp(&ocspRequest, &ocspResponse) == 0)
{
result = xstat2err(ocspResponse.status->status);
}
else
{
CYASSL_MSG("OCSP Response incorrect for Request");
result = OCSP_LOOKUP_FAIL;
}
}
if (ocspReqBuf != NULL) {
XFREE(ocspRespBuf, NULL, DYNAMIC_TYPE_IN_BUFFER);
}
return result;
}
#endif /* HAVE_OCSP */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,531 @@
/* tls.c
*
* Copyright (C) 2006-2012 Sawtooth Consulting Ltd.
*
* This file is part of CyaSSL.
*
* CyaSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* CyaSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <cyassl/ssl.h>
#include <cyassl/internal.h>
#include <cyassl/error.h>
#include <cyassl/ctaocrypt/hmac.h>
#ifndef NO_TLS
#ifndef min
static INLINE word32 min(word32 a, word32 b)
{
return a > b ? b : a;
}
#endif /* min */
/* calculate XOR for TLSv1 PRF */
static INLINE void get_xor(byte *digest, word32 digLen, byte* md5, byte* sha)
{
word32 i;
for (i = 0; i < digLen; i++)
digest[i] = md5[i] ^ sha[i];
}
#ifdef CYASSL_SHA384
#define PHASH_MAX_DIGEST_SIZE SHA384_DIGEST_SIZE
#else
#define PHASH_MAX_DIGEST_SIZE SHA256_DIGEST_SIZE
#endif
/* compute p_hash for MD5, SHA-1, SHA-256, or SHA-384 for TLSv1 PRF */
static void p_hash(byte* result, word32 resLen, const byte* secret,
word32 secLen, const byte* seed, word32 seedLen, int hash)
{
word32 len = MD5_DIGEST_SIZE;
word32 times;
word32 lastLen;
word32 lastTime;
word32 i;
word32 idx = 0;
byte previous[PHASH_MAX_DIGEST_SIZE]; /* max size */
byte current[PHASH_MAX_DIGEST_SIZE]; /* max size */
Hmac hmac;
if (hash == md5_mac) {
hash = MD5;
}
else if (hash == sha_mac) {
len = SHA_DIGEST_SIZE;
hash = SHA;
} else if (hash == sha256_mac) {
len = SHA256_DIGEST_SIZE;
hash = SHA256;
}
#ifdef CYASSL_SHA384
else if (hash == sha384_mac)
{
len = SHA384_DIGEST_SIZE;
hash = SHA384;
}
#endif
times = resLen / len;
lastLen = resLen % len;
if (lastLen) times += 1;
lastTime = times - 1;
HmacSetKey(&hmac, hash, secret, secLen);
HmacUpdate(&hmac, seed, seedLen); /* A0 = seed */
HmacFinal(&hmac, previous); /* A1 */
for (i = 0; i < times; i++) {
HmacUpdate(&hmac, previous, len);
HmacUpdate(&hmac, seed, seedLen);
HmacFinal(&hmac, current);
if ( (i == lastTime) && lastLen)
XMEMCPY(&result[idx], current, min(lastLen, sizeof(current)));
else {
XMEMCPY(&result[idx], current, len);
idx += len;
HmacUpdate(&hmac, previous, len);
HmacFinal(&hmac, previous);
}
}
}
/* compute TLSv1 PRF (pseudo random function using HMAC) */
static void PRF(byte* digest, word32 digLen, const byte* secret, word32 secLen,
const byte* label, word32 labLen, const byte* seed, word32 seedLen,
int useAtLeastSha256, int hash_type)
{
word32 half = (secLen + 1) / 2;
byte md5_half[MAX_PRF_HALF]; /* half is real size */
byte sha_half[MAX_PRF_HALF]; /* half is real size */
byte labelSeed[MAX_PRF_LABSEED]; /* labLen + seedLen is real size */
byte md5_result[MAX_PRF_DIG]; /* digLen is real size */
byte sha_result[MAX_PRF_DIG]; /* digLen is real size */
if (half > MAX_PRF_HALF)
return;
if (labLen + seedLen > MAX_PRF_LABSEED)
return;
if (digLen > MAX_PRF_DIG)
return;
XMEMCPY(md5_half, secret, half);
XMEMCPY(sha_half, secret + half - secLen % 2, half);
XMEMCPY(labelSeed, label, labLen);
XMEMCPY(labelSeed + labLen, seed, seedLen);
if (useAtLeastSha256) {
/* If a cipher suite wants an algorithm better than sha256, it
* should use better. */
if (hash_type < sha256_mac)
hash_type = sha256_mac;
p_hash(digest, digLen, secret, secLen, labelSeed, labLen + seedLen,
hash_type);
return;
}
p_hash(md5_result, digLen, md5_half, half, labelSeed, labLen + seedLen,
md5_mac);
p_hash(sha_result, digLen, sha_half, half, labelSeed, labLen + seedLen,
sha_mac);
get_xor(digest, digLen, md5_result, sha_result);
}
#ifdef CYASSL_SHA384
#define HSHASH_SZ SHA384_DIGEST_SIZE
#else
#define HSHASH_SZ FINISHED_SZ
#endif
void BuildTlsFinished(CYASSL* ssl, Hashes* hashes, const byte* sender)
{
const byte* side;
byte handshake_hash[HSHASH_SZ];
word32 hashSz = FINISHED_SZ;
Md5Final(&ssl->hashMd5, handshake_hash);
ShaFinal(&ssl->hashSha, &handshake_hash[MD5_DIGEST_SIZE]);
if (IsAtLeastTLSv1_2(ssl)) {
#ifndef NO_SHA256
if (ssl->specs.mac_algorithm <= sha256_mac) {
Sha256Final(&ssl->hashSha256, handshake_hash);
hashSz = SHA256_DIGEST_SIZE;
}
#endif
#ifdef CYASSL_SHA384
if (ssl->specs.mac_algorithm == sha384_mac) {
Sha384Final(&ssl->hashSha384, handshake_hash);
hashSz = SHA384_DIGEST_SIZE;
}
#endif
}
if ( XSTRNCMP((const char*)sender, (const char*)client, SIZEOF_SENDER) == 0)
side = tls_client;
else
side = tls_server;
PRF(hashes->md5, TLS_FINISHED_SZ, ssl->arrays.masterSecret, SECRET_LEN,
side, FINISHED_LABEL_SZ, handshake_hash, hashSz, IsAtLeastTLSv1_2(ssl),
ssl->specs.mac_algorithm);
}
ProtocolVersion MakeTLSv1(void)
{
ProtocolVersion pv;
pv.major = SSLv3_MAJOR;
pv.minor = TLSv1_MINOR;
return pv;
}
ProtocolVersion MakeTLSv1_1(void)
{
ProtocolVersion pv;
pv.major = SSLv3_MAJOR;
pv.minor = TLSv1_1_MINOR;
return pv;
}
ProtocolVersion MakeTLSv1_2(void)
{
ProtocolVersion pv;
pv.major = SSLv3_MAJOR;
pv.minor = TLSv1_2_MINOR;
return pv;
}
static const byte master_label[MASTER_LABEL_SZ + 1] = "master secret";
static const byte key_label [KEY_LABEL_SZ + 1] = "key expansion";
int DeriveTlsKeys(CYASSL* ssl)
{
int length = 2 * ssl->specs.hash_size +
2 * ssl->specs.key_size +
2 * ssl->specs.iv_size;
byte seed[SEED_LEN];
byte key_data[MAX_PRF_DIG];
XMEMCPY(seed, ssl->arrays.serverRandom, RAN_LEN);
XMEMCPY(&seed[RAN_LEN], ssl->arrays.clientRandom, RAN_LEN);
PRF(key_data, length, ssl->arrays.masterSecret, SECRET_LEN, key_label,
KEY_LABEL_SZ, seed, SEED_LEN, IsAtLeastTLSv1_2(ssl),
ssl->specs.mac_algorithm);
return StoreKeys(ssl, key_data);
}
int MakeTlsMasterSecret(CYASSL* ssl)
{
byte seed[SEED_LEN];
XMEMCPY(seed, ssl->arrays.clientRandom, RAN_LEN);
XMEMCPY(&seed[RAN_LEN], ssl->arrays.serverRandom, RAN_LEN);
PRF(ssl->arrays.masterSecret, SECRET_LEN,
ssl->arrays.preMasterSecret, ssl->arrays.preMasterSz,
master_label, MASTER_LABEL_SZ,
seed, SEED_LEN, IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm);
#ifdef SHOW_SECRETS
{
int i;
printf("master secret: ");
for (i = 0; i < SECRET_LEN; i++)
printf("%02x", ssl->arrays.masterSecret[i]);
printf("\n");
}
#endif
return DeriveTlsKeys(ssl);
}
/*** next for static INLINE s copied from cyassl_int.c ***/
/* convert 16 bit integer to opaque */
INLINE static void c16toa(word16 u16, byte* c)
{
c[0] = (u16 >> 8) & 0xff;
c[1] = u16 & 0xff;
}
/* convert 32 bit integer to opaque */
static INLINE void c32toa(word32 u32, byte* c)
{
c[0] = (u32 >> 24) & 0xff;
c[1] = (u32 >> 16) & 0xff;
c[2] = (u32 >> 8) & 0xff;
c[3] = u32 & 0xff;
}
static INLINE word32 GetSEQIncrement(CYASSL* ssl, int verify)
{
#ifdef CYASSL_DTLS
if (ssl->options.dtls) {
if (verify)
return ssl->keys.dtls_peer_sequence_number; /* explicit from peer */
else
return ssl->keys.dtls_sequence_number - 1; /* already incremented */
}
#endif
if (verify)
return ssl->keys.peer_sequence_number++;
else
return ssl->keys.sequence_number++;
}
#ifdef CYASSL_DTLS
static INLINE word32 GetEpoch(CYASSL* ssl, int verify)
{
if (verify)
return ssl->keys.dtls_peer_epoch;
else
return ssl->keys.dtls_epoch;
}
#endif /* CYASSL_DTLS */
static INLINE const byte* GetMacSecret(CYASSL* ssl, int verify)
{
if ( (ssl->options.side == CLIENT_END && !verify) ||
(ssl->options.side == SERVER_END && verify) )
return ssl->keys.client_write_MAC_secret;
else
return ssl->keys.server_write_MAC_secret;
}
/*** end copy ***/
/* TLS type HMAC */
void TLS_hmac(CYASSL* ssl, byte* digest, const byte* in, word32 sz,
int content, int verify)
{
Hmac hmac;
byte seq[SEQ_SZ] = { 0x00, 0x00, 0x00, 0x00 };
byte length[LENGTH_SZ];
byte inner[ENUM_LEN + VERSION_SZ + LENGTH_SZ]; /* type + version +len */
int type;
c16toa((word16)sz, length);
#ifdef CYASSL_DTLS
if (ssl->options.dtls)
c16toa(GetEpoch(ssl, verify), seq);
#endif
c32toa(GetSEQIncrement(ssl, verify), &seq[sizeof(word32)]);
if (ssl->specs.mac_algorithm == md5_mac)
type = MD5;
else if (ssl->specs.mac_algorithm == sha_mac)
type = SHA;
else
type = SHA256;
HmacSetKey(&hmac, type, GetMacSecret(ssl, verify), ssl->specs.hash_size);
HmacUpdate(&hmac, seq, SEQ_SZ); /* seq_num */
inner[0] = (byte)content; /* type */
inner[ENUM_LEN] = ssl->version.major;
inner[ENUM_LEN + ENUM_LEN] = ssl->version.minor; /* version */
XMEMCPY(&inner[ENUM_LEN + VERSION_SZ], length, LENGTH_SZ); /* length */
HmacUpdate(&hmac, inner, sizeof(inner));
HmacUpdate(&hmac, in, sz); /* content */
HmacFinal(&hmac, digest);
}
#ifndef NO_CYASSL_CLIENT
CYASSL_METHOD* CyaTLSv1_client_method(void)
{
CYASSL_METHOD* method =
(CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
DYNAMIC_TYPE_METHOD);
if (method)
InitSSL_Method(method, MakeTLSv1());
return method;
}
CYASSL_METHOD* CyaTLSv1_1_client_method(void)
{
CYASSL_METHOD* method =
(CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
DYNAMIC_TYPE_METHOD);
if (method)
InitSSL_Method(method, MakeTLSv1_1());
return method;
}
#ifndef NO_SHA256 /* can't use without SHA256 */
CYASSL_METHOD* CyaTLSv1_2_client_method(void)
{
CYASSL_METHOD* method =
(CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
DYNAMIC_TYPE_METHOD);
if (method)
InitSSL_Method(method, MakeTLSv1_2());
return method;
}
#endif
CYASSL_METHOD* CyaSSLv23_client_method(void)
{
CYASSL_METHOD* method =
(CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
DYNAMIC_TYPE_METHOD);
if (method) {
#ifndef NO_SHA256 /* 1.2 requires SHA256 */
InitSSL_Method(method, MakeTLSv1_2());
#else
InitSSL_Method(method, MakeTLSv1_1());
#endif
method->downgrade = 1;
}
return method;
}
#endif /* NO_CYASSL_CLIENT */
#ifndef NO_CYASSL_SERVER
CYASSL_METHOD* CyaTLSv1_server_method(void)
{
CYASSL_METHOD* method =
(CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
DYNAMIC_TYPE_METHOD);
if (method) {
InitSSL_Method(method, MakeTLSv1());
method->side = SERVER_END;
}
return method;
}
CYASSL_METHOD* CyaTLSv1_1_server_method(void)
{
CYASSL_METHOD* method =
(CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
DYNAMIC_TYPE_METHOD);
if (method) {
InitSSL_Method(method, MakeTLSv1_1());
method->side = SERVER_END;
}
return method;
}
#ifndef NO_SHA256 /* can't use without SHA256 */
CYASSL_METHOD* CyaTLSv1_2_server_method(void)
{
CYASSL_METHOD* method =
(CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
DYNAMIC_TYPE_METHOD);
if (method) {
InitSSL_Method(method, MakeTLSv1_2());
method->side = SERVER_END;
}
return method;
}
#endif
CYASSL_METHOD* CyaSSLv23_server_method(void)
{
CYASSL_METHOD* method =
(CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
DYNAMIC_TYPE_METHOD);
if (method) {
#ifndef NO_SHA256 /* 1.2 requires SHA256 */
InitSSL_Method(method, MakeTLSv1_2());
#else
InitSSL_Method(method, MakeTLSv1_1());
#endif
method->side = SERVER_END;
method->downgrade = 1;
}
return method;
}
#endif /* NO_CYASSL_SERVER */
#else /* NO_TLS */
/* catch CyaSSL programming errors */
void BuildTlsFinished(CYASSL* ssl, Hashes* hashes, const byte* sender)
{
}
int DeriveTlsKeys(CYASSL* ssl)
{
return NOT_COMPILED_IN;
}
int MakeTlsMasterSecret(CYASSL* ssl)
{
return NOT_COMPILED_IN;
}
#endif /* NO_TLS */