Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
Nodemcu Firmware
Commits
e905c24d
Commit
e905c24d
authored
Oct 08, 2015
by
Johny Mattsson
Browse files
Removed unsused, now incompatible SSL code.
parent
21c4e110
Changes
42
Hide whitespace changes
Inline
Side-by-side
app/ssl/app/espconn_ssl.c
deleted
100644 → 0
View file @
21c4e110
/******************************************************************************
* Copyright 2013-2014 Espressif Systems (Wuxi)
*
* FileName: espconn_ssl.c
*
* Description: ssl encrypt interface
*
* Modification history:
* 2014/3/31, v1.0 create this file.
*******************************************************************************/
#include "lwip/netif.h"
#include "netif/etharp.h"
#include "lwip/tcp.h"
#include "lwip/ip.h"
#include "lwip/init.h"
#include "lwip/tcp_impl.h"
#include "ssl/ssl_os_port.h"
#include "ssl/app/espconn_ssl.h"
#include "ets_sys.h"
#include "os_type.h"
//#include "os.h"
#include "lwip/app/espconn.h"
struct
pbuf
*
psslpbuf
=
NULL
;
extern
espconn_msg
*
plink_active
;
static
err_t
espconn_ssl_crecv
(
void
*
arg
,
struct
tcp_pcb
*
pcb
,
struct
pbuf
*
p
,
err_t
err
);
static
err_t
espconn_ssl_srecv
(
void
*
arg
,
struct
tcp_pcb
*
pcb
,
struct
pbuf
*
p
,
err_t
err
);
static
void
espconn_ssl_sclose
(
void
*
arg
,
struct
tcp_pcb
*
pcb
);
static
void
espconn_ssl_cclose
(
void
*
arg
,
struct
tcp_pcb
*
pcb
);
/////////////////////////////common function///////////////////////////////////
/******************************************************************************
* FunctionName : display_session_id
* Description : Display what session id we have.
* Parameters :
* Returns :
*******************************************************************************/
static
void
ICACHE_FLASH_ATTR
display_session_id
(
SSL
*
ssl
)
{
int
i
;
const
uint8_t
*
session_id
=
ssl_get_session_id
(
ssl
);
int
sess_id_size
=
ssl_get_session_id_size
(
ssl
);
if
(
sess_id_size
>
0
)
{
ssl_printf
(
"-----BEGIN SSL SESSION PARAMETERS-----
\n
"
);
for
(
i
=
0
;
i
<
sess_id_size
;
i
++
)
{
ssl_printf
(
"%02x"
,
session_id
[
i
]);
}
ssl_printf
(
"
\n
-----END SSL SESSION PARAMETERS-----
\n
"
);
//TTY_FLUSH();
}
}
/******************************************************************************
* FunctionName : display_cipher
* Description : Display what cipher we are using
* Parameters :
* Returns :
*******************************************************************************/
static
void
ICACHE_FLASH_ATTR
display_cipher
(
SSL
*
ssl
)
{
ssl_printf
(
"CIPHER is "
);
switch
(
ssl_get_cipher_id
(
ssl
))
{
case
SSL_AES128_SHA
:
ssl_printf
(
"AES128-SHA"
);
break
;
case
SSL_AES256_SHA
:
ssl_printf
(
"AES256-SHA"
);
break
;
case
SSL_RC4_128_SHA
:
ssl_printf
(
"RC4-SHA"
);
break
;
case
SSL_RC4_128_MD5
:
ssl_printf
(
"RC4-MD5"
);
break
;
default:
ssl_printf
(
"Unknown - %d"
,
ssl_get_cipher_id
(
ssl
));
break
;
}
ssl_printf
(
"
\n
"
);
//TTY_FLUSH();
}
/******************************************************************************
* FunctionName : espconn_ssl_reconnect
* Description : reconnect with host
* Parameters : arg -- Additional argument to pass to the callback function
* Returns : none
*******************************************************************************/
static
void
ICACHE_FLASH_ATTR
espconn_ssl_reconnect
(
void
*
arg
)
{
espconn_msg
*
pssl_recon
=
arg
;
struct
espconn
*
espconn
=
NULL
;
ssl_msg
*
pssl
=
NULL
;
sint8
ssl_reerr
=
0
;
if
(
pssl_recon
!=
NULL
)
{
espconn
=
pssl_recon
->
preverse
;
if
(
pssl_recon
->
pespconn
!=
NULL
){
if
(
espconn
!=
NULL
){
/*espconn_copy_partial(espconn, pssl_recon->pespconn);
if (pssl_recon->pespconn->proto.tcp != NULL){
os_free(pssl_recon->pespconn->proto.tcp);
pssl_recon->pespconn->proto.tcp = NULL;
}
os_free(pssl_recon->pespconn);
pssl_recon->pespconn = NULL;*/
espconn
=
pssl_recon
->
preverse
;
}
else
{
espconn
=
pssl_recon
->
pespconn
;
}
}
pssl
=
pssl_recon
->
pssl
;
ssl_reerr
=
pssl_recon
->
pcommon
.
err
;
if
(
pssl
!=
NULL
)
{
if
(
pssl
->
ssl
)
{
ssl_free
(
pssl
->
ssl
);
}
if
(
pssl
->
ssl_ctx
)
{
ssl_ctx_free
(
pssl
->
ssl_ctx
);
}
os_free
(
pssl
);
pssl
=
NULL
;
pssl_recon
->
pssl
=
pssl
;
}
os_free
(
pssl_recon
);
pssl_recon
=
NULL
;
if
(
espconn
->
proto
.
tcp
->
reconnect_callback
!=
NULL
)
{
espconn
->
proto
.
tcp
->
reconnect_callback
(
espconn
,
ssl_reerr
);
}
}
else
{
ssl_printf
(
"espconn_ssl_reconnect err
\n
"
);
}
}
/******************************************************************************
* FunctionName : espconn_ssl_dissuccessful
* Description : as
* Parameters :
* Returns :
*******************************************************************************/
static
void
ICACHE_FLASH_ATTR
espconn_ssl_dissuccessful
(
void
*
arg
)
{
espconn_msg
*
pdiscon
=
arg
;
struct
espconn
*
espconn
=
NULL
;
struct
tcp_pcb
*
pcb
=
NULL
;
ssl_msg
*
pssl
=
NULL
;
if
(
pdiscon
!=
NULL
)
{
espconn
=
pdiscon
->
preverse
;
if
(
pdiscon
->
pespconn
!=
NULL
){
if
(
espconn
!=
NULL
){
/*espconn_copy_partial(espconn, pdiscon->pespconn);
if (pdiscon->pespconn->proto.tcp != NULL){
os_free(pdiscon->pespconn->proto.tcp);
pdiscon->pespconn->proto.tcp = NULL;
}
os_free(pdiscon->pespconn);
pdiscon->pespconn = NULL;*/
espconn
=
pdiscon
->
preverse
;
}
else
{
espconn
=
pdiscon
->
pespconn
;
}
pcb
=
pdiscon
->
pcommon
.
pcb
;
tcp_arg
(
pcb
,
NULL
);
tcp_err
(
pcb
,
NULL
);
}
pssl
=
pdiscon
->
pssl
;
if
(
pssl
!=
NULL
)
{
if
(
pssl
->
ssl
)
{
ssl_free
(
pssl
->
ssl
);
}
if
(
pssl
->
ssl_ctx
)
{
ssl_ctx_free
(
pssl
->
ssl_ctx
);
}
os_free
(
pssl
);
pssl
=
NULL
;
pdiscon
->
pssl
=
pssl
;
}
os_free
(
pdiscon
);
pdiscon
=
NULL
;
if
(
espconn
->
proto
.
tcp
->
disconnect_callback
!=
NULL
)
{
espconn
->
proto
.
tcp
->
disconnect_callback
(
espconn
);
}
}
else
{
espconn_printf
(
"espconn_ssl_dissuccessful err
\n
"
);
}
}
/******************************************************************************
* FunctionName : espconn_ssl_write
* Description : sent data for client or server
* Parameters : void *arg -- client or server to send
* uint8* psent -- Data to send
* uint16 length -- Length of data to send
* Returns : none
*******************************************************************************/
void
ICACHE_FLASH_ATTR
espconn_ssl_sent
(
void
*
arg
,
uint8
*
psent
,
uint16
length
)
{
espconn_msg
*
pssl_sent
=
arg
;
struct
tcp_pcb
*
pcb
=
NULL
;
ssl_msg
*
pssl
=
NULL
;
u16_t
len
=
0
;
int
res
=
0
;
ssl_printf
(
"espconn_ssl_sent pcb %p psent %p length %d
\n
"
,
arg
,
psent
,
length
);
if
(
pssl_sent
==
NULL
||
psent
==
NULL
||
length
==
0
)
{
return
;
}
pcb
=
pssl_sent
->
pcommon
.
pcb
;
pssl
=
pssl_sent
->
pssl
;
if
(
RT_MAX_PLAIN_LENGTH
<
length
)
{
len
=
RT_MAX_PLAIN_LENGTH
;
}
else
{
len
=
length
;
}
if
(
pssl
!=
NULL
)
{
if
(
pssl
->
ssl
!=
NULL
)
{
pssl
->
ssl
->
SslClient_pcb
=
pcb
;
res
=
ssl_write
(
pssl
->
ssl
,
psent
,
len
);
pssl_sent
->
pcommon
.
ptrbuf
=
psent
+
len
;
pssl_sent
->
pcommon
.
cntr
=
length
-
len
;
}
}
}
/******************************************************************************
* FunctionName : espconn_sent_packet
* Description : sent data for client or server
* Parameters : void *arg -- client or server to send
* uint8* psent -- Data to send
* uint16 length -- Length of data to send
* Returns : none
*******************************************************************************/
void
ICACHE_FLASH_ATTR
espconn_sent_packet
(
struct
tcp_pcb
*
pcb
,
uint8
*
psent
,
uint16
length
)
{
err_t
err
=
0
;
u16_t
len
=
0
;
if
(
pcb
==
NULL
||
psent
==
NULL
||
length
==
0
)
{
return
;
}
if
(
tcp_sndbuf
(
pcb
)
<
length
)
{
len
=
tcp_sndbuf
(
pcb
);
}
else
{
len
=
length
;
}
if
(
len
>
(
2
*
pcb
->
mss
))
{
len
=
2
*
pcb
->
mss
;
}
do
{
err
=
tcp_write
(
pcb
,
psent
,
len
,
0
);
if
(
err
==
ERR_MEM
)
{
len
/=
2
;
}
}
while
(
err
==
ERR_MEM
&&
len
>
1
);
if
(
err
==
ERR_OK
)
{
err
=
tcp_output
(
pcb
);
}
}
////////////////////////////////client function////////////////////////////////
/******************************************************************************
* FunctionName : espconn_ssl_cclose_cb
* Description : as
* Parameters :
* Returns :
*******************************************************************************/
static
void
ICACHE_FLASH_ATTR
espconn_ssl_cclose_cb
(
void
*
arg
)
{
static
uint16
timecount
=
0
;
espconn_msg
*
pcclose_cb
=
arg
;
if
(
pcclose_cb
==
NULL
)
{
return
;
}
struct
tcp_pcb
*
pcb
=
pcclose_cb
->
pcommon
.
pcb
;
ssl_printf
(
"espconn_ssl_cclose_cb %d %d
\n
"
,
pcb
->
state
,
pcb
->
nrtx
);
if
(
pcb
->
state
==
TIME_WAIT
||
pcb
->
state
==
CLOSED
)
{
pcclose_cb
->
pespconn
->
state
=
ESPCONN_CLOSE
;
/*remove the node from the client's active connection list*/
espconn_list_delete
(
&
plink_active
,
pcclose_cb
);
espconn_ssl_dissuccessful
((
void
*
)
pcclose_cb
);
}
else
{
os_timer_arm
(
&
pcclose_cb
->
pcommon
.
ptimer
,
TCP_FAST_INTERVAL
,
0
);
}
}
/******************************************************************************
* FunctionName : espconn_sslclient_close
* Description : The connection shall be actively closed.
* Parameters : pcb -- Additional argument to pass to the callback function
* pcb -- the pcb to close
* Returns : none
*******************************************************************************/
static
void
ICACHE_FLASH_ATTR
espconn_ssl_cclose
(
void
*
arg
,
struct
tcp_pcb
*
pcb
)
{
espconn_msg
*
pcclose
=
arg
;
os_timer_disarm
(
&
pcclose
->
pcommon
.
ptimer
);
os_timer_setfn
(
&
pcclose
->
pcommon
.
ptimer
,
espconn_ssl_cclose_cb
,
pcclose
);
os_timer_arm
(
&
pcclose
->
pcommon
.
ptimer
,
TCP_FAST_INTERVAL
,
0
);
tcp_recv
(
pcb
,
NULL
);
pcclose
->
pcommon
.
err
=
tcp_close
(
pcb
);
ssl_printf
(
"espconn_ssl_cclose %d
\n
"
,
pcclose
->
pcommon
.
err
);
if
(
pcclose
->
pcommon
.
err
!=
ERR_OK
)
{
/* closing failed, try again later */
tcp_recv
(
pcb
,
espconn_ssl_crecv
);
}
else
{
tcp_sent
(
pcb
,
NULL
);
tcp_poll
(
pcb
,
NULL
,
0
);
}
}
/******************************************************************************
* FunctionName : espconn_sslclient_sent
* Description : Data has been sent and acknowledged by the remote host.
* This means that more data can be sent.
* Parameters : arg -- Additional argument to pass to the callback function
* pcb -- The connection pcb for which data has been acknowledged
* len -- The amount of bytes acknowledged
* Returns : ERR_OK: try to send some data by calling tcp_output
* ERR_ABRT: if you have called tcp_abort from within the function!
*******************************************************************************/
static
err_t
ICACHE_FLASH_ATTR
espconn_ssl_csent
(
void
*
arg
,
struct
tcp_pcb
*
pcb
,
u16_t
len
)
{
espconn_msg
*
psent
=
arg
;
ssl_msg
*
pssl
=
psent
->
pssl
;
psent
->
pcommon
.
pcb
=
pcb
;
if
(
pssl
->
quiet
==
true
)
{
int
pkt_size
=
pssl
->
ssl
->
bm_index
+
SSL_RECORD_SIZE
;
u16_t
max_len
=
2
*
pcb
->
mss
;
pssl
->
pkt_length
+=
len
;
ssl_printf
(
"espconn_ssl_csent %d %d %d
\n
"
,
len
,
pssl
->
pkt_length
,
pkt_size
);
if
(
pssl
->
pkt_length
==
pkt_size
){
pssl
->
ssl
->
bm_index
=
0
;
pssl
->
pkt_length
=
0
;
if
(
psent
->
pcommon
.
cntr
==
0
)
{
psent
->
pespconn
->
state
=
ESPCONN_CONNECT
;
if
(
psent
->
pespconn
->
sent_callback
!=
NULL
)
{
psent
->
pespconn
->
sent_callback
(
psent
->
pespconn
);
}
}
else
{
espconn_ssl_sent
(
psent
,
psent
->
pcommon
.
ptrbuf
,
psent
->
pcommon
.
cntr
);
}
}
else
{
if
(
len
==
max_len
){
espconn_sent_packet
(
pcb
,
&
pssl
->
ssl
->
bm_all_data
[
pssl
->
pkt_length
],
pkt_size
-
pssl
->
pkt_length
);
}
}
}
else
{
ssl_printf
(
"espconn_ssl_csent %p %p %d
\n
"
,
pcb
,
pssl
->
ssl
->
bm_all_data
,
len
);
}
return
ERR_OK
;
}
/******************************************************************************
* FunctionName : espconn_sslclient_recv
* Description : Data has been received on this pcb.
* Parameters : arg -- Additional argument to pass to the callback function
* pcb -- The connection pcb which received data
* p -- The received data (or NULL when the connection has been closed!)
* err -- An error code if there has been an error receiving
* Returns : ERR_ABRT: if you have called tcp_abort from within the function!
*******************************************************************************/
static
err_t
ICACHE_FLASH_ATTR
espconn_ssl_crecv
(
void
*
arg
,
struct
tcp_pcb
*
pcb
,
struct
pbuf
*
p
,
err_t
err
)
{
u16_t
ret
=
0
;
espconn_msg
*
precv
=
arg
;
ssl_msg
*
pssl
=
precv
->
pssl
;
ssl_printf
(
"espconn_ssl_crecv %d %p %p
\n
"
,
__LINE__
,
pssl
->
ssl
,
p
);
if
(
p
!=
NULL
)
{
tcp_recved
(
pcb
,
p
->
tot_len
);
if
(
pssl
->
ssl
==
NULL
)
{
pbuf_free
(
p
);
}
else
{
pssl
->
ssl
->
ssl_pbuf
=
p
;
if
(
ssl_handshake_status
(
pssl
->
ssl
)
!=
SSL_OK
)
{
ret
=
ssl_read
(
pssl
->
ssl
,
NULL
);
pbuf_free
(
p
);
if
(
ret
!=
SSL_OK
){
os_printf
(
"client handshake failed
\n
"
);
espconn_ssl_cclose
(
arg
,
pcb
);
}
}
if
(
ssl_handshake_status
(
pssl
->
ssl
)
==
SSL_OK
)
{
if
(
!
pssl
->
quiet
)
{
ssl_printf
(
"client handshake need size %d
\n
"
,
system_get_free_heap_size
());
const
char
*
common_name
=
ssl_get_cert_dn
(
pssl
->
ssl
,
SSL_X509_CERT_COMMON_NAME
);
if
(
common_name
)
{
ssl_printf
(
"Common Name:
\t\t\t
%s
\n
"
,
common_name
);
}
display_session_id
(
pssl
->
ssl
);
display_cipher
(
pssl
->
ssl
);
pssl
->
quiet
=
true
;
os_printf
(
"client handshake ok!
\n
"
);
REG_CLR_BIT
(
0x3ff00014
,
BIT
(
0
));
ets_update_cpu_frequency
(
80
);
precv
->
pespconn
->
state
=
ESPCONN_CONNECT
;
precv
->
pcommon
.
pcb
=
pcb
;
pbuf_free
(
p
);
if
(
precv
->
pespconn
->
proto
.
tcp
->
connect_callback
!=
NULL
)
{
precv
->
pespconn
->
proto
.
tcp
->
connect_callback
(
precv
->
pespconn
);
}
}
else
{
uint8_t
*
read_buf
=
NULL
;
ret
=
ssl_read
(
pssl
->
ssl
,
&
read_buf
);
precv
->
pespconn
->
state
=
ESPCONN_READ
;
precv
->
pcommon
.
pcb
=
pcb
;
pbuf_free
(
p
);
if
(
precv
->
pespconn
->
recv_callback
!=
NULL
&&
read_buf
!=
NULL
)
{
precv
->
pespconn
->
recv_callback
(
precv
->
pespconn
,
read_buf
,
ret
);
}
precv
->
pespconn
->
state
=
ESPCONN_CONNECT
;
}
}
}
}
if
(
err
==
ERR_OK
&&
p
==
NULL
)
{
espconn_ssl_cclose
(
precv
,
pcb
);
}
return
ERR_OK
;
}
/******************************************************************************
* FunctionName : espconn_client_err
* Description : The pcb had an error and is already deallocated.
* The argument might still be valid (if != NULL).
* Parameters : arg -- Additional argument to pass to the callback function
* err -- Error code to indicate why the pcb has been closed
* Returns : none
*******************************************************************************/
static
void
ICACHE_FLASH_ATTR
espconn_ssl_cerr
(
void
*
arg
,
err_t
err
)
{
espconn_msg
*
pssl_cerr
=
arg
;
struct
tcp_pcb
*
pcb
=
NULL
;
LWIP_UNUSED_ARG
(
err
);
if
(
pssl_cerr
!=
NULL
)
{
os_timer_disarm
(
&
pssl_cerr
->
pcommon
.
ptimer
);
pcb
=
pssl_cerr
->
pcommon
.
pcb
;
pssl_cerr
->
pespconn
->
state
=
ESPCONN_CLOSE
;
espconn_printf
(
"espconn_ssl_cerr %d %d %d
\n
"
,
pcb
->
state
,
pcb
->
nrtx
,
err
);
/*remove the node from the client's active connection list*/
espconn_list_delete
(
&
plink_active
,
pssl_cerr
);
if
(
err
==
ERR_ABRT
)
{
switch
(
pcb
->
state
)
{
case
SYN_SENT
:
if
(
pcb
->
nrtx
==
TCP_SYNMAXRTX
)
{
pssl_cerr
->
pcommon
.
err
=
ESPCONN_CONN
;
}
else
{
pssl_cerr
->
pcommon
.
err
=
err
;
}
break
;
case
ESTABLISHED
:
if
(
pcb
->
nrtx
==
TCP_MAXRTX
)
{
pssl_cerr
->
pcommon
.
err
=
ESPCONN_TIMEOUT
;
}
else
{
pssl_cerr
->
pcommon
.
err
=
err
;
}
break
;
case
FIN_WAIT_1
:
if
(
pcb
->
nrtx
==
TCP_MAXRTX
)
{
pssl_cerr
->
pcommon
.
err
=
ESPCONN_CLSD
;
}
else
{
pssl_cerr
->
pcommon
.
err
=
err
;
}
break
;
case
FIN_WAIT_2
:
pssl_cerr
->
pcommon
.
err
=
ESPCONN_CLSD
;
break
;
case
CLOSED
:
pssl_cerr
->
pcommon
.
err
=
ESPCONN_CONN
;
break
;
default
:
break
;
}
}
else
{
pssl_cerr
->
pcommon
.
err
=
err
;
}
os_timer_setfn
(
&
pssl_cerr
->
pcommon
.
ptimer
,
espconn_ssl_reconnect
,
pssl_cerr
);
os_timer_arm
(
&
pssl_cerr
->
pcommon
.
ptimer
,
10
,
0
);
}
}
#if 0
/******************************************************************************
* FunctionName : espconn_ssl_cpoll
* Description : The poll function is called every 3nd second.
* If there has been no data sent (which resets the retries) in 3 seconds, close.
* If the last portion of a file has not been sent in 3 seconds, close.
*
* This could be increased, but we don't want to waste resources for bad connections.
* Parameters : arg -- Additional argument to pass to the callback function
* pcb -- The connection pcb for which data has been acknowledged
* Returns : ERR_OK: try to send some data by calling tcp_output
* ERR_ABRT: if you have called tcp_abort from within the function!
*******************************************************************************/
static err_t ICACHE_FLASH_ATTR
espconn_ssl_cpoll(void *arg, struct tcp_pcb *pcb)
{
ssl_printf("espconn_ssl_cpoll %p %d\n", pcb, pcb->state);
struct espconn *espconn = arg;
if (arg == NULL) {
tcp_abandon(pcb, 0);
tcp_poll(pcb, NULL, 0);
return ERR_ABRT;
}
if (pcb ->state == ESTABLISHED) {
espconn->recv_check ++;
if (espconn ->recv_check == 0x05){
//tcp_poll(pcb, espconn_ssl_cpoll, 0);
espconn->recv_check = 0;
espconn_ssl_cclose(arg, pcb);
}
} else {
//tcp_poll(pcb, espconn_ssl_cpoll, 0);
espconn_ssl_cclose(arg, pcb);
}
return ERR_OK;
}
#endif
/******************************************************************************
* FunctionName : espconn_sslclient_connect
* Description : A new incoming connection has been connected.
* Parameters : arg -- Additional argument to pass to the callback function
* tpcb -- The connection pcb which is connected
* err -- An unused error code, always ERR_OK currently
* Returns : connection result
*******************************************************************************/
static
err_t
ICACHE_FLASH_ATTR
espconn_ssl_connect
(
void
*
arg
,
struct
tcp_pcb
*
tpcb
,
err_t
err
)
{
espconn_msg
*
pconnect
=
arg
;
ssl_msg
*
pssl
=
NULL
;
uint32_t
options
;
options
=
SSL_SERVER_VERIFY_LATER
|
SSL_DISPLAY_CERTS
|
SSL_NO_DEFAULT_KEY
;
ssl_printf
(
"espconn_ssl_connect %p %p %p %d
\n
"
,
tpcb
,
arg
,
pespconn
->
psecure
,
system_get_free_heap_size
());
//if (pespconn->psecure != NULL){
// return ERR_ISCONN;
//}
pconnect
->
pcommon
.
pcb
=
tpcb
;
pssl
=
(
ssl_msg
*
)
os_zalloc
(
sizeof
(
ssl_msg
));
pconnect
->
pssl
=
pssl
;
if
(
pssl
==
NULL
)
{
return
ERR_MEM
;
}
REG_SET_BIT
(
0x3ff00014
,
BIT
(
0
));
ets_update_cpu_frequency
(
160
);
os_printf
(
"client handshake start.
\n
"
);
pssl
->
quiet
=
false
;
pssl
->
ssl_ctx
=
ssl_ctx_new
(
options
,
SSL_DEFAULT_CLNT_SESS
);
if
(
pssl
->
ssl_ctx
==
NULL
)
{
return
ERR_MEM
;
}
ssl_printf
(
"espconn_ssl_client ssl_ctx %p
\n
"
,
pssl
->
ssl_ctx
);
pssl
->
ssl
=
SSLClient_new
(
pssl
->
ssl_ctx
,
tpcb
,
NULL
,
0
);
if
(
pssl
->
ssl
==
NULL
)
{
return
ERR_MEM
;
}
tcp_arg
(
tpcb
,
arg
);
tcp_sent
(
tpcb
,
espconn_ssl_csent
);
tcp_recv
(
tpcb
,
espconn_ssl_crecv
);
//tcp_poll(tpcb, espconn_ssl_cpoll, 6);
return
ERR_OK
;
}
/******************************************************************************
* FunctionName : espconn_ssl_disconnect
* Description : A new incoming connection has been disconnected.
* Parameters : espconn -- the espconn used to disconnect with host
* Returns : none
*******************************************************************************/
void
ICACHE_FLASH_ATTR
espconn_ssl_disconnect
(
espconn_msg
*
pdis
)
{
if
(
pdis
!=
NULL
)
{
if
(
pdis
->
preverse
==
NULL
)
espconn_ssl_cclose
(
pdis
,
pdis
->
pcommon
.
pcb
);
else
espconn_ssl_sclose
(
pdis
,
pdis
->
pcommon
.
pcb
);
}
else
{
ssl_printf
(
"espconn_ssl_disconnect err.
\n
"
);
}
}
/******************************************************************************
* FunctionName : espconn_ssl_client
* Description : Initialize the client: set up a connect PCB and bind it to
* the defined port
* Parameters : espconn -- the espconn used to build client
* Returns : none
*******************************************************************************/
sint8
ICACHE_FLASH_ATTR
espconn_ssl_client
(
struct
espconn
*
espconn
)
{
struct
tcp_pcb
*
pcb
;
struct
ip_addr
ipaddr
;
espconn_msg
*
pclient
=
NULL
;
pclient
=
plink_active
;
while
(
pclient
!=
NULL
){
if
(
pclient
->
pssl
!=
NULL
)
return
ESPCONN_ISCONN
;
pclient
=
pclient
->
pnext
;
}
pclient
=
(
espconn_msg
*
)
os_zalloc
(
sizeof
(
espconn_msg
));
if
(
pclient
==
NULL
){
return
ESPCONN_MEM
;
}
IP4_ADDR
(
&
ipaddr
,
espconn
->
proto
.
tcp
->
remote_ip
[
0
],
espconn
->
proto
.
tcp
->
remote_ip
[
1
],
espconn
->
proto
.
tcp
->
remote_ip
[
2
],
espconn
->
proto
.
tcp
->
remote_ip
[
3
]);
pcb
=
tcp_new
();
if
(
pcb
==
NULL
)
{
espconn
->
state
=
ESPCONN_NONE
;
os_free
(
pclient
);
pclient
=
NULL
;
return
ESPCONN_MEM
;
}
else
{
/*insert the node to the active connection list*/
espconn_list_creat
(
&
plink_active
,
pclient
);
tcp_arg
(
pcb
,
(
void
*
)
pclient
);
tcp_err
(
pcb
,
espconn_ssl_cerr
);
pclient
->
preverse
=
NULL
;
pclient
->
pespconn
=
espconn
;
pclient
->
pespconn
->
state
=
ESPCONN_WAIT
;
pclient
->
pcommon
.
pcb
=
pcb
;
tcp_bind
(
pcb
,
IP_ADDR_ANY
,
pclient
->
pespconn
->
proto
.
tcp
->
local_port
);
pclient
->
pcommon
.
err
=
tcp_connect
(
pcb
,
&
ipaddr
,
pclient
->
pespconn
->
proto
.
tcp
->
remote_port
,
espconn_ssl_connect
);
return
ESPCONN_OK
;
}
}
/////////////////////////////server's function/////////////////////////////////
/******************************************************************************
* FunctionName : espconn_ssl_sclose_cb
* Description : as
* Parameters :
* Returns :
*******************************************************************************/
static
void
ICACHE_FLASH_ATTR
espconn_ssl_sclose_cb
(
void
*
arg
)
{
static
uint16
timecount
=
0
;
espconn_msg
*
psclose_cb
=
arg
;
if
(
psclose_cb
==
NULL
)
{
return
;
}
struct
tcp_pcb
*
pcb
=
psclose_cb
->
pcommon
.
pcb
;
ssl_printf
(
"espconn_ssl_sclose_cb %d %d
\n
"
,
pcb
->
state
,
pcb
->
nrtx
);
if
(
pcb
->
state
==
CLOSED
||
pcb
->
state
==
TIME_WAIT
)
{
psclose_cb
->
pespconn
->
state
=
ESPCONN_CLOSE
;
psclose_cb
->
pespconn
->
link_cnt
--
;
/*remove the node from the server's active connection list*/
espconn_list_delete
(
&
plink_active
,
psclose_cb
);
espconn_ssl_dissuccessful
((
void
*
)
psclose_cb
);
}
else
{
os_timer_arm
(
&
psclose_cb
->
pcommon
.
ptimer
,
TCP_FAST_INTERVAL
,
0
);
}
}
/******************************************************************************
* FunctionName : espconn_sslclient_close
* Description : The connection shall be actively closed.
* Parameters : pcb -- Additional argument to pass to the callback function
* pcb -- the pcb to close
* Returns : none
*******************************************************************************/
static
void
ICACHE_FLASH_ATTR
espconn_ssl_sclose
(
void
*
arg
,
struct
tcp_pcb
*
pcb
)
{
espconn_msg
*
psclose
=
arg
;
os_timer_disarm
(
&
psclose
->
pcommon
.
ptimer
);
os_timer_setfn
(
&
psclose
->
pcommon
.
ptimer
,
espconn_ssl_sclose_cb
,
psclose
);
os_timer_arm
(
&
psclose
->
pcommon
.
ptimer
,
TCP_FAST_INTERVAL
,
0
);
tcp_recv
(
pcb
,
NULL
);
psclose
->
pcommon
.
err
=
tcp_close
(
pcb
);
if
(
psclose
->
pcommon
.
err
!=
ERR_OK
)
{
/* closing failed, try again later */
tcp_recv
(
pcb
,
espconn_ssl_srecv
);
}
else
{
tcp_sent
(
pcb
,
NULL
);
tcp_poll
(
pcb
,
NULL
,
0
);
}
}
/******************************************************************************
* FunctionName : espconn_sslclient_sent
* Description : Data has been sent and acknowledged by the remote host.
* This means that more data can be sent.
* Parameters : arg -- Additional argument to pass to the callback function
* pcb -- The connection pcb for which data has been acknowledged
* len -- The amount of bytes acknowledged
* Returns : ERR_OK: try to send some data by calling tcp_output
* ERR_ABRT: if you have called tcp_abort from within the function!
*******************************************************************************/
static
err_t
ICACHE_FLASH_ATTR
espconn_ssl_ssent
(
void
*
arg
,
struct
tcp_pcb
*
pcb
,
u16_t
len
)
{
espconn_msg
*
psent
=
arg
;
ssl_msg
*
pssl
=
psent
->
pssl
;
psent
->
pcommon
.
pcb
=
pcb
;
psent
->
pcommon
.
recv_check
=
0
;
if
(
ssl_handshake_status
(
pssl
->
ssl
)
==
SSL_OK
)
{
if
(
!
pssl
->
quiet
)
{
ssl_printf
(
"espconn_ssl_ssent %p %d
\n
"
,
pcb
,
system_get_free_heap_size
());
const
char
*
common_name
=
ssl_get_cert_dn
(
pssl
->
ssl
,
SSL_X509_CERT_COMMON_NAME
);
if
(
common_name
)
{
ssl_printf
(
"Common Name:
\t\t\t
%s
\n
"
,
common_name
);
}
display_session_id
(
pssl
->
ssl
);
display_cipher
(
pssl
->
ssl
);
pssl
->
quiet
=
true
;
os_printf
(
"server handshake ok!
\n
"
);
REG_CLR_BIT
(
0x3ff00014
,
BIT
(
0
));
ets_update_cpu_frequency
(
80
);
psent
->
pespconn
->
state
=
ESPCONN_CONNECT
;
if
(
psent
->
pespconn
->
proto
.
tcp
->
connect_callback
!=
NULL
)
{
psent
->
pespconn
->
proto
.
tcp
->
connect_callback
(
psent
->
pespconn
);
}
}
else
{
int
pkt_size
=
pssl
->
ssl
->
bm_index
+
SSL_RECORD_SIZE
;
u16_t
max_len
=
2
*
pcb
->
mss
;
pssl
->
pkt_length
+=
len
;
ssl_printf
(
"espconn_ssl_ssent %d %d %d
\n
"
,
len
,
pssl
->
pkt_length
,
pkt_size
);
if
(
pssl
->
pkt_length
==
pkt_size
){
pssl
->
ssl
->
bm_index
=
0
;
pssl
->
pkt_length
=
0
;
if
(
psent
->
pcommon
.
cntr
==
0
)
{
psent
->
pespconn
->
state
=
ESPCONN_CONNECT
;
if
(
psent
->
pespconn
->
sent_callback
!=
NULL
)
{
psent
->
pespconn
->
sent_callback
(
psent
->
pespconn
);
}
}
else
{
espconn_ssl_sent
(
psent
,
psent
->
pcommon
.
ptrbuf
,
psent
->
pcommon
.
cntr
);
}
}
else
{
if
(
len
==
max_len
){
espconn_sent_packet
(
pcb
,
&
pssl
->
ssl
->
bm_all_data
[
pssl
->
pkt_length
],
pkt_size
-
pssl
->
pkt_length
);
}
}
}
}
else
{
ssl_printf
(
"espconn_ssl_ssent %p %p %d
\n
"
,
pcb
,
pssl
->
ssl
->
bm_all_data
,
len
);
}
return
ERR_OK
;
}
/******************************************************************************
* FunctionName : espconn_sslclient_recv
* Description : Data has been received on this pcb.
* Parameters : arg -- Additional argument to pass to the callback function
* pcb -- The connection pcb which received data
* p -- The received data (or NULL when the connection has been closed!)
* err -- An error code if there has been an error receiving
* Returns : ERR_ABRT: if you have called tcp_abort from within the function!
*******************************************************************************/
static
err_t
ICACHE_FLASH_ATTR
espconn_ssl_srecv
(
void
*
arg
,
struct
tcp_pcb
*
pcb
,
struct
pbuf
*
p
,
err_t
err
)
{
u16_t
ret
=
0
;
espconn_msg
*
precv
=
arg
;
ssl_msg
*
pssl
=
precv
->
pssl
;
ssl_printf
(
"espconn_ssl_srecv %d %p %p
\n
"
,
__LINE__
,
pcb
,
p
);
if
(
p
!=
NULL
)
{
tcp_recved
(
pcb
,
p
->
tot_len
);
precv
->
pcommon
.
recv_check
=
0
;
if
(
pssl
->
ssl
==
NULL
)
{
pbuf_free
(
p
);
}
else
{
pssl
->
ssl
->
ssl_pbuf
=
p
;
if
(
ssl_handshake_status
(
pssl
->
ssl
)
!=
SSL_OK
)
{
ret
=
ssl_read
(
pssl
->
ssl
,
NULL
);
pbuf_free
(
p
);
if
(
ret
!=
SSL_OK
){
os_printf
(
"server handshake failed.
\n
"
);
espconn_ssl_sclose
(
arg
,
pcb
);
}
}
else
{
uint8_t
*
read_buf
=
NULL
;
ret
=
ssl_read
(
pssl
->
ssl
,
&
read_buf
);
precv
->
pespconn
->
state
=
ESPCONN_READ
;
precv
->
pcommon
.
pcb
=
pcb
;
pbuf_free
(
p
);
if
(
precv
->
pespconn
->
recv_callback
!=
NULL
&&
read_buf
!=
NULL
)
{
precv
->
pespconn
->
recv_callback
(
precv
->
pespconn
,
read_buf
,
ret
);
}
precv
->
pespconn
->
state
=
ESPCONN_CONNECT
;
}
}
}
if
(
err
==
ERR_OK
&&
p
==
NULL
)
{
espconn_ssl_sclose
(
precv
,
pcb
);
}
return
ERR_OK
;
}
/******************************************************************************
* FunctionName : espconn_server_poll
* Description : The poll function is called every 3nd second.
* If there has been no data sent (which resets the retries) in 3 seconds, close.
* If the last portion of a file has not been sent in 3 seconds, close.
*
* This could be increased, but we don't want to waste resources for bad connections.
* Parameters : arg -- Additional argument to pass to the callback function
* pcb -- The connection pcb for which data has been acknowledged
* Returns : ERR_OK: try to send some data by calling tcp_output
* ERR_ABRT: if you have called tcp_abort from within the function!
*******************************************************************************/
static
err_t
ICACHE_FLASH_ATTR
espconn_ssl_spoll
(
void
*
arg
,
struct
tcp_pcb
*
pcb
)
{
ssl_printf
(
"espconn_ssl_spoll %p %d
\n
"
,
pcb
,
pcb
->
state
);
espconn_msg
*
pspoll
=
arg
;
if
(
arg
==
NULL
)
{
tcp_abandon
(
pcb
,
0
);
tcp_poll
(
pcb
,
NULL
,
0
);
return
ERR_ABRT
;
}
if
(
pcb
->
state
==
ESTABLISHED
)
{
pspoll
->
pcommon
.
recv_check
++
;
if
(
pspoll
->
pcommon
.
recv_check
==
pspoll
->
pcommon
.
timeout
){
tcp_poll
(
pcb
,
NULL
,
0
);
pspoll
->
pcommon
.
recv_check
=
0
;
espconn_ssl_sclose
(
arg
,
pcb
);
}
}
else
{
tcp_poll
(
pcb
,
NULL
,
0
);
espconn_ssl_sclose
(
arg
,
pcb
);
}
return
ERR_OK
;
}
/******************************************************************************
* FunctionName : esponn_server_err
* Description : The pcb had an error and is already deallocated.
* The argument might still be valid (if != NULL).
* Parameters : arg -- Additional argument to pass to the callback function
* err -- Error code to indicate why the pcb has been closed
* Returns : none
*******************************************************************************/
static
void
ICACHE_FLASH_ATTR
espconn_ssl_serr
(
void
*
arg
,
err_t
err
)
{
espconn_msg
*
pserr
=
arg
;
struct
tcp_pcb
*
pcb
=
NULL
;
LWIP_UNUSED_ARG
(
err
);
if
(
pserr
!=
NULL
)
{
os_timer_disarm
(
&
pserr
->
pcommon
.
ptimer
);
pcb
=
pserr
->
pcommon
.
pcb
;
pserr
->
pespconn
->
state
=
ESPCONN_CLOSE
;
/*remove the node from the server's active connection list*/
espconn_list_delete
(
&
plink_active
,
pserr
);
if
(
err
==
ERR_ABRT
)
{
switch
(
pcb
->
state
)
{
case
SYN_RCVD
:
if
(
pcb
->
nrtx
==
TCP_SYNMAXRTX
)
{
pserr
->
pcommon
.
err
=
ESPCONN_CONN
;
}
else
{
pserr
->
pcommon
.
err
=
err
;
}
break
;
case
ESTABLISHED
:
if
(
pcb
->
nrtx
==
TCP_MAXRTX
)
{
pserr
->
pcommon
.
err
=
ESPCONN_TIMEOUT
;
}
else
{
pserr
->
pcommon
.
err
=
err
;
}
break
;
case
CLOSE_WAIT
:
if
(
pcb
->
nrtx
==
TCP_MAXRTX
)
{
pserr
->
pcommon
.
err
=
ESPCONN_CLSD
;
}
else
{
pserr
->
pcommon
.
err
=
err
;
}
break
;
case
LAST_ACK
:
pserr
->
pcommon
.
err
=
ESPCONN_CLSD
;
break
;
case
CLOSED
:
pserr
->
pcommon
.
err
=
ESPCONN_CONN
;
break
;
default
:
break
;
}
}
else
{
pserr
->
pcommon
.
err
=
err
;
}
os_timer_setfn
(
&
pserr
->
pcommon
.
ptimer
,
espconn_ssl_reconnect
,
pserr
);
os_timer_arm
(
&
pserr
->
pcommon
.
ptimer
,
10
,
0
);
}
}
/******************************************************************************
* FunctionName : espconn_tcp_accept
* Description : A new incoming connection has been accepted.
* Parameters : arg -- Additional argument to pass to the callback function
* pcb -- The connection pcb which is accepted
* err -- An unused error code, always ERR_OK currently
* Returns : acception result
*******************************************************************************/
static
err_t
ICACHE_FLASH_ATTR
espconn_ssl_accept
(
void
*
arg
,
struct
tcp_pcb
*
pcb
,
err_t
err
)
{
struct
espconn
*
espconn
=
arg
;
ssl_msg
*
pssl
=
NULL
;
espconn_msg
*
paccept
=
NULL
;
remot_info
*
pinfo
=
NULL
;
ssl_printf
(
"espconn_ssl_accept %p %p %p %d
\n
"
,
pcb
,
arg
,
espconn
->
psecure
,
system_get_free_heap_size
());
LWIP_UNUSED_ARG
(
err
);
paccept
=
(
espconn_msg
*
)
os_zalloc
(
sizeof
(
espconn_msg
));
tcp_arg
(
pcb
,
paccept
);
tcp_err
(
pcb
,
espconn_ssl_serr
);
if
(
paccept
==
NULL
)
return
ERR_MEM
;
/*insert the node to the active connection list*/
espconn_list_creat
(
&
plink_active
,
paccept
);
paccept
->
preverse
=
espconn
;
paccept
->
pespconn
=
espconn
;
paccept
->
pcommon
.
timeout
=
0x0a
;
paccept
->
pcommon
.
pcb
=
pcb
;
paccept
->
pcommon
.
remote_port
=
pcb
->
remote_port
;
paccept
->
pcommon
.
remote_ip
[
0
]
=
ip4_addr1_16
(
&
pcb
->
remote_ip
);
paccept
->
pcommon
.
remote_ip
[
1
]
=
ip4_addr2_16
(
&
pcb
->
remote_ip
);
paccept
->
pcommon
.
remote_ip
[
2
]
=
ip4_addr3_16
(
&
pcb
->
remote_ip
);
paccept
->
pcommon
.
remote_ip
[
3
]
=
ip4_addr4_16
(
&
pcb
->
remote_ip
);
os_memcpy
(
espconn
->
proto
.
tcp
->
remote_ip
,
paccept
->
pcommon
.
remote_ip
,
4
);
espconn
->
proto
.
tcp
->
remote_port
=
pcb
->
remote_port
;
espconn_get_connection_info
(
espconn
,
&
pinfo
,
ESPCONN_SSL
);
if
(
espconn
->
link_cnt
==
0x01
)
return
ERR_ISCONN
;
pssl
=
(
ssl_msg
*
)
os_zalloc
(
sizeof
(
ssl_msg
));
paccept
->
pssl
=
pssl
;
if
(
pssl
==
NULL
)
{
return
ERR_MEM
;
}
REG_SET_BIT
(
0x3ff00014
,
BIT
(
0
));
ets_update_cpu_frequency
(
160
);
os_printf
(
"server handshake start.
\n
"
);
pssl
->
quiet
=
false
;
pssl
->
ssl_ctx
=
ssl_ctx_new
(
SSL_DISPLAY_CERTS
,
SSL_DEFAULT_SVR_SESS
);
if
(
pssl
->
ssl_ctx
==
NULL
)
{
ssl_printf
(
"Error: Server context is invalid
\n
"
);
return
ERR_MEM
;
}
ssl_printf
(
"Server context %p
\n
"
,
pssl
->
ssl_ctx
);
pssl
->
ssl
=
sslserver_new
(
pssl
->
ssl_ctx
,
pcb
);
if
(
pssl
->
ssl
==
NULL
)
{
ssl_printf
(
"Error: Server ssl connection is invalid
\n
"
);
return
ERR_MEM
;
}
tcp_sent
(
pcb
,
espconn_ssl_ssent
);
tcp_recv
(
pcb
,
espconn_ssl_srecv
);
tcp_poll
(
pcb
,
espconn_ssl_spoll
,
2
);
return
ERR_OK
;
}
/******************************************************************************
* FunctionName : espconn_ssl_server
* Description : as
* Parameters :
* Returns :
*******************************************************************************/
sint8
ICACHE_FLASH_ATTR
espconn_ssl_server
(
struct
espconn
*
espconn
)
{
struct
tcp_pcb
*
pcb
;
pcb
=
tcp_new
();
if
(
pcb
==
NULL
)
{
espconn
->
state
=
ESPCONN_NONE
;
return
ESPCONN_MEM
;
}
else
{
tcp_bind
(
pcb
,
IP_ADDR_ANY
,
espconn
->
proto
.
tcp
->
local_port
);
pcb
=
tcp_listen
(
pcb
);
if
(
pcb
!=
NULL
)
{
espconn
->
state
=
ESPCONN_LISTEN
;
tcp_arg
(
pcb
,
(
void
*
)
espconn
);
tcp_accept
(
pcb
,
espconn_ssl_accept
);
return
ESPCONN_OK
;
}
else
{
espconn
->
state
=
ESPCONN_NONE
;
return
ESPCONN_MEM
;
}
}
}
app/ssl/crypto/Makefile
deleted
100644 → 0
View file @
21c4e110
#############################################################
# Required variables for each makefile
# Discard this section from all parent makefiles
# Expected variables (with automatic defaults):
# CSRCS (all "C" files in the dir)
# SUBDIRS (all subdirs with a Makefile)
# GEN_LIBS - list of libs to be generated ()
# GEN_IMAGES - list of images to be generated ()
# COMPONENTS_xxx - a list of libs/objs in the form
# subdir/lib to be extracted and rolled up into
# a generated lib/image xxx.a ()
#
ifndef
PDIR
GEN_LIBS
=
libsslcrypto.a
endif
#############################################################
# Configuration i.e. compile options etc.
# Target specific stuff (defines etc.) goes in here!
# Generally values applying to a tree are captured in the
# makefile at its root level - these are then overridden
# for a subtree within the makefile rooted therein
#
#DEFINES +=
#############################################################
# Recursion Magic - Don't touch this!!
#
# Each subtree potentially has an include directory
# corresponding to the common APIs applicable to modules
# rooted at that subtree. Accordingly, the INCLUDE PATH
# of a module can only contain the include directories up
# its parent path, and not its siblings
#
# Required for each makefile to inherit from the parent
#
INCLUDES
:=
$(INCLUDES)
-I
$(PDIR)
include
INCLUDES
+=
-I
./
PDIR
:=
../
$(PDIR)
sinclude
$(PDIR)Makefile
app/ssl/crypto/ssl_aes.c
deleted
100644 → 0
View file @
21c4e110
/*
* Copyright (c) 2007, Cameron Rich
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the axTLS project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* AES implementation - this is a small code version. There are much faster
* versions around but they are much larger in size (i.e. they use large
* submix tables).
*/
//#include <string.h>
#include "lwip/opt.h"
#include "lwip/def.h"
#include "ssl/ssl_os_port.h"
#include "ssl/ssl_crypto.h"
/* all commented out in skeleton mode */
#ifndef CONFIG_SSL_SKELETON_MODE
#define rot1(x) (((x) << 24) | ((x) >> 8))
#define rot2(x) (((x) << 16) | ((x) >> 16))
#define rot3(x) (((x) << 8) | ((x) >> 24))
/*
* This cute trick does 4 'mul by two' at once. Stolen from
* Dr B. R. Gladman <brg@gladman.uk.net> but I'm sure the u-(u>>7) is
* a standard graphics trick
* The key to this is that we need to xor with 0x1b if the top bit is set.
* a 1xxx xxxx 0xxx 0xxx First we mask the 7bit,
* b 1000 0000 0000 0000 then we shift right by 7 putting the 7bit in 0bit,
* c 0000 0001 0000 0000 we then subtract (c) from (b)
* d 0111 1111 0000 0000 and now we and with our mask
* e 0001 1011 0000 0000
*/
#define mt 0x80808080
#define ml 0x7f7f7f7f
#define mh 0xfefefefe
#define mm 0x1b1b1b1b
#define mul2(x,t) ((t)=((x)&mt), \
((((x)+(x))&mh)^(((t)-((t)>>7))&mm)))
#define inv_mix_col(x,f2,f4,f8,f9) (\
(f2)=mul2(x,f2), \
(f4)=mul2(f2,f4), \
(f8)=mul2(f4,f8), \
(f9)=(x)^(f8), \
(f8)=((f2)^(f4)^(f8)), \
(f2)^=(f9), \
(f4)^=(f9), \
(f8)^=rot3(f2), \
(f8)^=rot2(f4), \
(f8)^rot1(f9))
/*
* AES S-box
*/
static
const
uint8_t
aes_sbox
[
256
]
ICACHE_STORE_ATTR
ICACHE_RODATA_ATTR
=
{
0x63
,
0x7C
,
0x77
,
0x7B
,
0xF2
,
0x6B
,
0x6F
,
0xC5
,
0x30
,
0x01
,
0x67
,
0x2B
,
0xFE
,
0xD7
,
0xAB
,
0x76
,
0xCA
,
0x82
,
0xC9
,
0x7D
,
0xFA
,
0x59
,
0x47
,
0xF0
,
0xAD
,
0xD4
,
0xA2
,
0xAF
,
0x9C
,
0xA4
,
0x72
,
0xC0
,
0xB7
,
0xFD
,
0x93
,
0x26
,
0x36
,
0x3F
,
0xF7
,
0xCC
,
0x34
,
0xA5
,
0xE5
,
0xF1
,
0x71
,
0xD8
,
0x31
,
0x15
,
0x04
,
0xC7
,
0x23
,
0xC3
,
0x18
,
0x96
,
0x05
,
0x9A
,
0x07
,
0x12
,
0x80
,
0xE2
,
0xEB
,
0x27
,
0xB2
,
0x75
,
0x09
,
0x83
,
0x2C
,
0x1A
,
0x1B
,
0x6E
,
0x5A
,
0xA0
,
0x52
,
0x3B
,
0xD6
,
0xB3
,
0x29
,
0xE3
,
0x2F
,
0x84
,
0x53
,
0xD1
,
0x00
,
0xED
,
0x20
,
0xFC
,
0xB1
,
0x5B
,
0x6A
,
0xCB
,
0xBE
,
0x39
,
0x4A
,
0x4C
,
0x58
,
0xCF
,
0xD0
,
0xEF
,
0xAA
,
0xFB
,
0x43
,
0x4D
,
0x33
,
0x85
,
0x45
,
0xF9
,
0x02
,
0x7F
,
0x50
,
0x3C
,
0x9F
,
0xA8
,
0x51
,
0xA3
,
0x40
,
0x8F
,
0x92
,
0x9D
,
0x38
,
0xF5
,
0xBC
,
0xB6
,
0xDA
,
0x21
,
0x10
,
0xFF
,
0xF3
,
0xD2
,
0xCD
,
0x0C
,
0x13
,
0xEC
,
0x5F
,
0x97
,
0x44
,
0x17
,
0xC4
,
0xA7
,
0x7E
,
0x3D
,
0x64
,
0x5D
,
0x19
,
0x73
,
0x60
,
0x81
,
0x4F
,
0xDC
,
0x22
,
0x2A
,
0x90
,
0x88
,
0x46
,
0xEE
,
0xB8
,
0x14
,
0xDE
,
0x5E
,
0x0B
,
0xDB
,
0xE0
,
0x32
,
0x3A
,
0x0A
,
0x49
,
0x06
,
0x24
,
0x5C
,
0xC2
,
0xD3
,
0xAC
,
0x62
,
0x91
,
0x95
,
0xE4
,
0x79
,
0xE7
,
0xC8
,
0x37
,
0x6D
,
0x8D
,
0xD5
,
0x4E
,
0xA9
,
0x6C
,
0x56
,
0xF4
,
0xEA
,
0x65
,
0x7A
,
0xAE
,
0x08
,
0xBA
,
0x78
,
0x25
,
0x2E
,
0x1C
,
0xA6
,
0xB4
,
0xC6
,
0xE8
,
0xDD
,
0x74
,
0x1F
,
0x4B
,
0xBD
,
0x8B
,
0x8A
,
0x70
,
0x3E
,
0xB5
,
0x66
,
0x48
,
0x03
,
0xF6
,
0x0E
,
0x61
,
0x35
,
0x57
,
0xB9
,
0x86
,
0xC1
,
0x1D
,
0x9E
,
0xE1
,
0xF8
,
0x98
,
0x11
,
0x69
,
0xD9
,
0x8E
,
0x94
,
0x9B
,
0x1E
,
0x87
,
0xE9
,
0xCE
,
0x55
,
0x28
,
0xDF
,
0x8C
,
0xA1
,
0x89
,
0x0D
,
0xBF
,
0xE6
,
0x42
,
0x68
,
0x41
,
0x99
,
0x2D
,
0x0F
,
0xB0
,
0x54
,
0xBB
,
0x16
,
};
/*
* AES is-box
*/
static
const
uint8_t
aes_isbox
[
256
]
ICACHE_STORE_ATTR
ICACHE_RODATA_ATTR
=
{
0x52
,
0x09
,
0x6a
,
0xd5
,
0x30
,
0x36
,
0xa5
,
0x38
,
0xbf
,
0x40
,
0xa3
,
0x9e
,
0x81
,
0xf3
,
0xd7
,
0xfb
,
0x7c
,
0xe3
,
0x39
,
0x82
,
0x9b
,
0x2f
,
0xff
,
0x87
,
0x34
,
0x8e
,
0x43
,
0x44
,
0xc4
,
0xde
,
0xe9
,
0xcb
,
0x54
,
0x7b
,
0x94
,
0x32
,
0xa6
,
0xc2
,
0x23
,
0x3d
,
0xee
,
0x4c
,
0x95
,
0x0b
,
0x42
,
0xfa
,
0xc3
,
0x4e
,
0x08
,
0x2e
,
0xa1
,
0x66
,
0x28
,
0xd9
,
0x24
,
0xb2
,
0x76
,
0x5b
,
0xa2
,
0x49
,
0x6d
,
0x8b
,
0xd1
,
0x25
,
0x72
,
0xf8
,
0xf6
,
0x64
,
0x86
,
0x68
,
0x98
,
0x16
,
0xd4
,
0xa4
,
0x5c
,
0xcc
,
0x5d
,
0x65
,
0xb6
,
0x92
,
0x6c
,
0x70
,
0x48
,
0x50
,
0xfd
,
0xed
,
0xb9
,
0xda
,
0x5e
,
0x15
,
0x46
,
0x57
,
0xa7
,
0x8d
,
0x9d
,
0x84
,
0x90
,
0xd8
,
0xab
,
0x00
,
0x8c
,
0xbc
,
0xd3
,
0x0a
,
0xf7
,
0xe4
,
0x58
,
0x05
,
0xb8
,
0xb3
,
0x45
,
0x06
,
0xd0
,
0x2c
,
0x1e
,
0x8f
,
0xca
,
0x3f
,
0x0f
,
0x02
,
0xc1
,
0xaf
,
0xbd
,
0x03
,
0x01
,
0x13
,
0x8a
,
0x6b
,
0x3a
,
0x91
,
0x11
,
0x41
,
0x4f
,
0x67
,
0xdc
,
0xea
,
0x97
,
0xf2
,
0xcf
,
0xce
,
0xf0
,
0xb4
,
0xe6
,
0x73
,
0x96
,
0xac
,
0x74
,
0x22
,
0xe7
,
0xad
,
0x35
,
0x85
,
0xe2
,
0xf9
,
0x37
,
0xe8
,
0x1c
,
0x75
,
0xdf
,
0x6e
,
0x47
,
0xf1
,
0x1a
,
0x71
,
0x1d
,
0x29
,
0xc5
,
0x89
,
0x6f
,
0xb7
,
0x62
,
0x0e
,
0xaa
,
0x18
,
0xbe
,
0x1b
,
0xfc
,
0x56
,
0x3e
,
0x4b
,
0xc6
,
0xd2
,
0x79
,
0x20
,
0x9a
,
0xdb
,
0xc0
,
0xfe
,
0x78
,
0xcd
,
0x5a
,
0xf4
,
0x1f
,
0xdd
,
0xa8
,
0x33
,
0x88
,
0x07
,
0xc7
,
0x31
,
0xb1
,
0x12
,
0x10
,
0x59
,
0x27
,
0x80
,
0xec
,
0x5f
,
0x60
,
0x51
,
0x7f
,
0xa9
,
0x19
,
0xb5
,
0x4a
,
0x0d
,
0x2d
,
0xe5
,
0x7a
,
0x9f
,
0x93
,
0xc9
,
0x9c
,
0xef
,
0xa0
,
0xe0
,
0x3b
,
0x4d
,
0xae
,
0x2a
,
0xf5
,
0xb0
,
0xc8
,
0xeb
,
0xbb
,
0x3c
,
0x83
,
0x53
,
0x99
,
0x61
,
0x17
,
0x2b
,
0x04
,
0x7e
,
0xba
,
0x77
,
0xd6
,
0x26
,
0xe1
,
0x69
,
0x14
,
0x63
,
0x55
,
0x21
,
0x0c
,
0x7d
};
static
const
unsigned
char
Rcon
[
30
]
=
{
0x01
,
0x02
,
0x04
,
0x08
,
0x10
,
0x20
,
0x40
,
0x80
,
0x1b
,
0x36
,
0x6c
,
0xd8
,
0xab
,
0x4d
,
0x9a
,
0x2f
,
0x5e
,
0xbc
,
0x63
,
0xc6
,
0x97
,
0x35
,
0x6a
,
0xd4
,
0xb3
,
0x7d
,
0xfa
,
0xef
,
0xc5
,
0x91
,
};
/* ----- static functions ----- */
static
void
AES_encrypt
(
const
AES_CTX
*
ctx
,
uint32_t
*
data
);
static
void
AES_decrypt
(
const
AES_CTX
*
ctx
,
uint32_t
*
data
);
/* Perform doubling in Galois Field GF(2^8) using the irreducible polynomial
x^8+x^4+x^3+x+1 */
static
unsigned
char
ICACHE_FLASH_ATTR
AES_xtime
(
uint32_t
x
)
{
return
(
x
&
0x80
)
?
(
x
<<
1
)
^
0x1b
:
x
<<
1
;
}
/**
* Set up AES with the key/iv and cipher size.
*/
void
ICACHE_FLASH_ATTR
AES_set_key
(
AES_CTX
*
ctx
,
const
uint8_t
*
key
,
const
uint8_t
*
iv
,
AES_MODE
mode
)
{
int
i
,
ii
;
uint32_t
*
W
,
tmp
,
tmp2
;
const
unsigned
char
*
ip
;
int
words
;
switch
(
mode
)
{
case
AES_MODE_128
:
i
=
10
;
words
=
4
;
break
;
case
AES_MODE_256
:
i
=
14
;
words
=
8
;
break
;
default:
/* fail silently */
return
;
}
ctx
->
rounds
=
i
;
ctx
->
key_size
=
words
;
W
=
ctx
->
ks
;
for
(
i
=
0
;
i
<
words
;
i
+=
2
)
{
W
[
i
+
0
]
=
((
uint32_t
)
key
[
0
]
<<
24
)
|
((
uint32_t
)
key
[
1
]
<<
16
)
|
((
uint32_t
)
key
[
2
]
<<
8
)
|
((
uint32_t
)
key
[
3
]
);
W
[
i
+
1
]
=
((
uint32_t
)
key
[
4
]
<<
24
)
|
((
uint32_t
)
key
[
5
]
<<
16
)
|
((
uint32_t
)
key
[
6
]
<<
8
)
|
((
uint32_t
)
key
[
7
]
);
key
+=
8
;
}
ip
=
Rcon
;
ii
=
4
*
(
ctx
->
rounds
+
1
);
for
(
i
=
words
;
i
<
ii
;
i
++
)
{
tmp
=
W
[
i
-
1
];
if
((
i
%
words
)
==
0
)
{
// tmp2 =(uint32_t)aes_sbox[(tmp )&0xff]<< 8;
// tmp2|=(uint32_t)aes_sbox[(tmp>> 8)&0xff]<<16;
// tmp2|=(uint32_t)aes_sbox[(tmp>>16)&0xff]<<24;
// tmp2|=(uint32_t)aes_sbox[(tmp>>24) ];
tmp2
=
((
uint32_t
)
byte_of_aligned_array
(
aes_sbox
,(
tmp
)
&
0xff
))
<<
8
;
tmp2
|=
((
uint32_t
)
byte_of_aligned_array
(
aes_sbox
,(
tmp
>>
8
)
&
0xff
))
<<
16
;
tmp2
|=
((
uint32_t
)
byte_of_aligned_array
(
aes_sbox
,(
tmp
>>
16
)
&
0xff
))
<<
24
;
tmp2
|=
((
uint32_t
)
byte_of_aligned_array
(
aes_sbox
,(
tmp
>>
24
)
));
tmp
=
tmp2
^
(((
unsigned
int
)
*
ip
)
<<
24
);
ip
++
;
}
if
((
words
==
8
)
&&
((
i
%
words
)
==
4
))
{
// tmp2 =(uint32_t)aes_sbox[(tmp )&0xff] ;
// tmp2|=(uint32_t)aes_sbox[(tmp>> 8)&0xff]<< 8;
// tmp2|=(uint32_t)aes_sbox[(tmp>>16)&0xff]<<16;
// tmp2|=(uint32_t)aes_sbox[(tmp>>24) ]<<24;
tmp2
=
((
uint32_t
)
byte_of_aligned_array
(
aes_sbox
,(
tmp
)
&
0xff
))
;
tmp2
|=
((
uint32_t
)
byte_of_aligned_array
(
aes_sbox
,(
tmp
>>
8
)
&
0xff
))
<<
8
;
tmp2
|=
((
uint32_t
)
byte_of_aligned_array
(
aes_sbox
,(
tmp
>>
16
)
&
0xff
))
<<
16
;
tmp2
|=
((
uint32_t
)
byte_of_aligned_array
(
aes_sbox
,(
tmp
>>
24
)
))
<<
24
;
tmp
=
tmp2
;
}
W
[
i
]
=
W
[
i
-
words
]
^
tmp
;
}
/* copy the iv across */
os_memcpy
(
ctx
->
iv
,
iv
,
16
);
}
/**
* Change a key for decryption.
*/
void
ICACHE_FLASH_ATTR
AES_convert_key
(
AES_CTX
*
ctx
)
{
int
i
;
uint32_t
*
k
,
w
,
t1
,
t2
,
t3
,
t4
;
k
=
ctx
->
ks
;
k
+=
4
;
for
(
i
=
ctx
->
rounds
*
4
;
i
>
4
;
i
--
)
{
w
=
*
k
;
w
=
inv_mix_col
(
w
,
t1
,
t2
,
t3
,
t4
);
*
k
++
=
w
;
}
}
/**
* Encrypt a byte sequence (with a block size 16) using the AES cipher.
*/
void
ICACHE_FLASH_ATTR
AES_cbc_encrypt
(
AES_CTX
*
ctx
,
const
uint8_t
*
msg
,
uint8_t
*
out
,
int
length
)
{
int
i
;
uint32_t
tin
[
4
],
tout
[
4
],
iv
[
4
];
os_memcpy
(
iv
,
ctx
->
iv
,
AES_IV_SIZE
);
for
(
i
=
0
;
i
<
4
;
i
++
)
tout
[
i
]
=
ntohl
(
iv
[
i
]);
for
(
length
-=
AES_BLOCKSIZE
;
length
>=
0
;
length
-=
AES_BLOCKSIZE
)
{
uint32_t
msg_32
[
4
];
uint32_t
out_32
[
4
];
os_memcpy
(
msg_32
,
msg
,
AES_BLOCKSIZE
);
msg
+=
AES_BLOCKSIZE
;
for
(
i
=
0
;
i
<
4
;
i
++
)
tin
[
i
]
=
ntohl
(
msg_32
[
i
])
^
tout
[
i
];
AES_encrypt
(
ctx
,
tin
);
for
(
i
=
0
;
i
<
4
;
i
++
)
{
tout
[
i
]
=
tin
[
i
];
out_32
[
i
]
=
htonl
(
tout
[
i
]);
}
os_memcpy
(
out
,
out_32
,
AES_BLOCKSIZE
);
out
+=
AES_BLOCKSIZE
;
}
for
(
i
=
0
;
i
<
4
;
i
++
)
iv
[
i
]
=
htonl
(
tout
[
i
]);
os_memcpy
(
ctx
->
iv
,
iv
,
AES_IV_SIZE
);
}
/**
* Decrypt a byte sequence (with a block size 16) using the AES cipher.
*/
void
ICACHE_FLASH_ATTR
AES_cbc_decrypt
(
AES_CTX
*
ctx
,
const
uint8_t
*
msg
,
uint8_t
*
out
,
int
length
)
{
int
i
;
uint32_t
tin
[
4
],
xor
[
4
],
tout
[
4
],
data
[
4
],
iv
[
4
];
os_memcpy
(
iv
,
ctx
->
iv
,
AES_IV_SIZE
);
for
(
i
=
0
;
i
<
4
;
i
++
)
xor
[
i
]
=
ntohl
(
iv
[
i
]);
for
(
length
-=
16
;
length
>=
0
;
length
-=
16
)
{
uint32_t
msg_32
[
4
];
uint32_t
out_32
[
4
];
os_memcpy
(
msg_32
,
msg
,
AES_BLOCKSIZE
);
msg
+=
AES_BLOCKSIZE
;
for
(
i
=
0
;
i
<
4
;
i
++
)
{
tin
[
i
]
=
ntohl
(
msg_32
[
i
]);
data
[
i
]
=
tin
[
i
];
}
AES_decrypt
(
ctx
,
data
);
for
(
i
=
0
;
i
<
4
;
i
++
)
{
tout
[
i
]
=
data
[
i
]
^
xor
[
i
];
xor
[
i
]
=
tin
[
i
];
out_32
[
i
]
=
htonl
(
tout
[
i
]);
}
os_memcpy
(
out
,
out_32
,
AES_BLOCKSIZE
);
out
+=
AES_BLOCKSIZE
;
}
for
(
i
=
0
;
i
<
4
;
i
++
)
iv
[
i
]
=
htonl
(
xor
[
i
]);
os_memcpy
(
ctx
->
iv
,
iv
,
AES_IV_SIZE
);
}
/**
* Encrypt a single block (16 bytes) of data
*/
static
void
ICACHE_FLASH_ATTR
AES_encrypt
(
const
AES_CTX
*
ctx
,
uint32_t
*
data
)
{
/* To make this code smaller, generate the sbox entries on the fly.
* This will have a really heavy effect upon performance.
*/
uint32_t
tmp
[
4
];
uint32_t
tmp1
,
old_a0
,
a0
,
a1
,
a2
,
a3
,
row
;
int
curr_rnd
;
int
rounds
=
ctx
->
rounds
;
const
uint32_t
*
k
=
ctx
->
ks
;
/* Pre-round key addition */
for
(
row
=
0
;
row
<
4
;
row
++
)
data
[
row
]
^=
*
(
k
++
);
/* Encrypt one block. */
for
(
curr_rnd
=
0
;
curr_rnd
<
rounds
;
curr_rnd
++
)
{
/* Perform ByteSub and ShiftRow operations together */
for
(
row
=
0
;
row
<
4
;
row
++
)
{
// a0 = (uint32_t)aes_sbox[(data[row%4]>>24)&0xFF];
// a1 = (uint32_t)aes_sbox[(data[(row+1)%4]>>16)&0xFF];
// a2 = (uint32_t)aes_sbox[(data[(row+2)%4]>>8)&0xFF];
// a3 = (uint32_t)aes_sbox[(data[(row+3)%4])&0xFF];
a0
=
(
uint32_t
)(
byte_of_aligned_array
(
aes_sbox
,(
data
[
row
%
4
]
>>
24
)
&
0xFF
));
a1
=
(
uint32_t
)(
byte_of_aligned_array
(
aes_sbox
,(
data
[(
row
+
1
)
%
4
]
>>
16
)
&
0xFF
));
a2
=
(
uint32_t
)(
byte_of_aligned_array
(
aes_sbox
,(
data
[(
row
+
2
)
%
4
]
>>
8
)
&
0xFF
));
a3
=
(
uint32_t
)(
byte_of_aligned_array
(
aes_sbox
,(
data
[(
row
+
3
)
%
4
])
&
0xFF
));
/* Perform MixColumn iff not last round */
if
(
curr_rnd
<
(
rounds
-
1
))
{
tmp1
=
a0
^
a1
^
a2
^
a3
;
old_a0
=
a0
;
a0
^=
tmp1
^
AES_xtime
(
a0
^
a1
);
a1
^=
tmp1
^
AES_xtime
(
a1
^
a2
);
a2
^=
tmp1
^
AES_xtime
(
a2
^
a3
);
a3
^=
tmp1
^
AES_xtime
(
a3
^
old_a0
);
}
tmp
[
row
]
=
((
a0
<<
24
)
|
(
a1
<<
16
)
|
(
a2
<<
8
)
|
a3
);
}
/* KeyAddition - note that it is vital that this loop is separate from
the MixColumn operation, which must be atomic...*/
for
(
row
=
0
;
row
<
4
;
row
++
)
data
[
row
]
=
tmp
[
row
]
^
*
(
k
++
);
}
}
/**
* Decrypt a single block (16 bytes) of data
*/
static
void
ICACHE_FLASH_ATTR
AES_decrypt
(
const
AES_CTX
*
ctx
,
uint32_t
*
data
)
{
uint32_t
tmp
[
4
];
uint32_t
xt0
,
xt1
,
xt2
,
xt3
,
xt4
,
xt5
,
xt6
;
uint32_t
a0
,
a1
,
a2
,
a3
,
row
;
int
curr_rnd
;
int
rounds
=
ctx
->
rounds
;
const
uint32_t
*
k
=
ctx
->
ks
+
((
rounds
+
1
)
*
4
);
/* pre-round key addition */
for
(
row
=
4
;
row
>
0
;
row
--
)
data
[
row
-
1
]
^=
*
(
--
k
);
/* Decrypt one block */
for
(
curr_rnd
=
0
;
curr_rnd
<
rounds
;
curr_rnd
++
)
{
/* Perform ByteSub and ShiftRow operations together */
for
(
row
=
4
;
row
>
0
;
row
--
)
{
// a0 = aes_isbox[(data[(row+3)%4]>>24)&0xFF];
// a1 = aes_isbox[(data[(row+2)%4]>>16)&0xFF];
// a2 = aes_isbox[(data[(row+1)%4]>>8)&0xFF];
// a3 = aes_isbox[(data[row%4])&0xFF];
a0
=
byte_of_aligned_array
(
aes_isbox
,(
data
[(
row
+
3
)
%
4
]
>>
24
)
&
0xFF
);
a1
=
byte_of_aligned_array
(
aes_isbox
,(
data
[(
row
+
2
)
%
4
]
>>
16
)
&
0xFF
);
a2
=
byte_of_aligned_array
(
aes_isbox
,(
data
[(
row
+
1
)
%
4
]
>>
8
)
&
0xFF
);
a3
=
byte_of_aligned_array
(
aes_isbox
,(
data
[
row
%
4
])
&
0xFF
);
/* Perform MixColumn iff not last round */
if
(
curr_rnd
<
(
rounds
-
1
))
{
/* The MDS cofefficients (0x09, 0x0B, 0x0D, 0x0E)
are quite large compared to encryption; this
operation slows decryption down noticeably. */
xt0
=
AES_xtime
(
a0
^
a1
);
xt1
=
AES_xtime
(
a1
^
a2
);
xt2
=
AES_xtime
(
a2
^
a3
);
xt3
=
AES_xtime
(
a3
^
a0
);
xt4
=
AES_xtime
(
xt0
^
xt1
);
xt5
=
AES_xtime
(
xt1
^
xt2
);
xt6
=
AES_xtime
(
xt4
^
xt5
);
xt0
^=
a1
^
a2
^
a3
^
xt4
^
xt6
;
xt1
^=
a0
^
a2
^
a3
^
xt5
^
xt6
;
xt2
^=
a0
^
a1
^
a3
^
xt4
^
xt6
;
xt3
^=
a0
^
a1
^
a2
^
xt5
^
xt6
;
tmp
[
row
-
1
]
=
((
xt0
<<
24
)
|
(
xt1
<<
16
)
|
(
xt2
<<
8
)
|
xt3
);
}
else
tmp
[
row
-
1
]
=
((
a0
<<
24
)
|
(
a1
<<
16
)
|
(
a2
<<
8
)
|
a3
);
}
for
(
row
=
4
;
row
>
0
;
row
--
)
data
[
row
-
1
]
=
tmp
[
row
-
1
]
^
*
(
--
k
);
}
}
#endif
app/ssl/crypto/ssl_bigint.c
deleted
100644 → 0
View file @
21c4e110
/*
* Copyright (c) 2007, Cameron Rich
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the axTLS project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @defgroup bigint_api Big Integer API
* @brief The bigint implementation as used by the axTLS project.
*
* The bigint library is for RSA encryption/decryption as well as signing.
* This code tries to minimise use of malloc/free by maintaining a small
* cache. A bigint context may maintain state by being made "permanent".
* It be be later released with a bi_depermanent() and bi_free() call.
*
* It supports the following reduction techniques:
* - Classical
* - Barrett
* - Montgomery
*
* It also implements the following:
* - Karatsuba multiplication
* - Squaring
* - Sliding window exponentiation
* - Chinese Remainder Theorem (implemented in rsa.c).
*
* All the algorithms used are pretty standard, and designed for different
* data bus sizes. Negative numbers are not dealt with at all, so a subtraction
* may need to be tested for negativity.
*
* This library steals some ideas from Jef Poskanzer
* <http://cs.marlboro.edu/term/cs-fall02/algorithms/crypto/RSA/bigint>
* and GMP <http://www.swox.com/gmp>. It gets most of its implementation
* detail from "The Handbook of Applied Cryptography"
* <http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf>
* @{
*/
//#include <stdlib.h>
//#include <limits.h>
//#include <string.h>
//#include <stdio.h>
//#include <time.h>
#include "ssl/ssl_os_port.h"
#include "ssl/ssl_bigint.h"
//#include "os.h"
#include "lwip/mem.h"
#define V1 v->comps[v->size-1]
/**< v1 for division */
#define V2 v->comps[v->size-2]
/**< v2 for division */
#define U(j) tmp_u->comps[tmp_u->size-j-1]
/**< uj for division */
#define Q(j) quotient->comps[quotient->size-j-1]
/**< qj for division */
static
bigint
*
bi_int_multiply
(
BI_CTX
*
ctx
,
bigint
*
bi
,
comp
i
);
static
bigint
*
bi_int_divide
(
BI_CTX
*
ctx
,
bigint
*
biR
,
comp
denom
);
static
bigint
*
alloc
(
BI_CTX
*
ctx
,
int
size
);
static
bigint
*
trim
(
bigint
*
bi
);
static
void
more_comps
(
bigint
*
bi
,
int
n
);
#if defined(CONFIG_BIGINT_KARATSUBA) || defined(CONFIG_BIGINT_BARRETT) || \
defined(CONFIG_BIGINT_MONTGOMERY)
static
bigint
*
comp_right_shift
(
bigint
*
biR
,
int
num_shifts
);
static
bigint
*
comp_left_shift
(
bigint
*
biR
,
int
num_shifts
);
#endif
#ifdef CONFIG_BIGINT_CHECK_ON
static
void
check
(
const
bigint
*
bi
);
#else
#define check(A)
/**< disappears in normal production mode */
#endif
/**
* @brief Start a new bigint context.
* @return A bigint context.
*/
BI_CTX
*
ICACHE_FLASH_ATTR
bi_initialize
(
void
)
{
/* calloc() sets everything to zero */
BI_CTX
*
ctx
=
(
BI_CTX
*
)
os_zalloc
(
sizeof
(
BI_CTX
));
/* the radix */
ctx
->
bi_radix
=
alloc
(
ctx
,
2
);
ctx
->
bi_radix
->
comps
[
0
]
=
0
;
ctx
->
bi_radix
->
comps
[
1
]
=
1
;
bi_permanent
(
ctx
->
bi_radix
);
return
ctx
;
}
/**
* @brief Close the bigint context and free any resources.
*
* Free up any used memory - a check is done if all objects were not
* properly freed.
* @param ctx [in] The bigint session context.
*/
void
ICACHE_FLASH_ATTR
bi_terminate
(
BI_CTX
*
ctx
)
{
bi_depermanent
(
ctx
->
bi_radix
);
bi_free
(
ctx
,
ctx
->
bi_radix
);
if
(
ctx
->
active_count
!=
0
)
{
#ifdef CONFIG_SSL_FULL_MODE
ssl_printf
(
"bi_terminate: there were %d un-freed bigints
\n
"
,
ctx
->
active_count
);
#endif
return
;
/* wujg : org ---> abort(); */
}
bi_clear_cache
(
ctx
);
os_free
(
ctx
);
}
/**
*@brief Clear the memory cache.
*/
void
ICACHE_FLASH_ATTR
bi_clear_cache
(
BI_CTX
*
ctx
)
{
bigint
*
p
,
*
pn
;
if
(
ctx
->
free_list
==
NULL
)
return
;
for
(
p
=
ctx
->
free_list
;
p
!=
NULL
;
p
=
pn
)
{
pn
=
p
->
next
;
os_free
(
p
->
comps
);
os_free
(
p
);
}
ctx
->
free_count
=
0
;
ctx
->
free_list
=
NULL
;
}
/**
* @brief Increment the number of references to this object.
* It does not do a full copy.
* @param bi [in] The bigint to copy.
* @return A reference to the same bigint.
*/
bigint
*
ICACHE_FLASH_ATTR
bi_copy
(
bigint
*
bi
)
{
check
(
bi
);
if
(
bi
->
refs
!=
PERMANENT
)
bi
->
refs
++
;
return
bi
;
}
/**
* @brief Simply make a bigint object "unfreeable" if bi_free() is called on it.
*
* For this object to be freed, bi_depermanent() must be called.
* @param bi [in] The bigint to be made permanent.
*/
void
ICACHE_FLASH_ATTR
bi_permanent
(
bigint
*
bi
)
{
check
(
bi
);
if
(
bi
->
refs
!=
1
)
{
#ifdef CONFIG_SSL_FULL_MODE
ssl_printf
(
"bi_permanent: refs was not 1
\n
"
);
#endif
return
;
/* wujg : org ----> abort(); */
}
bi
->
refs
=
PERMANENT
;
}
/**
* @brief Take a permanent object and make it eligible for freedom.
* @param bi [in] The bigint to be made back to temporary.
*/
void
ICACHE_FLASH_ATTR
bi_depermanent
(
bigint
*
bi
)
{
check
(
bi
);
if
(
bi
->
refs
!=
PERMANENT
)
{
#ifdef CONFIG_SSL_FULL_MODE
ssl_printf
(
"bi_depermanent: bigint was not permanent
\n
"
);
#endif
return
;
/* wujg : org ----> abort(); */
}
bi
->
refs
=
1
;
}
/**
* @brief Free a bigint object so it can be used again.
*
* The memory itself it not actually freed, just tagged as being available
* @param ctx [in] The bigint session context.
* @param bi [in] The bigint to be freed.
*/
void
ICACHE_FLASH_ATTR
bi_free
(
BI_CTX
*
ctx
,
bigint
*
bi
)
{
check
(
bi
);
if
(
bi
->
refs
==
PERMANENT
)
{
return
;
}
if
(
--
bi
->
refs
>
0
)
{
return
;
}
bi
->
next
=
ctx
->
free_list
;
ctx
->
free_list
=
bi
;
ctx
->
free_count
++
;
if
(
--
ctx
->
active_count
<
0
)
{
#ifdef CONFIG_SSL_FULL_MODE
ssl_printf
(
"bi_free: active_count went negative "
"- double-freed bigint?
\n
"
);
#endif
return
;
/* wujg : org ----> abort(); */
}
}
/**
* @brief Convert an (unsigned) integer into a bigint.
* @param ctx [in] The bigint session context.
* @param i [in] The (unsigned) integer to be converted.
*
*/
bigint
*
ICACHE_FLASH_ATTR
int_to_bi
(
BI_CTX
*
ctx
,
comp
i
)
{
bigint
*
biR
=
alloc
(
ctx
,
1
);
biR
->
comps
[
0
]
=
i
;
return
biR
;
}
/**
* @brief Do a full copy of the bigint object.
* @param ctx [in] The bigint session context.
* @param bi [in] The bigint object to be copied.
*/
bigint
*
ICACHE_FLASH_ATTR
bi_clone
(
BI_CTX
*
ctx
,
const
bigint
*
bi
)
{
bigint
*
biR
=
alloc
(
ctx
,
bi
->
size
);
check
(
bi
);
os_memcpy
(
biR
->
comps
,
bi
->
comps
,
bi
->
size
*
COMP_BYTE_SIZE
);
return
biR
;
}
/**
* @brief Perform an addition operation between two bigints.
* @param ctx [in] The bigint session context.
* @param bia [in] A bigint.
* @param bib [in] Another bigint.
* @return The result of the addition.
*/
bigint
*
ICACHE_FLASH_ATTR
bi_add
(
BI_CTX
*
ctx
,
bigint
*
bia
,
bigint
*
bib
)
{
int
n
;
comp
carry
=
0
;
comp
*
pa
,
*
pb
;
check
(
bia
);
check
(
bib
);
n
=
max
(
bia
->
size
,
bib
->
size
);
more_comps
(
bia
,
n
+
1
);
more_comps
(
bib
,
n
);
pa
=
bia
->
comps
;
pb
=
bib
->
comps
;
do
{
comp
sl
,
rl
,
cy1
;
sl
=
*
pa
+
*
pb
++
;
rl
=
sl
+
carry
;
cy1
=
sl
<
*
pa
;
carry
=
cy1
|
(
rl
<
sl
);
*
pa
++
=
rl
;
}
while
(
--
n
!=
0
);
*
pa
=
carry
;
/* do overflow */
bi_free
(
ctx
,
bib
);
return
trim
(
bia
);
}
/**
* @brief Perform a subtraction operation between two bigints.
* @param ctx [in] The bigint session context.
* @param bia [in] A bigint.
* @param bib [in] Another bigint.
* @param is_negative [out] If defined, indicates that the result was negative.
* is_negative may be null.
* @return The result of the subtraction. The result is always positive.
*/
bigint
*
ICACHE_FLASH_ATTR
bi_subtract
(
BI_CTX
*
ctx
,
bigint
*
bia
,
bigint
*
bib
,
int
*
is_negative
)
{
int
n
=
bia
->
size
;
comp
*
pa
,
*
pb
,
carry
=
0
;
check
(
bia
);
check
(
bib
);
more_comps
(
bib
,
n
);
pa
=
bia
->
comps
;
pb
=
bib
->
comps
;
do
{
comp
sl
,
rl
,
cy1
;
sl
=
*
pa
-
*
pb
++
;
rl
=
sl
-
carry
;
cy1
=
sl
>
*
pa
;
carry
=
cy1
|
(
rl
>
sl
);
*
pa
++
=
rl
;
}
while
(
--
n
!=
0
);
if
(
is_negative
)
/* indicate a negative result */
{
*
is_negative
=
carry
;
}
bi_free
(
ctx
,
trim
(
bib
));
/* put bib back to the way it was */
return
trim
(
bia
);
}
/**
* Perform a multiply between a bigint an an (unsigned) integer
*/
static
bigint
*
ICACHE_FLASH_ATTR
bi_int_multiply
(
BI_CTX
*
ctx
,
bigint
*
bia
,
comp
b
)
{
int
j
=
0
,
n
=
bia
->
size
;
bigint
*
biR
=
alloc
(
ctx
,
n
+
1
);
comp
carry
=
0
;
comp
*
r
=
biR
->
comps
;
comp
*
a
=
bia
->
comps
;
check
(
bia
);
/* clear things to start with */
os_memset
(
r
,
0
,
((
n
+
1
)
*
COMP_BYTE_SIZE
));
do
{
long_comp
tmp
=
*
r
+
(
long_comp
)
a
[
j
]
*
b
+
carry
;
*
r
++
=
(
comp
)
tmp
;
/* downsize */
carry
=
(
comp
)(
tmp
>>
COMP_BIT_SIZE
);
}
while
(
++
j
<
n
);
*
r
=
carry
;
bi_free
(
ctx
,
bia
);
return
trim
(
biR
);
}
/**
* @brief Does both division and modulo calculations.
*
* Used extensively when doing classical reduction.
* @param ctx [in] The bigint session context.
* @param u [in] A bigint which is the numerator.
* @param v [in] Either the denominator or the modulus depending on the mode.
* @param is_mod [n] Determines if this is a normal division (0) or a reduction
* (1).
* @return The result of the division/reduction.
*/
bigint
*
ICACHE_FLASH_ATTR
bi_divide
(
BI_CTX
*
ctx
,
bigint
*
u
,
bigint
*
v
,
int
is_mod
)
{
int
n
=
v
->
size
,
m
=
u
->
size
-
n
;
int
j
=
0
,
orig_u_size
=
u
->
size
;
uint8_t
mod_offset
=
ctx
->
mod_offset
;
comp
d
;
bigint
*
quotient
,
*
tmp_u
;
comp
q_dash
;
check
(
u
);
check
(
v
);
/* if doing reduction and we are < mod, then return mod */
if
(
is_mod
&&
bi_compare
(
v
,
u
)
>
0
)
{
bi_free
(
ctx
,
v
);
return
u
;
}
quotient
=
alloc
(
ctx
,
m
+
1
);
tmp_u
=
alloc
(
ctx
,
n
+
1
);
v
=
trim
(
v
);
/* make sure we have no leading 0's */
d
=
(
comp
)((
long_comp
)
COMP_RADIX
/
(
V1
+
1
));
/* clear things to start with */
os_memset
(
quotient
->
comps
,
0
,
((
quotient
->
size
)
*
COMP_BYTE_SIZE
));
/* normalise */
if
(
d
>
1
)
{
u
=
bi_int_multiply
(
ctx
,
u
,
d
);
if
(
is_mod
)
{
v
=
ctx
->
bi_normalised_mod
[
mod_offset
];
}
else
{
v
=
bi_int_multiply
(
ctx
,
v
,
d
);
}
}
if
(
orig_u_size
==
u
->
size
)
/* new digit position u0 */
{
more_comps
(
u
,
orig_u_size
+
1
);
}
do
{
/* get a temporary short version of u */
os_memcpy
(
tmp_u
->
comps
,
&
u
->
comps
[
u
->
size
-
n
-
1
-
j
],
(
n
+
1
)
*
COMP_BYTE_SIZE
);
/* calculate q' */
if
(
U
(
0
)
==
V1
)
{
q_dash
=
COMP_RADIX
-
1
;
}
else
{
q_dash
=
(
comp
)(((
long_comp
)
U
(
0
)
*
COMP_RADIX
+
U
(
1
))
/
V1
);
if
(
v
->
size
>
1
&&
V2
)
{
/* we are implementing the following:
if (V2*q_dash > (((U(0)*COMP_RADIX + U(1) -
q_dash*V1)*COMP_RADIX) + U(2))) ... */
comp
inner
=
(
comp
)((
long_comp
)
COMP_RADIX
*
U
(
0
)
+
U
(
1
)
-
(
long_comp
)
q_dash
*
V1
);
if
((
long_comp
)
V2
*
q_dash
>
(
long_comp
)
inner
*
COMP_RADIX
+
U
(
2
))
{
q_dash
--
;
}
}
}
/* multiply and subtract */
if
(
q_dash
)
{
int
is_negative
;
tmp_u
=
bi_subtract
(
ctx
,
tmp_u
,
bi_int_multiply
(
ctx
,
bi_copy
(
v
),
q_dash
),
&
is_negative
);
more_comps
(
tmp_u
,
n
+
1
);
Q
(
j
)
=
q_dash
;
/* add back */
if
(
is_negative
)
{
Q
(
j
)
--
;
tmp_u
=
bi_add
(
ctx
,
tmp_u
,
bi_copy
(
v
));
/* lop off the carry */
tmp_u
->
size
--
;
v
->
size
--
;
}
}
else
{
Q
(
j
)
=
0
;
}
/* copy back to u */
os_memcpy
(
&
u
->
comps
[
u
->
size
-
n
-
1
-
j
],
tmp_u
->
comps
,
(
n
+
1
)
*
COMP_BYTE_SIZE
);
}
while
(
++
j
<=
m
);
bi_free
(
ctx
,
tmp_u
);
bi_free
(
ctx
,
v
);
if
(
is_mod
)
/* get the remainder */
{
bi_free
(
ctx
,
quotient
);
return
bi_int_divide
(
ctx
,
trim
(
u
),
d
);
}
else
/* get the quotient */
{
bi_free
(
ctx
,
u
);
return
trim
(
quotient
);
}
}
/*
* Perform an integer divide on a bigint.
*/
static
bigint
*
ICACHE_FLASH_ATTR
bi_int_divide
(
BI_CTX
*
ctx
,
bigint
*
biR
,
comp
denom
)
{
int
i
=
biR
->
size
-
1
;
long_comp
r
=
0
;
check
(
biR
);
do
{
r
=
(
r
<<
COMP_BIT_SIZE
)
+
biR
->
comps
[
i
];
biR
->
comps
[
i
]
=
(
comp
)(
r
/
denom
);
r
%=
denom
;
}
while
(
--
i
>=
0
);
return
trim
(
biR
);
}
#ifdef CONFIG_BIGINT_MONTGOMERY
/**
* There is a need for the value of integer N' such that B^-1(B-1)-N^-1N'=1,
* where B^-1(B-1) mod N=1. Actually, only the least significant part of
* N' is needed, hence the definition N0'=N' mod b. We reproduce below the
* simple algorithm from an article by Dusse and Kaliski to efficiently
* find N0' from N0 and b */
static
comp
ICACHE_FLASH_ATTR
modular_inverse
(
bigint
*
bim
)
{
int
i
;
comp
t
=
1
;
comp
two_2_i_minus_1
=
2
;
/* 2^(i-1) */
long_comp
two_2_i
=
4
;
/* 2^i */
comp
N
=
bim
->
comps
[
0
];
for
(
i
=
2
;
i
<=
COMP_BIT_SIZE
;
i
++
)
{
if
((
long_comp
)
N
*
t
%
two_2_i
>=
two_2_i_minus_1
)
{
t
+=
two_2_i_minus_1
;
}
two_2_i_minus_1
<<=
1
;
two_2_i
<<=
1
;
}
return
(
comp
)(
COMP_RADIX
-
t
);
}
#endif
#if defined(CONFIG_BIGINT_KARATSUBA) || defined(CONFIG_BIGINT_BARRETT) || \
defined(CONFIG_BIGINT_MONTGOMERY)
/**
* Take each component and shift down (in terms of components)
*/
static
bigint
*
ICACHE_FLASH_ATTR
comp_right_shift
(
bigint
*
biR
,
int
num_shifts
)
{
int
i
=
biR
->
size
-
num_shifts
;
comp
*
x
=
biR
->
comps
;
comp
*
y
=
&
biR
->
comps
[
num_shifts
];
check
(
biR
);
if
(
i
<=
0
)
/* have we completely right shifted? */
{
biR
->
comps
[
0
]
=
0
;
/* return 0 */
biR
->
size
=
1
;
return
biR
;
}
do
{
*
x
++
=
*
y
++
;
}
while
(
--
i
>
0
);
biR
->
size
-=
num_shifts
;
return
biR
;
}
/**
* Take each component and shift it up (in terms of components)
*/
static
bigint
*
ICACHE_FLASH_ATTR
comp_left_shift
(
bigint
*
biR
,
int
num_shifts
)
{
int
i
=
biR
->
size
-
1
;
comp
*
x
,
*
y
;
check
(
biR
);
if
(
num_shifts
<=
0
)
{
return
biR
;
}
more_comps
(
biR
,
biR
->
size
+
num_shifts
);
x
=
&
biR
->
comps
[
i
+
num_shifts
];
y
=
&
biR
->
comps
[
i
];
do
{
*
x
--
=
*
y
--
;
}
while
(
i
--
);
os_memset
(
biR
->
comps
,
0
,
num_shifts
*
COMP_BYTE_SIZE
);
/* zero LS comps */
return
biR
;
}
#endif
/**
* @brief Allow a binary sequence to be imported as a bigint.
* @param ctx [in] The bigint session context.
* @param data [in] The data to be converted.
* @param size [in] The number of bytes of data.
* @return A bigint representing this data.
*/
bigint
*
ICACHE_FLASH_ATTR
bi_import
(
BI_CTX
*
ctx
,
const
uint8_t
*
data
,
int
size
)
{
bigint
*
biR
=
alloc
(
ctx
,
(
size
+
COMP_BYTE_SIZE
-
1
)
/
COMP_BYTE_SIZE
);
int
i
,
j
=
0
,
offset
=
0
;
os_memset
(
biR
->
comps
,
0
,
biR
->
size
*
COMP_BYTE_SIZE
);
for
(
i
=
size
-
1
;
i
>=
0
;
i
--
)
{
biR
->
comps
[
offset
]
+=
data
[
i
]
<<
(
j
*
8
);
if
(
++
j
==
COMP_BYTE_SIZE
)
{
j
=
0
;
offset
++
;
}
}
return
trim
(
biR
);
}
#ifdef CONFIG_SSL_FULL_MODE
/**
* @brief The testharness uses this code to import text hex-streams and
* convert them into bigints.
* @param ctx [in] The bigint session context.
* @param data [in] A string consisting of hex characters. The characters must
* be in upper case.
* @return A bigint representing this data.
*/
bigint
*
ICACHE_FLASH_ATTR
bi_str_import
(
BI_CTX
*
ctx
,
const
char
*
data
)
{
int
size
=
os_strlen
(
data
);
bigint
*
biR
=
alloc
(
ctx
,
(
size
+
COMP_NUM_NIBBLES
-
1
)
/
COMP_NUM_NIBBLES
);
int
i
,
j
=
0
,
offset
=
0
;
os_memset
(
biR
->
comps
,
0
,
biR
->
size
*
COMP_BYTE_SIZE
);
for
(
i
=
size
-
1
;
i
>=
0
;
i
--
)
{
int
num
=
(
data
[
i
]
<=
'9'
)
?
(
data
[
i
]
-
'0'
)
:
(
data
[
i
]
-
'A'
+
10
);
biR
->
comps
[
offset
]
+=
num
<<
(
j
*
4
);
if
(
++
j
==
COMP_NUM_NIBBLES
)
{
j
=
0
;
offset
++
;
}
}
return
biR
;
}
void
ICACHE_FLASH_ATTR
bi_print
(
const
char
*
label
,
bigint
*
x
)
{
int
i
,
j
;
if
(
x
==
NULL
)
{
ssl_printf
(
"%s: (null)
\n
"
,
label
);
return
;
}
ssl_printf
(
"%s: (size %d)
\n
"
,
label
,
x
->
size
);
for
(
i
=
x
->
size
-
1
;
i
>=
0
;
i
--
)
{
for
(
j
=
COMP_NUM_NIBBLES
-
1
;
j
>=
0
;
j
--
)
{
comp
mask
=
0x0f
<<
(
j
*
4
);
comp
num
=
(
x
->
comps
[
i
]
&
mask
)
>>
(
j
*
4
);
os_putc
((
num
<=
9
)
?
(
num
+
'0'
)
:
(
num
+
'A'
-
10
));
}
}
ssl_printf
(
"
\n
"
);
}
#endif
/**
* @brief Take a bigint and convert it into a byte sequence.
*
* This is useful after a decrypt operation.
* @param ctx [in] The bigint session context.
* @param x [in] The bigint to be converted.
* @param data [out] The converted data as a byte stream.
* @param size [in] The maximum size of the byte stream. Unused bytes will be
* zeroed.
*/
void
ICACHE_FLASH_ATTR
bi_export
(
BI_CTX
*
ctx
,
bigint
*
x
,
uint8_t
*
data
,
int
size
)
{
int
i
,
j
,
k
=
size
-
1
;
check
(
x
);
os_memset
(
data
,
0
,
size
);
/* ensure all leading 0's are cleared */
for
(
i
=
0
;
i
<
x
->
size
;
i
++
)
{
for
(
j
=
0
;
j
<
COMP_BYTE_SIZE
;
j
++
)
{
comp
mask
=
0xff
<<
(
j
*
8
);
int
num
=
(
x
->
comps
[
i
]
&
mask
)
>>
(
j
*
8
);
data
[
k
--
]
=
num
;
if
(
k
<
0
)
{
goto
buf_done
;
}
}
}
buf_done:
bi_free
(
ctx
,
x
);
}
/**
* @brief Pre-calculate some of the expensive steps in reduction.
*
* This function should only be called once (normally when a session starts).
* When the session is over, bi_free_mod() should be called. bi_mod_power()
* relies on this function being called.
* @param ctx [in] The bigint session context.
* @param bim [in] The bigint modulus that will be used.
* @param mod_offset [in] There are three moduluii that can be stored - the
* standard modulus, and its two primes p and q. This offset refers to which
* modulus we are referring to.
* @see bi_free_mod(), bi_mod_power().
*/
void
ICACHE_FLASH_ATTR
bi_set_mod
(
BI_CTX
*
ctx
,
bigint
*
bim
,
int
mod_offset
)
{
int
k
=
bim
->
size
;
comp
d
=
(
comp
)((
long_comp
)
COMP_RADIX
/
(
bim
->
comps
[
k
-
1
]
+
1
));
#ifdef CONFIG_BIGINT_MONTGOMERY
bigint
*
R
,
*
R2
;
#endif
ctx
->
bi_mod
[
mod_offset
]
=
bim
;
bi_permanent
(
ctx
->
bi_mod
[
mod_offset
]);
ctx
->
bi_normalised_mod
[
mod_offset
]
=
bi_int_multiply
(
ctx
,
bim
,
d
);
bi_permanent
(
ctx
->
bi_normalised_mod
[
mod_offset
]);
#if defined(CONFIG_BIGINT_MONTGOMERY)
/* set montgomery variables */
R
=
comp_left_shift
(
bi_clone
(
ctx
,
ctx
->
bi_radix
),
k
-
1
);
/* R */
R2
=
comp_left_shift
(
bi_clone
(
ctx
,
ctx
->
bi_radix
),
k
*
2
-
1
);
/* R^2 */
ctx
->
bi_RR_mod_m
[
mod_offset
]
=
bi_mod
(
ctx
,
R2
);
/* R^2 mod m */
ctx
->
bi_R_mod_m
[
mod_offset
]
=
bi_mod
(
ctx
,
R
);
/* R mod m */
bi_permanent
(
ctx
->
bi_RR_mod_m
[
mod_offset
]);
bi_permanent
(
ctx
->
bi_R_mod_m
[
mod_offset
]);
ctx
->
N0_dash
[
mod_offset
]
=
modular_inverse
(
ctx
->
bi_mod
[
mod_offset
]);
#elif defined (CONFIG_BIGINT_BARRETT)
ctx
->
bi_mu
[
mod_offset
]
=
bi_divide
(
ctx
,
comp_left_shift
(
bi_clone
(
ctx
,
ctx
->
bi_radix
),
k
*
2
-
1
),
ctx
->
bi_mod
[
mod_offset
],
0
);
bi_permanent
(
ctx
->
bi_mu
[
mod_offset
]);
#endif
}
/**
* @brief Used when cleaning various bigints at the end of a session.
* @param ctx [in] The bigint session context.
* @param mod_offset [in] The offset to use.
* @see bi_set_mod().
*/
void
ICACHE_FLASH_ATTR
bi_free_mod
(
BI_CTX
*
ctx
,
int
mod_offset
)
{
bi_depermanent
(
ctx
->
bi_mod
[
mod_offset
]);
bi_free
(
ctx
,
ctx
->
bi_mod
[
mod_offset
]);
#if defined (CONFIG_BIGINT_MONTGOMERY)
bi_depermanent
(
ctx
->
bi_RR_mod_m
[
mod_offset
]);
bi_depermanent
(
ctx
->
bi_R_mod_m
[
mod_offset
]);
bi_free
(
ctx
,
ctx
->
bi_RR_mod_m
[
mod_offset
]);
bi_free
(
ctx
,
ctx
->
bi_R_mod_m
[
mod_offset
]);
#elif defined(CONFIG_BIGINT_BARRETT)
bi_depermanent
(
ctx
->
bi_mu
[
mod_offset
]);
bi_free
(
ctx
,
ctx
->
bi_mu
[
mod_offset
]);
#endif
bi_depermanent
(
ctx
->
bi_normalised_mod
[
mod_offset
]);
bi_free
(
ctx
,
ctx
->
bi_normalised_mod
[
mod_offset
]);
}
/**
* Perform a standard multiplication between two bigints.
*
* Barrett reduction has no need for some parts of the product, so ignore bits
* of the multiply. This routine gives Barrett its big performance
* improvements over Classical/Montgomery reduction methods.
*/
static
bigint
*
ICACHE_FLASH_ATTR
regular_multiply
(
BI_CTX
*
ctx
,
bigint
*
bia
,
bigint
*
bib
,
int
inner_partial
,
int
outer_partial
)
{
int
i
=
0
,
j
;
int
n
=
bia
->
size
;
int
t
=
bib
->
size
;
bigint
*
biR
=
alloc
(
ctx
,
n
+
t
);
comp
*
sr
=
biR
->
comps
;
comp
*
sa
=
bia
->
comps
;
comp
*
sb
=
bib
->
comps
;
check
(
bia
);
check
(
bib
);
/* clear things to start with */
os_memset
(
biR
->
comps
,
0
,
((
n
+
t
)
*
COMP_BYTE_SIZE
));
do
{
long_comp
tmp
;
comp
carry
=
0
;
int
r_index
=
i
;
j
=
0
;
if
(
outer_partial
&&
outer_partial
-
i
>
0
&&
outer_partial
<
n
)
{
r_index
=
outer_partial
-
1
;
j
=
outer_partial
-
i
-
1
;
}
do
{
if
(
inner_partial
&&
r_index
>=
inner_partial
)
{
break
;
}
tmp
=
sr
[
r_index
]
+
((
long_comp
)
sa
[
j
])
*
sb
[
i
]
+
carry
;
sr
[
r_index
++
]
=
(
comp
)
tmp
;
/* downsize */
carry
=
tmp
>>
COMP_BIT_SIZE
;
}
while
(
++
j
<
n
);
sr
[
r_index
]
=
carry
;
}
while
(
++
i
<
t
);
bi_free
(
ctx
,
bia
);
bi_free
(
ctx
,
bib
);
return
trim
(
biR
);
}
#ifdef CONFIG_BIGINT_KARATSUBA
/*
* Karatsuba improves on regular multiplication due to only 3 multiplications
* being done instead of 4. The additional additions/subtractions are O(N)
* rather than O(N^2) and so for big numbers it saves on a few operations
*/
static
bigint
*
ICACHE_FLASH_ATTR
karatsuba
(
BI_CTX
*
ctx
,
bigint
*
bia
,
bigint
*
bib
,
int
is_square
)
{
bigint
*
x0
,
*
x1
;
bigint
*
p0
,
*
p1
,
*
p2
;
int
m
;
if
(
is_square
)
{
m
=
(
bia
->
size
+
1
)
/
2
;
}
else
{
m
=
(
max
(
bia
->
size
,
bib
->
size
)
+
1
)
/
2
;
}
x0
=
bi_clone
(
ctx
,
bia
);
x0
->
size
=
m
;
x1
=
bi_clone
(
ctx
,
bia
);
comp_right_shift
(
x1
,
m
);
bi_free
(
ctx
,
bia
);
/* work out the 3 partial products */
if
(
is_square
)
{
p0
=
bi_square
(
ctx
,
bi_copy
(
x0
));
p2
=
bi_square
(
ctx
,
bi_copy
(
x1
));
p1
=
bi_square
(
ctx
,
bi_add
(
ctx
,
x0
,
x1
));
}
else
/* normal multiply */
{
bigint
*
y0
,
*
y1
;
y0
=
bi_clone
(
ctx
,
bib
);
y0
->
size
=
m
;
y1
=
bi_clone
(
ctx
,
bib
);
comp_right_shift
(
y1
,
m
);
bi_free
(
ctx
,
bib
);
p0
=
bi_multiply
(
ctx
,
bi_copy
(
x0
),
bi_copy
(
y0
));
p2
=
bi_multiply
(
ctx
,
bi_copy
(
x1
),
bi_copy
(
y1
));
p1
=
bi_multiply
(
ctx
,
bi_add
(
ctx
,
x0
,
x1
),
bi_add
(
ctx
,
y0
,
y1
));
}
p1
=
bi_subtract
(
ctx
,
bi_subtract
(
ctx
,
p1
,
bi_copy
(
p2
),
NULL
),
bi_copy
(
p0
),
NULL
);
comp_left_shift
(
p1
,
m
);
comp_left_shift
(
p2
,
2
*
m
);
return
bi_add
(
ctx
,
p1
,
bi_add
(
ctx
,
p0
,
p2
));
}
#endif
/**
* @brief Perform a multiplication operation between two bigints.
* @param ctx [in] The bigint session context.
* @param bia [in] A bigint.
* @param bib [in] Another bigint.
* @return The result of the multiplication.
*/
bigint
*
ICACHE_FLASH_ATTR
bi_multiply
(
BI_CTX
*
ctx
,
bigint
*
bia
,
bigint
*
bib
)
{
check
(
bia
);
check
(
bib
);
#ifdef CONFIG_BIGINT_KARATSUBA
if
(
min
(
bia
->
size
,
bib
->
size
)
<
MUL_KARATSUBA_THRESH
)
{
return
regular_multiply
(
ctx
,
bia
,
bib
,
0
,
0
);
}
return
karatsuba
(
ctx
,
bia
,
bib
,
0
);
#else
return
regular_multiply
(
ctx
,
bia
,
bib
,
0
,
0
);
#endif
}
#ifdef CONFIG_BIGINT_SQUARE
/*
* Perform the actual square operion. It takes into account overflow.
*/
static
bigint
*
ICACHE_FLASH_ATTR
regular_square
(
BI_CTX
*
ctx
,
bigint
*
bi
)
{
int
t
=
bi
->
size
;
int
i
=
0
,
j
;
bigint
*
biR
=
alloc
(
ctx
,
t
*
2
+
1
);
comp
*
w
=
biR
->
comps
;
comp
*
x
=
bi
->
comps
;
long_comp
carry
;
os_memset
(
w
,
0
,
biR
->
size
*
COMP_BYTE_SIZE
);
do
{
long_comp
tmp
=
w
[
2
*
i
]
+
(
long_comp
)
x
[
i
]
*
x
[
i
];
w
[
2
*
i
]
=
(
comp
)
tmp
;
carry
=
tmp
>>
COMP_BIT_SIZE
;
for
(
j
=
i
+
1
;
j
<
t
;
j
++
)
{
uint8_t
c
=
0
;
long_comp
xx
=
(
long_comp
)
x
[
i
]
*
x
[
j
];
if
((
COMP_MAX
-
xx
)
<
xx
)
c
=
1
;
tmp
=
(
xx
<<
1
);
if
((
COMP_MAX
-
tmp
)
<
w
[
i
+
j
])
c
=
1
;
tmp
+=
w
[
i
+
j
];
if
((
COMP_MAX
-
tmp
)
<
carry
)
c
=
1
;
tmp
+=
carry
;
w
[
i
+
j
]
=
(
comp
)
tmp
;
carry
=
tmp
>>
COMP_BIT_SIZE
;
if
(
c
)
carry
+=
COMP_RADIX
;
}
tmp
=
w
[
i
+
t
]
+
carry
;
w
[
i
+
t
]
=
(
comp
)
tmp
;
w
[
i
+
t
+
1
]
=
tmp
>>
COMP_BIT_SIZE
;
}
while
(
++
i
<
t
);
bi_free
(
ctx
,
bi
);
return
trim
(
biR
);
}
/**
* @brief Perform a square operation on a bigint.
* @param ctx [in] The bigint session context.
* @param bia [in] A bigint.
* @return The result of the multiplication.
*/
bigint
*
ICACHE_FLASH_ATTR
bi_square
(
BI_CTX
*
ctx
,
bigint
*
bia
)
{
check
(
bia
);
#ifdef CONFIG_BIGINT_KARATSUBA
if
(
bia
->
size
<
SQU_KARATSUBA_THRESH
)
{
return
regular_square
(
ctx
,
bia
);
}
return
karatsuba
(
ctx
,
bia
,
NULL
,
1
);
#else
return
regular_square
(
ctx
,
bia
);
#endif
}
#endif
/**
* @brief Compare two bigints.
* @param bia [in] A bigint.
* @param bib [in] Another bigint.
* @return -1 if smaller, 1 if larger and 0 if equal.
*/
int
ICACHE_FLASH_ATTR
bi_compare
(
bigint
*
bia
,
bigint
*
bib
)
{
int
r
,
i
;
check
(
bia
);
check
(
bib
);
if
(
bia
->
size
>
bib
->
size
)
r
=
1
;
else
if
(
bia
->
size
<
bib
->
size
)
r
=
-
1
;
else
{
comp
*
a
=
bia
->
comps
;
comp
*
b
=
bib
->
comps
;
/* Same number of components. Compare starting from the high end
* and working down. */
r
=
0
;
i
=
bia
->
size
-
1
;
do
{
if
(
a
[
i
]
>
b
[
i
])
{
r
=
1
;
break
;
}
else
if
(
a
[
i
]
<
b
[
i
])
{
r
=
-
1
;
break
;
}
}
while
(
--
i
>=
0
);
}
return
r
;
}
/*
* Allocate and zero more components. Does not consume bi.
*/
static
void
ICACHE_FLASH_ATTR
more_comps
(
bigint
*
bi
,
int
n
)
{
if
(
n
>
bi
->
max_comps
)
{
bi
->
max_comps
=
max
(
bi
->
max_comps
*
2
,
n
);
bi
->
comps
=
(
comp
*
)
os_realloc
(
bi
->
comps
,
bi
->
max_comps
*
COMP_BYTE_SIZE
);
}
if
(
n
>
bi
->
size
)
{
os_memset
(
&
bi
->
comps
[
bi
->
size
],
0
,
(
n
-
bi
->
size
)
*
COMP_BYTE_SIZE
);
}
bi
->
size
=
n
;
}
/*
* Make a new empty bigint. It may just use an old one if one is available.
* Otherwise get one off the heap.
*/
static
bigint
*
ICACHE_FLASH_ATTR
alloc
(
BI_CTX
*
ctx
,
int
size
)
{
bigint
*
biR
;
/* Can we recycle an old bigint? */
if
(
ctx
->
free_list
!=
NULL
)
{
biR
=
ctx
->
free_list
;
ctx
->
free_list
=
biR
->
next
;
ctx
->
free_count
--
;
if
(
biR
->
refs
!=
0
)
{
#ifdef CONFIG_SSL_FULL_MODE
ssl_printf
(
"alloc: refs was not 0
\n
"
);
#endif
return
;
/* wujg : org ----> abort(); */
}
more_comps
(
biR
,
size
);
}
else
{
/* No free bigints available - create a new one. */
biR
=
(
bigint
*
)
os_malloc
(
sizeof
(
bigint
));
biR
->
comps
=
(
comp
*
)
os_malloc
(
size
*
COMP_BYTE_SIZE
);
biR
->
max_comps
=
size
;
/* give some space to spare */
}
biR
->
size
=
size
;
biR
->
refs
=
1
;
biR
->
next
=
NULL
;
ctx
->
active_count
++
;
return
biR
;
}
/*
* Work out the highest '1' bit in an exponent. Used when doing sliding-window
* exponentiation.
*/
static
int
ICACHE_FLASH_ATTR
find_max_exp_index
(
bigint
*
biexp
)
{
int
i
=
COMP_BIT_SIZE
-
1
;
comp
shift
=
COMP_RADIX
/
2
;
comp
test
=
biexp
->
comps
[
biexp
->
size
-
1
];
/* assume no leading zeroes */
check
(
biexp
);
do
{
if
(
test
&
shift
)
{
return
i
+
(
biexp
->
size
-
1
)
*
COMP_BIT_SIZE
;
}
shift
>>=
1
;
}
while
(
i
--
!=
0
);
return
-
1
;
/* error - must have been a leading 0 */
}
/*
* Is a particular bit is an exponent 1 or 0? Used when doing sliding-window
* exponentiation.
*/
static
int
ICACHE_FLASH_ATTR
exp_bit_is_one
(
bigint
*
biexp
,
int
offset
)
{
comp
test
=
biexp
->
comps
[
offset
/
COMP_BIT_SIZE
];
int
num_shifts
=
offset
%
COMP_BIT_SIZE
;
comp
shift
=
1
;
int
i
;
check
(
biexp
);
for
(
i
=
0
;
i
<
num_shifts
;
i
++
)
{
shift
<<=
1
;
}
return
(
test
&
shift
)
!=
0
;
}
#ifdef CONFIG_BIGINT_CHECK_ON
/*
* Perform a sanity check on bi.
*/
static
void
ICACHE_FLASH_ATTR
check
(
const
bigint
*
bi
)
{
if
(
bi
->
refs
<=
0
)
{
ssl_printf
(
"check: zero or negative refs in bigint
\n
"
);
return
;
/* wujg : org ----> abort(); */
}
if
(
bi
->
next
!=
NULL
)
{
ssl_printf
(
"check: attempt to use a bigint from "
"the free list
\n
"
);
return
;
/* wujg : org ----> abort(); */
}
}
#endif
/*
* Delete any leading 0's (and allow for 0).
*/
static
bigint
*
ICACHE_FLASH_ATTR
trim
(
bigint
*
bi
)
{
check
(
bi
);
while
(
bi
->
comps
[
bi
->
size
-
1
]
==
0
&&
bi
->
size
>
1
)
{
bi
->
size
--
;
}
return
bi
;
}
#if defined(CONFIG_BIGINT_MONTGOMERY)
/**
* @brief Perform a single montgomery reduction.
* @param ctx [in] The bigint session context.
* @param bixy [in] A bigint.
* @return The result of the montgomery reduction.
*/
bigint
*
ICACHE_FLASH_ATTR
bi_mont
(
BI_CTX
*
ctx
,
bigint
*
bixy
)
{
int
i
=
0
,
n
;
uint8_t
mod_offset
=
ctx
->
mod_offset
;
bigint
*
bim
=
ctx
->
bi_mod
[
mod_offset
];
comp
mod_inv
=
ctx
->
N0_dash
[
mod_offset
];
check
(
bixy
);
if
(
ctx
->
use_classical
)
/* just use classical instead */
{
return
bi_mod
(
ctx
,
bixy
);
}
n
=
bim
->
size
;
do
{
bixy
=
bi_add
(
ctx
,
bixy
,
comp_left_shift
(
bi_int_multiply
(
ctx
,
bim
,
bixy
->
comps
[
i
]
*
mod_inv
),
i
));
}
while
(
++
i
<
n
);
comp_right_shift
(
bixy
,
n
);
if
(
bi_compare
(
bixy
,
bim
)
>=
0
)
{
bixy
=
bi_subtract
(
ctx
,
bixy
,
bim
,
NULL
);
}
return
bixy
;
}
#elif defined(CONFIG_BIGINT_BARRETT)
/*
* Stomp on the most significant components to give the illusion of a "mod base
* radix" operation
*/
static
bigint
*
ICACHE_FLASH_ATTR
comp_mod
(
bigint
*
bi
,
int
mod
)
{
check
(
bi
);
if
(
bi
->
size
>
mod
)
{
bi
->
size
=
mod
;
}
return
bi
;
}
/**
* @brief Perform a single Barrett reduction.
* @param ctx [in] The bigint session context.
* @param bi [in] A bigint.
* @return The result of the Barrett reduction.
*/
bigint
*
ICACHE_FLASH_ATTR
bi_barrett
(
BI_CTX
*
ctx
,
bigint
*
bi
)
{
bigint
*
q1
,
*
q2
,
*
q3
,
*
r1
,
*
r2
,
*
r
;
uint8_t
mod_offset
=
ctx
->
mod_offset
;
bigint
*
bim
=
ctx
->
bi_mod
[
mod_offset
];
int
k
=
bim
->
size
;
check
(
bi
);
check
(
bim
);
/* use Classical method instead - Barrett cannot help here */
if
(
bi
->
size
>
k
*
2
)
{
return
bi_mod
(
ctx
,
bi
);
}
q1
=
comp_right_shift
(
bi_clone
(
ctx
,
bi
),
k
-
1
);
/* do outer partial multiply */
q2
=
regular_multiply
(
ctx
,
q1
,
ctx
->
bi_mu
[
mod_offset
],
0
,
k
-
1
);
q3
=
comp_right_shift
(
q2
,
k
+
1
);
r1
=
comp_mod
(
bi
,
k
+
1
);
/* do inner partial multiply */
r2
=
comp_mod
(
regular_multiply
(
ctx
,
q3
,
bim
,
k
+
1
,
0
),
k
+
1
);
r
=
bi_subtract
(
ctx
,
r1
,
r2
,
NULL
);
/* if (r >= m) r = r - m; */
if
(
bi_compare
(
r
,
bim
)
>=
0
)
{
r
=
bi_subtract
(
ctx
,
r
,
bim
,
NULL
);
}
return
r
;
}
#endif
/* CONFIG_BIGINT_BARRETT */
#ifdef CONFIG_BIGINT_SLIDING_WINDOW
/*
* Work out g1, g3, g5, g7... etc for the sliding-window algorithm
*/
static
void
ICACHE_FLASH_ATTR
precompute_slide_window
(
BI_CTX
*
ctx
,
int
window
,
bigint
*
g1
)
{
int
k
=
1
,
i
;
bigint
*
g2
;
for
(
i
=
0
;
i
<
window
-
1
;
i
++
)
/* compute 2^(window-1) */
{
k
<<=
1
;
}
ctx
->
g
=
(
bigint
**
)
os_malloc
(
k
*
sizeof
(
bigint
*
));
ctx
->
g
[
0
]
=
bi_clone
(
ctx
,
g1
);
bi_permanent
(
ctx
->
g
[
0
]);
g2
=
bi_residue
(
ctx
,
bi_square
(
ctx
,
ctx
->
g
[
0
]));
/* g^2 */
for
(
i
=
1
;
i
<
k
;
i
++
)
{
ctx
->
g
[
i
]
=
bi_residue
(
ctx
,
bi_multiply
(
ctx
,
ctx
->
g
[
i
-
1
],
bi_copy
(
g2
)));
bi_permanent
(
ctx
->
g
[
i
]);
}
bi_free
(
ctx
,
g2
);
ctx
->
window
=
k
;
}
#endif
/**
* @brief Perform a modular exponentiation.
*
* This function requires bi_set_mod() to have been called previously. This is
* one of the optimisations used for performance.
* @param ctx [in] The bigint session context.
* @param bi [in] The bigint on which to perform the mod power operation.
* @param biexp [in] The bigint exponent.
* @return The result of the mod exponentiation operation
* @see bi_set_mod().
*/
bigint
*
ICACHE_FLASH_ATTR
bi_mod_power
(
BI_CTX
*
ctx
,
bigint
*
bi
,
bigint
*
biexp
)
{
int
i
=
find_max_exp_index
(
biexp
),
j
,
window_size
=
1
;
bigint
*
biR
=
int_to_bi
(
ctx
,
1
);
#if defined(CONFIG_BIGINT_MONTGOMERY)
uint8_t
mod_offset
=
ctx
->
mod_offset
;
if
(
!
ctx
->
use_classical
)
{
/* preconvert */
bi
=
bi_mont
(
ctx
,
bi_multiply
(
ctx
,
bi
,
ctx
->
bi_RR_mod_m
[
mod_offset
]));
/* x' */
bi_free
(
ctx
,
biR
);
biR
=
ctx
->
bi_R_mod_m
[
mod_offset
];
/* A */
}
#endif
check
(
bi
);
check
(
biexp
);
#ifdef CONFIG_BIGINT_SLIDING_WINDOW
for
(
j
=
i
;
j
>
32
;
j
/=
5
)
/* work out an optimum size */
window_size
++
;
/* work out the slide constants */
precompute_slide_window
(
ctx
,
window_size
,
bi
);
#else
/* just one constant */
ctx
->
g
=
(
bigint
**
)
os_malloc
(
sizeof
(
bigint
*
));
ctx
->
g
[
0
]
=
bi_clone
(
ctx
,
bi
);
ctx
->
window
=
1
;
bi_permanent
(
ctx
->
g
[
0
]);
#endif
/* if sliding-window is off, then only one bit will be done at a time and
* will reduce to standard left-to-right exponentiation */
do
{
if
(
exp_bit_is_one
(
biexp
,
i
))
{
int
l
=
i
-
window_size
+
1
;
int
part_exp
=
0
;
if
(
l
<
0
)
/* LSB of exponent will always be 1 */
l
=
0
;
else
{
while
(
exp_bit_is_one
(
biexp
,
l
)
==
0
)
l
++
;
/* go back up */
}
/* build up the section of the exponent */
for
(
j
=
i
;
j
>=
l
;
j
--
)
{
biR
=
bi_residue
(
ctx
,
bi_square
(
ctx
,
biR
));
if
(
exp_bit_is_one
(
biexp
,
j
))
part_exp
++
;
if
(
j
!=
l
)
part_exp
<<=
1
;
}
part_exp
=
(
part_exp
-
1
)
/
2
;
/* adjust for array */
biR
=
bi_residue
(
ctx
,
bi_multiply
(
ctx
,
biR
,
ctx
->
g
[
part_exp
]));
i
=
l
-
1
;
}
else
/* square it */
{
biR
=
bi_residue
(
ctx
,
bi_square
(
ctx
,
biR
));
i
--
;
}
}
while
(
i
>=
0
);
/* cleanup */
for
(
i
=
0
;
i
<
ctx
->
window
;
i
++
)
{
bi_depermanent
(
ctx
->
g
[
i
]);
bi_free
(
ctx
,
ctx
->
g
[
i
]);
}
os_free
(
ctx
->
g
);
bi_free
(
ctx
,
bi
);
bi_free
(
ctx
,
biexp
);
#if defined CONFIG_BIGINT_MONTGOMERY
return
ctx
->
use_classical
?
biR
:
bi_mont
(
ctx
,
biR
);
/* convert back */
#else
/* CONFIG_BIGINT_CLASSICAL or CONFIG_BIGINT_BARRETT */
return
biR
;
#endif
}
#ifdef CONFIG_SSL_CERT_VERIFICATION
/**
* @brief Perform a modular exponentiation using a temporary modulus.
*
* We need this function to check the signatures of certificates. The modulus
* of this function is temporary as it's just used for authentication.
* @param ctx [in] The bigint session context.
* @param bi [in] The bigint to perform the exp/mod.
* @param bim [in] The temporary modulus.
* @param biexp [in] The bigint exponent.
* @return The result of the mod exponentiation operation
* @see bi_set_mod().
*/
bigint
*
ICACHE_FLASH_ATTR
bi_mod_power2
(
BI_CTX
*
ctx
,
bigint
*
bi
,
bigint
*
bim
,
bigint
*
biexp
)
{
bigint
*
biR
,
*
tmp_biR
;
/* Set up a temporary bigint context and transfer what we need between
* them. We need to do this since we want to keep the original modulus
* which is already in this context. This operation is only called when
* doing peer verification, and so is not expensive :-) */
BI_CTX
*
tmp_ctx
=
bi_initialize
();
bi_set_mod
(
tmp_ctx
,
bi_clone
(
tmp_ctx
,
bim
),
BIGINT_M_OFFSET
);
tmp_biR
=
bi_mod_power
(
tmp_ctx
,
bi_clone
(
tmp_ctx
,
bi
),
bi_clone
(
tmp_ctx
,
biexp
));
biR
=
bi_clone
(
ctx
,
tmp_biR
);
bi_free
(
tmp_ctx
,
tmp_biR
);
bi_free_mod
(
tmp_ctx
,
BIGINT_M_OFFSET
);
bi_terminate
(
tmp_ctx
);
bi_free
(
ctx
,
bi
);
bi_free
(
ctx
,
bim
);
bi_free
(
ctx
,
biexp
);
return
biR
;
}
#endif
#ifdef CONFIG_BIGINT_CRT
/**
* @brief Use the Chinese Remainder Theorem to quickly perform RSA decrypts.
*
* @param ctx [in] The bigint session context.
* @param bi [in] The bigint to perform the exp/mod.
* @param dP [in] CRT's dP bigint
* @param dQ [in] CRT's dQ bigint
* @param p [in] CRT's p bigint
* @param q [in] CRT's q bigint
* @param qInv [in] CRT's qInv bigint
* @return The result of the CRT operation
*/
bigint
*
ICACHE_FLASH_ATTR
bi_crt
(
BI_CTX
*
ctx
,
bigint
*
bi
,
bigint
*
dP
,
bigint
*
dQ
,
bigint
*
p
,
bigint
*
q
,
bigint
*
qInv
)
{
bigint
*
m1
,
*
m2
,
*
h
;
/* Montgomery has a condition the 0 < x, y < m and these products violate
* that condition. So disable Montgomery when using CRT */
#if defined(CONFIG_BIGINT_MONTGOMERY)
ctx
->
use_classical
=
1
;
#endif
ctx
->
mod_offset
=
BIGINT_P_OFFSET
;
m1
=
bi_mod_power
(
ctx
,
bi_copy
(
bi
),
dP
);
ctx
->
mod_offset
=
BIGINT_Q_OFFSET
;
m2
=
bi_mod_power
(
ctx
,
bi
,
dQ
);
h
=
bi_subtract
(
ctx
,
bi_add
(
ctx
,
m1
,
p
),
bi_copy
(
m2
),
NULL
);
h
=
bi_multiply
(
ctx
,
h
,
qInv
);
ctx
->
mod_offset
=
BIGINT_P_OFFSET
;
h
=
bi_residue
(
ctx
,
h
);
#if defined(CONFIG_BIGINT_MONTGOMERY)
ctx
->
use_classical
=
0
;
/* reset for any further operation */
#endif
return
bi_add
(
ctx
,
m2
,
bi_multiply
(
ctx
,
q
,
h
));
}
#endif
/** @} */
app/ssl/crypto/ssl_crypto_misc.c
deleted
100644 → 0
View file @
21c4e110
/*
* Copyright (c) 2007, Cameron Rich
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the axTLS project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* Some misc. routines to help things out
*/
#include <stdlib.h>
//#include <string.h>
//#include <stdarg.h>
//#include <stdio.h>
#include "ssl/ssl_os_port.h"
#include "ssl/ssl_crypto_misc.h"
#ifdef CONFIG_WIN32_USE_CRYPTO_LIB
#include "wincrypt.h"
#endif
#ifndef WIN32
static
int
rng_fd
=
-
1
;
#elif defined(CONFIG_WIN32_USE_CRYPTO_LIB)
static
HCRYPTPROV
gCryptProv
;
#endif
#if (!defined(CONFIG_USE_DEV_URANDOM) && !defined(CONFIG_WIN32_USE_CRYPTO_LIB))
/* change to processor registers as appropriate */
#define ENTROPY_POOL_SIZE 32
#define ENTROPY_COUNTER1 ((((uint64_t)tv.tv_sec)<<32) | tv.tv_usec)
#define ENTROPY_COUNTER2 rand()
static
uint8_t
entropy_pool
[
ENTROPY_POOL_SIZE
];
#endif
const
char
*
const
unsupported_str
=
"Error: Feature not supported
\n
"
;
#ifndef CONFIG_SSL_SKELETON_MODE
/**
* Retrieve a file and put it into memory
* @return The size of the file, or -1 on failure.
*/
int
get_file
(
const
char
*
filename
,
uint8_t
**
buf
)
{
#if 0
int total_bytes = 0;
int bytes_read = 0;
int filesize;
FILE *stream = fopen(filename, "rb");
if (stream == NULL)
{
#ifdef CONFIG_SSL_FULL_MODE
printf("file '%s' does not exist\n", filename); //TTY_FLUSH();
#endif
return -1;
}
/* Win CE doesn't support stat() */
fseek(stream, 0, SEEK_END);
filesize = ftell(stream);
*buf = (uint8_t *)os_malloc(filesize);
fseek(stream, 0, SEEK_SET);
do
{
bytes_read = fread(*buf+total_bytes, 1, filesize-total_bytes, stream);
total_bytes += bytes_read;
} while (total_bytes < filesize && bytes_read > 0);
fclose(stream);
return filesize;
#endif
return
0
;
}
#endif
/**
* Initialise the Random Number Generator engine.
* - On Win32 use the platform SDK's crypto engine.
* - On Linux use /dev/urandom
* - If none of these work then use a custom RNG.
*/
EXP_FUNC
void
STDCALL
ICACHE_FLASH_ATTR
RNG_initialize
()
{
#if !defined(WIN32) && defined(CONFIG_USE_DEV_URANDOM)
rng_fd
=
ax_open
(
"/dev/urandom"
,
O_RDONLY
);
#elif defined(WIN32) && defined(CONFIG_WIN32_USE_CRYPTO_LIB)
if
(
!
CryptAcquireContext
(
&
gCryptProv
,
NULL
,
NULL
,
PROV_RSA_FULL
,
0
))
{
if
(
GetLastError
()
==
NTE_BAD_KEYSET
&&
!
CryptAcquireContext
(
&
gCryptProv
,
NULL
,
NULL
,
PROV_RSA_FULL
,
CRYPT_NEWKEYSET
))
{
printf
(
"CryptoLib: %x
\n
"
,
unsupported_str
,
GetLastError
());
exit
(
1
);
}
}
#else
/* start of with a stack to copy across */
int
i
;
os_memcpy
(
entropy_pool
,
&
i
,
ENTROPY_POOL_SIZE
);
srand
((
unsigned
int
)
&
i
);
#endif
}
/**
* If no /dev/urandom, then initialise the RNG with something interesting.
*/
EXP_FUNC
void
STDCALL
ICACHE_FLASH_ATTR
RNG_custom_init
(
const
uint8_t
*
seed_buf
,
int
size
)
{
#if defined(WIN32) || defined(CONFIG_WIN32_USE_CRYPTO_LIB)
int
i
;
for
(
i
=
0
;
i
<
ENTROPY_POOL_SIZE
&&
i
<
size
;
i
++
)
entropy_pool
[
i
]
^=
seed_buf
[
i
];
#endif
}
/**
* Terminate the RNG engine.
*/
EXP_FUNC
void
STDCALL
ICACHE_FLASH_ATTR
RNG_terminate
(
void
)
{
#ifndef WIN32
// close(rng_fd);
#elif defined(CONFIG_WIN32_USE_CRYPTO_LIB)
CryptReleaseContext
(
gCryptProv
,
0
);
#endif
}
/**
* Set a series of bytes with a random number. Individual bytes can be 0
*/
EXP_FUNC
void
STDCALL
ICACHE_FLASH_ATTR
get_random
(
int
num_rand_bytes
,
uint8_t
*
rand_data
)
{
#if !defined(WIN32) && defined(CONFIG_USE_DEV_URANDOM)
/* use the Linux default */
read
(
rng_fd
,
rand_data
,
num_rand_bytes
);
/* read from /dev/urandom */
#elif defined(WIN32) && defined(CONFIG_WIN32_USE_CRYPTO_LIB)
/* use Microsoft Crypto Libraries */
CryptGenRandom
(
gCryptProv
,
num_rand_bytes
,
rand_data
);
#else
/* nothing else to use, so use a custom RNG */
/* The method we use when we've got nothing better. Use RC4, time
and a couple of random seeds to generate a random sequence */
RC4_CTX
rng_ctx
;
struct
timeval
tv
;
MD5_CTX
rng_digest_ctx
;
uint8_t
digest
[
MD5_SIZE
];
uint64_t
*
ep
;
int
i
;
/* A proper implementation would use counters etc for entropy */
// gettimeofday(&tv, NULL);
ep
=
(
uint64_t
*
)
entropy_pool
;
ep
[
0
]
^=
ENTROPY_COUNTER1
;
ep
[
1
]
^=
ENTROPY_COUNTER2
;
/* use a digested version of the entropy pool as a key */
MD5_Init
(
&
rng_digest_ctx
);
MD5_Update
(
&
rng_digest_ctx
,
entropy_pool
,
ENTROPY_POOL_SIZE
);
MD5_Final
(
digest
,
&
rng_digest_ctx
);
/* come up with the random sequence */
RC4_setup
(
&
rng_ctx
,
digest
,
MD5_SIZE
);
/* use as a key */
os_memcpy
(
rand_data
,
entropy_pool
,
num_rand_bytes
<
ENTROPY_POOL_SIZE
?
num_rand_bytes
:
ENTROPY_POOL_SIZE
);
RC4_crypt
(
&
rng_ctx
,
rand_data
,
rand_data
,
num_rand_bytes
);
/* move things along */
for
(
i
=
ENTROPY_POOL_SIZE
-
1
;
i
>=
MD5_SIZE
;
i
--
)
entropy_pool
[
i
]
=
entropy_pool
[
i
-
MD5_SIZE
];
/* insert the digest at the start of the entropy pool */
os_memcpy
(
entropy_pool
,
digest
,
MD5_SIZE
);
#endif
}
/**
* Set a series of bytes with a random number. Individual bytes are not zero.
*/
void
ICACHE_FLASH_ATTR
get_random_NZ
(
int
num_rand_bytes
,
uint8_t
*
rand_data
)
{
int
i
;
get_random
(
num_rand_bytes
,
rand_data
);
for
(
i
=
0
;
i
<
num_rand_bytes
;
i
++
)
{
while
(
rand_data
[
i
]
==
0
)
/* can't be 0 */
rand_data
[
i
]
=
(
uint8_t
)(
rand
());
}
}
/**
* Some useful diagnostic routines
*/
#if defined(CONFIG_SSL_FULL_MODE) || defined(CONFIG_DEBUG)
int
hex_finish
;
int
hex_index
;
static
void
ICACHE_FLASH_ATTR
print_hex_init
(
int
finish
)
{
hex_finish
=
finish
;
hex_index
=
0
;
}
static
void
ICACHE_FLASH_ATTR
print_hex
(
uint8_t
hex
)
{
static
int
column
;
if
(
hex_index
==
0
)
{
column
=
0
;
}
ssl_printf
(
"%02x "
,
hex
);
if
(
++
column
==
8
)
{
ssl_printf
(
": "
);
}
else
if
(
column
>=
16
)
{
ssl_printf
(
"
\n
"
);
column
=
0
;
}
if
(
++
hex_index
>=
hex_finish
&&
column
>
0
)
{
ssl_printf
(
"
\n
"
);
}
}
/**
* Spit out a blob of data for diagnostics. The data is is a nice column format
* for easy reading.
*
* @param format [in] The string (with possible embedded format characters)
* @param size [in] The number of numbers to print
* @param data [in] The start of data to use
* @param ... [in] Any additional arguments
*/
EXP_FUNC
void
STDCALL
ICACHE_FLASH_ATTR
print_blob
(
const
char
*
format
,
const
uint8_t
*
data
,
int
size
,
...)
{
// int i;
// char tmp[80];
// va_list(ap);
// va_start(ap, size);
// sprintf(tmp, "%s\n", format);
// vprintf(tmp, ap);
// print_hex_init(size);
// for (i = 0; i < size; i++)
// {
// print_hex(data[i]);
// }
// va_end(ap);
// TTY_FLUSH();
}
#elif defined(WIN32)
/* VC6.0 doesn't handle variadic macros */
EXP_FUNC
void
STDCALL
print_blob
(
const
char
*
format
,
const
unsigned
char
*
data
,
int
size
,
...)
{}
#endif
#if defined(CONFIG_SSL_HAS_PEM) || defined(CONFIG_HTTP_HAS_AUTHORIZATION)
/* base64 to binary lookup table */
static
const
uint8_t
map
[
128
]
=
{
255
,
255
,
255
,
255
,
255
,
255
,
255
,
255
,
255
,
255
,
255
,
255
,
255
,
255
,
255
,
255
,
255
,
255
,
255
,
255
,
255
,
255
,
255
,
255
,
255
,
255
,
255
,
255
,
255
,
255
,
255
,
255
,
255
,
255
,
255
,
255
,
255
,
255
,
255
,
255
,
255
,
255
,
255
,
62
,
255
,
255
,
255
,
63
,
52
,
53
,
54
,
55
,
56
,
57
,
58
,
59
,
60
,
61
,
255
,
255
,
255
,
254
,
255
,
255
,
255
,
0
,
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
,
9
,
10
,
11
,
12
,
13
,
14
,
15
,
16
,
17
,
18
,
19
,
20
,
21
,
22
,
23
,
24
,
25
,
255
,
255
,
255
,
255
,
255
,
255
,
26
,
27
,
28
,
29
,
30
,
31
,
32
,
33
,
34
,
35
,
36
,
37
,
38
,
39
,
40
,
41
,
42
,
43
,
44
,
45
,
46
,
47
,
48
,
49
,
50
,
51
,
255
,
255
,
255
,
255
,
255
};
EXP_FUNC
int
STDCALL
ICACHE_FLASH_ATTR
base64_decode
(
const
char
*
in
,
int
len
,
uint8_t
*
out
,
int
*
outlen
)
{
int
g
,
t
,
x
,
y
,
z
;
uint8_t
c
;
int
ret
=
-
1
;
g
=
3
;
for
(
x
=
y
=
z
=
t
=
0
;
x
<
len
;
x
++
)
{
if
((
c
=
map
[
in
[
x
]
&
0x7F
])
==
0xff
)
continue
;
if
(
c
==
254
)
/* this is the end... */
{
c
=
0
;
if
(
--
g
<
0
)
goto
error
;
}
else
if
(
g
!=
3
)
/* only allow = at end */
goto
error
;
t
=
(
t
<<
6
)
|
c
;
if
(
++
y
==
4
)
{
out
[
z
++
]
=
(
uint8_t
)((
t
>>
16
)
&
255
);
if
(
g
>
1
)
out
[
z
++
]
=
(
uint8_t
)((
t
>>
8
)
&
255
);
if
(
g
>
2
)
out
[
z
++
]
=
(
uint8_t
)(
t
&
255
);
y
=
t
=
0
;
}
/* check that we don't go past the output buffer */
if
(
z
>
*
outlen
)
goto
error
;
}
if
(
y
!=
0
)
goto
error
;
*
outlen
=
z
;
ret
=
0
;
error:
#ifdef CONFIG_SSL_FULL_MODE
if
(
ret
<
0
)
ssl_printf
(
"Error: Invalid base64
\n
"
);
//TTY_FLUSH();
#endif
//TTY_FLUSH();
return
ret
;
}
#endif
app/ssl/crypto/ssl_hmac.c
deleted
100644 → 0
View file @
21c4e110
/*
* Copyright (c) 2007, Cameron Rich
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the axTLS project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* HMAC implementation - This code was originally taken from RFC2104
* See http://www.ietf.org/rfc/rfc2104.txt and
* http://www.faqs.org/rfcs/rfc2202.html
*/
//#include <string.h>
#include "ssl/ssl_os_port.h"
#include "ssl/ssl_crypto.h"
/**
* Perform HMAC-MD5
* NOTE: does not handle keys larger than the block size.
*/
void
ICACHE_FLASH_ATTR
ssl_hmac_md5
(
const
uint8_t
*
msg
,
int
length
,
const
uint8_t
*
key
,
int
key_len
,
uint8_t
*
digest
)
{
MD5_CTX
context
;
uint8_t
k_ipad
[
64
];
uint8_t
k_opad
[
64
];
int
i
;
os_memset
(
k_ipad
,
0
,
sizeof
k_ipad
);
os_memset
(
k_opad
,
0
,
sizeof
k_opad
);
os_memcpy
(
k_ipad
,
key
,
key_len
);
os_memcpy
(
k_opad
,
key
,
key_len
);
for
(
i
=
0
;
i
<
64
;
i
++
)
{
k_ipad
[
i
]
^=
0x36
;
k_opad
[
i
]
^=
0x5c
;
}
MD5_Init
(
&
context
);
MD5_Update
(
&
context
,
k_ipad
,
64
);
MD5_Update
(
&
context
,
msg
,
length
);
MD5_Final
(
digest
,
&
context
);
MD5_Init
(
&
context
);
MD5_Update
(
&
context
,
k_opad
,
64
);
MD5_Update
(
&
context
,
digest
,
MD5_SIZE
);
MD5_Final
(
digest
,
&
context
);
}
/**
* Perform HMAC-SHA1
* NOTE: does not handle keys larger than the block size.
*/
void
ICACHE_FLASH_ATTR
ssl_hmac_sha1
(
const
uint8_t
*
msg
,
int
length
,
const
uint8_t
*
key
,
int
key_len
,
uint8_t
*
digest
)
{
SHA1_CTX
context
;
uint8_t
k_ipad
[
64
];
uint8_t
k_opad
[
64
];
int
i
;
os_memset
(
k_ipad
,
0
,
sizeof
k_ipad
);
os_memset
(
k_opad
,
0
,
sizeof
k_opad
);
os_memcpy
(
k_ipad
,
key
,
key_len
);
os_memcpy
(
k_opad
,
key
,
key_len
);
for
(
i
=
0
;
i
<
64
;
i
++
)
{
k_ipad
[
i
]
^=
0x36
;
k_opad
[
i
]
^=
0x5c
;
}
SHA1_Init
(
&
context
);
SHA1_Update
(
&
context
,
k_ipad
,
64
);
SHA1_Update
(
&
context
,
msg
,
length
);
SHA1_Final
(
digest
,
&
context
);
SHA1_Init
(
&
context
);
SHA1_Update
(
&
context
,
k_opad
,
64
);
SHA1_Update
(
&
context
,
digest
,
SHA1_SIZE
);
SHA1_Final
(
digest
,
&
context
);
}
app/ssl/crypto/ssl_md2.c
deleted
100644 → 0
View file @
21c4e110
/*
* Copyright (c) 2007, Cameron Rich
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the axTLS project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* RFC 1115/1319 compliant MD2 implementation
* The MD2 algorithm was designed by Ron Rivest in 1989.
*
* http://www.ietf.org/rfc/rfc1115.txt
* http://www.ietf.org/rfc/rfc1319.txt
*/
//#include <string.h>
//#include <stdio.h>
#include "ssl/ssl_os_port.h"
#include "ssl/ssl_crypto.h"
//#include "os.h"
#include "lwip/mem.h"
/**
* This code is only here to enable the verification of Verisign root
* certificates. So only enable it for verification mode.
*/
#ifdef CONFIG_SSL_CERT_VERIFICATION
static
const
uint8_t
PI_SUBST
[
256
]
=
{
0x29
,
0x2E
,
0x43
,
0xC9
,
0xA2
,
0xD8
,
0x7C
,
0x01
,
0x3D
,
0x36
,
0x54
,
0xA1
,
0xEC
,
0xF0
,
0x06
,
0x13
,
0x62
,
0xA7
,
0x05
,
0xF3
,
0xC0
,
0xC7
,
0x73
,
0x8C
,
0x98
,
0x93
,
0x2B
,
0xD9
,
0xBC
,
0x4C
,
0x82
,
0xCA
,
0x1E
,
0x9B
,
0x57
,
0x3C
,
0xFD
,
0xD4
,
0xE0
,
0x16
,
0x67
,
0x42
,
0x6F
,
0x18
,
0x8A
,
0x17
,
0xE5
,
0x12
,
0xBE
,
0x4E
,
0xC4
,
0xD6
,
0xDA
,
0x9E
,
0xDE
,
0x49
,
0xA0
,
0xFB
,
0xF5
,
0x8E
,
0xBB
,
0x2F
,
0xEE
,
0x7A
,
0xA9
,
0x68
,
0x79
,
0x91
,
0x15
,
0xB2
,
0x07
,
0x3F
,
0x94
,
0xC2
,
0x10
,
0x89
,
0x0B
,
0x22
,
0x5F
,
0x21
,
0x80
,
0x7F
,
0x5D
,
0x9A
,
0x5A
,
0x90
,
0x32
,
0x27
,
0x35
,
0x3E
,
0xCC
,
0xE7
,
0xBF
,
0xF7
,
0x97
,
0x03
,
0xFF
,
0x19
,
0x30
,
0xB3
,
0x48
,
0xA5
,
0xB5
,
0xD1
,
0xD7
,
0x5E
,
0x92
,
0x2A
,
0xAC
,
0x56
,
0xAA
,
0xC6
,
0x4F
,
0xB8
,
0x38
,
0xD2
,
0x96
,
0xA4
,
0x7D
,
0xB6
,
0x76
,
0xFC
,
0x6B
,
0xE2
,
0x9C
,
0x74
,
0x04
,
0xF1
,
0x45
,
0x9D
,
0x70
,
0x59
,
0x64
,
0x71
,
0x87
,
0x20
,
0x86
,
0x5B
,
0xCF
,
0x65
,
0xE6
,
0x2D
,
0xA8
,
0x02
,
0x1B
,
0x60
,
0x25
,
0xAD
,
0xAE
,
0xB0
,
0xB9
,
0xF6
,
0x1C
,
0x46
,
0x61
,
0x69
,
0x34
,
0x40
,
0x7E
,
0x0F
,
0x55
,
0x47
,
0xA3
,
0x23
,
0xDD
,
0x51
,
0xAF
,
0x3A
,
0xC3
,
0x5C
,
0xF9
,
0xCE
,
0xBA
,
0xC5
,
0xEA
,
0x26
,
0x2C
,
0x53
,
0x0D
,
0x6E
,
0x85
,
0x28
,
0x84
,
0x09
,
0xD3
,
0xDF
,
0xCD
,
0xF4
,
0x41
,
0x81
,
0x4D
,
0x52
,
0x6A
,
0xDC
,
0x37
,
0xC8
,
0x6C
,
0xC1
,
0xAB
,
0xFA
,
0x24
,
0xE1
,
0x7B
,
0x08
,
0x0C
,
0xBD
,
0xB1
,
0x4A
,
0x78
,
0x88
,
0x95
,
0x8B
,
0xE3
,
0x63
,
0xE8
,
0x6D
,
0xE9
,
0xCB
,
0xD5
,
0xFE
,
0x3B
,
0x00
,
0x1D
,
0x39
,
0xF2
,
0xEF
,
0xB7
,
0x0E
,
0x66
,
0x58
,
0xD0
,
0xE4
,
0xA6
,
0x77
,
0x72
,
0xF8
,
0xEB
,
0x75
,
0x4B
,
0x0A
,
0x31
,
0x44
,
0x50
,
0xB4
,
0x8F
,
0xED
,
0x1F
,
0x1A
,
0xDB
,
0x99
,
0x8D
,
0x33
,
0x9F
,
0x11
,
0x83
,
0x14
};
/*
* MD2 context setup
*/
EXP_FUNC
void
STDCALL
ICACHE_FLASH_ATTR
MD2_Init
(
MD2_CTX
*
ctx
)
{
os_memset
(
ctx
,
0
,
sizeof
*
ctx
);
}
static
void
ICACHE_FLASH_ATTR
md2_process
(
MD2_CTX
*
ctx
)
{
int
i
,
j
;
uint8_t
t
=
0
;
for
(
i
=
0
;
i
<
16
;
i
++
)
{
ctx
->
state
[
i
+
16
]
=
ctx
->
buffer
[
i
];
ctx
->
state
[
i
+
32
]
=
ctx
->
buffer
[
i
]
^
ctx
->
state
[
i
];
}
for
(
i
=
0
;
i
<
18
;
i
++
)
{
for
(
j
=
0
;
j
<
48
;
j
++
)
t
=
(
ctx
->
state
[
j
]
^=
PI_SUBST
[
t
]);
t
=
(
t
+
i
)
&
0xFF
;
}
t
=
ctx
->
cksum
[
15
];
for
(
i
=
0
;
i
<
16
;
i
++
)
t
=
(
ctx
->
cksum
[
i
]
^=
PI_SUBST
[
ctx
->
buffer
[
i
]
^
t
]);
}
/*
* MD2 process buffer
*/
EXP_FUNC
void
STDCALL
ICACHE_FLASH_ATTR
MD2_Update
(
MD2_CTX
*
ctx
,
const
uint8_t
*
input
,
int
ilen
)
{
int
fill
;
while
(
ilen
>
0
)
{
if
(
ctx
->
left
+
ilen
>
16
)
fill
=
16
-
ctx
->
left
;
else
fill
=
ilen
;
os_memcpy
(
ctx
->
buffer
+
ctx
->
left
,
input
,
fill
);
ctx
->
left
+=
fill
;
input
+=
fill
;
ilen
-=
fill
;
if
(
ctx
->
left
==
16
)
{
ctx
->
left
=
0
;
md2_process
(
ctx
);
}
}
}
/*
* MD2 final digest
*/
EXP_FUNC
void
STDCALL
ICACHE_FLASH_ATTR
MD2_Final
(
uint8_t
*
output
,
MD2_CTX
*
ctx
)
{
int
i
;
uint8_t
x
;
x
=
(
uint8_t
)(
16
-
ctx
->
left
);
for
(
i
=
ctx
->
left
;
i
<
16
;
i
++
)
ctx
->
buffer
[
i
]
=
x
;
md2_process
(
ctx
);
os_memcpy
(
ctx
->
buffer
,
ctx
->
cksum
,
16
);
md2_process
(
ctx
);
os_memcpy
(
output
,
ctx
->
state
,
16
);
}
#endif
app/ssl/crypto/ssl_md5.c
deleted
100644 → 0
View file @
21c4e110
/*
* Copyright (c) 2007, Cameron Rich
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the axTLS project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* This file implements the MD5 algorithm as defined in RFC1321
*/
//#include <string.h>
#include "ssl/ssl_os_port.h"
#include "ssl/ssl_crypto.h"
//#include "os.h"
#include "lwip/mem.h"
/* Constants for MD5Transform routine.
*/
#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21
/* ----- static functions ----- */
static
void
MD5Transform
(
uint32_t
state
[
4
],
const
uint8_t
block
[
64
]);
static
void
Encode
(
uint8_t
*
output
,
uint32_t
*
input
,
uint32_t
len
);
static
void
Decode
(
uint32_t
*
output
,
const
uint8_t
*
input
,
uint32_t
len
);
static
const
uint8_t
PADDING
[
64
]
=
{
0x80
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
};
/* F, G, H and I are basic MD5 functions.
*/
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))
/* ROTATE_LEFT rotates x left n bits. */
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
Rotation is separate from addition to prevent recomputation. */
#define FF(a, b, c, d, x, s, ac) { \
(a) += F ((b), (c), (d)) + (x) + (uint32_t)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) { \
(a) += G ((b), (c), (d)) + (x) + (uint32_t)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) { \
(a) += H ((b), (c), (d)) + (x) + (uint32_t)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define II(a, b, c, d, x, s, ac) { \
(a) += I ((b), (c), (d)) + (x) + (uint32_t)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
/**
* MD5 initialization - begins an MD5 operation, writing a new ctx.
*/
EXP_FUNC
void
STDCALL
ICACHE_FLASH_ATTR
MD5_Init
(
MD5_CTX
*
ctx
)
{
ctx
->
count
[
0
]
=
ctx
->
count
[
1
]
=
0
;
/* Load magic initialization constants.
*/
ctx
->
state
[
0
]
=
0x67452301
;
ctx
->
state
[
1
]
=
0xefcdab89
;
ctx
->
state
[
2
]
=
0x98badcfe
;
ctx
->
state
[
3
]
=
0x10325476
;
}
/**
* Accepts an array of octets as the next portion of the message.
*/
EXP_FUNC
void
STDCALL
ICACHE_FLASH_ATTR
MD5_Update
(
MD5_CTX
*
ctx
,
const
uint8_t
*
msg
,
int
len
)
{
uint32_t
x
;
int
i
,
partLen
;
/* Compute number of bytes mod 64 */
x
=
(
uint32_t
)((
ctx
->
count
[
0
]
>>
3
)
&
0x3F
);
/* Update number of bits */
if
((
ctx
->
count
[
0
]
+=
((
uint32_t
)
len
<<
3
))
<
((
uint32_t
)
len
<<
3
))
ctx
->
count
[
1
]
++
;
ctx
->
count
[
1
]
+=
((
uint32_t
)
len
>>
29
);
partLen
=
64
-
x
;
/* Transform as many times as possible. */
if
(
len
>=
partLen
)
{
os_memcpy
(
&
ctx
->
buffer
[
x
],
msg
,
partLen
);
MD5Transform
(
ctx
->
state
,
ctx
->
buffer
);
for
(
i
=
partLen
;
i
+
63
<
len
;
i
+=
64
)
MD5Transform
(
ctx
->
state
,
&
msg
[
i
]);
x
=
0
;
}
else
i
=
0
;
/* Buffer remaining input */
os_memcpy
(
&
ctx
->
buffer
[
x
],
&
msg
[
i
],
len
-
i
);
}
/**
* Return the 128-bit message digest into the user's array
*/
EXP_FUNC
void
STDCALL
ICACHE_FLASH_ATTR
MD5_Final
(
uint8_t
*
digest
,
MD5_CTX
*
ctx
)
{
uint8_t
bits
[
8
];
uint32_t
x
,
padLen
;
/* Save number of bits */
Encode
(
bits
,
ctx
->
count
,
8
);
/* Pad out to 56 mod 64.
*/
x
=
(
uint32_t
)((
ctx
->
count
[
0
]
>>
3
)
&
0x3f
);
padLen
=
(
x
<
56
)
?
(
56
-
x
)
:
(
120
-
x
);
MD5_Update
(
ctx
,
PADDING
,
padLen
);
/* Append length (before padding) */
MD5_Update
(
ctx
,
bits
,
8
);
/* Store state in digest */
Encode
(
digest
,
ctx
->
state
,
MD5_SIZE
);
}
/**
* MD5 basic transformation. Transforms state based on block.
*/
static
void
ICACHE_FLASH_ATTR
MD5Transform
(
uint32_t
state
[
4
],
const
uint8_t
block
[
64
])
{
uint32_t
a
=
state
[
0
],
b
=
state
[
1
],
c
=
state
[
2
],
d
=
state
[
3
],
x
[
MD5_SIZE
];
Decode
(
x
,
block
,
64
);
/* Round 1 */
FF
(
a
,
b
,
c
,
d
,
x
[
0
],
S11
,
0xd76aa478
);
/* 1 */
FF
(
d
,
a
,
b
,
c
,
x
[
1
],
S12
,
0xe8c7b756
);
/* 2 */
FF
(
c
,
d
,
a
,
b
,
x
[
2
],
S13
,
0x242070db
);
/* 3 */
FF
(
b
,
c
,
d
,
a
,
x
[
3
],
S14
,
0xc1bdceee
);
/* 4 */
FF
(
a
,
b
,
c
,
d
,
x
[
4
],
S11
,
0xf57c0faf
);
/* 5 */
FF
(
d
,
a
,
b
,
c
,
x
[
5
],
S12
,
0x4787c62a
);
/* 6 */
FF
(
c
,
d
,
a
,
b
,
x
[
6
],
S13
,
0xa8304613
);
/* 7 */
FF
(
b
,
c
,
d
,
a
,
x
[
7
],
S14
,
0xfd469501
);
/* 8 */
FF
(
a
,
b
,
c
,
d
,
x
[
8
],
S11
,
0x698098d8
);
/* 9 */
FF
(
d
,
a
,
b
,
c
,
x
[
9
],
S12
,
0x8b44f7af
);
/* 10 */
FF
(
c
,
d
,
a
,
b
,
x
[
10
],
S13
,
0xffff5bb1
);
/* 11 */
FF
(
b
,
c
,
d
,
a
,
x
[
11
],
S14
,
0x895cd7be
);
/* 12 */
FF
(
a
,
b
,
c
,
d
,
x
[
12
],
S11
,
0x6b901122
);
/* 13 */
FF
(
d
,
a
,
b
,
c
,
x
[
13
],
S12
,
0xfd987193
);
/* 14 */
FF
(
c
,
d
,
a
,
b
,
x
[
14
],
S13
,
0xa679438e
);
/* 15 */
FF
(
b
,
c
,
d
,
a
,
x
[
15
],
S14
,
0x49b40821
);
/* 16 */
/* Round 2 */
GG
(
a
,
b
,
c
,
d
,
x
[
1
],
S21
,
0xf61e2562
);
/* 17 */
GG
(
d
,
a
,
b
,
c
,
x
[
6
],
S22
,
0xc040b340
);
/* 18 */
GG
(
c
,
d
,
a
,
b
,
x
[
11
],
S23
,
0x265e5a51
);
/* 19 */
GG
(
b
,
c
,
d
,
a
,
x
[
0
],
S24
,
0xe9b6c7aa
);
/* 20 */
GG
(
a
,
b
,
c
,
d
,
x
[
5
],
S21
,
0xd62f105d
);
/* 21 */
GG
(
d
,
a
,
b
,
c
,
x
[
10
],
S22
,
0x2441453
);
/* 22 */
GG
(
c
,
d
,
a
,
b
,
x
[
15
],
S23
,
0xd8a1e681
);
/* 23 */
GG
(
b
,
c
,
d
,
a
,
x
[
4
],
S24
,
0xe7d3fbc8
);
/* 24 */
GG
(
a
,
b
,
c
,
d
,
x
[
9
],
S21
,
0x21e1cde6
);
/* 25 */
GG
(
d
,
a
,
b
,
c
,
x
[
14
],
S22
,
0xc33707d6
);
/* 26 */
GG
(
c
,
d
,
a
,
b
,
x
[
3
],
S23
,
0xf4d50d87
);
/* 27 */
GG
(
b
,
c
,
d
,
a
,
x
[
8
],
S24
,
0x455a14ed
);
/* 28 */
GG
(
a
,
b
,
c
,
d
,
x
[
13
],
S21
,
0xa9e3e905
);
/* 29 */
GG
(
d
,
a
,
b
,
c
,
x
[
2
],
S22
,
0xfcefa3f8
);
/* 30 */
GG
(
c
,
d
,
a
,
b
,
x
[
7
],
S23
,
0x676f02d9
);
/* 31 */
GG
(
b
,
c
,
d
,
a
,
x
[
12
],
S24
,
0x8d2a4c8a
);
/* 32 */
/* Round 3 */
HH
(
a
,
b
,
c
,
d
,
x
[
5
],
S31
,
0xfffa3942
);
/* 33 */
HH
(
d
,
a
,
b
,
c
,
x
[
8
],
S32
,
0x8771f681
);
/* 34 */
HH
(
c
,
d
,
a
,
b
,
x
[
11
],
S33
,
0x6d9d6122
);
/* 35 */
HH
(
b
,
c
,
d
,
a
,
x
[
14
],
S34
,
0xfde5380c
);
/* 36 */
HH
(
a
,
b
,
c
,
d
,
x
[
1
],
S31
,
0xa4beea44
);
/* 37 */
HH
(
d
,
a
,
b
,
c
,
x
[
4
],
S32
,
0x4bdecfa9
);
/* 38 */
HH
(
c
,
d
,
a
,
b
,
x
[
7
],
S33
,
0xf6bb4b60
);
/* 39 */
HH
(
b
,
c
,
d
,
a
,
x
[
10
],
S34
,
0xbebfbc70
);
/* 40 */
HH
(
a
,
b
,
c
,
d
,
x
[
13
],
S31
,
0x289b7ec6
);
/* 41 */
HH
(
d
,
a
,
b
,
c
,
x
[
0
],
S32
,
0xeaa127fa
);
/* 42 */
HH
(
c
,
d
,
a
,
b
,
x
[
3
],
S33
,
0xd4ef3085
);
/* 43 */
HH
(
b
,
c
,
d
,
a
,
x
[
6
],
S34
,
0x4881d05
);
/* 44 */
HH
(
a
,
b
,
c
,
d
,
x
[
9
],
S31
,
0xd9d4d039
);
/* 45 */
HH
(
d
,
a
,
b
,
c
,
x
[
12
],
S32
,
0xe6db99e5
);
/* 46 */
HH
(
c
,
d
,
a
,
b
,
x
[
15
],
S33
,
0x1fa27cf8
);
/* 47 */
HH
(
b
,
c
,
d
,
a
,
x
[
2
],
S34
,
0xc4ac5665
);
/* 48 */
/* Round 4 */
II
(
a
,
b
,
c
,
d
,
x
[
0
],
S41
,
0xf4292244
);
/* 49 */
II
(
d
,
a
,
b
,
c
,
x
[
7
],
S42
,
0x432aff97
);
/* 50 */
II
(
c
,
d
,
a
,
b
,
x
[
14
],
S43
,
0xab9423a7
);
/* 51 */
II
(
b
,
c
,
d
,
a
,
x
[
5
],
S44
,
0xfc93a039
);
/* 52 */
II
(
a
,
b
,
c
,
d
,
x
[
12
],
S41
,
0x655b59c3
);
/* 53 */
II
(
d
,
a
,
b
,
c
,
x
[
3
],
S42
,
0x8f0ccc92
);
/* 54 */
II
(
c
,
d
,
a
,
b
,
x
[
10
],
S43
,
0xffeff47d
);
/* 55 */
II
(
b
,
c
,
d
,
a
,
x
[
1
],
S44
,
0x85845dd1
);
/* 56 */
II
(
a
,
b
,
c
,
d
,
x
[
8
],
S41
,
0x6fa87e4f
);
/* 57 */
II
(
d
,
a
,
b
,
c
,
x
[
15
],
S42
,
0xfe2ce6e0
);
/* 58 */
II
(
c
,
d
,
a
,
b
,
x
[
6
],
S43
,
0xa3014314
);
/* 59 */
II
(
b
,
c
,
d
,
a
,
x
[
13
],
S44
,
0x4e0811a1
);
/* 60 */
II
(
a
,
b
,
c
,
d
,
x
[
4
],
S41
,
0xf7537e82
);
/* 61 */
II
(
d
,
a
,
b
,
c
,
x
[
11
],
S42
,
0xbd3af235
);
/* 62 */
II
(
c
,
d
,
a
,
b
,
x
[
2
],
S43
,
0x2ad7d2bb
);
/* 63 */
II
(
b
,
c
,
d
,
a
,
x
[
9
],
S44
,
0xeb86d391
);
/* 64 */
state
[
0
]
+=
a
;
state
[
1
]
+=
b
;
state
[
2
]
+=
c
;
state
[
3
]
+=
d
;
}
/**
* Encodes input (uint32_t) into output (uint8_t). Assumes len is
* a multiple of 4.
*/
static
void
ICACHE_FLASH_ATTR
Encode
(
uint8_t
*
output
,
uint32_t
*
input
,
uint32_t
len
)
{
uint32_t
i
,
j
;
for
(
i
=
0
,
j
=
0
;
j
<
len
;
i
++
,
j
+=
4
)
{
output
[
j
]
=
(
uint8_t
)(
input
[
i
]
&
0xff
);
output
[
j
+
1
]
=
(
uint8_t
)((
input
[
i
]
>>
8
)
&
0xff
);
output
[
j
+
2
]
=
(
uint8_t
)((
input
[
i
]
>>
16
)
&
0xff
);
output
[
j
+
3
]
=
(
uint8_t
)((
input
[
i
]
>>
24
)
&
0xff
);
}
}
/**
* Decodes input (uint8_t) into output (uint32_t). Assumes len is
* a multiple of 4.
*/
static
void
ICACHE_FLASH_ATTR
Decode
(
uint32_t
*
output
,
const
uint8_t
*
input
,
uint32_t
len
)
{
uint32_t
i
,
j
;
for
(
i
=
0
,
j
=
0
;
j
<
len
;
i
++
,
j
+=
4
)
output
[
i
]
=
((
uint32_t
)
input
[
j
])
|
(((
uint32_t
)
input
[
j
+
1
])
<<
8
)
|
(((
uint32_t
)
input
[
j
+
2
])
<<
16
)
|
(((
uint32_t
)
input
[
j
+
3
])
<<
24
);
}
app/ssl/crypto/ssl_rc4.c
deleted
100644 → 0
View file @
21c4e110
/*
* Copyright (c) 2007, Cameron Rich
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the axTLS project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* An implementation of the RC4/ARC4 algorithm.
* Originally written by Christophe Devine.
*/
//#include <string.h>
#include "ssl/ssl_os_port.h"
#include "ssl/ssl_crypto.h"
/**
* Get ready for an encrypt/decrypt operation
*/
void
ICACHE_FLASH_ATTR
RC4_setup
(
RC4_CTX
*
ctx
,
const
uint8_t
*
key
,
int
length
)
{
int
i
,
j
=
0
,
k
=
0
,
a
;
uint8_t
*
m
;
ctx
->
x
=
0
;
ctx
->
y
=
0
;
m
=
ctx
->
m
;
for
(
i
=
0
;
i
<
256
;
i
++
)
m
[
i
]
=
i
;
for
(
i
=
0
;
i
<
256
;
i
++
)
{
a
=
m
[
i
];
j
=
(
uint8_t
)(
j
+
a
+
key
[
k
]);
m
[
i
]
=
m
[
j
];
m
[
j
]
=
a
;
if
(
++
k
>=
length
)
k
=
0
;
}
}
/**
* Perform the encrypt/decrypt operation (can use it for either since
* this is a stream cipher).
* NOTE: *msg and *out must be the same pointer (performance tweak)
*/
void
ICACHE_FLASH_ATTR
RC4_crypt
(
RC4_CTX
*
ctx
,
const
uint8_t
*
msg
,
uint8_t
*
out
,
int
length
)
{
int
i
;
uint8_t
*
m
,
x
,
y
,
a
,
b
;
x
=
ctx
->
x
;
y
=
ctx
->
y
;
m
=
ctx
->
m
;
for
(
i
=
0
;
i
<
length
;
i
++
)
{
a
=
m
[
++
x
];
y
+=
a
;
m
[
x
]
=
b
=
m
[
y
];
m
[
y
]
=
a
;
out
[
i
]
^=
m
[(
uint8_t
)(
a
+
b
)];
}
ctx
->
x
=
x
;
ctx
->
y
=
y
;
}
app/ssl/crypto/ssl_rsa.c
deleted
100644 → 0
View file @
21c4e110
/*
* Copyright (c) 2007, Cameron Rich
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the axTLS project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* Implements the RSA public encryption algorithm. Uses the bigint library to
* perform its calculations.
*/
//#include <stdio.h>
//#include <string.h>
//#include <time.h>
//#include <stdlib.h>
#include "ssl/ssl_os_port.h"
#include "ssl/ssl_crypto.h"
//#include "os.h"
#include "lwip/mem.h"
void
ICACHE_FLASH_ATTR
RSA_priv_key_new
(
RSA_CTX
**
ctx
,
const
uint8_t
*
modulus
,
int
mod_len
,
const
uint8_t
*
pub_exp
,
int
pub_len
,
const
uint8_t
*
priv_exp
,
int
priv_len
#if CONFIG_BIGINT_CRT
,
const
uint8_t
*
p
,
int
p_len
,
const
uint8_t
*
q
,
int
q_len
,
const
uint8_t
*
dP
,
int
dP_len
,
const
uint8_t
*
dQ
,
int
dQ_len
,
const
uint8_t
*
qInv
,
int
qInv_len
#endif
)
{
RSA_CTX
*
rsa_ctx
;
BI_CTX
*
bi_ctx
;
RSA_pub_key_new
(
ctx
,
modulus
,
mod_len
,
pub_exp
,
pub_len
);
rsa_ctx
=
*
ctx
;
bi_ctx
=
rsa_ctx
->
bi_ctx
;
rsa_ctx
->
d
=
bi_import
(
bi_ctx
,
priv_exp
,
priv_len
);
bi_permanent
(
rsa_ctx
->
d
);
#ifdef CONFIG_BIGINT_CRT
rsa_ctx
->
p
=
bi_import
(
bi_ctx
,
p
,
p_len
);
rsa_ctx
->
q
=
bi_import
(
bi_ctx
,
q
,
q_len
);
rsa_ctx
->
dP
=
bi_import
(
bi_ctx
,
dP
,
dP_len
);
rsa_ctx
->
dQ
=
bi_import
(
bi_ctx
,
dQ
,
dQ_len
);
rsa_ctx
->
qInv
=
bi_import
(
bi_ctx
,
qInv
,
qInv_len
);
bi_permanent
(
rsa_ctx
->
dP
);
bi_permanent
(
rsa_ctx
->
dQ
);
bi_permanent
(
rsa_ctx
->
qInv
);
bi_set_mod
(
bi_ctx
,
rsa_ctx
->
p
,
BIGINT_P_OFFSET
);
bi_set_mod
(
bi_ctx
,
rsa_ctx
->
q
,
BIGINT_Q_OFFSET
);
#endif
}
void
ICACHE_FLASH_ATTR
RSA_pub_key_new
(
RSA_CTX
**
ctx
,
const
uint8_t
*
modulus
,
int
mod_len
,
const
uint8_t
*
pub_exp
,
int
pub_len
)
{
RSA_CTX
*
rsa_ctx
;
BI_CTX
*
bi_ctx
;
if
(
*
ctx
)
/* if we load multiple certs, dump the old one */
RSA_free
(
*
ctx
);
bi_ctx
=
bi_initialize
();
*
ctx
=
(
RSA_CTX
*
)
os_zalloc
(
sizeof
(
RSA_CTX
));
rsa_ctx
=
*
ctx
;
rsa_ctx
->
bi_ctx
=
bi_ctx
;
rsa_ctx
->
num_octets
=
mod_len
;
rsa_ctx
->
m
=
bi_import
(
bi_ctx
,
modulus
,
mod_len
);
bi_set_mod
(
bi_ctx
,
rsa_ctx
->
m
,
BIGINT_M_OFFSET
);
rsa_ctx
->
e
=
bi_import
(
bi_ctx
,
pub_exp
,
pub_len
);
bi_permanent
(
rsa_ctx
->
e
);
}
/**
* Free up any RSA context resources.
*/
void
ICACHE_FLASH_ATTR
RSA_free
(
RSA_CTX
*
rsa_ctx
)
{
BI_CTX
*
bi_ctx
;
if
(
rsa_ctx
==
NULL
)
/* deal with ptrs that are null */
return
;
bi_ctx
=
rsa_ctx
->
bi_ctx
;
bi_depermanent
(
rsa_ctx
->
e
);
bi_free
(
bi_ctx
,
rsa_ctx
->
e
);
bi_free_mod
(
rsa_ctx
->
bi_ctx
,
BIGINT_M_OFFSET
);
if
(
rsa_ctx
->
d
)
{
bi_depermanent
(
rsa_ctx
->
d
);
bi_free
(
bi_ctx
,
rsa_ctx
->
d
);
#ifdef CONFIG_BIGINT_CRT
bi_depermanent
(
rsa_ctx
->
dP
);
bi_depermanent
(
rsa_ctx
->
dQ
);
bi_depermanent
(
rsa_ctx
->
qInv
);
bi_free
(
bi_ctx
,
rsa_ctx
->
dP
);
bi_free
(
bi_ctx
,
rsa_ctx
->
dQ
);
bi_free
(
bi_ctx
,
rsa_ctx
->
qInv
);
bi_free_mod
(
rsa_ctx
->
bi_ctx
,
BIGINT_P_OFFSET
);
bi_free_mod
(
rsa_ctx
->
bi_ctx
,
BIGINT_Q_OFFSET
);
#endif
}
bi_terminate
(
bi_ctx
);
os_free
(
rsa_ctx
);
}
/**
* @brief Use PKCS1.5 for decryption/verification.
* @param ctx [in] The context
* @param in_data [in] The data to encrypt (must be < modulus size-11)
* @param out_data [out] The encrypted data.
* @param is_decryption [in] Decryption or verify operation.
* @return The number of bytes that were originally encrypted. -1 on error.
* @see http://www.rsasecurity.com/rsalabs/node.asp?id=2125
*/
int
ICACHE_FLASH_ATTR
RSA_decrypt
(
const
RSA_CTX
*
ctx
,
const
uint8_t
*
in_data
,
uint8_t
*
out_data
,
int
is_decryption
)
{
const
int
byte_size
=
ctx
->
num_octets
;
int
i
,
size
;
bigint
*
decrypted_bi
,
*
dat_bi
;
uint8_t
*
block
=
(
uint8_t
*
)
os_malloc
(
byte_size
);
os_memset
(
out_data
,
0
,
byte_size
);
/* initialise */
/* decrypt */
dat_bi
=
bi_import
(
ctx
->
bi_ctx
,
in_data
,
byte_size
);
#ifdef CONFIG_SSL_CERT_VERIFICATION
decrypted_bi
=
is_decryption
?
/* decrypt or verify? */
RSA_private
(
ctx
,
dat_bi
)
:
RSA_public
(
ctx
,
dat_bi
);
#else
/* always a decryption */
decrypted_bi
=
RSA_private
(
ctx
,
dat_bi
);
#endif
/* convert to a normal block */
bi_export
(
ctx
->
bi_ctx
,
decrypted_bi
,
block
,
byte_size
);
i
=
10
;
/* start at the first possible non-padded byte */
#ifdef CONFIG_SSL_CERT_VERIFICATION
if
(
is_decryption
==
0
)
/* PKCS1.5 signing pads with "0xff"s */
{
while
(
block
[
i
++
]
==
0xff
&&
i
<
byte_size
);
if
(
block
[
i
-
2
]
!=
0xff
)
i
=
byte_size
;
/*ensure size is 0 */
}
else
/* PKCS1.5 encryption padding is random */
#endif
{
while
(
block
[
i
++
]
&&
i
<
byte_size
);
}
size
=
byte_size
-
i
;
/* get only the bit we want */
if
(
size
>
0
)
os_memcpy
(
out_data
,
&
block
[
i
],
size
);
os_free
(
block
);
return
size
?
size
:
-
1
;
}
/**
* Performs m = c^d mod n
*/
bigint
*
ICACHE_FLASH_ATTR
RSA_private
(
const
RSA_CTX
*
c
,
bigint
*
bi_msg
)
{
#ifdef CONFIG_BIGINT_CRT
return
bi_crt
(
c
->
bi_ctx
,
bi_msg
,
c
->
dP
,
c
->
dQ
,
c
->
p
,
c
->
q
,
c
->
qInv
);
#else
BI_CTX
*
ctx
=
c
->
bi_ctx
;
ctx
->
mod_offset
=
BIGINT_M_OFFSET
;
return
bi_mod_power
(
ctx
,
bi_msg
,
c
->
d
);
#endif
}
#ifdef CONFIG_SSL_FULL_MODE
/**
* Used for diagnostics.
*/
void
ICACHE_FLASH_ATTR
RSA_print
(
const
RSA_CTX
*
rsa_ctx
)
{
if
(
rsa_ctx
==
NULL
)
return
;
ssl_printf
(
"----------------- RSA DEBUG ----------------
\n
"
);
ssl_printf
(
"Size:
\t
%d
\n
"
,
rsa_ctx
->
num_octets
);
bi_print
(
"Modulus"
,
rsa_ctx
->
m
);
bi_print
(
"Public Key"
,
rsa_ctx
->
e
);
bi_print
(
"Private Key"
,
rsa_ctx
->
d
);
}
#endif
#if defined(CONFIG_SSL_CERT_VERIFICATION) || defined(CONFIG_SSL_GENERATE_X509_CERT)
/**
* Performs c = m^e mod n
*/
bigint
*
ICACHE_FLASH_ATTR
RSA_public
(
const
RSA_CTX
*
c
,
bigint
*
bi_msg
)
{
c
->
bi_ctx
->
mod_offset
=
BIGINT_M_OFFSET
;
return
bi_mod_power
(
c
->
bi_ctx
,
bi_msg
,
c
->
e
);
}
/**
* Use PKCS1.5 for encryption/signing.
* see http://www.rsasecurity.com/rsalabs/node.asp?id=2125
*/
int
ICACHE_FLASH_ATTR
RSA_encrypt
(
const
RSA_CTX
*
ctx
,
const
uint8_t
*
in_data
,
uint16_t
in_len
,
uint8_t
*
out_data
,
int
is_signing
)
{
int
byte_size
=
ctx
->
num_octets
;
int
num_pads_needed
=
byte_size
-
in_len
-
3
;
bigint
*
dat_bi
,
*
encrypt_bi
;
/* note: in_len+11 must be > byte_size */
out_data
[
0
]
=
0
;
/* ensure encryption block is < modulus */
if
(
is_signing
)
{
out_data
[
1
]
=
1
;
/* PKCS1.5 signing pads with "0xff"'s */
os_memset
(
&
out_data
[
2
],
0xff
,
num_pads_needed
);
}
else
/* randomize the encryption padding with non-zero bytes */
{
out_data
[
1
]
=
2
;
get_random_NZ
(
num_pads_needed
,
&
out_data
[
2
]);
}
out_data
[
2
+
num_pads_needed
]
=
0
;
os_memcpy
(
&
out_data
[
3
+
num_pads_needed
],
in_data
,
in_len
);
/* now encrypt it */
dat_bi
=
bi_import
(
ctx
->
bi_ctx
,
out_data
,
byte_size
);
encrypt_bi
=
is_signing
?
RSA_private
(
ctx
,
dat_bi
)
:
RSA_public
(
ctx
,
dat_bi
);
bi_export
(
ctx
->
bi_ctx
,
encrypt_bi
,
out_data
,
byte_size
);
/* save a few bytes of memory */
bi_clear_cache
(
ctx
->
bi_ctx
);
return
byte_size
;
}
#endif
/* CONFIG_SSL_CERT_VERIFICATION */
app/ssl/crypto/ssl_sha1.c
deleted
100644 → 0
View file @
21c4e110
/*
* Copyright (c) 2007, Cameron Rich
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the axTLS project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* SHA1 implementation - as defined in FIPS PUB 180-1 published April 17, 1995.
* This code was originally taken from RFC3174
*/
//#include <string.h>
#include "ssl/ssl_os_port.h"
#include "ssl/ssl_crypto.h"
//#include "os.h"
#include "lwip/mem.h"
/*
* Define the SHA1 circular left shift macro
*/
#define SHA1CircularShift(bits,word) \
(((word) << (bits)) | ((word) >> (32-(bits))))
/* ----- static functions ----- */
static
void
SHA1PadMessage
(
SHA1_CTX
*
ctx
);
static
void
SHA1ProcessMessageBlock
(
SHA1_CTX
*
ctx
);
/**
* Initialize the SHA1 context
*/
void
ICACHE_FLASH_ATTR
SHA1_Init
(
SHA1_CTX
*
ctx
)
{
ctx
->
Length_Low
=
0
;
ctx
->
Length_High
=
0
;
ctx
->
Message_Block_Index
=
0
;
ctx
->
Intermediate_Hash
[
0
]
=
0x67452301
;
ctx
->
Intermediate_Hash
[
1
]
=
0xEFCDAB89
;
ctx
->
Intermediate_Hash
[
2
]
=
0x98BADCFE
;
ctx
->
Intermediate_Hash
[
3
]
=
0x10325476
;
ctx
->
Intermediate_Hash
[
4
]
=
0xC3D2E1F0
;
}
/**
* Accepts an array of octets as the next portion of the message.
*/
void
ICACHE_FLASH_ATTR
SHA1_Update
(
SHA1_CTX
*
ctx
,
const
uint8_t
*
msg
,
int
len
)
{
while
(
len
--
)
{
ctx
->
Message_Block
[
ctx
->
Message_Block_Index
++
]
=
(
*
msg
&
0xFF
);
ctx
->
Length_Low
+=
8
;
if
(
ctx
->
Length_Low
==
0
)
ctx
->
Length_High
++
;
if
(
ctx
->
Message_Block_Index
==
64
)
SHA1ProcessMessageBlock
(
ctx
);
msg
++
;
}
}
/**
* Return the 160-bit message digest into the user's array
*/
void
ICACHE_FLASH_ATTR
SHA1_Final
(
uint8_t
*
digest
,
SHA1_CTX
*
ctx
)
{
int
i
;
SHA1PadMessage
(
ctx
);
os_memset
(
ctx
->
Message_Block
,
0
,
64
);
ctx
->
Length_Low
=
0
;
/* and clear length */
ctx
->
Length_High
=
0
;
for
(
i
=
0
;
i
<
SHA1_SIZE
;
i
++
)
{
digest
[
i
]
=
ctx
->
Intermediate_Hash
[
i
>>
2
]
>>
8
*
(
3
-
(
i
&
0x03
)
);
}
}
/**
* Process the next 512 bits of the message stored in the array.
*/
static
void
ICACHE_FLASH_ATTR
SHA1ProcessMessageBlock
(
SHA1_CTX
*
ctx
)
{
const
uint32_t
K
[]
=
{
/* Constants defined in SHA-1 */
0x5A827999
,
0x6ED9EBA1
,
0x8F1BBCDC
,
0xCA62C1D6
};
int
t
;
/* Loop counter */
uint32_t
temp
;
/* Temporary word value */
uint32_t
W
[
80
];
/* Word sequence */
uint32_t
A
,
B
,
C
,
D
,
E
;
/* Word buffers */
/*
* Initialize the first 16 words in the array W
*/
for
(
t
=
0
;
t
<
16
;
t
++
)
{
W
[
t
]
=
ctx
->
Message_Block
[
t
*
4
]
<<
24
;
W
[
t
]
|=
ctx
->
Message_Block
[
t
*
4
+
1
]
<<
16
;
W
[
t
]
|=
ctx
->
Message_Block
[
t
*
4
+
2
]
<<
8
;
W
[
t
]
|=
ctx
->
Message_Block
[
t
*
4
+
3
];
}
for
(
t
=
16
;
t
<
80
;
t
++
)
{
W
[
t
]
=
SHA1CircularShift
(
1
,
W
[
t
-
3
]
^
W
[
t
-
8
]
^
W
[
t
-
14
]
^
W
[
t
-
16
]);
}
A
=
ctx
->
Intermediate_Hash
[
0
];
B
=
ctx
->
Intermediate_Hash
[
1
];
C
=
ctx
->
Intermediate_Hash
[
2
];
D
=
ctx
->
Intermediate_Hash
[
3
];
E
=
ctx
->
Intermediate_Hash
[
4
];
for
(
t
=
0
;
t
<
20
;
t
++
)
{
temp
=
SHA1CircularShift
(
5
,
A
)
+
((
B
&
C
)
|
((
~
B
)
&
D
))
+
E
+
W
[
t
]
+
K
[
0
];
E
=
D
;
D
=
C
;
C
=
SHA1CircularShift
(
30
,
B
);
B
=
A
;
A
=
temp
;
}
for
(
t
=
20
;
t
<
40
;
t
++
)
{
temp
=
SHA1CircularShift
(
5
,
A
)
+
(
B
^
C
^
D
)
+
E
+
W
[
t
]
+
K
[
1
];
E
=
D
;
D
=
C
;
C
=
SHA1CircularShift
(
30
,
B
);
B
=
A
;
A
=
temp
;
}
for
(
t
=
40
;
t
<
60
;
t
++
)
{
temp
=
SHA1CircularShift
(
5
,
A
)
+
((
B
&
C
)
|
(
B
&
D
)
|
(
C
&
D
))
+
E
+
W
[
t
]
+
K
[
2
];
E
=
D
;
D
=
C
;
C
=
SHA1CircularShift
(
30
,
B
);
B
=
A
;
A
=
temp
;
}
for
(
t
=
60
;
t
<
80
;
t
++
)
{
temp
=
SHA1CircularShift
(
5
,
A
)
+
(
B
^
C
^
D
)
+
E
+
W
[
t
]
+
K
[
3
];
E
=
D
;
D
=
C
;
C
=
SHA1CircularShift
(
30
,
B
);
B
=
A
;
A
=
temp
;
}
ctx
->
Intermediate_Hash
[
0
]
+=
A
;
ctx
->
Intermediate_Hash
[
1
]
+=
B
;
ctx
->
Intermediate_Hash
[
2
]
+=
C
;
ctx
->
Intermediate_Hash
[
3
]
+=
D
;
ctx
->
Intermediate_Hash
[
4
]
+=
E
;
ctx
->
Message_Block_Index
=
0
;
}
/*
* According to the standard, the message must be padded to an even
* 512 bits. The first padding bit must be a '1'. The last 64
* bits represent the length of the original message. All bits in
* between should be 0. This function will pad the message
* according to those rules by filling the Message_Block array
* accordingly. It will also call the ProcessMessageBlock function
* provided appropriately. When it returns, it can be assumed that
* the message digest has been computed.
*
* @param ctx [in, out] The SHA1 context
*/
static
void
ICACHE_FLASH_ATTR
SHA1PadMessage
(
SHA1_CTX
*
ctx
)
{
/*
* Check to see if the current message block is too small to hold
* the initial padding bits and length. If so, we will pad the
* block, process it, and then continue padding into a second
* block.
*/
if
(
ctx
->
Message_Block_Index
>
55
)
{
ctx
->
Message_Block
[
ctx
->
Message_Block_Index
++
]
=
0x80
;
while
(
ctx
->
Message_Block_Index
<
64
)
{
ctx
->
Message_Block
[
ctx
->
Message_Block_Index
++
]
=
0
;
}
SHA1ProcessMessageBlock
(
ctx
);
while
(
ctx
->
Message_Block_Index
<
56
)
{
ctx
->
Message_Block
[
ctx
->
Message_Block_Index
++
]
=
0
;
}
}
else
{
ctx
->
Message_Block
[
ctx
->
Message_Block_Index
++
]
=
0x80
;
while
(
ctx
->
Message_Block_Index
<
56
)
{
ctx
->
Message_Block
[
ctx
->
Message_Block_Index
++
]
=
0
;
}
}
/*
* Store the message length as the last 8 octets
*/
ctx
->
Message_Block
[
56
]
=
ctx
->
Length_High
>>
24
;
ctx
->
Message_Block
[
57
]
=
ctx
->
Length_High
>>
16
;
ctx
->
Message_Block
[
58
]
=
ctx
->
Length_High
>>
8
;
ctx
->
Message_Block
[
59
]
=
ctx
->
Length_High
;
ctx
->
Message_Block
[
60
]
=
ctx
->
Length_Low
>>
24
;
ctx
->
Message_Block
[
61
]
=
ctx
->
Length_Low
>>
16
;
ctx
->
Message_Block
[
62
]
=
ctx
->
Length_Low
>>
8
;
ctx
->
Message_Block
[
63
]
=
ctx
->
Length_Low
;
SHA1ProcessMessageBlock
(
ctx
);
}
app/ssl/ssl/Makefile
deleted
100644 → 0
View file @
21c4e110
#############################################################
# Required variables for each makefile
# Discard this section from all parent makefiles
# Expected variables (with automatic defaults):
# CSRCS (all "C" files in the dir)
# SUBDIRS (all subdirs with a Makefile)
# GEN_LIBS - list of libs to be generated ()
# GEN_IMAGES - list of images to be generated ()
# COMPONENTS_xxx - a list of libs/objs in the form
# subdir/lib to be extracted and rolled up into
# a generated lib/image xxx.a ()
#
ifndef
PDIR
GEN_LIBS
=
libsslssl.a
endif
#############################################################
# Configuration i.e. compile options etc.
# Target specific stuff (defines etc.) goes in here!
# Generally values applying to a tree are captured in the
# makefile at its root level - these are then overridden
# for a subtree within the makefile rooted therein
#
#DEFINES +=
#############################################################
# Recursion Magic - Don't touch this!!
#
# Each subtree potentially has an include directory
# corresponding to the common APIs applicable to modules
# rooted at that subtree. Accordingly, the INCLUDE PATH
# of a module can only contain the include directories up
# its parent path, and not its siblings
#
# Required for each makefile to inherit from the parent
#
INCLUDES
:=
$(INCLUDES)
-I
$(PDIR)
include
INCLUDES
+=
-I
./
PDIR
:=
../
$(PDIR)
sinclude
$(PDIR)Makefile
app/ssl/ssl/ssl_asn1.c
deleted
100644 → 0
View file @
21c4e110
/*
* Copyright (c) 2007, Cameron Rich
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the axTLS project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* Some primitive asn methods for extraction ASN.1 data.
*/
//#include <stdio.h>
//#include <stdlib.h>
//#include <string.h>
//#include <time.h>
#include "ssl/ssl_os_port.h"
#include "ssl/ssl_crypto.h"
#include "ssl/ssl_crypto_misc.h"
//#include "os.h"
#include "lwip/mem.h"
struct
tm
{
int
tm_sec
;
/* Seconds. [0-60] (1 leap second) */
int
tm_min
;
/* Minutes. [0-59] */
int
tm_hour
;
/* Hours. [0-23] */
int
tm_mday
;
/* Day. [1-31] */
int
tm_mon
;
/* Month. [0-11] */
int
tm_year
;
/* Year - 1900. */
int
tm_wday
;
/* Day of week. [0-6] */
int
tm_yday
;
/* Days in year.[0-365] */
int
tm_isdst
;
/* DST. [-1/0/1]*/
#ifdef __USE_BSD
long
int
tm_gmtoff
;
/* Seconds east of UTC. */
__const
char
*
tm_zone
;
/* Timezone abbreviation. */
#else
long
int
__tm_gmtoff
;
/* Seconds east of UTC. */
__const
char
*
__tm_zone
;
/* Timezone abbreviation. */
#endif
};
#define SIG_OID_PREFIX_SIZE 8
#define SIG_IIS6_OID_SIZE 5
#define SIG_SUBJECT_ALT_NAME_SIZE 3
/* Must be an RSA algorithm with either SHA1 or MD5 for verifying to work */
static
const
uint8_t
sig_oid_prefix
[
SIG_OID_PREFIX_SIZE
]
=
{
0x2a
,
0x86
,
0x48
,
0x86
,
0xf7
,
0x0d
,
0x01
,
0x01
};
static
const
uint8_t
sig_sha1WithRSAEncrypt
[
SIG_IIS6_OID_SIZE
]
=
{
0x2b
,
0x0e
,
0x03
,
0x02
,
0x1d
};
static
const
uint8_t
sig_subject_alt_name
[
SIG_SUBJECT_ALT_NAME_SIZE
]
=
{
0x55
,
0x1d
,
0x11
};
/* CN, O, OU */
static
const
uint8_t
g_dn_types
[]
=
{
3
,
10
,
11
};
int
ICACHE_FLASH_ATTR
get_asn1_length
(
const
uint8_t
*
buf
,
int
*
offset
)
{
int
len
,
i
;
if
(
!
(
buf
[
*
offset
]
&
0x80
))
/* short form */
{
len
=
buf
[(
*
offset
)
++
];
}
else
/* long form */
{
int
length_bytes
=
buf
[(
*
offset
)
++
]
&
0x7f
;
len
=
0
;
for
(
i
=
0
;
i
<
length_bytes
;
i
++
)
{
len
<<=
8
;
len
+=
buf
[(
*
offset
)
++
];
}
}
return
len
;
}
/**
* Skip the ASN1.1 object type and its length. Get ready to read the object's
* data.
*/
int
ICACHE_FLASH_ATTR
asn1_next_obj
(
const
uint8_t
*
buf
,
int
*
offset
,
int
obj_type
)
{
if
(
buf
[
*
offset
]
!=
obj_type
)
return
X509_NOT_OK
;
(
*
offset
)
++
;
return
get_asn1_length
(
buf
,
offset
);
}
/**
* Skip over an ASN.1 object type completely. Get ready to read the next
* object.
*/
int
ICACHE_FLASH_ATTR
asn1_skip_obj
(
const
uint8_t
*
buf
,
int
*
offset
,
int
obj_type
)
{
int
len
;
if
(
buf
[
*
offset
]
!=
obj_type
)
return
X509_NOT_OK
;
(
*
offset
)
++
;
len
=
get_asn1_length
(
buf
,
offset
);
*
offset
+=
len
;
return
0
;
}
/**
* Read an integer value for ASN.1 data
* Note: This function allocates memory which must be freed by the user.
*/
int
ICACHE_FLASH_ATTR
asn1_get_int
(
const
uint8_t
*
buf
,
int
*
offset
,
uint8_t
**
object
)
{
int
len
;
if
((
len
=
asn1_next_obj
(
buf
,
offset
,
ASN1_INTEGER
))
<
0
)
goto
end_int_array
;
if
(
len
>
1
&&
buf
[
*
offset
]
==
0x00
)
/* ignore the negative byte */
{
len
--
;
(
*
offset
)
++
;
}
*
object
=
(
uint8_t
*
)
os_malloc
(
len
);
os_memcpy
(
*
object
,
&
buf
[
*
offset
],
len
);
*
offset
+=
len
;
end_int_array:
return
len
;
}
/**
* Get all the RSA private key specifics from an ASN.1 encoded file
*/
int
ICACHE_FLASH_ATTR
asn1_get_private_key
(
const
uint8_t
*
buf
,
int
len
,
RSA_CTX
**
rsa_ctx
)
{
int
offset
=
7
;
uint8_t
*
modulus
=
NULL
,
*
priv_exp
=
NULL
,
*
pub_exp
=
NULL
;
int
mod_len
,
priv_len
,
pub_len
;
#ifdef CONFIG_BIGINT_CRT
uint8_t
*
p
=
NULL
,
*
q
=
NULL
,
*
dP
=
NULL
,
*
dQ
=
NULL
,
*
qInv
=
NULL
;
int
p_len
,
q_len
,
dP_len
,
dQ_len
,
qInv_len
;
#endif
/* not in der format */
if
(
buf
[
0
]
!=
ASN1_SEQUENCE
)
/* basic sanity check */
{
#ifdef CONFIG_SSL_FULL_MODE
ssl_printf
(
"Error: This is not a valid ASN.1 file
\n
"
);
#endif
return
X509_INVALID_PRIV_KEY
;
}
/* Use the private key to mix up the RNG if possible. */
RNG_custom_init
(
buf
,
len
);
mod_len
=
asn1_get_int
(
buf
,
&
offset
,
&
modulus
);
pub_len
=
asn1_get_int
(
buf
,
&
offset
,
&
pub_exp
);
priv_len
=
asn1_get_int
(
buf
,
&
offset
,
&
priv_exp
);
if
(
mod_len
<=
0
||
pub_len
<=
0
||
priv_len
<=
0
)
return
X509_INVALID_PRIV_KEY
;
#ifdef CONFIG_BIGINT_CRT
p_len
=
asn1_get_int
(
buf
,
&
offset
,
&
p
);
q_len
=
asn1_get_int
(
buf
,
&
offset
,
&
q
);
dP_len
=
asn1_get_int
(
buf
,
&
offset
,
&
dP
);
dQ_len
=
asn1_get_int
(
buf
,
&
offset
,
&
dQ
);
qInv_len
=
asn1_get_int
(
buf
,
&
offset
,
&
qInv
);
if
(
p_len
<=
0
||
q_len
<=
0
||
dP_len
<=
0
||
dQ_len
<=
0
||
qInv_len
<=
0
)
return
X509_INVALID_PRIV_KEY
;
RSA_priv_key_new
(
rsa_ctx
,
modulus
,
mod_len
,
pub_exp
,
pub_len
,
priv_exp
,
priv_len
,
p
,
p_len
,
q
,
p_len
,
dP
,
dP_len
,
dQ
,
dQ_len
,
qInv
,
qInv_len
);
os_free
(
p
);
os_free
(
q
);
os_free
(
dP
);
os_free
(
dQ
);
os_free
(
qInv
);
#else
RSA_priv_key_new
(
rsa_ctx
,
modulus
,
mod_len
,
pub_exp
,
pub_len
,
priv_exp
,
priv_len
);
#endif
os_free
(
modulus
);
os_free
(
priv_exp
);
os_free
(
pub_exp
);
return
X509_OK
;
}
/**
* Get the time of a certificate. Ignore hours/minutes/seconds.
*/
static
int
ICACHE_FLASH_ATTR
asn1_get_utc_time
(
const
uint8_t
*
buf
,
int
*
offset
,
time_t
*
t
)
{
int
ret
=
X509_NOT_OK
,
len
,
t_offset
;
struct
tm
tm
;
if
(
buf
[(
*
offset
)
++
]
!=
ASN1_UTC_TIME
)
goto
end_utc_time
;
len
=
get_asn1_length
(
buf
,
offset
);
t_offset
=
*
offset
;
os_memset
(
&
tm
,
0
,
sizeof
(
struct
tm
));
tm
.
tm_year
=
(
buf
[
t_offset
]
-
'0'
)
*
10
+
(
buf
[
t_offset
+
1
]
-
'0'
);
if
(
tm
.
tm_year
<=
50
)
/* 1951-2050 thing */
{
tm
.
tm_year
+=
100
;
}
tm
.
tm_mon
=
(
buf
[
t_offset
+
2
]
-
'0'
)
*
10
+
(
buf
[
t_offset
+
3
]
-
'0'
)
-
1
;
tm
.
tm_mday
=
(
buf
[
t_offset
+
4
]
-
'0'
)
*
10
+
(
buf
[
t_offset
+
5
]
-
'0'
);
// wujg : pass compile first
// *t = mktime(&tm);
*
offset
+=
len
;
ret
=
X509_OK
;
end_utc_time:
return
ret
;
}
/**
* Get the version type of a certificate (which we don't actually care about)
*/
int
ICACHE_FLASH_ATTR
asn1_version
(
const
uint8_t
*
cert
,
int
*
offset
,
X509_CTX
*
x509_ctx
)
{
int
ret
=
X509_NOT_OK
;
(
*
offset
)
+=
2
;
/* get past explicit tag */
if
(
asn1_skip_obj
(
cert
,
offset
,
ASN1_INTEGER
))
goto
end_version
;
ret
=
X509_OK
;
end_version:
return
ret
;
}
/**
* Retrieve the notbefore and notafter certificate times.
*/
int
ICACHE_FLASH_ATTR
asn1_validity
(
const
uint8_t
*
cert
,
int
*
offset
,
X509_CTX
*
x509_ctx
)
{
return
(
asn1_next_obj
(
cert
,
offset
,
ASN1_SEQUENCE
)
<
0
||
asn1_get_utc_time
(
cert
,
offset
,
&
x509_ctx
->
not_before
)
||
asn1_get_utc_time
(
cert
,
offset
,
&
x509_ctx
->
not_after
));
}
/**
* Get the components of a distinguished name
*/
static
int
ICACHE_FLASH_ATTR
asn1_get_oid_x520
(
const
uint8_t
*
buf
,
int
*
offset
)
{
int
dn_type
=
0
;
int
len
;
if
((
len
=
asn1_next_obj
(
buf
,
offset
,
ASN1_OID
))
<
0
)
goto
end_oid
;
/* expect a sequence of 2.5.4.[x] where x is a one of distinguished name
components we are interested in. */
if
(
len
==
3
&&
buf
[(
*
offset
)
++
]
==
0x55
&&
buf
[(
*
offset
)
++
]
==
0x04
)
dn_type
=
buf
[(
*
offset
)
++
];
else
{
*
offset
+=
len
;
/* skip over it */
}
end_oid:
return
dn_type
;
}
/**
* Obtain an ASN.1 printable string type.
*/
static
int
ICACHE_FLASH_ATTR
asn1_get_printable_str
(
const
uint8_t
*
buf
,
int
*
offset
,
char
**
str
)
{
int
len
=
X509_NOT_OK
;
int
asn1_type
=
buf
[
*
offset
];
/* some certs have this awful crud in them for some reason */
if
(
asn1_type
!=
ASN1_PRINTABLE_STR
&&
asn1_type
!=
ASN1_PRINTABLE_STR2
&&
asn1_type
!=
ASN1_TELETEX_STR
&&
asn1_type
!=
ASN1_IA5_STR
&&
asn1_type
!=
ASN1_UNICODE_STR
)
goto
end_pnt_str
;
(
*
offset
)
++
;
len
=
get_asn1_length
(
buf
,
offset
);
if
(
asn1_type
==
ASN1_UNICODE_STR
)
{
int
i
;
*
str
=
(
char
*
)
os_malloc
(
len
/
2
+
1
);
/* allow for null */
for
(
i
=
0
;
i
<
len
;
i
+=
2
)
(
*
str
)[
i
/
2
]
=
buf
[
*
offset
+
i
+
1
];
(
*
str
)[
len
/
2
]
=
0
;
/* null terminate */
}
else
{
*
str
=
(
char
*
)
os_malloc
(
len
+
1
);
/* allow for null */
os_memcpy
(
*
str
,
&
buf
[
*
offset
],
len
);
(
*
str
)[
len
]
=
0
;
/* null terminate */
}
*
offset
+=
len
;
end_pnt_str:
return
len
;
}
/**
* Get the subject name (or the issuer) of a certificate.
*/
int
ICACHE_FLASH_ATTR
asn1_name
(
const
uint8_t
*
cert
,
int
*
offset
,
char
*
dn
[])
{
int
ret
=
X509_NOT_OK
;
int
dn_type
;
char
*
tmp
;
if
(
asn1_next_obj
(
cert
,
offset
,
ASN1_SEQUENCE
)
<
0
)
goto
end_name
;
while
(
asn1_next_obj
(
cert
,
offset
,
ASN1_SET
)
>=
0
)
{
int
i
,
found
=
0
;
if
(
asn1_next_obj
(
cert
,
offset
,
ASN1_SEQUENCE
)
<
0
||
(
dn_type
=
asn1_get_oid_x520
(
cert
,
offset
))
<
0
)
goto
end_name
;
tmp
=
NULL
;
if
(
asn1_get_printable_str
(
cert
,
offset
,
&
tmp
)
<
0
)
{
os_free
(
tmp
);
goto
end_name
;
}
/* find the distinguished named type */
for
(
i
=
0
;
i
<
X509_NUM_DN_TYPES
;
i
++
)
{
if
(
dn_type
==
g_dn_types
[
i
])
{
if
(
dn
[
i
]
==
NULL
)
{
dn
[
i
]
=
tmp
;
found
=
1
;
break
;
}
}
}
if
(
found
==
0
)
/* not found so get rid of it */
{
os_free
(
tmp
);
}
}
ret
=
X509_OK
;
end_name:
return
ret
;
}
/**
* Read the modulus and public exponent of a certificate.
*/
int
ICACHE_FLASH_ATTR
asn1_public_key
(
const
uint8_t
*
cert
,
int
*
offset
,
X509_CTX
*
x509_ctx
)
{
int
ret
=
X509_NOT_OK
,
mod_len
,
pub_len
;
uint8_t
*
modulus
=
NULL
,
*
pub_exp
=
NULL
;
if
(
asn1_next_obj
(
cert
,
offset
,
ASN1_SEQUENCE
)
<
0
||
asn1_skip_obj
(
cert
,
offset
,
ASN1_SEQUENCE
)
||
asn1_next_obj
(
cert
,
offset
,
ASN1_BIT_STRING
)
<
0
)
goto
end_pub_key
;
(
*
offset
)
++
;
/* ignore the padding bit field */
if
(
asn1_next_obj
(
cert
,
offset
,
ASN1_SEQUENCE
)
<
0
)
goto
end_pub_key
;
mod_len
=
asn1_get_int
(
cert
,
offset
,
&
modulus
);
pub_len
=
asn1_get_int
(
cert
,
offset
,
&
pub_exp
);
RSA_pub_key_new
(
&
x509_ctx
->
rsa_ctx
,
modulus
,
mod_len
,
pub_exp
,
pub_len
);
os_free
(
modulus
);
os_free
(
pub_exp
);
ret
=
X509_OK
;
end_pub_key:
return
ret
;
}
#ifdef CONFIG_SSL_CERT_VERIFICATION
/**
* Read the signature of the certificate.
*/
int
ICACHE_FLASH_ATTR
asn1_signature
(
const
uint8_t
*
cert
,
int
*
offset
,
X509_CTX
*
x509_ctx
)
{
int
ret
=
X509_NOT_OK
;
if
(
cert
[(
*
offset
)
++
]
!=
ASN1_BIT_STRING
)
goto
end_sig
;
x509_ctx
->
sig_len
=
get_asn1_length
(
cert
,
offset
)
-
1
;
(
*
offset
)
++
;
/* ignore bit string padding bits */
x509_ctx
->
signature
=
(
uint8_t
*
)
os_malloc
(
x509_ctx
->
sig_len
);
os_memcpy
(
x509_ctx
->
signature
,
&
cert
[
*
offset
],
x509_ctx
->
sig_len
);
*
offset
+=
x509_ctx
->
sig_len
;
ret
=
X509_OK
;
end_sig:
return
ret
;
}
/*
* Compare 2 distinguished name components for equality
* @return 0 if a match
*/
static
int
ICACHE_FLASH_ATTR
asn1_compare_dn_comp
(
const
char
*
dn1
,
const
char
*
dn2
)
{
int
ret
;
if
(
dn1
==
NULL
&&
dn2
==
NULL
)
ret
=
0
;
else
ret
=
(
dn1
&&
dn2
)
?
os_strcmp
(
dn1
,
dn2
)
:
1
;
return
ret
;
}
/**
* Clean up all of the CA certificates.
*/
void
ICACHE_FLASH_ATTR
remove_ca_certs
(
CA_CERT_CTX
*
ca_cert_ctx
)
{
int
i
=
0
;
if
(
ca_cert_ctx
==
NULL
)
return
;
while
(
i
<
CONFIG_X509_MAX_CA_CERTS
&&
ca_cert_ctx
->
cert
[
i
])
{
x509_free
(
ca_cert_ctx
->
cert
[
i
]);
ca_cert_ctx
->
cert
[
i
++
]
=
NULL
;
}
os_free
(
ca_cert_ctx
);
}
/*
* Compare 2 distinguished names for equality
* @return 0 if a match
*/
int
ICACHE_FLASH_ATTR
asn1_compare_dn
(
char
*
const
dn1
[],
char
*
const
dn2
[])
{
int
i
;
for
(
i
=
0
;
i
<
X509_NUM_DN_TYPES
;
i
++
)
{
if
(
asn1_compare_dn_comp
(
dn1
[
i
],
dn2
[
i
]))
return
1
;
}
return
0
;
/* all good */
}
int
ICACHE_FLASH_ATTR
asn1_find_oid
(
const
uint8_t
*
cert
,
int
*
offset
,
const
uint8_t
*
oid
,
int
oid_length
)
{
int
seqlen
;
if
((
seqlen
=
asn1_next_obj
(
cert
,
offset
,
ASN1_SEQUENCE
))
>
0
)
{
int
end
=
*
offset
+
seqlen
;
while
(
*
offset
<
end
)
{
int
type
=
cert
[(
*
offset
)
++
];
int
length
=
get_asn1_length
(
cert
,
offset
);
int
noffset
=
*
offset
+
length
;
if
(
type
==
ASN1_SEQUENCE
)
{
type
=
cert
[(
*
offset
)
++
];
length
=
get_asn1_length
(
cert
,
offset
);
if
(
type
==
ASN1_OID
&&
length
==
oid_length
&&
os_memcmp
(
cert
+
*
offset
,
oid
,
oid_length
)
==
0
)
{
*
offset
+=
oid_length
;
return
1
;
}
}
*
offset
=
noffset
;
}
}
return
0
;
}
int
ICACHE_FLASH_ATTR
asn1_find_subjectaltname
(
const
uint8_t
*
cert
,
int
offset
)
{
if
(
asn1_find_oid
(
cert
,
&
offset
,
sig_subject_alt_name
,
SIG_SUBJECT_ALT_NAME_SIZE
))
{
return
offset
;
}
return
0
;
}
#endif
/* CONFIG_SSL_CERT_VERIFICATION */
/**
* Read the signature type of the certificate. We only support RSA-MD5 and
* RSA-SHA1 signature types.
*/
int
ICACHE_FLASH_ATTR
asn1_signature_type
(
const
uint8_t
*
cert
,
int
*
offset
,
X509_CTX
*
x509_ctx
)
{
int
ret
=
X509_NOT_OK
,
len
;
if
(
cert
[(
*
offset
)
++
]
!=
ASN1_OID
)
goto
end_check_sig
;
len
=
get_asn1_length
(
cert
,
offset
);
if
(
len
==
5
&&
os_memcmp
(
sig_sha1WithRSAEncrypt
,
&
cert
[
*
offset
],
SIG_IIS6_OID_SIZE
)
==
0
)
{
x509_ctx
->
sig_type
=
SIG_TYPE_SHA1
;
}
else
{
if
(
os_memcmp
(
sig_oid_prefix
,
&
cert
[
*
offset
],
SIG_OID_PREFIX_SIZE
))
goto
end_check_sig
;
/* unrecognised cert type */
x509_ctx
->
sig_type
=
cert
[
*
offset
+
SIG_OID_PREFIX_SIZE
];
}
*
offset
+=
len
;
asn1_skip_obj
(
cert
,
offset
,
ASN1_NULL
);
/* if it's there */
ret
=
X509_OK
;
end_check_sig:
return
ret
;
}
app/ssl/ssl/ssl_gen_cert.c
deleted
100644 → 0
View file @
21c4e110
/*
* Copyright (c) 2007, Cameron Rich
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the axTLS project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "ssl/ssl_config.h"
#ifdef CONFIG_SSL_GENERATE_X509_CERT
#include <string.h>
#include <stdlib.h>
#include "ssl/ssl_os_port.h"
#include "ssl/ssl_ssl.h"
/**
* Generate a basic X.509 certificate
*/
static
uint8_t
ICACHE_FLASH_ATTR
set_gen_length
(
int
len
,
uint8_t
*
buf
,
int
*
offset
)
{
if
(
len
<
0x80
)
/* short form */
{
buf
[(
*
offset
)
++
]
=
len
;
return
1
;
}
else
/* long form */
{
int
i
,
length_bytes
=
0
;
if
(
len
&
0x00FF0000
)
length_bytes
=
3
;
else
if
(
len
&
0x0000FF00
)
length_bytes
=
2
;
else
if
(
len
&
0x000000FF
)
length_bytes
=
1
;
buf
[(
*
offset
)
++
]
=
0x80
+
length_bytes
;
for
(
i
=
length_bytes
-
1
;
i
>=
0
;
i
--
)
{
buf
[
*
offset
+
i
]
=
len
&
0xFF
;
len
>>=
8
;
}
*
offset
+=
length_bytes
;
return
length_bytes
+
1
;
}
}
static
int
ICACHE_FLASH_ATTR
pre_adjust_with_size
(
uint8_t
type
,
int
*
seq_offset
,
uint8_t
*
buf
,
int
*
offset
)
{
buf
[(
*
offset
)
++
]
=
type
;
*
seq_offset
=
*
offset
;
*
offset
+=
4
;
/* fill in later */
return
*
offset
;
}
static
void
ICACHE_FLASH_ATTR
adjust_with_size
(
int
seq_size
,
int
seq_start
,
uint8_t
*
buf
,
int
*
offset
)
{
uint8_t
seq_byte_size
;
int
orig_seq_size
=
seq_size
;
int
orig_seq_start
=
seq_start
;
seq_size
=
*
offset
-
seq_size
;
seq_byte_size
=
set_gen_length
(
seq_size
,
buf
,
&
seq_start
);
if
(
seq_byte_size
!=
4
)
{
memmove
(
&
buf
[
orig_seq_start
+
seq_byte_size
],
&
buf
[
orig_seq_size
],
seq_size
);
*
offset
-=
4
-
seq_byte_size
;
}
}
static
void
ICACHE_FLASH_ATTR
gen_serial_number
(
uint8_t
*
buf
,
int
*
offset
)
{
static
const
uint8_t
ser_oid
[]
=
{
ASN1_INTEGER
,
1
,
0x7F
};
memcpy
(
&
buf
[
*
offset
],
ser_oid
,
sizeof
(
ser_oid
));
*
offset
+=
sizeof
(
ser_oid
);
}
static
void
ICACHE_FLASH_ATTR
gen_signature_alg
(
uint8_t
*
buf
,
int
*
offset
)
{
/* OBJECT IDENTIFIER sha1withRSAEncryption (1 2 840 113549 1 1 5) */
static
const
uint8_t
sig_oid
[]
=
{
ASN1_SEQUENCE
,
0x0d
,
ASN1_OID
,
0x09
,
0x2a
,
0x86
,
0x48
,
0x86
,
0xf7
,
0x0d
,
0x01
,
0x01
,
0x05
,
ASN1_NULL
,
0x00
};
memcpy
(
&
buf
[
*
offset
],
sig_oid
,
sizeof
(
sig_oid
));
*
offset
+=
sizeof
(
sig_oid
);
}
static
int
ICACHE_FLASH_ATTR
gen_dn
(
const
char
*
name
,
uint8_t
dn_type
,
uint8_t
*
buf
,
int
*
offset
)
{
int
ret
=
X509_OK
;
int
name_size
=
strlen
(
name
);
if
(
name_size
>
0x70
)
/* just too big */
{
ret
=
X509_NOT_OK
;
goto
error
;
}
buf
[(
*
offset
)
++
]
=
ASN1_SET
;
set_gen_length
(
9
+
name_size
,
buf
,
offset
);
buf
[(
*
offset
)
++
]
=
ASN1_SEQUENCE
;
set_gen_length
(
7
+
name_size
,
buf
,
offset
);
buf
[(
*
offset
)
++
]
=
ASN1_OID
;
buf
[(
*
offset
)
++
]
=
3
;
buf
[(
*
offset
)
++
]
=
0x55
;
buf
[(
*
offset
)
++
]
=
0x04
;
buf
[(
*
offset
)
++
]
=
dn_type
;
buf
[(
*
offset
)
++
]
=
ASN1_PRINTABLE_STR
;
buf
[(
*
offset
)
++
]
=
name_size
;
strcpy
(
&
buf
[
*
offset
],
name
);
*
offset
+=
name_size
;
error:
return
ret
;
}
static
int
ICACHE_FLASH_ATTR
gen_issuer
(
const
char
*
dn
[],
uint8_t
*
buf
,
int
*
offset
)
{
int
ret
=
X509_OK
;
int
seq_offset
;
int
seq_size
=
pre_adjust_with_size
(
ASN1_SEQUENCE
,
&
seq_offset
,
buf
,
offset
);
char
fqdn
[
128
];
/* we need the common name, so if not configured, work out the fully
* qualified domain name */
if
(
dn
[
X509_COMMON_NAME
]
==
NULL
||
strlen
(
dn
[
X509_COMMON_NAME
])
==
0
)
{
int
fqdn_len
;
gethostname
(
fqdn
,
sizeof
(
fqdn
));
fqdn_len
=
strlen
(
fqdn
);
fqdn
[
fqdn_len
++
]
=
'.'
;
getdomainname
(
&
fqdn
[
fqdn_len
],
sizeof
(
fqdn
)
-
fqdn_len
);
fqdn_len
=
strlen
(
fqdn
);
if
(
fqdn
[
fqdn_len
-
1
]
==
'.'
)
/* ensure '.' is not last char */
fqdn
[
fqdn_len
-
1
]
=
0
;
dn
[
X509_COMMON_NAME
]
=
fqdn
;
}
if
((
ret
=
gen_dn
(
dn
[
X509_COMMON_NAME
],
3
,
buf
,
offset
)))
goto
error
;
if
(
dn
[
X509_ORGANIZATION
]
!=
NULL
&&
strlen
(
dn
[
X509_ORGANIZATION
])
>
0
)
{
if
((
ret
=
gen_dn
(
dn
[
X509_ORGANIZATION
],
10
,
buf
,
offset
)))
goto
error
;
}
if
(
dn
[
X509_ORGANIZATIONAL_UNIT
]
!=
NULL
&&
strlen
(
dn
[
X509_ORGANIZATIONAL_UNIT
])
>
0
)
{
if
((
ret
=
gen_dn
(
dn
[
X509_ORGANIZATIONAL_UNIT
],
11
,
buf
,
offset
)))
goto
error
;
}
adjust_with_size
(
seq_size
,
seq_offset
,
buf
,
offset
);
error:
return
ret
;
}
static
void
ICACHE_FLASH_ATTR
gen_utc_time
(
uint8_t
*
buf
,
int
*
offset
)
{
static
const
uint8_t
time_seq
[]
=
{
ASN1_SEQUENCE
,
30
,
ASN1_UTC_TIME
,
13
,
'0'
,
'7'
,
'0'
,
'1'
,
'0'
,
'1'
,
'0'
,
'0'
,
'0'
,
'0'
,
'0'
,
'0'
,
'Z'
,
ASN1_UTC_TIME
,
13
,
/* make it good for 30 or so years */
'3'
,
'8'
,
'0'
,
'1'
,
'0'
,
'1'
,
'0'
,
'0'
,
'0'
,
'0'
,
'0'
,
'0'
,
'Z'
};
/* fixed time */
memcpy
(
&
buf
[
*
offset
],
time_seq
,
sizeof
(
time_seq
));
*
offset
+=
sizeof
(
time_seq
);
}
static
void
ICACHE_FLASH_ATTR
gen_pub_key2
(
const
RSA_CTX
*
rsa_ctx
,
uint8_t
*
buf
,
int
*
offset
)
{
static
const
uint8_t
pub_key_seq
[]
=
{
ASN1_INTEGER
,
0x03
,
0x01
,
0x00
,
0x01
/* INTEGER 65537 */
};
int
seq_offset
;
int
pub_key_size
=
rsa_ctx
->
num_octets
;
uint8_t
*
block
=
(
uint8_t
*
)
alloca
(
pub_key_size
);
int
seq_size
=
pre_adjust_with_size
(
ASN1_SEQUENCE
,
&
seq_offset
,
buf
,
offset
);
buf
[(
*
offset
)
++
]
=
ASN1_INTEGER
;
bi_export
(
rsa_ctx
->
bi_ctx
,
rsa_ctx
->
m
,
block
,
pub_key_size
);
if
(
*
block
&
0x80
)
/* make integer positive */
{
set_gen_length
(
pub_key_size
+
1
,
buf
,
offset
);
buf
[(
*
offset
)
++
]
=
0
;
}
else
set_gen_length
(
pub_key_size
,
buf
,
offset
);
memcpy
(
&
buf
[
*
offset
],
block
,
pub_key_size
);
*
offset
+=
pub_key_size
;
memcpy
(
&
buf
[
*
offset
],
pub_key_seq
,
sizeof
(
pub_key_seq
));
*
offset
+=
sizeof
(
pub_key_seq
);
adjust_with_size
(
seq_size
,
seq_offset
,
buf
,
offset
);
}
static
void
ICACHE_FLASH_ATTR
gen_pub_key1
(
const
RSA_CTX
*
rsa_ctx
,
uint8_t
*
buf
,
int
*
offset
)
{
int
seq_offset
;
int
seq_size
=
pre_adjust_with_size
(
ASN1_BIT_STRING
,
&
seq_offset
,
buf
,
offset
);
buf
[(
*
offset
)
++
]
=
0
;
/* bit string is multiple of 8 */
gen_pub_key2
(
rsa_ctx
,
buf
,
offset
);
adjust_with_size
(
seq_size
,
seq_offset
,
buf
,
offset
);
}
static
void
ICACHE_FLASH_ATTR
gen_pub_key
(
const
RSA_CTX
*
rsa_ctx
,
uint8_t
*
buf
,
int
*
offset
)
{
/* OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1) */
static
const
uint8_t
rsa_enc_oid
[]
=
{
ASN1_SEQUENCE
,
0x0d
,
ASN1_OID
,
0x09
,
0x2a
,
0x86
,
0x48
,
0x86
,
0xf7
,
0x0d
,
0x01
,
0x01
,
0x01
,
ASN1_NULL
,
0x00
};
int
seq_offset
;
int
seq_size
=
pre_adjust_with_size
(
ASN1_SEQUENCE
,
&
seq_offset
,
buf
,
offset
);
memcpy
(
&
buf
[
*
offset
],
rsa_enc_oid
,
sizeof
(
rsa_enc_oid
));
*
offset
+=
sizeof
(
rsa_enc_oid
);
gen_pub_key1
(
rsa_ctx
,
buf
,
offset
);
adjust_with_size
(
seq_size
,
seq_offset
,
buf
,
offset
);
}
static
void
ICACHE_FLASH_ATTR
gen_signature
(
const
RSA_CTX
*
rsa_ctx
,
const
uint8_t
*
sha_dgst
,
uint8_t
*
buf
,
int
*
offset
)
{
static
const
uint8_t
asn1_sig
[]
=
{
ASN1_SEQUENCE
,
0x21
,
ASN1_SEQUENCE
,
0x09
,
ASN1_OID
,
0x05
,
0x2b
,
0x0e
,
0x03
,
0x02
,
0x1a
,
/* sha1 (1 3 14 3 2 26) */
ASN1_NULL
,
0x00
,
ASN1_OCTET_STRING
,
0x14
};
uint8_t
*
enc_block
=
(
uint8_t
*
)
alloca
(
rsa_ctx
->
num_octets
);
uint8_t
*
block
=
(
uint8_t
*
)
alloca
(
sizeof
(
asn1_sig
)
+
SHA1_SIZE
);
int
sig_size
;
/* add the digest as an embedded asn.1 sequence */
memcpy
(
block
,
asn1_sig
,
sizeof
(
asn1_sig
));
memcpy
(
&
block
[
sizeof
(
asn1_sig
)],
sha_dgst
,
SHA1_SIZE
);
sig_size
=
RSA_encrypt
(
rsa_ctx
,
block
,
sizeof
(
asn1_sig
)
+
SHA1_SIZE
,
enc_block
,
1
);
buf
[(
*
offset
)
++
]
=
ASN1_BIT_STRING
;
set_gen_length
(
sig_size
+
1
,
buf
,
offset
);
buf
[(
*
offset
)
++
]
=
0
;
/* bit string is multiple of 8 */
memcpy
(
&
buf
[
*
offset
],
enc_block
,
sig_size
);
*
offset
+=
sig_size
;
}
static
int
ICACHE_FLASH_ATTR
gen_tbs_cert
(
const
char
*
dn
[],
const
RSA_CTX
*
rsa_ctx
,
uint8_t
*
buf
,
int
*
offset
,
uint8_t
*
sha_dgst
)
{
int
ret
=
X509_OK
;
SHA1_CTX
sha_ctx
;
int
seq_offset
;
int
begin_tbs
=
*
offset
;
int
seq_size
=
pre_adjust_with_size
(
ASN1_SEQUENCE
,
&
seq_offset
,
buf
,
offset
);
gen_serial_number
(
buf
,
offset
);
gen_signature_alg
(
buf
,
offset
);
/* CA certicate issuer */
if
((
ret
=
gen_issuer
(
dn
,
buf
,
offset
)))
goto
error
;
gen_utc_time
(
buf
,
offset
);
/* certificate issuer */
if
((
ret
=
gen_issuer
(
dn
,
buf
,
offset
)))
goto
error
;
gen_pub_key
(
rsa_ctx
,
buf
,
offset
);
adjust_with_size
(
seq_size
,
seq_offset
,
buf
,
offset
);
SHA1_Init
(
&
sha_ctx
);
SHA1_Update
(
&
sha_ctx
,
&
buf
[
begin_tbs
],
*
offset
-
begin_tbs
);
SHA1_Final
(
sha_dgst
,
&
sha_ctx
);
error:
return
ret
;
}
/**
* Create a new certificate.
*/
EXP_FUNC
int
ICACHE_FLASH_ATTR
STDCALL
ssl_x509_create
(
SSL_CTX
*
ssl_ctx
,
uint32_t
options
,
const
char
*
dn
[],
uint8_t
**
cert_data
)
{
int
ret
=
X509_OK
,
offset
=
0
,
seq_offset
;
/* allocate enough space to load a new certificate */
uint8_t
*
buf
=
(
uint8_t
*
)
alloca
(
ssl_ctx
->
rsa_ctx
->
num_octets
*
2
+
512
);
uint8_t
sha_dgst
[
SHA1_SIZE
];
int
seq_size
=
pre_adjust_with_size
(
ASN1_SEQUENCE
,
&
seq_offset
,
buf
,
&
offset
);
if
((
ret
=
gen_tbs_cert
(
dn
,
ssl_ctx
->
rsa_ctx
,
buf
,
&
offset
,
sha_dgst
))
<
0
)
goto
error
;
gen_signature_alg
(
buf
,
&
offset
);
gen_signature
(
ssl_ctx
->
rsa_ctx
,
sha_dgst
,
buf
,
&
offset
);
adjust_with_size
(
seq_size
,
seq_offset
,
buf
,
&
offset
);
*
cert_data
=
(
uint8_t
*
)
os_malloc
(
offset
);
/* create the exact memory for it */
memcpy
(
*
cert_data
,
buf
,
offset
);
error:
return
ret
<
0
?
ret
:
offset
;
}
#endif
app/ssl/ssl/ssl_loader.c
deleted
100644 → 0
View file @
21c4e110
/*
* Copyright (c) 2007, Cameron Rich
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the axTLS project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* Load certificates/keys into memory. These can be in many different formats.
* PEM support and other formats can be processed here.
*
* The PEM private keys may be optionally encrypted with AES128 or AES256.
* The encrypted PEM keys were generated with something like:
*
* openssl genrsa -aes128 -passout pass:abcd -out axTLS.key_aes128.pem 512
*/
//#include <stdlib.h>
//#include <string.h>
//#include <stdio.h>
#include "ssl/ssl_os_port.h"
#include "ssl/ssl_ssl.h"
static
int
do_obj
(
SSL_CTX
*
ssl_ctx
,
int
obj_type
,
SSLObjLoader
*
ssl_obj
,
const
char
*
password
);
#ifdef CONFIG_SSL_HAS_PEM
static
int
ssl_obj_PEM_load
(
SSL_CTX
*
ssl_ctx
,
int
obj_type
,
SSLObjLoader
*
ssl_obj
,
const
char
*
password
);
#endif
/*
* Load a file into memory that is in binary DER (or ascii PEM) format.
*/
EXP_FUNC
int
STDCALL
ICACHE_FLASH_ATTR
ssl_obj_load
(
SSL_CTX
*
ssl_ctx
,
int
obj_type
,
const
char
*
filename
,
const
char
*
password
)
{
#ifndef CONFIG_SSL_SKELETON_MODE
static
const
char
*
const
begin
=
"-----BEGIN"
;
int
ret
=
SSL_OK
;
SSLObjLoader
*
ssl_obj
=
NULL
;
if
(
filename
==
NULL
)
{
ret
=
SSL_ERROR_INVALID_KEY
;
goto
error
;
}
ssl_obj
=
(
SSLObjLoader
*
)
os_zalloc
(
sizeof
(
SSLObjLoader
));
ssl_obj
->
len
=
get_file
(
filename
,
&
ssl_obj
->
buf
);
if
(
ssl_obj
->
len
<=
0
)
{
ret
=
SSL_ERROR_INVALID_KEY
;
goto
error
;
}
/* is the file a PEM file? */
if
((
char
*
)
os_strstr
((
const
char
*
)
ssl_obj
->
buf
,
begin
)
!=
NULL
)
{
#ifdef CONFIG_SSL_HAS_PEM
ret
=
ssl_obj_PEM_load
(
ssl_ctx
,
obj_type
,
ssl_obj
,
password
);
#else
ssl_printf
(
unsupported_str
);
ret
=
SSL_ERROR_NOT_SUPPORTED
;
#endif
}
else
ret
=
do_obj
(
ssl_ctx
,
obj_type
,
ssl_obj
,
password
);
error:
ssl_obj_free
(
ssl_obj
);
return
ret
;
#else
ssl_printf
(
unsupported_str
);
return
SSL_ERROR_NOT_SUPPORTED
;
#endif
/* CONFIG_SSL_SKELETON_MODE */
}
/*
* Transfer binary data into the object loader.
*/
EXP_FUNC
int
STDCALL
ICACHE_FLASH_ATTR
ssl_obj_memory_load
(
SSL_CTX
*
ssl_ctx
,
int
mem_type
,
const
uint8_t
*
data
,
int
len
,
const
char
*
password
)
{
int
ret
;
SSLObjLoader
*
ssl_obj
;
ssl_obj
=
(
SSLObjLoader
*
)
os_zalloc
(
sizeof
(
SSLObjLoader
));
ssl_obj
->
buf
=
(
uint8_t
*
)
os_malloc
(
len
);
os_memcpy
(
ssl_obj
->
buf
,
data
,
len
);
ssl_obj
->
len
=
len
;
ret
=
do_obj
(
ssl_ctx
,
mem_type
,
ssl_obj
,
password
);
ssl_obj_free
(
ssl_obj
);
return
ret
;
}
/*
* Actually work out what we are doing
*/
static
int
ICACHE_FLASH_ATTR
do_obj
(
SSL_CTX
*
ssl_ctx
,
int
obj_type
,
SSLObjLoader
*
ssl_obj
,
const
char
*
password
)
{
int
ret
=
SSL_OK
;
switch
(
obj_type
)
{
case
SSL_OBJ_RSA_KEY
:
ret
=
add_private_key
(
ssl_ctx
,
ssl_obj
);
break
;
case
SSL_OBJ_X509_CERT
:
ret
=
add_cert
(
ssl_ctx
,
ssl_obj
->
buf
,
ssl_obj
->
len
);
break
;
#ifdef CONFIG_SSL_CERT_VERIFICATION
case
SSL_OBJ_X509_CACERT
:
add_cert_auth
(
ssl_ctx
,
ssl_obj
->
buf
,
ssl_obj
->
len
);
break
;
#endif
#ifdef CONFIG_SSL_USE_PKCS12
case
SSL_OBJ_PKCS8
:
ret
=
pkcs8_decode
(
ssl_ctx
,
ssl_obj
,
password
);
break
;
case
SSL_OBJ_PKCS12
:
ret
=
pkcs12_decode
(
ssl_ctx
,
ssl_obj
,
password
);
break
;
#endif
default:
ssl_printf
(
unsupported_str
);
ret
=
SSL_ERROR_NOT_SUPPORTED
;
break
;
}
return
ret
;
}
/*
* Clean up our mess.
*/
void
ICACHE_FLASH_ATTR
ssl_obj_free
(
SSLObjLoader
*
ssl_obj
)
{
if
(
ssl_obj
)
{
os_free
(
ssl_obj
->
buf
);
os_free
(
ssl_obj
);
}
}
/*
* Support for PEM encoded keys/certificates.
*/
#ifdef CONFIG_SSL_HAS_PEM
#define NUM_PEM_TYPES 4
#define IV_SIZE 16
#define IS_RSA_PRIVATE_KEY 0
#define IS_ENCRYPTED_PRIVATE_KEY 1
#define IS_PRIVATE_KEY 2
#define IS_CERTIFICATE 3
static
const
char
*
const
begins
[
NUM_PEM_TYPES
]
=
{
"-----BEGIN RSA PRIVATE KEY-----"
,
"-----BEGIN ENCRYPTED PRIVATE KEY-----"
,
"-----BEGIN PRIVATE KEY-----"
,
"-----BEGIN CERTIFICATE-----"
,
};
static
const
char
*
const
ends
[
NUM_PEM_TYPES
]
=
{
"-----END RSA PRIVATE KEY-----"
,
"-----END ENCRYPTED PRIVATE KEY-----"
,
"-----END PRIVATE KEY-----"
,
"-----END CERTIFICATE-----"
,
};
static
const
char
*
const
aes_str
[
2
]
=
{
"DEK-Info: AES-128-CBC,"
,
"DEK-Info: AES-256-CBC,"
};
/**
* Take a base64 blob of data and decrypt it (using AES) into its
* proper ASN.1 form.
*/
static
int
ICACHE_FLASH_ATTR
pem_decrypt
(
const
char
*
where
,
const
char
*
end
,
const
char
*
password
,
SSLObjLoader
*
ssl_obj
)
{
int
ret
=
-
1
;
int
is_aes_256
=
0
;
char
*
start
=
NULL
;
uint8_t
iv
[
IV_SIZE
];
int
i
,
pem_size
;
MD5_CTX
md5_ctx
;
AES_CTX
aes_ctx
;
uint8_t
key
[
32
];
/* AES256 size */
if
(
password
==
NULL
||
os_strlen
(
password
)
==
0
)
{
#ifdef CONFIG_SSL_FULL_MODE
ssl_printf
(
"Error: Need a password for this PEM file
\n
"
);
//TTY_FLUSH();
#endif
goto
error
;
}
if
((
start
=
(
char
*
)
os_strstr
((
const
char
*
)
where
,
aes_str
[
0
])))
/* AES128? */
{
start
+=
os_strlen
(
aes_str
[
0
]);
}
else
if
((
start
=
(
char
*
)
os_strstr
((
const
char
*
)
where
,
aes_str
[
1
])))
/* AES256? */
{
is_aes_256
=
1
;
start
+=
os_strlen
(
aes_str
[
1
]);
}
else
{
#ifdef CONFIG_SSL_FULL_MODE
ssl_printf
(
"Error: Unsupported password cipher
\n
"
);
//TTY_FLUSH();
#endif
goto
error
;
}
/* convert from hex to binary - assumes uppercase hex */
for
(
i
=
0
;
i
<
IV_SIZE
;
i
++
)
{
char
c
=
*
start
++
-
'0'
;
iv
[
i
]
=
(
c
>
9
?
c
+
'0'
-
'A'
+
10
:
c
)
<<
4
;
c
=
*
start
++
-
'0'
;
iv
[
i
]
+=
(
c
>
9
?
c
+
'0'
-
'A'
+
10
:
c
);
}
while
(
*
start
==
'\r'
||
*
start
==
'\n'
)
start
++
;
/* turn base64 into binary */
pem_size
=
(
int
)(
end
-
start
);
if
(
base64_decode
(
start
,
pem_size
,
ssl_obj
->
buf
,
&
ssl_obj
->
len
)
!=
0
)
goto
error
;
/* work out the key */
MD5_Init
(
&
md5_ctx
);
MD5_Update
(
&
md5_ctx
,
(
const
uint8_t
*
)
password
,
os_strlen
(
password
));
MD5_Update
(
&
md5_ctx
,
iv
,
SALT_SIZE
);
MD5_Final
(
key
,
&
md5_ctx
);
if
(
is_aes_256
)
{
MD5_Init
(
&
md5_ctx
);
MD5_Update
(
&
md5_ctx
,
key
,
MD5_SIZE
);
MD5_Update
(
&
md5_ctx
,
(
const
uint8_t
*
)
password
,
os_strlen
(
password
));
MD5_Update
(
&
md5_ctx
,
iv
,
SALT_SIZE
);
MD5_Final
(
&
key
[
MD5_SIZE
],
&
md5_ctx
);
}
/* decrypt using the key/iv */
AES_set_key
(
&
aes_ctx
,
key
,
iv
,
is_aes_256
?
AES_MODE_256
:
AES_MODE_128
);
AES_convert_key
(
&
aes_ctx
);
AES_cbc_decrypt
(
&
aes_ctx
,
ssl_obj
->
buf
,
ssl_obj
->
buf
,
ssl_obj
->
len
);
ret
=
0
;
error:
return
ret
;
}
/**
* Take a base64 blob of data and turn it into its proper ASN.1 form.
*/
static
int
ICACHE_FLASH_ATTR
new_pem_obj
(
SSL_CTX
*
ssl_ctx
,
int
is_cacert
,
char
*
where
,
int
remain
,
const
char
*
password
)
{
int
ret
=
SSL_ERROR_BAD_CERTIFICATE
;
SSLObjLoader
*
ssl_obj
=
NULL
;
while
(
remain
>
0
)
{
int
i
,
pem_size
,
obj_type
;
char
*
start
=
NULL
,
*
end
=
NULL
;
for
(
i
=
0
;
i
<
NUM_PEM_TYPES
;
i
++
)
{
if
((
start
=
(
char
*
)
os_strstr
(
where
,
begins
[
i
]))
&&
(
end
=
(
char
*
)
os_strstr
(
where
,
ends
[
i
])))
{
remain
-=
(
int
)(
end
-
where
);
start
+=
os_strlen
(
begins
[
i
]);
pem_size
=
(
int
)(
end
-
start
);
ssl_obj
=
(
SSLObjLoader
*
)
os_zalloc
(
sizeof
(
SSLObjLoader
));
/* 4/3 bigger than what we need but so what */
ssl_obj
->
buf
=
(
uint8_t
*
)
os_zalloc
(
pem_size
);
ssl_obj
->
len
=
pem_size
;
if
(
i
==
IS_RSA_PRIVATE_KEY
&&
os_strstr
(
start
,
"Proc-Type:"
)
&&
os_strstr
(
start
,
"4,ENCRYPTED"
))
{
/* check for encrypted PEM file */
if
(
pem_decrypt
(
start
,
end
,
password
,
ssl_obj
)
<
0
)
{
ret
=
SSL_ERROR_BAD_CERTIFICATE
;
goto
error
;
}
}
else
{
ssl_obj
->
len
=
pem_size
;
if
(
base64_decode
(
start
,
pem_size
,
ssl_obj
->
buf
,
&
ssl_obj
->
len
)
!=
0
)
{
ret
=
SSL_ERROR_BAD_CERTIFICATE
;
goto
error
;
}
}
switch
(
i
)
{
case
IS_RSA_PRIVATE_KEY
:
obj_type
=
SSL_OBJ_RSA_KEY
;
break
;
case
IS_ENCRYPTED_PRIVATE_KEY
:
case
IS_PRIVATE_KEY
:
obj_type
=
SSL_OBJ_PKCS8
;
break
;
case
IS_CERTIFICATE
:
obj_type
=
is_cacert
?
SSL_OBJ_X509_CACERT
:
SSL_OBJ_X509_CERT
;
break
;
default:
ret
=
SSL_ERROR_BAD_CERTIFICATE
;
goto
error
;
}
/* In a format we can now understand - so process it */
if
((
ret
=
do_obj
(
ssl_ctx
,
obj_type
,
ssl_obj
,
password
)))
goto
error
;
end
+=
os_strlen
(
ends
[
i
]);
remain
-=
os_strlen
(
ends
[
i
]);
while
(
remain
>
0
&&
(
*
end
==
'\r'
||
*
end
==
'\n'
))
{
end
++
;
remain
--
;
}
where
=
end
;
break
;
}
}
ssl_obj_free
(
ssl_obj
);
ssl_obj
=
NULL
;
if
(
start
==
NULL
)
break
;
}
error:
ssl_obj_free
(
ssl_obj
);
return
ret
;
}
/*
* Load a file into memory that is in ASCII PEM format.
*/
static
int
ICACHE_FLASH_ATTR
ssl_obj_PEM_load
(
SSL_CTX
*
ssl_ctx
,
int
obj_type
,
SSLObjLoader
*
ssl_obj
,
const
char
*
password
)
{
char
*
start
;
/* add a null terminator */
ssl_obj
->
len
++
;
ssl_obj
->
buf
=
(
uint8_t
*
)
os_realloc
(
ssl_obj
->
buf
,
ssl_obj
->
len
);
ssl_obj
->
buf
[
ssl_obj
->
len
-
1
]
=
0
;
start
=
(
char
*
)
ssl_obj
->
buf
;
return
new_pem_obj
(
ssl_ctx
,
obj_type
==
SSL_OBJ_X509_CACERT
,
start
,
ssl_obj
->
len
,
password
);
}
#endif
/* CONFIG_SSL_HAS_PEM */
/**
* Load the key/certificates in memory depending on compile-time and user
* options.
*/
int
ICACHE_FLASH_ATTR
load_key_certs
(
SSL_CTX
*
ssl_ctx
)
{
int
ret
=
SSL_OK
;
uint32_t
options
=
ssl_ctx
->
options
;
#ifdef CONFIG_SSL_GENERATE_X509_CERT
uint8_t
*
cert_data
=
NULL
;
int
cert_size
;
static
const
char
*
dn
[]
=
{
CONFIG_SSL_X509_COMMON_NAME
,
CONFIG_SSL_X509_ORGANIZATION_NAME
,
CONFIG_SSL_X509_ORGANIZATION_UNIT_NAME
};
#endif
/* do the private key first */
if
(
os_strlen
(
CONFIG_SSL_PRIVATE_KEY_LOCATION
)
>
0
)
{
if
((
ret
=
ssl_obj_load
(
ssl_ctx
,
SSL_OBJ_RSA_KEY
,
CONFIG_SSL_PRIVATE_KEY_LOCATION
,
CONFIG_SSL_PRIVATE_KEY_PASSWORD
))
<
0
)
goto
error
;
}
else
if
(
!
(
options
&
SSL_NO_DEFAULT_KEY
))
{
#if defined(CONFIG_SSL_USE_DEFAULT_KEY) || defined(CONFIG_SSL_SKELETON_MODE)
// static const /* saves a few more bytes */
//#include "private_key.h"
extern
unsigned
int
default_private_key_len
;
extern
unsigned
char
default_private_key
[];
ssl_obj_memory_load
(
ssl_ctx
,
SSL_OBJ_RSA_KEY
,
default_private_key
,
default_private_key_len
,
NULL
);
#endif
}
/* now load the certificate */
#ifdef CONFIG_SSL_GENERATE_X509_CERT
if
((
cert_size
=
ssl_x509_create
(
ssl_ctx
,
0
,
dn
,
&
cert_data
))
<
0
)
{
ret
=
cert_size
;
goto
error
;
}
ssl_obj_memory_load
(
ssl_ctx
,
SSL_OBJ_X509_CERT
,
cert_data
,
cert_size
,
NULL
);
os_free
(
cert_data
);
#else
if
(
os_strlen
(
CONFIG_SSL_X509_CERT_LOCATION
))
{
if
((
ret
=
ssl_obj_load
(
ssl_ctx
,
SSL_OBJ_X509_CERT
,
CONFIG_SSL_X509_CERT_LOCATION
,
NULL
))
<
0
)
goto
error
;
}
else
if
(
!
(
options
&
SSL_NO_DEFAULT_KEY
))
{
#if defined(CONFIG_SSL_USE_DEFAULT_KEY) || defined(CONFIG_SSL_SKELETON_MODE)
// static const /* saves a few bytes and RAM */
//#include "cert.h"
extern
unsigned
char
default_certificate
[];
extern
unsigned
int
default_certificate_len
;
ssl_obj_memory_load
(
ssl_ctx
,
SSL_OBJ_X509_CERT
,
default_certificate
,
default_certificate_len
,
NULL
);
#endif
}
#endif
error:
#ifdef CONFIG_SSL_FULL_MODE
if
(
ret
)
{
ssl_printf
(
"Error: Certificate or key not loaded
\n
"
);
//TTY_FLUSH();
}
#endif
return
ret
;
}
app/ssl/ssl/ssl_openssl.c
deleted
100644 → 0
View file @
21c4e110
/*
* Copyright (c) 2007, Cameron Rich
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the axTLS project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Enable a subset of openssl compatible functions. We don't aim to be 100%
* compatible - just to be able to do basic ports etc.
*
* Only really tested on mini_httpd, so I'm not too sure how extensive this
* port is.
*/
#include "ssl/ssl_config.h"
#ifdef CONFIG_OPENSSL_COMPATIBLE
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "ssl/ssl_os_port.h"
#include "ssl/ssl_ssl.h"
#define OPENSSL_CTX_ATTR ((OPENSSL_CTX *)ssl_ctx->bonus_attr)
static
char
*
key_password
=
NULL
;
void
*
SSLv23_server_method
(
void
)
{
return
NULL
;
}
void
*
SSLv3_server_method
(
void
)
{
return
NULL
;
}
void
*
TLSv1_server_method
(
void
)
{
return
NULL
;
}
void
*
SSLv23_client_method
(
void
)
{
return
NULL
;
}
void
*
SSLv3_client_method
(
void
)
{
return
NULL
;
}
void
*
TLSv1_client_method
(
void
)
{
return
NULL
;
}
typedef
void
*
(
*
ssl_func_type_t
)(
void
);
typedef
void
*
(
*
bio_func_type_t
)(
void
);
typedef
struct
{
ssl_func_type_t
ssl_func_type
;
}
OPENSSL_CTX
;
SSL_CTX
*
ICACHE_FLASH_ATTR
SSL_CTX_new
(
ssl_func_type_t
meth
)
{
SSL_CTX
*
ssl_ctx
=
ssl_ctx_new
(
0
,
5
);
ssl_ctx
->
bonus_attr
=
os_malloc
(
sizeof
(
OPENSSL_CTX
));
OPENSSL_CTX_ATTR
->
ssl_func_type
=
meth
;
return
ssl_ctx
;
}
void
ICACHE_FLASH_ATTR
SSL_CTX_free
(
SSL_CTX
*
ssl_ctx
)
{
free
(
ssl_ctx
->
bonus_attr
);
ssl_ctx_free
(
ssl_ctx
);
}
SSL
*
ICACHE_FLASH_ATTR
SSL_new
(
SSL_CTX
*
ssl_ctx
)
{
SSL
*
ssl
;
ssl_func_type_t
ssl_func_type
;
ssl
=
ssl_new
(
ssl_ctx
,
-
1
);
/* fd is set later */
ssl_func_type
=
OPENSSL_CTX_ATTR
->
ssl_func_type
;
#ifdef CONFIG_SSL_ENABLE_CLIENT
if
(
ssl_func_type
==
SSLv23_client_method
||
ssl_func_type
==
SSLv3_client_method
||
ssl_func_type
==
TLSv1_client_method
)
{
SET_SSL_FLAG
(
SSL_IS_CLIENT
);
}
else
#endif
{
ssl
->
next_state
=
HS_CLIENT_HELLO
;
}
return
ssl
;
}
int
ICACHE_FLASH_ATTR
SSL_set_fd
(
SSL
*
s
,
int
fd
)
{
s
->
client_fd
=
fd
;
return
1
;
/* always succeeds */
}
int
ICACHE_FLASH_ATTR
SSL_accept
(
SSL
*
ssl
)
{
while
(
ssl_read
(
ssl
,
NULL
)
==
SSL_OK
)
{
if
(
ssl
->
next_state
==
HS_CLIENT_HELLO
)
return
1
;
/* we're done */
}
return
-
1
;
}
#ifdef CONFIG_SSL_ENABLE_CLIENT
int
ICACHE_FLASH_ATTR
SSL_connect
(
SSL
*
ssl
)
{
return
do_client_connect
(
ssl
)
==
SSL_OK
?
1
:
-
1
;
}
#endif
void
ICACHE_FLASH_ATTR
SSL_free
(
SSL
*
ssl
)
{
ssl_free
(
ssl
);
}
int
ICACHE_FLASH_ATTR
SSL_read
(
SSL
*
ssl
,
void
*
buf
,
int
num
)
{
uint8_t
*
read_buf
;
int
ret
;
while
((
ret
=
ssl_read
(
ssl
,
&
read_buf
))
==
SSL_OK
);
if
(
ret
>
SSL_OK
)
{
os_memcpy
(
buf
,
read_buf
,
ret
>
num
?
num
:
ret
);
}
return
ret
;
}
int
ICACHE_FLASH_ATTR
SSL_write
(
SSL
*
ssl
,
const
void
*
buf
,
int
num
)
{
return
ssl_write
(
ssl
,
buf
,
num
);
}
int
ICACHE_FLASH_ATTR
SSL_CTX_use_certificate_file
(
SSL_CTX
*
ssl_ctx
,
const
char
*
file
,
int
type
)
{
return
(
ssl_obj_load
(
ssl_ctx
,
SSL_OBJ_X509_CERT
,
file
,
NULL
)
==
SSL_OK
);
}
int
ICACHE_FLASH_ATTR
SSL_CTX_use_PrivateKey_file
(
SSL_CTX
*
ssl_ctx
,
const
char
*
file
,
int
type
)
{
return
(
ssl_obj_load
(
ssl_ctx
,
SSL_OBJ_RSA_KEY
,
file
,
key_password
)
==
SSL_OK
);
}
int
ICACHE_FLASH_ATTR
SSL_CTX_use_certificate_ASN1
(
SSL_CTX
*
ssl_ctx
,
int
len
,
const
uint8_t
*
d
)
{
return
(
ssl_obj_memory_load
(
ssl_ctx
,
SSL_OBJ_X509_CERT
,
d
,
len
,
NULL
)
==
SSL_OK
);
}
int
ICACHE_FLASH_ATTR
SSL_CTX_set_session_id_context
(
SSL_CTX
*
ctx
,
const
unsigned
char
*
sid_ctx
,
unsigned
int
sid_ctx_len
)
{
return
1
;
}
int
ICACHE_FLASH_ATTR
SSL_CTX_set_default_verify_paths
(
SSL_CTX
*
ctx
)
{
return
1
;
}
int
ICACHE_FLASH_ATTR
SSL_CTX_use_certificate_chain_file
(
SSL_CTX
*
ssl_ctx
,
const
char
*
file
)
{
return
(
ssl_obj_load
(
ssl_ctx
,
SSL_OBJ_X509_CERT
,
file
,
NULL
)
==
SSL_OK
);
}
int
ICACHE_FLASH_ATTR
SSL_shutdown
(
SSL
*
ssl
)
{
return
1
;
}
/*** get/set session ***/
SSL_SESSION
*
ICACHE_FLASH_ATTR
SSL_get1_session
(
SSL
*
ssl
)
{
return
(
SSL_SESSION
*
)
ssl_get_session_id
(
ssl
);
/* note: wrong cast */
}
int
ICACHE_FLASH_ATTR
SSL_set_session
(
SSL
*
ssl
,
SSL_SESSION
*
session
)
{
os_memcpy
(
ssl
->
session_id
,
(
uint8_t
*
)
session
,
SSL_SESSION_ID_SIZE
);
return
1
;
}
void
ICACHE_FLASH_ATTR
SSL_SESSION_free
(
SSL_SESSION
*
session
)
{
}
/*** end get/set session ***/
long
ICACHE_FLASH_ATTR
SSL_CTX_ctrl
(
SSL_CTX
*
ctx
,
int
cmd
,
long
larg
,
void
*
parg
)
{
return
0
;
}
void
ICACHE_FLASH_ATTR
SSL_CTX_set_verify
(
SSL_CTX
*
ctx
,
int
mode
,
int
(
*
verify_callback
)(
int
,
void
*
))
{
}
void
ICACHE_FLASH_ATTR
SSL_CTX_set_verify_depth
(
SSL_CTX
*
ctx
,
int
depth
)
{
}
int
ICACHE_FLASH_ATTR
SSL_CTX_load_verify_locations
(
SSL_CTX
*
ctx
,
const
char
*
CAfile
,
const
char
*
CApath
)
{
return
1
;
}
void
*
ICACHE_FLASH_ATTR
SSL_load_client_CA_file
(
const
char
*
file
)
{
return
(
void
*
)
file
;
}
void
ICACHE_FLASH_ATTR
SSL_CTX_set_client_CA_list
(
SSL_CTX
*
ssl_ctx
,
void
*
file
)
{
ssl_obj_load
(
ssl_ctx
,
SSL_OBJ_X509_CERT
,
(
const
char
*
)
file
,
NULL
);
}
void
ICACHE_FLASH_ATTR
SSLv23_method
(
void
)
{
}
void
ICACHE_FLASH_ATTR
SSL_CTX_set_default_passwd_cb
(
SSL_CTX
*
ctx
,
void
*
cb
)
{
}
void
ICACHE_FLASH_ATTR
SSL_CTX_set_default_passwd_cb_userdata
(
SSL_CTX
*
ctx
,
void
*
u
)
{
key_password
=
(
char
*
)
u
;
}
int
ICACHE_FLASH_ATTR
SSL_peek
(
SSL
*
ssl
,
void
*
buf
,
int
num
)
{
os_memcpy
(
buf
,
ssl
->
bm_data
,
num
);
return
num
;
}
void
ICACHE_FLASH_ATTR
SSL_set_bio
(
SSL
*
ssl
,
void
*
rbio
,
void
*
wbio
)
{
}
long
ICACHE_FLASH_ATTR
SSL_get_verify_result
(
const
SSL
*
ssl
)
{
return
ssl_handshake_status
(
ssl
);
}
int
ICACHE_FLASH_ATTR
SSL_state
(
SSL
*
ssl
)
{
return
0x03
;
// ok state
}
/** end of could do better list */
void
*
ICACHE_FLASH_ATTR
SSL_get_peer_certificate
(
const
SSL
*
ssl
)
{
return
&
ssl
->
ssl_ctx
->
certs
[
0
];
}
int
ICACHE_FLASH_ATTR
SSL_clear
(
SSL
*
ssl
)
{
return
1
;
}
int
ICACHE_FLASH_ATTR
SSL_CTX_check_private_key
(
const
SSL_CTX
*
ctx
)
{
return
1
;
}
int
ICACHE_FLASH_ATTR
SSL_CTX_set_cipher_list
(
SSL
*
s
,
const
char
*
str
)
{
return
1
;
}
int
ICACHE_FLASH_ATTR
SSL_get_error
(
const
SSL
*
ssl
,
int
ret
)
{
ssl_display_error
(
ret
);
return
0
;
/* TODO: return proper return code */
}
void
ICACHE_FLASH_ATTR
SSL_CTX_set_options
(
SSL_CTX
*
ssl_ctx
,
int
option
)
{}
int
ICACHE_FLASH_ATTR
SSL_library_init
(
void
)
{
return
1
;
}
void
ICACHE_FLASH_ATTR
SSL_load_error_strings
(
void
)
{}
void
ICACHE_FLASH_ATTR
ERR_print_errors_fp
(
FILE
*
fp
)
{}
#ifndef CONFIG_SSL_SKELETON_MODE
long
ICACHE_FLASH_ATTR
SSL_CTX_get_timeout
(
const
SSL_CTX
*
ssl_ctx
)
{
return
CONFIG_SSL_EXPIRY_TIME
*
3600
;
}
long
ICACHE_FLASH_ATTR
SSL_CTX_set_timeout
(
SSL_CTX
*
ssl_ctx
,
long
t
)
{
return
SSL_CTX_get_timeout
(
ssl_ctx
);
}
#endif
void
ICACHE_FLASH_ATTR
BIO_printf
(
FILE
*
f
,
const
char
*
format
,
...)
{
va_list
(
ap
);
va_start
(
ap
,
format
);
vfprintf
(
f
,
format
,
ap
);
va_end
(
ap
);
}
void
*
ICACHE_FLASH_ATTR
BIO_s_null
(
void
)
{
return
NULL
;
}
FILE
*
ICACHE_FLASH_ATTR
BIO_new
(
bio_func_type_t
func
)
{
if
(
func
==
BIO_s_null
)
return
fopen
(
"/dev/null"
,
"r"
);
else
return
NULL
;
}
FILE
*
ICACHE_FLASH_ATTR
BIO_new_fp
(
FILE
*
stream
,
int
close_flag
)
{
return
stream
;
}
int
ICACHE_FLASH_ATTR
BIO_free
(
FILE
*
a
)
{
if
(
a
!=
stdout
&&
a
!=
stderr
)
fclose
(
a
);
return
1
;
}
#endif
app/ssl/ssl/ssl_os_port.c
deleted
100644 → 0
View file @
21c4e110
/*
* Copyright (c) 2007, Cameron Rich
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the axTLS project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file os_port.c
*
* OS specific functions.
*/
//#include <time.h>
//#include <stdlib.h>
//#include <errno.h>
//#include <stdarg.h>
#include "ssl/ssl_os_port.h"
#ifdef WIN32
/**
* gettimeofday() not in Win32
*/
EXP_FUNC
void
STDCALL
gettimeofday
(
struct
timeval
*
t
,
void
*
timezone
)
{
#if defined(_WIN32_WCE)
t
->
tv_sec
=
time
(
NULL
);
t
->
tv_usec
=
0
;
/* 1sec precision only */
#else
struct
_timeb
timebuffer
;
_ftime
(
&
timebuffer
);
t
->
tv_sec
=
(
long
)
timebuffer
.
time
;
t
->
tv_usec
=
1000
*
timebuffer
.
millitm
;
/* 1ms precision */
#endif
}
/**
* strcasecmp() not in Win32
*/
EXP_FUNC
int
STDCALL
strcasecmp
(
const
char
*
s1
,
const
char
*
s2
)
{
while
(
tolower
(
*
s1
)
==
tolower
(
*
s2
++
))
{
if
(
*
s1
++
==
'\0'
)
{
return
0
;
}
}
return
*
(
unsigned
char
*
)
s1
-
*
(
unsigned
char
*
)(
s2
-
1
);
}
EXP_FUNC
int
STDCALL
getdomainname
(
char
*
buf
,
int
buf_size
)
{
HKEY
hKey
;
unsigned
long
datatype
;
unsigned
long
bufferlength
=
buf_size
;
if
(
RegOpenKeyEx
(
HKEY_LOCAL_MACHINE
,
TEXT
(
"SYSTEM
\\
CurrentControlSet
\\
Services
\\
Tcpip
\\
Parameters"
),
0
,
KEY_QUERY_VALUE
,
&
hKey
)
!=
ERROR_SUCCESS
)
return
-
1
;
RegQueryValueEx
(
hKey
,
"Domain"
,
NULL
,
&
datatype
,
buf
,
&
bufferlength
);
RegCloseKey
(
hKey
);
return
0
;
}
#endif
#if 0
#undef malloc
#undef realloc
#undef calloc
static const char * out_of_mem_str = "out of memory";
static const char * file_open_str = "Could not open file \"%s\"";
/*
* Some functions that call display some error trace and then call abort().
* This just makes life much easier on embedded systems, since we're
* suffering major trauma...
*/
EXP_FUNC void * STDCALL ax_malloc(size_t s)
{
void *x;
if ((x = malloc(s)) == NULL)
exit_now(out_of_mem_str);
return x;
}
EXP_FUNC void * STDCALL ax_realloc(void *y, size_t s)
{
void *x;
if ((x = realloc(y, s)) == NULL)
exit_now(out_of_mem_str);
return x;
}
EXP_FUNC void * STDCALL ax_calloc(size_t n, size_t s)
{
void *x;
if ((x = calloc(n, s)) == NULL)
exit_now(out_of_mem_str);
return x;
}
EXP_FUNC int STDCALL ax_open(const char *pathname, int flags)
{
int x;
if ((x = open(pathname, flags)) < 0)
exit_now(file_open_str, pathname);
return x;
}
/**
* This is a call which will deliberately exit an application, but will
* display some information before dying.
*/
void exit_now(const char *format, ...)
{
va_list argp;
va_start(argp, format);
vfprintf(stderr, format, argp);
va_end(argp);
abort();
}
/**
* gettimeofday() not in Win32
*/
EXP_FUNC void STDCALL gettimeofday(struct timeval* t, void* timezone)
{
#if defined(_WIN32_WCE)
t->tv_sec = time(NULL);
t->tv_usec = 0; /* 1sec precision only */
#else
/* wujg : pass compile first */
t->tv_sec = 0;
t->tv_usec = 0; /* 1ms precision */
#endif
}
#endif
app/ssl/ssl/ssl_p12.c
deleted
100644 → 0
View file @
21c4e110
/*
* Copyright (c) 2007, Cameron Rich
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the axTLS project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* Process PKCS#8/PKCS#12 keys.
*
* The decoding of a PKCS#12 key is fairly specific - this code was tested on a
* key generated with:
*
* openssl pkcs12 -export -in axTLS.x509_1024.pem -inkey axTLS.key_1024.pem
* -keypbe PBE-SHA1-RC4-128 -certpbe PBE-SHA1-RC4-128
* -name "p12_withoutCA" -out axTLS.withoutCA.p12 -password pass:abcd
*
* or with a certificate chain:
*
* openssl pkcs12 -export -in axTLS.x509_1024.pem -inkey axTLS.key_1024.pem
* -certfile axTLS.ca_x509.pem -keypbe PBE-SHA1-RC4-128 -certpbe
* PBE-SHA1-RC4-128 -name "p12_withCA" -out axTLS.withCA.p12 -password pass:abcd
*
* Note that the PBE has to be specified with PBE-SHA1-RC4-128. The
* private/public keys/certs have to use RSA encryption. Both the integrity
* and privacy passwords are the same.
*
* The PKCS#8 files were generated with something like:
*
* PEM format:
* openssl pkcs8 -in axTLS.key_512.pem -passout pass:abcd -topk8 -v1
* PBE-SHA1-RC4-128 -out axTLS.encrypted_pem.p8
*
* DER format:
* openssl pkcs8 -in axTLS.key_512.pem -passout pass:abcd -topk8 -outform DER
* -v1 PBE-SHA1-RC4-128 -out axTLS.encrypted.p8
*/
//#include <stdlib.h>
//#include <string.h>
//#include <stdio.h>
#include "ssl/ssl_os_port.h"
#include "ssl/ssl_ssl.h"
/* all commented out if not used */
#ifdef CONFIG_SSL_USE_PKCS12
#define BLOCK_SIZE 64
#define PKCS12_KEY_ID 1
#define PKCS12_IV_ID 2
#define PKCS12_MAC_ID 3
static
char
*
make_uni_pass
(
const
char
*
password
,
int
*
uni_pass_len
);
static
int
p8_decrypt
(
const
char
*
uni_pass
,
int
uni_pass_len
,
const
uint8_t
*
salt
,
int
iter
,
uint8_t
*
priv_key
,
int
priv_key_len
,
int
id
);
static
int
p8_add_key
(
SSL_CTX
*
ssl_ctx
,
uint8_t
*
priv_key
);
static
int
get_pbe_params
(
uint8_t
*
buf
,
int
*
offset
,
const
uint8_t
**
salt
,
int
*
iterations
);
/*
* Take a raw pkcs8 block and then decrypt it and turn it into a normal key.
*/
int
ICACHE_FLASH_ATTR
pkcs8_decode
(
SSL_CTX
*
ssl_ctx
,
SSLObjLoader
*
ssl_obj
,
const
char
*
password
)
{
uint8_t
*
buf
=
ssl_obj
->
buf
;
int
len
,
offset
=
0
;
int
iterations
;
int
ret
=
SSL_NOT_OK
;
uint8_t
*
version
=
NULL
;
const
uint8_t
*
salt
;
uint8_t
*
priv_key
;
int
uni_pass_len
;
char
*
uni_pass
=
make_uni_pass
(
password
,
&
uni_pass_len
);
if
(
asn1_next_obj
(
buf
,
&
offset
,
ASN1_SEQUENCE
)
<
0
)
{
#ifdef CONFIG_SSL_FULL_MODE
ssl_printf
(
"Error: Invalid p8 ASN.1 file
\n
"
);
#endif
goto
error
;
}
/* unencrypted key? */
if
(
asn1_get_int
(
buf
,
&
offset
,
&
version
)
>
0
&&
*
version
==
0
)
{
ret
=
p8_add_key
(
ssl_ctx
,
buf
);
goto
error
;
}
if
(
get_pbe_params
(
buf
,
&
offset
,
&
salt
,
&
iterations
)
<
0
)
goto
error
;
if
((
len
=
asn1_next_obj
(
buf
,
&
offset
,
ASN1_OCTET_STRING
))
<
0
)
goto
error
;
priv_key
=
&
buf
[
offset
];
p8_decrypt
(
uni_pass
,
uni_pass_len
,
salt
,
iterations
,
priv_key
,
len
,
PKCS12_KEY_ID
);
ret
=
p8_add_key
(
ssl_ctx
,
priv_key
);
error:
os_free
(
version
);
os_free
(
uni_pass
);
return
ret
;
}
/*
* Take the unencrypted pkcs8 and turn it into a private key
*/
static
int
ICACHE_FLASH_ATTR
p8_add_key
(
SSL_CTX
*
ssl_ctx
,
uint8_t
*
priv_key
)
{
uint8_t
*
buf
=
priv_key
;
int
len
,
offset
=
0
;
int
ret
=
SSL_NOT_OK
;
/* Skip the preamble and go straight to the private key.
We only support rsaEncryption (1.2.840.113549.1.1.1) */
if
(
asn1_next_obj
(
buf
,
&
offset
,
ASN1_SEQUENCE
)
<
0
||
asn1_skip_obj
(
buf
,
&
offset
,
ASN1_INTEGER
)
<
0
||
asn1_skip_obj
(
buf
,
&
offset
,
ASN1_SEQUENCE
)
<
0
||
(
len
=
asn1_next_obj
(
buf
,
&
offset
,
ASN1_OCTET_STRING
))
<
0
)
goto
error
;
ret
=
asn1_get_private_key
(
&
buf
[
offset
],
len
,
&
ssl_ctx
->
rsa_ctx
);
error:
return
ret
;
}
/*
* Create the unicode password
*/
static
char
*
ICACHE_FLASH_ATTR
make_uni_pass
(
const
char
*
password
,
int
*
uni_pass_len
)
{
int
pass_len
=
0
,
i
;
char
*
uni_pass
;
if
(
password
==
NULL
)
{
password
=
""
;
}
uni_pass
=
(
char
*
)
os_malloc
((
os_strlen
(
password
)
+
1
)
*
2
);
/* modify the password into a unicode version */
for
(
i
=
0
;
i
<
(
int
)
os_strlen
(
password
);
i
++
)
{
uni_pass
[
pass_len
++
]
=
0
;
uni_pass
[
pass_len
++
]
=
password
[
i
];
}
uni_pass
[
pass_len
++
]
=
0
;
/* null terminate */
uni_pass
[
pass_len
++
]
=
0
;
*
uni_pass_len
=
pass_len
;
return
uni_pass
;
}
/*
* Decrypt a pkcs8 block.
*/
static
int
ICACHE_FLASH_ATTR
p8_decrypt
(
const
char
*
uni_pass
,
int
uni_pass_len
,
const
uint8_t
*
salt
,
int
iter
,
uint8_t
*
priv_key
,
int
priv_key_len
,
int
id
)
{
uint8_t
p
[
BLOCK_SIZE
*
2
];
uint8_t
d
[
BLOCK_SIZE
];
uint8_t
Ai
[
SHA1_SIZE
];
SHA1_CTX
sha_ctx
;
RC4_CTX
rc4_ctx
;
int
i
;
for
(
i
=
0
;
i
<
BLOCK_SIZE
;
i
++
)
{
p
[
i
]
=
salt
[
i
%
SALT_SIZE
];
p
[
BLOCK_SIZE
+
i
]
=
uni_pass
[
i
%
uni_pass_len
];
d
[
i
]
=
id
;
}
/* get the key - no IV since we are using RC4 */
SHA1_Init
(
&
sha_ctx
);
SHA1_Update
(
&
sha_ctx
,
d
,
sizeof
(
d
));
SHA1_Update
(
&
sha_ctx
,
p
,
sizeof
(
p
));
SHA1_Final
(
Ai
,
&
sha_ctx
);
for
(
i
=
1
;
i
<
iter
;
i
++
)
{
SHA1_Init
(
&
sha_ctx
);
SHA1_Update
(
&
sha_ctx
,
Ai
,
SHA1_SIZE
);
SHA1_Final
(
Ai
,
&
sha_ctx
);
}
/* do the decryption */
if
(
id
==
PKCS12_KEY_ID
)
{
RC4_setup
(
&
rc4_ctx
,
Ai
,
16
);
RC4_crypt
(
&
rc4_ctx
,
priv_key
,
priv_key
,
priv_key_len
);
}
else
/* MAC */
os_memcpy
(
priv_key
,
Ai
,
SHA1_SIZE
);
return
0
;
}
/*
* Take a raw pkcs12 block and the decrypt it and turn it into a certificate(s)
* and keys.
*/
int
ICACHE_FLASH_ATTR
pkcs12_decode
(
SSL_CTX
*
ssl_ctx
,
SSLObjLoader
*
ssl_obj
,
const
char
*
password
)
{
uint8_t
*
buf
=
ssl_obj
->
buf
;
int
len
,
iterations
,
auth_safes_start
,
auth_safes_end
,
auth_safes_len
,
key_offset
,
offset
=
0
;
int
all_certs
=
0
;
uint8_t
*
version
=
NULL
,
*
auth_safes
=
NULL
,
*
cert
,
*
orig_mac
;
uint8_t
key
[
SHA1_SIZE
];
uint8_t
mac
[
SHA1_SIZE
];
const
uint8_t
*
salt
;
int
uni_pass_len
,
ret
=
SSL_OK
;
char
*
uni_pass
=
make_uni_pass
(
password
,
&
uni_pass_len
);
static
const
uint8_t
pkcs_data
[]
=
/* pkc7 data */
{
0x2a
,
0x86
,
0x48
,
0x86
,
0xf7
,
0x0d
,
0x01
,
0x07
,
0x01
};
static
const
uint8_t
pkcs_encrypted
[]
=
/* pkc7 encrypted */
{
0x2a
,
0x86
,
0x48
,
0x86
,
0xf7
,
0x0d
,
0x01
,
0x07
,
0x06
};
static
const
uint8_t
pkcs8_key_bag
[]
=
/* 1.2.840.113549.1.12.10.1.2 */
{
0x2a
,
0x86
,
0x48
,
0x86
,
0xf7
,
0x0d
,
0x01
,
0x0c
,
0x0a
,
0x01
,
0x02
};
if
(
asn1_next_obj
(
buf
,
&
offset
,
ASN1_SEQUENCE
)
<
0
)
{
#ifdef CONFIG_SSL_FULL_MODE
ssl_printf
(
"Error: Invalid p12 ASN.1 file
\n
"
);
#endif
goto
error
;
}
if
(
asn1_get_int
(
buf
,
&
offset
,
&
version
)
<
0
||
*
version
!=
3
)
{
ret
=
SSL_ERROR_INVALID_VERSION
;
goto
error
;
}
/* remove all the boring pcks7 bits */
if
(
asn1_next_obj
(
buf
,
&
offset
,
ASN1_SEQUENCE
)
<
0
||
(
len
=
asn1_next_obj
(
buf
,
&
offset
,
ASN1_OID
))
<
0
||
len
!=
sizeof
(
pkcs_data
)
||
os_memcmp
(
&
buf
[
offset
],
pkcs_data
,
sizeof
(
pkcs_data
)))
goto
error
;
offset
+=
len
;
if
(
asn1_next_obj
(
buf
,
&
offset
,
ASN1_EXPLICIT_TAG
)
<
0
||
asn1_next_obj
(
buf
,
&
offset
,
ASN1_OCTET_STRING
)
<
0
)
goto
error
;
/* work out the MAC start/end points (done on AuthSafes) */
auth_safes_start
=
offset
;
auth_safes_end
=
offset
;
if
(
asn1_skip_obj
(
buf
,
&
auth_safes_end
,
ASN1_SEQUENCE
)
<
0
)
goto
error
;
auth_safes_len
=
auth_safes_end
-
auth_safes_start
;
auth_safes
=
os_malloc
(
auth_safes_len
);
os_memcpy
(
auth_safes
,
&
buf
[
auth_safes_start
],
auth_safes_len
);
if
(
asn1_next_obj
(
buf
,
&
offset
,
ASN1_SEQUENCE
)
<
0
||
asn1_next_obj
(
buf
,
&
offset
,
ASN1_SEQUENCE
)
<
0
||
(
len
=
asn1_next_obj
(
buf
,
&
offset
,
ASN1_OID
))
<
0
||
(
len
!=
sizeof
(
pkcs_encrypted
)
||
os_memcmp
(
&
buf
[
offset
],
pkcs_encrypted
,
sizeof
(
pkcs_encrypted
))))
goto
error
;
offset
+=
len
;
if
(
asn1_next_obj
(
buf
,
&
offset
,
ASN1_EXPLICIT_TAG
)
<
0
||
asn1_next_obj
(
buf
,
&
offset
,
ASN1_SEQUENCE
)
<
0
||
asn1_skip_obj
(
buf
,
&
offset
,
ASN1_INTEGER
)
<
0
||
asn1_next_obj
(
buf
,
&
offset
,
ASN1_SEQUENCE
)
<
0
||
(
len
=
asn1_next_obj
(
buf
,
&
offset
,
ASN1_OID
))
<
0
||
len
!=
sizeof
(
pkcs_data
)
||
os_memcmp
(
&
buf
[
offset
],
pkcs_data
,
sizeof
(
pkcs_data
)))
goto
error
;
offset
+=
len
;
/* work out the salt for the certificate */
if
(
get_pbe_params
(
buf
,
&
offset
,
&
salt
,
&
iterations
)
<
0
||
(
len
=
asn1_next_obj
(
buf
,
&
offset
,
ASN1_IMPLICIT_TAG
))
<
0
)
goto
error
;
/* decrypt the certificate */
cert
=
&
buf
[
offset
];
if
((
ret
=
p8_decrypt
(
uni_pass
,
uni_pass_len
,
salt
,
iterations
,
cert
,
len
,
PKCS12_KEY_ID
))
<
0
)
goto
error
;
offset
+=
len
;
/* load the certificate */
key_offset
=
0
;
all_certs
=
asn1_next_obj
(
cert
,
&
key_offset
,
ASN1_SEQUENCE
);
/* keep going until all certs are loaded */
while
(
key_offset
<
all_certs
)
{
int
cert_offset
=
key_offset
;
if
(
asn1_skip_obj
(
cert
,
&
cert_offset
,
ASN1_SEQUENCE
)
<
0
||
asn1_next_obj
(
cert
,
&
key_offset
,
ASN1_SEQUENCE
)
<
0
||
asn1_skip_obj
(
cert
,
&
key_offset
,
ASN1_OID
)
<
0
||
asn1_next_obj
(
cert
,
&
key_offset
,
ASN1_EXPLICIT_TAG
)
<
0
||
asn1_next_obj
(
cert
,
&
key_offset
,
ASN1_SEQUENCE
)
<
0
||
asn1_skip_obj
(
cert
,
&
key_offset
,
ASN1_OID
)
<
0
||
asn1_next_obj
(
cert
,
&
key_offset
,
ASN1_EXPLICIT_TAG
)
<
0
||
(
len
=
asn1_next_obj
(
cert
,
&
key_offset
,
ASN1_OCTET_STRING
))
<
0
)
goto
error
;
if
((
ret
=
add_cert
(
ssl_ctx
,
&
cert
[
key_offset
],
len
))
<
0
)
goto
error
;
key_offset
=
cert_offset
;
}
if
(
asn1_next_obj
(
buf
,
&
offset
,
ASN1_SEQUENCE
)
<
0
||
(
len
=
asn1_next_obj
(
buf
,
&
offset
,
ASN1_OID
))
<
0
||
len
!=
sizeof
(
pkcs_data
)
||
os_memcmp
(
&
buf
[
offset
],
pkcs_data
,
sizeof
(
pkcs_data
)))
goto
error
;
offset
+=
len
;
if
(
asn1_next_obj
(
buf
,
&
offset
,
ASN1_EXPLICIT_TAG
)
<
0
||
asn1_next_obj
(
buf
,
&
offset
,
ASN1_OCTET_STRING
)
<
0
||
asn1_next_obj
(
buf
,
&
offset
,
ASN1_SEQUENCE
)
<
0
||
asn1_next_obj
(
buf
,
&
offset
,
ASN1_SEQUENCE
)
<
0
||
(
len
=
asn1_next_obj
(
buf
,
&
offset
,
ASN1_OID
))
<
0
||
(
len
!=
sizeof
(
pkcs8_key_bag
))
||
os_memcmp
(
&
buf
[
offset
],
pkcs8_key_bag
,
sizeof
(
pkcs8_key_bag
)))
goto
error
;
offset
+=
len
;
/* work out the salt for the private key */
if
(
asn1_next_obj
(
buf
,
&
offset
,
ASN1_EXPLICIT_TAG
)
<
0
||
asn1_next_obj
(
buf
,
&
offset
,
ASN1_SEQUENCE
)
<
0
||
get_pbe_params
(
buf
,
&
offset
,
&
salt
,
&
iterations
)
<
0
||
(
len
=
asn1_next_obj
(
buf
,
&
offset
,
ASN1_OCTET_STRING
))
<
0
)
goto
error
;
/* decrypt the private key */
cert
=
&
buf
[
offset
];
if
((
ret
=
p8_decrypt
(
uni_pass
,
uni_pass_len
,
salt
,
iterations
,
cert
,
len
,
PKCS12_KEY_ID
))
<
0
)
goto
error
;
offset
+=
len
;
/* load the private key */
if
((
ret
=
p8_add_key
(
ssl_ctx
,
cert
))
<
0
)
goto
error
;
/* miss out on friendly name, local key id etc */
if
(
asn1_skip_obj
(
buf
,
&
offset
,
ASN1_SET
)
<
0
)
goto
error
;
/* work out the MAC */
if
(
asn1_next_obj
(
buf
,
&
offset
,
ASN1_SEQUENCE
)
<
0
||
asn1_next_obj
(
buf
,
&
offset
,
ASN1_SEQUENCE
)
<
0
||
asn1_skip_obj
(
buf
,
&
offset
,
ASN1_SEQUENCE
)
<
0
||
(
len
=
asn1_next_obj
(
buf
,
&
offset
,
ASN1_OCTET_STRING
))
<
0
||
len
!=
SHA1_SIZE
)
goto
error
;
orig_mac
=
&
buf
[
offset
];
offset
+=
len
;
/* get the salt */
if
((
len
=
asn1_next_obj
(
buf
,
&
offset
,
ASN1_OCTET_STRING
))
<
0
||
len
!=
8
)
goto
error
;
salt
=
&
buf
[
offset
];
/* work out what the mac should be */
if
((
ret
=
p8_decrypt
(
uni_pass
,
uni_pass_len
,
salt
,
iterations
,
key
,
SHA1_SIZE
,
PKCS12_MAC_ID
))
<
0
)
goto
error
;
ssl_hmac_sha1
(
auth_safes
,
auth_safes_len
,
key
,
SHA1_SIZE
,
mac
);
if
(
os_memcmp
(
mac
,
orig_mac
,
SHA1_SIZE
))
{
ret
=
SSL_ERROR_INVALID_HMAC
;
goto
error
;
}
error:
os_free
(
version
);
os_free
(
uni_pass
);
os_free
(
auth_safes
);
return
ret
;
}
/*
* Retrieve the salt/iteration details from a PBE block.
*/
static
int
ICACHE_FLASH_ATTR
get_pbe_params
(
uint8_t
*
buf
,
int
*
offset
,
const
uint8_t
**
salt
,
int
*
iterations
)
{
static
const
uint8_t
pbeSH1RC4
[]
=
/* pbeWithSHAAnd128BitRC4 */
{
0x2a
,
0x86
,
0x48
,
0x86
,
0xf7
,
0x0d
,
0x01
,
0x0c
,
0x01
,
0x01
};
int
i
,
len
;
uint8_t
*
iter
=
NULL
;
int
error_code
=
SSL_ERROR_NOT_SUPPORTED
;
/* Get the PBE type */
if
(
asn1_next_obj
(
buf
,
offset
,
ASN1_SEQUENCE
)
<
0
||
(
len
=
asn1_next_obj
(
buf
,
offset
,
ASN1_OID
))
<
0
)
goto
error
;
/* we expect pbeWithSHAAnd128BitRC4 (1.2.840.113549.1.12.1.1)
which is the only algorithm we support */
if
(
len
!=
sizeof
(
pbeSH1RC4
)
||
os_memcmp
(
&
buf
[
*
offset
],
pbeSH1RC4
,
sizeof
(
pbeSH1RC4
)))
{
#ifdef CONFIG_SSL_FULL_MODE
ssl_printf
(
"Error: pkcs8/pkcs12 must use
\"
PBE-SHA1-RC4-128
\"\n
"
);
#endif
goto
error
;
}
*
offset
+=
len
;
if
(
asn1_next_obj
(
buf
,
offset
,
ASN1_SEQUENCE
)
<
0
||
(
len
=
asn1_next_obj
(
buf
,
offset
,
ASN1_OCTET_STRING
))
<
0
||
len
!=
8
)
goto
error
;
*
salt
=
&
buf
[
*
offset
];
*
offset
+=
len
;
if
((
len
=
asn1_get_int
(
buf
,
offset
,
&
iter
))
<
0
)
goto
error
;
*
iterations
=
0
;
for
(
i
=
0
;
i
<
len
;
i
++
)
{
(
*
iterations
)
<<=
8
;
(
*
iterations
)
+=
iter
[
i
];
}
os_free
(
iter
);
error_code
=
SSL_OK
;
/* got here - we are ok */
error:
return
error_code
;
}
#endif
app/ssl/ssl/ssl_tls1.c
deleted
100644 → 0
View file @
21c4e110
/*
* Copyright (c) 2007, Cameron Rich
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the axTLS project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* Common ssl/tlsv1 code to both the client and server implementations.
*/
//#include <string.h>
//#include <stdlib.h>
//#include <stdio.h>
//#include <stdarg.h>
#include "ssl/ssl_os_port.h"
#include "ssl/ssl_ssl.h"
#include "lwip/tcp.h"
#include "ssl/app/espconn_ssl.h"
extern
struct
pbuf
*
psslpbuf
;
/* The session expiry time */
#define SSL_EXPIRY_TIME (CONFIG_SSL_EXPIRY_TIME*3600)
static
const
uint8_t
g_hello_request
[]
=
{
HS_HELLO_REQUEST
,
0
,
0
,
0
};
static
const
uint8_t
g_chg_cipher_spec_pkt
[]
=
{
1
};
static
const
char
*
server_finished
=
"server finished"
;
static
const
char
*
client_finished
=
"client finished"
;
static
int
do_handshake
(
SSL
*
ssl
,
uint8_t
*
buf
,
int
read_len
);
static
int
set_key_block
(
SSL
*
ssl
,
int
is_write
);
static
int
verify_digest
(
SSL
*
ssl
,
int
mode
,
const
uint8_t
*
buf
,
int
read_len
);
static
void
*
crypt_new
(
SSL
*
ssl
,
uint8_t
*
key
,
uint8_t
*
iv
,
int
is_decrypt
);
static
err_t
send_raw_packet
(
SSL
*
ssl
,
uint8_t
protocol
);
/**
* The server will pick the cipher based on the order that the order that the
* ciphers are listed. This order is defined at compile time.
*/
#ifdef CONFIG_SSL_SKELETON_MODE
const
uint8_t
ssl_prot_prefs
[
NUM_PROTOCOLS
]
=
{
SSL_RC4_128_SHA
};
#else
static
void
session_free
(
SSL_SESSION
*
ssl_sessions
[],
int
sess_index
);
const
uint8_t
ssl_prot_prefs
[
NUM_PROTOCOLS
]
=
#ifdef CONFIG_SSL_PROT_LOW
/* low security, fast speed */
{
SSL_RC4_128_SHA
,
SSL_AES128_SHA
,
SSL_AES256_SHA
,
SSL_RC4_128_MD5
};
#elif CONFIG_SSL_PROT_MEDIUM
/* medium security, medium speed */
{
SSL_AES128_SHA
,
SSL_AES256_SHA
,
SSL_RC4_128_SHA
,
SSL_RC4_128_MD5
};
#else
/* CONFIG_SSL_PROT_HIGH */
/* high security, low speed */
{
SSL_AES256_SHA
,
SSL_AES128_SHA
,
SSL_RC4_128_SHA
,
SSL_RC4_128_MD5
};
#endif
#endif
/* CONFIG_SSL_SKELETON_MODE */
/**
* The cipher map containing all the essentials for each cipher.
*/
#ifdef CONFIG_SSL_SKELETON_MODE
static
const
cipher_info_t
cipher_info
[
NUM_PROTOCOLS
]
=
{
{
/* RC4-SHA */
SSL_RC4_128_SHA
,
/* RC4-SHA */
16
,
/* key size */
0
,
/* iv size */
2
*
(
SHA1_SIZE
+
16
),
/* key block size */
0
,
/* no padding */
SHA1_SIZE
,
/* digest size */
ssl_hmac_sha1
,
/* hmac algorithm */
(
crypt_func
)
RC4_crypt
,
/* encrypt */
(
crypt_func
)
RC4_crypt
/* decrypt */
},
};
#else
static
const
cipher_info_t
cipher_info
[
NUM_PROTOCOLS
]
=
{
{
/* AES128-SHA */
SSL_AES128_SHA
,
/* AES128-SHA */
16
,
/* key size */
16
,
/* iv size */
2
*
(
SHA1_SIZE
+
16
+
16
),
/* key block size */
16
,
/* block padding size */
SHA1_SIZE
,
/* digest size */
ssl_hmac_sha1
,
/* hmac algorithm */
(
crypt_func
)
AES_cbc_encrypt
,
/* encrypt */
(
crypt_func
)
AES_cbc_decrypt
/* decrypt */
},
{
/* AES256-SHA */
SSL_AES256_SHA
,
/* AES256-SHA */
32
,
/* key size */
16
,
/* iv size */
2
*
(
SHA1_SIZE
+
32
+
16
),
/* key block size */
16
,
/* block padding size */
SHA1_SIZE
,
/* digest size */
ssl_hmac_sha1
,
/* hmac algorithm */
(
crypt_func
)
AES_cbc_encrypt
,
/* encrypt */
(
crypt_func
)
AES_cbc_decrypt
/* decrypt */
},
{
/* RC4-SHA */
SSL_RC4_128_SHA
,
/* RC4-SHA */
16
,
/* key size */
0
,
/* iv size */
2
*
(
SHA1_SIZE
+
16
),
/* key block size */
0
,
/* no padding */
SHA1_SIZE
,
/* digest size */
ssl_hmac_sha1
,
/* hmac algorithm */
(
crypt_func
)
RC4_crypt
,
/* encrypt */
(
crypt_func
)
RC4_crypt
/* decrypt */
},
/*
* This protocol is from SSLv2 days and is unlikely to be used - but was
* useful for testing different possible digest algorithms.
*/
{
/* RC4-MD5 */
SSL_RC4_128_MD5
,
/* RC4-MD5 */
16
,
/* key size */
0
,
/* iv size */
2
*
(
MD5_SIZE
+
16
),
/* key block size */
0
,
/* no padding */
MD5_SIZE
,
/* digest size */
ssl_hmac_md5
,
/* hmac algorithm */
(
crypt_func
)
RC4_crypt
,
/* encrypt */
(
crypt_func
)
RC4_crypt
/* decrypt */
},
};
#endif
static
void
prf
(
const
uint8_t
*
sec
,
int
sec_len
,
uint8_t
*
seed
,
int
seed_len
,
uint8_t
*
out
,
int
olen
);
static
const
cipher_info_t
*
get_cipher_info
(
uint8_t
cipher
);
static
void
increment_read_sequence
(
SSL
*
ssl
);
static
void
increment_write_sequence
(
SSL
*
ssl
);
static
void
add_hmac_digest
(
SSL
*
ssl
,
int
snd
,
uint8_t
*
hmac_header
,
const
uint8_t
*
buf
,
int
buf_len
,
uint8_t
*
hmac_buf
);
/* win32 VC6.0 doesn't have variadic macros */
#if defined(WIN32) && !defined(CONFIG_SSL_FULL_MODE)
void
DISPLAY_BYTES
(
SSL
*
ssl
,
const
char
*
format
,
const
uint8_t
*
data
,
int
size
,
...)
{}
#endif
/**
* Establish a new client/server context.
*/
EXP_FUNC
SSL_CTX
*
STDCALL
ICACHE_FLASH_ATTR
ssl_ctx_new
(
uint32_t
options
,
int
num_sessions
)
{
SSL_CTX
*
ssl_ctx
=
(
SSL_CTX
*
)
os_zalloc
(
sizeof
(
SSL_CTX
));
ssl_ctx
->
options
=
options
;
RNG_initialize
();
if
(
load_key_certs
(
ssl_ctx
)
<
0
)
{
os_free
(
ssl_ctx
);
/* can't load our key/certificate pair, so die */
return
NULL
;
}
#ifndef CONFIG_SSL_SKELETON_MODE
ssl_ctx
->
num_sessions
=
num_sessions
;
#endif
SSL_CTX_MUTEX_INIT
(
ssl_ctx
->
mutex
);
#ifndef CONFIG_SSL_SKELETON_MODE
if
(
num_sessions
)
{
ssl_ctx
->
ssl_sessions
=
(
SSL_SESSION
**
)
os_zalloc
(
num_sessions
*
sizeof
(
SSL_SESSION
*
));
}
#endif
return
ssl_ctx
;
}
/*
* Remove a client/server context.
*/
EXP_FUNC
void
STDCALL
ICACHE_FLASH_ATTR
ssl_ctx_free
(
SSL_CTX
*
ssl_ctx
)
{
SSL
*
ssl
;
int
i
;
if
(
ssl_ctx
==
NULL
)
return
;
ssl
=
ssl_ctx
->
head
;
/* clear out all the ssl entries */
while
(
ssl
)
{
SSL
*
next
=
ssl
->
next
;
ssl_free
(
ssl
);
ssl
=
next
;
}
#ifndef CONFIG_SSL_SKELETON_MODE
/* clear out all the sessions */
for
(
i
=
0
;
i
<
ssl_ctx
->
num_sessions
;
i
++
)
session_free
(
ssl_ctx
->
ssl_sessions
,
i
);
os_free
(
ssl_ctx
->
ssl_sessions
);
#endif
i
=
0
;
while
(
i
<
CONFIG_SSL_MAX_CERTS
&&
ssl_ctx
->
certs
[
i
].
buf
)
{
os_free
(
ssl_ctx
->
certs
[
i
].
buf
);
ssl_ctx
->
certs
[
i
++
].
buf
=
NULL
;
}
#ifdef CONFIG_SSL_CERT_VERIFICATION
remove_ca_certs
(
ssl_ctx
->
ca_cert_ctx
);
#endif
ssl_ctx
->
chain_length
=
0
;
SSL_CTX_MUTEX_DESTROY
(
ssl_ctx
->
mutex
);
// ssl_printf("%s %p\n", __func__,ssl_ctx->rsa_ctx);
RSA_free
(
ssl_ctx
->
rsa_ctx
);
RNG_terminate
();
// ssl_printf("%s %p\n", __func__,ssl_ctx);
os_free
(
ssl_ctx
);
}
/*
* Free any used resources used by this connection.
*/
EXP_FUNC
void
STDCALL
ICACHE_FLASH_ATTR
ssl_free
(
SSL
*
ssl
)
{
SSL_CTX
*
ssl_ctx
;
if
(
ssl
==
NULL
)
/* just ignore null pointers */
return
;
/* only notify if we weren't notified first */
/* spec says we must notify when we are dying */
if
(
!
IS_SET_SSL_FLAG
(
SSL_SENT_CLOSE_NOTIFY
))
send_alert
(
ssl
,
SSL_ALERT_CLOSE_NOTIFY
);
// ssl_printf("%s %d\n", __func__, __LINE__);
ssl_ctx
=
ssl
->
ssl_ctx
;
SSL_CTX_LOCK
(
ssl_ctx
->
mutex
);
/* adjust the server SSL list */
if
(
ssl
->
prev
)
ssl
->
prev
->
next
=
ssl
->
next
;
else
ssl_ctx
->
head
=
ssl
->
next
;
if
(
ssl
->
next
)
ssl
->
next
->
prev
=
ssl
->
prev
;
else
ssl_ctx
->
tail
=
ssl
->
prev
;
SSL_CTX_UNLOCK
(
ssl_ctx
->
mutex
);
/* may already be free - but be sure */
os_free
(
ssl
->
encrypt_ctx
);
os_free
(
ssl
->
decrypt_ctx
);
disposable_free
(
ssl
);
#ifdef CONFIG_SSL_CERT_VERIFICATION
x509_free
(
ssl
->
x509_ctx
);
#endif
os_free
(
ssl
);
}
/*
* Read the SSL connection and send any alerts for various errors.
*/
EXP_FUNC
int
STDCALL
ICACHE_FLASH_ATTR
ssl_read
(
SSL
*
ssl
,
uint8_t
**
in_data
)
{
int
ret
=
basic_read
(
ssl
,
in_data
);
/* check for return code so we can send an alert */
if
(
ret
<
SSL_OK
&&
ret
!=
SSL_CLOSE_NOTIFY
)
{
if
(
ret
!=
SSL_ERROR_CONN_LOST
)
{
send_alert
(
ssl
,
ret
);
#ifndef CONFIG_SSL_SKELETON_MODE
/* something nasty happened, so get rid of this session */
kill_ssl_session
(
ssl
->
ssl_ctx
->
ssl_sessions
,
ssl
);
#endif
}
}
return
ret
;
}
/*
* Write application data to the client
*/
EXP_FUNC
int
STDCALL
ICACHE_FLASH_ATTR
ssl_write
(
SSL
*
ssl
,
const
uint8_t
*
out_data
,
int
out_len
)
{
int
n
=
out_len
,
nw
,
i
,
tot
=
0
;
/* maximum size of a TLS packet is around 16kB, so fragment */
do
{
nw
=
n
;
if
(
nw
>
RT_MAX_PLAIN_LENGTH
)
/* fragment if necessary */
nw
=
RT_MAX_PLAIN_LENGTH
;
if
((
i
=
send_packet
(
ssl
,
PT_APP_PROTOCOL_DATA
,
&
out_data
[
tot
],
nw
))
<=
0
)
{
out_len
=
i
;
/* an error */
break
;
}
tot
+=
i
;
n
-=
i
;
}
while
(
n
>
0
);
return
out_len
;
}
/**
* Add a certificate to the certificate chain.
*/
int
ICACHE_FLASH_ATTR
add_cert
(
SSL_CTX
*
ssl_ctx
,
const
uint8_t
*
buf
,
int
len
)
{
int
ret
=
SSL_ERROR_NO_CERT_DEFINED
,
i
=
0
;
SSL_CERT
*
ssl_cert
;
X509_CTX
*
cert
=
NULL
;
int
offset
;
while
(
ssl_ctx
->
certs
[
i
].
buf
&&
i
<
CONFIG_SSL_MAX_CERTS
)
i
++
;
if
(
i
==
CONFIG_SSL_MAX_CERTS
)
/* too many certs */
{
#ifdef CONFIG_SSL_FULL_MODE
ssl_printf
(
"Error: maximum number of certs added (%d) - change of "
"compile-time configuration required
\n
"
,
CONFIG_SSL_MAX_CERTS
);
#endif
goto
error
;
}
if
((
ret
=
x509_new
(
buf
,
&
offset
,
&
cert
)))
goto
error
;
#if defined (CONFIG_SSL_FULL_MODE)
if
(
ssl_ctx
->
options
&
SSL_DISPLAY_CERTS
)
x509_print
(
cert
,
NULL
);
#endif
ssl_cert
=
&
ssl_ctx
->
certs
[
i
];
ssl_cert
->
size
=
len
;
ssl_cert
->
buf
=
(
uint8_t
*
)
os_malloc
(
len
);
os_memcpy
(
ssl_cert
->
buf
,
buf
,
len
);
ssl_ctx
->
chain_length
++
;
len
-=
offset
;
ret
=
SSL_OK
;
/* ok so far */
/* recurse? */
if
(
len
>
0
)
{
ret
=
add_cert
(
ssl_ctx
,
&
buf
[
offset
],
len
);
}
error:
x509_free
(
cert
);
/* don't need anymore */
return
ret
;
}
#ifdef CONFIG_SSL_CERT_VERIFICATION
/**
* Add a certificate authority.
*/
int
ICACHE_FLASH_ATTR
add_cert_auth
(
SSL_CTX
*
ssl_ctx
,
const
uint8_t
*
buf
,
int
len
)
{
int
ret
=
SSL_OK
;
/* ignore errors for now */
int
i
=
0
;
CA_CERT_CTX
*
ca_cert_ctx
;
if
(
ssl_ctx
->
ca_cert_ctx
==
NULL
)
ssl_ctx
->
ca_cert_ctx
=
(
CA_CERT_CTX
*
)
os_zalloc
(
sizeof
(
CA_CERT_CTX
));
ca_cert_ctx
=
ssl_ctx
->
ca_cert_ctx
;
while
(
i
<
CONFIG_X509_MAX_CA_CERTS
&&
ca_cert_ctx
->
cert
[
i
])
i
++
;
while
(
len
>
0
)
{
int
offset
;
if
(
i
>=
CONFIG_X509_MAX_CA_CERTS
)
{
#ifdef CONFIG_SSL_FULL_MODE
ssl_printf
(
"Error: maximum number of CA certs added (%d) - change of "
"compile-time configuration required
\n
"
,
CONFIG_X509_MAX_CA_CERTS
);
#endif
break
;
}
/* ignore the return code */
if
(
x509_new
(
buf
,
&
offset
,
&
ca_cert_ctx
->
cert
[
i
])
==
X509_OK
)
{
#if defined (CONFIG_SSL_FULL_MODE)
if
(
ssl_ctx
->
options
&
SSL_DISPLAY_CERTS
)
x509_print
(
ca_cert_ctx
->
cert
[
i
],
NULL
);
#endif
}
i
++
;
len
-=
offset
;
}
return
ret
;
}
/*
* Retrieve an X.509 distinguished name component
*/
EXP_FUNC
const
char
*
STDCALL
ICACHE_FLASH_ATTR
ssl_get_cert_dn
(
const
SSL
*
ssl
,
int
component
)
{
if
(
ssl
->
x509_ctx
==
NULL
)
return
NULL
;
switch
(
component
)
{
case
SSL_X509_CERT_COMMON_NAME
:
return
ssl
->
x509_ctx
->
cert_dn
[
X509_COMMON_NAME
];
case
SSL_X509_CERT_ORGANIZATION
:
return
ssl
->
x509_ctx
->
cert_dn
[
X509_ORGANIZATION
];
case
SSL_X509_CERT_ORGANIZATIONAL_NAME
:
return
ssl
->
x509_ctx
->
cert_dn
[
X509_ORGANIZATIONAL_UNIT
];
case
SSL_X509_CA_CERT_COMMON_NAME
:
return
ssl
->
x509_ctx
->
ca_cert_dn
[
X509_COMMON_NAME
];
case
SSL_X509_CA_CERT_ORGANIZATION
:
return
ssl
->
x509_ctx
->
ca_cert_dn
[
X509_ORGANIZATION
];
case
SSL_X509_CA_CERT_ORGANIZATIONAL_NAME
:
return
ssl
->
x509_ctx
->
ca_cert_dn
[
X509_ORGANIZATIONAL_UNIT
];
default:
return
NULL
;
}
}
/*
* Retrieve a "Subject Alternative Name" from a v3 certificate
*/
EXP_FUNC
const
char
*
STDCALL
ICACHE_FLASH_ATTR
ssl_get_cert_subject_alt_dnsname
(
const
SSL
*
ssl
,
int
dnsindex
)
{
int
i
;
if
(
ssl
->
x509_ctx
==
NULL
||
ssl
->
x509_ctx
->
subject_alt_dnsnames
==
NULL
)
return
NULL
;
for
(
i
=
0
;
i
<
dnsindex
;
++
i
)
{
if
(
ssl
->
x509_ctx
->
subject_alt_dnsnames
[
i
]
==
NULL
)
return
NULL
;
}
return
ssl
->
x509_ctx
->
subject_alt_dnsnames
[
dnsindex
];
}
#endif
/* CONFIG_SSL_CERT_VERIFICATION */
#if 0
/*
* Find an ssl object based on the client's file descriptor.
*/
EXP_FUNC SSL * STDCALL ICACHE_FLASH_ATTR ssl_find(SSL_CTX *ssl_ctx, int client_fd)
{
SSL *ssl;
SSL_CTX_LOCK(ssl_ctx->mutex);
ssl = ssl_ctx->head;
/* search through all the ssl entries */
while (ssl)
{
if (ssl->client_fd == client_fd)
{
SSL_CTX_UNLOCK(ssl_ctx->mutex);
return ssl;
}
ssl = ssl->next;
}
SSL_CTX_UNLOCK(ssl_ctx->mutex);
return NULL;
}
#endif
/*
* Force the client to perform its handshake again.
*/
EXP_FUNC
int
STDCALL
ICACHE_FLASH_ATTR
ssl_renegotiate
(
SSL
*
ssl
)
{
int
ret
=
SSL_OK
;
disposable_new
(
ssl
);
#ifdef CONFIG_SSL_ENABLE_CLIENT
if
(
IS_SET_SSL_FLAG
(
SSL_IS_CLIENT
))
{
ret
=
do_client_connect
(
ssl
);
}
else
#endif
{
send_packet
(
ssl
,
PT_HANDSHAKE_PROTOCOL
,
g_hello_request
,
sizeof
(
g_hello_request
));
SET_SSL_FLAG
(
SSL_NEED_RECORD
);
}
return
ret
;
}
/**
* @brief Get what we need for key info.
* @param cipher [in] The cipher information we are after
* @param key_size [out] The key size for the cipher
* @param iv_size [out] The iv size for the cipher
* @return The amount of key information we need.
*/
static
const
cipher_info_t
*
ICACHE_FLASH_ATTR
get_cipher_info
(
uint8_t
cipher
)
{
int
i
;
for
(
i
=
0
;
i
<
NUM_PROTOCOLS
;
i
++
)
{
if
(
cipher_info
[
i
].
cipher
==
cipher
)
{
return
&
cipher_info
[
i
];
}
}
return
NULL
;
/* error */
}
#if 0
/*
* Get a new ssl context for a new connection.
*/
SSL *ICACHE_FLASH_ATTR ssl_new(SSL_CTX *ssl_ctx, int client_fd)
{
SSL *ssl = (SSL *)os_zalloc(sizeof(SSL));
ssl->ssl_ctx = ssl_ctx;
ssl->need_bytes = SSL_RECORD_SIZE; /* need a record */
ssl->client_fd = client_fd;
ssl->flag = SSL_NEED_RECORD;
ssl->bm_data = ssl->bm_all_data+BM_RECORD_OFFSET; /* space at the start */
ssl->hs_status = SSL_NOT_OK; /* not connected */
#ifdef CONFIG_ENABLE_VERIFICATION
ssl->ca_cert_ctx = ssl_ctx->ca_cert_ctx;
#endif
disposable_new(ssl);
/* a bit hacky but saves a few bytes of memory */
ssl->flag |= ssl_ctx->options;
SSL_CTX_LOCK(ssl_ctx->mutex);
if (ssl_ctx->head == NULL)
{
ssl_ctx->head = ssl;
ssl_ctx->tail = ssl;
}
else
{
ssl->prev = ssl_ctx->tail;
ssl_ctx->tail->next = ssl;
ssl_ctx->tail = ssl;
}
SSL_CTX_UNLOCK(ssl_ctx->mutex);
return ssl;
}
#endif
/*
* Get a new ssl context for a new connection.(raw api)add by ives 12.12.2013
*/
SSL
*
ICACHE_FLASH_ATTR
ssl_new_context
(
SSL_CTX
*
ssl_ctx
,
struct
tcp_pcb
*
SslClient_pcb
)
{
SSL
*
ssl
=
(
SSL
*
)
os_zalloc
(
sizeof
(
SSL
));
ssl
->
ssl_ctx
=
ssl_ctx
;
ssl
->
need_bytes
=
SSL_RECORD_SIZE
;
/* need a record */
//ssl->client_fd = client_fd;annotation by ives 12.12.2013
ssl
->
SslClient_pcb
=
SslClient_pcb
;
ssl
->
ssl_pbuf
=
NULL
;
ssl
->
flag
=
SSL_NEED_RECORD
;
ssl
->
bm_data
=
ssl
->
bm_all_data
+
BM_RECORD_OFFSET
;
/* space at the start */
ssl
->
hs_status
=
SSL_NOT_OK
;
/* not connected */
#ifdef CONFIG_ENABLE_VERIFICATION
ssl
->
ca_cert_ctx
=
ssl_ctx
->
ca_cert_ctx
;
#endif
disposable_new
(
ssl
);
/* a bit hacky but saves a few bytes of memory */
ssl
->
flag
|=
ssl_ctx
->
options
;
SSL_CTX_LOCK
(
ssl_ctx
->
mutex
);
if
(
ssl_ctx
->
head
==
NULL
)
{
ssl_ctx
->
head
=
ssl
;
ssl_ctx
->
tail
=
ssl
;
}
else
{
ssl
->
prev
=
ssl_ctx
->
tail
;
ssl_ctx
->
tail
->
next
=
ssl
;
ssl_ctx
->
tail
=
ssl
;
}
SSL_CTX_UNLOCK
(
ssl_ctx
->
mutex
);
return
ssl
;
}
/*
* Add a private key to a context.
*/
int
ICACHE_FLASH_ATTR
add_private_key
(
SSL_CTX
*
ssl_ctx
,
SSLObjLoader
*
ssl_obj
)
{
int
ret
=
SSL_OK
;
/* get the private key details */
if
(
asn1_get_private_key
(
ssl_obj
->
buf
,
ssl_obj
->
len
,
&
ssl_ctx
->
rsa_ctx
))
{
ret
=
SSL_ERROR_INVALID_KEY
;
goto
error
;
}
error:
return
ret
;
}
/**
* Increment the read sequence number (as a 64 bit endian indepenent #)
*/
static
void
ICACHE_FLASH_ATTR
increment_read_sequence
(
SSL
*
ssl
)
{
int
i
;
for
(
i
=
7
;
i
>=
0
;
i
--
)
{
if
(
++
ssl
->
read_sequence
[
i
])
break
;
}
}
/**
* Increment the read sequence number (as a 64 bit endian indepenent #)
*/
static
void
ICACHE_FLASH_ATTR
increment_write_sequence
(
SSL
*
ssl
)
{
int
i
;
for
(
i
=
7
;
i
>=
0
;
i
--
)
{
if
(
++
ssl
->
write_sequence
[
i
])
break
;
}
}
/**
* Work out the HMAC digest in a packet.
*/
static
void
ICACHE_FLASH_ATTR
add_hmac_digest
(
SSL
*
ssl
,
int
mode
,
uint8_t
*
hmac_header
,
const
uint8_t
*
buf
,
int
buf_len
,
uint8_t
*
hmac_buf
)
{
int
hmac_len
=
buf_len
+
8
+
SSL_RECORD_SIZE
;
uint8_t
*
t_buf
=
(
uint8_t
*
)
os_malloc
(
hmac_len
+
10
);
os_memcpy
(
t_buf
,
(
mode
==
SSL_SERVER_WRITE
||
mode
==
SSL_CLIENT_WRITE
)
?
ssl
->
write_sequence
:
ssl
->
read_sequence
,
8
);
os_memcpy
(
&
t_buf
[
8
],
hmac_header
,
SSL_RECORD_SIZE
);
os_memcpy
(
&
t_buf
[
8
+
SSL_RECORD_SIZE
],
buf
,
buf_len
);
ssl
->
cipher_info
->
hmac
(
t_buf
,
hmac_len
,
(
mode
==
SSL_SERVER_WRITE
||
mode
==
SSL_CLIENT_READ
)
?
ssl
->
server_mac
:
ssl
->
client_mac
,
ssl
->
cipher_info
->
digest_size
,
hmac_buf
);
/* add by wujg */
os_free
(
t_buf
);
#if 0
print_blob("record", hmac_header, SSL_RECORD_SIZE);
print_blob("buf", buf, buf_len);
if (mode == SSL_SERVER_WRITE || mode == SSL_CLIENT_WRITE)
{
print_blob("write seq", ssl->write_sequence, 8);
}
else
{
print_blob("read seq", ssl->read_sequence, 8);
}
if (mode == SSL_SERVER_WRITE || mode == SSL_CLIENT_READ)
{
print_blob("server mac",
ssl->server_mac, ssl->cipher_info->digest_size);
}
else
{
print_blob("client mac",
ssl->client_mac, ssl->cipher_info->digest_size);
}
print_blob("hmac", hmac_buf, SHA1_SIZE);
#endif
}
/**
* Verify that the digest of a packet is correct.
*/
static
int
ICACHE_FLASH_ATTR
verify_digest
(
SSL
*
ssl
,
int
mode
,
const
uint8_t
*
buf
,
int
read_len
)
{
uint8_t
hmac_buf
[
SHA1_SIZE
];
int
hmac_offset
;
if
(
ssl
->
cipher_info
->
padding_size
)
{
int
last_blk_size
=
buf
[
read_len
-
1
],
i
;
hmac_offset
=
read_len
-
last_blk_size
-
ssl
->
cipher_info
->
digest_size
-
1
;
/* guard against a timing attack - make sure we do the digest */
if
(
hmac_offset
<
0
)
{
hmac_offset
=
0
;
}
else
{
/* already looked at last byte */
for
(
i
=
1
;
i
<
last_blk_size
;
i
++
)
{
if
(
buf
[
read_len
-
i
]
!=
last_blk_size
)
{
hmac_offset
=
0
;
break
;
}
}
}
}
else
/* stream cipher */
{
hmac_offset
=
read_len
-
ssl
->
cipher_info
->
digest_size
;
if
(
hmac_offset
<
0
)
{
hmac_offset
=
0
;
}
}
/* sanity check the offset */
ssl
->
hmac_header
[
3
]
=
hmac_offset
>>
8
;
/* insert size */
ssl
->
hmac_header
[
4
]
=
hmac_offset
&
0xff
;
add_hmac_digest
(
ssl
,
mode
,
ssl
->
hmac_header
,
buf
,
hmac_offset
,
hmac_buf
);
if
(
memcmp
(
hmac_buf
,
&
buf
[
hmac_offset
],
ssl
->
cipher_info
->
digest_size
))
{
return
SSL_ERROR_INVALID_HMAC
;
}
return
hmac_offset
;
}
/**
* Add a packet to the end of our sent and received packets, so that we may use
* it to calculate the hash at the end.
*/
void
ICACHE_FLASH_ATTR
add_packet
(
SSL
*
ssl
,
const
uint8_t
*
pkt
,
int
len
)
{
MD5_Update
(
&
ssl
->
dc
->
md5_ctx
,
pkt
,
len
);
SHA1_Update
(
&
ssl
->
dc
->
sha1_ctx
,
pkt
,
len
);
}
/**
* Work out the MD5 PRF.
*/
static
void
ICACHE_FLASH_ATTR
p_hash_md5
(
const
uint8_t
*
sec
,
int
sec_len
,
uint8_t
*
seed
,
int
seed_len
,
uint8_t
*
out
,
int
olen
)
{
uint8_t
a1
[
128
];
/* A(1) */
ssl_hmac_md5
(
seed
,
seed_len
,
sec
,
sec_len
,
a1
);
os_memcpy
(
&
a1
[
MD5_SIZE
],
seed
,
seed_len
);
ssl_hmac_md5
(
a1
,
MD5_SIZE
+
seed_len
,
sec
,
sec_len
,
out
);
while
(
olen
>
MD5_SIZE
)
{
uint8_t
a2
[
MD5_SIZE
];
out
+=
MD5_SIZE
;
olen
-=
MD5_SIZE
;
/* A(N) */
ssl_hmac_md5
(
a1
,
MD5_SIZE
,
sec
,
sec_len
,
a2
);
os_memcpy
(
a1
,
a2
,
MD5_SIZE
);
/* work out the actual hash */
ssl_hmac_md5
(
a1
,
MD5_SIZE
+
seed_len
,
sec
,
sec_len
,
out
);
}
}
/**
* Work out the SHA1 PRF.
*/
static
void
ICACHE_FLASH_ATTR
p_hash_sha1
(
const
uint8_t
*
sec
,
int
sec_len
,
uint8_t
*
seed
,
int
seed_len
,
uint8_t
*
out
,
int
olen
)
{
uint8_t
a1
[
128
];
/* A(1) */
ssl_hmac_sha1
(
seed
,
seed_len
,
sec
,
sec_len
,
a1
);
os_memcpy
(
&
a1
[
SHA1_SIZE
],
seed
,
seed_len
);
ssl_hmac_sha1
(
a1
,
SHA1_SIZE
+
seed_len
,
sec
,
sec_len
,
out
);
while
(
olen
>
SHA1_SIZE
)
{
uint8_t
a2
[
SHA1_SIZE
];
out
+=
SHA1_SIZE
;
olen
-=
SHA1_SIZE
;
/* A(N) */
ssl_hmac_sha1
(
a1
,
SHA1_SIZE
,
sec
,
sec_len
,
a2
);
os_memcpy
(
a1
,
a2
,
SHA1_SIZE
);
/* work out the actual hash */
ssl_hmac_sha1
(
a1
,
SHA1_SIZE
+
seed_len
,
sec
,
sec_len
,
out
);
}
}
/**
* Work out the PRF.
*/
static
void
ICACHE_FLASH_ATTR
prf
(
const
uint8_t
*
sec
,
int
sec_len
,
uint8_t
*
seed
,
int
seed_len
,
uint8_t
*
out
,
int
olen
)
{
int
len
,
i
;
const
uint8_t
*
S1
,
*
S2
;
uint8_t
xbuf
[
256
];
/* needs to be > the amount of key data */
uint8_t
ybuf
[
256
];
/* needs to be > the amount of key data */
len
=
sec_len
/
2
;
S1
=
sec
;
S2
=
&
sec
[
len
];
len
+=
(
sec_len
&
1
);
/* add for odd, make longer */
p_hash_md5
(
S1
,
len
,
seed
,
seed_len
,
xbuf
,
olen
);
p_hash_sha1
(
S2
,
len
,
seed
,
seed_len
,
ybuf
,
olen
);
for
(
i
=
0
;
i
<
olen
;
i
++
)
out
[
i
]
=
xbuf
[
i
]
^
ybuf
[
i
];
}
/**
* Generate a master secret based on the client/server random data and the
* premaster secret.
*/
void
ICACHE_FLASH_ATTR
generate_master_secret
(
SSL
*
ssl
,
const
uint8_t
*
premaster_secret
)
{
uint8_t
buf
[
128
];
/* needs to be > 13+32+32 in size */
os_strcpy
((
char
*
)
buf
,
"master secret"
);
os_memcpy
(
&
buf
[
13
],
ssl
->
dc
->
client_random
,
SSL_RANDOM_SIZE
);
os_memcpy
(
&
buf
[
45
],
ssl
->
dc
->
server_random
,
SSL_RANDOM_SIZE
);
prf
(
premaster_secret
,
SSL_SECRET_SIZE
,
buf
,
77
,
ssl
->
dc
->
master_secret
,
SSL_SECRET_SIZE
);
}
/**
* Generate a 'random' blob of data used for the generation of keys.
*/
static
void
ICACHE_FLASH_ATTR
generate_key_block
(
uint8_t
*
client_random
,
uint8_t
*
server_random
,
uint8_t
*
master_secret
,
uint8_t
*
key_block
,
int
key_block_size
)
{
uint8_t
buf
[
128
];
os_strcpy
((
char
*
)
buf
,
"key expansion"
);
os_memcpy
(
&
buf
[
13
],
server_random
,
SSL_RANDOM_SIZE
);
os_memcpy
(
&
buf
[
45
],
client_random
,
SSL_RANDOM_SIZE
);
prf
(
master_secret
,
SSL_SECRET_SIZE
,
buf
,
77
,
key_block
,
key_block_size
);
}
/**
* Calculate the digest used in the finished message. This function also
* doubles up as a certificate verify function.
*/
void
ICACHE_FLASH_ATTR
finished_digest
(
SSL
*
ssl
,
const
char
*
label
,
uint8_t
*
digest
)
{
uint8_t
mac_buf
[
128
];
uint8_t
*
q
=
mac_buf
;
MD5_CTX
md5_ctx
=
ssl
->
dc
->
md5_ctx
;
SHA1_CTX
sha1_ctx
=
ssl
->
dc
->
sha1_ctx
;
if
(
label
)
{
os_strcpy
((
char
*
)
q
,
label
);
q
+=
os_strlen
(
label
);
}
MD5_Final
(
q
,
&
md5_ctx
);
q
+=
MD5_SIZE
;
SHA1_Final
(
q
,
&
sha1_ctx
);
q
+=
SHA1_SIZE
;
if
(
label
)
{
prf
(
ssl
->
dc
->
master_secret
,
SSL_SECRET_SIZE
,
mac_buf
,
(
int
)(
q
-
mac_buf
),
digest
,
SSL_FINISHED_HASH_SIZE
);
}
else
/* for use in a certificate verify */
{
os_memcpy
(
digest
,
mac_buf
,
MD5_SIZE
+
SHA1_SIZE
);
}
#if 0
printf("label: %s\n", label);
print_blob("master secret", ssl->dc->master_secret, 48);
print_blob("mac_buf", mac_buf, q-mac_buf);
print_blob("finished digest", digest, SSL_FINISHED_HASH_SIZE);
#endif
}
/**
* Retrieve (and initialise) the context of a cipher.
*/
static
void
*
ICACHE_FLASH_ATTR
crypt_new
(
SSL
*
ssl
,
uint8_t
*
key
,
uint8_t
*
iv
,
int
is_decrypt
)
{
switch
(
ssl
->
cipher
)
{
#ifndef CONFIG_SSL_SKELETON_MODE
case
SSL_AES128_SHA
:
{
AES_CTX
*
aes_ctx
=
(
AES_CTX
*
)
os_malloc
(
sizeof
(
AES_CTX
));
AES_set_key
(
aes_ctx
,
key
,
iv
,
AES_MODE_128
);
if
(
is_decrypt
)
{
AES_convert_key
(
aes_ctx
);
}
return
(
void
*
)
aes_ctx
;
}
case
SSL_AES256_SHA
:
{
AES_CTX
*
aes_ctx
=
(
AES_CTX
*
)
os_malloc
(
sizeof
(
AES_CTX
));
AES_set_key
(
aes_ctx
,
key
,
iv
,
AES_MODE_256
);
if
(
is_decrypt
)
{
AES_convert_key
(
aes_ctx
);
}
return
(
void
*
)
aes_ctx
;
}
case
SSL_RC4_128_MD5
:
#endif
case
SSL_RC4_128_SHA
:
{
RC4_CTX
*
rc4_ctx
=
(
RC4_CTX
*
)
os_malloc
(
sizeof
(
RC4_CTX
));
RC4_setup
(
rc4_ctx
,
key
,
16
);
return
(
void
*
)
rc4_ctx
;
}
}
return
NULL
;
/* its all gone wrong */
}
/**
* Send a packet over the socket.
*/
static
err_t
ICACHE_FLASH_ATTR
send_raw_packet
(
SSL
*
ssl
,
uint8_t
protocol
)
{
uint8_t
*
rec_buf
=
ssl
->
bm_all_data
;
int
pkt_size
=
SSL_RECORD_SIZE
+
ssl
->
bm_index
;
int
Length
=
0
;
//int ret = SSL_OK;
err_t
Err
=
ERR_OK
;
rec_buf
[
0
]
=
protocol
;
rec_buf
[
1
]
=
0x03
;
/* version = 3.1 or higher */
rec_buf
[
2
]
=
ssl
->
version
&
0x0f
;
rec_buf
[
3
]
=
ssl
->
bm_index
>>
8
;
rec_buf
[
4
]
=
ssl
->
bm_index
&
0xff
;
//DISPLAY_BYTES(ssl, "sending %d bytes", ssl->bm_all_data,
// pkt_size, pkt_size);
ssl_printf
(
"send_raw_packet pkt_size %d
\n
"
,
pkt_size
);
if
(
tcp_sndbuf
(
ssl
->
SslClient_pcb
)
<
pkt_size
)
{
Length
=
tcp_sndbuf
(
ssl
->
SslClient_pcb
);
}
else
{
Length
=
pkt_size
;
}
if
(
Length
>
2
*
ssl
->
SslClient_pcb
->
mss
)
{
Length
=
2
*
ssl
->
SslClient_pcb
->
mss
;
}
do
{
Err
=
tcp_write
(
ssl
->
SslClient_pcb
,
&
ssl
->
bm_all_data
[
0
],
Length
,
0
);
if
(
Err
==
ERR_MEM
)
{
Length
/=
2
;
}
}
while
(
Err
==
ERR_MEM
&&
Length
>
1
);
ssl_printf
(
"send_raw_packet Length %d
\n
"
,
Length
);
if
(
Err
==
ERR_OK
)
{
Err
=
tcp_output
(
ssl
->
SslClient_pcb
);
}
SET_SSL_FLAG
(
SSL_NEED_RECORD
);
/* reset for next time */
//ssl->bm_index = 0;
if
(
protocol
!=
PT_APP_PROTOCOL_DATA
)
{
/* always return SSL_OK during handshake */
ssl
->
bm_index
=
0
;
Err
=
SSL_OK
;
}
return
Err
;
}
/**
* Send an encrypted packet with padding bytes if necessary.
*/
int
ICACHE_FLASH_ATTR
send_packet
(
SSL
*
ssl
,
uint8_t
protocol
,
const
uint8_t
*
in
,
int
length
)
{
int
ret
,
msg_length
=
0
;
/* if our state is bad, don't bother */
if
(
ssl
->
hs_status
==
SSL_ERROR_DEAD
)
return
SSL_ERROR_CONN_LOST
;
if
(
in
)
/* has the buffer already been initialised? */
{
os_memcpy
(
ssl
->
bm_data
,
in
,
length
);
}
msg_length
+=
length
;
if
(
IS_SET_SSL_FLAG
(
SSL_TX_ENCRYPTED
))
{
int
mode
=
IS_SET_SSL_FLAG
(
SSL_IS_CLIENT
)
?
SSL_CLIENT_WRITE
:
SSL_SERVER_WRITE
;
uint8_t
hmac_header
[
SSL_RECORD_SIZE
]
=
{
protocol
,
0x03
,
/* version = 3.1 or higher */
ssl
->
version
&
0x0f
,
msg_length
>>
8
,
msg_length
&
0xff
};
if
(
protocol
==
PT_HANDSHAKE_PROTOCOL
)
{
//DISPLAY_STATE(ssl, 1, ssl->bm_data[0], 0);
if
(
ssl
->
bm_data
[
0
]
!=
HS_HELLO_REQUEST
)
{
add_packet
(
ssl
,
ssl
->
bm_data
,
msg_length
);
}
}
/* add the packet digest */
add_hmac_digest
(
ssl
,
mode
,
hmac_header
,
ssl
->
bm_data
,
msg_length
,
&
ssl
->
bm_data
[
msg_length
]);
msg_length
+=
ssl
->
cipher_info
->
digest_size
;
/* add padding? */
if
(
ssl
->
cipher_info
->
padding_size
)
{
int
last_blk_size
=
msg_length
%
ssl
->
cipher_info
->
padding_size
;
int
pad_bytes
=
ssl
->
cipher_info
->
padding_size
-
last_blk_size
;
/* ensure we always have at least 1 padding byte */
if
(
pad_bytes
==
0
)
pad_bytes
+=
ssl
->
cipher_info
->
padding_size
;
os_memset
(
&
ssl
->
bm_data
[
msg_length
],
pad_bytes
-
1
,
pad_bytes
);
msg_length
+=
pad_bytes
;
}
//DISPLAY_BYTES(ssl, "unencrypted write", ssl->bm_data, msg_length);
increment_write_sequence
(
ssl
);
/* add the explicit IV for TLS1.1 */
if
(
ssl
->
version
>=
SSL_PROTOCOL_VERSION1_1
&&
ssl
->
cipher_info
->
iv_size
)
{
uint8_t
iv_size
=
ssl
->
cipher_info
->
iv_size
;
uint8_t
*
t_buf
=
(
uint8_t
*
)
os_malloc
(
msg_length
+
iv_size
);
os_memcpy
(
t_buf
+
iv_size
,
ssl
->
bm_data
,
msg_length
);
get_random
(
iv_size
,
t_buf
);
msg_length
+=
iv_size
;
os_memcpy
(
ssl
->
bm_data
,
t_buf
,
msg_length
);
os_free
(
t_buf
);
/* add by wujg */
}
/* now encrypt the packet */
ssl
->
cipher_info
->
encrypt
(
ssl
->
encrypt_ctx
,
ssl
->
bm_data
,
ssl
->
bm_data
,
msg_length
);
}
else
if
(
protocol
==
PT_HANDSHAKE_PROTOCOL
)
{
//DISPLAY_STATE(ssl, 1, ssl->bm_data[0], 0);
if
(
ssl
->
bm_data
[
0
]
!=
HS_HELLO_REQUEST
)
{
add_packet
(
ssl
,
ssl
->
bm_data
,
length
);
}
}
ssl
->
bm_index
=
msg_length
;
if
((
ret
=
send_raw_packet
(
ssl
,
protocol
))
<=
0
)
return
ret
;
return
length
;
/* just return what we wanted to send */
}
/**
* Work out the cipher keys we are going to use for this session based on the
* master secret.
*/
static
int
ICACHE_FLASH_ATTR
set_key_block
(
SSL
*
ssl
,
int
is_write
)
{
const
cipher_info_t
*
ciph_info
=
get_cipher_info
(
ssl
->
cipher
);
uint8_t
*
q
;
uint8_t
client_key
[
32
],
server_key
[
32
];
/* big enough for AES256 */
uint8_t
client_iv
[
16
],
server_iv
[
16
];
/* big enough for AES128/256 */
int
is_client
=
IS_SET_SSL_FLAG
(
SSL_IS_CLIENT
);
if
(
ciph_info
==
NULL
)
return
-
1
;
/* only do once in a handshake */
if
(
ssl
->
dc
->
key_block
==
NULL
)
{
ssl
->
dc
->
key_block
=
(
uint8_t
*
)
os_malloc
(
ciph_info
->
key_block_size
);
#if 0
print_blob("client", ssl->dc->client_random, 32);
print_blob("server", ssl->dc->server_random, 32);
print_blob("master", ssl->dc->master_secret, SSL_SECRET_SIZE);
#endif
generate_key_block
(
ssl
->
dc
->
client_random
,
ssl
->
dc
->
server_random
,
ssl
->
dc
->
master_secret
,
ssl
->
dc
->
key_block
,
ciph_info
->
key_block_size
);
#if 0
print_blob("keyblock", ssl->dc->key_block, ciph_info->key_block_size);
#endif
}
q
=
ssl
->
dc
->
key_block
;
if
((
is_client
&&
is_write
)
||
(
!
is_client
&&
!
is_write
))
{
os_memcpy
(
ssl
->
client_mac
,
q
,
ciph_info
->
digest_size
);
}
q
+=
ciph_info
->
digest_size
;
if
((
!
is_client
&&
is_write
)
||
(
is_client
&&
!
is_write
))
{
os_memcpy
(
ssl
->
server_mac
,
q
,
ciph_info
->
digest_size
);
}
q
+=
ciph_info
->
digest_size
;
os_memcpy
(
client_key
,
q
,
ciph_info
->
key_size
);
q
+=
ciph_info
->
key_size
;
os_memcpy
(
server_key
,
q
,
ciph_info
->
key_size
);
q
+=
ciph_info
->
key_size
;
#ifndef CONFIG_SSL_SKELETON_MODE
if
(
ciph_info
->
iv_size
)
/* RC4 has no IV, AES does */
{
os_memcpy
(
client_iv
,
q
,
ciph_info
->
iv_size
);
q
+=
ciph_info
->
iv_size
;
os_memcpy
(
server_iv
,
q
,
ciph_info
->
iv_size
);
q
+=
ciph_info
->
iv_size
;
}
#endif
os_free
(
is_write
?
ssl
->
encrypt_ctx
:
ssl
->
decrypt_ctx
);
/* now initialise the ciphers */
if
(
is_client
)
{
finished_digest
(
ssl
,
server_finished
,
ssl
->
dc
->
final_finish_mac
);
if
(
is_write
)
ssl
->
encrypt_ctx
=
crypt_new
(
ssl
,
client_key
,
client_iv
,
0
);
else
ssl
->
decrypt_ctx
=
crypt_new
(
ssl
,
server_key
,
server_iv
,
1
);
}
else
{
finished_digest
(
ssl
,
client_finished
,
ssl
->
dc
->
final_finish_mac
);
if
(
is_write
)
ssl
->
encrypt_ctx
=
crypt_new
(
ssl
,
server_key
,
server_iv
,
0
);
else
ssl
->
decrypt_ctx
=
crypt_new
(
ssl
,
client_key
,
client_iv
,
1
);
}
ssl
->
cipher_info
=
ciph_info
;
return
0
;
}
/**
* Read the SSL connection.
*/
int
ICACHE_FLASH_ATTR
basic_read
(
SSL
*
ssl
,
uint8_t
**
in_data
)
{
int
ret
=
SSL_OK
;
int
j
,
i
=
0
;
int
read_len
,
is_client
=
IS_SET_SSL_FLAG
(
SSL_IS_CLIENT
);
uint8_t
*
buf
=
ssl
->
bm_data
;
uint8_t
*
read_buf
=
NULL
;
uint8_t
*
pread_buf
=
NULL
;
u16_t
recvlength
=
0
;
read_buf
=
(
uint8_t
*
)
os_zalloc
(
ssl
->
ssl_pbuf
->
len
+
1
);
pread_buf
=
read_buf
;
if
(
pread_buf
!=
NULL
){
recvlength
=
pbuf_copy_partial
(
ssl
->
ssl_pbuf
,
read_buf
,
ssl
->
ssl_pbuf
->
len
,
0
);
}
if
(
recvlength
!=
0
){
do
{
// ssl_printf("basic_read ssl->bm_read_index %d\n", ssl->bm_read_index);
// ssl_printf("basic_read ssl->need_bytes %d\n", ssl->need_bytes);
// ssl_printf("basic_read ssl->got_bytes %d\n", ssl->got_bytes);
read_len
=
ssl
->
need_bytes
-
ssl
->
got_bytes
;
if
(
read_len
>=
recvlength
){
read_len
=
recvlength
;
}
os_memcpy
(
&
buf
[
ssl
->
bm_read_index
],
read_buf
,
read_len
);
// ssl_printf("basic_read read_len %d\n", read_len);
// for (i = ssl->bm_read_index; i < (ssl->bm_read_index + read_len); i ++){
// ssl_printf("%2x ",buf[i]);
// if ((i + 1) % 16 == 0)
// ssl_printf("\n");
// }
// ssl_printf("\n");
read_buf
+=
read_len
;
recvlength
-=
read_len
;
// ssl_printf("basic_read %d %d\n", __LINE__, recvlength);
/* connection has gone, so die */
if
(
read_len
<=
0
)
{
ret
=
SSL_ERROR_CONN_LOST
;
ssl
->
hs_status
=
SSL_ERROR_DEAD
;
/* make sure it stays dead */
goto
error
;
}
//DISPLAY_BYTES(ssl, "received %d bytes",
// &ssl->bm_data[ssl->bm_read_index], read_len, read_len);
ssl
->
got_bytes
+=
read_len
;
ssl
->
bm_read_index
+=
read_len
;
/* haven't quite got what we want, so try again later */
if
(
ssl
->
got_bytes
<
ssl
->
need_bytes
){
// ssl_printf("basic_read %d %p\n", __LINE__, pread_buf);
os_free
(
pread_buf
);
pread_buf
=
NULL
;
return
SSL_OK
;
}
read_len
=
ssl
->
got_bytes
;
ssl
->
got_bytes
=
0
;
if
(
IS_SET_SSL_FLAG
(
SSL_NEED_RECORD
))
{
/* check for sslv2 "client hello" */
if
(
buf
[
0
]
&
0x80
&&
buf
[
2
]
==
1
)
{
#ifdef CONFIG_SSL_ENABLE_V23_HANDSHAKE
uint8_t
version
=
(
buf
[
3
]
<<
4
)
+
buf
[
4
];
DISPLAY_BYTES
(
ssl
,
"ssl2 record"
,
buf
,
5
);
/* should be v3.1 (TLSv1) or better */
ssl
->
version
=
ssl
->
client_version
=
version
;
if
(
version
>
SSL_PROTOCOL_VERSION_MAX
)
{
/* use client's version */
ssl
->
version
=
SSL_PROTOCOL_VERSION_MAX
;
}
else
if
(
version
<
SSL_PROTOCOL_MIN_VERSION
)
{
ret
=
SSL_ERROR_INVALID_VERSION
;
ssl_display_error
(
ret
);
return
ret
;
}
add_packet
(
ssl
,
&
buf
[
2
],
3
);
ret
=
process_sslv23_client_hello
(
ssl
);
#else
ssl_printf
(
"Error: no SSLv23 handshaking allowed
\n
"
);
//TTY_FLUSH();
ret
=
SSL_ERROR_NOT_SUPPORTED
;
#endif
goto
error
;
/* not an error - just get out of here */
}
ssl
->
need_bytes
=
(
buf
[
3
]
<<
8
)
+
buf
[
4
];
/* do we violate the spec with the message size? */
if
(
ssl
->
need_bytes
>
RT_MAX_PLAIN_LENGTH
+
RT_EXTRA
-
BM_RECORD_OFFSET
)
{
ret
=
SSL_ERROR_INVALID_PROT_MSG
;
recvlength
=
0
;
os_printf
(
"we violate the spec with the message size
\n
"
);
goto
error
;
}
CLR_SSL_FLAG
(
SSL_NEED_RECORD
);
os_memcpy
(
ssl
->
hmac_header
,
buf
,
3
);
/* store for hmac */
ssl
->
record_type
=
buf
[
0
];
goto
error
;
/* no error, we're done */
}
/* for next time - just do it now in case of an error */
SET_SSL_FLAG
(
SSL_NEED_RECORD
);
ssl
->
need_bytes
=
SSL_RECORD_SIZE
;
/* decrypt if we need to */
if
(
IS_SET_SSL_FLAG
(
SSL_RX_ENCRYPTED
))
{
ssl
->
cipher_info
->
decrypt
(
ssl
->
decrypt_ctx
,
buf
,
buf
,
read_len
);
if
(
ssl
->
version
>=
SSL_PROTOCOL_VERSION1_1
&&
ssl
->
cipher_info
->
iv_size
)
{
buf
+=
ssl
->
cipher_info
->
iv_size
;
read_len
-=
ssl
->
cipher_info
->
iv_size
;
}
read_len
=
verify_digest
(
ssl
,
is_client
?
SSL_CLIENT_READ
:
SSL_SERVER_READ
,
buf
,
read_len
);
/* does the hmac work? */
if
(
read_len
<
0
)
{
ret
=
read_len
;
goto
error
;
}
//DISPLAY_BYTES(ssl, "decrypted", buf, read_len);
increment_read_sequence
(
ssl
);
}
/* The main part of the SSL packet */
//ssl_printf("basic_read %d %x %p\n", __LINE__, ssl->record_type, in_data);
switch
(
ssl
->
record_type
)
{
case
PT_HANDSHAKE_PROTOCOL
:
if
(
ssl
->
dc
!=
NULL
)
{
ssl
->
dc
->
bm_proc_index
=
0
;
ret
=
do_handshake
(
ssl
,
buf
,
read_len
);
}
else
/* no client renegotiation allowed */
{
ret
=
SSL_ERROR_NO_CLIENT_RENOG
;
goto
error
;
}
break
;
case
PT_CHANGE_CIPHER_SPEC
:
if
(
ssl
->
next_state
!=
HS_FINISHED
)
{
ret
=
SSL_ERROR_INVALID_HANDSHAKE
;
goto
error
;
}
/* all encrypted from now on */
SET_SSL_FLAG
(
SSL_RX_ENCRYPTED
);
if
(
set_key_block
(
ssl
,
0
)
<
0
)
{
ret
=
SSL_ERROR_INVALID_HANDSHAKE
;
goto
error
;
}
os_memset
(
ssl
->
read_sequence
,
0
,
8
);
break
;
case
PT_APP_PROTOCOL_DATA
:
if
(
in_data
)
{
*
in_data
=
buf
;
/* point to the work buffer */
(
*
in_data
)[
read_len
]
=
0
;
/* null terminate just in case */
}
ret
=
read_len
;
recvlength
=
0
;
break
;
case
PT_ALERT_PROTOCOL
:
/* return the alert # with alert bit set */
if
(
buf
[
0
]
==
SSL_ALERT_TYPE_WARNING
&&
buf
[
1
]
==
SSL_ALERT_CLOSE_NOTIFY
)
{
ret
=
SSL_CLOSE_NOTIFY
;
//send_alert(ssl, SSL_ALERT_CLOSE_NOTIFY);
SET_SSL_FLAG
(
SSL_SENT_CLOSE_NOTIFY
);
}
else
{
ret
=
-
buf
[
1
];
//DISPLAY_ALERT(ssl, buf[1]);
}
break
;
default:
ret
=
SSL_ERROR_INVALID_PROT_MSG
;
break
;
}
error:
ssl
->
bm_read_index
=
0
;
/* reset to go again */
if
(
ret
<
SSL_OK
&&
in_data
)
/* if all wrong, then clear this buffer ptr */
*
in_data
=
NULL
;
}
while
(
recvlength
!=
0
);
}
else
{
ssl_printf
(
"%s %d %d
\n
"
,
__func__
,
__LINE__
,
recvlength
);
}
os_free
(
pread_buf
);
pread_buf
=
NULL
;
return
ret
;
}
/**
* Do some basic checking of data and then perform the appropriate handshaking.
*/
static
int
ICACHE_FLASH_ATTR
do_handshake
(
SSL
*
ssl
,
uint8_t
*
buf
,
int
read_len
)
{
int
hs_len
=
(
buf
[
2
]
<<
8
)
+
buf
[
3
];
uint8_t
handshake_type
=
buf
[
0
];
int
ret
=
SSL_OK
;
int
is_client
=
IS_SET_SSL_FLAG
(
SSL_IS_CLIENT
);
/* some integrity checking on the handshake */
PARANOIA_CHECK
(
read_len
-
SSL_HS_HDR_SIZE
,
hs_len
);
if
(
handshake_type
!=
ssl
->
next_state
)
{
/* handle a special case on the client */
if
(
!
is_client
||
handshake_type
!=
HS_CERT_REQ
||
ssl
->
next_state
!=
HS_SERVER_HELLO_DONE
)
{
ret
=
SSL_ERROR_INVALID_HANDSHAKE
;
goto
error
;
}
}
hs_len
+=
SSL_HS_HDR_SIZE
;
/* adjust for when adding packets */
ssl
->
bm_index
=
hs_len
;
/* store the size and check later */
//DISPLAY_STATE(ssl, 0, handshake_type, 0);
if
(
handshake_type
!=
HS_CERT_VERIFY
&&
handshake_type
!=
HS_HELLO_REQUEST
)
add_packet
(
ssl
,
buf
,
hs_len
);
#if defined(CONFIG_SSL_ENABLE_CLIENT)
ret
=
is_client
?
do_clnt_handshake
(
ssl
,
handshake_type
,
buf
,
hs_len
)
:
do_svr_handshake
(
ssl
,
handshake_type
,
buf
,
hs_len
);
#else
ret
=
do_svr_handshake
(
ssl
,
handshake_type
,
buf
,
hs_len
);
#endif
/* just use recursion to get the rest */
if
(
hs_len
<
read_len
&&
ret
==
SSL_OK
)
ret
=
do_handshake
(
ssl
,
&
buf
[
hs_len
],
read_len
-
hs_len
);
error:
return
ret
;
}
/**
* Sends the change cipher spec message. We have just read a finished message
* from the client.
*/
int
ICACHE_FLASH_ATTR
send_change_cipher_spec
(
SSL
*
ssl
)
{
int
ret
=
send_packet
(
ssl
,
PT_CHANGE_CIPHER_SPEC
,
g_chg_cipher_spec_pkt
,
sizeof
(
g_chg_cipher_spec_pkt
));
SET_SSL_FLAG
(
SSL_TX_ENCRYPTED
);
if
(
ret
>=
0
&&
set_key_block
(
ssl
,
1
)
<
0
)
ret
=
SSL_ERROR_INVALID_HANDSHAKE
;
os_memset
(
ssl
->
write_sequence
,
0
,
8
);
return
ret
;
}
/**
* Send a "finished" message
*/
int
ICACHE_FLASH_ATTR
send_finished
(
SSL
*
ssl
)
{
uint8_t
buf
[
SSL_FINISHED_HASH_SIZE
+
4
]
=
{
HS_FINISHED
,
0
,
0
,
SSL_FINISHED_HASH_SIZE
};
/* now add the finished digest mac (12 bytes) */
finished_digest
(
ssl
,
IS_SET_SSL_FLAG
(
SSL_IS_CLIENT
)
?
client_finished
:
server_finished
,
&
buf
[
4
]);
#ifndef CONFIG_SSL_SKELETON_MODE
/* store in the session cache */
if
(
!
IS_SET_SSL_FLAG
(
SSL_SESSION_RESUME
)
&&
ssl
->
ssl_ctx
->
num_sessions
)
{
os_memcpy
(
ssl
->
session
->
master_secret
,
ssl
->
dc
->
master_secret
,
SSL_SECRET_SIZE
);
}
#endif
return
send_packet
(
ssl
,
PT_HANDSHAKE_PROTOCOL
,
buf
,
SSL_FINISHED_HASH_SIZE
+
4
);
}
/**
* Send an alert message.
* Return 1 if the alert was an "error".
*/
int
ICACHE_FLASH_ATTR
send_alert
(
SSL
*
ssl
,
int
error_code
)
{
int
alert_num
=
0
;
int
is_warning
=
0
;
uint8_t
buf
[
2
];
/* Don't bother we're already dead */
if
(
ssl
->
hs_status
==
SSL_ERROR_DEAD
)
{
return
SSL_ERROR_CONN_LOST
;
}
#ifdef CONFIG_SSL_FULL_MODE
//if (IS_SET_SSL_FLAG(SSL_DISPLAY_STATES))
//ssl_display_error(error_code);
#endif
switch
(
error_code
)
{
case
SSL_ALERT_CLOSE_NOTIFY
:
is_warning
=
1
;
alert_num
=
SSL_ALERT_CLOSE_NOTIFY
;
break
;
case
SSL_ERROR_CONN_LOST
:
/* don't send alert just yet */
is_warning
=
1
;
break
;
case
SSL_ERROR_INVALID_HANDSHAKE
:
case
SSL_ERROR_INVALID_PROT_MSG
:
alert_num
=
SSL_ALERT_HANDSHAKE_FAILURE
;
break
;
case
SSL_ERROR_INVALID_HMAC
:
case
SSL_ERROR_FINISHED_INVALID
:
alert_num
=
SSL_ALERT_BAD_RECORD_MAC
;
break
;
case
SSL_ERROR_INVALID_VERSION
:
alert_num
=
SSL_ALERT_INVALID_VERSION
;
break
;
case
SSL_ERROR_INVALID_SESSION
:
case
SSL_ERROR_NO_CIPHER
:
case
SSL_ERROR_INVALID_KEY
:
alert_num
=
SSL_ALERT_ILLEGAL_PARAMETER
;
break
;
case
SSL_ERROR_BAD_CERTIFICATE
:
alert_num
=
SSL_ALERT_BAD_CERTIFICATE
;
break
;
case
SSL_ERROR_NO_CLIENT_RENOG
:
alert_num
=
SSL_ALERT_NO_RENEGOTIATION
;
break
;
default:
/* a catch-all for any badly verified certificates */
alert_num
=
(
error_code
<=
SSL_X509_OFFSET
)
?
SSL_ALERT_BAD_CERTIFICATE
:
SSL_ALERT_UNEXPECTED_MESSAGE
;
break
;
}
buf
[
0
]
=
is_warning
?
1
:
2
;
buf
[
1
]
=
alert_num
;
send_packet
(
ssl
,
PT_ALERT_PROTOCOL
,
buf
,
sizeof
(
buf
));
//DISPLAY_ALERT(ssl, alert_num);
return
is_warning
?
0
:
1
;
}
/**
* Process a client finished message.
*/
int
ICACHE_FLASH_ATTR
process_finished
(
SSL
*
ssl
,
uint8_t
*
buf
,
int
hs_len
)
{
int
ret
=
SSL_OK
;
int
is_client
=
IS_SET_SSL_FLAG
(
SSL_IS_CLIENT
);
int
resume
=
IS_SET_SSL_FLAG
(
SSL_SESSION_RESUME
);
PARANOIA_CHECK
(
ssl
->
bm_index
,
SSL_FINISHED_HASH_SIZE
+
4
);
/* check that we all work before we continue */
if
(
os_memcmp
(
ssl
->
dc
->
final_finish_mac
,
&
buf
[
4
],
SSL_FINISHED_HASH_SIZE
))
return
SSL_ERROR_FINISHED_INVALID
;
if
((
!
is_client
&&
!
resume
)
||
(
is_client
&&
resume
))
{
if
((
ret
=
send_change_cipher_spec
(
ssl
))
==
SSL_OK
)
ret
=
send_finished
(
ssl
);
}
/* if we ever renegotiate */
ssl
->
next_state
=
is_client
?
HS_HELLO_REQUEST
:
HS_CLIENT_HELLO
;
ssl
->
hs_status
=
ret
;
/* set the final handshake status */
error:
return
ret
;
}
/**
* Send a certificate.
*/
int
ICACHE_FLASH_ATTR
send_certificate
(
SSL
*
ssl
)
{
int
i
=
0
;
uint8_t
*
buf
=
ssl
->
bm_data
;
int
offset
=
7
;
int
chain_length
;
buf
[
0
]
=
HS_CERTIFICATE
;
buf
[
1
]
=
0
;
buf
[
4
]
=
0
;
while
(
i
<
ssl
->
ssl_ctx
->
chain_length
)
{
SSL_CERT
*
cert
=
&
ssl
->
ssl_ctx
->
certs
[
i
];
buf
[
offset
++
]
=
0
;
buf
[
offset
++
]
=
cert
->
size
>>
8
;
/* cert 1 length */
buf
[
offset
++
]
=
cert
->
size
&
0xff
;
os_memcpy
(
&
buf
[
offset
],
cert
->
buf
,
cert
->
size
);
offset
+=
cert
->
size
;
i
++
;
}
chain_length
=
offset
-
7
;
buf
[
5
]
=
chain_length
>>
8
;
/* cert chain length */
buf
[
6
]
=
chain_length
&
0xff
;
chain_length
+=
3
;
buf
[
2
]
=
chain_length
>>
8
;
/* handshake length */
buf
[
3
]
=
chain_length
&
0xff
;
ssl
->
bm_index
=
offset
;
return
send_packet
(
ssl
,
PT_HANDSHAKE_PROTOCOL
,
NULL
,
offset
);
}
/**
* Create a blob of memory that we'll get rid of once the handshake is
* complete.
*/
void
ICACHE_FLASH_ATTR
disposable_new
(
SSL
*
ssl
)
{
if
(
ssl
->
dc
==
NULL
)
{
ssl
->
dc
=
(
DISPOSABLE_CTX
*
)
os_zalloc
(
sizeof
(
DISPOSABLE_CTX
));
MD5_Init
(
&
ssl
->
dc
->
md5_ctx
);
SHA1_Init
(
&
ssl
->
dc
->
sha1_ctx
);
}
}
/**
* Remove the temporary blob of memory.
*/
void
ICACHE_FLASH_ATTR
disposable_free
(
SSL
*
ssl
)
{
if
(
ssl
->
dc
)
{
os_free
(
ssl
->
dc
->
key_block
);
os_memset
(
ssl
->
dc
,
0
,
sizeof
(
DISPOSABLE_CTX
));
os_free
(
ssl
->
dc
);
ssl
->
dc
=
NULL
;
}
}
#ifndef CONFIG_SSL_SKELETON_MODE
/* no session resumption in this mode */
/**
* Find if an existing session has the same session id. If so, use the
* master secret from this session for session resumption.
*/
SSL_SESSION
*
ICACHE_FLASH_ATTR
ssl_session_update
(
int
max_sessions
,
SSL_SESSION
*
ssl_sessions
[],
SSL
*
ssl
,
const
uint8_t
*
session_id
)
{
time_t
tm
=
0
;
//time(NULL); wujg
time_t
oldest_sess_time
=
tm
;
SSL_SESSION
*
oldest_sess
=
NULL
;
int
i
;
/* no sessions? Then bail */
if
(
max_sessions
==
0
)
return
NULL
;
SSL_CTX_LOCK
(
ssl
->
ssl_ctx
->
mutex
);
if
(
session_id
)
{
for
(
i
=
0
;
i
<
max_sessions
;
i
++
)
{
if
(
ssl_sessions
[
i
])
{
/* kill off any expired sessions (including those in
the future) */
if
((
tm
>
ssl_sessions
[
i
]
->
conn_time
+
SSL_EXPIRY_TIME
)
||
(
tm
<
ssl_sessions
[
i
]
->
conn_time
))
{
session_free
(
ssl_sessions
,
i
);
continue
;
}
/* if the session id matches, it must still be less than
the expiry time */
if
(
os_memcmp
(
ssl_sessions
[
i
]
->
session_id
,
session_id
,
SSL_SESSION_ID_SIZE
)
==
0
)
{
ssl
->
session_index
=
i
;
os_memcpy
(
ssl
->
dc
->
master_secret
,
ssl_sessions
[
i
]
->
master_secret
,
SSL_SECRET_SIZE
);
SET_SSL_FLAG
(
SSL_SESSION_RESUME
);
SSL_CTX_UNLOCK
(
ssl
->
ssl_ctx
->
mutex
);
return
ssl_sessions
[
i
];
/* a session was found */
}
}
}
}
/* If we've got here, no matching session was found - so create one */
for
(
i
=
0
;
i
<
max_sessions
;
i
++
)
{
if
(
ssl_sessions
[
i
]
==
NULL
)
{
/* perfect, this will do */
ssl_sessions
[
i
]
=
(
SSL_SESSION
*
)
os_zalloc
(
sizeof
(
SSL_SESSION
));
ssl_sessions
[
i
]
->
conn_time
=
tm
;
ssl
->
session_index
=
i
;
SSL_CTX_UNLOCK
(
ssl
->
ssl_ctx
->
mutex
);
return
ssl_sessions
[
i
];
/* return the session object */
}
else
if
(
ssl_sessions
[
i
]
->
conn_time
<=
oldest_sess_time
)
{
/* find the oldest session */
oldest_sess_time
=
ssl_sessions
[
i
]
->
conn_time
;
oldest_sess
=
ssl_sessions
[
i
];
ssl
->
session_index
=
i
;
}
}
/* ok, we've used up all of our sessions. So blow the oldest session away */
oldest_sess
->
conn_time
=
tm
;
os_memset
(
oldest_sess
->
session_id
,
0
,
sizeof
(
SSL_SESSION_ID_SIZE
));
os_memset
(
oldest_sess
->
master_secret
,
0
,
sizeof
(
SSL_SECRET_SIZE
));
SSL_CTX_UNLOCK
(
ssl
->
ssl_ctx
->
mutex
);
return
oldest_sess
;
}
/**
* Free an existing session.
*/
static
void
ICACHE_FLASH_ATTR
session_free
(
SSL_SESSION
*
ssl_sessions
[],
int
sess_index
)
{
if
(
ssl_sessions
[
sess_index
])
{
os_free
(
ssl_sessions
[
sess_index
]);
ssl_sessions
[
sess_index
]
=
NULL
;
}
}
/**
* This ssl object doesn't want this session anymore.
*/
void
ICACHE_FLASH_ATTR
kill_ssl_session
(
SSL_SESSION
**
ssl_sessions
,
SSL
*
ssl
)
{
SSL_CTX_LOCK
(
ssl
->
ssl_ctx
->
mutex
);
if
(
ssl
->
ssl_ctx
->
num_sessions
)
{
session_free
(
ssl_sessions
,
ssl
->
session_index
);
ssl
->
session
=
NULL
;
}
SSL_CTX_UNLOCK
(
ssl
->
ssl_ctx
->
mutex
);
}
#endif
/* CONFIG_SSL_SKELETON_MODE */
/*
* Get the session id for a handshake. This will be a 32 byte sequence.
*/
EXP_FUNC
const
uint8_t
*
STDCALL
ICACHE_FLASH_ATTR
ssl_get_session_id
(
const
SSL
*
ssl
)
{
return
ssl
->
session_id
;
}
/*
* Get the session id size for a handshake.
*/
EXP_FUNC
uint8_t
STDCALL
ICACHE_FLASH_ATTR
ssl_get_session_id_size
(
const
SSL
*
ssl
)
{
return
ssl
->
sess_id_size
;
}
/*
* Return the cipher id (in the SSL form).
*/
EXP_FUNC
uint8_t
STDCALL
ICACHE_FLASH_ATTR
ssl_get_cipher_id
(
const
SSL
*
ssl
)
{
return
ssl
->
cipher
;
}
/*
* Return the status of the handshake.
*/
EXP_FUNC
int
STDCALL
ICACHE_FLASH_ATTR
ssl_handshake_status
(
const
SSL
*
ssl
)
{
return
ssl
->
hs_status
;
}
/*
* Retrieve various parameters about the SSL engine.
*/
EXP_FUNC
int
STDCALL
ICACHE_FLASH_ATTR
ssl_get_config
(
int
offset
)
{
switch
(
offset
)
{
/* return the appropriate build mode */
case
SSL_BUILD_MODE
:
#if defined(CONFIG_SSL_FULL_MODE)
return
SSL_BUILD_FULL_MODE
;
#elif defined(CONFIG_SSL_ENABLE_CLIENT)
return
SSL_BUILD_ENABLE_CLIENT
;
#elif defined(CONFIG_ENABLE_VERIFICATION)
return
SSL_BUILD_ENABLE_VERIFICATION
;
#elif defined(CONFIG_SSL_SERVER_ONLY )
return
SSL_BUILD_SERVER_ONLY
;
#else
return
SSL_BUILD_SKELETON_MODE
;
#endif
case
SSL_MAX_CERT_CFG_OFFSET
:
return
CONFIG_SSL_MAX_CERTS
;
#ifdef CONFIG_SSL_CERT_VERIFICATION
case
SSL_MAX_CA_CERT_CFG_OFFSET
:
return
CONFIG_X509_MAX_CA_CERTS
;
#endif
#ifdef CONFIG_SSL_HAS_PEM
case
SSL_HAS_PEM
:
return
1
;
#endif
default:
return
0
;
}
}
#ifdef CONFIG_SSL_CERT_VERIFICATION
/**
* Authenticate a received certificate.
*/
EXP_FUNC
int
STDCALL
ICACHE_FLASH_ATTR
ssl_verify_cert
(
const
SSL
*
ssl
)
{
int
ret
;
SSL_CTX_LOCK
(
ssl
->
ssl_ctx
->
mutex
);
ret
=
x509_verify
(
ssl
->
ssl_ctx
->
ca_cert_ctx
,
ssl
->
x509_ctx
);
SSL_CTX_UNLOCK
(
ssl
->
ssl_ctx
->
mutex
);
if
(
ret
)
/* modify into an SSL error type */
{
ret
=
SSL_X509_ERROR
(
ret
);
}
return
ret
;
}
/**
* Process a certificate message.
*/
int
ICACHE_FLASH_ATTR
process_certificate
(
SSL
*
ssl
,
X509_CTX
**
x509_ctx
)
{
int
ret
=
SSL_OK
;
uint8_t
*
buf
=
&
ssl
->
bm_data
[
ssl
->
dc
->
bm_proc_index
];
int
pkt_size
=
ssl
->
bm_index
;
int
cert_size
,
offset
=
5
;
int
total_cert_size
=
(
buf
[
offset
]
<<
8
)
+
buf
[
offset
+
1
];
int
is_client
=
IS_SET_SSL_FLAG
(
SSL_IS_CLIENT
);
X509_CTX
**
chain
=
x509_ctx
;
offset
+=
2
;
PARANOIA_CHECK
(
total_cert_size
,
offset
);
while
(
offset
<
total_cert_size
)
{
offset
++
;
/* skip empty char */
cert_size
=
(
buf
[
offset
]
<<
8
)
+
buf
[
offset
+
1
];
offset
+=
2
;
if
(
x509_new
(
&
buf
[
offset
],
NULL
,
chain
))
{
ret
=
SSL_ERROR_BAD_CERTIFICATE
;
goto
error
;
}
chain
=
&
((
*
chain
)
->
next
);
offset
+=
cert_size
;
}
PARANOIA_CHECK
(
pkt_size
,
offset
);
/* if we are client we can do the verify now or later */
if
(
is_client
&&
!
IS_SET_SSL_FLAG
(
SSL_SERVER_VERIFY_LATER
))
{
ret
=
ssl_verify_cert
(
ssl
);
}
ssl
->
next_state
=
is_client
?
HS_SERVER_HELLO_DONE
:
HS_CLIENT_KEY_XCHG
;
ssl
->
dc
->
bm_proc_index
+=
offset
;
error:
return
ret
;
}
#endif
/* CONFIG_SSL_CERT_VERIFICATION */
/**
* Debugging routine to display SSL handshaking stuff.
*/
#ifdef CONFIG_SSL_FULL_MODE
/**
* Debugging routine to display SSL states.
*/
#if 0
void ICACHE_FLASH_ATTR DISPLAY_STATE(SSL *ssl, int is_send, uint8_t state, int not_ok)
{
const char *str;
if (!IS_SET_SSL_FLAG(SSL_DISPLAY_STATES))
return;
ssl_printf(not_ok ? "Error - invalid State:\t" : "State:\t");
ssl_printf(is_send ? "sending " : "receiving ");
switch (state)
{
case HS_HELLO_REQUEST:
str = "Hello Request (0)";
break;
case HS_CLIENT_HELLO:
str = "Client Hello (1)";
break;
case HS_SERVER_HELLO:
str = "Server Hello (2)";
break;
case HS_CERTIFICATE:
str = "Certificate (11)";
break;
case HS_SERVER_KEY_XCHG:
str = "Certificate Request (12)";
break;
case HS_CERT_REQ:
str = "Certificate Request (13)";
break;
case HS_SERVER_HELLO_DONE:
str = "Server Hello Done (14)";
break;
case HS_CERT_VERIFY:
str = "Certificate Verify (15)";
break;
case HS_CLIENT_KEY_XCHG:
str = "Client Key Exchange (16)";
break;
case HS_FINISHED:
str = "Finished (16)";
break;
default:
str = "Error (Unknown)";
break;
}
ssl_printf("%s\n", str);
//TTY_FLUSH();
}
/**
* Debugging routine to display RSA objects
*/
void ICACHE_FLASH_ATTR DISPLAY_RSA(SSL *ssl, const RSA_CTX *rsa_ctx)
{
if (!IS_SET_SSL_FLAG(SSL_DISPLAY_RSA))
return;
RSA_print(rsa_ctx);
//TTY_FLUSH();
}
/**
* Debugging routine to display SSL handshaking bytes.
*/
void ICACHE_FLASH_ATTR DISPLAY_BYTES(SSL *ssl, const char *format,
const uint8_t *data, int size, ...)
{
// wujg : pass compile first
// va_list(ap);
// if (!IS_SET_SSL_FLAG(SSL_DISPLAY_BYTES))
// return;
// va_start(ap, size);
// print_blob(format, data, size, va_arg(ap, char *));
// va_end(ap);
// TTY_FLUSH();
}
/**
* Debugging routine to display SSL handshaking errors.
*/
EXP_FUNC void STDCALL ICACHE_FLASH_ATTR ssl_display_error(int error_code)
{
if (error_code == SSL_OK)
return;
ssl_printf("Error: ");
/* X509 error? */
if (error_code < SSL_X509_OFFSET)
{
ssl_printf("%s\n", x509_display_error(error_code - SSL_X509_OFFSET));
return;
}
/* SSL alert error code */
if (error_code > SSL_ERROR_CONN_LOST)
{
ssl_printf("SSL error %d\n", -error_code);
return;
}
switch (error_code)
{
case SSL_ERROR_DEAD:
ssl_printf("connection dead");
break;
case SSL_ERROR_INVALID_HANDSHAKE:
ssl_printf("invalid handshake");
break;
case SSL_ERROR_INVALID_PROT_MSG:
ssl_printf("invalid protocol message");
break;
case SSL_ERROR_INVALID_HMAC:
ssl_printf("invalid mac");
break;
case SSL_ERROR_INVALID_VERSION:
ssl_printf("invalid version");
break;
case SSL_ERROR_INVALID_SESSION:
ssl_printf("invalid session");
break;
case SSL_ERROR_NO_CIPHER:
ssl_printf("no cipher");
break;
case SSL_ERROR_CONN_LOST:
ssl_printf("connection lost");
break;
case SSL_ERROR_BAD_CERTIFICATE:
ssl_printf("bad certificate");
break;
case SSL_ERROR_INVALID_KEY:
ssl_printf("invalid key");
break;
case SSL_ERROR_FINISHED_INVALID:
ssl_printf("finished invalid");
break;
case SSL_ERROR_NO_CERT_DEFINED:
ssl_printf("no certificate defined");
break;
case SSL_ERROR_NO_CLIENT_RENOG:
ssl_printf("client renegotiation not supported");
break;
case SSL_ERROR_NOT_SUPPORTED:
ssl_printf("Option not supported");
break;
default:
ssl_printf("undefined as yet - %d", error_code);
break;
}
ssl_printf("\n");
//TTY_FLUSH();
}
/**
* Debugging routine to display alerts.
*/
void ICACHE_FLASH_ATTR DISPLAY_ALERT(SSL *ssl, int alert)
{
if (!IS_SET_SSL_FLAG(SSL_DISPLAY_STATES))
return;
ssl_printf("Alert: ");
switch (alert)
{
case SSL_ALERT_CLOSE_NOTIFY:
ssl_printf("close notify");
break;
case SSL_ALERT_INVALID_VERSION:
ssl_printf("invalid version");
break;
case SSL_ALERT_BAD_CERTIFICATE:
ssl_printf("bad certificate");
break;
case SSL_ALERT_UNEXPECTED_MESSAGE:
ssl_printf("unexpected message");
break;
case SSL_ALERT_BAD_RECORD_MAC:
ssl_printf("bad record mac");
break;
case SSL_ALERT_HANDSHAKE_FAILURE:
ssl_printf("handshake failure");
break;
case SSL_ALERT_ILLEGAL_PARAMETER:
ssl_printf("illegal parameter");
break;
case SSL_ALERT_DECODE_ERROR:
ssl_printf("decode error");
break;
case SSL_ALERT_DECRYPT_ERROR:
ssl_printf("decrypt error");
break;
case SSL_ALERT_NO_RENEGOTIATION:
ssl_printf("no renegotiation");
break;
default:
ssl_printf("alert - (unknown %d)", alert);
break;
}
ssl_printf("\n");
//TTY_FLUSH();
}
#endif
#endif
/* CONFIG_SSL_FULL_MODE */
/**
* Return the version of this library.
*/
EXP_FUNC
const
char
*
STDCALL
ICACHE_FLASH_ATTR
ssl_version
()
{
static
const
char
*
axtls_version
=
AXTLS_VERSION
;
return
axtls_version
;
}
/**
* Enable the various language bindings to work regardless of the
* configuration - they just return an error statement and a bad return code.
*/
#if !defined(CONFIG_SSL_FULL_MODE)
EXP_FUNC
void
STDCALL
ssl_display_error
(
int
error_code
)
{}
#endif
#ifdef CONFIG_BINDINGS
#if !defined(CONFIG_SSL_ENABLE_CLIENT)
EXP_FUNC
SSL
*
STDCALL
ICACHE_FLASH_ATTR
ssl_client_new
(
SSL_CTX
*
ssl_ctx
,
int
client_fd
,
const
uint8_t
*
session_id
,
uint8_t
sess_id_size
)
{
ssl_printf
(
unsupported_str
);
return
NULL
;
}
#endif
#if !defined(CONFIG_SSL_CERT_VERIFICATION)
EXP_FUNC
int
STDCALL
ICACHE_FLASH_ATTR
ssl_verify_cert
(
const
SSL
*
ssl
)
{
ssl_printf
(
unsupported_str
);
return
-
1
;
}
EXP_FUNC
const
char
*
STDCALL
ICACHE_FLASH_ATTR
ssl_get_cert_dn
(
const
SSL
*
ssl
,
int
component
)
{
ssl_printf
(
unsupported_str
);
return
NULL
;
}
EXP_FUNC
const
char
*
STDCALL
ICACHE_FLASH_ATTR
ssl_get_cert_subject_alt_dnsname
(
const
SSL
*
ssl
,
int
index
)
{
ssl_printf
(
unsupported_str
);
return
NULL
;
}
#endif
/* CONFIG_SSL_CERT_VERIFICATION */
#endif
/* CONFIG_BINDINGS */
app/ssl/ssl/ssl_tls1_clnt.c
deleted
100644 → 0
View file @
21c4e110
/*
* Copyright (c) 2007, Cameron Rich
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the axTLS project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//#include <stdlib.h>
//#include <string.h>
//#include <time.h>
//#include <stdio.h>
#include "ssl/ssl_os_port.h"
#include "ssl/ssl_ssl.h"
#include "lwip/tcp.h"
#include "ssl/app/espconn_ssl.h"
#ifdef CONFIG_SSL_ENABLE_CLIENT
/* all commented out if no client */
static
int
send_client_hello
(
SSL
*
ssl
);
static
int
process_server_hello
(
SSL
*
ssl
);
static
int
process_server_hello_done
(
SSL
*
ssl
);
static
int
send_client_key_xchg
(
SSL
*
ssl
);
static
int
process_cert_req
(
SSL
*
ssl
);
static
int
send_cert_verify
(
SSL
*
ssl
);
#if 0
/*
* Establish a new SSL connection to an SSL server.
*/
EXP_FUNC SSL * STDCALL ICACHE_FLASH_ATTR ssl_client_new(SSL_CTX *ssl_ctx, int client_fd, const
uint8_t *session_id, uint8_t sess_id_size)
{
SSL *ssl = ssl_new(ssl_ctx, client_fd);
ssl->version = SSL_PROTOCOL_VERSION_MAX; /* try top version first */
if (session_id && ssl_ctx->num_sessions)
{
if (sess_id_size > SSL_SESSION_ID_SIZE) /* validity check */
{
ssl_free(ssl);
return NULL;
}
os_memcpy(ssl->session_id, session_id, sess_id_size);
ssl->sess_id_size = sess_id_size;
SET_SSL_FLAG(SSL_SESSION_RESUME); /* just flag for later */
}
SET_SSL_FLAG(SSL_IS_CLIENT);
do_client_connect(ssl);
return ssl;
}
#endif
/*
* Establish a new SSL connection to an SSL server.(raw api)add by ives 12.12.2013
*/
EXP_FUNC
SSL
*
STDCALL
ICACHE_FLASH_ATTR
SSLClient_new
(
SSL_CTX
*
ssl_ctx
,
struct
tcp_pcb
*
SslClient_pcb
,
const
uint8_t
*
session_id
,
uint8_t
sess_id_size
)
{
SSL
*
ssl
=
ssl_new_context
(
ssl_ctx
,
SslClient_pcb
);
ssl
->
version
=
SSL_PROTOCOL_VERSION_MAX
;
if
(
session_id
&&
ssl_ctx
->
num_sessions
)
{
if
(
sess_id_size
>
SSL_SESSION_ID_SIZE
)
{
ssl_free
(
ssl
);
return
NULL
;
}
os_memcpy
(
ssl
->
session_id
,
session_id
,
sess_id_size
);
ssl
->
sess_id_size
=
sess_id_size
;
SET_SSL_FLAG
(
SSL_SESSION_RESUME
);
}
SET_SSL_FLAG
(
SSL_IS_CLIENT
);
do_client_connect
(
ssl
);
return
ssl
;
}
/*
* Process the handshake record.
*/
int
ICACHE_FLASH_ATTR
do_clnt_handshake
(
SSL
*
ssl
,
int
handshake_type
,
uint8_t
*
buf
,
int
hs_len
)
{
int
ret
;
/* To get here the state must be valid */
// ssl_printf("do_clnt_handshake: %d %d\n",__LINE__, handshake_type);
switch
(
handshake_type
)
{
case
HS_SERVER_HELLO
:
ret
=
process_server_hello
(
ssl
);
break
;
case
HS_CERTIFICATE
:
ret
=
process_certificate
(
ssl
,
&
ssl
->
x509_ctx
);
break
;
case
HS_SERVER_HELLO_DONE
:
if
((
ret
=
process_server_hello_done
(
ssl
))
==
SSL_OK
)
{
if
(
IS_SET_SSL_FLAG
(
SSL_HAS_CERT_REQ
))
{
if
((
ret
=
send_certificate
(
ssl
))
==
SSL_OK
&&
(
ret
=
send_client_key_xchg
(
ssl
))
==
SSL_OK
)
{
send_cert_verify
(
ssl
);
}
}
else
{
ret
=
send_client_key_xchg
(
ssl
);
}
if
(
ret
==
SSL_OK
&&
(
ret
=
send_change_cipher_spec
(
ssl
))
==
SSL_OK
)
{
ret
=
send_finished
(
ssl
);
}
}
break
;
case
HS_CERT_REQ
:
ret
=
process_cert_req
(
ssl
);
break
;
case
HS_FINISHED
:
ret
=
process_finished
(
ssl
,
buf
,
hs_len
);
disposable_free
(
ssl
);
/* free up some memory */
/* note: client renegotiation is not allowed after this */
break
;
case
HS_HELLO_REQUEST
:
disposable_new
(
ssl
);
ret
=
do_client_connect
(
ssl
);
break
;
default:
ret
=
SSL_ERROR_INVALID_HANDSHAKE
;
break
;
}
return
ret
;
}
/*
* Do the handshaking from the beginning.
*/
int
ICACHE_FLASH_ATTR
do_client_connect
(
SSL
*
ssl
)
{
int
ret
=
SSL_OK
;
send_client_hello
(
ssl
);
/* send the client hello */
ssl
->
bm_read_index
=
0
;
ssl
->
next_state
=
HS_SERVER_HELLO
;
ssl
->
hs_status
=
SSL_NOT_OK
;
/* not connected */
#if 0
/* sit in a loop until it all looks good */
if (!IS_SET_SSL_FLAG(SSL_CONNECT_IN_PARTS))
{
while (ssl->hs_status != SSL_OK)
{
ret = ssl_read(ssl, NULL);
ssl_printf("%s %d %d\n", __func__, __LINE__,ret);
if (ret < SSL_OK)
break;
}
ssl->hs_status = ret; /* connected? */
}
#endif
return
ret
;
}
/*
* Send the initial client hello.
*/
static
int
ICACHE_FLASH_ATTR
send_client_hello
(
SSL
*
ssl
)
{
uint8_t
*
buf
=
ssl
->
bm_data
;
time_t
tm
=
0
;
//time(NULL); wujg : pass compile first
uint8_t
*
tm_ptr
=
&
buf
[
6
];
/* time will go here */
int
i
,
offset
;
buf
[
0
]
=
HS_CLIENT_HELLO
;
buf
[
1
]
=
0
;
buf
[
2
]
=
0
;
/* byte 3 is calculated later */
buf
[
4
]
=
0x03
;
buf
[
5
]
=
ssl
->
version
&
0x0f
;
/* client random value - spec says that 1st 4 bytes are big endian time */
*
tm_ptr
++
=
(
uint8_t
)(((
long
)
tm
&
0xff000000
)
>>
24
);
*
tm_ptr
++
=
(
uint8_t
)(((
long
)
tm
&
0x00ff0000
)
>>
16
);
*
tm_ptr
++
=
(
uint8_t
)(((
long
)
tm
&
0x0000ff00
)
>>
8
);
*
tm_ptr
++
=
(
uint8_t
)(((
long
)
tm
&
0x000000ff
));
get_random
(
SSL_RANDOM_SIZE
-
4
,
&
buf
[
10
]);
os_memcpy
(
ssl
->
dc
->
client_random
,
&
buf
[
6
],
SSL_RANDOM_SIZE
);
offset
=
6
+
SSL_RANDOM_SIZE
;
/* give session resumption a go */
if
(
IS_SET_SSL_FLAG
(
SSL_SESSION_RESUME
))
/* set initially by user */
{
buf
[
offset
++
]
=
ssl
->
sess_id_size
;
os_memcpy
(
&
buf
[
offset
],
ssl
->
session_id
,
ssl
->
sess_id_size
);
offset
+=
ssl
->
sess_id_size
;
CLR_SSL_FLAG
(
SSL_SESSION_RESUME
);
/* clear so we can set later */
}
else
{
/* no session id - because no session resumption just yet */
buf
[
offset
++
]
=
0
;
}
buf
[
offset
++
]
=
0
;
/* number of ciphers */
buf
[
offset
++
]
=
NUM_PROTOCOLS
*
2
;
/* number of ciphers */
/* put all our supported protocols in our request */
for
(
i
=
0
;
i
<
NUM_PROTOCOLS
;
i
++
)
{
buf
[
offset
++
]
=
0
;
/* cipher we are using */
buf
[
offset
++
]
=
ssl_prot_prefs
[
i
];
}
buf
[
offset
++
]
=
1
;
/* no compression */
buf
[
offset
++
]
=
0
;
buf
[
3
]
=
offset
-
4
;
/* handshake size */
return
send_packet
(
ssl
,
PT_HANDSHAKE_PROTOCOL
,
NULL
,
offset
);
}
/*
* Process the server hello.
*/
static
int
ICACHE_FLASH_ATTR
process_server_hello
(
SSL
*
ssl
)
{
uint8_t
*
buf
=
ssl
->
bm_data
;
int
pkt_size
=
ssl
->
bm_index
;
int
num_sessions
=
ssl
->
ssl_ctx
->
num_sessions
;
uint8_t
sess_id_size
;
int
offset
,
ret
=
SSL_OK
;
/* check that we are talking to a TLSv1 server */
uint8_t
version
=
(
buf
[
4
]
<<
4
)
+
buf
[
5
];
if
(
version
>
SSL_PROTOCOL_VERSION_MAX
)
{
version
=
SSL_PROTOCOL_VERSION_MAX
;
}
else
if
(
ssl
->
version
<
SSL_PROTOCOL_MIN_VERSION
)
{
ret
=
SSL_ERROR_INVALID_VERSION
;
//ssl_display_error(ret);
goto
error
;
}
ssl
->
version
=
version
;
/* get the server random value */
os_memcpy
(
ssl
->
dc
->
server_random
,
&
buf
[
6
],
SSL_RANDOM_SIZE
);
offset
=
6
+
SSL_RANDOM_SIZE
;
/* skip of session id size */
sess_id_size
=
buf
[
offset
++
];
if
(
sess_id_size
>
SSL_SESSION_ID_SIZE
)
{
ret
=
SSL_ERROR_INVALID_SESSION
;
goto
error
;
}
if
(
num_sessions
)
{
ssl
->
session
=
ssl_session_update
(
num_sessions
,
ssl
->
ssl_ctx
->
ssl_sessions
,
ssl
,
&
buf
[
offset
]);
os_memcpy
(
ssl
->
session
->
session_id
,
&
buf
[
offset
],
sess_id_size
);
/* pad the rest with 0's */
if
(
sess_id_size
<
SSL_SESSION_ID_SIZE
)
{
os_memset
(
&
ssl
->
session
->
session_id
[
sess_id_size
],
0
,
SSL_SESSION_ID_SIZE
-
sess_id_size
);
}
}
os_memcpy
(
ssl
->
session_id
,
&
buf
[
offset
],
sess_id_size
);
ssl
->
sess_id_size
=
sess_id_size
;
offset
+=
sess_id_size
;
/* get the real cipher we are using */
ssl
->
cipher
=
buf
[
++
offset
];
ssl
->
next_state
=
IS_SET_SSL_FLAG
(
SSL_SESSION_RESUME
)
?
HS_FINISHED
:
HS_CERTIFICATE
;
offset
++
;
// skip the compr
PARANOIA_CHECK
(
pkt_size
,
offset
);
ssl
->
dc
->
bm_proc_index
=
offset
+
1
;
error:
return
ret
;
}
/**
* Process the server hello done message.
*/
static
int
ICACHE_FLASH_ATTR
process_server_hello_done
(
SSL
*
ssl
)
{
ssl
->
next_state
=
HS_FINISHED
;
return
SSL_OK
;
}
/*
* Send a client key exchange message.
*/
static
int
ICACHE_FLASH_ATTR
send_client_key_xchg
(
SSL
*
ssl
)
{
uint8_t
*
buf
=
ssl
->
bm_data
;
uint8_t
premaster_secret
[
SSL_SECRET_SIZE
];
int
enc_secret_size
=
-
1
;
buf
[
0
]
=
HS_CLIENT_KEY_XCHG
;
buf
[
1
]
=
0
;
premaster_secret
[
0
]
=
0x03
;
/* encode the version number */
premaster_secret
[
1
]
=
SSL_PROTOCOL_MINOR_VERSION
;
/* must be TLS 1.1 */
get_random
(
SSL_SECRET_SIZE
-
2
,
&
premaster_secret
[
2
]);
//DISPLAY_RSA(ssl, ssl->x509_ctx->rsa_ctx);
/* rsa_ctx->bi_ctx is not thread-safe */
SSL_CTX_LOCK
(
ssl
->
ssl_ctx
->
mutex
);
enc_secret_size
=
RSA_encrypt
(
ssl
->
x509_ctx
->
rsa_ctx
,
premaster_secret
,
SSL_SECRET_SIZE
,
&
buf
[
6
],
0
);
SSL_CTX_UNLOCK
(
ssl
->
ssl_ctx
->
mutex
);
buf
[
2
]
=
(
enc_secret_size
+
2
)
>>
8
;
buf
[
3
]
=
(
enc_secret_size
+
2
)
&
0xff
;
buf
[
4
]
=
enc_secret_size
>>
8
;
buf
[
5
]
=
enc_secret_size
&
0xff
;
generate_master_secret
(
ssl
,
premaster_secret
);
return
send_packet
(
ssl
,
PT_HANDSHAKE_PROTOCOL
,
NULL
,
enc_secret_size
+
6
);
}
/*
* Process the certificate request.
*/
static
int
ICACHE_FLASH_ATTR
process_cert_req
(
SSL
*
ssl
)
{
uint8_t
*
buf
=
&
ssl
->
bm_data
[
ssl
->
dc
->
bm_proc_index
];
int
ret
=
SSL_OK
;
int
offset
=
(
buf
[
2
]
<<
4
)
+
buf
[
3
];
int
pkt_size
=
ssl
->
bm_index
;
/* don't do any processing - we will send back an RSA certificate anyway */
ssl
->
next_state
=
HS_SERVER_HELLO_DONE
;
SET_SSL_FLAG
(
SSL_HAS_CERT_REQ
);
ssl
->
dc
->
bm_proc_index
+=
offset
;
PARANOIA_CHECK
(
pkt_size
,
offset
);
error:
return
ret
;
}
/*
* Send a certificate verify message.
*/
static
int
ICACHE_FLASH_ATTR
send_cert_verify
(
SSL
*
ssl
)
{
uint8_t
*
buf
=
ssl
->
bm_data
;
uint8_t
dgst
[
MD5_SIZE
+
SHA1_SIZE
];
RSA_CTX
*
rsa_ctx
=
ssl
->
ssl_ctx
->
rsa_ctx
;
int
n
=
0
,
ret
;
//DISPLAY_RSA(ssl, rsa_ctx);
buf
[
0
]
=
HS_CERT_VERIFY
;
buf
[
1
]
=
0
;
finished_digest
(
ssl
,
NULL
,
dgst
);
/* calculate the digest */
/* rsa_ctx->bi_ctx is not thread-safe */
if
(
rsa_ctx
)
{
SSL_CTX_LOCK
(
ssl
->
ssl_ctx
->
mutex
);
n
=
RSA_encrypt
(
rsa_ctx
,
dgst
,
sizeof
(
dgst
),
&
buf
[
6
],
1
);
SSL_CTX_UNLOCK
(
ssl
->
ssl_ctx
->
mutex
);
if
(
n
==
0
)
{
ret
=
SSL_ERROR_INVALID_KEY
;
goto
error
;
}
}
buf
[
4
]
=
n
>>
8
;
/* add the RSA size (not officially documented) */
buf
[
5
]
=
n
&
0xff
;
n
+=
2
;
buf
[
2
]
=
n
>>
8
;
buf
[
3
]
=
n
&
0xff
;
ret
=
send_packet
(
ssl
,
PT_HANDSHAKE_PROTOCOL
,
NULL
,
n
+
4
);
error:
return
ret
;
}
#endif
/* CONFIG_SSL_ENABLE_CLIENT */
Prev
1
2
3
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment